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