8bbcff155eff9862c4902a66d10913b5b3df7bd3
[people/meteger/gpxe.git] / src / net / ipv4.c
1 #include <string.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <errno.h>
6 #include <byteswap.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 <gpxe/ip.h>
14 #include <gpxe/tcpip.h>
15
16 /** @file
17  *
18  * IPv4 protocol
19  *
20  */
21
22 /* Unique IP datagram identification number */
23 static uint16_t next_ident = 0;
24
25 struct net_protocol ipv4_protocol;
26
27 /** List of IPv4 miniroutes */
28 struct list_head ipv4_miniroutes = LIST_HEAD_INIT ( ipv4_miniroutes );
29
30 /** List of fragment reassembly buffers */
31 static LIST_HEAD ( frag_buffers );
32
33 static void ipv4_forget_netdev ( struct reference *ref );
34
35 /**
36  * Add IPv4 minirouting table entry
37  *
38  * @v netdev            Network device
39  * @v address           IPv4 address
40  * @v netmask           Subnet mask
41  * @v gateway           Gateway address (or @c INADDR_NONE for no gateway)
42  * @ret miniroute       Routing table entry, or NULL
43  */
44 static struct ipv4_miniroute * add_ipv4_miniroute ( struct net_device *netdev,
45                                                     struct in_addr address,
46                                                     struct in_addr netmask,
47                                                     struct in_addr gateway ) {
48         struct ipv4_miniroute *miniroute;
49
50         DBG ( "IPv4 add %s", inet_ntoa ( address ) );
51         DBG ( "/%s ", inet_ntoa ( netmask ) );
52         if ( gateway.s_addr != INADDR_NONE )
53                 DBG ( "gw %s ", inet_ntoa ( gateway ) );
54         DBG ( "via %s\n", netdev->name );
55
56         /* Allocate and populate miniroute structure */
57         miniroute = malloc ( sizeof ( *miniroute ) );
58         if ( ! miniroute ) {
59                 DBG ( "IPv4 could not add miniroute\n" );
60                 return NULL;
61         }
62
63         /* Record routing information */
64         miniroute->netdev = netdev;
65         miniroute->address = address;
66         miniroute->netmask = netmask;
67         miniroute->gateway = gateway;
68                 
69         /* Add to end of list if we have a gateway, otherwise
70          * to start of list.
71          */
72         if ( gateway.s_addr != INADDR_NONE ) {
73                 list_add_tail ( &miniroute->list, &ipv4_miniroutes );
74         } else {
75                 list_add ( &miniroute->list, &ipv4_miniroutes );
76         }
77
78         /* Record reference to net_device */
79         miniroute->netdev_ref.forget = ipv4_forget_netdev;
80         ref_add ( &miniroute->netdev_ref, &netdev->references );
81
82         return miniroute;
83 }
84
85 /**
86  * Delete IPv4 minirouting table entry
87  *
88  * @v miniroute         Routing table entry
89  */
90 static void del_ipv4_miniroute ( struct ipv4_miniroute *miniroute ) {
91
92         DBG ( "IPv4 del %s", inet_ntoa ( miniroute->address ) );
93         DBG ( "/%s ", inet_ntoa ( miniroute->netmask ) );
94         if ( miniroute->gateway.s_addr != INADDR_NONE )
95                 DBG ( "gw %s ", inet_ntoa ( miniroute->gateway ) );
96         DBG ( "via %s\n", miniroute->netdev->name );
97
98         ref_del ( &miniroute->netdev_ref );
99         list_del ( &miniroute->list );
100         free ( miniroute );
101 }
102
103 /**
104  * Forget reference to net_device
105  *
106  * @v ref               Persistent reference
107  */
108 static void ipv4_forget_netdev ( struct reference *ref ) {
109         struct ipv4_miniroute *miniroute
110                 = container_of ( ref, struct ipv4_miniroute, netdev_ref );
111
112         del_ipv4_miniroute ( miniroute );
113 }
114
115 /**
116  * Add IPv4 interface
117  *
118  * @v netdev    Network device
119  * @v address   IPv4 address
120  * @v netmask   Subnet mask
121  * @v gateway   Gateway address (or @c INADDR_NONE for no gateway)
122  * @ret rc      Return status code
123  *
124  */
125 int add_ipv4_address ( struct net_device *netdev, struct in_addr address,
126                        struct in_addr netmask, struct in_addr gateway ) {
127         struct ipv4_miniroute *miniroute;
128
129         /* Clear any existing address for this net device */
130         del_ipv4_address ( netdev );
131
132         /* Add new miniroute */
133         miniroute = add_ipv4_miniroute ( netdev, address, netmask, gateway );
134         if ( ! miniroute )
135                 return -ENOMEM;
136
137         return 0;
138 }
139
140 /**
141  * Remove IPv4 interface
142  *
143  * @v netdev    Network device
144  */
145 void del_ipv4_address ( struct net_device *netdev ) {
146         struct ipv4_miniroute *miniroute;
147
148         list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
149                 if ( miniroute->netdev == netdev ) {
150                         del_ipv4_miniroute ( miniroute );
151                         break;
152                 }
153         }
154 }
155
156 /**
157  * Perform IPv4 routing
158  *
159  * @v dest              Final destination address
160  * @ret dest            Next hop destination address
161  * @ret miniroute       Routing table entry to use, or NULL if no route
162  */
163 static struct ipv4_miniroute * ipv4_route ( struct in_addr *dest ) {
164         struct ipv4_miniroute *miniroute;
165         int local;
166         int has_gw;
167
168         list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
169                 local = ( ( ( dest->s_addr ^ miniroute->address.s_addr )
170                             & miniroute->netmask.s_addr ) == 0 );
171                 has_gw = ( miniroute->gateway.s_addr != INADDR_NONE );
172                 if ( local || has_gw ) {
173                         if ( ! local )
174                                 *dest = miniroute->gateway;
175                         return miniroute;
176                 }
177         }
178
179         return NULL;
180 }
181
182 /**
183  * Fragment reassembly counter timeout
184  *
185  * @v timer     Retry timer
186  * @v over      If asserted, the timer is greater than @c MAX_TIMEOUT 
187  */
188 static void ipv4_frag_expired ( struct retry_timer *timer __unused,
189                                 int over ) {
190         if ( over ) {
191                 DBG ( "Fragment reassembly timeout" );
192                 /* Free the fragment buffer */
193         }
194 }
195
196 /**
197  * Free fragment buffer
198  *
199  * @v fragbug   Fragment buffer
200  */
201 static void free_fragbuf ( struct frag_buffer *fragbuf ) {
202         free ( fragbuf );
203 }
204
205 /**
206  * Fragment reassembler
207  *
208  * @v pkb               Packet buffer, fragment of the datagram
209  * @ret frag_pkb        Reassembled packet, or NULL
210  */
211 static struct pk_buff * ipv4_reassemble ( struct pk_buff * pkb ) {
212         struct iphdr *iphdr = pkb->data;
213         struct frag_buffer *fragbuf;
214         
215         /**
216          * Check if the fragment belongs to any fragment series
217          */
218         list_for_each_entry ( fragbuf, &frag_buffers, list ) {
219                 if ( fragbuf->ident == iphdr->ident &&
220                      fragbuf->src.s_addr == iphdr->src.s_addr ) {
221                         /**
222                          * Check if the packet is the expected fragment
223                          * 
224                          * The offset of the new packet must be equal to the
225                          * length of the data accumulated so far (the length of
226                          * the reassembled packet buffer
227                          */
228                         if ( pkb_len ( fragbuf->frag_pkb ) == 
229                               ( iphdr->frags & IP_MASK_OFFSET ) ) {
230                                 /**
231                                  * Append the contents of the fragment to the
232                                  * reassembled packet buffer
233                                  */
234                                 pkb_pull ( pkb, sizeof ( *iphdr ) );
235                                 memcpy ( pkb_put ( fragbuf->frag_pkb,
236                                                         pkb_len ( pkb ) ),
237                                          pkb->data, pkb_len ( pkb ) );
238                                 free_pkb ( pkb );
239
240                                 /** Check if the fragment series is over */
241                                 if ( !iphdr->frags & IP_MASK_MOREFRAGS ) {
242                                         pkb = fragbuf->frag_pkb;
243                                         free_fragbuf ( fragbuf );
244                                         return pkb;
245                                 }
246
247                         } else {
248                                 /* Discard the fragment series */
249                                 free_fragbuf ( fragbuf );
250                                 free_pkb ( pkb );
251                         }
252                         return NULL;
253                 }
254         }
255         
256         /** Check if the fragment is the first in the fragment series */
257         if ( iphdr->frags & IP_MASK_MOREFRAGS &&
258                         ( ( iphdr->frags & IP_MASK_OFFSET ) == 0 ) ) {
259         
260                 /** Create a new fragment buffer */
261                 fragbuf = ( struct frag_buffer* ) malloc ( sizeof( *fragbuf ) );
262                 fragbuf->ident = iphdr->ident;
263                 fragbuf->src = iphdr->src;
264
265                 /* Set up the reassembly packet buffer */
266                 fragbuf->frag_pkb = alloc_pkb ( IP_FRAG_PKB_SIZE );
267                 pkb_pull ( pkb, sizeof ( *iphdr ) );
268                 memcpy ( pkb_put ( fragbuf->frag_pkb, pkb_len ( pkb ) ),
269                          pkb->data, pkb_len ( pkb ) );
270                 free_pkb ( pkb );
271
272                 /* Set the reassembly timer */
273                 fragbuf->frag_timer.timeout = IP_FRAG_TIMEOUT;
274                 fragbuf->frag_timer.expired = ipv4_frag_expired;
275                 start_timer ( &fragbuf->frag_timer );
276
277                 /* Add the fragment buffer to the list of fragment buffers */
278                 list_add ( &fragbuf->list, &frag_buffers );
279         }
280         
281         return NULL;
282 }
283
284 /**
285  * Add IPv4 pseudo-header checksum to existing checksum
286  *
287  * @v pkb               Packet buffer
288  * @v csum              Existing checksum
289  * @ret csum            Updated checksum
290  */
291 static uint16_t ipv4_pshdr_chksum ( struct pk_buff *pkb, uint16_t csum ) {
292         struct ipv4_pseudo_header pshdr;
293         struct iphdr *iphdr = pkb->data;
294         size_t hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 );
295
296         /* Build pseudo-header */
297         pshdr.src = iphdr->src;
298         pshdr.dest = iphdr->dest;
299         pshdr.zero_padding = 0x00;
300         pshdr.protocol = iphdr->protocol;
301         pshdr.len = htons ( pkb_len ( pkb ) - hdrlen );
302
303         /* Update the checksum value */
304         return tcpip_continue_chksum ( csum, &pshdr, sizeof ( pshdr ) );
305 }
306
307 /**
308  * Determine link-layer address
309  *
310  * @v dest              IPv4 destination address
311  * @v src               IPv4 source address
312  * @v netdev            Network device
313  * @v ll_dest           Link-layer destination address buffer
314  * @ret rc              Return status code
315  */
316 static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src,
317                           struct net_device *netdev, uint8_t *ll_dest ) {
318         struct ll_protocol *ll_protocol = netdev->ll_protocol;
319         uint8_t *dest_bytes = ( ( uint8_t * ) &dest );
320
321         if ( dest.s_addr == INADDR_BROADCAST ) {
322                 /* Broadcast address */
323                 memcpy ( ll_dest, ll_protocol->ll_broadcast,
324                          ll_protocol->ll_addr_len );
325                 return 0;
326         } else if ( IN_MULTICAST ( dest.s_addr ) ) {
327                 /* Special case: IPv4 multicast over Ethernet.  This
328                  * code may need to be generalised once we find out
329                  * what happens for other link layers.
330                  */
331                 ll_dest[0] = 0x01;
332                 ll_dest[1] = 0x00;
333                 ll_dest[2] = 0x5e;
334                 ll_dest[3] = dest_bytes[1] & 0x7f;
335                 ll_dest[4] = dest_bytes[2];
336                 ll_dest[5] = dest_bytes[3];
337                 return 0;
338         } else {
339                 /* Unicast address: resolve via ARP */
340                 return arp_resolve ( netdev, &ipv4_protocol, &dest,
341                                      &src, ll_dest );
342         }
343 }
344
345 /**
346  * Transmit IP packet
347  *
348  * @v pkb               Packet buffer
349  * @v tcpip             Transport-layer protocol
350  * @v st_dest           Destination network-layer address
351  * @v netdev            Network device to use if no route found, or NULL
352  * @v trans_csum        Transport-layer checksum to complete, or NULL
353  * @ret rc              Status
354  *
355  * This function expects a transport-layer segment and prepends the IP header
356  */
357 static int ipv4_tx ( struct pk_buff *pkb,
358                      struct tcpip_protocol *tcpip_protocol,
359                      struct sockaddr_tcpip *st_dest,
360                      struct net_device *netdev,
361                      uint16_t *trans_csum ) {
362         struct iphdr *iphdr = pkb_push ( pkb, sizeof ( *iphdr ) );
363         struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest );
364         struct ipv4_miniroute *miniroute;
365         struct in_addr next_hop;
366         uint8_t ll_dest[MAX_LL_ADDR_LEN];
367         int rc;
368
369         /* Fill up the IP header, except source address */
370         memset ( iphdr, 0, sizeof ( *iphdr ) );
371         iphdr->verhdrlen = ( IP_VER | ( sizeof ( *iphdr ) / 4 ) );
372         iphdr->service = IP_TOS;
373         iphdr->len = htons ( pkb_len ( pkb ) ); 
374         iphdr->ident = htons ( ++next_ident );
375         iphdr->ttl = IP_TTL;
376         iphdr->protocol = tcpip_protocol->tcpip_proto;
377         iphdr->dest = sin_dest->sin_addr;
378
379         /* Use routing table to identify next hop and transmitting netdev */
380         next_hop = iphdr->dest;
381         if ( ( miniroute = ipv4_route ( &next_hop ) ) ) {
382                 iphdr->src = miniroute->address;
383                 netdev = miniroute->netdev;
384         }
385         if ( ! netdev ) {
386                 DBG ( "IPv4 has no route to %s\n", inet_ntoa ( iphdr->dest ) );
387                 rc = -ENETUNREACH;
388                 goto err;
389         }
390
391         /* Determine link-layer destination address */
392         if ( ( rc = ipv4_ll_addr ( next_hop, iphdr->src, netdev,
393                                    ll_dest ) ) != 0 ) {
394                 DBG ( "IPv4 has no link-layer address for %s: %s\n",
395                       inet_ntoa ( next_hop ), strerror ( rc ) );
396                 goto err;
397         }
398
399         /* Fix up checksums */
400         if ( trans_csum )
401                 *trans_csum = ipv4_pshdr_chksum ( pkb, *trans_csum );
402         iphdr->chksum = tcpip_chksum ( iphdr, sizeof ( *iphdr ) );
403
404         /* Print IP4 header for debugging */
405         DBG ( "IPv4 TX %s->", inet_ntoa ( iphdr->src ) );
406         DBG ( "%s len %d proto %d id %04x csum %04x\n",
407               inet_ntoa ( iphdr->dest ), ntohs ( iphdr->len ), iphdr->protocol,
408               ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
409
410         /* Hand off to link layer */
411         if ( ( rc = net_tx ( pkb, netdev, &ipv4_protocol, ll_dest ) ) != 0 ) {
412                 DBG ( "IPv4 could not transmit packet via %s: %s\n",
413                       netdev->name, strerror ( rc ) );
414                 return rc;
415         }
416
417         return 0;
418
419  err:
420         free_pkb ( pkb );
421         return rc;
422 }
423
424 /**
425  * Process incoming packets
426  *
427  * @v pkb       Packet buffer
428  * @v netdev    Network device
429  * @v ll_source Link-layer destination source
430  *
431  * This function expects an IP4 network datagram. It processes the headers 
432  * and sends it to the transport layer.
433  */
434 static int ipv4_rx ( struct pk_buff *pkb, struct net_device *netdev __unused,
435                      const void *ll_source __unused ) {
436         struct iphdr *iphdr = pkb->data;
437         size_t hdrlen;
438         size_t len;
439         union {
440                 struct sockaddr_in sin;
441                 struct sockaddr_tcpip st;
442         } src, dest;
443         uint16_t csum;
444         uint16_t pshdr_csum;
445         int rc;
446
447         /* Sanity check the IPv4 header */
448         if ( pkb_len ( pkb ) < sizeof ( *iphdr ) ) {
449                 DBG ( "IPv4 packet too short at %d bytes (min %d bytes)\n",
450                       pkb_len ( pkb ), sizeof ( *iphdr ) );
451                 goto err;
452         }
453         if ( ( iphdr->verhdrlen & IP_MASK_VER ) != IP_VER ) {
454                 DBG ( "IPv4 version %#02x not supported\n", iphdr->verhdrlen );
455                 goto err;
456         }
457         hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 );
458         if ( hdrlen < sizeof ( *iphdr ) ) {
459                 DBG ( "IPv4 header too short at %d bytes (min %d bytes)\n",
460                       hdrlen, sizeof ( *iphdr ) );
461                 goto err;
462         }
463         if ( hdrlen > pkb_len ( pkb ) ) {
464                 DBG ( "IPv4 header too long at %d bytes "
465                       "(packet is %d bytes)\n", hdrlen, pkb_len ( pkb ) );
466                 goto err;
467         }
468         if ( ( csum = tcpip_chksum ( iphdr, hdrlen ) ) != 0 ) {
469                 DBG ( "IPv4 checksum incorrect (is %04x including checksum "
470                       "field, should be 0000)\n", csum );
471                 goto err;
472         }
473         len = ntohs ( iphdr->len );
474         if ( len < hdrlen ) {
475                 DBG ( "IPv4 length too short at %d bytes "
476                       "(header is %d bytes)\n", len, hdrlen );
477                 goto err;
478         }
479         if ( len > pkb_len ( pkb ) ) {
480                 DBG ( "IPv4 length too long at %d bytes "
481                       "(packet is %d bytes)\n", len, pkb_len ( pkb ) );
482                 goto err;
483         }
484
485         /* Print IPv4 header for debugging */
486         DBG ( "IPv4 RX %s<-", inet_ntoa ( iphdr->dest ) );
487         DBG ( "%s len %d proto %d id %04x csum %04x\n",
488               inet_ntoa ( iphdr->src ), ntohs ( iphdr->len ), iphdr->protocol,
489               ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
490
491         /* Truncate packet to correct length, calculate pseudo-header
492          * checksum and then strip off the IPv4 header.
493          */
494         pkb_unput ( pkb, ( pkb_len ( pkb ) - len ) );
495         pshdr_csum = ipv4_pshdr_chksum ( pkb, TCPIP_EMPTY_CSUM );
496         pkb_pull ( pkb, hdrlen );
497
498         /* Fragment reassembly */
499         if ( ( iphdr->frags & htons ( IP_MASK_MOREFRAGS ) ) || 
500              ( ( iphdr->frags & htons ( IP_MASK_OFFSET ) ) != 0 ) ) {
501                 /* Pass the fragment to ipv4_reassemble() which either
502                  * returns a fully reassembled packet buffer or NULL.
503                  */
504                 pkb = ipv4_reassemble ( pkb );
505                 if ( ! pkb )
506                         return 0;
507         }
508
509         /* Construct socket addresses and hand off to transport layer */
510         memset ( &src, 0, sizeof ( src ) );
511         src.sin.sin_family = AF_INET;
512         src.sin.sin_addr = iphdr->src;
513         memset ( &dest, 0, sizeof ( dest ) );
514         dest.sin.sin_family = AF_INET;
515         dest.sin.sin_addr = iphdr->dest;
516         if ( ( rc = tcpip_rx ( pkb, iphdr->protocol, &src.st,
517                                &dest.st, pshdr_csum ) ) != 0 ) {
518                 DBG ( "IPv4 received packet rejected by stack: %s\n",
519                       strerror ( rc ) );
520                 return rc;
521         }
522
523         return 0;
524
525  err:
526         free_pkb ( pkb );
527         return -EINVAL;
528 }
529
530 /** 
531  * Check existence of IPv4 address for ARP
532  *
533  * @v netdev            Network device
534  * @v net_addr          Network-layer address
535  * @ret rc              Return status code
536  */
537 static int ipv4_arp_check ( struct net_device *netdev, const void *net_addr ) {
538         const struct in_addr *address = net_addr;
539         struct ipv4_miniroute *miniroute;
540
541         list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
542                 if ( ( miniroute->netdev == netdev ) &&
543                      ( miniroute->address.s_addr == address->s_addr ) ) {
544                         /* Found matching address */
545                         return 0;
546                 }
547         }
548         return -ENOENT;
549 }
550
551 /**
552  * Convert IPv4 address to dotted-quad notation
553  *
554  * @v in        IP address
555  * @ret string  IP address in dotted-quad notation
556  */
557 char * inet_ntoa ( struct in_addr in ) {
558         static char buf[16]; /* "xxx.xxx.xxx.xxx" */
559         uint8_t *bytes = ( uint8_t * ) &in;
560         
561         sprintf ( buf, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3] );
562         return buf;
563 }
564
565 /**
566  * Transcribe IP address
567  *
568  * @v net_addr  IP address
569  * @ret string  IP address in dotted-quad notation
570  *
571  */
572 static const char * ipv4_ntoa ( const void *net_addr ) {
573         return inet_ntoa ( * ( ( struct in_addr * ) net_addr ) );
574 }
575
576 /** IPv4 protocol */
577 struct net_protocol ipv4_protocol __net_protocol = {
578         .name = "IP",
579         .net_proto = htons ( ETH_P_IP ),
580         .net_addr_len = sizeof ( struct in_addr ),
581         .rx = ipv4_rx,
582         .ntoa = ipv4_ntoa,
583 };
584
585 /** IPv4 TCPIP net protocol */
586 struct tcpip_net_protocol ipv4_tcpip_protocol __tcpip_net_protocol = {
587         .name = "IPv4",
588         .sa_family = AF_INET,
589         .tx = ipv4_tx,
590 };
591
592 /** IPv4 ARP protocol */
593 struct arp_net_protocol ipv4_arp_protocol __arp_net_protocol = {
594         .net_protocol = &ipv4_protocol,
595         .check = ipv4_arp_check,
596 };