[infiniband] Parse MLID, rate, and SL from multicast membership record
[ipxe.git] / src / net / tcpip.c
1 #include <stdint.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <byteswap.h>
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>
11
12 /** @file
13 *
14 * Transport-network layer interface
15 *
16 * This file contains functions and utilities for the
17 * TCP/IP transport-network layer interface
18 */
19
20 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
21
22 /**
23 * Process a received TCP/IP packet
24 *
25 * @v iobuf I/O buffer
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
33 *
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).
39 */
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;
45
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 );
50 stats->in_delivers++;
51 return tcpip->rx ( iobuf, netdev, st_src, st_dest,
52 pshdr_csum );
53 }
54 }
55
56 DBG ( "Unrecognised TCP/IP protocol %d\n", tcpip_proto );
57 stats->in_unknown_protos++;
58 free_iob ( iobuf );
59 return -EPROTONOSUPPORT;
60 }
61
62 /**
63 * Find TCP/IP network-layer protocol
64 *
65 * @v sa_family Address family
66 * @ret tcpip_net TCP/IP network-layer protocol, or NULL if not found
67 */
68 struct tcpip_net_protocol * tcpip_net_protocol ( sa_family_t sa_family ) {
69 struct tcpip_net_protocol *tcpip_net;
70
71 for_each_table_entry ( tcpip_net, TCPIP_NET_PROTOCOLS ) {
72 if ( tcpip_net->sa_family == sa_family )
73 return tcpip_net;
74 }
75
76 DBG ( "Unrecognised TCP/IP address family %d\n", sa_family );
77 return NULL;
78 }
79
80 /**
81 * Transmit a TCP/IP packet
82 *
83 * @v iobuf I/O buffer
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
90 */
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;
95
96 /* Hand off packet to the appropriate network-layer protocol */
97 tcpip_net = tcpip_net_protocol ( st_dest->st_family );
98 if ( tcpip_net ) {
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 );
102 }
103
104 free_iob ( iobuf );
105 return -EAFNOSUPPORT;
106 }
107
108 /**
109 * Determine transmitting network device
110 *
111 * @v st_dest Destination address
112 * @ret netdev Network device, or NULL
113 */
114 struct net_device * tcpip_netdev ( struct sockaddr_tcpip *st_dest ) {
115 struct tcpip_net_protocol *tcpip_net;
116
117 /* Hand off to the appropriate network-layer protocol */
118 tcpip_net = tcpip_net_protocol ( st_dest->st_family );
119 if ( tcpip_net )
120 return tcpip_net->netdev ( st_dest );
121
122 return NULL;
123 }
124
125 /**
126 * Determine maximum transmission unit
127 *
128 * @v st_dest Destination address
129 * @ret mtu Maximum transmission unit
130 */
131 size_t tcpip_mtu ( struct sockaddr_tcpip *st_dest ) {
132 struct tcpip_net_protocol *tcpip_net;
133 struct net_device *netdev;
134 size_t mtu;
135
136 /* Find appropriate network-layer protocol */
137 tcpip_net = tcpip_net_protocol ( st_dest->st_family );
138 if ( ! tcpip_net )
139 return 0;
140
141 /* Find transmitting network device */
142 netdev = tcpip_net->netdev ( st_dest );
143 if ( ! netdev )
144 return 0;
145
146 /* Calculate MTU */
147 mtu = ( netdev->max_pkt_len - netdev->ll_protocol->ll_header_len -
148 tcpip_net->header_len );
149
150 return mtu;
151 }
152
153 /**
154 * Calculate continued TCP/IP checkum
155 *
156 * @v partial Checksum of already-summed data, in network byte order
157 * @v data Data buffer
158 * @v len Length of data buffer
159 * @ret cksum Updated checksum, in network byte order
160 *
161 * Calculates a TCP/IP-style 16-bit checksum over the data block. The
162 * checksum is returned in network byte order.
163 *
164 * This function may be used to add new data to an existing checksum.
165 * The function assumes that both the old data and the new data start
166 * on even byte offsets; if this is not the case then you will need to
167 * byte-swap either the input partial checksum, the output checksum,
168 * or both. Deciding which to swap is left as an exercise for the
169 * interested reader.
170 */
171 uint16_t generic_tcpip_continue_chksum ( uint16_t partial,
172 const void *data, size_t len ) {
173 unsigned int cksum = ( ( ~partial ) & 0xffff );
174 unsigned int value;
175 unsigned int i;
176
177 for ( i = 0 ; i < len ; i++ ) {
178 value = * ( ( uint8_t * ) data + i );
179 if ( i & 1 ) {
180 /* Odd bytes: swap on little-endian systems */
181 value = be16_to_cpu ( value );
182 } else {
183 /* Even bytes: swap on big-endian systems */
184 value = le16_to_cpu ( value );
185 }
186 cksum += value;
187 if ( cksum > 0xffff )
188 cksum -= 0xffff;
189 }
190
191 return ( ~cksum );
192 }
193
194 /**
195 * Calculate TCP/IP checkum
196 *
197 * @v data Data buffer
198 * @v len Length of data buffer
199 * @ret cksum Checksum, in network byte order
200 *
201 * Calculates a TCP/IP-style 16-bit checksum over the data block. The
202 * checksum is returned in network byte order.
203 */
204 uint16_t tcpip_chksum ( const void *data, size_t len ) {
205 return tcpip_continue_chksum ( TCPIP_EMPTY_CSUM, data, len );
206 }
207
208 /**
209 * Bind to local TCP/IP port
210 *
211 * @v st_local Local TCP/IP socket address, or NULL
212 * @v available Function to check port availability
213 * @ret port Local port number, or negative error
214 */
215 int tcpip_bind ( struct sockaddr_tcpip *st_local,
216 int ( * available ) ( int port ) ) {
217 uint16_t flags = 0;
218 uint16_t try_port = 0;
219 uint16_t min_port;
220 uint16_t max_port;
221 unsigned int offset;
222 unsigned int i;
223
224 /* Extract parameters from local socket address */
225 if ( st_local ) {
226 flags = st_local->st_flags;
227 try_port = ntohs ( st_local->st_port );
228 }
229
230 /* If an explicit port is specified, check its availability */
231 if ( try_port )
232 return available ( try_port );
233
234 /* Otherwise, find an available port in the range [1,1023] or
235 * [1025,65535] as appropriate.
236 */
237 min_port = ( ( ( ~flags ) & TCPIP_BIND_PRIVILEGED ) + 1 );
238 max_port = ( ( flags & TCPIP_BIND_PRIVILEGED ) - 1 );
239 offset = random();
240 for ( i = 0 ; i <= max_port ; i++ ) {
241 try_port = ( ( i + offset ) & max_port );
242 if ( try_port < min_port )
243 continue;
244 if ( available ( try_port ) < 0 )
245 continue;
246 return try_port;
247 }
248 return -EADDRINUSE;
249 }