6 #include <ipxe/iobuf.h>
7 #include <ipxe/tables.h>
8 #include <ipxe/ipstat.h>
9 #include <ipxe/netdevice.h>
10 #include <ipxe/tcpip.h>
14 * Transport-network layer interface
16 * This file contains functions and utilities for the
17 * TCP/IP transport-network layer interface
20 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL
);
23 * Process a received TCP/IP packet
26 * @v netdev Network device
27 * @v tcpip_proto Transport-layer protocol number
28 * @v st_src Partially-filled source address
29 * @v st_dest Partially-filled destination address
30 * @v pshdr_csum Pseudo-header checksum
31 * @v stats IP statistics
32 * @ret rc Return status code
34 * This function expects a transport-layer segment from the network
35 * layer. The network layer should fill in as much as it can of the
36 * source and destination addresses (i.e. it should fill in the
37 * address family and the network-layer addresses, but leave the ports
38 * and the rest of the structures as zero).
40 int tcpip_rx ( struct io_buffer
*iobuf
, struct net_device
*netdev
,
41 uint8_t tcpip_proto
, struct sockaddr_tcpip
*st_src
,
42 struct sockaddr_tcpip
*st_dest
, uint16_t pshdr_csum
,
43 struct ip_statistics
*stats
) {
44 struct tcpip_protocol
*tcpip
;
46 /* Hand off packet to the appropriate transport-layer protocol */
47 for_each_table_entry ( tcpip
, TCPIP_PROTOCOLS
) {
48 if ( tcpip
->tcpip_proto
== tcpip_proto
) {
49 DBG ( "TCP/IP received %s packet\n", tcpip
->name
);
51 return tcpip
->rx ( iobuf
, netdev
, st_src
, st_dest
,
56 DBG ( "Unrecognised TCP/IP protocol %d\n", tcpip_proto
);
57 stats
->in_unknown_protos
++;
59 return -EPROTONOSUPPORT
;
63 * Find TCP/IP network-layer protocol
65 * @v sa_family Address family
66 * @ret tcpip_net TCP/IP network-layer protocol, or NULL if not found
68 struct tcpip_net_protocol
* tcpip_net_protocol ( sa_family_t sa_family
) {
69 struct tcpip_net_protocol
*tcpip_net
;
71 for_each_table_entry ( tcpip_net
, TCPIP_NET_PROTOCOLS
) {
72 if ( tcpip_net
->sa_family
== sa_family
)
76 DBG ( "Unrecognised TCP/IP address family %d\n", sa_family
);
81 * Transmit a TCP/IP packet
84 * @v tcpip_protocol Transport-layer protocol
85 * @v st_src Source address, or NULL to use route default
86 * @v st_dest Destination address
87 * @v netdev Network device to use if no route found, or NULL
88 * @v trans_csum Transport-layer checksum to complete, or NULL
89 * @ret rc Return status code
91 int tcpip_tx ( struct io_buffer
*iobuf
, struct tcpip_protocol
*tcpip_protocol
,
92 struct sockaddr_tcpip
*st_src
, struct sockaddr_tcpip
*st_dest
,
93 struct net_device
*netdev
, uint16_t *trans_csum
) {
94 struct tcpip_net_protocol
*tcpip_net
;
96 /* Hand off packet to the appropriate network-layer protocol */
97 tcpip_net
= tcpip_net_protocol ( st_dest
->st_family
);
99 DBG ( "TCP/IP sending %s packet\n", tcpip_net
->name
);
100 return tcpip_net
->tx ( iobuf
, tcpip_protocol
, st_src
, st_dest
,
101 netdev
, trans_csum
);
105 return -EAFNOSUPPORT
;
109 * Determine transmitting network device
111 * @v st_dest Destination address
112 * @ret netdev Network device, or NULL
114 struct net_device
* tcpip_netdev ( struct sockaddr_tcpip
*st_dest
) {
115 struct tcpip_net_protocol
*tcpip_net
;
117 /* Hand off to the appropriate network-layer protocol */
118 tcpip_net
= tcpip_net_protocol ( st_dest
->st_family
);
120 return tcpip_net
->netdev ( st_dest
);
126 * Determine maximum transmission unit
128 * @v st_dest Destination address
129 * @ret mtu Maximum transmission unit
131 size_t tcpip_mtu ( struct sockaddr_tcpip
*st_dest
) {
132 struct tcpip_net_protocol
*tcpip_net
;
133 struct net_device
*netdev
;
136 /* Find appropriate network-layer protocol */
137 tcpip_net
= tcpip_net_protocol ( st_dest
->st_family
);
141 /* Find transmitting network device */
142 netdev
= tcpip_net
->netdev ( st_dest
);
147 mtu
= ( netdev
->mtu
- tcpip_net
->header_len
);
153 * Calculate continued TCP/IP checkum
155 * @v partial Checksum of already-summed data, in network byte order
156 * @v data Data buffer
157 * @v len Length of data buffer
158 * @ret cksum Updated checksum, in network byte order
160 * Calculates a TCP/IP-style 16-bit checksum over the data block. The
161 * checksum is returned in network byte order.
163 * This function may be used to add new data to an existing checksum.
164 * The function assumes that both the old data and the new data start
165 * on even byte offsets; if this is not the case then you will need to
166 * byte-swap either the input partial checksum, the output checksum,
167 * or both. Deciding which to swap is left as an exercise for the
170 uint16_t generic_tcpip_continue_chksum ( uint16_t partial
,
171 const void *data
, size_t len
) {
172 unsigned int cksum
= ( ( ~partial
) & 0xffff );
176 for ( i
= 0 ; i
< len
; i
++ ) {
177 value
= * ( ( uint8_t * ) data
+ i
);
179 /* Odd bytes: swap on little-endian systems */
180 value
= be16_to_cpu ( value
);
182 /* Even bytes: swap on big-endian systems */
183 value
= le16_to_cpu ( value
);
186 if ( cksum
> 0xffff )
194 * Calculate TCP/IP checkum
196 * @v data Data buffer
197 * @v len Length of data buffer
198 * @ret cksum Checksum, in network byte order
200 * Calculates a TCP/IP-style 16-bit checksum over the data block. The
201 * checksum is returned in network byte order.
203 uint16_t tcpip_chksum ( const void *data
, size_t len
) {
204 return tcpip_continue_chksum ( TCPIP_EMPTY_CSUM
, data
, len
);
208 * Bind to local TCP/IP port
210 * @v st_local Local TCP/IP socket address, or NULL
211 * @v available Function to check port availability
212 * @ret port Local port number, or negative error
214 int tcpip_bind ( struct sockaddr_tcpip
*st_local
,
215 int ( * available
) ( int port
) ) {
217 uint16_t try_port
= 0;
223 /* Extract parameters from local socket address */
225 flags
= st_local
->st_flags
;
226 try_port
= ntohs ( st_local
->st_port
);
229 /* If an explicit port is specified, check its availability */
231 return available ( try_port
);
233 /* Otherwise, find an available port in the range [1,1023] or
234 * [1025,65535] as appropriate.
236 min_port
= ( ( ( ~flags
) & TCPIP_BIND_PRIVILEGED
) + 1 );
237 max_port
= ( ( flags
& TCPIP_BIND_PRIVILEGED
) - 1 );
239 for ( i
= 0 ; i
<= max_port
; i
++ ) {
240 try_port
= ( ( i
+ offset
) & max_port
);
241 if ( try_port
< min_port
)
243 if ( available ( try_port
) < 0 )