Added fragment reassembly code
[people/xl0/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/tcpip_if.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 /** List of fragment reassembly buffers */
51 static LIST_HEAD ( frag_buffers );
52
53 /**
54  * Add IPv4 interface
55  *
56  * @v netdev    Network device
57  * @v address   IPv4 address
58  * @v netmask   Subnet mask
59  * @v gateway   Gateway address (or @c INADDR_NONE for no gateway)
60  * @ret rc      Return status code
61  *
62  */
63 int add_ipv4_address ( struct net_device *netdev, struct in_addr address,
64                        struct in_addr netmask, struct in_addr gateway ) {
65         struct ipv4_miniroute *miniroute;
66
67         /* Allocate and populate miniroute structure */
68         miniroute = malloc ( sizeof ( *miniroute ) );
69         if ( ! miniroute )
70                 return -ENOMEM;
71         miniroute->netdev = netdev;
72         miniroute->address = address;
73         miniroute->netmask = netmask;
74         miniroute->gateway = gateway;
75         
76         /* Add to end of list if we have a gateway, otherwise to start
77          * of list.
78          */
79         if ( gateway.s_addr != INADDR_NONE ) {
80                 list_add_tail ( &miniroute->list, &miniroutes );
81         } else {
82                 list_add ( &miniroute->list, &miniroutes );
83         }
84         return 0;
85 }
86
87 /**
88  * Remove IPv4 interface
89  *
90  * @v netdev    Network device
91  */
92 void del_ipv4_address ( struct net_device *netdev ) {
93         struct ipv4_miniroute *miniroute;
94
95         list_for_each_entry ( miniroute, &miniroutes, list ) {
96                 if ( miniroute->netdev == netdev ) {
97                         list_del ( &miniroute->list );
98                         break;
99                 }
100         }
101 }
102
103 /**
104  * Dump IPv4 packet header
105  *
106  * @v iphdr     IPv4 header
107  */
108 static void ipv4_dump ( struct iphdr *iphdr __unused ) {
109
110         DBG ( "IP4 header at %p+%zx\n", iphdr, sizeof ( *iphdr ) );
111         DBG ( "\tVersion = %d\n", ( iphdr->verhdrlen & IP_MASK_VER ) / 16 );
112         DBG ( "\tHeader length = %d\n", iphdr->verhdrlen & IP_MASK_HLEN );
113         DBG ( "\tService = %d\n", iphdr->service );
114         DBG ( "\tTotal length = %d\n", ntohs ( iphdr->len ) );
115         DBG ( "\tIdent = %d\n", ntohs ( iphdr->ident ) );
116         DBG ( "\tFrags/Offset = %d\n", ntohs ( iphdr->frags ) );
117         DBG ( "\tIP TTL = %d\n", iphdr->ttl );
118         DBG ( "\tProtocol = %d\n", iphdr->protocol );
119         DBG ( "\tHeader Checksum (at %p) = %x\n", &iphdr->chksum, 
120                                 ntohs ( iphdr->chksum ) );
121         DBG ( "\tSource = %s\n", inet_ntoa ( iphdr->src ) );
122         DBG ( "\tDestination = %s\n", inet_ntoa ( iphdr->dest ) );
123 }
124
125 /**
126  * Fragment reassembly counter timeout
127  *
128  * @v timer     Retry timer
129  * @v over      If asserted, the timer is greater than @c MAX_TIMEOUT 
130  */
131 void ipv4_frag_expired ( struct retry_timer *timer __unused , int over ) {
132         if ( over ) {
133                 DBG ( "Fragment reassembly timeout" );
134                 /* Free the fragment buffer */
135         }
136 }
137
138 /**
139  * Free fragment buffer
140  *
141  * @v fragbug   Fragment buffer
142  */
143 void free_fragbuf ( struct frag_buffer *fragbuf ) {
144         if ( fragbuf ) {
145                 free_dma ( fragbuf, sizeof ( *fragbuf ) );
146         }
147 }
148
149 /**
150  * Fragment reassembler
151  *
152  * @v pkb               Packet buffer, fragment of the datagram
153  * @ret frag_pkb        Reassembled packet, or NULL
154  */
155 struct pk_buff * ipv4_reassemble ( struct pk_buff * pkb ) {
156         struct iphdr *iphdr = pkb->data;
157         struct frag_buffer *fragbuf;
158         
159         /**
160          * Check if the fragment belongs to any fragment series
161          */
162         list_for_each_entry ( fragbuf, &frag_buffers, list ) {
163                 if ( fragbuf->ident == iphdr->ident &&
164                      fragbuf->src.s_addr == iphdr->src.s_addr ) {
165                         /**
166                          * Check if the packet is the expected fragment
167                          * 
168                          * The offset of the new packet must be equal to the
169                          * length of the data accumulated so far (the length of
170                          * the reassembled packet buffer
171                          */
172                         if ( pkb_len ( fragbuf->frag_pkb ) == 
173                               ( iphdr->frags & IP_MASK_OFFSET ) ) {
174                                 /**
175                                  * Append the contents of the fragment to the
176                                  * reassembled packet buffer
177                                  */
178                                 pkb_pull ( pkb, sizeof ( *iphdr ) );
179                                 memcpy ( pkb_put ( fragbuf->frag_pkb,
180                                                         pkb_len ( pkb ) ),
181                                          pkb->data, pkb_len ( pkb ) );
182                                 free_pkb ( pkb );
183
184                                 /** Check if the fragment series is over */
185                                 if ( !iphdr->frags & IP_MASK_MOREFRAGS ) {
186                                         pkb = fragbuf->frag_pkb;
187                                         free_fragbuf ( fragbuf );
188                                         return pkb;
189                                 }
190
191                         } else {
192                                 /* Discard the fragment series */
193                                 free_fragbuf ( fragbuf );
194                                 free_pkb ( pkb );
195                         }
196                         return NULL;
197                 }
198         }
199         
200         /** Check if the fragment is the first in the fragment series */
201         if ( iphdr->frags & IP_MASK_MOREFRAGS &&
202                         ( ( iphdr->frags & IP_MASK_OFFSET ) == 0 ) ) {
203         
204                 /** Create a new fragment buffer */
205                 fragbuf = ( struct frag_buffer* ) malloc ( sizeof( *fragbuf ) );
206                 fragbuf->ident = iphdr->ident;
207                 fragbuf->src = iphdr->src;
208
209                 /* Set up the reassembly packet buffer */
210                 fragbuf->frag_pkb = alloc_pkb ( IP_FRAG_PKB_SIZE );
211                 pkb_pull ( pkb, sizeof ( *iphdr ) );
212                 memcpy ( pkb_put ( fragbuf->frag_pkb, pkb_len ( pkb ) ),
213                          pkb->data, pkb_len ( pkb ) );
214                 free_pkb ( pkb );
215
216                 /* Set the reassembly timer */
217                 fragbuf->frag_timer.timeout = IP_FRAG_TIMEOUT;
218                 fragbuf->frag_timer.expired = ipv4_frag_expired;
219                 start_timer ( &fragbuf->frag_timer );
220
221                 /* Add the fragment buffer to the list of fragment buffers */
222                 list_add ( &fragbuf->list, &frag_buffers );
223         }
224         
225         return NULL;
226 }
227
228
229 /**
230  * Complete the transport-layer checksum
231  *
232  * @v pkb       Packet buffer
233  * @v tcpip     Transport-layer protocol
234  *
235  * This function calculates the tcpip 
236  */
237 void ipv4_tx_csum ( struct pk_buff *pkb, struct tcpip_protocol *tcpip ) {
238
239         struct iphdr *iphdr = pkb->data;
240         struct ipv4_pseudo_header pshdr;
241         void *csum_offset = iphdr + sizeof ( *iphdr ) + tcpip->csum_offset;
242         uint16_t partial_csum = *( ( uint16_t* ) csum_offset );
243         uint16_t csum;
244
245         /* Calculate pseudo header */
246         pshdr.src = iphdr->src;
247         pshdr.dest = iphdr->dest;
248         pshdr.zero_padding = 0x00;
249         pshdr.protocol = iphdr->protocol;
250         pshdr.len = htons ( pkb_len ( pkb ) - sizeof ( *iphdr ) );
251
252         /* Update the checksum value */
253         csum = partial_csum + calc_chksum ( &pshdr, sizeof ( pshdr ) );
254         memcpy ( csum_offset, &csum, 2 );
255 }
256
257 /**
258  * Calculate the transport-layer checksum while processing packets
259  */
260 uint16_t ipv4_rx_csum ( struct pk_buff *pkb __unused,
261                         uint8_t trans_proto __unused ) {
262         /** 
263          * This function needs to be implemented. Until then, it will return
264          * 0xffffffff every time
265          */
266         return 0xffff;
267 }
268
269 /**
270  * Transmit packet constructed by uIP
271  *
272  * @v pkb               Packet buffer
273  * @ret rc              Return status code
274  *
275  */
276 int ipv4_uip_tx ( struct pk_buff *pkb ) {
277         struct iphdr *iphdr = pkb->data;
278         struct ipv4_miniroute *miniroute;
279         struct net_device *netdev = NULL;
280         struct in_addr next_hop;
281         struct in_addr source;
282         uint8_t ll_dest_buf[MAX_LL_ADDR_LEN];
283         const uint8_t *ll_dest = ll_dest_buf;
284         int rc;
285
286         /* Use routing table to identify next hop and transmitting netdev */
287         next_hop = iphdr->dest;
288         list_for_each_entry ( miniroute, &miniroutes, list ) {
289                 if ( ( ( ( iphdr->dest.s_addr ^ miniroute->address.s_addr ) &
290                          miniroute->netmask.s_addr ) == 0 ) ||
291                      ( miniroute->gateway.s_addr != INADDR_NONE ) ) {
292                         netdev = miniroute->netdev;
293                         source = miniroute->address;
294                         if ( miniroute->gateway.s_addr != INADDR_NONE )
295                                 next_hop = miniroute->gateway;
296                         break;
297                 }
298         }
299
300         /* Abort if no network device identified */
301         if ( ! netdev ) {
302                 DBG ( "No route to %s\n", inet_ntoa ( iphdr->dest ) );
303                 rc = -EHOSTUNREACH;
304                 goto err;
305         }
306
307         /* Determine link-layer destination address */
308         if ( next_hop.s_addr == INADDR_BROADCAST ) {
309                 /* Broadcast address */
310                 ll_dest = netdev->ll_protocol->ll_broadcast;
311         } else if ( IN_MULTICAST ( next_hop.s_addr ) ) {
312                 /* Special case: IPv4 multicast over Ethernet.  This
313                  * code may need to be generalised once we find out
314                  * what happens for other link layers.
315                  */
316                 uint8_t *next_hop_bytes = ( uint8_t * ) &next_hop;
317                 ll_dest_buf[0] = 0x01;
318                 ll_dest_buf[0] = 0x00;
319                 ll_dest_buf[0] = 0x5e;
320                 ll_dest_buf[3] = next_hop_bytes[1] & 0x7f;
321                 ll_dest_buf[4] = next_hop_bytes[2];
322                 ll_dest_buf[5] = next_hop_bytes[3];
323         } else {
324                 /* Unicast address: resolve via ARP */
325                 if ( ( rc = arp_resolve ( netdev, &ipv4_protocol, &next_hop,
326                                           &source, ll_dest_buf ) ) != 0 ) {
327                         DBG ( "No ARP entry for %s\n",
328                               inet_ntoa ( iphdr->dest ) );
329                         goto err;
330                 }
331         }
332         
333         /* Hand off to link layer */
334         return net_tx ( pkb, netdev, &ipv4_protocol, ll_dest );
335
336  err:
337         free_pkb ( pkb );
338         return rc;
339 }
340
341 /**
342  * Transmit IP packet (without uIP)
343  *
344  * @v pkb               Packet buffer
345  * @v tcpip             Transport-layer protocol
346  * @v dest              Destination network-layer address
347  * @ret rc              Status
348  *
349  * This function expects a transport-layer segment and prepends the IP header
350  */
351 int ipv4_tx ( struct pk_buff *pkb, struct tcpip_protocol *tcpip,
352               struct in_addr *dest ) {
353         struct iphdr *iphdr = pkb_push ( pkb, sizeof ( *iphdr ) );
354         struct ipv4_miniroute *miniroute;
355         struct net_device *netdev = NULL;
356         struct in_addr next_hop;
357         uint8_t ll_dest_buf[MAX_LL_ADDR_LEN];
358         const uint8_t *ll_dest = ll_dest_buf;
359         int rc;
360
361         /* Fill up the IP header, except source address */
362         iphdr->verhdrlen = ( IP_VER << 4 ) | ( sizeof ( *iphdr ) / 4 );
363         iphdr->service = IP_TOS;
364         iphdr->len = htons ( pkb_len ( pkb ) ); 
365         iphdr->ident = htons ( next_ident++ );
366         iphdr->frags = 0;
367         iphdr->ttl = IP_TTL;
368         iphdr->protocol = tcpip->trans_proto;
369
370         /* Copy destination address */
371         iphdr->dest = *dest;
372
373         /**
374          * All fields in the IP header filled in except the source network
375          * address (which requires routing) and the header checksum (which
376          * requires the source network address). As the pseudo header requires
377          * the source address as well and the transport-layer checksum is
378          * updated after routing.
379          *
380          * Continue processing as in ipv4_uip_tx()
381          */
382
383         /* Use routing table to identify next hop and transmitting netdev */
384         next_hop = iphdr->dest;
385         list_for_each_entry ( miniroute, &miniroutes, list ) {
386                 if ( ( ( ( iphdr->dest.s_addr ^ miniroute->address.s_addr ) &
387                          miniroute->netmask.s_addr ) == 0 ) ||
388                      ( miniroute->gateway.s_addr != INADDR_NONE ) ) {
389                         netdev = miniroute->netdev;
390                         iphdr->src = miniroute->address;
391                         if ( miniroute->gateway.s_addr != INADDR_NONE )
392                                 next_hop = miniroute->gateway;
393                         break;
394                 }
395         }
396         /* Abort if no network device identified */
397         if ( ! netdev ) {
398                 DBG ( "No route to %s\n", inet_ntoa ( iphdr->dest ) );
399                 rc = -EHOSTUNREACH;
400                 goto err;
401         }
402
403         /* Calculate the transport layer checksum */
404         if ( tcpip->csum_offset > 0 ) {
405                 ipv4_tx_csum ( pkb, tcpip );
406         }
407
408         /* Calculate header checksum, in network byte order */
409         iphdr->chksum = 0;
410         iphdr->chksum = htons ( calc_chksum ( iphdr, sizeof ( *iphdr ) ) );
411
412         /* Print IP4 header for debugging */
413         ipv4_dump ( iphdr );
414
415         /* Determine link-layer destination address */
416         if ( next_hop.s_addr == INADDR_BROADCAST ) {
417                 /* Broadcast address */
418                 ll_dest = netdev->ll_protocol->ll_broadcast;
419         } else if ( IN_MULTICAST ( next_hop.s_addr ) ) {
420                 /* Special case: IPv4 multicast over Ethernet.  This
421                  * code may need to be generalised once we find out
422                  * what happens for other link layers.
423                  */
424                 uint8_t *next_hop_bytes = ( uint8_t * ) &next_hop;
425                 ll_dest_buf[0] = 0x01;
426                 ll_dest_buf[0] = 0x00;
427                 ll_dest_buf[0] = 0x5e;
428                 ll_dest_buf[3] = next_hop_bytes[1] & 0x7f;
429                 ll_dest_buf[4] = next_hop_bytes[2];
430                 ll_dest_buf[5] = next_hop_bytes[3];
431         } else {
432                 /* Unicast address: resolve via ARP */
433                 if ( ( rc = arp_resolve ( netdev, &ipv4_protocol, &next_hop,
434                                           &iphdr->src, ll_dest_buf ) ) != 0 ) {
435                         DBG ( "No ARP entry for %s\n",
436                               inet_ntoa ( iphdr->dest ) );
437                         goto err;
438                 }
439         }
440
441         /* Hand off to link layer */
442         return net_tx ( pkb, netdev, &ipv4_protocol, ll_dest );
443
444  err:
445         free_pkb ( pkb );
446         return rc;
447 }
448
449 /**
450  * Process incoming IP packets
451  *
452  * @v pkb               Packet buffer
453  * @v netdev            Network device
454  * @v ll_source         Link-layer source address
455  * @ret rc              Return status code
456  *
457  * This handles IP packets by handing them off to the uIP protocol
458  * stack.
459  */
460 static int ipv4_uip_rx ( struct pk_buff *pkb,
461                          struct net_device *netdev __unused,
462                          const void *ll_source __unused ) {
463
464         /* Transfer to uIP buffer.  Horrendously space-inefficient,
465          * but will do as a proof-of-concept for now.
466          */
467         uip_len = pkb_len ( pkb );
468         memcpy ( uip_buf, pkb->data, uip_len );
469         free_pkb ( pkb );
470
471         /* Hand to uIP for processing */
472         uip_input ();
473         if ( uip_len > 0 ) {
474                 pkb = alloc_pkb ( MAX_LL_HEADER_LEN + uip_len );
475                 if ( ! pkb )
476                         return -ENOMEM;
477                 pkb_reserve ( pkb, MAX_LL_HEADER_LEN );
478                 memcpy ( pkb_put ( pkb, uip_len ), uip_buf, uip_len );
479                 ipv4_uip_tx ( pkb );
480         }
481         return 0;
482 }
483
484 /**
485  * Process incoming packets (without uIP)
486  *
487  * @v pkb       Packet buffer
488  * @v netdev    Network device
489  * @v ll_source Link-layer destination source
490  *
491  * This function expects an IP4 network datagram. It processes the headers 
492  * and sends it to the transport layer.
493  */
494 void ipv4_rx ( struct pk_buff *pkb, struct net_device *netdev __unused,
495                         const void *ll_source __unused ) {
496         struct iphdr *iphdr = pkb->data;
497         struct in_addr *src = &iphdr->src;
498         struct in_addr *dest = &iphdr->dest;
499         uint16_t chksum;
500
501         /* Sanity check */
502         if ( pkb_len ( pkb ) < sizeof ( *iphdr ) ) {
503                 DBG ( "IP datagram too short (%d bytes)\n",
504                         pkb_len ( pkb ) );
505                 return;
506         }
507
508         /* Print IP4 header for debugging */
509         ipv4_dump ( iphdr );
510
511         /* Validate version and header length */
512         if ( iphdr->verhdrlen != 0x45 ) {
513                 DBG ( "Bad version and header length %x\n", iphdr->verhdrlen );
514                 return;
515         }
516
517         /* Validate length of IP packet */
518         if ( ntohs ( iphdr->len ) != pkb_len ( pkb ) ) {
519                 DBG ( "Inconsistent packet length %d\n",
520                                         ntohs ( iphdr->len ) );
521                 return;
522         }
523
524         /* Verify the checksum */
525         if ( ( chksum = ipv4_rx_csum ( pkb, iphdr->protocol ) ) != 0xffff ) {
526                 DBG ( "Bad checksum %x\n", chksum );
527         }
528         /* Fragment reassembly */
529         if ( iphdr->frags & IP_MASK_MOREFRAGS || 
530                 ( !iphdr->frags & IP_MASK_MOREFRAGS &&
531                         iphdr->frags & IP_MASK_OFFSET != 0 ) ) {
532                 /* Pass the fragment to the reassembler ipv4_ressable() which
533                  * either returns a fully reassembled packet buffer or NULL.
534                  */
535                 pkb = ipv4_reassemble ( pkb );
536                 if ( !pkb ) {
537                         return;
538                 }
539         }
540
541         /* To reduce code size, the following functions are not implemented:
542          * 1. Check the destination address
543          * 2. Check the TTL field
544          * 3. Check the service field
545          */
546
547         /* Strip header */
548         pkb_pull ( pkb, sizeof ( *iphdr ) );
549
550         /* Send it to the transport layer */
551         trans_rx ( pkb, iphdr->protocol, src, dest );
552 }
553
554 /** 
555  * Check existence of IPv4 address for ARP
556  *
557  * @v netdev            Network device
558  * @v net_addr          Network-layer address
559  * @ret rc              Return status code
560  */
561 static int ipv4_arp_check ( struct net_device *netdev, const void *net_addr ) {
562         const struct in_addr *address = net_addr;
563         struct ipv4_miniroute *miniroute;
564
565         list_for_each_entry ( miniroute, &miniroutes, list ) {
566                 if ( ( miniroute->netdev == netdev ) &&
567                      ( miniroute->address.s_addr == address->s_addr ) ) {
568                         /* Found matching address */
569                         return 0;
570                 }
571         }
572         return -ENOENT;
573 }
574
575 /**
576  * Convert IPv4 address to dotted-quad notation
577  *
578  * @v in        IP address
579  * @ret string  IP address in dotted-quad notation
580  */
581 char * inet_ntoa ( struct in_addr in ) {
582         static char buf[16]; /* "xxx.xxx.xxx.xxx" */
583         uint8_t *bytes = ( uint8_t * ) &in;
584         
585         sprintf ( buf, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3] );
586         return buf;
587 }
588
589 /**
590  * Transcribe IP address
591  *
592  * @v net_addr  IP address
593  * @ret string  IP address in dotted-quad notation
594  *
595  */
596 static const char * ipv4_ntoa ( const void *net_addr ) {
597         return inet_ntoa ( * ( ( struct in_addr * ) net_addr ) );
598 }
599
600 /** IPv4 protocol */
601 struct net_protocol ipv4_protocol = {
602         .name = "IP",
603         .net_proto = htons ( ETH_P_IP ),
604         .net_addr_len = sizeof ( struct in_addr ),
605 #if USE_UIP
606         .rx = ipv4_uip_rx,
607 #else
608         .rx = ipv4_rx,
609 #endif
610         .ntoa = ipv4_ntoa,
611 };
612
613 NET_PROTOCOL ( ipv4_protocol );
614
615 /** IPv4 TCPIP net protocol */
616 struct tcpip_net_protocol ipv4_tcpip_protocol = {
617         .net_protocol = &ipv4_protocol,
618         .tx_csum = ipv4_tx_csum,
619 };
620
621 TCPIP_NET_PROTOCOL ( ipv4_tcpip_protocol );
622
623 /** IPv4 ARP protocol */
624 struct arp_net_protocol ipv4_arp_protocol = {
625         .net_protocol = &ipv4_protocol,
626         .check = ipv4_arp_check,
627 };
628
629 ARP_NET_PROTOCOL ( ipv4_arp_protocol );