diff options
Diffstat (limited to 'src/fnet/interface.c')
-rw-r--r-- | src/fnet/interface.c | 194 |
1 files changed, 100 insertions, 94 deletions
diff --git a/src/fnet/interface.c b/src/fnet/interface.c index 3b44b70e3..62df0930e 100644 --- a/src/fnet/interface.c +++ b/src/fnet/interface.c | |||
@@ -374,81 +374,83 @@ void net_if_ip6(const char *ifname, const char *addr6) { | |||
374 | } | 374 | } |
375 | 375 | ||
376 | static int net_netlink_address_tentative(struct nlmsghdr *current_header) { | 376 | static int net_netlink_address_tentative(struct nlmsghdr *current_header) { |
377 | struct ifaddrmsg *msg = NLMSG_DATA(current_header); | 377 | struct ifaddrmsg *msg = NLMSG_DATA(current_header); |
378 | struct rtattr *rta = IFA_RTA(msg); | 378 | int has_flags = 0; |
379 | size_t msg_len = IFA_PAYLOAD(current_header); | 379 | #ifdef IFA_FLAGS |
380 | int has_flags = 0; | 380 | struct rtattr *rta = IFA_RTA(msg); |
381 | while (RTA_OK(rta, msg_len)) { | 381 | size_t msg_len = IFA_PAYLOAD(current_header); |
382 | if (rta->rta_type == IFA_FLAGS) { | 382 | while (RTA_OK(rta, msg_len)) { |
383 | has_flags = 1; | 383 | if (rta->rta_type == IFA_FLAGS) { |
384 | uint32_t *flags = RTA_DATA(rta); | 384 | has_flags = 1; |
385 | if (*flags & IFA_F_TENTATIVE) | 385 | uint32_t *flags = RTA_DATA(rta); |
386 | return 1; | 386 | if (*flags & IFA_F_TENTATIVE) |
387 | } | 387 | return 1; |
388 | rta = RTA_NEXT(rta, msg_len); | 388 | } |
389 | } | 389 | rta = RTA_NEXT(rta, msg_len); |
390 | // According to <linux/if_addr.h>, if an IFA_FLAGS attribute is present, | 390 | } |
391 | // the field ifa_flags should be ignored. | 391 | #endif |
392 | return !has_flags && (msg->ifa_flags & IFA_F_TENTATIVE); | 392 | // According to <linux/if_addr.h>, if an IFA_FLAGS attribute is present, |
393 | // the field ifa_flags should be ignored. | ||
394 | return !has_flags && (msg->ifa_flags & IFA_F_TENTATIVE); | ||
393 | } | 395 | } |
394 | 396 | ||
395 | static int net_netlink_if_has_ll(int sock, int index) { | 397 | static int net_netlink_if_has_ll(int sock, uint32_t index) { |
396 | struct { | 398 | struct { |
397 | struct nlmsghdr header; | 399 | struct nlmsghdr header; |
398 | struct ifaddrmsg message; | 400 | struct ifaddrmsg message; |
399 | } req; | 401 | } req; |
400 | memset(&req, 0, sizeof(req)); | 402 | memset(&req, 0, sizeof(req)); |
401 | req.header.nlmsg_len = NLMSG_LENGTH(sizeof(req.message)); | 403 | req.header.nlmsg_len = NLMSG_LENGTH(sizeof(req.message)); |
402 | req.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; | 404 | req.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; |
403 | req.header.nlmsg_type = RTM_GETADDR; | 405 | req.header.nlmsg_type = RTM_GETADDR; |
404 | req.message.ifa_family = AF_INET6; | 406 | req.message.ifa_family = AF_INET6; |
405 | if (send(sock, &req, req.header.nlmsg_len, 0) != req.header.nlmsg_len) | 407 | if (send(sock, &req, req.header.nlmsg_len, 0) != req.header.nlmsg_len) |
406 | errExit("send"); | 408 | errExit("send"); |
407 | 409 | ||
408 | int found = 0; | 410 | int found = 0; |
409 | int all_parts_processed = 0; | 411 | int all_parts_processed = 0; |
410 | while (!all_parts_processed) { | 412 | while (!all_parts_processed) { |
411 | char buf[16384]; | 413 | char buf[16384]; |
412 | ssize_t len = recv(sock, buf, sizeof(buf), 0); | 414 | ssize_t len = recv(sock, buf, sizeof(buf), 0); |
413 | if (len < 0) | 415 | if (len < 0) |
414 | errExit("recv"); | 416 | errExit("recv"); |
415 | if (len < sizeof(struct nlmsghdr)) { | 417 | if (len < (ssize_t) sizeof(struct nlmsghdr)) { |
416 | fprintf(stderr, "Received incomplete netlink message\n"); | 418 | fprintf(stderr, "Received incomplete netlink message\n"); |
417 | exit(1); | 419 | exit(1); |
418 | } | 420 | } |
419 | 421 | ||
420 | struct nlmsghdr *current_header = (struct nlmsghdr *) buf; | 422 | struct nlmsghdr *current_header = (struct nlmsghdr *) buf; |
421 | while (NLMSG_OK(current_header, len)) { | 423 | while (NLMSG_OK(current_header, len)) { |
422 | switch (current_header->nlmsg_type) { | 424 | switch (current_header->nlmsg_type) { |
423 | case RTM_NEWADDR: { | 425 | case RTM_NEWADDR: { |
424 | struct ifaddrmsg *msg = NLMSG_DATA(current_header); | 426 | struct ifaddrmsg *msg = NLMSG_DATA(current_header); |
425 | if (!found && msg->ifa_index == index && msg->ifa_scope == RT_SCOPE_LINK && | 427 | if (!found && msg->ifa_index == index && msg->ifa_scope == RT_SCOPE_LINK && |
426 | !net_netlink_address_tentative(current_header)) | 428 | !net_netlink_address_tentative(current_header)) |
427 | found = 1; | 429 | found = 1; |
428 | } | 430 | } |
429 | break; | 431 | break; |
430 | case NLMSG_NOOP: | 432 | case NLMSG_NOOP: |
431 | break; | 433 | break; |
432 | case NLMSG_DONE: | 434 | case NLMSG_DONE: |
433 | all_parts_processed = 1; | 435 | all_parts_processed = 1; |
434 | break; | 436 | break; |
435 | case NLMSG_ERROR: { | 437 | case NLMSG_ERROR: { |
436 | struct nlmsgerr *err = NLMSG_DATA(current_header); | 438 | struct nlmsgerr *err = NLMSG_DATA(current_header); |
437 | fprintf(stderr, "Netlink error: %d\n", err->error); | 439 | fprintf(stderr, "Netlink error: %d\n", err->error); |
438 | exit(1); | 440 | exit(1); |
439 | } | 441 | } |
440 | break; | 442 | break; |
441 | default: | 443 | default: |
442 | fprintf(stderr, "Unknown netlink message type: %u\n", current_header->nlmsg_type); | 444 | fprintf(stderr, "Unknown netlink message type: %u\n", current_header->nlmsg_type); |
443 | exit(1); | 445 | exit(1); |
444 | break; | 446 | break; |
445 | } | 447 | } |
446 | 448 | ||
447 | current_header = NLMSG_NEXT(current_header, len); | 449 | current_header = NLMSG_NEXT(current_header, len); |
448 | } | 450 | } |
449 | } | 451 | } |
450 | 452 | ||
451 | return found; | 453 | return found; |
452 | } | 454 | } |
453 | 455 | ||
454 | // wait for a link-local IPv6 address for DHCPv6 | 456 | // wait for a link-local IPv6 address for DHCPv6 |
@@ -468,27 +470,31 @@ void net_if_waitll(const char *ifname) { | |||
468 | perror("ioctl SIOGIFINDEX"); | 470 | perror("ioctl SIOGIFINDEX"); |
469 | exit(1); | 471 | exit(1); |
470 | } | 472 | } |
471 | close(inet6_sock); | 473 | close(inet6_sock); |
472 | int index = ifr.ifr_ifindex; | 474 | if (ifr.ifr_ifindex < 0) { |
475 | fprintf(stderr, "Error fnet: interface index is negative\n"); | ||
476 | exit(1); | ||
477 | } | ||
478 | uint32_t index = (uint32_t) ifr.ifr_ifindex; | ||
473 | 479 | ||
474 | // poll for link-local address | 480 | // poll for link-local address |
475 | int netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); | 481 | int netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); |
476 | if (netlink_sock < 0) | 482 | if (netlink_sock < 0) |
477 | errExit("socket"); | 483 | errExit("socket"); |
478 | int tries = 0; | 484 | int tries = 0; |
479 | int found = 0; | 485 | int found = 0; |
480 | while (tries < 60 && !found) { | 486 | while (tries < 60 && !found) { |
481 | if (tries >= 1) | 487 | if (tries >= 1) |
482 | usleep(500000); | 488 | usleep(500000); |
483 | 489 | ||
484 | found = net_netlink_if_has_ll(netlink_sock, index); | 490 | found = net_netlink_if_has_ll(netlink_sock, index); |
485 | 491 | ||
486 | tries++; | 492 | tries++; |
487 | } | 493 | } |
488 | close(netlink_sock); | 494 | close(netlink_sock); |
489 | 495 | ||
490 | if (!found) { | 496 | if (!found) { |
491 | fprintf(stderr, "Waiting for link-local IPv6 address of %s timed out\n", ifname); | 497 | fprintf(stderr, "Waiting for link-local IPv6 address of %s timed out\n", ifname); |
492 | exit(1); | 498 | exit(1); |
493 | } | 499 | } |
494 | } | 500 | } |