diff options
author | Glenn L McGrath <bug1@ihug.co.nz> | 2002-11-10 01:33:55 +0000 |
---|---|---|
committer | Glenn L McGrath <bug1@ihug.co.nz> | 2002-11-10 01:33:55 +0000 |
commit | 9a2d27249cc2235f7e001a9ea8d4605406bc5f38 (patch) | |
tree | b7b2917c3cf46ac3fa25df5f9a27a9a9fbfb0398 /networking/libiproute | |
parent | 021fa7db9139bff3b4bf404dfd7d2b1541ed71f8 (diff) | |
download | busybox-w32-9a2d27249cc2235f7e001a9ea8d4605406bc5f38.tar.gz busybox-w32-9a2d27249cc2235f7e001a9ea8d4605406bc5f38.tar.bz2 busybox-w32-9a2d27249cc2235f7e001a9ea8d4605406bc5f38.zip |
IP applet by Bastian Blank <waldi@debian.org>
Diffstat (limited to 'networking/libiproute')
-rw-r--r-- | networking/libiproute/Makefile | 30 | ||||
-rw-r--r-- | networking/libiproute/Makefile.in | 43 | ||||
-rw-r--r-- | networking/libiproute/ip_common.h | 20 | ||||
-rw-r--r-- | networking/libiproute/ipaddress.c | 723 | ||||
-rw-r--r-- | networking/libiproute/iplink.c | 349 | ||||
-rw-r--r-- | networking/libiproute/iproute.c | 674 | ||||
-rw-r--r-- | networking/libiproute/iptunnel.c | 548 | ||||
-rw-r--r-- | networking/libiproute/libnetlink.c | 521 | ||||
-rw-r--r-- | networking/libiproute/libnetlink.h | 46 | ||||
-rw-r--r-- | networking/libiproute/linux/pkt_sched.h | 413 | ||||
-rw-r--r-- | networking/libiproute/ll_addr.c | 92 | ||||
-rw-r--r-- | networking/libiproute/ll_map.c | 169 | ||||
-rw-r--r-- | networking/libiproute/ll_map.h | 12 | ||||
-rw-r--r-- | networking/libiproute/ll_proto.c | 118 | ||||
-rw-r--r-- | networking/libiproute/ll_types.c | 121 | ||||
-rw-r--r-- | networking/libiproute/rt_names.c | 389 | ||||
-rw-r--r-- | networking/libiproute/rt_names.h | 30 | ||||
-rw-r--r-- | networking/libiproute/rtm_map.c | 116 | ||||
-rw-r--r-- | networking/libiproute/rtm_map.h | 10 | ||||
-rw-r--r-- | networking/libiproute/utils.c | 368 | ||||
-rw-r--r-- | networking/libiproute/utils.h | 101 |
21 files changed, 4893 insertions, 0 deletions
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__ */ | ||