Mercurial > hg > toybox
comparison toys/pending/ifconfig.c @ 919:a186f9a1406d
More ifconfig cleanup, described on list.
author | Rob Landley <rob@landley.net> |
---|---|
date | Sun, 02 Jun 2013 20:51:17 -0500 |
parents | ecb0befac82a |
children | 6a37f642b572 |
comparison
equal
deleted
inserted
replaced
918:eea4c1b35959 | 919:a186f9a1406d |
---|---|
50 | 50 |
51 // man netdevice | 51 // man netdevice |
52 struct if_list { | 52 struct if_list { |
53 struct if_list *next; | 53 struct if_list *next; |
54 int hw_type, mtu, metric, txqueuelen, non_virtual_iface; | 54 int hw_type, mtu, metric, txqueuelen, non_virtual_iface; |
55 short flags, hasaddr; | 55 short flags; |
56 struct sockaddr addr, dstaddr, broadaddr, netmask, hwaddr; | 56 struct sockaddr addr, dstaddr, broadaddr, netmask, hwaddr; |
57 struct ifmap map; | 57 struct ifmap map; |
58 | 58 |
59 char name[IFNAMSIZ]; | 59 char name[IFNAMSIZ]; |
60 unsigned long long val[16]; | 60 unsigned long long val[16]; |
191 } | 191 } |
192 } else if(sock->sa_family == AF_UNIX) { | 192 } else if(sock->sa_family == AF_UNIX) { |
193 struct sockaddr_un *sockun = (void*)sock; | 193 struct sockaddr_un *sockun = (void*)sock; |
194 return xmsprintf("local:%.*s", (int) sizeof(sockun->sun_path), sockun->sun_path); | 194 return xmsprintf("local:%.*s", (int) sizeof(sockun->sun_path), sockun->sun_path); |
195 } else return NULL; | 195 } else return NULL; |
196 } | |
197 | |
198 static void set_flags(int sockfd, struct ifreq *ifre, int set_flag, | |
199 int reset_flag) | |
200 { | |
201 xioctl(sockfd, SIOCGIFFLAGS, ifre); | |
202 ifre->ifr_flags &= ~reset_flag; | |
203 ifre->ifr_flags |= set_flag; | |
204 xioctl(sockfd, SIOCSIFFLAGS, ifre); | |
205 } | 196 } |
206 | 197 |
207 static void set_ipv6_addr(int sockfd, struct ifreq *ifre, char *ipv6_addr, int request) | 198 static void set_ipv6_addr(int sockfd, struct ifreq *ifre, char *ipv6_addr, int request) |
208 { | 199 { |
209 char *prefix; | 200 char *prefix; |
277 { | 268 { |
278 struct ifreq ifre; | 269 struct ifreq ifre; |
279 char *name = il->name; | 270 char *name = il->name; |
280 int sokfd; | 271 int sokfd; |
281 | 272 |
273 il->txqueuelen = -1; | |
274 | |
282 sokfd = xsocket(AF_INET, SOCK_DGRAM, 0); | 275 sokfd = xsocket(AF_INET, SOCK_DGRAM, 0); |
283 xstrncpy(ifre.ifr_name, name, IFNAMSIZ); | 276 xstrncpy(ifre.ifr_name, name, IFNAMSIZ); |
284 if(ioctl(sokfd, SIOCGIFFLAGS, &ifre)<0) perror_exit("%s", il->name); | 277 if (ioctl(sokfd, SIOCGIFFLAGS, &ifre)<0) perror_exit("%s", il->name); |
285 il->flags = ifre.ifr_flags; | 278 il->flags = ifre.ifr_flags; |
286 | 279 |
287 if(ioctl(sokfd, SIOCGIFHWADDR, &ifre) >= 0) | 280 if (ioctl(sokfd, SIOCGIFHWADDR, &ifre) >= 0) |
288 memcpy(il->hwaddr.sa_data, ifre.ifr_hwaddr.sa_data, sizeof(il->hwaddr.sa_data)); | 281 memcpy(il->hwaddr.sa_data, ifre.ifr_hwaddr.sa_data, sizeof(il->hwaddr.sa_data)); |
289 | |
290 il->hw_type = ifre.ifr_hwaddr.sa_family; | 282 il->hw_type = ifre.ifr_hwaddr.sa_family; |
291 | 283 |
292 if(ioctl(sokfd, SIOCGIFMETRIC, &ifre) >= 0) | 284 if (ioctl(sokfd, SIOCGIFMETRIC, &ifre) >= 0) il->metric = ifre.ifr_metric; |
293 il->metric = ifre.ifr_metric; | 285 if (ioctl(sokfd, SIOCGIFMTU, &ifre) >= 0) il->mtu = ifre.ifr_mtu; |
294 | 286 if (ioctl(sokfd, SIOCGIFMAP, &ifre) == 0) il->map = ifre.ifr_map; |
295 if(ioctl(sokfd, SIOCGIFMTU, &ifre) >= 0) | 287 if (ioctl(sokfd, SIOCGIFTXQLEN, &ifre) >= 0) il->txqueuelen = ifre.ifr_qlen; |
296 il->mtu = ifre.ifr_mtu; | 288 |
297 | 289 // If an address is assigned record that. |
298 if(ioctl(sokfd, SIOCGIFMAP, &ifre) == 0) | |
299 il->map = ifre.ifr_map; | |
300 | |
301 il->txqueuelen = -1; | |
302 if(ioctl(sokfd, SIOCGIFTXQLEN, &ifre) >= 0) | |
303 il->txqueuelen = ifre.ifr_qlen; | |
304 | 290 |
305 ifre.ifr_addr.sa_family = AF_INET; | 291 ifre.ifr_addr.sa_family = AF_INET; |
306 | 292 if (!ioctl(sokfd, SIOCGIFADDR, &ifre)) il->addr = ifre.ifr_addr; |
307 if(!ioctl(sokfd, SIOCGIFADDR, &ifre)) { | 293 if (ioctl(sokfd, SIOCGIFDSTADDR, &ifre) >= 0) il->dstaddr = ifre.ifr_dstaddr; |
308 il->hasaddr = 1; | 294 if (ioctl(sokfd, SIOCGIFBRDADDR, &ifre) >= 0) il->broadaddr = ifre.ifr_broadaddr; |
309 il->addr = ifre.ifr_addr; | 295 if (ioctl(sokfd, SIOCGIFNETMASK, &ifre) >= 0) il->netmask = ifre.ifr_netmask; |
310 if(ioctl(sokfd, SIOCGIFDSTADDR, &ifre) >= 0) | |
311 il->dstaddr = ifre.ifr_dstaddr; | |
312 | |
313 if(ioctl(sokfd, SIOCGIFBRDADDR, &ifre) >= 0) | |
314 il->broadaddr = ifre.ifr_broadaddr; | |
315 | |
316 if(ioctl(sokfd, SIOCGIFNETMASK, &ifre) >= 0) | |
317 il->netmask = ifre.ifr_netmask; | |
318 } | |
319 close(sokfd); | 296 close(sokfd); |
320 } | 297 } |
321 | 298 |
322 static void print_ip6_addr(struct if_list *il) | 299 static void print_ip6_addr(struct if_list *il) |
323 { | 300 { |
374 {ARPHRD_LOOPBACK, "Local Loopback"}, {ARPHRD_ETHER, "Ethernet"}, | 351 {ARPHRD_LOOPBACK, "Local Loopback"}, {ARPHRD_ETHER, "Ethernet"}, |
375 {ARPHRD_PPP, "Point-to-Point Protocol"}, {ARPHRD_INFINIBAND, "InfiniBand"}, | 352 {ARPHRD_PPP, "Point-to-Point Protocol"}, {ARPHRD_INFINIBAND, "InfiniBand"}, |
376 {ARPHRD_SIT, "IPv6-in-IPv4"}, {-1, "UNSPEC"} | 353 {ARPHRD_SIT, "IPv6-in-IPv4"}, {-1, "UNSPEC"} |
377 }; | 354 }; |
378 int i; | 355 int i; |
356 char *p; | |
379 | 357 |
380 for (i=0; i < (sizeof(types)/sizeof(*types))-1; i++) | 358 for (i=0; i < (sizeof(types)/sizeof(*types))-1; i++) |
381 if (il->hw_type == types[i].type) break; | 359 if (il->hw_type == types[i].type) break; |
382 | 360 |
383 xprintf("%-9s Link encap:%s ", il->name, types[i].title); | 361 xprintf("%-9s Link encap:%s ", il->name, types[i].title); |
385 xprintf("HWaddr "); | 363 xprintf("HWaddr "); |
386 for (i=0; i<6; i++) xprintf(":%02X"+!i, il->hwaddr.sa_data[i]); | 364 for (i=0; i<6; i++) xprintf(":%02X"+!i, il->hwaddr.sa_data[i]); |
387 } | 365 } |
388 xputc('\n'); | 366 xputc('\n'); |
389 | 367 |
390 if(il->hasaddr) { | 368 p = (char *)&il->addr; |
369 for (i = 0; i<sizeof(il->addr); i++) if (p[i]) break; | |
370 if (i != sizeof(il->addr)) { | |
391 int af = il->addr.sa_family; | 371 int af = il->addr.sa_family; |
392 struct { | 372 struct { |
393 char *name; | 373 char *name; |
394 int flag, offset; | 374 int flag, offset; |
395 } addr[] = { | 375 } addr[] = { |
465 xputc('\n'); | 445 xputc('\n'); |
466 } | 446 } |
467 | 447 |
468 static void readconf(void) | 448 static void readconf(void) |
469 { | 449 { |
470 int num_of_req = 30; | |
471 struct ifconf ifcon; | 450 struct ifconf ifcon; |
472 struct ifreq *ifre; | 451 struct ifreq *ifre; |
473 int num, sokfd; | 452 int num, sokfd; |
474 | 453 |
454 sokfd = xsocket(AF_INET, SOCK_DGRAM, 0); | |
455 | |
456 // Loop until buffer's big enough | |
475 ifcon.ifc_buf = NULL; | 457 ifcon.ifc_buf = NULL; |
476 sokfd = socket(AF_INET, SOCK_DGRAM, 0); | 458 for (num = 30;;num += 10) { |
477 if(sokfd < 0) perror_exit("socket"); | 459 ifcon.ifc_len = sizeof(struct ifreq)*num; |
478 for (;;) { | |
479 ifcon.ifc_len = sizeof(struct ifreq) * num_of_req; //Size of buffer. | |
480 ifcon.ifc_buf = xrealloc(ifcon.ifc_buf, ifcon.ifc_len); | 460 ifcon.ifc_buf = xrealloc(ifcon.ifc_buf, ifcon.ifc_len); |
481 | |
482 xioctl(sokfd, SIOCGIFCONF, &ifcon); | 461 xioctl(sokfd, SIOCGIFCONF, &ifcon); |
483 //in case of overflow, increase number of requests and retry. | 462 if (ifcon.ifc_len != sizeof(struct ifreq)*num) break; |
484 if (ifcon.ifc_len == (int)(sizeof(struct ifreq) * num_of_req)) { | |
485 num_of_req += 10; | |
486 continue; | |
487 } | |
488 break; | |
489 } | 463 } |
490 | 464 |
491 ifre = ifcon.ifc_req; | 465 ifre = ifcon.ifc_req; |
492 for(num = 0; num < ifcon.ifc_len && ifre; num += sizeof(struct ifreq), ifre++) { | 466 for(num = 0; num < ifcon.ifc_len && ifre; num += sizeof(struct ifreq), ifre++) |
493 //Escape duplicate values from the list. | 467 { |
494 struct if_list *il; | 468 struct if_list *il; |
495 | 469 |
470 // Skip duplicates | |
496 for(il = TT.if_list; il; il = il->next) | 471 for(il = TT.if_list; il; il = il->next) |
497 if(!strcmp(ifre->ifr_name, il->name)) break; | 472 if(!strcmp(ifre->ifr_name, il->name)) break; |
498 if(!il) { | 473 if(!il) { |
499 il = xzalloc(sizeof(struct if_list)); | 474 il = xzalloc(sizeof(struct if_list)); |
500 xstrncpy(il->name, ifre->ifr_name, IFNAMSIZ); | 475 xstrncpy(il->name, ifre->ifr_name, IFNAMSIZ); |
501 add_iface_to_list(il); | 476 add_iface_to_list(il); |
502 errno = 0; | |
503 get_device_info(il); | 477 get_device_info(il); |
504 } | 478 } |
505 } | 479 } |
506 | 480 |
507 close(sokfd); | 481 close(sokfd); |
536 errno = 0; | 510 errno = 0; |
537 get_device_info(il); | 511 get_device_info(il); |
538 } | 512 } |
539 fclose(fp); | 513 fclose(fp); |
540 | 514 |
541 if(iface_name) { | 515 if (iface_name) { |
542 for(il = TT.if_list; il; il = il->next) { | 516 for(il = TT.if_list; il; il = il->next) { |
543 if(!strcmp(il->name, iface_name)) { | 517 if(!strcmp(il->name, iface_name)) { |
544 display_ifconfig(il); | 518 display_ifconfig(il); |
545 break; | 519 break; |
546 } | 520 } |
562 } | 536 } |
563 | 537 |
564 if (CFG_TOYBOX_FREE) llist_traverse(TT.if_list, free); | 538 if (CFG_TOYBOX_FREE) llist_traverse(TT.if_list, free); |
565 } | 539 } |
566 | 540 |
541 // Encode offset and size of field into an int, and make result negative | |
542 #define IFREQ_OFFSZ(x) -(int)((offsetof(struct ifreq, x)<<16) + sizeof(ifre.x)) | |
543 | |
567 void ifconfig_main(void) | 544 void ifconfig_main(void) |
568 { | 545 { |
569 char **argv = toys.optargs; | 546 char **argv = toys.optargs; |
570 struct ifreq ifre; | 547 struct ifreq ifre; |
571 int i, sockfd = 0; | 548 int i, sockfd = 0; |
575 if(toys.optc < 2) { | 552 if(toys.optc < 2) { |
576 show_iface(*argv); | 553 show_iface(*argv); |
577 return; | 554 return; |
578 } | 555 } |
579 | 556 |
580 //get interface name | 557 // Open interface |
581 memset(&ifre, 0, sizeof(struct ifreq)); | 558 memset(&ifre, 0, sizeof(struct ifreq)); |
582 xstrncpy(ifre.ifr_name, *argv, IFNAMSIZ); | 559 xstrncpy(ifre.ifr_name, *argv, IFNAMSIZ); |
583 sockfd = xsocket(AF_INET, SOCK_DGRAM, 0); | 560 sockfd = xsocket(AF_INET, SOCK_DGRAM, 0); |
584 | 561 |
562 // Perform operations on interface | |
585 while(*++argv) { | 563 while(*++argv) { |
586 struct argh { | 564 struct argh { |
587 char *name; | 565 char *name; |
588 int on, off; // set, clear | 566 int on, off; // set, clear |
589 } try[] = { | 567 } try[] = { |
596 {"multicast", IFF_MULTICAST, 0}, | 574 {"multicast", IFF_MULTICAST, 0}, |
597 {"dynamic", IFF_DYNAMIC, 0}, | 575 {"dynamic", IFF_DYNAMIC, 0}, |
598 {"pointopoint", IFF_POINTOPOINT, SIOCSIFDSTADDR}, | 576 {"pointopoint", IFF_POINTOPOINT, SIOCSIFDSTADDR}, |
599 {"broadcast", IFF_BROADCAST, SIOCSIFBRDADDR}, | 577 {"broadcast", IFF_BROADCAST, SIOCSIFBRDADDR}, |
600 {"netmask", 0, SIOCSIFNETMASK}, | 578 {"netmask", 0, SIOCSIFNETMASK}, |
601 {"dstaddr", 0, SIOCSIFDSTADDR} | 579 {"dstaddr", 0, SIOCSIFDSTADDR}, |
580 {"mtu", IFREQ_OFFSZ(ifr_mtu), SIOCSIFMTU}, | |
581 {"keepalive", IFREQ_OFFSZ(ifr_data), SIOCSKEEPALIVE}, | |
582 {"outfill", IFREQ_OFFSZ(ifr_data), SIOCSOUTFILL}, | |
583 {"metric", IFREQ_OFFSZ(ifr_metric), SIOCSIFMETRIC}, | |
584 {"txqueuelen", IFREQ_OFFSZ(ifr_qlen), SIOCSIFTXQLEN}, | |
585 {"mem_start", IFREQ_OFFSZ(ifr_map.mem_start), SIOCSIFMAP}, | |
586 {"io_addr", IFREQ_OFFSZ(ifr_map.base_addr), SIOCSIFMAP}, | |
587 {"irq", IFREQ_OFFSZ(ifr_map.irq), SIOCSIFMAP}, | |
588 {"inet", 0, 0}, | |
589 {"inet6", 0, 0} | |
602 }; | 590 }; |
603 char *s = *argv; | 591 char *s = *argv; |
604 int rev = (*s == '-'); | 592 int rev = (*s == '-'); |
605 | 593 |
606 s += rev; | 594 s += rev; |
610 int on = t->on, off = t->off; | 598 int on = t->on, off = t->off; |
611 | 599 |
612 if (strcmp(t->name, s)) continue; | 600 if (strcmp(t->name, s)) continue; |
613 | 601 |
614 // Is this an SIOCSI entry? | 602 // Is this an SIOCSI entry? |
615 if ((t->off | 0xff) == 0x89ff) { | 603 if ((off|0xff) == 0x89ff) { |
616 if (!rev) { | 604 if (!rev) { |
617 if (!*++argv) show_help(); | 605 if (!*++argv) show_help(); |
618 set_address(sockfd, *argv, &ifre, off); | 606 |
607 // Assign value to ifre field and call ioctl? (via IFREQ_OFFSZ.) | |
608 if (on < 0) { | |
609 long l = strtoul(*argv, 0, 0); | |
610 | |
611 if (off == SIOCSIFMAP) xioctl(sockfd, SIOCGIFMAP, &ifre); | |
612 on = -on; | |
613 poke((on>>16) + (char *)&ifre, l, on&15); | |
614 xioctl(sockfd, off, &ifre); | |
615 break; | |
616 } else set_address(sockfd, *argv, &ifre, off); | |
619 } | 617 } |
620 off = 0; | 618 off = 0; |
621 } | 619 } |
620 | |
621 // Set flags | |
622 if (on || off) { | 622 if (on || off) { |
623 xioctl(sockfd, SIOCGIFFLAGS, &ifre); | 623 xioctl(sockfd, SIOCGIFFLAGS, &ifre); |
624 ifre.ifr_flags &= ~(rev ? on : off); | 624 ifre.ifr_flags &= ~(rev ? on : off); |
625 ifre.ifr_flags |= (rev ? off : on); | 625 ifre.ifr_flags |= (rev ? off : on); |
626 xioctl(sockfd, SIOCSIFFLAGS, &ifre); | 626 xioctl(sockfd, SIOCSIFFLAGS, &ifre); |
661 } | 661 } |
662 | 662 |
663 if ((p-ptr) != count || *hw_addr) | 663 if ((p-ptr) != count || *hw_addr) |
664 error_exit("bad hw-addr '%s'", hw_addr ? hw_addr : ""); | 664 error_exit("bad hw-addr '%s'", hw_addr ? hw_addr : ""); |
665 xioctl(sockfd, SIOCSIFHWADDR, &ifre); | 665 xioctl(sockfd, SIOCSIFHWADDR, &ifre); |
666 } else if (!strcmp(*argv, "mtu")) { | 666 |
667 if (!*++argv) show_help(); | 667 } else if (!strcmp(*argv, "add") || !strcmp(*argv, "del")) { |
668 ifre.ifr_mtu = strtoul(*argv, NULL, 0); | 668 if (!argv[1]) show_help(); |
669 xioctl(sockfd, SIOCSIFMTU, &ifre); | 669 set_ipv6_addr(sockfd, &ifre, argv[1], |
670 } else if (!strcmp(*argv, "keepalive")) { | 670 **argv=='a' ? SIOCSIFADDR : SIOCDIFADDR); |
671 if (!*++argv) show_help(); | 671 argv++; |
672 ifre.ifr_data = (void *)strtoul(*argv, 0, 0); | 672 } else if (isdigit(**argv) || !strcmp(*argv, "default")) { |
673 xioctl(sockfd, SIOCSKEEPALIVE, &ifre); | |
674 } else if (!strcmp(*argv, "outfill")) { | |
675 if (!*++argv) show_help(); | |
676 ifre.ifr_data = (void *)strtoul(*argv, 0, 0); | |
677 xioctl(sockfd, SIOCSOUTFILL, &ifre); | |
678 } else if (!strcmp(*argv, "metric")) { | |
679 if (!*++argv) show_help(); | |
680 ifre.ifr_metric = strtoul(*argv, NULL, 0); | |
681 xioctl(sockfd, SIOCSIFMETRIC, &ifre); | |
682 } else if (!strcmp(*argv, "txqueuelen")) { | |
683 if (!*++argv) show_help(); | |
684 ifre.ifr_qlen = strtoul(*argv, NULL, 0); | |
685 xioctl(sockfd, SIOCSIFTXQLEN, &ifre); | |
686 | |
687 } else if (!strcmp(*argv, "add")) { | |
688 if (!*++argv) show_help(); | |
689 set_ipv6_addr(sockfd, &ifre, *argv, SIOCSIFADDR); | |
690 } else if (!strcmp(*argv, "del")) { | |
691 if (!*++argv) show_help(); | |
692 set_ipv6_addr(sockfd, &ifre, *argv, SIOCDIFADDR); | |
693 } else if (!strcmp(*argv, "mem_start")) { | |
694 if (!*++argv) show_help(); | |
695 xioctl(sockfd, SIOCGIFMAP, &ifre); | |
696 ifre.ifr_map.mem_start = strtoul(*argv, NULL, 0); | |
697 xioctl(sockfd, SIOCSIFMAP, &ifre); | |
698 } else if (!strcmp(*argv, "io_addr")) { | |
699 if (!*++argv) show_help(); | |
700 xioctl(sockfd, SIOCGIFMAP, &ifre); | |
701 ifre.ifr_map.base_addr = strtoul(*argv, NULL, 0); | |
702 xioctl(sockfd, SIOCSIFMAP, &ifre); | |
703 } else if (!strcmp(*argv, "irq")) { | |
704 if (!*++argv) show_help(); | |
705 xioctl(sockfd, SIOCGIFMAP, &ifre); | |
706 ifre.ifr_map.irq = strtoul(*argv, NULL, 0); | |
707 xioctl(sockfd, SIOCSIFMAP, &ifre); | |
708 } else { | |
709 if (isdigit(**argv) || !strcmp(*argv, "default")) { | |
710 set_address(sockfd, *argv, &ifre, SIOCSIFADDR); | 673 set_address(sockfd, *argv, &ifre, SIOCSIFADDR); |
711 //if the interface name is not an alias; set the flag and continue. | 674 //if the interface name is not an alias; set the flag and continue. |
712 if(!strchr(ifre.ifr_name, ':')) | 675 if(!strchr(ifre.ifr_name, ':')) { |
713 set_flags(sockfd, &ifre, IFF_UP | IFF_RUNNING, 0); | 676 xioctl(sockfd, SIOCGIFFLAGS, &ifre); |
714 } else if (!strcmp(*argv, "inet") || !strcmp(*argv, "inet6")) continue; | 677 ifre.ifr_flags |= IFF_UP|IFF_RUNNING; |
715 else { | 678 xioctl(sockfd, SIOCSIFFLAGS, &ifre); |
716 errno = EINVAL; | 679 } |
717 toys.exithelp++; | 680 |
718 error_exit("bad argument '%s'", *argv); | 681 } else { |
719 } | 682 errno = EINVAL; |
720 } | 683 toys.exithelp++; |
721 | 684 error_exit("bad argument '%s'", *argv); |
722 } | 685 } |
723 if(sockfd > 0) close(sockfd); | 686 } |
724 } | 687 if (CFG_TOYBOX_FREE && sockfd > 0) close(sockfd); |
688 } |