00001 #include <string.h>
00002 #include <stdint.h>
00003 #include <stdlib.h>
00004 #include <stdio.h>
00005 #include <errno.h>
00006 #include <byteswap.h>
00007 #include <gpxe/list.h>
00008 #include <gpxe/in.h>
00009 #include <gpxe/arp.h>
00010 #include <gpxe/if_ether.h>
00011 #include <gpxe/iobuf.h>
00012 #include <gpxe/netdevice.h>
00013 #include <gpxe/ip.h>
00014 #include <gpxe/tcpip.h>
00015 #include <gpxe/dhcp.h>
00016 #include <gpxe/settings.h>
00017
00018
00019
00020
00021
00022
00023
00024 FILE_LICENCE ( GPL2_OR_LATER );
00025
00026
00027 static uint16_t next_ident = 0;
00028
00029 struct net_protocol ipv4_protocol;
00030
00031
00032 struct list_head ipv4_miniroutes = LIST_HEAD_INIT ( ipv4_miniroutes );
00033
00034
00035 static LIST_HEAD ( frag_buffers );
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 static struct ipv4_miniroute * __malloc
00047 add_ipv4_miniroute ( struct net_device *netdev, struct in_addr address,
00048 struct in_addr netmask, struct in_addr gateway ) {
00049 struct ipv4_miniroute *miniroute;
00050
00051 DBG ( "IPv4 add %s", inet_ntoa ( address ) );
00052 DBG ( "/%s ", inet_ntoa ( netmask ) );
00053 if ( gateway.s_addr )
00054 DBG ( "gw %s ", inet_ntoa ( gateway ) );
00055 DBG ( "via %s\n", netdev->name );
00056
00057
00058 miniroute = malloc ( sizeof ( *miniroute ) );
00059 if ( ! miniroute ) {
00060 DBG ( "IPv4 could not add miniroute\n" );
00061 return NULL;
00062 }
00063
00064
00065 miniroute->netdev = netdev_get ( netdev );
00066 miniroute->address = address;
00067 miniroute->netmask = netmask;
00068 miniroute->gateway = gateway;
00069
00070
00071
00072
00073 if ( gateway.s_addr ) {
00074 list_add_tail ( &miniroute->list, &ipv4_miniroutes );
00075 } else {
00076 list_add ( &miniroute->list, &ipv4_miniroutes );
00077 }
00078
00079 return miniroute;
00080 }
00081
00082
00083
00084
00085
00086
00087 static void del_ipv4_miniroute ( struct ipv4_miniroute *miniroute ) {
00088
00089 DBG ( "IPv4 del %s", inet_ntoa ( miniroute->address ) );
00090 DBG ( "/%s ", inet_ntoa ( miniroute->netmask ) );
00091 if ( miniroute->gateway.s_addr )
00092 DBG ( "gw %s ", inet_ntoa ( miniroute->gateway ) );
00093 DBG ( "via %s\n", miniroute->netdev->name );
00094
00095 netdev_put ( miniroute->netdev );
00096 list_del ( &miniroute->list );
00097 free ( miniroute );
00098 }
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110 static struct ipv4_miniroute * ipv4_route ( struct in_addr *dest ) {
00111 struct ipv4_miniroute *miniroute;
00112 int local;
00113 int has_gw;
00114
00115
00116 if ( dest->s_addr == INADDR_BROADCAST )
00117 return NULL;
00118
00119
00120 list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
00121 if ( ! netdev_is_open ( miniroute->netdev ) )
00122 continue;
00123 local = ( ( ( dest->s_addr ^ miniroute->address.s_addr )
00124 & miniroute->netmask.s_addr ) == 0 );
00125 has_gw = ( miniroute->gateway.s_addr );
00126 if ( local || has_gw ) {
00127 if ( ! local )
00128 *dest = miniroute->gateway;
00129 return miniroute;
00130 }
00131 }
00132
00133 return NULL;
00134 }
00135
00136
00137
00138
00139
00140
00141
00142 static void ipv4_frag_expired ( struct retry_timer *timer __unused,
00143 int over ) {
00144 if ( over ) {
00145 DBG ( "Fragment reassembly timeout" );
00146
00147 }
00148 }
00149
00150
00151
00152
00153
00154
00155 static void free_fragbuf ( struct frag_buffer *fragbuf ) {
00156 free ( fragbuf );
00157 }
00158
00159
00160
00161
00162
00163
00164
00165 static struct io_buffer * ipv4_reassemble ( struct io_buffer * iobuf ) {
00166 struct iphdr *iphdr = iobuf->data;
00167 struct frag_buffer *fragbuf;
00168
00169
00170
00171
00172 list_for_each_entry ( fragbuf, &frag_buffers, list ) {
00173 if ( fragbuf->ident == iphdr->ident &&
00174 fragbuf->src.s_addr == iphdr->src.s_addr ) {
00175
00176
00177
00178
00179
00180
00181
00182 if ( iob_len ( fragbuf->frag_iob ) ==
00183 ( iphdr->frags & IP_MASK_OFFSET ) ) {
00184
00185
00186
00187
00188 iob_pull ( iobuf, sizeof ( *iphdr ) );
00189 memcpy ( iob_put ( fragbuf->frag_iob,
00190 iob_len ( iobuf ) ),
00191 iobuf->data, iob_len ( iobuf ) );
00192 free_iob ( iobuf );
00193
00194
00195 if ( ! ( iphdr->frags & IP_MASK_MOREFRAGS ) ) {
00196 iobuf = fragbuf->frag_iob;
00197 free_fragbuf ( fragbuf );
00198 return iobuf;
00199 }
00200
00201 } else {
00202
00203 free_fragbuf ( fragbuf );
00204 free_iob ( iobuf );
00205 }
00206 return NULL;
00207 }
00208 }
00209
00210
00211 if ( iphdr->frags & IP_MASK_MOREFRAGS &&
00212 ( ( iphdr->frags & IP_MASK_OFFSET ) == 0 ) ) {
00213
00214
00215 fragbuf = ( struct frag_buffer* ) malloc ( sizeof( *fragbuf ) );
00216 fragbuf->ident = iphdr->ident;
00217 fragbuf->src = iphdr->src;
00218
00219
00220 fragbuf->frag_iob = alloc_iob ( IP_FRAG_IOB_SIZE );
00221 iob_pull ( iobuf, sizeof ( *iphdr ) );
00222 memcpy ( iob_put ( fragbuf->frag_iob, iob_len ( iobuf ) ),
00223 iobuf->data, iob_len ( iobuf ) );
00224 free_iob ( iobuf );
00225
00226
00227 fragbuf->frag_timer.timeout = IP_FRAG_TIMEOUT;
00228 fragbuf->frag_timer.expired = ipv4_frag_expired;
00229 start_timer ( &fragbuf->frag_timer );
00230
00231
00232 list_add ( &fragbuf->list, &frag_buffers );
00233 }
00234
00235 return NULL;
00236 }
00237
00238
00239
00240
00241
00242
00243
00244
00245 static uint16_t ipv4_pshdr_chksum ( struct io_buffer *iobuf, uint16_t csum ) {
00246 struct ipv4_pseudo_header pshdr;
00247 struct iphdr *iphdr = iobuf->data;
00248 size_t hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 );
00249
00250
00251 pshdr.src = iphdr->src;
00252 pshdr.dest = iphdr->dest;
00253 pshdr.zero_padding = 0x00;
00254 pshdr.protocol = iphdr->protocol;
00255 pshdr.len = htons ( iob_len ( iobuf ) - hdrlen );
00256
00257
00258 return tcpip_continue_chksum ( csum, &pshdr, sizeof ( pshdr ) );
00259 }
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270 static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src,
00271 struct net_device *netdev, uint8_t *ll_dest ) {
00272 struct ll_protocol *ll_protocol = netdev->ll_protocol;
00273
00274 if ( dest.s_addr == INADDR_BROADCAST ) {
00275
00276 memcpy ( ll_dest, netdev->ll_broadcast,
00277 ll_protocol->ll_addr_len );
00278 return 0;
00279 } else if ( IN_MULTICAST ( ntohl ( dest.s_addr ) ) ) {
00280 return ll_protocol->mc_hash ( AF_INET, &dest, ll_dest );
00281 } else {
00282
00283 return arp_resolve ( netdev, &ipv4_protocol, &dest,
00284 &src, ll_dest );
00285 }
00286 }
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301 static int ipv4_tx ( struct io_buffer *iobuf,
00302 struct tcpip_protocol *tcpip_protocol,
00303 struct sockaddr_tcpip *st_src,
00304 struct sockaddr_tcpip *st_dest,
00305 struct net_device *netdev,
00306 uint16_t *trans_csum ) {
00307 struct iphdr *iphdr = iob_push ( iobuf, sizeof ( *iphdr ) );
00308 struct sockaddr_in *sin_src = ( ( struct sockaddr_in * ) st_src );
00309 struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest );
00310 struct ipv4_miniroute *miniroute;
00311 struct in_addr next_hop;
00312 uint8_t ll_dest[MAX_LL_ADDR_LEN];
00313 int rc;
00314
00315
00316 memset ( iphdr, 0, sizeof ( *iphdr ) );
00317 iphdr->verhdrlen = ( IP_VER | ( sizeof ( *iphdr ) / 4 ) );
00318 iphdr->service = IP_TOS;
00319 iphdr->len = htons ( iob_len ( iobuf ) );
00320 iphdr->ident = htons ( ++next_ident );
00321 iphdr->ttl = IP_TTL;
00322 iphdr->protocol = tcpip_protocol->tcpip_proto;
00323 iphdr->dest = sin_dest->sin_addr;
00324
00325
00326 next_hop = iphdr->dest;
00327 if ( sin_src )
00328 iphdr->src = sin_src->sin_addr;
00329 if ( ( next_hop.s_addr != INADDR_BROADCAST ) &&
00330 ( ! IN_MULTICAST ( ntohl ( next_hop.s_addr ) ) ) &&
00331 ( ( miniroute = ipv4_route ( &next_hop ) ) != NULL ) ) {
00332 iphdr->src = miniroute->address;
00333 netdev = miniroute->netdev;
00334 }
00335 if ( ! netdev ) {
00336 DBG ( "IPv4 has no route to %s\n", inet_ntoa ( iphdr->dest ) );
00337 rc = -ENETUNREACH;
00338 goto err;
00339 }
00340
00341
00342 if ( ( rc = ipv4_ll_addr ( next_hop, iphdr->src, netdev,
00343 ll_dest ) ) != 0 ) {
00344 DBG ( "IPv4 has no link-layer address for %s: %s\n",
00345 inet_ntoa ( next_hop ), strerror ( rc ) );
00346 goto err;
00347 }
00348
00349
00350 if ( trans_csum )
00351 *trans_csum = ipv4_pshdr_chksum ( iobuf, *trans_csum );
00352 iphdr->chksum = tcpip_chksum ( iphdr, sizeof ( *iphdr ) );
00353
00354
00355 DBG ( "IPv4 TX %s->", inet_ntoa ( iphdr->src ) );
00356 DBG ( "%s len %d proto %d id %04x csum %04x\n",
00357 inet_ntoa ( iphdr->dest ), ntohs ( iphdr->len ), iphdr->protocol,
00358 ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
00359
00360
00361 if ( ( rc = net_tx ( iobuf, netdev, &ipv4_protocol, ll_dest ) ) != 0 ) {
00362 DBG ( "IPv4 could not transmit packet via %s: %s\n",
00363 netdev->name, strerror ( rc ) );
00364 return rc;
00365 }
00366
00367 return 0;
00368
00369 err:
00370 free_iob ( iobuf );
00371 return rc;
00372 }
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384 static int ipv4_rx ( struct io_buffer *iobuf, struct net_device *netdev __unused,
00385 const void *ll_source __unused ) {
00386 struct iphdr *iphdr = iobuf->data;
00387 size_t hdrlen;
00388 size_t len;
00389 union {
00390 struct sockaddr_in sin;
00391 struct sockaddr_tcpip st;
00392 } src, dest;
00393 uint16_t csum;
00394 uint16_t pshdr_csum;
00395 int rc;
00396
00397
00398 if ( iob_len ( iobuf ) < sizeof ( *iphdr ) ) {
00399 DBG ( "IPv4 packet too short at %zd bytes (min %zd bytes)\n",
00400 iob_len ( iobuf ), sizeof ( *iphdr ) );
00401 goto err;
00402 }
00403 if ( ( iphdr->verhdrlen & IP_MASK_VER ) != IP_VER ) {
00404 DBG ( "IPv4 version %#02x not supported\n", iphdr->verhdrlen );
00405 goto err;
00406 }
00407 hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 );
00408 if ( hdrlen < sizeof ( *iphdr ) ) {
00409 DBG ( "IPv4 header too short at %zd bytes (min %zd bytes)\n",
00410 hdrlen, sizeof ( *iphdr ) );
00411 goto err;
00412 }
00413 if ( hdrlen > iob_len ( iobuf ) ) {
00414 DBG ( "IPv4 header too long at %zd bytes "
00415 "(packet is %zd bytes)\n", hdrlen, iob_len ( iobuf ) );
00416 goto err;
00417 }
00418 if ( ( csum = tcpip_chksum ( iphdr, hdrlen ) ) != 0 ) {
00419 DBG ( "IPv4 checksum incorrect (is %04x including checksum "
00420 "field, should be 0000)\n", csum );
00421 goto err;
00422 }
00423 len = ntohs ( iphdr->len );
00424 if ( len < hdrlen ) {
00425 DBG ( "IPv4 length too short at %zd bytes "
00426 "(header is %zd bytes)\n", len, hdrlen );
00427 goto err;
00428 }
00429 if ( len > iob_len ( iobuf ) ) {
00430 DBG ( "IPv4 length too long at %zd bytes "
00431 "(packet is %zd bytes)\n", len, iob_len ( iobuf ) );
00432 goto err;
00433 }
00434
00435
00436 DBG ( "IPv4 RX %s<-", inet_ntoa ( iphdr->dest ) );
00437 DBG ( "%s len %d proto %d id %04x csum %04x\n",
00438 inet_ntoa ( iphdr->src ), ntohs ( iphdr->len ), iphdr->protocol,
00439 ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
00440
00441
00442
00443
00444 iob_unput ( iobuf, ( iob_len ( iobuf ) - len ) );
00445 pshdr_csum = ipv4_pshdr_chksum ( iobuf, TCPIP_EMPTY_CSUM );
00446 iob_pull ( iobuf, hdrlen );
00447
00448
00449 if ( ( iphdr->frags & htons ( IP_MASK_MOREFRAGS ) ) ||
00450 ( ( iphdr->frags & htons ( IP_MASK_OFFSET ) ) != 0 ) ) {
00451
00452
00453
00454 iobuf = ipv4_reassemble ( iobuf );
00455 if ( ! iobuf )
00456 return 0;
00457 }
00458
00459
00460 memset ( &src, 0, sizeof ( src ) );
00461 src.sin.sin_family = AF_INET;
00462 src.sin.sin_addr = iphdr->src;
00463 memset ( &dest, 0, sizeof ( dest ) );
00464 dest.sin.sin_family = AF_INET;
00465 dest.sin.sin_addr = iphdr->dest;
00466 if ( ( rc = tcpip_rx ( iobuf, iphdr->protocol, &src.st,
00467 &dest.st, pshdr_csum ) ) != 0 ) {
00468 DBG ( "IPv4 received packet rejected by stack: %s\n",
00469 strerror ( rc ) );
00470 return rc;
00471 }
00472
00473 return 0;
00474
00475 err:
00476 free_iob ( iobuf );
00477 return -EINVAL;
00478 }
00479
00480
00481
00482
00483
00484
00485
00486
00487 static int ipv4_arp_check ( struct net_device *netdev, const void *net_addr ) {
00488 const struct in_addr *address = net_addr;
00489 struct ipv4_miniroute *miniroute;
00490
00491 list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
00492 if ( ( miniroute->netdev == netdev ) &&
00493 ( miniroute->address.s_addr == address->s_addr ) ) {
00494
00495 return 0;
00496 }
00497 }
00498 return -ENOENT;
00499 }
00500
00501
00502
00503
00504
00505
00506
00507 char * inet_ntoa ( struct in_addr in ) {
00508 static char buf[16];
00509 uint8_t *bytes = ( uint8_t * ) ∈
00510
00511 sprintf ( buf, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3] );
00512 return buf;
00513 }
00514
00515
00516
00517
00518
00519
00520
00521
00522 static const char * ipv4_ntoa ( const void *net_addr ) {
00523 return inet_ntoa ( * ( ( struct in_addr * ) net_addr ) );
00524 }
00525
00526
00527 struct net_protocol ipv4_protocol __net_protocol = {
00528 .name = "IP",
00529 .net_proto = htons ( ETH_P_IP ),
00530 .net_addr_len = sizeof ( struct in_addr ),
00531 .rx = ipv4_rx,
00532 .ntoa = ipv4_ntoa,
00533 };
00534
00535
00536 struct tcpip_net_protocol ipv4_tcpip_protocol __tcpip_net_protocol = {
00537 .name = "IPv4",
00538 .sa_family = AF_INET,
00539 .tx = ipv4_tx,
00540 };
00541
00542
00543 struct arp_net_protocol ipv4_arp_protocol __arp_net_protocol = {
00544 .net_protocol = &ipv4_protocol,
00545 .check = ipv4_arp_check,
00546 };
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556 struct setting ip_setting __setting = {
00557 .name = "ip",
00558 .description = "IPv4 address",
00559 .tag = DHCP_EB_YIADDR,
00560 .type = &setting_type_ipv4,
00561 };
00562
00563
00564 struct setting netmask_setting __setting = {
00565 .name = "netmask",
00566 .description = "IPv4 subnet mask",
00567 .tag = DHCP_SUBNET_MASK,
00568 .type = &setting_type_ipv4,
00569 };
00570
00571
00572 struct setting gateway_setting __setting = {
00573 .name = "gateway",
00574 .description = "Default gateway",
00575 .tag = DHCP_ROUTERS,
00576 .type = &setting_type_ipv4,
00577 };
00578
00579
00580
00581
00582
00583
00584 static int ipv4_create_routes ( void ) {
00585 struct ipv4_miniroute *miniroute;
00586 struct ipv4_miniroute *tmp;
00587 struct net_device *netdev;
00588 struct settings *settings;
00589 struct in_addr address = { 0 };
00590 struct in_addr netmask = { 0 };
00591 struct in_addr gateway = { 0 };
00592
00593
00594 list_for_each_entry_safe ( miniroute, tmp, &ipv4_miniroutes, list )
00595 del_ipv4_miniroute ( miniroute );
00596
00597
00598 for_each_netdev ( netdev ) {
00599 settings = netdev_settings ( netdev );
00600
00601 address.s_addr = 0;
00602 fetch_ipv4_setting ( settings, &ip_setting, &address );
00603 if ( ! address.s_addr )
00604 continue;
00605
00606 fetch_ipv4_setting ( settings, &netmask_setting, &netmask );
00607
00608 if ( ! netmask.s_addr ) {
00609 if ( IN_CLASSA ( ntohl ( address.s_addr ) ) ) {
00610 netmask.s_addr = htonl ( IN_CLASSA_NET );
00611 } else if ( IN_CLASSB ( ntohl ( address.s_addr ) ) ) {
00612 netmask.s_addr = htonl ( IN_CLASSB_NET );
00613 } else if ( IN_CLASSC ( ntohl ( address.s_addr ) ) ) {
00614 netmask.s_addr = htonl ( IN_CLASSC_NET );
00615 }
00616 }
00617
00618 fetch_ipv4_setting ( settings, &gateway_setting, &gateway );
00619
00620 miniroute = add_ipv4_miniroute ( netdev, address,
00621 netmask, gateway );
00622 if ( ! miniroute )
00623 return -ENOMEM;
00624 }
00625
00626 return 0;
00627 }
00628
00629
00630 struct settings_applicator ipv4_settings_applicator __settings_applicator = {
00631 .apply = ipv4_create_routes,
00632 };
00633
00634
00635 REQUIRE_OBJECT ( icmp );