[T106][ZXW-22]7520V3SCV2.01.01.02P42U09_VEC_V0.8_AP_VEC origin source commit
Change-Id: Ic6e05d89ecd62fc34f82b23dcf306c93764aec4b
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/Makefile b/ap/app/iproute2/iproute2-3.4.0/ip/Makefile
new file mode 100755
index 0000000..ed4b926
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/Makefile
@@ -0,0 +1,50 @@
+IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \
+ rtm_map.o iptunnel.o ip6tunnel.o tunnel.o ipneigh.o ipntable.o iplink.o \
+ ipmaddr.o ipmonitor.o ipmroute.o ipprefix.o iptuntap.o \
+ ipxfrm.o xfrm_state.o xfrm_policy.o xfrm_monitor.o \
+ iplink_vlan.o link_veth.o link_gre.o iplink_can.o \
+ iplink_macvlan.o iplink_macvtap.o ipl2tp.o
+
+RTMONOBJ=rtmon.o
+
+include ../Config
+
+ifeq ($(IP_CONFIG_SETNS),y)
+ CFLAGS += -DHAVE_SETNS
+endif
+
+ALLOBJ=$(IPOBJ) $(RTMONOBJ)
+SCRIPTS=ifcfg rtpr routel routef
+TARGETS=ip rtmon
+
+all: $(TARGETS) $(SCRIPTS)
+
+ip: $(IPOBJ) $(LIBNETLINK)
+
+
+rtmon: $(RTMONOBJ)
+
+install: all
+ install -m 0755 $(TARGETS) $(DESTDIR)$(SBINDIR)
+ install -m 0755 $(SCRIPTS) $(DESTDIR)$(SBINDIR)
+
+clean:
+ rm -f $(ALLOBJ) $(TARGETS) *.elf
+
+SHARED_LIBS ?= y
+ifeq ($(SHARED_LIBS),y)
+
+LDLIBS += -ldl
+LDFLAGS += -Wl,-export-dynamic
+
+else
+
+ip: static-syms.o
+static-syms.o: static-syms.h
+static-syms.h: $(wildcard *.c)
+ files="$^" ; \
+ for s in `grep -B 3 '\<dlsym' $$files | sed -n '/snprintf/{s:.*"\([^"]*\)".*:\1:;s:%s::;p}'` ; do \
+ sed -n '/'$$s'[^ ]* =/{s:.* \([^ ]*'$$s'[^ ]*\) .*:extern char \1[] __attribute__((weak)); if (!strcmp(sym, "\1")) return \1;:;p}' $$files ; \
+ done > $@
+
+endif
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/ifcfg b/ap/app/iproute2/iproute2-3.4.0/ip/ifcfg
new file mode 100755
index 0000000..083d9df
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/ifcfg
@@ -0,0 +1,149 @@
+#! /bin/bash
+
+CheckForwarding () {
+ local sbase fwd
+ sbase=/proc/sys/net/ipv4/conf
+ fwd=0
+ if [ -d $sbase ]; then
+ for dir in $sbase/*/forwarding; do
+ fwd=$[$fwd + `cat $dir`]
+ done
+ else
+ fwd=2
+ fi
+ return $fwd
+}
+
+RestartRDISC () {
+ killall -HUP rdisc || rdisc -fs
+}
+
+ABCMaskLen () {
+ local class;
+
+ class=${1%%.*}
+ if [ "$1" = "" -o $class -eq 0 -o $class -ge 224 ]; then return 0
+ elif [ $class -ge 224 ]; then return 0
+ elif [ $class -ge 192 ]; then return 24
+ elif [ $class -ge 128 ]; then return 16
+ else return 8; fi
+}
+
+label="label $1"
+ldev="$1"
+dev=${1%:*}
+if [ "$dev" = "" -o "$1" = "help" ]; then
+ echo "Usage: ifcfg DEV [[add|del [ADDR[/LEN]] [PEER] | stop]" 1>&2
+ echo " add - add new address" 1>&2
+ echo " del - delete address" 1>&2
+ echo " stop - completely disable IP" 1>&2
+ exit 1
+fi
+shift
+
+CheckForwarding
+fwd=$?
+if [ $fwd -ne 0 ]; then
+ echo "Forwarding is ON or its state is unknown ($fwd). OK, No RDISC." 1>&2
+fi
+
+
+deleting=0
+case "$1" in
+add) shift ;;
+stop)
+ if [ "$ldev" != "$dev" ]; then
+ echo "Cannot stop alias $ldev" 1>&2
+ exit 1;
+ fi
+ ip -4 addr flush dev $dev $label || exit 1
+ if [ $fwd -eq 0 ]; then RestartRDISC; fi
+ exit 0 ;;
+del*)
+ deleting=1; shift ;;
+*)
+esac
+
+ipaddr=
+pfxlen=
+if [ "$1" != "" ]; then
+ ipaddr=${1%/*}
+ if [ "$1" != "$ipaddr" ]; then
+ pfxlen=${1#*/}
+ fi
+ if [ "$ipaddr" = "" ]; then
+ echo "$1 is bad IP address." 1>&2
+ exit 1
+ fi
+fi
+shift
+
+peer=$1
+if [ "$peer" != "" ]; then
+ if [ "$pfxlen" != "" -a "$pfxlen" != "32" ]; then
+ echo "Peer address with non-trivial netmask." 1>&2
+ exit 1
+ fi
+ pfx="$ipaddr peer $peer"
+else
+ if [ "$ipaddr" = "" ]; then
+ echo "Missing IP address argument." 1>&2
+ exit 1
+ fi
+ if [ "$pfxlen" = "" ]; then
+ ABCMaskLen $ipaddr
+ pfxlen=$?
+ fi
+ pfx="$ipaddr/$pfxlen"
+fi
+
+if [ "$ldev" = "$dev" -a "$ipaddr" != "" ]; then
+ label=
+fi
+
+if [ $deleting -ne 0 ]; then
+ ip addr del $pfx dev $dev $label || exit 1
+ if [ $fwd -eq 0 ]; then RestartRDISC; fi
+ exit 0
+fi
+
+
+if ! ip link set up dev $dev ; then
+ echo "Error: cannot enable interface $dev." 1>&2
+ exit 1
+fi
+if [ "$ipaddr" = "" ]; then exit 0; fi
+
+if ! arping -q -c 2 -w 3 -D -I $dev $ipaddr ; then
+ echo "Error: some host already uses address $ipaddr on $dev." 1>&2
+ exit 1
+fi
+
+if ! ip address add $pfx brd + dev $dev $label; then
+ echo "Error: failed to add $pfx on $dev." 1>&2
+ exit 1
+fi
+
+arping -q -A -c 1 -I $dev $ipaddr
+noarp=$?
+( sleep 2 ;
+ arping -q -U -c 1 -I $dev $ipaddr ) >& /dev/null </dev/null &
+
+ip route add unreachable 224.0.0.0/24 >& /dev/null
+ip route add unreachable 255.255.255.255 >& /dev/null
+if [ `ip link ls $dev | grep -c MULTICAST` -ge 1 ]; then
+ ip route add 224.0.0.0/4 dev $dev scope global >& /dev/null
+fi
+
+if [ $fwd -eq 0 ]; then
+ if [ $noarp -eq 0 ]; then
+ ip ro append default dev $dev metric 30000 scope global
+ elif [ "$peer" != "" ]; then
+ if ping -q -c 2 -w 4 $peer ; then
+ ip ro append default via $peer dev $dev metric 30001
+ fi
+ fi
+ RestartRDISC
+fi
+
+exit 0
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/ip.c b/ap/app/iproute2/iproute2-3.4.0/ip/ip.c
new file mode 100755
index 0000000..20dc3b5
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/ip.c
@@ -0,0 +1,266 @@
+/*
+ * ip.c "ip" utility frontend.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <errno.h>
+
+#include "SNAPSHOT.h"
+#include "utils.h"
+#include "ip_common.h"
+
+int preferred_family = AF_UNSPEC;
+int show_stats = 0;
+int show_details = 0;
+int resolve_hosts = 0;
+int oneline = 0;
+int timestamp = 0;
+char * _SL_ = NULL;
+char *batch_file = NULL;
+int force = 0;
+int max_flush_loops = 10;
+
+struct rtnl_handle rth = { .fd = -1 };
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+ fprintf(stderr,
+"Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }\n"
+" ip [ -force ] -batch filename\n"
+"where OBJECT := { link | addr | addrlabel | route | rule | neigh | ntable |\n"
+" tunnel | tuntap | maddr | mroute | mrule | monitor | xfrm |\n"
+" netns | l2tp }\n"
+" OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n"
+" -f[amily] { inet | inet6 | ipx | dnet | link } |\n"
+" -l[oops] { maximum-addr-flush-attempts } |\n"
+" -o[neline] | -t[imestamp] | -b[atch] [filename] |\n"
+" -rc[vbuf] [size]}\n");
+ exit(-1);
+}
+
+static int do_help(int argc, char **argv)
+{
+ usage();
+}
+
+static const struct cmd {
+ const char *cmd;
+ int (*func)(int argc, char **argv);
+} cmds[] = {
+ { "address", do_ipaddr },
+ { "addrlabel", do_ipaddrlabel },
+ { "maddress", do_multiaddr },
+ { "route", do_iproute },
+ { "rule", do_iprule },
+ { "neighbor", do_ipneigh },
+ { "neighbour", do_ipneigh },
+ { "ntable", do_ipntable },
+ { "ntbl", do_ipntable },
+ { "link", do_iplink },
+ { "l2tp", do_ipl2tp },
+ { "tunnel", do_iptunnel },
+ { "tunl", do_iptunnel },
+ { "tuntap", do_iptuntap },
+ { "tap", do_iptuntap },
+ { "monitor", do_ipmonitor },
+ { "xfrm", do_xfrm },
+ { "mroute", do_multiroute },
+ { "mrule", do_multirule },
+ { "netns", do_netns },
+ { "help", do_help },
+ { 0 }
+};
+
+static int do_cmd(const char *argv0, int argc, char **argv)
+{
+ const struct cmd *c;
+
+ for (c = cmds; c->cmd; ++c) {
+ if (matches(argv0, c->cmd) == 0) {
+ return -(c->func(argc-1, argv+1));
+ }
+ }
+
+ fprintf(stderr, "Object \"%s\" is unknown, try \"ip help\".\n", argv0);
+ return EXIT_FAILURE;
+}
+
+static int batch(const char *name)
+{
+ char *line = NULL;
+ size_t len = 0;
+ int ret = EXIT_SUCCESS;
+
+ if (name && strcmp(name, "-") != 0) {
+ if (freopen(name, "r", stdin) == NULL) {
+ fprintf(stderr, "Cannot open file \"%s\" for reading: %s\n",
+ name, strerror(errno));
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (rtnl_open(&rth, 0) < 0) {
+ fprintf(stderr, "Cannot open rtnetlink\n");
+ return EXIT_FAILURE;
+ }
+
+ cmdlineno = 0;
+ while (getcmdline(&line, &len, stdin) != -1) {
+ char *largv[100];
+ int largc;
+
+ largc = makeargs(line, largv, 100);
+ if (largc == 0)
+ continue; /* blank line */
+
+ if (do_cmd(largv[0], largc, largv)) {
+ fprintf(stderr, "Command failed %s:%d\n", name, cmdlineno);
+ ret = EXIT_FAILURE;
+ if (!force)
+ break;
+ }
+ }
+ if (line)
+ free(line);
+
+ rtnl_close(&rth);
+ return ret;
+}
+
+
+int main(int argc, char **argv)
+{
+ char *basename;
+
+ basename = strrchr(argv[0], '/');
+ if (basename == NULL)
+ basename = argv[0];
+ else
+ basename++;
+
+ while (argc > 1) {
+ char *opt = argv[1];
+ if (strcmp(opt,"--") == 0) {
+ argc--; argv++;
+ break;
+ }
+ if (opt[0] != '-')
+ break;
+ if (opt[1] == '-')
+ opt++;
+ if (matches(opt, "-loops") == 0) {
+ argc--;
+ argv++;
+ if (argc <= 1)
+ usage();
+ max_flush_loops = atoi(argv[1]);
+ } else if (matches(opt, "-family") == 0) {
+ argc--;
+ argv++;
+ if (argc <= 1)
+ usage();
+ if (strcmp(argv[1], "inet") == 0)
+ preferred_family = AF_INET;
+ else if (strcmp(argv[1], "inet6") == 0)
+ preferred_family = AF_INET6;
+ else if (strcmp(argv[1], "dnet") == 0)
+ preferred_family = AF_DECnet;
+ else if (strcmp(argv[1], "link") == 0)
+ preferred_family = AF_PACKET;
+ else if (strcmp(argv[1], "ipx") == 0)
+ preferred_family = AF_IPX;
+ else if (strcmp(argv[1], "help") == 0)
+ usage();
+ else
+ invarg(argv[1], "invalid protocol family");
+ } else if (strcmp(opt, "-4") == 0) {
+ preferred_family = AF_INET;
+ } else if (strcmp(opt, "-6") == 0) {
+ preferred_family = AF_INET6;
+ } else if (strcmp(opt, "-0") == 0) {
+ preferred_family = AF_PACKET;
+ } else if (strcmp(opt, "-I") == 0) {
+ preferred_family = AF_IPX;
+ } else if (strcmp(opt, "-D") == 0) {
+ preferred_family = AF_DECnet;
+ } else if (matches(opt, "-stats") == 0 ||
+ matches(opt, "-statistics") == 0) {
+ ++show_stats;
+ } else if (matches(opt, "-details") == 0) {
+ ++show_details;
+ } else if (matches(opt, "-resolve") == 0) {
+ ++resolve_hosts;
+ } else if (matches(opt, "-oneline") == 0) {
+ ++oneline;
+ } else if (matches(opt, "-timestamp") == 0) {
+ ++timestamp;
+#if 0
+ } else if (matches(opt, "-numeric") == 0) {
+ rtnl_names_numeric++;
+#endif
+ } else if (matches(opt, "-Version") == 0) {
+ printf("ip utility, iproute2-ss%s\n", SNAPSHOT);
+ exit(0);
+ } else if (matches(opt, "-force") == 0) {
+ ++force;
+ } else if (matches(opt, "-batch") == 0) {
+ argc--;
+ argv++;
+ if (argc <= 1)
+ usage();
+ batch_file = argv[1];
+ } else if (matches(opt, "-rcvbuf") == 0) {
+ unsigned int size;
+
+ argc--;
+ argv++;
+ if (argc <= 1)
+ usage();
+ if (get_unsigned(&size, argv[1], 0)) {
+ fprintf(stderr, "Invalid rcvbuf size '%s'\n",
+ argv[1]);
+ exit(-1);
+ }
+ rcvbuf = size;
+ } else if (matches(opt, "-help") == 0) {
+ usage();
+ } else {
+ fprintf(stderr, "Option \"%s\" is unknown, try \"ip -help\".\n", opt);
+ exit(-1);
+ }
+ argc--; argv++;
+ }
+
+ _SL_ = oneline ? "\\" : "\n" ;
+
+ if (batch_file)
+ return batch(batch_file);
+
+ if (rtnl_open(&rth, 0) < 0)
+ exit(1);
+
+ if (strlen(basename) > 2)
+ return do_cmd(basename+2, argc, argv);
+
+ if (argc > 1)
+ return do_cmd(argv[1], argc-1, argv+1);
+
+ rtnl_close(&rth);
+ usage();
+}
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/ip6tunnel.c b/ap/app/iproute2/iproute2-3.4.0/ip/ip6tunnel.c
new file mode 100755
index 0000000..d5bee36
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/ip6tunnel.c
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C)2006 USAGI/WIDE Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*
+ * Author:
+ * Masahide NAKAMURA @USAGI
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#include <linux/ip.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/if_tunnel.h>
+#include <linux/ip6_tunnel.h>
+
+#include "utils.h"
+#include "tunnel.h"
+#include "ip_common.h"
+
+#define IP6_FLOWINFO_TCLASS htonl(0x0FF00000)
+#define IP6_FLOWINFO_FLOWLABEL htonl(0x000FFFFF)
+
+#define DEFAULT_TNL_HOP_LIMIT (64)
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: ip -f inet6 tunnel { add | change | del | show } [ NAME ]\n");
+ fprintf(stderr, " [ mode { ip6ip6 | ipip6 | any } ]\n");
+ fprintf(stderr, " [ remote ADDR local ADDR ] [ dev PHYS_DEV ]\n");
+ fprintf(stderr, " [ encaplimit ELIM ]\n");
+ fprintf(stderr ," [ hoplimit TTL ] [ tclass TCLASS ] [ flowlabel FLOWLABEL ]\n");
+ fprintf(stderr, " [ dscp inherit ]\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Where: NAME := STRING\n");
+ fprintf(stderr, " ADDR := IPV6_ADDRESS\n");
+ fprintf(stderr, " ELIM := { none | 0..255 }(default=%d)\n",
+ IPV6_DEFAULT_TNL_ENCAP_LIMIT);
+ fprintf(stderr, " TTL := 0..255 (default=%d)\n",
+ DEFAULT_TNL_HOP_LIMIT);
+ fprintf(stderr, " TOS := { 0x0..0xff | inherit }\n");
+ fprintf(stderr, " FLOWLABEL := { 0x0..0xfffff | inherit }\n");
+ exit(-1);
+}
+
+static void print_tunnel(struct ip6_tnl_parm *p)
+{
+ char remote[64];
+ char local[64];
+
+ inet_ntop(AF_INET6, &p->raddr, remote, sizeof(remote));
+ inet_ntop(AF_INET6, &p->laddr, local, sizeof(local));
+
+ printf("%s: %s/ipv6 remote %s local %s",
+ p->name, tnl_strproto(p->proto), remote, local);
+ if (p->link) {
+ const char *n = ll_index_to_name(p->link);
+ if (n)
+ printf(" dev %s", n);
+ }
+
+ if (p->flags & IP6_TNL_F_IGN_ENCAP_LIMIT)
+ printf(" encaplimit none");
+ else
+ printf(" encaplimit %u", p->encap_limit);
+
+ printf(" hoplimit %u", p->hop_limit);
+
+ if (p->flags & IP6_TNL_F_USE_ORIG_TCLASS)
+ printf(" tclass inherit");
+ else {
+ __u32 val = ntohl(p->flowinfo & IP6_FLOWINFO_TCLASS);
+ printf(" tclass 0x%02x", (__u8)(val >> 20));
+ }
+
+ if (p->flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)
+ printf(" flowlabel inherit");
+ else
+ printf(" flowlabel 0x%05x", ntohl(p->flowinfo & IP6_FLOWINFO_FLOWLABEL));
+
+ printf(" (flowinfo 0x%08x)", ntohl(p->flowinfo));
+
+ if (p->flags & IP6_TNL_F_RCV_DSCP_COPY)
+ printf(" dscp inherit");
+}
+
+static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm *p)
+{
+ int count = 0;
+ char medium[IFNAMSIZ];
+
+ memset(medium, 0, sizeof(medium));
+
+ while (argc > 0) {
+ if (strcmp(*argv, "mode") == 0) {
+ NEXT_ARG();
+ if (strcmp(*argv, "ipv6/ipv6") == 0 ||
+ strcmp(*argv, "ip6ip6") == 0)
+ p->proto = IPPROTO_IPV6;
+ else if (strcmp(*argv, "ip/ipv6") == 0 ||
+ strcmp(*argv, "ipv4/ipv6") == 0 ||
+ strcmp(*argv, "ipip6") == 0 ||
+ strcmp(*argv, "ip4ip6") == 0)
+ p->proto = IPPROTO_IPIP;
+ else if (strcmp(*argv, "any/ipv6") == 0 ||
+ strcmp(*argv, "any") == 0)
+ p->proto = 0;
+ else {
+ fprintf(stderr,"Cannot guess tunnel mode.\n");
+ exit(-1);
+ }
+ } else if (strcmp(*argv, "remote") == 0) {
+ inet_prefix raddr;
+ NEXT_ARG();
+ get_prefix(&raddr, *argv, preferred_family);
+ if (raddr.family == AF_UNSPEC)
+ invarg("\"remote\" address family is AF_UNSPEC", *argv);
+ memcpy(&p->raddr, &raddr.data, sizeof(p->raddr));
+ } else if (strcmp(*argv, "local") == 0) {
+ inet_prefix laddr;
+ NEXT_ARG();
+ get_prefix(&laddr, *argv, preferred_family);
+ if (laddr.family == AF_UNSPEC)
+ invarg("\"local\" address family is AF_UNSPEC", *argv);
+ memcpy(&p->laddr, &laddr.data, sizeof(p->laddr));
+ } else if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ strncpy(medium, *argv, IFNAMSIZ - 1);
+ } else if (strcmp(*argv, "encaplimit") == 0) {
+ NEXT_ARG();
+ if (strcmp(*argv, "none") == 0) {
+ p->flags |= IP6_TNL_F_IGN_ENCAP_LIMIT;
+ } else {
+ __u8 uval;
+ if (get_u8(&uval, *argv, 0) < -1)
+ invarg("invalid ELIM", *argv);
+ p->encap_limit = uval;
+ }
+ } else if (strcmp(*argv, "hoplimit") == 0 ||
+ strcmp(*argv, "ttl") == 0 ||
+ strcmp(*argv, "hlim") == 0) {
+ __u8 uval;
+ NEXT_ARG();
+ if (get_u8(&uval, *argv, 0))
+ invarg("invalid TTL", *argv);
+ p->hop_limit = uval;
+ } else if (strcmp(*argv, "tclass") == 0 ||
+ strcmp(*argv, "tc") == 0 ||
+ strcmp(*argv, "tos") == 0 ||
+ matches(*argv, "dsfield") == 0) {
+ __u8 uval;
+ NEXT_ARG();
+ if (strcmp(*argv, "inherit") == 0)
+ p->flags |= IP6_TNL_F_USE_ORIG_TCLASS;
+ else {
+ if (get_u8(&uval, *argv, 16))
+ invarg("invalid TClass", *argv);
+ p->flowinfo |= htonl((__u32)uval << 20) & IP6_FLOWINFO_TCLASS;
+ p->flags &= ~IP6_TNL_F_USE_ORIG_TCLASS;
+ }
+ } else if (strcmp(*argv, "flowlabel") == 0 ||
+ strcmp(*argv, "fl") == 0) {
+ __u32 uval;
+ NEXT_ARG();
+ if (strcmp(*argv, "inherit") == 0)
+ p->flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL;
+ else {
+ if (get_u32(&uval, *argv, 16))
+ invarg("invalid Flowlabel", *argv);
+ if (uval > 0xFFFFF)
+ invarg("invalid Flowlabel", *argv);
+ p->flowinfo |= htonl(uval) & IP6_FLOWINFO_FLOWLABEL;
+ p->flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL;
+ }
+ } else if (strcmp(*argv, "dscp") == 0) {
+ NEXT_ARG();
+ if (strcmp(*argv, "inherit") != 0)
+ invarg("not inherit", *argv);
+ p->flags |= IP6_TNL_F_RCV_DSCP_COPY;
+ } else {
+ if (strcmp(*argv, "name") == 0) {
+ NEXT_ARG();
+ }
+ if (matches(*argv, "help") == 0)
+ usage();
+ if (p->name[0])
+ duparg2("name", *argv);
+ strncpy(p->name, *argv, IFNAMSIZ - 1);
+ if (cmd == SIOCCHGTUNNEL && count == 0) {
+ struct ip6_tnl_parm old_p;
+ memset(&old_p, 0, sizeof(old_p));
+ if (tnl_get_ioctl(*argv, &old_p))
+ return -1;
+ *p = old_p;
+ }
+ }
+ count++;
+ argc--; argv++;
+ }
+ if (medium[0]) {
+ p->link = ll_name_to_index(medium);
+ if (p->link == 0)
+ return -1;
+ }
+ return 0;
+}
+
+static void ip6_tnl_parm_init(struct ip6_tnl_parm *p, int apply_default)
+{
+ memset(p, 0, sizeof(*p));
+ p->proto = IPPROTO_IPV6;
+ if (apply_default) {
+ p->hop_limit = DEFAULT_TNL_HOP_LIMIT;
+ p->encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT;
+ }
+}
+
+/*
+ * @p1: user specified parameter
+ * @p2: database entry
+ */
+static int ip6_tnl_parm_match(const struct ip6_tnl_parm *p1,
+ const struct ip6_tnl_parm *p2)
+{
+ return ((!p1->link || p1->link == p2->link) &&
+ (!p1->name[0] || strcmp(p1->name, p2->name) == 0) &&
+ (memcmp(&p1->laddr, &in6addr_any, sizeof(p1->laddr)) == 0 ||
+ memcmp(&p1->laddr, &p2->laddr, sizeof(p1->laddr)) == 0) &&
+ (memcmp(&p1->raddr, &in6addr_any, sizeof(p1->raddr)) == 0 ||
+ memcmp(&p1->raddr, &p2->raddr, sizeof(p1->raddr)) == 0) &&
+ (!p1->proto || !p2->proto || p1->proto == p2->proto) &&
+ (!p1->encap_limit || p1->encap_limit == p2->encap_limit) &&
+ (!p1->hop_limit || p1->hop_limit == p2->hop_limit) &&
+ (!(p1->flowinfo & IP6_FLOWINFO_TCLASS) ||
+ !((p1->flowinfo ^ p2->flowinfo) & IP6_FLOWINFO_TCLASS)) &&
+ (!(p1->flowinfo & IP6_FLOWINFO_FLOWLABEL) ||
+ !((p1->flowinfo ^ p2->flowinfo) & IP6_FLOWINFO_FLOWLABEL)) &&
+ (!p1->flags || (p1->flags & p2->flags)));
+}
+
+static int do_tunnels_list(struct ip6_tnl_parm *p)
+{
+ char buf[512];
+ int err = -1;
+ FILE *fp = fopen("/proc/net/dev", "r");
+ if (fp == NULL) {
+ perror("fopen");
+ goto end;
+ }
+
+ /* skip two lines at the begenning of the file */
+ if (!fgets(buf, sizeof(buf), fp) ||
+ !fgets(buf, sizeof(buf), fp)) {
+ fprintf(stderr, "/proc/net/dev read error\n");
+ return -1;
+ }
+
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ char name[IFNAMSIZ];
+ int index, type;
+ unsigned long rx_bytes, rx_packets, rx_errs, rx_drops,
+ rx_fifo, rx_frame,
+ tx_bytes, tx_packets, tx_errs, tx_drops,
+ tx_fifo, tx_colls, tx_carrier, rx_multi;
+ struct ip6_tnl_parm p1;
+ char *ptr;
+
+ buf[sizeof(buf) - 1] = '\0';
+ if ((ptr = strchr(buf, ':')) == NULL ||
+ (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) {
+ fprintf(stderr, "Wrong format of /proc/net/dev. Sorry.\n");
+ goto end;
+ }
+ if (sscanf(ptr, "%ld%ld%ld%ld%ld%ld%ld%*d%ld%ld%ld%ld%ld%ld%ld",
+ &rx_bytes, &rx_packets, &rx_errs, &rx_drops,
+ &rx_fifo, &rx_frame, &rx_multi,
+ &tx_bytes, &tx_packets, &tx_errs, &tx_drops,
+ &tx_fifo, &tx_colls, &tx_carrier) != 14)
+ continue;
+ if (p->name[0] && strcmp(p->name, name))
+ continue;
+ index = ll_name_to_index(name);
+ if (index == 0)
+ continue;
+ type = ll_index_to_type(index);
+ if (type == -1) {
+ fprintf(stderr, "Failed to get type of [%s]\n", name);
+ continue;
+ }
+ if (type != ARPHRD_TUNNEL6)
+ continue;
+ memset(&p1, 0, sizeof(p1));
+ ip6_tnl_parm_init(&p1, 0);
+ strcpy(p1.name, name);
+ p1.link = ll_name_to_index(p1.name);
+ if (p1.link == 0)
+ continue;
+ if (tnl_get_ioctl(p1.name, &p1))
+ continue;
+ if (!ip6_tnl_parm_match(p, &p1))
+ continue;
+ print_tunnel(&p1);
+ if (show_stats) {
+ printf("%s", _SL_);
+ printf("RX: Packets Bytes Errors CsumErrs OutOfSeq Mcasts%s", _SL_);
+ printf(" %-10ld %-12ld %-6ld %-8ld %-8ld %-8ld%s",
+ rx_packets, rx_bytes, rx_errs, rx_frame, rx_fifo, rx_multi, _SL_);
+ printf("TX: Packets Bytes Errors DeadLoop NoRoute NoBufs%s", _SL_);
+ printf(" %-10ld %-12ld %-6ld %-8ld %-8ld %-6ld",
+ tx_packets, tx_bytes, tx_errs, tx_colls, tx_carrier, tx_drops);
+ }
+ printf("\n");
+ }
+ err = 0;
+
+ end:
+ if (fp)
+ fclose(fp);
+ return err;
+}
+
+static int do_show(int argc, char **argv)
+{
+ struct ip6_tnl_parm p;
+
+ ll_init_map(&rth);
+ ip6_tnl_parm_init(&p, 0);
+ p.proto = 0; /* default to any */
+
+ if (parse_args(argc, argv, SIOCGETTUNNEL, &p) < 0)
+ return -1;
+
+ if (!p.name[0] || show_stats)
+ do_tunnels_list(&p);
+ else {
+ if (tnl_get_ioctl(p.name, &p))
+ return -1;
+ print_tunnel(&p);
+ printf("\n");
+ }
+
+ return 0;
+}
+
+static int do_add(int cmd, int argc, char **argv)
+{
+ struct ip6_tnl_parm p;
+
+ ip6_tnl_parm_init(&p, 1);
+
+ if (parse_args(argc, argv, cmd, &p) < 0)
+ return -1;
+
+ return tnl_add_ioctl(cmd,
+ cmd == SIOCCHGTUNNEL && p.name[0] ?
+ p.name : "ip6tnl0", p.name, &p);
+}
+
+static int do_del(int argc, char **argv)
+{
+ struct ip6_tnl_parm p;
+
+ ip6_tnl_parm_init(&p, 1);
+
+ if (parse_args(argc, argv, SIOCDELTUNNEL, &p) < 0)
+ return -1;
+
+ return tnl_del_ioctl(p.name[0] ? p.name : "ip6tnl0", p.name, &p);
+}
+
+int do_ip6tunnel(int argc, char **argv)
+{
+ switch (preferred_family) {
+ case AF_UNSPEC:
+ preferred_family = AF_INET6;
+ break;
+ case AF_INET6:
+ break;
+ default:
+ fprintf(stderr, "Unsupported family:%d\n", preferred_family);
+ exit(-1);
+ }
+
+ if (argc > 0) {
+ if (matches(*argv, "add") == 0)
+ return do_add(SIOCADDTUNNEL, argc - 1, argv + 1);
+ if (matches(*argv, "change") == 0)
+ return do_add(SIOCCHGTUNNEL, argc - 1, argv + 1);
+ if (matches(*argv, "del") == 0)
+ return do_del(argc - 1, argv + 1);
+ if (matches(*argv, "show") == 0 ||
+ matches(*argv, "lst") == 0 ||
+ matches(*argv, "list") == 0)
+ return do_show(argc - 1, argv + 1);
+ if (matches(*argv, "help") == 0)
+ usage();
+ } else
+ return do_show(0, NULL);
+
+ fprintf(stderr, "Command \"%s\" is unknown, try \"ip -f inet6 tunnel help\".\n", *argv);
+ exit(-1);
+}
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/ip_common.h b/ap/app/iproute2/iproute2-3.4.0/ip/ip_common.h
new file mode 100755
index 0000000..5fa2cc0
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/ip_common.h
@@ -0,0 +1,74 @@
+extern int get_operstate(const char *name);
+extern int print_linkinfo(const struct sockaddr_nl *who,
+ struct nlmsghdr *n,
+ void *arg);
+extern int print_addrinfo(const struct sockaddr_nl *who,
+ struct nlmsghdr *n,
+ void *arg);
+extern int print_addrlabel(const struct sockaddr_nl *who,
+ struct nlmsghdr *n, void *arg);
+extern int print_neigh(const struct sockaddr_nl *who,
+ struct nlmsghdr *n, void *arg);
+extern int print_ntable(const struct sockaddr_nl *who,
+ struct nlmsghdr *n, void *arg);
+extern int ipaddr_list(int argc, char **argv);
+extern int ipaddr_list_link(int argc, char **argv);
+extern int iproute_monitor(int argc, char **argv);
+extern void iplink_usage(void) __attribute__((noreturn));
+extern void iproute_reset_filter(void);
+extern void ipaddr_reset_filter(int);
+extern void ipneigh_reset_filter(void);
+extern void ipntable_reset_filter(void);
+extern int print_route(const struct sockaddr_nl *who,
+ struct nlmsghdr *n, void *arg);
+extern int print_prefix(const struct sockaddr_nl *who,
+ struct nlmsghdr *n, void *arg);
+extern int print_rule(const struct sockaddr_nl *who,
+ struct nlmsghdr *n, void *arg);
+extern int do_ipaddr(int argc, char **argv);
+extern int do_ipaddrlabel(int argc, char **argv);
+extern int do_iproute(int argc, char **argv);
+extern int do_iprule(int argc, char **argv);
+extern int do_ipneigh(int argc, char **argv);
+extern int do_ipntable(int argc, char **argv);
+extern int do_iptunnel(int argc, char **argv);
+extern int do_ip6tunnel(int argc, char **argv);
+extern int do_iptuntap(int argc, char **argv);
+extern int do_iplink(int argc, char **argv);
+extern int do_ipmonitor(int argc, char **argv);
+extern int do_multiaddr(int argc, char **argv);
+extern int do_multiroute(int argc, char **argv);
+extern int do_multirule(int argc, char **argv);
+extern int do_netns(int argc, char **argv);
+extern int do_xfrm(int argc, char **argv);
+extern int do_ipl2tp(int argc, char **argv);
+
+static inline int rtm_get_table(struct rtmsg *r, struct rtattr **tb)
+{
+ __u32 table = r->rtm_table;
+ if (tb[RTA_TABLE])
+ table = rta_getattr_u32(tb[RTA_TABLE]);
+ return table;
+}
+
+extern struct rtnl_handle rth;
+
+struct link_util
+{
+ struct link_util *next;
+ const char *id;
+ int maxattr;
+ int (*parse_opt)(struct link_util *, int, char **,
+ struct nlmsghdr *);
+ void (*print_opt)(struct link_util *, FILE *,
+ struct rtattr *[]);
+ void (*print_xstats)(struct link_util *, FILE *,
+ struct rtattr *);
+};
+
+struct link_util *get_link_kind(const char *kind);
+int get_netns_fd(const char *name);
+
+#ifndef INFINITY_LIFE_TIME
+#define INFINITY_LIFE_TIME 0xFFFFFFFFU
+#endif
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/ipaddress.c b/ap/app/iproute2/iproute2-3.4.0/ip/ipaddress.c
new file mode 100755
index 0000000..9ab65ec
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/ipaddress.c
@@ -0,0 +1,1267 @@
+/*
+ * ipaddress.c "ip address".
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <inttypes.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <fnmatch.h>
+
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/sockios.h>
+
+#include "rt_names.h"
+#include "utils.h"
+#include "ll_map.h"
+#include "ip_common.h"
+
+
+static struct
+{
+ int ifindex;
+ int family;
+ int oneline;
+ int showqueue;
+ inet_prefix pfx;
+ int scope, scopemask;
+ int flags, flagmask;
+ int up;
+ char *label;
+ int flushed;
+ char *flushb;
+ int flushp;
+ int flushe;
+ int group;
+} filter;
+
+static int do_link;
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+ if (do_link) {
+ iplink_usage();
+ }
+ fprintf(stderr, "Usage: ip addr {add|change|replace} IFADDR dev STRING [ LIFETIME ]\n");
+ fprintf(stderr, " [ CONFFLAG-LIST ]\n");
+ fprintf(stderr, " ip addr del IFADDR dev STRING\n");
+ fprintf(stderr, " ip addr {show|flush} [ dev STRING ] [ scope SCOPE-ID ]\n");
+ fprintf(stderr, " [ to PREFIX ] [ FLAG-LIST ] [ label PATTERN ]\n");
+ fprintf(stderr, "IFADDR := PREFIX | ADDR peer PREFIX\n");
+ fprintf(stderr, " [ broadcast ADDR ] [ anycast ADDR ]\n");
+ fprintf(stderr, " [ label STRING ] [ scope SCOPE-ID ]\n");
+ fprintf(stderr, "SCOPE-ID := [ host | link | global | NUMBER ]\n");
+ fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n");
+ fprintf(stderr, "FLAG := [ permanent | dynamic | secondary | primary |\n");
+ fprintf(stderr, " tentative | deprecated | dadfailed | temporary |\n");
+ fprintf(stderr, " CONFFLAG-LIST ]\n");
+ fprintf(stderr, "CONFFLAG-LIST := [ CONFFLAG-LIST ] CONFFLAG\n");
+ fprintf(stderr, "CONFFLAG := [ home | nodad ]\n");
+ fprintf(stderr, "LIFETIME := [ valid_lft LFT ] [ preferred_lft LFT ]\n");
+ fprintf(stderr, "LFT := forever | SECONDS\n");
+
+ exit(-1);
+}
+
+void print_link_flags(FILE *fp, unsigned flags, unsigned mdown)
+{
+ fprintf(fp, "<");
+ if (flags & IFF_UP && !(flags & IFF_RUNNING))
+ fprintf(fp, "NO-CARRIER%s", flags ? "," : "");
+ flags &= ~IFF_RUNNING;
+#define _PF(f) if (flags&IFF_##f) { \
+ flags &= ~IFF_##f ; \
+ fprintf(fp, #f "%s", flags ? "," : ""); }
+ _PF(LOOPBACK);
+ _PF(BROADCAST);
+ _PF(POINTOPOINT);
+ _PF(MULTICAST);
+ _PF(NOARP);
+ _PF(ALLMULTI);
+ _PF(PROMISC);
+ _PF(MASTER);
+ _PF(SLAVE);
+ _PF(DEBUG);
+ _PF(DYNAMIC);
+ _PF(AUTOMEDIA);
+ _PF(PORTSEL);
+ _PF(NOTRAILERS);
+ _PF(UP);
+ _PF(LOWER_UP);
+ _PF(DORMANT);
+ _PF(ECHO);
+#undef _PF
+ if (flags)
+ fprintf(fp, "%x", flags);
+ if (mdown)
+ fprintf(fp, ",M-DOWN");
+ fprintf(fp, "> ");
+}
+
+static const char *oper_states[] = {
+ "UNKNOWN", "NOTPRESENT", "DOWN", "LOWERLAYERDOWN",
+ "TESTING", "DORMANT", "UP"
+};
+
+static void print_operstate(FILE *f, __u8 state)
+{
+ if (state >= sizeof(oper_states)/sizeof(oper_states[0]))
+ fprintf(f, "state %#x ", state);
+ else
+ fprintf(f, "state %s ", oper_states[state]);
+}
+
+int get_operstate(const char *name)
+{
+ int i;
+
+ for (i = 0; i < sizeof(oper_states)/sizeof(oper_states[0]); i++)
+ if (strcasecmp(name, oper_states[i]) == 0)
+ return i;
+ return -1;
+}
+
+static void print_queuelen(FILE *f, struct rtattr *tb[IFLA_MAX + 1])
+{
+ int qlen;
+
+ if (tb[IFLA_TXQLEN])
+ qlen = *(int *)RTA_DATA(tb[IFLA_TXQLEN]);
+ else {
+ struct ifreq ifr;
+ int s = socket(AF_INET, SOCK_STREAM, 0);
+
+ if (s < 0)
+ return;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strcpy(ifr.ifr_name, rta_getattr_str(tb[IFLA_IFNAME]));
+ if (ioctl(s, SIOCGIFTXQLEN, &ifr) < 0) {
+ fprintf(f, "ioctl(SIOCGIFXQLEN) failed: %s\n", strerror(errno));
+ close(s);
+ return;
+ }
+ close(s);
+ qlen = ifr.ifr_qlen;
+ }
+ if (qlen)
+ fprintf(f, "qlen %d", qlen);
+}
+
+static const char *link_modes[] = {
+ "DEFAULT", "DORMANT"
+};
+
+static void print_linkmode(FILE *f, struct rtattr *tb)
+{
+ unsigned int mode = rta_getattr_u8(tb);
+
+ if (mode >= sizeof(link_modes) / sizeof(link_modes[0]))
+ fprintf(f, "mode %d ", mode);
+ else
+ fprintf(f, "mode %s ", link_modes[mode]);
+}
+
+static void print_linktype(FILE *fp, struct rtattr *tb)
+{
+ struct rtattr *linkinfo[IFLA_INFO_MAX+1];
+ struct link_util *lu;
+ char *kind;
+
+ parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb);
+
+ if (!linkinfo[IFLA_INFO_KIND])
+ return;
+ kind = RTA_DATA(linkinfo[IFLA_INFO_KIND]);
+
+ fprintf(fp, "%s", _SL_);
+ fprintf(fp, " %s ", kind);
+
+ lu = get_link_kind(kind);
+ if (!lu || !lu->print_opt)
+ return;
+
+ if (1) {
+ struct rtattr *attr[lu->maxattr+1], **data = NULL;
+
+ if (linkinfo[IFLA_INFO_DATA]) {
+ parse_rtattr_nested(attr, lu->maxattr,
+ linkinfo[IFLA_INFO_DATA]);
+ data = attr;
+ }
+ lu->print_opt(lu, fp, data);
+
+ if (linkinfo[IFLA_INFO_XSTATS] && show_stats &&
+ lu->print_xstats)
+ lu->print_xstats(lu, fp, linkinfo[IFLA_INFO_XSTATS]);
+ }
+}
+
+static void print_vfinfo(FILE *fp, struct rtattr *vfinfo)
+{
+ struct ifla_vf_mac *vf_mac;
+ struct ifla_vf_vlan *vf_vlan;
+ struct ifla_vf_tx_rate *vf_tx_rate;
+ struct ifla_vf_spoofchk *vf_spoofchk;
+ struct rtattr *vf[IFLA_VF_MAX+1];
+ struct rtattr *tmp;
+ SPRINT_BUF(b1);
+
+ if (vfinfo->rta_type != IFLA_VF_INFO) {
+ fprintf(stderr, "BUG: rta type is %d\n", vfinfo->rta_type);
+ return;
+ }
+
+ parse_rtattr_nested(vf, IFLA_VF_MAX, vfinfo);
+
+ vf_mac = RTA_DATA(vf[IFLA_VF_MAC]);
+ vf_vlan = RTA_DATA(vf[IFLA_VF_VLAN]);
+ vf_tx_rate = RTA_DATA(vf[IFLA_VF_TX_RATE]);
+
+ /* Check if the spoof checking vf info type is supported by
+ * this kernel.
+ */
+ tmp = (struct rtattr *)((char *)vf[IFLA_VF_TX_RATE] +
+ vf[IFLA_VF_TX_RATE]->rta_len);
+
+ if (tmp->rta_type != IFLA_VF_SPOOFCHK)
+ vf_spoofchk = NULL;
+ else
+ vf_spoofchk = RTA_DATA(vf[IFLA_VF_SPOOFCHK]);
+
+ fprintf(fp, "\n vf %d MAC %s", vf_mac->vf,
+ ll_addr_n2a((unsigned char *)&vf_mac->mac,
+ ETH_ALEN, 0, b1, sizeof(b1)));
+ if (vf_vlan->vlan)
+ fprintf(fp, ", vlan %d", vf_vlan->vlan);
+ if (vf_vlan->qos)
+ fprintf(fp, ", qos %d", vf_vlan->qos);
+ if (vf_tx_rate->rate)
+ fprintf(fp, ", tx rate %d (Mbps)", vf_tx_rate->rate);
+ if (vf_spoofchk && vf_spoofchk->setting != -1) {
+ if (vf_spoofchk->setting)
+ fprintf(fp, ", spoof checking on");
+ else
+ fprintf(fp, ", spoof checking off");
+ }
+}
+
+static void print_link_stats64(FILE *fp, const struct rtnl_link_stats64 *s) {
+ fprintf(fp, "%s", _SL_);
+ fprintf(fp, " RX: bytes packets errors dropped overrun mcast %s%s",
+ s->rx_compressed ? "compressed" : "", _SL_);
+ fprintf(fp, " %-10"PRIu64" %-8"PRIu64" %-7"PRIu64" %-7"PRIu64" %-7"PRIu64" %-7"PRIu64"",
+ (uint64_t)s->rx_bytes,
+ (uint64_t)s->rx_packets,
+ (uint64_t)s->rx_errors,
+ (uint64_t)s->rx_dropped,
+ (uint64_t)s->rx_over_errors,
+ (uint64_t)s->multicast);
+ if (s->rx_compressed)
+ fprintf(fp, " %-7"PRIu64"",
+ (uint64_t)s->rx_compressed);
+ if (show_stats > 1) {
+ fprintf(fp, "%s", _SL_);
+ fprintf(fp, " RX errors: length crc frame fifo missed%s", _SL_);
+ fprintf(fp, " %-7"PRIu64" %-7"PRIu64" %-7"PRIu64" %-7"PRIu64" %-7"PRIu64"",
+ (uint64_t)s->rx_length_errors,
+ (uint64_t)s->rx_crc_errors,
+ (uint64_t)s->rx_frame_errors,
+ (uint64_t)s->rx_fifo_errors,
+ (uint64_t)s->rx_missed_errors);
+ }
+ fprintf(fp, "%s", _SL_);
+ fprintf(fp, " TX: bytes packets errors dropped carrier collsns %s%s",
+ (uint64_t)s->tx_compressed ? "compressed" : "", _SL_);
+ fprintf(fp, " %-10"PRIu64" %-8"PRIu64" %-7"PRIu64" %-7"PRIu64" %-7"PRIu64" %-7"PRIu64"",
+ (uint64_t)s->tx_bytes,
+ (uint64_t)s->tx_packets,
+ (uint64_t)s->tx_errors,
+ (uint64_t)s->tx_dropped,
+ (uint64_t)s->tx_carrier_errors,
+ (uint64_t)s->collisions);
+ if (s->tx_compressed)
+ fprintf(fp, " %-7"PRIu64"",
+ (uint64_t)s->tx_compressed);
+ if (show_stats > 1) {
+ fprintf(fp, "%s", _SL_);
+ fprintf(fp, " TX errors: aborted fifo window heartbeat%s", _SL_);
+ fprintf(fp, " %-7"PRIu64" %-7"PRIu64" %-7"PRIu64" %-7"PRIu64"",
+ (uint64_t)s->tx_aborted_errors,
+ (uint64_t)s->tx_fifo_errors,
+ (uint64_t)s->tx_window_errors,
+ (uint64_t)s->tx_heartbeat_errors);
+ }
+}
+
+static void print_link_stats(FILE *fp, const struct rtnl_link_stats *s)
+{
+ fprintf(fp, "%s", _SL_);
+ fprintf(fp, " RX: bytes packets errors dropped overrun mcast %s%s",
+ s->rx_compressed ? "compressed" : "", _SL_);
+ fprintf(fp, " %-10u %-8u %-7u %-7u %-7u %-7u",
+ s->rx_bytes, s->rx_packets, s->rx_errors,
+ s->rx_dropped, s->rx_over_errors,
+ s->multicast
+ );
+ if (s->rx_compressed)
+ fprintf(fp, " %-7u", s->rx_compressed);
+ if (show_stats > 1) {
+ fprintf(fp, "%s", _SL_);
+ fprintf(fp, " RX errors: length crc frame fifo missed%s", _SL_);
+ fprintf(fp, " %-7u %-7u %-7u %-7u %-7u",
+ s->rx_length_errors,
+ s->rx_crc_errors,
+ s->rx_frame_errors,
+ s->rx_fifo_errors,
+ s->rx_missed_errors
+ );
+ }
+ fprintf(fp, "%s", _SL_);
+ fprintf(fp, " TX: bytes packets errors dropped carrier collsns %s%s",
+ s->tx_compressed ? "compressed" : "", _SL_);
+ fprintf(fp, " %-10u %-8u %-7u %-7u %-7u %-7u",
+ s->tx_bytes, s->tx_packets, s->tx_errors,
+ s->tx_dropped, s->tx_carrier_errors, s->collisions);
+ if (s->tx_compressed)
+ fprintf(fp, " %-7u", s->tx_compressed);
+ if (show_stats > 1) {
+ fprintf(fp, "%s", _SL_);
+ fprintf(fp, " TX errors: aborted fifo window heartbeat%s", _SL_);
+ fprintf(fp, " %-7u %-7u %-7u %-7u",
+ s->tx_aborted_errors,
+ s->tx_fifo_errors,
+ s->tx_window_errors,
+ s->tx_heartbeat_errors
+ );
+ }
+}
+
+int print_linkinfo(const struct sockaddr_nl *who,
+ struct nlmsghdr *n, void *arg)
+{
+ FILE *fp = (FILE*)arg;
+ struct ifinfomsg *ifi = NLMSG_DATA(n);
+ struct rtattr * tb[IFLA_MAX+1];
+ int len = n->nlmsg_len;
+ unsigned m_flag = 0;
+
+ if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK)
+ return 0;
+
+ len -= NLMSG_LENGTH(sizeof(*ifi));
+ if (len < 0)
+ return -1;
+
+ if (filter.ifindex && ifi->ifi_index != filter.ifindex)
+ return 0;
+ if (filter.up && !(ifi->ifi_flags&IFF_UP))
+ return 0;
+
+ parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
+ if (tb[IFLA_IFNAME] == NULL) {
+ fprintf(stderr, "BUG: device with ifindex %d has nil ifname\n", ifi->ifi_index);
+ }
+ if (filter.label &&
+ (!filter.family || filter.family == AF_PACKET) &&
+ fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0))
+ return 0;
+
+ if (tb[IFLA_GROUP]) {
+ int group = *(int*)RTA_DATA(tb[IFLA_GROUP]);
+ if (group != filter.group)
+ return -1;
+ }
+
+ if (n->nlmsg_type == RTM_DELLINK)
+ fprintf(fp, "Deleted ");
+
+ fprintf(fp, "%d: %s", ifi->ifi_index,
+ tb[IFLA_IFNAME] ? rta_getattr_str(tb[IFLA_IFNAME]) : "<nil>");
+
+ if (tb[IFLA_LINK]) {
+ SPRINT_BUF(b1);
+ int iflink = *(int*)RTA_DATA(tb[IFLA_LINK]);
+ if (iflink == 0)
+ fprintf(fp, "@NONE: ");
+ else {
+ fprintf(fp, "@%s: ", ll_idx_n2a(iflink, b1));
+ m_flag = ll_index_to_flags(iflink);
+ m_flag = !(m_flag & IFF_UP);
+ }
+ } else {
+ fprintf(fp, ": ");
+ }
+ print_link_flags(fp, ifi->ifi_flags, m_flag);
+
+ if (tb[IFLA_MTU])
+ fprintf(fp, "mtu %u ", *(int*)RTA_DATA(tb[IFLA_MTU]));
+ if (tb[IFLA_QDISC])
+ fprintf(fp, "qdisc %s ", rta_getattr_str(tb[IFLA_QDISC]));
+ if (tb[IFLA_MASTER]) {
+ SPRINT_BUF(b1);
+ fprintf(fp, "master %s ", ll_idx_n2a(*(int*)RTA_DATA(tb[IFLA_MASTER]), b1));
+ }
+
+ if (tb[IFLA_OPERSTATE])
+ print_operstate(fp, rta_getattr_u8(tb[IFLA_OPERSTATE]));
+
+ if (do_link && tb[IFLA_LINKMODE])
+ print_linkmode(fp, tb[IFLA_LINKMODE]);
+
+ if (filter.showqueue)
+ print_queuelen(fp, tb);
+
+ if (!filter.family || filter.family == AF_PACKET) {
+ SPRINT_BUF(b1);
+ fprintf(fp, "%s", _SL_);
+ fprintf(fp, " link/%s ", ll_type_n2a(ifi->ifi_type, b1, sizeof(b1)));
+
+ if (tb[IFLA_ADDRESS]) {
+ fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]),
+ RTA_PAYLOAD(tb[IFLA_ADDRESS]),
+ ifi->ifi_type,
+ b1, sizeof(b1)));
+ }
+ if (tb[IFLA_BROADCAST]) {
+ if (ifi->ifi_flags&IFF_POINTOPOINT)
+ fprintf(fp, " peer ");
+ else
+ fprintf(fp, " brd ");
+ fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(tb[IFLA_BROADCAST]),
+ RTA_PAYLOAD(tb[IFLA_BROADCAST]),
+ ifi->ifi_type,
+ b1, sizeof(b1)));
+ }
+ }
+
+ if (do_link && tb[IFLA_LINKINFO] && show_details)
+ print_linktype(fp, tb[IFLA_LINKINFO]);
+
+ if (do_link && tb[IFLA_IFALIAS])
+ fprintf(fp,"\n alias %s",
+ rta_getattr_str(tb[IFLA_IFALIAS]));
+
+ if (do_link && show_stats) {
+ if (tb[IFLA_STATS64])
+ print_link_stats64(fp, RTA_DATA(tb[IFLA_STATS64]));
+ else if (tb[IFLA_STATS])
+ print_link_stats(fp, RTA_DATA(tb[IFLA_STATS]));
+ }
+
+ if (do_link && tb[IFLA_VFINFO_LIST] && tb[IFLA_NUM_VF]) {
+ struct rtattr *i, *vflist = tb[IFLA_VFINFO_LIST];
+ int rem = RTA_PAYLOAD(vflist);
+ for (i = RTA_DATA(vflist); RTA_OK(i, rem); i = RTA_NEXT(i, rem))
+ print_vfinfo(fp, i);
+ }
+
+ fprintf(fp, "\n");
+ fflush(fp);
+ return 0;
+}
+
+static int flush_update(void)
+{
+ if (rtnl_send_check(&rth, filter.flushb, filter.flushp) < 0) {
+ perror("Failed to send flush request");
+ return -1;
+ }
+ filter.flushp = 0;
+ return 0;
+}
+
+static int set_lifetime(unsigned int *lifetime, char *argv)
+{
+ if (strcmp(argv, "forever") == 0)
+ *lifetime = INFINITY_LIFE_TIME;
+ else if (get_u32(lifetime, argv, 0))
+ return -1;
+
+ return 0;
+}
+
+int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
+ void *arg)
+{
+ FILE *fp = (FILE*)arg;
+ struct ifaddrmsg *ifa = NLMSG_DATA(n);
+ int len = n->nlmsg_len;
+ int deprecated = 0;
+ /* Use local copy of ifa_flags to not interfere with filtering code */
+ unsigned int ifa_flags;
+ struct rtattr * rta_tb[IFA_MAX+1];
+ char abuf[256];
+ SPRINT_BUF(b1);
+
+ if (n->nlmsg_type != RTM_NEWADDR && n->nlmsg_type != RTM_DELADDR)
+ return 0;
+ len -= NLMSG_LENGTH(sizeof(*ifa));
+ if (len < 0) {
+ fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+ return -1;
+ }
+
+ if (filter.flushb && n->nlmsg_type != RTM_NEWADDR)
+ return 0;
+
+ parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
+
+ if (!rta_tb[IFA_LOCAL])
+ rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
+ if (!rta_tb[IFA_ADDRESS])
+ rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL];
+
+ if (filter.ifindex && filter.ifindex != ifa->ifa_index)
+ return 0;
+ if ((filter.scope^ifa->ifa_scope)&filter.scopemask)
+ return 0;
+ if ((filter.flags^ifa->ifa_flags)&filter.flagmask)
+ return 0;
+ if (filter.label) {
+ SPRINT_BUF(b1);
+ const char *label;
+ if (rta_tb[IFA_LABEL])
+ label = RTA_DATA(rta_tb[IFA_LABEL]);
+ else
+ label = ll_idx_n2a(ifa->ifa_index, b1);
+ if (fnmatch(filter.label, label, 0) != 0)
+ return 0;
+ }
+ if (filter.pfx.family) {
+ if (rta_tb[IFA_LOCAL]) {
+ inet_prefix dst;
+ memset(&dst, 0, sizeof(dst));
+ dst.family = ifa->ifa_family;
+ memcpy(&dst.data, RTA_DATA(rta_tb[IFA_LOCAL]), RTA_PAYLOAD(rta_tb[IFA_LOCAL]));
+ if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen))
+ return 0;
+ }
+ }
+
+ if (filter.family && filter.family != ifa->ifa_family)
+ return 0;
+
+ if (filter.flushb) {
+ struct nlmsghdr *fn;
+ if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) {
+ if (flush_update())
+ return -1;
+ }
+ fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp));
+ memcpy(fn, n, n->nlmsg_len);
+ fn->nlmsg_type = RTM_DELADDR;
+ fn->nlmsg_flags = NLM_F_REQUEST;
+ fn->nlmsg_seq = ++rth.seq;
+ filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb;
+ filter.flushed++;
+ if (show_stats < 2)
+ return 0;
+ }
+
+ if (n->nlmsg_type == RTM_DELADDR)
+ fprintf(fp, "Deleted ");
+
+ if (filter.oneline || filter.flushb)
+ fprintf(fp, "%u: %s", ifa->ifa_index, ll_index_to_name(ifa->ifa_index));
+ if (ifa->ifa_family == AF_INET)
+ fprintf(fp, " inet ");
+ else if (ifa->ifa_family == AF_INET6)
+ fprintf(fp, " inet6 ");
+ else if (ifa->ifa_family == AF_DECnet)
+ fprintf(fp, " dnet ");
+ else if (ifa->ifa_family == AF_IPX)
+ fprintf(fp, " ipx ");
+ else
+ fprintf(fp, " family %d ", ifa->ifa_family);
+
+ if (rta_tb[IFA_LOCAL]) {
+ fprintf(fp, "%s", rt_addr_n2a(ifa->ifa_family,
+ RTA_PAYLOAD(rta_tb[IFA_LOCAL]),
+ RTA_DATA(rta_tb[IFA_LOCAL]),
+ abuf, sizeof(abuf)));
+
+ if (rta_tb[IFA_ADDRESS] == NULL ||
+ memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]), 4) == 0) {
+ fprintf(fp, "/%d ", ifa->ifa_prefixlen);
+ } else {
+ fprintf(fp, " peer %s/%d ",
+ rt_addr_n2a(ifa->ifa_family,
+ RTA_PAYLOAD(rta_tb[IFA_ADDRESS]),
+ RTA_DATA(rta_tb[IFA_ADDRESS]),
+ abuf, sizeof(abuf)),
+ ifa->ifa_prefixlen);
+ }
+ }
+
+ if (rta_tb[IFA_BROADCAST]) {
+ fprintf(fp, "brd %s ",
+ rt_addr_n2a(ifa->ifa_family,
+ RTA_PAYLOAD(rta_tb[IFA_BROADCAST]),
+ RTA_DATA(rta_tb[IFA_BROADCAST]),
+ abuf, sizeof(abuf)));
+ }
+ if (rta_tb[IFA_ANYCAST]) {
+ fprintf(fp, "any %s ",
+ rt_addr_n2a(ifa->ifa_family,
+ RTA_PAYLOAD(rta_tb[IFA_ANYCAST]),
+ RTA_DATA(rta_tb[IFA_ANYCAST]),
+ abuf, sizeof(abuf)));
+ }
+ fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1)));
+ ifa_flags = ifa->ifa_flags;
+ if (ifa->ifa_flags&IFA_F_SECONDARY) {
+ ifa_flags &= ~IFA_F_SECONDARY;
+ if (ifa->ifa_family == AF_INET6)
+ fprintf(fp, "temporary ");
+ else
+ fprintf(fp, "secondary ");
+ }
+ if (ifa->ifa_flags&IFA_F_TENTATIVE) {
+ ifa_flags &= ~IFA_F_TENTATIVE;
+ fprintf(fp, "tentative ");
+ }
+ if (ifa->ifa_flags&IFA_F_DEPRECATED) {
+ ifa_flags &= ~IFA_F_DEPRECATED;
+ deprecated = 1;
+ fprintf(fp, "deprecated ");
+ }
+ if (ifa->ifa_flags&IFA_F_HOMEADDRESS) {
+ ifa_flags &= ~IFA_F_HOMEADDRESS;
+ fprintf(fp, "home ");
+ }
+ if (ifa->ifa_flags&IFA_F_NODAD) {
+ ifa_flags &= ~IFA_F_NODAD;
+ fprintf(fp, "nodad ");
+ }
+ if (!(ifa->ifa_flags&IFA_F_PERMANENT)) {
+ fprintf(fp, "dynamic ");
+ } else
+ ifa_flags &= ~IFA_F_PERMANENT;
+ if (ifa->ifa_flags&IFA_F_DADFAILED) {
+ ifa_flags &= ~IFA_F_DADFAILED;
+ fprintf(fp, "dadfailed ");
+ }
+ if (ifa_flags)
+ fprintf(fp, "flags %02x ", ifa_flags);
+ if (rta_tb[IFA_LABEL])
+ fprintf(fp, "%s", rta_getattr_str(rta_tb[IFA_LABEL]));
+ if (rta_tb[IFA_CACHEINFO]) {
+ struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]);
+ fprintf(fp, "%s", _SL_);
+ fprintf(fp, " valid_lft ");
+ if (ci->ifa_valid == INFINITY_LIFE_TIME)
+ fprintf(fp, "forever");
+ else
+ fprintf(fp, "%usec", ci->ifa_valid);
+ fprintf(fp, " preferred_lft ");
+ if (ci->ifa_prefered == INFINITY_LIFE_TIME)
+ fprintf(fp, "forever");
+ else {
+ if (deprecated)
+ fprintf(fp, "%dsec", ci->ifa_prefered);
+ else
+ fprintf(fp, "%usec", ci->ifa_prefered);
+ }
+ }
+ fprintf(fp, "\n");
+ fflush(fp);
+ return 0;
+}
+
+int print_addrinfo_primary(const struct sockaddr_nl *who, struct nlmsghdr *n,
+ void *arg)
+{
+ struct ifaddrmsg *ifa = NLMSG_DATA(n);
+
+ if (ifa->ifa_flags & IFA_F_SECONDARY)
+ return 0;
+
+ return print_addrinfo(who, n, arg);
+}
+
+int print_addrinfo_secondary(const struct sockaddr_nl *who, struct nlmsghdr *n,
+ void *arg)
+{
+ struct ifaddrmsg *ifa = NLMSG_DATA(n);
+
+ if (!(ifa->ifa_flags & IFA_F_SECONDARY))
+ return 0;
+
+ return print_addrinfo(who, n, arg);
+}
+
+struct nlmsg_list
+{
+ struct nlmsg_list *next;
+ struct nlmsghdr h;
+};
+
+static int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo, FILE *fp)
+{
+ for ( ;ainfo ; ainfo = ainfo->next) {
+ struct nlmsghdr *n = &ainfo->h;
+ struct ifaddrmsg *ifa = NLMSG_DATA(n);
+
+ if (n->nlmsg_type != RTM_NEWADDR)
+ continue;
+
+ if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifa)))
+ return -1;
+
+ if (ifa->ifa_index != ifindex ||
+ (filter.family && filter.family != ifa->ifa_family))
+ continue;
+
+ print_addrinfo(NULL, n, fp);
+ }
+ return 0;
+}
+
+
+static int store_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n,
+ void *arg)
+{
+ struct nlmsg_list **linfo = (struct nlmsg_list**)arg;
+ struct nlmsg_list *h;
+ struct nlmsg_list **lp;
+
+ h = malloc(n->nlmsg_len+sizeof(void*));
+ if (h == NULL)
+ return -1;
+
+ memcpy(&h->h, n, n->nlmsg_len);
+ h->next = NULL;
+
+ for (lp = linfo; *lp; lp = &(*lp)->next) /* NOTHING */;
+ *lp = h;
+
+ ll_remember_index(who, n, NULL);
+ return 0;
+}
+
+static int ipaddr_list_or_flush(int argc, char **argv, int flush)
+{
+ struct nlmsg_list *linfo = NULL;
+ struct nlmsg_list *ainfo = NULL;
+ struct nlmsg_list *l, *n;
+ char *filter_dev = NULL;
+ int no_link = 0;
+
+ ipaddr_reset_filter(oneline);
+ filter.showqueue = 1;
+
+ if (filter.family == AF_UNSPEC)
+ filter.family = preferred_family;
+
+ filter.group = INIT_NETDEV_GROUP;
+
+ if (flush) {
+ if (argc <= 0) {
+ fprintf(stderr, "Flush requires arguments.\n");
+
+ return -1;
+ }
+ if (filter.family == AF_PACKET) {
+ fprintf(stderr, "Cannot flush link addresses.\n");
+ return -1;
+ }
+ }
+
+ while (argc > 0) {
+ if (strcmp(*argv, "to") == 0) {
+ NEXT_ARG();
+ get_prefix(&filter.pfx, *argv, filter.family);
+ if (filter.family == AF_UNSPEC)
+ filter.family = filter.pfx.family;
+ } else if (strcmp(*argv, "scope") == 0) {
+ unsigned scope = 0;
+ NEXT_ARG();
+ filter.scopemask = -1;
+ if (rtnl_rtscope_a2n(&scope, *argv)) {
+ if (strcmp(*argv, "all") != 0)
+ invarg("invalid \"scope\"\n", *argv);
+ scope = RT_SCOPE_NOWHERE;
+ filter.scopemask = 0;
+ }
+ filter.scope = scope;
+ } else if (strcmp(*argv, "up") == 0) {
+ filter.up = 1;
+ } else if (strcmp(*argv, "dynamic") == 0) {
+ filter.flags &= ~IFA_F_PERMANENT;
+ filter.flagmask |= IFA_F_PERMANENT;
+ } else if (strcmp(*argv, "permanent") == 0) {
+ filter.flags |= IFA_F_PERMANENT;
+ filter.flagmask |= IFA_F_PERMANENT;
+ } else if (strcmp(*argv, "secondary") == 0 ||
+ strcmp(*argv, "temporary") == 0) {
+ filter.flags |= IFA_F_SECONDARY;
+ filter.flagmask |= IFA_F_SECONDARY;
+ } else if (strcmp(*argv, "primary") == 0) {
+ filter.flags &= ~IFA_F_SECONDARY;
+ filter.flagmask |= IFA_F_SECONDARY;
+ } else if (strcmp(*argv, "tentative") == 0) {
+ filter.flags |= IFA_F_TENTATIVE;
+ filter.flagmask |= IFA_F_TENTATIVE;
+ } else if (strcmp(*argv, "deprecated") == 0) {
+ filter.flags |= IFA_F_DEPRECATED;
+ filter.flagmask |= IFA_F_DEPRECATED;
+ } else if (strcmp(*argv, "home") == 0) {
+ filter.flags |= IFA_F_HOMEADDRESS;
+ filter.flagmask |= IFA_F_HOMEADDRESS;
+ } else if (strcmp(*argv, "nodad") == 0) {
+ filter.flags |= IFA_F_NODAD;
+ filter.flagmask |= IFA_F_NODAD;
+ } else if (strcmp(*argv, "dadfailed") == 0) {
+ filter.flags |= IFA_F_DADFAILED;
+ filter.flagmask |= IFA_F_DADFAILED;
+ } else if (strcmp(*argv, "label") == 0) {
+ NEXT_ARG();
+ filter.label = *argv;
+ } else if (strcmp(*argv, "group") == 0) {
+ NEXT_ARG();
+ if (rtnl_group_a2n(&filter.group, *argv))
+ invarg("Invalid \"group\" value\n", *argv);
+ } else {
+ if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ }
+ if (matches(*argv, "help") == 0)
+ usage();
+ if (filter_dev)
+ duparg2("dev", *argv);
+ filter_dev = *argv;
+ }
+ argv++; argc--;
+ }
+
+ if (rtnl_wilddump_request(&rth, preferred_family, RTM_GETLINK) < 0) {
+ perror("Cannot send dump request");
+ exit(1);
+ }
+
+ if (rtnl_dump_filter(&rth, store_nlmsg, &linfo) < 0) {
+ fprintf(stderr, "Dump terminated\n");
+ exit(1);
+ }
+
+ if (filter_dev) {
+ filter.ifindex = ll_name_to_index(filter_dev);
+ if (filter.ifindex <= 0) {
+ fprintf(stderr, "Device \"%s\" does not exist.\n", filter_dev);
+ return -1;
+ }
+ }
+
+ if (flush) {
+ int round = 0;
+ char flushb[4096-512];
+
+ filter.flushb = flushb;
+ filter.flushp = 0;
+ filter.flushe = sizeof(flushb);
+
+ while ((max_flush_loops == 0) || (round < max_flush_loops)) {
+ const struct rtnl_dump_filter_arg a[3] = {
+ {
+ .filter = print_addrinfo_secondary,
+ .arg1 = stdout,
+ },
+ {
+ .filter = print_addrinfo_primary,
+ .arg1 = stdout,
+ },
+ {
+ .filter = NULL,
+ .arg1 = NULL,
+ },
+ };
+ if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) {
+ perror("Cannot send dump request");
+ exit(1);
+ }
+ filter.flushed = 0;
+ if (rtnl_dump_filter_l(&rth, a) < 0) {
+ fprintf(stderr, "Flush terminated\n");
+ exit(1);
+ }
+ if (filter.flushed == 0) {
+flush_done:
+ if (show_stats) {
+ if (round == 0)
+ printf("Nothing to flush.\n");
+ else
+ printf("*** Flush is complete after %d round%s ***\n", round, round>1?"s":"");
+ }
+ fflush(stdout);
+ return 0;
+ }
+ round++;
+ if (flush_update() < 0)
+ return 1;
+
+ if (show_stats) {
+ printf("\n*** Round %d, deleting %d addresses ***\n", round, filter.flushed);
+ fflush(stdout);
+ }
+
+ /* If we are flushing, and specifying primary, then we
+ * want to flush only a single round. Otherwise, we'll
+ * start flushing secondaries that were promoted to
+ * primaries.
+ */
+ if (!(filter.flags & IFA_F_SECONDARY) && (filter.flagmask & IFA_F_SECONDARY))
+ goto flush_done;
+ }
+ fprintf(stderr, "*** Flush remains incomplete after %d rounds. ***\n", max_flush_loops);
+ fflush(stderr);
+ return 1;
+ }
+
+ if (filter.family != AF_PACKET) {
+ if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) {
+ perror("Cannot send dump request");
+ exit(1);
+ }
+
+ if (rtnl_dump_filter(&rth, store_nlmsg, &ainfo) < 0) {
+ fprintf(stderr, "Dump terminated\n");
+ exit(1);
+ }
+ }
+
+
+ if (filter.family && filter.family != AF_PACKET) {
+ struct nlmsg_list **lp;
+ lp=&linfo;
+
+ if (filter.oneline)
+ no_link = 1;
+
+ while ((l=*lp)!=NULL) {
+ int ok = 0;
+ struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
+ struct nlmsg_list *a;
+
+ for (a=ainfo; a; a=a->next) {
+ struct nlmsghdr *n = &a->h;
+ struct ifaddrmsg *ifa = NLMSG_DATA(n);
+
+ if (ifa->ifa_index != ifi->ifi_index ||
+ (filter.family && filter.family != ifa->ifa_family))
+ continue;
+ if ((filter.scope^ifa->ifa_scope)&filter.scopemask)
+ continue;
+ if ((filter.flags^ifa->ifa_flags)&filter.flagmask)
+ continue;
+ if (filter.pfx.family || filter.label) {
+ struct rtattr *tb[IFA_MAX+1];
+ parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(n));
+ if (!tb[IFA_LOCAL])
+ tb[IFA_LOCAL] = tb[IFA_ADDRESS];
+
+ if (filter.pfx.family && tb[IFA_LOCAL]) {
+ inet_prefix dst;
+ memset(&dst, 0, sizeof(dst));
+ dst.family = ifa->ifa_family;
+ memcpy(&dst.data, RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_LOCAL]));
+ if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen))
+ continue;
+ }
+ if (filter.label) {
+ SPRINT_BUF(b1);
+ const char *label;
+ if (tb[IFA_LABEL])
+ label = RTA_DATA(tb[IFA_LABEL]);
+ else
+ label = ll_idx_n2a(ifa->ifa_index, b1);
+ if (fnmatch(filter.label, label, 0) != 0)
+ continue;
+ }
+ }
+
+ ok = 1;
+ break;
+ }
+ if (!ok)
+ *lp = l->next;
+ else
+ lp = &l->next;
+ }
+ }
+
+ for (l=linfo; l; l = n) {
+ n = l->next;
+ if (no_link || print_linkinfo(NULL, &l->h, stdout) == 0) {
+ struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
+ if (filter.family != AF_PACKET)
+ print_selected_addrinfo(ifi->ifi_index, ainfo, stdout);
+ }
+ fflush(stdout);
+ free(l);
+ }
+
+ return 0;
+}
+
+int ipaddr_list_link(int argc, char **argv)
+{
+ preferred_family = AF_PACKET;
+ do_link = 1;
+ return ipaddr_list_or_flush(argc, argv, 0);
+}
+
+void ipaddr_reset_filter(int oneline)
+{
+ memset(&filter, 0, sizeof(filter));
+ filter.oneline = oneline;
+}
+
+static int default_scope(inet_prefix *lcl)
+{
+ if (lcl->family == AF_INET) {
+ if (lcl->bytelen >= 1 && *(__u8*)&lcl->data == 127)
+ return RT_SCOPE_HOST;
+ }
+ return 0;
+}
+
+static int ipaddr_modify(int cmd, int flags, int argc, char **argv)
+{
+ struct {
+ struct nlmsghdr n;
+ struct ifaddrmsg ifa;
+ char buf[256];
+ } req;
+ char *d = NULL;
+ char *l = NULL;
+ char *lcl_arg = NULL;
+ char *valid_lftp = NULL;
+ char *preferred_lftp = NULL;
+ inet_prefix lcl;
+ inet_prefix peer;
+ int local_len = 0;
+ int peer_len = 0;
+ int brd_len = 0;
+ int any_len = 0;
+ int scoped = 0;
+ __u32 preferred_lft = INFINITY_LIFE_TIME;
+ __u32 valid_lft = INFINITY_LIFE_TIME;
+ struct ifa_cacheinfo cinfo;
+
+ memset(&req, 0, sizeof(req));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST | flags;
+ req.n.nlmsg_type = cmd;
+ req.ifa.ifa_family = preferred_family;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "peer") == 0 ||
+ strcmp(*argv, "remote") == 0) {
+ NEXT_ARG();
+
+ if (peer_len)
+ duparg("peer", *argv);
+ get_prefix(&peer, *argv, req.ifa.ifa_family);
+ peer_len = peer.bytelen;
+ if (req.ifa.ifa_family == AF_UNSPEC)
+ req.ifa.ifa_family = peer.family;
+ addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &peer.data, peer.bytelen);
+ req.ifa.ifa_prefixlen = peer.bitlen;
+ } else if (matches(*argv, "broadcast") == 0 ||
+ strcmp(*argv, "brd") == 0) {
+ inet_prefix addr;
+ NEXT_ARG();
+ if (brd_len)
+ duparg("broadcast", *argv);
+ if (strcmp(*argv, "+") == 0)
+ brd_len = -1;
+ else if (strcmp(*argv, "-") == 0)
+ brd_len = -2;
+ else {
+ get_addr(&addr, *argv, req.ifa.ifa_family);
+ if (req.ifa.ifa_family == AF_UNSPEC)
+ req.ifa.ifa_family = addr.family;
+ addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &addr.data, addr.bytelen);
+ brd_len = addr.bytelen;
+ }
+ } else if (strcmp(*argv, "anycast") == 0) {
+ inet_prefix addr;
+ NEXT_ARG();
+ if (any_len)
+ duparg("anycast", *argv);
+ get_addr(&addr, *argv, req.ifa.ifa_family);
+ if (req.ifa.ifa_family == AF_UNSPEC)
+ req.ifa.ifa_family = addr.family;
+ addattr_l(&req.n, sizeof(req), IFA_ANYCAST, &addr.data, addr.bytelen);
+ any_len = addr.bytelen;
+ } else if (strcmp(*argv, "scope") == 0) {
+ unsigned scope = 0;
+ NEXT_ARG();
+ if (rtnl_rtscope_a2n(&scope, *argv))
+ invarg(*argv, "invalid scope value.");
+ req.ifa.ifa_scope = scope;
+ scoped = 1;
+ } else if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ d = *argv;
+ } else if (strcmp(*argv, "label") == 0) {
+ NEXT_ARG();
+ l = *argv;
+ addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1);
+ } else if (matches(*argv, "valid_lft") == 0) {
+ if (valid_lftp)
+ duparg("valid_lft", *argv);
+ NEXT_ARG();
+ valid_lftp = *argv;
+ if (set_lifetime(&valid_lft, *argv))
+ invarg("valid_lft value", *argv);
+ } else if (matches(*argv, "preferred_lft") == 0) {
+ if (preferred_lftp)
+ duparg("preferred_lft", *argv);
+ NEXT_ARG();
+ preferred_lftp = *argv;
+ if (set_lifetime(&preferred_lft, *argv))
+ invarg("preferred_lft value", *argv);
+ } else if (strcmp(*argv, "home") == 0) {
+ req.ifa.ifa_flags |= IFA_F_HOMEADDRESS;
+ } else if (strcmp(*argv, "nodad") == 0) {
+ req.ifa.ifa_flags |= IFA_F_NODAD;
+ } else {
+ if (strcmp(*argv, "local") == 0) {
+ NEXT_ARG();
+ }
+ if (matches(*argv, "help") == 0)
+ usage();
+ if (local_len)
+ duparg2("local", *argv);
+ lcl_arg = *argv;
+ get_prefix(&lcl, *argv, req.ifa.ifa_family);
+ if (req.ifa.ifa_family == AF_UNSPEC)
+ req.ifa.ifa_family = lcl.family;
+ addattr_l(&req.n, sizeof(req), IFA_LOCAL, &lcl.data, lcl.bytelen);
+ local_len = lcl.bytelen;
+ }
+ argc--; argv++;
+ }
+ if (d == NULL) {
+ fprintf(stderr, "Not enough information: \"dev\" argument is required.\n");
+ return -1;
+ }
+ if (l && matches(d, l) != 0) {
+ fprintf(stderr, "\"dev\" (%s) must match \"label\" (%s).\n", d, l);
+ return -1;
+ }
+
+ if (peer_len == 0 && local_len) {
+ if (cmd == RTM_DELADDR && lcl.family == AF_INET && !(lcl.flags & PREFIXLEN_SPECIFIED)) {
+ fprintf(stderr,
+ "Warning: Executing wildcard deletion to stay compatible with old scripts.\n" \
+ " Explicitly specify the prefix length (%s/%d) to avoid this warning.\n" \
+ " This special behaviour is likely to disappear in further releases,\n" \
+ " fix your scripts!\n", lcl_arg, local_len*8);
+ } else {
+ peer = lcl;
+ addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &lcl.data, lcl.bytelen);
+ }
+ }
+ if (req.ifa.ifa_prefixlen == 0)
+ req.ifa.ifa_prefixlen = lcl.bitlen;
+
+ if (brd_len < 0 && cmd != RTM_DELADDR) {
+ inet_prefix brd;
+ int i;
+ if (req.ifa.ifa_family != AF_INET) {
+ fprintf(stderr, "Broadcast can be set only for IPv4 addresses\n");
+ return -1;
+ }
+ brd = peer;
+ if (brd.bitlen <= 30) {
+ for (i=31; i>=brd.bitlen; i--) {
+ if (brd_len == -1)
+ brd.data[0] |= htonl(1<<(31-i));
+ else
+ brd.data[0] &= ~htonl(1<<(31-i));
+ }
+ addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &brd.data, brd.bytelen);
+ brd_len = brd.bytelen;
+ }
+ }
+ if (!scoped && cmd != RTM_DELADDR)
+ req.ifa.ifa_scope = default_scope(&lcl);
+
+ ll_init_map(&rth);
+
+ if ((req.ifa.ifa_index = ll_name_to_index(d)) == 0) {
+ fprintf(stderr, "Cannot find device \"%s\"\n", d);
+ return -1;
+ }
+
+ if (valid_lftp || preferred_lftp) {
+ if (!valid_lft) {
+ fprintf(stderr, "valid_lft is zero\n");
+ return -1;
+ }
+ if (valid_lft < preferred_lft) {
+ fprintf(stderr, "preferred_lft is greater than valid_lft\n");
+ return -1;
+ }
+
+ memset(&cinfo, 0, sizeof(cinfo));
+ cinfo.ifa_prefered = preferred_lft;
+ cinfo.ifa_valid = valid_lft;
+ addattr_l(&req.n, sizeof(req), IFA_CACHEINFO, &cinfo,
+ sizeof(cinfo));
+ }
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ return -2;
+
+ return 0;
+}
+
+int do_ipaddr(int argc, char **argv)
+{
+ if (argc < 1)
+ return ipaddr_list_or_flush(0, NULL, 0);
+ if (matches(*argv, "add") == 0)
+ return ipaddr_modify(RTM_NEWADDR, NLM_F_CREATE|NLM_F_EXCL, argc-1, argv+1);
+ if (matches(*argv, "change") == 0 ||
+ strcmp(*argv, "chg") == 0)
+ return ipaddr_modify(RTM_NEWADDR, NLM_F_REPLACE, argc-1, argv+1);
+ if (matches(*argv, "replace") == 0)
+ return ipaddr_modify(RTM_NEWADDR, NLM_F_CREATE|NLM_F_REPLACE, argc-1, argv+1);
+ if (matches(*argv, "delete") == 0)
+ return ipaddr_modify(RTM_DELADDR, 0, argc-1, argv+1);
+ if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
+ || matches(*argv, "lst") == 0)
+ return ipaddr_list_or_flush(argc-1, argv+1, 0);
+ if (matches(*argv, "flush") == 0)
+ return ipaddr_list_or_flush(argc-1, argv+1, 1);
+ if (matches(*argv, "help") == 0)
+ usage();
+ fprintf(stderr, "Command \"%s\" is unknown, try \"ip addr help\".\n", *argv);
+ exit(-1);
+}
+
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/ipaddrlabel.c b/ap/app/iproute2/iproute2-3.4.0/ip/ipaddrlabel.c
new file mode 100755
index 0000000..eb6a48c
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/ipaddrlabel.c
@@ -0,0 +1,268 @@
+/*
+ * ipaddrlabel.c "ip addrlabel"
+ *
+ * Copyright (C)2007 USAGI/WIDE Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ * Based on iprule.c.
+ *
+ * Authors: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <linux/types.h>
+#include <linux/if_addrlabel.h>
+
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+
+#define IFAL_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrlblmsg))))
+#define IFAL_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrlblmsg))
+
+extern struct rtnl_handle rth;
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: ip addrlabel [ list | add | del | flush ] prefix PREFIX [ dev DEV ] [ label LABEL ]\n");
+ exit(-1);
+}
+
+int print_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+{
+ FILE *fp = (FILE*)arg;
+ struct ifaddrlblmsg *ifal = NLMSG_DATA(n);
+ int len = n->nlmsg_len;
+ struct rtattr *tb[IFAL_MAX+1];
+ char abuf[256];
+
+ if (n->nlmsg_type != RTM_NEWADDRLABEL && n->nlmsg_type != RTM_DELADDRLABEL)
+ return 0;
+
+ len -= NLMSG_LENGTH(sizeof(*ifal));
+ if (len < 0)
+ return -1;
+
+ parse_rtattr(tb, IFAL_MAX, IFAL_RTA(ifal), len);
+
+ if (n->nlmsg_type == RTM_DELADDRLABEL)
+ fprintf(fp, "Deleted ");
+
+ if (tb[IFAL_ADDRESS]) {
+ fprintf(fp, "prefix %s/%u ",
+ format_host(ifal->ifal_family,
+ RTA_PAYLOAD(tb[IFAL_ADDRESS]),
+ RTA_DATA(tb[IFAL_ADDRESS]),
+ abuf, sizeof(abuf)),
+ ifal->ifal_prefixlen);
+ }
+
+ if (ifal->ifal_index)
+ fprintf(fp, "dev %s ", ll_index_to_name(ifal->ifal_index));
+
+ if (tb[IFAL_LABEL] && RTA_PAYLOAD(tb[IFAL_LABEL]) == sizeof(int32_t)) {
+ int32_t label;
+ memcpy(&label, RTA_DATA(tb[IFAL_LABEL]), sizeof(label));
+ fprintf(fp, "label %d ", label);
+ }
+
+ fprintf(fp, "\n");
+ fflush(fp);
+ return 0;
+}
+
+static int ipaddrlabel_list(int argc, char **argv)
+{
+ int af = preferred_family;
+
+ if (af == AF_UNSPEC)
+ af = AF_INET6;
+
+ if (argc > 0) {
+ fprintf(stderr, "\"ip addrlabel show\" does not take any arguments.\n");
+ return -1;
+ }
+
+ if (rtnl_wilddump_request(&rth, af, RTM_GETADDRLABEL) < 0) {
+ perror("Cannot send dump request");
+ return 1;
+ }
+
+ if (rtnl_dump_filter(&rth, print_addrlabel, stdout) < 0) {
+ fprintf(stderr, "Dump terminated\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int ipaddrlabel_modify(int cmd, int argc, char **argv)
+{
+ struct {
+ struct nlmsghdr n;
+ struct ifaddrlblmsg ifal;
+ char buf[1024];
+ } req;
+
+ inet_prefix prefix;
+ uint32_t label = 0xffffffffUL;
+ char *p = NULL;
+ char *l = NULL;
+
+ memset(&req, 0, sizeof(req));
+ memset(&prefix, 0, sizeof(prefix));
+
+ req.n.nlmsg_type = cmd;
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrlblmsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.ifal.ifal_family = preferred_family;
+ req.ifal.ifal_prefixlen = 0;
+ req.ifal.ifal_index = 0;
+
+ if (cmd == RTM_NEWADDRLABEL) {
+ req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
+ }
+
+ while (argc > 0) {
+ if (strcmp(*argv, "prefix") == 0) {
+ NEXT_ARG();
+ p = *argv;
+ get_prefix(&prefix, *argv, preferred_family);
+ } else if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ if ((req.ifal.ifal_index = ll_name_to_index(*argv)) == 0)
+ invarg("dev is invalid\n", *argv);
+ } else if (strcmp(*argv, "label") == 0) {
+ NEXT_ARG();
+ l = *argv;
+ if (get_u32(&label, *argv, 0) || label == 0xffffffffUL)
+ invarg("label is invalid\n", *argv);
+ }
+ argc--;
+ argv++;
+ }
+ if (p == NULL) {
+ fprintf(stderr, "Not enough information: \"prefix\" argument is required.\n");
+ return -1;
+ }
+ if (l == NULL) {
+ fprintf(stderr, "Not enough information: \"label\" argument is required.\n");
+ return -1;
+ }
+ addattr32(&req.n, sizeof(req), IFAL_LABEL, label);
+ addattr_l(&req.n, sizeof(req), IFAL_ADDRESS, &prefix.data, prefix.bytelen);
+ req.ifal.ifal_prefixlen = prefix.bitlen;
+
+ if (req.ifal.ifal_family == AF_UNSPEC)
+ req.ifal.ifal_family = AF_INET6;
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ return 2;
+
+ return 0;
+}
+
+
+static int flush_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+{
+ struct rtnl_handle rth2;
+ struct rtmsg *r = NLMSG_DATA(n);
+ int len = n->nlmsg_len;
+ struct rtattr * tb[IFAL_MAX+1];
+
+ len -= NLMSG_LENGTH(sizeof(*r));
+ if (len < 0)
+ return -1;
+
+ parse_rtattr(tb, IFAL_MAX, RTM_RTA(r), len);
+
+ if (tb[IFAL_ADDRESS]) {
+ n->nlmsg_type = RTM_DELADDRLABEL;
+ n->nlmsg_flags = NLM_F_REQUEST;
+
+ if (rtnl_open(&rth2, 0) < 0)
+ return -1;
+
+ if (rtnl_talk(&rth2, n, 0, 0, NULL) < 0)
+ return -2;
+
+ rtnl_close(&rth2);
+ }
+
+ return 0;
+}
+
+static int ipaddrlabel_flush(int argc, char **argv)
+{
+ int af = preferred_family;
+
+ if (af == AF_UNSPEC)
+ af = AF_INET6;
+
+ if (argc > 0) {
+ fprintf(stderr, "\"ip addrlabel flush\" does not allow extra arguments\n");
+ return -1;
+ }
+
+ if (rtnl_wilddump_request(&rth, af, RTM_GETADDRLABEL) < 0) {
+ perror("Cannot send dump request");
+ return 1;
+ }
+
+ if (rtnl_dump_filter(&rth, flush_addrlabel, NULL) < 0) {
+ fprintf(stderr, "Flush terminated\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+int do_ipaddrlabel(int argc, char **argv)
+{
+ ll_init_map(&rth);
+
+ if (argc < 1) {
+ return ipaddrlabel_list(0, NULL);
+ } else if (matches(argv[0], "list") == 0 ||
+ matches(argv[0], "show") == 0) {
+ return ipaddrlabel_list(argc-1, argv+1);
+ } else if (matches(argv[0], "add") == 0) {
+ return ipaddrlabel_modify(RTM_NEWADDRLABEL, argc-1, argv+1);
+ } else if (matches(argv[0], "delete") == 0) {
+ return ipaddrlabel_modify(RTM_DELADDRLABEL, argc-1, argv+1);
+ } else if (matches(argv[0], "flush") == 0) {
+ return ipaddrlabel_flush(argc-1, argv+1);
+ } else if (matches(argv[0], "help") == 0)
+ usage();
+
+ fprintf(stderr, "Command \"%s\" is unknown, try \"ip addrlabel help\".\n", *argv);
+ exit(-1);
+}
+
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/ipl2tp.c b/ap/app/iproute2/iproute2-3.4.0/ip/ipl2tp.c
new file mode 100755
index 0000000..c5683f5
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/ipl2tp.c
@@ -0,0 +1,809 @@
+/*
+ * ipl2tp.c "ip l2tp"
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Original Author: James Chapman <jchapman@katalix.com>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/ip.h>
+
+#include <linux/genetlink.h>
+#include <linux/l2tp.h>
+
+#include "utils.h"
+#include "ip_common.h"
+
+enum {
+ L2TP_ADD,
+ L2TP_CHG,
+ L2TP_DEL,
+ L2TP_GET
+};
+
+struct l2tp_parm {
+ uint32_t tunnel_id;
+ uint32_t peer_tunnel_id;
+ uint32_t session_id;
+ uint32_t peer_session_id;
+ uint32_t offset;
+ uint32_t peer_offset;
+ enum l2tp_encap_type encap;
+ uint16_t local_udp_port;
+ uint16_t peer_udp_port;
+ int cookie_len;
+ uint8_t cookie[8];
+ int peer_cookie_len;
+ uint8_t peer_cookie[8];
+ struct in_addr local_ip;
+ struct in_addr peer_ip;
+
+ uint16_t pw_type;
+ uint16_t mtu;
+ int udp_csum:1;
+ int recv_seq:1;
+ int send_seq:1;
+ int lns_mode:1;
+ int data_seq:2;
+ int tunnel:1;
+ int session:1;
+ int reorder_timeout;
+ const char *ifname;
+};
+
+struct l2tp_stats {
+ uint64_t data_rx_packets;
+ uint64_t data_rx_bytes;
+ uint64_t data_rx_errors;
+ uint64_t data_rx_oos_packets;
+ uint64_t data_rx_oos_discards;
+ uint64_t data_tx_packets;
+ uint64_t data_tx_bytes;
+ uint64_t data_tx_errors;
+};
+
+struct l2tp_data {
+ struct l2tp_parm config;
+ struct l2tp_stats stats;
+};
+
+/* netlink socket */
+static struct rtnl_handle genl_rth;
+static int genl_family = -1;
+
+/*****************************************************************************
+ * Netlink actions
+ *****************************************************************************/
+
+static int create_tunnel(struct l2tp_parm *p)
+{
+ struct {
+ struct nlmsghdr n;
+ struct genlmsghdr g;
+ char buf[1024];
+ } req;
+
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_type = genl_family;
+ req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+ req.g.cmd = L2TP_CMD_TUNNEL_CREATE;
+ req.g.version = L2TP_GENL_VERSION;
+
+ addattr32(&req.n, 1024, L2TP_ATTR_CONN_ID, p->tunnel_id);
+ addattr32(&req.n, 1024, L2TP_ATTR_PEER_CONN_ID, p->peer_tunnel_id);
+ addattr8(&req.n, 1024, L2TP_ATTR_PROTO_VERSION, 3);
+ addattr16(&req.n, 1024, L2TP_ATTR_ENCAP_TYPE, p->encap);
+
+ addattr32(&req.n, 1024, L2TP_ATTR_IP_SADDR, p->local_ip.s_addr);
+ addattr32(&req.n, 1024, L2TP_ATTR_IP_DADDR, p->peer_ip.s_addr);
+ if (p->encap == L2TP_ENCAPTYPE_UDP) {
+ addattr16(&req.n, 1024, L2TP_ATTR_UDP_SPORT, p->local_udp_port);
+ addattr16(&req.n, 1024, L2TP_ATTR_UDP_DPORT, p->peer_udp_port);
+ }
+
+ if (rtnl_talk(&genl_rth, &req.n, 0, 0, NULL) < 0)
+ return -2;
+
+ return 0;
+}
+
+static int delete_tunnel(struct l2tp_parm *p)
+{
+ struct {
+ struct nlmsghdr n;
+ struct genlmsghdr g;
+ char buf[128];
+ } req;
+
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_type = genl_family;
+ req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+ req.g.cmd = L2TP_CMD_TUNNEL_DELETE;
+ req.g.version = L2TP_GENL_VERSION;
+
+ addattr32(&req.n, 128, L2TP_ATTR_CONN_ID, p->tunnel_id);
+
+ if (rtnl_talk(&genl_rth, &req.n, 0, 0, NULL) < 0)
+ return -2;
+
+ return 0;
+}
+
+static int create_session(struct l2tp_parm *p)
+{
+ struct {
+ struct nlmsghdr n;
+ struct genlmsghdr g;
+ char buf[1024];
+ } req;
+
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_type = genl_family;
+ req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+ req.g.cmd = L2TP_CMD_SESSION_CREATE;
+ req.g.version = L2TP_GENL_VERSION;
+
+ addattr32(&req.n, 1024, L2TP_ATTR_CONN_ID, p->tunnel_id);
+ addattr32(&req.n, 1024, L2TP_ATTR_PEER_CONN_ID, p->peer_tunnel_id);
+ addattr32(&req.n, 1024, L2TP_ATTR_SESSION_ID, p->session_id);
+ addattr32(&req.n, 1024, L2TP_ATTR_PEER_SESSION_ID, p->peer_session_id);
+ addattr16(&req.n, 1024, L2TP_ATTR_PW_TYPE, p->pw_type);
+
+ if (p->mtu) addattr16(&req.n, 1024, L2TP_ATTR_MTU, p->mtu);
+ if (p->recv_seq) addattr(&req.n, 1024, L2TP_ATTR_RECV_SEQ);
+ if (p->send_seq) addattr(&req.n, 1024, L2TP_ATTR_SEND_SEQ);
+ if (p->lns_mode) addattr(&req.n, 1024, L2TP_ATTR_LNS_MODE);
+ if (p->data_seq) addattr8(&req.n, 1024, L2TP_ATTR_DATA_SEQ, p->data_seq);
+ if (p->reorder_timeout) addattr64(&req.n, 1024, L2TP_ATTR_RECV_TIMEOUT,
+ p->reorder_timeout);
+ if (p->offset) addattr16(&req.n, 1024, L2TP_ATTR_OFFSET, p->offset);
+ if (p->cookie_len) addattr_l(&req.n, 1024, L2TP_ATTR_COOKIE,
+ p->cookie, p->cookie_len);
+ if (p->peer_cookie_len) addattr_l(&req.n, 1024, L2TP_ATTR_PEER_COOKIE,
+ p->peer_cookie, p->peer_cookie_len);
+ if (p->ifname && p->ifname[0])
+ addattrstrz(&req.n, 1024, L2TP_ATTR_IFNAME, p->ifname);
+
+ if (rtnl_talk(&genl_rth, &req.n, 0, 0, NULL) < 0)
+ return -2;
+
+ return 0;
+}
+
+static int delete_session(struct l2tp_parm *p)
+{
+ struct {
+ struct nlmsghdr n;
+ struct genlmsghdr g;
+ char buf[128];
+ } req;
+
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_type = genl_family;
+ req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+ req.g.cmd = L2TP_CMD_SESSION_DELETE;
+ req.g.version = L2TP_GENL_VERSION;
+
+ addattr32(&req.n, 1024, L2TP_ATTR_CONN_ID, p->tunnel_id);
+ addattr32(&req.n, 1024, L2TP_ATTR_SESSION_ID, p->session_id);
+ if (rtnl_talk(&genl_rth, &req.n, 0, 0, NULL) < 0)
+ return -2;
+
+ return 0;
+}
+
+static void print_cookie(char *name, const uint8_t *cookie, int len)
+{
+ printf(" %s %02x%02x%02x%02x", name,
+ cookie[0], cookie[1],
+ cookie[2], cookie[3]);
+ if (len == 8)
+ printf("%02x%02x%02x%02x",
+ cookie[4], cookie[5],
+ cookie[6], cookie[7]);
+}
+
+static void print_tunnel(const struct l2tp_data *data)
+{
+ const struct l2tp_parm *p = &data->config;
+
+ printf("Tunnel %u, encap %s\n",
+ p->tunnel_id,
+ p->encap == L2TP_ENCAPTYPE_UDP ? "UDP" :
+ p->encap == L2TP_ENCAPTYPE_IP ? "IP" : "??");
+ printf(" From %s ", inet_ntoa(p->local_ip));
+ printf("to %s\n", inet_ntoa(p->peer_ip));
+ printf(" Peer tunnel %u\n",
+ p->peer_tunnel_id);
+
+ if (p->encap == L2TP_ENCAPTYPE_UDP)
+ printf(" UDP source / dest ports: %hu/%hu\n",
+ p->local_udp_port, p->peer_udp_port);
+}
+
+static void print_session(struct l2tp_data *data)
+{
+ struct l2tp_parm *p = &data->config;
+
+ printf("Session %u in tunnel %u\n",
+ p->session_id, p->tunnel_id);
+ printf(" Peer session %u, tunnel %u\n",
+ p->peer_session_id, p->peer_tunnel_id);
+
+ if (p->ifname != NULL) {
+ printf(" interface name: %s\n", p->ifname);
+ }
+ printf(" offset %u, peer offset %u\n",
+ p->offset, p->peer_offset);
+ if (p->cookie_len > 0)
+ print_cookie("cookie", p->cookie, p->cookie_len);
+ if (p->peer_cookie_len > 0)
+ print_cookie("peer cookie", p->peer_cookie, p->peer_cookie_len);
+
+ if (p->reorder_timeout != 0) {
+ printf(" reorder timeout: %u\n", p->reorder_timeout);
+ }
+}
+
+static int get_response(struct nlmsghdr *n, void *arg)
+{
+ struct genlmsghdr *ghdr;
+ struct l2tp_data *data = arg;
+ struct l2tp_parm *p = &data->config;
+ struct rtattr *attrs[L2TP_ATTR_MAX + 1];
+ struct rtattr *nla_stats;
+ int len;
+
+ /* Validate message and parse attributes */
+ if (n->nlmsg_type == NLMSG_ERROR)
+ return -EBADMSG;
+
+ ghdr = NLMSG_DATA(n);
+ len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*ghdr));
+ if (len < 0)
+ return -1;
+
+ parse_rtattr(attrs, L2TP_ATTR_MAX, (void *)ghdr + GENL_HDRLEN, len);
+
+ if (attrs[L2TP_ATTR_PW_TYPE])
+ p->pw_type = rta_getattr_u16(attrs[L2TP_ATTR_PW_TYPE]);
+ if (attrs[L2TP_ATTR_ENCAP_TYPE])
+ p->encap = rta_getattr_u16(attrs[L2TP_ATTR_ENCAP_TYPE]);
+ if (attrs[L2TP_ATTR_OFFSET])
+ p->offset = rta_getattr_u16(attrs[L2TP_ATTR_OFFSET]);
+ if (attrs[L2TP_ATTR_DATA_SEQ])
+ p->data_seq = rta_getattr_u16(attrs[L2TP_ATTR_DATA_SEQ]);
+ if (attrs[L2TP_ATTR_CONN_ID])
+ p->tunnel_id = rta_getattr_u32(attrs[L2TP_ATTR_CONN_ID]);
+ if (attrs[L2TP_ATTR_PEER_CONN_ID])
+ p->peer_tunnel_id = rta_getattr_u32(attrs[L2TP_ATTR_PEER_CONN_ID]);
+ if (attrs[L2TP_ATTR_SESSION_ID])
+ p->session_id = rta_getattr_u32(attrs[L2TP_ATTR_SESSION_ID]);
+ if (attrs[L2TP_ATTR_PEER_SESSION_ID])
+ p->peer_session_id = rta_getattr_u32(attrs[L2TP_ATTR_PEER_SESSION_ID]);
+
+ p->udp_csum = !!attrs[L2TP_ATTR_UDP_CSUM];
+ if (attrs[L2TP_ATTR_COOKIE])
+ memcpy(p->cookie, RTA_DATA(attrs[L2TP_ATTR_COOKIE]),
+ p->cookie_len = RTA_PAYLOAD(attrs[L2TP_ATTR_COOKIE]));
+
+ if (attrs[L2TP_ATTR_PEER_COOKIE])
+ memcpy(p->peer_cookie, RTA_DATA(attrs[L2TP_ATTR_PEER_COOKIE]),
+ p->peer_cookie_len = RTA_PAYLOAD(attrs[L2TP_ATTR_PEER_COOKIE]));
+
+ p->recv_seq = !!attrs[L2TP_ATTR_RECV_SEQ];
+ p->send_seq = !!attrs[L2TP_ATTR_SEND_SEQ];
+
+ if (attrs[L2TP_ATTR_RECV_TIMEOUT])
+ p->reorder_timeout = rta_getattr_u64(attrs[L2TP_ATTR_RECV_TIMEOUT]);
+ if (attrs[L2TP_ATTR_IP_SADDR])
+ p->local_ip.s_addr = rta_getattr_u32(attrs[L2TP_ATTR_IP_SADDR]);
+ if (attrs[L2TP_ATTR_IP_DADDR])
+ p->peer_ip.s_addr = rta_getattr_u32(attrs[L2TP_ATTR_IP_DADDR]);
+ if (attrs[L2TP_ATTR_UDP_SPORT])
+ p->local_udp_port = rta_getattr_u16(attrs[L2TP_ATTR_UDP_SPORT]);
+ if (attrs[L2TP_ATTR_UDP_DPORT])
+ p->peer_udp_port = rta_getattr_u16(attrs[L2TP_ATTR_UDP_DPORT]);
+ if (attrs[L2TP_ATTR_MTU])
+ p->mtu = rta_getattr_u16(attrs[L2TP_ATTR_MTU]);
+ if (attrs[L2TP_ATTR_IFNAME])
+ p->ifname = rta_getattr_str(attrs[L2TP_ATTR_IFNAME]);
+
+ nla_stats = attrs[L2TP_ATTR_STATS];
+ if (nla_stats) {
+ struct rtattr *tb[L2TP_ATTR_STATS_MAX + 1];
+
+ parse_rtattr_nested(tb, L2TP_ATTR_STATS_MAX, nla_stats);
+
+ if (tb[L2TP_ATTR_TX_PACKETS])
+ data->stats.data_tx_packets = rta_getattr_u64(tb[L2TP_ATTR_TX_PACKETS]);
+ if (tb[L2TP_ATTR_TX_BYTES])
+ data->stats.data_tx_bytes = rta_getattr_u64(tb[L2TP_ATTR_TX_BYTES]);
+ if (tb[L2TP_ATTR_TX_ERRORS])
+ data->stats.data_tx_errors = rta_getattr_u64(tb[L2TP_ATTR_TX_ERRORS]);
+ if (tb[L2TP_ATTR_RX_PACKETS])
+ data->stats.data_rx_packets = rta_getattr_u64(tb[L2TP_ATTR_RX_PACKETS]);
+ if (tb[L2TP_ATTR_RX_BYTES])
+ data->stats.data_rx_bytes = rta_getattr_u64(tb[L2TP_ATTR_RX_BYTES]);
+ if (tb[L2TP_ATTR_RX_ERRORS])
+ data->stats.data_rx_errors = rta_getattr_u64(tb[L2TP_ATTR_RX_ERRORS]);
+ if (tb[L2TP_ATTR_RX_SEQ_DISCARDS])
+ data->stats.data_rx_oos_discards = rta_getattr_u64(tb[L2TP_ATTR_RX_SEQ_DISCARDS]);
+ if (tb[L2TP_ATTR_RX_OOS_PACKETS])
+ data->stats.data_rx_oos_packets = rta_getattr_u64(tb[L2TP_ATTR_RX_OOS_PACKETS]);
+ }
+
+ return 0;
+}
+
+static int session_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+{
+ int ret = get_response(n, arg);
+
+ if (ret == 0)
+ print_session(arg);
+
+ return ret;
+}
+
+static int get_session(struct l2tp_data *p)
+{
+ struct {
+ struct nlmsghdr n;
+ struct genlmsghdr g;
+ char buf[128];
+ } req;
+
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+ req.n.nlmsg_type = genl_family;
+ req.n.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
+ req.n.nlmsg_seq = genl_rth.dump = ++genl_rth.seq;
+
+ req.g.cmd = L2TP_CMD_SESSION_GET;
+ req.g.version = L2TP_GENL_VERSION;
+
+ if (p->config.tunnel_id && p->config.session_id) {
+ addattr32(&req.n, 128, L2TP_ATTR_CONN_ID, p->config.tunnel_id);
+ addattr32(&req.n, 128, L2TP_ATTR_SESSION_ID, p->config.session_id);
+ }
+
+ if (rtnl_send(&genl_rth, &req, req.n.nlmsg_len) < 0)
+ return -2;
+
+ if (rtnl_dump_filter(&genl_rth, session_nlmsg, p) < 0) {
+ fprintf(stderr, "Dump terminated\n");
+ exit(1);
+ }
+
+ return 0;
+}
+
+static int tunnel_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+{
+ int ret = get_response(n, arg);
+
+ if (ret == 0)
+ print_tunnel(arg);
+
+ return ret;
+}
+
+static int get_tunnel(struct l2tp_data *p)
+{
+ struct {
+ struct nlmsghdr n;
+ struct genlmsghdr g;
+ char buf[1024];
+ } req;
+
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+ req.n.nlmsg_type = genl_family;
+ req.n.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
+ req.n.nlmsg_seq = genl_rth.dump = ++genl_rth.seq;
+
+ req.g.cmd = L2TP_CMD_TUNNEL_GET;
+ req.g.version = L2TP_GENL_VERSION;
+
+ if (p->config.tunnel_id)
+ addattr32(&req.n, 1024, L2TP_ATTR_CONN_ID, p->config.tunnel_id);
+
+ if (rtnl_send(&genl_rth, &req, req.n.nlmsg_len) < 0)
+ return -2;
+
+ if (rtnl_dump_filter(&genl_rth, tunnel_nlmsg, p) < 0) {
+ fprintf(stderr, "Dump terminated\n");
+ exit(1);
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+ * Command parser
+ *****************************************************************************/
+
+static int hex(char ch)
+{
+ if ((ch >= 'a') && (ch <= 'f'))
+ return ch - 'a' + 10;
+ if ((ch >= '0') && (ch <= '9'))
+ return ch - '0';
+ if ((ch >= 'A') && (ch <= 'F'))
+ return ch - 'A' + 10;
+ return -1;
+}
+
+static int hex2mem(const char *buf, uint8_t *mem, int count)
+{
+ int i, j;
+ int c;
+
+ for (i = 0, j = 0; i < count; i++, j += 2) {
+ c = hex(buf[j]);
+ if (c < 0)
+ goto err;
+
+ mem[i] = c << 4;
+
+ c = hex(buf[j + 1]);
+ if (c < 0)
+ goto err;
+
+ mem[i] |= c;
+ }
+
+ return 0;
+
+err:
+ return -1;
+}
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: ip l2tp add tunnel\n");
+ fprintf(stderr, " remote ADDR local ADDR\n");
+ fprintf(stderr, " tunnel_id ID peer_tunnel_id ID\n");
+ fprintf(stderr, " [ encap { ip | udp } ]\n");
+ fprintf(stderr, " [ udp_sport PORT ] [ udp_dport PORT ]\n");
+ fprintf(stderr, "Usage: ip l2tp add session [ name NAME ]\n");
+ fprintf(stderr, " tunnel_id ID\n");
+ fprintf(stderr, " session_id ID peer_session_id ID\n");
+ fprintf(stderr, " [ cookie HEXSTR ] [ peer_cookie HEXSTR ]\n");
+ fprintf(stderr, " [ offset OFFSET ] [ peer_offset OFFSET ]\n");
+ fprintf(stderr, " ip l2tp del tunnel tunnel_id ID\n");
+ fprintf(stderr, " ip l2tp del session tunnel_id ID session_id ID\n");
+ fprintf(stderr, " ip l2tp show tunnel [ tunnel_id ID ]\n");
+ fprintf(stderr, " ip l2tp show session [ tunnel_id ID ] [ session_id ID ]\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Where: NAME := STRING\n");
+ fprintf(stderr, " ADDR := { IP_ADDRESS | any }\n");
+ fprintf(stderr, " PORT := { 0..65535 }\n");
+ fprintf(stderr, " ID := { 1..4294967295 }\n");
+ fprintf(stderr, " HEXSTR := { 8 or 16 hex digits (4 / 8 bytes) }\n");
+ exit(-1);
+}
+
+static int parse_args(int argc, char **argv, int cmd, struct l2tp_parm *p)
+{
+ memset(p, 0, sizeof(*p));
+
+ if (argc == 0)
+ usage();
+
+ while (argc > 0) {
+ if (strcmp(*argv, "encap") == 0) {
+ NEXT_ARG();
+ if (strcmp(*argv, "ip") == 0) {
+ p->encap = L2TP_ENCAPTYPE_IP;
+ } else if (strcmp(*argv, "udp") == 0) {
+ p->encap = L2TP_ENCAPTYPE_UDP;
+ } else {
+ fprintf(stderr, "Unknown tunnel encapsulation.\n");
+ exit(-1);
+ }
+ } else if (strcmp(*argv, "name") == 0) {
+ NEXT_ARG();
+ p->ifname = *argv;
+ } else if (strcmp(*argv, "remote") == 0) {
+ NEXT_ARG();
+ p->peer_ip.s_addr = get_addr32(*argv);
+ } else if (strcmp(*argv, "local") == 0) {
+ NEXT_ARG();
+ p->local_ip.s_addr = get_addr32(*argv);
+ } else if ((strcmp(*argv, "tunnel_id") == 0) ||
+ (strcmp(*argv, "tid") == 0)) {
+ __u32 uval;
+ NEXT_ARG();
+ if (get_u32(&uval, *argv, 0))
+ invarg("invalid ID\n", *argv);
+ p->tunnel_id = uval;
+ } else if ((strcmp(*argv, "peer_tunnel_id") == 0) ||
+ (strcmp(*argv, "ptid") == 0)) {
+ __u32 uval;
+ NEXT_ARG();
+ if (get_u32(&uval, *argv, 0))
+ invarg("invalid ID\n", *argv);
+ p->peer_tunnel_id = uval;
+ } else if ((strcmp(*argv, "session_id") == 0) ||
+ (strcmp(*argv, "sid") == 0)) {
+ __u32 uval;
+ NEXT_ARG();
+ if (get_u32(&uval, *argv, 0))
+ invarg("invalid ID\n", *argv);
+ p->session_id = uval;
+ } else if ((strcmp(*argv, "peer_session_id") == 0) ||
+ (strcmp(*argv, "psid") == 0)) {
+ __u32 uval;
+ NEXT_ARG();
+ if (get_u32(&uval, *argv, 0))
+ invarg("invalid ID\n", *argv);
+ p->peer_session_id = uval;
+ } else if (strcmp(*argv, "udp_sport") == 0) {
+ __u16 uval;
+ NEXT_ARG();
+ if (get_u16(&uval, *argv, 0))
+ invarg("invalid port\n", *argv);
+ p->local_udp_port = uval;
+ } else if (strcmp(*argv, "udp_dport") == 0) {
+ __u16 uval;
+ NEXT_ARG();
+ if (get_u16(&uval, *argv, 0))
+ invarg("invalid port\n", *argv);
+ p->peer_udp_port = uval;
+ } else if (strcmp(*argv, "offset") == 0) {
+ __u8 uval;
+ NEXT_ARG();
+ if (get_u8(&uval, *argv, 0))
+ invarg("invalid offset\n", *argv);
+ p->offset = uval;
+ } else if (strcmp(*argv, "peer_offset") == 0) {
+ __u8 uval;
+ NEXT_ARG();
+ if (get_u8(&uval, *argv, 0))
+ invarg("invalid offset\n", *argv);
+ p->peer_offset = uval;
+ } else if (strcmp(*argv, "cookie") == 0) {
+ int slen;
+ NEXT_ARG();
+ slen = strlen(*argv);
+ if ((slen != 8) && (slen != 16))
+ invarg("cookie must be either 8 or 16 hex digits\n", *argv);
+
+ p->cookie_len = slen / 2;
+ if (hex2mem(*argv, p->cookie, p->cookie_len) < 0)
+ invarg("cookie must be a hex string\n", *argv);
+ } else if (strcmp(*argv, "peer_cookie") == 0) {
+ int slen;
+ NEXT_ARG();
+ slen = strlen(*argv);
+ if ((slen != 8) && (slen != 16))
+ invarg("cookie must be either 8 or 16 hex digits\n", *argv);
+
+ p->peer_cookie_len = slen / 2;
+ if (hex2mem(*argv, p->peer_cookie, p->peer_cookie_len) < 0)
+ invarg("cookie must be a hex string\n", *argv);
+ } else if (strcmp(*argv, "tunnel") == 0) {
+ p->tunnel = 1;
+ } else if (strcmp(*argv, "session") == 0) {
+ p->session = 1;
+ } else if (matches(*argv, "help") == 0) {
+ usage();
+ } else {
+ fprintf(stderr, "Unknown command: %s\n", *argv);
+ usage();
+ }
+
+ argc--; argv++;
+ }
+
+ return 0;
+}
+
+
+static int do_add(int argc, char **argv)
+{
+ struct l2tp_parm p;
+ int ret = 0;
+
+ if (parse_args(argc, argv, L2TP_ADD, &p) < 0)
+ return -1;
+
+ if (!p.tunnel && !p.session)
+ missarg("tunnel or session");
+
+ if (p.tunnel_id == 0)
+ missarg("tunnel_id");
+
+ /* session_id and peer_session_id must be provided for sessions */
+ if ((p.session) && (p.peer_session_id == 0))
+ missarg("peer_session_id");
+ if ((p.session) && (p.session_id == 0))
+ missarg("session_id");
+
+ /* peer_tunnel_id is needed for tunnels */
+ if ((p.tunnel) && (p.peer_tunnel_id == 0))
+ missarg("peer_tunnel_id");
+
+ if (p.tunnel) {
+ if (p.local_ip.s_addr == 0)
+ missarg("local");
+
+ if (p.peer_ip.s_addr == 0)
+ missarg("remote");
+
+ if (p.encap == L2TP_ENCAPTYPE_UDP) {
+ if (p.local_udp_port == 0)
+ missarg("udp_sport");
+ if (p.peer_udp_port == 0)
+ missarg("udp_dport");
+ }
+
+ ret = create_tunnel(&p);
+ }
+
+ if (p.session) {
+ /* Only ethernet pseudowires supported */
+ p.pw_type = L2TP_PWTYPE_ETH;
+
+ ret = create_session(&p);
+ }
+
+ return ret;
+}
+
+static int do_del(int argc, char **argv)
+{
+ struct l2tp_parm p;
+
+ if (parse_args(argc, argv, L2TP_DEL, &p) < 0)
+ return -1;
+
+ if (!p.tunnel && !p.session)
+ missarg("tunnel or session");
+
+ if ((p.tunnel) && (p.tunnel_id == 0))
+ missarg("tunnel_id");
+ if ((p.session) && (p.session_id == 0))
+ missarg("session_id");
+
+ if (p.session_id)
+ return delete_session(&p);
+ else
+ return delete_tunnel(&p);
+
+ return -1;
+}
+
+static int do_show(int argc, char **argv)
+{
+ struct l2tp_data data;
+ struct l2tp_parm *p = &data.config;
+
+ if (parse_args(argc, argv, L2TP_GET, p) < 0)
+ return -1;
+
+ if (!p->tunnel && !p->session)
+ missarg("tunnel or session");
+
+ if (p->session)
+ get_session(&data);
+ else
+ get_tunnel(&data);
+
+ return 0;
+}
+
+static int genl_parse_getfamily(struct nlmsghdr *nlh)
+{
+ struct rtattr *tb[CTRL_ATTR_MAX + 1];
+ struct genlmsghdr *ghdr = NLMSG_DATA(nlh);
+ int len = nlh->nlmsg_len;
+ struct rtattr *attrs;
+
+ if (nlh->nlmsg_type != GENL_ID_CTRL) {
+ fprintf(stderr, "Not a controller message, nlmsg_len=%d "
+ "nlmsg_type=0x%x\n", nlh->nlmsg_len, nlh->nlmsg_type);
+ return -1;
+ }
+
+ if (ghdr->cmd != CTRL_CMD_NEWFAMILY) {
+ fprintf(stderr, "Unknown controller command %d\n", ghdr->cmd);
+ return -1;
+ }
+
+ len -= NLMSG_LENGTH(GENL_HDRLEN);
+
+ if (len < 0) {
+ fprintf(stderr, "wrong controller message len %d\n", len);
+ return -1;
+ }
+
+ attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
+ parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);
+
+ if (tb[CTRL_ATTR_FAMILY_ID] == NULL) {
+ fprintf(stderr, "Missing family id TLV\n");
+ return -1;
+ }
+
+ return rta_getattr_u16(tb[CTRL_ATTR_FAMILY_ID]);
+}
+
+int genl_ctrl_resolve_family(const char *family)
+{
+ struct {
+ struct nlmsghdr n;
+ struct genlmsghdr g;
+ char buf[1024];
+ } req;
+
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = GENL_ID_CTRL;
+ req.g.cmd = CTRL_CMD_GETFAMILY;
+
+ addattr_l(&req.n, 1024, CTRL_ATTR_FAMILY_NAME,
+ family, strlen(family) + 1);
+
+ if (rtnl_talk(&genl_rth, &req.n, 0, 0, &req.n) < 0) {
+ fprintf(stderr, "Error talking to the kernel\n");
+ return -2;
+ }
+
+ return genl_parse_getfamily(&req.n);
+}
+
+int do_ipl2tp(int argc, char **argv)
+{
+ if (genl_family < 0) {
+ if (rtnl_open_byproto(&genl_rth, 0, NETLINK_GENERIC) < 0) {
+ fprintf(stderr, "Cannot open generic netlink socket\n");
+ exit(1);
+ }
+
+ genl_family = genl_ctrl_resolve_family(L2TP_GENL_NAME);
+ if (genl_family < 0)
+ exit(1);
+ }
+
+ if (argc < 1)
+ usage();
+
+ if (matches(*argv, "add") == 0)
+ return do_add(argc-1, argv+1);
+ if (matches(*argv, "del") == 0)
+ return do_del(argc-1, argv+1);
+ if (matches(*argv, "show") == 0 ||
+ matches(*argv, "lst") == 0 ||
+ matches(*argv, "list") == 0)
+ return do_show(argc-1, argv+1);
+ if (matches(*argv, "help") == 0)
+ usage();
+
+ fprintf(stderr, "Command \"%s\" is unknown, try \"ip l2tp help\".\n", *argv);
+ exit(-1);
+}
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/iplink.c b/ap/app/iproute2/iproute2-3.4.0/ip/iplink.c
new file mode 100755
index 0000000..679091e
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/iplink.c
@@ -0,0 +1,979 @@
+/*
+ * iplink.c "ip link".
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <linux/if_packet.h>
+#include <linux/if_ether.h>
+#include <linux/sockios.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <linux/sockios.h>
+
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+
+#define IPLINK_IOCTL_COMPAT 1
+#ifndef LIBDIR
+#define LIBDIR "/usr/lib"
+#endif
+
+static void usage(void) __attribute__((noreturn));
+static int iplink_have_newlink(void);
+
+void iplink_usage(void)
+{
+ if (iplink_have_newlink()) {
+ fprintf(stderr, "Usage: ip link add [link DEV] [ name ] NAME\n");
+ fprintf(stderr, " [ txqueuelen PACKETS ]\n");
+ fprintf(stderr, " [ address LLADDR ]\n");
+ fprintf(stderr, " [ broadcast LLADDR ]\n");
+ fprintf(stderr, " [ mtu MTU ]\n");
+ fprintf(stderr, " type TYPE [ ARGS ]\n");
+ fprintf(stderr, " ip link delete DEV type TYPE [ ARGS ]\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, " ip link set { dev DEVICE | group DEVGROUP } [ { up | down } ]\n");
+ } else
+ fprintf(stderr, "Usage: ip link set DEVICE [ { up | down } ]\n");
+
+ fprintf(stderr, " [ arp { on | off } ]\n");
+ fprintf(stderr, " [ dynamic { on | off } ]\n");
+ fprintf(stderr, " [ multicast { on | off } ]\n");
+ fprintf(stderr, " [ allmulticast { on | off } ]\n");
+ fprintf(stderr, " [ promisc { on | off } ]\n");
+ fprintf(stderr, " [ trailers { on | off } ]\n");
+ fprintf(stderr, " [ txqueuelen PACKETS ]\n");
+ fprintf(stderr, " [ name NEWNAME ]\n");
+ fprintf(stderr, " [ address LLADDR ]\n");
+ fprintf(stderr, " [ broadcast LLADDR ]\n");
+ fprintf(stderr, " [ mtu MTU ]\n");
+ fprintf(stderr, " [ netns PID ]\n");
+ fprintf(stderr, " [ netns NAME ]\n");
+ fprintf(stderr, " [ alias NAME ]\n");
+ fprintf(stderr, " [ vf NUM [ mac LLADDR ]\n");
+ fprintf(stderr, " [ vlan VLANID [ qos VLAN-QOS ] ]\n");
+
+ fprintf(stderr, " [ rate TXRATE ] ] \n");
+
+ fprintf(stderr, " [ spoofchk { on | off} ] ] \n");
+ fprintf(stderr, " [ master DEVICE ]\n");
+ fprintf(stderr, " [ nomaster ]\n");
+ fprintf(stderr, " ip link show [ DEVICE | group GROUP ]\n");
+
+ if (iplink_have_newlink()) {
+ fprintf(stderr, "\n");
+ fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | can | bridge }\n");
+ }
+ exit(-1);
+}
+
+static void usage(void)
+{
+ iplink_usage();
+}
+
+static int on_off(char *msg)
+{
+ fprintf(stderr, "Error: argument of \"%s\" must be \"on\" or \"off\"\n", msg);
+ return -1;
+}
+
+static void *BODY; /* cached dlopen(NULL) handle */
+static struct link_util *linkutil_list;
+
+struct link_util *get_link_kind(const char *id)
+{
+ void *dlh;
+ char buf[256];
+ struct link_util *l;
+
+ for (l = linkutil_list; l; l = l->next)
+ if (strcmp(l->id, id) == 0)
+ return l;
+
+ snprintf(buf, sizeof(buf), LIBDIR "/ip/link_%s.so", id);
+ dlh = dlopen(buf, RTLD_LAZY);
+ if (dlh == NULL) {
+ /* look in current binary, only open once */
+ dlh = BODY;
+ if (dlh == NULL) {
+ dlh = BODY = dlopen(NULL, RTLD_LAZY);
+ if (dlh == NULL)
+ return NULL;
+ }
+ }
+
+ snprintf(buf, sizeof(buf), "%s_link_util", id);
+ l = dlsym(dlh, buf);
+ if (l == NULL)
+ return NULL;
+
+ l->next = linkutil_list;
+ linkutil_list = l;
+ return l;
+}
+
+int get_link_mode(const char *mode)
+{
+ if (strcasecmp(mode, "default") == 0)
+ return IF_LINK_MODE_DEFAULT;
+ if (strcasecmp(mode, "dormant") == 0)
+ return IF_LINK_MODE_DORMANT;
+ return -1;
+}
+
+#if IPLINK_IOCTL_COMPAT
+static int have_rtnl_newlink = -1;
+
+static int accept_msg(const struct sockaddr_nl *who,
+ struct nlmsghdr *n, void *arg)
+{
+ struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
+
+ if (n->nlmsg_type == NLMSG_ERROR &&
+ (err->error == -EOPNOTSUPP || err->error == -EINVAL))
+ have_rtnl_newlink = 0;
+ else
+ have_rtnl_newlink = 1;
+ return -1;
+}
+
+static int iplink_have_newlink(void)
+{
+ struct {
+ struct nlmsghdr n;
+ struct ifinfomsg i;
+ char buf[1024];
+ } req;
+
+ if (have_rtnl_newlink < 0) {
+ memset(&req, 0, sizeof(req));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
+ req.n.nlmsg_type = RTM_NEWLINK;
+ req.i.ifi_family = AF_UNSPEC;
+
+ rtnl_send(&rth, &req.n, req.n.nlmsg_len);
+ rtnl_listen(&rth, accept_msg, NULL);
+ }
+ return have_rtnl_newlink;
+}
+#else /* IPLINK_IOCTL_COMPAT */
+static int iplink_have_newlink(void)
+{
+ return 1;
+}
+#endif /* ! IPLINK_IOCTL_COMPAT */
+
+struct iplink_req {
+ struct nlmsghdr n;
+ struct ifinfomsg i;
+ char buf[1024];
+};
+
+int iplink_parse_vf(int vf, int *argcp, char ***argvp,
+ struct iplink_req *req)
+{
+ int len, argc = *argcp;
+ char **argv = *argvp;
+ struct rtattr *vfinfo;
+
+ vfinfo = addattr_nest(&req->n, sizeof(*req), IFLA_VF_INFO);
+
+ while (NEXT_ARG_OK()) {
+ NEXT_ARG();
+ if (matches(*argv, "mac") == 0) {
+ struct ifla_vf_mac ivm;
+ NEXT_ARG();
+ ivm.vf = vf;
+ len = ll_addr_a2n((char *)ivm.mac, 32, *argv);
+ if (len < 0)
+ return -1;
+ addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC, &ivm, sizeof(ivm));
+ } else if (matches(*argv, "vlan") == 0) {
+ struct ifla_vf_vlan ivv;
+ NEXT_ARG();
+ if (get_unsigned(&ivv.vlan, *argv, 0)) {
+ invarg("Invalid \"vlan\" value\n", *argv);
+ }
+ ivv.vf = vf;
+ ivv.qos = 0;
+ if (NEXT_ARG_OK()) {
+ NEXT_ARG();
+ if (matches(*argv, "qos") == 0) {
+ NEXT_ARG();
+ if (get_unsigned(&ivv.qos, *argv, 0)) {
+ invarg("Invalid \"qos\" value\n", *argv);
+ }
+ } else {
+ /* rewind arg */
+ PREV_ARG();
+ }
+ }
+ addattr_l(&req->n, sizeof(*req), IFLA_VF_VLAN, &ivv, sizeof(ivv));
+ } else if (matches(*argv, "rate") == 0) {
+ struct ifla_vf_tx_rate ivt;
+ NEXT_ARG();
+ if (get_unsigned(&ivt.rate, *argv, 0)) {
+ invarg("Invalid \"rate\" value\n", *argv);
+ }
+ ivt.vf = vf;
+ addattr_l(&req->n, sizeof(*req), IFLA_VF_TX_RATE, &ivt, sizeof(ivt));
+
+ } else if (matches(*argv, "spoofchk") == 0) {
+ struct ifla_vf_spoofchk ivs;
+ NEXT_ARG();
+ if (matches(*argv, "on") == 0)
+ ivs.setting = 1;
+ else if (matches(*argv, "off") == 0)
+ ivs.setting = 0;
+ else
+ invarg("Invalid \"spoofchk\" value\n", *argv);
+ ivs.vf = vf;
+ addattr_l(&req->n, sizeof(*req), IFLA_VF_SPOOFCHK, &ivs, sizeof(ivs));
+
+ } else {
+ /* rewind arg */
+ PREV_ARG();
+ break;
+ }
+ }
+
+ if (argc == *argcp)
+ incomplete_command();
+
+ addattr_nest_end(&req->n, vfinfo);
+
+ *argcp = argc;
+ *argvp = argv;
+ return 0;
+}
+
+
+int iplink_parse(int argc, char **argv, struct iplink_req *req,
+ char **name, char **type, char **link, char **dev, int *group)
+{
+ int ret, len;
+ char abuf[32];
+ int qlen = -1;
+ int mtu = -1;
+ int netns = -1;
+ int vf = -1;
+
+ *group = -1;
+ ret = argc;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "up") == 0) {
+ req->i.ifi_change |= IFF_UP;
+ req->i.ifi_flags |= IFF_UP;
+ } else if (strcmp(*argv, "down") == 0) {
+ req->i.ifi_change |= IFF_UP;
+ req->i.ifi_flags &= ~IFF_UP;
+ } else if (strcmp(*argv, "name") == 0) {
+ NEXT_ARG();
+ *name = *argv;
+ } else if (matches(*argv, "link") == 0) {
+ NEXT_ARG();
+ *link = *argv;
+ } else if (matches(*argv, "address") == 0) {
+ NEXT_ARG();
+ len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
+ if (len < 0)
+ return -1;
+ addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, len);
+ } else if (matches(*argv, "broadcast") == 0 ||
+ strcmp(*argv, "brd") == 0) {
+ NEXT_ARG();
+ len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
+ if (len < 0)
+ return -1;
+ addattr_l(&req->n, sizeof(*req), IFLA_BROADCAST, abuf, len);
+ } else if (matches(*argv, "txqueuelen") == 0 ||
+ strcmp(*argv, "qlen") == 0 ||
+ matches(*argv, "txqlen") == 0) {
+ NEXT_ARG();
+ if (qlen != -1)
+ duparg("txqueuelen", *argv);
+ if (get_integer(&qlen, *argv, 0))
+ invarg("Invalid \"txqueuelen\" value\n", *argv);
+ addattr_l(&req->n, sizeof(*req), IFLA_TXQLEN, &qlen, 4);
+ } else if (strcmp(*argv, "mtu") == 0) {
+ NEXT_ARG();
+ if (mtu != -1)
+ duparg("mtu", *argv);
+ if (get_integer(&mtu, *argv, 0))
+ invarg("Invalid \"mtu\" value\n", *argv);
+ addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4);
+ } else if (strcmp(*argv, "netns") == 0) {
+ NEXT_ARG();
+ if (netns != -1)
+ duparg("netns", *argv);
+ if ((netns = get_netns_fd(*argv)) >= 0)
+ addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD, &netns, 4);
+ else if (get_integer(&netns, *argv, 0) == 0)
+ addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, &netns, 4);
+ else
+ invarg("Invalid \"netns\" value\n", *argv);
+ } else if (strcmp(*argv, "multicast") == 0) {
+ NEXT_ARG();
+ req->i.ifi_change |= IFF_MULTICAST;
+ if (strcmp(*argv, "on") == 0) {
+ req->i.ifi_flags |= IFF_MULTICAST;
+ } else if (strcmp(*argv, "off") == 0) {
+ req->i.ifi_flags &= ~IFF_MULTICAST;
+ } else
+ return on_off("multicast");
+ } else if (strcmp(*argv, "allmulticast") == 0) {
+ NEXT_ARG();
+ req->i.ifi_change |= IFF_ALLMULTI;
+ if (strcmp(*argv, "on") == 0) {
+ req->i.ifi_flags |= IFF_ALLMULTI;
+ } else if (strcmp(*argv, "off") == 0) {
+ req->i.ifi_flags &= ~IFF_ALLMULTI;
+ } else
+ return on_off("allmulticast");
+ } else if (strcmp(*argv, "promisc") == 0) {
+ NEXT_ARG();
+ req->i.ifi_change |= IFF_PROMISC;
+ if (strcmp(*argv, "on") == 0) {
+ req->i.ifi_flags |= IFF_PROMISC;
+ } else if (strcmp(*argv, "off") == 0) {
+ req->i.ifi_flags &= ~IFF_PROMISC;
+ } else
+ return on_off("promisc");
+ } else if (strcmp(*argv, "trailers") == 0) {
+ NEXT_ARG();
+ req->i.ifi_change |= IFF_NOTRAILERS;
+ if (strcmp(*argv, "off") == 0) {
+ req->i.ifi_flags |= IFF_NOTRAILERS;
+ } else if (strcmp(*argv, "on") == 0) {
+ req->i.ifi_flags &= ~IFF_NOTRAILERS;
+ } else
+ return on_off("trailers");
+ } else if (strcmp(*argv, "arp") == 0) {
+ NEXT_ARG();
+ req->i.ifi_change |= IFF_NOARP;
+ if (strcmp(*argv, "on") == 0) {
+ req->i.ifi_flags &= ~IFF_NOARP;
+ } else if (strcmp(*argv, "off") == 0) {
+ req->i.ifi_flags |= IFF_NOARP;
+ } else
+ return on_off("noarp");
+ } else if (strcmp(*argv, "vf") == 0) {
+ struct rtattr *vflist;
+ NEXT_ARG();
+ if (get_integer(&vf, *argv, 0)) {
+ invarg("Invalid \"vf\" value\n", *argv);
+ }
+ vflist = addattr_nest(&req->n, sizeof(*req),
+ IFLA_VFINFO_LIST);
+ len = iplink_parse_vf(vf, &argc, &argv, req);
+ if (len < 0)
+ return -1;
+ addattr_nest_end(&req->n, vflist);
+ } else if (matches(*argv, "master") == 0) {
+ int ifindex;
+ NEXT_ARG();
+ ifindex = ll_name_to_index(*argv);
+ if (!ifindex)
+ invarg("Device does not exist\n", *argv);
+ addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
+ &ifindex, 4);
+ } else if (matches(*argv, "nomaster") == 0) {
+ int ifindex = 0;
+ addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
+ &ifindex, 4);
+ } else if (matches(*argv, "dynamic") == 0) {
+ NEXT_ARG();
+ req->i.ifi_change |= IFF_DYNAMIC;
+ if (strcmp(*argv, "on") == 0) {
+ req->i.ifi_flags |= IFF_DYNAMIC;
+ } else if (strcmp(*argv, "off") == 0) {
+ req->i.ifi_flags &= ~IFF_DYNAMIC;
+ } else
+ return on_off("dynamic");
+ } else if (matches(*argv, "type") == 0) {
+ NEXT_ARG();
+ *type = *argv;
+ argc--; argv++;
+ break;
+ } else if (matches(*argv, "alias") == 0) {
+ NEXT_ARG();
+ addattr_l(&req->n, sizeof(*req), IFLA_IFALIAS,
+ *argv, strlen(*argv));
+ argc--; argv++;
+ break;
+ } else if (strcmp(*argv, "group") == 0) {
+ NEXT_ARG();
+ if (*group != -1)
+ duparg("group", *argv);
+ if (rtnl_group_a2n(group, *argv))
+ invarg("Invalid \"group\" value\n", *argv);
+ } else if (strcmp(*argv, "mode") == 0) {
+ int mode;
+ NEXT_ARG();
+ mode = get_link_mode(*argv);
+ if (mode < 0)
+ invarg("Invalid link mode\n", *argv);
+ addattr8(&req->n, sizeof(*req), IFLA_LINKMODE, mode);
+ } else if (strcmp(*argv, "state") == 0) {
+ int state;
+ NEXT_ARG();
+ state = get_operstate(*argv);
+ if (state < 0)
+ invarg("Invalid operstate\n", *argv);
+
+ addattr8(&req->n, sizeof(*req), IFLA_OPERSTATE, state);
+ } else {
+ if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ }
+ if (matches(*argv, "help") == 0)
+ usage();
+ if (*dev)
+ duparg2("dev", *argv);
+ *dev = *argv;
+ }
+ argc--; argv++;
+ }
+
+ return ret - argc;
+}
+
+static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
+{
+ int len;
+ char *dev = NULL;
+ char *name = NULL;
+ char *link = NULL;
+ char *type = NULL;
+ int group;
+ struct link_util *lu = NULL;
+ struct iplink_req req;
+ int ret;
+
+ memset(&req, 0, sizeof(req));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST|flags;
+ req.n.nlmsg_type = cmd;
+ req.i.ifi_family = preferred_family;
+
+ ret = iplink_parse(argc, argv, &req, &name, &type, &link, &dev, &group);
+ if (ret < 0)
+ return ret;
+
+ argc -= ret;
+ argv += ret;
+
+ if (group != -1) {
+ if (dev)
+ addattr_l(&req.n, sizeof(req), IFLA_GROUP,
+ &group, sizeof(group));
+ else {
+ if (argc) {
+ fprintf(stderr, "Garbage instead of arguments "
+ "\"%s ...\". Try \"ip link "
+ "help\".\n", *argv);
+ return -1;
+ }
+ if (flags & NLM_F_CREATE) {
+ fprintf(stderr, "group cannot be used when "
+ "creating devices.\n");
+ return -1;
+ }
+
+ req.i.ifi_index = 0;
+ addattr32(&req.n, sizeof(req), IFLA_GROUP, group);
+ if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ exit(2);
+ return 0;
+ }
+ }
+
+ ll_init_map(&rth);
+
+ if (!(flags & NLM_F_CREATE)) {
+ if (!dev) {
+ fprintf(stderr, "Not enough information: \"dev\" "
+ "argument is required.\n");
+ exit(-1);
+ }
+
+ req.i.ifi_index = ll_name_to_index(dev);
+ if (req.i.ifi_index == 0) {
+ fprintf(stderr, "Cannot find device \"%s\"\n", dev);
+ return -1;
+ }
+ } else {
+ /* Allow "ip link add dev" and "ip link add name" */
+ if (!name)
+ name = dev;
+
+ if (link) {
+ int ifindex;
+
+ ifindex = ll_name_to_index(link);
+ if (ifindex == 0) {
+ fprintf(stderr, "Cannot find device \"%s\"\n",
+ link);
+ return -1;
+ }
+ addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4);
+ }
+ }
+
+ if (name) {
+ len = strlen(name) + 1;
+ if (len == 1)
+ invarg("\"\" is not a valid device identifier\n", "name");
+ if (len > IFNAMSIZ)
+ invarg("\"name\" too long\n", name);
+ addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len);
+ }
+
+ if (type) {
+ struct rtattr *linkinfo = NLMSG_TAIL(&req.n);
+ addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
+ addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type,
+ strlen(type));
+
+ lu = get_link_kind(type);
+ if (lu && argc) {
+ struct rtattr * data = NLMSG_TAIL(&req.n);
+ addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0);
+
+ if (lu->parse_opt &&
+ lu->parse_opt(lu, argc, argv, &req.n))
+ return -1;
+
+ data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
+ } else if (argc) {
+ if (matches(*argv, "help") == 0)
+ usage();
+ fprintf(stderr, "Garbage instead of arguments \"%s ...\". "
+ "Try \"ip link help\".\n", *argv);
+ return -1;
+ }
+ linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
+ } else if (flags & NLM_F_CREATE) {
+ fprintf(stderr, "Not enough information: \"type\" argument "
+ "is required\n");
+ return -1;
+ }
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ exit(2);
+
+ return 0;
+}
+
+#if IPLINK_IOCTL_COMPAT
+static int get_ctl_fd(void)
+{
+ int s_errno;
+ int fd;
+
+ fd = socket(PF_INET, SOCK_DGRAM, 0);
+ if (fd >= 0)
+ return fd;
+ s_errno = errno;
+ fd = socket(PF_PACKET, SOCK_DGRAM, 0);
+ if (fd >= 0)
+ return fd;
+ fd = socket(PF_INET6, SOCK_DGRAM, 0);
+ if (fd >= 0)
+ return fd;
+ errno = s_errno;
+ perror("Cannot create control socket");
+ return -1;
+}
+
+static int do_chflags(const char *dev, __u32 flags, __u32 mask)
+{
+ struct ifreq ifr;
+ int fd;
+ int err;
+
+ strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+ fd = get_ctl_fd();
+ if (fd < 0)
+ return -1;
+ err = ioctl(fd, SIOCGIFFLAGS, &ifr);
+ if (err) {
+ perror("SIOCGIFFLAGS");
+ close(fd);
+ return -1;
+ }
+ if ((ifr.ifr_flags^flags)&mask) {
+ ifr.ifr_flags &= ~mask;
+ ifr.ifr_flags |= mask&flags;
+ err = ioctl(fd, SIOCSIFFLAGS, &ifr);
+ if (err)
+ perror("SIOCSIFFLAGS");
+ }
+ close(fd);
+ return err;
+}
+
+static int do_changename(const char *dev, const char *newdev)
+{
+ struct ifreq ifr;
+ int fd;
+ int err;
+
+ strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+ strncpy(ifr.ifr_newname, newdev, IFNAMSIZ);
+ fd = get_ctl_fd();
+ if (fd < 0)
+ return -1;
+ err = ioctl(fd, SIOCSIFNAME, &ifr);
+ if (err) {
+ perror("SIOCSIFNAME");
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ return err;
+}
+
+static int set_qlen(const char *dev, int qlen)
+{
+ struct ifreq ifr;
+ int s;
+
+ s = get_ctl_fd();
+ if (s < 0)
+ return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+ ifr.ifr_qlen = qlen;
+ if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) {
+ perror("SIOCSIFXQLEN");
+ close(s);
+ return -1;
+ }
+ close(s);
+
+ return 0;
+}
+
+static int set_mtu(const char *dev, int mtu)
+{
+ struct ifreq ifr;
+ int s;
+
+ s = get_ctl_fd();
+ if (s < 0)
+ return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+ ifr.ifr_mtu = mtu;
+ if (ioctl(s, SIOCSIFMTU, &ifr) < 0) {
+ perror("SIOCSIFMTU");
+ close(s);
+ return -1;
+ }
+ close(s);
+
+ return 0;
+}
+
+static int get_address(const char *dev, int *htype)
+{
+ struct ifreq ifr;
+ struct sockaddr_ll me;
+ socklen_t alen;
+ int s;
+
+ s = socket(PF_PACKET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket(PF_PACKET)");
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+ if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
+ perror("SIOCGIFINDEX");
+ close(s);
+ return -1;
+ }
+
+ memset(&me, 0, sizeof(me));
+ me.sll_family = AF_PACKET;
+ me.sll_ifindex = ifr.ifr_ifindex;
+ me.sll_protocol = htons(ETH_P_LOOP);
+ if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) {
+ perror("bind");
+ close(s);
+ return -1;
+ }
+
+ alen = sizeof(me);
+ if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) {
+ perror("getsockname");
+ close(s);
+ return -1;
+ }
+ close(s);
+ *htype = me.sll_hatype;
+ return me.sll_halen;
+}
+
+static int parse_address(const char *dev, int hatype, int halen,
+ char *lla, struct ifreq *ifr)
+{
+ int alen;
+
+ memset(ifr, 0, sizeof(*ifr));
+ strncpy(ifr->ifr_name, dev, IFNAMSIZ);
+ ifr->ifr_hwaddr.sa_family = hatype;
+ alen = ll_addr_a2n(ifr->ifr_hwaddr.sa_data, 14, lla);
+ if (alen < 0)
+ return -1;
+ if (alen != halen) {
+ fprintf(stderr, "Wrong address (%s) length: expected %d bytes\n", lla, halen);
+ return -1;
+ }
+ return 0;
+}
+
+static int set_address(struct ifreq *ifr, int brd)
+{
+ int s;
+
+ s = get_ctl_fd();
+ if (s < 0)
+ return -1;
+ if (ioctl(s, brd?SIOCSIFHWBROADCAST:SIOCSIFHWADDR, ifr) < 0) {
+ perror(brd?"SIOCSIFHWBROADCAST":"SIOCSIFHWADDR");
+ close(s);
+ return -1;
+ }
+ close(s);
+ return 0;
+}
+
+
+static int do_set(int argc, char **argv)
+{
+ char *dev = NULL;
+ __u32 mask = 0;
+ __u32 flags = 0;
+ int qlen = -1;
+ int mtu = -1;
+ char *newaddr = NULL;
+ char *newbrd = NULL;
+ struct ifreq ifr0, ifr1;
+ char *newname = NULL;
+ int htype, halen;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "up") == 0) {
+ mask |= IFF_UP;
+ flags |= IFF_UP;
+ } else if (strcmp(*argv, "down") == 0) {
+ mask |= IFF_UP;
+ flags &= ~IFF_UP;
+ } else if (strcmp(*argv, "name") == 0) {
+ NEXT_ARG();
+ newname = *argv;
+ } else if (matches(*argv, "address") == 0) {
+ NEXT_ARG();
+ newaddr = *argv;
+ } else if (matches(*argv, "broadcast") == 0 ||
+ strcmp(*argv, "brd") == 0) {
+ NEXT_ARG();
+ newbrd = *argv;
+ } else if (matches(*argv, "txqueuelen") == 0 ||
+ strcmp(*argv, "qlen") == 0 ||
+ matches(*argv, "txqlen") == 0) {
+ NEXT_ARG();
+ if (qlen != -1)
+ duparg("txqueuelen", *argv);
+ if (get_integer(&qlen, *argv, 0))
+ invarg("Invalid \"txqueuelen\" value\n", *argv);
+ } else if (strcmp(*argv, "mtu") == 0) {
+ NEXT_ARG();
+ if (mtu != -1)
+ duparg("mtu", *argv);
+ if (get_integer(&mtu, *argv, 0))
+ invarg("Invalid \"mtu\" value\n", *argv);
+ } else if (strcmp(*argv, "multicast") == 0) {
+ NEXT_ARG();
+ mask |= IFF_MULTICAST;
+ if (strcmp(*argv, "on") == 0) {
+ flags |= IFF_MULTICAST;
+ } else if (strcmp(*argv, "off") == 0) {
+ flags &= ~IFF_MULTICAST;
+ } else
+ return on_off("multicast");
+ } else if (strcmp(*argv, "allmulticast") == 0) {
+ NEXT_ARG();
+ mask |= IFF_ALLMULTI;
+ if (strcmp(*argv, "on") == 0) {
+ flags |= IFF_ALLMULTI;
+ } else if (strcmp(*argv, "off") == 0) {
+ flags &= ~IFF_ALLMULTI;
+ } else
+ return on_off("allmulticast");
+ } else if (strcmp(*argv, "promisc") == 0) {
+ NEXT_ARG();
+ mask |= IFF_PROMISC;
+ if (strcmp(*argv, "on") == 0) {
+ flags |= IFF_PROMISC;
+ } else if (strcmp(*argv, "off") == 0) {
+ flags &= ~IFF_PROMISC;
+ } else
+ return on_off("promisc");
+ } else if (strcmp(*argv, "trailers") == 0) {
+ NEXT_ARG();
+ mask |= IFF_NOTRAILERS;
+ if (strcmp(*argv, "off") == 0) {
+ flags |= IFF_NOTRAILERS;
+ } else if (strcmp(*argv, "on") == 0) {
+ flags &= ~IFF_NOTRAILERS;
+ } else
+ return on_off("trailers");
+ } else if (strcmp(*argv, "arp") == 0) {
+ NEXT_ARG();
+ mask |= IFF_NOARP;
+ if (strcmp(*argv, "on") == 0) {
+ flags &= ~IFF_NOARP;
+ } else if (strcmp(*argv, "off") == 0) {
+ flags |= IFF_NOARP;
+ } else
+ return on_off("noarp");
+ } else if (matches(*argv, "dynamic") == 0) {
+ NEXT_ARG();
+ mask |= IFF_DYNAMIC;
+ if (strcmp(*argv, "on") == 0) {
+ flags |= IFF_DYNAMIC;
+ } else if (strcmp(*argv, "off") == 0) {
+ flags &= ~IFF_DYNAMIC;
+ } else
+ return on_off("dynamic");
+ } else {
+ if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ }
+ if (matches(*argv, "help") == 0)
+ usage();
+ if (dev)
+ duparg2("dev", *argv);
+ dev = *argv;
+ }
+ argc--; argv++;
+ }
+
+ if (!dev) {
+ fprintf(stderr, "Not enough of information: \"dev\" argument is required.\n");
+ exit(-1);
+ }
+
+ if (newaddr || newbrd) {
+ halen = get_address(dev, &htype);
+ if (halen < 0)
+ return -1;
+ if (newaddr) {
+ if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0)
+ return -1;
+ }
+ if (newbrd) {
+ if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0)
+ return -1;
+ }
+ }
+
+ if (newname && strcmp(dev, newname)) {
+ if (strlen(newname) == 0)
+ invarg("\"\" is not a valid device identifier\n", "name");
+ if (do_changename(dev, newname) < 0)
+ return -1;
+ dev = newname;
+ }
+ if (qlen != -1) {
+ if (set_qlen(dev, qlen) < 0)
+ return -1;
+ }
+ if (mtu != -1) {
+ if (set_mtu(dev, mtu) < 0)
+ return -1;
+ }
+ if (newaddr || newbrd) {
+ if (newbrd) {
+ if (set_address(&ifr1, 1) < 0)
+ return -1;
+ }
+ if (newaddr) {
+ if (set_address(&ifr0, 0) < 0)
+ return -1;
+ }
+ }
+ if (mask)
+ return do_chflags(dev, flags, mask);
+ return 0;
+}
+#endif /* IPLINK_IOCTL_COMPAT */
+
+int do_iplink(int argc, char **argv)
+{
+ if (argc > 0) {
+ if (iplink_have_newlink()) {
+ if (matches(*argv, "add") == 0)
+ return iplink_modify(RTM_NEWLINK,
+ NLM_F_CREATE|NLM_F_EXCL,
+ argc-1, argv+1);
+ if (matches(*argv, "set") == 0 ||
+ matches(*argv, "change") == 0)
+ return iplink_modify(RTM_NEWLINK, 0,
+ argc-1, argv+1);
+ if (matches(*argv, "replace") == 0)
+ return iplink_modify(RTM_NEWLINK,
+ NLM_F_CREATE|NLM_F_REPLACE,
+ argc-1, argv+1);
+ if (matches(*argv, "delete") == 0)
+ return iplink_modify(RTM_DELLINK, 0,
+ argc-1, argv+1);
+ } else {
+#if IPLINK_IOCTL_COMPAT
+ if (matches(*argv, "set") == 0)
+ return do_set(argc-1, argv+1);
+#endif
+ }
+ if (matches(*argv, "show") == 0 ||
+ matches(*argv, "lst") == 0 ||
+ matches(*argv, "list") == 0)
+ return ipaddr_list_link(argc-1, argv+1);
+ if (matches(*argv, "help") == 0)
+ usage();
+ } else
+ return ipaddr_list_link(0, NULL);
+
+ fprintf(stderr, "Command \"%s\" is unknown, try \"ip link help\".\n", *argv);
+ exit(-1);
+}
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/iplink_can.c b/ap/app/iproute2/iproute2-3.4.0/ip/iplink_can.c
new file mode 100755
index 0000000..c8af4bc
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/iplink_can.c
@@ -0,0 +1,283 @@
+/*
+ * iplink_can.c CAN device support
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Wolfgang Grandegger <wg@grandegger.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <linux/can/netlink.h>
+
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "Usage: ip link set DEVICE type can\n"
+ "\t[ bitrate BITRATE [ sample-point SAMPLE-POINT] ] | \n"
+ "\t[ tq TQ prop-seg PROP_SEG phase-seg1 PHASE-SEG1\n "
+ "\t phase-seg2 PHASE-SEG2 [ sjw SJW ] ]\n"
+ "\n"
+ "\t[ loopback { on | off } ]\n"
+ "\t[ listen-only { on | off } ]\n"
+ "\t[ triple-sampling { on | off } ]\n"
+ "\t[ one-shot { on | off } ]\n"
+ "\t[ berr-reporting { on | off } ]\n"
+ "\n"
+ "\t[ restart-ms TIME-MS ]\n"
+ "\t[ restart ]\n"
+ "\n"
+ "\tWhere: BITRATE := { 1..1000000 }\n"
+ "\t SAMPLE-POINT := { 0.000..0.999 }\n"
+ "\t TQ := { NUMBER }\n"
+ "\t PROP-SEG := { 1..8 }\n"
+ "\t PHASE-SEG1 := { 1..8 }\n"
+ "\t PHASE-SEG2 := { 1..8 }\n"
+ "\t SJW := { 1..4 }\n"
+ "\t RESTART-MS := { 0 | NUMBER }\n"
+ );
+}
+
+static int get_float(float *val, const char *arg)
+{
+ float res;
+ char *ptr;
+
+ if (!arg || !*arg)
+ return -1;
+ res = strtof(arg, &ptr);
+ if (!ptr || ptr == arg || *ptr)
+ return -1;
+ *val = res;
+ return 0;
+}
+
+static void set_ctrlmode(char* name, char *arg,
+ struct can_ctrlmode *cm, __u32 flags)
+{
+ if (strcmp(arg, "on") == 0) {
+ cm->flags |= flags;
+ } else if (strcmp(arg, "off") != 0) {
+ fprintf(stderr,
+ "Error: argument of \"%s\" must be \"on\" or \"off\"\n",
+ name);
+ exit(-1);
+ }
+ cm->mask |= flags;
+}
+
+static void print_ctrlmode(FILE *f, __u32 cm)
+{
+ fprintf(f, "<");
+#define _PF(cmflag, cmname) \
+ if (cm & cmflag) { \
+ cm &= ~cmflag; \
+ fprintf(f, "%s%s", cmname, cm ? "," : ""); \
+ }
+ _PF(CAN_CTRLMODE_LOOPBACK, "LOOPBACK");
+ _PF(CAN_CTRLMODE_LISTENONLY, "LISTEN-ONLY");
+ _PF(CAN_CTRLMODE_3_SAMPLES, "TRIPLE-SAMPLING");
+ _PF(CAN_CTRLMODE_ONE_SHOT, "ONE-SHOT");
+ _PF(CAN_CTRLMODE_BERR_REPORTING, "BERR-REPORTING");
+#undef _PF
+ if (cm)
+ fprintf(f, "%x", cm);
+ fprintf(f, "> ");
+}
+
+static int can_parse_opt(struct link_util *lu, int argc, char **argv,
+ struct nlmsghdr *n)
+{
+ struct can_bittiming bt;
+ struct can_ctrlmode cm = {0, 0};
+
+ memset(&bt, 0, sizeof(bt));
+ while (argc > 0) {
+ if (matches(*argv, "bitrate") == 0) {
+ NEXT_ARG();
+ if (get_u32(&bt.bitrate, *argv, 0))
+ invarg("invalid \"bitrate\" value\n", *argv);
+ } else if (matches(*argv, "sample-point") == 0) {
+ float sp;
+
+ NEXT_ARG();
+ if (get_float(&sp, *argv))
+ invarg("invalid \"sample-point\" value\n",
+ *argv);
+ bt.sample_point = (__u32)(sp * 1000);
+ } else if (matches(*argv, "tq") == 0) {
+ NEXT_ARG();
+ if (get_u32(&bt.tq, *argv, 0))
+ invarg("invalid \"tq\" value\n", *argv);
+ } else if (matches(*argv, "prop-seg") == 0) {
+ NEXT_ARG();
+ if (get_u32(&bt.prop_seg, *argv, 0))
+ invarg("invalid \"prop-seg\" value\n", *argv);
+ } else if (matches(*argv, "phase-seg1") == 0) {
+ NEXT_ARG();
+ if (get_u32(&bt.phase_seg1, *argv, 0))
+ invarg("invalid \"phase-seg1\" value\n", *argv);
+ } else if (matches(*argv, "phase-seg2") == 0) {
+ NEXT_ARG();
+ if (get_u32(&bt.phase_seg2, *argv, 0))
+ invarg("invalid \"phase-seg2\" value\n", *argv);
+ } else if (matches(*argv, "sjw") == 0) {
+ NEXT_ARG();
+ if (get_u32(&bt.sjw, *argv, 0))
+ invarg("invalid \"sjw\" value\n", *argv);
+ } else if (matches(*argv, "loopback") == 0) {
+ NEXT_ARG();
+ set_ctrlmode("loopback", *argv, &cm,
+ CAN_CTRLMODE_LOOPBACK);
+ } else if (matches(*argv, "listen-only") == 0) {
+ NEXT_ARG();
+ set_ctrlmode("listen-only", *argv, &cm,
+ CAN_CTRLMODE_LISTENONLY);
+ } else if (matches(*argv, "triple-sampling") == 0) {
+ NEXT_ARG();
+ set_ctrlmode("triple-sampling", *argv, &cm,
+ CAN_CTRLMODE_3_SAMPLES);
+ } else if (matches(*argv, "one-shot") == 0) {
+ NEXT_ARG();
+ set_ctrlmode("one-shot", *argv, &cm,
+ CAN_CTRLMODE_ONE_SHOT);
+ } else if (matches(*argv, "berr-reporting") == 0) {
+ NEXT_ARG();
+ set_ctrlmode("berr-reporting", *argv, &cm,
+ CAN_CTRLMODE_BERR_REPORTING);
+ } else if (matches(*argv, "restart") == 0) {
+ __u32 val = 1;
+
+ addattr32(n, 1024, IFLA_CAN_RESTART, val);
+ } else if (matches(*argv, "restart-ms") == 0) {
+ __u32 val;
+
+ NEXT_ARG();
+ if (get_u32(&val, *argv, 0))
+ invarg("invalid \"restart-ms\" value\n", *argv);
+ addattr32(n, 1024, IFLA_CAN_RESTART_MS, val);
+ } else if (matches(*argv, "help") == 0) {
+ usage();
+ return -1;
+ } else {
+ fprintf(stderr, "can: what is \"%s\"?\n", *argv);
+ usage();
+ return -1;
+ }
+ argc--, argv++;
+ }
+
+ if (bt.bitrate || bt.tq)
+ addattr_l(n, 1024, IFLA_CAN_BITTIMING, &bt, sizeof(bt));
+ if (cm.mask)
+ addattr_l(n, 1024, IFLA_CAN_CTRLMODE, &cm, sizeof(cm));
+
+ return 0;
+}
+
+static const char *can_state_names[] = {
+ [CAN_STATE_ERROR_ACTIVE] = "ERROR-ACTIVE",
+ [CAN_STATE_ERROR_WARNING] = "ERROR-WARNING",
+ [CAN_STATE_ERROR_PASSIVE] = "ERROR-PASSIVE",
+ [CAN_STATE_BUS_OFF] = "BUS-OFF",
+ [CAN_STATE_STOPPED] = "STOPPED",
+ [CAN_STATE_SLEEPING] = "SLEEPING"
+};
+
+static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
+{
+ if (!tb)
+ return;
+
+ if (tb[IFLA_CAN_CTRLMODE]) {
+ struct can_ctrlmode *cm = RTA_DATA(tb[IFLA_CAN_CTRLMODE]);
+
+ if (cm->flags)
+ print_ctrlmode(f, cm->flags);
+ }
+
+ if (tb[IFLA_CAN_STATE]) {
+ int *state = RTA_DATA(tb[IFLA_CAN_STATE]);
+
+ fprintf(f, "state %s ", *state <= CAN_STATE_MAX ?
+ can_state_names[*state] : "UNKNOWN");
+ }
+
+ if (tb[IFLA_CAN_BERR_COUNTER]) {
+ struct can_berr_counter *bc =
+ RTA_DATA(tb[IFLA_CAN_BERR_COUNTER]);
+
+ fprintf(f, "(berr-counter tx %d rx %d) ", bc->txerr, bc->rxerr);
+ }
+
+ if (tb[IFLA_CAN_RESTART_MS]) {
+ __u32 *restart_ms = RTA_DATA(tb[IFLA_CAN_RESTART_MS]);
+
+ fprintf(f, "restart-ms %d ", *restart_ms);
+ }
+
+ if (tb[IFLA_CAN_BITTIMING]) {
+ struct can_bittiming *bt = RTA_DATA(tb[IFLA_CAN_BITTIMING]);
+
+ fprintf(f, "\n "
+ "bitrate %d sample-point %.3f ",
+ bt->bitrate, (float)bt->sample_point / 1000.);
+ fprintf(f, "\n "
+ "tq %d prop-seg %d phase-seg1 %d phase-seg2 %d sjw %d",
+ bt->tq, bt->prop_seg, bt->phase_seg1, bt->phase_seg2,
+ bt->sjw);
+ }
+
+ if (tb[IFLA_CAN_BITTIMING_CONST]) {
+ struct can_bittiming_const *btc =
+ RTA_DATA(tb[IFLA_CAN_BITTIMING_CONST]);
+
+ fprintf(f, "\n "
+ "%s: tseg1 %d..%d tseg2 %d..%d "
+ "sjw 1..%d brp %d..%d brp-inc %d",
+ btc->name, btc->tseg1_min, btc->tseg1_max,
+ btc->tseg2_min, btc->tseg2_max, btc->sjw_max,
+ btc->brp_min, btc->brp_max, btc->brp_inc);
+ }
+
+ if (tb[IFLA_CAN_CLOCK]) {
+ struct can_clock *clock = RTA_DATA(tb[IFLA_CAN_CLOCK]);
+
+ fprintf(f, "\n clock %d", clock->freq);
+ }
+
+}
+
+static void can_print_xstats(struct link_util *lu,
+ FILE *f, struct rtattr *xstats)
+{
+ struct can_device_stats *stats;
+
+ if (xstats && RTA_PAYLOAD(xstats) == sizeof(*stats)) {
+ stats = RTA_DATA(xstats);
+ fprintf(f, "\n "
+ "re-started bus-errors arbit-lost "
+ "error-warn error-pass bus-off");
+ fprintf(f, "\n %-10d %-10d %-10d %-10d %-10d %-10d",
+ stats->restarts, stats->bus_error,
+ stats->arbitration_lost, stats->error_warning,
+ stats->error_passive, stats->bus_off);
+ }
+}
+
+struct link_util can_link_util = {
+ .id = "can",
+ .maxattr = IFLA_CAN_MAX,
+ .parse_opt = can_parse_opt,
+ .print_opt = can_print_opt,
+ .print_xstats = can_print_xstats,
+};
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/iplink_macvlan.c b/ap/app/iproute2/iproute2-3.4.0/ip/iplink_macvlan.c
new file mode 100755
index 0000000..ed0e34b
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/iplink_macvlan.c
@@ -0,0 +1,96 @@
+/*
+ * iplink_vlan.c VLAN device support
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Patrick McHardy <kaber@trash.net>
+ * Arnd Bergmann <arnd@arndb.de>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <linux/if_link.h>
+
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+
+static void explain(void)
+{
+ fprintf(stderr,
+ "Usage: ... macvlan mode { private | vepa | bridge | passthru }\n"
+ );
+}
+
+static int mode_arg(void)
+{
+ fprintf(stderr, "Error: argument of \"mode\" must be \"private\", "
+ "\"vepa\", \"bridge\" or \"passthru\" \n");
+ return -1;
+}
+
+static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv,
+ struct nlmsghdr *n)
+{
+ while (argc > 0) {
+ if (matches(*argv, "mode") == 0) {
+ __u32 mode = 0;
+ NEXT_ARG();
+
+ if (strcmp(*argv, "private") == 0)
+ mode = MACVLAN_MODE_PRIVATE;
+ else if (strcmp(*argv, "vepa") == 0)
+ mode = MACVLAN_MODE_VEPA;
+ else if (strcmp(*argv, "bridge") == 0)
+ mode = MACVLAN_MODE_BRIDGE;
+ else if (strcmp(*argv, "passthru") == 0)
+ mode = MACVLAN_MODE_PASSTHRU;
+ else
+ return mode_arg();
+
+ addattr32(n, 1024, IFLA_MACVLAN_MODE, mode);
+ } else if (matches(*argv, "help") == 0) {
+ explain();
+ return -1;
+ } else {
+ fprintf(stderr, "macvlan: what is \"%s\"?\n", *argv);
+ explain();
+ return -1;
+ }
+ argc--, argv++;
+ }
+
+ return 0;
+}
+
+static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
+{
+ __u32 mode;
+
+ if (!tb)
+ return;
+
+ if (!tb[IFLA_MACVLAN_MODE] ||
+ RTA_PAYLOAD(tb[IFLA_MACVLAN_MODE]) < sizeof(__u32))
+ return;
+
+ mode = rta_getattr_u32(tb[IFLA_VLAN_ID]);
+ fprintf(f, " mode %s ",
+ mode == MACVLAN_MODE_PRIVATE ? "private"
+ : mode == MACVLAN_MODE_VEPA ? "vepa"
+ : mode == MACVLAN_MODE_BRIDGE ? "bridge"
+ : mode == MACVLAN_MODE_PASSTHRU ? "passthru"
+ : "unknown");
+}
+
+struct link_util macvlan_link_util = {
+ .id = "macvlan",
+ .maxattr = IFLA_MACVLAN_MAX,
+ .parse_opt = macvlan_parse_opt,
+ .print_opt = macvlan_print_opt,
+};
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/iplink_macvtap.c b/ap/app/iproute2/iproute2-3.4.0/ip/iplink_macvtap.c
new file mode 100755
index 0000000..6c7fe1f
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/iplink_macvtap.c
@@ -0,0 +1,93 @@
+/*
+ * iplink_macvtap.c macvtap device support
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <linux/if_link.h>
+
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+
+static void explain(void)
+{
+ fprintf(stderr,
+ "Usage: ... macvtap mode { private | vepa | bridge | passthru }\n"
+ );
+}
+
+static int mode_arg(void)
+{
+ fprintf(stderr, "Error: argument of \"mode\" must be \"private\", "
+ "\"vepa\", \"bridge\" or \"passthru\" \n");
+ return -1;
+}
+
+static int macvtap_parse_opt(struct link_util *lu, int argc, char **argv,
+ struct nlmsghdr *n)
+{
+ while (argc > 0) {
+ if (matches(*argv, "mode") == 0) {
+ __u32 mode = 0;
+ NEXT_ARG();
+
+ if (strcmp(*argv, "private") == 0)
+ mode = MACVLAN_MODE_PRIVATE;
+ else if (strcmp(*argv, "vepa") == 0)
+ mode = MACVLAN_MODE_VEPA;
+ else if (strcmp(*argv, "bridge") == 0)
+ mode = MACVLAN_MODE_BRIDGE;
+ else if (strcmp(*argv, "passthru") == 0)
+ mode = MACVLAN_MODE_PASSTHRU;
+ else
+ return mode_arg();
+
+ addattr32(n, 1024, IFLA_MACVLAN_MODE, mode);
+ } else if (matches(*argv, "help") == 0) {
+ explain();
+ return -1;
+ } else {
+ fprintf(stderr, "macvtap: what is \"%s\"?\n", *argv);
+ explain();
+ return -1;
+ }
+ argc--, argv++;
+ }
+
+ return 0;
+}
+
+static void macvtap_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
+{
+ __u32 mode;
+
+ if (!tb)
+ return;
+
+ if (!tb[IFLA_MACVLAN_MODE] ||
+ RTA_PAYLOAD(tb[IFLA_MACVLAN_MODE]) < sizeof(__u32))
+ return;
+
+ mode = rta_getattr_u32(tb[IFLA_VLAN_ID]);
+ fprintf(f, " mode %s ",
+ mode == MACVLAN_MODE_PRIVATE ? "private"
+ : mode == MACVLAN_MODE_VEPA ? "vepa"
+ : mode == MACVLAN_MODE_BRIDGE ? "bridge"
+ : mode == MACVLAN_MODE_PASSTHRU ? "passthru"
+ : "unknown");
+}
+
+struct link_util macvtap_link_util = {
+ .id = "macvtap",
+ .maxattr = IFLA_MACVLAN_MAX,
+ .parse_opt = macvtap_parse_opt,
+ .print_opt = macvtap_print_opt,
+};
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/iplink_vlan.c b/ap/app/iproute2/iproute2-3.4.0/ip/iplink_vlan.c
new file mode 100755
index 0000000..97af8d6
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/iplink_vlan.c
@@ -0,0 +1,205 @@
+/*
+ * iplink_vlan.c VLAN device support
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Patrick McHardy <kaber@trash.net>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <linux/if_vlan.h>
+
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+
+static void explain(void)
+{
+ fprintf(stderr,
+ "Usage: ... vlan id VLANID [ FLAG-LIST ]\n"
+ " [ ingress-qos-map QOS-MAP ] [ egress-qos-map QOS-MAP ]\n"
+ "\n"
+ "VLANID := 0-4095\n"
+ "FLAG-LIST := [ FLAG-LIST ] FLAG\n"
+ "FLAG := [ reorder_hdr { on | off } ] [ gvrp { on | off } ]\n"
+ " [ loose_binding { on | off } ]\n"
+ "QOS-MAP := [ QOS-MAP ] QOS-MAPPING\n"
+ "QOS-MAPPING := FROM:TO\n"
+ );
+}
+
+static int on_off(char *msg)
+{
+ fprintf(stderr, "Error: argument of \"%s\" must be \"on\" or \"off\"\n", msg);
+ return -1;
+}
+
+static int vlan_parse_qos_map(int *argcp, char ***argvp, struct nlmsghdr *n,
+ int attrtype)
+{
+ int argc = *argcp;
+ char **argv = *argvp;
+ struct ifla_vlan_qos_mapping m;
+ struct rtattr *tail;
+
+ tail = NLMSG_TAIL(n);
+ addattr_l(n, 1024, attrtype, NULL, 0);
+
+ while (argc > 0) {
+ char *colon = strchr(*argv, ':');
+
+ if (!colon)
+ break;
+ *colon = '\0';
+
+ if (get_u32(&m.from, *argv, 0))
+ return 1;
+ if (get_u32(&m.to, colon + 1, 0))
+ return 1;
+ argc--, argv++;
+
+ addattr_l(n, 1024, IFLA_VLAN_QOS_MAPPING, &m, sizeof(m));
+ }
+
+ tail->rta_len = (void *) NLMSG_TAIL(n) - (void *)tail;
+
+ *argcp = argc;
+ *argvp = argv;
+ return 0;
+}
+
+static int vlan_parse_opt(struct link_util *lu, int argc, char **argv,
+ struct nlmsghdr *n)
+{
+ struct ifla_vlan_flags flags = { 0 };
+ __u16 id;
+
+ while (argc > 0) {
+ if (matches(*argv, "id") == 0) {
+ NEXT_ARG();
+ if (get_u16(&id, *argv, 0))
+ invarg("id is invalid", *argv);
+ addattr_l(n, 1024, IFLA_VLAN_ID, &id, 2);
+ } else if (matches(*argv, "reorder_hdr") == 0) {
+ NEXT_ARG();
+ flags.mask |= VLAN_FLAG_REORDER_HDR;
+ if (strcmp(*argv, "on") == 0)
+ flags.flags |= VLAN_FLAG_REORDER_HDR;
+ else if (strcmp(*argv, "off") == 0)
+ flags.flags &= ~VLAN_FLAG_REORDER_HDR;
+ else
+ return on_off("reorder_hdr");
+ } else if (matches(*argv, "gvrp") == 0) {
+ NEXT_ARG();
+ flags.mask |= VLAN_FLAG_GVRP;
+ if (strcmp(*argv, "on") == 0)
+ flags.flags |= VLAN_FLAG_GVRP;
+ else if (strcmp(*argv, "off") == 0)
+ flags.flags &= ~VLAN_FLAG_GVRP;
+ else
+ return on_off("gvrp");
+ } else if (matches(*argv, "loose_binding") == 0) {
+ NEXT_ARG();
+ flags.mask |= VLAN_FLAG_LOOSE_BINDING;
+ if (strcmp(*argv, "on") == 0)
+ flags.flags |= VLAN_FLAG_LOOSE_BINDING;
+ else if (strcmp(*argv, "off") == 0)
+ flags.flags &= ~VLAN_FLAG_LOOSE_BINDING;
+ else
+ return on_off("loose_binding");
+ } else if (matches(*argv, "ingress-qos-map") == 0) {
+ NEXT_ARG();
+ if (vlan_parse_qos_map(&argc, &argv, n,
+ IFLA_VLAN_INGRESS_QOS))
+ invarg("invalid ingress-qos-map", *argv);
+ continue;
+ } else if (matches(*argv, "egress-qos-map") == 0) {
+ NEXT_ARG();
+ if (vlan_parse_qos_map(&argc, &argv, n,
+ IFLA_VLAN_EGRESS_QOS))
+ invarg("invalid egress-qos-map", *argv);
+ continue;
+ } else if (matches(*argv, "help") == 0) {
+ explain();
+ return -1;
+ } else {
+ fprintf(stderr, "vlan: what is \"%s\"?\n", *argv);
+ explain();
+ return -1;
+ }
+ argc--, argv++;
+ }
+
+ if (flags.mask)
+ addattr_l(n, 1024, IFLA_VLAN_FLAGS, &flags, sizeof(flags));
+
+ return 0;
+}
+
+static void vlan_print_map(FILE *f, char *name, struct rtattr *attr)
+{
+ struct ifla_vlan_qos_mapping *m;
+ struct rtattr *i;
+ int rem;
+
+ fprintf(f, "\n %s { ", name);
+
+ rem = RTA_PAYLOAD(attr);
+ for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
+ m = RTA_DATA(i);
+ fprintf(f, "%u:%u ", m->from, m->to);
+ }
+ fprintf(f, "} ");
+}
+
+static void vlan_print_flags(FILE *fp, __u32 flags)
+{
+ fprintf(fp, "<");
+#define _PF(f) if (flags & VLAN_FLAG_##f) { \
+ flags &= ~ VLAN_FLAG_##f; \
+ fprintf(fp, #f "%s", flags ? "," : ""); \
+ }
+ _PF(REORDER_HDR);
+ _PF(GVRP);
+ _PF(LOOSE_BINDING);
+#undef _PF
+ if (flags)
+ fprintf(fp, "%x", flags);
+ fprintf(fp, "> ");
+}
+
+static void vlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
+{
+ struct ifla_vlan_flags *flags;
+ if (!tb)
+ return;
+
+ if (!tb[IFLA_VLAN_ID] ||
+ RTA_PAYLOAD(tb[IFLA_VLAN_ID]) < sizeof(__u16))
+ return;
+
+ fprintf(f, "id %u ", rta_getattr_u16(tb[IFLA_VLAN_ID]));
+
+ if (tb[IFLA_VLAN_FLAGS]) {
+ if (RTA_PAYLOAD(tb[IFLA_VLAN_FLAGS]) < sizeof(*flags))
+ return;
+ flags = RTA_DATA(tb[IFLA_VLAN_FLAGS]);
+ vlan_print_flags(f, flags->flags);
+ }
+ if (tb[IFLA_VLAN_INGRESS_QOS])
+ vlan_print_map(f, "ingress-qos-map", tb[IFLA_VLAN_INGRESS_QOS]);
+ if (tb[IFLA_VLAN_EGRESS_QOS])
+ vlan_print_map(f, "egress-qos-map", tb[IFLA_VLAN_EGRESS_QOS]);
+}
+
+struct link_util vlan_link_util = {
+ .id = "vlan",
+ .maxattr = IFLA_VLAN_MAX,
+ .parse_opt = vlan_parse_opt,
+ .print_opt = vlan_print_opt,
+};
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/ipmaddr.c b/ap/app/iproute2/iproute2-3.4.0/ip/ipmaddr.c
new file mode 100755
index 0000000..3ae9478
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/ipmaddr.c
@@ -0,0 +1,347 @@
+/*
+ * ipmaddr.c "ip maddress".
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include <linux/netdevice.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/sockios.h>
+
+#include "rt_names.h"
+#include "utils.h"
+
+static struct {
+ char *dev;
+ int family;
+} filter;
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: ip maddr [ add | del ] MULTIADDR dev STRING\n");
+ fprintf(stderr, " ip maddr show [ dev STRING ]\n");
+ exit(-1);
+}
+
+static int parse_hex(char *str, unsigned char *addr, size_t size)
+{
+ int len=0;
+
+ while (*str && (len < 2 * size)) {
+ int tmp;
+ if (str[1] == 0)
+ return -1;
+ if (sscanf(str, "%02x", &tmp) != 1)
+ return -1;
+ addr[len] = tmp;
+ len++;
+ str += 2;
+ }
+ return len;
+}
+
+struct ma_info
+{
+ struct ma_info *next;
+ int index;
+ int users;
+ char *features;
+ char name[IFNAMSIZ];
+ inet_prefix addr;
+};
+
+void maddr_ins(struct ma_info **lst, struct ma_info *m)
+{
+ struct ma_info *mp;
+
+ for (; (mp=*lst) != NULL; lst = &mp->next) {
+ if (mp->index > m->index)
+ break;
+ }
+ m->next = *lst;
+ *lst = m;
+}
+
+void read_dev_mcast(struct ma_info **result_p)
+{
+ char buf[256];
+ FILE *fp = fopen("/proc/net/dev_mcast", "r");
+
+ if (!fp)
+ return;
+
+ while (fgets(buf, sizeof(buf), fp)) {
+ char hexa[256];
+ struct ma_info m;
+ int len;
+ int st;
+
+ memset(&m, 0, sizeof(m));
+ sscanf(buf, "%d%s%d%d%s", &m.index, m.name, &m.users, &st,
+ hexa);
+ if (filter.dev && strcmp(filter.dev, m.name))
+ continue;
+
+ m.addr.family = AF_PACKET;
+
+ len = parse_hex(hexa, (unsigned char*)&m.addr.data, sizeof (m.addr.data));
+ if (len >= 0) {
+ struct ma_info *ma = malloc(sizeof(m));
+
+ memcpy(ma, &m, sizeof(m));
+ ma->addr.bytelen = len;
+ ma->addr.bitlen = len<<3;
+ if (st)
+ ma->features = "static";
+ maddr_ins(result_p, ma);
+ }
+ }
+ fclose(fp);
+}
+
+void read_igmp(struct ma_info **result_p)
+{
+ struct ma_info m;
+ char buf[256];
+ FILE *fp = fopen("/proc/net/igmp", "r");
+
+ if (!fp)
+ return;
+ memset(&m, 0, sizeof(m));
+ if (!fgets(buf, sizeof(buf), fp)) {
+ fclose(fp);
+ return;
+ }
+
+ m.addr.family = AF_INET;
+ m.addr.bitlen = 32;
+ m.addr.bytelen = 4;
+
+ while (fgets(buf, sizeof(buf), fp)) {
+ struct ma_info *ma;
+
+ if (buf[0] != '\t') {
+ sscanf(buf, "%d%s", &m.index, m.name);
+ continue;
+ }
+
+ if (filter.dev && strcmp(filter.dev, m.name))
+ continue;
+
+ sscanf(buf, "%08x%d", (__u32*)&m.addr.data, &m.users);
+
+ ma = malloc(sizeof(m));
+ memcpy(ma, &m, sizeof(m));
+ maddr_ins(result_p, ma);
+ }
+ fclose(fp);
+}
+
+
+void read_igmp6(struct ma_info **result_p)
+{
+ char buf[256];
+ FILE *fp = fopen("/proc/net/igmp6", "r");
+
+ if (!fp)
+ return;
+
+ while (fgets(buf, sizeof(buf), fp)) {
+ char hexa[256];
+ struct ma_info m;
+ int len;
+
+ memset(&m, 0, sizeof(m));
+ sscanf(buf, "%d%s%s%d", &m.index, m.name, hexa, &m.users);
+
+ if (filter.dev && strcmp(filter.dev, m.name))
+ continue;
+
+ m.addr.family = AF_INET6;
+
+ len = parse_hex(hexa, (unsigned char*)&m.addr.data, sizeof (m.addr.data));
+ if (len >= 0) {
+ struct ma_info *ma = malloc(sizeof(m));
+
+ memcpy(ma, &m, sizeof(m));
+
+ ma->addr.bytelen = len;
+ ma->addr.bitlen = len<<3;
+ maddr_ins(result_p, ma);
+ }
+ }
+ fclose(fp);
+}
+
+static void print_maddr(FILE *fp, struct ma_info *list)
+{
+ fprintf(fp, "\t");
+
+ if (list->addr.family == AF_PACKET) {
+ SPRINT_BUF(b1);
+ fprintf(fp, "link %s", ll_addr_n2a((unsigned char*)list->addr.data,
+ list->addr.bytelen, 0,
+ b1, sizeof(b1)));
+ } else {
+ char abuf[256];
+ switch(list->addr.family) {
+ case AF_INET:
+ fprintf(fp, "inet ");
+ break;
+ case AF_INET6:
+ fprintf(fp, "inet6 ");
+ break;
+ default:
+ fprintf(fp, "family %d ", list->addr.family);
+ break;
+ }
+ fprintf(fp, "%s",
+ format_host(list->addr.family,
+ -1,
+ list->addr.data,
+ abuf, sizeof(abuf)));
+ }
+ if (list->users != 1)
+ fprintf(fp, " users %d", list->users);
+ if (list->features)
+ fprintf(fp, " %s", list->features);
+ fprintf(fp, "\n");
+}
+
+static void print_mlist(FILE *fp, struct ma_info *list)
+{
+ int cur_index = 0;
+
+ for (; list; list = list->next) {
+ if (oneline) {
+ cur_index = list->index;
+ fprintf(fp, "%d:\t%s%s", cur_index, list->name, _SL_);
+ } else if (cur_index != list->index) {
+ cur_index = list->index;
+ fprintf(fp, "%d:\t%s\n", cur_index, list->name);
+ }
+ print_maddr(fp, list);
+ }
+}
+
+static int multiaddr_list(int argc, char **argv)
+{
+ struct ma_info *list = NULL;
+
+ if (!filter.family)
+ filter.family = preferred_family;
+
+ while (argc > 0) {
+ if (1) {
+ if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ }
+ if (matches(*argv, "help") == 0)
+ usage();
+ if (filter.dev)
+ duparg2("dev", *argv);
+ filter.dev = *argv;
+ }
+ argv++; argc--;
+ }
+
+ if (!filter.family || filter.family == AF_PACKET)
+ read_dev_mcast(&list);
+ if (!filter.family || filter.family == AF_INET)
+ read_igmp(&list);
+ if (!filter.family || filter.family == AF_INET6)
+ read_igmp6(&list);
+ print_mlist(stdout, list);
+ return 0;
+}
+
+int multiaddr_modify(int cmd, int argc, char **argv)
+{
+ struct ifreq ifr;
+ int fd;
+
+ memset(&ifr, 0, sizeof(ifr));
+
+ if (cmd == RTM_NEWADDR)
+ cmd = SIOCADDMULTI;
+ else
+ cmd = SIOCDELMULTI;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ if (ifr.ifr_name[0])
+ duparg("dev", *argv);
+ strncpy(ifr.ifr_name, *argv, IFNAMSIZ);
+ } else {
+ if (matches(*argv, "address") == 0) {
+ NEXT_ARG();
+ }
+ if (matches(*argv, "help") == 0)
+ usage();
+ if (ifr.ifr_hwaddr.sa_data[0])
+ duparg("address", *argv);
+ if (ll_addr_a2n(ifr.ifr_hwaddr.sa_data,
+ 14, *argv) < 0) {
+ fprintf(stderr, "Error: \"%s\" is not a legal ll address.\n", *argv);
+ exit(1);
+ }
+ }
+ argc--; argv++;
+ }
+ if (ifr.ifr_name[0] == 0) {
+ fprintf(stderr, "Not enough information: \"dev\" is required.\n");
+ exit(-1);
+ }
+
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ perror("Cannot create socket");
+ exit(1);
+ }
+ if (ioctl(fd, cmd, (char*)&ifr) != 0) {
+ perror("ioctl");
+ exit(1);
+ }
+ close(fd);
+
+ exit(0);
+}
+
+
+int do_multiaddr(int argc, char **argv)
+{
+ if (argc < 1)
+ return multiaddr_list(0, NULL);
+ if (matches(*argv, "add") == 0)
+ return multiaddr_modify(RTM_NEWADDR, argc-1, argv+1);
+ if (matches(*argv, "delete") == 0)
+ return multiaddr_modify(RTM_DELADDR, argc-1, argv+1);
+ if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
+ || matches(*argv, "lst") == 0)
+ return multiaddr_list(argc-1, argv+1);
+ if (matches(*argv, "help") == 0)
+ usage();
+ fprintf(stderr, "Command \"%s\" is unknown, try \"ip maddr help\".\n", *argv);
+ exit(-1);
+}
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/ipmonitor.c b/ap/app/iproute2/iproute2-3.4.0/ip/ipmonitor.c
new file mode 100755
index 0000000..4b1d469
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/ipmonitor.c
@@ -0,0 +1,197 @@
+/*
+ * ipmonitor.c "ip monitor".
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <time.h>
+
+#include "utils.h"
+#include "ip_common.h"
+
+static void usage(void) __attribute__((noreturn));
+int prefix_banner;
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: ip monitor [ all | LISTofOBJECTS ]\n");
+ exit(-1);
+}
+
+
+int accept_msg(const struct sockaddr_nl *who,
+ struct nlmsghdr *n, void *arg)
+{
+ FILE *fp = (FILE*)arg;
+
+ if (timestamp)
+ print_timestamp(fp);
+
+ if (n->nlmsg_type == RTM_NEWROUTE || n->nlmsg_type == RTM_DELROUTE) {
+ if (prefix_banner)
+ fprintf(fp, "[ROUTE]");
+ print_route(who, n, arg);
+ return 0;
+ }
+ if (n->nlmsg_type == RTM_NEWLINK || n->nlmsg_type == RTM_DELLINK) {
+ ll_remember_index(who, n, NULL);
+ if (prefix_banner)
+ fprintf(fp, "[LINK]");
+ print_linkinfo(who, n, arg);
+ return 0;
+ }
+ if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) {
+ if (prefix_banner)
+ fprintf(fp, "[ADDR]");
+ print_addrinfo(who, n, arg);
+ return 0;
+ }
+ if (n->nlmsg_type == RTM_NEWADDRLABEL || n->nlmsg_type == RTM_DELADDRLABEL) {
+ if (prefix_banner)
+ fprintf(fp, "[ADDRLABEL]");
+ print_addrlabel(who, n, arg);
+ return 0;
+ }
+ if (n->nlmsg_type == RTM_NEWNEIGH || n->nlmsg_type == RTM_DELNEIGH) {
+ if (prefix_banner)
+ fprintf(fp, "[NEIGH]");
+ print_neigh(who, n, arg);
+ return 0;
+ }
+ if (n->nlmsg_type == RTM_NEWPREFIX) {
+ if (prefix_banner)
+ fprintf(fp, "[PREFIX]");
+ print_prefix(who, n, arg);
+ return 0;
+ }
+ if (n->nlmsg_type == RTM_NEWRULE || n->nlmsg_type == RTM_DELRULE) {
+ if (prefix_banner)
+ fprintf(fp, "[RULE]");
+ print_rule(who, n, arg);
+ return 0;
+ }
+ if (n->nlmsg_type == 15) {
+ char *tstr;
+ time_t secs = ((__u32*)NLMSG_DATA(n))[0];
+ long usecs = ((__u32*)NLMSG_DATA(n))[1];
+ tstr = asctime(localtime(&secs));
+ tstr[strlen(tstr)-1] = 0;
+ fprintf(fp, "Timestamp: %s %lu us\n", tstr, usecs);
+ return 0;
+ }
+ if (n->nlmsg_type == RTM_NEWQDISC ||
+ n->nlmsg_type == RTM_DELQDISC ||
+ n->nlmsg_type == RTM_NEWTCLASS ||
+ n->nlmsg_type == RTM_DELTCLASS ||
+ n->nlmsg_type == RTM_NEWTFILTER ||
+ n->nlmsg_type == RTM_DELTFILTER)
+ return 0;
+ if (n->nlmsg_type != NLMSG_ERROR && n->nlmsg_type != NLMSG_NOOP &&
+ n->nlmsg_type != NLMSG_DONE) {
+ fprintf(fp, "Unknown message: %08x %08x %08x\n",
+ n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
+ }
+ return 0;
+}
+
+int do_ipmonitor(int argc, char **argv)
+{
+ char *file = NULL;
+ unsigned groups = ~RTMGRP_TC;
+ int llink=0;
+ int laddr=0;
+ int lroute=0;
+ int lprefix=0;
+ int lneigh=0;
+
+ rtnl_close(&rth);
+ ipaddr_reset_filter(1);
+ iproute_reset_filter();
+ ipneigh_reset_filter();
+
+ while (argc > 0) {
+ if (matches(*argv, "file") == 0) {
+ NEXT_ARG();
+ file = *argv;
+ } else if (matches(*argv, "link") == 0) {
+ llink=1;
+ groups = 0;
+ } else if (matches(*argv, "address") == 0) {
+ laddr=1;
+ groups = 0;
+ } else if (matches(*argv, "route") == 0) {
+ lroute=1;
+ groups = 0;
+ } else if (matches(*argv, "prefix") == 0) {
+ lprefix=1;
+ groups = 0;
+ } else if (matches(*argv, "neigh") == 0) {
+ lneigh = 1;
+ groups = 0;
+ } else if (strcmp(*argv, "all") == 0) {
+ groups = ~RTMGRP_TC;
+ prefix_banner=1;
+ } else if (matches(*argv, "help") == 0) {
+ usage();
+ } else {
+ fprintf(stderr, "Argument \"%s\" is unknown, try \"ip monitor help\".\n", *argv);
+ exit(-1);
+ }
+ argc--; argv++;
+ }
+
+ if (llink)
+ groups |= nl_mgrp(RTNLGRP_LINK);
+ if (laddr) {
+ if (!preferred_family || preferred_family == AF_INET)
+ groups |= nl_mgrp(RTNLGRP_IPV4_IFADDR);
+ if (!preferred_family || preferred_family == AF_INET6)
+ groups |= nl_mgrp(RTNLGRP_IPV6_IFADDR);
+ }
+ if (lroute) {
+ if (!preferred_family || preferred_family == AF_INET)
+ groups |= nl_mgrp(RTNLGRP_IPV4_ROUTE);
+ if (!preferred_family || preferred_family == AF_INET6)
+ groups |= nl_mgrp(RTNLGRP_IPV6_ROUTE);
+ }
+ if (lprefix) {
+ if (!preferred_family || preferred_family == AF_INET6)
+ groups |= nl_mgrp(RTNLGRP_IPV6_PREFIX);
+ }
+ if (lneigh) {
+ groups |= nl_mgrp(RTNLGRP_NEIGH);
+ }
+ if (file) {
+ FILE *fp;
+ fp = fopen(file, "r");
+ if (fp == NULL) {
+ perror("Cannot fopen");
+ exit(-1);
+ }
+ return rtnl_from_file(fp, accept_msg, stdout);
+ }
+
+ if (rtnl_open(&rth, groups) < 0)
+ exit(1);
+ ll_init_map(&rth);
+
+ if (rtnl_listen(&rth, accept_msg, stdout) < 0)
+ exit(2);
+
+ return 0;
+}
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/ipmroute.c b/ap/app/iproute2/iproute2-3.4.0/ip/ipmroute.c
new file mode 100755
index 0000000..c3b9098
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/ipmroute.c
@@ -0,0 +1,212 @@
+/*
+ * ipmroute.c "ip mroute".
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include <linux/netdevice.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/sockios.h>
+
+#include "utils.h"
+
+char filter_dev[16];
+int filter_family;
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: ip mroute show [ PREFIX ] [ from PREFIX ] [ iif DEVICE ]\n");
+#if 0
+ fprintf(stderr, "Usage: ip mroute [ add | del ] DESTINATION from SOURCE [ iif DEVICE ] [ oif DEVICE ]\n");
+#endif
+ exit(-1);
+}
+
+static char *viftable[32];
+
+struct rtfilter
+{
+ inet_prefix mdst;
+ inet_prefix msrc;
+};
+static struct rtfilter filter;
+
+static void read_viftable(void)
+{
+ char buf[256];
+ FILE *fp = fopen("/proc/net/ip_mr_vif", "r");
+
+ if (!fp)
+ return;
+
+ if (!fgets(buf, sizeof(buf), fp)) {
+ fclose(fp);
+ return;
+ }
+ while (fgets(buf, sizeof(buf), fp)) {
+ int vifi;
+ char dev[256];
+
+ if (sscanf(buf, "%d%s", &vifi, dev) < 2)
+ continue;
+
+ if (vifi<0 || vifi>31)
+ continue;
+
+ viftable[vifi] = strdup(dev);
+ }
+ fclose(fp);
+}
+
+static void read_mroute_list(FILE *ofp)
+{
+ char buf[256];
+ FILE *fp = fopen("/proc/net/ip_mr_cache", "r");
+
+ if (!fp)
+ return;
+
+ if (!fgets(buf, sizeof(buf), fp)) {
+ fclose(fp);
+ return;
+ }
+
+ while (fgets(buf, sizeof(buf), fp)) {
+ inet_prefix maddr, msrc;
+ unsigned pkts, b, w;
+ int vifi;
+ char oiflist[256];
+ char sbuf[256];
+ char mbuf[256];
+ char obuf[256];
+
+ oiflist[0] = 0;
+ if (sscanf(buf, "%x%x%d%u%u%u %[^\n]",
+ maddr.data, msrc.data, &vifi,
+ &pkts, &b, &w, oiflist) < 6)
+ continue;
+
+ if (vifi!=-1 && (vifi < 0 || vifi>31))
+ continue;
+
+ if (filter_dev[0] && (vifi<0 || strcmp(filter_dev, viftable[vifi])))
+ continue;
+ if (filter.mdst.family && inet_addr_match(&maddr, &filter.mdst, filter.mdst.bitlen))
+ continue;
+ if (filter.msrc.family && inet_addr_match(&msrc, &filter.msrc, filter.msrc.bitlen))
+ continue;
+
+ snprintf(obuf, sizeof(obuf), "(%s, %s)",
+ format_host(AF_INET, 4, &msrc.data[0], sbuf, sizeof(sbuf)),
+ format_host(AF_INET, 4, &maddr.data[0], mbuf, sizeof(mbuf)));
+
+ fprintf(ofp, "%-32s Iif: ", obuf);
+
+ if (vifi == -1)
+ fprintf(ofp, "unresolved ");
+ else
+ fprintf(ofp, "%-10s ", viftable[vifi]);
+
+ if (oiflist[0]) {
+ char *next = NULL;
+ char *p = oiflist;
+ int ovifi, ottl;
+
+ fprintf(ofp, "Oifs: ");
+
+ while (p) {
+ next = strchr(p, ' ');
+ if (next) {
+ *next = 0;
+ next++;
+ }
+ if (sscanf(p, "%d:%d", &ovifi, &ottl)<2) {
+ p = next;
+ continue;
+ }
+ p = next;
+
+ fprintf(ofp, "%s", viftable[ovifi]);
+ if (ottl>1)
+ fprintf(ofp, "(ttl %d) ", ovifi);
+ else
+ fprintf(ofp, " ");
+ }
+ }
+
+ if (show_stats && b) {
+ fprintf(ofp, "%s %u packets, %u bytes", _SL_, pkts, b);
+ if (w)
+ fprintf(ofp, ", %u arrived on wrong iif.", w);
+ }
+ fprintf(ofp, "\n");
+ }
+ fclose(fp);
+}
+
+
+static int mroute_list(int argc, char **argv)
+{
+ while (argc > 0) {
+ if (strcmp(*argv, "iif") == 0) {
+ NEXT_ARG();
+ strncpy(filter_dev, *argv, sizeof(filter_dev)-1);
+ } else if (matches(*argv, "from") == 0) {
+ NEXT_ARG();
+ get_prefix(&filter.msrc, *argv, AF_INET);
+ } else {
+ if (strcmp(*argv, "to") == 0) {
+ NEXT_ARG();
+ }
+ if (matches(*argv, "help") == 0)
+ usage();
+ get_prefix(&filter.mdst, *argv, AF_INET);
+ }
+ argv++; argc--;
+ }
+
+ read_viftable();
+ read_mroute_list(stdout);
+ return 0;
+}
+
+int do_multiroute(int argc, char **argv)
+{
+ if (argc < 1)
+ return mroute_list(0, NULL);
+#if 0
+ if (matches(*argv, "add") == 0)
+ return mroute_modify(RTM_NEWADDR, argc-1, argv+1);
+ if (matches(*argv, "delete") == 0)
+ return mroute_modify(RTM_DELADDR, argc-1, argv+1);
+ if (matches(*argv, "get") == 0)
+ return mroute_get(argc-1, argv+1);
+#endif
+ if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
+ || matches(*argv, "lst") == 0)
+ return mroute_list(argc-1, argv+1);
+ if (matches(*argv, "help") == 0)
+ usage();
+ fprintf(stderr, "Command \"%s\" is unknown, try \"ip mroute help\".\n", *argv);
+ exit(-1);
+}
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/ipneigh.c b/ap/app/iproute2/iproute2-3.4.0/ip/ipneigh.c
new file mode 100755
index 0000000..93cfba2
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/ipneigh.c
@@ -0,0 +1,472 @@
+/*
+ * ipneigh.c "ip neigh".
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+
+#define NUD_VALID (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE|NUD_PROBE|NUD_STALE|NUD_DELAY)
+#define MAX_ROUNDS 10
+
+static struct
+{
+ int family;
+ int index;
+ int state;
+ int unused_only;
+ inet_prefix pfx;
+ int flushed;
+ char *flushb;
+ int flushp;
+ int flushe;
+} filter;
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: ip neigh { add | del | change | replace } { ADDR [ lladdr LLADDR ]\n"
+ " [ nud { permanent | noarp | stale | reachable } ]\n"
+ " | proxy ADDR } [ dev DEV ]\n");
+ fprintf(stderr, " ip neigh {show|flush} [ to PREFIX ] [ dev DEV ] [ nud STATE ]\n");
+ exit(-1);
+}
+
+int nud_state_a2n(unsigned *state, char *arg)
+{
+ if (matches(arg, "permanent") == 0)
+ *state = NUD_PERMANENT;
+ else if (matches(arg, "reachable") == 0)
+ *state = NUD_REACHABLE;
+ else if (strcmp(arg, "noarp") == 0)
+ *state = NUD_NOARP;
+ else if (strcmp(arg, "none") == 0)
+ *state = NUD_NONE;
+ else if (strcmp(arg, "stale") == 0)
+ *state = NUD_STALE;
+ else if (strcmp(arg, "incomplete") == 0)
+ *state = NUD_INCOMPLETE;
+ else if (strcmp(arg, "delay") == 0)
+ *state = NUD_DELAY;
+ else if (strcmp(arg, "probe") == 0)
+ *state = NUD_PROBE;
+ else if (matches(arg, "failed") == 0)
+ *state = NUD_FAILED;
+ else {
+ if (get_unsigned(state, arg, 0))
+ return -1;
+ if (*state>=0x100 || (*state&((*state)-1)))
+ return -1;
+ }
+ return 0;
+}
+
+static int flush_update(void)
+{
+ if (rtnl_send_check(&rth, filter.flushb, filter.flushp) < 0) {
+ perror("Failed to send flush request");
+ return -1;
+ }
+ filter.flushp = 0;
+ return 0;
+}
+
+
+static int ipneigh_modify(int cmd, int flags, int argc, char **argv)
+{
+ struct {
+ struct nlmsghdr n;
+ struct ndmsg ndm;
+ char buf[256];
+ } req;
+ char *d = NULL;
+ int dst_ok = 0;
+ int lladdr_ok = 0;
+ char * lla = NULL;
+ inet_prefix dst;
+
+ memset(&req, 0, sizeof(req));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST|flags;
+ req.n.nlmsg_type = cmd;
+ req.ndm.ndm_family = preferred_family;
+ req.ndm.ndm_state = NUD_PERMANENT;
+
+ while (argc > 0) {
+ if (matches(*argv, "lladdr") == 0) {
+ NEXT_ARG();
+ if (lladdr_ok)
+ duparg("lladdr", *argv);
+ lla = *argv;
+ lladdr_ok = 1;
+ } else if (strcmp(*argv, "nud") == 0) {
+ unsigned state;
+ NEXT_ARG();
+ if (nud_state_a2n(&state, *argv))
+ invarg("nud state is bad", *argv);
+ req.ndm.ndm_state = state;
+ } else if (matches(*argv, "proxy") == 0) {
+ NEXT_ARG();
+ if (matches(*argv, "help") == 0)
+ usage();
+ if (dst_ok)
+ duparg("address", *argv);
+ get_addr(&dst, *argv, preferred_family);
+ dst_ok = 1;
+ req.ndm.ndm_flags |= NTF_PROXY;
+ } else if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ d = *argv;
+ } else {
+ if (strcmp(*argv, "to") == 0) {
+ NEXT_ARG();
+ }
+ if (matches(*argv, "help") == 0) {
+ NEXT_ARG();
+ }
+ if (dst_ok)
+ duparg2("to", *argv);
+ get_addr(&dst, *argv, preferred_family);
+ dst_ok = 1;
+ }
+ argc--; argv++;
+ }
+ if (d == NULL || !dst_ok || dst.family == AF_UNSPEC) {
+ fprintf(stderr, "Device and destination are required arguments.\n");
+ exit(-1);
+ }
+ req.ndm.ndm_family = dst.family;
+ addattr_l(&req.n, sizeof(req), NDA_DST, &dst.data, dst.bytelen);
+
+ if (lla && strcmp(lla, "null")) {
+ char llabuf[20];
+ int l;
+
+ l = ll_addr_a2n(llabuf, sizeof(llabuf), lla);
+ addattr_l(&req.n, sizeof(req), NDA_LLADDR, llabuf, l);
+ }
+
+ ll_init_map(&rth);
+
+ if ((req.ndm.ndm_ifindex = ll_name_to_index(d)) == 0) {
+ fprintf(stderr, "Cannot find device \"%s\"\n", d);
+ return -1;
+ }
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ exit(2);
+
+ return 0;
+}
+
+
+int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+{
+ FILE *fp = (FILE*)arg;
+ struct ndmsg *r = NLMSG_DATA(n);
+ int len = n->nlmsg_len;
+ struct rtattr * tb[NDA_MAX+1];
+ char abuf[256];
+
+ if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH) {
+ fprintf(stderr, "Not RTM_NEWNEIGH: %08x %08x %08x\n",
+ n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
+
+ return 0;
+ }
+ len -= NLMSG_LENGTH(sizeof(*r));
+ if (len < 0) {
+ fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+ return -1;
+ }
+
+ if (filter.flushb && n->nlmsg_type != RTM_NEWNEIGH)
+ return 0;
+
+ if (filter.family && filter.family != r->ndm_family)
+ return 0;
+ if (filter.index && filter.index != r->ndm_ifindex)
+ return 0;
+ if (!(filter.state&r->ndm_state) &&
+ !(r->ndm_flags & NTF_PROXY) &&
+ (r->ndm_state || !(filter.state&0x100)) &&
+ (r->ndm_family != AF_DECnet))
+ return 0;
+
+ parse_rtattr(tb, NDA_MAX, NDA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
+
+ if (tb[NDA_DST]) {
+ if (filter.pfx.family) {
+ inet_prefix dst;
+ memset(&dst, 0, sizeof(dst));
+ dst.family = r->ndm_family;
+ memcpy(&dst.data, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST]));
+ if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen))
+ return 0;
+ }
+ }
+ if (filter.unused_only && tb[NDA_CACHEINFO]) {
+ struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
+ if (ci->ndm_refcnt)
+ return 0;
+ }
+
+ if (filter.flushb) {
+ struct nlmsghdr *fn;
+ if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) {
+ if (flush_update())
+ return -1;
+ }
+ fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp));
+ memcpy(fn, n, n->nlmsg_len);
+ fn->nlmsg_type = RTM_DELNEIGH;
+ fn->nlmsg_flags = NLM_F_REQUEST;
+ fn->nlmsg_seq = ++rth.seq;
+ filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb;
+ filter.flushed++;
+ if (show_stats < 2)
+ return 0;
+ }
+
+ if (tb[NDA_DST]) {
+ fprintf(fp, "%s ",
+ format_host(r->ndm_family,
+ RTA_PAYLOAD(tb[NDA_DST]),
+ RTA_DATA(tb[NDA_DST]),
+ abuf, sizeof(abuf)));
+ }
+ if (!filter.index && r->ndm_ifindex)
+ fprintf(fp, "dev %s ", ll_index_to_name(r->ndm_ifindex));
+ if (tb[NDA_LLADDR]) {
+ SPRINT_BUF(b1);
+ fprintf(fp, "lladdr %s", ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
+ RTA_PAYLOAD(tb[NDA_LLADDR]),
+ ll_index_to_type(r->ndm_ifindex),
+ b1, sizeof(b1)));
+ }
+ if (r->ndm_flags & NTF_ROUTER) {
+ fprintf(fp, " router");
+ }
+ if (r->ndm_flags & NTF_PROXY) {
+ fprintf(fp, " proxy");
+ }
+ if (tb[NDA_CACHEINFO] && show_stats) {
+ struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
+ int hz = get_user_hz();
+
+ if (ci->ndm_refcnt)
+ printf(" ref %d", ci->ndm_refcnt);
+ fprintf(fp, " used %d/%d/%d", ci->ndm_used/hz,
+ ci->ndm_confirmed/hz, ci->ndm_updated/hz);
+ }
+
+ if (tb[NDA_PROBES] && show_stats) {
+ __u32 p = rta_getattr_u32(tb[NDA_PROBES]);
+ fprintf(fp, " probes %u", p);
+ }
+
+ if (r->ndm_state) {
+ int nud = r->ndm_state;
+ fprintf(fp, " ");
+
+#define PRINT_FLAG(f) if (nud & NUD_##f) { \
+ nud &= ~NUD_##f; fprintf(fp, #f "%s", nud ? "," : ""); }
+ PRINT_FLAG(INCOMPLETE);
+ PRINT_FLAG(REACHABLE);
+ PRINT_FLAG(STALE);
+ PRINT_FLAG(DELAY);
+ PRINT_FLAG(PROBE);
+ PRINT_FLAG(FAILED);
+ PRINT_FLAG(NOARP);
+ PRINT_FLAG(PERMANENT);
+#undef PRINT_FLAG
+ }
+ fprintf(fp, "\n");
+
+ fflush(fp);
+ return 0;
+}
+
+void ipneigh_reset_filter()
+{
+ memset(&filter, 0, sizeof(filter));
+ filter.state = ~0;
+}
+
+int do_show_or_flush(int argc, char **argv, int flush)
+{
+ char *filter_dev = NULL;
+ int state_given = 0;
+ struct ndmsg ndm = { 0 };
+
+ ipneigh_reset_filter();
+
+ if (!filter.family)
+ filter.family = preferred_family;
+
+ if (flush) {
+ if (argc <= 0) {
+ fprintf(stderr, "Flush requires arguments.\n");
+ return -1;
+ }
+ filter.state = ~(NUD_PERMANENT|NUD_NOARP);
+ } else
+ filter.state = 0xFF & ~NUD_NOARP;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ if (filter_dev)
+ duparg("dev", *argv);
+ filter_dev = *argv;
+ } else if (strcmp(*argv, "unused") == 0) {
+ filter.unused_only = 1;
+ } else if (strcmp(*argv, "nud") == 0) {
+ unsigned state;
+ NEXT_ARG();
+ if (!state_given) {
+ state_given = 1;
+ filter.state = 0;
+ }
+ if (nud_state_a2n(&state, *argv)) {
+ if (strcmp(*argv, "all") != 0)
+ invarg("nud state is bad", *argv);
+ state = ~0;
+ if (flush)
+ state &= ~NUD_NOARP;
+ }
+ if (state == 0)
+ state = 0x100;
+ filter.state |= state;
+ } else if (strcmp(*argv, "proxy") == 0)
+ ndm.ndm_flags = NTF_PROXY;
+ else {
+ if (strcmp(*argv, "to") == 0) {
+ NEXT_ARG();
+ }
+ if (matches(*argv, "help") == 0)
+ usage();
+ get_prefix(&filter.pfx, *argv, filter.family);
+ if (filter.family == AF_UNSPEC)
+ filter.family = filter.pfx.family;
+ }
+ argc--; argv++;
+ }
+
+ ll_init_map(&rth);
+
+ if (filter_dev) {
+ if ((filter.index = ll_name_to_index(filter_dev)) == 0) {
+ fprintf(stderr, "Cannot find device \"%s\"\n", filter_dev);
+ return -1;
+ }
+ }
+
+ if (flush) {
+ int round = 0;
+ char flushb[4096-512];
+
+ filter.flushb = flushb;
+ filter.flushp = 0;
+ filter.flushe = sizeof(flushb);
+ filter.state &= ~NUD_FAILED;
+
+ while (round < MAX_ROUNDS) {
+ if (rtnl_wilddump_request(&rth, filter.family, RTM_GETNEIGH) < 0) {
+ perror("Cannot send dump request");
+ exit(1);
+ }
+ filter.flushed = 0;
+ if (rtnl_dump_filter(&rth, print_neigh, stdout) < 0) {
+ fprintf(stderr, "Flush terminated\n");
+ exit(1);
+ }
+ if (filter.flushed == 0) {
+ if (show_stats) {
+ if (round == 0)
+ printf("Nothing to flush.\n");
+ else
+ printf("*** Flush is complete after %d round%s ***\n", round, round>1?"s":"");
+ }
+ fflush(stdout);
+ return 0;
+ }
+ round++;
+ if (flush_update() < 0)
+ exit(1);
+ if (show_stats) {
+ printf("\n*** Round %d, deleting %d entries ***\n", round, filter.flushed);
+ fflush(stdout);
+ }
+ }
+ printf("*** Flush not complete bailing out after %d rounds\n",
+ MAX_ROUNDS);
+ return 1;
+ }
+
+ ndm.ndm_family = filter.family;
+
+ if (rtnl_dump_request(&rth, RTM_GETNEIGH, &ndm, sizeof(struct ndmsg)) < 0) {
+ perror("Cannot send dump request");
+ exit(1);
+ }
+
+ if (rtnl_dump_filter(&rth, print_neigh, stdout) < 0) {
+ fprintf(stderr, "Dump terminated\n");
+ exit(1);
+ }
+
+ return 0;
+}
+
+int do_ipneigh(int argc, char **argv)
+{
+ if (argc > 0) {
+ if (matches(*argv, "add") == 0)
+ return ipneigh_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_EXCL, argc-1, argv+1);
+ if (matches(*argv, "change") == 0 ||
+ strcmp(*argv, "chg") == 0)
+ return ipneigh_modify(RTM_NEWNEIGH, NLM_F_REPLACE, argc-1, argv+1);
+ if (matches(*argv, "replace") == 0)
+ return ipneigh_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_REPLACE, argc-1, argv+1);
+ if (matches(*argv, "delete") == 0)
+ return ipneigh_modify(RTM_DELNEIGH, 0, argc-1, argv+1);
+ if (matches(*argv, "get") == 0) {
+ fprintf(stderr, "Sorry, \"neigh get\" is not implemented :-(\n");
+ return -1;
+ }
+ if (matches(*argv, "show") == 0 ||
+ matches(*argv, "lst") == 0 ||
+ matches(*argv, "list") == 0)
+ return do_show_or_flush(argc-1, argv+1, 0);
+ if (matches(*argv, "flush") == 0)
+ return do_show_or_flush(argc-1, argv+1, 1);
+ if (matches(*argv, "help") == 0)
+ usage();
+ } else
+ return do_show_or_flush(0, NULL, 0);
+
+ fprintf(stderr, "Command \"%s\" is unknown, try \"ip neigh help\".\n", *argv);
+ exit(-1);
+}
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/ipnetns.c b/ap/app/iproute2/iproute2-3.4.0/ip/ipnetns.c
new file mode 100755
index 0000000..e41a598
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/ipnetns.c
@@ -0,0 +1,309 @@
+#define _ATFILE_SOURCE
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/inotify.h>
+#include <sys/mount.h>
+#include <sys/param.h>
+#include <sys/syscall.h>
+#include <stdio.h>
+#include <string.h>
+#include <sched.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "utils.h"
+#include "ip_common.h"
+
+#define NETNS_RUN_DIR "/var/run/netns"
+#define NETNS_ETC_DIR "/etc/netns"
+
+#ifndef CLONE_NEWNET
+#define CLONE_NEWNET 0x40000000 /* New network namespace (lo, device, names sockets, etc) */
+#endif
+
+#ifndef MNT_DETACH
+#define MNT_DETACH 0x00000002 /* Just detach from the tree */
+#endif /* MNT_DETACH */
+
+#ifndef HAVE_SETNS
+static int setns(int fd, int nstype)
+{
+#ifdef __NR_setns
+ return syscall(__NR_setns, fd, nstype);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+#endif /* HAVE_SETNS */
+
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: ip netns list\n");
+ fprintf(stderr, " ip netns add NAME\n");
+ fprintf(stderr, " ip netns delete NAME\n");
+ fprintf(stderr, " ip netns exec NAME cmd ...\n");
+ fprintf(stderr, " ip netns monitor\n");
+ exit(-1);
+}
+
+int get_netns_fd(const char *name)
+{
+ char pathbuf[MAXPATHLEN];
+ const char *path, *ptr;
+
+ path = name;
+ ptr = strchr(name, '/');
+ if (!ptr) {
+ snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
+ NETNS_RUN_DIR, name );
+ path = pathbuf;
+ }
+ return open(path, O_RDONLY);
+}
+
+static int netns_list(int argc, char **argv)
+{
+ struct dirent *entry;
+ DIR *dir;
+
+ dir = opendir(NETNS_RUN_DIR);
+ if (!dir)
+ return 0;
+
+ while ((entry = readdir(dir)) != NULL) {
+ if (strcmp(entry->d_name, ".") == 0)
+ continue;
+ if (strcmp(entry->d_name, "..") == 0)
+ continue;
+ printf("%s\n", entry->d_name);
+ }
+ closedir(dir);
+ return 0;
+}
+
+static void bind_etc(const char *name)
+{
+ char etc_netns_path[MAXPATHLEN];
+ char netns_name[MAXPATHLEN];
+ char etc_name[MAXPATHLEN];
+ struct dirent *entry;
+ DIR *dir;
+
+ snprintf(etc_netns_path, sizeof(etc_netns_path), "%s/%s", NETNS_ETC_DIR, name);
+ dir = opendir(etc_netns_path);
+ if (!dir)
+ return;
+
+ while ((entry = readdir(dir)) != NULL) {
+ if (strcmp(entry->d_name, ".") == 0)
+ continue;
+ if (strcmp(entry->d_name, "..") == 0)
+ continue;
+ snprintf(netns_name, sizeof(netns_name), "%s/%s", etc_netns_path, entry->d_name);
+ snprintf(etc_name, sizeof(etc_name), "/etc/%s", entry->d_name);
+ if (mount(netns_name, etc_name, "none", MS_BIND, NULL) < 0) {
+ fprintf(stderr, "Bind %s -> %s failed: %s\n",
+ netns_name, etc_name, strerror(errno));
+ }
+ }
+ closedir(dir);
+}
+
+static int netns_exec(int argc, char **argv)
+{
+ /* Setup the proper environment for apps that are not netns
+ * aware, and execute a program in that environment.
+ */
+ const char *name, *cmd;
+ char net_path[MAXPATHLEN];
+ int netns;
+
+ if (argc < 1) {
+ fprintf(stderr, "No netns name specified\n");
+ return -1;
+ }
+ if (argc < 2) {
+ fprintf(stderr, "No cmd specified\n");
+ return -1;
+ }
+ name = argv[0];
+ cmd = argv[1];
+ snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name);
+ netns = open(net_path, O_RDONLY);
+ if (netns < 0) {
+ fprintf(stderr, "Cannot open network namespace: %s\n",
+ strerror(errno));
+ return -1;
+ }
+ if (setns(netns, CLONE_NEWNET) < 0) {
+ fprintf(stderr, "seting the network namespace failed: %s\n",
+ strerror(errno));
+ return -1;
+ }
+
+ if (unshare(CLONE_NEWNS) < 0) {
+ fprintf(stderr, "unshare failed: %s\n", strerror(errno));
+ return -1;
+ }
+ /* Mount a version of /sys that describes the network namespace */
+ if (umount2("/sys", MNT_DETACH) < 0) {
+ fprintf(stderr, "umount of /sys failed: %s\n", strerror(errno));
+ return -1;
+ }
+ if (mount(name, "/sys", "sysfs", 0, NULL) < 0) {
+ fprintf(stderr, "mount of /sys failed: %s\n",strerror(errno));
+ return -1;
+ }
+
+ /* Setup bind mounts for config files in /etc */
+ bind_etc(name);
+
+ if (execvp(cmd, argv + 1) < 0)
+ fprintf(stderr, "exec of %s failed: %s\n",
+ cmd, strerror(errno));
+ exit(-1);
+}
+
+static int netns_delete(int argc, char **argv)
+{
+ const char *name;
+ char netns_path[MAXPATHLEN];
+
+ if (argc < 1) {
+ fprintf(stderr, "No netns name specified\n");
+ return -1;
+ }
+
+ name = argv[0];
+ snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
+ umount2(netns_path, MNT_DETACH);
+ if (unlink(netns_path) < 0) {
+ fprintf(stderr, "Cannot remove %s: %s\n",
+ netns_path, strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+static int netns_add(int argc, char **argv)
+{
+ /* This function creates a new network namespace and
+ * a new mount namespace and bind them into a well known
+ * location in the filesystem based on the name provided.
+ *
+ * The mount namespace is created so that any necessary
+ * userspace tweaks like remounting /sys, or bind mounting
+ * a new /etc/resolv.conf can be shared between uers.
+ */
+ char netns_path[MAXPATHLEN];
+ const char *name;
+ int fd;
+
+ if (argc < 1) {
+ fprintf(stderr, "No netns name specified\n");
+ return -1;
+ }
+ name = argv[0];
+
+ snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
+
+ /* Create the base netns directory if it doesn't exist */
+ mkdir(NETNS_RUN_DIR, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
+
+ /* Create the filesystem state */
+ fd = open(netns_path, O_RDONLY|O_CREAT|O_EXCL, 0);
+ if (fd < 0) {
+ fprintf(stderr, "Could not create %s: %s\n",
+ netns_path, strerror(errno));
+ return -1;
+ }
+ close(fd);
+ if (unshare(CLONE_NEWNET) < 0) {
+ fprintf(stderr, "Failed to create a new network namespace: %s\n",
+ strerror(errno));
+ goto out_delete;
+ }
+
+ /* Bind the netns last so I can watch for it */
+ if (mount("/proc/self/ns/net", netns_path, "none", MS_BIND, NULL) < 0) {
+ fprintf(stderr, "Bind /proc/self/ns/net -> %s failed: %s\n",
+ netns_path, strerror(errno));
+ goto out_delete;
+ }
+ return 0;
+out_delete:
+ netns_delete(argc, argv);
+ exit(-1);
+ return -1;
+}
+
+
+static int netns_monitor(int argc, char **argv)
+{
+ char buf[4096];
+ struct inotify_event *event;
+ int fd;
+ fd = inotify_init();
+ if (fd < 0) {
+ fprintf(stderr, "inotify_init failed: %s\n",
+ strerror(errno));
+ return -1;
+ }
+ if (inotify_add_watch(fd, NETNS_RUN_DIR, IN_CREATE | IN_DELETE) < 0) {
+ fprintf(stderr, "inotify_add_watch failed: %s\n",
+ strerror(errno));
+ return -1;
+ }
+ for(;;) {
+ ssize_t len = read(fd, buf, sizeof(buf));
+ if (len < 0) {
+ fprintf(stderr, "read failed: %s\n",
+ strerror(errno));
+ return -1;
+ }
+ for (event = (struct inotify_event *)buf;
+ (char *)event < &buf[len];
+ event = (struct inotify_event *)((char *)event + sizeof(*event) + event->len)) {
+ if (event->mask & IN_CREATE)
+ printf("add %s\n", event->name);
+ if (event->mask & IN_DELETE)
+ printf("delete %s\n", event->name);
+ }
+ }
+ return 0;
+}
+
+int do_netns(int argc, char **argv)
+{
+ if (argc < 1)
+ return netns_list(0, NULL);
+
+ if ((matches(*argv, "list") == 0) || (matches(*argv, "show") == 0) ||
+ (matches(*argv, "lst") == 0))
+ return netns_list(argc-1, argv+1);
+
+ if (matches(*argv, "help") == 0)
+ usage();
+
+ if (matches(*argv, "add") == 0)
+ return netns_add(argc-1, argv+1);
+
+ if (matches(*argv, "delete") == 0)
+ return netns_delete(argc-1, argv+1);
+
+ if (matches(*argv, "exec") == 0)
+ return netns_exec(argc-1, argv+1);
+
+ if (matches(*argv, "monitor") == 0)
+ return netns_monitor(argc-1, argv+1);
+
+ fprintf(stderr, "Command \"%s\" is unknown, try \"ip netns help\".\n", *argv);
+ exit(-1);
+}
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/ipntable.c b/ap/app/iproute2/iproute2-3.4.0/ip/ipntable.c
new file mode 100755
index 0000000..639f512
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/ipntable.c
@@ -0,0 +1,657 @@
+/*
+ * Copyright (C)2006 USAGI/WIDE Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*
+ * based on ipneigh.c
+ */
+/*
+ * Authors:
+ * Masahide NAKAMURA @USAGI
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "utils.h"
+#include "ip_common.h"
+
+static struct
+{
+ int family;
+ int index;
+#define NONE_DEV (-1)
+ char name[1024];
+} filter;
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "Usage: ip ntable change name NAME [ dev DEV ]\n"
+ " [ thresh1 VAL ] [ thresh2 VAL ] [ thresh3 VAL ] [ gc_int MSEC ]\n"
+ " [ PARMS ]\n"
+ "Usage: ip ntable show [ dev DEV ] [ name NAME ]\n"
+
+ "PARMS := [ base_reachable MSEC ] [ retrans MSEC ] [ gc_stale MSEC ]\n"
+ " [ delay_probe MSEC ] [ queue LEN ]\n"
+ " [ app_probs VAL ] [ ucast_probes VAL ] [ mcast_probes VAL ]\n"
+ " [ anycast_delay MSEC ] [ proxy_delay MSEC ] [ proxy_queue LEN ]\n"
+ " [ locktime MSEC ]\n"
+ );
+
+ exit(-1);
+}
+
+static int ipntable_modify(int cmd, int flags, int argc, char **argv)
+{
+ struct {
+ struct nlmsghdr n;
+ struct ndtmsg ndtm;
+ char buf[1024];
+ } req;
+ char *namep = NULL;
+ char *threshsp = NULL;
+ char *gc_intp = NULL;
+ char parms_buf[1024];
+ struct rtattr *parms_rta = (struct rtattr *)parms_buf;
+ int parms_change = 0;
+
+ memset(&req, 0, sizeof(req));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndtmsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST|flags;
+ req.n.nlmsg_type = cmd;
+
+ req.ndtm.ndtm_family = preferred_family;
+ req.ndtm.ndtm_pad1 = 0;
+ req.ndtm.ndtm_pad2 = 0;
+
+ memset(&parms_buf, 0, sizeof(parms_buf));
+
+ parms_rta->rta_type = NDTA_PARMS;
+ parms_rta->rta_len = RTA_LENGTH(0);
+
+ while (argc > 0) {
+ if (strcmp(*argv, "name") == 0) {
+ int len;
+
+ NEXT_ARG();
+ if (namep)
+ duparg("NAME", *argv);
+
+ namep = *argv;
+ len = strlen(namep) + 1;
+ addattr_l(&req.n, sizeof(req), NDTA_NAME, namep, len);
+ } else if (strcmp(*argv, "thresh1") == 0) {
+ __u32 thresh1;
+
+ NEXT_ARG();
+ threshsp = *argv;
+
+ if (get_u32(&thresh1, *argv, 0))
+ invarg("\"thresh1\" value is invalid", *argv);
+
+ addattr32(&req.n, sizeof(req), NDTA_THRESH1, thresh1);
+ } else if (strcmp(*argv, "thresh2") == 0) {
+ __u32 thresh2;
+
+ NEXT_ARG();
+ threshsp = *argv;
+
+ if (get_u32(&thresh2, *argv, 0))
+ invarg("\"thresh2\" value is invalid", *argv);
+
+ addattr32(&req.n, sizeof(req), NDTA_THRESH2, thresh2);
+ } else if (strcmp(*argv, "thresh3") == 0) {
+ __u32 thresh3;
+
+ NEXT_ARG();
+ threshsp = *argv;
+
+ if (get_u32(&thresh3, *argv, 0))
+ invarg("\"thresh3\" value is invalid", *argv);
+
+ addattr32(&req.n, sizeof(req), NDTA_THRESH3, thresh3);
+ } else if (strcmp(*argv, "gc_int") == 0) {
+ __u64 gc_int;
+
+ NEXT_ARG();
+ gc_intp = *argv;
+
+ if (get_u64(&gc_int, *argv, 0))
+ invarg("\"gc_int\" value is invalid", *argv);
+
+ addattr_l(&req.n, sizeof(req), NDTA_GC_INTERVAL,
+ &gc_int, sizeof(gc_int));
+ } else if (strcmp(*argv, "dev") == 0) {
+ __u32 ifindex;
+
+ NEXT_ARG();
+ ifindex = ll_name_to_index(*argv);
+ if (ifindex == 0) {
+ fprintf(stderr, "Cannot find device \"%s\"\n", *argv);
+ return -1;
+ }
+
+ rta_addattr32(parms_rta, sizeof(parms_buf),
+ NDTPA_IFINDEX, ifindex);
+ } else if (strcmp(*argv, "base_reachable") == 0) {
+ __u64 breachable;
+
+ NEXT_ARG();
+
+ if (get_u64(&breachable, *argv, 0))
+ invarg("\"base_reachable\" value is invalid", *argv);
+
+ rta_addattr_l(parms_rta, sizeof(parms_buf),
+ NDTPA_BASE_REACHABLE_TIME,
+ &breachable, sizeof(breachable));
+ parms_change = 1;
+ } else if (strcmp(*argv, "retrans") == 0) {
+ __u64 retrans;
+
+ NEXT_ARG();
+
+ if (get_u64(&retrans, *argv, 0))
+ invarg("\"retrans\" value is invalid", *argv);
+
+ rta_addattr_l(parms_rta, sizeof(parms_buf),
+ NDTPA_RETRANS_TIME,
+ &retrans, sizeof(retrans));
+ parms_change = 1;
+ } else if (strcmp(*argv, "gc_stale") == 0) {
+ __u64 gc_stale;
+
+ NEXT_ARG();
+
+ if (get_u64(&gc_stale, *argv, 0))
+ invarg("\"gc_stale\" value is invalid", *argv);
+
+ rta_addattr_l(parms_rta, sizeof(parms_buf),
+ NDTPA_GC_STALETIME,
+ &gc_stale, sizeof(gc_stale));
+ parms_change = 1;
+ } else if (strcmp(*argv, "delay_probe") == 0) {
+ __u64 delay_probe;
+
+ NEXT_ARG();
+
+ if (get_u64(&delay_probe, *argv, 0))
+ invarg("\"delay_probe\" value is invalid", *argv);
+
+ rta_addattr_l(parms_rta, sizeof(parms_buf),
+ NDTPA_DELAY_PROBE_TIME,
+ &delay_probe, sizeof(delay_probe));
+ parms_change = 1;
+ } else if (strcmp(*argv, "queue") == 0) {
+ __u32 queue;
+
+ NEXT_ARG();
+
+ if (get_u32(&queue, *argv, 0))
+ invarg("\"queue\" value is invalid", *argv);
+
+ if (!parms_rta)
+ parms_rta = (struct rtattr *)&parms_buf;
+ rta_addattr32(parms_rta, sizeof(parms_buf),
+ NDTPA_QUEUE_LEN, queue);
+ parms_change = 1;
+ } else if (strcmp(*argv, "app_probes") == 0) {
+ __u32 aprobe;
+
+ NEXT_ARG();
+
+ if (get_u32(&aprobe, *argv, 0))
+ invarg("\"app_probes\" value is invalid", *argv);
+
+ rta_addattr32(parms_rta, sizeof(parms_buf),
+ NDTPA_APP_PROBES, aprobe);
+ parms_change = 1;
+ } else if (strcmp(*argv, "ucast_probes") == 0) {
+ __u32 uprobe;
+
+ NEXT_ARG();
+
+ if (get_u32(&uprobe, *argv, 0))
+ invarg("\"ucast_probes\" value is invalid", *argv);
+
+ rta_addattr32(parms_rta, sizeof(parms_buf),
+ NDTPA_UCAST_PROBES, uprobe);
+ parms_change = 1;
+ } else if (strcmp(*argv, "mcast_probes") == 0) {
+ __u32 mprobe;
+
+ NEXT_ARG();
+
+ if (get_u32(&mprobe, *argv, 0))
+ invarg("\"mcast_probes\" value is invalid", *argv);
+
+ rta_addattr32(parms_rta, sizeof(parms_buf),
+ NDTPA_MCAST_PROBES, mprobe);
+ parms_change = 1;
+ } else if (strcmp(*argv, "anycast_delay") == 0) {
+ __u64 anycast_delay;
+
+ NEXT_ARG();
+
+ if (get_u64(&anycast_delay, *argv, 0))
+ invarg("\"anycast_delay\" value is invalid", *argv);
+
+ rta_addattr_l(parms_rta, sizeof(parms_buf),
+ NDTPA_ANYCAST_DELAY,
+ &anycast_delay, sizeof(anycast_delay));
+ parms_change = 1;
+ } else if (strcmp(*argv, "proxy_delay") == 0) {
+ __u64 proxy_delay;
+
+ NEXT_ARG();
+
+ if (get_u64(&proxy_delay, *argv, 0))
+ invarg("\"proxy_delay\" value is invalid", *argv);
+
+ rta_addattr_l(parms_rta, sizeof(parms_buf),
+ NDTPA_PROXY_DELAY,
+ &proxy_delay, sizeof(proxy_delay));
+ parms_change = 1;
+ } else if (strcmp(*argv, "proxy_queue") == 0) {
+ __u32 pqueue;
+
+ NEXT_ARG();
+
+ if (get_u32(&pqueue, *argv, 0))
+ invarg("\"proxy_queue\" value is invalid", *argv);
+
+ rta_addattr32(parms_rta, sizeof(parms_buf),
+ NDTPA_PROXY_QLEN, pqueue);
+ parms_change = 1;
+ } else if (strcmp(*argv, "locktime") == 0) {
+ __u64 locktime;
+
+ NEXT_ARG();
+
+ if (get_u64(&locktime, *argv, 0))
+ invarg("\"locktime\" value is invalid", *argv);
+
+ rta_addattr_l(parms_rta, sizeof(parms_buf),
+ NDTPA_LOCKTIME,
+ &locktime, sizeof(locktime));
+ parms_change = 1;
+ } else {
+ invarg("unknown", *argv);
+ }
+
+ argc--; argv++;
+ }
+
+ if (!namep)
+ missarg("NAME");
+ if (!threshsp && !gc_intp && !parms_change) {
+ fprintf(stderr, "Not enough information: changable attributes required.\n");
+ exit(-1);
+ }
+
+ if (parms_rta->rta_len > RTA_LENGTH(0)) {
+ addattr_l(&req.n, sizeof(req), NDTA_PARMS, RTA_DATA(parms_rta),
+ RTA_PAYLOAD(parms_rta));
+ }
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ exit(2);
+
+ return 0;
+}
+
+static const char *ntable_strtime_delta(__u32 msec)
+{
+ static char str[32];
+ struct timeval now;
+ time_t t;
+ struct tm *tp;
+
+ if (msec == 0)
+ goto error;
+
+ memset(&now, 0, sizeof(now));
+
+ if (gettimeofday(&now, NULL) < 0) {
+ perror("gettimeofday");
+ goto error;
+ }
+
+ t = now.tv_sec - (msec / 1000);
+ tp = localtime(&t);
+ if (!tp)
+ goto error;
+
+ strftime(str, sizeof(str), "%Y-%m-%d %T", tp);
+
+ return str;
+ error:
+ strcpy(str, "(error)");
+ return str;
+}
+
+int print_ntable(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+{
+ FILE *fp = (FILE*)arg;
+ struct ndtmsg *ndtm = NLMSG_DATA(n);
+ int len = n->nlmsg_len;
+ struct rtattr *tb[NDTA_MAX+1];
+ struct rtattr *tpb[NDTPA_MAX+1];
+ int ret;
+
+ if (n->nlmsg_type != RTM_NEWNEIGHTBL) {
+ fprintf(stderr, "Not NEIGHTBL: %08x %08x %08x\n",
+ n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
+ return 0;
+ }
+ len -= NLMSG_LENGTH(sizeof(*ndtm));
+ if (len < 0) {
+ fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+ return -1;
+ }
+
+ if (preferred_family && preferred_family != ndtm->ndtm_family)
+ return 0;
+
+ parse_rtattr(tb, NDTA_MAX, NDTA_RTA(ndtm),
+ n->nlmsg_len - NLMSG_LENGTH(sizeof(*ndtm)));
+
+ if (tb[NDTA_NAME]) {
+ const char *name = rta_getattr_str(tb[NDTA_NAME]);
+
+ if (strlen(filter.name) > 0 && strcmp(filter.name, name))
+ return 0;
+ }
+ if (tb[NDTA_PARMS]) {
+ parse_rtattr(tpb, NDTPA_MAX, RTA_DATA(tb[NDTA_PARMS]),
+ RTA_PAYLOAD(tb[NDTA_PARMS]));
+
+ if (tpb[NDTPA_IFINDEX]) {
+ __u32 ifindex = rta_getattr_u32(tpb[NDTPA_IFINDEX]);
+
+ if (filter.index && filter.index != ifindex)
+ return 0;
+ } else {
+ if (filter.index && filter.index != NONE_DEV)
+ return 0;
+ }
+ }
+
+ if (ndtm->ndtm_family == AF_INET)
+ fprintf(fp, "inet ");
+ else if (ndtm->ndtm_family == AF_INET6)
+ fprintf(fp, "inet6 ");
+ else if (ndtm->ndtm_family == AF_DECnet)
+ fprintf(fp, "dnet ");
+ else
+ fprintf(fp, "(%d) ", ndtm->ndtm_family);
+
+ if (tb[NDTA_NAME]) {
+ const char *name = rta_getattr_str(tb[NDTA_NAME]);
+ fprintf(fp, "%s ", name);
+ }
+
+ fprintf(fp, "%s", _SL_);
+
+ ret = (tb[NDTA_THRESH1] || tb[NDTA_THRESH2] || tb[NDTA_THRESH3] ||
+ tb[NDTA_GC_INTERVAL]);
+ if (ret)
+ fprintf(fp, " ");
+
+ if (tb[NDTA_THRESH1]) {
+ __u32 thresh1 = rta_getattr_u32(tb[NDTA_THRESH1]);
+ fprintf(fp, "thresh1 %u ", thresh1);
+ }
+ if (tb[NDTA_THRESH2]) {
+ __u32 thresh2 = rta_getattr_u32(tb[NDTA_THRESH2]);
+ fprintf(fp, "thresh2 %u ", thresh2);
+ }
+ if (tb[NDTA_THRESH3]) {
+ __u32 thresh3 = rta_getattr_u32(tb[NDTA_THRESH3]);
+ fprintf(fp, "thresh3 %u ", thresh3);
+ }
+ if (tb[NDTA_GC_INTERVAL]) {
+ __u64 gc_int = rta_getattr_u64(tb[NDTA_GC_INTERVAL]);
+ fprintf(fp, "gc_int %llu ", gc_int);
+ }
+
+ if (ret)
+ fprintf(fp, "%s", _SL_);
+
+ if (tb[NDTA_CONFIG] && show_stats) {
+ struct ndt_config *ndtc = RTA_DATA(tb[NDTA_CONFIG]);
+
+ fprintf(fp, " ");
+ fprintf(fp, "config ");
+
+ fprintf(fp, "key_len %u ", ndtc->ndtc_key_len);
+ fprintf(fp, "entry_size %u ", ndtc->ndtc_entry_size);
+ fprintf(fp, "entries %u ", ndtc->ndtc_entries);
+
+ fprintf(fp, "%s", _SL_);
+ fprintf(fp, " ");
+
+ fprintf(fp, "last_flush %s ",
+ ntable_strtime_delta(ndtc->ndtc_last_flush));
+ fprintf(fp, "last_rand %s ",
+ ntable_strtime_delta(ndtc->ndtc_last_rand));
+
+ fprintf(fp, "%s", _SL_);
+ fprintf(fp, " ");
+
+ fprintf(fp, "hash_rnd %u ", ndtc->ndtc_hash_rnd);
+ fprintf(fp, "hash_mask %08x ", ndtc->ndtc_hash_mask);
+
+ fprintf(fp, "hash_chain_gc %u ", ndtc->ndtc_hash_chain_gc);
+ fprintf(fp, "proxy_qlen %u ", ndtc->ndtc_proxy_qlen);
+
+ fprintf(fp, "%s", _SL_);
+ }
+
+ if (tb[NDTA_PARMS]) {
+ if (tpb[NDTPA_IFINDEX]) {
+ __u32 ifindex = rta_getattr_u32(tpb[NDTPA_IFINDEX]);
+
+ fprintf(fp, " ");
+ fprintf(fp, "dev %s ", ll_index_to_name(ifindex));
+ fprintf(fp, "%s", _SL_);
+ }
+
+ fprintf(fp, " ");
+
+ if (tpb[NDTPA_REFCNT]) {
+ __u32 refcnt = rta_getattr_u32(tpb[NDTPA_REFCNT]);
+ fprintf(fp, "refcnt %u ", refcnt);
+ }
+ if (tpb[NDTPA_REACHABLE_TIME]) {
+ __u64 reachable = rta_getattr_u64(tpb[NDTPA_REACHABLE_TIME]);
+ fprintf(fp, "reachable %llu ", reachable);
+ }
+ if (tpb[NDTPA_BASE_REACHABLE_TIME]) {
+ __u64 breachable = rta_getattr_u64(tpb[NDTPA_BASE_REACHABLE_TIME]);
+ fprintf(fp, "base_reachable %llu ", breachable);
+ }
+ if (tpb[NDTPA_RETRANS_TIME]) {
+ __u64 retrans = rta_getattr_u64(tpb[NDTPA_RETRANS_TIME]);
+ fprintf(fp, "retrans %llu ", retrans);
+ }
+
+ fprintf(fp, "%s", _SL_);
+
+ fprintf(fp, " ");
+
+ if (tpb[NDTPA_GC_STALETIME]) {
+ __u64 gc_stale = rta_getattr_u64(tpb[NDTPA_GC_STALETIME]);
+ fprintf(fp, "gc_stale %llu ", gc_stale);
+ }
+ if (tpb[NDTPA_DELAY_PROBE_TIME]) {
+ __u64 delay_probe = rta_getattr_u64(tpb[NDTPA_DELAY_PROBE_TIME]);
+ fprintf(fp, "delay_probe %llu ", delay_probe);
+ }
+ if (tpb[NDTPA_QUEUE_LEN]) {
+ __u32 queue = rta_getattr_u32(tpb[NDTPA_QUEUE_LEN]);
+ fprintf(fp, "queue %u ", queue);
+ }
+
+ fprintf(fp, "%s", _SL_);
+
+ fprintf(fp, " ");
+
+ if (tpb[NDTPA_APP_PROBES]) {
+ __u32 aprobe = rta_getattr_u32(tpb[NDTPA_APP_PROBES]);
+ fprintf(fp, "app_probes %u ", aprobe);
+ }
+ if (tpb[NDTPA_UCAST_PROBES]) {
+ __u32 uprobe = rta_getattr_u32(tpb[NDTPA_UCAST_PROBES]);
+ fprintf(fp, "ucast_probes %u ", uprobe);
+ }
+ if (tpb[NDTPA_MCAST_PROBES]) {
+ __u32 mprobe = rta_getattr_u32(tpb[NDTPA_MCAST_PROBES]);
+ fprintf(fp, "mcast_probes %u ", mprobe);
+ }
+
+ fprintf(fp, "%s", _SL_);
+
+ fprintf(fp, " ");
+
+ if (tpb[NDTPA_ANYCAST_DELAY]) {
+ __u64 anycast_delay = rta_getattr_u64(tpb[NDTPA_ANYCAST_DELAY]);
+ fprintf(fp, "anycast_delay %llu ", anycast_delay);
+ }
+ if (tpb[NDTPA_PROXY_DELAY]) {
+ __u64 proxy_delay = rta_getattr_u64(tpb[NDTPA_PROXY_DELAY]);
+ fprintf(fp, "proxy_delay %llu ", proxy_delay);
+ }
+ if (tpb[NDTPA_PROXY_QLEN]) {
+ __u32 pqueue = rta_getattr_u32(tpb[NDTPA_PROXY_QLEN]);
+ fprintf(fp, "proxy_queue %u ", pqueue);
+ }
+ if (tpb[NDTPA_LOCKTIME]) {
+ __u64 locktime = rta_getattr_u64(tpb[NDTPA_LOCKTIME]);
+ fprintf(fp, "locktime %llu ", locktime);
+ }
+
+ fprintf(fp, "%s", _SL_);
+ }
+
+ if (tb[NDTA_STATS] && show_stats) {
+ struct ndt_stats *ndts = RTA_DATA(tb[NDTA_STATS]);
+
+ fprintf(fp, " ");
+ fprintf(fp, "stats ");
+
+ fprintf(fp, "allocs %llu ", ndts->ndts_allocs);
+ fprintf(fp, "destroys %llu ", ndts->ndts_destroys);
+ fprintf(fp, "hash_grows %llu ", ndts->ndts_hash_grows);
+
+ fprintf(fp, "%s", _SL_);
+ fprintf(fp, " ");
+
+ fprintf(fp, "res_failed %llu ", ndts->ndts_res_failed);
+ fprintf(fp, "lookups %llu ", ndts->ndts_lookups);
+ fprintf(fp, "hits %llu ", ndts->ndts_hits);
+
+ fprintf(fp, "%s", _SL_);
+ fprintf(fp, " ");
+
+ fprintf(fp, "rcv_probes_mcast %llu ", ndts->ndts_rcv_probes_mcast);
+ fprintf(fp, "rcv_probes_ucast %llu ", ndts->ndts_rcv_probes_ucast);
+
+ fprintf(fp, "%s", _SL_);
+ fprintf(fp, " ");
+
+ fprintf(fp, "periodic_gc_runs %llu ", ndts->ndts_periodic_gc_runs);
+ fprintf(fp, "forced_gc_runs %llu ", ndts->ndts_forced_gc_runs);
+
+ fprintf(fp, "%s", _SL_);
+ }
+
+ fprintf(fp, "\n");
+
+ fflush(fp);
+ return 0;
+}
+
+void ipntable_reset_filter(void)
+{
+ memset(&filter, 0, sizeof(filter));
+}
+
+static int ipntable_show(int argc, char **argv)
+{
+ ipntable_reset_filter();
+
+ filter.family = preferred_family;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+
+ if (strcmp("none", *argv) == 0)
+ filter.index = NONE_DEV;
+ else if ((filter.index = ll_name_to_index(*argv)) == 0)
+ invarg("\"DEV\" is invalid", *argv);
+ } else if (strcmp(*argv, "name") == 0) {
+ NEXT_ARG();
+
+ strncpy(filter.name, *argv, sizeof(filter.name));
+ } else
+ invarg("unknown", *argv);
+
+ argc--; argv++;
+ }
+
+ if (rtnl_wilddump_request(&rth, preferred_family, RTM_GETNEIGHTBL) < 0) {
+ perror("Cannot send dump request");
+ exit(1);
+ }
+
+ if (rtnl_dump_filter(&rth, print_ntable, stdout) < 0) {
+ fprintf(stderr, "Dump terminated\n");
+ exit(1);
+ }
+
+ return 0;
+}
+
+int do_ipntable(int argc, char **argv)
+{
+ ll_init_map(&rth);
+
+ if (argc > 0) {
+ if (matches(*argv, "change") == 0 ||
+ matches(*argv, "chg") == 0)
+ return ipntable_modify(RTM_SETNEIGHTBL,
+ NLM_F_REPLACE,
+ argc-1, argv+1);
+ if (matches(*argv, "show") == 0 ||
+ matches(*argv, "lst") == 0 ||
+ matches(*argv, "list") == 0)
+ return ipntable_show(argc-1, argv+1);
+ if (matches(*argv, "help") == 0)
+ usage();
+ } else
+ return ipntable_show(0, NULL);
+
+ fprintf(stderr, "Command \"%s\" is unknown, try \"ip ntable help\".\n", *argv);
+ exit(-1);
+}
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/ipprefix.c b/ap/app/iproute2/iproute2-3.4.0/ip/ipprefix.c
new file mode 100755
index 0000000..d8327be
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/ipprefix.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C)2005 USAGI/WIDE Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*
+ * based on ip.c, iproute.c
+ */
+/*
+ * Authors:
+ * Masahide NAKAMURA @USAGI
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/icmp6.h>
+#include "utils.h"
+
+/* prefix flags; see kernel's net/ipv6/addrconf.c and include/net/if_inet6.h */
+#define IF_PREFIX_ONLINK 0x01
+#define IF_PREFIX_AUTOCONF 0x02
+
+int print_prefix(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+{
+ FILE *fp = (FILE*)arg;
+ struct prefixmsg *prefix = NLMSG_DATA(n);
+ int len = n->nlmsg_len;
+ struct rtattr * tb[RTA_MAX+1];
+ int family = preferred_family;
+
+ if (n->nlmsg_type != RTM_NEWPREFIX) {
+ fprintf(stderr, "Not a prefix: %08x %08x %08x\n",
+ n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
+ return 0;
+ }
+
+ len -= NLMSG_LENGTH(sizeof(*prefix));
+ if (len < 0) {
+ fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+ return -1;
+ }
+
+ if (family == AF_UNSPEC)
+ family = AF_INET6;
+ if (family != AF_INET6)
+ return 0;
+
+ if (prefix->prefix_family != AF_INET6) {
+ fprintf(stderr, "wrong family %d\n", prefix->prefix_family);
+ return 0;
+ }
+ if (prefix->prefix_type != ND_OPT_PREFIX_INFORMATION) {
+ fprintf(stderr, "wrong ND type %d\n", prefix->prefix_type);
+ return 0;
+ }
+
+ parse_rtattr(tb, RTA_MAX, RTM_RTA(prefix), len);
+
+ fprintf(fp, "prefix ");
+
+ if (tb[PREFIX_ADDRESS]) {
+ struct in6_addr *pfx;
+ char abuf[256];
+
+ pfx = (struct in6_addr *)RTA_DATA(tb[PREFIX_ADDRESS]);
+
+ memset(abuf, '\0', sizeof(abuf));
+ fprintf(fp, "%s", rt_addr_n2a(family, sizeof(*pfx), pfx,
+ abuf, sizeof(abuf)));
+ }
+ fprintf(fp, "/%u ", prefix->prefix_len);
+
+ fprintf(fp, "dev %s ", ll_index_to_name(prefix->prefix_ifindex));
+
+ if (prefix->prefix_flags & IF_PREFIX_ONLINK)
+ fprintf(fp, "onlink ");
+ if (prefix->prefix_flags & IF_PREFIX_AUTOCONF)
+ fprintf(fp, "autoconf ");
+
+ if (tb[PREFIX_CACHEINFO]) {
+ struct prefix_cacheinfo *pc;
+ pc = (struct prefix_cacheinfo *)RTA_DATA(tb[PREFIX_CACHEINFO]);
+
+ fprintf(fp, "valid %u ", pc->valid_time);
+ fprintf(fp, "preferred %u ", pc->preferred_time);
+ }
+
+ fprintf(fp, "\n");
+ fflush(fp);
+
+ return 0;
+}
+
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/iproute.c b/ap/app/iproute2/iproute2-3.4.0/ip/iproute.c
new file mode 100755
index 0000000..5cd313e
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/iproute.c
@@ -0,0 +1,1578 @@
+/*
+ * iproute.c "ip route".
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+#include <linux/in_route.h>
+#include <errno.h>
+
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+
+#ifndef RTAX_RTTVAR
+#define RTAX_RTTVAR RTAX_HOPS
+#endif
+
+enum list_action {
+ IPROUTE_LIST,
+ IPROUTE_FLUSH,
+ IPROUTE_SAVE,
+};
+static const char *mx_names[RTAX_MAX+1] = {
+ [RTAX_MTU] = "mtu",
+ [RTAX_WINDOW] = "window",
+ [RTAX_RTT] = "rtt",
+ [RTAX_RTTVAR] = "rttvar",
+ [RTAX_SSTHRESH] = "ssthresh",
+ [RTAX_CWND] = "cwnd",
+ [RTAX_ADVMSS] = "advmss",
+ [RTAX_REORDERING]="reordering",
+ [RTAX_HOPLIMIT] = "hoplimit",
+ [RTAX_INITCWND] = "initcwnd",
+ [RTAX_FEATURES] = "features",
+ [RTAX_RTO_MIN] = "rto_min",
+ [RTAX_INITRWND] = "initrwnd",
+};
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: ip route { list | flush } SELECTOR\n");
+ fprintf(stderr, " ip route save SELECTOR\n");
+ fprintf(stderr, " ip route restore\n");
+ fprintf(stderr, " ip route get ADDRESS [ from ADDRESS iif STRING ]\n");
+ fprintf(stderr, " [ oif STRING ] [ tos TOS ]\n");
+ fprintf(stderr, " [ mark NUMBER ]\n");
+ fprintf(stderr, " ip route { add | del | change | append | replace } ROUTE\n");
+ fprintf(stderr, "SELECTOR := [ root PREFIX ] [ match PREFIX ] [ exact PREFIX ]\n");
+ fprintf(stderr, " [ table TABLE_ID ] [ proto RTPROTO ]\n");
+ fprintf(stderr, " [ type TYPE ] [ scope SCOPE ]\n");
+ fprintf(stderr, "ROUTE := NODE_SPEC [ INFO_SPEC ]\n");
+ fprintf(stderr, "NODE_SPEC := [ TYPE ] PREFIX [ tos TOS ]\n");
+ fprintf(stderr, " [ table TABLE_ID ] [ proto RTPROTO ]\n");
+ fprintf(stderr, " [ scope SCOPE ] [ metric METRIC ]\n");
+ fprintf(stderr, "INFO_SPEC := NH OPTIONS FLAGS [ nexthop NH ]...\n");
+ fprintf(stderr, "NH := [ via ADDRESS ] [ dev STRING ] [ weight NUMBER ] NHFLAGS\n");
+ fprintf(stderr, "OPTIONS := FLAGS [ mtu NUMBER ] [ advmss NUMBER ]\n");
+ fprintf(stderr, " [ rtt TIME ] [ rttvar TIME ] [reordering NUMBER ]\n");
+ fprintf(stderr, " [ window NUMBER] [ cwnd NUMBER ] [ initcwnd NUMBER ]\n");
+ fprintf(stderr, " [ ssthresh NUMBER ] [ realms REALM ] [ src ADDRESS ]\n");
+ fprintf(stderr, " [ rto_min TIME ] [ hoplimit NUMBER ] [ initrwnd NUMBER ]\n");
+ fprintf(stderr, "TYPE := [ unicast | local | broadcast | multicast | throw |\n");
+ fprintf(stderr, " unreachable | prohibit | blackhole | nat ]\n");
+ fprintf(stderr, "TABLE_ID := [ local | main | default | all | NUMBER ]\n");
+ fprintf(stderr, "SCOPE := [ host | link | global | NUMBER ]\n");
+ fprintf(stderr, "MP_ALGO := { rr | drr | random | wrandom }\n");
+ fprintf(stderr, "NHFLAGS := [ onlink | pervasive ]\n");
+ fprintf(stderr, "RTPROTO := [ kernel | boot | static | NUMBER ]\n");
+ fprintf(stderr, "TIME := NUMBER[s|ms]\n");
+ exit(-1);
+}
+
+
+static struct
+{
+ int tb;
+ int cloned;
+ int flushed;
+ char *flushb;
+ int flushp;
+ int flushe;
+ int protocol, protocolmask;
+ int scope, scopemask;
+ int type, typemask;
+ int tos, tosmask;
+ int iif, iifmask;
+ int oif, oifmask;
+ int mark, markmask;
+ int realm, realmmask;
+ inet_prefix rprefsrc;
+ inet_prefix rvia;
+ inet_prefix rdst;
+ inet_prefix mdst;
+ inet_prefix rsrc;
+ inet_prefix msrc;
+} filter;
+
+static int flush_update(void)
+{
+ if (rtnl_send_check(&rth, filter.flushb, filter.flushp) < 0) {
+ perror("Failed to send flush request");
+ return -1;
+ }
+ filter.flushp = 0;
+ return 0;
+}
+
+int filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
+{
+ struct rtmsg *r = NLMSG_DATA(n);
+ inet_prefix dst;
+ inet_prefix src;
+ inet_prefix via;
+ inet_prefix prefsrc;
+ __u32 table;
+ static int ip6_multiple_tables;
+
+ table = rtm_get_table(r, tb);
+
+ if (r->rtm_family == AF_INET6 && table != RT_TABLE_MAIN)
+ ip6_multiple_tables = 1;
+
+ if (filter.cloned == !(r->rtm_flags&RTM_F_CLONED))
+ return 0;
+
+ if (r->rtm_family == AF_INET6 && !ip6_multiple_tables) {
+ if (filter.tb) {
+ if (filter.tb == RT_TABLE_LOCAL) {
+ if (r->rtm_type != RTN_LOCAL)
+ return 0;
+ } else if (filter.tb == RT_TABLE_MAIN) {
+ if (r->rtm_type == RTN_LOCAL)
+ return 0;
+ } else {
+ return 0;
+ }
+ }
+ } else {
+ if (filter.tb > 0 && filter.tb != table)
+ return 0;
+ }
+ if ((filter.protocol^r->rtm_protocol)&filter.protocolmask)
+ return 0;
+ if ((filter.scope^r->rtm_scope)&filter.scopemask)
+ return 0;
+ if ((filter.type^r->rtm_type)&filter.typemask)
+ return 0;
+ if ((filter.tos^r->rtm_tos)&filter.tosmask)
+ return 0;
+ if (filter.rdst.family &&
+ (r->rtm_family != filter.rdst.family || filter.rdst.bitlen > r->rtm_dst_len))
+ return 0;
+ if (filter.mdst.family &&
+ (r->rtm_family != filter.mdst.family ||
+ (filter.mdst.bitlen >= 0 && filter.mdst.bitlen < r->rtm_dst_len)))
+ return 0;
+ if (filter.rsrc.family &&
+ (r->rtm_family != filter.rsrc.family || filter.rsrc.bitlen > r->rtm_src_len))
+ return 0;
+ if (filter.msrc.family &&
+ (r->rtm_family != filter.msrc.family ||
+ (filter.msrc.bitlen >= 0 && filter.msrc.bitlen < r->rtm_src_len)))
+ return 0;
+ if (filter.rvia.family && r->rtm_family != filter.rvia.family)
+ return 0;
+ if (filter.rprefsrc.family && r->rtm_family != filter.rprefsrc.family)
+ return 0;
+
+ memset(&dst, 0, sizeof(dst));
+ dst.family = r->rtm_family;
+ if (tb[RTA_DST])
+ memcpy(&dst.data, RTA_DATA(tb[RTA_DST]), (r->rtm_dst_len+7)/8);
+ if (filter.rsrc.family || filter.msrc.family) {
+ memset(&src, 0, sizeof(src));
+ src.family = r->rtm_family;
+ if (tb[RTA_SRC])
+ memcpy(&src.data, RTA_DATA(tb[RTA_SRC]), (r->rtm_src_len+7)/8);
+ }
+ if (filter.rvia.bitlen>0) {
+ memset(&via, 0, sizeof(via));
+ via.family = r->rtm_family;
+ if (tb[RTA_GATEWAY])
+ memcpy(&via.data, RTA_DATA(tb[RTA_GATEWAY]), host_len/8);
+ }
+ if (filter.rprefsrc.bitlen>0) {
+ memset(&prefsrc, 0, sizeof(prefsrc));
+ prefsrc.family = r->rtm_family;
+ if (tb[RTA_PREFSRC])
+ memcpy(&prefsrc.data, RTA_DATA(tb[RTA_PREFSRC]), host_len/8);
+ }
+
+ if (filter.rdst.family && inet_addr_match(&dst, &filter.rdst, filter.rdst.bitlen))
+ return 0;
+ if (filter.mdst.family && filter.mdst.bitlen >= 0 &&
+ inet_addr_match(&dst, &filter.mdst, r->rtm_dst_len))
+ return 0;
+
+ if (filter.rsrc.family && inet_addr_match(&src, &filter.rsrc, filter.rsrc.bitlen))
+ return 0;
+ if (filter.msrc.family && filter.msrc.bitlen >= 0 &&
+ inet_addr_match(&src, &filter.msrc, r->rtm_src_len))
+ return 0;
+
+ if (filter.rvia.family && inet_addr_match(&via, &filter.rvia, filter.rvia.bitlen))
+ return 0;
+ if (filter.rprefsrc.family && inet_addr_match(&prefsrc, &filter.rprefsrc, filter.rprefsrc.bitlen))
+ return 0;
+ if (filter.realmmask) {
+ __u32 realms = 0;
+ if (tb[RTA_FLOW])
+ realms = rta_getattr_u32(tb[RTA_FLOW]);
+ if ((realms^filter.realm)&filter.realmmask)
+ return 0;
+ }
+ if (filter.iifmask) {
+ int iif = 0;
+ if (tb[RTA_IIF])
+ iif = *(int*)RTA_DATA(tb[RTA_IIF]);
+ if ((iif^filter.iif)&filter.iifmask)
+ return 0;
+ }
+ if (filter.oifmask) {
+ int oif = 0;
+ if (tb[RTA_OIF])
+ oif = *(int*)RTA_DATA(tb[RTA_OIF]);
+ if ((oif^filter.oif)&filter.oifmask)
+ return 0;
+ }
+ if (filter.markmask) {
+ int mark = 0;
+ if (tb[RTA_MARK])
+ mark = *(int *)RTA_DATA(tb[RTA_MARK]);
+ if ((mark ^ filter.mark) & filter.markmask)
+ return 0;
+ }
+ if (filter.flushb &&
+ r->rtm_family == AF_INET6 &&
+ r->rtm_dst_len == 0 &&
+ r->rtm_type == RTN_UNREACHABLE &&
+ tb[RTA_PRIORITY] &&
+ *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1)
+ return 0;
+
+ return 1;
+}
+
+int calc_host_len(struct rtmsg *r)
+{
+ if (r->rtm_family == AF_INET6)
+ return 128;
+ else if (r->rtm_family == AF_INET)
+ return 32;
+ else if (r->rtm_family == AF_DECnet)
+ return 16;
+ else if (r->rtm_family == AF_IPX)
+ return 80;
+ else
+ return -1;
+}
+
+int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+{
+ FILE *fp = (FILE*)arg;
+ struct rtmsg *r = NLMSG_DATA(n);
+ int len = n->nlmsg_len;
+ struct rtattr * tb[RTA_MAX+1];
+ char abuf[256];
+ int host_len = -1;
+ __u32 table;
+ SPRINT_BUF(b1);
+ static int hz;
+
+ if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
+ fprintf(stderr, "Not a route: %08x %08x %08x\n",
+ n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
+ return 0;
+ }
+ if (filter.flushb && n->nlmsg_type != RTM_NEWROUTE)
+ return 0;
+ len -= NLMSG_LENGTH(sizeof(*r));
+ if (len < 0) {
+ fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+ return -1;
+ }
+
+ host_len = calc_host_len(r);
+
+ parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
+ table = rtm_get_table(r, tb);
+
+ if (!filter_nlmsg(n, tb, host_len))
+ return 0;
+
+ if (filter.flushb) {
+ struct nlmsghdr *fn;
+ if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) {
+ if (flush_update())
+ return -1;
+ }
+ fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp));
+ memcpy(fn, n, n->nlmsg_len);
+ fn->nlmsg_type = RTM_DELROUTE;
+ fn->nlmsg_flags = NLM_F_REQUEST;
+ fn->nlmsg_seq = ++rth.seq;
+ filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb;
+ filter.flushed++;
+ if (show_stats < 2)
+ return 0;
+ }
+
+ if (n->nlmsg_type == RTM_DELROUTE)
+ fprintf(fp, "Deleted ");
+ if (r->rtm_type != RTN_UNICAST && !filter.type)
+ fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
+
+ if (tb[RTA_DST]) {
+ if (r->rtm_dst_len != host_len) {
+ fprintf(fp, "%s/%u ", rt_addr_n2a(r->rtm_family,
+ RTA_PAYLOAD(tb[RTA_DST]),
+ RTA_DATA(tb[RTA_DST]),
+ abuf, sizeof(abuf)),
+ r->rtm_dst_len
+ );
+ } else {
+ fprintf(fp, "%s ", format_host(r->rtm_family,
+ RTA_PAYLOAD(tb[RTA_DST]),
+ RTA_DATA(tb[RTA_DST]),
+ abuf, sizeof(abuf))
+ );
+ }
+ } else if (r->rtm_dst_len) {
+ fprintf(fp, "0/%d ", r->rtm_dst_len);
+ } else {
+ fprintf(fp, "default ");
+ }
+ if (tb[RTA_SRC]) {
+ if (r->rtm_src_len != host_len) {
+ fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family,
+ RTA_PAYLOAD(tb[RTA_SRC]),
+ RTA_DATA(tb[RTA_SRC]),
+ abuf, sizeof(abuf)),
+ r->rtm_src_len
+ );
+ } else {
+ fprintf(fp, "from %s ", format_host(r->rtm_family,
+ RTA_PAYLOAD(tb[RTA_SRC]),
+ RTA_DATA(tb[RTA_SRC]),
+ abuf, sizeof(abuf))
+ );
+ }
+ } else if (r->rtm_src_len) {
+ fprintf(fp, "from 0/%u ", r->rtm_src_len);
+ }
+ if (r->rtm_tos && filter.tosmask != -1) {
+ SPRINT_BUF(b1);
+ fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
+ }
+
+ if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) {
+ fprintf(fp, "via %s ",
+ format_host(r->rtm_family,
+ RTA_PAYLOAD(tb[RTA_GATEWAY]),
+ RTA_DATA(tb[RTA_GATEWAY]),
+ abuf, sizeof(abuf)));
+ }
+ if (tb[RTA_OIF] && filter.oifmask != -1)
+ fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));
+
+ if (!(r->rtm_flags&RTM_F_CLONED)) {
+ if (table != RT_TABLE_MAIN && !filter.tb)
+ fprintf(fp, " table %s ", rtnl_rttable_n2a(table, b1, sizeof(b1)));
+ if (r->rtm_protocol != RTPROT_BOOT && filter.protocolmask != -1)
+ fprintf(fp, " proto %s ", rtnl_rtprot_n2a(r->rtm_protocol, b1, sizeof(b1)));
+ if (r->rtm_scope != RT_SCOPE_UNIVERSE && filter.scopemask != -1)
+ fprintf(fp, " scope %s ", rtnl_rtscope_n2a(r->rtm_scope, b1, sizeof(b1)));
+ }
+ if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) {
+ /* Do not use format_host(). It is our local addr
+ and symbolic name will not be useful.
+ */
+ fprintf(fp, " src %s ",
+ rt_addr_n2a(r->rtm_family,
+ RTA_PAYLOAD(tb[RTA_PREFSRC]),
+ RTA_DATA(tb[RTA_PREFSRC]),
+ abuf, sizeof(abuf)));
+ }
+ if (tb[RTA_PRIORITY])
+ fprintf(fp, " metric %u ", rta_getattr_u32(tb[RTA_PRIORITY]));
+ if (r->rtm_flags & RTNH_F_DEAD)
+ fprintf(fp, "dead ");
+ if (r->rtm_flags & RTNH_F_ONLINK)
+ fprintf(fp, "onlink ");
+ if (r->rtm_flags & RTNH_F_PERVASIVE)
+ fprintf(fp, "pervasive ");
+ if (r->rtm_flags & RTM_F_NOTIFY)
+ fprintf(fp, "notify ");
+ if (tb[RTA_MARK]) {
+ unsigned int mark = *(unsigned int*)RTA_DATA(tb[RTA_MARK]);
+ if (mark) {
+ if (mark >= 16)
+ fprintf(fp, " mark 0x%x", mark);
+ else
+ fprintf(fp, " mark %u", mark);
+ }
+ }
+
+ if (tb[RTA_FLOW] && filter.realmmask != ~0U) {
+ __u32 to = rta_getattr_u32(tb[RTA_FLOW]);
+ __u32 from = to>>16;
+ to &= 0xFFFF;
+ fprintf(fp, "realm%s ", from ? "s" : "");
+ if (from) {
+ fprintf(fp, "%s/",
+ rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
+ }
+ fprintf(fp, "%s ",
+ rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
+ }
+ if ((r->rtm_flags&RTM_F_CLONED) && r->rtm_family == AF_INET) {
+ __u32 flags = r->rtm_flags&~0xFFFF;
+ int first = 1;
+
+ fprintf(fp, "%s cache ", _SL_);
+
+#define PRTFL(fl,flname) if (flags&RTCF_##fl) { \
+ flags &= ~RTCF_##fl; \
+ fprintf(fp, "%s" flname "%s", first ? "<" : "", flags ? "," : "> "); \
+ first = 0; }
+ PRTFL(LOCAL, "local");
+ PRTFL(REJECT, "reject");
+ PRTFL(MULTICAST, "mc");
+ PRTFL(BROADCAST, "brd");
+ PRTFL(DNAT, "dst-nat");
+ PRTFL(SNAT, "src-nat");
+ PRTFL(MASQ, "masq");
+ PRTFL(DIRECTDST, "dst-direct");
+ PRTFL(DIRECTSRC, "src-direct");
+ PRTFL(REDIRECTED, "redirected");
+ PRTFL(DOREDIRECT, "redirect");
+ PRTFL(FAST, "fastroute");
+ PRTFL(NOTIFY, "notify");
+ PRTFL(TPROXY, "proxy");
+
+ if (flags)
+ fprintf(fp, "%s%x> ", first ? "<" : "", flags);
+ if (tb[RTA_CACHEINFO]) {
+ struct rta_cacheinfo *ci = RTA_DATA(tb[RTA_CACHEINFO]);
+ if (!hz)
+ hz = get_user_hz();
+ if (ci->rta_expires != 0)
+ fprintf(fp, " expires %dsec", ci->rta_expires/hz);
+ if (ci->rta_error != 0)
+ fprintf(fp, " error %d", ci->rta_error);
+ if (show_stats) {
+ if (ci->rta_clntref)
+ fprintf(fp, " users %d", ci->rta_clntref);
+ if (ci->rta_used != 0)
+ fprintf(fp, " used %d", ci->rta_used);
+ if (ci->rta_lastuse != 0)
+ fprintf(fp, " age %dsec", ci->rta_lastuse/hz);
+ }
+ if (ci->rta_id)
+ fprintf(fp, " ipid 0x%04x", ci->rta_id);
+ if (ci->rta_ts || ci->rta_tsage)
+ fprintf(fp, " ts 0x%x tsage %dsec",
+ ci->rta_ts, ci->rta_tsage);
+ }
+ } else if (r->rtm_family == AF_INET6) {
+ struct rta_cacheinfo *ci = NULL;
+ if (tb[RTA_CACHEINFO])
+ ci = RTA_DATA(tb[RTA_CACHEINFO]);
+ if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
+ if (!hz)
+ hz = get_user_hz();
+ if (r->rtm_flags & RTM_F_CLONED)
+ fprintf(fp, "%s cache ", _SL_);
+ if (ci->rta_expires)
+ fprintf(fp, " expires %dsec", ci->rta_expires/hz);
+ if (ci->rta_error != 0)
+ fprintf(fp, " error %d", ci->rta_error);
+ if (show_stats) {
+ if (ci->rta_clntref)
+ fprintf(fp, " users %d", ci->rta_clntref);
+ if (ci->rta_used != 0)
+ fprintf(fp, " used %d", ci->rta_used);
+ if (ci->rta_lastuse != 0)
+ fprintf(fp, " age %dsec", ci->rta_lastuse/hz);
+ }
+ } else if (ci) {
+ if (ci->rta_error != 0)
+ fprintf(fp, " error %d", ci->rta_error);
+ }
+ }
+ if (tb[RTA_METRICS]) {
+ int i;
+ unsigned mxlock = 0;
+ struct rtattr *mxrta[RTAX_MAX+1];
+
+ parse_rtattr(mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]),
+ RTA_PAYLOAD(tb[RTA_METRICS]));
+ if (mxrta[RTAX_LOCK])
+ mxlock = *(unsigned*)RTA_DATA(mxrta[RTAX_LOCK]);
+
+ for (i=2; i<= RTAX_MAX; i++) {
+ unsigned val;
+
+ if (mxrta[i] == NULL)
+ continue;
+
+ if (i < sizeof(mx_names)/sizeof(char*) && mx_names[i])
+ fprintf(fp, " %s", mx_names[i]);
+ else
+ fprintf(fp, " metric %d", i);
+ if (mxlock & (1<<i))
+ fprintf(fp, " lock");
+
+ val = *(unsigned*)RTA_DATA(mxrta[i]);
+ switch (i) {
+ case RTAX_HOPLIMIT:
+ if ((int)val == -1)
+ val = 0;
+ /* fall through */
+ default:
+ fprintf(fp, " %u", val);
+ break;
+
+ case RTAX_RTT:
+ case RTAX_RTTVAR:
+ case RTAX_RTO_MIN:
+ if (i == RTAX_RTT)
+ val /= 8;
+ else if (i == RTAX_RTTVAR)
+ val /= 4;
+
+ if (val >= 1000)
+ fprintf(fp, " %gs", val/1e3);
+ else
+ fprintf(fp, " %ums", val);
+ }
+ }
+ }
+ if (tb[RTA_IIF] && filter.iifmask != -1) {
+ fprintf(fp, " iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF])));
+ }
+ if (tb[RTA_MULTIPATH]) {
+ struct rtnexthop *nh = RTA_DATA(tb[RTA_MULTIPATH]);
+ int first = 0;
+
+ len = RTA_PAYLOAD(tb[RTA_MULTIPATH]);
+
+ for (;;) {
+ if (len < sizeof(*nh))
+ break;
+ if (nh->rtnh_len > len)
+ break;
+ if (r->rtm_flags&RTM_F_CLONED && r->rtm_type == RTN_MULTICAST) {
+ if (first)
+ fprintf(fp, " Oifs:");
+ else
+ fprintf(fp, " ");
+ } else
+ fprintf(fp, "%s\tnexthop", _SL_);
+ if (nh->rtnh_len > sizeof(*nh)) {
+ parse_rtattr(tb, RTA_MAX, RTNH_DATA(nh), nh->rtnh_len - sizeof(*nh));
+ if (tb[RTA_GATEWAY]) {
+ fprintf(fp, " via %s ",
+ format_host(r->rtm_family,
+ RTA_PAYLOAD(tb[RTA_GATEWAY]),
+ RTA_DATA(tb[RTA_GATEWAY]),
+ abuf, sizeof(abuf)));
+ }
+ if (tb[RTA_FLOW]) {
+ __u32 to = rta_getattr_u32(tb[RTA_FLOW]);
+ __u32 from = to>>16;
+ to &= 0xFFFF;
+ fprintf(fp, " realm%s ", from ? "s" : "");
+ if (from) {
+ fprintf(fp, "%s/",
+ rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
+ }
+ fprintf(fp, "%s",
+ rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
+ }
+ }
+ if (r->rtm_flags&RTM_F_CLONED && r->rtm_type == RTN_MULTICAST) {
+ fprintf(fp, " %s", ll_index_to_name(nh->rtnh_ifindex));
+ if (nh->rtnh_hops != 1)
+ fprintf(fp, "(ttl>%d)", nh->rtnh_hops);
+ } else {
+ fprintf(fp, " dev %s", ll_index_to_name(nh->rtnh_ifindex));
+ fprintf(fp, " weight %d", nh->rtnh_hops+1);
+ }
+ if (nh->rtnh_flags & RTNH_F_DEAD)
+ fprintf(fp, " dead");
+ if (nh->rtnh_flags & RTNH_F_ONLINK)
+ fprintf(fp, " onlink");
+ if (nh->rtnh_flags & RTNH_F_PERVASIVE)
+ fprintf(fp, " pervasive");
+ len -= NLMSG_ALIGN(nh->rtnh_len);
+ nh = RTNH_NEXT(nh);
+ }
+ }
+ fprintf(fp, "\n");
+ fflush(fp);
+ return 0;
+}
+
+
+int parse_one_nh(struct rtattr *rta, struct rtnexthop *rtnh, int *argcp, char ***argvp)
+{
+ int argc = *argcp;
+ char **argv = *argvp;
+
+ while (++argv, --argc > 0) {
+ if (strcmp(*argv, "via") == 0) {
+ NEXT_ARG();
+ rta_addattr32(rta, 4096, RTA_GATEWAY, get_addr32(*argv));
+ rtnh->rtnh_len += sizeof(struct rtattr) + 4;
+ } else if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ if ((rtnh->rtnh_ifindex = ll_name_to_index(*argv)) == 0) {
+ fprintf(stderr, "Cannot find device \"%s\"\n", *argv);
+ exit(1);
+ }
+ } else if (strcmp(*argv, "weight") == 0) {
+ unsigned w;
+ NEXT_ARG();
+ if (get_unsigned(&w, *argv, 0) || w == 0 || w > 256)
+ invarg("\"weight\" is invalid\n", *argv);
+ rtnh->rtnh_hops = w - 1;
+ } else if (strcmp(*argv, "onlink") == 0) {
+ rtnh->rtnh_flags |= RTNH_F_ONLINK;
+ } else if (matches(*argv, "realms") == 0) {
+ __u32 realm;
+ NEXT_ARG();
+ if (get_rt_realms(&realm, *argv))
+ invarg("\"realm\" value is invalid\n", *argv);
+ rta_addattr32(rta, 4096, RTA_FLOW, realm);
+ rtnh->rtnh_len += sizeof(struct rtattr) + 4;
+ } else
+ break;
+ }
+ *argcp = argc;
+ *argvp = argv;
+ return 0;
+}
+
+int parse_nexthops(struct nlmsghdr *n, struct rtmsg *r, int argc, char **argv)
+{
+ char buf[1024];
+ struct rtattr *rta = (void*)buf;
+ struct rtnexthop *rtnh;
+
+ rta->rta_type = RTA_MULTIPATH;
+ rta->rta_len = RTA_LENGTH(0);
+ rtnh = RTA_DATA(rta);
+
+ while (argc > 0) {
+ if (strcmp(*argv, "nexthop") != 0) {
+ fprintf(stderr, "Error: \"nexthop\" or end of line is expected instead of \"%s\"\n", *argv);
+ exit(-1);
+ }
+ if (argc <= 1) {
+ fprintf(stderr, "Error: unexpected end of line after \"nexthop\"\n");
+ exit(-1);
+ }
+ memset(rtnh, 0, sizeof(*rtnh));
+ rtnh->rtnh_len = sizeof(*rtnh);
+ rta->rta_len += rtnh->rtnh_len;
+ parse_one_nh(rta, rtnh, &argc, &argv);
+ rtnh = RTNH_NEXT(rtnh);
+ }
+
+ if (rta->rta_len > RTA_LENGTH(0))
+ addattr_l(n, 1024, RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta));
+ return 0;
+}
+
+
+int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
+{
+ struct {
+ struct nlmsghdr n;
+ struct rtmsg r;
+ char buf[1024];
+ } req;
+ char mxbuf[256];
+ struct rtattr * mxrta = (void*)mxbuf;
+ unsigned mxlock = 0;
+ char *d = NULL;
+ int gw_ok = 0;
+ int dst_ok = 0;
+ int nhs_ok = 0;
+ int scope_ok = 0;
+ int table_ok = 0;
+ int raw = 0;
+
+ memset(&req, 0, sizeof(req));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST|flags;
+ req.n.nlmsg_type = cmd;
+ req.r.rtm_family = preferred_family;
+ req.r.rtm_table = RT_TABLE_MAIN;
+ req.r.rtm_scope = RT_SCOPE_NOWHERE;
+
+ if (cmd != RTM_DELROUTE) {
+ req.r.rtm_protocol = RTPROT_BOOT;
+ req.r.rtm_scope = RT_SCOPE_UNIVERSE;
+ req.r.rtm_type = RTN_UNICAST;
+ }
+
+ mxrta->rta_type = RTA_METRICS;
+ mxrta->rta_len = RTA_LENGTH(0);
+
+ while (argc > 0) {
+ if (strcmp(*argv, "src") == 0) {
+ inet_prefix addr;
+ NEXT_ARG();
+ get_addr(&addr, *argv, req.r.rtm_family);
+ if (req.r.rtm_family == AF_UNSPEC)
+ req.r.rtm_family = addr.family;
+ addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen);
+ } else if (strcmp(*argv, "via") == 0) {
+ inet_prefix addr;
+ gw_ok = 1;
+ NEXT_ARG();
+ get_addr(&addr, *argv, req.r.rtm_family);
+ if (req.r.rtm_family == AF_UNSPEC)
+ req.r.rtm_family = addr.family;
+ addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen);
+ } else if (strcmp(*argv, "from") == 0) {
+ inet_prefix addr;
+ NEXT_ARG();
+ get_prefix(&addr, *argv, req.r.rtm_family);
+ if (req.r.rtm_family == AF_UNSPEC)
+ req.r.rtm_family = addr.family;
+ if (addr.bytelen)
+ addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen);
+ req.r.rtm_src_len = addr.bitlen;
+ } else if (strcmp(*argv, "tos") == 0 ||
+ matches(*argv, "dsfield") == 0) {
+ __u32 tos;
+ NEXT_ARG();
+ if (rtnl_dsfield_a2n(&tos, *argv))
+ invarg("\"tos\" value is invalid\n", *argv);
+ req.r.rtm_tos = tos;
+ } else if (matches(*argv, "metric") == 0 ||
+ matches(*argv, "priority") == 0 ||
+ matches(*argv, "preference") == 0) {
+ __u32 metric;
+ NEXT_ARG();
+ if (get_u32(&metric, *argv, 0))
+ invarg("\"metric\" value is invalid\n", *argv);
+ addattr32(&req.n, sizeof(req), RTA_PRIORITY, metric);
+ } else if (strcmp(*argv, "scope") == 0) {
+ __u32 scope = 0;
+ NEXT_ARG();
+ if (rtnl_rtscope_a2n(&scope, *argv))
+ invarg("invalid \"scope\" value\n", *argv);
+ req.r.rtm_scope = scope;
+ scope_ok = 1;
+ } else if (strcmp(*argv, "mtu") == 0) {
+ unsigned mtu;
+ NEXT_ARG();
+ if (strcmp(*argv, "lock") == 0) {
+ mxlock |= (1<<RTAX_MTU);
+ NEXT_ARG();
+ }
+ if (get_unsigned(&mtu, *argv, 0))
+ invarg("\"mtu\" value is invalid\n", *argv);
+ rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu);
+ } else if (strcmp(*argv, "hoplimit") == 0) {
+ unsigned hoplimit;
+ NEXT_ARG();
+ if (strcmp(*argv, "lock") == 0) {
+ mxlock |= (1<<RTAX_HOPLIMIT);
+ NEXT_ARG();
+ }
+ if (get_unsigned(&hoplimit, *argv, 0))
+ invarg("\"hoplimit\" value is invalid\n", *argv);
+ rta_addattr32(mxrta, sizeof(mxbuf), RTAX_HOPLIMIT, hoplimit);
+ } else if (strcmp(*argv, "advmss") == 0) {
+ unsigned mss;
+ NEXT_ARG();
+ if (strcmp(*argv, "lock") == 0) {
+ mxlock |= (1<<RTAX_ADVMSS);
+ NEXT_ARG();
+ }
+ if (get_unsigned(&mss, *argv, 0))
+ invarg("\"mss\" value is invalid\n", *argv);
+ rta_addattr32(mxrta, sizeof(mxbuf), RTAX_ADVMSS, mss);
+ } else if (matches(*argv, "reordering") == 0) {
+ unsigned reord;
+ NEXT_ARG();
+ if (strcmp(*argv, "lock") == 0) {
+ mxlock |= (1<<RTAX_REORDERING);
+ NEXT_ARG();
+ }
+ if (get_unsigned(&reord, *argv, 0))
+ invarg("\"reordering\" value is invalid\n", *argv);
+ rta_addattr32(mxrta, sizeof(mxbuf), RTAX_REORDERING, reord);
+ } else if (strcmp(*argv, "rtt") == 0) {
+ unsigned rtt;
+ NEXT_ARG();
+ if (strcmp(*argv, "lock") == 0) {
+ mxlock |= (1<<RTAX_RTT);
+ NEXT_ARG();
+ }
+ if (get_time_rtt(&rtt, *argv, &raw))
+ invarg("\"rtt\" value is invalid\n", *argv);
+ rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTT,
+ (raw) ? rtt : rtt * 8);
+ } else if (strcmp(*argv, "rto_min") == 0) {
+ unsigned rto_min;
+ NEXT_ARG();
+ mxlock |= (1<<RTAX_RTO_MIN);
+ if (get_time_rtt(&rto_min, *argv, &raw))
+ invarg("\"rto_min\" value is invalid\n",
+ *argv);
+ rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTO_MIN,
+ rto_min);
+ } else if (matches(*argv, "window") == 0) {
+ unsigned win;
+ NEXT_ARG();
+ if (strcmp(*argv, "lock") == 0) {
+ mxlock |= (1<<RTAX_WINDOW);
+ NEXT_ARG();
+ }
+ if (get_unsigned(&win, *argv, 0))
+ invarg("\"window\" value is invalid\n", *argv);
+ rta_addattr32(mxrta, sizeof(mxbuf), RTAX_WINDOW, win);
+ } else if (matches(*argv, "cwnd") == 0) {
+ unsigned win;
+ NEXT_ARG();
+ if (strcmp(*argv, "lock") == 0) {
+ mxlock |= (1<<RTAX_CWND);
+ NEXT_ARG();
+ }
+ if (get_unsigned(&win, *argv, 0))
+ invarg("\"cwnd\" value is invalid\n", *argv);
+ rta_addattr32(mxrta, sizeof(mxbuf), RTAX_CWND, win);
+ } else if (matches(*argv, "initcwnd") == 0) {
+ unsigned win;
+ NEXT_ARG();
+ if (strcmp(*argv, "lock") == 0) {
+ mxlock |= (1<<RTAX_INITCWND);
+ NEXT_ARG();
+ }
+ if (get_unsigned(&win, *argv, 0))
+ invarg("\"initcwnd\" value is invalid\n", *argv);
+ rta_addattr32(mxrta, sizeof(mxbuf), RTAX_INITCWND, win);
+ } else if (matches(*argv, "initrwnd") == 0) {
+ unsigned win;
+ NEXT_ARG();
+ if (strcmp(*argv, "lock") == 0) {
+ mxlock |= (1<<RTAX_INITRWND);
+ NEXT_ARG();
+ }
+ if (get_unsigned(&win, *argv, 0))
+ invarg("\"initrwnd\" value is invalid\n", *argv);
+ rta_addattr32(mxrta, sizeof(mxbuf), RTAX_INITRWND, win);
+ } else if (matches(*argv, "rttvar") == 0) {
+ unsigned win;
+ NEXT_ARG();
+ if (strcmp(*argv, "lock") == 0) {
+ mxlock |= (1<<RTAX_RTTVAR);
+ NEXT_ARG();
+ }
+ if (get_time_rtt(&win, *argv, &raw))
+ invarg("\"rttvar\" value is invalid\n", *argv);
+ rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTTVAR,
+ (raw) ? win : win * 4);
+ } else if (matches(*argv, "ssthresh") == 0) {
+ unsigned win;
+ NEXT_ARG();
+ if (strcmp(*argv, "lock") == 0) {
+ mxlock |= (1<<RTAX_SSTHRESH);
+ NEXT_ARG();
+ }
+ if (get_unsigned(&win, *argv, 0))
+ invarg("\"ssthresh\" value is invalid\n", *argv);
+ rta_addattr32(mxrta, sizeof(mxbuf), RTAX_SSTHRESH, win);
+ } else if (matches(*argv, "realms") == 0) {
+ __u32 realm;
+ NEXT_ARG();
+ if (get_rt_realms(&realm, *argv))
+ invarg("\"realm\" value is invalid\n", *argv);
+ addattr32(&req.n, sizeof(req), RTA_FLOW, realm);
+ } else if (strcmp(*argv, "onlink") == 0) {
+ req.r.rtm_flags |= RTNH_F_ONLINK;
+ } else if (strcmp(*argv, "nexthop") == 0) {
+ nhs_ok = 1;
+ break;
+ } else if (matches(*argv, "protocol") == 0) {
+ __u32 prot;
+ NEXT_ARG();
+ if (rtnl_rtprot_a2n(&prot, *argv))
+ invarg("\"protocol\" value is invalid\n", *argv);
+ req.r.rtm_protocol = prot;
+ } else if (matches(*argv, "table") == 0) {
+ __u32 tid;
+ NEXT_ARG();
+ if (rtnl_rttable_a2n(&tid, *argv))
+ invarg("\"table\" value is invalid\n", *argv);
+ if (tid < 256)
+ req.r.rtm_table = tid;
+ else {
+ req.r.rtm_table = RT_TABLE_UNSPEC;
+ addattr32(&req.n, sizeof(req), RTA_TABLE, tid);
+ }
+ table_ok = 1;
+ } else if (strcmp(*argv, "dev") == 0 ||
+ strcmp(*argv, "oif") == 0) {
+ NEXT_ARG();
+ d = *argv;
+ } else {
+ int type;
+ inet_prefix dst;
+
+ if (strcmp(*argv, "to") == 0) {
+ NEXT_ARG();
+ }
+ if ((**argv < '0' || **argv > '9') &&
+ rtnl_rtntype_a2n(&type, *argv) == 0) {
+ NEXT_ARG();
+ req.r.rtm_type = type;
+ }
+
+ if (matches(*argv, "help") == 0)
+ usage();
+ if (dst_ok)
+ duparg2("to", *argv);
+ get_prefix(&dst, *argv, req.r.rtm_family);
+ if (req.r.rtm_family == AF_UNSPEC)
+ req.r.rtm_family = dst.family;
+ req.r.rtm_dst_len = dst.bitlen;
+ dst_ok = 1;
+ if (dst.bytelen)
+ addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen);
+ }
+ argc--; argv++;
+ }
+
+ if (d || nhs_ok) {
+ int idx;
+
+ ll_init_map(&rth);
+
+ if (d) {
+ if ((idx = ll_name_to_index(d)) == 0) {
+ fprintf(stderr, "Cannot find device \"%s\"\n", d);
+ return -1;
+ }
+ addattr32(&req.n, sizeof(req), RTA_OIF, idx);
+ }
+ }
+
+ if (mxrta->rta_len > RTA_LENGTH(0)) {
+ if (mxlock)
+ rta_addattr32(mxrta, sizeof(mxbuf), RTAX_LOCK, mxlock);
+ addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta));
+ }
+
+ if (nhs_ok)
+ parse_nexthops(&req.n, &req.r, argc, argv);
+
+ if (!table_ok) {
+ if (req.r.rtm_type == RTN_LOCAL ||
+ req.r.rtm_type == RTN_BROADCAST ||
+ req.r.rtm_type == RTN_NAT ||
+ req.r.rtm_type == RTN_ANYCAST)
+ req.r.rtm_table = RT_TABLE_LOCAL;
+ }
+ if (!scope_ok) {
+ if (req.r.rtm_type == RTN_LOCAL ||
+ req.r.rtm_type == RTN_NAT)
+ req.r.rtm_scope = RT_SCOPE_HOST;
+ else if (req.r.rtm_type == RTN_BROADCAST ||
+ req.r.rtm_type == RTN_MULTICAST ||
+ req.r.rtm_type == RTN_ANYCAST)
+ req.r.rtm_scope = RT_SCOPE_LINK;
+ else if (req.r.rtm_type == RTN_UNICAST ||
+ req.r.rtm_type == RTN_UNSPEC) {
+ if (cmd == RTM_DELROUTE)
+ req.r.rtm_scope = RT_SCOPE_NOWHERE;
+ else if (!gw_ok && !nhs_ok)
+ req.r.rtm_scope = RT_SCOPE_LINK;
+ }
+ }
+
+ if (req.r.rtm_family == AF_UNSPEC)
+ req.r.rtm_family = AF_INET;
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ exit(2);
+
+ return 0;
+}
+
+static int rtnl_rtcache_request(struct rtnl_handle *rth, int family)
+{
+ struct {
+ struct nlmsghdr nlh;
+ struct rtmsg rtm;
+ } req;
+ struct sockaddr_nl nladdr;
+
+ memset(&nladdr, 0, sizeof(nladdr));
+ memset(&req, 0, sizeof(req));
+ nladdr.nl_family = AF_NETLINK;
+
+ req.nlh.nlmsg_len = sizeof(req);
+ req.nlh.nlmsg_type = RTM_GETROUTE;
+ req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_REQUEST;
+ req.nlh.nlmsg_pid = 0;
+ req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
+ req.rtm.rtm_family = family;
+ req.rtm.rtm_flags |= RTM_F_CLONED;
+
+ return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
+}
+
+static int iproute_flush_cache(void)
+{
+#define ROUTE_FLUSH_PATH "/proc/sys/net/ipv4/route/flush"
+
+ int len;
+ int flush_fd = open (ROUTE_FLUSH_PATH, O_WRONLY);
+ char *buffer = "-1";
+
+ if (flush_fd < 0) {
+ fprintf (stderr, "Cannot open \"%s\"\n", ROUTE_FLUSH_PATH);
+ return -1;
+ }
+
+ len = strlen (buffer);
+
+ if ((write (flush_fd, (void *)buffer, len)) < len) {
+ fprintf (stderr, "Cannot flush routing cache\n");
+ close(flush_fd);
+ return -1;
+ }
+ close(flush_fd);
+ return 0;
+}
+
+int save_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+{
+ int ret;
+ int len = n->nlmsg_len;
+ struct rtmsg *r = NLMSG_DATA(n);
+ struct rtattr *tb[RTA_MAX+1];
+ int host_len = -1;
+
+ if (isatty(STDOUT_FILENO)) {
+ fprintf(stderr, "Not sending binary stream to stdout\n");
+ return -1;
+ }
+
+ host_len = calc_host_len(r);
+ len -= NLMSG_LENGTH(sizeof(*r));
+ parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
+
+ if (!filter_nlmsg(n, tb, host_len))
+ return 0;
+
+ ret = write(STDOUT_FILENO, n, n->nlmsg_len);
+ if ((ret > 0) && (ret != n->nlmsg_len)) {
+ fprintf(stderr, "Short write while saving nlmsg\n");
+ ret = -EIO;
+ }
+
+ return ret == n->nlmsg_len ? 0 : ret;
+}
+
+static int iproute_list_flush_or_save(int argc, char **argv, int action)
+{
+ int do_ipv6 = preferred_family;
+ char *id = NULL;
+ char *od = NULL;
+ unsigned int mark = 0;
+ rtnl_filter_t filter_fn;
+
+ if (action == IPROUTE_SAVE)
+ filter_fn = save_route;
+ else
+ filter_fn = print_route;
+
+ iproute_reset_filter();
+ filter.tb = RT_TABLE_MAIN;
+
+ if ((action == IPROUTE_FLUSH) && argc <= 0) {
+ fprintf(stderr, "\"ip route flush\" requires arguments.\n");
+ return -1;
+ }
+
+ while (argc > 0) {
+ if (matches(*argv, "table") == 0) {
+ __u32 tid;
+ NEXT_ARG();
+ if (rtnl_rttable_a2n(&tid, *argv)) {
+ if (strcmp(*argv, "all") == 0) {
+ filter.tb = 0;
+ } else if (strcmp(*argv, "cache") == 0) {
+ filter.cloned = 1;
+ } else if (strcmp(*argv, "help") == 0) {
+ usage();
+ } else {
+ invarg("table id value is invalid\n", *argv);
+ }
+ } else
+ filter.tb = tid;
+ } else if (matches(*argv, "cached") == 0 ||
+ matches(*argv, "cloned") == 0) {
+ filter.cloned = 1;
+ } else if (strcmp(*argv, "tos") == 0 ||
+ matches(*argv, "dsfield") == 0) {
+ __u32 tos;
+ NEXT_ARG();
+ if (rtnl_dsfield_a2n(&tos, *argv))
+ invarg("TOS value is invalid\n", *argv);
+ filter.tos = tos;
+ filter.tosmask = -1;
+ } else if (matches(*argv, "protocol") == 0) {
+ __u32 prot = 0;
+ NEXT_ARG();
+ filter.protocolmask = -1;
+ if (rtnl_rtprot_a2n(&prot, *argv)) {
+ if (strcmp(*argv, "all") != 0)
+ invarg("invalid \"protocol\"\n", *argv);
+ prot = 0;
+ filter.protocolmask = 0;
+ }
+ filter.protocol = prot;
+ } else if (matches(*argv, "scope") == 0) {
+ __u32 scope = 0;
+ NEXT_ARG();
+ filter.scopemask = -1;
+ if (rtnl_rtscope_a2n(&scope, *argv)) {
+ if (strcmp(*argv, "all") != 0)
+ invarg("invalid \"scope\"\n", *argv);
+ scope = RT_SCOPE_NOWHERE;
+ filter.scopemask = 0;
+ }
+ filter.scope = scope;
+ } else if (matches(*argv, "type") == 0) {
+ int type;
+ NEXT_ARG();
+ filter.typemask = -1;
+ if (rtnl_rtntype_a2n(&type, *argv))
+ invarg("node type value is invalid\n", *argv);
+ filter.type = type;
+ } else if (strcmp(*argv, "dev") == 0 ||
+ strcmp(*argv, "oif") == 0) {
+ NEXT_ARG();
+ od = *argv;
+ } else if (strcmp(*argv, "iif") == 0) {
+ NEXT_ARG();
+ id = *argv;
+ } else if (strcmp(*argv, "mark") == 0) {
+ NEXT_ARG();
+ get_unsigned(&mark, *argv, 0);
+ filter.markmask = -1;
+ } else if (strcmp(*argv, "via") == 0) {
+ NEXT_ARG();
+ get_prefix(&filter.rvia, *argv, do_ipv6);
+ } else if (strcmp(*argv, "src") == 0) {
+ NEXT_ARG();
+ get_prefix(&filter.rprefsrc, *argv, do_ipv6);
+ } else if (matches(*argv, "realms") == 0) {
+ __u32 realm;
+ NEXT_ARG();
+ if (get_rt_realms(&realm, *argv))
+ invarg("invalid realms\n", *argv);
+ filter.realm = realm;
+ filter.realmmask = ~0U;
+ if ((filter.realm&0xFFFF) == 0 &&
+ (*argv)[strlen(*argv) - 1] == '/')
+ filter.realmmask &= ~0xFFFF;
+ if ((filter.realm&0xFFFF0000U) == 0 &&
+ (strchr(*argv, '/') == NULL ||
+ (*argv)[0] == '/'))
+ filter.realmmask &= ~0xFFFF0000U;
+ } else if (matches(*argv, "from") == 0) {
+ NEXT_ARG();
+ if (matches(*argv, "root") == 0) {
+ NEXT_ARG();
+ get_prefix(&filter.rsrc, *argv, do_ipv6);
+ } else if (matches(*argv, "match") == 0) {
+ NEXT_ARG();
+ get_prefix(&filter.msrc, *argv, do_ipv6);
+ } else {
+ if (matches(*argv, "exact") == 0) {
+ NEXT_ARG();
+ }
+ get_prefix(&filter.msrc, *argv, do_ipv6);
+ filter.rsrc = filter.msrc;
+ }
+ } else {
+ if (matches(*argv, "to") == 0) {
+ NEXT_ARG();
+ }
+ if (matches(*argv, "root") == 0) {
+ NEXT_ARG();
+ get_prefix(&filter.rdst, *argv, do_ipv6);
+ } else if (matches(*argv, "match") == 0) {
+ NEXT_ARG();
+ get_prefix(&filter.mdst, *argv, do_ipv6);
+ } else {
+ if (matches(*argv, "exact") == 0) {
+ NEXT_ARG();
+ }
+ get_prefix(&filter.mdst, *argv, do_ipv6);
+ filter.rdst = filter.mdst;
+ }
+ }
+ argc--; argv++;
+ }
+
+ if (do_ipv6 == AF_UNSPEC && filter.tb)
+ do_ipv6 = AF_INET;
+
+ ll_init_map(&rth);
+
+ if (id || od) {
+ int idx;
+
+ if (id) {
+ if ((idx = ll_name_to_index(id)) == 0) {
+ fprintf(stderr, "Cannot find device \"%s\"\n", id);
+ return -1;
+ }
+ filter.iif = idx;
+ filter.iifmask = -1;
+ }
+ if (od) {
+ if ((idx = ll_name_to_index(od)) == 0) {
+ fprintf(stderr, "Cannot find device \"%s\"\n", od);
+ return -1;
+ }
+ filter.oif = idx;
+ filter.oifmask = -1;
+ }
+ }
+ filter.mark = mark;
+
+ if (action == IPROUTE_FLUSH) {
+ int round = 0;
+ char flushb[4096-512];
+ time_t start = time(0);
+
+ if (filter.cloned) {
+ if (do_ipv6 != AF_INET6) {
+ iproute_flush_cache();
+ if (show_stats)
+ printf("*** IPv4 routing cache is flushed.\n");
+ }
+ if (do_ipv6 == AF_INET)
+ return 0;
+ }
+
+ filter.flushb = flushb;
+ filter.flushp = 0;
+ filter.flushe = sizeof(flushb);
+
+ for (;;) {
+ if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
+ perror("Cannot send dump request");
+ exit(1);
+ }
+ filter.flushed = 0;
+ if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) {
+ fprintf(stderr, "Flush terminated\n");
+ exit(1);
+ }
+ if (filter.flushed == 0) {
+ if (show_stats) {
+ if (round == 0 && (!filter.cloned || do_ipv6 == AF_INET6))
+ printf("Nothing to flush.\n");
+ else
+ printf("*** Flush is complete after %d round%s ***\n", round, round>1?"s":"");
+ }
+ fflush(stdout);
+ return 0;
+ }
+ round++;
+ if (flush_update() < 0)
+ exit(1);
+
+ if (time(0) - start > 30) {
+ printf("\n*** Flush not completed after %ld seconds, %d entries remain ***\n",
+ time(0) - start, filter.flushed);
+ exit(1);
+ }
+
+ if (show_stats) {
+ printf("\n*** Round %d, deleting %d entries ***\n", round, filter.flushed);
+ fflush(stdout);
+ }
+ }
+ }
+
+ if (!filter.cloned) {
+ if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
+ perror("Cannot send dump request");
+ exit(1);
+ }
+ } else {
+ if (rtnl_rtcache_request(&rth, do_ipv6) < 0) {
+ perror("Cannot send dump request");
+ exit(1);
+ }
+ }
+
+ if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) {
+ fprintf(stderr, "Dump terminated\n");
+ exit(1);
+ }
+
+ exit(0);
+}
+
+
+int iproute_get(int argc, char **argv)
+{
+ struct {
+ struct nlmsghdr n;
+ struct rtmsg r;
+ char buf[1024];
+ } req;
+ char *idev = NULL;
+ char *odev = NULL;
+ int connected = 0;
+ int from_ok = 0;
+ unsigned int mark = 0;
+
+ memset(&req, 0, sizeof(req));
+
+ iproute_reset_filter();
+ filter.cloned = 2;
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = RTM_GETROUTE;
+ req.r.rtm_family = preferred_family;
+ req.r.rtm_table = 0;
+ req.r.rtm_protocol = 0;
+ req.r.rtm_scope = 0;
+ req.r.rtm_type = 0;
+ req.r.rtm_src_len = 0;
+ req.r.rtm_dst_len = 0;
+ req.r.rtm_tos = 0;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "tos") == 0 ||
+ matches(*argv, "dsfield") == 0) {
+ __u32 tos;
+ NEXT_ARG();
+ if (rtnl_dsfield_a2n(&tos, *argv))
+ invarg("TOS value is invalid\n", *argv);
+ req.r.rtm_tos = tos;
+ } else if (matches(*argv, "from") == 0) {
+ inet_prefix addr;
+ NEXT_ARG();
+ if (matches(*argv, "help") == 0)
+ usage();
+ from_ok = 1;
+ get_prefix(&addr, *argv, req.r.rtm_family);
+ if (req.r.rtm_family == AF_UNSPEC)
+ req.r.rtm_family = addr.family;
+ if (addr.bytelen)
+ addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen);
+ req.r.rtm_src_len = addr.bitlen;
+ } else if (matches(*argv, "iif") == 0) {
+ NEXT_ARG();
+ idev = *argv;
+ } else if (matches(*argv, "mark") == 0) {
+ NEXT_ARG();
+ get_unsigned(&mark, *argv, 0);
+ } else if (matches(*argv, "oif") == 0 ||
+ strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ odev = *argv;
+ } else if (matches(*argv, "notify") == 0) {
+ req.r.rtm_flags |= RTM_F_NOTIFY;
+ } else if (matches(*argv, "connected") == 0) {
+ connected = 1;
+ } else {
+ inet_prefix addr;
+ if (strcmp(*argv, "to") == 0) {
+ NEXT_ARG();
+ }
+ if (matches(*argv, "help") == 0)
+ usage();
+ get_prefix(&addr, *argv, req.r.rtm_family);
+ if (req.r.rtm_family == AF_UNSPEC)
+ req.r.rtm_family = addr.family;
+ if (addr.bytelen)
+ addattr_l(&req.n, sizeof(req), RTA_DST, &addr.data, addr.bytelen);
+ req.r.rtm_dst_len = addr.bitlen;
+ }
+ argc--; argv++;
+ }
+
+ if (req.r.rtm_dst_len == 0) {
+ fprintf(stderr, "need at least destination address\n");
+ exit(1);
+ }
+
+ ll_init_map(&rth);
+
+ if (idev || odev) {
+ int idx;
+
+ if (idev) {
+ if ((idx = ll_name_to_index(idev)) == 0) {
+ fprintf(stderr, "Cannot find device \"%s\"\n", idev);
+ return -1;
+ }
+ addattr32(&req.n, sizeof(req), RTA_IIF, idx);
+ }
+ if (odev) {
+ if ((idx = ll_name_to_index(odev)) == 0) {
+ fprintf(stderr, "Cannot find device \"%s\"\n", odev);
+ return -1;
+ }
+ addattr32(&req.n, sizeof(req), RTA_OIF, idx);
+ }
+ }
+ if (mark)
+ addattr32(&req.n, sizeof(req), RTA_MARK, mark);
+
+ if (req.r.rtm_family == AF_UNSPEC)
+ req.r.rtm_family = AF_INET;
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0)
+ exit(2);
+
+ if (connected && !from_ok) {
+ struct rtmsg *r = NLMSG_DATA(&req.n);
+ int len = req.n.nlmsg_len;
+ struct rtattr * tb[RTA_MAX+1];
+
+ if (print_route(NULL, &req.n, (void*)stdout) < 0) {
+ fprintf(stderr, "An error :-)\n");
+ exit(1);
+ }
+
+ if (req.n.nlmsg_type != RTM_NEWROUTE) {
+ fprintf(stderr, "Not a route?\n");
+ return -1;
+ }
+ len -= NLMSG_LENGTH(sizeof(*r));
+ if (len < 0) {
+ fprintf(stderr, "Wrong len %d\n", len);
+ return -1;
+ }
+
+ parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
+
+ if (tb[RTA_PREFSRC]) {
+ tb[RTA_PREFSRC]->rta_type = RTA_SRC;
+ r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]);
+ } else if (!tb[RTA_SRC]) {
+ fprintf(stderr, "Failed to connect the route\n");
+ return -1;
+ }
+ if (!odev && tb[RTA_OIF])
+ tb[RTA_OIF]->rta_type = 0;
+ if (tb[RTA_GATEWAY])
+ tb[RTA_GATEWAY]->rta_type = 0;
+ if (!idev && tb[RTA_IIF])
+ tb[RTA_IIF]->rta_type = 0;
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = RTM_GETROUTE;
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0)
+ exit(2);
+ }
+
+ if (print_route(NULL, &req.n, (void*)stdout) < 0) {
+ fprintf(stderr, "An error :-)\n");
+ exit(1);
+ }
+
+ exit(0);
+}
+
+int restore_handler(const struct sockaddr_nl *nl, struct nlmsghdr *n, void *arg)
+{
+ int ret;
+
+ n->nlmsg_flags |= NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK;
+
+ ll_init_map(&rth);
+
+ ret = rtnl_talk(&rth, n, 0, 0, n);
+ if ((ret < 0) && (errno == EEXIST))
+ ret = 0;
+
+ return ret;
+}
+
+int iproute_restore(void)
+{
+ exit(rtnl_from_file(stdin, &restore_handler, NULL));
+}
+
+void iproute_reset_filter()
+{
+ memset(&filter, 0, sizeof(filter));
+ filter.mdst.bitlen = -1;
+ filter.msrc.bitlen = -1;
+}
+
+int do_iproute(int argc, char **argv)
+{
+ if (argc < 1)
+ return iproute_list_flush_or_save(0, NULL, IPROUTE_LIST);
+
+ if (matches(*argv, "add") == 0)
+ return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_EXCL,
+ argc-1, argv+1);
+ if (matches(*argv, "change") == 0 || strcmp(*argv, "chg") == 0)
+ return iproute_modify(RTM_NEWROUTE, NLM_F_REPLACE,
+ argc-1, argv+1);
+ if (matches(*argv, "replace") == 0)
+ return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_REPLACE,
+ argc-1, argv+1);
+ if (matches(*argv, "prepend") == 0)
+ return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE,
+ argc-1, argv+1);
+ if (matches(*argv, "append") == 0)
+ return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_APPEND,
+ argc-1, argv+1);
+ if (matches(*argv, "test") == 0)
+ return iproute_modify(RTM_NEWROUTE, NLM_F_EXCL,
+ argc-1, argv+1);
+ if (matches(*argv, "delete") == 0)
+ return iproute_modify(RTM_DELROUTE, 0,
+ argc-1, argv+1);
+ if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
+ || matches(*argv, "lst") == 0)
+ return iproute_list_flush_or_save(argc-1, argv+1, IPROUTE_LIST);
+ if (matches(*argv, "get") == 0)
+ return iproute_get(argc-1, argv+1);
+ if (matches(*argv, "flush") == 0)
+ return iproute_list_flush_or_save(argc-1, argv+1, IPROUTE_FLUSH);
+ if (matches(*argv, "save") == 0)
+ return iproute_list_flush_or_save(argc-1, argv+1, IPROUTE_SAVE);
+ if (matches(*argv, "restore") == 0)
+ return iproute_restore();
+ if (matches(*argv, "help") == 0)
+ usage();
+ fprintf(stderr, "Command \"%s\" is unknown, try \"ip route help\".\n", *argv);
+ exit(-1);
+}
+
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/iprule.c b/ap/app/iproute2/iproute2-3.4.0/ip/iprule.c
new file mode 100755
index 0000000..a5fcd43
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/iprule.c
@@ -0,0 +1,460 @@
+/*
+ * iprule.c "ip rule".
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <linux/fib_rules.h>
+
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+
+extern struct rtnl_handle rth;
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: ip rule [ list | add | del | flush ] SELECTOR ACTION\n");
+ fprintf(stderr, "SELECTOR := [ not ] [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK[/MASK] ]\n");
+ fprintf(stderr, " [ iif STRING ] [ oif STRING ] [ pref NUMBER ]\n");
+ fprintf(stderr, "ACTION := [ table TABLE_ID ]\n");
+ fprintf(stderr, " [ prohibit | reject | unreachable ]\n");
+ fprintf(stderr, " [ realms [SRCREALM/]DSTREALM ]\n");
+ fprintf(stderr, " [ goto NUMBER ]\n");
+ fprintf(stderr, "TABLE_ID := [ local | main | default | NUMBER ]\n");
+ exit(-1);
+}
+
+int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+{
+ FILE *fp = (FILE*)arg;
+ struct rtmsg *r = NLMSG_DATA(n);
+ int len = n->nlmsg_len;
+ int host_len = -1;
+ __u32 table;
+ struct rtattr * tb[FRA_MAX+1];
+ char abuf[256];
+ SPRINT_BUF(b1);
+
+ if (n->nlmsg_type != RTM_NEWRULE && n->nlmsg_type != RTM_DELRULE)
+ return 0;
+
+ len -= NLMSG_LENGTH(sizeof(*r));
+ if (len < 0)
+ return -1;
+
+ parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len);
+
+ if (r->rtm_family == AF_INET)
+ host_len = 32;
+ else if (r->rtm_family == AF_INET6)
+ host_len = 128;
+ else if (r->rtm_family == AF_DECnet)
+ host_len = 16;
+ else if (r->rtm_family == AF_IPX)
+ host_len = 80;
+
+ if (n->nlmsg_type == RTM_DELRULE)
+ fprintf(fp, "Deleted ");
+
+ if (tb[FRA_PRIORITY])
+ fprintf(fp, "%u:\t", *(unsigned*)RTA_DATA(tb[FRA_PRIORITY]));
+ else
+ fprintf(fp, "0:\t");
+
+ if (r->rtm_flags & FIB_RULE_INVERT)
+ fprintf(fp, "not ");
+
+ if (tb[FRA_SRC]) {
+ if (r->rtm_src_len != host_len) {
+ fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family,
+ RTA_PAYLOAD(tb[FRA_SRC]),
+ RTA_DATA(tb[FRA_SRC]),
+ abuf, sizeof(abuf)),
+ r->rtm_src_len
+ );
+ } else {
+ fprintf(fp, "from %s ", format_host(r->rtm_family,
+ RTA_PAYLOAD(tb[FRA_SRC]),
+ RTA_DATA(tb[FRA_SRC]),
+ abuf, sizeof(abuf))
+ );
+ }
+ } else if (r->rtm_src_len) {
+ fprintf(fp, "from 0/%d ", r->rtm_src_len);
+ } else {
+ fprintf(fp, "from all ");
+ }
+
+ if (tb[FRA_DST]) {
+ if (r->rtm_dst_len != host_len) {
+ fprintf(fp, "to %s/%u ", rt_addr_n2a(r->rtm_family,
+ RTA_PAYLOAD(tb[FRA_DST]),
+ RTA_DATA(tb[FRA_DST]),
+ abuf, sizeof(abuf)),
+ r->rtm_dst_len
+ );
+ } else {
+ fprintf(fp, "to %s ", format_host(r->rtm_family,
+ RTA_PAYLOAD(tb[FRA_DST]),
+ RTA_DATA(tb[FRA_DST]),
+ abuf, sizeof(abuf)));
+ }
+ } else if (r->rtm_dst_len) {
+ fprintf(fp, "to 0/%d ", r->rtm_dst_len);
+ }
+
+ if (r->rtm_tos) {
+ SPRINT_BUF(b1);
+ fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
+ }
+
+ if (tb[FRA_FWMARK] || tb[FRA_FWMASK]) {
+ __u32 mark = 0, mask = 0;
+
+ if (tb[FRA_FWMARK])
+ mark = rta_getattr_u32(tb[FRA_FWMARK]);
+
+ if (tb[FRA_FWMASK] &&
+ (mask = rta_getattr_u32(tb[FRA_FWMASK])) != 0xFFFFFFFF)
+ fprintf(fp, "fwmark 0x%x/0x%x ", mark, mask);
+ else
+ fprintf(fp, "fwmark 0x%x ", mark);
+ }
+
+ if (tb[FRA_IFNAME]) {
+ fprintf(fp, "iif %s ", rta_getattr_str(tb[FRA_IFNAME]));
+ if (r->rtm_flags & FIB_RULE_IIF_DETACHED)
+ fprintf(fp, "[detached] ");
+ }
+
+ if (tb[FRA_OIFNAME]) {
+ fprintf(fp, "oif %s ", rta_getattr_str(tb[FRA_OIFNAME]));
+ if (r->rtm_flags & FIB_RULE_OIF_DETACHED)
+ fprintf(fp, "[detached] ");
+ }
+
+ table = rtm_get_table(r, tb);
+ if (table)
+ fprintf(fp, "lookup %s ", rtnl_rttable_n2a(table, b1, sizeof(b1)));
+
+ if (tb[FRA_FLOW]) {
+ __u32 to = rta_getattr_u32(tb[FRA_FLOW]);
+ __u32 from = to>>16;
+ to &= 0xFFFF;
+ if (from) {
+ fprintf(fp, "realms %s/",
+ rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
+ }
+ fprintf(fp, "%s ",
+ rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
+ }
+
+ if (r->rtm_type == RTN_NAT) {
+ if (tb[RTA_GATEWAY]) {
+ fprintf(fp, "map-to %s ",
+ format_host(r->rtm_family,
+ RTA_PAYLOAD(tb[RTA_GATEWAY]),
+ RTA_DATA(tb[RTA_GATEWAY]),
+ abuf, sizeof(abuf)));
+ } else
+ fprintf(fp, "masquerade");
+ } else if (r->rtm_type == FR_ACT_GOTO) {
+ fprintf(fp, "goto ");
+ if (tb[FRA_GOTO])
+ fprintf(fp, "%u", rta_getattr_u32(tb[FRA_GOTO]));
+ else
+ fprintf(fp, "none");
+ if (r->rtm_flags & FIB_RULE_UNRESOLVED)
+ fprintf(fp, " [unresolved]");
+ } else if (r->rtm_type == FR_ACT_NOP)
+ fprintf(fp, "nop");
+ else if (r->rtm_type != RTN_UNICAST)
+ fprintf(fp, "%s", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
+
+ fprintf(fp, "\n");
+ fflush(fp);
+ return 0;
+}
+
+static int iprule_list(int argc, char **argv)
+{
+ int af = preferred_family;
+
+ if (af == AF_UNSPEC)
+ af = AF_INET;
+
+ if (argc > 0) {
+ fprintf(stderr, "\"ip rule show\" does not take any arguments.\n");
+ return -1;
+ }
+
+ if (rtnl_wilddump_request(&rth, af, RTM_GETRULE) < 0) {
+ perror("Cannot send dump request");
+ return 1;
+ }
+
+ if (rtnl_dump_filter(&rth, print_rule, stdout) < 0) {
+ fprintf(stderr, "Dump terminated\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int iprule_modify(int cmd, int argc, char **argv)
+{
+ int table_ok = 0;
+ struct {
+ struct nlmsghdr n;
+ struct rtmsg r;
+ char buf[1024];
+ } req;
+
+ memset(&req, 0, sizeof(req));
+
+ req.n.nlmsg_type = cmd;
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.r.rtm_family = preferred_family;
+ req.r.rtm_protocol = RTPROT_BOOT;
+ req.r.rtm_scope = RT_SCOPE_UNIVERSE;
+ req.r.rtm_table = 0;
+ req.r.rtm_type = RTN_UNSPEC;
+ req.r.rtm_flags = 0;
+
+ if (cmd == RTM_NEWRULE) {
+ req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
+ req.r.rtm_type = RTN_UNICAST;
+ }
+
+ while (argc > 0) {
+ if (strcmp(*argv, "not") == 0) {
+ req.r.rtm_flags |= FIB_RULE_INVERT;
+ } else if (strcmp(*argv, "from") == 0) {
+ inet_prefix dst;
+ NEXT_ARG();
+ get_prefix(&dst, *argv, req.r.rtm_family);
+ req.r.rtm_src_len = dst.bitlen;
+ addattr_l(&req.n, sizeof(req), FRA_SRC, &dst.data, dst.bytelen);
+ } else if (strcmp(*argv, "to") == 0) {
+ inet_prefix dst;
+ NEXT_ARG();
+ get_prefix(&dst, *argv, req.r.rtm_family);
+ req.r.rtm_dst_len = dst.bitlen;
+ addattr_l(&req.n, sizeof(req), FRA_DST, &dst.data, dst.bytelen);
+ } else if (matches(*argv, "preference") == 0 ||
+ matches(*argv, "order") == 0 ||
+ matches(*argv, "priority") == 0) {
+ __u32 pref;
+ NEXT_ARG();
+ if (get_u32(&pref, *argv, 0))
+ invarg("preference value is invalid\n", *argv);
+ addattr32(&req.n, sizeof(req), FRA_PRIORITY, pref);
+ } else if (strcmp(*argv, "tos") == 0 ||
+ matches(*argv, "dsfield") == 0) {
+ __u32 tos;
+ NEXT_ARG();
+ if (rtnl_dsfield_a2n(&tos, *argv))
+ invarg("TOS value is invalid\n", *argv);
+ req.r.rtm_tos = tos;
+ } else if (strcmp(*argv, "fwmark") == 0) {
+ char *slash;
+ __u32 fwmark, fwmask;
+ NEXT_ARG();
+ if ((slash = strchr(*argv, '/')) != NULL)
+ *slash = '\0';
+ if (get_u32(&fwmark, *argv, 0))
+ invarg("fwmark value is invalid\n", *argv);
+ addattr32(&req.n, sizeof(req), FRA_FWMARK, fwmark);
+ if (slash) {
+ if (get_u32(&fwmask, slash+1, 0))
+ invarg("fwmask value is invalid\n", slash+1);
+ addattr32(&req.n, sizeof(req), FRA_FWMASK, fwmask);
+ }
+ } else if (matches(*argv, "realms") == 0) {
+ __u32 realm;
+ NEXT_ARG();
+ if (get_rt_realms(&realm, *argv))
+ invarg("invalid realms\n", *argv);
+ addattr32(&req.n, sizeof(req), FRA_FLOW, realm);
+ } else if (matches(*argv, "table") == 0 ||
+ strcmp(*argv, "lookup") == 0) {
+ __u32 tid;
+ NEXT_ARG();
+ if (rtnl_rttable_a2n(&tid, *argv))
+ invarg("invalid table ID\n", *argv);
+ if (tid < 256)
+ req.r.rtm_table = tid;
+ else {
+ req.r.rtm_table = RT_TABLE_UNSPEC;
+ addattr32(&req.n, sizeof(req), FRA_TABLE, tid);
+ }
+ table_ok = 1;
+ } else if (strcmp(*argv, "dev") == 0 ||
+ strcmp(*argv, "iif") == 0) {
+ NEXT_ARG();
+ addattr_l(&req.n, sizeof(req), FRA_IFNAME, *argv, strlen(*argv)+1);
+ } else if (strcmp(*argv, "oif") == 0) {
+ NEXT_ARG();
+ addattr_l(&req.n, sizeof(req), FRA_OIFNAME, *argv, strlen(*argv)+1);
+ } else if (strcmp(*argv, "nat") == 0 ||
+ matches(*argv, "map-to") == 0) {
+ NEXT_ARG();
+ fprintf(stderr, "Warning: route NAT is deprecated\n");
+ addattr32(&req.n, sizeof(req), RTA_GATEWAY, get_addr32(*argv));
+ req.r.rtm_type = RTN_NAT;
+ } else {
+ int type;
+
+ if (strcmp(*argv, "type") == 0) {
+ NEXT_ARG();
+ }
+ if (matches(*argv, "help") == 0)
+ usage();
+ else if (matches(*argv, "goto") == 0) {
+ __u32 target;
+ type = FR_ACT_GOTO;
+ NEXT_ARG();
+ if (get_u32(&target, *argv, 0))
+ invarg("invalid target\n", *argv);
+ addattr32(&req.n, sizeof(req), FRA_GOTO, target);
+ } else if (matches(*argv, "nop") == 0)
+ type = FR_ACT_NOP;
+ else if (rtnl_rtntype_a2n(&type, *argv))
+ invarg("Failed to parse rule type", *argv);
+ req.r.rtm_type = type;
+ table_ok = 1;
+ }
+ argc--;
+ argv++;
+ }
+
+ if (req.r.rtm_family == AF_UNSPEC)
+ req.r.rtm_family = AF_INET;
+
+ if (!table_ok && cmd == RTM_NEWRULE)
+ req.r.rtm_table = RT_TABLE_MAIN;
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ return 2;
+
+ return 0;
+}
+
+
+static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+{
+ struct rtnl_handle rth2;
+ struct rtmsg *r = NLMSG_DATA(n);
+ int len = n->nlmsg_len;
+ struct rtattr * tb[FRA_MAX+1];
+
+ len -= NLMSG_LENGTH(sizeof(*r));
+ if (len < 0)
+ return -1;
+
+ parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len);
+
+ if (tb[FRA_PRIORITY]) {
+ n->nlmsg_type = RTM_DELRULE;
+ n->nlmsg_flags = NLM_F_REQUEST;
+
+ if (rtnl_open(&rth2, 0) < 0)
+ return -1;
+
+ if (rtnl_talk(&rth2, n, 0, 0, NULL) < 0)
+ return -2;
+
+ rtnl_close(&rth2);
+ }
+
+ return 0;
+}
+
+static int iprule_flush(int argc, char **argv)
+{
+ int af = preferred_family;
+
+ if (af == AF_UNSPEC)
+ af = AF_INET;
+
+ if (argc > 0) {
+ fprintf(stderr, "\"ip rule flush\" does not allow arguments\n");
+ return -1;
+ }
+
+ if (rtnl_wilddump_request(&rth, af, RTM_GETRULE) < 0) {
+ perror("Cannot send dump request");
+ return 1;
+ }
+
+ if (rtnl_dump_filter(&rth, flush_rule, NULL) < 0) {
+ fprintf(stderr, "Flush terminated\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+int do_iprule(int argc, char **argv)
+{
+ if (argc < 1) {
+ return iprule_list(0, NULL);
+ } else if (matches(argv[0], "list") == 0 ||
+ matches(argv[0], "lst") == 0 ||
+ matches(argv[0], "show") == 0) {
+ return iprule_list(argc-1, argv+1);
+ } else if (matches(argv[0], "add") == 0) {
+ return iprule_modify(RTM_NEWRULE, argc-1, argv+1);
+ } else if (matches(argv[0], "delete") == 0) {
+ return iprule_modify(RTM_DELRULE, argc-1, argv+1);
+ } else if (matches(argv[0], "flush") == 0) {
+ return iprule_flush(argc-1, argv+1);
+ } else if (matches(argv[0], "help") == 0)
+ usage();
+
+ fprintf(stderr, "Command \"%s\" is unknown, try \"ip rule help\".\n", *argv);
+ exit(-1);
+}
+
+int do_multirule(int argc, char **argv)
+{
+ switch (preferred_family) {
+ case AF_UNSPEC:
+ case AF_INET:
+ preferred_family = RTNL_FAMILY_IPMR;
+ break;
+ case AF_INET6:
+ preferred_family = RTNL_FAMILY_IP6MR;
+ break;
+ case RTNL_FAMILY_IPMR:
+ case RTNL_FAMILY_IP6MR:
+ break;
+ default:
+ fprintf(stderr, "Multicast rules are only supported for IPv4/IPv6, was: %i\n",
+ preferred_family);
+ exit(-1);
+ }
+
+ return do_iprule(argc, argv);
+}
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/iptunnel.c b/ap/app/iproute2/iproute2-3.4.0/ip/iptunnel.c
new file mode 100755
index 0000000..3d41a27
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/iptunnel.c
@@ -0,0 +1,640 @@
+/*
+ * iptunnel.c "ip tunnel"
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <linux/ip.h>
+#include <linux/if_tunnel.h>
+
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+#include "tunnel.h"
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: ip tunnel { add | change | del | show | prl | 6rd } [ NAME ]\n");
+ fprintf(stderr, " [ mode { ipip | gre | sit | isatap } ] [ remote ADDR ] [ local ADDR ]\n");
+ fprintf(stderr, " [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n");
+ fprintf(stderr, " [ prl-default ADDR ] [ prl-nodefault ADDR ] [ prl-delete ADDR ]\n");
+ fprintf(stderr, " [ 6rd-prefix ADDR ] [ 6rd-relay_prefix ADDR ] [ 6rd-reset ]\n");
+ fprintf(stderr, " [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Where: NAME := STRING\n");
+ fprintf(stderr, " ADDR := { IP_ADDRESS | any }\n");
+ fprintf(stderr, " TOS := { NUMBER | inherit }\n");
+ fprintf(stderr, " TTL := { 1..255 | inherit }\n");
+ fprintf(stderr, " KEY := { DOTTED_QUAD | NUMBER }\n");
+ exit(-1);
+}
+
+static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
+{
+ int count = 0;
+ char medium[IFNAMSIZ];
+ int isatap = 0;
+
+ memset(p, 0, sizeof(*p));
+ memset(&medium, 0, sizeof(medium));
+
+ p->iph.version = 4;
+ p->iph.ihl = 5;
+#ifndef IP_DF
+#define IP_DF 0x4000 /* Flag: "Don't Fragment" */
+#endif
+ p->iph.frag_off = htons(IP_DF);
+
+ while (argc > 0) {
+ if (strcmp(*argv, "mode") == 0) {
+ NEXT_ARG();
+ if (strcmp(*argv, "ipip") == 0 ||
+ strcmp(*argv, "ip/ip") == 0) {
+ if (p->iph.protocol && p->iph.protocol != IPPROTO_IPIP) {
+ fprintf(stderr,"You managed to ask for more than one tunnel mode.\n");
+ exit(-1);
+ }
+ p->iph.protocol = IPPROTO_IPIP;
+ } else if (strcmp(*argv, "gre") == 0 ||
+ strcmp(*argv, "gre/ip") == 0) {
+ if (p->iph.protocol && p->iph.protocol != IPPROTO_GRE) {
+ fprintf(stderr,"You managed to ask for more than one tunnel mode.\n");
+ exit(-1);
+ }
+ p->iph.protocol = IPPROTO_GRE;
+ } else if (strcmp(*argv, "sit") == 0 ||
+ strcmp(*argv, "ipv6/ip") == 0) {
+ if (p->iph.protocol && p->iph.protocol != IPPROTO_IPV6) {
+ fprintf(stderr,"You managed to ask for more than one tunnel mode.\n");
+ exit(-1);
+ }
+ p->iph.protocol = IPPROTO_IPV6;
+ } else if (strcmp(*argv, "isatap") == 0) {
+ if (p->iph.protocol && p->iph.protocol != IPPROTO_IPV6) {
+ fprintf(stderr, "You managed to ask for more than one tunnel mode.\n");
+ exit(-1);
+ }
+ p->iph.protocol = IPPROTO_IPV6;
+ isatap++;
+ } else {
+ fprintf(stderr,"Cannot guess tunnel mode.\n");
+ exit(-1);
+ }
+ } else if (strcmp(*argv, "key") == 0) {
+ unsigned uval;
+ NEXT_ARG();
+ p->i_flags |= GRE_KEY;
+ p->o_flags |= GRE_KEY;
+ if (strchr(*argv, '.'))
+ p->i_key = p->o_key = get_addr32(*argv);
+ else {
+ if (get_unsigned(&uval, *argv, 0)<0) {
+ fprintf(stderr, "invalid value of \"key\"\n");
+ exit(-1);
+ }
+ p->i_key = p->o_key = htonl(uval);
+ }
+ } else if (strcmp(*argv, "ikey") == 0) {
+ unsigned uval;
+ NEXT_ARG();
+ p->i_flags |= GRE_KEY;
+ if (strchr(*argv, '.'))
+ p->i_key = get_addr32(*argv);
+ else {
+ if (get_unsigned(&uval, *argv, 0)<0) {
+ fprintf(stderr, "invalid value of \"ikey\"\n");
+ exit(-1);
+ }
+ p->i_key = htonl(uval);
+ }
+ } else if (strcmp(*argv, "okey") == 0) {
+ unsigned uval;
+ NEXT_ARG();
+ p->o_flags |= GRE_KEY;
+ if (strchr(*argv, '.'))
+ p->o_key = get_addr32(*argv);
+ else {
+ if (get_unsigned(&uval, *argv, 0)<0) {
+ fprintf(stderr, "invalid value of \"okey\"\n");
+ exit(-1);
+ }
+ p->o_key = htonl(uval);
+ }
+ } else if (strcmp(*argv, "seq") == 0) {
+ p->i_flags |= GRE_SEQ;
+ p->o_flags |= GRE_SEQ;
+ } else if (strcmp(*argv, "iseq") == 0) {
+ p->i_flags |= GRE_SEQ;
+ } else if (strcmp(*argv, "oseq") == 0) {
+ p->o_flags |= GRE_SEQ;
+ } else if (strcmp(*argv, "csum") == 0) {
+ p->i_flags |= GRE_CSUM;
+ p->o_flags |= GRE_CSUM;
+ } else if (strcmp(*argv, "icsum") == 0) {
+ p->i_flags |= GRE_CSUM;
+ } else if (strcmp(*argv, "ocsum") == 0) {
+ p->o_flags |= GRE_CSUM;
+ } else if (strcmp(*argv, "nopmtudisc") == 0) {
+ p->iph.frag_off = 0;
+ } else if (strcmp(*argv, "pmtudisc") == 0) {
+ p->iph.frag_off = htons(IP_DF);
+ } else if (strcmp(*argv, "remote") == 0) {
+ NEXT_ARG();
+ if (strcmp(*argv, "any"))
+ p->iph.daddr = get_addr32(*argv);
+ } else if (strcmp(*argv, "local") == 0) {
+ NEXT_ARG();
+ if (strcmp(*argv, "any"))
+ p->iph.saddr = get_addr32(*argv);
+ } else if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ strncpy(medium, *argv, IFNAMSIZ-1);
+ } else if (strcmp(*argv, "ttl") == 0 ||
+ strcmp(*argv, "hoplimit") == 0) {
+ unsigned uval;
+ NEXT_ARG();
+ if (strcmp(*argv, "inherit") != 0) {
+ if (get_unsigned(&uval, *argv, 0))
+ invarg("invalid TTL\n", *argv);
+ if (uval > 255)
+ invarg("TTL must be <=255\n", *argv);
+ p->iph.ttl = uval;
+ }
+ } else if (strcmp(*argv, "tos") == 0 ||
+ strcmp(*argv, "tclass") == 0 ||
+ matches(*argv, "dsfield") == 0) {
+ __u32 uval;
+ NEXT_ARG();
+ if (strcmp(*argv, "inherit") != 0) {
+ if (rtnl_dsfield_a2n(&uval, *argv))
+ invarg("bad TOS value", *argv);
+ p->iph.tos = uval;
+ } else
+ p->iph.tos = 1;
+ } else {
+ if (strcmp(*argv, "name") == 0) {
+ NEXT_ARG();
+ } else if (matches(*argv, "help") == 0)
+ usage();
+ if (p->name[0])
+ duparg2("name", *argv);
+ strncpy(p->name, *argv, IFNAMSIZ);
+ if (cmd == SIOCCHGTUNNEL && count == 0) {
+ struct ip_tunnel_parm old_p;
+ memset(&old_p, 0, sizeof(old_p));
+ if (tnl_get_ioctl(*argv, &old_p))
+ return -1;
+ *p = old_p;
+ }
+ }
+ count++;
+ argc--; argv++;
+ }
+
+
+ if (p->iph.protocol == 0) {
+ if (memcmp(p->name, "gre", 3) == 0)
+ p->iph.protocol = IPPROTO_GRE;
+ else if (memcmp(p->name, "ipip", 4) == 0)
+ p->iph.protocol = IPPROTO_IPIP;
+ else if (memcmp(p->name, "sit", 3) == 0)
+ p->iph.protocol = IPPROTO_IPV6;
+ else if (memcmp(p->name, "isatap", 6) == 0) {
+ p->iph.protocol = IPPROTO_IPV6;
+ isatap++;
+ }
+ }
+
+ if (p->iph.protocol == IPPROTO_IPIP || p->iph.protocol == IPPROTO_IPV6) {
+ if ((p->i_flags & GRE_KEY) || (p->o_flags & GRE_KEY)) {
+ fprintf(stderr, "Keys are not allowed with ipip and sit.\n");
+ return -1;
+ }
+ }
+
+ if (medium[0]) {
+ p->link = if_nametoindex(medium);
+ if (p->link == 0)
+ return -1;
+ }
+
+ if (p->i_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) {
+ p->i_key = p->iph.daddr;
+ p->i_flags |= GRE_KEY;
+ }
+ if (p->o_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) {
+ p->o_key = p->iph.daddr;
+ p->o_flags |= GRE_KEY;
+ }
+ if (IN_MULTICAST(ntohl(p->iph.daddr)) && !p->iph.saddr) {
+ fprintf(stderr, "Broadcast tunnel requires a source address.\n");
+ return -1;
+ }
+ if (isatap)
+ p->i_flags |= SIT_ISATAP;
+
+ return 0;
+}
+
+
+static int do_add(int cmd, int argc, char **argv)
+{
+ struct ip_tunnel_parm p;
+
+ if (parse_args(argc, argv, cmd, &p) < 0)
+ return -1;
+
+ if (p.iph.ttl && p.iph.frag_off == 0) {
+ fprintf(stderr, "ttl != 0 and noptmudisc are incompatible\n");
+ return -1;
+ }
+
+ switch (p.iph.protocol) {
+ case IPPROTO_IPIP:
+ return tnl_add_ioctl(cmd, "tunl0", p.name, &p);
+ case IPPROTO_GRE:
+ return tnl_add_ioctl(cmd, "gre0", p.name, &p);
+ case IPPROTO_IPV6:
+ return tnl_add_ioctl(cmd, "sit0", p.name, &p);
+ default:
+ fprintf(stderr, "cannot determine tunnel mode (ipip, gre or sit)\n");
+ return -1;
+ }
+ return -1;
+}
+
+static int do_del(int argc, char **argv)
+{
+ struct ip_tunnel_parm p;
+
+ if (parse_args(argc, argv, SIOCDELTUNNEL, &p) < 0)
+ return -1;
+
+ switch (p.iph.protocol) {
+ case IPPROTO_IPIP:
+ return tnl_del_ioctl("tunl0", p.name, &p);
+ case IPPROTO_GRE:
+ return tnl_del_ioctl("gre0", p.name, &p);
+ case IPPROTO_IPV6:
+ return tnl_del_ioctl("sit0", p.name, &p);
+ default:
+ return tnl_del_ioctl(p.name, p.name, &p);
+ }
+ return -1;
+}
+
+static void print_tunnel(struct ip_tunnel_parm *p)
+{
+ struct ip_tunnel_6rd ip6rd;
+ char s1[1024];
+ char s2[1024];
+
+ memset(&ip6rd, 0, sizeof(ip6rd));
+
+ /* Do not use format_host() for local addr,
+ * symbolic name will not be useful.
+ */
+ printf("%s: %s/ip remote %s local %s ",
+ p->name,
+ tnl_strproto(p->iph.protocol),
+ p->iph.daddr ? format_host(AF_INET, 4, &p->iph.daddr, s1, sizeof(s1)) : "any",
+ p->iph.saddr ? rt_addr_n2a(AF_INET, 4, &p->iph.saddr, s2, sizeof(s2)) : "any");
+
+ if (p->i_flags & SIT_ISATAP) {
+ struct ip_tunnel_prl prl[16];
+ int i;
+
+ memset(prl, 0, sizeof(prl));
+ prl[0].datalen = sizeof(prl) - sizeof(prl[0]);
+ prl[0].addr = htonl(INADDR_ANY);
+
+ if (!tnl_prl_ioctl(SIOCGETPRL, p->name, prl))
+ for (i = 1; i < sizeof(prl) / sizeof(prl[0]); i++)
+ {
+ if (prl[i].addr != htonl(INADDR_ANY)) {
+ printf(" %s %s ",
+ (prl[i].flags & PRL_DEFAULT) ? "pdr" : "pr",
+ format_host(AF_INET, 4, &prl[i].addr, s1, sizeof(s1)));
+ }
+ }
+ }
+
+ if (p->link) {
+ const char *n = ll_index_to_name(p->link);
+ if (n)
+ printf(" dev %s ", n);
+ }
+
+ if (p->iph.ttl)
+ printf(" ttl %d ", p->iph.ttl);
+ else
+ printf(" ttl inherit ");
+
+ if (p->iph.tos) {
+ SPRINT_BUF(b1);
+ printf(" tos");
+ if (p->iph.tos&1)
+ printf(" inherit");
+ if (p->iph.tos&~1)
+ printf("%c%s ", p->iph.tos&1 ? '/' : ' ',
+ rtnl_dsfield_n2a(p->iph.tos&~1, b1, sizeof(b1)));
+ }
+
+ if (!(p->iph.frag_off&htons(IP_DF)))
+ printf(" nopmtudisc");
+
+ if (p->iph.protocol == IPPROTO_IPV6 && !tnl_ioctl_get_6rd(p->name, &ip6rd) && ip6rd.prefixlen) {
+ printf(" 6rd-prefix %s/%u ",
+ inet_ntop(AF_INET6, &ip6rd.prefix, s1, sizeof(s1)),
+ ip6rd.prefixlen);
+ if (ip6rd.relay_prefix) {
+ printf("6rd-relay_prefix %s/%u ",
+ format_host(AF_INET, 4, &ip6rd.relay_prefix, s1, sizeof(s1)),
+ ip6rd.relay_prefixlen);
+ }
+ }
+
+ if ((p->i_flags&GRE_KEY) && (p->o_flags&GRE_KEY) && p->o_key == p->i_key)
+ printf(" key %u", ntohl(p->i_key));
+ else if ((p->i_flags|p->o_flags)&GRE_KEY) {
+ if (p->i_flags&GRE_KEY)
+ printf(" ikey %u ", ntohl(p->i_key));
+ if (p->o_flags&GRE_KEY)
+ printf(" okey %u ", ntohl(p->o_key));
+ }
+
+ if (p->i_flags&GRE_SEQ)
+ printf("%s Drop packets out of sequence.\n", _SL_);
+ if (p->i_flags&GRE_CSUM)
+ printf("%s Checksum in received packet is required.", _SL_);
+ if (p->o_flags&GRE_SEQ)
+ printf("%s Sequence packets on output.", _SL_);
+ if (p->o_flags&GRE_CSUM)
+ printf("%s Checksum output packets.", _SL_);
+}
+
+static int do_tunnels_list(struct ip_tunnel_parm *p)
+{
+ char name[IFNAMSIZ];
+ unsigned long rx_bytes, rx_packets, rx_errs, rx_drops,
+ rx_fifo, rx_frame,
+ tx_bytes, tx_packets, tx_errs, tx_drops,
+ tx_fifo, tx_colls, tx_carrier, rx_multi;
+ struct ip_tunnel_parm p1;
+
+ char buf[512];
+ FILE *fp = fopen("/proc/net/dev", "r");
+ if (fp == NULL) {
+ perror("fopen");
+ return -1;
+ }
+
+ /* skip header lines */
+ if (!fgets(buf, sizeof(buf), fp) ||
+ !fgets(buf, sizeof(buf), fp)) {
+ fprintf(stderr, "/proc/net/dev read error\n");
+ fclose(fp);
+ return -1;
+ }
+
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ int index, type;
+ char *ptr;
+ buf[sizeof(buf) - 1] = 0;
+ if ((ptr = strchr(buf, ':')) == NULL ||
+ (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) {
+ fprintf(stderr, "Wrong format of /proc/net/dev. Sorry.\n");
+ fclose(fp);
+ return -1;
+ }
+ if (sscanf(ptr, "%ld%ld%ld%ld%ld%ld%ld%*d%ld%ld%ld%ld%ld%ld%ld",
+ &rx_bytes, &rx_packets, &rx_errs, &rx_drops,
+ &rx_fifo, &rx_frame, &rx_multi,
+ &tx_bytes, &tx_packets, &tx_errs, &tx_drops,
+ &tx_fifo, &tx_colls, &tx_carrier) != 14)
+ continue;
+ if (p->name[0] && strcmp(p->name, name))
+ continue;
+ index = ll_name_to_index(name);
+ if (index == 0)
+ continue;
+ type = ll_index_to_type(index);
+ if (type == -1) {
+ fprintf(stderr, "Failed to get type of [%s]\n", name);
+ continue;
+ }
+ if (type != ARPHRD_TUNNEL && type != ARPHRD_IPGRE && type != ARPHRD_SIT)
+ continue;
+ memset(&p1, 0, sizeof(p1));
+ if (tnl_get_ioctl(name, &p1))
+ continue;
+ if ((p->link && p1.link != p->link) ||
+ (p->name[0] && strcmp(p1.name, p->name)) ||
+ (p->iph.daddr && p1.iph.daddr != p->iph.daddr) ||
+ (p->iph.saddr && p1.iph.saddr != p->iph.saddr) ||
+ (p->i_key && p1.i_key != p->i_key))
+ continue;
+ print_tunnel(&p1);
+ if (show_stats) {
+ printf("%s", _SL_);
+ printf("RX: Packets Bytes Errors CsumErrs OutOfSeq Mcasts%s", _SL_);
+ printf(" %-10ld %-12ld %-6ld %-8ld %-8ld %-8ld%s",
+ rx_packets, rx_bytes, rx_errs, rx_frame, rx_fifo, rx_multi, _SL_);
+ printf("TX: Packets Bytes Errors DeadLoop NoRoute NoBufs%s", _SL_);
+ printf(" %-10ld %-12ld %-6ld %-8ld %-8ld %-6ld",
+ tx_packets, tx_bytes, tx_errs, tx_colls, tx_carrier, tx_drops);
+ }
+ printf("\n");
+ }
+ fclose(fp);
+ return 0;
+}
+
+static int do_show(int argc, char **argv)
+{
+ int err;
+ struct ip_tunnel_parm p;
+
+ ll_init_map(&rth);
+ if (parse_args(argc, argv, SIOCGETTUNNEL, &p) < 0)
+ return -1;
+
+ switch (p.iph.protocol) {
+ case IPPROTO_IPIP:
+ err = tnl_get_ioctl(p.name[0] ? p.name : "tunl0", &p);
+ break;
+ case IPPROTO_GRE:
+ err = tnl_get_ioctl(p.name[0] ? p.name : "gre0", &p);
+ break;
+ case IPPROTO_IPV6:
+ err = tnl_get_ioctl(p.name[0] ? p.name : "sit0", &p);
+ break;
+ default:
+ do_tunnels_list(&p);
+ return 0;
+ }
+ if (err)
+ return -1;
+
+ print_tunnel(&p);
+ printf("\n");
+ return 0;
+}
+
+static int do_prl(int argc, char **argv)
+{
+ struct ip_tunnel_prl p;
+ int count = 0;
+ int devname = 0;
+ int cmd = 0;
+ char medium[IFNAMSIZ];
+
+ memset(&p, 0, sizeof(p));
+ memset(&medium, 0, sizeof(medium));
+
+ while (argc > 0) {
+ if (strcmp(*argv, "prl-default") == 0) {
+ NEXT_ARG();
+ cmd = SIOCADDPRL;
+ p.addr = get_addr32(*argv);
+ p.flags |= PRL_DEFAULT;
+ count++;
+ } else if (strcmp(*argv, "prl-nodefault") == 0) {
+ NEXT_ARG();
+ cmd = SIOCADDPRL;
+ p.addr = get_addr32(*argv);
+ count++;
+ } else if (strcmp(*argv, "prl-delete") == 0) {
+ NEXT_ARG();
+ cmd = SIOCDELPRL;
+ p.addr = get_addr32(*argv);
+ count++;
+ } else if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ strncpy(medium, *argv, IFNAMSIZ-1);
+ devname++;
+ } else {
+ fprintf(stderr,"%s: Invalid PRL parameter.\n", *argv);
+ exit(-1);
+ }
+ if (count > 1) {
+ fprintf(stderr,"One PRL entry at a time.\n");
+ exit(-1);
+ }
+ argc--; argv++;
+ }
+ if (devname == 0) {
+ fprintf(stderr, "Must specify dev.\n");
+ exit(-1);
+ }
+
+ return tnl_prl_ioctl(cmd, medium, &p);
+}
+
+static int do_6rd(int argc, char **argv)
+{
+ struct ip_tunnel_6rd ip6rd;
+ int devname = 0;
+ int cmd = 0;
+ char medium[IFNAMSIZ];
+ inet_prefix prefix;
+
+ memset(&ip6rd, 0, sizeof(ip6rd));
+ memset(&medium, 0, sizeof(medium));
+
+ while (argc > 0) {
+ if (strcmp(*argv, "6rd-prefix") == 0) {
+ NEXT_ARG();
+ if (get_prefix(&prefix, *argv, AF_INET6))
+ invarg("invalid 6rd_prefix\n", *argv);
+ cmd = SIOCADD6RD;
+ memcpy(&ip6rd.prefix, prefix.data, 16);
+ ip6rd.prefixlen = prefix.bitlen;
+ } else if (strcmp(*argv, "6rd-relay_prefix") == 0) {
+ NEXT_ARG();
+ if (get_prefix(&prefix, *argv, AF_INET))
+ invarg("invalid 6rd-relay_prefix\n", *argv);
+ cmd = SIOCADD6RD;
+ memcpy(&ip6rd.relay_prefix, prefix.data, 4);
+ ip6rd.relay_prefixlen = prefix.bitlen;
+ } else if (strcmp(*argv, "6rd-reset") == 0) {
+ cmd = SIOCDEL6RD;
+ } else if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ strncpy(medium, *argv, IFNAMSIZ-1);
+ devname++;
+ } else {
+ fprintf(stderr,"%s: Invalid 6RD parameter.\n", *argv);
+ exit(-1);
+ }
+ argc--; argv++;
+ }
+ if (devname == 0) {
+ fprintf(stderr, "Must specify dev.\n");
+ exit(-1);
+ }
+
+ return tnl_6rd_ioctl(cmd, medium, &ip6rd);
+}
+
+int do_iptunnel(int argc, char **argv)
+{
+ switch (preferred_family) {
+ case AF_UNSPEC:
+ preferred_family = AF_INET;
+ break;
+ case AF_INET:
+ break;
+ /*
+ * This is silly enough but we have no easy way to make it
+ * protocol-independent because of unarranged structure between
+ * IPv4 and IPv6.
+ */
+ case AF_INET6:
+ return do_ip6tunnel(argc, argv);
+ default:
+ fprintf(stderr, "Unsupported family:%d\n", preferred_family);
+ exit(-1);
+ }
+
+ if (argc > 0) {
+ if (matches(*argv, "add") == 0)
+ return do_add(SIOCADDTUNNEL, argc-1, argv+1);
+ if (matches(*argv, "change") == 0)
+ return do_add(SIOCCHGTUNNEL, argc-1, argv+1);
+ if (matches(*argv, "del") == 0)
+ return do_del(argc-1, argv+1);
+ if (matches(*argv, "show") == 0 ||
+ matches(*argv, "lst") == 0 ||
+ matches(*argv, "list") == 0)
+ return do_show(argc-1, argv+1);
+ if (matches(*argv, "prl") == 0)
+ return do_prl(argc-1, argv+1);
+ if (matches(*argv, "6rd") == 0)
+ return do_6rd(argc-1, argv+1);
+ if (matches(*argv, "help") == 0)
+ usage();
+ } else
+ return do_show(0, NULL);
+
+ fprintf(stderr, "Command \"%s\" is unknown, try \"ip tunnel help\".\n", *argv);
+ exit(-1);
+}
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/iptuntap.c b/ap/app/iproute2/iproute2-3.4.0/ip/iptuntap.c
new file mode 100755
index 0000000..29f2777
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/iptuntap.c
@@ -0,0 +1,324 @@
+/*
+ * iptunnel.c "ip tuntap"
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: David Woodhouse <David.Woodhouse@intel.com>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <pwd.h>
+#include <grp.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+
+#define TUNDEV "/dev/net/tun"
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: ip tuntap { add | del } [ dev PHYS_DEV ] \n");
+ fprintf(stderr, " [ mode { tun | tap } ] [ user USER ] [ group GROUP ]\n");
+ fprintf(stderr, " [ one_queue ] [ pi ] [ vnet_hdr ]\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Where: USER := { STRING | NUMBER }\n");
+ fprintf(stderr, " GROUP := { STRING | NUMBER }\n");
+ exit(-1);
+}
+
+static int tap_add_ioctl(struct ifreq *ifr, uid_t uid, gid_t gid)
+{
+ int fd;
+ int ret = -1;
+
+#ifdef IFF_TUN_EXCL
+ ifr->ifr_flags |= IFF_TUN_EXCL;
+#endif
+
+ fd = open(TUNDEV, O_RDWR);
+ if (fd < 0) {
+ perror("open");
+ return -1;
+ }
+ if (ioctl(fd, TUNSETIFF, ifr)) {
+ perror("ioctl(TUNSETIFF)");
+ goto out;
+ }
+ if (uid != -1 && ioctl(fd, TUNSETOWNER, uid)) {
+ perror("ioctl(TUNSETOWNER)");
+ goto out;
+ }
+ if (gid != -1 && ioctl(fd, TUNSETGROUP, gid)) {
+ perror("ioctl(TUNSETGROUP)");
+ goto out;
+ }
+ if (ioctl(fd, TUNSETPERSIST, 1)) {
+ perror("ioctl(TUNSETPERSIST)");
+ goto out;
+ }
+ ret = 0;
+ out:
+ close(fd);
+ return ret;
+}
+
+static int tap_del_ioctl(struct ifreq *ifr)
+{
+ int fd = open(TUNDEV, O_RDWR);
+ int ret = -1;
+
+ if (fd < 0) {
+ perror("open");
+ return -1;
+ }
+ if (ioctl(fd, TUNSETIFF, ifr)) {
+ perror("ioctl(TUNSETIFF)");
+ goto out;
+ }
+ if (ioctl(fd, TUNSETPERSIST, 0)) {
+ perror("ioctl(TUNSETPERSIST)");
+ goto out;
+ }
+ ret = 0;
+ out:
+ close(fd);
+ return ret;
+
+}
+static int parse_args(int argc, char **argv, struct ifreq *ifr, uid_t *uid, gid_t *gid)
+{
+ int count = 0;
+
+ memset(ifr, 0, sizeof(*ifr));
+
+ ifr->ifr_flags |= IFF_NO_PI;
+
+ while (argc > 0) {
+ if (matches(*argv, "mode") == 0) {
+ NEXT_ARG();
+ if (matches(*argv, "tun") == 0) {
+ if (ifr->ifr_flags & IFF_TAP) {
+ fprintf(stderr,"You managed to ask for more than one tunnel mode.\n");
+ exit(-1);
+ }
+ ifr->ifr_flags |= IFF_TUN;
+ } else if (matches(*argv, "tap") == 0) {
+ if (ifr->ifr_flags & IFF_TUN) {
+ fprintf(stderr,"You managed to ask for more than one tunnel mode.\n");
+ exit(-1);
+ }
+ ifr->ifr_flags |= IFF_TAP;
+ } else {
+ fprintf(stderr,"Cannot guess tunnel mode.\n");
+ exit(-1);
+ }
+ } else if (uid && matches(*argv, "user") == 0) {
+ char *end;
+ unsigned long user;
+
+ NEXT_ARG();
+ if (**argv && ((user = strtol(*argv, &end, 10)), !*end))
+ *uid = user;
+ else {
+ struct passwd *pw = getpwnam(*argv);
+ if (!pw) {
+ fprintf(stderr, "invalid user \"%s\"\n", *argv);
+ exit(-1);
+ }
+ *uid = pw->pw_uid;
+ }
+ } else if (gid && matches(*argv, "group") == 0) {
+ char *end;
+ unsigned long group;
+
+ NEXT_ARG();
+
+ if (**argv && ((group = strtol(*argv, &end, 10)), !*end))
+ *gid = group;
+ else {
+ struct group *gr = getgrnam(*argv);
+ if (!gr) {
+ fprintf(stderr, "invalid group \"%s\"\n", *argv);
+ exit(-1);
+ }
+ *gid = gr->gr_gid;
+ }
+ } else if (matches(*argv, "pi") == 0) {
+ ifr->ifr_flags &= ~IFF_NO_PI;
+ } else if (matches(*argv, "one_queue") == 0) {
+ ifr->ifr_flags |= IFF_ONE_QUEUE;
+ } else if (matches(*argv, "vnet_hdr") == 0) {
+ ifr->ifr_flags |= IFF_VNET_HDR;
+ } else if (matches(*argv, "dev") == 0) {
+ NEXT_ARG();
+ strncpy(ifr->ifr_name, *argv, IFNAMSIZ-1);
+ } else {
+ if (matches(*argv, "name") == 0) {
+ NEXT_ARG();
+ } else if (matches(*argv, "help") == 0)
+ usage();
+ if (ifr->ifr_name[0])
+ duparg2("name", *argv);
+ strncpy(ifr->ifr_name, *argv, IFNAMSIZ);
+ }
+ count++;
+ argc--; argv++;
+ }
+
+ return 0;
+}
+
+
+static int do_add(int argc, char **argv)
+{
+ struct ifreq ifr;
+ uid_t uid = -1;
+ gid_t gid = -1;
+
+ if (parse_args(argc, argv, &ifr, &uid, &gid) < 0)
+ return -1;
+
+ if (!(ifr.ifr_flags & TUN_TYPE_MASK)) {
+ fprintf(stderr, "You failed to specify a tunnel mode\n");
+ return -1;
+ }
+ return tap_add_ioctl(&ifr, uid, gid);
+}
+
+static int do_del(int argc, char **argv)
+{
+ struct ifreq ifr;
+
+ if (parse_args(argc, argv, &ifr, NULL, NULL) < 0)
+ return -1;
+
+ return tap_del_ioctl(&ifr);
+}
+
+static int read_prop(char *dev, char *prop, long *value)
+{
+ char fname[IFNAMSIZ+25], buf[80], *endp;
+ ssize_t len;
+ int fd;
+ long result;
+
+ sprintf(fname, "/sys/class/net/%s/%s", dev, prop);
+ fd = open(fname, O_RDONLY);
+ if (fd < 0) {
+ if (strcmp(prop, "tun_flags"))
+ fprintf(stderr, "open %s: %s\n", fname,
+ strerror(errno));
+ return -1;
+ }
+ len = read(fd, buf, sizeof(buf)-1);
+ close(fd);
+ if (len < 0) {
+ fprintf(stderr, "read %s: %s", fname, strerror(errno));
+ return -1;
+ }
+
+ buf[len] = 0;
+ result = strtol(buf, &endp, 0);
+ if (*endp != '\n') {
+ fprintf(stderr, "Failed to parse %s\n", fname);
+ return -1;
+ }
+ *value = result;
+ return 0;
+}
+
+static void print_flags(long flags)
+{
+ if (flags & IFF_TUN)
+ printf(" tun");
+
+ if (flags & IFF_TAP)
+ printf(" tap");
+
+ if (!(flags & IFF_NO_PI))
+ printf(" pi");
+
+ if (flags & IFF_ONE_QUEUE)
+ printf(" one_queue");
+
+ if (flags & IFF_VNET_HDR)
+ printf(" vnet_hdr");
+
+ flags &= ~(IFF_TUN|IFF_TAP|IFF_NO_PI|IFF_ONE_QUEUE|IFF_VNET_HDR);
+ if (flags)
+ printf(" UNKNOWN_FLAGS:%lx", flags);
+}
+
+static int do_show(int argc, char **argv)
+{
+ DIR *dir;
+ struct dirent *d;
+ long flags, owner = -1, group = -1;
+
+ dir = opendir("/sys/class/net");
+ if (!dir) {
+ perror("opendir");
+ return -1;
+ }
+ while ((d = readdir(dir))) {
+ if (d->d_name[0] == '.' &&
+ (d->d_name[1] == 0 || d->d_name[1] == '.'))
+ continue;
+
+ if (read_prop(d->d_name, "tun_flags", &flags))
+ continue;
+
+ read_prop(d->d_name, "owner", &owner);
+ read_prop(d->d_name, "group", &group);
+
+ printf("%s:", d->d_name);
+ print_flags(flags);
+ if (owner != -1)
+ printf(" user %ld", owner);
+ if (group != -1)
+ printf(" group %ld", group);
+ printf("\n");
+ }
+ closedir(dir);
+ return 0;
+}
+
+int do_iptuntap(int argc, char **argv)
+{
+ if (argc > 0) {
+ if (matches(*argv, "add") == 0)
+ return do_add(argc-1, argv+1);
+ if (matches(*argv, "del") == 0)
+ return do_del(argc-1, argv+1);
+ if (matches(*argv, "show") == 0 ||
+ matches(*argv, "lst") == 0 ||
+ matches(*argv, "list") == 0)
+ return do_show(argc-1, argv+1);
+ if (matches(*argv, "help") == 0)
+ usage();
+ } else
+ return do_show(0, NULL);
+
+ fprintf(stderr, "Command \"%s\" is unknown, try \"ip tuntap help\".\n",
+ *argv);
+ exit(-1);
+}
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/ipxfrm.c b/ap/app/iproute2/iproute2-3.4.0/ip/ipxfrm.c
new file mode 100755
index 0000000..c7b3420
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/ipxfrm.c
@@ -0,0 +1,1459 @@
+/* $USAGI: $ */
+
+/*
+ * Copyright (C)2004 USAGI/WIDE Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*
+ * based on ip.c, iproute.c
+ */
+/*
+ * Authors:
+ * Masahide NAKAMURA @USAGI
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <time.h>
+#include <netdb.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/xfrm.h>
+
+#include "utils.h"
+#include "xfrm.h"
+
+#define STRBUF_SIZE (128)
+#define STRBUF_CAT(buf, str) \
+ do { \
+ int rest = sizeof(buf) - 1 - strlen(buf); \
+ if (rest > 0) { \
+ int len = strlen(str); \
+ if (len > rest) \
+ len = rest; \
+ strncat(buf, str, len); \
+ buf[sizeof(buf) - 1] = '\0'; \
+ } \
+ } while(0);
+
+struct xfrm_filter filter;
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "Usage: ip xfrm XFRM-OBJECT { COMMAND | help }\n"
+ "where XFRM-OBJECT := state | policy | monitor\n");
+ exit(-1);
+}
+
+/* This is based on utils.c(inet_addr_match) */
+int xfrm_addr_match(xfrm_address_t *x1, xfrm_address_t *x2, int bits)
+{
+ __u32 *a1 = (__u32 *)x1;
+ __u32 *a2 = (__u32 *)x2;
+ int words = bits >> 0x05;
+
+ bits &= 0x1f;
+
+ if (words)
+ if (memcmp(a1, a2, words << 2))
+ return -1;
+
+ if (bits) {
+ __u32 w1, w2;
+ __u32 mask;
+
+ w1 = a1[words];
+ w2 = a2[words];
+
+ mask = htonl((0xffffffff) << (0x20 - bits));
+
+ if ((w1 ^ w2) & mask)
+ return 1;
+ }
+
+ return 0;
+}
+
+int xfrm_xfrmproto_is_ipsec(__u8 proto)
+{
+ return (proto == IPPROTO_ESP ||
+ proto == IPPROTO_AH ||
+ proto == IPPROTO_COMP);
+}
+
+int xfrm_xfrmproto_is_ro(__u8 proto)
+{
+ return (proto == IPPROTO_ROUTING ||
+ proto == IPPROTO_DSTOPTS);
+}
+
+struct typeent {
+ const char *t_name;
+ int t_type;
+};
+
+static const struct typeent xfrmproto_types[]= {
+ { "esp", IPPROTO_ESP }, { "ah", IPPROTO_AH }, { "comp", IPPROTO_COMP },
+ { "route2", IPPROTO_ROUTING }, { "hao", IPPROTO_DSTOPTS },
+ { "ipsec-any", IPSEC_PROTO_ANY },
+ { NULL, -1 }
+};
+
+int xfrm_xfrmproto_getbyname(char *name)
+{
+ int i;
+
+ for (i = 0; ; i++) {
+ const struct typeent *t = &xfrmproto_types[i];
+ if (!t->t_name || t->t_type == -1)
+ break;
+
+ if (strcmp(t->t_name, name) == 0)
+ return t->t_type;
+ }
+
+ return -1;
+}
+
+const char *strxf_xfrmproto(__u8 proto)
+{
+ static char str[16];
+ int i;
+
+ for (i = 0; ; i++) {
+ const struct typeent *t = &xfrmproto_types[i];
+ if (!t->t_name || t->t_type == -1)
+ break;
+
+ if (t->t_type == proto)
+ return t->t_name;
+ }
+
+ sprintf(str, "%u", proto);
+ return str;
+}
+
+static const struct typeent algo_types[]= {
+ { "enc", XFRMA_ALG_CRYPT }, { "auth", XFRMA_ALG_AUTH },
+ { "comp", XFRMA_ALG_COMP }, { "aead", XFRMA_ALG_AEAD },
+ { "auth-trunc", XFRMA_ALG_AUTH_TRUNC },
+ { NULL, -1 }
+};
+
+int xfrm_algotype_getbyname(char *name)
+{
+ int i;
+
+ for (i = 0; ; i++) {
+ const struct typeent *t = &algo_types[i];
+ if (!t->t_name || t->t_type == -1)
+ break;
+
+ if (strcmp(t->t_name, name) == 0)
+ return t->t_type;
+ }
+
+ return -1;
+}
+
+const char *strxf_algotype(int type)
+{
+ static char str[32];
+ int i;
+
+ for (i = 0; ; i++) {
+ const struct typeent *t = &algo_types[i];
+ if (!t->t_name || t->t_type == -1)
+ break;
+
+ if (t->t_type == type)
+ return t->t_name;
+ }
+
+ sprintf(str, "%d", type);
+ return str;
+}
+
+const char *strxf_mask8(__u8 mask)
+{
+ static char str[16];
+ const int sn = sizeof(mask) * 8 - 1;
+ __u8 b;
+ int i = 0;
+
+ for (b = (1 << sn); b > 0; b >>= 1)
+ str[i++] = ((b & mask) ? '1' : '0');
+ str[i] = '\0';
+
+ return str;
+}
+
+const char *strxf_mask32(__u32 mask)
+{
+ static char str[16];
+
+ sprintf(str, "%.8x", mask);
+
+ return str;
+}
+
+const char *strxf_share(__u8 share)
+{
+ static char str[32];
+
+ switch (share) {
+ case XFRM_SHARE_ANY:
+ strcpy(str, "any");
+ break;
+ case XFRM_SHARE_SESSION:
+ strcpy(str, "session");
+ break;
+ case XFRM_SHARE_USER:
+ strcpy(str, "user");
+ break;
+ case XFRM_SHARE_UNIQUE:
+ strcpy(str, "unique");
+ break;
+ default:
+ sprintf(str, "%u", share);
+ break;
+ }
+
+ return str;
+}
+
+const char *strxf_proto(__u8 proto)
+{
+ static char buf[32];
+ struct protoent *pp;
+ const char *p;
+
+ pp = getprotobynumber(proto);
+ if (pp)
+ p = pp->p_name;
+ else {
+ sprintf(buf, "%u", proto);
+ p = buf;
+ }
+
+ return p;
+}
+
+const char *strxf_ptype(__u8 ptype)
+{
+ static char str[16];
+
+ switch (ptype) {
+ case XFRM_POLICY_TYPE_MAIN:
+ strcpy(str, "main");
+ break;
+ case XFRM_POLICY_TYPE_SUB:
+ strcpy(str, "sub");
+ break;
+ default:
+ sprintf(str, "%u", ptype);
+ break;
+ }
+
+ return str;
+}
+
+void xfrm_id_info_print(xfrm_address_t *saddr, struct xfrm_id *id,
+ __u8 mode, __u32 reqid, __u16 family, int force_spi,
+ FILE *fp, const char *prefix, const char *title)
+{
+ char abuf[256];
+
+ if (title)
+ fputs(title, fp);
+
+ memset(abuf, '\0', sizeof(abuf));
+ fprintf(fp, "src %s ", rt_addr_n2a(family, sizeof(*saddr),
+ saddr, abuf, sizeof(abuf)));
+ memset(abuf, '\0', sizeof(abuf));
+ fprintf(fp, "dst %s", rt_addr_n2a(family, sizeof(id->daddr),
+ &id->daddr, abuf, sizeof(abuf)));
+ fprintf(fp, "%s", _SL_);
+
+ if (prefix)
+ fputs(prefix, fp);
+ fprintf(fp, "\t");
+
+ fprintf(fp, "proto %s ", strxf_xfrmproto(id->proto));
+
+ if (show_stats > 0 || force_spi || id->spi) {
+ __u32 spi = ntohl(id->spi);
+ fprintf(fp, "spi 0x%08x", spi);
+ if (show_stats > 0)
+ fprintf(fp, "(%u)", spi);
+ fprintf(fp, " ");
+ }
+
+ fprintf(fp, "reqid %u", reqid);
+ if (show_stats > 0)
+ fprintf(fp, "(0x%08x)", reqid);
+ fprintf(fp, " ");
+
+ fprintf(fp, "mode ");
+ switch (mode) {
+ case XFRM_MODE_TRANSPORT:
+ fprintf(fp, "transport");
+ break;
+ case XFRM_MODE_TUNNEL:
+ fprintf(fp, "tunnel");
+ break;
+ case XFRM_MODE_ROUTEOPTIMIZATION:
+ fprintf(fp, "ro");
+ break;
+ case XFRM_MODE_IN_TRIGGER:
+ fprintf(fp, "in_trigger");
+ break;
+ case XFRM_MODE_BEET:
+ fprintf(fp, "beet");
+ break;
+ default:
+ fprintf(fp, "%u", mode);
+ break;
+ }
+ fprintf(fp, "%s", _SL_);
+}
+
+static const char *strxf_limit(__u64 limit)
+{
+ static char str[32];
+ if (limit == XFRM_INF)
+ strcpy(str, "(INF)");
+ else
+ sprintf(str, "%llu", (unsigned long long) limit);
+
+ return str;
+}
+
+void xfrm_stats_print(struct xfrm_stats *s, FILE *fp, const char *prefix)
+{
+ if (prefix)
+ fputs(prefix, fp);
+ fprintf(fp, "stats:%s", _SL_);
+
+ if (prefix)
+ fputs(prefix, fp);
+ fprintf(fp, " replay-window %u replay %u failed %u%s",
+ s->replay_window, s->replay, s->integrity_failed, _SL_);
+}
+
+static const char *strxf_time(__u64 time)
+{
+ static char str[32];
+
+ if (time == 0)
+ strcpy(str, "-");
+ else {
+ time_t t;
+ struct tm *tp;
+
+ /* XXX: treat time in the same manner of kernel's
+ * net/xfrm/xfrm_{user,state}.c
+ */
+ t = (long)time;
+ tp = localtime(&t);
+
+ strftime(str, sizeof(str), "%Y-%m-%d %T", tp);
+ }
+
+ return str;
+}
+
+void xfrm_lifetime_print(struct xfrm_lifetime_cfg *cfg,
+ struct xfrm_lifetime_cur *cur,
+ FILE *fp, const char *prefix)
+{
+ if (cfg) {
+ if (prefix)
+ fputs(prefix, fp);
+ fprintf(fp, "lifetime config:%s",_SL_);
+
+ if (prefix)
+ fputs(prefix, fp);
+ fprintf(fp, " limit: soft %s(bytes),",
+ strxf_limit(cfg->soft_byte_limit));
+ fprintf(fp, " hard %s(bytes)%s",
+ strxf_limit(cfg->hard_byte_limit), _SL_);
+
+ if (prefix)
+ fputs(prefix, fp);
+ fprintf(fp, " limit: soft %s(packets),",
+ strxf_limit(cfg->soft_packet_limit));
+ fprintf(fp, " hard %s(packets)%s",
+ strxf_limit(cfg->hard_packet_limit), _SL_);
+
+ if (prefix)
+ fputs(prefix, fp);
+ fprintf(fp, " expire add: soft %llu(sec), hard %llu(sec)%s",
+ (unsigned long long) cfg->soft_add_expires_seconds,
+ (unsigned long long) cfg->hard_add_expires_seconds,
+ _SL_);
+
+ if (prefix)
+ fputs(prefix, fp);
+ fprintf(fp, " expire use: soft %llu(sec), hard %llu(sec)%s",
+ (unsigned long long) cfg->soft_use_expires_seconds,
+ (unsigned long long) cfg->hard_use_expires_seconds,
+ _SL_);
+ }
+ if (cur) {
+ if (prefix)
+ fputs(prefix, fp);
+ fprintf(fp, "lifetime current:%s", _SL_);
+
+ if (prefix)
+ fputs(prefix, fp);
+ fprintf(fp, " %llu(bytes), %llu(packets)%s",
+ (unsigned long long) cur->bytes,
+ (unsigned long long) cur->packets,
+ _SL_);
+
+ if (prefix)
+ fputs(prefix, fp);
+ fprintf(fp, " add %s ", strxf_time(cur->add_time));
+ fprintf(fp, "use %s%s", strxf_time(cur->use_time), _SL_);
+ }
+}
+
+void xfrm_selector_print(struct xfrm_selector *sel, __u16 family,
+ FILE *fp, const char *prefix)
+{
+ char abuf[256];
+ __u16 f;
+
+ f = sel->family;
+ if (f == AF_UNSPEC)
+ f = family;
+ if (f == AF_UNSPEC)
+ f = preferred_family;
+
+ if (prefix)
+ fputs(prefix, fp);
+
+ memset(abuf, '\0', sizeof(abuf));
+ fprintf(fp, "src %s/%u ", rt_addr_n2a(f, sizeof(sel->saddr),
+ &sel->saddr, abuf, sizeof(abuf)),
+ sel->prefixlen_s);
+
+ memset(abuf, '\0', sizeof(abuf));
+ fprintf(fp, "dst %s/%u ", rt_addr_n2a(f, sizeof(sel->daddr),
+ &sel->daddr, abuf, sizeof(abuf)),
+ sel->prefixlen_d);
+
+ if (sel->proto)
+ fprintf(fp, "proto %s ", strxf_proto(sel->proto));
+ switch (sel->proto) {
+ case IPPROTO_TCP:
+ case IPPROTO_UDP:
+ case IPPROTO_SCTP:
+ case IPPROTO_DCCP:
+ default: /* XXX */
+ if (sel->sport_mask)
+ fprintf(fp, "sport %u ", ntohs(sel->sport));
+ if (sel->dport_mask)
+ fprintf(fp, "dport %u ", ntohs(sel->dport));
+ break;
+ case IPPROTO_ICMP:
+ case IPPROTO_ICMPV6:
+ /* type/code is stored at sport/dport in selector */
+ if (sel->sport_mask)
+ fprintf(fp, "type %u ", ntohs(sel->sport));
+ if (sel->dport_mask)
+ fprintf(fp, "code %u ", ntohs(sel->dport));
+ break;
+ case IPPROTO_GRE:
+ if (sel->sport_mask || sel->dport_mask)
+ fprintf(fp, "key %u ",
+ (((__u32)ntohs(sel->sport)) << 16) +
+ ntohs(sel->dport));
+ break;
+ case IPPROTO_MH:
+ if (sel->sport_mask)
+ fprintf(fp, "type %u ", ntohs(sel->sport));
+ if (sel->dport_mask) {
+ if (show_stats > 0)
+ fprintf(fp, "(dport) 0x%.4x ", sel->dport);
+ }
+ break;
+ }
+
+ if (sel->ifindex > 0)
+ fprintf(fp, "dev %s ", ll_index_to_name(sel->ifindex));
+
+ if (show_stats > 0)
+ fprintf(fp, "uid %u", sel->user);
+
+ fprintf(fp, "%s", _SL_);
+}
+
+static void __xfrm_algo_print(struct xfrm_algo *algo, int type, int len,
+ FILE *fp, const char *prefix, int newline)
+{
+ int keylen;
+ int i;
+
+ if (prefix)
+ fputs(prefix, fp);
+
+ fprintf(fp, "%s ", strxf_algotype(type));
+
+ if (len < sizeof(*algo)) {
+ fprintf(fp, "(ERROR truncated)");
+ goto fin;
+ }
+ len -= sizeof(*algo);
+
+ fprintf(fp, "%s ", algo->alg_name);
+
+ keylen = algo->alg_key_len / 8;
+ if (len < keylen) {
+ fprintf(fp, "(ERROR truncated)");
+ goto fin;
+ }
+
+ fprintf(fp, "0x");
+ for (i = 0; i < keylen; i ++)
+ fprintf(fp, "%.2x", (unsigned char)algo->alg_key[i]);
+
+ if (show_stats > 0)
+ fprintf(fp, " (%d bits)", algo->alg_key_len);
+
+ fin:
+ if (newline)
+ fprintf(fp, "%s", _SL_);
+}
+
+static inline void xfrm_algo_print(struct xfrm_algo *algo, int type, int len,
+ FILE *fp, const char *prefix)
+{
+ return __xfrm_algo_print(algo, type, len, fp, prefix, 1);
+}
+
+static void xfrm_aead_print(struct xfrm_algo_aead *algo, int len,
+ FILE *fp, const char *prefix)
+{
+ struct {
+ struct xfrm_algo algo;
+ char key[algo->alg_key_len / 8];
+ } base;
+
+ memcpy(base.algo.alg_name, algo->alg_name, sizeof(base.algo.alg_name));
+ base.algo.alg_key_len = algo->alg_key_len;
+ memcpy(base.algo.alg_key, algo->alg_key, algo->alg_key_len / 8);
+
+ __xfrm_algo_print(&base.algo, XFRMA_ALG_AEAD, len, fp, prefix, 0);
+
+ fprintf(fp, " %d", algo->alg_icv_len);
+
+ fprintf(fp, "%s", _SL_);
+}
+
+static void xfrm_auth_trunc_print(struct xfrm_algo_auth *algo, int len,
+ FILE *fp, const char *prefix)
+{
+ struct {
+ struct xfrm_algo algo;
+ char key[algo->alg_key_len / 8];
+ } base;
+
+ memcpy(base.algo.alg_name, algo->alg_name, sizeof(base.algo.alg_name));
+ base.algo.alg_key_len = algo->alg_key_len;
+ memcpy(base.algo.alg_key, algo->alg_key, algo->alg_key_len / 8);
+
+ __xfrm_algo_print(&base.algo, XFRMA_ALG_AUTH_TRUNC, len, fp, prefix, 0);
+
+ fprintf(fp, " %d", algo->alg_trunc_len);
+
+ fprintf(fp, "%s", _SL_);
+}
+
+static void xfrm_tmpl_print(struct xfrm_user_tmpl *tmpls, int len,
+ __u16 family, FILE *fp, const char *prefix)
+{
+ int ntmpls = len / sizeof(struct xfrm_user_tmpl);
+ int i;
+
+ if (ntmpls <= 0) {
+ if (prefix)
+ fputs(prefix, fp);
+ fprintf(fp, "(ERROR \"tmpl\" truncated)");
+ fprintf(fp, "%s", _SL_);
+ return;
+ }
+
+ for (i = 0; i < ntmpls; i++) {
+ struct xfrm_user_tmpl *tmpl = &tmpls[i];
+
+ if (prefix)
+ fputs(prefix, fp);
+
+ xfrm_id_info_print(&tmpl->saddr, &tmpl->id, tmpl->mode,
+ tmpl->reqid, tmpl->family, 0, fp, prefix, "tmpl ");
+
+ if (show_stats > 0 || tmpl->optional) {
+ if (prefix)
+ fputs(prefix, fp);
+ fprintf(fp, "\t");
+ switch (tmpl->optional) {
+ case 0:
+ if (show_stats > 0)
+ fprintf(fp, "level required ");
+ break;
+ case 1:
+ fprintf(fp, "level use ");
+ break;
+ default:
+ fprintf(fp, "level %u ", tmpl->optional);
+ break;
+ }
+
+ if (show_stats > 0)
+ fprintf(fp, "share %s ", strxf_share(tmpl->share));
+
+ fprintf(fp, "%s", _SL_);
+ }
+
+ if (show_stats > 0) {
+ if (prefix)
+ fputs(prefix, fp);
+ fprintf(fp, "\t");
+ fprintf(fp, "%s-mask %s ",
+ strxf_algotype(XFRMA_ALG_CRYPT),
+ strxf_mask32(tmpl->ealgos));
+ fprintf(fp, "%s-mask %s ",
+ strxf_algotype(XFRMA_ALG_AUTH),
+ strxf_mask32(tmpl->aalgos));
+ fprintf(fp, "%s-mask %s",
+ strxf_algotype(XFRMA_ALG_COMP),
+ strxf_mask32(tmpl->calgos));
+
+ fprintf(fp, "%s", _SL_);
+ }
+ }
+}
+
+int xfrm_parse_mark(struct xfrm_mark *mark, int *argcp, char ***argvp)
+{
+ int argc = *argcp;
+ char **argv = *argvp;
+
+ NEXT_ARG();
+ if (get_u32(&mark->v, *argv, 0)) {
+ invarg("Illegal \"mark\" value\n", *argv);
+ }
+ if (argc > 1)
+ NEXT_ARG();
+ else { /* last entry on parse line */
+ mark->m = 0xffffffff;
+ goto done;
+ }
+
+ if (strcmp(*argv, "mask") == 0) {
+ NEXT_ARG();
+ if (get_u32(&mark->m, *argv, 0)) {
+ invarg("Illegal \"mark\" mask\n", *argv);
+ }
+ } else {
+ mark->m = 0xffffffff;
+ PREV_ARG();
+ }
+
+done:
+ *argcp = argc;
+ *argvp = argv;
+
+ return 0;
+}
+
+void xfrm_xfrma_print(struct rtattr *tb[], __u16 family,
+ FILE *fp, const char *prefix)
+{
+ if (tb[XFRMA_MARK]) {
+ struct rtattr *rta = tb[XFRMA_MARK];
+ struct xfrm_mark *m = (struct xfrm_mark *) RTA_DATA(rta);
+ fprintf(fp, "\tmark %d/0x%x\n", m->v, m->m);
+ }
+
+ if (tb[XFRMA_ALG_AUTH] && !tb[XFRMA_ALG_AUTH_TRUNC]) {
+ struct rtattr *rta = tb[XFRMA_ALG_AUTH];
+ xfrm_algo_print((struct xfrm_algo *) RTA_DATA(rta),
+ XFRMA_ALG_AUTH, RTA_PAYLOAD(rta), fp, prefix);
+ }
+
+ if (tb[XFRMA_ALG_AUTH_TRUNC]) {
+ struct rtattr *rta = tb[XFRMA_ALG_AUTH_TRUNC];
+ xfrm_auth_trunc_print((struct xfrm_algo_auth *) RTA_DATA(rta),
+ RTA_PAYLOAD(rta), fp, prefix);
+ }
+
+ if (tb[XFRMA_ALG_AEAD]) {
+ struct rtattr *rta = tb[XFRMA_ALG_AEAD];
+ xfrm_aead_print((struct xfrm_algo_aead *)RTA_DATA(rta),
+ RTA_PAYLOAD(rta), fp, prefix);
+ }
+
+ if (tb[XFRMA_ALG_CRYPT]) {
+ struct rtattr *rta = tb[XFRMA_ALG_CRYPT];
+ xfrm_algo_print((struct xfrm_algo *) RTA_DATA(rta),
+ XFRMA_ALG_CRYPT, RTA_PAYLOAD(rta), fp, prefix);
+ }
+
+ if (tb[XFRMA_ALG_COMP]) {
+ struct rtattr *rta = tb[XFRMA_ALG_COMP];
+ xfrm_algo_print((struct xfrm_algo *) RTA_DATA(rta),
+ XFRMA_ALG_COMP, RTA_PAYLOAD(rta), fp, prefix);
+ }
+
+ if (tb[XFRMA_ENCAP]) {
+ struct xfrm_encap_tmpl *e;
+ char abuf[256];
+
+ if (prefix)
+ fputs(prefix, fp);
+ fprintf(fp, "encap ");
+
+ if (RTA_PAYLOAD(tb[XFRMA_ENCAP]) < sizeof(*e)) {
+ fprintf(fp, "(ERROR truncated)");
+ fprintf(fp, "%s", _SL_);
+ return;
+ }
+ e = (struct xfrm_encap_tmpl *) RTA_DATA(tb[XFRMA_ENCAP]);
+
+ fprintf(fp, "type ");
+ switch (e->encap_type) {
+ case 1:
+ fprintf(fp, "espinudp-nonike ");
+ break;
+ case 2:
+ fprintf(fp, "espinudp ");
+ break;
+ default:
+ fprintf(fp, "%u ", e->encap_type);
+ break;
+ }
+ fprintf(fp, "sport %u ", ntohs(e->encap_sport));
+ fprintf(fp, "dport %u ", ntohs(e->encap_dport));
+
+ memset(abuf, '\0', sizeof(abuf));
+ fprintf(fp, "addr %s",
+ rt_addr_n2a(family, sizeof(e->encap_oa),
+ &e->encap_oa, abuf, sizeof(abuf)));
+ fprintf(fp, "%s", _SL_);
+ }
+
+ if (tb[XFRMA_TMPL]) {
+ struct rtattr *rta = tb[XFRMA_TMPL];
+ xfrm_tmpl_print((struct xfrm_user_tmpl *) RTA_DATA(rta),
+ RTA_PAYLOAD(rta), family, fp, prefix);
+ }
+
+ if (tb[XFRMA_COADDR]) {
+ char abuf[256];
+ xfrm_address_t *coa;
+
+ if (prefix)
+ fputs(prefix, fp);
+ fprintf(fp, "coa ");
+
+ coa = (xfrm_address_t *)RTA_DATA(tb[XFRMA_COADDR]);
+
+ if (RTA_PAYLOAD(tb[XFRMA_COADDR]) < sizeof(*coa)) {
+ fprintf(fp, "(ERROR truncated)");
+ fprintf(fp, "%s", _SL_);
+ return;
+ }
+
+ memset(abuf, '\0', sizeof(abuf));
+ fprintf(fp, "%s",
+ rt_addr_n2a(family, sizeof(*coa), coa,
+ abuf, sizeof(abuf)));
+ fprintf(fp, "%s", _SL_);
+ }
+
+ if (tb[XFRMA_LASTUSED]) {
+ __u64 lastused;
+
+ if (prefix)
+ fputs(prefix, fp);
+ fprintf(fp, "lastused ");
+
+ if (RTA_PAYLOAD(tb[XFRMA_LASTUSED]) < sizeof(lastused)) {
+ fprintf(fp, "(ERROR truncated)");
+ fprintf(fp, "%s", _SL_);
+ return;
+ }
+
+ lastused = rta_getattr_u64(tb[XFRMA_LASTUSED]);
+
+ fprintf(fp, "%s", strxf_time(lastused));
+ fprintf(fp, "%s", _SL_);
+ }
+
+}
+
+static int xfrm_selector_iszero(struct xfrm_selector *s)
+{
+ struct xfrm_selector s0;
+
+ memset(&s0, 0, sizeof(s0));
+
+ return (memcmp(&s0, s, sizeof(s0)) == 0);
+}
+
+void xfrm_state_info_print(struct xfrm_usersa_info *xsinfo,
+ struct rtattr *tb[], FILE *fp, const char *prefix,
+ const char *title)
+{
+ char buf[STRBUF_SIZE];
+ int force_spi = xfrm_xfrmproto_is_ipsec(xsinfo->id.proto);
+
+ memset(buf, '\0', sizeof(buf));
+
+ xfrm_id_info_print(&xsinfo->saddr, &xsinfo->id, xsinfo->mode,
+ xsinfo->reqid, xsinfo->family, force_spi, fp,
+ prefix, title);
+
+ if (prefix)
+ STRBUF_CAT(buf, prefix);
+ STRBUF_CAT(buf, "\t");
+
+ fputs(buf, fp);
+ fprintf(fp, "replay-window %u ", xsinfo->replay_window);
+ if (show_stats > 0)
+ fprintf(fp, "seq 0x%08u ", xsinfo->seq);
+ if (show_stats > 0 || xsinfo->flags) {
+ __u8 flags = xsinfo->flags;
+
+ fprintf(fp, "flag ");
+ XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_NOECN, "noecn");
+ XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_DECAP_DSCP, "decap-dscp");
+ XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_NOPMTUDISC, "nopmtudisc");
+ XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_WILDRECV, "wildrecv");
+ XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_ICMP, "icmp");
+ XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_AF_UNSPEC, "af-unspec");
+ XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_ALIGN4, "align4");
+ if (flags)
+ fprintf(fp, "%x", flags);
+ }
+ if (show_stats > 0)
+ fprintf(fp, " (0x%s)", strxf_mask8(xsinfo->flags));
+ fprintf(fp, "%s", _SL_);
+
+ xfrm_xfrma_print(tb, xsinfo->family, fp, buf);
+
+ if (!xfrm_selector_iszero(&xsinfo->sel)) {
+ char sbuf[STRBUF_SIZE];
+
+ memcpy(sbuf, buf, sizeof(sbuf));
+ STRBUF_CAT(sbuf, "sel ");
+
+ xfrm_selector_print(&xsinfo->sel, xsinfo->family, fp, sbuf);
+ }
+
+ if (show_stats > 0) {
+ xfrm_lifetime_print(&xsinfo->lft, &xsinfo->curlft, fp, buf);
+ xfrm_stats_print(&xsinfo->stats, fp, buf);
+ }
+
+ if (tb[XFRMA_SEC_CTX]) {
+ struct xfrm_user_sec_ctx *sctx;
+
+ fprintf(fp, "\tsecurity context ");
+
+ if (RTA_PAYLOAD(tb[XFRMA_SEC_CTX]) < sizeof(*sctx))
+ fprintf(fp, "(ERROR truncated)");
+
+ sctx = (struct xfrm_user_sec_ctx *)RTA_DATA(tb[XFRMA_SEC_CTX]);
+
+ fprintf(fp, "%s %s", (char *)(sctx + 1), _SL_);
+ }
+
+}
+
+void xfrm_policy_info_print(struct xfrm_userpolicy_info *xpinfo,
+ struct rtattr *tb[], FILE *fp, const char *prefix,
+ const char *title)
+{
+ char buf[STRBUF_SIZE];
+
+ memset(buf, '\0', sizeof(buf));
+
+ xfrm_selector_print(&xpinfo->sel, preferred_family, fp, title);
+
+ if (tb[XFRMA_SEC_CTX]) {
+ struct xfrm_user_sec_ctx *sctx;
+
+ fprintf(fp, "\tsecurity context ");
+
+ if (RTA_PAYLOAD(tb[XFRMA_SEC_CTX]) < sizeof(*sctx))
+ fprintf(fp, "(ERROR truncated)");
+
+ sctx = (struct xfrm_user_sec_ctx *)RTA_DATA(tb[XFRMA_SEC_CTX]);
+
+ fprintf(fp, "%s ", (char *)(sctx + 1));
+ fprintf(fp, "%s", _SL_);
+ }
+
+ if (prefix)
+ STRBUF_CAT(buf, prefix);
+ STRBUF_CAT(buf, "\t");
+
+ fputs(buf, fp);
+ if (xpinfo->dir >= XFRM_POLICY_MAX) {
+ xpinfo->dir -= XFRM_POLICY_MAX;
+ fprintf(fp, "socket ");
+ } else
+ fprintf(fp, "dir ");
+
+ switch (xpinfo->dir) {
+ case XFRM_POLICY_IN:
+ fprintf(fp, "in");
+ break;
+ case XFRM_POLICY_OUT:
+ fprintf(fp, "out");
+ break;
+ case XFRM_POLICY_FWD:
+ fprintf(fp, "fwd");
+ break;
+ default:
+ fprintf(fp, "%u", xpinfo->dir);
+ break;
+ }
+ fprintf(fp, " ");
+
+ switch (xpinfo->action) {
+ case XFRM_POLICY_ALLOW:
+ if (show_stats > 0)
+ fprintf(fp, "action allow ");
+ break;
+ case XFRM_POLICY_BLOCK:
+ fprintf(fp, "action block ");
+ break;
+ default:
+ fprintf(fp, "action %u ", xpinfo->action);
+ break;
+ }
+
+ if (show_stats)
+ fprintf(fp, "index %u ", xpinfo->index);
+ fprintf(fp, "priority %u ", xpinfo->priority);
+
+ if (tb[XFRMA_POLICY_TYPE]) {
+ struct xfrm_userpolicy_type *upt;
+
+ fprintf(fp, "ptype ");
+
+ if (RTA_PAYLOAD(tb[XFRMA_POLICY_TYPE]) < sizeof(*upt))
+ fprintf(fp, "(ERROR truncated)");
+
+ upt = (struct xfrm_userpolicy_type *)RTA_DATA(tb[XFRMA_POLICY_TYPE]);
+ fprintf(fp, "%s ", strxf_ptype(upt->type));
+ }
+
+ if (show_stats > 0)
+ fprintf(fp, "share %s ", strxf_share(xpinfo->share));
+
+ if (show_stats > 0 || xpinfo->flags) {
+ __u8 flags = xpinfo->flags;
+
+ fprintf(fp, "flag ");
+ XFRM_FLAG_PRINT(fp, flags, XFRM_POLICY_LOCALOK, "localok");
+ XFRM_FLAG_PRINT(fp, flags, XFRM_POLICY_ICMP, "icmp");
+ if (flags)
+ fprintf(fp, "%x", flags);
+ }
+ if (show_stats > 0)
+ fprintf(fp, " (0x%s)", strxf_mask8(xpinfo->flags));
+ fprintf(fp, "%s", _SL_);
+
+ if (show_stats > 0)
+ xfrm_lifetime_print(&xpinfo->lft, &xpinfo->curlft, fp, buf);
+
+ xfrm_xfrma_print(tb, xpinfo->sel.family, fp, buf);
+}
+
+int xfrm_id_parse(xfrm_address_t *saddr, struct xfrm_id *id, __u16 *family,
+ int loose, int *argcp, char ***argvp)
+{
+ int argc = *argcp;
+ char **argv = *argvp;
+ inet_prefix dst;
+ inet_prefix src;
+
+ memset(&dst, 0, sizeof(dst));
+ memset(&src, 0, sizeof(src));
+
+ while (1) {
+ if (strcmp(*argv, "src") == 0) {
+ NEXT_ARG();
+
+ get_prefix(&src, *argv, preferred_family);
+ if (src.family == AF_UNSPEC)
+ invarg("\"src\" address family is AF_UNSPEC", *argv);
+ if (family)
+ *family = src.family;
+
+ memcpy(saddr, &src.data, sizeof(*saddr));
+
+ filter.id_src_mask = src.bitlen;
+
+ } else if (strcmp(*argv, "dst") == 0) {
+ NEXT_ARG();
+
+ get_prefix(&dst, *argv, preferred_family);
+ if (dst.family == AF_UNSPEC)
+ invarg("\"dst\" address family is AF_UNSPEC", *argv);
+ if (family)
+ *family = dst.family;
+
+ memcpy(&id->daddr, &dst.data, sizeof(id->daddr));
+
+ filter.id_dst_mask = dst.bitlen;
+
+ } else if (strcmp(*argv, "proto") == 0) {
+ int ret;
+
+ NEXT_ARG();
+
+ ret = xfrm_xfrmproto_getbyname(*argv);
+ if (ret < 0)
+ invarg("\"XFRM-PROTO\" is invalid", *argv);
+
+ id->proto = (__u8)ret;
+
+ filter.id_proto_mask = XFRM_FILTER_MASK_FULL;
+
+ } else if (strcmp(*argv, "spi") == 0) {
+ __u32 spi;
+
+ NEXT_ARG();
+ if (get_u32(&spi, *argv, 0))
+ invarg("\"SPI\" is invalid", *argv);
+
+ spi = htonl(spi);
+ id->spi = spi;
+
+ filter.id_spi_mask = XFRM_FILTER_MASK_FULL;
+
+ } else {
+ PREV_ARG(); /* back track */
+ break;
+ }
+
+ if (!NEXT_ARG_OK())
+ break;
+ NEXT_ARG();
+ }
+
+ if (src.family && dst.family && (src.family != dst.family))
+ invarg("the same address family is required between \"src\" and \"dst\"", *argv);
+
+ if (loose == 0 && id->proto == 0)
+ missarg("XFRM-PROTO");
+ if (argc == *argcp)
+ missarg("ID");
+
+ *argcp = argc;
+ *argvp = argv;
+
+ return 0;
+}
+
+int xfrm_mode_parse(__u8 *mode, int *argcp, char ***argvp)
+{
+ int argc = *argcp;
+ char **argv = *argvp;
+
+ if (matches(*argv, "transport") == 0)
+ *mode = XFRM_MODE_TRANSPORT;
+ else if (matches(*argv, "tunnel") == 0)
+ *mode = XFRM_MODE_TUNNEL;
+ else if (matches(*argv, "ro") == 0)
+ *mode = XFRM_MODE_ROUTEOPTIMIZATION;
+ else if (matches(*argv, "in_trigger") == 0)
+ *mode = XFRM_MODE_IN_TRIGGER;
+ else if (matches(*argv, "beet") == 0)
+ *mode = XFRM_MODE_BEET;
+ else
+ invarg("\"MODE\" is invalid", *argv);
+
+ *argcp = argc;
+ *argvp = argv;
+
+ return 0;
+}
+
+int xfrm_encap_type_parse(__u16 *type, int *argcp, char ***argvp)
+{
+ int argc = *argcp;
+ char **argv = *argvp;
+
+ if (strcmp(*argv, "espinudp-nonike") == 0)
+ *type = 1;
+ else if (strcmp(*argv, "espinudp") == 0)
+ *type = 2;
+ else
+ invarg("\"ENCAP-TYPE\" is invalid", *argv);
+
+ *argcp = argc;
+ *argvp = argv;
+
+ return 0;
+}
+
+/* NOTE: reqid is used by host-byte order */
+int xfrm_reqid_parse(__u32 *reqid, int *argcp, char ***argvp)
+{
+ int argc = *argcp;
+ char **argv = *argvp;
+
+ if (get_u32(reqid, *argv, 0))
+ invarg("\"REQID\" is invalid", *argv);
+
+ *argcp = argc;
+ *argvp = argv;
+
+ return 0;
+}
+
+static int xfrm_selector_upspec_parse(struct xfrm_selector *sel,
+ int *argcp, char ***argvp)
+{
+ int argc = *argcp;
+ char **argv = *argvp;
+ char *sportp = NULL;
+ char *dportp = NULL;
+ char *typep = NULL;
+ char *codep = NULL;
+ char *grekey = NULL;
+
+ while (1) {
+ if (strcmp(*argv, "proto") == 0) {
+ __u8 upspec;
+
+ NEXT_ARG();
+
+ if (strcmp(*argv, "any") == 0)
+ upspec = 0;
+ else {
+ struct protoent *pp;
+ pp = getprotobyname(*argv);
+ if (pp)
+ upspec = pp->p_proto;
+ else {
+ if (get_u8(&upspec, *argv, 0))
+ invarg("\"PROTO\" is invalid", *argv);
+ }
+ }
+ sel->proto = upspec;
+
+ filter.upspec_proto_mask = XFRM_FILTER_MASK_FULL;
+
+ } else if (strcmp(*argv, "sport") == 0) {
+ sportp = *argv;
+
+ NEXT_ARG();
+
+ if (get_u16(&sel->sport, *argv, 0))
+ invarg("\"PORT\" is invalid", *argv);
+ sel->sport = htons(sel->sport);
+ if (sel->sport)
+ sel->sport_mask = ~((__u16)0);
+
+ filter.upspec_sport_mask = XFRM_FILTER_MASK_FULL;
+
+ } else if (strcmp(*argv, "dport") == 0) {
+ dportp = *argv;
+
+ NEXT_ARG();
+
+ if (get_u16(&sel->dport, *argv, 0))
+ invarg("\"PORT\" is invalid", *argv);
+ sel->dport = htons(sel->dport);
+ if (sel->dport)
+ sel->dport_mask = ~((__u16)0);
+
+ filter.upspec_dport_mask = XFRM_FILTER_MASK_FULL;
+
+ } else if (strcmp(*argv, "type") == 0) {
+ typep = *argv;
+
+ NEXT_ARG();
+
+ if (get_u16(&sel->sport, *argv, 0) ||
+ (sel->sport & ~((__u16)0xff)))
+ invarg("\"type\" value is invalid", *argv);
+ sel->sport = htons(sel->sport);
+ sel->sport_mask = ~((__u16)0);
+
+ filter.upspec_sport_mask = XFRM_FILTER_MASK_FULL;
+
+
+ } else if (strcmp(*argv, "code") == 0) {
+ codep = *argv;
+
+ NEXT_ARG();
+
+ if (get_u16(&sel->dport, *argv, 0) ||
+ (sel->dport & ~((__u16)0xff)))
+ invarg("\"code\" value is invalid", *argv);
+ sel->dport = htons(sel->dport);
+ sel->dport_mask = ~((__u16)0);
+
+ filter.upspec_dport_mask = XFRM_FILTER_MASK_FULL;
+
+ } else if (strcmp(*argv, "key") == 0) {
+ unsigned uval;
+
+ grekey = *argv;
+
+ NEXT_ARG();
+
+ if (strchr(*argv, '.'))
+ uval = htonl(get_addr32(*argv));
+ else {
+ if (get_unsigned(&uval, *argv, 0)<0) {
+ fprintf(stderr, "invalid value of \"key\"\n");
+ exit(-1);
+ }
+ }
+
+ sel->sport = htons(uval >> 16);
+ sel->dport = htons(uval & 0xffff);
+ sel->sport_mask = ~((__u16)0);
+ sel->dport_mask = ~((__u16)0);
+
+ filter.upspec_dport_mask = XFRM_FILTER_MASK_FULL;
+
+ } else {
+ PREV_ARG(); /* back track */
+ break;
+ }
+
+ if (!NEXT_ARG_OK())
+ break;
+ NEXT_ARG();
+ }
+ if (argc == *argcp)
+ missarg("UPSPEC");
+ if (sportp || dportp) {
+ switch (sel->proto) {
+ case IPPROTO_TCP:
+ case IPPROTO_UDP:
+ case IPPROTO_SCTP:
+ case IPPROTO_DCCP:
+ break;
+ default:
+ fprintf(stderr, "\"sport\" and \"dport\" are invalid with proto=%s\n", strxf_proto(sel->proto));
+ exit(1);
+ }
+ }
+ if (typep || codep) {
+ switch (sel->proto) {
+ case IPPROTO_ICMP:
+ case IPPROTO_ICMPV6:
+ case IPPROTO_MH:
+ break;
+ default:
+ fprintf(stderr, "\"type\" and \"code\" are invalid with proto=%s\n", strxf_proto(sel->proto));
+ exit(1);
+ }
+ }
+ if (grekey) {
+ switch (sel->proto) {
+ case IPPROTO_GRE:
+ break;
+ default:
+ fprintf(stderr, "\"key\" is invalid with proto=%s\n", strxf_proto(sel->proto));
+ exit(1);
+ }
+ }
+
+ *argcp = argc;
+ *argvp = argv;
+
+ return 0;
+}
+
+int xfrm_selector_parse(struct xfrm_selector *sel, int *argcp, char ***argvp)
+{
+ int argc = *argcp;
+ char **argv = *argvp;
+ inet_prefix dst;
+ inet_prefix src;
+ char *upspecp = NULL;
+
+ memset(&dst, 0, sizeof(dst));
+ memset(&src, 0, sizeof(src));
+
+ while (1) {
+ if (strcmp(*argv, "src") == 0) {
+ NEXT_ARG();
+
+ get_prefix(&src, *argv, preferred_family);
+ if (src.family == AF_UNSPEC)
+ invarg("\"src\" address family is AF_UNSPEC", *argv);
+ sel->family = src.family;
+
+ memcpy(&sel->saddr, &src.data, sizeof(sel->saddr));
+ sel->prefixlen_s = src.bitlen;
+
+ filter.sel_src_mask = src.bitlen;
+
+ } else if (strcmp(*argv, "dst") == 0) {
+ NEXT_ARG();
+
+ get_prefix(&dst, *argv, preferred_family);
+ if (dst.family == AF_UNSPEC)
+ invarg("\"dst\" address family is AF_UNSPEC", *argv);
+ sel->family = dst.family;
+
+ memcpy(&sel->daddr, &dst.data, sizeof(sel->daddr));
+ sel->prefixlen_d = dst.bitlen;
+
+ filter.sel_dst_mask = dst.bitlen;
+
+ } else if (strcmp(*argv, "dev") == 0) {
+ int ifindex;
+
+ NEXT_ARG();
+
+ if (strcmp(*argv, "none") == 0)
+ ifindex = 0;
+ else {
+ ifindex = ll_name_to_index(*argv);
+ if (ifindex <= 0)
+ invarg("\"DEV\" is invalid", *argv);
+ }
+ sel->ifindex = ifindex;
+
+ filter.sel_dev_mask = XFRM_FILTER_MASK_FULL;
+
+ } else {
+ if (upspecp) {
+ PREV_ARG(); /* back track */
+ break;
+ } else {
+ upspecp = *argv;
+ xfrm_selector_upspec_parse(sel, &argc, &argv);
+ }
+ }
+
+ if (!NEXT_ARG_OK())
+ break;
+
+ NEXT_ARG();
+ }
+
+ if (src.family && dst.family && (src.family != dst.family))
+ invarg("the same address family is required between \"src\" and \"dst\"", *argv);
+
+ if (argc == *argcp)
+ missarg("SELECTOR");
+
+ *argcp = argc;
+ *argvp = argv;
+
+ return 0;
+}
+
+int xfrm_lifetime_cfg_parse(struct xfrm_lifetime_cfg *lft,
+ int *argcp, char ***argvp)
+{
+ int argc = *argcp;
+ char **argv = *argvp;
+ int ret;
+
+ if (strcmp(*argv, "time-soft") == 0) {
+ NEXT_ARG();
+ ret = get_u64(&lft->soft_add_expires_seconds, *argv, 0);
+ if (ret)
+ invarg("\"time-soft\" value is invalid", *argv);
+ } else if (strcmp(*argv, "time-hard") == 0) {
+ NEXT_ARG();
+ ret = get_u64(&lft->hard_add_expires_seconds, *argv, 0);
+ if (ret)
+ invarg("\"time-hard\" value is invalid", *argv);
+ } else if (strcmp(*argv, "time-use-soft") == 0) {
+ NEXT_ARG();
+ ret = get_u64(&lft->soft_use_expires_seconds, *argv, 0);
+ if (ret)
+ invarg("\"time-use-soft\" value is invalid", *argv);
+ } else if (strcmp(*argv, "time-use-hard") == 0) {
+ NEXT_ARG();
+ ret = get_u64(&lft->hard_use_expires_seconds, *argv, 0);
+ if (ret)
+ invarg("\"time-use-hard\" value is invalid", *argv);
+ } else if (strcmp(*argv, "byte-soft") == 0) {
+ NEXT_ARG();
+ ret = get_u64(&lft->soft_byte_limit, *argv, 0);
+ if (ret)
+ invarg("\"byte-soft\" value is invalid", *argv);
+ } else if (strcmp(*argv, "byte-hard") == 0) {
+ NEXT_ARG();
+ ret = get_u64(&lft->hard_byte_limit, *argv, 0);
+ if (ret)
+ invarg("\"byte-hard\" value is invalid", *argv);
+ } else if (strcmp(*argv, "packet-soft") == 0) {
+ NEXT_ARG();
+ ret = get_u64(&lft->soft_packet_limit, *argv, 0);
+ if (ret)
+ invarg("\"packet-soft\" value is invalid", *argv);
+ } else if (strcmp(*argv, "packet-hard") == 0) {
+ NEXT_ARG();
+ ret = get_u64(&lft->hard_packet_limit, *argv, 0);
+ if (ret)
+ invarg("\"packet-hard\" value is invalid", *argv);
+ } else
+ invarg("\"LIMIT\" is invalid", *argv);
+
+ *argcp = argc;
+ *argvp = argv;
+
+ return 0;
+}
+
+int do_xfrm(int argc, char **argv)
+{
+ memset(&filter, 0, sizeof(filter));
+
+ if (argc < 1)
+ usage();
+
+ if (matches(*argv, "state") == 0 ||
+ matches(*argv, "sa") == 0)
+ return do_xfrm_state(argc-1, argv+1);
+ else if (matches(*argv, "policy") == 0)
+ return do_xfrm_policy(argc-1, argv+1);
+ else if (matches(*argv, "monitor") == 0)
+ return do_xfrm_monitor(argc-1, argv+1);
+ else if (matches(*argv, "help") == 0) {
+ usage();
+ fprintf(stderr, "xfrm Object \"%s\" is unknown.\n", *argv);
+ exit(-1);
+ }
+ usage();
+}
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/link_gre.c b/ap/app/iproute2/iproute2-3.4.0/ip/link_gre.c
new file mode 100755
index 0000000..839fb29
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/link_gre.c
@@ -0,0 +1,366 @@
+/*
+ * link_gre.c gre driver module
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ */
+
+#include <string.h>
+#include <net/if.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <linux/ip.h>
+#include <linux/if_tunnel.h>
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+#include "tunnel.h"
+
+static void usage(void) __attribute__((noreturn));
+static void usage(void)
+{
+ fprintf(stderr, "Usage: ip link { add | set | change | replace | del } NAME\n");
+ fprintf(stderr, " type { gre | gretap } [ remote ADDR ] [ local ADDR ]\n");
+ fprintf(stderr, " [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n");
+ fprintf(stderr, " [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Where: NAME := STRING\n");
+ fprintf(stderr, " ADDR := { IP_ADDRESS | any }\n");
+ fprintf(stderr, " TOS := { NUMBER | inherit }\n");
+ fprintf(stderr, " TTL := { 1..255 | inherit }\n");
+ fprintf(stderr, " KEY := { DOTTED_QUAD | NUMBER }\n");
+ exit(-1);
+}
+
+static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
+ struct nlmsghdr *n)
+{
+ struct {
+ struct nlmsghdr n;
+ struct ifinfomsg i;
+ char buf[1024];
+ } req;
+ struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
+ struct rtattr *tb[IFLA_MAX + 1];
+ struct rtattr *linkinfo[IFLA_INFO_MAX+1];
+ struct rtattr *greinfo[IFLA_GRE_MAX + 1];
+ __u16 iflags = 0;
+ __u16 oflags = 0;
+ unsigned ikey = 0;
+ unsigned okey = 0;
+ unsigned saddr = 0;
+ unsigned daddr = 0;
+ unsigned link = 0;
+ __u8 pmtudisc = 1;
+ __u8 ttl = 0;
+ __u8 tos = 0;
+ int len;
+
+ if (!(n->nlmsg_flags & NLM_F_CREATE)) {
+ memset(&req, 0, sizeof(req));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = RTM_GETLINK;
+ req.i.ifi_family = preferred_family;
+ req.i.ifi_index = ifi->ifi_index;
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) {
+get_failed:
+ fprintf(stderr,
+ "Failed to get existing tunnel info.\n");
+ return -1;
+ }
+
+ len = req.n.nlmsg_len;
+ len -= NLMSG_LENGTH(sizeof(*ifi));
+ if (len < 0)
+ goto get_failed;
+
+ parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len);
+
+ if (!tb[IFLA_LINKINFO])
+ goto get_failed;
+
+ parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
+
+ if (!linkinfo[IFLA_INFO_DATA])
+ goto get_failed;
+
+ parse_rtattr_nested(greinfo, IFLA_GRE_MAX,
+ linkinfo[IFLA_INFO_DATA]);
+
+ if (greinfo[IFLA_GRE_IKEY])
+ ikey = rta_getattr_u32(greinfo[IFLA_GRE_IKEY]);
+
+ if (greinfo[IFLA_GRE_OKEY])
+ okey = rta_getattr_u32(greinfo[IFLA_GRE_OKEY]);
+
+ if (greinfo[IFLA_GRE_IFLAGS])
+ iflags = rta_getattr_u16(greinfo[IFLA_GRE_IFLAGS]);
+
+ if (greinfo[IFLA_GRE_OFLAGS])
+ oflags = rta_getattr_u16(greinfo[IFLA_GRE_OFLAGS]);
+
+ if (greinfo[IFLA_GRE_LOCAL])
+ saddr = rta_getattr_u32(greinfo[IFLA_GRE_LOCAL]);
+
+ if (greinfo[IFLA_GRE_REMOTE])
+ daddr = rta_getattr_u32(greinfo[IFLA_GRE_REMOTE]);
+
+ if (greinfo[IFLA_GRE_PMTUDISC])
+ pmtudisc = rta_getattr_u8(
+ greinfo[IFLA_GRE_PMTUDISC]);
+
+ if (greinfo[IFLA_GRE_TTL])
+ ttl = rta_getattr_u8(greinfo[IFLA_GRE_TTL]);
+
+ if (greinfo[IFLA_GRE_TOS])
+ tos = rta_getattr_u8(greinfo[IFLA_GRE_TOS]);
+
+ if (greinfo[IFLA_GRE_LINK])
+ link = rta_getattr_u8(greinfo[IFLA_GRE_LINK]);
+ }
+
+ while (argc > 0) {
+ if (!matches(*argv, "key")) {
+ unsigned uval;
+
+ NEXT_ARG();
+ iflags |= GRE_KEY;
+ oflags |= GRE_KEY;
+ if (strchr(*argv, '.'))
+ uval = get_addr32(*argv);
+ else {
+ if (get_unsigned(&uval, *argv, 0) < 0) {
+ fprintf(stderr,
+ "Invalid value for \"key\"\n");
+ exit(-1);
+ }
+ uval = htonl(uval);
+ }
+
+ ikey = okey = uval;
+ } else if (!matches(*argv, "ikey")) {
+ unsigned uval;
+
+ NEXT_ARG();
+ iflags |= GRE_KEY;
+ if (strchr(*argv, '.'))
+ uval = get_addr32(*argv);
+ else {
+ if (get_unsigned(&uval, *argv, 0)<0) {
+ fprintf(stderr, "invalid value of \"ikey\"\n");
+ exit(-1);
+ }
+ uval = htonl(uval);
+ }
+ ikey = uval;
+ } else if (!matches(*argv, "okey")) {
+ unsigned uval;
+
+ NEXT_ARG();
+ oflags |= GRE_KEY;
+ if (strchr(*argv, '.'))
+ uval = get_addr32(*argv);
+ else {
+ if (get_unsigned(&uval, *argv, 0)<0) {
+ fprintf(stderr, "invalid value of \"okey\"\n");
+ exit(-1);
+ }
+ uval = htonl(uval);
+ }
+ okey = uval;
+ } else if (!matches(*argv, "seq")) {
+ iflags |= GRE_SEQ;
+ oflags |= GRE_SEQ;
+ } else if (!matches(*argv, "iseq")) {
+ iflags |= GRE_SEQ;
+ } else if (!matches(*argv, "oseq")) {
+ oflags |= GRE_SEQ;
+ } else if (!matches(*argv, "csum")) {
+ iflags |= GRE_CSUM;
+ oflags |= GRE_CSUM;
+ } else if (!matches(*argv, "icsum")) {
+ iflags |= GRE_CSUM;
+ } else if (!matches(*argv, "ocsum")) {
+ oflags |= GRE_CSUM;
+ } else if (!matches(*argv, "nopmtudisc")) {
+ pmtudisc = 0;
+ } else if (!matches(*argv, "pmtudisc")) {
+ pmtudisc = 1;
+ } else if (!matches(*argv, "remote")) {
+ NEXT_ARG();
+ if (strcmp(*argv, "any"))
+ daddr = get_addr32(*argv);
+ } else if (!matches(*argv, "local")) {
+ NEXT_ARG();
+ if (strcmp(*argv, "any"))
+ saddr = get_addr32(*argv);
+ } else if (!matches(*argv, "dev")) {
+ NEXT_ARG();
+ link = if_nametoindex(*argv);
+ if (link == 0)
+ exit(-1);
+ } else if (!matches(*argv, "ttl") ||
+ !matches(*argv, "hoplimit")) {
+ unsigned uval;
+
+ NEXT_ARG();
+ if (strcmp(*argv, "inherit") != 0) {
+ if (get_unsigned(&uval, *argv, 0))
+ invarg("invalid TTL\n", *argv);
+ if (uval > 255)
+ invarg("TTL must be <= 255\n", *argv);
+ ttl = uval;
+ }
+ } else if (!matches(*argv, "tos") ||
+ !matches(*argv, "tclass") ||
+ !matches(*argv, "dsfield")) {
+ __u32 uval;
+
+ NEXT_ARG();
+ if (strcmp(*argv, "inherit") != 0) {
+ if (rtnl_dsfield_a2n(&uval, *argv))
+ invarg("bad TOS value", *argv);
+ tos = uval;
+ } else
+ tos = 1;
+ } else
+ usage();
+ argc--; argv++;
+ }
+
+ if (!ikey && IN_MULTICAST(ntohl(daddr))) {
+ ikey = daddr;
+ iflags |= GRE_KEY;
+ }
+ if (!okey && IN_MULTICAST(ntohl(daddr))) {
+ okey = daddr;
+ oflags |= GRE_KEY;
+ }
+ if (IN_MULTICAST(ntohl(daddr)) && !saddr) {
+ fprintf(stderr, "Broadcast tunnel requires a source address.\n");
+ return -1;
+ }
+
+ addattr32(n, 1024, IFLA_GRE_IKEY, ikey);
+ addattr32(n, 1024, IFLA_GRE_OKEY, okey);
+ addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2);
+ addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2);
+ addattr_l(n, 1024, IFLA_GRE_LOCAL, &saddr, 4);
+ addattr_l(n, 1024, IFLA_GRE_REMOTE, &daddr, 4);
+ addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &pmtudisc, 1);
+ if (link)
+ addattr32(n, 1024, IFLA_GRE_LINK, link);
+ addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1);
+ addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1);
+
+ return 0;
+}
+
+static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
+{
+ char s1[1024];
+ char s2[64];
+ const char *local = "any";
+ const char *remote = "any";
+ unsigned iflags = 0;
+ unsigned oflags = 0;
+
+ if (!tb)
+ return;
+
+ if (tb[IFLA_GRE_REMOTE]) {
+ unsigned addr = rta_getattr_u32(tb[IFLA_GRE_REMOTE]);
+
+ if (addr)
+ remote = format_host(AF_INET, 4, &addr, s1, sizeof(s1));
+ }
+
+ fprintf(f, "remote %s ", remote);
+
+ if (tb[IFLA_GRE_LOCAL]) {
+ unsigned addr = rta_getattr_u32(tb[IFLA_GRE_LOCAL]);
+
+ if (addr)
+ local = format_host(AF_INET, 4, &addr, s1, sizeof(s1));
+ }
+
+ fprintf(f, "local %s ", local);
+
+ if (tb[IFLA_GRE_LINK] && rta_getattr_u32(tb[IFLA_GRE_LINK])) {
+ unsigned link = rta_getattr_u32(tb[IFLA_GRE_LINK]);
+ const char *n = if_indextoname(link, s2);
+
+ if (n)
+ fprintf(f, "dev %s ", n);
+ else
+ fprintf(f, "dev %u ", link);
+ }
+
+ if (tb[IFLA_GRE_TTL] && rta_getattr_u8(tb[IFLA_GRE_TTL]))
+ fprintf(f, "ttl %d ", rta_getattr_u8(tb[IFLA_GRE_TTL]));
+ else
+ fprintf(f, "ttl inherit ");
+
+ if (tb[IFLA_GRE_TOS] && rta_getattr_u8(tb[IFLA_GRE_TOS])) {
+ int tos = rta_getattr_u8(tb[IFLA_GRE_TOS]);
+
+ fputs("tos ", f);
+ if (tos == 1)
+ fputs("inherit ", f);
+ else
+ fprintf(f, "0x%x ", tos);
+ }
+
+ if (tb[IFLA_GRE_PMTUDISC] &&
+ !rta_getattr_u8(tb[IFLA_GRE_PMTUDISC]))
+ fputs("nopmtudisc ", f);
+
+ if (tb[IFLA_GRE_IFLAGS])
+ iflags = rta_getattr_u16(tb[IFLA_GRE_IFLAGS]);
+
+ if (tb[IFLA_GRE_OFLAGS])
+ oflags = rta_getattr_u16(tb[IFLA_GRE_OFLAGS]);
+
+ if ((iflags & GRE_KEY) && tb[IFLA_GRE_IKEY]) {
+ inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_IKEY]), s2, sizeof(s2));
+ fprintf(f, "ikey %s ", s2);
+ }
+
+ if ((oflags & GRE_KEY) && tb[IFLA_GRE_OKEY]) {
+ inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_OKEY]), s2, sizeof(s2));
+ fprintf(f, "okey %s ", s2);
+ }
+
+ if (iflags & GRE_SEQ)
+ fputs("iseq ", f);
+ if (oflags & GRE_SEQ)
+ fputs("oseq ", f);
+ if (iflags & GRE_CSUM)
+ fputs("icsum ", f);
+ if (oflags & GRE_CSUM)
+ fputs("ocsum ", f);
+}
+
+struct link_util gre_link_util = {
+ .id = "gre",
+ .maxattr = IFLA_GRE_MAX,
+ .parse_opt = gre_parse_opt,
+ .print_opt = gre_print_opt,
+};
+
+struct link_util gretap_link_util = {
+ .id = "gretap",
+ .maxattr = IFLA_GRE_MAX,
+ .parse_opt = gre_parse_opt,
+ .print_opt = gre_print_opt,
+};
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/link_veth.c b/ap/app/iproute2/iproute2-3.4.0/ip/link_veth.c
new file mode 100755
index 0000000..3d19b01
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/link_veth.c
@@ -0,0 +1,64 @@
+/*
+ * link_veth.c veth driver module
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Pavel Emelianov <xemul@openvz.org>
+ *
+ */
+
+#include <string.h>
+#include <net/if.h>
+#include <linux/veth.h>
+
+#include "utils.h"
+#include "ip_common.h"
+
+static void usage(void)
+{
+ printf("Usage: ip link <options> type veth "
+ "[peer <options>]\nTo get <options> type "
+ "'ip link add help'\n");
+}
+
+static int veth_parse_opt(struct link_util *lu, int argc, char **argv,
+ struct nlmsghdr *hdr)
+{
+ char *name, *type, *link, *dev;
+ int err, len;
+ struct rtattr * data;
+ int group;
+
+ if (strcmp(argv[0], "peer") != 0) {
+ usage();
+ return -1;
+ }
+
+ data = NLMSG_TAIL(hdr);
+ addattr_l(hdr, 1024, VETH_INFO_PEER, NULL, 0);
+
+ hdr->nlmsg_len += sizeof(struct ifinfomsg);
+
+ err = iplink_parse(argc - 1, argv + 1, (struct iplink_req *)hdr,
+ &name, &type, &link, &dev, &group);
+ if (err < 0)
+ return err;
+
+ if (name) {
+ len = strlen(name) + 1;
+ if (len > IFNAMSIZ)
+ invarg("\"name\" too long\n", *argv);
+ addattr_l(hdr, 1024, IFLA_IFNAME, name, len);
+ }
+
+ data->rta_len = (void *)NLMSG_TAIL(hdr) - (void *)data;
+ return argc - 1 - err;
+}
+
+struct link_util veth_link_util = {
+ .id = "veth",
+ .parse_opt = veth_parse_opt,
+};
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/routef b/ap/app/iproute2/iproute2-3.4.0/ip/routef
new file mode 100755
index 0000000..d266e2d
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/routef
@@ -0,0 +1,9 @@
+#! /bin/sh
+
+if [ -z "$*" ] ; then
+ exec ip -4 ro flush scope global type unicast
+else
+ echo "Usage: routef"
+ echo
+ echo "This script will flush the IPv4 routing table"
+fi
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/routel b/ap/app/iproute2/iproute2-3.4.0/ip/routel
new file mode 100755
index 0000000..8d1d352
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/routel
@@ -0,0 +1,60 @@
+#!/bin/sh
+#$Id$
+
+#
+# Script created by: Stephen R. van den Berg <srb@cuci.nl>, 1999/04/18
+# Donated to the public domain.
+#
+# This script transforms the output of "ip" into more readable text.
+# "ip" is the Linux-advanced-routing configuration tool part of the
+# iproute package.
+#
+
+test "X-h" = "X$1" && echo "Usage: $0 [tablenr [raw ip args...]]" && exit 64
+
+test -z "$*" && set 0
+
+ip route list table "$@" |
+ while read network rest
+ do set xx $rest
+ shift
+ proto=""
+ via=""
+ dev=""
+ scope=""
+ src=""
+ table=""
+ case $network in
+ broadcast|local|unreachable) via=$network
+ network=$1
+ shift
+ ;;
+ esac
+ while test $# != 0
+ do
+ key=$1
+ val=$2
+ eval "$key=$val"
+ shift 2
+ done
+ echo "$network $via $src $proto $scope $dev $table"
+ done | awk -F ' ' '
+BEGIN {
+ format="%15s%-3s %15s %15s %8s %8s%7s %s\n";
+ printf(format,"target","","gateway","source","proto","scope","dev","tbl");
+ }
+ { network=$1;
+ mask="";
+ if(match(network,"/"))
+ { mask=" "substr(network,RSTART+1);
+ network=substr(network,0,RSTART);
+ }
+ via=$2;
+ src=$3;
+ proto=$4;
+ scope=$5;
+ dev=$6;
+ table=$7;
+ printf(format,network,mask,via,src,proto,scope,dev,table);
+ }
+'
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/rtm_map.c b/ap/app/iproute2/iproute2-3.4.0/ip/rtm_map.c
new file mode 100755
index 0000000..21e818b
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/rtm_map.c
@@ -0,0 +1,116 @@
+/*
+ * rtm_map.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include "rt_names.h"
+#include "utils.h"
+
+char *rtnl_rtntype_n2a(int id, char *buf, int len)
+{
+ switch (id) {
+ case RTN_UNSPEC:
+ return "none";
+ case RTN_UNICAST:
+ return "unicast";
+ case RTN_LOCAL:
+ return "local";
+ case RTN_BROADCAST:
+ return "broadcast";
+ case RTN_ANYCAST:
+ return "anycast";
+ case RTN_MULTICAST:
+ return "multicast";
+ case RTN_BLACKHOLE:
+ return "blackhole";
+ case RTN_UNREACHABLE:
+ return "unreachable";
+ case RTN_PROHIBIT:
+ return "prohibit";
+ case RTN_THROW:
+ return "throw";
+ case RTN_NAT:
+ return "nat";
+ case RTN_XRESOLVE:
+ return "xresolve";
+ default:
+ snprintf(buf, len, "%d", id);
+ return buf;
+ }
+}
+
+
+int rtnl_rtntype_a2n(int *id, char *arg)
+{
+ char *end;
+ unsigned long res;
+
+ if (strcmp(arg, "local") == 0)
+ res = RTN_LOCAL;
+ else if (strcmp(arg, "nat") == 0)
+ res = RTN_NAT;
+ else if (matches(arg, "broadcast") == 0 ||
+ strcmp(arg, "brd") == 0)
+ res = RTN_BROADCAST;
+ else if (matches(arg, "anycast") == 0)
+ res = RTN_ANYCAST;
+ else if (matches(arg, "multicast") == 0)
+ res = RTN_MULTICAST;
+ else if (matches(arg, "prohibit") == 0)
+ res = RTN_PROHIBIT;
+ else if (matches(arg, "unreachable") == 0)
+ res = RTN_UNREACHABLE;
+ else if (matches(arg, "blackhole") == 0)
+ res = RTN_BLACKHOLE;
+ else if (matches(arg, "xresolve") == 0)
+ res = RTN_XRESOLVE;
+ else if (matches(arg, "unicast") == 0)
+ res = RTN_UNICAST;
+ else if (strcmp(arg, "throw") == 0)
+ res = RTN_THROW;
+ else {
+ res = strtoul(arg, &end, 0);
+ if (!end || end == arg || *end || res > 255)
+ return -1;
+ }
+ *id = res;
+ return 0;
+}
+
+int get_rt_realms(__u32 *realms, char *arg)
+{
+ __u32 realm = 0;
+ char *p = strchr(arg, '/');
+
+ *realms = 0;
+ if (p) {
+ *p = 0;
+ if (rtnl_rtrealm_a2n(realms, arg)) {
+ *p = '/';
+ return -1;
+ }
+ *realms <<= 16;
+ *p = '/';
+ arg = p+1;
+ }
+ if (*arg && rtnl_rtrealm_a2n(&realm, arg))
+ return -1;
+ *realms |= realm;
+ return 0;
+}
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/rtmon.c b/ap/app/iproute2/iproute2-3.4.0/ip/rtmon.c
new file mode 100755
index 0000000..c1416a0
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/rtmon.c
@@ -0,0 +1,177 @@
+/*
+ * rtmon.c RTnetlink listener.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <string.h>
+
+#include "SNAPSHOT.h"
+
+#include "utils.h"
+#include "libnetlink.h"
+
+int resolve_hosts = 0;
+static int init_phase = 1;
+
+static void write_stamp(FILE *fp)
+{
+ char buf[128];
+ struct nlmsghdr *n1 = (void*)buf;
+ struct timeval tv;
+
+ n1->nlmsg_type = 15;
+ n1->nlmsg_flags = 0;
+ n1->nlmsg_seq = 0;
+ n1->nlmsg_pid = 0;
+ n1->nlmsg_len = NLMSG_LENGTH(4*2);
+ gettimeofday(&tv, NULL);
+ ((__u32*)NLMSG_DATA(n1))[0] = tv.tv_sec;
+ ((__u32*)NLMSG_DATA(n1))[1] = tv.tv_usec;
+ fwrite((void*)n1, 1, NLMSG_ALIGN(n1->nlmsg_len), fp);
+}
+
+static int dump_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
+ void *arg)
+{
+ FILE *fp = (FILE*)arg;
+ if (!init_phase)
+ write_stamp(fp);
+ fwrite((void*)n, 1, NLMSG_ALIGN(n->nlmsg_len), fp);
+ fflush(fp);
+ return 0;
+}
+
+void usage(void)
+{
+ fprintf(stderr, "Usage: rtmon file FILE [ all | LISTofOBJECTS]\n");
+ fprintf(stderr, "LISTofOBJECTS := [ link ] [ address ] [ route ]\n");
+ exit(-1);
+}
+
+int
+main(int argc, char **argv)
+{
+ FILE *fp;
+ struct rtnl_handle rth;
+ int family = AF_UNSPEC;
+ unsigned groups = ~0U;
+ int llink = 0;
+ int laddr = 0;
+ int lroute = 0;
+ char *file = NULL;
+
+ while (argc > 1) {
+ if (matches(argv[1], "-family") == 0) {
+ argc--;
+ argv++;
+ if (argc <= 1)
+ usage();
+ if (strcmp(argv[1], "inet") == 0)
+ family = AF_INET;
+ else if (strcmp(argv[1], "inet6") == 0)
+ family = AF_INET6;
+ else if (strcmp(argv[1], "link") == 0)
+ family = AF_INET6;
+ else if (strcmp(argv[1], "help") == 0)
+ usage();
+ else {
+ fprintf(stderr, "Protocol ID \"%s\" is unknown, try \"rtmon help\".\n", argv[1]);
+ exit(-1);
+ }
+ } else if (strcmp(argv[1], "-4") == 0) {
+ family = AF_INET;
+ } else if (strcmp(argv[1], "-6") == 0) {
+ family = AF_INET6;
+ } else if (strcmp(argv[1], "-0") == 0) {
+ family = AF_PACKET;
+ } else if (matches(argv[1], "-Version") == 0) {
+ printf("rtmon utility, iproute2-ss%s\n", SNAPSHOT);
+ exit(0);
+ } else if (matches(argv[1], "file") == 0) {
+ argc--;
+ argv++;
+ if (argc <= 1)
+ usage();
+ file = argv[1];
+ } else if (matches(argv[1], "link") == 0) {
+ llink=1;
+ groups = 0;
+ } else if (matches(argv[1], "address") == 0) {
+ laddr=1;
+ groups = 0;
+ } else if (matches(argv[1], "route") == 0) {
+ lroute=1;
+ groups = 0;
+ } else if (strcmp(argv[1], "all") == 0) {
+ groups = ~0U;
+ } else if (matches(argv[1], "help") == 0) {
+ usage();
+ } else {
+ fprintf(stderr, "Argument \"%s\" is unknown, try \"rtmon help\".\n", argv[1]);
+ exit(-1);
+ }
+ argc--; argv++;
+ }
+
+ if (file == NULL) {
+ fprintf(stderr, "Not enough information: argument \"file\" is required\n");
+ exit(-1);
+ }
+ if (llink)
+ groups |= nl_mgrp(RTNLGRP_LINK);
+ if (laddr) {
+ if (!family || family == AF_INET)
+ groups |= nl_mgrp(RTNLGRP_IPV4_IFADDR);
+ if (!family || family == AF_INET6)
+ groups |= nl_mgrp(RTNLGRP_IPV6_IFADDR);
+ }
+ if (lroute) {
+ if (!family || family == AF_INET)
+ groups |= nl_mgrp(RTNLGRP_IPV4_ROUTE);
+ if (!family || family == AF_INET6)
+ groups |= nl_mgrp(RTNLGRP_IPV6_ROUTE);
+ }
+
+ fp = fopen(file, "w");
+ if (fp == NULL) {
+ perror("Cannot fopen");
+ exit(-1);
+ }
+
+ if (rtnl_open(&rth, groups) < 0)
+ exit(1);
+
+ if (rtnl_wilddump_request(&rth, AF_UNSPEC, RTM_GETLINK) < 0) {
+ perror("Cannot send dump request");
+ exit(1);
+ }
+
+ write_stamp(fp);
+
+ if (rtnl_dump_filter(&rth, dump_msg, fp) < 0) {
+ fprintf(stderr, "Dump terminated\n");
+ return 1;
+ }
+
+ init_phase = 0;
+
+ if (rtnl_listen(&rth, dump_msg, (void*)fp) < 0)
+ exit(2);
+
+ exit(0);
+}
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/rtpr b/ap/app/iproute2/iproute2-3.4.0/ip/rtpr
new file mode 100755
index 0000000..c3629fd
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/rtpr
@@ -0,0 +1,4 @@
+#! /bin/bash
+
+exec tr "[\\\\]" "[
+]"
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/static-syms.c b/ap/app/iproute2/iproute2-3.4.0/ip/static-syms.c
new file mode 100755
index 0000000..1ed3a8a
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/static-syms.c
@@ -0,0 +1,6 @@
+#include <string.h>
+void *_dlsym(const char *sym)
+{
+#include "static-syms.h"
+ return NULL;
+}
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/tunnel.c b/ap/app/iproute2/iproute2-3.4.0/ip/tunnel.c
new file mode 100755
index 0000000..b176d3f
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/tunnel.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C)2006 USAGI/WIDE Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*
+ * split from ip_tunnel.c
+ */
+/*
+ * Author:
+ * Masahide NAKAMURA @USAGI
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <linux/if.h>
+#include <linux/ip.h>
+#include <linux/if_tunnel.h>
+
+#include "utils.h"
+#include "tunnel.h"
+
+const char *tnl_strproto(__u8 proto)
+{
+ static char buf[16];
+
+ switch (proto) {
+ case IPPROTO_IPIP:
+ strcpy(buf, "ip");
+ break;
+ case IPPROTO_GRE:
+ strcpy(buf, "gre");
+ break;
+ case IPPROTO_IPV6:
+ strcpy(buf, "ipv6");
+ break;
+ case 0:
+ strcpy(buf, "any");
+ break;
+ default:
+ strcpy(buf, "unknown");
+ break;
+ }
+
+ return buf;
+}
+
+int tnl_get_ioctl(const char *basedev, void *p)
+{
+ struct ifreq ifr;
+ int fd;
+ int err;
+
+ strncpy(ifr.ifr_name, basedev, IFNAMSIZ);
+ ifr.ifr_ifru.ifru_data = (void*)p;
+ fd = socket(preferred_family, SOCK_DGRAM, 0);
+ err = ioctl(fd, SIOCGETTUNNEL, &ifr);
+ if (err)
+ fprintf(stderr, "get tunnel %s failed: %s\n", basedev,
+ strerror(errno));
+
+ close(fd);
+ return err;
+}
+
+int tnl_add_ioctl(int cmd, const char *basedev, const char *name, void *p)
+{
+ struct ifreq ifr;
+ int fd;
+ int err;
+
+ if (cmd == SIOCCHGTUNNEL && name[0])
+ strncpy(ifr.ifr_name, name, IFNAMSIZ);
+ else
+ strncpy(ifr.ifr_name, basedev, IFNAMSIZ);
+ ifr.ifr_ifru.ifru_data = p;
+ fd = socket(preferred_family, SOCK_DGRAM, 0);
+ err = ioctl(fd, cmd, &ifr);
+ if (err)
+ fprintf(stderr, "add tunnel %s failed: %s\n", ifr.ifr_name,
+ strerror(errno));
+ close(fd);
+ return err;
+}
+
+int tnl_del_ioctl(const char *basedev, const char *name, void *p)
+{
+ struct ifreq ifr;
+ int fd;
+ int err;
+
+ if (name[0])
+ strncpy(ifr.ifr_name, name, IFNAMSIZ);
+ else
+ strncpy(ifr.ifr_name, basedev, IFNAMSIZ);
+
+ ifr.ifr_ifru.ifru_data = p;
+ fd = socket(preferred_family, SOCK_DGRAM, 0);
+ err = ioctl(fd, SIOCDELTUNNEL, &ifr);
+ if (err)
+ fprintf(stderr, "delete tunnel %s failed: %s\n",
+ ifr.ifr_name, strerror(errno));
+ close(fd);
+ return err;
+}
+
+static int tnl_gen_ioctl(int cmd, const char *name,
+ void *p, int skiperr)
+{
+ struct ifreq ifr;
+ int fd;
+ int err;
+
+ strncpy(ifr.ifr_name, name, IFNAMSIZ);
+ ifr.ifr_ifru.ifru_data = p;
+ fd = socket(preferred_family, SOCK_DGRAM, 0);
+ err = ioctl(fd, cmd, &ifr);
+ if (err && errno != skiperr)
+ fprintf(stderr, "%s: ioctl %x failed: %s\n", name,
+ cmd, strerror(errno));
+ close(fd);
+ return err;
+}
+
+int tnl_prl_ioctl(int cmd, const char *name, void *p)
+{
+ return tnl_gen_ioctl(cmd, name, p, -1);
+}
+
+int tnl_6rd_ioctl(int cmd, const char *name, void *p)
+{
+ return tnl_gen_ioctl(cmd, name, p, -1);
+}
+
+int tnl_ioctl_get_6rd(const char *name, void *p)
+{
+ return tnl_gen_ioctl(SIOCGET6RD, name, p, EINVAL);
+}
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/tunnel.h b/ap/app/iproute2/iproute2-3.4.0/ip/tunnel.h
new file mode 100755
index 0000000..7e7fe13
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/tunnel.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C)2006 USAGI/WIDE Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*
+ * Author:
+ * Masahide NAKAMURA @USAGI
+ */
+#ifndef __TUNNEL_H__
+#define __TUNNEL_H__ 1
+
+#include <linux/types.h>
+
+const char *tnl_strproto(__u8 proto);
+
+int tnl_get_ioctl(const char *basedev, void *p);
+int tnl_add_ioctl(int cmd, const char *basedev, const char *name, void *p);
+int tnl_del_ioctl(const char *basedev, const char *name, void *p);
+int tnl_prl_ioctl(int cmd, const char *name, void *p);
+int tnl_6rd_ioctl(int cmd, const char *name, void *p);
+int tnl_ioctl_get_6rd(const char *name, void *p);
+
+#endif
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/xfrm.h b/ap/app/iproute2/iproute2-3.4.0/ip/xfrm.h
new file mode 100755
index 0000000..784a201
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/xfrm.h
@@ -0,0 +1,159 @@
+/* $USAGI: $ */
+
+/*
+ * Copyright (C)2004 USAGI/WIDE Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*
+ * Authors:
+ * Masahide NAKAMURA @USAGI
+ */
+
+#ifndef __XFRM_H__
+#define __XFRM_H__ 1
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <linux/xfrm.h>
+
+#ifndef IPPROTO_SCTP
+# define IPPROTO_SCTP 132
+#endif
+#ifndef IPPROTO_DCCP
+# define IPPROTO_DCCP 33
+#endif
+#ifndef IPPROTO_MH
+# define IPPROTO_MH 135
+#endif
+
+#define XFRMS_RTA(x) ((struct rtattr*)(((char*)(x)) + NLMSG_ALIGN(sizeof(struct xfrm_usersa_info))))
+#define XFRMS_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct xfrm_usersa_info))
+
+#define XFRMP_RTA(x) ((struct rtattr*)(((char*)(x)) + NLMSG_ALIGN(sizeof(struct xfrm_userpolicy_info))))
+#define XFRMP_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct xfrm_userpoilcy_info))
+
+#define XFRMSID_RTA(x) ((struct rtattr*)(((char*)(x)) + NLMSG_ALIGN(sizeof(struct xfrm_usersa_id))))
+#define XFRMSID_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct xfrm_usersa_id))
+
+#define XFRMPID_RTA(x) ((struct rtattr*)(((char*)(x)) + NLMSG_ALIGN(sizeof(struct xfrm_userpolicy_id))))
+#define XFRMPID_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct xfrm_userpoilcy_id))
+
+#define XFRMACQ_RTA(x) ((struct rtattr*)(((char*)(x)) + NLMSG_ALIGN(sizeof(struct xfrm_user_acquire))))
+#define XFRMEXP_RTA(x) ((struct rtattr*)(((char*)(x)) + NLMSG_ALIGN(sizeof(struct xfrm_user_expire))))
+#define XFRMPEXP_RTA(x) ((struct rtattr*)(((char*)(x)) + NLMSG_ALIGN(sizeof(struct xfrm_user_polexpire))))
+
+#define XFRMREP_RTA(x) ((struct rtattr*)(((char*)(x)) + NLMSG_ALIGN(sizeof(struct xfrm_user_report))))
+
+#define XFRMSAPD_RTA(x) ((struct rtattr*)(((char*)(x)) + NLMSG_ALIGN(sizeof(__u32))))
+#define XFRM_FLAG_PRINT(fp, flags, f, s) \
+ do { \
+ if (flags & f) { \
+ flags &= ~f; \
+ fprintf(fp, s "%s", (flags ? " " : "")); \
+ } \
+ } while(0)
+
+struct xfrm_buffer {
+ char *buf;
+ int size;
+ int offset;
+
+ int nlmsg_count;
+ struct rtnl_handle *rth;
+};
+
+struct xfrm_filter {
+ int use;
+
+ struct xfrm_usersa_info xsinfo;
+ __u8 id_src_mask;
+ __u8 id_dst_mask;
+ __u8 id_proto_mask;
+ __u32 id_spi_mask;
+ __u8 mode_mask;
+ __u32 reqid_mask;
+ __u8 state_flags_mask;
+
+ struct xfrm_userpolicy_info xpinfo;
+ __u8 dir_mask;
+ __u8 sel_src_mask;
+ __u8 sel_dst_mask;
+ __u32 sel_dev_mask;
+ __u8 upspec_proto_mask;
+ __u16 upspec_sport_mask;
+ __u16 upspec_dport_mask;
+ __u32 index_mask;
+ __u8 action_mask;
+ __u32 priority_mask;
+ __u8 policy_flags_mask;
+
+ __u8 ptype;
+ __u8 ptype_mask;
+
+};
+#define XFRM_FILTER_MASK_FULL (~0)
+
+extern struct xfrm_filter filter;
+
+int xfrm_state_print(const struct sockaddr_nl *who, struct nlmsghdr *n,
+ void *arg);
+int xfrm_policy_print(const struct sockaddr_nl *who, struct nlmsghdr *n,
+ void *arg);
+int do_xfrm_state(int argc, char **argv);
+int do_xfrm_policy(int argc, char **argv);
+int do_xfrm_monitor(int argc, char **argv);
+
+int xfrm_addr_match(xfrm_address_t *x1, xfrm_address_t *x2, int bits);
+int xfrm_xfrmproto_is_ipsec(__u8 proto);
+int xfrm_xfrmproto_is_ro(__u8 proto);
+int xfrm_xfrmproto_getbyname(char *name);
+int xfrm_algotype_getbyname(char *name);
+int xfrm_parse_mark(struct xfrm_mark *mark, int *argcp, char ***argvp);
+const char *strxf_xfrmproto(__u8 proto);
+const char *strxf_algotype(int type);
+const char *strxf_mask8(__u8 mask);
+const char *strxf_mask32(__u32 mask);
+const char *strxf_share(__u8 share);
+const char *strxf_proto(__u8 proto);
+const char *strxf_ptype(__u8 ptype);
+void xfrm_id_info_print(xfrm_address_t *saddr, struct xfrm_id *id,
+ __u8 mode, __u32 reqid, __u16 family, int force_spi,
+ FILE *fp, const char *prefix, const char *title);
+void xfrm_stats_print(struct xfrm_stats *s, FILE *fp, const char *prefix);
+void xfrm_lifetime_print(struct xfrm_lifetime_cfg *cfg,
+ struct xfrm_lifetime_cur *cur,
+ FILE *fp, const char *prefix);
+void xfrm_selector_print(struct xfrm_selector *sel, __u16 family,
+ FILE *fp, const char *prefix);
+void xfrm_xfrma_print(struct rtattr *tb[], __u16 family,
+ FILE *fp, const char *prefix);
+void xfrm_state_info_print(struct xfrm_usersa_info *xsinfo,
+ struct rtattr *tb[], FILE *fp, const char *prefix,
+ const char *title);
+void xfrm_policy_info_print(struct xfrm_userpolicy_info *xpinfo,
+ struct rtattr *tb[], FILE *fp, const char *prefix,
+ const char *title);
+int xfrm_id_parse(xfrm_address_t *saddr, struct xfrm_id *id, __u16 *family,
+ int loose, int *argcp, char ***argvp);
+int xfrm_mode_parse(__u8 *mode, int *argcp, char ***argvp);
+int xfrm_encap_type_parse(__u16 *type, int *argcp, char ***argvp);
+int xfrm_reqid_parse(__u32 *reqid, int *argcp, char ***argvp);
+int xfrm_selector_parse(struct xfrm_selector *sel, int *argcp, char ***argvp);
+int xfrm_lifetime_cfg_parse(struct xfrm_lifetime_cfg *lft,
+ int *argcp, char ***argvp);
+int xfrm_sctx_parse(char *ctxstr, char *context,
+ struct xfrm_user_sec_ctx *sctx);
+#endif
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/xfrm_monitor.c b/ap/app/iproute2/iproute2-3.4.0/ip/xfrm_monitor.c
new file mode 100755
index 0000000..ea17987
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/xfrm_monitor.c
@@ -0,0 +1,420 @@
+/* $USAGI: $ */
+
+/*
+ * Copyright (C)2005 USAGI/WIDE Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*
+ * based on ipmonitor.c
+ */
+/*
+ * Authors:
+ * Masahide NAKAMURA @USAGI
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <linux/xfrm.h>
+#include "utils.h"
+#include "xfrm.h"
+#include "ip_common.h"
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: ip xfrm monitor [ all | LISTofXFRM-OBJECTS ]\n");
+ exit(-1);
+}
+
+static int xfrm_acquire_print(const struct sockaddr_nl *who,
+ struct nlmsghdr *n, void *arg)
+{
+ FILE *fp = (FILE*)arg;
+ struct xfrm_user_acquire *xacq = NLMSG_DATA(n);
+ int len = n->nlmsg_len;
+ struct rtattr * tb[XFRMA_MAX+1];
+ __u16 family;
+
+ len -= NLMSG_LENGTH(sizeof(*xacq));
+ if (len < 0) {
+ fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+ return -1;
+ }
+
+ parse_rtattr(tb, XFRMA_MAX, XFRMACQ_RTA(xacq), len);
+
+ family = xacq->sel.family;
+ if (family == AF_UNSPEC)
+ family = xacq->policy.sel.family;
+ if (family == AF_UNSPEC)
+ family = preferred_family;
+
+ fprintf(fp, "acquire ");
+
+ fprintf(fp, "proto %s ", strxf_xfrmproto(xacq->id.proto));
+ if (show_stats > 0 || xacq->id.spi) {
+ __u32 spi = ntohl(xacq->id.spi);
+ fprintf(fp, "spi 0x%08x", spi);
+ if (show_stats > 0)
+ fprintf(fp, "(%u)", spi);
+ fprintf(fp, " ");
+ }
+ fprintf(fp, "%s", _SL_);
+
+ xfrm_selector_print(&xacq->sel, family, fp, " sel ");
+
+ xfrm_policy_info_print(&xacq->policy, tb, fp, " ", " policy ");
+
+ if (show_stats > 0)
+ fprintf(fp, " seq 0x%08u ", xacq->seq);
+ if (show_stats > 0) {
+ fprintf(fp, "%s-mask %s ",
+ strxf_algotype(XFRMA_ALG_CRYPT),
+ strxf_mask32(xacq->ealgos));
+ fprintf(fp, "%s-mask %s ",
+ strxf_algotype(XFRMA_ALG_AUTH),
+ strxf_mask32(xacq->aalgos));
+ fprintf(fp, "%s-mask %s",
+ strxf_algotype(XFRMA_ALG_COMP),
+ strxf_mask32(xacq->calgos));
+ }
+ fprintf(fp, "%s", _SL_);
+
+ if (oneline)
+ fprintf(fp, "\n");
+ fflush(fp);
+
+ return 0;
+}
+
+static int xfrm_state_flush_print(const struct sockaddr_nl *who,
+ struct nlmsghdr *n, void *arg)
+{
+ FILE *fp = (FILE*)arg;
+ struct xfrm_usersa_flush *xsf = NLMSG_DATA(n);
+ int len = n->nlmsg_len;
+ const char *str;
+
+ len -= NLMSG_SPACE(sizeof(*xsf));
+ if (len < 0) {
+ fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+ return -1;
+ }
+
+ fprintf(fp, "Flushed state ");
+
+ str = strxf_xfrmproto(xsf->proto);
+ if (str)
+ fprintf(fp, "proto %s", str);
+ else
+ fprintf(fp, "proto %u", xsf->proto);
+ fprintf(fp, "%s", _SL_);
+
+ if (oneline)
+ fprintf(fp, "\n");
+ fflush(fp);
+
+ return 0;
+}
+
+static int xfrm_policy_flush_print(const struct sockaddr_nl *who,
+ struct nlmsghdr *n, void *arg)
+{
+ struct rtattr * tb[XFRMA_MAX+1];
+ FILE *fp = (FILE*)arg;
+ int len = n->nlmsg_len;
+
+ len -= NLMSG_SPACE(0);
+ if (len < 0) {
+ fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+ return -1;
+ }
+
+ fprintf(fp, "Flushed policy ");
+
+ parse_rtattr(tb, XFRMA_MAX, NLMSG_DATA(n), len);
+
+ if (tb[XFRMA_POLICY_TYPE]) {
+ struct xfrm_userpolicy_type *upt;
+
+ fprintf(fp, "ptype ");
+
+ if (RTA_PAYLOAD(tb[XFRMA_POLICY_TYPE]) < sizeof(*upt))
+ fprintf(fp, "(ERROR truncated)");
+
+ upt = (struct xfrm_userpolicy_type *)RTA_DATA(tb[XFRMA_POLICY_TYPE]);
+ fprintf(fp, "%s ", strxf_ptype(upt->type));
+ }
+
+ fprintf(fp, "%s", _SL_);
+
+ if (oneline)
+ fprintf(fp, "\n");
+ fflush(fp);
+
+ return 0;
+}
+
+static int xfrm_report_print(const struct sockaddr_nl *who,
+ struct nlmsghdr *n, void *arg)
+{
+ FILE *fp = (FILE*)arg;
+ struct xfrm_user_report *xrep = NLMSG_DATA(n);
+ int len = n->nlmsg_len;
+ struct rtattr * tb[XFRMA_MAX+1];
+ __u16 family;
+
+ len -= NLMSG_LENGTH(sizeof(*xrep));
+ if (len < 0) {
+ fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+ return -1;
+ }
+
+ family = xrep->sel.family;
+ if (family == AF_UNSPEC)
+ family = preferred_family;
+
+ fprintf(fp, "report ");
+
+ fprintf(fp, "proto %s ", strxf_xfrmproto(xrep->proto));
+ fprintf(fp, "%s", _SL_);
+
+ xfrm_selector_print(&xrep->sel, family, fp, " sel ");
+
+ parse_rtattr(tb, XFRMA_MAX, XFRMREP_RTA(xrep), len);
+
+ xfrm_xfrma_print(tb, family, fp, " ");
+
+ if (oneline)
+ fprintf(fp, "\n");
+
+ return 0;
+}
+
+void xfrm_ae_flags_print(__u32 flags, void *arg)
+{
+ FILE *fp = (FILE*)arg;
+ fprintf(fp, " (0x%x) ", flags);
+ if (!flags)
+ return;
+ if (flags & XFRM_AE_CR)
+ fprintf(fp, " replay update ");
+ if (flags & XFRM_AE_CE)
+ fprintf(fp, " timer expired ");
+ if (flags & XFRM_AE_CU)
+ fprintf(fp, " policy updated ");
+
+}
+
+static void xfrm_usersa_print(const struct xfrm_usersa_id *sa_id, __u32 reqid, FILE *fp)
+{
+ char buf[256];
+
+ buf[0] = 0;
+ fprintf(fp, "dst %s ", rt_addr_n2a(sa_id->family,
+ sizeof(sa_id->daddr), &sa_id->daddr, buf, sizeof(buf)));
+
+ fprintf(fp, " reqid 0x%x", reqid);
+
+ fprintf(fp, " protocol %s ", strxf_proto(sa_id->proto));
+ fprintf(fp, " SPI 0x%x", ntohl(sa_id->spi));
+}
+
+static int xfrm_ae_print(const struct sockaddr_nl *who,
+ struct nlmsghdr *n, void *arg)
+{
+ FILE *fp = (FILE*)arg;
+ struct xfrm_aevent_id *id = NLMSG_DATA(n);
+ char abuf[256];
+
+ fprintf(fp, "Async event ");
+ xfrm_ae_flags_print(id->flags, arg);
+ fprintf(fp,"\n\t");
+ memset(abuf, '\0', sizeof(abuf));
+ fprintf(fp, "src %s ", rt_addr_n2a(id->sa_id.family,
+ sizeof(id->saddr), &id->saddr,
+ abuf, sizeof(abuf)));
+
+ xfrm_usersa_print(&id->sa_id, id->reqid, fp);
+
+ fprintf(fp, "\n");
+ fflush(fp);
+
+ return 0;
+}
+
+static void xfrm_print_addr(FILE *fp, int family, xfrm_address_t *a, size_t s)
+{
+ char buf[256];
+
+ buf[0] = 0;
+ fprintf(fp, "%s", rt_addr_n2a(family, s, a, buf, sizeof(buf)));
+}
+
+static int xfrm_mapping_print(const struct sockaddr_nl *who,
+ struct nlmsghdr *n, void *arg)
+{
+ FILE *fp = (FILE*)arg;
+ struct xfrm_user_mapping *map = NLMSG_DATA(n);
+
+ fprintf(fp, "Mapping change ");
+ xfrm_print_addr(fp, map->id.family, &map->old_saddr,
+ sizeof(map->old_saddr));
+
+ fprintf(fp, ":%d -> ", ntohs(map->old_sport));
+ xfrm_print_addr(fp, map->id.family, &map->new_saddr,
+ sizeof(map->new_saddr));
+ fprintf(fp, ":%d\n\t", ntohs(map->new_sport));
+
+ xfrm_usersa_print(&map->id, map->reqid, fp);
+
+ fprintf(fp, "\n");
+ fflush(fp);
+ return 0;
+}
+
+static int xfrm_accept_msg(const struct sockaddr_nl *who,
+ struct nlmsghdr *n, void *arg)
+{
+ FILE *fp = (FILE*)arg;
+
+ if (timestamp)
+ print_timestamp(fp);
+
+ switch (n->nlmsg_type) {
+ case XFRM_MSG_NEWSA:
+ case XFRM_MSG_DELSA:
+ case XFRM_MSG_UPDSA:
+ case XFRM_MSG_EXPIRE:
+ xfrm_state_print(who, n, arg);
+ return 0;
+ case XFRM_MSG_NEWPOLICY:
+ case XFRM_MSG_DELPOLICY:
+ case XFRM_MSG_UPDPOLICY:
+ case XFRM_MSG_POLEXPIRE:
+ xfrm_policy_print(who, n, arg);
+ return 0;
+ case XFRM_MSG_ACQUIRE:
+ xfrm_acquire_print(who, n, arg);
+ return 0;
+ case XFRM_MSG_FLUSHSA:
+ xfrm_state_flush_print(who, n, arg);
+ return 0;
+ case XFRM_MSG_FLUSHPOLICY:
+ xfrm_policy_flush_print(who, n, arg);
+ return 0;
+ case XFRM_MSG_REPORT:
+ xfrm_report_print(who, n, arg);
+ return 0;
+ case XFRM_MSG_NEWAE:
+ xfrm_ae_print(who, n, arg);
+ return 0;
+ case XFRM_MSG_MAPPING:
+ xfrm_mapping_print(who, n, arg);
+ return 0;
+ default:
+ break;
+ }
+
+ if (n->nlmsg_type != NLMSG_ERROR && n->nlmsg_type != NLMSG_NOOP &&
+ n->nlmsg_type != NLMSG_DONE) {
+ fprintf(fp, "Unknown message: %08d 0x%08x 0x%08x\n",
+ n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
+ }
+ return 0;
+}
+
+extern struct rtnl_handle rth;
+
+int do_xfrm_monitor(int argc, char **argv)
+{
+ char *file = NULL;
+ unsigned groups = ~((unsigned)0); /* XXX */
+ int lacquire=0;
+ int lexpire=0;
+ int laevent=0;
+ int lpolicy=0;
+ int lsa=0;
+ int lreport=0;
+
+ rtnl_close(&rth);
+
+ while (argc > 0) {
+ if (matches(*argv, "file") == 0) {
+ NEXT_ARG();
+ file = *argv;
+ } else if (matches(*argv, "acquire") == 0) {
+ lacquire=1;
+ groups = 0;
+ } else if (matches(*argv, "expire") == 0) {
+ lexpire=1;
+ groups = 0;
+ } else if (matches(*argv, "SA") == 0) {
+ lsa=1;
+ groups = 0;
+ } else if (matches(*argv, "aevent") == 0) {
+ laevent=1;
+ groups = 0;
+ } else if (matches(*argv, "policy") == 0) {
+ lpolicy=1;
+ groups = 0;
+ } else if (matches(*argv, "report") == 0) {
+ lreport=1;
+ groups = 0;
+ } else if (matches(*argv, "help") == 0) {
+ usage();
+ } else {
+ fprintf(stderr, "Argument \"%s\" is unknown, try \"ip xfrm monitor help\".\n", *argv);
+ exit(-1);
+ }
+ argc--; argv++;
+ }
+
+ if (lacquire)
+ groups |= nl_mgrp(XFRMNLGRP_ACQUIRE);
+ if (lexpire)
+ groups |= nl_mgrp(XFRMNLGRP_EXPIRE);
+ if (lsa)
+ groups |= nl_mgrp(XFRMNLGRP_SA);
+ if (lpolicy)
+ groups |= nl_mgrp(XFRMNLGRP_POLICY);
+ if (laevent)
+ groups |= nl_mgrp(XFRMNLGRP_AEVENTS);
+ if (lreport)
+ groups |= nl_mgrp(XFRMNLGRP_REPORT);
+
+ if (file) {
+ FILE *fp;
+ fp = fopen(file, "r");
+ if (fp == NULL) {
+ perror("Cannot fopen");
+ exit(-1);
+ }
+ return rtnl_from_file(fp, xfrm_accept_msg, (void*)stdout);
+ }
+
+ //ll_init_map(&rth);
+
+ if (rtnl_open_byproto(&rth, groups, NETLINK_XFRM) < 0)
+ exit(1);
+
+ if (rtnl_listen(&rth, xfrm_accept_msg, (void*)stdout) < 0)
+ exit(2);
+
+ return 0;
+}
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/xfrm_policy.c b/ap/app/iproute2/iproute2-3.4.0/ip/xfrm_policy.c
new file mode 100755
index 0000000..8e3aec5
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/xfrm_policy.c
@@ -0,0 +1,1066 @@
+/* $USAGI: $ */
+
+/*
+ * Copyright (C)2004 USAGI/WIDE Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*
+ * based on iproute.c
+ */
+/*
+ * Authors:
+ * Masahide NAKAMURA @USAGI
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <linux/netlink.h>
+#include <linux/xfrm.h>
+#include "utils.h"
+#include "xfrm.h"
+#include "ip_common.h"
+
+//#define NLMSG_DELETEALL_BUF_SIZE (4096-512)
+#define NLMSG_DELETEALL_BUF_SIZE 8192
+
+/*
+ * Receiving buffer defines:
+ * nlmsg
+ * data = struct xfrm_userpolicy_info
+ * rtattr
+ * data = struct xfrm_user_tmpl[]
+ */
+#define NLMSG_BUF_SIZE 4096
+#define RTA_BUF_SIZE 2048
+#define XFRM_TMPLS_BUF_SIZE 1024
+#define CTX_BUF_SIZE 256
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: ip xfrm policy { add | update } SELECTOR dir DIR [ ctx CTX ]\n");
+ fprintf(stderr, " [ mark MARK [ mask MASK ] ] [ index INDEX ] [ ptype PTYPE ]\n");
+ fprintf(stderr, " [ action ACTION ] [ priority PRIORITY ] [ flag FLAG-LIST ]\n");
+ fprintf(stderr, " [ LIMIT-LIST ] [ TMPL-LIST ]\n");
+ fprintf(stderr, "Usage: ip xfrm policy { delete | get } { SELECTOR | index INDEX } dir DIR\n");
+ fprintf(stderr, " [ ctx CTX ] [ mark MARK [ mask MASK ] ] [ ptype PTYPE ]\n");
+ fprintf(stderr, "Usage: ip xfrm policy { deleteall | list } [ SELECTOR ] [ dir DIR ]\n");
+ fprintf(stderr, " [ index INDEX ] [ ptype PTYPE ] [ action ACTION ] [ priority PRIORITY ]\n");
+ fprintf(stderr, " [ flag FLAG-LIST ]\n");
+ fprintf(stderr, "Usage: ip xfrm policy flush [ ptype PTYPE ]\n");
+ fprintf(stderr, "Usage: ip xfrm count\n");
+ fprintf(stderr, "SELECTOR := [ src ADDR[/PLEN] ] [ dst ADDR[/PLEN] ] [ dev DEV ] [ UPSPEC ]\n");
+ fprintf(stderr, "UPSPEC := proto { { ");
+ fprintf(stderr, "%s | ", strxf_proto(IPPROTO_TCP));
+ fprintf(stderr, "%s | ", strxf_proto(IPPROTO_UDP));
+ fprintf(stderr, "%s | ", strxf_proto(IPPROTO_SCTP));
+ fprintf(stderr, "%s", strxf_proto(IPPROTO_DCCP));
+ fprintf(stderr, " } [ sport PORT ] [ dport PORT ] |\n");
+ fprintf(stderr, " { ");
+ fprintf(stderr, "%s | ", strxf_proto(IPPROTO_ICMP));
+ fprintf(stderr, "%s | ", strxf_proto(IPPROTO_ICMPV6));
+ fprintf(stderr, "%s", strxf_proto(IPPROTO_MH));
+ fprintf(stderr, " } [ type NUMBER ] [ code NUMBER ] |\n");
+ fprintf(stderr, " %s", strxf_proto(IPPROTO_GRE));
+ fprintf(stderr, " [ key { DOTTED-QUAD | NUMBER } ] | PROTO }\n");
+ fprintf(stderr, "DIR := in | out | fwd\n");
+ fprintf(stderr, "PTYPE := main | sub\n");
+ fprintf(stderr, "ACTION := allow | block\n");
+ fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n");
+ fprintf(stderr, "FLAG := localok | icmp\n");
+ fprintf(stderr, "LIMIT-LIST := [ LIMIT-LIST ] limit LIMIT\n");
+ fprintf(stderr, "LIMIT := { time-soft | time-hard | time-use-soft | time-use-hard } SECONDS |\n");
+ fprintf(stderr, " { byte-soft | byte-hard } SIZE | { packet-soft | packet-hard } COUNT\n");
+ fprintf(stderr, "TMPL-LIST := [ TMPL-LIST ] tmpl TMPL\n");
+ fprintf(stderr, "TMPL := ID [ mode MODE ] [ reqid REQID ] [ level LEVEL ]\n");
+ fprintf(stderr, "ID := [ src ADDR ] [ dst ADDR ] [ proto XFRM-PROTO ] [ spi SPI ]\n");
+ fprintf(stderr, "XFRM-PROTO := ");
+ fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ESP));
+ fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_AH));
+ fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_COMP));
+ fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ROUTING));
+ fprintf(stderr, "%s\n", strxf_xfrmproto(IPPROTO_DSTOPTS));
+ fprintf(stderr, "MODE := transport | tunnel | ro | in_trigger | beet\n");
+ fprintf(stderr, "LEVEL := required | use\n");
+
+ exit(-1);
+}
+
+static int xfrm_policy_dir_parse(__u8 *dir, int *argcp, char ***argvp)
+{
+ int argc = *argcp;
+ char **argv = *argvp;
+
+ if (strcmp(*argv, "in") == 0)
+ *dir = XFRM_POLICY_IN;
+ else if (strcmp(*argv, "out") == 0)
+ *dir = XFRM_POLICY_OUT;
+ else if (strcmp(*argv, "fwd") == 0)
+ *dir = XFRM_POLICY_FWD;
+ else
+ invarg("\"DIR\" is invalid", *argv);
+
+ *argcp = argc;
+ *argvp = argv;
+
+ return 0;
+}
+
+static int xfrm_policy_ptype_parse(__u8 *ptype, int *argcp, char ***argvp)
+{
+ int argc = *argcp;
+ char **argv = *argvp;
+
+ if (strcmp(*argv, "main") == 0)
+ *ptype = XFRM_POLICY_TYPE_MAIN;
+ else if (strcmp(*argv, "sub") == 0)
+ *ptype = XFRM_POLICY_TYPE_SUB;
+ else
+ invarg("\"PTYPE\" is invalid", *argv);
+
+ *argcp = argc;
+ *argvp = argv;
+
+ return 0;
+}
+
+static int xfrm_policy_flag_parse(__u8 *flags, int *argcp, char ***argvp)
+{
+ int argc = *argcp;
+ char **argv = *argvp;
+ int len = strlen(*argv);
+
+ if (len > 2 && strncmp(*argv, "0x", 2) == 0) {
+ __u8 val = 0;
+
+ if (get_u8(&val, *argv, 16))
+ invarg("\"FLAG\" is invalid", *argv);
+ *flags = val;
+ } else {
+ while (1) {
+ if (strcmp(*argv, "localok") == 0)
+ *flags |= XFRM_POLICY_LOCALOK;
+ else if (strcmp(*argv, "icmp") == 0)
+ *flags |= XFRM_POLICY_ICMP;
+ else {
+ PREV_ARG(); /* back track */
+ break;
+ }
+
+ if (!NEXT_ARG_OK())
+ break;
+ NEXT_ARG();
+ }
+ }
+
+ *argcp = argc;
+ *argvp = argv;
+
+ return 0;
+}
+
+static int xfrm_tmpl_parse(struct xfrm_user_tmpl *tmpl,
+ int *argcp, char ***argvp)
+{
+ int argc = *argcp;
+ char **argv = *argvp;
+ char *idp = NULL;
+
+ while (1) {
+ if (strcmp(*argv, "mode") == 0) {
+ NEXT_ARG();
+ xfrm_mode_parse(&tmpl->mode, &argc, &argv);
+ } else if (strcmp(*argv, "reqid") == 0) {
+ NEXT_ARG();
+ xfrm_reqid_parse(&tmpl->reqid, &argc, &argv);
+ } else if (strcmp(*argv, "level") == 0) {
+ NEXT_ARG();
+
+ if (strcmp(*argv, "required") == 0)
+ tmpl->optional = 0;
+ else if (strcmp(*argv, "use") == 0)
+ tmpl->optional = 1;
+ else
+ invarg("\"LEVEL\" is invalid\n", *argv);
+
+ } else {
+ if (idp) {
+ PREV_ARG(); /* back track */
+ break;
+ }
+ idp = *argv;
+ preferred_family = AF_UNSPEC;
+ xfrm_id_parse(&tmpl->saddr, &tmpl->id, &tmpl->family,
+ 0, &argc, &argv);
+ preferred_family = tmpl->family;
+ }
+
+ if (!NEXT_ARG_OK())
+ break;
+
+ NEXT_ARG();
+ }
+ if (argc == *argcp)
+ missarg("TMPL");
+
+ *argcp = argc;
+ *argvp = argv;
+
+ return 0;
+}
+
+int xfrm_sctx_parse(char *ctxstr, char *s,
+ struct xfrm_user_sec_ctx *sctx)
+{
+ int slen;
+
+ slen = strlen(s) + 1;
+
+ sctx->exttype = XFRMA_SEC_CTX;
+ sctx->ctx_doi = 1;
+ sctx->ctx_alg = 1;
+ sctx->ctx_len = slen;
+ sctx->len = sizeof(struct xfrm_user_sec_ctx) + slen;
+ memcpy(ctxstr, s, slen);
+
+ return 0;
+}
+
+static int xfrm_policy_modify(int cmd, unsigned flags, int argc, char **argv)
+{
+ struct rtnl_handle rth;
+ struct {
+ struct nlmsghdr n;
+ struct xfrm_userpolicy_info xpinfo;
+ char buf[RTA_BUF_SIZE];
+ } req;
+ char *dirp = NULL;
+ char *selp = NULL;
+ char *ptypep = NULL;
+ char *sctxp = NULL;
+ struct xfrm_userpolicy_type upt;
+ char tmpls_buf[XFRM_TMPLS_BUF_SIZE];
+ int tmpls_len = 0;
+ struct xfrm_mark mark = {0, 0};
+ struct {
+ struct xfrm_user_sec_ctx sctx;
+ char str[CTX_BUF_SIZE];
+ } ctx;
+
+ memset(&req, 0, sizeof(req));
+ memset(&upt, 0, sizeof(upt));
+ memset(&tmpls_buf, 0, sizeof(tmpls_buf));
+ memset(&ctx, 0, sizeof(ctx));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xpinfo));
+ req.n.nlmsg_flags = NLM_F_REQUEST|flags;
+ req.n.nlmsg_type = cmd;
+ req.xpinfo.sel.family = preferred_family;
+
+ req.xpinfo.lft.soft_byte_limit = XFRM_INF;
+ req.xpinfo.lft.hard_byte_limit = XFRM_INF;
+ req.xpinfo.lft.soft_packet_limit = XFRM_INF;
+ req.xpinfo.lft.hard_packet_limit = XFRM_INF;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "dir") == 0) {
+ if (dirp)
+ duparg("dir", *argv);
+ dirp = *argv;
+
+ NEXT_ARG();
+ xfrm_policy_dir_parse(&req.xpinfo.dir, &argc, &argv);
+ } else if (strcmp(*argv, "ctx") == 0) {
+ char *context;
+
+ if (sctxp)
+ duparg("ctx", *argv);
+ sctxp = *argv;
+ NEXT_ARG();
+ context = *argv;
+ xfrm_sctx_parse((char *)&ctx.str, context, &ctx.sctx);
+ } else if (strcmp(*argv, "mark") == 0) {
+ xfrm_parse_mark(&mark, &argc, &argv);
+ } else if (strcmp(*argv, "index") == 0) {
+ NEXT_ARG();
+ if (get_u32(&req.xpinfo.index, *argv, 0))
+ invarg("\"INDEX\" is invalid", *argv);
+ } else if (strcmp(*argv, "ptype") == 0) {
+ if (ptypep)
+ duparg("ptype", *argv);
+ ptypep = *argv;
+
+ NEXT_ARG();
+ xfrm_policy_ptype_parse(&upt.type, &argc, &argv);
+ } else if (strcmp(*argv, "action") == 0) {
+ NEXT_ARG();
+ if (strcmp(*argv, "allow") == 0)
+ req.xpinfo.action = XFRM_POLICY_ALLOW;
+ else if (strcmp(*argv, "block") == 0)
+ req.xpinfo.action = XFRM_POLICY_BLOCK;
+ else
+ invarg("\"action\" value is invalid\n", *argv);
+ } else if (strcmp(*argv, "priority") == 0) {
+ NEXT_ARG();
+ if (get_u32(&req.xpinfo.priority, *argv, 0))
+ invarg("\"PRIORITY\" is invalid", *argv);
+ } else if (strcmp(*argv, "flag") == 0) {
+ NEXT_ARG();
+ xfrm_policy_flag_parse(&req.xpinfo.flags, &argc,
+ &argv);
+ } else if (strcmp(*argv, "limit") == 0) {
+ NEXT_ARG();
+ xfrm_lifetime_cfg_parse(&req.xpinfo.lft, &argc, &argv);
+ } else if (strcmp(*argv, "tmpl") == 0) {
+ struct xfrm_user_tmpl *tmpl;
+
+ if (tmpls_len + sizeof(*tmpl) > sizeof(tmpls_buf)) {
+ fprintf(stderr, "Too many tmpls: buffer overflow\n");
+ exit(1);
+ }
+ tmpl = (struct xfrm_user_tmpl *)((char *)tmpls_buf + tmpls_len);
+
+ tmpl->family = preferred_family;
+ tmpl->aalgos = (~(__u32)0);
+ tmpl->ealgos = (~(__u32)0);
+ tmpl->calgos = (~(__u32)0);
+
+ NEXT_ARG();
+ xfrm_tmpl_parse(tmpl, &argc, &argv);
+
+ tmpls_len += sizeof(*tmpl);
+ } else {
+ if (selp)
+ duparg("unknown", *argv);
+ selp = *argv;
+
+ xfrm_selector_parse(&req.xpinfo.sel, &argc, &argv);
+ if (preferred_family == AF_UNSPEC)
+ preferred_family = req.xpinfo.sel.family;
+ }
+
+ argc--; argv++;
+ }
+
+ if (!dirp) {
+ fprintf(stderr, "Not enough information: \"DIR\" is required.\n");
+ exit(1);
+ }
+
+ if (ptypep) {
+ addattr_l(&req.n, sizeof(req), XFRMA_POLICY_TYPE,
+ (void *)&upt, sizeof(upt));
+ }
+
+ if (tmpls_len > 0) {
+ addattr_l(&req.n, sizeof(req), XFRMA_TMPL,
+ (void *)tmpls_buf, tmpls_len);
+ }
+
+ if (mark.m & mark.v) {
+ int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK,
+ (void *)&mark, sizeof(mark));
+ if (r < 0) {
+ fprintf(stderr, "%s: XFRMA_MARK failed\n",__func__);
+ exit(1);
+ }
+ }
+
+ if (sctxp) {
+ addattr_l(&req.n, sizeof(req), XFRMA_SEC_CTX,
+ (void *)&ctx, ctx.sctx.len);
+ }
+
+ if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
+ exit(1);
+
+ if (req.xpinfo.sel.family == AF_UNSPEC)
+ req.xpinfo.sel.family = AF_INET;
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ exit(2);
+
+ rtnl_close(&rth);
+
+ return 0;
+}
+
+static int xfrm_policy_filter_match(struct xfrm_userpolicy_info *xpinfo,
+ __u8 ptype)
+{
+ if (!filter.use)
+ return 1;
+
+ if ((xpinfo->dir^filter.xpinfo.dir)&filter.dir_mask)
+ return 0;
+
+ if ((ptype^filter.ptype)&filter.ptype_mask)
+ return 0;
+
+ if (filter.sel_src_mask) {
+ if (xfrm_addr_match(&xpinfo->sel.saddr, &filter.xpinfo.sel.saddr,
+ filter.sel_src_mask))
+ return 0;
+ }
+
+ if (filter.sel_dst_mask) {
+ if (xfrm_addr_match(&xpinfo->sel.daddr, &filter.xpinfo.sel.daddr,
+ filter.sel_dst_mask))
+ return 0;
+ }
+
+ if ((xpinfo->sel.ifindex^filter.xpinfo.sel.ifindex)&filter.sel_dev_mask)
+ return 0;
+
+ if ((xpinfo->sel.proto^filter.xpinfo.sel.proto)&filter.upspec_proto_mask)
+ return 0;
+
+ if (filter.upspec_sport_mask) {
+ if ((xpinfo->sel.sport^filter.xpinfo.sel.sport)&filter.upspec_sport_mask)
+ return 0;
+ }
+
+ if (filter.upspec_dport_mask) {
+ if ((xpinfo->sel.dport^filter.xpinfo.sel.dport)&filter.upspec_dport_mask)
+ return 0;
+ }
+
+ if ((xpinfo->index^filter.xpinfo.index)&filter.index_mask)
+ return 0;
+
+ if ((xpinfo->action^filter.xpinfo.action)&filter.action_mask)
+ return 0;
+
+ if ((xpinfo->priority^filter.xpinfo.priority)&filter.priority_mask)
+ return 0;
+
+ if (filter.policy_flags_mask)
+ if ((xpinfo->flags & filter.xpinfo.flags) == 0)
+ return 0;
+
+ return 1;
+}
+
+int xfrm_policy_print(const struct sockaddr_nl *who, struct nlmsghdr *n,
+ void *arg)
+{
+ struct rtattr * tb[XFRMA_MAX+1];
+ struct rtattr * rta;
+ struct xfrm_userpolicy_info *xpinfo = NULL;
+ struct xfrm_user_polexpire *xpexp = NULL;
+ struct xfrm_userpolicy_id *xpid = NULL;
+ __u8 ptype = XFRM_POLICY_TYPE_MAIN;
+ FILE *fp = (FILE*)arg;
+ int len = n->nlmsg_len;
+
+ if (n->nlmsg_type != XFRM_MSG_NEWPOLICY &&
+ n->nlmsg_type != XFRM_MSG_DELPOLICY &&
+ n->nlmsg_type != XFRM_MSG_UPDPOLICY &&
+ n->nlmsg_type != XFRM_MSG_POLEXPIRE) {
+ fprintf(stderr, "Not a policy: %08x %08x %08x\n",
+ n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
+ return 0;
+ }
+
+ if (n->nlmsg_type == XFRM_MSG_DELPOLICY) {
+ xpid = NLMSG_DATA(n);
+ len -= NLMSG_SPACE(sizeof(*xpid));
+ } else if (n->nlmsg_type == XFRM_MSG_POLEXPIRE) {
+ xpexp = NLMSG_DATA(n);
+ xpinfo = &xpexp->pol;
+ len -= NLMSG_SPACE(sizeof(*xpexp));
+ } else {
+ xpexp = NULL;
+ xpinfo = NLMSG_DATA(n);
+ len -= NLMSG_SPACE(sizeof(*xpinfo));
+ }
+
+ if (len < 0) {
+ fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+ return -1;
+ }
+
+ if (n->nlmsg_type == XFRM_MSG_DELPOLICY)
+ rta = XFRMPID_RTA(xpid);
+ else if (n->nlmsg_type == XFRM_MSG_POLEXPIRE)
+ rta = XFRMPEXP_RTA(xpexp);
+ else
+ rta = XFRMP_RTA(xpinfo);
+
+ parse_rtattr(tb, XFRMA_MAX, rta, len);
+
+ if (tb[XFRMA_POLICY_TYPE]) {
+ struct xfrm_userpolicy_type *upt;
+
+ if (RTA_PAYLOAD(tb[XFRMA_POLICY_TYPE]) < sizeof(*upt)) {
+ fprintf(stderr, "too short XFRMA_POLICY_TYPE len\n");
+ return -1;
+ }
+ upt = (struct xfrm_userpolicy_type *)RTA_DATA(tb[XFRMA_POLICY_TYPE]);
+ ptype = upt->type;
+ }
+
+ if (xpinfo && !xfrm_policy_filter_match(xpinfo, ptype))
+ return 0;
+
+ if (n->nlmsg_type == XFRM_MSG_DELPOLICY)
+ fprintf(fp, "Deleted ");
+ else if (n->nlmsg_type == XFRM_MSG_UPDPOLICY)
+ fprintf(fp, "Updated ");
+ else if (n->nlmsg_type == XFRM_MSG_POLEXPIRE)
+ fprintf(fp, "Expired ");
+
+ if (n->nlmsg_type == XFRM_MSG_DELPOLICY) {
+ //xfrm_policy_id_print();
+ if (!tb[XFRMA_POLICY]) {
+ fprintf(stderr, "Buggy XFRM_MSG_DELPOLICY: no XFRMA_POLICY\n");
+ return -1;
+ }
+ if (RTA_PAYLOAD(tb[XFRMA_POLICY]) < sizeof(*xpinfo)) {
+ fprintf(stderr, "Buggy XFRM_MSG_DELPOLICY: too short XFRMA_POLICY len\n");
+ return -1;
+ }
+ xpinfo = (struct xfrm_userpolicy_info *)RTA_DATA(tb[XFRMA_POLICY]);
+ }
+
+ xfrm_policy_info_print(xpinfo, tb, fp, NULL, NULL);
+
+ if (n->nlmsg_type == XFRM_MSG_POLEXPIRE) {
+ fprintf(fp, "\t");
+ fprintf(fp, "hard %u", xpexp->hard);
+ fprintf(fp, "%s", _SL_);
+ }
+
+ if (oneline)
+ fprintf(fp, "\n");
+ fflush(fp);
+
+ return 0;
+}
+
+static int xfrm_policy_get_or_delete(int argc, char **argv, int delete,
+ void *res_nlbuf)
+{
+ struct rtnl_handle rth;
+ struct {
+ struct nlmsghdr n;
+ struct xfrm_userpolicy_id xpid;
+ char buf[RTA_BUF_SIZE];
+ } req;
+ char *dirp = NULL;
+ char *selp = NULL;
+ char *indexp = NULL;
+ char *ptypep = NULL;
+ char *sctxp = NULL;
+ struct xfrm_userpolicy_type upt;
+ struct xfrm_mark mark = {0, 0};
+ struct {
+ struct xfrm_user_sec_ctx sctx;
+ char str[CTX_BUF_SIZE];
+ } ctx;
+
+
+ memset(&req, 0, sizeof(req));
+ memset(&upt, 0, sizeof(upt));
+ memset(&ctx, 0, sizeof(ctx));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xpid));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = delete ? XFRM_MSG_DELPOLICY : XFRM_MSG_GETPOLICY;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "dir") == 0) {
+ if (dirp)
+ duparg("dir", *argv);
+ dirp = *argv;
+
+ NEXT_ARG();
+ xfrm_policy_dir_parse(&req.xpid.dir, &argc, &argv);
+
+ } else if (strcmp(*argv, "ctx") == 0) {
+ char *context;
+
+ if (sctxp)
+ duparg("ctx", *argv);
+ sctxp = *argv;
+ NEXT_ARG();
+ context = *argv;
+ xfrm_sctx_parse((char *)&ctx.str, context, &ctx.sctx);
+ } else if (strcmp(*argv, "mark") == 0) {
+ xfrm_parse_mark(&mark, &argc, &argv);
+ } else if (strcmp(*argv, "index") == 0) {
+ if (indexp)
+ duparg("index", *argv);
+ indexp = *argv;
+
+ NEXT_ARG();
+ if (get_u32(&req.xpid.index, *argv, 0))
+ invarg("\"INDEX\" is invalid", *argv);
+
+ } else if (strcmp(*argv, "ptype") == 0) {
+ if (ptypep)
+ duparg("ptype", *argv);
+ ptypep = *argv;
+
+ NEXT_ARG();
+ xfrm_policy_ptype_parse(&upt.type, &argc, &argv);
+
+ } else {
+ if (selp)
+ invarg("unknown", *argv);
+ selp = *argv;
+
+ xfrm_selector_parse(&req.xpid.sel, &argc, &argv);
+ if (preferred_family == AF_UNSPEC)
+ preferred_family = req.xpid.sel.family;
+
+ }
+
+ argc--; argv++;
+ }
+
+ if (!dirp) {
+ fprintf(stderr, "Not enough information: \"DIR\" is required.\n");
+ exit(1);
+ }
+ if (ptypep) {
+ addattr_l(&req.n, sizeof(req), XFRMA_POLICY_TYPE,
+ (void *)&upt, sizeof(upt));
+ }
+ if (!selp && !indexp) {
+ fprintf(stderr, "Not enough information: either \"SELECTOR\" or \"INDEX\" is required.\n");
+ exit(1);
+ }
+ if (selp && indexp)
+ duparg2("SELECTOR", "INDEX");
+
+ if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
+ exit(1);
+
+ if (req.xpid.sel.family == AF_UNSPEC)
+ req.xpid.sel.family = AF_INET;
+
+ if (mark.m & mark.v) {
+ int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK,
+ (void *)&mark, sizeof(mark));
+ if (r < 0) {
+ fprintf(stderr, "%s: XFRMA_MARK failed\n",__func__);
+ exit(1);
+ }
+ }
+
+ if (sctxp) {
+ addattr_l(&req.n, sizeof(req), XFRMA_SEC_CTX,
+ (void *)&ctx, ctx.sctx.len);
+ }
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, res_nlbuf) < 0)
+ exit(2);
+
+ rtnl_close(&rth);
+
+ return 0;
+}
+
+static int xfrm_policy_delete(int argc, char **argv)
+{
+ return xfrm_policy_get_or_delete(argc, argv, 1, NULL);
+}
+
+static int xfrm_policy_get(int argc, char **argv)
+{
+ char buf[NLMSG_BUF_SIZE];
+ struct nlmsghdr *n = (struct nlmsghdr *)buf;
+
+ memset(buf, 0, sizeof(buf));
+
+ xfrm_policy_get_or_delete(argc, argv, 0, n);
+
+ if (xfrm_policy_print(NULL, n, (void*)stdout) < 0) {
+ fprintf(stderr, "An error :-)\n");
+ exit(1);
+ }
+
+ return 0;
+}
+
+/*
+ * With an existing policy of nlmsg, make new nlmsg for deleting the policy
+ * and store it to buffer.
+ */
+static int xfrm_policy_keep(const struct sockaddr_nl *who,
+ struct nlmsghdr *n,
+ void *arg)
+{
+ struct xfrm_buffer *xb = (struct xfrm_buffer *)arg;
+ struct rtnl_handle *rth = xb->rth;
+ struct xfrm_userpolicy_info *xpinfo = NLMSG_DATA(n);
+ int len = n->nlmsg_len;
+ struct rtattr *tb[XFRMA_MAX+1];
+ __u8 ptype = XFRM_POLICY_TYPE_MAIN;
+ struct nlmsghdr *new_n;
+ struct xfrm_userpolicy_id *xpid;
+
+ if (n->nlmsg_type != XFRM_MSG_NEWPOLICY) {
+ fprintf(stderr, "Not a policy: %08x %08x %08x\n",
+ n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
+ return 0;
+ }
+
+ len -= NLMSG_LENGTH(sizeof(*xpinfo));
+ if (len < 0) {
+ fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+ return -1;
+ }
+
+ parse_rtattr(tb, XFRMA_MAX, XFRMP_RTA(xpinfo), len);
+
+ if (tb[XFRMA_POLICY_TYPE]) {
+ struct xfrm_userpolicy_type *upt;
+
+ if (RTA_PAYLOAD(tb[XFRMA_POLICY_TYPE]) < sizeof(*upt)) {
+ fprintf(stderr, "too short XFRMA_POLICY_TYPE len\n");
+ return -1;
+ }
+ upt = (struct xfrm_userpolicy_type *)RTA_DATA(tb[XFRMA_POLICY_TYPE]);
+ ptype = upt->type;
+ }
+
+ if (!xfrm_policy_filter_match(xpinfo, ptype))
+ return 0;
+
+ if (xb->offset > xb->size) {
+ fprintf(stderr, "Policy buffer overflow\n");
+ return -1;
+ }
+
+ new_n = (struct nlmsghdr *)(xb->buf + xb->offset);
+ new_n->nlmsg_len = NLMSG_LENGTH(sizeof(*xpid));
+ new_n->nlmsg_flags = NLM_F_REQUEST;
+ new_n->nlmsg_type = XFRM_MSG_DELPOLICY;
+ new_n->nlmsg_seq = ++rth->seq;
+
+ xpid = NLMSG_DATA(new_n);
+ memcpy(&xpid->sel, &xpinfo->sel, sizeof(xpid->sel));
+ xpid->dir = xpinfo->dir;
+ xpid->index = xpinfo->index;
+
+ xb->offset += new_n->nlmsg_len;
+ xb->nlmsg_count ++;
+
+ return 0;
+}
+
+static int xfrm_policy_list_or_deleteall(int argc, char **argv, int deleteall)
+{
+ char *selp = NULL;
+ struct rtnl_handle rth;
+
+ if (argc > 0)
+ filter.use = 1;
+ filter.xpinfo.sel.family = preferred_family;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "dir") == 0) {
+ NEXT_ARG();
+ xfrm_policy_dir_parse(&filter.xpinfo.dir, &argc, &argv);
+
+ filter.dir_mask = XFRM_FILTER_MASK_FULL;
+
+ } else if (strcmp(*argv, "index") == 0) {
+ NEXT_ARG();
+ if (get_u32(&filter.xpinfo.index, *argv, 0))
+ invarg("\"INDEX\" is invalid", *argv);
+
+ filter.index_mask = XFRM_FILTER_MASK_FULL;
+
+ } else if (strcmp(*argv, "ptype") == 0) {
+ NEXT_ARG();
+ xfrm_policy_ptype_parse(&filter.ptype, &argc, &argv);
+
+ filter.ptype_mask = XFRM_FILTER_MASK_FULL;
+
+ } else if (strcmp(*argv, "action") == 0) {
+ NEXT_ARG();
+ if (strcmp(*argv, "allow") == 0)
+ filter.xpinfo.action = XFRM_POLICY_ALLOW;
+ else if (strcmp(*argv, "block") == 0)
+ filter.xpinfo.action = XFRM_POLICY_BLOCK;
+ else
+ invarg("\"ACTION\" is invalid\n", *argv);
+
+ filter.action_mask = XFRM_FILTER_MASK_FULL;
+
+ } else if (strcmp(*argv, "priority") == 0) {
+ NEXT_ARG();
+ if (get_u32(&filter.xpinfo.priority, *argv, 0))
+ invarg("\"PRIORITY\" is invalid", *argv);
+
+ filter.priority_mask = XFRM_FILTER_MASK_FULL;
+
+ } else if (strcmp(*argv, "flag") == 0) {
+ NEXT_ARG();
+ xfrm_policy_flag_parse(&filter.xpinfo.flags, &argc,
+ &argv);
+
+ filter.policy_flags_mask = XFRM_FILTER_MASK_FULL;
+
+ } else {
+ if (selp)
+ invarg("unknown", *argv);
+ selp = *argv;
+
+ xfrm_selector_parse(&filter.xpinfo.sel, &argc, &argv);
+ if (preferred_family == AF_UNSPEC)
+ preferred_family = filter.xpinfo.sel.family;
+
+ }
+
+ argc--; argv++;
+ }
+
+ if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
+ exit(1);
+
+ if (deleteall) {
+ struct xfrm_buffer xb;
+ char buf[NLMSG_DELETEALL_BUF_SIZE];
+ int i;
+
+ xb.buf = buf;
+ xb.size = sizeof(buf);
+ xb.rth = &rth;
+
+ for (i = 0; ; i++) {
+ xb.offset = 0;
+ xb.nlmsg_count = 0;
+
+ if (show_stats > 1)
+ fprintf(stderr, "Delete-all round = %d\n", i);
+
+ if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETPOLICY) < 0) {
+ perror("Cannot send dump request");
+ exit(1);
+ }
+
+ if (rtnl_dump_filter(&rth, xfrm_policy_keep, &xb) < 0) {
+ fprintf(stderr, "Delete-all terminated\n");
+ exit(1);
+ }
+ if (xb.nlmsg_count == 0) {
+ if (show_stats > 1)
+ fprintf(stderr, "Delete-all completed\n");
+ break;
+ }
+
+ if (rtnl_send_check(&rth, xb.buf, xb.offset) < 0) {
+ perror("Failed to send delete-all request");
+ exit(1);
+ }
+ if (show_stats > 1)
+ fprintf(stderr, "Delete-all nlmsg count = %d\n", xb.nlmsg_count);
+
+ xb.offset = 0;
+ xb.nlmsg_count = 0;
+ }
+ } else {
+ if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETPOLICY) < 0) {
+ perror("Cannot send dump request");
+ exit(1);
+ }
+
+ if (rtnl_dump_filter(&rth, xfrm_policy_print, stdout) < 0) {
+ fprintf(stderr, "Dump terminated\n");
+ exit(1);
+ }
+ }
+
+ rtnl_close(&rth);
+
+ exit(0);
+}
+
+int print_spdinfo( struct nlmsghdr *n, void *arg)
+{
+ FILE *fp = (FILE*)arg;
+ __u32 *f = NLMSG_DATA(n);
+ struct rtattr * tb[XFRMA_SPD_MAX+1];
+ struct rtattr * rta;
+
+ int len = n->nlmsg_len;
+
+ len -= NLMSG_LENGTH(sizeof(__u32));
+ if (len < 0) {
+ fprintf(stderr, "SPDinfo: Wrong len %d\n", len);
+ return -1;
+ }
+
+ rta = XFRMSAPD_RTA(f);
+ parse_rtattr(tb, XFRMA_SPD_MAX, rta, len);
+
+ fprintf(fp,"\t SPD");
+ if (tb[XFRMA_SPD_INFO]) {
+ struct xfrmu_spdinfo *si;
+
+ if (RTA_PAYLOAD(tb[XFRMA_SPD_INFO]) < sizeof(*si)) {
+ fprintf(stderr, "SPDinfo: Wrong len %d\n", len);
+ return -1;
+ }
+ si = RTA_DATA(tb[XFRMA_SPD_INFO]);
+ fprintf(fp," IN %d", si->incnt);
+ fprintf(fp," OUT %d", si->outcnt);
+ fprintf(fp," FWD %d", si->fwdcnt);
+
+ if (show_stats) {
+ fprintf(fp," (Sock:");
+ fprintf(fp," IN %d", si->inscnt);
+ fprintf(fp," OUT %d", si->outscnt);
+ fprintf(fp," FWD %d", si->fwdscnt);
+ fprintf(fp,")");
+ }
+
+ fprintf(fp,"\n");
+ }
+ if (show_stats > 1) {
+ struct xfrmu_spdhinfo *sh;
+
+ if (tb[XFRMA_SPD_HINFO]) {
+ if (RTA_PAYLOAD(tb[XFRMA_SPD_HINFO]) < sizeof(*sh)) {
+ fprintf(stderr, "SPDinfo: Wrong len %d\n", len);
+ return -1;
+ }
+ sh = RTA_DATA(tb[XFRMA_SPD_HINFO]);
+ fprintf(fp,"\t SPD buckets:");
+ fprintf(fp," count %d", sh->spdhcnt);
+ fprintf(fp," Max %d", sh->spdhmcnt);
+ }
+ }
+ fprintf(fp,"\n");
+
+ return 0;
+}
+
+static int xfrm_spd_getinfo(int argc, char **argv)
+{
+ struct rtnl_handle rth;
+ struct {
+ struct nlmsghdr n;
+ __u32 flags;
+ char ans[128];
+ } req;
+
+ memset(&req, 0, sizeof(req));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(__u32));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = XFRM_MSG_GETSPDINFO;
+ req.flags = 0XFFFFFFFF;
+
+ if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
+ exit(1);
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0)
+ exit(2);
+
+ print_spdinfo(&req.n, (void*)stdout);
+
+ rtnl_close(&rth);
+
+ return 0;
+}
+
+static int xfrm_policy_flush(int argc, char **argv)
+{
+ struct rtnl_handle rth;
+ struct {
+ struct nlmsghdr n;
+ char buf[RTA_BUF_SIZE];
+ } req;
+ char *ptypep = NULL;
+ struct xfrm_userpolicy_type upt;
+
+ memset(&req, 0, sizeof(req));
+ memset(&upt, 0, sizeof(upt));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(0); /* nlmsg data is nothing */
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = XFRM_MSG_FLUSHPOLICY;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "ptype") == 0) {
+ if (ptypep)
+ duparg("ptype", *argv);
+ ptypep = *argv;
+
+ NEXT_ARG();
+ xfrm_policy_ptype_parse(&upt.type, &argc, &argv);
+ } else
+ invarg("unknown", *argv);
+
+ argc--; argv++;
+ }
+
+ if (ptypep) {
+ addattr_l(&req.n, sizeof(req), XFRMA_POLICY_TYPE,
+ (void *)&upt, sizeof(upt));
+ }
+
+ if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
+ exit(1);
+
+ if (show_stats > 1)
+ fprintf(stderr, "Flush policy\n");
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ exit(2);
+
+ rtnl_close(&rth);
+
+ return 0;
+}
+
+int do_xfrm_policy(int argc, char **argv)
+{
+ if (argc < 1)
+ return xfrm_policy_list_or_deleteall(0, NULL, 0);
+
+ if (matches(*argv, "add") == 0)
+ return xfrm_policy_modify(XFRM_MSG_NEWPOLICY, 0,
+ argc-1, argv+1);
+ if (matches(*argv, "update") == 0)
+ return xfrm_policy_modify(XFRM_MSG_UPDPOLICY, 0,
+ argc-1, argv+1);
+ if (matches(*argv, "delete") == 0)
+ return xfrm_policy_delete(argc-1, argv+1);
+ if (matches(*argv, "deleteall") == 0 || matches(*argv, "delall") == 0)
+ return xfrm_policy_list_or_deleteall(argc-1, argv+1, 1);
+ if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
+ || matches(*argv, "lst") == 0)
+ return xfrm_policy_list_or_deleteall(argc-1, argv+1, 0);
+ if (matches(*argv, "get") == 0)
+ return xfrm_policy_get(argc-1, argv+1);
+ if (matches(*argv, "flush") == 0)
+ return xfrm_policy_flush(argc-1, argv+1);
+ if (matches(*argv, "count") == 0)
+ return xfrm_spd_getinfo(argc, argv);
+ if (matches(*argv, "help") == 0)
+ usage();
+ fprintf(stderr, "Command \"%s\" is unknown, try \"ip xfrm policy help\".\n", *argv);
+ exit(-1);
+}
diff --git a/ap/app/iproute2/iproute2-3.4.0/ip/xfrm_state.c b/ap/app/iproute2/iproute2-3.4.0/ip/xfrm_state.c
new file mode 100755
index 0000000..0d98e78
--- /dev/null
+++ b/ap/app/iproute2/iproute2-3.4.0/ip/xfrm_state.c
@@ -0,0 +1,1216 @@
+/* $USAGI: $ */
+
+/*
+ * Copyright (C)2004 USAGI/WIDE Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*
+ * based on iproute.c
+ */
+/*
+ * Authors:
+ * Masahide NAKAMURA @USAGI
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <linux/xfrm.h>
+#include "utils.h"
+#include "xfrm.h"
+#include "ip_common.h"
+
+//#define NLMSG_DELETEALL_BUF_SIZE (4096-512)
+#define NLMSG_DELETEALL_BUF_SIZE 8192
+
+/*
+ * Receiving buffer defines:
+ * nlmsg
+ * data = struct xfrm_usersa_info
+ * rtattr
+ * rtattr
+ * ... (max count of rtattr is XFRM_MAX+1
+ *
+ * each rtattr data = struct xfrm_algo(dynamic size) or xfrm_address_t
+ */
+#define NLMSG_BUF_SIZE 4096
+#define RTA_BUF_SIZE 2048
+#define XFRM_ALGO_KEY_BUF_SIZE 512
+#define CTX_BUF_SIZE 256
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: ip xfrm state { add | update } ID [ ALGO-LIST ] [ mode MODE ]\n");
+ fprintf(stderr, " [ mark MARK [ mask MASK ] ] [ reqid REQID ] [ seq SEQ ]\n");
+ fprintf(stderr, " [ replay-window SIZE ] [ replay-seq SEQ ] [ replay-oseq SEQ ]\n");
+ fprintf(stderr, " [ flag FLAG-LIST ] [ sel SELECTOR ] [ LIMIT-LIST ] [ encap ENCAP ]\n");
+ fprintf(stderr, " [ coa ADDR[/PLEN] ] [ ctx CTX ]\n");
+ fprintf(stderr, "Usage: ip xfrm state allocspi ID [ mode MODE ] [ mark MARK [ mask MASK ] ]\n");
+ fprintf(stderr, " [ reqid REQID ] [ seq SEQ ] [ min SPI max SPI ]\n");
+ fprintf(stderr, "Usage: ip xfrm state { delete | get } ID [ mark MARK [ mask MASK ] ]\n");
+ fprintf(stderr, "Usage: ip xfrm state { deleteall | list } [ ID ] [ mode MODE ] [ reqid REQID ]\n");
+ fprintf(stderr, " [ flag FLAG-LIST ]\n");
+ fprintf(stderr, "Usage: ip xfrm state flush [ proto XFRM-PROTO ]\n");
+ fprintf(stderr, "Usage: ip xfrm state count\n");
+ fprintf(stderr, "ID := [ src ADDR ] [ dst ADDR ] [ proto XFRM-PROTO ] [ spi SPI ]\n");
+ fprintf(stderr, "XFRM-PROTO := ");
+ fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ESP));
+ fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_AH));
+ fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_COMP));
+ fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ROUTING));
+ fprintf(stderr, "%s\n", strxf_xfrmproto(IPPROTO_DSTOPTS));
+ fprintf(stderr, "ALGO-LIST := [ ALGO-LIST ] ALGO\n");
+ fprintf(stderr, "ALGO := { ");
+ fprintf(stderr, "%s | ", strxf_algotype(XFRMA_ALG_CRYPT));
+ fprintf(stderr, "%s | ", strxf_algotype(XFRMA_ALG_AUTH));
+ fprintf(stderr, "%s", strxf_algotype(XFRMA_ALG_COMP));
+ fprintf(stderr, " } ALGO-NAME ALGO-KEY |\n");
+ fprintf(stderr, " %s", strxf_algotype(XFRMA_ALG_AEAD));
+ fprintf(stderr, " ALGO-NAME ALGO-KEY ALGO-ICV-LEN |\n");
+ fprintf(stderr, " %s", strxf_algotype(XFRMA_ALG_AUTH_TRUNC));
+ fprintf(stderr, " ALGO-NAME ALGO-KEY ALGO-TRUNC-LEN\n");
+ fprintf(stderr, "MODE := transport | tunnel | ro | in_trigger | beet\n");
+ fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n");
+ fprintf(stderr, "FLAG := noecn | decap-dscp | nopmtudisc | wildrecv | icmp | af-unspec | align4\n");
+ fprintf(stderr, "SELECTOR := [ src ADDR[/PLEN] ] [ dst ADDR[/PLEN] ] [ dev DEV ] [ UPSPEC ]\n");
+ fprintf(stderr, "UPSPEC := proto { { ");
+ fprintf(stderr, "%s | ", strxf_proto(IPPROTO_TCP));
+ fprintf(stderr, "%s | ", strxf_proto(IPPROTO_UDP));
+ fprintf(stderr, "%s | ", strxf_proto(IPPROTO_SCTP));
+ fprintf(stderr, "%s", strxf_proto(IPPROTO_DCCP));
+ fprintf(stderr, " } [ sport PORT ] [ dport PORT ] |\n");
+ fprintf(stderr, " { ");
+ fprintf(stderr, "%s | ", strxf_proto(IPPROTO_ICMP));
+ fprintf(stderr, "%s | ", strxf_proto(IPPROTO_ICMPV6));
+ fprintf(stderr, "%s", strxf_proto(IPPROTO_MH));
+ fprintf(stderr, " } [ type NUMBER ] [ code NUMBER ] |\n");
+ fprintf(stderr, " %s", strxf_proto(IPPROTO_GRE));
+ fprintf(stderr, " [ key { DOTTED-QUAD | NUMBER } ] | PROTO }\n");
+ fprintf(stderr, "LIMIT-LIST := [ LIMIT-LIST ] limit LIMIT\n");
+ fprintf(stderr, "LIMIT := { time-soft | time-hard | time-use-soft | time-use-hard } SECONDS |\n");
+ fprintf(stderr, " { byte-soft | byte-hard } SIZE | { packet-soft | packet-hard } COUNT\n");
+ fprintf(stderr, "ENCAP := { espinudp | espinudp-nonike } SPORT DPORT OADDR\n");
+
+ exit(-1);
+}
+
+static int xfrm_algo_parse(struct xfrm_algo *alg, enum xfrm_attr_type_t type,
+ char *name, char *key, char *buf, int max)
+{
+ int len;
+ int slen = strlen(key);
+
+#if 0
+ /* XXX: verifying both name and key is required! */
+ fprintf(stderr, "warning: ALGO-NAME/ALGO-KEY will send to kernel promiscuously! (verifying them isn't implemented yet)\n");
+#endif
+
+ strncpy(alg->alg_name, name, sizeof(alg->alg_name));
+
+ if (slen > 2 && strncmp(key, "0x", 2) == 0) {
+ /* split two chars "0x" from the top */
+ char *p = key + 2;
+ int plen = slen - 2;
+ int i;
+ int j;
+
+ /* Converting hexadecimal numbered string into real key;
+ * Convert each two chars into one char(value). If number
+ * of the length is odd, add zero on the top for rounding.
+ */
+
+ /* calculate length of the converted values(real key) */
+ len = (plen + 1) / 2;
+ if (len > max)
+ invarg("\"ALGO-KEY\" makes buffer overflow\n", key);
+
+ for (i = - (plen % 2), j = 0; j < len; i += 2, j++) {
+ char vbuf[3];
+ __u8 val;
+
+ vbuf[0] = i >= 0 ? p[i] : '0';
+ vbuf[1] = p[i + 1];
+ vbuf[2] = '\0';
+
+ if (get_u8(&val, vbuf, 16))
+ invarg("\"ALGO-KEY\" is invalid", key);
+
+ buf[j] = val;
+ }
+ } else {
+ len = slen;
+ if (len > 0) {
+ if (len > max)
+ invarg("\"ALGO-KEY\" makes buffer overflow\n", key);
+
+ strncpy(buf, key, len);
+ }
+ }
+
+ alg->alg_key_len = len * 8;
+
+ return 0;
+}
+
+static int xfrm_seq_parse(__u32 *seq, int *argcp, char ***argvp)
+{
+ int argc = *argcp;
+ char **argv = *argvp;
+
+ if (get_u32(seq, *argv, 0))
+ invarg("\"SEQ\" is invalid", *argv);
+
+ *seq = htonl(*seq);
+
+ *argcp = argc;
+ *argvp = argv;
+
+ return 0;
+}
+
+static int xfrm_state_flag_parse(__u8 *flags, int *argcp, char ***argvp)
+{
+ int argc = *argcp;
+ char **argv = *argvp;
+ int len = strlen(*argv);
+
+ if (len > 2 && strncmp(*argv, "0x", 2) == 0) {
+ __u8 val = 0;
+
+ if (get_u8(&val, *argv, 16))
+ invarg("\"FLAG\" is invalid", *argv);
+ *flags = val;
+ } else {
+ while (1) {
+ if (strcmp(*argv, "noecn") == 0)
+ *flags |= XFRM_STATE_NOECN;
+ else if (strcmp(*argv, "decap-dscp") == 0)
+ *flags |= XFRM_STATE_DECAP_DSCP;
+ else if (strcmp(*argv, "nopmtudisc") == 0)
+ *flags |= XFRM_STATE_NOPMTUDISC;
+ else if (strcmp(*argv, "wildrecv") == 0)
+ *flags |= XFRM_STATE_WILDRECV;
+ else if (strcmp(*argv, "icmp") == 0)
+ *flags |= XFRM_STATE_ICMP;
+ else if (strcmp(*argv, "af-unspec") == 0)
+ *flags |= XFRM_STATE_AF_UNSPEC;
+ else if (strcmp(*argv, "align4") == 0)
+ *flags |= XFRM_STATE_ALIGN4;
+ else {
+ PREV_ARG(); /* back track */
+ break;
+ }
+
+ if (!NEXT_ARG_OK())
+ break;
+ NEXT_ARG();
+ }
+ }
+
+ *argcp = argc;
+ *argvp = argv;
+
+ return 0;
+}
+
+static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
+{
+ struct rtnl_handle rth;
+ struct {
+ struct nlmsghdr n;
+ struct xfrm_usersa_info xsinfo;
+ char buf[RTA_BUF_SIZE];
+ } req;
+ struct xfrm_replay_state replay;
+ char *idp = NULL;
+ char *aeadop = NULL;
+ char *ealgop = NULL;
+ char *aalgop = NULL;
+ char *calgop = NULL;
+ char *coap = NULL;
+ char *sctxp = NULL;
+ struct xfrm_mark mark = {0, 0};
+ struct {
+ struct xfrm_user_sec_ctx sctx;
+ char str[CTX_BUF_SIZE];
+ } ctx;
+
+ memset(&req, 0, sizeof(req));
+ memset(&replay, 0, sizeof(replay));
+ memset(&ctx, 0, sizeof(ctx));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsinfo));
+ req.n.nlmsg_flags = NLM_F_REQUEST|flags;
+ req.n.nlmsg_type = cmd;
+ req.xsinfo.family = preferred_family;
+
+ req.xsinfo.lft.soft_byte_limit = XFRM_INF;
+ req.xsinfo.lft.hard_byte_limit = XFRM_INF;
+ req.xsinfo.lft.soft_packet_limit = XFRM_INF;
+ req.xsinfo.lft.hard_packet_limit = XFRM_INF;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "mode") == 0) {
+ NEXT_ARG();
+ xfrm_mode_parse(&req.xsinfo.mode, &argc, &argv);
+ } else if (strcmp(*argv, "mark") == 0) {
+ xfrm_parse_mark(&mark, &argc, &argv);
+ } else if (strcmp(*argv, "reqid") == 0) {
+ NEXT_ARG();
+ xfrm_reqid_parse(&req.xsinfo.reqid, &argc, &argv);
+ } else if (strcmp(*argv, "seq") == 0) {
+ NEXT_ARG();
+ xfrm_seq_parse(&req.xsinfo.seq, &argc, &argv);
+ } else if (strcmp(*argv, "replay-window") == 0) {
+ NEXT_ARG();
+ if (get_u8(&req.xsinfo.replay_window, *argv, 0))
+ invarg("\"replay-window\" value is invalid", *argv);
+ } else if (strcmp(*argv, "replay-seq") == 0) {
+ NEXT_ARG();
+ if (get_u32(&replay.seq, *argv, 0))
+ invarg("\"replay-seq\" value is invalid", *argv);
+ } else if (strcmp(*argv, "replay-oseq") == 0) {
+ NEXT_ARG();
+ if (get_u32(&replay.oseq, *argv, 0))
+ invarg("\"replay-oseq\" value is invalid", *argv);
+ } else if (strcmp(*argv, "flag") == 0) {
+ NEXT_ARG();
+ xfrm_state_flag_parse(&req.xsinfo.flags, &argc, &argv);
+ } else if (strcmp(*argv, "sel") == 0) {
+ NEXT_ARG();
+ xfrm_selector_parse(&req.xsinfo.sel, &argc, &argv);
+ } else if (strcmp(*argv, "limit") == 0) {
+ NEXT_ARG();
+ xfrm_lifetime_cfg_parse(&req.xsinfo.lft, &argc, &argv);
+ } else if (strcmp(*argv, "encap") == 0) {
+ struct xfrm_encap_tmpl encap;
+ inet_prefix oa;
+ NEXT_ARG();
+ xfrm_encap_type_parse(&encap.encap_type, &argc, &argv);
+ NEXT_ARG();
+ if (get_u16(&encap.encap_sport, *argv, 0))
+ invarg("\"encap\" sport value is invalid", *argv);
+ encap.encap_sport = htons(encap.encap_sport);
+ NEXT_ARG();
+ if (get_u16(&encap.encap_dport, *argv, 0))
+ invarg("\"encap\" dport value is invalid", *argv);
+ encap.encap_dport = htons(encap.encap_dport);
+ NEXT_ARG();
+ get_addr(&oa, *argv, AF_UNSPEC);
+ memcpy(&encap.encap_oa, &oa.data, sizeof(encap.encap_oa));
+ addattr_l(&req.n, sizeof(req.buf), XFRMA_ENCAP,
+ (void *)&encap, sizeof(encap));
+ } else if (strcmp(*argv, "coa") == 0) {
+ inet_prefix coa;
+ xfrm_address_t xcoa;
+
+ if (coap)
+ duparg("coa", *argv);
+ coap = *argv;
+
+ NEXT_ARG();
+
+ get_prefix(&coa, *argv, preferred_family);
+ if (coa.family == AF_UNSPEC)
+ invarg("\"coa\" address family is AF_UNSPEC", *argv);
+ if (coa.bytelen > sizeof(xcoa))
+ invarg("\"coa\" address length is too large", *argv);
+
+ memset(&xcoa, 0, sizeof(xcoa));
+ memcpy(&xcoa, &coa.data, coa.bytelen);
+
+ addattr_l(&req.n, sizeof(req.buf), XFRMA_COADDR,
+ (void *)&xcoa, sizeof(xcoa));
+ } else if (strcmp(*argv, "ctx") == 0) {
+ char *context;
+
+ if (sctxp)
+ duparg("ctx", *argv);
+ sctxp = *argv;
+
+ NEXT_ARG();
+ context = *argv;
+
+ xfrm_sctx_parse((char *)&ctx.str, context, &ctx.sctx);
+ addattr_l(&req.n, sizeof(req.buf), XFRMA_SEC_CTX,
+ (void *)&ctx, ctx.sctx.len);
+ } else {
+ /* try to assume ALGO */
+ int type = xfrm_algotype_getbyname(*argv);
+ switch (type) {
+ case XFRMA_ALG_AEAD:
+ case XFRMA_ALG_CRYPT:
+ case XFRMA_ALG_AUTH:
+ case XFRMA_ALG_AUTH_TRUNC:
+ case XFRMA_ALG_COMP:
+ {
+ /* ALGO */
+ struct {
+ union {
+ struct xfrm_algo alg;
+ struct xfrm_algo_aead aead;
+ struct xfrm_algo_auth auth;
+ } u;
+ char buf[XFRM_ALGO_KEY_BUF_SIZE];
+ } alg = {};
+ int len;
+ __u32 icvlen, trunclen;
+ char *name;
+ char *key;
+ char *buf;
+
+ switch (type) {
+ case XFRMA_ALG_AEAD:
+ if (aeadop)
+ duparg("ALGO-TYPE", *argv);
+ aeadop = *argv;
+ break;
+ case XFRMA_ALG_CRYPT:
+ if (ealgop)
+ duparg("ALGO-TYPE", *argv);
+ ealgop = *argv;
+ break;
+ case XFRMA_ALG_AUTH:
+ case XFRMA_ALG_AUTH_TRUNC:
+ if (aalgop)
+ duparg("ALGO-TYPE", *argv);
+ aalgop = *argv;
+ break;
+ case XFRMA_ALG_COMP:
+ if (calgop)
+ duparg("ALGO-TYPE", *argv);
+ calgop = *argv;
+ break;
+ default:
+ /* not reached */
+ invarg("\"ALGO-TYPE\" is invalid\n", *argv);
+ }
+
+ if (!NEXT_ARG_OK())
+ missarg("ALGO-NAME");
+ NEXT_ARG();
+ name = *argv;
+
+ if (!NEXT_ARG_OK())
+ missarg("ALGO-KEY");
+ NEXT_ARG();
+ key = *argv;
+
+ buf = alg.u.alg.alg_key;
+ len = sizeof(alg.u.alg);
+
+ switch (type) {
+ case XFRMA_ALG_AEAD:
+ if (!NEXT_ARG_OK())
+ missarg("ALGO-ICV-LEN");
+ NEXT_ARG();
+ if (get_u32(&icvlen, *argv, 0))
+ invarg("\"aead\" ICV length is invalid",
+ *argv);
+ alg.u.aead.alg_icv_len = icvlen;
+
+ buf = alg.u.aead.alg_key;
+ len = sizeof(alg.u.aead);
+ break;
+ case XFRMA_ALG_AUTH_TRUNC:
+ if (!NEXT_ARG_OK())
+ missarg("ALGO-TRUNC-LEN");
+ NEXT_ARG();
+ if (get_u32(&trunclen, *argv, 0))
+ invarg("\"auth\" trunc length is invalid",
+ *argv);
+ alg.u.auth.alg_trunc_len = trunclen;
+
+ buf = alg.u.auth.alg_key;
+ len = sizeof(alg.u.auth);
+ break;
+ }
+
+ xfrm_algo_parse((void *)&alg, type, name, key,
+ buf, sizeof(alg.buf));
+ len += alg.u.alg.alg_key_len;
+
+ addattr_l(&req.n, sizeof(req.buf), type,
+ (void *)&alg, len);
+ break;
+ }
+ default:
+ /* try to assume ID */
+ if (idp)
+ invarg("unknown", *argv);
+ idp = *argv;
+
+ /* ID */
+ xfrm_id_parse(&req.xsinfo.saddr, &req.xsinfo.id,
+ &req.xsinfo.family, 0, &argc, &argv);
+ if (preferred_family == AF_UNSPEC)
+ preferred_family = req.xsinfo.family;
+ }
+ }
+ argc--; argv++;
+ }
+
+ if (replay.seq || replay.oseq)
+ addattr_l(&req.n, sizeof(req.buf), XFRMA_REPLAY_VAL,
+ (void *)&replay, sizeof(replay));
+
+ if (!idp) {
+ fprintf(stderr, "Not enough information: \"ID\" is required\n");
+ exit(1);
+ }
+
+ if (mark.m & mark.v) {
+ int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK,
+ (void *)&mark, sizeof(mark));
+ if (r < 0) {
+ fprintf(stderr, "XFRMA_MARK failed\n");
+ exit(1);
+ }
+ }
+
+ switch (req.xsinfo.mode) {
+ case XFRM_MODE_TRANSPORT:
+ case XFRM_MODE_TUNNEL:
+ if (!xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) {
+ fprintf(stderr, "\"mode\" is invalid with proto=%s\n",
+ strxf_xfrmproto(req.xsinfo.id.proto));
+ exit(1);
+ }
+ break;
+ case XFRM_MODE_ROUTEOPTIMIZATION:
+ case XFRM_MODE_IN_TRIGGER:
+ if (!xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) {
+ fprintf(stderr, "\"mode\" is invalid with proto=%s\n",
+ strxf_xfrmproto(req.xsinfo.id.proto));
+ exit(1);
+ }
+ if (req.xsinfo.id.spi != 0) {
+ fprintf(stderr, "\"spi\" must be 0 with proto=%s\n",
+ strxf_xfrmproto(req.xsinfo.id.proto));
+ exit(1);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (aeadop || ealgop || aalgop || calgop) {
+ if (!xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) {
+ fprintf(stderr, "\"ALGO\" is invalid with proto=%s\n",
+ strxf_xfrmproto(req.xsinfo.id.proto));
+ exit(1);
+ }
+ } else {
+ if (xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) {
+ fprintf(stderr, "\"ALGO\" is required with proto=%s\n",
+ strxf_xfrmproto(req.xsinfo.id.proto));
+ exit (1);
+ }
+ }
+
+ if (coap) {
+ if (!xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) {
+ fprintf(stderr, "\"coa\" is invalid with proto=%s\n",
+ strxf_xfrmproto(req.xsinfo.id.proto));
+ exit(1);
+ }
+ } else {
+ if (xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) {
+ fprintf(stderr, "\"coa\" is required with proto=%s\n",
+ strxf_xfrmproto(req.xsinfo.id.proto));
+ exit (1);
+ }
+ }
+
+ if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
+ exit(1);
+
+ if (req.xsinfo.family == AF_UNSPEC)
+ req.xsinfo.family = AF_INET;
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ exit(2);
+
+ rtnl_close(&rth);
+
+ return 0;
+}
+
+static int xfrm_state_allocspi(int argc, char **argv)
+{
+ struct rtnl_handle rth;
+ struct {
+ struct nlmsghdr n;
+ struct xfrm_userspi_info xspi;
+ char buf[RTA_BUF_SIZE];
+ } req;
+ char *idp = NULL;
+ char *minp = NULL;
+ char *maxp = NULL;
+ struct xfrm_mark mark = {0, 0};
+ char res_buf[NLMSG_BUF_SIZE];
+ struct nlmsghdr *res_n = (struct nlmsghdr *)res_buf;
+
+ memset(res_buf, 0, sizeof(res_buf));
+
+ memset(&req, 0, sizeof(req));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xspi));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = XFRM_MSG_ALLOCSPI;
+ req.xspi.info.family = preferred_family;
+
+#if 0
+ req.xsinfo.lft.soft_byte_limit = XFRM_INF;
+ req.xsinfo.lft.hard_byte_limit = XFRM_INF;
+ req.xsinfo.lft.soft_packet_limit = XFRM_INF;
+ req.xsinfo.lft.hard_packet_limit = XFRM_INF;
+#endif
+
+ while (argc > 0) {
+ if (strcmp(*argv, "mode") == 0) {
+ NEXT_ARG();
+ xfrm_mode_parse(&req.xspi.info.mode, &argc, &argv);
+ } else if (strcmp(*argv, "mark") == 0) {
+ xfrm_parse_mark(&mark, &argc, &argv);
+ } else if (strcmp(*argv, "reqid") == 0) {
+ NEXT_ARG();
+ xfrm_reqid_parse(&req.xspi.info.reqid, &argc, &argv);
+ } else if (strcmp(*argv, "seq") == 0) {
+ NEXT_ARG();
+ xfrm_seq_parse(&req.xspi.info.seq, &argc, &argv);
+ } else if (strcmp(*argv, "min") == 0) {
+ if (minp)
+ duparg("min", *argv);
+ minp = *argv;
+
+ NEXT_ARG();
+
+ if (get_u32(&req.xspi.min, *argv, 0))
+ invarg("\"min\" value is invalid", *argv);
+ } else if (strcmp(*argv, "max") == 0) {
+ if (maxp)
+ duparg("max", *argv);
+ maxp = *argv;
+
+ NEXT_ARG();
+
+ if (get_u32(&req.xspi.max, *argv, 0))
+ invarg("\"max\" value is invalid", *argv);
+ } else {
+ /* try to assume ID */
+ if (idp)
+ invarg("unknown", *argv);
+ idp = *argv;
+
+ /* ID */
+ xfrm_id_parse(&req.xspi.info.saddr, &req.xspi.info.id,
+ &req.xspi.info.family, 0, &argc, &argv);
+ if (req.xspi.info.id.spi) {
+ fprintf(stderr, "\"SPI\" must be zero\n");
+ exit(1);
+ }
+ if (preferred_family == AF_UNSPEC)
+ preferred_family = req.xspi.info.family;
+ }
+ argc--; argv++;
+ }
+
+ if (!idp) {
+ fprintf(stderr, "Not enough information: \"ID\" is required\n");
+ exit(1);
+ }
+
+ if (minp) {
+ if (!maxp) {
+ fprintf(stderr, "\"max\" is missing\n");
+ exit(1);
+ }
+ if (req.xspi.min > req.xspi.max) {
+ fprintf(stderr, "\"min\" value is larger than \"max\" value\n");
+ exit(1);
+ }
+ } else {
+ if (maxp) {
+ fprintf(stderr, "\"min\" is missing\n");
+ exit(1);
+ }
+
+ /* XXX: Default value defined in PF_KEY;
+ * See kernel's net/key/af_key.c(pfkey_getspi).
+ */
+ req.xspi.min = 0x100;
+ req.xspi.max = 0x0fffffff;
+
+ /* XXX: IPCOMP spi is 16-bits;
+ * See kernel's net/xfrm/xfrm_user(verify_userspi_info).
+ */
+ if (req.xspi.info.id.proto == IPPROTO_COMP)
+ req.xspi.max = 0xffff;
+ }
+
+ if (mark.m & mark.v) {
+ int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK,
+ (void *)&mark, sizeof(mark));
+ if (r < 0) {
+ fprintf(stderr, "XFRMA_MARK failed\n");
+ exit(1);
+ }
+ }
+
+ if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
+ exit(1);
+
+ if (req.xspi.info.family == AF_UNSPEC)
+ req.xspi.info.family = AF_INET;
+
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, res_n) < 0)
+ exit(2);
+
+ if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
+ fprintf(stderr, "An error :-)\n");
+ exit(1);
+ }
+
+ rtnl_close(&rth);
+
+ return 0;
+}
+
+static int xfrm_state_filter_match(struct xfrm_usersa_info *xsinfo)
+{
+ if (!filter.use)
+ return 1;
+
+ if (filter.id_src_mask)
+ if (xfrm_addr_match(&xsinfo->saddr, &filter.xsinfo.saddr,
+ filter.id_src_mask))
+ return 0;
+ if (filter.id_dst_mask)
+ if (xfrm_addr_match(&xsinfo->id.daddr, &filter.xsinfo.id.daddr,
+ filter.id_dst_mask))
+ return 0;
+ if ((xsinfo->id.proto^filter.xsinfo.id.proto)&filter.id_proto_mask)
+ return 0;
+ if ((xsinfo->id.spi^filter.xsinfo.id.spi)&filter.id_spi_mask)
+ return 0;
+ if ((xsinfo->mode^filter.xsinfo.mode)&filter.mode_mask)
+ return 0;
+ if ((xsinfo->reqid^filter.xsinfo.reqid)&filter.reqid_mask)
+ return 0;
+ if (filter.state_flags_mask)
+ if ((xsinfo->flags & filter.xsinfo.flags) == 0)
+ return 0;
+
+ return 1;
+}
+
+int xfrm_state_print(const struct sockaddr_nl *who, struct nlmsghdr *n,
+ void *arg)
+{
+ FILE *fp = (FILE*)arg;
+ struct rtattr * tb[XFRMA_MAX+1];
+ struct rtattr * rta;
+ struct xfrm_usersa_info *xsinfo = NULL;
+ struct xfrm_user_expire *xexp = NULL;
+ struct xfrm_usersa_id *xsid = NULL;
+ int len = n->nlmsg_len;
+
+ if (n->nlmsg_type != XFRM_MSG_NEWSA &&
+ n->nlmsg_type != XFRM_MSG_DELSA &&
+ n->nlmsg_type != XFRM_MSG_UPDSA &&
+ n->nlmsg_type != XFRM_MSG_EXPIRE) {
+ fprintf(stderr, "Not a state: %08x %08x %08x\n",
+ n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
+ return 0;
+ }
+
+ if (n->nlmsg_type == XFRM_MSG_DELSA) {
+ /* Dont blame me for this .. Herbert made me do it */
+ xsid = NLMSG_DATA(n);
+ len -= NLMSG_SPACE(sizeof(*xsid));
+ } else if (n->nlmsg_type == XFRM_MSG_EXPIRE) {
+ xexp = NLMSG_DATA(n);
+ xsinfo = &xexp->state;
+ len -= NLMSG_SPACE(sizeof(*xexp));
+ } else {
+ xexp = NULL;
+ xsinfo = NLMSG_DATA(n);
+ len -= NLMSG_SPACE(sizeof(*xsinfo));
+ }
+
+ if (len < 0) {
+ fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+ return -1;
+ }
+
+ if (xsinfo && !xfrm_state_filter_match(xsinfo))
+ return 0;
+
+ if (n->nlmsg_type == XFRM_MSG_DELSA)
+ fprintf(fp, "Deleted ");
+ else if (n->nlmsg_type == XFRM_MSG_UPDSA)
+ fprintf(fp, "Updated ");
+ else if (n->nlmsg_type == XFRM_MSG_EXPIRE)
+ fprintf(fp, "Expired ");
+
+ if (n->nlmsg_type == XFRM_MSG_DELSA)
+ rta = XFRMSID_RTA(xsid);
+ else if (n->nlmsg_type == XFRM_MSG_EXPIRE)
+ rta = XFRMEXP_RTA(xexp);
+ else
+ rta = XFRMS_RTA(xsinfo);
+
+ parse_rtattr(tb, XFRMA_MAX, rta, len);
+
+ if (n->nlmsg_type == XFRM_MSG_DELSA) {
+ //xfrm_policy_id_print();
+
+ if (!tb[XFRMA_SA]) {
+ fprintf(stderr, "Buggy XFRM_MSG_DELSA: no XFRMA_SA\n");
+ return -1;
+ }
+ if (RTA_PAYLOAD(tb[XFRMA_SA]) < sizeof(*xsinfo)) {
+ fprintf(stderr, "Buggy XFRM_MSG_DELPOLICY: too short XFRMA_POLICY len\n");
+ return -1;
+ }
+ xsinfo = RTA_DATA(tb[XFRMA_SA]);
+ }
+
+ xfrm_state_info_print(xsinfo, tb, fp, NULL, NULL);
+
+ if (n->nlmsg_type == XFRM_MSG_EXPIRE) {
+ fprintf(fp, "\t");
+ fprintf(fp, "hard %u", xexp->hard);
+ fprintf(fp, "%s", _SL_);
+ }
+
+ if (oneline)
+ fprintf(fp, "\n");
+ fflush(fp);
+
+ return 0;
+}
+
+static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
+{
+ struct rtnl_handle rth;
+ struct {
+ struct nlmsghdr n;
+ struct xfrm_usersa_id xsid;
+ char buf[RTA_BUF_SIZE];
+ } req;
+ struct xfrm_id id;
+ char *idp = NULL;
+ struct xfrm_mark mark = {0, 0};
+
+ memset(&req, 0, sizeof(req));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsid));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = delete ? XFRM_MSG_DELSA : XFRM_MSG_GETSA;
+ req.xsid.family = preferred_family;
+
+ while (argc > 0) {
+ xfrm_address_t saddr;
+
+ if (strcmp(*argv, "mark") == 0) {
+ xfrm_parse_mark(&mark, &argc, &argv);
+ } else {
+ if (idp)
+ invarg("unknown", *argv);
+ idp = *argv;
+
+ /* ID */
+ memset(&id, 0, sizeof(id));
+ memset(&saddr, 0, sizeof(saddr));
+ xfrm_id_parse(&saddr, &id, &req.xsid.family, 0,
+ &argc, &argv);
+
+ memcpy(&req.xsid.daddr, &id.daddr, sizeof(req.xsid.daddr));
+ req.xsid.spi = id.spi;
+ req.xsid.proto = id.proto;
+
+ addattr_l(&req.n, sizeof(req.buf), XFRMA_SRCADDR,
+ (void *)&saddr, sizeof(saddr));
+ }
+
+ argc--; argv++;
+ }
+
+ if (mark.m & mark.v) {
+ int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK,
+ (void *)&mark, sizeof(mark));
+ if (r < 0) {
+ fprintf(stderr, "XFRMA_MARK failed\n");
+ exit(1);
+ }
+ }
+
+ if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
+ exit(1);
+
+ if (req.xsid.family == AF_UNSPEC)
+ req.xsid.family = AF_INET;
+
+ if (delete) {
+ if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ exit(2);
+ } else {
+ char buf[NLMSG_BUF_SIZE];
+ struct nlmsghdr *res_n = (struct nlmsghdr *)buf;
+
+ memset(buf, 0, sizeof(buf));
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, res_n) < 0)
+ exit(2);
+
+ if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
+ fprintf(stderr, "An error :-)\n");
+ exit(1);
+ }
+ }
+
+ rtnl_close(&rth);
+
+ return 0;
+}
+
+/*
+ * With an existing state of nlmsg, make new nlmsg for deleting the state
+ * and store it to buffer.
+ */
+static int xfrm_state_keep(const struct sockaddr_nl *who,
+ struct nlmsghdr *n,
+ void *arg)
+{
+ struct xfrm_buffer *xb = (struct xfrm_buffer *)arg;
+ struct rtnl_handle *rth = xb->rth;
+ struct xfrm_usersa_info *xsinfo = NLMSG_DATA(n);
+ int len = n->nlmsg_len;
+ struct nlmsghdr *new_n;
+ struct xfrm_usersa_id *xsid;
+
+ if (n->nlmsg_type != XFRM_MSG_NEWSA) {
+ fprintf(stderr, "Not a state: %08x %08x %08x\n",
+ n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
+ return 0;
+ }
+
+ len -= NLMSG_LENGTH(sizeof(*xsinfo));
+ if (len < 0) {
+ fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+ return -1;
+ }
+
+ if (!xfrm_state_filter_match(xsinfo))
+ return 0;
+
+ if (xb->offset > xb->size) {
+ fprintf(stderr, "State buffer overflow\n");
+ return -1;
+ }
+
+ new_n = (struct nlmsghdr *)(xb->buf + xb->offset);
+ new_n->nlmsg_len = NLMSG_LENGTH(sizeof(*xsid));
+ new_n->nlmsg_flags = NLM_F_REQUEST;
+ new_n->nlmsg_type = XFRM_MSG_DELSA;
+ new_n->nlmsg_seq = ++rth->seq;
+
+ xsid = NLMSG_DATA(new_n);
+ xsid->family = xsinfo->family;
+ memcpy(&xsid->daddr, &xsinfo->id.daddr, sizeof(xsid->daddr));
+ xsid->spi = xsinfo->id.spi;
+ xsid->proto = xsinfo->id.proto;
+
+ addattr_l(new_n, xb->size, XFRMA_SRCADDR, &xsinfo->saddr,
+ sizeof(xsid->daddr));
+
+ xb->offset += new_n->nlmsg_len;
+ xb->nlmsg_count ++;
+
+ return 0;
+}
+
+static int xfrm_state_list_or_deleteall(int argc, char **argv, int deleteall)
+{
+ char *idp = NULL;
+ struct rtnl_handle rth;
+
+ if(argc > 0)
+ filter.use = 1;
+ filter.xsinfo.family = preferred_family;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "mode") == 0) {
+ NEXT_ARG();
+ xfrm_mode_parse(&filter.xsinfo.mode, &argc, &argv);
+
+ filter.mode_mask = XFRM_FILTER_MASK_FULL;
+
+ } else if (strcmp(*argv, "reqid") == 0) {
+ NEXT_ARG();
+ xfrm_reqid_parse(&filter.xsinfo.reqid, &argc, &argv);
+
+ filter.reqid_mask = XFRM_FILTER_MASK_FULL;
+
+ } else if (strcmp(*argv, "flag") == 0) {
+ NEXT_ARG();
+ xfrm_state_flag_parse(&filter.xsinfo.flags, &argc, &argv);
+
+ filter.state_flags_mask = XFRM_FILTER_MASK_FULL;
+
+ } else {
+ if (idp)
+ invarg("unknown", *argv);
+ idp = *argv;
+
+ /* ID */
+ xfrm_id_parse(&filter.xsinfo.saddr, &filter.xsinfo.id,
+ &filter.xsinfo.family, 1, &argc, &argv);
+ if (preferred_family == AF_UNSPEC)
+ preferred_family = filter.xsinfo.family;
+ }
+ argc--; argv++;
+ }
+
+ if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
+ exit(1);
+
+ if (deleteall) {
+ struct xfrm_buffer xb;
+ char buf[NLMSG_DELETEALL_BUF_SIZE];
+ int i;
+
+ xb.buf = buf;
+ xb.size = sizeof(buf);
+ xb.rth = &rth;
+
+ for (i = 0; ; i++) {
+ xb.offset = 0;
+ xb.nlmsg_count = 0;
+
+ if (show_stats > 1)
+ fprintf(stderr, "Delete-all round = %d\n", i);
+
+ if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETSA) < 0) {
+ perror("Cannot send dump request");
+ exit(1);
+ }
+
+ if (rtnl_dump_filter(&rth, xfrm_state_keep, &xb) < 0) {
+ fprintf(stderr, "Delete-all terminated\n");
+ exit(1);
+ }
+ if (xb.nlmsg_count == 0) {
+ if (show_stats > 1)
+ fprintf(stderr, "Delete-all completed\n");
+ break;
+ }
+
+ if (rtnl_send_check(&rth, xb.buf, xb.offset) < 0) {
+ perror("Failed to send delete-all request\n");
+ exit(1);
+ }
+ if (show_stats > 1)
+ fprintf(stderr, "Delete-all nlmsg count = %d\n", xb.nlmsg_count);
+
+ xb.offset = 0;
+ xb.nlmsg_count = 0;
+ }
+
+ } else {
+ if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETSA) < 0) {
+ perror("Cannot send dump request");
+ exit(1);
+ }
+
+ if (rtnl_dump_filter(&rth, xfrm_state_print, stdout) < 0) {
+ fprintf(stderr, "Dump terminated\n");
+ exit(1);
+ }
+ }
+
+ rtnl_close(&rth);
+
+ exit(0);
+}
+
+int print_sadinfo(struct nlmsghdr *n, void *arg)
+{
+ FILE *fp = (FILE*)arg;
+ __u32 *f = NLMSG_DATA(n);
+ struct rtattr *tb[XFRMA_SAD_MAX+1];
+ struct rtattr *rta;
+ __u32 *cnt;
+
+ int len = n->nlmsg_len;
+
+ len -= NLMSG_LENGTH(sizeof(__u32));
+ if (len < 0) {
+ fprintf(stderr, "SADinfo: Wrong len %d\n", len);
+ return -1;
+ }
+
+ rta = XFRMSAPD_RTA(f);
+ parse_rtattr(tb, XFRMA_SAD_MAX, rta, len);
+
+ if (tb[XFRMA_SAD_CNT]) {
+ fprintf(fp,"\t SAD");
+ cnt = (__u32 *)RTA_DATA(tb[XFRMA_SAD_CNT]);
+ fprintf(fp," count %d", *cnt);
+ } else {
+ fprintf(fp,"BAD SAD info returned\n");
+ return -1;
+ }
+
+ if (show_stats) {
+ if (tb[XFRMA_SAD_HINFO]) {
+ struct xfrmu_sadhinfo *si;
+
+ if (RTA_PAYLOAD(tb[XFRMA_SAD_HINFO]) < sizeof(*si)) {
+ fprintf(fp,"BAD SAD length returned\n");
+ return -1;
+ }
+
+ si = RTA_DATA(tb[XFRMA_SAD_HINFO]);
+ fprintf(fp," (buckets ");
+ fprintf(fp,"count %d", si->sadhcnt);
+ fprintf(fp," Max %d", si->sadhmcnt);
+ fprintf(fp,")");
+ }
+ }
+ fprintf(fp,"\n");
+
+ return 0;
+}
+
+static int xfrm_sad_getinfo(int argc, char **argv)
+{
+ struct rtnl_handle rth;
+ struct {
+ struct nlmsghdr n;
+ __u32 flags;
+ char ans[64];
+ } req;
+
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.flags));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = XFRM_MSG_GETSADINFO;
+ req.flags = 0XFFFFFFFF;
+
+ if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
+ exit(1);
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0)
+ exit(2);
+
+ print_sadinfo(&req.n, (void*)stdout);
+
+ rtnl_close(&rth);
+
+ return 0;
+}
+
+static int xfrm_state_flush(int argc, char **argv)
+{
+ struct rtnl_handle rth;
+ struct {
+ struct nlmsghdr n;
+ struct xfrm_usersa_flush xsf;
+ } req;
+ char *protop = NULL;
+
+ memset(&req, 0, sizeof(req));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsf));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = XFRM_MSG_FLUSHSA;
+ req.xsf.proto = 0;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "proto") == 0) {
+ int ret;
+
+ if (protop)
+ duparg("proto", *argv);
+ protop = *argv;
+
+ NEXT_ARG();
+
+ ret = xfrm_xfrmproto_getbyname(*argv);
+ if (ret < 0)
+ invarg("\"XFRM-PROTO\" is invalid", *argv);
+
+ req.xsf.proto = (__u8)ret;
+ } else
+ invarg("unknown", *argv);
+
+ argc--; argv++;
+ }
+
+ if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
+ exit(1);
+
+ if (show_stats > 1)
+ fprintf(stderr, "Flush state proto=%s\n",
+ strxf_xfrmproto(req.xsf.proto));
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ exit(2);
+
+ rtnl_close(&rth);
+
+ return 0;
+}
+
+int do_xfrm_state(int argc, char **argv)
+{
+ if (argc < 1)
+ return xfrm_state_list_or_deleteall(0, NULL, 0);
+
+ if (matches(*argv, "add") == 0)
+ return xfrm_state_modify(XFRM_MSG_NEWSA, 0,
+ argc-1, argv+1);
+ if (matches(*argv, "update") == 0)
+ return xfrm_state_modify(XFRM_MSG_UPDSA, 0,
+ argc-1, argv+1);
+ if (matches(*argv, "allocspi") == 0)
+ return xfrm_state_allocspi(argc-1, argv+1);
+ if (matches(*argv, "delete") == 0)
+ return xfrm_state_get_or_delete(argc-1, argv+1, 1);
+ if (matches(*argv, "deleteall") == 0 || matches(*argv, "delall") == 0)
+ return xfrm_state_list_or_deleteall(argc-1, argv+1, 1);
+ if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
+ || matches(*argv, "lst") == 0)
+ return xfrm_state_list_or_deleteall(argc-1, argv+1, 0);
+ if (matches(*argv, "get") == 0)
+ return xfrm_state_get_or_delete(argc-1, argv+1, 0);
+ if (matches(*argv, "flush") == 0)
+ return xfrm_state_flush(argc-1, argv+1);
+ if (matches(*argv, "count") == 0) {
+ return xfrm_sad_getinfo(argc, argv);
+ }
+ if (matches(*argv, "help") == 0)
+ usage();
+ fprintf(stderr, "Command \"%s\" is unknown, try \"ip xfrm state help\".\n", *argv);
+ exit(-1);
+}