diff options
| author | bug1 <bug1@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2002-11-10 01:33:55 +0000 |
|---|---|---|
| committer | bug1 <bug1@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2002-11-10 01:33:55 +0000 |
| commit | 7cde7525fdff2b5baf1c50850141d890c4641ed9 (patch) | |
| tree | b7b2917c3cf46ac3fa25df5f9a27a9a9fbfb0398 | |
| parent | b37ac647f73cc931a008814d9884f9c3b2c8e168 (diff) | |
| download | busybox-w32-7cde7525fdff2b5baf1c50850141d890c4641ed9.tar.gz busybox-w32-7cde7525fdff2b5baf1c50850141d890c4641ed9.tar.bz2 busybox-w32-7cde7525fdff2b5baf1c50850141d890c4641ed9.zip | |
IP applet by Bastian Blank <waldi@debian.org>
git-svn-id: svn://busybox.net/trunk/busybox@5894 69ca8d6d-28ef-0310-b511-8ec308f3f277
27 files changed, 5016 insertions, 3 deletions
| @@ -22,8 +22,8 @@ include $(TOPDIR).config | |||
| 22 | include $(TOPDIR)Rules.mak | 22 | include $(TOPDIR)Rules.mak |
| 23 | SUBDIRS:=applets archival archival/libunarchive console-tools \ | 23 | SUBDIRS:=applets archival archival/libunarchive console-tools \ |
| 24 | editors fileutils findutils init miscutils modutils networking \ | 24 | editors fileutils findutils init miscutils modutils networking \ |
| 25 | networking/udhcp procps loginutils shell shellutils sysklogd \ | 25 | networking/libiproute networking/udhcp procps loginutils shell \ |
| 26 | textutils util-linux libbb libpwdgrp | 26 | shellutils sysklogd textutils util-linux libbb libpwdgrp |
| 27 | 27 | ||
| 28 | all: do-it-all | 28 | all: do-it-all |
| 29 | 29 | ||
diff --git a/include/applets.h b/include/applets.h index 2de9c9909..317344511 100644 --- a/include/applets.h +++ b/include/applets.h | |||
| @@ -251,6 +251,9 @@ | |||
| 251 | #ifdef CONFIG_INSMOD | 251 | #ifdef CONFIG_INSMOD |
| 252 | APPLET(insmod, insmod_main, _BB_DIR_SBIN, _BB_SUID_NEVER) | 252 | APPLET(insmod, insmod_main, _BB_DIR_SBIN, _BB_SUID_NEVER) |
| 253 | #endif | 253 | #endif |
| 254 | #ifdef CONFIG_IP | ||
| 255 | APPLET(ip, ip_main, _BB_DIR_BIN, _BB_SUID_NEVER) | ||
| 256 | #endif | ||
| 254 | #ifdef CONFIG_KILL | 257 | #ifdef CONFIG_KILL |
| 255 | APPLET(kill, kill_main, _BB_DIR_BIN, _BB_SUID_NEVER) | 258 | APPLET(kill, kill_main, _BB_DIR_BIN, _BB_SUID_NEVER) |
| 256 | #endif | 259 | #endif |
diff --git a/include/usage.h b/include/usage.h index 2d20722a9..d0aa3243f 100644 --- a/include/usage.h +++ b/include/usage.h | |||
| @@ -977,6 +977,11 @@ | |||
| 977 | "\t-L\tLock to prevent simultaneous loads of a module\n" \ | 977 | "\t-L\tLock to prevent simultaneous loads of a module\n" \ |
| 978 | "\t-x\tdo not export externs" | 978 | "\t-x\tdo not export externs" |
| 979 | 979 | ||
| 980 | #define ip_trivial_usage \ | ||
| 981 | "not written yet" | ||
| 982 | #define ip_full_usage \ | ||
| 983 | "not written yet" | ||
| 984 | |||
| 980 | #define kill_trivial_usage \ | 985 | #define kill_trivial_usage \ |
| 981 | "[-signal] process-id [process-id ...]" | 986 | "[-signal] process-id [process-id ...]" |
| 982 | #define kill_full_usage \ | 987 | #define kill_full_usage \ |
diff --git a/networking/Makefile.in b/networking/Makefile.in index 743990bb6..d249c0423 100644 --- a/networking/Makefile.in +++ b/networking/Makefile.in | |||
| @@ -26,7 +26,8 @@ NETWORKING-y:= | |||
| 26 | NETWORKING-$(CONFIG_HOSTNAME) += hostname.o | 26 | NETWORKING-$(CONFIG_HOSTNAME) += hostname.o |
| 27 | NETWORKING-$(CONFIG_IFCONFIG) += ifconfig.o | 27 | NETWORKING-$(CONFIG_IFCONFIG) += ifconfig.o |
| 28 | NETWORKING-$(CONFIG_IFUPDOWN) += ifupdown.o | 28 | NETWORKING-$(CONFIG_IFUPDOWN) += ifupdown.o |
| 29 | NETWORKING-$(CONFIG_NC) += nc.o | 29 | NETWORKING-$(CONFIG_IP) += ip.o |
| 30 | NETWORKING-$(CONFIG_NC) += nc.o | ||
| 30 | NETWORKING-$(CONFIG_NETSTAT) += netstat.o | 31 | NETWORKING-$(CONFIG_NETSTAT) += netstat.o |
| 31 | NETWORKING-$(CONFIG_NSLOOKUP) += nslookup.o | 32 | NETWORKING-$(CONFIG_NSLOOKUP) += nslookup.o |
| 32 | NETWORKING-$(CONFIG_PING) += ping.o | 33 | NETWORKING-$(CONFIG_PING) += ping.o |
diff --git a/networking/config.in b/networking/config.in index 09b2b5c6f..fe714fe0c 100644 --- a/networking/config.in +++ b/networking/config.in | |||
| @@ -22,6 +22,13 @@ if [ "$CONFIG_IFUPDOWN" = "y" ]; then | |||
| 22 | bool ' Enable support for IPv6 (requires ip command)' CONFIG_FEATURE_IFUPDOWN_IPV6 | 22 | bool ' Enable support for IPv6 (requires ip command)' CONFIG_FEATURE_IFUPDOWN_IPV6 |
| 23 | bool ' Enable support for IPX (requires ipx_interface command)' CONFIG_FEATURE_IFUPDOWN_IPX | 23 | bool ' Enable support for IPX (requires ipx_interface command)' CONFIG_FEATURE_IFUPDOWN_IPX |
| 24 | fi | 24 | fi |
| 25 | bool 'ip' CONFIG_IP | ||
| 26 | if [ "$CONFIG_IP" = "y" ]; then | ||
| 27 | bool ' address' CONFIG_FEATURE_IP_ADDRESS | ||
| 28 | bool ' link' CONFIG_FEATURE_IP_LINK | ||
| 29 | bool ' route' CONFIG_FEATURE_IP_ROUTE | ||
| 30 | bool ' tunnel' CONFIG_FEATURE_IP_TUNNEL | ||
| 31 | fi | ||
| 25 | bool 'nc' CONFIG_NC | 32 | bool 'nc' CONFIG_NC |
| 26 | bool 'netstat' CONFIG_NETSTAT | 33 | bool 'netstat' CONFIG_NETSTAT |
| 27 | bool 'nslookup' CONFIG_NSLOOKUP | 34 | bool 'nslookup' CONFIG_NSLOOKUP |
diff --git a/networking/ip.c b/networking/ip.c new file mode 100644 index 000000000..f045f5f78 --- /dev/null +++ b/networking/ip.c | |||
| @@ -0,0 +1,104 @@ | |||
| 1 | /* | ||
| 2 | * ip.c "ip" utility frontend. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version | ||
| 7 | * 2 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> | ||
| 10 | * | ||
| 11 | * | ||
| 12 | * Changes: | ||
| 13 | * | ||
| 14 | * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <stdio.h> | ||
| 18 | #include <stdlib.h> | ||
| 19 | #include <unistd.h> | ||
| 20 | #include <syslog.h> | ||
| 21 | #include <fcntl.h> | ||
| 22 | #include <sys/socket.h> | ||
| 23 | #include <netinet/in.h> | ||
| 24 | #include <string.h> | ||
| 25 | |||
| 26 | #include "./libiproute/utils.h" | ||
| 27 | #include "./libiproute/ip_common.h" | ||
| 28 | |||
| 29 | #include "busybox.h" | ||
| 30 | |||
| 31 | int preferred_family = AF_UNSPEC; | ||
| 32 | int oneline = 0; | ||
| 33 | char * _SL_ = NULL; | ||
| 34 | |||
| 35 | int ip_main(int argc, char **argv) | ||
| 36 | { | ||
| 37 | char *basename; | ||
| 38 | |||
| 39 | basename = strrchr(argv[0], '/'); | ||
| 40 | if (basename == NULL) | ||
| 41 | basename = argv[0]; | ||
| 42 | else | ||
| 43 | basename++; | ||
| 44 | |||
| 45 | while (argc > 1) { | ||
| 46 | char *opt = argv[1]; | ||
| 47 | if (strcmp(opt,"--") == 0) { | ||
| 48 | argc--; argv++; | ||
| 49 | break; | ||
| 50 | } | ||
| 51 | if (opt[0] != '-') | ||
| 52 | break; | ||
| 53 | if (opt[1] == '-') | ||
| 54 | opt++; | ||
| 55 | if (matches(opt, "-family") == 0) { | ||
| 56 | argc--; | ||
| 57 | argv++; | ||
| 58 | if (strcmp(argv[1], "inet") == 0) | ||
| 59 | preferred_family = AF_INET; | ||
| 60 | else if (strcmp(argv[1], "inet6") == 0) | ||
| 61 | preferred_family = AF_INET6; | ||
| 62 | else if (strcmp(argv[1], "link") == 0) | ||
| 63 | preferred_family = AF_PACKET; | ||
| 64 | else | ||
| 65 | invarg(argv[1], "invalid protocol family"); | ||
| 66 | } else if (strcmp(opt, "-4") == 0) { | ||
| 67 | preferred_family = AF_INET; | ||
| 68 | } else if (strcmp(opt, "-6") == 0) { | ||
| 69 | preferred_family = AF_INET6; | ||
| 70 | } else if (strcmp(opt, "-0") == 0) { | ||
| 71 | preferred_family = AF_PACKET; | ||
| 72 | } else if (matches(opt, "-oneline") == 0) { | ||
| 73 | ++oneline; | ||
| 74 | } else { | ||
| 75 | fprintf(stderr, "Option \"%s\" is unknown, try \"ip -help\".\n", opt); | ||
| 76 | exit(-1); | ||
| 77 | } | ||
| 78 | argc--; argv++; | ||
| 79 | } | ||
| 80 | |||
| 81 | _SL_ = oneline ? "\\" : "\n" ; | ||
| 82 | |||
| 83 | if (argc > 1) { | ||
| 84 | #ifdef CONFIG_FEATURE_IP_ADDRESS | ||
| 85 | if (matches(argv[1], "address") == 0) | ||
| 86 | return do_ipaddr(argc-2, argv+2); | ||
| 87 | #endif | ||
| 88 | #ifdef CONFIG_FEATURE_IP_ROUTE | ||
| 89 | if (matches(argv[1], "route") == 0) | ||
| 90 | return do_iproute(argc-2, argv+2); | ||
| 91 | #endif | ||
| 92 | #ifdef CONFIG_FEATURE_IP_LINK | ||
| 93 | if (matches(argv[1], "link") == 0) | ||
| 94 | return do_iplink(argc-2, argv+2); | ||
| 95 | #endif | ||
| 96 | #ifdef CONFIG_FEATURE_IP_TUNNEL | ||
| 97 | if (matches(argv[1], "tunnel") == 0 || | ||
| 98 | strcmp(argv[1], "tunl") == 0) | ||
| 99 | return do_iptunnel(argc-2, argv+2); | ||
| 100 | #endif | ||
| 101 | fprintf(stderr, "Object \"%s\" is unknown, try \"ip help\".\n", argv[1]); | ||
| 102 | exit(-1); | ||
| 103 | } | ||
| 104 | } | ||
diff --git a/networking/libiproute/Makefile b/networking/libiproute/Makefile new file mode 100644 index 000000000..29419fd4a --- /dev/null +++ b/networking/libiproute/Makefile | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | # Makefile for busybox | ||
| 2 | # | ||
| 3 | # Copyright (C) 1999-2002 Erik Andersen <andersee@debian.org> | ||
| 4 | # | ||
| 5 | # This program is free software; you can redistribute it and/or modify | ||
| 6 | # it under the terms of the GNU General Public License as published by | ||
| 7 | # the Free Software Foundation; either version 2 of the License, or | ||
| 8 | # (at your option) any later version. | ||
| 9 | # | ||
| 10 | # This program is distributed in the hope that it will be useful, | ||
| 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | # General Public License for more details. | ||
| 14 | # | ||
| 15 | # You should have received a copy of the GNU General Public License | ||
| 16 | # along with this program; if not, write to the Free Software | ||
| 17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 18 | # | ||
| 19 | |||
| 20 | TOPDIR:= ../../ | ||
| 21 | LIBIPROUTE_DIR:=./ | ||
| 22 | include $(TOPDIR).config | ||
| 23 | include $(TOPDIR)Rules.mak | ||
| 24 | include Makefile.in | ||
| 25 | all: $(libraries-y) | ||
| 26 | -include $(TOPDIR).depend | ||
| 27 | |||
| 28 | clean: | ||
| 29 | rm -f *.o *.a $(AR_TARGET) | ||
| 30 | |||
diff --git a/networking/libiproute/Makefile.in b/networking/libiproute/Makefile.in new file mode 100644 index 000000000..9f782af16 --- /dev/null +++ b/networking/libiproute/Makefile.in | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | # Makefile for busybox | ||
| 2 | # | ||
| 3 | # Copyright (C) 1999-2002 by Erik Andersen <andersee@debian.org> | ||
| 4 | # | ||
| 5 | # This program is free software; you can redistribute it and/or modify | ||
| 6 | # it under the terms of the GNU General Public License as published by | ||
| 7 | # the Free Software Foundation; either version 2 of the License, or | ||
| 8 | # (at your option) any later version. | ||
| 9 | # | ||
| 10 | # This program is distributed in the hope that it will be useful, | ||
| 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | # General Public License for more details. | ||
| 14 | # | ||
| 15 | # You should have received a copy of the GNU General Public License | ||
| 16 | # along with this program; if not, write to the Free Software | ||
| 17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 18 | # | ||
| 19 | |||
| 20 | LIBIPROUTE_AR:=libiproute.a | ||
| 21 | ifndef $(LIBIPROUTE_DIR) | ||
| 22 | LIBIPROUTE_DIR:=$(TOPDIR)networking/libiproute/ | ||
| 23 | endif | ||
| 24 | |||
| 25 | LIBIPROUTE-y:= \ | ||
| 26 | ipaddress.o \ | ||
| 27 | iplink.o \ | ||
| 28 | iproute.o \ | ||
| 29 | iptunnel.o \ | ||
| 30 | libnetlink.o \ | ||
| 31 | ll_addr.o \ | ||
| 32 | ll_map.o \ | ||
| 33 | ll_proto.o \ | ||
| 34 | ll_types.o \ | ||
| 35 | rt_names.o \ | ||
| 36 | rtm_map.o \ | ||
| 37 | utils.o | ||
| 38 | |||
| 39 | libraries-y+=$(LIBIPROUTE_DIR)$(LIBIPROUTE_AR) | ||
| 40 | |||
| 41 | $(LIBIPROUTE_DIR)$(LIBIPROUTE_AR): $(patsubst %,$(LIBIPROUTE_DIR)%, $(LIBIPROUTE-y)) | ||
| 42 | $(AR) -ro $@ $(patsubst %,$(LIBIPROUTE_DIR)%, $(LIBIPROUTE-y)) | ||
| 43 | |||
diff --git a/networking/libiproute/ip_common.h b/networking/libiproute/ip_common.h new file mode 100644 index 000000000..5ac43218e --- /dev/null +++ b/networking/libiproute/ip_common.h | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | extern int print_linkinfo(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); | ||
| 2 | extern int print_addrinfo(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); | ||
| 3 | extern int print_neigh(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); | ||
| 4 | extern int ipaddr_list(int argc, char **argv); | ||
| 5 | extern int ipaddr_list_link(int argc, char **argv); | ||
| 6 | extern int iproute_monitor(int argc, char **argv); | ||
| 7 | extern void iplink_usage(void) __attribute__((noreturn)); | ||
| 8 | extern void iproute_reset_filter(void); | ||
| 9 | extern void ipaddr_reset_filter(int); | ||
| 10 | extern void ipneigh_reset_filter(void); | ||
| 11 | extern int print_route(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); | ||
| 12 | extern int do_ipaddr(int argc, char **argv); | ||
| 13 | extern int do_iproute(int argc, char **argv); | ||
| 14 | extern int do_iprule(int argc, char **argv); | ||
| 15 | extern int do_ipneigh(int argc, char **argv); | ||
| 16 | extern int do_iptunnel(int argc, char **argv); | ||
| 17 | extern int do_iplink(int argc, char **argv); | ||
| 18 | extern int do_ipmonitor(int argc, char **argv); | ||
| 19 | extern int do_multiaddr(int argc, char **argv); | ||
| 20 | extern int do_multiroute(int argc, char **argv); | ||
diff --git a/networking/libiproute/ipaddress.c b/networking/libiproute/ipaddress.c new file mode 100644 index 000000000..8f491f327 --- /dev/null +++ b/networking/libiproute/ipaddress.c | |||
| @@ -0,0 +1,723 @@ | |||
| 1 | /* | ||
| 2 | * ipaddress.c "ip address". | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version | ||
| 7 | * 2 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> | ||
| 10 | * | ||
| 11 | * Changes: | ||
| 12 | * Laszlo Valko <valko@linux.karinthy.hu> 990223: address label must be zero terminated | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <stdio.h> | ||
| 16 | #include <stdlib.h> | ||
| 17 | #include <unistd.h> | ||
| 18 | #include <syslog.h> | ||
| 19 | #include <fcntl.h> | ||
| 20 | #include <sys/ioctl.h> | ||
| 21 | #include <sys/socket.h> | ||
| 22 | #include <sys/ioctl.h> | ||
| 23 | #include <netinet/in.h> | ||
| 24 | #include <arpa/inet.h> | ||
| 25 | #include <string.h> | ||
| 26 | #include <fnmatch.h> | ||
| 27 | |||
| 28 | #include <linux/netdevice.h> | ||
| 29 | #include <linux/if_arp.h> | ||
| 30 | #include <linux/sockios.h> | ||
| 31 | |||
| 32 | #include "rt_names.h" | ||
| 33 | #include "utils.h" | ||
| 34 | #include "ll_map.h" | ||
| 35 | #include "ip_common.h" | ||
| 36 | |||
| 37 | #include "busybox.h" | ||
| 38 | |||
| 39 | static struct | ||
| 40 | { | ||
| 41 | int ifindex; | ||
| 42 | int family; | ||
| 43 | int oneline; | ||
| 44 | int showqueue; | ||
| 45 | inet_prefix pfx; | ||
| 46 | int scope, scopemask; | ||
| 47 | int flags, flagmask; | ||
| 48 | int up; | ||
| 49 | char *label; | ||
| 50 | struct rtnl_handle *rth; | ||
| 51 | } filter; | ||
| 52 | |||
| 53 | static int do_link; | ||
| 54 | |||
| 55 | void print_link_flags(FILE *fp, unsigned flags, unsigned mdown) | ||
| 56 | { | ||
| 57 | fprintf(fp, "<"); | ||
| 58 | flags &= ~IFF_RUNNING; | ||
| 59 | #define _PF(f) if (flags&IFF_##f) { \ | ||
| 60 | flags &= ~IFF_##f ; \ | ||
| 61 | fprintf(fp, #f "%s", flags ? "," : ""); } | ||
| 62 | _PF(LOOPBACK); | ||
| 63 | _PF(BROADCAST); | ||
| 64 | _PF(POINTOPOINT); | ||
| 65 | _PF(MULTICAST); | ||
| 66 | _PF(NOARP); | ||
| 67 | #if 0 | ||
| 68 | _PF(ALLMULTI); | ||
| 69 | _PF(PROMISC); | ||
| 70 | _PF(MASTER); | ||
| 71 | _PF(SLAVE); | ||
| 72 | _PF(DEBUG); | ||
| 73 | _PF(DYNAMIC); | ||
| 74 | _PF(AUTOMEDIA); | ||
| 75 | _PF(PORTSEL); | ||
| 76 | _PF(NOTRAILERS); | ||
| 77 | #endif | ||
| 78 | _PF(UP); | ||
| 79 | #undef _PF | ||
| 80 | if (flags) | ||
| 81 | fprintf(fp, "%x", flags); | ||
| 82 | if (mdown) | ||
| 83 | fprintf(fp, ",M-DOWN"); | ||
| 84 | fprintf(fp, "> "); | ||
| 85 | } | ||
| 86 | |||
| 87 | void print_queuelen(char *name) | ||
| 88 | { | ||
| 89 | struct ifreq ifr; | ||
| 90 | int s; | ||
| 91 | |||
| 92 | s = socket(AF_INET, SOCK_STREAM, 0); | ||
| 93 | if (s < 0) | ||
| 94 | return; | ||
| 95 | |||
| 96 | memset(&ifr, 0, sizeof(ifr)); | ||
| 97 | strcpy(ifr.ifr_name, name); | ||
| 98 | if (ioctl(s, SIOCGIFTXQLEN, &ifr) < 0) { | ||
| 99 | perror("SIOCGIFXQLEN"); | ||
| 100 | close(s); | ||
| 101 | return; | ||
| 102 | } | ||
| 103 | close(s); | ||
| 104 | |||
| 105 | if (ifr.ifr_qlen) | ||
| 106 | printf("qlen %d", ifr.ifr_qlen); | ||
| 107 | } | ||
| 108 | |||
| 109 | int print_linkinfo(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) | ||
| 110 | { | ||
| 111 | FILE *fp = (FILE*)arg; | ||
| 112 | struct ifinfomsg *ifi = NLMSG_DATA(n); | ||
| 113 | struct rtattr * tb[IFLA_MAX+1]; | ||
| 114 | int len = n->nlmsg_len; | ||
| 115 | unsigned m_flag = 0; | ||
| 116 | |||
| 117 | if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK) | ||
| 118 | return 0; | ||
| 119 | |||
| 120 | len -= NLMSG_LENGTH(sizeof(*ifi)); | ||
| 121 | if (len < 0) | ||
| 122 | return -1; | ||
| 123 | |||
| 124 | if (filter.ifindex && ifi->ifi_index != filter.ifindex) | ||
| 125 | return 0; | ||
| 126 | if (filter.up && !(ifi->ifi_flags&IFF_UP)) | ||
| 127 | return 0; | ||
| 128 | |||
| 129 | memset(tb, 0, sizeof(tb)); | ||
| 130 | parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); | ||
| 131 | if (tb[IFLA_IFNAME] == NULL) { | ||
| 132 | fprintf(stderr, "BUG: nil ifname\n"); | ||
| 133 | return -1; | ||
| 134 | } | ||
| 135 | if (filter.label && | ||
| 136 | (!filter.family || filter.family == AF_PACKET) && | ||
| 137 | fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0)) | ||
| 138 | return 0; | ||
| 139 | |||
| 140 | if (n->nlmsg_type == RTM_DELLINK) | ||
| 141 | fprintf(fp, "Deleted "); | ||
| 142 | |||
| 143 | fprintf(fp, "%d: %s", ifi->ifi_index, | ||
| 144 | tb[IFLA_IFNAME] ? (char*)RTA_DATA(tb[IFLA_IFNAME]) : "<nil>"); | ||
| 145 | |||
| 146 | if (tb[IFLA_LINK]) { | ||
| 147 | SPRINT_BUF(b1); | ||
| 148 | int iflink = *(int*)RTA_DATA(tb[IFLA_LINK]); | ||
| 149 | if (iflink == 0) | ||
| 150 | fprintf(fp, "@NONE: "); | ||
| 151 | else { | ||
| 152 | fprintf(fp, "@%s: ", ll_idx_n2a(iflink, b1)); | ||
| 153 | m_flag = ll_index_to_flags(iflink); | ||
| 154 | m_flag = !(m_flag & IFF_UP); | ||
| 155 | } | ||
| 156 | } else { | ||
| 157 | fprintf(fp, ": "); | ||
| 158 | } | ||
| 159 | print_link_flags(fp, ifi->ifi_flags, m_flag); | ||
| 160 | |||
| 161 | if (tb[IFLA_MTU]) | ||
| 162 | fprintf(fp, "mtu %u ", *(int*)RTA_DATA(tb[IFLA_MTU])); | ||
| 163 | if (tb[IFLA_QDISC]) | ||
| 164 | fprintf(fp, "qdisc %s ", (char*)RTA_DATA(tb[IFLA_QDISC])); | ||
| 165 | #ifdef IFLA_MASTER | ||
| 166 | if (tb[IFLA_MASTER]) { | ||
| 167 | SPRINT_BUF(b1); | ||
| 168 | fprintf(fp, "master %s ", ll_idx_n2a(*(int*)RTA_DATA(tb[IFLA_MASTER]), b1)); | ||
| 169 | } | ||
| 170 | #endif | ||
| 171 | if (filter.showqueue) | ||
| 172 | print_queuelen((char*)RTA_DATA(tb[IFLA_IFNAME])); | ||
| 173 | |||
| 174 | if (!filter.family || filter.family == AF_PACKET) { | ||
| 175 | SPRINT_BUF(b1); | ||
| 176 | fprintf(fp, "%s", _SL_); | ||
| 177 | fprintf(fp, " link/%s ", ll_type_n2a(ifi->ifi_type, b1, sizeof(b1))); | ||
| 178 | |||
| 179 | if (tb[IFLA_ADDRESS]) { | ||
| 180 | fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]), | ||
| 181 | RTA_PAYLOAD(tb[IFLA_ADDRESS]), | ||
| 182 | ifi->ifi_type, | ||
| 183 | b1, sizeof(b1))); | ||
| 184 | } | ||
| 185 | if (tb[IFLA_BROADCAST]) { | ||
| 186 | if (ifi->ifi_flags&IFF_POINTOPOINT) | ||
| 187 | fprintf(fp, " peer "); | ||
| 188 | else | ||
| 189 | fprintf(fp, " brd "); | ||
| 190 | fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(tb[IFLA_BROADCAST]), | ||
| 191 | RTA_PAYLOAD(tb[IFLA_BROADCAST]), | ||
| 192 | ifi->ifi_type, | ||
| 193 | b1, sizeof(b1))); | ||
| 194 | } | ||
| 195 | } | ||
| 196 | fprintf(fp, "\n"); | ||
| 197 | fflush(fp); | ||
| 198 | return 0; | ||
| 199 | } | ||
| 200 | |||
| 201 | int print_addrinfo(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) | ||
| 202 | { | ||
| 203 | FILE *fp = (FILE*)arg; | ||
| 204 | struct ifaddrmsg *ifa = NLMSG_DATA(n); | ||
| 205 | int len = n->nlmsg_len; | ||
| 206 | struct rtattr * rta_tb[IFA_MAX+1]; | ||
| 207 | char abuf[256]; | ||
| 208 | SPRINT_BUF(b1); | ||
| 209 | |||
| 210 | if (n->nlmsg_type != RTM_NEWADDR && n->nlmsg_type != RTM_DELADDR) | ||
| 211 | return 0; | ||
| 212 | len -= NLMSG_LENGTH(sizeof(*ifa)); | ||
| 213 | if (len < 0) { | ||
| 214 | fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); | ||
| 215 | return -1; | ||
| 216 | } | ||
| 217 | |||
| 218 | memset(rta_tb, 0, sizeof(rta_tb)); | ||
| 219 | parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa))); | ||
| 220 | |||
| 221 | if (!rta_tb[IFA_LOCAL]) | ||
| 222 | rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS]; | ||
| 223 | if (!rta_tb[IFA_ADDRESS]) | ||
| 224 | rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL]; | ||
| 225 | |||
| 226 | if (filter.ifindex && filter.ifindex != ifa->ifa_index) | ||
| 227 | return 0; | ||
| 228 | if ((filter.scope^ifa->ifa_scope)&filter.scopemask) | ||
| 229 | return 0; | ||
| 230 | if ((filter.flags^ifa->ifa_flags)&filter.flagmask) | ||
| 231 | return 0; | ||
| 232 | if (filter.label) { | ||
| 233 | SPRINT_BUF(b1); | ||
| 234 | const char *label; | ||
| 235 | if (rta_tb[IFA_LABEL]) | ||
| 236 | label = RTA_DATA(rta_tb[IFA_LABEL]); | ||
| 237 | else | ||
| 238 | label = ll_idx_n2a(ifa->ifa_index, b1); | ||
| 239 | if (fnmatch(filter.label, label, 0) != 0) | ||
| 240 | return 0; | ||
| 241 | } | ||
| 242 | if (filter.pfx.family) { | ||
| 243 | if (rta_tb[IFA_LOCAL]) { | ||
| 244 | inet_prefix dst; | ||
| 245 | memset(&dst, 0, sizeof(dst)); | ||
| 246 | dst.family = ifa->ifa_family; | ||
| 247 | memcpy(&dst.data, RTA_DATA(rta_tb[IFA_LOCAL]), RTA_PAYLOAD(rta_tb[IFA_LOCAL])); | ||
| 248 | if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen)) | ||
| 249 | return 0; | ||
| 250 | } | ||
| 251 | } | ||
| 252 | |||
| 253 | if (n->nlmsg_type == RTM_DELADDR) | ||
| 254 | fprintf(fp, "Deleted "); | ||
| 255 | |||
| 256 | if (filter.oneline) | ||
| 257 | fprintf(fp, "%u: %s", ifa->ifa_index, ll_index_to_name(ifa->ifa_index)); | ||
| 258 | if (ifa->ifa_family == AF_INET) | ||
| 259 | fprintf(fp, " inet "); | ||
| 260 | else if (ifa->ifa_family == AF_INET6) | ||
| 261 | fprintf(fp, " inet6 "); | ||
| 262 | else | ||
| 263 | fprintf(fp, " family %d ", ifa->ifa_family); | ||
| 264 | |||
| 265 | if (rta_tb[IFA_LOCAL]) { | ||
| 266 | fprintf(fp, "%s", rt_addr_n2a(ifa->ifa_family, | ||
| 267 | RTA_PAYLOAD(rta_tb[IFA_LOCAL]), | ||
| 268 | RTA_DATA(rta_tb[IFA_LOCAL]), | ||
| 269 | abuf, sizeof(abuf))); | ||
| 270 | |||
| 271 | if (rta_tb[IFA_ADDRESS] == NULL || | ||
| 272 | memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]), 4) == 0) { | ||
| 273 | fprintf(fp, "/%d ", ifa->ifa_prefixlen); | ||
| 274 | } else { | ||
| 275 | fprintf(fp, " peer %s/%d ", | ||
| 276 | rt_addr_n2a(ifa->ifa_family, | ||
| 277 | RTA_PAYLOAD(rta_tb[IFA_ADDRESS]), | ||
| 278 | RTA_DATA(rta_tb[IFA_ADDRESS]), | ||
| 279 | abuf, sizeof(abuf)), | ||
| 280 | ifa->ifa_prefixlen); | ||
| 281 | } | ||
| 282 | } | ||
| 283 | |||
| 284 | if (rta_tb[IFA_BROADCAST]) { | ||
| 285 | fprintf(fp, "brd %s ", | ||
| 286 | rt_addr_n2a(ifa->ifa_family, | ||
| 287 | RTA_PAYLOAD(rta_tb[IFA_BROADCAST]), | ||
| 288 | RTA_DATA(rta_tb[IFA_BROADCAST]), | ||
| 289 | abuf, sizeof(abuf))); | ||
| 290 | } | ||
| 291 | if (rta_tb[IFA_ANYCAST]) { | ||
| 292 | fprintf(fp, "any %s ", | ||
| 293 | rt_addr_n2a(ifa->ifa_family, | ||
| 294 | RTA_PAYLOAD(rta_tb[IFA_ANYCAST]), | ||
| 295 | RTA_DATA(rta_tb[IFA_ANYCAST]), | ||
| 296 | abuf, sizeof(abuf))); | ||
| 297 | } | ||
| 298 | fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1))); | ||
| 299 | if (ifa->ifa_flags&IFA_F_SECONDARY) { | ||
| 300 | ifa->ifa_flags &= ~IFA_F_SECONDARY; | ||
| 301 | fprintf(fp, "secondary "); | ||
| 302 | } | ||
| 303 | if (ifa->ifa_flags&IFA_F_TENTATIVE) { | ||
| 304 | ifa->ifa_flags &= ~IFA_F_TENTATIVE; | ||
| 305 | fprintf(fp, "tentative "); | ||
| 306 | } | ||
| 307 | if (ifa->ifa_flags&IFA_F_DEPRECATED) { | ||
| 308 | ifa->ifa_flags &= ~IFA_F_DEPRECATED; | ||
| 309 | fprintf(fp, "deprecated "); | ||
| 310 | } | ||
| 311 | if (!(ifa->ifa_flags&IFA_F_PERMANENT)) { | ||
| 312 | fprintf(fp, "dynamic "); | ||
| 313 | } else | ||
| 314 | ifa->ifa_flags &= ~IFA_F_PERMANENT; | ||
| 315 | if (ifa->ifa_flags) | ||
| 316 | fprintf(fp, "flags %02x ", ifa->ifa_flags); | ||
| 317 | if (rta_tb[IFA_LABEL]) | ||
| 318 | fprintf(fp, "%s", (char*)RTA_DATA(rta_tb[IFA_LABEL])); | ||
| 319 | if (rta_tb[IFA_CACHEINFO]) { | ||
| 320 | struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]); | ||
| 321 | char buf[128]; | ||
| 322 | fprintf(fp, "%s", _SL_); | ||
| 323 | if (ci->ifa_valid == 0xFFFFFFFFU) | ||
| 324 | sprintf(buf, "valid_lft forever"); | ||
| 325 | else | ||
| 326 | sprintf(buf, "valid_lft %dsec", ci->ifa_valid); | ||
| 327 | if (ci->ifa_prefered == 0xFFFFFFFFU) | ||
| 328 | sprintf(buf+strlen(buf), " preferred_lft forever"); | ||
| 329 | else | ||
| 330 | sprintf(buf+strlen(buf), " preferred_lft %dsec", ci->ifa_prefered); | ||
| 331 | fprintf(fp, " %s", buf); | ||
| 332 | } | ||
| 333 | fprintf(fp, "\n"); | ||
| 334 | fflush(fp); | ||
| 335 | return 0; | ||
| 336 | } | ||
| 337 | |||
| 338 | |||
| 339 | struct nlmsg_list | ||
| 340 | { | ||
| 341 | struct nlmsg_list *next; | ||
| 342 | struct nlmsghdr h; | ||
| 343 | }; | ||
| 344 | |||
| 345 | int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo, FILE *fp) | ||
| 346 | { | ||
| 347 | for ( ;ainfo ; ainfo = ainfo->next) { | ||
| 348 | struct nlmsghdr *n = &ainfo->h; | ||
| 349 | struct ifaddrmsg *ifa = NLMSG_DATA(n); | ||
| 350 | |||
| 351 | if (n->nlmsg_type != RTM_NEWADDR) | ||
| 352 | continue; | ||
| 353 | |||
| 354 | if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifa))) | ||
| 355 | return -1; | ||
| 356 | |||
| 357 | if (ifa->ifa_index != ifindex || | ||
| 358 | (filter.family && filter.family != ifa->ifa_family)) | ||
| 359 | continue; | ||
| 360 | |||
| 361 | print_addrinfo(NULL, n, fp); | ||
| 362 | } | ||
| 363 | return 0; | ||
| 364 | } | ||
| 365 | |||
| 366 | |||
| 367 | int store_nlmsg(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) | ||
| 368 | { | ||
| 369 | struct nlmsg_list **linfo = (struct nlmsg_list**)arg; | ||
| 370 | struct nlmsg_list *h; | ||
| 371 | struct nlmsg_list **lp; | ||
| 372 | |||
| 373 | h = malloc(n->nlmsg_len+sizeof(void*)); | ||
| 374 | if (h == NULL) | ||
| 375 | return -1; | ||
| 376 | |||
| 377 | memcpy(&h->h, n, n->nlmsg_len); | ||
| 378 | h->next = NULL; | ||
| 379 | |||
| 380 | for (lp = linfo; *lp; lp = &(*lp)->next) /* NOTHING */; | ||
| 381 | *lp = h; | ||
| 382 | |||
| 383 | ll_remember_index(who, n, NULL); | ||
| 384 | return 0; | ||
| 385 | } | ||
| 386 | |||
| 387 | int ipaddr_list(int argc, char **argv) | ||
| 388 | { | ||
| 389 | struct nlmsg_list *linfo = NULL; | ||
| 390 | struct nlmsg_list *ainfo = NULL; | ||
| 391 | struct nlmsg_list *l; | ||
| 392 | struct rtnl_handle rth; | ||
| 393 | char *filter_dev = NULL; | ||
| 394 | int no_link = 0; | ||
| 395 | |||
| 396 | ipaddr_reset_filter(oneline); | ||
| 397 | filter.showqueue = 1; | ||
| 398 | |||
| 399 | if (filter.family == AF_UNSPEC) | ||
| 400 | filter.family = preferred_family; | ||
| 401 | |||
| 402 | while (argc > 0) { | ||
| 403 | if (strcmp(*argv, "to") == 0) { | ||
| 404 | NEXT_ARG(); | ||
| 405 | get_prefix(&filter.pfx, *argv, filter.family); | ||
| 406 | if (filter.family == AF_UNSPEC) | ||
| 407 | filter.family = filter.pfx.family; | ||
| 408 | } else if (strcmp(*argv, "scope") == 0) { | ||
| 409 | int scope = 0; | ||
| 410 | NEXT_ARG(); | ||
| 411 | filter.scopemask = -1; | ||
| 412 | if (rtnl_rtscope_a2n(&scope, *argv)) { | ||
| 413 | if (strcmp(*argv, "all") != 0) | ||
| 414 | invarg("invalid \"scope\"\n", *argv); | ||
| 415 | scope = RT_SCOPE_NOWHERE; | ||
| 416 | filter.scopemask = 0; | ||
| 417 | } | ||
| 418 | filter.scope = scope; | ||
| 419 | } else if (strcmp(*argv, "up") == 0) { | ||
| 420 | filter.up = 1; | ||
| 421 | } else if (strcmp(*argv, "label") == 0) { | ||
| 422 | NEXT_ARG(); | ||
| 423 | filter.label = *argv; | ||
| 424 | } else { | ||
| 425 | if (strcmp(*argv, "dev") == 0) { | ||
| 426 | NEXT_ARG(); | ||
| 427 | } | ||
| 428 | if (filter_dev) | ||
| 429 | duparg2("dev", *argv); | ||
| 430 | filter_dev = *argv; | ||
| 431 | } | ||
| 432 | argv++; argc--; | ||
| 433 | } | ||
| 434 | |||
| 435 | if (rtnl_open(&rth, 0) < 0) | ||
| 436 | exit(1); | ||
| 437 | |||
| 438 | if (rtnl_wilddump_request(&rth, preferred_family, RTM_GETLINK) < 0) { | ||
| 439 | perror("Cannot send dump request"); | ||
| 440 | exit(1); | ||
| 441 | } | ||
| 442 | |||
| 443 | if (rtnl_dump_filter(&rth, store_nlmsg, &linfo, NULL, NULL) < 0) { | ||
| 444 | fprintf(stderr, "Dump terminated\n"); | ||
| 445 | exit(1); | ||
| 446 | } | ||
| 447 | |||
| 448 | if (filter_dev) { | ||
| 449 | filter.ifindex = ll_name_to_index(filter_dev); | ||
| 450 | if (filter.ifindex <= 0) { | ||
| 451 | fprintf(stderr, "Device \"%s\" does not exist.\n", filter_dev); | ||
| 452 | return -1; | ||
| 453 | } | ||
| 454 | } | ||
| 455 | |||
| 456 | if (filter.family != AF_PACKET) { | ||
| 457 | if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) { | ||
| 458 | perror("Cannot send dump request"); | ||
| 459 | exit(1); | ||
| 460 | } | ||
| 461 | |||
| 462 | if (rtnl_dump_filter(&rth, store_nlmsg, &ainfo, NULL, NULL) < 0) { | ||
| 463 | fprintf(stderr, "Dump terminated\n"); | ||
| 464 | exit(1); | ||
| 465 | } | ||
| 466 | } | ||
| 467 | |||
| 468 | |||
| 469 | if (filter.family && filter.family != AF_PACKET) { | ||
| 470 | struct nlmsg_list **lp; | ||
| 471 | lp=&linfo; | ||
| 472 | |||
| 473 | if (filter.oneline) | ||
| 474 | no_link = 1; | ||
| 475 | |||
| 476 | while ((l=*lp)!=NULL) { | ||
| 477 | int ok = 0; | ||
| 478 | struct ifinfomsg *ifi = NLMSG_DATA(&l->h); | ||
| 479 | struct nlmsg_list *a; | ||
| 480 | |||
| 481 | for (a=ainfo; a; a=a->next) { | ||
| 482 | struct nlmsghdr *n = &a->h; | ||
| 483 | struct ifaddrmsg *ifa = NLMSG_DATA(n); | ||
| 484 | |||
| 485 | if (ifa->ifa_index != ifi->ifi_index || | ||
| 486 | (filter.family && filter.family != ifa->ifa_family)) | ||
| 487 | continue; | ||
| 488 | if ((filter.scope^ifa->ifa_scope)&filter.scopemask) | ||
| 489 | continue; | ||
| 490 | if ((filter.flags^ifa->ifa_flags)&filter.flagmask) | ||
| 491 | continue; | ||
| 492 | if (filter.pfx.family || filter.label) { | ||
| 493 | struct rtattr *tb[IFA_MAX+1]; | ||
| 494 | memset(tb, 0, sizeof(tb)); | ||
| 495 | parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(n)); | ||
| 496 | if (!tb[IFA_LOCAL]) | ||
| 497 | tb[IFA_LOCAL] = tb[IFA_ADDRESS]; | ||
| 498 | |||
| 499 | if (filter.pfx.family && tb[IFA_LOCAL]) { | ||
| 500 | inet_prefix dst; | ||
| 501 | memset(&dst, 0, sizeof(dst)); | ||
| 502 | dst.family = ifa->ifa_family; | ||
| 503 | memcpy(&dst.data, RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_LOCAL])); | ||
| 504 | if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen)) | ||
| 505 | continue; | ||
| 506 | } | ||
| 507 | if (filter.label) { | ||
| 508 | SPRINT_BUF(b1); | ||
| 509 | const char *label; | ||
| 510 | if (tb[IFA_LABEL]) | ||
| 511 | label = RTA_DATA(tb[IFA_LABEL]); | ||
| 512 | else | ||
| 513 | label = ll_idx_n2a(ifa->ifa_index, b1); | ||
| 514 | if (fnmatch(filter.label, label, 0) != 0) | ||
| 515 | continue; | ||
| 516 | } | ||
| 517 | } | ||
| 518 | |||
| 519 | ok = 1; | ||
| 520 | break; | ||
| 521 | } | ||
| 522 | if (!ok) | ||
| 523 | *lp = l->next; | ||
| 524 | else | ||
| 525 | lp = &l->next; | ||
| 526 | } | ||
| 527 | } | ||
| 528 | |||
| 529 | for (l=linfo; l; l = l->next) { | ||
| 530 | if (no_link || print_linkinfo(NULL, &l->h, stdout) == 0) { | ||
| 531 | struct ifinfomsg *ifi = NLMSG_DATA(&l->h); | ||
| 532 | if (filter.family != AF_PACKET) | ||
| 533 | print_selected_addrinfo(ifi->ifi_index, ainfo, stdout); | ||
| 534 | } | ||
| 535 | fflush(stdout); | ||
| 536 | } | ||
| 537 | |||
| 538 | exit(0); | ||
| 539 | } | ||
| 540 | |||
| 541 | int ipaddr_list_link(int argc, char **argv) | ||
| 542 | { | ||
| 543 | preferred_family = AF_PACKET; | ||
| 544 | do_link = 1; | ||
| 545 | return ipaddr_list(argc, argv); | ||
| 546 | } | ||
| 547 | |||
| 548 | void ipaddr_reset_filter(int oneline) | ||
| 549 | { | ||
| 550 | memset(&filter, 0, sizeof(filter)); | ||
| 551 | filter.oneline = oneline; | ||
| 552 | } | ||
| 553 | |||
| 554 | int default_scope(inet_prefix *lcl) | ||
| 555 | { | ||
| 556 | if (lcl->family == AF_INET) { | ||
| 557 | if (lcl->bytelen >= 1 && *(__u8*)&lcl->data == 127) | ||
| 558 | return RT_SCOPE_HOST; | ||
| 559 | } | ||
| 560 | return 0; | ||
| 561 | } | ||
| 562 | |||
| 563 | int ipaddr_modify(int cmd, int argc, char **argv) | ||
| 564 | { | ||
| 565 | struct rtnl_handle rth; | ||
| 566 | struct { | ||
| 567 | struct nlmsghdr n; | ||
| 568 | struct ifaddrmsg ifa; | ||
| 569 | char buf[256]; | ||
| 570 | } req; | ||
| 571 | char *d = NULL; | ||
| 572 | char *l = NULL; | ||
| 573 | inet_prefix lcl; | ||
| 574 | inet_prefix peer; | ||
| 575 | int local_len = 0; | ||
| 576 | int peer_len = 0; | ||
| 577 | int brd_len = 0; | ||
| 578 | int any_len = 0; | ||
| 579 | int scoped = 0; | ||
| 580 | |||
| 581 | memset(&req, 0, sizeof(req)); | ||
| 582 | |||
| 583 | req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); | ||
| 584 | req.n.nlmsg_flags = NLM_F_REQUEST; | ||
| 585 | req.n.nlmsg_type = cmd; | ||
| 586 | req.ifa.ifa_family = preferred_family; | ||
| 587 | |||
| 588 | while (argc > 0) { | ||
| 589 | if (strcmp(*argv, "peer") == 0 || | ||
| 590 | strcmp(*argv, "remote") == 0) { | ||
| 591 | NEXT_ARG(); | ||
| 592 | |||
| 593 | if (peer_len) | ||
| 594 | duparg("peer", *argv); | ||
| 595 | get_prefix(&peer, *argv, req.ifa.ifa_family); | ||
| 596 | peer_len = peer.bytelen; | ||
| 597 | if (req.ifa.ifa_family == AF_UNSPEC) | ||
| 598 | req.ifa.ifa_family = peer.family; | ||
| 599 | addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &peer.data, peer.bytelen); | ||
| 600 | req.ifa.ifa_prefixlen = peer.bitlen; | ||
| 601 | } else if (matches(*argv, "broadcast") == 0 || | ||
| 602 | strcmp(*argv, "brd") == 0) { | ||
| 603 | inet_prefix addr; | ||
| 604 | NEXT_ARG(); | ||
| 605 | if (brd_len) | ||
| 606 | duparg("broadcast", *argv); | ||
| 607 | if (strcmp(*argv, "+") == 0) | ||
| 608 | brd_len = -1; | ||
| 609 | else if (strcmp(*argv, "-") == 0) | ||
| 610 | brd_len = -2; | ||
| 611 | else { | ||
| 612 | get_addr(&addr, *argv, req.ifa.ifa_family); | ||
| 613 | if (req.ifa.ifa_family == AF_UNSPEC) | ||
| 614 | req.ifa.ifa_family = addr.family; | ||
| 615 | addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &addr.data, addr.bytelen); | ||
| 616 | brd_len = addr.bytelen; | ||
| 617 | } | ||
| 618 | } else if (strcmp(*argv, "anycast") == 0) { | ||
| 619 | inet_prefix addr; | ||
| 620 | NEXT_ARG(); | ||
| 621 | if (any_len) | ||
| 622 | duparg("anycast", *argv); | ||
| 623 | get_addr(&addr, *argv, req.ifa.ifa_family); | ||
| 624 | if (req.ifa.ifa_family == AF_UNSPEC) | ||
| 625 | req.ifa.ifa_family = addr.family; | ||
| 626 | addattr_l(&req.n, sizeof(req), IFA_ANYCAST, &addr.data, addr.bytelen); | ||
| 627 | any_len = addr.bytelen; | ||
| 628 | } else if (strcmp(*argv, "scope") == 0) { | ||
| 629 | int scope = 0; | ||
| 630 | NEXT_ARG(); | ||
| 631 | if (rtnl_rtscope_a2n(&scope, *argv)) | ||
| 632 | invarg(*argv, "invalid scope value."); | ||
| 633 | req.ifa.ifa_scope = scope; | ||
| 634 | scoped = 1; | ||
| 635 | } else if (strcmp(*argv, "dev") == 0) { | ||
| 636 | NEXT_ARG(); | ||
| 637 | d = *argv; | ||
| 638 | } else if (strcmp(*argv, "label") == 0) { | ||
| 639 | NEXT_ARG(); | ||
| 640 | l = *argv; | ||
| 641 | addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1); | ||
| 642 | } else { | ||
| 643 | if (strcmp(*argv, "local") == 0) { | ||
| 644 | NEXT_ARG(); | ||
| 645 | } | ||
| 646 | if (local_len) | ||
| 647 | duparg2("local", *argv); | ||
| 648 | get_prefix(&lcl, *argv, req.ifa.ifa_family); | ||
| 649 | if (req.ifa.ifa_family == AF_UNSPEC) | ||
| 650 | req.ifa.ifa_family = lcl.family; | ||
| 651 | addattr_l(&req.n, sizeof(req), IFA_LOCAL, &lcl.data, lcl.bytelen); | ||
| 652 | local_len = lcl.bytelen; | ||
| 653 | } | ||
| 654 | argc--; argv++; | ||
| 655 | } | ||
| 656 | if (d == NULL) { | ||
| 657 | fprintf(stderr, "Not enough information: \"dev\" argument is required.\n"); | ||
| 658 | return -1; | ||
| 659 | } | ||
| 660 | if (l && matches(d, l) != 0) { | ||
| 661 | fprintf(stderr, "\"dev\" (%s) must match \"label\" (%s).\n", d, l); | ||
| 662 | exit(1); | ||
| 663 | } | ||
| 664 | |||
| 665 | if (peer_len == 0 && local_len && cmd != RTM_DELADDR) { | ||
| 666 | peer = lcl; | ||
| 667 | addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &lcl.data, lcl.bytelen); | ||
| 668 | } | ||
| 669 | if (req.ifa.ifa_prefixlen == 0) | ||
| 670 | req.ifa.ifa_prefixlen = lcl.bitlen; | ||
| 671 | |||
| 672 | if (brd_len < 0 && cmd != RTM_DELADDR) { | ||
| 673 | inet_prefix brd; | ||
| 674 | int i; | ||
| 675 | if (req.ifa.ifa_family != AF_INET) { | ||
| 676 | fprintf(stderr, "Broadcast can be set only for IPv4 addresses\n"); | ||
| 677 | return -1; | ||
| 678 | } | ||
| 679 | brd = peer; | ||
| 680 | if (brd.bitlen <= 30) { | ||
| 681 | for (i=31; i>=brd.bitlen; i--) { | ||
| 682 | if (brd_len == -1) | ||
| 683 | brd.data[0] |= htonl(1<<(31-i)); | ||
| 684 | else | ||
| 685 | brd.data[0] &= ~htonl(1<<(31-i)); | ||
| 686 | } | ||
| 687 | addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &brd.data, brd.bytelen); | ||
| 688 | brd_len = brd.bytelen; | ||
| 689 | } | ||
| 690 | } | ||
| 691 | if (!scoped && cmd != RTM_DELADDR) | ||
| 692 | req.ifa.ifa_scope = default_scope(&lcl); | ||
| 693 | |||
| 694 | if (rtnl_open(&rth, 0) < 0) | ||
| 695 | exit(1); | ||
| 696 | |||
| 697 | ll_init_map(&rth); | ||
| 698 | |||
| 699 | if ((req.ifa.ifa_index = ll_name_to_index(d)) == 0) { | ||
| 700 | fprintf(stderr, "Cannot find device \"%s\"\n", d); | ||
| 701 | return -1; | ||
| 702 | } | ||
| 703 | |||
| 704 | if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) | ||
| 705 | exit(2); | ||
| 706 | |||
| 707 | exit(0); | ||
| 708 | } | ||
| 709 | |||
| 710 | int do_ipaddr(int argc, char **argv) | ||
| 711 | { | ||
| 712 | if (argc < 1) | ||
| 713 | return ipaddr_list(0, NULL); | ||
| 714 | if (matches(*argv, "add") == 0) | ||
| 715 | return ipaddr_modify(RTM_NEWADDR, argc-1, argv+1); | ||
| 716 | if (matches(*argv, "delete") == 0) | ||
| 717 | return ipaddr_modify(RTM_DELADDR, argc-1, argv+1); | ||
| 718 | if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0 | ||
| 719 | || matches(*argv, "lst") == 0) | ||
| 720 | return ipaddr_list(argc-1, argv+1); | ||
| 721 | fprintf(stderr, "Command \"%s\" is unknown, try \"ip address help\".\n", *argv); | ||
| 722 | exit(-1); | ||
| 723 | } | ||
diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c new file mode 100644 index 000000000..90d60b44c --- /dev/null +++ b/networking/libiproute/iplink.c | |||
| @@ -0,0 +1,349 @@ | |||
| 1 | /* | ||
| 2 | * iplink.c "ip link". | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version | ||
| 7 | * 2 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> | ||
| 10 | * | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <stdio.h> | ||
| 14 | #include <stdlib.h> | ||
| 15 | #include <unistd.h> | ||
| 16 | #include <syslog.h> | ||
| 17 | #include <fcntl.h> | ||
| 18 | #include <errno.h> | ||
| 19 | #include <sys/socket.h> | ||
| 20 | #include <linux/if.h> | ||
| 21 | #include <linux/if_packet.h> | ||
| 22 | #include <linux/if_ether.h> | ||
| 23 | #include <linux/sockios.h> | ||
| 24 | #include <netinet/in.h> | ||
| 25 | #include <arpa/inet.h> | ||
| 26 | #include <string.h> | ||
| 27 | #include <sys/ioctl.h> | ||
| 28 | #include <linux/sockios.h> | ||
| 29 | |||
| 30 | #include "rt_names.h" | ||
| 31 | #include "utils.h" | ||
| 32 | #include "ip_common.h" | ||
| 33 | |||
| 34 | #include "busybox.h" | ||
| 35 | |||
| 36 | static int on_off(char *msg) | ||
| 37 | { | ||
| 38 | fprintf(stderr, "Error: argument of \"%s\" must be \"on\" or \"off\"\n", msg); | ||
| 39 | return -1; | ||
| 40 | } | ||
| 41 | |||
| 42 | static int get_ctl_fd(void) | ||
| 43 | { | ||
| 44 | int s_errno; | ||
| 45 | int fd; | ||
| 46 | |||
| 47 | fd = socket(PF_INET, SOCK_DGRAM, 0); | ||
| 48 | if (fd >= 0) | ||
| 49 | return fd; | ||
| 50 | s_errno = errno; | ||
| 51 | fd = socket(PF_PACKET, SOCK_DGRAM, 0); | ||
| 52 | if (fd >= 0) | ||
| 53 | return fd; | ||
| 54 | fd = socket(PF_INET6, SOCK_DGRAM, 0); | ||
| 55 | if (fd >= 0) | ||
| 56 | return fd; | ||
| 57 | errno = s_errno; | ||
| 58 | perror("Cannot create control socket"); | ||
| 59 | return -1; | ||
| 60 | } | ||
| 61 | |||
| 62 | static int do_chflags(char *dev, __u32 flags, __u32 mask) | ||
| 63 | { | ||
| 64 | struct ifreq ifr; | ||
| 65 | int fd; | ||
| 66 | int err; | ||
| 67 | |||
| 68 | strcpy(ifr.ifr_name, dev); | ||
| 69 | fd = get_ctl_fd(); | ||
| 70 | if (fd < 0) | ||
| 71 | return -1; | ||
| 72 | err = ioctl(fd, SIOCGIFFLAGS, &ifr); | ||
| 73 | if (err) { | ||
| 74 | perror("SIOCGIFFLAGS"); | ||
| 75 | close(fd); | ||
| 76 | return -1; | ||
| 77 | } | ||
| 78 | if ((ifr.ifr_flags^flags)&mask) { | ||
| 79 | ifr.ifr_flags &= ~mask; | ||
| 80 | ifr.ifr_flags |= mask&flags; | ||
| 81 | err = ioctl(fd, SIOCSIFFLAGS, &ifr); | ||
| 82 | if (err) | ||
| 83 | perror("SIOCSIFFLAGS"); | ||
| 84 | } | ||
| 85 | close(fd); | ||
| 86 | return err; | ||
| 87 | } | ||
| 88 | |||
| 89 | static int do_changename(char *dev, char *newdev) | ||
| 90 | { | ||
| 91 | struct ifreq ifr; | ||
| 92 | int fd; | ||
| 93 | int err; | ||
| 94 | |||
| 95 | strcpy(ifr.ifr_name, dev); | ||
| 96 | strcpy(ifr.ifr_newname, newdev); | ||
| 97 | fd = get_ctl_fd(); | ||
| 98 | if (fd < 0) | ||
| 99 | return -1; | ||
| 100 | err = ioctl(fd, SIOCSIFNAME, &ifr); | ||
| 101 | if (err) { | ||
| 102 | perror("SIOCSIFNAME"); | ||
| 103 | close(fd); | ||
| 104 | return -1; | ||
| 105 | } | ||
| 106 | close(fd); | ||
| 107 | return err; | ||
| 108 | } | ||
| 109 | |||
| 110 | static int set_qlen(char *dev, int qlen) | ||
| 111 | { | ||
| 112 | struct ifreq ifr; | ||
| 113 | int s; | ||
| 114 | |||
| 115 | s = get_ctl_fd(); | ||
| 116 | if (s < 0) | ||
| 117 | return -1; | ||
| 118 | |||
| 119 | memset(&ifr, 0, sizeof(ifr)); | ||
| 120 | strcpy(ifr.ifr_name, dev); | ||
| 121 | ifr.ifr_qlen = qlen; | ||
| 122 | if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) { | ||
| 123 | perror("SIOCSIFXQLEN"); | ||
| 124 | close(s); | ||
| 125 | return -1; | ||
| 126 | } | ||
| 127 | close(s); | ||
| 128 | |||
| 129 | return 0; | ||
| 130 | } | ||
| 131 | |||
| 132 | static int set_mtu(char *dev, int mtu) | ||
| 133 | { | ||
| 134 | struct ifreq ifr; | ||
| 135 | int s; | ||
| 136 | |||
| 137 | s = get_ctl_fd(); | ||
| 138 | if (s < 0) | ||
| 139 | return -1; | ||
| 140 | |||
| 141 | memset(&ifr, 0, sizeof(ifr)); | ||
| 142 | strcpy(ifr.ifr_name, dev); | ||
| 143 | ifr.ifr_mtu = mtu; | ||
| 144 | if (ioctl(s, SIOCSIFMTU, &ifr) < 0) { | ||
| 145 | perror("SIOCSIFMTU"); | ||
| 146 | close(s); | ||
| 147 | return -1; | ||
| 148 | } | ||
| 149 | close(s); | ||
| 150 | |||
| 151 | return 0; | ||
| 152 | } | ||
| 153 | |||
| 154 | static int get_address(char *dev, int *htype) | ||
| 155 | { | ||
| 156 | struct ifreq ifr; | ||
| 157 | struct sockaddr_ll me; | ||
| 158 | int alen; | ||
| 159 | int s; | ||
| 160 | |||
| 161 | s = socket(PF_PACKET, SOCK_DGRAM, 0); | ||
| 162 | if (s < 0) { | ||
| 163 | perror("socket(PF_PACKET)"); | ||
| 164 | return -1; | ||
| 165 | } | ||
| 166 | |||
| 167 | memset(&ifr, 0, sizeof(ifr)); | ||
| 168 | strcpy(ifr.ifr_name, dev); | ||
| 169 | if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { | ||
| 170 | perror("SIOCGIFINDEX"); | ||
| 171 | close(s); | ||
| 172 | return -1; | ||
| 173 | } | ||
| 174 | |||
| 175 | memset(&me, 0, sizeof(me)); | ||
| 176 | me.sll_family = AF_PACKET; | ||
| 177 | me.sll_ifindex = ifr.ifr_ifindex; | ||
| 178 | me.sll_protocol = htons(ETH_P_LOOP); | ||
| 179 | if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) { | ||
| 180 | perror("bind"); | ||
| 181 | close(s); | ||
| 182 | return -1; | ||
| 183 | } | ||
| 184 | |||
| 185 | alen = sizeof(me); | ||
| 186 | if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) { | ||
| 187 | perror("getsockname"); | ||
| 188 | close(s); | ||
| 189 | return -1; | ||
| 190 | } | ||
| 191 | close(s); | ||
| 192 | *htype = me.sll_hatype; | ||
| 193 | return me.sll_halen; | ||
| 194 | } | ||
| 195 | |||
| 196 | static int parse_address(char *dev, int hatype, int halen, char *lla, struct ifreq *ifr) | ||
| 197 | { | ||
| 198 | int alen; | ||
| 199 | |||
| 200 | memset(ifr, 0, sizeof(*ifr)); | ||
| 201 | strcpy(ifr->ifr_name, dev); | ||
| 202 | ifr->ifr_hwaddr.sa_family = hatype; | ||
| 203 | alen = ll_addr_a2n(ifr->ifr_hwaddr.sa_data, 14, lla); | ||
| 204 | if (alen < 0) | ||
| 205 | return -1; | ||
| 206 | if (alen != halen) { | ||
| 207 | fprintf(stderr, "Wrong address (%s) length: expected %d bytes\n", lla, halen); | ||
| 208 | return -1; | ||
| 209 | } | ||
| 210 | return 0; | ||
| 211 | } | ||
| 212 | |||
| 213 | static int set_address(struct ifreq *ifr, int brd) | ||
| 214 | { | ||
| 215 | int s; | ||
| 216 | |||
| 217 | s = get_ctl_fd(); | ||
| 218 | if (s < 0) | ||
| 219 | return -1; | ||
| 220 | if (ioctl(s, brd?SIOCSIFHWBROADCAST:SIOCSIFHWADDR, ifr) < 0) { | ||
| 221 | perror(brd?"SIOCSIFHWBROADCAST":"SIOCSIFHWADDR"); | ||
| 222 | close(s); | ||
| 223 | return -1; | ||
| 224 | } | ||
| 225 | close(s); | ||
| 226 | return 0; | ||
| 227 | } | ||
| 228 | |||
| 229 | |||
| 230 | static int do_set(int argc, char **argv) | ||
| 231 | { | ||
| 232 | char *dev = NULL; | ||
| 233 | __u32 mask = 0; | ||
| 234 | __u32 flags = 0; | ||
| 235 | int qlen = -1; | ||
| 236 | int mtu = -1; | ||
| 237 | char *newaddr = NULL; | ||
| 238 | char *newbrd = NULL; | ||
| 239 | struct ifreq ifr0, ifr1; | ||
| 240 | char *newname = NULL; | ||
| 241 | int htype, halen; | ||
| 242 | |||
| 243 | while (argc > 0) { | ||
| 244 | if (strcmp(*argv, "up") == 0) { | ||
| 245 | mask |= IFF_UP; | ||
| 246 | flags |= IFF_UP; | ||
| 247 | } else if (strcmp(*argv, "down") == 0) { | ||
| 248 | mask |= IFF_UP; | ||
| 249 | flags &= ~IFF_UP; | ||
| 250 | } else if (strcmp(*argv, "name") == 0) { | ||
| 251 | NEXT_ARG(); | ||
| 252 | newname = *argv; | ||
| 253 | } else if (strcmp(*argv, "mtu") == 0) { | ||
| 254 | NEXT_ARG(); | ||
| 255 | if (mtu != -1) | ||
| 256 | duparg("mtu", *argv); | ||
| 257 | if (get_integer(&mtu, *argv, 0)) | ||
| 258 | invarg("Invalid \"mtu\" value\n", *argv); | ||
| 259 | } else if (strcmp(*argv, "multicast") == 0) { | ||
| 260 | NEXT_ARG(); | ||
| 261 | mask |= IFF_MULTICAST; | ||
| 262 | if (strcmp(*argv, "on") == 0) { | ||
| 263 | flags |= IFF_MULTICAST; | ||
| 264 | } else if (strcmp(*argv, "off") == 0) { | ||
| 265 | flags &= ~IFF_MULTICAST; | ||
| 266 | } else | ||
| 267 | return on_off("multicast"); | ||
| 268 | } else if (strcmp(*argv, "arp") == 0) { | ||
| 269 | NEXT_ARG(); | ||
| 270 | mask |= IFF_NOARP; | ||
| 271 | if (strcmp(*argv, "on") == 0) { | ||
| 272 | flags &= ~IFF_NOARP; | ||
| 273 | } else if (strcmp(*argv, "off") == 0) { | ||
| 274 | flags |= IFF_NOARP; | ||
| 275 | } else | ||
| 276 | return on_off("noarp"); | ||
| 277 | } else { | ||
| 278 | if (strcmp(*argv, "dev") == 0) { | ||
| 279 | NEXT_ARG(); | ||
| 280 | } | ||
| 281 | if (dev) | ||
| 282 | duparg2("dev", *argv); | ||
| 283 | dev = *argv; | ||
| 284 | } | ||
| 285 | argc--; argv++; | ||
| 286 | } | ||
| 287 | |||
| 288 | if (!dev) { | ||
| 289 | fprintf(stderr, "Not enough of information: \"dev\" argument is required.\n"); | ||
| 290 | exit(-1); | ||
| 291 | } | ||
| 292 | |||
| 293 | if (newaddr || newbrd) { | ||
| 294 | halen = get_address(dev, &htype); | ||
| 295 | if (halen < 0) | ||
| 296 | return -1; | ||
| 297 | if (newaddr) { | ||
| 298 | if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0) | ||
| 299 | return -1; | ||
| 300 | } | ||
| 301 | if (newbrd) { | ||
| 302 | if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0) | ||
| 303 | return -1; | ||
| 304 | } | ||
| 305 | } | ||
| 306 | |||
| 307 | if (newname && strcmp(dev, newname)) { | ||
| 308 | if (do_changename(dev, newname) < 0) | ||
| 309 | return -1; | ||
| 310 | dev = newname; | ||
| 311 | } | ||
| 312 | if (qlen != -1) { | ||
| 313 | if (set_qlen(dev, qlen) < 0) | ||
| 314 | return -1; | ||
| 315 | } | ||
| 316 | if (mtu != -1) { | ||
| 317 | if (set_mtu(dev, mtu) < 0) | ||
| 318 | return -1; | ||
| 319 | } | ||
| 320 | if (newaddr || newbrd) { | ||
| 321 | if (newbrd) { | ||
| 322 | if (set_address(&ifr1, 1) < 0) | ||
| 323 | return -1; | ||
| 324 | } | ||
| 325 | if (newaddr) { | ||
| 326 | if (set_address(&ifr0, 0) < 0) | ||
| 327 | return -1; | ||
| 328 | } | ||
| 329 | } | ||
| 330 | if (mask) | ||
| 331 | return do_chflags(dev, flags, mask); | ||
| 332 | return 0; | ||
| 333 | } | ||
| 334 | |||
| 335 | int do_iplink(int argc, char **argv) | ||
| 336 | { | ||
| 337 | if (argc > 0) { | ||
| 338 | if (matches(*argv, "set") == 0) | ||
| 339 | return do_set(argc-1, argv+1); | ||
| 340 | if (matches(*argv, "show") == 0 || | ||
| 341 | matches(*argv, "lst") == 0 || | ||
| 342 | matches(*argv, "list") == 0) | ||
| 343 | return ipaddr_list_link(argc-1, argv+1); | ||
| 344 | } else | ||
| 345 | return ipaddr_list_link(0, NULL); | ||
| 346 | |||
| 347 | fprintf(stderr, "Command \"%s\" is unknown, try \"ip link help\".\n", *argv); | ||
| 348 | exit(-1); | ||
| 349 | } | ||
diff --git a/networking/libiproute/iproute.c b/networking/libiproute/iproute.c new file mode 100644 index 000000000..e38abcd01 --- /dev/null +++ b/networking/libiproute/iproute.c | |||
| @@ -0,0 +1,674 @@ | |||
| 1 | /* | ||
| 2 | * iproute.c "ip route". | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version | ||
| 7 | * 2 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> | ||
| 10 | * | ||
| 11 | * | ||
| 12 | * Changes: | ||
| 13 | * | ||
| 14 | * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses | ||
| 15 | * Kunihiro Ishiguro <kunihiro@zebra.org> 001102: rtnh_ifindex was not initialized | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include <stdio.h> | ||
| 19 | #include <stdlib.h> | ||
| 20 | #include <unistd.h> | ||
| 21 | #include <syslog.h> | ||
| 22 | #include <fcntl.h> | ||
| 23 | #include <string.h> | ||
| 24 | #include <sys/time.h> | ||
| 25 | #include <sys/socket.h> | ||
| 26 | #include <netinet/in.h> | ||
| 27 | #include <netinet/ip.h> | ||
| 28 | #include <arpa/inet.h> | ||
| 29 | #include <linux/in_route.h> | ||
| 30 | |||
| 31 | #include "rt_names.h" | ||
| 32 | #include "utils.h" | ||
| 33 | #include "ip_common.h" | ||
| 34 | |||
| 35 | #include "busybox.h" | ||
| 36 | |||
| 37 | #ifndef RTAX_RTTVAR | ||
| 38 | #define RTAX_RTTVAR RTAX_HOPS | ||
| 39 | #endif | ||
| 40 | |||
| 41 | |||
| 42 | static struct | ||
| 43 | { | ||
| 44 | int tb; | ||
| 45 | int flushp; | ||
| 46 | int flushe; | ||
| 47 | struct rtnl_handle *rth; | ||
| 48 | int protocol, protocolmask; | ||
| 49 | int scope, scopemask; | ||
| 50 | int type, typemask; | ||
| 51 | int tos, tosmask; | ||
| 52 | int iif, iifmask; | ||
| 53 | int oif, oifmask; | ||
| 54 | int realm, realmmask; | ||
| 55 | inet_prefix rprefsrc; | ||
| 56 | inet_prefix rvia; | ||
| 57 | inet_prefix rdst; | ||
| 58 | inet_prefix mdst; | ||
| 59 | inet_prefix rsrc; | ||
| 60 | inet_prefix msrc; | ||
| 61 | } filter; | ||
| 62 | |||
| 63 | int print_route(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) | ||
| 64 | { | ||
| 65 | FILE *fp = (FILE*)arg; | ||
| 66 | struct rtmsg *r = NLMSG_DATA(n); | ||
| 67 | int len = n->nlmsg_len; | ||
| 68 | struct rtattr * tb[RTA_MAX+1]; | ||
| 69 | char abuf[256]; | ||
| 70 | int host_len = -1; | ||
| 71 | SPRINT_BUF(b1); | ||
| 72 | |||
| 73 | |||
| 74 | if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) { | ||
| 75 | fprintf(stderr, "Not a route: %08x %08x %08x\n", | ||
| 76 | n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); | ||
| 77 | return 0; | ||
| 78 | } | ||
| 79 | len -= NLMSG_LENGTH(sizeof(*r)); | ||
| 80 | if (len < 0) { | ||
| 81 | fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); | ||
| 82 | return -1; | ||
| 83 | } | ||
| 84 | |||
| 85 | if (r->rtm_family == AF_INET6) | ||
| 86 | host_len = 128; | ||
| 87 | else if (r->rtm_family == AF_INET) | ||
| 88 | host_len = 32; | ||
| 89 | |||
| 90 | if (r->rtm_family == AF_INET6) { | ||
| 91 | if (filter.tb) { | ||
| 92 | if (filter.tb < 0) { | ||
| 93 | if (!(r->rtm_flags&RTM_F_CLONED)) | ||
| 94 | return 0; | ||
| 95 | } else { | ||
| 96 | if (r->rtm_flags&RTM_F_CLONED) | ||
| 97 | return 0; | ||
| 98 | if (filter.tb == RT_TABLE_LOCAL) { | ||
| 99 | if (r->rtm_type != RTN_LOCAL) | ||
| 100 | return 0; | ||
| 101 | } else if (filter.tb == RT_TABLE_MAIN) { | ||
| 102 | if (r->rtm_type == RTN_LOCAL) | ||
| 103 | return 0; | ||
| 104 | } else { | ||
| 105 | return 0; | ||
| 106 | } | ||
| 107 | } | ||
| 108 | } | ||
| 109 | } else { | ||
| 110 | if (filter.tb > 0 && filter.tb != r->rtm_table) | ||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | if (filter.rdst.family && | ||
| 114 | (r->rtm_family != filter.rdst.family || filter.rdst.bitlen > r->rtm_dst_len)) | ||
| 115 | return 0; | ||
| 116 | if (filter.mdst.family && | ||
| 117 | (r->rtm_family != filter.mdst.family || | ||
| 118 | (filter.mdst.bitlen >= 0 && filter.mdst.bitlen < r->rtm_dst_len))) | ||
| 119 | return 0; | ||
| 120 | if (filter.rsrc.family && | ||
| 121 | (r->rtm_family != filter.rsrc.family || filter.rsrc.bitlen > r->rtm_src_len)) | ||
| 122 | return 0; | ||
| 123 | if (filter.msrc.family && | ||
| 124 | (r->rtm_family != filter.msrc.family || | ||
| 125 | (filter.msrc.bitlen >= 0 && filter.msrc.bitlen < r->rtm_src_len))) | ||
| 126 | return 0; | ||
| 127 | |||
| 128 | memset(tb, 0, sizeof(tb)); | ||
| 129 | parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); | ||
| 130 | |||
| 131 | if (n->nlmsg_type == RTM_DELROUTE) | ||
| 132 | fprintf(fp, "Deleted "); | ||
| 133 | if (r->rtm_type != RTN_UNICAST && !filter.type) | ||
| 134 | fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1))); | ||
| 135 | |||
| 136 | if (tb[RTA_DST]) { | ||
| 137 | if (r->rtm_dst_len != host_len) { | ||
| 138 | fprintf(fp, "%s/%u ", rt_addr_n2a(r->rtm_family, | ||
| 139 | RTA_PAYLOAD(tb[RTA_DST]), | ||
| 140 | RTA_DATA(tb[RTA_DST]), | ||
| 141 | abuf, sizeof(abuf)), | ||
| 142 | r->rtm_dst_len | ||
| 143 | ); | ||
| 144 | } else { | ||
| 145 | fprintf(fp, "%s ", format_host(r->rtm_family, | ||
| 146 | RTA_PAYLOAD(tb[RTA_DST]), | ||
| 147 | RTA_DATA(tb[RTA_DST]), | ||
| 148 | abuf, sizeof(abuf)) | ||
| 149 | ); | ||
| 150 | } | ||
| 151 | } else if (r->rtm_dst_len) { | ||
| 152 | fprintf(fp, "0/%d ", r->rtm_dst_len); | ||
| 153 | } else { | ||
| 154 | fprintf(fp, "default "); | ||
| 155 | } | ||
| 156 | if (tb[RTA_SRC]) { | ||
| 157 | if (r->rtm_src_len != host_len) { | ||
| 158 | fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family, | ||
| 159 | RTA_PAYLOAD(tb[RTA_SRC]), | ||
| 160 | RTA_DATA(tb[RTA_SRC]), | ||
| 161 | abuf, sizeof(abuf)), | ||
| 162 | r->rtm_src_len | ||
| 163 | ); | ||
| 164 | } else { | ||
| 165 | fprintf(fp, "from %s ", format_host(r->rtm_family, | ||
| 166 | RTA_PAYLOAD(tb[RTA_SRC]), | ||
| 167 | RTA_DATA(tb[RTA_SRC]), | ||
| 168 | abuf, sizeof(abuf)) | ||
| 169 | ); | ||
| 170 | } | ||
| 171 | } else if (r->rtm_src_len) { | ||
| 172 | fprintf(fp, "from 0/%u ", r->rtm_src_len); | ||
| 173 | } | ||
| 174 | if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) { | ||
| 175 | fprintf(fp, "via %s ", | ||
| 176 | format_host(r->rtm_family, | ||
| 177 | RTA_PAYLOAD(tb[RTA_GATEWAY]), | ||
| 178 | RTA_DATA(tb[RTA_GATEWAY]), | ||
| 179 | abuf, sizeof(abuf))); | ||
| 180 | } | ||
| 181 | if (tb[RTA_OIF] && filter.oifmask != -1) | ||
| 182 | fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF]))); | ||
| 183 | |||
| 184 | if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) { | ||
| 185 | /* Do not use format_host(). It is our local addr | ||
| 186 | and symbolic name will not be useful. | ||
| 187 | */ | ||
| 188 | fprintf(fp, " src %s ", | ||
| 189 | rt_addr_n2a(r->rtm_family, | ||
| 190 | RTA_PAYLOAD(tb[RTA_PREFSRC]), | ||
| 191 | RTA_DATA(tb[RTA_PREFSRC]), | ||
| 192 | abuf, sizeof(abuf))); | ||
| 193 | } | ||
| 194 | if (tb[RTA_PRIORITY]) | ||
| 195 | fprintf(fp, " metric %d ", *(__u32*)RTA_DATA(tb[RTA_PRIORITY])); | ||
| 196 | if (r->rtm_family == AF_INET6) { | ||
| 197 | struct rta_cacheinfo *ci = NULL; | ||
| 198 | if (tb[RTA_CACHEINFO]) | ||
| 199 | ci = RTA_DATA(tb[RTA_CACHEINFO]); | ||
| 200 | if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) { | ||
| 201 | static int hz; | ||
| 202 | if (!hz) | ||
| 203 | hz = get_hz(); | ||
| 204 | if (r->rtm_flags & RTM_F_CLONED) | ||
| 205 | fprintf(fp, "%s cache ", _SL_); | ||
| 206 | if (ci->rta_expires) | ||
| 207 | fprintf(fp, " expires %dsec", ci->rta_expires/hz); | ||
| 208 | if (ci->rta_error != 0) | ||
| 209 | fprintf(fp, " error %d", ci->rta_error); | ||
| 210 | } else if (ci) { | ||
| 211 | if (ci->rta_error != 0) | ||
| 212 | fprintf(fp, " error %d", ci->rta_error); | ||
| 213 | } | ||
| 214 | } | ||
| 215 | if (tb[RTA_IIF] && filter.iifmask != -1) { | ||
| 216 | fprintf(fp, " iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF]))); | ||
| 217 | } | ||
| 218 | fprintf(fp, "\n"); | ||
| 219 | fflush(fp); | ||
| 220 | return 0; | ||
| 221 | } | ||
| 222 | |||
| 223 | int iproute_modify(int cmd, unsigned flags, int argc, char **argv) | ||
| 224 | { | ||
| 225 | struct rtnl_handle rth; | ||
| 226 | struct { | ||
| 227 | struct nlmsghdr n; | ||
| 228 | struct rtmsg r; | ||
| 229 | char buf[1024]; | ||
| 230 | } req; | ||
| 231 | char mxbuf[256]; | ||
| 232 | struct rtattr * mxrta = (void*)mxbuf; | ||
| 233 | unsigned mxlock = 0; | ||
| 234 | char *d = NULL; | ||
| 235 | int gw_ok = 0; | ||
| 236 | int dst_ok = 0; | ||
| 237 | //int nhs_ok = 0; | ||
| 238 | //int scope_ok = 0; | ||
| 239 | //int table_ok = 0; | ||
| 240 | int proto_ok = 0; | ||
| 241 | int type_ok = 0; | ||
| 242 | |||
| 243 | memset(&req, 0, sizeof(req)); | ||
| 244 | |||
| 245 | req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); | ||
| 246 | req.n.nlmsg_flags = NLM_F_REQUEST|flags; | ||
| 247 | req.n.nlmsg_type = cmd; | ||
| 248 | req.r.rtm_family = preferred_family; | ||
| 249 | req.r.rtm_table = RT_TABLE_MAIN; | ||
| 250 | req.r.rtm_scope = RT_SCOPE_NOWHERE; | ||
| 251 | |||
| 252 | if (cmd != RTM_DELROUTE) { | ||
| 253 | req.r.rtm_protocol = RTPROT_BOOT; | ||
| 254 | req.r.rtm_scope = RT_SCOPE_UNIVERSE; | ||
| 255 | req.r.rtm_type = RTN_UNICAST; | ||
| 256 | } | ||
| 257 | |||
| 258 | mxrta->rta_type = RTA_METRICS; | ||
| 259 | mxrta->rta_len = RTA_LENGTH(0); | ||
| 260 | |||
| 261 | while (argc > 0) { | ||
| 262 | if (strcmp(*argv, "src") == 0) { | ||
| 263 | inet_prefix addr; | ||
| 264 | NEXT_ARG(); | ||
| 265 | get_addr(&addr, *argv, req.r.rtm_family); | ||
| 266 | if (req.r.rtm_family == AF_UNSPEC) | ||
| 267 | req.r.rtm_family = addr.family; | ||
| 268 | addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen); | ||
| 269 | } else if (strcmp(*argv, "via") == 0) { | ||
| 270 | inet_prefix addr; | ||
| 271 | gw_ok = 1; | ||
| 272 | NEXT_ARG(); | ||
| 273 | get_addr(&addr, *argv, req.r.rtm_family); | ||
| 274 | if (req.r.rtm_family == AF_UNSPEC) | ||
| 275 | req.r.rtm_family = addr.family; | ||
| 276 | addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen); | ||
| 277 | } else if (strcmp(*argv, "mtu") == 0) { | ||
| 278 | unsigned mtu; | ||
| 279 | NEXT_ARG(); | ||
| 280 | if (strcmp(*argv, "lock") == 0) { | ||
| 281 | mxlock |= (1<<RTAX_MTU); | ||
| 282 | NEXT_ARG(); | ||
| 283 | } | ||
| 284 | if (get_unsigned(&mtu, *argv, 0)) | ||
| 285 | invarg("\"mtu\" value is invalid\n", *argv); | ||
| 286 | rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu); | ||
| 287 | } else if (matches(*argv, "protocol") == 0) { | ||
| 288 | int prot; | ||
| 289 | NEXT_ARG(); | ||
| 290 | if (rtnl_rtprot_a2n(&prot, *argv)) | ||
| 291 | invarg("\"protocol\" value is invalid\n", *argv); | ||
| 292 | req.r.rtm_protocol = prot; | ||
| 293 | proto_ok =1; | ||
| 294 | } else if (strcmp(*argv, "dev") == 0 || | ||
| 295 | strcmp(*argv, "oif") == 0) { | ||
| 296 | NEXT_ARG(); | ||
| 297 | d = *argv; | ||
| 298 | } else { | ||
| 299 | int type; | ||
| 300 | inet_prefix dst; | ||
| 301 | |||
| 302 | if (strcmp(*argv, "to") == 0) { | ||
| 303 | NEXT_ARG(); | ||
| 304 | } | ||
| 305 | if ((**argv < '0' || **argv > '9') && | ||
| 306 | rtnl_rtntype_a2n(&type, *argv) == 0) { | ||
| 307 | NEXT_ARG(); | ||
| 308 | req.r.rtm_type = type; | ||
| 309 | type_ok = 1; | ||
| 310 | } | ||
| 311 | |||
| 312 | if (dst_ok) | ||
| 313 | duparg2("to", *argv); | ||
| 314 | get_prefix(&dst, *argv, req.r.rtm_family); | ||
| 315 | if (req.r.rtm_family == AF_UNSPEC) | ||
| 316 | req.r.rtm_family = dst.family; | ||
| 317 | req.r.rtm_dst_len = dst.bitlen; | ||
| 318 | dst_ok = 1; | ||
| 319 | if (dst.bytelen) | ||
| 320 | addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen); | ||
| 321 | } | ||
| 322 | argc--; argv++; | ||
| 323 | } | ||
| 324 | |||
| 325 | if (rtnl_open(&rth, 0) < 0) | ||
| 326 | exit(1); | ||
| 327 | |||
| 328 | if (mxrta->rta_len > RTA_LENGTH(0)) { | ||
| 329 | if (mxlock) | ||
| 330 | rta_addattr32(mxrta, sizeof(mxbuf), RTAX_LOCK, mxlock); | ||
| 331 | addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta)); | ||
| 332 | } | ||
| 333 | |||
| 334 | if (req.r.rtm_family == AF_UNSPEC) | ||
| 335 | req.r.rtm_family = AF_INET; | ||
| 336 | |||
| 337 | if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) | ||
| 338 | exit(2); | ||
| 339 | |||
| 340 | return 0; | ||
| 341 | } | ||
| 342 | |||
| 343 | static int rtnl_rtcache_request(struct rtnl_handle *rth, int family) | ||
| 344 | { | ||
| 345 | struct { | ||
| 346 | struct nlmsghdr nlh; | ||
| 347 | struct rtmsg rtm; | ||
| 348 | } req; | ||
| 349 | struct sockaddr_nl nladdr; | ||
| 350 | |||
| 351 | memset(&nladdr, 0, sizeof(nladdr)); | ||
| 352 | memset(&req, 0, sizeof(req)); | ||
| 353 | nladdr.nl_family = AF_NETLINK; | ||
| 354 | |||
| 355 | req.nlh.nlmsg_len = sizeof(req); | ||
| 356 | req.nlh.nlmsg_type = RTM_GETROUTE; | ||
| 357 | req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_REQUEST; | ||
| 358 | req.nlh.nlmsg_pid = 0; | ||
| 359 | req.nlh.nlmsg_seq = rth->dump = ++rth->seq; | ||
| 360 | req.rtm.rtm_family = family; | ||
| 361 | req.rtm.rtm_flags |= RTM_F_CLONED; | ||
| 362 | |||
| 363 | return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr)); | ||
| 364 | } | ||
| 365 | |||
| 366 | static int iproute_list(int argc, char **argv) | ||
| 367 | { | ||
| 368 | int do_ipv6 = preferred_family; | ||
| 369 | struct rtnl_handle rth; | ||
| 370 | char *id = NULL; | ||
| 371 | char *od = NULL; | ||
| 372 | |||
| 373 | iproute_reset_filter(); | ||
| 374 | filter.tb = RT_TABLE_MAIN; | ||
| 375 | |||
| 376 | while (argc > 0) { | ||
| 377 | if (matches(*argv, "protocol") == 0) { | ||
| 378 | int prot = 0; | ||
| 379 | NEXT_ARG(); | ||
| 380 | filter.protocolmask = -1; | ||
| 381 | if (rtnl_rtprot_a2n(&prot, *argv)) { | ||
| 382 | if (strcmp(*argv, "all") != 0) | ||
| 383 | invarg("invalid \"protocol\"\n", *argv); | ||
| 384 | prot = 0; | ||
| 385 | filter.protocolmask = 0; | ||
| 386 | } | ||
| 387 | filter.protocol = prot; | ||
| 388 | } else if (strcmp(*argv, "dev") == 0 || | ||
| 389 | strcmp(*argv, "oif") == 0) { | ||
| 390 | NEXT_ARG(); | ||
| 391 | od = *argv; | ||
| 392 | } else if (strcmp(*argv, "iif") == 0) { | ||
| 393 | NEXT_ARG(); | ||
| 394 | id = *argv; | ||
| 395 | } else if (matches(*argv, "from") == 0) { | ||
| 396 | NEXT_ARG(); | ||
| 397 | if (matches(*argv, "root") == 0) { | ||
| 398 | NEXT_ARG(); | ||
| 399 | get_prefix(&filter.rsrc, *argv, do_ipv6); | ||
| 400 | } else if (matches(*argv, "match") == 0) { | ||
| 401 | NEXT_ARG(); | ||
| 402 | get_prefix(&filter.msrc, *argv, do_ipv6); | ||
| 403 | } else { | ||
| 404 | if (matches(*argv, "exact") == 0) { | ||
| 405 | NEXT_ARG(); | ||
| 406 | } | ||
| 407 | get_prefix(&filter.msrc, *argv, do_ipv6); | ||
| 408 | filter.rsrc = filter.msrc; | ||
| 409 | } | ||
| 410 | } else { | ||
| 411 | if (matches(*argv, "to") == 0) { | ||
| 412 | NEXT_ARG(); | ||
| 413 | } | ||
| 414 | if (matches(*argv, "root") == 0) { | ||
| 415 | NEXT_ARG(); | ||
| 416 | get_prefix(&filter.rdst, *argv, do_ipv6); | ||
| 417 | } else if (matches(*argv, "match") == 0) { | ||
| 418 | NEXT_ARG(); | ||
| 419 | get_prefix(&filter.mdst, *argv, do_ipv6); | ||
| 420 | } else { | ||
| 421 | if (matches(*argv, "exact") == 0) { | ||
| 422 | NEXT_ARG(); | ||
| 423 | } | ||
| 424 | get_prefix(&filter.mdst, *argv, do_ipv6); | ||
| 425 | filter.rdst = filter.mdst; | ||
| 426 | } | ||
| 427 | } | ||
| 428 | argc--; argv++; | ||
| 429 | } | ||
| 430 | |||
| 431 | if (do_ipv6 == AF_UNSPEC && filter.tb) | ||
| 432 | do_ipv6 = AF_INET; | ||
| 433 | |||
| 434 | if (rtnl_open(&rth, 0) < 0) | ||
| 435 | exit(1); | ||
| 436 | |||
| 437 | ll_init_map(&rth); | ||
| 438 | |||
| 439 | if (id || od) { | ||
| 440 | int idx; | ||
| 441 | |||
| 442 | if (id) { | ||
| 443 | if ((idx = ll_name_to_index(id)) == 0) { | ||
| 444 | fprintf(stderr, "Cannot find device \"%s\"\n", id); | ||
| 445 | return -1; | ||
| 446 | } | ||
| 447 | filter.iif = idx; | ||
| 448 | filter.iifmask = -1; | ||
| 449 | } | ||
| 450 | if (od) { | ||
| 451 | if ((idx = ll_name_to_index(od)) == 0) { | ||
| 452 | fprintf(stderr, "Cannot find device \"%s\"\n", od); | ||
| 453 | return -1; | ||
| 454 | } | ||
| 455 | filter.oif = idx; | ||
| 456 | filter.oifmask = -1; | ||
| 457 | } | ||
| 458 | } | ||
| 459 | |||
| 460 | if (filter.tb != -1) { | ||
| 461 | if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) { | ||
| 462 | perror("Cannot send dump request"); | ||
| 463 | exit(1); | ||
| 464 | } | ||
| 465 | } else { | ||
| 466 | if (rtnl_rtcache_request(&rth, do_ipv6) < 0) { | ||
| 467 | perror("Cannot send dump request"); | ||
| 468 | exit(1); | ||
| 469 | } | ||
| 470 | } | ||
| 471 | |||
| 472 | if (rtnl_dump_filter(&rth, print_route, stdout, NULL, NULL) < 0) { | ||
| 473 | fprintf(stderr, "Dump terminated\n"); | ||
| 474 | exit(1); | ||
| 475 | } | ||
| 476 | |||
| 477 | exit(0); | ||
| 478 | } | ||
| 479 | |||
| 480 | |||
| 481 | int iproute_get(int argc, char **argv) | ||
| 482 | { | ||
| 483 | struct rtnl_handle rth; | ||
| 484 | struct { | ||
| 485 | struct nlmsghdr n; | ||
| 486 | struct rtmsg r; | ||
| 487 | char buf[1024]; | ||
| 488 | } req; | ||
| 489 | char *idev = NULL; | ||
| 490 | char *odev = NULL; | ||
| 491 | int connected = 0; | ||
| 492 | int from_ok = 0; | ||
| 493 | |||
| 494 | memset(&req, 0, sizeof(req)); | ||
| 495 | |||
| 496 | iproute_reset_filter(); | ||
| 497 | |||
| 498 | req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); | ||
| 499 | req.n.nlmsg_flags = NLM_F_REQUEST; | ||
| 500 | req.n.nlmsg_type = RTM_GETROUTE; | ||
| 501 | req.r.rtm_family = preferred_family; | ||
| 502 | req.r.rtm_table = 0; | ||
| 503 | req.r.rtm_protocol = 0; | ||
| 504 | req.r.rtm_scope = 0; | ||
| 505 | req.r.rtm_type = 0; | ||
| 506 | req.r.rtm_src_len = 0; | ||
| 507 | req.r.rtm_dst_len = 0; | ||
| 508 | req.r.rtm_tos = 0; | ||
| 509 | |||
| 510 | while (argc > 0) { | ||
| 511 | if (matches(*argv, "from") == 0) { | ||
| 512 | inet_prefix addr; | ||
| 513 | NEXT_ARG(); | ||
| 514 | from_ok = 1; | ||
| 515 | get_prefix(&addr, *argv, req.r.rtm_family); | ||
| 516 | if (req.r.rtm_family == AF_UNSPEC) | ||
| 517 | req.r.rtm_family = addr.family; | ||
| 518 | if (addr.bytelen) | ||
| 519 | addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen); | ||
| 520 | req.r.rtm_src_len = addr.bitlen; | ||
| 521 | } else if (matches(*argv, "iif") == 0) { | ||
| 522 | NEXT_ARG(); | ||
| 523 | idev = *argv; | ||
| 524 | } else if (matches(*argv, "oif") == 0 || | ||
| 525 | strcmp(*argv, "dev") == 0) { | ||
| 526 | NEXT_ARG(); | ||
| 527 | odev = *argv; | ||
| 528 | } else if (matches(*argv, "notify") == 0) { | ||
| 529 | req.r.rtm_flags |= RTM_F_NOTIFY; | ||
| 530 | } else if (matches(*argv, "connected") == 0) { | ||
| 531 | connected = 1; | ||
| 532 | } else { | ||
| 533 | inet_prefix addr; | ||
| 534 | if (strcmp(*argv, "to") == 0) { | ||
| 535 | NEXT_ARG(); | ||
| 536 | } | ||
| 537 | get_prefix(&addr, *argv, req.r.rtm_family); | ||
| 538 | if (req.r.rtm_family == AF_UNSPEC) | ||
| 539 | req.r.rtm_family = addr.family; | ||
| 540 | if (addr.bytelen) | ||
| 541 | addattr_l(&req.n, sizeof(req), RTA_DST, &addr.data, addr.bytelen); | ||
| 542 | req.r.rtm_dst_len = addr.bitlen; | ||
| 543 | } | ||
| 544 | argc--; argv++; | ||
| 545 | } | ||
| 546 | |||
| 547 | if (req.r.rtm_dst_len == 0) { | ||
| 548 | fprintf(stderr, "need at least destination address\n"); | ||
| 549 | exit(1); | ||
| 550 | } | ||
| 551 | |||
| 552 | if (rtnl_open(&rth, 0) < 0) | ||
| 553 | exit(1); | ||
| 554 | |||
| 555 | ll_init_map(&rth); | ||
| 556 | |||
| 557 | if (idev || odev) { | ||
| 558 | int idx; | ||
| 559 | |||
| 560 | if (idev) { | ||
| 561 | if ((idx = ll_name_to_index(idev)) == 0) { | ||
| 562 | fprintf(stderr, "Cannot find device \"%s\"\n", idev); | ||
| 563 | return -1; | ||
| 564 | } | ||
| 565 | addattr32(&req.n, sizeof(req), RTA_IIF, idx); | ||
| 566 | } | ||
| 567 | if (odev) { | ||
| 568 | if ((idx = ll_name_to_index(odev)) == 0) { | ||
| 569 | fprintf(stderr, "Cannot find device \"%s\"\n", odev); | ||
| 570 | return -1; | ||
| 571 | } | ||
| 572 | addattr32(&req.n, sizeof(req), RTA_OIF, idx); | ||
| 573 | } | ||
| 574 | } | ||
| 575 | |||
| 576 | if (req.r.rtm_family == AF_UNSPEC) | ||
| 577 | req.r.rtm_family = AF_INET; | ||
| 578 | |||
| 579 | if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) | ||
| 580 | exit(2); | ||
| 581 | |||
| 582 | if (connected && !from_ok) { | ||
| 583 | struct rtmsg *r = NLMSG_DATA(&req.n); | ||
| 584 | int len = req.n.nlmsg_len; | ||
| 585 | struct rtattr * tb[RTA_MAX+1]; | ||
| 586 | |||
| 587 | if (print_route(NULL, &req.n, (void*)stdout) < 0) { | ||
| 588 | fprintf(stderr, "An error :-)\n"); | ||
| 589 | exit(1); | ||
| 590 | } | ||
| 591 | |||
| 592 | if (req.n.nlmsg_type != RTM_NEWROUTE) { | ||
| 593 | fprintf(stderr, "Not a route?\n"); | ||
| 594 | return -1; | ||
| 595 | } | ||
| 596 | len -= NLMSG_LENGTH(sizeof(*r)); | ||
| 597 | if (len < 0) { | ||
| 598 | fprintf(stderr, "Wrong len %d\n", len); | ||
| 599 | return -1; | ||
| 600 | } | ||
| 601 | |||
| 602 | memset(tb, 0, sizeof(tb)); | ||
| 603 | parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); | ||
| 604 | |||
| 605 | if (tb[RTA_PREFSRC]) { | ||
| 606 | tb[RTA_PREFSRC]->rta_type = RTA_SRC; | ||
| 607 | r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]); | ||
| 608 | } else if (!tb[RTA_SRC]) { | ||
| 609 | fprintf(stderr, "Failed to connect the route\n"); | ||
| 610 | return -1; | ||
| 611 | } | ||
| 612 | if (!odev && tb[RTA_OIF]) | ||
| 613 | tb[RTA_OIF]->rta_type = 0; | ||
| 614 | if (tb[RTA_GATEWAY]) | ||
| 615 | tb[RTA_GATEWAY]->rta_type = 0; | ||
| 616 | if (!idev && tb[RTA_IIF]) | ||
| 617 | tb[RTA_IIF]->rta_type = 0; | ||
| 618 | req.n.nlmsg_flags = NLM_F_REQUEST; | ||
| 619 | req.n.nlmsg_type = RTM_GETROUTE; | ||
| 620 | |||
| 621 | if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) | ||
| 622 | exit(2); | ||
| 623 | } | ||
| 624 | |||
| 625 | if (print_route(NULL, &req.n, (void*)stdout) < 0) { | ||
| 626 | fprintf(stderr, "An error :-)\n"); | ||
| 627 | exit(1); | ||
| 628 | } | ||
| 629 | |||
| 630 | exit(0); | ||
| 631 | } | ||
| 632 | |||
| 633 | void iproute_reset_filter() | ||
| 634 | { | ||
| 635 | memset(&filter, 0, sizeof(filter)); | ||
| 636 | filter.mdst.bitlen = -1; | ||
| 637 | filter.msrc.bitlen = -1; | ||
| 638 | } | ||
| 639 | |||
| 640 | int do_iproute(int argc, char **argv) | ||
| 641 | { | ||
| 642 | if (argc < 1) | ||
| 643 | return iproute_list(0, NULL); | ||
| 644 | |||
| 645 | if (matches(*argv, "add") == 0) | ||
| 646 | return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_EXCL, | ||
| 647 | argc-1, argv+1); | ||
| 648 | if (matches(*argv, "change") == 0 || strcmp(*argv, "chg") == 0) | ||
| 649 | return iproute_modify(RTM_NEWROUTE, NLM_F_REPLACE, | ||
| 650 | argc-1, argv+1); | ||
| 651 | if (matches(*argv, "replace") == 0) | ||
| 652 | return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_REPLACE, | ||
| 653 | argc-1, argv+1); | ||
| 654 | if (matches(*argv, "prepend") == 0) | ||
| 655 | return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE, | ||
| 656 | argc-1, argv+1); | ||
| 657 | if (matches(*argv, "append") == 0) | ||
| 658 | return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_APPEND, | ||
| 659 | argc-1, argv+1); | ||
| 660 | if (matches(*argv, "test") == 0) | ||
| 661 | return iproute_modify(RTM_NEWROUTE, NLM_F_EXCL, | ||
| 662 | argc-1, argv+1); | ||
| 663 | if (matches(*argv, "delete") == 0) | ||
| 664 | return iproute_modify(RTM_DELROUTE, 0, | ||
| 665 | argc-1, argv+1); | ||
| 666 | if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0 | ||
| 667 | || matches(*argv, "lst") == 0) | ||
| 668 | return iproute_list(argc-1, argv+1); | ||
| 669 | if (matches(*argv, "get") == 0) | ||
| 670 | return iproute_get(argc-1, argv+1); | ||
| 671 | fprintf(stderr, "Command \"%s\" is unknown, try \"ip route help\".\n", *argv); | ||
| 672 | exit(-1); | ||
| 673 | } | ||
| 674 | |||
diff --git a/networking/libiproute/iptunnel.c b/networking/libiproute/iptunnel.c new file mode 100644 index 000000000..beb8bb675 --- /dev/null +++ b/networking/libiproute/iptunnel.c | |||
| @@ -0,0 +1,548 @@ | |||
| 1 | /* | ||
| 2 | * iptunnel.c "ip tunnel" | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version | ||
| 7 | * 2 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> | ||
| 10 | * | ||
| 11 | * | ||
| 12 | * Changes: | ||
| 13 | * | ||
| 14 | * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses | ||
| 15 | * Rani Assaf <rani@magic.metawire.com> 980930: do not allow key for ipip/sit | ||
| 16 | * Phil Karn <karn@ka9q.ampr.org> 990408: "pmtudisc" flag | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <stdio.h> | ||
| 20 | #include <stdlib.h> | ||
| 21 | #include <string.h> | ||
| 22 | #include <unistd.h> | ||
| 23 | #include <syslog.h> | ||
| 24 | #include <fcntl.h> | ||
| 25 | #include <sys/socket.h> | ||
| 26 | #include <sys/ioctl.h> | ||
| 27 | #include <netinet/in.h> | ||
| 28 | #include <netinet/ip.h> | ||
| 29 | #include <arpa/inet.h> | ||
| 30 | |||
| 31 | #include <linux/if.h> | ||
| 32 | #include <linux/if_arp.h> | ||
| 33 | #include <linux/if_tunnel.h> | ||
| 34 | |||
| 35 | #include "rt_names.h" | ||
| 36 | #include "utils.h" | ||
| 37 | |||
| 38 | #include "busybox.h" | ||
| 39 | |||
| 40 | static int do_ioctl_get_ifindex(char *dev) | ||
| 41 | { | ||
| 42 | struct ifreq ifr; | ||
| 43 | int fd; | ||
| 44 | int err; | ||
| 45 | |||
| 46 | strcpy(ifr.ifr_name, dev); | ||
| 47 | fd = socket(AF_INET, SOCK_DGRAM, 0); | ||
| 48 | err = ioctl(fd, SIOCGIFINDEX, &ifr); | ||
| 49 | if (err) { | ||
| 50 | perror("ioctl"); | ||
| 51 | return 0; | ||
| 52 | } | ||
| 53 | close(fd); | ||
| 54 | return ifr.ifr_ifindex; | ||
| 55 | } | ||
| 56 | |||
| 57 | static int do_ioctl_get_iftype(char *dev) | ||
| 58 | { | ||
| 59 | struct ifreq ifr; | ||
| 60 | int fd; | ||
| 61 | int err; | ||
| 62 | |||
| 63 | strcpy(ifr.ifr_name, dev); | ||
| 64 | fd = socket(AF_INET, SOCK_DGRAM, 0); | ||
| 65 | err = ioctl(fd, SIOCGIFHWADDR, &ifr); | ||
| 66 | if (err) { | ||
| 67 | perror("ioctl"); | ||
| 68 | return -1; | ||
| 69 | } | ||
| 70 | close(fd); | ||
| 71 | return ifr.ifr_addr.sa_family; | ||
| 72 | } | ||
| 73 | |||
| 74 | |||
| 75 | static char * do_ioctl_get_ifname(int idx) | ||
| 76 | { | ||
| 77 | static struct ifreq ifr; | ||
| 78 | int fd; | ||
| 79 | int err; | ||
| 80 | |||
| 81 | ifr.ifr_ifindex = idx; | ||
| 82 | fd = socket(AF_INET, SOCK_DGRAM, 0); | ||
| 83 | err = ioctl(fd, SIOCGIFNAME, &ifr); | ||
| 84 | if (err) { | ||
| 85 | perror("ioctl"); | ||
| 86 | return NULL; | ||
| 87 | } | ||
| 88 | close(fd); | ||
| 89 | return ifr.ifr_name; | ||
| 90 | } | ||
| 91 | |||
| 92 | |||
| 93 | |||
| 94 | static int do_get_ioctl(char *basedev, struct ip_tunnel_parm *p) | ||
| 95 | { | ||
| 96 | struct ifreq ifr; | ||
| 97 | int fd; | ||
| 98 | int err; | ||
| 99 | |||
| 100 | strcpy(ifr.ifr_name, basedev); | ||
| 101 | ifr.ifr_ifru.ifru_data = (void*)p; | ||
| 102 | fd = socket(AF_INET, SOCK_DGRAM, 0); | ||
| 103 | err = ioctl(fd, SIOCGETTUNNEL, &ifr); | ||
| 104 | if (err) | ||
| 105 | perror("ioctl"); | ||
| 106 | close(fd); | ||
| 107 | return err; | ||
| 108 | } | ||
| 109 | |||
| 110 | static int do_add_ioctl(int cmd, char *basedev, struct ip_tunnel_parm *p) | ||
| 111 | { | ||
| 112 | struct ifreq ifr; | ||
| 113 | int fd; | ||
| 114 | int err; | ||
| 115 | |||
| 116 | if (cmd == SIOCCHGTUNNEL && p->name[0]) | ||
| 117 | strcpy(ifr.ifr_name, p->name); | ||
| 118 | else | ||
| 119 | strcpy(ifr.ifr_name, basedev); | ||
| 120 | ifr.ifr_ifru.ifru_data = (void*)p; | ||
| 121 | fd = socket(AF_INET, SOCK_DGRAM, 0); | ||
| 122 | err = ioctl(fd, cmd, &ifr); | ||
| 123 | if (err) | ||
| 124 | perror("ioctl"); | ||
| 125 | close(fd); | ||
| 126 | return err; | ||
| 127 | } | ||
| 128 | |||
| 129 | static int do_del_ioctl(char *basedev, struct ip_tunnel_parm *p) | ||
| 130 | { | ||
| 131 | struct ifreq ifr; | ||
| 132 | int fd; | ||
| 133 | int err; | ||
| 134 | |||
| 135 | if (p->name[0]) | ||
| 136 | strcpy(ifr.ifr_name, p->name); | ||
| 137 | else | ||
| 138 | strcpy(ifr.ifr_name, basedev); | ||
| 139 | ifr.ifr_ifru.ifru_data = (void*)p; | ||
| 140 | fd = socket(AF_INET, SOCK_DGRAM, 0); | ||
| 141 | err = ioctl(fd, SIOCDELTUNNEL, &ifr); | ||
| 142 | if (err) | ||
| 143 | perror("ioctl"); | ||
| 144 | close(fd); | ||
| 145 | return err; | ||
| 146 | } | ||
| 147 | |||
| 148 | static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p) | ||
| 149 | { | ||
| 150 | int count = 0; | ||
| 151 | char medium[IFNAMSIZ]; | ||
| 152 | |||
| 153 | memset(p, 0, sizeof(*p)); | ||
| 154 | memset(&medium, 0, sizeof(medium)); | ||
| 155 | |||
| 156 | p->iph.version = 4; | ||
| 157 | p->iph.ihl = 5; | ||
| 158 | #ifndef IP_DF | ||
| 159 | #define IP_DF 0x4000 /* Flag: "Don't Fragment" */ | ||
| 160 | #endif | ||
| 161 | p->iph.frag_off = htons(IP_DF); | ||
| 162 | |||
| 163 | while (argc > 0) { | ||
| 164 | if (strcmp(*argv, "mode") == 0) { | ||
| 165 | NEXT_ARG(); | ||
| 166 | if (strcmp(*argv, "ipip") == 0 || | ||
| 167 | strcmp(*argv, "ip/ip") == 0) { | ||
| 168 | if (p->iph.protocol && p->iph.protocol != IPPROTO_IPIP) { | ||
| 169 | fprintf(stderr,"You managed to ask for more than one tunnel mode.\n"); | ||
| 170 | exit(-1); | ||
| 171 | } | ||
| 172 | p->iph.protocol = IPPROTO_IPIP; | ||
| 173 | } else if (strcmp(*argv, "gre") == 0 || | ||
| 174 | strcmp(*argv, "gre/ip") == 0) { | ||
| 175 | if (p->iph.protocol && p->iph.protocol != IPPROTO_GRE) { | ||
| 176 | fprintf(stderr,"You managed to ask for more than one tunnel mode.\n"); | ||
| 177 | exit(-1); | ||
| 178 | } | ||
| 179 | p->iph.protocol = IPPROTO_GRE; | ||
| 180 | } else if (strcmp(*argv, "sit") == 0 || | ||
| 181 | strcmp(*argv, "ipv6/ip") == 0) { | ||
| 182 | if (p->iph.protocol && p->iph.protocol != IPPROTO_IPV6) { | ||
| 183 | fprintf(stderr,"You managed to ask for more than one tunnel mode.\n"); | ||
| 184 | exit(-1); | ||
| 185 | } | ||
| 186 | p->iph.protocol = IPPROTO_IPV6; | ||
| 187 | } else { | ||
| 188 | fprintf(stderr,"Cannot guess tunnel mode.\n"); | ||
| 189 | exit(-1); | ||
| 190 | } | ||
| 191 | } else if (strcmp(*argv, "key") == 0) { | ||
| 192 | unsigned uval; | ||
| 193 | NEXT_ARG(); | ||
| 194 | p->i_flags |= GRE_KEY; | ||
| 195 | p->o_flags |= GRE_KEY; | ||
| 196 | if (strchr(*argv, '.')) | ||
| 197 | p->i_key = p->o_key = get_addr32(*argv); | ||
| 198 | else { | ||
| 199 | if (get_unsigned(&uval, *argv, 0)<0) { | ||
| 200 | fprintf(stderr, "invalid value of \"key\"\n"); | ||
| 201 | exit(-1); | ||
| 202 | } | ||
| 203 | p->i_key = p->o_key = htonl(uval); | ||
| 204 | } | ||
| 205 | } else if (strcmp(*argv, "ikey") == 0) { | ||
| 206 | unsigned uval; | ||
| 207 | NEXT_ARG(); | ||
| 208 | p->i_flags |= GRE_KEY; | ||
| 209 | if (strchr(*argv, '.')) | ||
| 210 | p->o_key = get_addr32(*argv); | ||
| 211 | else { | ||
| 212 | if (get_unsigned(&uval, *argv, 0)<0) { | ||
| 213 | fprintf(stderr, "invalid value of \"ikey\"\n"); | ||
| 214 | exit(-1); | ||
| 215 | } | ||
| 216 | p->i_key = htonl(uval); | ||
| 217 | } | ||
| 218 | } else if (strcmp(*argv, "okey") == 0) { | ||
| 219 | unsigned uval; | ||
| 220 | NEXT_ARG(); | ||
| 221 | p->o_flags |= GRE_KEY; | ||
| 222 | if (strchr(*argv, '.')) | ||
| 223 | p->o_key = get_addr32(*argv); | ||
| 224 | else { | ||
| 225 | if (get_unsigned(&uval, *argv, 0)<0) { | ||
| 226 | fprintf(stderr, "invalid value of \"okey\"\n"); | ||
| 227 | exit(-1); | ||
| 228 | } | ||
| 229 | p->o_key = htonl(uval); | ||
| 230 | } | ||
| 231 | } else if (strcmp(*argv, "seq") == 0) { | ||
| 232 | p->i_flags |= GRE_SEQ; | ||
| 233 | p->o_flags |= GRE_SEQ; | ||
| 234 | } else if (strcmp(*argv, "iseq") == 0) { | ||
| 235 | p->i_flags |= GRE_SEQ; | ||
| 236 | } else if (strcmp(*argv, "oseq") == 0) { | ||
| 237 | p->o_flags |= GRE_SEQ; | ||
| 238 | } else if (strcmp(*argv, "csum") == 0) { | ||
| 239 | p->i_flags |= GRE_CSUM; | ||
| 240 | p->o_flags |= GRE_CSUM; | ||
| 241 | } else if (strcmp(*argv, "icsum") == 0) { | ||
| 242 | p->i_flags |= GRE_CSUM; | ||
| 243 | } else if (strcmp(*argv, "ocsum") == 0) { | ||
| 244 | p->o_flags |= GRE_CSUM; | ||
| 245 | } else if (strcmp(*argv, "nopmtudisc") == 0) { | ||
| 246 | p->iph.frag_off = 0; | ||
| 247 | } else if (strcmp(*argv, "pmtudisc") == 0) { | ||
| 248 | p->iph.frag_off = htons(IP_DF); | ||
| 249 | } else if (strcmp(*argv, "remote") == 0) { | ||
| 250 | NEXT_ARG(); | ||
| 251 | if (strcmp(*argv, "any")) | ||
| 252 | p->iph.daddr = get_addr32(*argv); | ||
| 253 | } else if (strcmp(*argv, "local") == 0) { | ||
| 254 | NEXT_ARG(); | ||
| 255 | if (strcmp(*argv, "any")) | ||
| 256 | p->iph.saddr = get_addr32(*argv); | ||
| 257 | } else if (strcmp(*argv, "dev") == 0) { | ||
| 258 | NEXT_ARG(); | ||
| 259 | strncpy(medium, *argv, IFNAMSIZ-1); | ||
| 260 | } else if (strcmp(*argv, "ttl") == 0) { | ||
| 261 | unsigned uval; | ||
| 262 | NEXT_ARG(); | ||
| 263 | if (strcmp(*argv, "inherit") != 0) { | ||
| 264 | if (get_unsigned(&uval, *argv, 0)) | ||
| 265 | invarg("invalid TTL\n", *argv); | ||
| 266 | if (uval > 255) | ||
| 267 | invarg("TTL must be <=255\n", *argv); | ||
| 268 | p->iph.ttl = uval; | ||
| 269 | } | ||
| 270 | } else if (strcmp(*argv, "tos") == 0 || | ||
| 271 | matches(*argv, "dsfield") == 0) { | ||
| 272 | __u32 uval; | ||
| 273 | NEXT_ARG(); | ||
| 274 | if (strcmp(*argv, "inherit") != 0) { | ||
| 275 | if (rtnl_dsfield_a2n(&uval, *argv)) | ||
| 276 | invarg("bad TOS value", *argv); | ||
| 277 | p->iph.tos = uval; | ||
| 278 | } else | ||
| 279 | p->iph.tos = 1; | ||
| 280 | } else { | ||
| 281 | if (strcmp(*argv, "name") == 0) { | ||
| 282 | NEXT_ARG(); | ||
| 283 | } | ||
| 284 | if (p->name[0]) | ||
| 285 | duparg2("name", *argv); | ||
| 286 | strncpy(p->name, *argv, IFNAMSIZ); | ||
| 287 | if (cmd == SIOCCHGTUNNEL && count == 0) { | ||
| 288 | struct ip_tunnel_parm old_p; | ||
| 289 | memset(&old_p, 0, sizeof(old_p)); | ||
| 290 | if (do_get_ioctl(*argv, &old_p)) | ||
| 291 | return -1; | ||
| 292 | *p = old_p; | ||
| 293 | } | ||
| 294 | } | ||
| 295 | count++; | ||
| 296 | argc--; argv++; | ||
| 297 | } | ||
| 298 | |||
| 299 | |||
| 300 | if (p->iph.protocol == 0) { | ||
| 301 | if (memcmp(p->name, "gre", 3) == 0) | ||
| 302 | p->iph.protocol = IPPROTO_GRE; | ||
| 303 | else if (memcmp(p->name, "ipip", 4) == 0) | ||
| 304 | p->iph.protocol = IPPROTO_IPIP; | ||
| 305 | else if (memcmp(p->name, "sit", 3) == 0) | ||
| 306 | p->iph.protocol = IPPROTO_IPV6; | ||
| 307 | } | ||
| 308 | |||
| 309 | if (p->iph.protocol == IPPROTO_IPIP || p->iph.protocol == IPPROTO_IPV6) { | ||
| 310 | if ((p->i_flags & GRE_KEY) || (p->o_flags & GRE_KEY)) { | ||
| 311 | fprintf(stderr, "Keys are not allowed with ipip and sit.\n"); | ||
| 312 | return -1; | ||
| 313 | } | ||
| 314 | } | ||
| 315 | |||
| 316 | if (medium[0]) { | ||
| 317 | p->link = do_ioctl_get_ifindex(medium); | ||
| 318 | if (p->link == 0) | ||
| 319 | return -1; | ||
| 320 | } | ||
| 321 | |||
| 322 | if (p->i_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) { | ||
| 323 | p->i_key = p->iph.daddr; | ||
| 324 | p->i_flags |= GRE_KEY; | ||
| 325 | } | ||
| 326 | if (p->o_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) { | ||
| 327 | p->o_key = p->iph.daddr; | ||
| 328 | p->o_flags |= GRE_KEY; | ||
| 329 | } | ||
| 330 | if (IN_MULTICAST(ntohl(p->iph.daddr)) && !p->iph.saddr) { | ||
| 331 | fprintf(stderr, "Broadcast tunnel requires a source address.\n"); | ||
| 332 | return -1; | ||
| 333 | } | ||
| 334 | return 0; | ||
| 335 | } | ||
| 336 | |||
| 337 | |||
| 338 | static int do_add(int cmd, int argc, char **argv) | ||
| 339 | { | ||
| 340 | struct ip_tunnel_parm p; | ||
| 341 | |||
| 342 | if (parse_args(argc, argv, cmd, &p) < 0) | ||
| 343 | return -1; | ||
| 344 | |||
| 345 | if (p.iph.ttl && p.iph.frag_off == 0) { | ||
| 346 | fprintf(stderr, "ttl != 0 and noptmudisc are incompatible\n"); | ||
| 347 | return -1; | ||
| 348 | } | ||
| 349 | |||
| 350 | switch (p.iph.protocol) { | ||
| 351 | case IPPROTO_IPIP: | ||
| 352 | return do_add_ioctl(cmd, "tunl0", &p); | ||
| 353 | case IPPROTO_GRE: | ||
| 354 | return do_add_ioctl(cmd, "gre0", &p); | ||
| 355 | case IPPROTO_IPV6: | ||
| 356 | return do_add_ioctl(cmd, "sit0", &p); | ||
| 357 | default: | ||
| 358 | fprintf(stderr, "cannot determine tunnel mode (ipip, gre or sit)\n"); | ||
| 359 | return -1; | ||
| 360 | } | ||
| 361 | return -1; | ||
| 362 | } | ||
| 363 | |||
| 364 | int do_del(int argc, char **argv) | ||
| 365 | { | ||
| 366 | struct ip_tunnel_parm p; | ||
| 367 | |||
| 368 | if (parse_args(argc, argv, SIOCDELTUNNEL, &p) < 0) | ||
| 369 | return -1; | ||
| 370 | |||
| 371 | switch (p.iph.protocol) { | ||
| 372 | case IPPROTO_IPIP: | ||
| 373 | return do_del_ioctl("tunl0", &p); | ||
| 374 | case IPPROTO_GRE: | ||
| 375 | return do_del_ioctl("gre0", &p); | ||
| 376 | case IPPROTO_IPV6: | ||
| 377 | return do_del_ioctl("sit0", &p); | ||
| 378 | default: | ||
| 379 | return do_del_ioctl(p.name, &p); | ||
| 380 | } | ||
| 381 | return -1; | ||
| 382 | } | ||
| 383 | |||
| 384 | void print_tunnel(struct ip_tunnel_parm *p) | ||
| 385 | { | ||
| 386 | char s1[256]; | ||
| 387 | char s2[256]; | ||
| 388 | char s3[64]; | ||
| 389 | char s4[64]; | ||
| 390 | |||
| 391 | format_host(AF_INET, 4, &p->iph.daddr, s1, sizeof(s1)); | ||
| 392 | format_host(AF_INET, 4, &p->iph.saddr, s2, sizeof(s2)); | ||
| 393 | inet_ntop(AF_INET, &p->i_key, s3, sizeof(s3)); | ||
| 394 | inet_ntop(AF_INET, &p->o_key, s4, sizeof(s4)); | ||
| 395 | |||
| 396 | printf("%s: %s/ip remote %s local %s ", | ||
| 397 | p->name, | ||
| 398 | p->iph.protocol == IPPROTO_IPIP ? "ip" : | ||
| 399 | (p->iph.protocol == IPPROTO_GRE ? "gre" : | ||
| 400 | (p->iph.protocol == IPPROTO_IPV6 ? "ipv6" : "unknown")), | ||
| 401 | p->iph.daddr ? s1 : "any", p->iph.saddr ? s2 : "any"); | ||
| 402 | if (p->link) { | ||
| 403 | char *n = do_ioctl_get_ifname(p->link); | ||
| 404 | if (n) | ||
| 405 | printf(" dev %s ", n); | ||
| 406 | } | ||
| 407 | if (p->iph.ttl) | ||
| 408 | printf(" ttl %d ", p->iph.ttl); | ||
| 409 | else | ||
| 410 | printf(" ttl inherit "); | ||
| 411 | if (p->iph.tos) { | ||
| 412 | SPRINT_BUF(b1); | ||
| 413 | printf(" tos"); | ||
| 414 | if (p->iph.tos&1) | ||
| 415 | printf(" inherit"); | ||
| 416 | if (p->iph.tos&~1) | ||
| 417 | printf("%c%s ", p->iph.tos&1 ? '/' : ' ', | ||
| 418 | rtnl_dsfield_n2a(p->iph.tos&~1, b1, sizeof(b1))); | ||
| 419 | } | ||
| 420 | if (!(p->iph.frag_off&htons(IP_DF))) | ||
| 421 | printf(" nopmtudisc"); | ||
| 422 | |||
| 423 | if ((p->i_flags&GRE_KEY) && (p->o_flags&GRE_KEY) && p->o_key == p->i_key) | ||
| 424 | printf(" key %s", s3); | ||
| 425 | else if ((p->i_flags|p->o_flags)&GRE_KEY) { | ||
| 426 | if (p->i_flags&GRE_KEY) | ||
| 427 | printf(" ikey %s ", s3); | ||
| 428 | if (p->o_flags&GRE_KEY) | ||
| 429 | printf(" okey %s ", s4); | ||
| 430 | } | ||
| 431 | |||
| 432 | if (p->i_flags&GRE_SEQ) | ||
| 433 | printf("%s Drop packets out of sequence.\n", _SL_); | ||
| 434 | if (p->i_flags&GRE_CSUM) | ||
| 435 | printf("%s Checksum in received packet is required.", _SL_); | ||
| 436 | if (p->o_flags&GRE_SEQ) | ||
| 437 | printf("%s Sequence packets on output.", _SL_); | ||
| 438 | if (p->o_flags&GRE_CSUM) | ||
| 439 | printf("%s Checksum output packets.", _SL_); | ||
| 440 | } | ||
| 441 | |||
| 442 | static int do_tunnels_list(struct ip_tunnel_parm *p) | ||
| 443 | { | ||
| 444 | char name[IFNAMSIZ]; | ||
| 445 | unsigned long rx_bytes, rx_packets, rx_errs, rx_drops, | ||
| 446 | rx_fifo, rx_frame, | ||
| 447 | tx_bytes, tx_packets, tx_errs, tx_drops, | ||
| 448 | tx_fifo, tx_colls, tx_carrier, rx_multi; | ||
| 449 | int type; | ||
| 450 | struct ip_tunnel_parm p1; | ||
| 451 | |||
| 452 | char buf[512]; | ||
| 453 | FILE *fp = fopen("/proc/net/dev", "r"); | ||
| 454 | if (fp == NULL) { | ||
| 455 | perror("fopen"); | ||
| 456 | return -1; | ||
| 457 | } | ||
| 458 | |||
| 459 | fgets(buf, sizeof(buf), fp); | ||
| 460 | fgets(buf, sizeof(buf), fp); | ||
| 461 | |||
| 462 | while (fgets(buf, sizeof(buf), fp) != NULL) { | ||
| 463 | char *ptr; | ||
| 464 | buf[sizeof(buf) - 1] = 0; | ||
| 465 | if ((ptr = strchr(buf, ':')) == NULL || | ||
| 466 | (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) { | ||
| 467 | fprintf(stderr, "Wrong format of /proc/net/dev. Sorry.\n"); | ||
| 468 | return -1; | ||
| 469 | } | ||
| 470 | if (sscanf(ptr, "%ld%ld%ld%ld%ld%ld%ld%*d%ld%ld%ld%ld%ld%ld%ld", | ||
| 471 | &rx_bytes, &rx_packets, &rx_errs, &rx_drops, | ||
| 472 | &rx_fifo, &rx_frame, &rx_multi, | ||
| 473 | &tx_bytes, &tx_packets, &tx_errs, &tx_drops, | ||
| 474 | &tx_fifo, &tx_colls, &tx_carrier) != 14) | ||
| 475 | continue; | ||
| 476 | if (p->name[0] && strcmp(p->name, name)) | ||
| 477 | continue; | ||
| 478 | type = do_ioctl_get_iftype(name); | ||
| 479 | if (type == -1) { | ||
| 480 | fprintf(stderr, "Failed to get type of [%s]\n", name); | ||
| 481 | continue; | ||
| 482 | } | ||
| 483 | if (type != ARPHRD_TUNNEL && type != ARPHRD_IPGRE && type != ARPHRD_SIT) | ||
| 484 | continue; | ||
| 485 | memset(&p1, 0, sizeof(p1)); | ||
| 486 | if (do_get_ioctl(name, &p1)) | ||
| 487 | continue; | ||
| 488 | if ((p->link && p1.link != p->link) || | ||
| 489 | (p->name[0] && strcmp(p1.name, p->name)) || | ||
| 490 | (p->iph.daddr && p1.iph.daddr != p->iph.daddr) || | ||
| 491 | (p->iph.saddr && p1.iph.saddr != p->iph.saddr) || | ||
| 492 | (p->i_key && p1.i_key != p->i_key)) | ||
| 493 | continue; | ||
| 494 | print_tunnel(&p1); | ||
| 495 | printf("\n"); | ||
| 496 | } | ||
| 497 | return 0; | ||
| 498 | } | ||
| 499 | |||
| 500 | static int do_show(int argc, char **argv) | ||
| 501 | { | ||
| 502 | int err; | ||
| 503 | struct ip_tunnel_parm p; | ||
| 504 | |||
| 505 | if (parse_args(argc, argv, SIOCGETTUNNEL, &p) < 0) | ||
| 506 | return -1; | ||
| 507 | |||
| 508 | switch (p.iph.protocol) { | ||
| 509 | case IPPROTO_IPIP: | ||
| 510 | err = do_get_ioctl(p.name[0] ? p.name : "tunl0", &p); | ||
| 511 | break; | ||
| 512 | case IPPROTO_GRE: | ||
| 513 | err = do_get_ioctl(p.name[0] ? p.name : "gre0", &p); | ||
| 514 | break; | ||
| 515 | case IPPROTO_IPV6: | ||
| 516 | err = do_get_ioctl(p.name[0] ? p.name : "sit0", &p); | ||
| 517 | break; | ||
| 518 | default: | ||
| 519 | do_tunnels_list(&p); | ||
| 520 | return 0; | ||
| 521 | } | ||
| 522 | if (err) | ||
| 523 | return -1; | ||
| 524 | |||
| 525 | print_tunnel(&p); | ||
| 526 | printf("\n"); | ||
| 527 | return 0; | ||
| 528 | } | ||
| 529 | |||
| 530 | int do_iptunnel(int argc, char **argv) | ||
| 531 | { | ||
| 532 | if (argc > 0) { | ||
| 533 | if (matches(*argv, "add") == 0) | ||
| 534 | return do_add(SIOCADDTUNNEL, argc-1, argv+1); | ||
| 535 | if (matches(*argv, "change") == 0) | ||
| 536 | return do_add(SIOCCHGTUNNEL, argc-1, argv+1); | ||
| 537 | if (matches(*argv, "del") == 0) | ||
| 538 | return do_del(argc-1, argv+1); | ||
| 539 | if (matches(*argv, "show") == 0 || | ||
| 540 | matches(*argv, "lst") == 0 || | ||
| 541 | matches(*argv, "list") == 0) | ||
| 542 | return do_show(argc-1, argv+1); | ||
| 543 | } else | ||
| 544 | return do_show(0, NULL); | ||
| 545 | |||
| 546 | fprintf(stderr, "Command \"%s\" is unknown, try \"ip tunnel help\".\n", *argv); | ||
| 547 | exit(-1); | ||
| 548 | } | ||
diff --git a/networking/libiproute/libnetlink.c b/networking/libiproute/libnetlink.c new file mode 100644 index 000000000..a1f39d409 --- /dev/null +++ b/networking/libiproute/libnetlink.c | |||
| @@ -0,0 +1,521 @@ | |||
| 1 | /* | ||
| 2 | * libnetlink.c RTnetlink service routines. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version | ||
| 7 | * 2 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> | ||
| 10 | * | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <stdio.h> | ||
| 14 | #include <stdlib.h> | ||
| 15 | #include <unistd.h> | ||
| 16 | #include <syslog.h> | ||
| 17 | #include <fcntl.h> | ||
| 18 | #include <net/if_arp.h> | ||
| 19 | #include <sys/socket.h> | ||
| 20 | #include <netinet/in.h> | ||
| 21 | #include <string.h> | ||
| 22 | #include <errno.h> | ||
| 23 | #include <time.h> | ||
| 24 | #include <sys/uio.h> | ||
| 25 | |||
| 26 | #include "libnetlink.h" | ||
| 27 | |||
| 28 | void rtnl_close(struct rtnl_handle *rth) | ||
| 29 | { | ||
| 30 | close(rth->fd); | ||
| 31 | } | ||
| 32 | |||
| 33 | int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions) | ||
| 34 | { | ||
| 35 | int addr_len; | ||
| 36 | |||
| 37 | memset(rth, 0, sizeof(rth)); | ||
| 38 | |||
| 39 | rth->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); | ||
| 40 | if (rth->fd < 0) { | ||
| 41 | perror("Cannot open netlink socket"); | ||
| 42 | return -1; | ||
| 43 | } | ||
| 44 | |||
| 45 | memset(&rth->local, 0, sizeof(rth->local)); | ||
| 46 | rth->local.nl_family = AF_NETLINK; | ||
| 47 | rth->local.nl_groups = subscriptions; | ||
| 48 | |||
| 49 | if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) { | ||
| 50 | perror("Cannot bind netlink socket"); | ||
| 51 | return -1; | ||
| 52 | } | ||
| 53 | addr_len = sizeof(rth->local); | ||
| 54 | if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) { | ||
| 55 | perror("Cannot getsockname"); | ||
| 56 | return -1; | ||
| 57 | } | ||
| 58 | if (addr_len != sizeof(rth->local)) { | ||
| 59 | fprintf(stderr, "Wrong address length %d\n", addr_len); | ||
| 60 | return -1; | ||
| 61 | } | ||
| 62 | if (rth->local.nl_family != AF_NETLINK) { | ||
| 63 | fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family); | ||
| 64 | return -1; | ||
| 65 | } | ||
| 66 | rth->seq = time(NULL); | ||
| 67 | return 0; | ||
| 68 | } | ||
| 69 | |||
| 70 | int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type) | ||
| 71 | { | ||
| 72 | struct { | ||
| 73 | struct nlmsghdr nlh; | ||
| 74 | struct rtgenmsg g; | ||
| 75 | } req; | ||
| 76 | struct sockaddr_nl nladdr; | ||
| 77 | |||
| 78 | memset(&nladdr, 0, sizeof(nladdr)); | ||
| 79 | nladdr.nl_family = AF_NETLINK; | ||
| 80 | |||
| 81 | req.nlh.nlmsg_len = sizeof(req); | ||
| 82 | req.nlh.nlmsg_type = type; | ||
| 83 | req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; | ||
| 84 | req.nlh.nlmsg_pid = 0; | ||
| 85 | req.nlh.nlmsg_seq = rth->dump = ++rth->seq; | ||
| 86 | req.g.rtgen_family = family; | ||
| 87 | |||
| 88 | return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr)); | ||
| 89 | } | ||
| 90 | |||
| 91 | int rtnl_send(struct rtnl_handle *rth, char *buf, int len) | ||
| 92 | { | ||
| 93 | struct sockaddr_nl nladdr; | ||
| 94 | |||
| 95 | memset(&nladdr, 0, sizeof(nladdr)); | ||
| 96 | nladdr.nl_family = AF_NETLINK; | ||
| 97 | |||
| 98 | return sendto(rth->fd, buf, len, 0, (struct sockaddr*)&nladdr, sizeof(nladdr)); | ||
| 99 | } | ||
| 100 | |||
| 101 | int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) | ||
| 102 | { | ||
| 103 | struct nlmsghdr nlh; | ||
| 104 | struct sockaddr_nl nladdr; | ||
| 105 | struct iovec iov[2] = { { &nlh, sizeof(nlh) }, { req, len } }; | ||
| 106 | struct msghdr msg = { | ||
| 107 | (void*)&nladdr, sizeof(nladdr), | ||
| 108 | iov, 2, | ||
| 109 | NULL, 0, | ||
| 110 | 0 | ||
| 111 | }; | ||
| 112 | |||
| 113 | memset(&nladdr, 0, sizeof(nladdr)); | ||
| 114 | nladdr.nl_family = AF_NETLINK; | ||
| 115 | |||
| 116 | nlh.nlmsg_len = NLMSG_LENGTH(len); | ||
| 117 | nlh.nlmsg_type = type; | ||
| 118 | nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; | ||
| 119 | nlh.nlmsg_pid = 0; | ||
| 120 | nlh.nlmsg_seq = rth->dump = ++rth->seq; | ||
| 121 | |||
| 122 | return sendmsg(rth->fd, &msg, 0); | ||
| 123 | } | ||
| 124 | |||
| 125 | int rtnl_dump_filter(struct rtnl_handle *rth, | ||
| 126 | int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *), | ||
| 127 | void *arg1, | ||
| 128 | int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), | ||
| 129 | void *arg2) | ||
| 130 | { | ||
| 131 | char buf[8192]; | ||
| 132 | struct sockaddr_nl nladdr; | ||
| 133 | struct iovec iov = { buf, sizeof(buf) }; | ||
| 134 | |||
| 135 | while (1) { | ||
| 136 | int status; | ||
| 137 | struct nlmsghdr *h; | ||
| 138 | |||
| 139 | struct msghdr msg = { | ||
| 140 | (void*)&nladdr, sizeof(nladdr), | ||
| 141 | &iov, 1, | ||
| 142 | NULL, 0, | ||
| 143 | 0 | ||
| 144 | }; | ||
| 145 | |||
| 146 | status = recvmsg(rth->fd, &msg, 0); | ||
| 147 | |||
| 148 | if (status < 0) { | ||
| 149 | if (errno == EINTR) | ||
| 150 | continue; | ||
| 151 | perror("OVERRUN"); | ||
| 152 | continue; | ||
| 153 | } | ||
| 154 | if (status == 0) { | ||
| 155 | fprintf(stderr, "EOF on netlink\n"); | ||
| 156 | return -1; | ||
| 157 | } | ||
| 158 | if (msg.msg_namelen != sizeof(nladdr)) { | ||
| 159 | fprintf(stderr, "sender address length == %d\n", msg.msg_namelen); | ||
| 160 | exit(1); | ||
| 161 | } | ||
| 162 | |||
| 163 | h = (struct nlmsghdr*)buf; | ||
| 164 | while (NLMSG_OK(h, status)) { | ||
| 165 | int err; | ||
| 166 | |||
| 167 | if (h->nlmsg_pid != rth->local.nl_pid || | ||
| 168 | h->nlmsg_seq != rth->dump) { | ||
| 169 | if (junk) { | ||
| 170 | err = junk(&nladdr, h, arg2); | ||
| 171 | if (err < 0) | ||
| 172 | return err; | ||
| 173 | } | ||
| 174 | goto skip_it; | ||
| 175 | } | ||
| 176 | |||
| 177 | if (h->nlmsg_type == NLMSG_DONE) | ||
| 178 | return 0; | ||
| 179 | if (h->nlmsg_type == NLMSG_ERROR) { | ||
| 180 | struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); | ||
| 181 | if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { | ||
| 182 | fprintf(stderr, "ERROR truncated\n"); | ||
| 183 | } else { | ||
| 184 | errno = -err->error; | ||
| 185 | perror("RTNETLINK answers"); | ||
| 186 | } | ||
| 187 | return -1; | ||
| 188 | } | ||
| 189 | err = filter(&nladdr, h, arg1); | ||
| 190 | if (err < 0) | ||
| 191 | return err; | ||
| 192 | |||
| 193 | skip_it: | ||
| 194 | h = NLMSG_NEXT(h, status); | ||
| 195 | } | ||
| 196 | if (msg.msg_flags & MSG_TRUNC) { | ||
| 197 | fprintf(stderr, "Message truncated\n"); | ||
| 198 | continue; | ||
| 199 | } | ||
| 200 | if (status) { | ||
| 201 | fprintf(stderr, "!!!Remnant of size %d\n", status); | ||
| 202 | exit(1); | ||
| 203 | } | ||
| 204 | } | ||
| 205 | } | ||
| 206 | |||
| 207 | int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, | ||
| 208 | unsigned groups, struct nlmsghdr *answer, | ||
| 209 | int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), | ||
| 210 | void *jarg) | ||
| 211 | { | ||
| 212 | int status; | ||
| 213 | unsigned seq; | ||
| 214 | struct nlmsghdr *h; | ||
| 215 | struct sockaddr_nl nladdr; | ||
| 216 | struct iovec iov = { (void*)n, n->nlmsg_len }; | ||
| 217 | char buf[8192]; | ||
| 218 | struct msghdr msg = { | ||
| 219 | (void*)&nladdr, sizeof(nladdr), | ||
| 220 | &iov, 1, | ||
| 221 | NULL, 0, | ||
| 222 | 0 | ||
| 223 | }; | ||
| 224 | |||
| 225 | memset(&nladdr, 0, sizeof(nladdr)); | ||
| 226 | nladdr.nl_family = AF_NETLINK; | ||
| 227 | nladdr.nl_pid = peer; | ||
| 228 | nladdr.nl_groups = groups; | ||
| 229 | |||
| 230 | n->nlmsg_seq = seq = ++rtnl->seq; | ||
| 231 | if (answer == NULL) | ||
| 232 | n->nlmsg_flags |= NLM_F_ACK; | ||
| 233 | |||
| 234 | status = sendmsg(rtnl->fd, &msg, 0); | ||
| 235 | |||
| 236 | if (status < 0) { | ||
| 237 | perror("Cannot talk to rtnetlink"); | ||
| 238 | return -1; | ||
| 239 | } | ||
| 240 | |||
| 241 | iov.iov_base = buf; | ||
| 242 | |||
| 243 | while (1) { | ||
| 244 | iov.iov_len = sizeof(buf); | ||
| 245 | status = recvmsg(rtnl->fd, &msg, 0); | ||
| 246 | |||
| 247 | if (status < 0) { | ||
| 248 | if (errno == EINTR) | ||
| 249 | continue; | ||
| 250 | perror("OVERRUN"); | ||
| 251 | continue; | ||
| 252 | } | ||
| 253 | if (status == 0) { | ||
| 254 | fprintf(stderr, "EOF on netlink\n"); | ||
| 255 | return -1; | ||
| 256 | } | ||
| 257 | if (msg.msg_namelen != sizeof(nladdr)) { | ||
| 258 | fprintf(stderr, "sender address length == %d\n", msg.msg_namelen); | ||
| 259 | exit(1); | ||
| 260 | } | ||
| 261 | for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { | ||
| 262 | int err; | ||
| 263 | int len = h->nlmsg_len; | ||
| 264 | int l = len - sizeof(*h); | ||
| 265 | |||
| 266 | if (l<0 || len>status) { | ||
| 267 | if (msg.msg_flags & MSG_TRUNC) { | ||
| 268 | fprintf(stderr, "Truncated message\n"); | ||
| 269 | return -1; | ||
| 270 | } | ||
| 271 | fprintf(stderr, "!!!malformed message: len=%d\n", len); | ||
| 272 | exit(1); | ||
| 273 | } | ||
| 274 | |||
| 275 | if (h->nlmsg_pid != rtnl->local.nl_pid || | ||
| 276 | h->nlmsg_seq != seq) { | ||
| 277 | if (junk) { | ||
| 278 | err = junk(&nladdr, h, jarg); | ||
| 279 | if (err < 0) | ||
| 280 | return err; | ||
| 281 | } | ||
| 282 | continue; | ||
| 283 | } | ||
| 284 | |||
| 285 | if (h->nlmsg_type == NLMSG_ERROR) { | ||
| 286 | struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); | ||
| 287 | if (l < sizeof(struct nlmsgerr)) { | ||
| 288 | fprintf(stderr, "ERROR truncated\n"); | ||
| 289 | } else { | ||
| 290 | errno = -err->error; | ||
| 291 | if (errno == 0) { | ||
| 292 | if (answer) | ||
| 293 | memcpy(answer, h, h->nlmsg_len); | ||
| 294 | return 0; | ||
| 295 | } | ||
| 296 | perror("RTNETLINK answers"); | ||
| 297 | } | ||
| 298 | return -1; | ||
| 299 | } | ||
| 300 | if (answer) { | ||
| 301 | memcpy(answer, h, h->nlmsg_len); | ||
| 302 | return 0; | ||
| 303 | } | ||
| 304 | |||
| 305 | fprintf(stderr, "Unexpected reply!!!\n"); | ||
| 306 | |||
| 307 | status -= NLMSG_ALIGN(len); | ||
| 308 | h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); | ||
| 309 | } | ||
| 310 | if (msg.msg_flags & MSG_TRUNC) { | ||
| 311 | fprintf(stderr, "Message truncated\n"); | ||
| 312 | continue; | ||
| 313 | } | ||
| 314 | if (status) { | ||
| 315 | fprintf(stderr, "!!!Remnant of size %d\n", status); | ||
| 316 | exit(1); | ||
| 317 | } | ||
| 318 | } | ||
| 319 | } | ||
| 320 | |||
| 321 | int rtnl_listen(struct rtnl_handle *rtnl, | ||
| 322 | int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *), | ||
| 323 | void *jarg) | ||
| 324 | { | ||
| 325 | int status; | ||
| 326 | struct nlmsghdr *h; | ||
| 327 | struct sockaddr_nl nladdr; | ||
| 328 | struct iovec iov; | ||
| 329 | char buf[8192]; | ||
| 330 | struct msghdr msg = { | ||
| 331 | (void*)&nladdr, sizeof(nladdr), | ||
| 332 | &iov, 1, | ||
| 333 | NULL, 0, | ||
| 334 | 0 | ||
| 335 | }; | ||
| 336 | |||
| 337 | memset(&nladdr, 0, sizeof(nladdr)); | ||
| 338 | nladdr.nl_family = AF_NETLINK; | ||
| 339 | nladdr.nl_pid = 0; | ||
| 340 | nladdr.nl_groups = 0; | ||
| 341 | |||
| 342 | |||
| 343 | iov.iov_base = buf; | ||
| 344 | |||
| 345 | while (1) { | ||
| 346 | iov.iov_len = sizeof(buf); | ||
| 347 | status = recvmsg(rtnl->fd, &msg, 0); | ||
| 348 | |||
| 349 | if (status < 0) { | ||
| 350 | if (errno == EINTR) | ||
| 351 | continue; | ||
| 352 | perror("OVERRUN"); | ||
| 353 | continue; | ||
| 354 | } | ||
| 355 | if (status == 0) { | ||
| 356 | fprintf(stderr, "EOF on netlink\n"); | ||
| 357 | return -1; | ||
| 358 | } | ||
| 359 | if (msg.msg_namelen != sizeof(nladdr)) { | ||
| 360 | fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen); | ||
| 361 | exit(1); | ||
| 362 | } | ||
| 363 | for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { | ||
| 364 | int err; | ||
| 365 | int len = h->nlmsg_len; | ||
| 366 | int l = len - sizeof(*h); | ||
| 367 | |||
| 368 | if (l<0 || len>status) { | ||
| 369 | if (msg.msg_flags & MSG_TRUNC) { | ||
| 370 | fprintf(stderr, "Truncated message\n"); | ||
| 371 | return -1; | ||
| 372 | } | ||
| 373 | fprintf(stderr, "!!!malformed message: len=%d\n", len); | ||
| 374 | exit(1); | ||
| 375 | } | ||
| 376 | |||
| 377 | err = handler(&nladdr, h, jarg); | ||
| 378 | if (err < 0) | ||
| 379 | return err; | ||
| 380 | |||
| 381 | status -= NLMSG_ALIGN(len); | ||
| 382 | h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); | ||
| 383 | } | ||
| 384 | if (msg.msg_flags & MSG_TRUNC) { | ||
| 385 | fprintf(stderr, "Message truncated\n"); | ||
| 386 | continue; | ||
| 387 | } | ||
| 388 | if (status) { | ||
| 389 | fprintf(stderr, "!!!Remnant of size %d\n", status); | ||
| 390 | exit(1); | ||
| 391 | } | ||
| 392 | } | ||
| 393 | } | ||
| 394 | |||
| 395 | int rtnl_from_file(FILE *rtnl, | ||
| 396 | int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *), | ||
| 397 | void *jarg) | ||
| 398 | { | ||
| 399 | int status; | ||
| 400 | struct sockaddr_nl nladdr; | ||
| 401 | char buf[8192]; | ||
| 402 | struct nlmsghdr *h = (void*)buf; | ||
| 403 | |||
| 404 | memset(&nladdr, 0, sizeof(nladdr)); | ||
| 405 | nladdr.nl_family = AF_NETLINK; | ||
| 406 | nladdr.nl_pid = 0; | ||
| 407 | nladdr.nl_groups = 0; | ||
| 408 | |||
| 409 | while (1) { | ||
| 410 | int err, len, type; | ||
| 411 | int l; | ||
| 412 | |||
| 413 | status = fread(&buf, 1, sizeof(*h), rtnl); | ||
| 414 | |||
| 415 | if (status < 0) { | ||
| 416 | if (errno == EINTR) | ||
| 417 | continue; | ||
| 418 | perror("rtnl_from_file: fread"); | ||
| 419 | return -1; | ||
| 420 | } | ||
| 421 | if (status == 0) | ||
| 422 | return 0; | ||
| 423 | |||
| 424 | len = h->nlmsg_len; | ||
| 425 | type= h->nlmsg_type; | ||
| 426 | l = len - sizeof(*h); | ||
| 427 | |||
| 428 | if (l<0 || len>sizeof(buf)) { | ||
| 429 | fprintf(stderr, "!!!malformed message: len=%d @%lu\n", | ||
| 430 | len, ftell(rtnl)); | ||
| 431 | return -1; | ||
| 432 | } | ||
| 433 | |||
| 434 | status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl); | ||
| 435 | |||
| 436 | if (status < 0) { | ||
| 437 | perror("rtnl_from_file: fread"); | ||
| 438 | return -1; | ||
| 439 | } | ||
| 440 | if (status < l) { | ||
| 441 | fprintf(stderr, "rtnl-from_file: truncated message\n"); | ||
| 442 | return -1; | ||
| 443 | } | ||
| 444 | |||
| 445 | err = handler(&nladdr, h, jarg); | ||
| 446 | if (err < 0) | ||
| 447 | return err; | ||
| 448 | } | ||
| 449 | } | ||
| 450 | |||
| 451 | int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data) | ||
| 452 | { | ||
| 453 | int len = RTA_LENGTH(4); | ||
| 454 | struct rtattr *rta; | ||
| 455 | if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) | ||
| 456 | return -1; | ||
| 457 | rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len)); | ||
| 458 | rta->rta_type = type; | ||
| 459 | rta->rta_len = len; | ||
| 460 | memcpy(RTA_DATA(rta), &data, 4); | ||
| 461 | n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len; | ||
| 462 | return 0; | ||
| 463 | } | ||
| 464 | |||
| 465 | int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen) | ||
| 466 | { | ||
| 467 | int len = RTA_LENGTH(alen); | ||
| 468 | struct rtattr *rta; | ||
| 469 | |||
| 470 | if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) | ||
| 471 | return -1; | ||
| 472 | rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len)); | ||
| 473 | rta->rta_type = type; | ||
| 474 | rta->rta_len = len; | ||
| 475 | memcpy(RTA_DATA(rta), data, alen); | ||
| 476 | n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len; | ||
| 477 | return 0; | ||
| 478 | } | ||
| 479 | |||
| 480 | int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data) | ||
| 481 | { | ||
| 482 | int len = RTA_LENGTH(4); | ||
| 483 | struct rtattr *subrta; | ||
| 484 | |||
| 485 | if (RTA_ALIGN(rta->rta_len) + len > maxlen) | ||
| 486 | return -1; | ||
| 487 | subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); | ||
| 488 | subrta->rta_type = type; | ||
| 489 | subrta->rta_len = len; | ||
| 490 | memcpy(RTA_DATA(subrta), &data, 4); | ||
| 491 | rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len; | ||
| 492 | return 0; | ||
| 493 | } | ||
| 494 | |||
| 495 | int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen) | ||
| 496 | { | ||
| 497 | struct rtattr *subrta; | ||
| 498 | int len = RTA_LENGTH(alen); | ||
| 499 | |||
| 500 | if (RTA_ALIGN(rta->rta_len) + len > maxlen) | ||
| 501 | return -1; | ||
| 502 | subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); | ||
| 503 | subrta->rta_type = type; | ||
| 504 | subrta->rta_len = len; | ||
| 505 | memcpy(RTA_DATA(subrta), data, alen); | ||
| 506 | rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len; | ||
| 507 | return 0; | ||
| 508 | } | ||
| 509 | |||
| 510 | |||
| 511 | int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) | ||
| 512 | { | ||
| 513 | while (RTA_OK(rta, len)) { | ||
| 514 | if (rta->rta_type <= max) | ||
| 515 | tb[rta->rta_type] = rta; | ||
| 516 | rta = RTA_NEXT(rta,len); | ||
| 517 | } | ||
| 518 | if (len) | ||
| 519 | fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len); | ||
| 520 | return 0; | ||
| 521 | } | ||
diff --git a/networking/libiproute/libnetlink.h b/networking/libiproute/libnetlink.h new file mode 100644 index 000000000..45d3ad2bc --- /dev/null +++ b/networking/libiproute/libnetlink.h | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | #ifndef __LIBNETLINK_H__ | ||
| 2 | #define __LIBNETLINK_H__ 1 | ||
| 3 | |||
| 4 | #include <asm/types.h> | ||
| 5 | #include <linux/netlink.h> | ||
| 6 | #include <linux/rtnetlink.h> | ||
| 7 | |||
| 8 | struct rtnl_handle | ||
| 9 | { | ||
| 10 | int fd; | ||
| 11 | struct sockaddr_nl local; | ||
| 12 | struct sockaddr_nl peer; | ||
| 13 | __u32 seq; | ||
| 14 | __u32 dump; | ||
| 15 | }; | ||
| 16 | |||
| 17 | extern int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions); | ||
| 18 | extern void rtnl_close(struct rtnl_handle *rth); | ||
| 19 | extern int rtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type); | ||
| 20 | extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len); | ||
| 21 | extern int rtnl_dump_filter(struct rtnl_handle *rth, | ||
| 22 | int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *), | ||
| 23 | void *arg1, | ||
| 24 | int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), | ||
| 25 | void *arg2); | ||
| 26 | extern int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, | ||
| 27 | unsigned groups, struct nlmsghdr *answer, | ||
| 28 | int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), | ||
| 29 | void *jarg); | ||
| 30 | extern int rtnl_send(struct rtnl_handle *rth, char *buf, int); | ||
| 31 | |||
| 32 | |||
| 33 | extern int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data); | ||
| 34 | extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen); | ||
| 35 | extern int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data); | ||
| 36 | extern int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen); | ||
| 37 | |||
| 38 | extern int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len); | ||
| 39 | |||
| 40 | extern int rtnl_listen(struct rtnl_handle *, int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *), | ||
| 41 | void *jarg); | ||
| 42 | extern int rtnl_from_file(FILE *, int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *), | ||
| 43 | void *jarg); | ||
| 44 | |||
| 45 | #endif /* __LIBNETLINK_H__ */ | ||
| 46 | |||
diff --git a/networking/libiproute/linux/pkt_sched.h b/networking/libiproute/linux/pkt_sched.h new file mode 100644 index 000000000..e174588f5 --- /dev/null +++ b/networking/libiproute/linux/pkt_sched.h | |||
| @@ -0,0 +1,413 @@ | |||
| 1 | #ifndef __LINUX_PKT_SCHED_H | ||
| 2 | #define __LINUX_PKT_SCHED_H | ||
| 3 | |||
| 4 | /* Logical priority bands not depending on specific packet scheduler. | ||
| 5 | Every scheduler will map them to real traffic classes, if it has | ||
| 6 | no more precise mechanism to classify packets. | ||
| 7 | |||
| 8 | These numbers have no special meaning, though their coincidence | ||
| 9 | with obsolete IPv6 values is not occasional :-). New IPv6 drafts | ||
| 10 | preferred full anarchy inspired by diffserv group. | ||
| 11 | |||
| 12 | Note: TC_PRIO_BESTEFFORT does not mean that it is the most unhappy | ||
| 13 | class, actually, as rule it will be handled with more care than | ||
| 14 | filler or even bulk. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <asm/types.h> | ||
| 18 | |||
| 19 | #define TC_PRIO_BESTEFFORT 0 | ||
| 20 | #define TC_PRIO_FILLER 1 | ||
| 21 | #define TC_PRIO_BULK 2 | ||
| 22 | #define TC_PRIO_INTERACTIVE_BULK 4 | ||
| 23 | #define TC_PRIO_INTERACTIVE 6 | ||
| 24 | #define TC_PRIO_CONTROL 7 | ||
| 25 | |||
| 26 | #define TC_PRIO_MAX 15 | ||
| 27 | |||
| 28 | /* Generic queue statistics, available for all the elements. | ||
| 29 | Particular schedulers may have also their private records. | ||
| 30 | */ | ||
| 31 | |||
| 32 | struct tc_stats | ||
| 33 | { | ||
| 34 | __u64 bytes; /* NUmber of enqueues bytes */ | ||
| 35 | __u32 packets; /* Number of enqueued packets */ | ||
| 36 | __u32 drops; /* Packets dropped because of lack of resources */ | ||
| 37 | __u32 overlimits; /* Number of throttle events when this | ||
| 38 | * flow goes out of allocated bandwidth */ | ||
| 39 | __u32 bps; /* Current flow byte rate */ | ||
| 40 | __u32 pps; /* Current flow packet rate */ | ||
| 41 | __u32 qlen; | ||
| 42 | __u32 backlog; | ||
| 43 | #ifdef __KERNEL__ | ||
| 44 | spinlock_t *lock; | ||
| 45 | #endif | ||
| 46 | }; | ||
| 47 | |||
| 48 | struct tc_estimator | ||
| 49 | { | ||
| 50 | char interval; | ||
| 51 | unsigned char ewma_log; | ||
| 52 | }; | ||
| 53 | |||
| 54 | /* "Handles" | ||
| 55 | --------- | ||
| 56 | |||
| 57 | All the traffic control objects have 32bit identifiers, or "handles". | ||
| 58 | |||
| 59 | They can be considered as opaque numbers from user API viewpoint, | ||
| 60 | but actually they always consist of two fields: major and | ||
| 61 | minor numbers, which are interpreted by kernel specially, | ||
| 62 | that may be used by applications, though not recommended. | ||
| 63 | |||
| 64 | F.e. qdisc handles always have minor number equal to zero, | ||
| 65 | classes (or flows) have major equal to parent qdisc major, and | ||
| 66 | minor uniquely identifying class inside qdisc. | ||
| 67 | |||
| 68 | Macros to manipulate handles: | ||
| 69 | */ | ||
| 70 | |||
| 71 | #define TC_H_MAJ_MASK (0xFFFF0000U) | ||
| 72 | #define TC_H_MIN_MASK (0x0000FFFFU) | ||
| 73 | #define TC_H_MAJ(h) ((h)&TC_H_MAJ_MASK) | ||
| 74 | #define TC_H_MIN(h) ((h)&TC_H_MIN_MASK) | ||
| 75 | #define TC_H_MAKE(maj,min) (((maj)&TC_H_MAJ_MASK)|((min)&TC_H_MIN_MASK)) | ||
| 76 | |||
| 77 | #define TC_H_UNSPEC (0U) | ||
| 78 | #define TC_H_ROOT (0xFFFFFFFFU) | ||
| 79 | #define TC_H_INGRESS (0xFFFFFFF1U) | ||
| 80 | |||
| 81 | struct tc_ratespec | ||
| 82 | { | ||
| 83 | unsigned char cell_log; | ||
| 84 | unsigned char __reserved; | ||
| 85 | unsigned short feature; | ||
| 86 | short addend; | ||
| 87 | unsigned short mpu; | ||
| 88 | __u32 rate; | ||
| 89 | }; | ||
| 90 | |||
| 91 | /* FIFO section */ | ||
| 92 | |||
| 93 | struct tc_fifo_qopt | ||
| 94 | { | ||
| 95 | __u32 limit; /* Queue length: bytes for bfifo, packets for pfifo */ | ||
| 96 | }; | ||
| 97 | |||
| 98 | /* PRIO section */ | ||
| 99 | |||
| 100 | #define TCQ_PRIO_BANDS 16 | ||
| 101 | |||
| 102 | struct tc_prio_qopt | ||
| 103 | { | ||
| 104 | int bands; /* Number of bands */ | ||
| 105 | __u8 priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> PRIO band */ | ||
| 106 | }; | ||
| 107 | |||
| 108 | /* CSZ section */ | ||
| 109 | |||
| 110 | struct tc_csz_qopt | ||
| 111 | { | ||
| 112 | int flows; /* Maximal number of guaranteed flows */ | ||
| 113 | unsigned char R_log; /* Fixed point position for round number */ | ||
| 114 | unsigned char delta_log; /* Log of maximal managed time interval */ | ||
| 115 | __u8 priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> CSZ band */ | ||
| 116 | }; | ||
| 117 | |||
| 118 | struct tc_csz_copt | ||
| 119 | { | ||
| 120 | struct tc_ratespec slice; | ||
| 121 | struct tc_ratespec rate; | ||
| 122 | struct tc_ratespec peakrate; | ||
| 123 | __u32 limit; | ||
| 124 | __u32 buffer; | ||
| 125 | __u32 mtu; | ||
| 126 | }; | ||
| 127 | |||
| 128 | enum | ||
| 129 | { | ||
| 130 | TCA_CSZ_UNSPEC, | ||
| 131 | TCA_CSZ_PARMS, | ||
| 132 | TCA_CSZ_RTAB, | ||
| 133 | TCA_CSZ_PTAB, | ||
| 134 | }; | ||
| 135 | |||
| 136 | /* TBF section */ | ||
| 137 | |||
| 138 | struct tc_tbf_qopt | ||
| 139 | { | ||
| 140 | struct tc_ratespec rate; | ||
| 141 | struct tc_ratespec peakrate; | ||
| 142 | __u32 limit; | ||
| 143 | __u32 buffer; | ||
| 144 | __u32 mtu; | ||
| 145 | }; | ||
| 146 | |||
| 147 | enum | ||
| 148 | { | ||
| 149 | TCA_TBF_UNSPEC, | ||
| 150 | TCA_TBF_PARMS, | ||
| 151 | TCA_TBF_RTAB, | ||
| 152 | TCA_TBF_PTAB, | ||
| 153 | }; | ||
| 154 | |||
| 155 | |||
| 156 | /* TEQL section */ | ||
| 157 | |||
| 158 | /* TEQL does not require any parameters */ | ||
| 159 | |||
| 160 | /* SFQ section */ | ||
| 161 | |||
| 162 | struct tc_sfq_qopt | ||
| 163 | { | ||
| 164 | unsigned quantum; /* Bytes per round allocated to flow */ | ||
| 165 | int perturb_period; /* Period of hash perturbation */ | ||
| 166 | __u32 limit; /* Maximal packets in queue */ | ||
| 167 | unsigned divisor; /* Hash divisor */ | ||
| 168 | unsigned flows; /* Maximal number of flows */ | ||
| 169 | }; | ||
| 170 | |||
| 171 | /* | ||
| 172 | * NOTE: limit, divisor and flows are hardwired to code at the moment. | ||
| 173 | * | ||
| 174 | * limit=flows=128, divisor=1024; | ||
| 175 | * | ||
| 176 | * The only reason for this is efficiency, it is possible | ||
| 177 | * to change these parameters in compile time. | ||
| 178 | */ | ||
| 179 | |||
| 180 | /* RED section */ | ||
| 181 | |||
| 182 | enum | ||
| 183 | { | ||
| 184 | TCA_RED_UNSPEC, | ||
| 185 | TCA_RED_PARMS, | ||
| 186 | TCA_RED_STAB, | ||
| 187 | }; | ||
| 188 | |||
| 189 | struct tc_red_qopt | ||
| 190 | { | ||
| 191 | __u32 limit; /* HARD maximal queue length (bytes) */ | ||
| 192 | __u32 qth_min; /* Min average length threshold (bytes) */ | ||
| 193 | __u32 qth_max; /* Max average length threshold (bytes) */ | ||
| 194 | unsigned char Wlog; /* log(W) */ | ||
| 195 | unsigned char Plog; /* log(P_max/(qth_max-qth_min)) */ | ||
| 196 | unsigned char Scell_log; /* cell size for idle damping */ | ||
| 197 | unsigned char flags; | ||
| 198 | #define TC_RED_ECN 1 | ||
| 199 | }; | ||
| 200 | |||
| 201 | struct tc_red_xstats | ||
| 202 | { | ||
| 203 | __u32 early; /* Early drops */ | ||
| 204 | __u32 pdrop; /* Drops due to queue limits */ | ||
| 205 | __u32 other; /* Drops due to drop() calls */ | ||
| 206 | __u32 marked; /* Marked packets */ | ||
| 207 | }; | ||
| 208 | |||
| 209 | /* GRED section */ | ||
| 210 | |||
| 211 | #define MAX_DPs 16 | ||
| 212 | |||
| 213 | enum | ||
| 214 | { | ||
| 215 | TCA_GRED_UNSPEC, | ||
| 216 | TCA_GRED_PARMS, | ||
| 217 | TCA_GRED_STAB, | ||
| 218 | TCA_GRED_DPS, | ||
| 219 | }; | ||
| 220 | |||
| 221 | #define TCA_SET_OFF TCA_GRED_PARMS | ||
| 222 | struct tc_gred_qopt | ||
| 223 | { | ||
| 224 | __u32 limit; /* HARD maximal queue length (bytes) | ||
| 225 | */ | ||
| 226 | __u32 qth_min; /* Min average length threshold (bytes) | ||
| 227 | */ | ||
| 228 | __u32 qth_max; /* Max average length threshold (bytes) | ||
| 229 | */ | ||
| 230 | __u32 DP; /* upto 2^32 DPs */ | ||
| 231 | __u32 backlog; | ||
| 232 | __u32 qave; | ||
| 233 | __u32 forced; | ||
| 234 | __u32 early; | ||
| 235 | __u32 other; | ||
| 236 | __u32 pdrop; | ||
| 237 | |||
| 238 | unsigned char Wlog; /* log(W) */ | ||
| 239 | unsigned char Plog; /* log(P_max/(qth_max-qth_min)) */ | ||
| 240 | unsigned char Scell_log; /* cell size for idle damping */ | ||
| 241 | __u8 prio; /* prio of this VQ */ | ||
| 242 | __u32 packets; | ||
| 243 | __u32 bytesin; | ||
| 244 | }; | ||
| 245 | /* gred setup */ | ||
| 246 | struct tc_gred_sopt | ||
| 247 | { | ||
| 248 | __u32 DPs; | ||
| 249 | __u32 def_DP; | ||
| 250 | __u8 grio; | ||
| 251 | }; | ||
| 252 | |||
| 253 | /* HTB section */ | ||
| 254 | #define TC_HTB_NUMPRIO 4 | ||
| 255 | #define TC_HTB_MAXDEPTH 4 | ||
| 256 | |||
| 257 | struct tc_htb_opt | ||
| 258 | { | ||
| 259 | struct tc_ratespec rate; | ||
| 260 | struct tc_ratespec ceil; | ||
| 261 | __u32 buffer; | ||
| 262 | __u32 cbuffer; | ||
| 263 | __u32 quantum; /* out only */ | ||
| 264 | __u32 level; /* out only */ | ||
| 265 | __u8 prio; | ||
| 266 | __u8 injectd; /* inject class distance */ | ||
| 267 | __u8 pad[2]; | ||
| 268 | }; | ||
| 269 | struct tc_htb_glob | ||
| 270 | { | ||
| 271 | __u32 rate2quantum; /* bps->quantum divisor */ | ||
| 272 | __u32 defcls; /* default class number */ | ||
| 273 | __u32 use_dcache; /* use dequeue cache ? */ | ||
| 274 | __u32 debug; /* debug flags */ | ||
| 275 | |||
| 276 | |||
| 277 | /* stats */ | ||
| 278 | __u32 deq_rate; /* dequeue rate */ | ||
| 279 | __u32 utilz; /* dequeue utilization */ | ||
| 280 | __u32 trials; /* deq_prio trials per dequeue */ | ||
| 281 | __u32 dcache_hits; | ||
| 282 | __u32 direct_pkts; /* count of non shapped packets */ | ||
| 283 | }; | ||
| 284 | enum | ||
| 285 | { | ||
| 286 | TCA_HTB_UNSPEC, | ||
| 287 | TCA_HTB_PARMS, | ||
| 288 | TCA_HTB_INIT, | ||
| 289 | TCA_HTB_CTAB, | ||
| 290 | TCA_HTB_RTAB, | ||
| 291 | }; | ||
| 292 | struct tc_htb_xstats | ||
| 293 | { | ||
| 294 | __u32 lends; | ||
| 295 | __u32 borrows; | ||
| 296 | __u32 giants; /* too big packets (rate will not be accurate) */ | ||
| 297 | __u32 injects; /* how many times leaf used injected bw */ | ||
| 298 | __u32 tokens; | ||
| 299 | __u32 ctokens; | ||
| 300 | }; | ||
| 301 | |||
| 302 | /* CBQ section */ | ||
| 303 | |||
| 304 | #define TC_CBQ_MAXPRIO 8 | ||
| 305 | #define TC_CBQ_MAXLEVEL 8 | ||
| 306 | #define TC_CBQ_DEF_EWMA 5 | ||
| 307 | |||
| 308 | struct tc_cbq_lssopt | ||
| 309 | { | ||
| 310 | unsigned char change; | ||
| 311 | unsigned char flags; | ||
| 312 | #define TCF_CBQ_LSS_BOUNDED 1 | ||
| 313 | #define TCF_CBQ_LSS_ISOLATED 2 | ||
| 314 | unsigned char ewma_log; | ||
| 315 | unsigned char level; | ||
| 316 | #define TCF_CBQ_LSS_FLAGS 1 | ||
| 317 | #define TCF_CBQ_LSS_EWMA 2 | ||
| 318 | #define TCF_CBQ_LSS_MAXIDLE 4 | ||
| 319 | #define TCF_CBQ_LSS_MINIDLE 8 | ||
| 320 | #define TCF_CBQ_LSS_OFFTIME 0x10 | ||
| 321 | #define TCF_CBQ_LSS_AVPKT 0x20 | ||
| 322 | __u32 maxidle; | ||
| 323 | __u32 minidle; | ||
| 324 | __u32 offtime; | ||
| 325 | __u32 avpkt; | ||
| 326 | }; | ||
| 327 | |||
| 328 | struct tc_cbq_wrropt | ||
| 329 | { | ||
| 330 | unsigned char flags; | ||
| 331 | unsigned char priority; | ||
| 332 | unsigned char cpriority; | ||
| 333 | unsigned char __reserved; | ||
| 334 | __u32 allot; | ||
| 335 | __u32 weight; | ||
| 336 | }; | ||
| 337 | |||
| 338 | struct tc_cbq_ovl | ||
| 339 | { | ||
| 340 | unsigned char strategy; | ||
| 341 | #define TC_CBQ_OVL_CLASSIC 0 | ||
| 342 | #define TC_CBQ_OVL_DELAY 1 | ||
| 343 | #define TC_CBQ_OVL_LOWPRIO 2 | ||
| 344 | #define TC_CBQ_OVL_DROP 3 | ||
| 345 | #define TC_CBQ_OVL_RCLASSIC 4 | ||
| 346 | unsigned char priority2; | ||
| 347 | __u32 penalty; | ||
| 348 | }; | ||
| 349 | |||
| 350 | struct tc_cbq_police | ||
| 351 | { | ||
| 352 | unsigned char police; | ||
| 353 | unsigned char __res1; | ||
| 354 | unsigned short __res2; | ||
| 355 | }; | ||
| 356 | |||
| 357 | struct tc_cbq_fopt | ||
| 358 | { | ||
| 359 | __u32 split; | ||
| 360 | __u32 defmap; | ||
| 361 | __u32 defchange; | ||
| 362 | }; | ||
| 363 | |||
| 364 | struct tc_cbq_xstats | ||
| 365 | { | ||
| 366 | __u32 borrows; | ||
| 367 | __u32 overactions; | ||
| 368 | __s32 avgidle; | ||
| 369 | __s32 undertime; | ||
| 370 | }; | ||
| 371 | |||
| 372 | enum | ||
| 373 | { | ||
| 374 | TCA_CBQ_UNSPEC, | ||
| 375 | TCA_CBQ_LSSOPT, | ||
| 376 | TCA_CBQ_WRROPT, | ||
| 377 | TCA_CBQ_FOPT, | ||
| 378 | TCA_CBQ_OVL_STRATEGY, | ||
| 379 | TCA_CBQ_RATE, | ||
| 380 | TCA_CBQ_RTAB, | ||
| 381 | TCA_CBQ_POLICE, | ||
| 382 | }; | ||
| 383 | |||
| 384 | #define TCA_CBQ_MAX TCA_CBQ_POLICE | ||
| 385 | |||
| 386 | /* dsmark section */ | ||
| 387 | |||
| 388 | enum { | ||
| 389 | TCA_DSMARK_UNSPEC, | ||
| 390 | TCA_DSMARK_INDICES, | ||
| 391 | TCA_DSMARK_DEFAULT_INDEX, | ||
| 392 | TCA_DSMARK_SET_TC_INDEX, | ||
| 393 | TCA_DSMARK_MASK, | ||
| 394 | TCA_DSMARK_VALUE | ||
| 395 | }; | ||
| 396 | |||
| 397 | #define TCA_DSMARK_MAX TCA_DSMARK_VALUE | ||
| 398 | |||
| 399 | /* ATM section */ | ||
| 400 | |||
| 401 | enum { | ||
| 402 | TCA_ATM_UNSPEC, | ||
| 403 | TCA_ATM_FD, /* file/socket descriptor */ | ||
| 404 | TCA_ATM_PTR, /* pointer to descriptor - later */ | ||
| 405 | TCA_ATM_HDR, /* LL header */ | ||
| 406 | TCA_ATM_EXCESS, /* excess traffic class (0 for CLP) */ | ||
| 407 | TCA_ATM_ADDR, /* PVC address (for output only) */ | ||
| 408 | TCA_ATM_STATE /* VC state (ATM_VS_*; for output only) */ | ||
| 409 | }; | ||
| 410 | |||
| 411 | #define TCA_ATM_MAX TCA_ATM_STATE | ||
| 412 | |||
| 413 | #endif | ||
diff --git a/networking/libiproute/ll_addr.c b/networking/libiproute/ll_addr.c new file mode 100644 index 000000000..51ff13b8c --- /dev/null +++ b/networking/libiproute/ll_addr.c | |||
| @@ -0,0 +1,92 @@ | |||
| 1 | /* | ||
| 2 | * ll_addr.c | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version | ||
| 7 | * 2 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <stdio.h> | ||
| 13 | #include <stdlib.h> | ||
| 14 | #include <unistd.h> | ||
| 15 | #include <syslog.h> | ||
| 16 | #include <fcntl.h> | ||
| 17 | #include <sys/ioctl.h> | ||
| 18 | #include <sys/socket.h> | ||
| 19 | #include <sys/ioctl.h> | ||
| 20 | #include <netinet/in.h> | ||
| 21 | #include <arpa/inet.h> | ||
| 22 | #include <string.h> | ||
| 23 | |||
| 24 | #include <linux/netdevice.h> | ||
| 25 | #include <linux/if_arp.h> | ||
| 26 | #include <linux/sockios.h> | ||
| 27 | |||
| 28 | #include "utils.h" | ||
| 29 | |||
| 30 | |||
| 31 | const char *ll_addr_n2a(unsigned char *addr, int alen, int type, char *buf, int blen) | ||
| 32 | { | ||
| 33 | int i; | ||
| 34 | int l; | ||
| 35 | |||
| 36 | if (alen == 4 && | ||
| 37 | (type == ARPHRD_TUNNEL || type == ARPHRD_SIT || type == ARPHRD_IPGRE)) { | ||
| 38 | return inet_ntop(AF_INET, addr, buf, blen); | ||
| 39 | } | ||
| 40 | l = 0; | ||
| 41 | for (i=0; i<alen; i++) { | ||
| 42 | if (i==0) { | ||
| 43 | snprintf(buf+l, blen, "%02x", addr[i]); | ||
| 44 | blen -= 2; | ||
| 45 | l += 2; | ||
| 46 | } else { | ||
| 47 | snprintf(buf+l, blen, ":%02x", addr[i]); | ||
| 48 | blen -= 3; | ||
| 49 | l += 3; | ||
| 50 | } | ||
| 51 | } | ||
| 52 | return buf; | ||
| 53 | } | ||
| 54 | |||
| 55 | int ll_addr_a2n(unsigned char *lladdr, int len, char *arg) | ||
| 56 | { | ||
| 57 | if (strchr(arg, '.')) { | ||
| 58 | inet_prefix pfx; | ||
| 59 | if (get_addr_1(&pfx, arg, AF_INET)) { | ||
| 60 | fprintf(stderr, "\"%s\" is invalid lladdr.\n", arg); | ||
| 61 | return -1; | ||
| 62 | } | ||
| 63 | if (len < 4) | ||
| 64 | return -1; | ||
| 65 | memcpy(lladdr, pfx.data, 4); | ||
| 66 | return 4; | ||
| 67 | } else { | ||
| 68 | int i; | ||
| 69 | |||
| 70 | for (i=0; i<len; i++) { | ||
| 71 | int temp; | ||
| 72 | char *cp = strchr(arg, ':'); | ||
| 73 | if (cp) { | ||
| 74 | *cp = 0; | ||
| 75 | cp++; | ||
| 76 | } | ||
| 77 | if (sscanf(arg, "%x", &temp) != 1) { | ||
| 78 | fprintf(stderr, "\"%s\" is invalid lladdr.\n", arg); | ||
| 79 | return -1; | ||
| 80 | } | ||
| 81 | if (temp < 0 || temp > 255) { | ||
| 82 | fprintf(stderr, "\"%s\" is invalid lladdr.\n", arg); | ||
| 83 | return -1; | ||
| 84 | } | ||
| 85 | lladdr[i] = temp; | ||
| 86 | if (!cp) | ||
| 87 | break; | ||
| 88 | arg = cp; | ||
| 89 | } | ||
| 90 | return i+1; | ||
| 91 | } | ||
| 92 | } | ||
diff --git a/networking/libiproute/ll_map.c b/networking/libiproute/ll_map.c new file mode 100644 index 000000000..e5a95e6a4 --- /dev/null +++ b/networking/libiproute/ll_map.c | |||
| @@ -0,0 +1,169 @@ | |||
| 1 | /* | ||
| 2 | * ll_map.c | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version | ||
| 7 | * 2 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> | ||
| 10 | * | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <stdio.h> | ||
| 14 | #include <stdlib.h> | ||
| 15 | #include <unistd.h> | ||
| 16 | #include <syslog.h> | ||
| 17 | #include <fcntl.h> | ||
| 18 | #include <sys/socket.h> | ||
| 19 | #include <netinet/in.h> | ||
| 20 | #include <string.h> | ||
| 21 | |||
| 22 | #include "libnetlink.h" | ||
| 23 | #include "ll_map.h" | ||
| 24 | |||
| 25 | struct idxmap | ||
| 26 | { | ||
| 27 | struct idxmap * next; | ||
| 28 | int index; | ||
| 29 | int type; | ||
| 30 | int alen; | ||
| 31 | unsigned flags; | ||
| 32 | unsigned char addr[8]; | ||
| 33 | char name[16]; | ||
| 34 | }; | ||
| 35 | |||
| 36 | static struct idxmap *idxmap[16]; | ||
| 37 | |||
| 38 | int ll_remember_index(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) | ||
| 39 | { | ||
| 40 | int h; | ||
| 41 | struct ifinfomsg *ifi = NLMSG_DATA(n); | ||
| 42 | struct idxmap *im, **imp; | ||
| 43 | struct rtattr *tb[IFLA_MAX+1]; | ||
| 44 | |||
| 45 | if (n->nlmsg_type != RTM_NEWLINK) | ||
| 46 | return 0; | ||
| 47 | |||
| 48 | if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi))) | ||
| 49 | return -1; | ||
| 50 | |||
| 51 | |||
| 52 | memset(tb, 0, sizeof(tb)); | ||
| 53 | parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n)); | ||
| 54 | if (tb[IFLA_IFNAME] == NULL) | ||
| 55 | return 0; | ||
| 56 | |||
| 57 | h = ifi->ifi_index&0xF; | ||
| 58 | |||
| 59 | for (imp=&idxmap[h]; (im=*imp)!=NULL; imp = &im->next) | ||
| 60 | if (im->index == ifi->ifi_index) | ||
| 61 | break; | ||
| 62 | |||
| 63 | if (im == NULL) { | ||
| 64 | im = malloc(sizeof(*im)); | ||
| 65 | if (im == NULL) | ||
| 66 | return 0; | ||
| 67 | im->next = *imp; | ||
| 68 | im->index = ifi->ifi_index; | ||
| 69 | *imp = im; | ||
| 70 | } | ||
| 71 | |||
| 72 | im->type = ifi->ifi_type; | ||
| 73 | im->flags = ifi->ifi_flags; | ||
| 74 | if (tb[IFLA_ADDRESS]) { | ||
| 75 | int alen; | ||
| 76 | im->alen = alen = RTA_PAYLOAD(tb[IFLA_ADDRESS]); | ||
| 77 | if (alen > sizeof(im->addr)) | ||
| 78 | alen = sizeof(im->addr); | ||
| 79 | memcpy(im->addr, RTA_DATA(tb[IFLA_ADDRESS]), alen); | ||
| 80 | } else { | ||
| 81 | im->alen = 0; | ||
| 82 | memset(im->addr, 0, sizeof(im->addr)); | ||
| 83 | } | ||
| 84 | strcpy(im->name, RTA_DATA(tb[IFLA_IFNAME])); | ||
| 85 | return 0; | ||
| 86 | } | ||
| 87 | |||
| 88 | const char *ll_idx_n2a(int idx, char *buf) | ||
| 89 | { | ||
| 90 | struct idxmap *im; | ||
| 91 | |||
| 92 | if (idx == 0) | ||
| 93 | return "*"; | ||
| 94 | for (im = idxmap[idx&0xF]; im; im = im->next) | ||
| 95 | if (im->index == idx) | ||
| 96 | return im->name; | ||
| 97 | snprintf(buf, 16, "if%d", idx); | ||
| 98 | return buf; | ||
| 99 | } | ||
| 100 | |||
| 101 | |||
| 102 | const char *ll_index_to_name(int idx) | ||
| 103 | { | ||
| 104 | static char nbuf[16]; | ||
| 105 | |||
| 106 | return ll_idx_n2a(idx, nbuf); | ||
| 107 | } | ||
| 108 | |||
| 109 | int ll_index_to_type(int idx) | ||
| 110 | { | ||
| 111 | struct idxmap *im; | ||
| 112 | |||
| 113 | if (idx == 0) | ||
| 114 | return -1; | ||
| 115 | for (im = idxmap[idx&0xF]; im; im = im->next) | ||
| 116 | if (im->index == idx) | ||
| 117 | return im->type; | ||
| 118 | return -1; | ||
| 119 | } | ||
| 120 | |||
| 121 | unsigned ll_index_to_flags(int idx) | ||
| 122 | { | ||
| 123 | struct idxmap *im; | ||
| 124 | |||
| 125 | if (idx == 0) | ||
| 126 | return 0; | ||
| 127 | |||
| 128 | for (im = idxmap[idx&0xF]; im; im = im->next) | ||
| 129 | if (im->index == idx) | ||
| 130 | return im->flags; | ||
| 131 | return 0; | ||
| 132 | } | ||
| 133 | |||
| 134 | int ll_name_to_index(char *name) | ||
| 135 | { | ||
| 136 | static char ncache[16]; | ||
| 137 | static int icache; | ||
| 138 | struct idxmap *im; | ||
| 139 | int i; | ||
| 140 | |||
| 141 | if (name == NULL) | ||
| 142 | return 0; | ||
| 143 | if (icache && strcmp(name, ncache) == 0) | ||
| 144 | return icache; | ||
| 145 | for (i=0; i<16; i++) { | ||
| 146 | for (im = idxmap[i]; im; im = im->next) { | ||
| 147 | if (strcmp(im->name, name) == 0) { | ||
| 148 | icache = im->index; | ||
| 149 | strcpy(ncache, name); | ||
| 150 | return im->index; | ||
| 151 | } | ||
| 152 | } | ||
| 153 | } | ||
| 154 | return 0; | ||
| 155 | } | ||
| 156 | |||
| 157 | int ll_init_map(struct rtnl_handle *rth) | ||
| 158 | { | ||
| 159 | if (rtnl_wilddump_request(rth, AF_UNSPEC, RTM_GETLINK) < 0) { | ||
| 160 | perror("Cannot send dump request"); | ||
| 161 | exit(1); | ||
| 162 | } | ||
| 163 | |||
| 164 | if (rtnl_dump_filter(rth, ll_remember_index, &idxmap, NULL, NULL) < 0) { | ||
| 165 | fprintf(stderr, "Dump terminated\n"); | ||
| 166 | exit(1); | ||
| 167 | } | ||
| 168 | return 0; | ||
| 169 | } | ||
diff --git a/networking/libiproute/ll_map.h b/networking/libiproute/ll_map.h new file mode 100644 index 000000000..739f157e7 --- /dev/null +++ b/networking/libiproute/ll_map.h | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | #ifndef __LL_MAP_H__ | ||
| 2 | #define __LL_MAP_H__ 1 | ||
| 3 | |||
| 4 | extern int ll_remember_index(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); | ||
| 5 | extern int ll_init_map(struct rtnl_handle *rth); | ||
| 6 | extern int ll_name_to_index(char *name); | ||
| 7 | extern const char *ll_index_to_name(int idx); | ||
| 8 | extern const char *ll_idx_n2a(int idx, char *buf); | ||
| 9 | extern int ll_index_to_type(int idx); | ||
| 10 | extern unsigned ll_index_to_flags(int idx); | ||
| 11 | |||
| 12 | #endif /* __LL_MAP_H__ */ | ||
diff --git a/networking/libiproute/ll_proto.c b/networking/libiproute/ll_proto.c new file mode 100644 index 000000000..394338aea --- /dev/null +++ b/networking/libiproute/ll_proto.c | |||
| @@ -0,0 +1,118 @@ | |||
| 1 | /* | ||
| 2 | * ll_proto.c | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version | ||
| 7 | * 2 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <stdio.h> | ||
| 13 | #include <stdlib.h> | ||
| 14 | #include <unistd.h> | ||
| 15 | #include <syslog.h> | ||
| 16 | #include <fcntl.h> | ||
| 17 | #include <sys/ioctl.h> | ||
| 18 | #include <sys/socket.h> | ||
| 19 | #include <sys/ioctl.h> | ||
| 20 | #include <netinet/in.h> | ||
| 21 | #include <arpa/inet.h> | ||
| 22 | #include <string.h> | ||
| 23 | |||
| 24 | #include <linux/netdevice.h> | ||
| 25 | #include <linux/if_arp.h> | ||
| 26 | #include <linux/sockios.h> | ||
| 27 | |||
| 28 | #include "utils.h" | ||
| 29 | |||
| 30 | |||
| 31 | #define __PF(f,n) { ETH_P_##f, #n }, | ||
| 32 | static struct { | ||
| 33 | int id; | ||
| 34 | char *name; | ||
| 35 | } llproto_names[] = { | ||
| 36 | __PF(LOOP,loop) | ||
| 37 | __PF(PUP,pup) | ||
| 38 | #ifdef ETH_P_PUPAT | ||
| 39 | __PF(PUPAT,pupat) | ||
| 40 | #endif | ||
| 41 | __PF(IP,ip) | ||
| 42 | __PF(X25,x25) | ||
| 43 | __PF(ARP,arp) | ||
| 44 | __PF(BPQ,bpq) | ||
| 45 | #ifdef ETH_P_IEEEPUP | ||
| 46 | __PF(IEEEPUP,ieeepup) | ||
| 47 | #endif | ||
| 48 | #ifdef ETH_P_IEEEPUPAT | ||
| 49 | __PF(IEEEPUPAT,ieeepupat) | ||
| 50 | #endif | ||
| 51 | __PF(DEC,dec) | ||
| 52 | __PF(DNA_DL,dna_dl) | ||
| 53 | __PF(DNA_RC,dna_rc) | ||
| 54 | __PF(DNA_RT,dna_rt) | ||
| 55 | __PF(LAT,lat) | ||
| 56 | __PF(DIAG,diag) | ||
| 57 | __PF(CUST,cust) | ||
| 58 | __PF(SCA,sca) | ||
| 59 | __PF(RARP,rarp) | ||
| 60 | __PF(ATALK,atalk) | ||
| 61 | __PF(AARP,aarp) | ||
| 62 | __PF(IPX,ipx) | ||
| 63 | __PF(IPV6,ipv6) | ||
| 64 | __PF(PPP_DISC,ppp_disc) | ||
| 65 | __PF(PPP_SES,ppp_ses) | ||
| 66 | __PF(ATMMPOA,atmmpoa) | ||
| 67 | __PF(ATMFATE,atmfate) | ||
| 68 | |||
| 69 | __PF(802_3,802_3) | ||
| 70 | __PF(AX25,ax25) | ||
| 71 | __PF(ALL,all) | ||
| 72 | __PF(802_2,802_2) | ||
| 73 | __PF(SNAP,snap) | ||
| 74 | __PF(DDCMP,ddcmp) | ||
| 75 | __PF(WAN_PPP,wan_ppp) | ||
| 76 | __PF(PPP_MP,ppp_mp) | ||
| 77 | __PF(LOCALTALK,localtalk) | ||
| 78 | __PF(PPPTALK,ppptalk) | ||
| 79 | __PF(TR_802_2,tr_802_2) | ||
| 80 | __PF(MOBITEX,mobitex) | ||
| 81 | __PF(CONTROL,control) | ||
| 82 | __PF(IRDA,irda) | ||
| 83 | __PF(ECONET,econet) | ||
| 84 | |||
| 85 | { 0x8100, "802.1Q" }, | ||
| 86 | { ETH_P_IP, "ipv4" }, | ||
| 87 | }; | ||
| 88 | #undef __PF | ||
| 89 | |||
| 90 | |||
| 91 | char * ll_proto_n2a(unsigned short id, char *buf, int len) | ||
| 92 | { | ||
| 93 | int i; | ||
| 94 | |||
| 95 | id = ntohs(id); | ||
| 96 | |||
| 97 | for (i=0; i<sizeof(llproto_names)/sizeof(llproto_names[0]); i++) { | ||
| 98 | if (llproto_names[i].id == id) | ||
| 99 | return llproto_names[i].name; | ||
| 100 | } | ||
| 101 | snprintf(buf, len, "[%d]", id); | ||
| 102 | return buf; | ||
| 103 | } | ||
| 104 | |||
| 105 | int ll_proto_a2n(unsigned short *id, char *buf) | ||
| 106 | { | ||
| 107 | int i; | ||
| 108 | for (i=0; i<sizeof(llproto_names)/sizeof(llproto_names[0]); i++) { | ||
| 109 | if (strcasecmp(llproto_names[i].name, buf) == 0) { | ||
| 110 | *id = htons(llproto_names[i].id); | ||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | } | ||
| 114 | if (get_u16(id, buf, 0)) | ||
| 115 | return -1; | ||
| 116 | *id = htons(*id); | ||
| 117 | return 0; | ||
| 118 | } | ||
diff --git a/networking/libiproute/ll_types.c b/networking/libiproute/ll_types.c new file mode 100644 index 000000000..f14583634 --- /dev/null +++ b/networking/libiproute/ll_types.c | |||
| @@ -0,0 +1,121 @@ | |||
| 1 | /* | ||
| 2 | * ll_types.c | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version | ||
| 7 | * 2 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <stdio.h> | ||
| 13 | #include <stdlib.h> | ||
| 14 | #include <unistd.h> | ||
| 15 | #include <syslog.h> | ||
| 16 | #include <fcntl.h> | ||
| 17 | #include <sys/ioctl.h> | ||
| 18 | #include <sys/socket.h> | ||
| 19 | #include <sys/ioctl.h> | ||
| 20 | #include <netinet/in.h> | ||
| 21 | #include <arpa/inet.h> | ||
| 22 | #include <string.h> | ||
| 23 | |||
| 24 | #include <linux/netdevice.h> | ||
| 25 | #include <linux/if_arp.h> | ||
| 26 | #include <linux/sockios.h> | ||
| 27 | |||
| 28 | char * ll_type_n2a(int type, char *buf, int len) | ||
| 29 | { | ||
| 30 | #define __PF(f,n) { ARPHRD_##f, #n }, | ||
| 31 | static struct { | ||
| 32 | int type; | ||
| 33 | char *name; | ||
| 34 | } arphrd_names[] = { | ||
| 35 | { 0, "generic" }, | ||
| 36 | __PF(ETHER,ether) | ||
| 37 | __PF(EETHER,eether) | ||
| 38 | __PF(AX25,ax25) | ||
| 39 | __PF(PRONET,pronet) | ||
| 40 | __PF(CHAOS,chaos) | ||
| 41 | #ifdef ARPHRD_IEEE802_TR | ||
| 42 | __PF(IEEE802,ieee802) | ||
| 43 | #else | ||
| 44 | __PF(IEEE802,tr) | ||
| 45 | #endif | ||
| 46 | __PF(ARCNET,arcnet) | ||
| 47 | __PF(APPLETLK,atalk) | ||
| 48 | __PF(DLCI,dlci) | ||
| 49 | __PF(ATM,atm) | ||
| 50 | __PF(METRICOM,metricom) | ||
| 51 | #ifdef ARPHRD_IEEE1394 | ||
| 52 | __PF(IEEE1394,ieee1394) | ||
| 53 | #endif | ||
| 54 | |||
| 55 | __PF(SLIP,slip) | ||
| 56 | __PF(CSLIP,cslip) | ||
| 57 | __PF(SLIP6,slip6) | ||
| 58 | __PF(CSLIP6,cslip6) | ||
| 59 | __PF(RSRVD,rsrvd) | ||
| 60 | __PF(ADAPT,adapt) | ||
| 61 | __PF(ROSE,rose) | ||
| 62 | __PF(X25,x25) | ||
| 63 | __PF(HWX25,hwx25) | ||
| 64 | __PF(PPP,ppp) | ||
| 65 | __PF(HDLC,hdlc) | ||
| 66 | __PF(LAPB,lapb) | ||
| 67 | __PF(DDCMP,ddcmp) | ||
| 68 | __PF(RAWHDLC,rawhdlc) | ||
| 69 | |||
| 70 | __PF(TUNNEL,ipip) | ||
| 71 | __PF(TUNNEL6,tunnel6) | ||
| 72 | __PF(FRAD,frad) | ||
| 73 | __PF(SKIP,skip) | ||
| 74 | __PF(LOOPBACK,loopback) | ||
| 75 | __PF(LOCALTLK,ltalk) | ||
| 76 | __PF(FDDI,fddi) | ||
| 77 | __PF(BIF,bif) | ||
| 78 | __PF(SIT,sit) | ||
| 79 | __PF(IPDDP,ip/ddp) | ||
| 80 | __PF(IPGRE,gre) | ||
| 81 | __PF(PIMREG,pimreg) | ||
| 82 | __PF(HIPPI,hippi) | ||
| 83 | __PF(ASH,ash) | ||
| 84 | __PF(ECONET,econet) | ||
| 85 | __PF(IRDA,irda) | ||
| 86 | __PF(FCPP,fcpp) | ||
| 87 | __PF(FCAL,fcal) | ||
| 88 | __PF(FCPL,fcpl) | ||
| 89 | __PF(FCFABRIC,fcfb0) | ||
| 90 | __PF(FCFABRIC+1,fcfb1) | ||
| 91 | __PF(FCFABRIC+2,fcfb2) | ||
| 92 | __PF(FCFABRIC+3,fcfb3) | ||
| 93 | __PF(FCFABRIC+4,fcfb4) | ||
| 94 | __PF(FCFABRIC+5,fcfb5) | ||
| 95 | __PF(FCFABRIC+6,fcfb6) | ||
| 96 | __PF(FCFABRIC+7,fcfb7) | ||
| 97 | __PF(FCFABRIC+8,fcfb8) | ||
| 98 | __PF(FCFABRIC+9,fcfb9) | ||
| 99 | __PF(FCFABRIC+10,fcfb10) | ||
| 100 | __PF(FCFABRIC+11,fcfb11) | ||
| 101 | __PF(FCFABRIC+12,fcfb12) | ||
| 102 | #ifdef ARPHRD_IEEE802_TR | ||
| 103 | __PF(IEEE802_TR,tr) | ||
| 104 | #endif | ||
| 105 | #ifdef ARPHRD_IEEE80211 | ||
| 106 | __PF(IEEE80211,ieee802.11) | ||
| 107 | #endif | ||
| 108 | #ifdef ARPHRD_VOID | ||
| 109 | __PF(VOID,void) | ||
| 110 | #endif | ||
| 111 | }; | ||
| 112 | #undef __PF | ||
| 113 | |||
| 114 | int i; | ||
| 115 | for (i=0; i<sizeof(arphrd_names)/sizeof(arphrd_names[0]); i++) { | ||
| 116 | if (arphrd_names[i].type == type) | ||
| 117 | return arphrd_names[i].name; | ||
| 118 | } | ||
| 119 | snprintf(buf, len, "[%d]", type); | ||
| 120 | return buf; | ||
| 121 | } | ||
diff --git a/networking/libiproute/rt_names.c b/networking/libiproute/rt_names.c new file mode 100644 index 000000000..2a7d85cdb --- /dev/null +++ b/networking/libiproute/rt_names.c | |||
| @@ -0,0 +1,389 @@ | |||
| 1 | /* | ||
| 2 | * rt_names.c rtnetlink names DB. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version | ||
| 7 | * 2 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <stdio.h> | ||
| 13 | #include <stdlib.h> | ||
| 14 | #include <unistd.h> | ||
| 15 | #include <syslog.h> | ||
| 16 | #include <fcntl.h> | ||
| 17 | #include <string.h> | ||
| 18 | #include <sys/time.h> | ||
| 19 | #include <stdint.h> | ||
| 20 | |||
| 21 | static void rtnl_tab_initialize(char *file, char **tab, int size) | ||
| 22 | { | ||
| 23 | char buf[512]; | ||
| 24 | FILE *fp; | ||
| 25 | |||
| 26 | fp = fopen(file, "r"); | ||
| 27 | if (!fp) | ||
| 28 | return; | ||
| 29 | while (fgets(buf, sizeof(buf), fp)) { | ||
| 30 | char *p = buf; | ||
| 31 | int id; | ||
| 32 | char namebuf[512]; | ||
| 33 | |||
| 34 | while (*p == ' ' || *p == '\t') | ||
| 35 | p++; | ||
| 36 | if (*p == '#' || *p == '\n' || *p == 0) | ||
| 37 | continue; | ||
| 38 | if (sscanf(p, "0x%x %s\n", &id, namebuf) != 2 && | ||
| 39 | sscanf(p, "0x%x %s #", &id, namebuf) != 2 && | ||
| 40 | sscanf(p, "%d %s\n", &id, namebuf) != 2 && | ||
| 41 | sscanf(p, "%d %s #", &id, namebuf) != 2) { | ||
| 42 | fprintf(stderr, "Database %s is corrupted at %s\n", | ||
| 43 | file, p); | ||
| 44 | return; | ||
| 45 | } | ||
| 46 | |||
| 47 | if (id<0 || id>size) | ||
| 48 | continue; | ||
| 49 | |||
| 50 | tab[id] = strdup(namebuf); | ||
| 51 | } | ||
| 52 | fclose(fp); | ||
| 53 | } | ||
| 54 | |||
| 55 | |||
| 56 | static char * rtnl_rtprot_tab[256] = { | ||
| 57 | "none", | ||
| 58 | "redirect", | ||
| 59 | "kernel", | ||
| 60 | "boot", | ||
| 61 | "static", | ||
| 62 | NULL, | ||
| 63 | NULL, | ||
| 64 | NULL, | ||
| 65 | "gated", | ||
| 66 | "ra", | ||
| 67 | "mrt", | ||
| 68 | "zebra", | ||
| 69 | "bird", | ||
| 70 | }; | ||
| 71 | |||
| 72 | |||
| 73 | |||
| 74 | static int rtnl_rtprot_init; | ||
| 75 | |||
| 76 | static void rtnl_rtprot_initialize(void) | ||
| 77 | { | ||
| 78 | rtnl_rtprot_init = 1; | ||
| 79 | rtnl_tab_initialize("/etc/iproute2/rt_protos", | ||
| 80 | rtnl_rtprot_tab, 256); | ||
| 81 | } | ||
| 82 | |||
| 83 | char * rtnl_rtprot_n2a(int id, char *buf, int len) | ||
| 84 | { | ||
| 85 | if (id<0 || id>=256) { | ||
| 86 | snprintf(buf, len, "%d", id); | ||
| 87 | return buf; | ||
| 88 | } | ||
| 89 | if (!rtnl_rtprot_tab[id]) { | ||
| 90 | if (!rtnl_rtprot_init) | ||
| 91 | rtnl_rtprot_initialize(); | ||
| 92 | } | ||
| 93 | if (rtnl_rtprot_tab[id]) | ||
| 94 | return rtnl_rtprot_tab[id]; | ||
| 95 | snprintf(buf, len, "%d", id); | ||
| 96 | return buf; | ||
| 97 | } | ||
| 98 | |||
| 99 | int rtnl_rtprot_a2n(uint32_t *id, char *arg) | ||
| 100 | { | ||
| 101 | static char *cache = NULL; | ||
| 102 | static unsigned long res; | ||
| 103 | char *end; | ||
| 104 | int i; | ||
| 105 | |||
| 106 | if (cache && strcmp(cache, arg) == 0) { | ||
| 107 | *id = res; | ||
| 108 | return 0; | ||
| 109 | } | ||
| 110 | |||
| 111 | if (!rtnl_rtprot_init) | ||
| 112 | rtnl_rtprot_initialize(); | ||
| 113 | |||
| 114 | for (i=0; i<256; i++) { | ||
| 115 | if (rtnl_rtprot_tab[i] && | ||
| 116 | strcmp(rtnl_rtprot_tab[i], arg) == 0) { | ||
| 117 | cache = rtnl_rtprot_tab[i]; | ||
| 118 | res = i; | ||
| 119 | *id = res; | ||
| 120 | return 0; | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | res = strtoul(arg, &end, 0); | ||
| 125 | if (!end || end == arg || *end || res > 255) | ||
| 126 | return -1; | ||
| 127 | *id = res; | ||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | |||
| 131 | |||
| 132 | |||
| 133 | static char * rtnl_rtscope_tab[256] = { | ||
| 134 | "global", | ||
| 135 | }; | ||
| 136 | |||
| 137 | static int rtnl_rtscope_init; | ||
| 138 | |||
| 139 | static void rtnl_rtscope_initialize(void) | ||
| 140 | { | ||
| 141 | rtnl_rtscope_init = 1; | ||
| 142 | rtnl_rtscope_tab[255] = "nowhere"; | ||
| 143 | rtnl_rtscope_tab[254] = "host"; | ||
| 144 | rtnl_rtscope_tab[253] = "link"; | ||
| 145 | rtnl_rtscope_tab[200] = "site"; | ||
| 146 | rtnl_tab_initialize("/etc/iproute2/rt_scopes", | ||
| 147 | rtnl_rtscope_tab, 256); | ||
| 148 | } | ||
| 149 | |||
| 150 | char * rtnl_rtscope_n2a(int id, char *buf, int len) | ||
| 151 | { | ||
| 152 | if (id<0 || id>=256) { | ||
| 153 | snprintf(buf, len, "%d", id); | ||
| 154 | return buf; | ||
| 155 | } | ||
| 156 | if (!rtnl_rtscope_tab[id]) { | ||
| 157 | if (!rtnl_rtscope_init) | ||
| 158 | rtnl_rtscope_initialize(); | ||
| 159 | } | ||
| 160 | if (rtnl_rtscope_tab[id]) | ||
| 161 | return rtnl_rtscope_tab[id]; | ||
| 162 | snprintf(buf, len, "%d", id); | ||
| 163 | return buf; | ||
| 164 | } | ||
| 165 | |||
| 166 | int rtnl_rtscope_a2n(uint32_t *id, char *arg) | ||
| 167 | { | ||
| 168 | static char *cache = NULL; | ||
| 169 | static unsigned long res; | ||
| 170 | char *end; | ||
| 171 | int i; | ||
| 172 | |||
| 173 | if (cache && strcmp(cache, arg) == 0) { | ||
| 174 | *id = res; | ||
| 175 | return 0; | ||
| 176 | } | ||
| 177 | |||
| 178 | if (!rtnl_rtscope_init) | ||
| 179 | rtnl_rtscope_initialize(); | ||
| 180 | |||
| 181 | for (i=0; i<256; i++) { | ||
| 182 | if (rtnl_rtscope_tab[i] && | ||
| 183 | strcmp(rtnl_rtscope_tab[i], arg) == 0) { | ||
| 184 | cache = rtnl_rtscope_tab[i]; | ||
| 185 | res = i; | ||
| 186 | *id = res; | ||
| 187 | return 0; | ||
| 188 | } | ||
| 189 | } | ||
| 190 | |||
| 191 | res = strtoul(arg, &end, 0); | ||
| 192 | if (!end || end == arg || *end || res > 255) | ||
| 193 | return -1; | ||
| 194 | *id = res; | ||
| 195 | return 0; | ||
| 196 | } | ||
| 197 | |||
| 198 | |||
| 199 | |||
| 200 | static char * rtnl_rtrealm_tab[256] = { | ||
| 201 | "unknown", | ||
| 202 | }; | ||
| 203 | |||
| 204 | static int rtnl_rtrealm_init; | ||
| 205 | |||
| 206 | static void rtnl_rtrealm_initialize(void) | ||
| 207 | { | ||
| 208 | rtnl_rtrealm_init = 1; | ||
| 209 | rtnl_tab_initialize("/etc/iproute2/rt_realms", | ||
| 210 | rtnl_rtrealm_tab, 256); | ||
| 211 | } | ||
| 212 | |||
| 213 | char * rtnl_rtrealm_n2a(int id, char *buf, int len) | ||
| 214 | { | ||
| 215 | if (id<0 || id>=256) { | ||
| 216 | snprintf(buf, len, "%d", id); | ||
| 217 | return buf; | ||
| 218 | } | ||
| 219 | if (!rtnl_rtrealm_tab[id]) { | ||
| 220 | if (!rtnl_rtrealm_init) | ||
| 221 | rtnl_rtrealm_initialize(); | ||
| 222 | } | ||
| 223 | if (rtnl_rtrealm_tab[id]) | ||
| 224 | return rtnl_rtrealm_tab[id]; | ||
| 225 | snprintf(buf, len, "%d", id); | ||
| 226 | return buf; | ||
| 227 | } | ||
| 228 | |||
| 229 | |||
| 230 | int rtnl_rtrealm_a2n(uint32_t *id, char *arg) | ||
| 231 | { | ||
| 232 | static char *cache = NULL; | ||
| 233 | static unsigned long res; | ||
| 234 | char *end; | ||
| 235 | int i; | ||
| 236 | |||
| 237 | if (cache && strcmp(cache, arg) == 0) { | ||
| 238 | *id = res; | ||
| 239 | return 0; | ||
| 240 | } | ||
| 241 | |||
| 242 | if (!rtnl_rtrealm_init) | ||
| 243 | rtnl_rtrealm_initialize(); | ||
| 244 | |||
| 245 | for (i=0; i<256; i++) { | ||
| 246 | if (rtnl_rtrealm_tab[i] && | ||
| 247 | strcmp(rtnl_rtrealm_tab[i], arg) == 0) { | ||
| 248 | cache = rtnl_rtrealm_tab[i]; | ||
| 249 | res = i; | ||
| 250 | *id = res; | ||
| 251 | return 0; | ||
| 252 | } | ||
| 253 | } | ||
| 254 | |||
| 255 | res = strtoul(arg, &end, 0); | ||
| 256 | if (!end || end == arg || *end || res > 255) | ||
| 257 | return -1; | ||
| 258 | *id = res; | ||
| 259 | return 0; | ||
| 260 | } | ||
| 261 | |||
| 262 | |||
| 263 | |||
| 264 | static char * rtnl_rttable_tab[256] = { | ||
| 265 | "unspec", | ||
| 266 | }; | ||
| 267 | |||
| 268 | static int rtnl_rttable_init; | ||
| 269 | |||
| 270 | static void rtnl_rttable_initialize(void) | ||
| 271 | { | ||
| 272 | rtnl_rttable_init = 1; | ||
| 273 | rtnl_rttable_tab[255] = "local"; | ||
| 274 | rtnl_rttable_tab[254] = "main"; | ||
| 275 | rtnl_tab_initialize("/etc/iproute2/rt_tables", | ||
| 276 | rtnl_rttable_tab, 256); | ||
| 277 | } | ||
| 278 | |||
| 279 | char * rtnl_rttable_n2a(int id, char *buf, int len) | ||
| 280 | { | ||
| 281 | if (id<0 || id>=256) { | ||
| 282 | snprintf(buf, len, "%d", id); | ||
| 283 | return buf; | ||
| 284 | } | ||
| 285 | if (!rtnl_rttable_tab[id]) { | ||
| 286 | if (!rtnl_rttable_init) | ||
| 287 | rtnl_rttable_initialize(); | ||
| 288 | } | ||
| 289 | if (rtnl_rttable_tab[id]) | ||
| 290 | return rtnl_rttable_tab[id]; | ||
| 291 | snprintf(buf, len, "%d", id); | ||
| 292 | return buf; | ||
| 293 | } | ||
| 294 | |||
| 295 | int rtnl_rttable_a2n(uint32_t *id, char *arg) | ||
| 296 | { | ||
| 297 | static char *cache = NULL; | ||
| 298 | static unsigned long res; | ||
| 299 | char *end; | ||
| 300 | int i; | ||
| 301 | |||
| 302 | if (cache && strcmp(cache, arg) == 0) { | ||
| 303 | *id = res; | ||
| 304 | return 0; | ||
| 305 | } | ||
| 306 | |||
| 307 | if (!rtnl_rttable_init) | ||
| 308 | rtnl_rttable_initialize(); | ||
| 309 | |||
| 310 | for (i=0; i<256; i++) { | ||
| 311 | if (rtnl_rttable_tab[i] && | ||
| 312 | strcmp(rtnl_rttable_tab[i], arg) == 0) { | ||
| 313 | cache = rtnl_rttable_tab[i]; | ||
| 314 | res = i; | ||
| 315 | *id = res; | ||
| 316 | return 0; | ||
| 317 | } | ||
| 318 | } | ||
| 319 | |||
| 320 | i = strtoul(arg, &end, 0); | ||
| 321 | if (!end || end == arg || *end || i > 255) | ||
| 322 | return -1; | ||
| 323 | *id = i; | ||
| 324 | return 0; | ||
| 325 | } | ||
| 326 | |||
| 327 | |||
| 328 | static char * rtnl_rtdsfield_tab[256] = { | ||
| 329 | "0", | ||
| 330 | }; | ||
| 331 | |||
| 332 | static int rtnl_rtdsfield_init; | ||
| 333 | |||
| 334 | static void rtnl_rtdsfield_initialize(void) | ||
| 335 | { | ||
| 336 | rtnl_rtdsfield_init = 1; | ||
| 337 | rtnl_tab_initialize("/etc/iproute2/rt_dsfield", | ||
| 338 | rtnl_rtdsfield_tab, 256); | ||
| 339 | } | ||
| 340 | |||
| 341 | char * rtnl_dsfield_n2a(int id, char *buf, int len) | ||
| 342 | { | ||
| 343 | if (id<0 || id>=256) { | ||
| 344 | snprintf(buf, len, "%d", id); | ||
| 345 | return buf; | ||
| 346 | } | ||
| 347 | if (!rtnl_rtdsfield_tab[id]) { | ||
| 348 | if (!rtnl_rtdsfield_init) | ||
| 349 | rtnl_rtdsfield_initialize(); | ||
| 350 | } | ||
| 351 | if (rtnl_rtdsfield_tab[id]) | ||
| 352 | return rtnl_rtdsfield_tab[id]; | ||
| 353 | snprintf(buf, len, "0x%02x", id); | ||
| 354 | return buf; | ||
| 355 | } | ||
| 356 | |||
| 357 | |||
| 358 | int rtnl_dsfield_a2n(uint32_t *id, char *arg) | ||
| 359 | { | ||
| 360 | static char *cache = NULL; | ||
| 361 | static unsigned long res; | ||
| 362 | char *end; | ||
| 363 | int i; | ||
| 364 | |||
| 365 | if (cache && strcmp(cache, arg) == 0) { | ||
| 366 | *id = res; | ||
| 367 | return 0; | ||
| 368 | } | ||
| 369 | |||
| 370 | if (!rtnl_rtdsfield_init) | ||
| 371 | rtnl_rtdsfield_initialize(); | ||
| 372 | |||
| 373 | for (i=0; i<256; i++) { | ||
| 374 | if (rtnl_rtdsfield_tab[i] && | ||
| 375 | strcmp(rtnl_rtdsfield_tab[i], arg) == 0) { | ||
| 376 | cache = rtnl_rtdsfield_tab[i]; | ||
| 377 | res = i; | ||
| 378 | *id = res; | ||
| 379 | return 0; | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 383 | res = strtoul(arg, &end, 16); | ||
| 384 | if (!end || end == arg || *end || res > 255) | ||
| 385 | return -1; | ||
| 386 | *id = res; | ||
| 387 | return 0; | ||
| 388 | } | ||
| 389 | |||
diff --git a/networking/libiproute/rt_names.h b/networking/libiproute/rt_names.h new file mode 100644 index 000000000..97bc6169f --- /dev/null +++ b/networking/libiproute/rt_names.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | #ifndef RT_NAMES_H_ | ||
| 2 | #define RT_NAMES_H_ 1 | ||
| 3 | |||
| 4 | #include <stdint.h> | ||
| 5 | |||
| 6 | const char* rtnl_rtprot_n2a(int id, char *buf, int len); | ||
| 7 | const char* rtnl_rtscope_n2a(int id, char *buf, int len); | ||
| 8 | const char* rtnl_rttable_n2a(int id, char *buf, int len); | ||
| 9 | const char* rtnl_rtrealm_n2a(int id, char *buf, int len); | ||
| 10 | const char* rtnl_dsfield_n2a(int id, char *buf, int len); | ||
| 11 | int rtnl_rtprot_a2n(int *id, char *arg); | ||
| 12 | int rtnl_rtscope_a2n(int *id, char *arg); | ||
| 13 | int rtnl_rttable_a2n(int *id, char *arg); | ||
| 14 | int rtnl_rtrealm_a2n(uint32_t *id, char *arg); | ||
| 15 | int rtnl_dsfield_a2n(uint32_t *id, char *arg); | ||
| 16 | |||
| 17 | const char *inet_proto_n2a(int proto, char *buf, int len); | ||
| 18 | int inet_proto_a2n(char *buf); | ||
| 19 | |||
| 20 | |||
| 21 | const char * ll_type_n2a(int type, char *buf, int len); | ||
| 22 | |||
| 23 | const char *ll_addr_n2a(unsigned char *addr, int alen, int type, char *buf, int blen); | ||
| 24 | int ll_addr_a2n(unsigned char *lladdr, int len, char *arg); | ||
| 25 | |||
| 26 | const char * ll_proto_n2a(unsigned short id, char *buf, int len); | ||
| 27 | int ll_proto_a2n(unsigned short *id, char *buf); | ||
| 28 | |||
| 29 | |||
| 30 | #endif | ||
diff --git a/networking/libiproute/rtm_map.c b/networking/libiproute/rtm_map.c new file mode 100644 index 000000000..21e818b4a --- /dev/null +++ b/networking/libiproute/rtm_map.c | |||
| @@ -0,0 +1,116 @@ | |||
| 1 | /* | ||
| 2 | * rtm_map.c | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version | ||
| 7 | * 2 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> | ||
| 10 | * | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <stdio.h> | ||
| 14 | #include <stdlib.h> | ||
| 15 | #include <unistd.h> | ||
| 16 | #include <syslog.h> | ||
| 17 | #include <fcntl.h> | ||
| 18 | #include <string.h> | ||
| 19 | #include <sys/socket.h> | ||
| 20 | #include <netinet/in.h> | ||
| 21 | |||
| 22 | #include "rt_names.h" | ||
| 23 | #include "utils.h" | ||
| 24 | |||
| 25 | char *rtnl_rtntype_n2a(int id, char *buf, int len) | ||
| 26 | { | ||
| 27 | switch (id) { | ||
| 28 | case RTN_UNSPEC: | ||
| 29 | return "none"; | ||
| 30 | case RTN_UNICAST: | ||
| 31 | return "unicast"; | ||
| 32 | case RTN_LOCAL: | ||
| 33 | return "local"; | ||
| 34 | case RTN_BROADCAST: | ||
| 35 | return "broadcast"; | ||
| 36 | case RTN_ANYCAST: | ||
| 37 | return "anycast"; | ||
| 38 | case RTN_MULTICAST: | ||
| 39 | return "multicast"; | ||
| 40 | case RTN_BLACKHOLE: | ||
| 41 | return "blackhole"; | ||
| 42 | case RTN_UNREACHABLE: | ||
| 43 | return "unreachable"; | ||
| 44 | case RTN_PROHIBIT: | ||
| 45 | return "prohibit"; | ||
| 46 | case RTN_THROW: | ||
| 47 | return "throw"; | ||
| 48 | case RTN_NAT: | ||
| 49 | return "nat"; | ||
| 50 | case RTN_XRESOLVE: | ||
| 51 | return "xresolve"; | ||
| 52 | default: | ||
| 53 | snprintf(buf, len, "%d", id); | ||
| 54 | return buf; | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | |||
| 59 | int rtnl_rtntype_a2n(int *id, char *arg) | ||
| 60 | { | ||
| 61 | char *end; | ||
| 62 | unsigned long res; | ||
| 63 | |||
| 64 | if (strcmp(arg, "local") == 0) | ||
| 65 | res = RTN_LOCAL; | ||
| 66 | else if (strcmp(arg, "nat") == 0) | ||
| 67 | res = RTN_NAT; | ||
| 68 | else if (matches(arg, "broadcast") == 0 || | ||
| 69 | strcmp(arg, "brd") == 0) | ||
| 70 | res = RTN_BROADCAST; | ||
| 71 | else if (matches(arg, "anycast") == 0) | ||
| 72 | res = RTN_ANYCAST; | ||
| 73 | else if (matches(arg, "multicast") == 0) | ||
| 74 | res = RTN_MULTICAST; | ||
| 75 | else if (matches(arg, "prohibit") == 0) | ||
| 76 | res = RTN_PROHIBIT; | ||
| 77 | else if (matches(arg, "unreachable") == 0) | ||
| 78 | res = RTN_UNREACHABLE; | ||
| 79 | else if (matches(arg, "blackhole") == 0) | ||
| 80 | res = RTN_BLACKHOLE; | ||
| 81 | else if (matches(arg, "xresolve") == 0) | ||
| 82 | res = RTN_XRESOLVE; | ||
| 83 | else if (matches(arg, "unicast") == 0) | ||
| 84 | res = RTN_UNICAST; | ||
| 85 | else if (strcmp(arg, "throw") == 0) | ||
| 86 | res = RTN_THROW; | ||
| 87 | else { | ||
| 88 | res = strtoul(arg, &end, 0); | ||
| 89 | if (!end || end == arg || *end || res > 255) | ||
| 90 | return -1; | ||
| 91 | } | ||
| 92 | *id = res; | ||
| 93 | return 0; | ||
| 94 | } | ||
| 95 | |||
| 96 | int get_rt_realms(__u32 *realms, char *arg) | ||
| 97 | { | ||
| 98 | __u32 realm = 0; | ||
| 99 | char *p = strchr(arg, '/'); | ||
| 100 | |||
| 101 | *realms = 0; | ||
| 102 | if (p) { | ||
| 103 | *p = 0; | ||
| 104 | if (rtnl_rtrealm_a2n(realms, arg)) { | ||
| 105 | *p = '/'; | ||
| 106 | return -1; | ||
| 107 | } | ||
| 108 | *realms <<= 16; | ||
| 109 | *p = '/'; | ||
| 110 | arg = p+1; | ||
| 111 | } | ||
| 112 | if (*arg && rtnl_rtrealm_a2n(&realm, arg)) | ||
| 113 | return -1; | ||
| 114 | *realms |= realm; | ||
| 115 | return 0; | ||
| 116 | } | ||
diff --git a/networking/libiproute/rtm_map.h b/networking/libiproute/rtm_map.h new file mode 100644 index 000000000..70bda7d05 --- /dev/null +++ b/networking/libiproute/rtm_map.h | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | #ifndef __RTM_MAP_H__ | ||
| 2 | #define __RTM_MAP_H__ 1 | ||
| 3 | |||
| 4 | char *rtnl_rtntype_n2a(int id, char *buf, int len); | ||
| 5 | int rtnl_rtntype_a2n(int *id, char *arg); | ||
| 6 | |||
| 7 | int get_rt_realms(__u32 *realms, char *arg); | ||
| 8 | |||
| 9 | |||
| 10 | #endif /* __RTM_MAP_H__ */ | ||
diff --git a/networking/libiproute/utils.c b/networking/libiproute/utils.c new file mode 100644 index 000000000..afc02d9d9 --- /dev/null +++ b/networking/libiproute/utils.c | |||
| @@ -0,0 +1,368 @@ | |||
| 1 | /* | ||
| 2 | * utils.c | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version | ||
| 7 | * 2 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> | ||
| 10 | * | ||
| 11 | * | ||
| 12 | * Changes: | ||
| 13 | * | ||
| 14 | * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <stdio.h> | ||
| 18 | #include <stdlib.h> | ||
| 19 | #include <unistd.h> | ||
| 20 | #include <syslog.h> | ||
| 21 | #include <fcntl.h> | ||
| 22 | #include <sys/socket.h> | ||
| 23 | #include <netinet/in.h> | ||
| 24 | #include <string.h> | ||
| 25 | #include <netdb.h> | ||
| 26 | #include <arpa/inet.h> | ||
| 27 | #include <resolv.h> | ||
| 28 | #include "./linux/pkt_sched.h" | ||
| 29 | |||
| 30 | #include "utils.h" | ||
| 31 | |||
| 32 | int get_integer(int *val, char *arg, int base) | ||
| 33 | { | ||
| 34 | long res; | ||
| 35 | char *ptr; | ||
| 36 | |||
| 37 | if (!arg || !*arg) | ||
| 38 | return -1; | ||
| 39 | res = strtol(arg, &ptr, base); | ||
| 40 | if (!ptr || ptr == arg || *ptr || res > INT_MAX || res < INT_MIN) | ||
| 41 | return -1; | ||
| 42 | *val = res; | ||
| 43 | return 0; | ||
| 44 | } | ||
| 45 | |||
| 46 | int get_unsigned(unsigned *val, char *arg, int base) | ||
| 47 | { | ||
| 48 | unsigned long res; | ||
| 49 | char *ptr; | ||
| 50 | |||
| 51 | if (!arg || !*arg) | ||
| 52 | return -1; | ||
| 53 | res = strtoul(arg, &ptr, base); | ||
| 54 | if (!ptr || ptr == arg || *ptr || res > UINT_MAX) | ||
| 55 | return -1; | ||
| 56 | *val = res; | ||
| 57 | return 0; | ||
| 58 | } | ||
| 59 | |||
| 60 | int get_u32(__u32 *val, char *arg, int base) | ||
| 61 | { | ||
| 62 | unsigned long res; | ||
| 63 | char *ptr; | ||
| 64 | |||
| 65 | if (!arg || !*arg) | ||
| 66 | return -1; | ||
| 67 | res = strtoul(arg, &ptr, base); | ||
| 68 | if (!ptr || ptr == arg || *ptr || res > 0xFFFFFFFFUL) | ||
| 69 | return -1; | ||
| 70 | *val = res; | ||
| 71 | return 0; | ||
| 72 | } | ||
| 73 | |||
| 74 | int get_u16(__u16 *val, char *arg, int base) | ||
| 75 | { | ||
| 76 | unsigned long res; | ||
| 77 | char *ptr; | ||
| 78 | |||
| 79 | if (!arg || !*arg) | ||
| 80 | return -1; | ||
| 81 | res = strtoul(arg, &ptr, base); | ||
| 82 | if (!ptr || ptr == arg || *ptr || res > 0xFFFF) | ||
| 83 | return -1; | ||
| 84 | *val = res; | ||
| 85 | return 0; | ||
| 86 | } | ||
| 87 | |||
| 88 | int get_u8(__u8 *val, char *arg, int base) | ||
| 89 | { | ||
| 90 | unsigned long res; | ||
| 91 | char *ptr; | ||
| 92 | |||
| 93 | if (!arg || !*arg) | ||
| 94 | return -1; | ||
| 95 | res = strtoul(arg, &ptr, base); | ||
| 96 | if (!ptr || ptr == arg || *ptr || res > 0xFF) | ||
| 97 | return -1; | ||
| 98 | *val = res; | ||
| 99 | return 0; | ||
| 100 | } | ||
| 101 | |||
| 102 | int get_s16(__s16 *val, char *arg, int base) | ||
| 103 | { | ||
| 104 | long res; | ||
| 105 | char *ptr; | ||
| 106 | |||
| 107 | if (!arg || !*arg) | ||
| 108 | return -1; | ||
| 109 | res = strtol(arg, &ptr, base); | ||
| 110 | if (!ptr || ptr == arg || *ptr || res > 0x7FFF || res < -0x8000) | ||
| 111 | return -1; | ||
| 112 | *val = res; | ||
| 113 | return 0; | ||
| 114 | } | ||
| 115 | |||
| 116 | int get_s8(__s8 *val, char *arg, int base) | ||
| 117 | { | ||
| 118 | long res; | ||
| 119 | char *ptr; | ||
| 120 | |||
| 121 | if (!arg || !*arg) | ||
| 122 | return -1; | ||
| 123 | res = strtol(arg, &ptr, base); | ||
| 124 | if (!ptr || ptr == arg || *ptr || res > 0x7F || res < -0x80) | ||
| 125 | return -1; | ||
| 126 | *val = res; | ||
| 127 | return 0; | ||
| 128 | } | ||
| 129 | |||
| 130 | int get_addr_1(inet_prefix *addr, char *name, int family) | ||
| 131 | { | ||
| 132 | char *cp; | ||
| 133 | unsigned char *ap = (unsigned char*)addr->data; | ||
| 134 | int i; | ||
| 135 | |||
| 136 | memset(addr, 0, sizeof(*addr)); | ||
| 137 | |||
| 138 | if (strcmp(name, "default") == 0 || | ||
| 139 | strcmp(name, "all") == 0 || | ||
| 140 | strcmp(name, "any") == 0) { | ||
| 141 | addr->family = family; | ||
| 142 | addr->bytelen = (family == AF_INET6 ? 16 : 4); | ||
| 143 | addr->bitlen = -1; | ||
| 144 | return 0; | ||
| 145 | } | ||
| 146 | |||
| 147 | if (strchr(name, ':')) { | ||
| 148 | addr->family = AF_INET6; | ||
| 149 | if (family != AF_UNSPEC && family != AF_INET6) | ||
| 150 | return -1; | ||
| 151 | if (inet_pton(AF_INET6, name, addr->data) <= 0) | ||
| 152 | return -1; | ||
| 153 | addr->bytelen = 16; | ||
| 154 | addr->bitlen = -1; | ||
| 155 | return 0; | ||
| 156 | } | ||
| 157 | |||
| 158 | addr->family = AF_INET; | ||
| 159 | if (family != AF_UNSPEC && family != AF_INET) | ||
| 160 | return -1; | ||
| 161 | addr->bytelen = 4; | ||
| 162 | addr->bitlen = -1; | ||
| 163 | for (cp=name, i=0; *cp; cp++) { | ||
| 164 | if (*cp <= '9' && *cp >= '0') { | ||
| 165 | ap[i] = 10*ap[i] + (*cp-'0'); | ||
| 166 | continue; | ||
| 167 | } | ||
| 168 | if (*cp == '.' && ++i <= 3) | ||
| 169 | continue; | ||
| 170 | return -1; | ||
| 171 | } | ||
| 172 | return 0; | ||
| 173 | } | ||
| 174 | |||
| 175 | int get_prefix_1(inet_prefix *dst, char *arg, int family) | ||
| 176 | { | ||
| 177 | int err; | ||
| 178 | unsigned plen; | ||
| 179 | char *slash; | ||
| 180 | |||
| 181 | memset(dst, 0, sizeof(*dst)); | ||
| 182 | |||
| 183 | if (strcmp(arg, "default") == 0 || strcmp(arg, "any") == 0) { | ||
| 184 | dst->family = family; | ||
| 185 | dst->bytelen = 0; | ||
| 186 | dst->bitlen = 0; | ||
| 187 | return 0; | ||
| 188 | } | ||
| 189 | |||
| 190 | slash = strchr(arg, '/'); | ||
| 191 | if (slash) | ||
| 192 | *slash = 0; | ||
| 193 | err = get_addr_1(dst, arg, family); | ||
| 194 | if (err == 0) { | ||
| 195 | switch(dst->family) { | ||
| 196 | case AF_INET6: | ||
| 197 | dst->bitlen = 128; | ||
| 198 | break; | ||
| 199 | default: | ||
| 200 | case AF_INET: | ||
| 201 | dst->bitlen = 32; | ||
| 202 | } | ||
| 203 | if (slash) { | ||
| 204 | if (get_integer(&plen, slash+1, 0) || plen > dst->bitlen) { | ||
| 205 | err = -1; | ||
| 206 | goto done; | ||
| 207 | } | ||
| 208 | dst->bitlen = plen; | ||
| 209 | } | ||
| 210 | } | ||
| 211 | done: | ||
| 212 | if (slash) | ||
| 213 | *slash = '/'; | ||
| 214 | return err; | ||
| 215 | } | ||
| 216 | |||
| 217 | int get_addr(inet_prefix *dst, char *arg, int family) | ||
| 218 | { | ||
| 219 | if (family == AF_PACKET) { | ||
| 220 | fprintf(stderr, "Error: \"%s\" may be inet address, but it is not allowed in this context.\n", arg); | ||
| 221 | exit(1); | ||
| 222 | } | ||
| 223 | if (get_addr_1(dst, arg, family)) { | ||
| 224 | fprintf(stderr, "Error: an inet address is expected rather than \"%s\".\n", arg); | ||
| 225 | exit(1); | ||
| 226 | } | ||
| 227 | return 0; | ||
| 228 | } | ||
| 229 | |||
| 230 | int get_prefix(inet_prefix *dst, char *arg, int family) | ||
| 231 | { | ||
| 232 | if (family == AF_PACKET) { | ||
| 233 | fprintf(stderr, "Error: \"%s\" may be inet prefix, but it is not allowed in this context.\n", arg); | ||
| 234 | exit(1); | ||
| 235 | } | ||
| 236 | if (get_prefix_1(dst, arg, family)) { | ||
| 237 | fprintf(stderr, "Error: an inet prefix is expected rather than \"%s\".\n", arg); | ||
| 238 | exit(1); | ||
| 239 | } | ||
| 240 | return 0; | ||
| 241 | } | ||
| 242 | |||
| 243 | __u32 get_addr32(char *name) | ||
| 244 | { | ||
| 245 | inet_prefix addr; | ||
| 246 | if (get_addr_1(&addr, name, AF_INET)) { | ||
| 247 | fprintf(stderr, "Error: an IP address is expected rather than \"%s\"\n", name); | ||
| 248 | exit(1); | ||
| 249 | } | ||
| 250 | return addr.data[0]; | ||
| 251 | } | ||
| 252 | |||
| 253 | void incomplete_command() | ||
| 254 | { | ||
| 255 | fprintf(stderr, "Command line is not complete. Try option \"help\"\n"); | ||
| 256 | exit(-1); | ||
| 257 | } | ||
| 258 | |||
| 259 | void invarg(char *msg, char *arg) | ||
| 260 | { | ||
| 261 | fprintf(stderr, "Error: argument \"%s\" is wrong: %s\n", arg, msg); | ||
| 262 | exit(-1); | ||
| 263 | } | ||
| 264 | |||
| 265 | void duparg(char *key, char *arg) | ||
| 266 | { | ||
| 267 | fprintf(stderr, "Error: duplicate \"%s\": \"%s\" is the second value.\n", key, arg); | ||
| 268 | exit(-1); | ||
| 269 | } | ||
| 270 | |||
| 271 | void duparg2(char *key, char *arg) | ||
| 272 | { | ||
| 273 | fprintf(stderr, "Error: either \"%s\" is duplicate, or \"%s\" is a garbage.\n", key, arg); | ||
| 274 | exit(-1); | ||
| 275 | } | ||
| 276 | |||
| 277 | int matches(char *cmd, char *pattern) | ||
| 278 | { | ||
| 279 | int len = strlen(cmd); | ||
| 280 | if (len > strlen(pattern)) | ||
| 281 | return -1; | ||
| 282 | return memcmp(pattern, cmd, len); | ||
| 283 | } | ||
| 284 | |||
| 285 | int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits) | ||
| 286 | { | ||
| 287 | __u32 *a1 = a->data; | ||
| 288 | __u32 *a2 = b->data; | ||
| 289 | int words = bits >> 0x05; | ||
| 290 | |||
| 291 | bits &= 0x1f; | ||
| 292 | |||
| 293 | if (words) | ||
| 294 | if (memcmp(a1, a2, words << 2)) | ||
| 295 | return -1; | ||
| 296 | |||
| 297 | if (bits) { | ||
| 298 | __u32 w1, w2; | ||
| 299 | __u32 mask; | ||
| 300 | |||
| 301 | w1 = a1[words]; | ||
| 302 | w2 = a2[words]; | ||
| 303 | |||
| 304 | mask = htonl((0xffffffff) << (0x20 - bits)); | ||
| 305 | |||
| 306 | if ((w1 ^ w2) & mask) | ||
| 307 | return 1; | ||
| 308 | } | ||
| 309 | |||
| 310 | return 0; | ||
| 311 | } | ||
| 312 | |||
| 313 | int __iproute2_hz_internal; | ||
| 314 | |||
| 315 | int __get_hz(void) | ||
| 316 | { | ||
| 317 | int hz = 0; | ||
| 318 | FILE *fp = fopen("/proc/net/psched", "r"); | ||
| 319 | |||
| 320 | if (fp) { | ||
| 321 | unsigned nom, denom; | ||
| 322 | if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2) | ||
| 323 | if (nom == 1000000) | ||
| 324 | hz = denom; | ||
| 325 | fclose(fp); | ||
| 326 | } | ||
| 327 | if (hz) | ||
| 328 | return hz; | ||
| 329 | return HZ; | ||
| 330 | } | ||
| 331 | |||
| 332 | const char *rt_addr_n2a(int af, int len, void *addr, char *buf, int buflen) | ||
| 333 | { | ||
| 334 | switch (af) { | ||
| 335 | case AF_INET: | ||
| 336 | case AF_INET6: | ||
| 337 | return inet_ntop(af, addr, buf, buflen); | ||
| 338 | default: | ||
| 339 | return "???"; | ||
| 340 | } | ||
| 341 | } | ||
| 342 | |||
| 343 | |||
| 344 | const char *format_host(int af, int len, void *addr, char *buf, int buflen) | ||
| 345 | { | ||
| 346 | #ifdef RESOLVE_HOSTNAMES | ||
| 347 | if (resolve_hosts) { | ||
| 348 | struct hostent *h_ent; | ||
| 349 | if (len <= 0) { | ||
| 350 | switch (af) { | ||
| 351 | case AF_INET: | ||
| 352 | len = 4; | ||
| 353 | break; | ||
| 354 | case AF_INET6: | ||
| 355 | len = 16; | ||
| 356 | break; | ||
| 357 | default: ; | ||
| 358 | } | ||
| 359 | } | ||
| 360 | if (len > 0 && | ||
| 361 | (h_ent = gethostbyaddr(addr, len, af)) != NULL) { | ||
| 362 | snprintf(buf, buflen-1, "%s", h_ent->h_name); | ||
| 363 | return buf; | ||
| 364 | } | ||
| 365 | } | ||
| 366 | #endif | ||
| 367 | return rt_addr_n2a(af, len, addr, buf, buflen); | ||
| 368 | } | ||
diff --git a/networking/libiproute/utils.h b/networking/libiproute/utils.h new file mode 100644 index 000000000..dc28c1b6a --- /dev/null +++ b/networking/libiproute/utils.h | |||
| @@ -0,0 +1,101 @@ | |||
| 1 | #ifndef __UTILS_H__ | ||
| 2 | #define __UTILS_H__ 1 | ||
| 3 | |||
| 4 | #include <asm/types.h> | ||
| 5 | #include <resolv.h> | ||
| 6 | |||
| 7 | #include "libnetlink.h" | ||
| 8 | #include "ll_map.h" | ||
| 9 | #include "rtm_map.h" | ||
| 10 | |||
| 11 | extern int preferred_family; | ||
| 12 | extern int show_stats; | ||
| 13 | extern int show_details; | ||
| 14 | extern int show_raw; | ||
| 15 | extern int resolve_hosts; | ||
| 16 | extern int oneline; | ||
| 17 | extern char * _SL_; | ||
| 18 | |||
| 19 | #ifndef IPPROTO_ESP | ||
| 20 | #define IPPROTO_ESP 50 | ||
| 21 | #endif | ||
| 22 | #ifndef IPPROTO_AH | ||
| 23 | #define IPPROTO_AH 51 | ||
| 24 | #endif | ||
| 25 | |||
| 26 | #define SPRINT_BSIZE 64 | ||
| 27 | #define SPRINT_BUF(x) char x[SPRINT_BSIZE] | ||
| 28 | |||
| 29 | extern void incomplete_command(void) __attribute__((noreturn)); | ||
| 30 | |||
| 31 | #define NEXT_ARG() do { argv++; if (--argc <= 0) incomplete_command(); } while(0) | ||
| 32 | |||
| 33 | typedef struct | ||
| 34 | { | ||
| 35 | __u8 family; | ||
| 36 | __u8 bytelen; | ||
| 37 | __s16 bitlen; | ||
| 38 | __u32 data[4]; | ||
| 39 | } inet_prefix; | ||
| 40 | |||
| 41 | #define DN_MAXADDL 20 | ||
| 42 | #ifndef AF_DECnet | ||
| 43 | #define AF_DECnet 12 | ||
| 44 | #endif | ||
| 45 | |||
| 46 | struct dn_naddr | ||
| 47 | { | ||
| 48 | unsigned short a_len; | ||
| 49 | unsigned char a_addr[DN_MAXADDL]; | ||
| 50 | }; | ||
| 51 | |||
| 52 | #define IPX_NODE_LEN 6 | ||
| 53 | |||
| 54 | struct ipx_addr { | ||
| 55 | u_int32_t ipx_net; | ||
| 56 | u_int8_t ipx_node[IPX_NODE_LEN]; | ||
| 57 | }; | ||
| 58 | |||
| 59 | extern __u32 get_addr32(char *name); | ||
| 60 | extern int get_addr_1(inet_prefix *dst, char *arg, int family); | ||
| 61 | extern int get_prefix_1(inet_prefix *dst, char *arg, int family); | ||
| 62 | extern int get_addr(inet_prefix *dst, char *arg, int family); | ||
| 63 | extern int get_prefix(inet_prefix *dst, char *arg, int family); | ||
| 64 | |||
| 65 | extern int get_integer(int *val, char *arg, int base); | ||
| 66 | extern int get_unsigned(unsigned *val, char *arg, int base); | ||
| 67 | #define get_byte get_u8 | ||
| 68 | #define get_ushort get_u16 | ||
| 69 | #define get_short get_s16 | ||
| 70 | extern int get_u32(__u32 *val, char *arg, int base); | ||
| 71 | extern int get_u16(__u16 *val, char *arg, int base); | ||
| 72 | extern int get_s16(__s16 *val, char *arg, int base); | ||
| 73 | extern int get_u8(__u8 *val, char *arg, int base); | ||
| 74 | extern int get_s8(__s8 *val, char *arg, int base); | ||
| 75 | |||
| 76 | extern const char *format_host(int af, int len, void *addr, char *buf, int buflen); | ||
| 77 | extern const char *rt_addr_n2a(int af, int len, void *addr, char *buf, int buflen); | ||
| 78 | |||
| 79 | void invarg(char *, char *) __attribute__((noreturn)); | ||
| 80 | void duparg(char *, char *) __attribute__((noreturn)); | ||
| 81 | void duparg2(char *, char *) __attribute__((noreturn)); | ||
| 82 | int matches(char *arg, char *pattern); | ||
| 83 | extern int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits); | ||
| 84 | |||
| 85 | const char *dnet_ntop(int af, const void *addr, char *str, size_t len); | ||
| 86 | int dnet_pton(int af, const char *src, void *addr); | ||
| 87 | |||
| 88 | const char *ipx_ntop(int af, const void *addr, char *str, size_t len); | ||
| 89 | int ipx_pton(int af, const char *src, void *addr); | ||
| 90 | |||
| 91 | extern int __iproute2_hz_internal; | ||
| 92 | extern int __get_hz(void); | ||
| 93 | |||
| 94 | static __inline__ int get_hz(void) | ||
| 95 | { | ||
| 96 | if (__iproute2_hz_internal == 0) | ||
| 97 | __iproute2_hz_internal = __get_hz(); | ||
| 98 | return __iproute2_hz_internal; | ||
| 99 | } | ||
| 100 | |||
| 101 | #endif /* __UTILS_H__ */ | ||
