10 #include <ipxe/if_ether.h>
11 #include <ipxe/iobuf.h>
12 #include <ipxe/netdevice.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>
27 FILE_LICENCE ( GPL2_OR_LATER );
29 /* Unique IP datagram identification number (high byte) */
30 static uint8_t next_ident_high = 0;
32 /** List of IPv4 miniroutes */
33 struct list_head ipv4_miniroutes = LIST_HEAD_INIT ( ipv4_miniroutes );
35 /** IPv4 statistics */
36 static struct ip_statistics ipv4_stats;
38 /** IPv4 statistics family */
39 struct ip_statistics_family
40 ipv4_stats_family __ip_statistics_family ( IP_STATISTICS_IPV4 ) = {
45 /** Transmit profiler */
46 static struct profiler ipv4_tx_profiler __profiler = { .name = "ipv4.tx" };
48 /** Receive profiler */
49 static struct profiler ipv4_rx_profiler __profiler = { .name = "ipv4.rx" };
52 * Add IPv4 minirouting table entry
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
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;
65 DBGC ( netdev, "IPv4 add %s", inet_ntoa ( address ) );
66 DBGC ( netdev, "/%s ", inet_ntoa ( netmask ) );
68 DBGC ( netdev, "gw %s ", inet_ntoa ( gateway ) );
69 DBGC ( netdev, "via %s\n", netdev->name );
71 /* Allocate and populate miniroute structure */
72 miniroute = malloc ( sizeof ( *miniroute ) );
74 DBGC ( netdev, "IPv4 could not add miniroute\n" );
78 /* Record routing information */
79 miniroute->netdev = netdev_get ( netdev );
80 miniroute->address = address;
81 miniroute->netmask = netmask;
82 miniroute->gateway = gateway;
84 /* Add to end of list if we have a gateway, otherwise
87 if ( gateway.s_addr ) {
88 list_add_tail ( &miniroute->list, &ipv4_miniroutes );
90 list_add ( &miniroute->list, &ipv4_miniroutes );
97 * Delete IPv4 minirouting table entry
99 * @v miniroute Routing table entry
101 static void del_ipv4_miniroute ( struct ipv4_miniroute *miniroute ) {
102 struct net_device *netdev = miniroute->netdev;
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 );
110 netdev_put ( miniroute->netdev );
111 list_del ( &miniroute->list );
116 * Perform IPv4 routing
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
122 * If the route requires use of a gateway, the next hop destination
123 * address will be overwritten with the gateway address.
125 static struct ipv4_miniroute * ipv4_route ( struct in_addr *dest ) {
126 struct ipv4_miniroute *miniroute;
130 /* Find first usable route in routing table */
131 list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
132 if ( ! netdev_is_open ( miniroute->netdev ) )
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 ) {
139 *dest = miniroute->gateway;
148 * Determine transmitting network device
150 * @v st_dest Destination network-layer address
151 * @ret netdev Transmitting network device, or NULL
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;
158 /* Find routing table entry */
159 miniroute = ipv4_route ( &dest );
163 return miniroute->netdev;
167 * Check if IPv4 fragment matches fragment reassembly buffer
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
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;
180 return ( ( iphdr->src.s_addr == frag_iphdr->src.s_addr ) &&
181 ( iphdr->ident == frag_iphdr->ident ) );
185 * Get IPv4 fragment offset
187 * @v iobuf I/O buffer
188 * @v hdrlen Length of non-fragmentable potion of I/O buffer
191 static size_t ipv4_fragment_offset ( struct io_buffer *iobuf,
192 size_t hdrlen __unused ) {
193 struct iphdr *iphdr = iobuf->data;
195 return ( ( ntohs ( iphdr->frags ) & IP_MASK_OFFSET ) << 3 );
199 * Check if more fragments exist
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
205 static int ipv4_more_fragments ( struct io_buffer *iobuf,
206 size_t hdrlen __unused ) {
207 struct iphdr *iphdr = iobuf->data;
209 return ( iphdr->frags & htons ( IP_MASK_MOREFRAGS ) );
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,
222 * Add IPv4 pseudo-header checksum to existing checksum
224 * @v iobuf I/O buffer
225 * @v csum Existing checksum
226 * @ret csum Updated checksum
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 );
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 );
240 /* Update the checksum value */
241 return tcpip_continue_chksum ( csum, &pshdr, sizeof ( pshdr ) );
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
255 * This function expects a transport-layer segment and prepends the IP header
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];
273 /* Start profiling */
274 profile_start ( &ipv4_tx_profiler );
276 /* Update statistics */
277 ipv4_stats.out_requests++;
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 ) );
285 iphdr->protocol = tcpip_protocol->tcpip_proto;
286 iphdr->dest = sin_dest->sin_addr;
288 /* Use routing table to identify next hop and transmitting netdev */
289 next_hop = iphdr->dest;
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;
300 DBGC ( sin_dest->sin_addr, "IPv4 has no route to %s\n",
301 inet_ntoa ( iphdr->dest ) );
302 ipv4_stats.out_no_routes++;
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.
311 iphdr->ident = htons ( ( (++next_ident_high) << 8 ) |
312 ( ( netdev->rx_stats.bad & 0xf ) << 4 ) |
313 ( ( netdev->rx_stats.good & 0xf ) << 0 ) );
315 /* Fix up checksums */
317 *trans_csum = ipv4_pshdr_chksum ( iobuf, *trans_csum );
318 iphdr->chksum = tcpip_chksum ( iphdr, sizeof ( *iphdr ) );
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 ) );
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 ) );
342 ll_dest = ll_dest_buf;
344 /* Unicast address */
348 /* Update statistics */
349 ipv4_stats.out_transmits++;
350 ipv4_stats.out_octets += iob_len ( iobuf );
352 /* Hand off to link layer (via ARP if applicable) */
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 ) );
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 ) );
371 profile_stop ( &ipv4_tx_profiler );
380 * Check if network device has any IPv4 address
382 * @v netdev Network device
383 * @ret has_any_addr Network device has any IPv4 address
385 int ipv4_has_any_addr ( struct net_device *netdev ) {
386 struct ipv4_miniroute *miniroute;
388 list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
389 if ( miniroute->netdev == netdev )
396 * Check if network device has a specific IPv4 address
398 * @v netdev Network device
399 * @v addr IPv4 address
400 * @ret has_addr Network device has this IPv4 address
402 static int ipv4_has_addr ( struct net_device *netdev, struct in_addr addr ) {
403 struct ipv4_miniroute *miniroute;
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 */
416 * Process incoming packets
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
425 * This function expects an IP4 network datagram. It processes the headers
426 * and sends it to the transport layer.
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;
437 struct sockaddr_in sin;
438 struct sockaddr_tcpip st;
444 /* Start profiling */
445 profile_start ( &ipv4_rx_profiler );
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++;
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 ) );
462 if ( ( iphdr->verhdrlen & IP_MASK_VER ) != IP_VER ) {
463 DBGC ( iphdr->src, "IPv4 version %#02x not supported\n",
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 ) );
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 ) );
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 );
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 );
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++;
496 /* Truncate packet to correct length */
497 iob_unput ( iobuf, ( iob_len ( iobuf ) - len ) );
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 ) );
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++;
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.
520 iobuf = fragment_reassemble ( &ipv4_reassembler, iobuf,
527 /* Construct socket addresses, calculate pseudo-header
528 * checksum, and hand off to transport layer
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 ) );
545 profile_stop ( &ipv4_rx_profiler );
549 ipv4_stats.in_hdr_errors++;
556 * Check existence of IPv4 address for ARP
558 * @v netdev Network device
559 * @v net_addr Network-layer address
560 * @ret rc Return status code
562 static int ipv4_arp_check ( struct net_device *netdev, const void *net_addr ) {
563 const struct in_addr *address = net_addr;
565 if ( ipv4_has_addr ( netdev, *address ) )
572 * Convert IPv4 address to dotted-quad notation
575 * @ret string IP address in dotted-quad notation
577 char * inet_ntoa ( struct in_addr in ) {
578 static char buf[16]; /* "xxx.xxx.xxx.xxx" */
579 uint8_t *bytes = ( uint8_t * ) ∈
581 sprintf ( buf, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3] );
586 * Transcribe IP address
588 * @v net_addr IP address
589 * @ret string IP address in dotted-quad notation
592 static const char * ipv4_ntoa ( const void *net_addr ) {
593 return inet_ntoa ( * ( ( struct in_addr * ) net_addr ) );
597 * Transcribe IPv4 socket address
599 * @v sa Socket address
600 * @ret string Socket address in standard notation
602 static const char * ipv4_sock_ntoa ( struct sockaddr *sa ) {
603 struct sockaddr_in *sin = ( ( struct sockaddr_in * ) sa );
605 return inet_ntoa ( sin->sin_addr );
609 * Parse IPv4 socket address
611 * @v string Socket address string
612 * @v sa Socket address to fill in
613 * @ret rc Return status code
615 static int ipv4_sock_aton ( const char *string, struct sockaddr *sa ) {
616 struct sockaddr_in *sin = ( ( struct sockaddr_in * ) sa );
619 if ( inet_aton ( string, &in ) ) {
627 struct net_protocol ipv4_protocol __net_protocol = {
629 .net_proto = htons ( ETH_P_IP ),
630 .net_addr_len = sizeof ( struct in_addr ),
635 /** IPv4 TCPIP net protocol */
636 struct tcpip_net_protocol ipv4_tcpip_protocol __tcpip_net_protocol = {
638 .sa_family = AF_INET,
639 .header_len = sizeof ( struct iphdr ),
641 .netdev = ipv4_netdev,
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,
650 /** IPv4 socket address converter */
651 struct sockaddr_converter ipv4_sockaddr_converter __sockaddr_converter = {
653 .ntoa = ipv4_sock_ntoa,
654 .aton = ipv4_sock_aton,
657 /******************************************************************************
661 ******************************************************************************
665 * Parse IPv4 address setting value
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
673 int parse_ipv4_setting ( const struct setting_type *type __unused,
674 const char *value, void *buf, size_t len ) {
677 /* Parse IPv4 address */
678 if ( inet_aton ( value, &ipv4 ) == 0 )
682 if ( len > sizeof ( ipv4 ) )
683 len = sizeof ( ipv4 );
684 memcpy ( buf, &ipv4, len );
686 return ( sizeof ( ipv4 ) );
690 * Format IPv4 address setting value
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
699 int format_ipv4_setting ( const struct setting_type *type __unused,
700 const void *raw, size_t raw_len, char *buf,
702 const struct in_addr *ipv4 = raw;
704 if ( raw_len < sizeof ( *ipv4 ) )
706 return snprintf ( buf, len, "%s", inet_ntoa ( *ipv4 ) );
709 /** IPv4 address setting */
710 const struct setting ip_setting __setting ( SETTING_IP, ip ) = {
712 .description = "IP address",
713 .tag = DHCP_EB_YIADDR,
714 .type = &setting_type_ipv4,
717 /** IPv4 subnet mask setting */
718 const struct setting netmask_setting __setting ( SETTING_IP, netmask ) = {
720 .description = "Subnet mask",
721 .tag = DHCP_SUBNET_MASK,
722 .type = &setting_type_ipv4,
725 /** Default gateway setting */
726 const struct setting gateway_setting __setting ( SETTING_IP, gateway ) = {
728 .description = "Default gateway",
730 .type = &setting_type_ipv4,
734 * Create IPv4 routing table based on configured settings
736 * @ret rc Return status code
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 };
747 /* Delete all existing routes */
748 list_for_each_entry_safe ( miniroute, tmp, &ipv4_miniroutes, list )
749 del_ipv4_miniroute ( miniroute );
751 /* Create a route for each configured network device */
752 for_each_netdev ( netdev ) {
753 settings = netdev_settings ( netdev );
754 /* Get IPv4 address */
756 fetch_ipv4_setting ( settings, &ip_setting, &address );
757 if ( ! address.s_addr )
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 );
771 /* Get default gateway, if present */
772 fetch_ipv4_setting ( settings, &gateway_setting, &gateway );
773 /* Configure route */
774 miniroute = add_ipv4_miniroute ( netdev, address,
783 /** IPv4 settings applicator */
784 struct settings_applicator ipv4_settings_applicator __settings_applicator = {
785 .apply = ipv4_create_routes,
789 REQUIRE_OBJECT ( icmpv4 );