Changes in uspace/srv/net/dhcp/dhcp.c [947e2ef:5a324d99] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/net/dhcp/dhcp.c
r947e2ef r5a324d99 35 35 */ 36 36 37 #include <adt/list.h> 37 38 #include <bitops.h> 39 #include <errno.h> 40 #include <fibril_synch.h> 38 41 #include <inet/addr.h> 39 42 #include <inet/dnsr.h> 40 43 #include <inet/inetcfg.h> 44 #include <io/log.h> 41 45 #include <loc.h> 42 #include <net/in.h>43 #include <net/inet.h>44 #include <net/socket.h>45 46 #include <stdio.h> 46 47 #include <stdlib.h> 47 48 49 #include "dhcp.h" 48 50 #include "dhcp_std.h" 49 50 #define NAME "dhcp" 51 #include "transport.h" 52 53 enum { 54 /** In microseconds */ 55 dhcp_discover_timeout_val = 5 * 1000 * 1000, 56 /** In microseconds */ 57 dhcp_request_timeout_val = 1 * 1000 * 1000, 58 dhcp_discover_retries = 5, 59 dhcp_request_retries = 3 60 }; 51 61 52 62 #define MAX_MSG_SIZE 1024 53 54 static int transport_fd = -1;55 static inet_link_info_t link_info;56 63 static uint8_t msgbuf[MAX_MSG_SIZE]; 64 65 /** List of registered links (of dhcp_link_t) */ 66 static list_t dhcp_links; 67 68 static void dhcpsrv_discover_timeout(void *); 69 static void dhcpsrv_request_timeout(void *); 70 71 typedef enum { 72 ds_bound, 73 ds_fail, 74 ds_init, 75 ds_init_reboot, 76 ds_rebinding, 77 ds_renewing, 78 ds_requesting, 79 ds_selecting 80 } dhcp_state_t; 57 81 58 82 typedef struct { … … 69 93 } dhcp_offer_t; 70 94 95 typedef struct { 96 /** Link to dhcp_links list */ 97 link_t links; 98 /** Link service ID */ 99 service_id_t link_id; 100 /** Link info */ 101 inet_link_info_t link_info; 102 /** Transport */ 103 dhcp_transport_t dt; 104 /** Transport timeout */ 105 fibril_timer_t *timeout; 106 /** Number of retries */ 107 int retries_left; 108 /** Link state */ 109 dhcp_state_t state; 110 /** Last received offer */ 111 dhcp_offer_t offer; 112 } dhcp_link_t; 113 114 static void dhcpsrv_recv(void *, void *, size_t); 115 71 116 /** Decode subnet mask into subnet prefix length. */ 72 117 static int subnet_mask_decode(uint32_t mask, int *bits) … … 101 146 } 102 147 103 static int dhcp_send(void *msg, size_t size) 104 { 105 struct sockaddr_in addr; 106 int rc; 107 108 addr.sin_family = AF_INET; 109 addr.sin_port = htons(dhcp_server_port); 110 addr.sin_addr.s_addr = htonl(addr32_broadcast_all_hosts); 111 112 rc = sendto(transport_fd, msg, size, 0, 113 (struct sockaddr *)&addr, sizeof(addr)); 114 if (rc != EOK) { 115 printf("Sending failed\n"); 116 return rc; 117 } 118 119 return EOK; 120 } 121 122 static int dhcp_send_discover(void) 148 static int dhcp_send_discover(dhcp_link_t *dlink) 123 149 { 124 150 dhcp_hdr_t *hdr = (dhcp_hdr_t *)msgbuf; … … 132 158 hdr->flags = flag_broadcast; 133 159 134 addr48( link_info.mac_addr, hdr->chaddr);160 addr48(dlink->link_info.mac_addr, hdr->chaddr); 135 161 hdr->opt_magic = host2uint32_t_be(dhcp_opt_magic); 136 162 … … 140 166 opt[3] = opt_end; 141 167 142 return dhcp_send(msgbuf, sizeof(dhcp_hdr_t) + 4); 143 } 144 145 static int dhcp_recv_msg(void **rmsg, size_t *rsize) 146 { 147 struct sockaddr_in src_addr; 148 socklen_t src_addr_size; 149 size_t recv_size; 150 int rc; 151 152 src_addr_size = sizeof(src_addr); 153 rc = recvfrom(transport_fd, msgbuf, MAX_MSG_SIZE, 0, 154 (struct sockaddr *)&src_addr, &src_addr_size); 155 if (rc < 0) { 156 printf("recvfrom failed (%d)\n", rc); 157 return rc; 158 } 159 160 recv_size = (size_t)rc; 161 *rmsg = msgbuf; 162 *rsize = recv_size; 163 164 return EOK; 165 } 166 167 static int dhcp_send_request(dhcp_offer_t *offer) 168 return dhcp_send(&dlink->dt, msgbuf, sizeof(dhcp_hdr_t) + 4); 169 } 170 171 static int dhcp_send_request(dhcp_link_t *dlink, dhcp_offer_t *offer) 168 172 { 169 173 dhcp_hdr_t *hdr = (dhcp_hdr_t *)msgbuf; … … 178 182 hdr->flags = flag_broadcast; 179 183 hdr->ciaddr = host2uint32_t_be(offer->oaddr.addr); 180 addr48( link_info.mac_addr, hdr->chaddr);184 addr48(dlink->link_info.mac_addr, hdr->chaddr); 181 185 hdr->opt_magic = host2uint32_t_be(dhcp_opt_magic); 182 186 … … 203 207 opt[i++] = opt_end; 204 208 205 return dhcp_send( msgbuf, sizeof(dhcp_hdr_t) + i);206 } 207 208 static int dhcp_ recv_reply(void *msg, size_t size, dhcp_offer_t *offer)209 return dhcp_send(&dlink->dt, msgbuf, sizeof(dhcp_hdr_t) + i); 210 } 211 212 static int dhcp_parse_reply(void *msg, size_t size, dhcp_offer_t *offer) 209 213 { 210 214 dhcp_hdr_t *hdr = (dhcp_hdr_t *)msg; … … 222 226 size_t i; 223 227 224 printf("Receive reply\n");228 log_msg(LOG_DEFAULT, LVL_DEBUG, "Receive reply"); 225 229 memset(offer, 0, sizeof(*offer)); 226 230 227 yiaddr.family = AF_INET; 228 yiaddr.addr = uint32_t_be2host(hdr->yiaddr); 231 inet_addr_set(uint32_t_be2host(hdr->yiaddr), &yiaddr); 229 232 rc = inet_addr_format(&yiaddr, &saddr); 230 233 if (rc != EOK) 231 234 return rc; 232 235 233 printf("Your IP address: %s\n", saddr);236 log_msg(LOG_DEFAULT, LVL_DEBUG, "Your IP address: %s", saddr); 234 237 free(saddr); 235 238 236 siaddr.family = AF_INET; 237 siaddr.addr = uint32_t_be2host(hdr->siaddr); 239 inet_addr_set(uint32_t_be2host(hdr->siaddr), &siaddr); 238 240 rc = inet_addr_format(&siaddr, &saddr); 239 241 if (rc != EOK) 240 242 return rc; 241 243 242 printf("Next server IP address: %s\n", saddr);244 log_msg(LOG_DEFAULT, LVL_DEBUG, "Next server IP address: %s", saddr); 243 245 free(saddr); 244 246 245 giaddr.family = AF_INET; 246 giaddr.addr = uint32_t_be2host(hdr->giaddr); 247 inet_addr_set(uint32_t_be2host(hdr->giaddr), &giaddr); 247 248 rc = inet_addr_format(&giaddr, &saddr); 248 249 if (rc != EOK) 249 250 return rc; 250 251 251 printf("Relay agent IP address: %s\n", saddr);252 log_msg(LOG_DEFAULT, LVL_DEBUG, "Relay agent IP address: %s", saddr); 252 253 free(saddr); 253 254 254 offer->oaddr.family = AF_INET; 255 offer->oaddr.addr = yiaddr.addr; 255 inet_naddr_set(yiaddr.addr, 0, &offer->oaddr); 256 256 257 257 msgb = (uint8_t *)msg; … … 293 293 if (opt_len != 4) 294 294 return EINVAL; 295 offer->srv_addr.family = AF_INET;296 offer->srv_addr.addr = dhcp_uint32_decode(&msgb[i]);295 inet_addr_set(dhcp_uint32_decode(&msgb[i]), 296 &offer->srv_addr); 297 297 have_server_id = true; 298 298 break; … … 300 300 if (opt_len != 4) 301 301 return EINVAL; 302 offer->router.family = AF_INET;303 offer->router.addr = dhcp_uint32_decode(&msgb[i]);302 inet_addr_set(dhcp_uint32_decode(&msgb[i]), 303 &offer->router); 304 304 break; 305 305 case opt_dns_server: 306 306 if (opt_len != 4) 307 307 return EINVAL; 308 offer->dns_server.family = AF_INET;309 offer->dns_server.addr = dhcp_uint32_decode(&msgb[i]);308 inet_addr_set(dhcp_uint32_decode(&msgb[i]), 309 &offer->dns_server); 310 310 break; 311 311 case opt_end: … … 320 320 321 321 if (!have_server_id) { 322 printf("Missing server ID option.\n");322 log_msg(LOG_DEFAULT, LVL_ERROR, "Missing server ID option."); 323 323 return rc; 324 324 } 325 325 326 326 if (!have_subnet_mask) { 327 printf("Missing subnet mask option.\n");327 log_msg(LOG_DEFAULT, LVL_ERROR, "Missing subnet mask option."); 328 328 return rc; 329 329 } … … 333 333 return rc; 334 334 335 printf("Offered network address: %s\n", saddr);335 log_msg(LOG_DEFAULT, LVL_DEBUG, "Offered network address: %s", saddr); 336 336 free(saddr); 337 337 … … 341 341 return rc; 342 342 343 printf("Router address: %s\n", saddr);343 log_msg(LOG_DEFAULT, LVL_DEBUG, "Router address: %s", saddr); 344 344 free(saddr); 345 345 } … … 350 350 return rc; 351 351 352 printf("DNS server: %s\n", saddr);352 log_msg(LOG_DEFAULT, LVL_DEBUG, "DNS server: %s", saddr); 353 353 free(saddr); 354 354 } … … 367 367 &addr_id); 368 368 if (rc != EOK) { 369 printf("Error creating IP address %s (%d)\n", "dhcp4a", rc); 369 log_msg(LOG_DEFAULT, LVL_ERROR, 370 "Error creating IP address %s (%d)", "dhcp4a", rc); 370 371 return rc; 371 372 } 372 373 373 374 if (offer->router.addr != 0) { 374 defr.family = AF_INET; 375 defr.addr = 0; 376 defr.prefix = 0; 375 inet_naddr_set(0, 0, &defr); 377 376 378 377 rc = inetcfg_sroute_create("dhcpdef", &defr, &offer->router, &sroute_id); 379 378 if (rc != EOK) { 380 printf("Error creating default route %s (%d).\n", "dhcpdef",381 rc);379 log_msg(LOG_DEFAULT, LVL_ERROR, "Error creating " 380 "default route %s (%d).", "dhcpdef", rc); 382 381 return rc; 383 382 } … … 387 386 rc = dnsr_set_srvaddr(&offer->dns_server); 388 387 if (rc != EOK) { 389 printf("%s: Error setting nameserver address (%d))\n",390 NAME, rc);388 log_msg(LOG_DEFAULT, LVL_ERROR, "Error setting " 389 "nameserver address (%d))", rc); 391 390 return rc; 392 391 } … … 396 395 } 397 396 398 int main(int argc, char *argv[]) 399 { 400 int fd; 401 struct sockaddr_in laddr; 402 void *msg; 403 service_id_t iplink; 404 size_t msg_size; 397 void dhcpsrv_links_init(void) 398 { 399 list_initialize(&dhcp_links); 400 } 401 402 static dhcp_link_t *dhcpsrv_link_find(service_id_t link_id) 403 { 404 list_foreach(dhcp_links, links, dhcp_link_t, dlink) { 405 if (dlink->link_id == link_id) 406 return dlink; 407 } 408 409 return NULL; 410 } 411 412 static void dhcp_link_set_failed(dhcp_link_t *dlink) 413 { 414 log_msg(LOG_DEFAULT, LVL_NOTE, "Giving up on link %s", 415 dlink->link_info.name); 416 dlink->state = ds_fail; 417 } 418 419 int dhcpsrv_link_add(service_id_t link_id) 420 { 421 dhcp_link_t *dlink; 422 int rc; 423 424 log_msg(LOG_DEFAULT, LVL_DEBUG, "dhcpsrv_link_add(%zu)", link_id); 425 426 if (dhcpsrv_link_find(link_id) != NULL) { 427 log_msg(LOG_DEFAULT, LVL_NOTE, "Link %zu already added", 428 link_id); 429 return EEXIST; 430 } 431 432 dlink = calloc(1, sizeof(dhcp_link_t)); 433 if (dlink == NULL) 434 return ENOMEM; 435 436 dlink->link_id = link_id; 437 dlink->timeout = fibril_timer_create(); 438 if (dlink->timeout == NULL) { 439 rc = ENOMEM; 440 goto error; 441 } 442 443 /* Get link hardware address */ 444 rc = inetcfg_link_get(link_id, &dlink->link_info); 445 if (rc != EOK) { 446 log_msg(LOG_DEFAULT, LVL_ERROR, "Error getting properties " 447 "for link %zu.", link_id); 448 rc = EIO; 449 goto error; 450 } 451 452 rc = dhcp_transport_init(&dlink->dt, link_id, dhcpsrv_recv, dlink); 453 if (rc != EOK) { 454 log_msg(LOG_DEFAULT, LVL_ERROR, "Error initializing DHCP " 455 "transport for link %s.", dlink->link_info.name); 456 rc = EIO; 457 goto error; 458 } 459 460 dlink->state = ds_selecting; 461 462 log_msg(LOG_DEFAULT, LVL_DEBUG, "Send DHCPDISCOVER"); 463 rc = dhcp_send_discover(dlink); 464 if (rc != EOK) { 465 log_msg(LOG_DEFAULT, LVL_ERROR, "Error sending DHCPDISCOVER."); 466 dhcp_link_set_failed(dlink); 467 rc = EIO; 468 goto error; 469 } 470 471 dlink->retries_left = dhcp_discover_retries; 472 fibril_timer_set(dlink->timeout, dhcp_discover_timeout_val, 473 dhcpsrv_discover_timeout, dlink); 474 475 list_append(&dlink->links, &dhcp_links); 476 477 return EOK; 478 error: 479 if (dlink != NULL && dlink->timeout != NULL) 480 fibril_timer_destroy(dlink->timeout); 481 free(dlink); 482 return rc; 483 } 484 485 int dhcpsrv_link_remove(service_id_t link_id) 486 { 487 return ENOTSUP; 488 } 489 490 static void dhcpsrv_recv_offer(dhcp_link_t *dlink, dhcp_offer_t *offer) 491 { 492 int rc; 493 494 if (dlink->state != ds_selecting) { 495 log_msg(LOG_DEFAULT, LVL_DEBUG, "Received offer in state " 496 " %d, ignoring.", (int)dlink->state); 497 return; 498 } 499 500 fibril_timer_clear(dlink->timeout); 501 dlink->offer = *offer; 502 dlink->state = ds_requesting; 503 504 log_msg(LOG_DEFAULT, LVL_DEBUG, "Send DHCPREQUEST"); 505 rc = dhcp_send_request(dlink, offer); 506 if (rc != EOK) { 507 log_msg(LOG_DEFAULT, LVL_DEBUG, "Error sending request."); 508 return; 509 } 510 511 dlink->retries_left = dhcp_request_retries; 512 fibril_timer_set(dlink->timeout, dhcp_request_timeout_val, 513 dhcpsrv_request_timeout, dlink); 514 } 515 516 static void dhcpsrv_recv_ack(dhcp_link_t *dlink, dhcp_offer_t *offer) 517 { 518 int rc; 519 520 if (dlink->state != ds_requesting) { 521 log_msg(LOG_DEFAULT, LVL_DEBUG, "Received ack in state " 522 " %d, ignoring.", (int)dlink->state); 523 return; 524 } 525 526 fibril_timer_clear(dlink->timeout); 527 dlink->offer = *offer; 528 dlink->state = ds_bound; 529 530 rc = dhcp_cfg_create(dlink->link_id, offer); 531 if (rc != EOK) { 532 log_msg(LOG_DEFAULT, LVL_DEBUG, "Error creating configuration."); 533 return; 534 } 535 536 log_msg(LOG_DEFAULT, LVL_NOTE, "%s: Successfully configured.", 537 dlink->link_info.name); 538 } 539 540 static void dhcpsrv_recv(void *arg, void *msg, size_t size) 541 { 542 dhcp_link_t *dlink = (dhcp_link_t *)arg; 405 543 dhcp_offer_t offer; 406 544 int rc; 407 545 408 if (argc < 2) { 409 printf("syntax: %s <ip-link>\n", NAME); 410 return 1; 411 } 412 413 rc = inetcfg_init(); 414 if (rc != EOK) { 415 printf("Error contacting inet configuration service.\n"); 416 return 1; 417 } 418 419 rc = loc_service_get_id(argv[1], &iplink, 0); 420 if (rc != EOK) { 421 printf("Error resolving service '%s'.\n", argv[1]); 422 return 1; 423 } 424 425 /* Get link hardware address */ 426 rc = inetcfg_link_get(iplink, &link_info); 427 if (rc != EOK) { 428 printf("Error getting properties for link '%s'.\n", argv[1]); 429 return 1; 430 } 431 432 laddr.sin_family = AF_INET; 433 laddr.sin_port = htons(dhcp_client_port); 434 laddr.sin_addr.s_addr = INADDR_ANY; 435 436 fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 437 if (fd < 0) 438 return 1; 439 440 printf("Bind socket.\n"); 441 rc = bind(fd, (struct sockaddr *)&laddr, sizeof(laddr)); 442 if (rc != EOK) 443 return 1; 444 445 printf("Set socket options\n"); 446 rc = setsockopt(fd, SOL_SOCKET, SO_IPLINK, &iplink, sizeof(iplink)); 447 if (rc != EOK) 448 return 1; 449 450 transport_fd = fd; 451 452 printf("Send DHCPDISCOVER\n"); 453 rc = dhcp_send_discover(); 454 if (rc != EOK) 455 return 1; 456 457 rc = dhcp_recv_msg(&msg, &msg_size); 458 if (rc != EOK) 459 return 1; 460 461 printf("Received %zu bytes\n", msg_size); 462 463 rc = dhcp_recv_reply(msg, msg_size, &offer); 464 if (rc != EOK) 465 return 1; 466 467 rc = dhcp_send_request(&offer); 468 if (rc != EOK) 469 return 1; 470 471 rc = dhcp_recv_msg(&msg, &msg_size); 472 if (rc != EOK) 473 return 1; 474 475 printf("Received %zu bytes\n", msg_size); 476 477 rc = dhcp_recv_reply(msg, msg_size, &offer); 478 if (rc != EOK) 479 return 1; 480 481 rc = dhcp_cfg_create(iplink, &offer); 482 if (rc != EOK) 483 return 1; 484 485 closesocket(fd); 486 return 0; 546 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: dhcpsrv_recv() %zu bytes", 547 dlink->link_info.name, size); 548 549 rc = dhcp_parse_reply(msg, size, &offer); 550 if (rc != EOK) { 551 log_msg(LOG_DEFAULT, LVL_DEBUG, "Error parsing reply"); 552 return; 553 } 554 555 switch (offer.msg_type) { 556 case msg_dhcpoffer: 557 dhcpsrv_recv_offer(dlink, &offer); 558 break; 559 case msg_dhcpack: 560 dhcpsrv_recv_ack(dlink, &offer); 561 break; 562 default: 563 log_msg(LOG_DEFAULT, LVL_DEBUG, "Received unexpected " 564 "message type. %d", (int)offer.msg_type); 565 break; 566 } 567 } 568 569 static void dhcpsrv_discover_timeout(void *arg) 570 { 571 dhcp_link_t *dlink = (dhcp_link_t *)arg; 572 int rc; 573 574 assert(dlink->state == ds_selecting); 575 log_msg(LOG_DEFAULT, LVL_NOTE, "%s: dcpsrv_discover_timeout", 576 dlink->link_info.name); 577 578 if (dlink->retries_left == 0) { 579 log_msg(LOG_DEFAULT, LVL_NOTE, "Retries exhausted"); 580 dhcp_link_set_failed(dlink); 581 return; 582 } 583 --dlink->retries_left; 584 585 log_msg(LOG_DEFAULT, LVL_DEBUG, "Send DHCPDISCOVER"); 586 rc = dhcp_send_discover(dlink); 587 if (rc != EOK) { 588 log_msg(LOG_DEFAULT, LVL_ERROR, "Error sending DHCPDISCOVER"); 589 dhcp_link_set_failed(dlink); 590 return; 591 } 592 593 fibril_timer_set(dlink->timeout, dhcp_discover_timeout_val, 594 dhcpsrv_discover_timeout, dlink); 595 } 596 597 static void dhcpsrv_request_timeout(void *arg) 598 { 599 dhcp_link_t *dlink = (dhcp_link_t *)arg; 600 int rc; 601 602 assert(dlink->state == ds_requesting); 603 log_msg(LOG_DEFAULT, LVL_NOTE, "%s: dcpsrv_request_timeout", 604 dlink->link_info.name); 605 606 if (dlink->retries_left == 0) { 607 log_msg(LOG_DEFAULT, LVL_NOTE, "Retries exhausted"); 608 dhcp_link_set_failed(dlink); 609 return; 610 } 611 --dlink->retries_left; 612 613 log_msg(LOG_DEFAULT, LVL_DEBUG, "Send DHCPREQUEST"); 614 rc = dhcp_send_request(dlink, &dlink->offer); 615 if (rc != EOK) { 616 log_msg(LOG_DEFAULT, LVL_DEBUG, "Error sending request."); 617 dhcp_link_set_failed(dlink); 618 return; 619 } 620 621 fibril_timer_set(dlink->timeout, dhcp_request_timeout_val, 622 dhcpsrv_request_timeout, dlink); 487 623 } 488 624
Note:
See TracChangeset
for help on using the changeset viewer.