32510b582127472fadc3af529d8e2170104f9d74
[gpxe.git] / src / net / ipv4.c
1 #include <string.h>
2 #include <stdint.h>
3 #include <errno.h>
4 #include <byteswap.h>
5 #include <malloc.h>
6 #include <vsprintf.h>
7 #include <gpxe/list.h>
8 #include <gpxe/in.h>
9 #include <gpxe/arp.h>
10 #include <gpxe/if_ether.h>
11 #include <gpxe/pkbuff.h>
12 #include <gpxe/netdevice.h>
13 #include "uip/uip.h"
14 #include <gpxe/ip.h>
15 #include <gpxe/interface.h>
16
17 /** @file
18  *
19  * IPv4 protocol
20  *
21  * The gPXE IP stack is currently implemented on top of the uIP
22  * protocol stack.  This file provides wrappers around uIP so that
23  * higher-level protocol implementations do not need to talk directly
24  * to uIP (which has a somewhat baroque API).
25  *
26  */
27
28 /* Unique IP datagram identification number */
29 static uint16_t next_ident = 0;
30
31 struct net_protocol ipv4_protocol;
32
33 /** An IPv4 address/routing table entry */
34 struct ipv4_miniroute {
35         /** List of miniroutes */
36         struct list_head list;
37         /** Network device */
38         struct net_device *netdev;
39         /** IPv4 address */
40         struct in_addr address;
41         /** Subnet mask */
42         struct in_addr netmask;
43         /** Gateway address */
44         struct in_addr gateway;
45 };
46
47 /** List of IPv4 miniroutes */
48 static LIST_HEAD ( miniroutes );
49
50 /**
51  * Add IPv4 interface
52  *
53  * @v netdev    Network device
54  * @v address   IPv4 address
55  * @v netmask   Subnet mask
56  * @v gateway   Gateway address (or @c INADDR_NONE for no gateway)
57  * @ret rc      Return status code
58  *
59  */
60 int add_ipv4_address ( struct net_device *netdev, struct in_addr address,
61                        struct in_addr netmask, struct in_addr gateway ) {
62         struct ipv4_miniroute *miniroute;
63
64         /* Allocate and populate miniroute structure */
65         miniroute = malloc ( sizeof ( *miniroute ) );
66         if ( ! miniroute )
67                 return -ENOMEM;
68         miniroute->netdev = netdev;
69         miniroute->address = address;
70         miniroute->netmask = netmask;
71         miniroute->gateway = gateway;
72         
73         /* Add to end of list if we have a gateway, otherwise to start
74          * of list.
75          */
76         if ( gateway.s_addr != INADDR_NONE ) {
77                 list_add_tail ( &miniroute->list, &miniroutes );
78         } else {
79                 list_add ( &miniroute->list, &miniroutes );
80         }
81         return 0;
82 }
83
84 /**
85  * Remove IPv4 interface
86  *
87  * @v netdev    Network device
88  */
89 void del_ipv4_address ( struct net_device *netdev ) {
90         struct ipv4_miniroute *miniroute;
91
92         list_for_each_entry ( miniroute, &miniroutes, list ) {
93                 if ( miniroute->netdev == netdev ) {
94                         list_del ( &miniroute->list );
95                         break;
96                 }
97         }
98 }
99
100 /**
101  * Complete the transport-layer checksum
102  *
103  * Refer to the note made in net/interface.c about this function
104  */
105 void ipv4_tx_csum ( struct pk_buff *pkb, uint8_t trans_proto ) {
106
107         struct iphdr *iphdr = pkb->data;
108         void *pshdr = malloc ( IP_PSHLEN );
109         void *csum_offset = iphdr + IP_HLEN + ( trans_proto == IP_UDP ? 6 : 16 );
110         int offset = 0;
111
112         /* Calculate pseudo header */
113         memcpy ( pshdr, &iphdr->src, sizeof ( in_addr ) );
114         offset += sizeof ( in_addr );
115         memcpy ( pshdr + offset, &iphdr->dest, sizeof ( in_addr ) );
116         offset += sizeof ( in_addr );
117         *( ( uint8_t* ) ( pshdr + offset++ ) ) = 0x00;
118         *( ( uint8_t* ) ( pshdr + offset++ ) ) = iphdr->protocol;
119         *( ( uint16_t* ) ( pshdr + offset ) ) = pkb_len ( pkb ) - IP_HLEN;
120
121         /* Update the checksum value */
122         *( ( uint16_t* ) csum_offset ) = *( ( uint16_t* ) csum_offset ) + calc_chksum ( pshdr, IP_PSHLEN );
123 }
124
125 /**
126  * Calculate the transport-layer checksum while processing packets
127  */
128 uint16_t ipv4_rx_csum ( struct pk_buff *pkb __unused, uint8_t trans_proto __unused ) {
129         /** This function needs to be implemented. Until then, it will return 0xffffffff every time */
130         return 0xffff;
131 }
132
133 /**
134  * Transmit packet constructed by uIP
135  *
136  * @v pkb               Packet buffer
137  * @ret rc              Return status code
138  *
139  */
140 int ipv4_uip_tx ( struct pk_buff *pkb ) {
141         struct iphdr *iphdr = pkb->data;
142         struct ipv4_miniroute *miniroute;
143         struct net_device *netdev = NULL;
144         struct in_addr next_hop;
145         struct in_addr source;
146         uint8_t ll_dest_buf[MAX_LL_ADDR_LEN];
147         const uint8_t *ll_dest = ll_dest_buf;
148         int rc;
149
150         /* Use routing table to identify next hop and transmitting netdev */
151         next_hop = iphdr->dest;
152         list_for_each_entry ( miniroute, &miniroutes, list ) {
153                 if ( ( ( ( iphdr->dest.s_addr ^ miniroute->address.s_addr ) &
154                          miniroute->netmask.s_addr ) == 0 ) ||
155                      ( miniroute->gateway.s_addr != INADDR_NONE ) ) {
156                         netdev = miniroute->netdev;
157                         source = miniroute->address;
158                         if ( miniroute->gateway.s_addr != INADDR_NONE )
159                                 next_hop = miniroute->gateway;
160                         break;
161                 }
162         }
163
164         /* Abort if no network device identified */
165         if ( ! netdev ) {
166                 DBG ( "No route to %s\n", inet_ntoa ( iphdr->dest ) );
167                 rc = -EHOSTUNREACH;
168                 goto err;
169         }
170
171         /* Determine link-layer destination address */
172         if ( next_hop.s_addr == INADDR_BROADCAST ) {
173                 /* Broadcast address */
174                 ll_dest = netdev->ll_protocol->ll_broadcast;
175         } else if ( IN_MULTICAST ( next_hop.s_addr ) ) {
176                 /* Special case: IPv4 multicast over Ethernet.  This
177                  * code may need to be generalised once we find out
178                  * what happens for other link layers.
179                  */
180                 uint8_t *next_hop_bytes = ( uint8_t * ) &next_hop;
181                 ll_dest_buf[0] = 0x01;
182                 ll_dest_buf[0] = 0x00;
183                 ll_dest_buf[0] = 0x5e;
184                 ll_dest_buf[3] = next_hop_bytes[1] & 0x7f;
185                 ll_dest_buf[4] = next_hop_bytes[2];
186                 ll_dest_buf[5] = next_hop_bytes[3];
187         } else {
188                 /* Unicast address: resolve via ARP */
189                 if ( ( rc = arp_resolve ( netdev, &ipv4_protocol, &next_hop,
190                                           &source, ll_dest_buf ) ) != 0 ) {
191                         DBG ( "No ARP entry for %s\n",
192                               inet_ntoa ( iphdr->dest ) );
193                         goto err;
194                 }
195         }
196         
197         /* Hand off to link layer */
198         return net_tx ( pkb, netdev, &ipv4_protocol, ll_dest );
199
200  err:
201         free_pkb ( pkb );
202         return rc;
203 }
204
205 /**
206  * Transmit IP packet (without uIP)
207  *
208  * @v pkb               Packet buffer
209  * @v trans_proto       Transport-layer protocol number
210  * @v dest              Destination network-layer address
211  * @ret rc              Status
212  *
213  * This function expects a transport-layer segment and prepends the IP header
214  */
215 int ipv4_tx ( struct pk_buff *pkb, uint16_t trans_proto, struct in_addr *dest ) {
216         struct iphdr *iphdr = pkb_push ( pkb, IP_HLEN );
217         struct ipv4_miniroute *miniroute;
218         struct net_device *netdev = NULL;
219         struct in_addr next_hop;
220         struct in_addr source;
221         uint8_t ll_dest_buf[MAX_LL_ADDR_LEN];
222         const uint8_t *ll_dest = ll_dest_buf;
223         int rc;
224
225         /* Fill up the IP header, except source address */
226         iphdr->verhdrlen = ( IP_VER << 4 ) | ( IP_HLEN / 4 );   /* Version = 4, Header length = 5 */
227         iphdr->service = IP_TOS;                                /* Service = 0, is not implemented */
228         iphdr->len = htons ( pkb_len ( pkb ) );                 /* Total packet length, in network byte order */
229         iphdr->ident = next_ident++;                            /* Identification number */
230         iphdr->frags = 0;                                       /* Fragmentation is not implemented at the host */
231         iphdr->ttl = IP_TTL;                                    /* Time to live */
232         iphdr->protocol = trans_proto;                          /* Transport-layer protocol - IP_XXX */
233
234         /* Calculate header checksum, in network byte order */
235         iphdr->chksum = 0;
236         iphdr->chksum = htons ( calc_chksum ( iphdr, IP_HLEN ) );
237         /* Copy destination address */
238         memcpy ( &iphdr->dest, dest, sizeof ( struct in_addr ) );
239
240         /**
241          * All fields in the IP header filled in except the source network address (which requires routing). As
242          * the pseudo header requires the source address as well and updating the transport-layer checksum is
243          * done after routing.
244          *
245          * Continue processing as in ipv4_uip_tx()
246          */
247
248         /* Use routing table to identify next hop and transmitting netdev */
249         next_hop = iphdr->dest;
250         list_for_each_entry ( miniroute, &miniroutes, list ) {
251                 if ( ( ( ( iphdr->dest.s_addr ^ miniroute->address.s_addr ) &
252                          miniroute->netmask.s_addr ) == 0 ) ||
253                      ( miniroute->gateway.s_addr != INADDR_NONE ) ) {
254                         netdev = miniroute->netdev;
255                         source = miniroute->address;
256                         if ( miniroute->gateway.s_addr != INADDR_NONE )
257                                 next_hop = miniroute->gateway;
258                         break;
259                 }
260         }
261         /* Abort if no network device identified */
262         if ( ! netdev ) {
263                 DBG ( "No route to %s\n", inet_ntoa ( iphdr->dest ) );
264                 rc = -EHOSTUNREACH;
265                 goto err;
266         }
267
268         /* Copy the source address, after this the IP header is complete */
269         memcpy ( &iphdr->src, &source, sizeof ( struct in_addr ) );
270         /* Calculate the transport layer checksum */
271         ipv4_tx_csum ( pkb, trans_proto );
272
273         /* Print IP4 header for debugging */
274         DBG ( "IP4 header at %#x + %d\n", iphdr, IP_HLEN  );
275         DBG ( "\tVersion = %d\n", ( iphdr->verhdrlen & IP_MASK_VER ) / 16 );
276         DBG ( "\tHeader length = %d\n", iphdr->verhdrlen & IP_MASK_HLEN );
277         DBG ( "\tService = %d\n", iphdr->service );
278         DBG ( "\tTotal length = %d\n", iphdr->len );
279         DBG ( "\tIdent = %d\n", iphdr->ident );
280         DBG ( "\tFrags/Offset = %d\n", iphdr->frags );
281         DBG ( "\tIP TTL = %d\n", iphdr->ttl );
282         DBG ( "\tProtocol = %d\n", iphdr->protocol );
283         DBG ( "\tHeader Checksum (at %#x) = %x\n", &iphdr->chksum, iphdr->chksum );
284         DBG ( "\tSource = %s\n", inet_ntoa ( iphdr->src) );
285         DBG ( "\tDestination = %s\n", inet_ntoa ( iphdr->dest ) );
286
287
288         /* Determine link-layer destination address */
289         if ( next_hop.s_addr == INADDR_BROADCAST ) {
290                 /* Broadcast address */
291                 ll_dest = netdev->ll_protocol->ll_broadcast;
292         } else if ( IN_MULTICAST ( next_hop.s_addr ) ) {
293                 /* Special case: IPv4 multicast over Ethernet.  This
294                  * code may need to be generalised once we find out
295                  * what happens for other link layers.
296                  */
297                 uint8_t *next_hop_bytes = ( uint8_t * ) &next_hop;
298                 ll_dest_buf[0] = 0x01;
299                 ll_dest_buf[0] = 0x00;
300                 ll_dest_buf[0] = 0x5e;
301                 ll_dest_buf[3] = next_hop_bytes[1] & 0x7f;
302                 ll_dest_buf[4] = next_hop_bytes[2];
303                 ll_dest_buf[5] = next_hop_bytes[3];
304         } else {
305                 /* Unicast address: resolve via ARP */
306                 if ( ( rc = arp_resolve ( netdev, &ipv4_protocol, &next_hop, &source, ll_dest_buf ) ) != 0 ) {
307                         DBG ( "No ARP entry for %s\n", inet_ntoa ( iphdr->dest ) );
308                         goto err;
309                 }
310         }
311
312         /* Hand off to link layer */
313         return net_tx ( pkb, netdev, &ipv4_protocol, ll_dest );
314
315  err:
316         /* Warning: Allowing this function to execute causes bochs to go into an infinite loop */
317         free_pkb ( pkb );
318         return rc;
319 }
320
321 /**
322  * Transmit IP6 packets
323  * 
324  * Placeholder to allow linking. The function should be placed in net/ipv6.c
325  */
326 int ipv6_tx ( struct pk_buff *pkb __unused, uint16_t trans_proto __unused, struct in6_addr *dest __unused) {
327         return -ENOSYS;
328 }
329
330
331 /**
332  * Process incoming IP packets
333  *
334  * @v pkb               Packet buffer
335  * @v netdev            Network device
336  * @v ll_source         Link-layer source address
337  * @ret rc              Return status code
338  *
339  * This handles IP packets by handing them off to the uIP protocol
340  * stack.
341  */
342 static int ipv4_uip_rx ( struct pk_buff *pkb,
343                          struct net_device *netdev __unused,
344                          const void *ll_source __unused ) {
345
346         /* Transfer to uIP buffer.  Horrendously space-inefficient,
347          * but will do as a proof-of-concept for now.
348          */
349         uip_len = pkb_len ( pkb );
350         memcpy ( uip_buf, pkb->data, uip_len );
351         free_pkb ( pkb );
352
353         /* Hand to uIP for processing */
354         uip_input ();
355         if ( uip_len > 0 ) {
356                 pkb = alloc_pkb ( MAX_LL_HEADER_LEN + uip_len );
357                 if ( ! pkb )
358                         return -ENOMEM;
359                 pkb_reserve ( pkb, MAX_LL_HEADER_LEN );
360                 memcpy ( pkb_put ( pkb, uip_len ), uip_buf, uip_len );
361                 ipv4_uip_tx ( pkb );
362         }
363         return 0;
364 }
365
366 /**
367  * Process incoming IP6 packets
368  * 
369  * Placeholder function. Should rewrite in net/ipv6.c
370  */
371 void ipv6_rx ( struct pk_buff *pkb __unused, struct net_device *netdev __unused, const void *ll_source __unused ) {
372 }
373
374 /**
375  * Process incoming packets (without uIP)
376  *
377  * @v pkb       Packet buffer
378  * @v netdev    Network device
379  * @v ll_source Link-layer destination source
380  *
381  * This function expects an IP4 network datagram. It will process the headers and send it to the transport layer
382  */
383 void ipv4_rx ( struct pk_buff *pkb, struct net_device *netdev __unused,
384                         const void *ll_source __unused ) {
385         struct iphdr *iphdr = pkb->data;
386         struct in_addr *src = &iphdr->src;
387         struct in_addr *dest = &iphdr->dest;
388         uint16_t chksum;
389
390         /* Print IP4 header for debugging */
391         DBG ( "IP4 header at %#x + %d\n", iphdr, IP_HLEN  );
392         DBG ( "\tVersion = %d\n", ( iphdr->verhdrlen & IP_MASK_VER ) / 16 );
393         DBG ( "\tHeader length = %d\n", iphdr->verhdrlen & IP_MASK_HLEN );
394         DBG ( "\tService = %d\n", iphdr->service );
395         DBG ( "\tTotal length = %d\n", iphdr->len );
396         DBG ( "\tIdent = %d\n", iphdr->ident );
397         DBG ( "\tFrags/Offset = %d\n", iphdr->frags );
398         DBG ( "\tIP TTL = %d\n", iphdr->ttl );
399         DBG ( "\tProtocol = %d\n", iphdr->protocol );
400         DBG ( "\tHeader Checksum (at %#x) = %x\n", &iphdr->chksum, iphdr->chksum );
401         DBG ( "\tSource = %s\n", inet_ntoa ( iphdr->src) );
402         DBG ( "\tDestination = %s\n", inet_ntoa ( iphdr->dest ) );
403
404         /* Process headers */
405         if ( iphdr->verhdrlen != 0x45 ) {
406                 DBG ( "Bad version and header length %x\n", iphdr->verhdrlen );
407                 return;
408         }
409
410         if ( iphdr->len != pkb_len ( pkb ) ) {
411                 DBG ( "Bad total length %d\n", iphdr->len );
412                 return;
413         }
414
415         if ( ( chksum = ipv4_rx_csum ( pkb, iphdr->protocol ) ) != 0xffff ) {
416                 DBG ( "Bad checksum %x\n", chksum );
417         }
418
419         /* Todo: Compute and verify the header checksum */
420
421         /* To reduce code size, the following functions are not implemented:
422          * 1. Check the destination address
423          * 2. Check the TTL field
424          * 3. Check the service field
425          */
426
427         /* Strip header */
428         pkb_pull ( pkb, IP_HLEN );
429
430         /* Send it to the transport layer */
431         trans_rx ( pkb, iphdr->protocol, src, dest );
432 }
433
434 /** 
435  * Check existence of IPv4 address for ARP
436  *
437  * @v netdev            Network device
438  * @v net_addr          Network-layer address
439  * @ret rc              Return status code
440  */
441 static int ipv4_arp_check ( struct net_device *netdev, const void *net_addr ) {
442         const struct in_addr *address = net_addr;
443         struct ipv4_miniroute *miniroute;
444
445         list_for_each_entry ( miniroute, &miniroutes, list ) {
446                 if ( ( miniroute->netdev == netdev ) &&
447                      ( miniroute->address.s_addr == address->s_addr ) ) {
448                         /* Found matching address */
449                         return 0;
450                 }
451         }
452         return -ENOENT;
453 }
454
455 /**
456  * Convert IPv4 address to dotted-quad notation
457  *
458  * @v in        IP address
459  * @ret string  IP address in dotted-quad notation
460  */
461 char * inet_ntoa ( struct in_addr in ) {
462         static char buf[16]; /* "xxx.xxx.xxx.xxx" */
463         uint8_t *bytes = ( uint8_t * ) &in;
464         
465         sprintf ( buf, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3] );
466         return buf;
467 }
468
469 /**
470  * Transcribe IP address
471  *
472  * @v net_addr  IP address
473  * @ret string  IP address in dotted-quad notation
474  *
475  */
476 static const char * ipv4_ntoa ( const void *net_addr ) {
477         return inet_ntoa ( * ( ( struct in_addr * ) net_addr ) );
478 }
479
480 /** IPv4 protocol */
481 struct net_protocol ipv4_protocol = {
482         .name = "IP",
483         .net_proto = htons ( ETH_P_IP ),
484         .net_addr_len = sizeof ( struct in_addr ),
485 #if USE_UIP
486         .rx = ipv4_uip_rx,
487 #else
488         .rx = ipv4_rx,
489 #endif
490         .ntoa = ipv4_ntoa,
491 };
492
493 NET_PROTOCOL ( ipv4_protocol );
494
495 /** IPv4 ARP protocol */
496 struct arp_net_protocol ipv4_arp_protocol = {
497         .net_protocol = &ipv4_protocol,
498         .check = ipv4_arp_check,
499 };
500
501 ARP_NET_PROTOCOL ( ipv4_arp_protocol );