Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / 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 <ipxe/list.h>
8 #include <ipxe/in.h>
9 #include <ipxe/arp.h>
10 #include <ipxe/if_ether.h>
11 #include <ipxe/iobuf.h>
12 #include <ipxe/netdevice.h>
13 #include <ipxe/ip.h>
14 #include <ipxe/tcpip.h>
15 #include <ipxe/dhcp.h>
16 #include <ipxe/settings.h>
17 #include <ipxe/fragment.h>
18 #include <ipxe/ipstat.h>
19 #include <ipxe/profile.h>
20
21 /** @file
22  *
23  * IPv4 protocol
24  *
25  */
26
27 FILE_LICENCE ( GPL2_OR_LATER );
28
29 /* Unique IP datagram identification number (high byte) */
30 static uint8_t next_ident_high = 0;
31
32 /** List of IPv4 miniroutes */
33 struct list_head ipv4_miniroutes = LIST_HEAD_INIT ( ipv4_miniroutes );
34
35 /** IPv4 statistics */
36 static struct ip_statistics ipv4_stats;
37
38 /** IPv4 statistics family */
39 struct ip_statistics_family
40 ipv4_stats_family __ip_statistics_family ( IP_STATISTICS_IPV4 ) = {
41         .version = 4,
42         .stats = &ipv4_stats,
43 };
44
45 /** Transmit profiler */
46 static struct profiler ipv4_tx_profiler __profiler = { .name = "ipv4.tx" };
47
48 /** Receive profiler */
49 static struct profiler ipv4_rx_profiler __profiler = { .name = "ipv4.rx" };
50
51 /**
52  * Add IPv4 minirouting table entry
53  *
54  * @v netdev            Network device
55  * @v address           IPv4 address
56  * @v netmask           Subnet mask
57  * @v gateway           Gateway address (if any)
58  * @ret miniroute       Routing table entry, or NULL
59  */
60 static struct ipv4_miniroute * __malloc
61 add_ipv4_miniroute ( struct net_device *netdev, struct in_addr address,
62                      struct in_addr netmask, struct in_addr gateway ) {
63         struct ipv4_miniroute *miniroute;
64
65         DBGC ( netdev, "IPv4 add %s", inet_ntoa ( address ) );
66         DBGC ( netdev, "/%s ", inet_ntoa ( netmask ) );
67         if ( gateway.s_addr )
68                 DBGC ( netdev, "gw %s ", inet_ntoa ( gateway ) );
69         DBGC ( netdev, "via %s\n", netdev->name );
70
71         /* Allocate and populate miniroute structure */
72         miniroute = malloc ( sizeof ( *miniroute ) );
73         if ( ! miniroute ) {
74                 DBGC ( netdev, "IPv4 could not add miniroute\n" );
75                 return NULL;
76         }
77
78         /* Record routing information */
79         miniroute->netdev = netdev_get ( netdev );
80         miniroute->address = address;
81         miniroute->netmask = netmask;
82         miniroute->gateway = gateway;
83                 
84         /* Add to end of list if we have a gateway, otherwise
85          * to start of list.
86          */
87         if ( gateway.s_addr ) {
88                 list_add_tail ( &miniroute->list, &ipv4_miniroutes );
89         } else {
90                 list_add ( &miniroute->list, &ipv4_miniroutes );
91         }
92
93         return miniroute;
94 }
95
96 /**
97  * Delete IPv4 minirouting table entry
98  *
99  * @v miniroute         Routing table entry
100  */
101 static void del_ipv4_miniroute ( struct ipv4_miniroute *miniroute ) {
102         struct net_device *netdev = miniroute->netdev;
103
104         DBGC ( netdev, "IPv4 del %s", inet_ntoa ( miniroute->address ) );
105         DBGC ( netdev, "/%s ", inet_ntoa ( miniroute->netmask ) );
106         if ( miniroute->gateway.s_addr )
107                 DBGC ( netdev, "gw %s ", inet_ntoa ( miniroute->gateway ) );
108         DBGC ( netdev, "via %s\n", miniroute->netdev->name );
109
110         netdev_put ( miniroute->netdev );
111         list_del ( &miniroute->list );
112         free ( miniroute );
113 }
114
115 /**
116  * Perform IPv4 routing
117  *
118  * @v dest              Final destination address
119  * @ret dest            Next hop destination address
120  * @ret miniroute       Routing table entry to use, or NULL if no route
121  *
122  * If the route requires use of a gateway, the next hop destination
123  * address will be overwritten with the gateway address.
124  */
125 static struct ipv4_miniroute * ipv4_route ( struct in_addr *dest ) {
126         struct ipv4_miniroute *miniroute;
127         int local;
128         int has_gw;
129
130         /* Find first usable route in routing table */
131         list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
132                 if ( ! netdev_is_open ( miniroute->netdev ) )
133                         continue;
134                 local = ( ( ( dest->s_addr ^ miniroute->address.s_addr )
135                             & miniroute->netmask.s_addr ) == 0 );
136                 has_gw = ( miniroute->gateway.s_addr );
137                 if ( local || has_gw ) {
138                         if ( ! local )
139                                 *dest = miniroute->gateway;
140                         return miniroute;
141                 }
142         }
143
144         return NULL;
145 }
146
147 /**
148  * Determine transmitting network device
149  *
150  * @v st_dest           Destination network-layer address
151  * @ret netdev          Transmitting network device, or NULL
152  */
153 static struct net_device * ipv4_netdev ( struct sockaddr_tcpip *st_dest ) {
154         struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest );
155         struct in_addr dest = sin_dest->sin_addr;
156         struct ipv4_miniroute *miniroute;
157
158         /* Find routing table entry */
159         miniroute = ipv4_route ( &dest );
160         if ( ! miniroute )
161                 return NULL;
162
163         return miniroute->netdev;
164 }
165
166 /**
167  * Check if IPv4 fragment matches fragment reassembly buffer
168  *
169  * @v fragment          Fragment reassembly buffer
170  * @v iobuf             I/O buffer
171  * @v hdrlen            Length of non-fragmentable potion of I/O buffer
172  * @ret is_fragment     Fragment matches this reassembly buffer
173  */
174 static int ipv4_is_fragment ( struct fragment *fragment,
175                               struct io_buffer *iobuf,
176                               size_t hdrlen __unused ) {
177         struct iphdr *frag_iphdr = fragment->iobuf->data;
178         struct iphdr *iphdr = iobuf->data;
179
180         return ( ( iphdr->src.s_addr == frag_iphdr->src.s_addr ) &&
181                  ( iphdr->ident == frag_iphdr->ident ) );
182 }
183
184 /**
185  * Get IPv4 fragment offset
186  *
187  * @v iobuf             I/O buffer
188  * @v hdrlen            Length of non-fragmentable potion of I/O buffer
189  * @ret offset          Offset
190  */
191 static size_t ipv4_fragment_offset ( struct io_buffer *iobuf,
192                                      size_t hdrlen __unused ) {
193         struct iphdr *iphdr = iobuf->data;
194
195         return ( ( ntohs ( iphdr->frags ) & IP_MASK_OFFSET ) << 3 );
196 }
197
198 /**
199  * Check if more fragments exist
200  *
201  * @v iobuf             I/O buffer
202  * @v hdrlen            Length of non-fragmentable potion of I/O buffer
203  * @ret more_frags      More fragments exist
204  */
205 static int ipv4_more_fragments ( struct io_buffer *iobuf,
206                                  size_t hdrlen __unused ) {
207         struct iphdr *iphdr = iobuf->data;
208
209         return ( iphdr->frags & htons ( IP_MASK_MOREFRAGS ) );
210 }
211
212 /** IPv4 fragment reassembler */
213 static struct fragment_reassembler ipv4_reassembler = {
214         .list = LIST_HEAD_INIT ( ipv4_reassembler.list ),
215         .is_fragment = ipv4_is_fragment,
216         .fragment_offset = ipv4_fragment_offset,
217         .more_fragments = ipv4_more_fragments,
218         .stats = &ipv4_stats,
219 };
220
221 /**
222  * Add IPv4 pseudo-header checksum to existing checksum
223  *
224  * @v iobuf             I/O buffer
225  * @v csum              Existing checksum
226  * @ret csum            Updated checksum
227  */
228 static uint16_t ipv4_pshdr_chksum ( struct io_buffer *iobuf, uint16_t csum ) {
229         struct ipv4_pseudo_header pshdr;
230         struct iphdr *iphdr = iobuf->data;
231         size_t hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 );
232
233         /* Build pseudo-header */
234         pshdr.src = iphdr->src;
235         pshdr.dest = iphdr->dest;
236         pshdr.zero_padding = 0x00;
237         pshdr.protocol = iphdr->protocol;
238         pshdr.len = htons ( iob_len ( iobuf ) - hdrlen );
239
240         /* Update the checksum value */
241         return tcpip_continue_chksum ( csum, &pshdr, sizeof ( pshdr ) );
242 }
243
244 /**
245  * Transmit IP packet
246  *
247  * @v iobuf             I/O buffer
248  * @v tcpip             Transport-layer protocol
249  * @v st_src            Source network-layer address
250  * @v st_dest           Destination network-layer address
251  * @v netdev            Network device to use if no route found, or NULL
252  * @v trans_csum        Transport-layer checksum to complete, or NULL
253  * @ret rc              Status
254  *
255  * This function expects a transport-layer segment and prepends the IP header
256  */
257 static int ipv4_tx ( struct io_buffer *iobuf,
258                      struct tcpip_protocol *tcpip_protocol,
259                      struct sockaddr_tcpip *st_src,
260                      struct sockaddr_tcpip *st_dest,
261                      struct net_device *netdev,
262                      uint16_t *trans_csum ) {
263         struct iphdr *iphdr = iob_push ( iobuf, sizeof ( *iphdr ) );
264         struct sockaddr_in *sin_src = ( ( struct sockaddr_in * ) st_src );
265         struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest );
266         struct ipv4_miniroute *miniroute;
267         struct in_addr next_hop;
268         struct in_addr netmask = { .s_addr = 0 };
269         uint8_t ll_dest_buf[MAX_LL_ADDR_LEN];
270         const void *ll_dest;
271         int rc;
272
273         /* Start profiling */
274         profile_start ( &ipv4_tx_profiler );
275
276         /* Update statistics */
277         ipv4_stats.out_requests++;
278
279         /* Fill up the IP header, except source address */
280         memset ( iphdr, 0, sizeof ( *iphdr ) );
281         iphdr->verhdrlen = ( IP_VER | ( sizeof ( *iphdr ) / 4 ) );
282         iphdr->service = IP_TOS;
283         iphdr->len = htons ( iob_len ( iobuf ) );       
284         iphdr->ttl = IP_TTL;
285         iphdr->protocol = tcpip_protocol->tcpip_proto;
286         iphdr->dest = sin_dest->sin_addr;
287
288         /* Use routing table to identify next hop and transmitting netdev */
289         next_hop = iphdr->dest;
290         if ( sin_src )
291                 iphdr->src = sin_src->sin_addr;
292         if ( ( next_hop.s_addr != INADDR_BROADCAST ) &&
293              ( ! IN_MULTICAST ( ntohl ( next_hop.s_addr ) ) ) &&
294              ( ( miniroute = ipv4_route ( &next_hop ) ) != NULL ) ) {
295                 iphdr->src = miniroute->address;
296                 netmask = miniroute->netmask;
297                 netdev = miniroute->netdev;
298         }
299         if ( ! netdev ) {
300                 DBGC ( sin_dest->sin_addr, "IPv4 has no route to %s\n",
301                        inet_ntoa ( iphdr->dest ) );
302                 ipv4_stats.out_no_routes++;
303                 rc = -ENETUNREACH;
304                 goto err;
305         }
306
307         /* (Ab)use the "ident" field to convey metadata about the
308          * network device statistics into packet traces.  Useful for
309          * extracting debug information from non-debug builds.
310          */
311         iphdr->ident = htons ( ( (++next_ident_high) << 8 ) |
312                                ( ( netdev->rx_stats.bad & 0xf ) << 4 ) |
313                                ( ( netdev->rx_stats.good & 0xf ) << 0 ) );
314
315         /* Fix up checksums */
316         if ( trans_csum )
317                 *trans_csum = ipv4_pshdr_chksum ( iobuf, *trans_csum );
318         iphdr->chksum = tcpip_chksum ( iphdr, sizeof ( *iphdr ) );
319
320         /* Print IP4 header for debugging */
321         DBGC2 ( sin_dest->sin_addr, "IPv4 TX %s->", inet_ntoa ( iphdr->src ) );
322         DBGC2 ( sin_dest->sin_addr, "%s len %d proto %d id %04x csum %04x\n",
323                 inet_ntoa ( iphdr->dest ), ntohs ( iphdr->len ),
324                 iphdr->protocol, ntohs ( iphdr->ident ),
325                 ntohs ( iphdr->chksum ) );
326
327         /* Calculate link-layer destination address, if possible */
328         if ( ( ( next_hop.s_addr ^ INADDR_BROADCAST ) & ~netmask.s_addr ) == 0){
329                 /* Broadcast address */
330                 ipv4_stats.out_bcast_pkts++;
331                 ll_dest = netdev->ll_broadcast;
332         } else if ( IN_MULTICAST ( ntohl ( next_hop.s_addr ) ) ) {
333                 /* Multicast address */
334                 ipv4_stats.out_mcast_pkts++;
335                 if ( ( rc = netdev->ll_protocol->mc_hash ( AF_INET, &next_hop,
336                                                            ll_dest_buf ) ) !=0){
337                         DBGC ( sin_dest->sin_addr, "IPv4 could not hash "
338                                "multicast %s: %s\n",
339                                inet_ntoa ( next_hop ), strerror ( rc ) );
340                         goto err;
341                 }
342                 ll_dest = ll_dest_buf;
343         } else {
344                 /* Unicast address */
345                 ll_dest = NULL;
346         }
347
348         /* Update statistics */
349         ipv4_stats.out_transmits++;
350         ipv4_stats.out_octets += iob_len ( iobuf );
351
352         /* Hand off to link layer (via ARP if applicable) */
353         if ( ll_dest ) {
354                 if ( ( rc = net_tx ( iobuf, netdev, &ipv4_protocol, ll_dest,
355                                      netdev->ll_addr ) ) != 0 ) {
356                         DBGC ( sin_dest->sin_addr, "IPv4 could not transmit "
357                                "packet via %s: %s\n",
358                                netdev->name, strerror ( rc ) );
359                         return rc;
360                 }
361         } else {
362                 if ( ( rc = arp_tx ( iobuf, netdev, &ipv4_protocol, &next_hop,
363                                      &iphdr->src, netdev->ll_addr ) ) != 0 ) {
364                         DBGC ( sin_dest->sin_addr, "IPv4 could not transmit "
365                                "packet via %s: %s\n",
366                                netdev->name, strerror ( rc ) );
367                         return rc;
368                 }
369         }
370
371         profile_stop ( &ipv4_tx_profiler );
372         return 0;
373
374  err:
375         free_iob ( iobuf );
376         return rc;
377 }
378
379 /**
380  * Check if network device has any IPv4 address
381  *
382  * @v netdev            Network device
383  * @ret has_any_addr    Network device has any IPv4 address
384  */
385 int ipv4_has_any_addr ( struct net_device *netdev ) {
386         struct ipv4_miniroute *miniroute;
387
388         list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
389                 if ( miniroute->netdev == netdev )
390                         return 1;
391         }
392         return 0;
393 }
394
395 /**
396  * Check if network device has a specific IPv4 address
397  *
398  * @v netdev            Network device
399  * @v addr              IPv4 address
400  * @ret has_addr        Network device has this IPv4 address
401  */
402 static int ipv4_has_addr ( struct net_device *netdev, struct in_addr addr ) {
403         struct ipv4_miniroute *miniroute;
404
405         list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
406                 if ( ( miniroute->netdev == netdev ) &&
407                      ( miniroute->address.s_addr == addr.s_addr ) ) {
408                         /* Found matching address */
409                         return 1;
410                 }
411         }
412         return 0;
413 }
414
415 /**
416  * Process incoming packets
417  *
418  * @v iobuf             I/O buffer
419  * @v netdev            Network device
420  * @v ll_dest           Link-layer destination address
421  * @v ll_source         Link-layer destination source
422  * @v flags             Packet flags
423  * @ret rc              Return status code
424  *
425  * This function expects an IP4 network datagram. It processes the headers 
426  * and sends it to the transport layer.
427  */
428 static int ipv4_rx ( struct io_buffer *iobuf,
429                      struct net_device *netdev,
430                      const void *ll_dest __unused,
431                      const void *ll_source __unused,
432                      unsigned int flags ) {
433         struct iphdr *iphdr = iobuf->data;
434         size_t hdrlen;
435         size_t len;
436         union {
437                 struct sockaddr_in sin;
438                 struct sockaddr_tcpip st;
439         } src, dest;
440         uint16_t csum;
441         uint16_t pshdr_csum;
442         int rc;
443
444         /* Start profiling */
445         profile_start ( &ipv4_rx_profiler );
446
447         /* Update statistics */
448         ipv4_stats.in_receives++;
449         ipv4_stats.in_octets += iob_len ( iobuf );
450         if ( flags & LL_BROADCAST ) {
451                 ipv4_stats.in_bcast_pkts++;
452         } else if ( flags & LL_MULTICAST ) {
453                 ipv4_stats.in_mcast_pkts++;
454         }
455
456         /* Sanity check the IPv4 header */
457         if ( iob_len ( iobuf ) < sizeof ( *iphdr ) ) {
458                 DBGC ( iphdr->src, "IPv4 packet too short at %zd bytes (min "
459                        "%zd bytes)\n", iob_len ( iobuf ), sizeof ( *iphdr ) );
460                 goto err_header;
461         }
462         if ( ( iphdr->verhdrlen & IP_MASK_VER ) != IP_VER ) {
463                 DBGC ( iphdr->src, "IPv4 version %#02x not supported\n",
464                        iphdr->verhdrlen );
465                 goto err_header;
466         }
467         hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 );
468         if ( hdrlen < sizeof ( *iphdr ) ) {
469                 DBGC ( iphdr->src, "IPv4 header too short at %zd bytes (min "
470                        "%zd bytes)\n", hdrlen, sizeof ( *iphdr ) );
471                 goto err_header;
472         }
473         if ( hdrlen > iob_len ( iobuf ) ) {
474                 DBGC ( iphdr->src, "IPv4 header too long at %zd bytes "
475                        "(packet is %zd bytes)\n", hdrlen, iob_len ( iobuf ) );
476                 goto err_header;
477         }
478         if ( ( csum = tcpip_chksum ( iphdr, hdrlen ) ) != 0 ) {
479                 DBGC ( iphdr->src, "IPv4 checksum incorrect (is %04x "
480                        "including checksum field, should be 0000)\n", csum );
481                 goto err_header;
482         }
483         len = ntohs ( iphdr->len );
484         if ( len < hdrlen ) {
485                 DBGC ( iphdr->src, "IPv4 length too short at %zd bytes "
486                        "(header is %zd bytes)\n", len, hdrlen );
487                 goto err_header;
488         }
489         if ( len > iob_len ( iobuf ) ) {
490                 DBGC ( iphdr->src, "IPv4 length too long at %zd bytes "
491                        "(packet is %zd bytes)\n", len, iob_len ( iobuf ) );
492                 ipv4_stats.in_truncated_pkts++;
493                 goto err_other;
494         }
495
496         /* Truncate packet to correct length */
497         iob_unput ( iobuf, ( iob_len ( iobuf ) - len ) );
498
499         /* Print IPv4 header for debugging */
500         DBGC2 ( iphdr->src, "IPv4 RX %s<-", inet_ntoa ( iphdr->dest ) );
501         DBGC2 ( iphdr->src, "%s len %d proto %d id %04x csum %04x\n",
502                 inet_ntoa ( iphdr->src ), ntohs ( iphdr->len ), iphdr->protocol,
503                 ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
504
505         /* Discard unicast packets not destined for us */
506         if ( ( ! ( flags & LL_MULTICAST ) ) &&
507              ipv4_has_any_addr ( netdev ) &&
508              ( ! ipv4_has_addr ( netdev, iphdr->dest ) ) ) {
509                 DBGC ( iphdr->src, "IPv4 discarding non-local unicast packet "
510                        "for %s\n", inet_ntoa ( iphdr->dest ) );
511                 ipv4_stats.in_addr_errors++;
512                 goto err_other;
513         }
514
515         /* Perform fragment reassembly if applicable */
516         if ( iphdr->frags & htons ( IP_MASK_OFFSET | IP_MASK_MOREFRAGS ) ) {
517                 /* Pass the fragment to fragment_reassemble() which returns
518                  * either a fully reassembled I/O buffer or NULL.
519                  */
520                 iobuf = fragment_reassemble ( &ipv4_reassembler, iobuf,
521                                               &hdrlen );
522                 if ( ! iobuf )
523                         return 0;
524                 iphdr = iobuf->data;
525         }
526
527         /* Construct socket addresses, calculate pseudo-header
528          * checksum, and hand off to transport layer
529          */
530         memset ( &src, 0, sizeof ( src ) );
531         src.sin.sin_family = AF_INET;
532         src.sin.sin_addr = iphdr->src;
533         memset ( &dest, 0, sizeof ( dest ) );
534         dest.sin.sin_family = AF_INET;
535         dest.sin.sin_addr = iphdr->dest;
536         pshdr_csum = ipv4_pshdr_chksum ( iobuf, TCPIP_EMPTY_CSUM );
537         iob_pull ( iobuf, hdrlen );
538         if ( ( rc = tcpip_rx ( iobuf, netdev, iphdr->protocol, &src.st,
539                                &dest.st, pshdr_csum, &ipv4_stats ) ) != 0 ) {
540                 DBGC ( src.sin.sin_addr, "IPv4 received packet rejected by "
541                        "stack: %s\n", strerror ( rc ) );
542                 return rc;
543         }
544
545         profile_stop ( &ipv4_rx_profiler );
546         return 0;
547
548  err_header:
549         ipv4_stats.in_hdr_errors++;
550  err_other:
551         free_iob ( iobuf );
552         return -EINVAL;
553 }
554
555 /** 
556  * Check existence of IPv4 address for ARP
557  *
558  * @v netdev            Network device
559  * @v net_addr          Network-layer address
560  * @ret rc              Return status code
561  */
562 static int ipv4_arp_check ( struct net_device *netdev, const void *net_addr ) {
563         const struct in_addr *address = net_addr;
564
565         if ( ipv4_has_addr ( netdev, *address ) )
566                 return 0;
567
568         return -ENOENT;
569 }
570
571 /**
572  * Convert IPv4 address to dotted-quad notation
573  *
574  * @v in        IP address
575  * @ret string  IP address in dotted-quad notation
576  */
577 char * inet_ntoa ( struct in_addr in ) {
578         static char buf[16]; /* "xxx.xxx.xxx.xxx" */
579         uint8_t *bytes = ( uint8_t * ) &in;
580         
581         sprintf ( buf, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3] );
582         return buf;
583 }
584
585 /**
586  * Transcribe IP address
587  *
588  * @v net_addr  IP address
589  * @ret string  IP address in dotted-quad notation
590  *
591  */
592 static const char * ipv4_ntoa ( const void *net_addr ) {
593         return inet_ntoa ( * ( ( struct in_addr * ) net_addr ) );
594 }
595
596 /**
597  * Transcribe IPv4 socket address
598  *
599  * @v sa                Socket address
600  * @ret string          Socket address in standard notation
601  */
602 static const char * ipv4_sock_ntoa ( struct sockaddr *sa ) {
603         struct sockaddr_in *sin = ( ( struct sockaddr_in * ) sa );
604
605         return inet_ntoa ( sin->sin_addr );
606 }
607
608 /**
609  * Parse IPv4 socket address
610  *
611  * @v string            Socket address string
612  * @v sa                Socket address to fill in
613  * @ret rc              Return status code
614  */
615 static int ipv4_sock_aton ( const char *string, struct sockaddr *sa ) {
616         struct sockaddr_in *sin = ( ( struct sockaddr_in * ) sa );
617         struct in_addr in;
618
619         if ( inet_aton ( string, &in ) ) {
620                 sin->sin_addr = in;
621                 return 0;
622         }
623         return -EINVAL;
624 }
625
626 /** IPv4 protocol */
627 struct net_protocol ipv4_protocol __net_protocol = {
628         .name = "IP",
629         .net_proto = htons ( ETH_P_IP ),
630         .net_addr_len = sizeof ( struct in_addr ),
631         .rx = ipv4_rx,
632         .ntoa = ipv4_ntoa,
633 };
634
635 /** IPv4 TCPIP net protocol */
636 struct tcpip_net_protocol ipv4_tcpip_protocol __tcpip_net_protocol = {
637         .name = "IPv4",
638         .sa_family = AF_INET,
639         .header_len = sizeof ( struct iphdr ),
640         .tx = ipv4_tx,
641         .netdev = ipv4_netdev,
642 };
643
644 /** IPv4 ARP protocol */
645 struct arp_net_protocol ipv4_arp_protocol __arp_net_protocol = {
646         .net_protocol = &ipv4_protocol,
647         .check = ipv4_arp_check,
648 };
649
650 /** IPv4 socket address converter */
651 struct sockaddr_converter ipv4_sockaddr_converter __sockaddr_converter = {
652         .family = AF_INET,
653         .ntoa = ipv4_sock_ntoa,
654         .aton = ipv4_sock_aton,
655 };
656
657 /******************************************************************************
658  *
659  * Settings
660  *
661  ******************************************************************************
662  */
663
664 /**
665  * Parse IPv4 address setting value
666  *
667  * @v type              Setting type
668  * @v value             Formatted setting value
669  * @v buf               Buffer to contain raw value
670  * @v len               Length of buffer
671  * @ret len             Length of raw value, or negative error
672  */
673 int parse_ipv4_setting ( const struct setting_type *type __unused,
674                          const char *value, void *buf, size_t len ) {
675         struct in_addr ipv4;
676
677         /* Parse IPv4 address */
678         if ( inet_aton ( value, &ipv4 ) == 0 )
679                 return -EINVAL;
680
681         /* Copy to buffer */
682         if ( len > sizeof ( ipv4 ) )
683                 len = sizeof ( ipv4 );
684         memcpy ( buf, &ipv4, len );
685
686         return ( sizeof ( ipv4 ) );
687 }
688
689 /**
690  * Format IPv4 address setting value
691  *
692  * @v type              Setting type
693  * @v raw               Raw setting value
694  * @v raw_len           Length of raw setting value
695  * @v buf               Buffer to contain formatted value
696  * @v len               Length of buffer
697  * @ret len             Length of formatted value, or negative error
698  */
699 int format_ipv4_setting ( const struct setting_type *type __unused,
700                           const void *raw, size_t raw_len, char *buf,
701                           size_t len ) {
702         const struct in_addr *ipv4 = raw;
703
704         if ( raw_len < sizeof ( *ipv4 ) )
705                 return -EINVAL;
706         return snprintf ( buf, len, "%s", inet_ntoa ( *ipv4 ) );
707 }
708
709 /** IPv4 address setting */
710 const struct setting ip_setting __setting ( SETTING_IP, ip ) = {
711         .name = "ip",
712         .description = "IP address",
713         .tag = DHCP_EB_YIADDR,
714         .type = &setting_type_ipv4,
715 };
716
717 /** IPv4 subnet mask setting */
718 const struct setting netmask_setting __setting ( SETTING_IP, netmask ) = {
719         .name = "netmask",
720         .description = "Subnet mask",
721         .tag = DHCP_SUBNET_MASK,
722         .type = &setting_type_ipv4,
723 };
724
725 /** Default gateway setting */
726 const struct setting gateway_setting __setting ( SETTING_IP, gateway ) = {
727         .name = "gateway",
728         .description = "Default gateway",
729         .tag = DHCP_ROUTERS,
730         .type = &setting_type_ipv4,
731 };
732
733 /**
734  * Create IPv4 routing table based on configured settings
735  *
736  * @ret rc              Return status code
737  */
738 static int ipv4_create_routes ( void ) {
739         struct ipv4_miniroute *miniroute;
740         struct ipv4_miniroute *tmp;
741         struct net_device *netdev;
742         struct settings *settings;
743         struct in_addr address = { 0 };
744         struct in_addr netmask = { 0 };
745         struct in_addr gateway = { 0 };
746
747         /* Delete all existing routes */
748         list_for_each_entry_safe ( miniroute, tmp, &ipv4_miniroutes, list )
749                 del_ipv4_miniroute ( miniroute );
750
751         /* Create a route for each configured network device */
752         for_each_netdev ( netdev ) {
753                 settings = netdev_settings ( netdev );
754                 /* Get IPv4 address */
755                 address.s_addr = 0;
756                 fetch_ipv4_setting ( settings, &ip_setting, &address );
757                 if ( ! address.s_addr )
758                         continue;
759                 /* Get subnet mask */
760                 fetch_ipv4_setting ( settings, &netmask_setting, &netmask );
761                 /* Calculate default netmask, if necessary */
762                 if ( ! netmask.s_addr ) {
763                         if ( IN_CLASSA ( ntohl ( address.s_addr ) ) ) {
764                                 netmask.s_addr = htonl ( IN_CLASSA_NET );
765                         } else if ( IN_CLASSB ( ntohl ( address.s_addr ) ) ) {
766                                 netmask.s_addr = htonl ( IN_CLASSB_NET );
767                         } else if ( IN_CLASSC ( ntohl ( address.s_addr ) ) ) {
768                                 netmask.s_addr = htonl ( IN_CLASSC_NET );
769                         }
770                 }
771                 /* Get default gateway, if present */
772                 fetch_ipv4_setting ( settings, &gateway_setting, &gateway );
773                 /* Configure route */
774                 miniroute = add_ipv4_miniroute ( netdev, address,
775                                                  netmask, gateway );
776                 if ( ! miniroute )
777                         return -ENOMEM;
778         }
779
780         return 0;
781 }
782
783 /** IPv4 settings applicator */
784 struct settings_applicator ipv4_settings_applicator __settings_applicator = {
785         .apply = ipv4_create_routes,
786 };
787
788 /* Drag in ICMPv4 */
789 REQUIRE_OBJECT ( icmpv4 );