aboutsummaryrefslogtreecommitdiffstats
path: root/src/fnet/interface.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fnet/interface.c')
-rw-r--r--src/fnet/interface.c194
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
376static int net_netlink_address_tentative(struct nlmsghdr *current_header) { 376static 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
395static int net_netlink_if_has_ll(int sock, int index) { 397static 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}