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