From 5e1a84ab74d5e97582427f016f291a8c11e66f99 Mon Sep 17 00:00:00 2001 From: jutteau Date: Fri, 11 May 2007 18:10:19 +0000 Subject: Completion du script de mise à jour de la pc-104 : * Ajout des sources de busybox dans ./conf/busybox/ * Ajout d'un fichier réclamé par les script dans ./conf/busybox.links --- .../conf/busybox/networking/libiproute/Kbuild | 66 ++ .../conf/busybox/networking/libiproute/ip_common.h | 35 + .../networking/libiproute/ip_parse_common_args.c | 79 ++ .../conf/busybox/networking/libiproute/ipaddress.c | 824 +++++++++++++++++++ .../conf/busybox/networking/libiproute/iplink.c | 350 ++++++++ .../conf/busybox/networking/libiproute/iproute.c | 878 +++++++++++++++++++++ .../conf/busybox/networking/libiproute/iprule.c | 334 ++++++++ .../conf/busybox/networking/libiproute/iptunnel.c | 547 +++++++++++++ .../busybox/networking/libiproute/libnetlink.c | 396 ++++++++++ .../busybox/networking/libiproute/libnetlink.h | 43 + .../conf/busybox/networking/libiproute/ll_addr.c | 85 ++ .../conf/busybox/networking/libiproute/ll_map.c | 186 +++++ .../conf/busybox/networking/libiproute/ll_map.h | 13 + .../conf/busybox/networking/libiproute/ll_proto.c | 121 +++ .../conf/busybox/networking/libiproute/ll_types.c | 117 +++ .../conf/busybox/networking/libiproute/rt_names.c | 365 +++++++++ .../conf/busybox/networking/libiproute/rt_names.h | 28 + .../conf/busybox/networking/libiproute/rtm_map.c | 110 +++ .../conf/busybox/networking/libiproute/rtm_map.h | 11 + .../conf/busybox/networking/libiproute/utils.c | 330 ++++++++ .../conf/busybox/networking/libiproute/utils.h | 91 +++ 21 files changed, 5009 insertions(+) create mode 100644 i/pc104/initrd/conf/busybox/networking/libiproute/Kbuild create mode 100644 i/pc104/initrd/conf/busybox/networking/libiproute/ip_common.h create mode 100644 i/pc104/initrd/conf/busybox/networking/libiproute/ip_parse_common_args.c create mode 100644 i/pc104/initrd/conf/busybox/networking/libiproute/ipaddress.c create mode 100644 i/pc104/initrd/conf/busybox/networking/libiproute/iplink.c create mode 100644 i/pc104/initrd/conf/busybox/networking/libiproute/iproute.c create mode 100644 i/pc104/initrd/conf/busybox/networking/libiproute/iprule.c create mode 100644 i/pc104/initrd/conf/busybox/networking/libiproute/iptunnel.c create mode 100644 i/pc104/initrd/conf/busybox/networking/libiproute/libnetlink.c create mode 100644 i/pc104/initrd/conf/busybox/networking/libiproute/libnetlink.h create mode 100644 i/pc104/initrd/conf/busybox/networking/libiproute/ll_addr.c create mode 100644 i/pc104/initrd/conf/busybox/networking/libiproute/ll_map.c create mode 100644 i/pc104/initrd/conf/busybox/networking/libiproute/ll_map.h create mode 100644 i/pc104/initrd/conf/busybox/networking/libiproute/ll_proto.c create mode 100644 i/pc104/initrd/conf/busybox/networking/libiproute/ll_types.c create mode 100644 i/pc104/initrd/conf/busybox/networking/libiproute/rt_names.c create mode 100644 i/pc104/initrd/conf/busybox/networking/libiproute/rt_names.h create mode 100644 i/pc104/initrd/conf/busybox/networking/libiproute/rtm_map.c create mode 100644 i/pc104/initrd/conf/busybox/networking/libiproute/rtm_map.h create mode 100644 i/pc104/initrd/conf/busybox/networking/libiproute/utils.c create mode 100644 i/pc104/initrd/conf/busybox/networking/libiproute/utils.h (limited to 'i/pc104/initrd/conf/busybox/networking/libiproute') diff --git a/i/pc104/initrd/conf/busybox/networking/libiproute/Kbuild b/i/pc104/initrd/conf/busybox/networking/libiproute/Kbuild new file mode 100644 index 0000000..8383630 --- /dev/null +++ b/i/pc104/initrd/conf/busybox/networking/libiproute/Kbuild @@ -0,0 +1,66 @@ +# Makefile for busybox +# +# Copyright (C) 1999-2004 by Erik Andersen +# +# Licensed under the GPL v2 or later, see the file LICENSE in this tarball. +# + +lib-y:= +lib-$(CONFIG_IP) += \ + ip_parse_common_args.o \ + ipaddress.o \ + iplink.o \ + iproute.o \ + iptunnel.o \ + iprule.o \ + libnetlink.o \ + ll_addr.o \ + ll_map.o \ + ll_proto.o \ + ll_types.o \ + rt_names.o \ + rtm_map.o \ + utils.o + +lib-$(CONFIG_IPADDR) += \ + ip_parse_common_args.o \ + ipaddress.o \ + libnetlink.o \ + ll_addr.o \ + ll_map.o \ + ll_types.o \ + rt_names.o \ + utils.o + +lib-$(CONFIG_IPLINK) += \ + ip_parse_common_args.o \ + ipaddress.o \ + iplink.o \ + libnetlink.o \ + ll_addr.o \ + ll_map.o \ + ll_types.o \ + rt_names.o \ + utils.o + +lib-$(CONFIG_IPROUTE) += \ + ip_parse_common_args.o \ + iproute.o \ + libnetlink.o \ + ll_map.o \ + rt_names.o \ + rtm_map.o \ + utils.o + +lib-$(CONFIG_IPTUNNEL) += \ + ip_parse_common_args.o \ + iptunnel.o \ + rt_names.o \ + utils.o + +lib-$(CONFIG_IPRULE) += \ + ip_parse_common_args.o \ + iprule.o \ + rt_names.o \ + utils.o + diff --git a/i/pc104/initrd/conf/busybox/networking/libiproute/ip_common.h b/i/pc104/initrd/conf/busybox/networking/libiproute/ip_common.h new file mode 100644 index 0000000..05a6a95 --- /dev/null +++ b/i/pc104/initrd/conf/busybox/networking/libiproute/ip_common.h @@ -0,0 +1,35 @@ +/* vi: set sw=4 ts=4: */ +#ifndef _IP_COMMON_H +#define _IP_COMMON_H 1 + +#include "busybox.h" +#include +#include +#include +#if !defined IFA_RTA +#include +#endif +#if !defined IFLA_RTA +#include +#endif + +extern int preferred_family; +//FIXME! Appears in two .h files! +extern const char * _SL_; + +extern void ip_parse_common_args(int *argcp, char ***argvp); +extern int print_neigh(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); +extern int ipaddr_list_or_flush(int argc, char **argv, int flush); +extern int iproute_monitor(int argc, char **argv); +extern void iplink_usage(void) ATTRIBUTE_NORETURN; +extern void ipneigh_reset_filter(void); +extern int do_ipaddr(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_iptunnel(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); +#endif /* ip_common.h */ diff --git a/i/pc104/initrd/conf/busybox/networking/libiproute/ip_parse_common_args.c b/i/pc104/initrd/conf/busybox/networking/libiproute/ip_parse_common_args.c new file mode 100644 index 0000000..00a8912 --- /dev/null +++ b/i/pc104/initrd/conf/busybox/networking/libiproute/ip_parse_common_args.c @@ -0,0 +1,79 @@ +/* vi: set sw=4 ts=4: */ +/* + * 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, + * + * + * Changes: + * + * Rani Assaf 980929: resolve addresses + */ + +#include + +#include "libbb.h" +#include "utils.h" +#include "ip_common.h" + + +int preferred_family = AF_UNSPEC; +int oneline = 0; +const char * _SL_ = NULL; + +void ip_parse_common_args(int *argcp, char ***argvp) +{ + int argc = *argcp; + char **argv = *argvp; + + 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, "-family") == 0) { + argc--; + argv++; + if (!argv[1]) + bb_show_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], "link") == 0) + preferred_family = AF_PACKET; + else + invarg(argv[1], "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 (matches(opt, "-oneline") == 0) { + ++oneline; + } else { + bb_show_usage(); + } + argc--; + argv++; + } + _SL_ = oneline ? "\\" : "\n" ; + *argcp = argc; + *argvp = argv; +} diff --git a/i/pc104/initrd/conf/busybox/networking/libiproute/ipaddress.c b/i/pc104/initrd/conf/busybox/networking/libiproute/ipaddress.c new file mode 100644 index 0000000..bc9963f --- /dev/null +++ b/i/pc104/initrd/conf/busybox/networking/libiproute/ipaddress.c @@ -0,0 +1,824 @@ +/* vi: set sw=4 ts=4: */ +/* + * ipaddress.c "ip address". + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * + * Authors: Alexey Kuznetsov, + * + * Changes: + * Laszlo Valko 990223: address label must be zero terminated + */ + +#include "libbb.h" +#include +#include + +#include +#include +#include + +#include +#include + +#include "rt_names.h" +#include "utils.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; + struct rtnl_handle *rth; +} filter; + +static void print_link_flags(FILE *fp, unsigned flags, unsigned mdown) +{ + fprintf(fp, "<"); + 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); +#if 0 + _PF(ALLMULTI); + _PF(PROMISC); + _PF(MASTER); + _PF(SLAVE); + _PF(DEBUG); + _PF(DYNAMIC); + _PF(AUTOMEDIA); + _PF(PORTSEL); + _PF(NOTRAILERS); +#endif + _PF(UP); +#undef _PF + if (flags) + fprintf(fp, "%x", flags); + if (mdown) + fprintf(fp, ",M-DOWN"); + fprintf(fp, "> "); +} + +static void print_queuelen(char *name) +{ + struct ifreq ifr; + int s; + + s = socket(AF_INET, SOCK_STREAM, 0); + if (s < 0) + return; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + if (ioctl(s, SIOCGIFTXQLEN, &ifr) < 0) { + perror("SIOCGIFXQLEN"); + close(s); + return; + } + close(s); + + if (ifr.ifr_qlen) + printf("qlen %d", ifr.ifr_qlen); +} + +static int print_linkinfo(struct sockaddr_nl ATTRIBUTE_UNUSED *who, + const struct nlmsghdr *n, void ATTRIBUTE_UNUSED *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; + + memset(tb, 0, sizeof(tb)); + parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); + if (tb[IFLA_IFNAME] == NULL) { + bb_error_msg("nil ifname"); + return -1; + } + if (filter.label && + (!filter.family || filter.family == AF_PACKET) && + fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0)) + return 0; + + if (n->nlmsg_type == RTM_DELLINK) + fprintf(fp, "Deleted "); + + fprintf(fp, "%d: %s", ifi->ifi_index, + tb[IFLA_IFNAME] ? (char*)RTA_DATA(tb[IFLA_IFNAME]) : ""); + + 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 ", (char*)RTA_DATA(tb[IFLA_QDISC])); +#ifdef IFLA_MASTER + if (tb[IFLA_MASTER]) { + SPRINT_BUF(b1); + fprintf(fp, "master %s ", ll_idx_n2a(*(int*)RTA_DATA(tb[IFLA_MASTER]), b1)); + } +#endif + if (filter.showqueue) + print_queuelen((char*)RTA_DATA(tb[IFLA_IFNAME])); + + 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))); + } + } + fprintf(fp, "\n"); + fflush(fp); + return 0; +} + +static int flush_update(void) +{ + if (rtnl_send(filter.rth, filter.flushb, filter.flushp) < 0) { + perror("Failed to send flush request\n"); + return -1; + } + filter.flushp = 0; + return 0; +} + +static int print_addrinfo(struct sockaddr_nl ATTRIBUTE_UNUSED *who, + struct nlmsghdr *n, void ATTRIBUTE_UNUSED *arg) +{ + FILE *fp = (FILE*)arg; + struct ifaddrmsg *ifa = NLMSG_DATA(n); + int len = n->nlmsg_len; + 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) { + bb_error_msg("wrong nlmsg len %d", len); + return -1; + } + + if (filter.flushb && n->nlmsg_type != RTM_NEWADDR) + return 0; + + memset(rta_tb, 0, sizeof(rta_tb)); + 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) { + 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.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 = ++filter.rth->seq; + filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb; + filter.flushed++; + return 0; + } + + if (n->nlmsg_type == RTM_DELADDR) + fprintf(fp, "Deleted "); + + if (filter.oneline) + 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 + 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))); + if (ifa->ifa_flags&IFA_F_SECONDARY) { + ifa->ifa_flags &= ~IFA_F_SECONDARY; + fprintf(fp, "secondary "); + } + if (ifa->ifa_flags&IFA_F_TENTATIVE) { + ifa->ifa_flags &= ~IFA_F_TENTATIVE; + fprintf(fp, "tentative "); + } + if (ifa->ifa_flags&IFA_F_DEPRECATED) { + ifa->ifa_flags &= ~IFA_F_DEPRECATED; + fprintf(fp, "deprecated "); + } + if (!(ifa->ifa_flags&IFA_F_PERMANENT)) { + fprintf(fp, "dynamic "); + } else + ifa->ifa_flags &= ~IFA_F_PERMANENT; + if (ifa->ifa_flags) + fprintf(fp, "flags %02x ", ifa->ifa_flags); + if (rta_tb[IFA_LABEL]) + fprintf(fp, "%s", (char*)RTA_DATA(rta_tb[IFA_LABEL])); + if (rta_tb[IFA_CACHEINFO]) { + struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]); + char buf[128]; + fprintf(fp, "%s", _SL_); + if (ci->ifa_valid == 0xFFFFFFFFU) + sprintf(buf, "valid_lft forever"); + else + sprintf(buf, "valid_lft %dsec", ci->ifa_valid); + if (ci->ifa_prefered == 0xFFFFFFFFU) + sprintf(buf+strlen(buf), " preferred_lft forever"); + else + sprintf(buf+strlen(buf), " preferred_lft %dsec", ci->ifa_prefered); + fprintf(fp, " %s", buf); + } + fprintf(fp, "\n"); + fflush(fp); + return 0; +} + + +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(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 void ipaddr_reset_filter(int _oneline) +{ + memset(&filter, 0, sizeof(filter)); + filter.oneline = _oneline; +} + +int ipaddr_list_or_flush(int argc, char **argv, int flush) +{ + static const char *const option[] = { "to", "scope", "up", "label", "dev", 0 }; + + struct nlmsg_list *linfo = NULL; + struct nlmsg_list *ainfo = NULL; + struct nlmsg_list *l; + struct rtnl_handle rth; + char *filter_dev = NULL; + int no_link = 0; + + ipaddr_reset_filter(oneline); + filter.showqueue = 1; + + if (filter.family == AF_UNSPEC) + filter.family = preferred_family; + + if (flush) { + if (argc <= 0) { + bb_error_msg(bb_msg_requires_arg, "flush"); + return -1; + } + if (filter.family == AF_PACKET) { + bb_error_msg("cannot flush link addresses"); + return -1; + } + } + + while (argc > 0) { + const int option_num = index_in_str_array(option, *argv); + switch (option_num) { + case 0: /* to */ + NEXT_ARG(); + get_prefix(&filter.pfx, *argv, filter.family); + if (filter.family == AF_UNSPEC) { + filter.family = filter.pfx.family; + } + break; + case 1: /* scope */ + { + uint32_t scope = 0; + NEXT_ARG(); + filter.scopemask = -1; + if (rtnl_rtscope_a2n(&scope, *argv)) { + if (strcmp(*argv, "all") != 0) { + invarg(*argv, "scope"); + } + scope = RT_SCOPE_NOWHERE; + filter.scopemask = 0; + } + filter.scope = scope; + break; + } + case 2: /* up */ + filter.up = 1; + break; + case 3: /* label */ + NEXT_ARG(); + filter.label = *argv; + break; + case 4: /* dev */ + NEXT_ARG(); + default: + if (filter_dev) { + duparg2("dev", *argv); + } + filter_dev = *argv; + } + argv++; + argc--; + } + + if (rtnl_open(&rth, 0) < 0) + exit(1); + + if (rtnl_wilddump_request(&rth, preferred_family, RTM_GETLINK) < 0) { + bb_perror_msg_and_die("cannot send dump request"); + } + + if (rtnl_dump_filter(&rth, store_nlmsg, &linfo, NULL, NULL) < 0) { + bb_error_msg_and_die("dump terminated"); + } + + if (filter_dev) { + filter.ifindex = ll_name_to_index(filter_dev); + if (filter.ifindex <= 0) { + bb_error_msg("device \"%s\" does not exist", filter_dev); + return -1; + } + } + + if (flush) { + char flushb[4096-512]; + + filter.flushb = flushb; + filter.flushp = 0; + filter.flushe = sizeof(flushb); + filter.rth = &rth; + + for (;;) { + if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) { + perror("Cannot send dump request"); + exit(1); + } + filter.flushed = 0; + if (rtnl_dump_filter(&rth, print_addrinfo, stdout, NULL, NULL) < 0) { + fprintf(stderr, "Flush terminated\n"); + exit(1); + } + if (filter.flushed == 0) { + fflush(stdout); + return 0; + } + if (flush_update() < 0) + exit(1); + } + } + + if (filter.family != AF_PACKET) { + if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) { + bb_perror_msg_and_die("cannot send dump request"); + } + + if (rtnl_dump_filter(&rth, store_nlmsg, &ainfo, NULL, NULL) < 0) { + bb_error_msg_and_die("dump terminated"); + } + } + + + 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]; + memset(tb, 0, sizeof(tb)); + 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 = 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); + } + + exit(0); +} + +static int default_scope(inet_prefix *lcl) +{ + if (lcl->family == AF_INET) { + if (lcl->bytelen >= 1 && *(uint8_t*)&lcl->data == 127) + return RT_SCOPE_HOST; + } + return 0; +} + +static int ipaddr_modify(int cmd, int argc, char **argv) +{ + static const char *const option[] = { + "peer", "remote", "broadcast", "brd", + "anycast", "scope", "dev", "label", "local", 0 + }; + + struct rtnl_handle rth; + struct { + struct nlmsghdr n; + struct ifaddrmsg ifa; + char buf[256]; + } req; + char *d = NULL; + char *l = 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; + + memset(&req, 0, sizeof(req)); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = cmd; + req.ifa.ifa_family = preferred_family; + + while (argc > 0) { + const int option_num = index_in_str_array(option, *argv); + switch (option_num) { + case 0: /* peer */ + case 1: /* remote */ + 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; + break; + case 2: /* broadcast */ + case 3: /* brd */ + { + inet_prefix addr; + NEXT_ARG(); + if (brd_len) { + duparg("broadcast", *argv); + } + if (LONE_CHAR(*argv, '+')) { + brd_len = -1; + } + else if (LONE_DASH(*argv)) { + 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; + } + break; + } + case 4: /* anycast */ + { + 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; + break; + } + case 5: /* scope */ + { + uint32_t scope = 0; + NEXT_ARG(); + if (rtnl_rtscope_a2n(&scope, *argv)) { + invarg(*argv, "scope"); + } + req.ifa.ifa_scope = scope; + scoped = 1; + break; + } + case 6: /* dev */ + NEXT_ARG(); + d = *argv; + break; + case 7: /* label */ + NEXT_ARG(); + l = *argv; + addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1); + break; + case 8: /* local */ + NEXT_ARG(); + default: + if (local_len) { + duparg2("local", *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) { + bb_error_msg(bb_msg_requires_arg,"\"dev\""); + return -1; + } + if (l && matches(d, l) != 0) { + bb_error_msg_and_die("\"dev\" (%s) must match \"label\" (%s)", d, l); + } + + if (peer_len == 0 && local_len && cmd != RTM_DELADDR) { + 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) { + bb_error_msg("broadcast can be set only for IPv4 addresses"); + 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); + + if (rtnl_open(&rth, 0) < 0) + exit(1); + + ll_init_map(&rth); + + if ((req.ifa.ifa_index = ll_name_to_index(d)) == 0) { + bb_error_msg("cannot find device \"%s\"", d); + return -1; + } + + if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) + exit(2); + + exit(0); +} + +int do_ipaddr(int argc, char **argv) +{ + static const char *const commands[] = { + "add", "delete", "list", "show", "lst", "flush", 0 + }; + + int command_num = 2; + + if (*argv) { + command_num = index_in_substr_array(commands, *argv); + } + switch (command_num) { + case 0: /* add */ + return ipaddr_modify(RTM_NEWADDR, argc-1, argv+1); + case 1: /* delete */ + return ipaddr_modify(RTM_DELADDR, argc-1, argv+1); + case 2: /* list */ + case 3: /* show */ + case 4: /* lst */ + return ipaddr_list_or_flush(argc-1, argv+1, 0); + case 5: /* flush */ + return ipaddr_list_or_flush(argc-1, argv+1, 1); + } + bb_error_msg_and_die("unknown command %s", *argv); +} diff --git a/i/pc104/initrd/conf/busybox/networking/libiproute/iplink.c b/i/pc104/initrd/conf/busybox/networking/libiproute/iplink.c new file mode 100644 index 0000000..cb6ee96 --- /dev/null +++ b/i/pc104/initrd/conf/busybox/networking/libiproute/iplink.c @@ -0,0 +1,350 @@ +/* vi: set sw=4 ts=4: */ +/* + * iplink.c "ip link". + * + * Authors: Alexey Kuznetsov, + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include "libbb.h" + +#include +#include + +#include +#include +#include + +#include + +#include "rt_names.h" +#include "utils.h" +#include "ip_common.h" + +/* take from linux/sockios.h */ +#define SIOCSIFNAME 0x8923 /* set interface name */ + +static int on_off(const char *msg) +{ + bb_error_msg("error: argument of \"%s\" must be \"on\" or \"off\"", msg); + return -1; +} + +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; + bb_perror_msg("cannot create control socket"); + return -1; +} + +static int do_chflags(char *dev, uint32_t flags, uint32_t mask) +{ + struct ifreq ifr; + int fd; + int err; + + strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); + fd = get_ctl_fd(); + if (fd < 0) + return -1; + err = ioctl(fd, SIOCGIFFLAGS, &ifr); + if (err) { + bb_perror_msg("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) + bb_perror_msg("SIOCSIFFLAGS"); + } + close(fd); + return err; +} + +static int do_changename(char *dev, char *newdev) +{ + struct ifreq ifr; + int fd; + int err; + + strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); + strncpy(ifr.ifr_newname, newdev, sizeof(ifr.ifr_newname)); + fd = get_ctl_fd(); + if (fd < 0) + return -1; + err = ioctl(fd, SIOCSIFNAME, &ifr); + if (err) { + bb_perror_msg("SIOCSIFNAME"); + close(fd); + return -1; + } + close(fd); + return err; +} + +static int set_qlen(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, sizeof(ifr.ifr_name)); + ifr.ifr_qlen = qlen; + if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) { + bb_perror_msg("SIOCSIFXQLEN"); + close(s); + return -1; + } + close(s); + + return 0; +} + +static int set_mtu(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, sizeof(ifr.ifr_name)); + ifr.ifr_mtu = mtu; + if (ioctl(s, SIOCSIFMTU, &ifr) < 0) { + bb_perror_msg("SIOCSIFMTU"); + close(s); + return -1; + } + close(s); + + return 0; +} + +static int get_address(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) { + bb_perror_msg("socket(PF_PACKET)"); + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); + if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { + bb_perror_msg("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) { + bb_perror_msg("bind"); + close(s); + return -1; + } + + alen = sizeof(me); + if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) { + bb_perror_msg("getsockname"); + close(s); + return -1; + } + close(s); + *htype = me.sll_hatype; + return me.sll_halen; +} + +static int parse_address(char *dev, int hatype, int halen, char *lla, struct ifreq *ifr) +{ + int alen; + + memset(ifr, 0, sizeof(*ifr)); + strncpy(ifr->ifr_name, dev, sizeof(ifr->ifr_name)); + ifr->ifr_hwaddr.sa_family = hatype; + alen = ll_addr_a2n((unsigned char *)(ifr->ifr_hwaddr.sa_data), 14, lla); + if (alen < 0) + return -1; + if (alen != halen) { + bb_error_msg("wrong address (%s) length: expected %d bytes", 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) { + bb_perror_msg(brd ? "SIOCSIFHWBROADCAST" : "SIOCSIFHWADDR"); + close(s); + return -1; + } + close(s); + return 0; +} + + +static int do_set(int argc, char **argv) +{ + char *dev = NULL; + uint32_t mask = 0; + uint32_t 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 (strcmp(*argv, "mtu") == 0) { + NEXT_ARG(); + if (mtu != -1) + duparg("mtu", *argv); + if (get_integer(&mtu, *argv, 0)) + invarg(*argv, "mtu"); + } 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, "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 (strcmp(*argv, "addr") == 0) { + NEXT_ARG(); + newaddr = *argv; + } else { + if (strcmp(*argv, "dev") == 0) { + NEXT_ARG(); + } + if (dev) + duparg2("dev", *argv); + dev = *argv; + } + argc--; argv++; + } + + if (!dev) { + bb_error_msg(bb_msg_requires_arg, "\"dev\""); + 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 (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; +} + +static int ipaddr_list_link(int argc, char **argv) +{ + preferred_family = AF_PACKET; + return ipaddr_list_or_flush(argc, argv, 0); +} + +int do_iplink(int argc, char **argv) +{ + if (argc > 0) { + if (matches(*argv, "set") == 0) + return do_set(argc-1, argv+1); + if (matches(*argv, "show") == 0 || + matches(*argv, "lst") == 0 || + matches(*argv, "list") == 0) + return ipaddr_list_link(argc-1, argv+1); + } else + return ipaddr_list_link(0, NULL); + + bb_error_msg("command \"%s\" is unknown", *argv); + exit(-1); +} diff --git a/i/pc104/initrd/conf/busybox/networking/libiproute/iproute.c b/i/pc104/initrd/conf/busybox/networking/libiproute/iproute.c new file mode 100644 index 0000000..27d37ac --- /dev/null +++ b/i/pc104/initrd/conf/busybox/networking/libiproute/iproute.c @@ -0,0 +1,878 @@ +/* vi: set sw=4 ts=4: */ +/* + * iproute.c "ip route". + * + * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * + * Authors: Alexey Kuznetsov, + * + * + * Changes: + * + * Rani Assaf 980929: resolve addresses + * Kunihiro Ishiguro 001102: rtnh_ifindex was not initialized + */ + +#include "libbb.h" + +#include "rt_names.h" +#include "utils.h" +#include "ip_common.h" + +#ifndef RTAX_RTTVAR +#define RTAX_RTTVAR RTAX_HOPS +#endif + + +static struct +{ + int tb; + int flushed; + char *flushb; + int flushp; + int flushe; + struct rtnl_handle *rth; + int protocol, protocolmask; + int scope, scopemask; + int type, typemask; + int tos, tosmask; + int iif, iifmask; + int oif, oifmask; + 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(filter.rth, filter.flushb, filter.flushp) < 0) { + perror("Failed to send flush request\n"); + return -1; + } + filter.flushp = 0; + return 0; +} + +static unsigned get_hz(void) +{ + static unsigned hz_internal; + FILE *fp; + + if (hz_internal) + return hz_internal; + + fp = fopen("/proc/net/psched", "r"); + if (fp) { + unsigned nom, denom; + + if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2) + if (nom == 1000000) + hz_internal = denom; + fclose(fp); + } + if (!hz_internal) + hz_internal = sysconf(_SC_CLK_TCK); + return hz_internal; +} + +static int print_route(struct sockaddr_nl *who ATTRIBUTE_UNUSED, + 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]; + inet_prefix dst; + inet_prefix src; + int host_len = -1; + SPRINT_BUF(b1); + + + 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) { + bb_error_msg("wrong nlmsg len %d", len); + return -1; + } + + if (r->rtm_family == AF_INET6) + host_len = 128; + else if (r->rtm_family == AF_INET) + host_len = 32; + + if (r->rtm_family == AF_INET6) { + if (filter.tb) { + if (filter.tb < 0) { + if (!(r->rtm_flags&RTM_F_CLONED)) { + return 0; + } + } else { + if (r->rtm_flags&RTM_F_CLONED) { + return 0; + } + 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 != r->rtm_table) { + 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; + } + + memset(tb, 0, sizeof(tb)); + parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); + + 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.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; + + 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 = ++filter.rth->seq; + filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb; + filter.flushed++; + 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 (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 (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 %d ", *(uint32_t*)RTA_DATA(tb[RTA_PRIORITY])); + } + 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 (r->rtm_flags & RTM_F_CLONED) { + fprintf(fp, "%s cache ", _SL_); + } + if (ci->rta_expires) { + fprintf(fp, " expires %dsec", ci->rta_expires / get_hz()); + } + if (ci->rta_error != 0) { + fprintf(fp, " error %d", ci->rta_error); + } + } else if (ci) { + if (ci->rta_error != 0) + fprintf(fp, " error %d", ci->rta_error); + } + } + if (tb[RTA_IIF] && filter.iifmask != -1) { + fprintf(fp, " iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF]))); + } + fprintf(fp, "\n"); + fflush(fp); + return 0; +} + +static int iproute_modify(int cmd, unsigned flags, int argc, char **argv) +{ + struct rtnl_handle rth; + 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 proto_ok = 0; + int type_ok = 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, "mtu") == 0) { + unsigned mtu; + NEXT_ARG(); + if (strcmp(*argv, "lock") == 0) { + mxlock |= (1< '9') && + rtnl_rtntype_a2n(&type, *argv) == 0) { + NEXT_ARG(); + req.r.rtm_type = type; + type_ok = 1; + } + + 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 (rtnl_open(&rth, 0) < 0) { + exit(1); + } + + if (d) { + int idx; + + ll_init_map(&rth); + + if (d) { + idx = ll_name_to_index(d); + if (idx == 0) { + bb_error_msg("cannot find device \"%s\"", 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 (req.r.rtm_family == AF_UNSPEC) { + req.r.rtm_family = AF_INET; + } + + if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, 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) +{ + static const char fn[] = "/proc/sys/net/ipv4/route/flush"; + int flush_fd = open(fn, O_WRONLY); + if (flush_fd < 0) { + bb_perror_msg("cannot open '%s'", fn); + return -1; + } + + if (write(flush_fd, "-1", 2) < 2) { + bb_perror_msg("cannot flush routing cache"); + return -1; + } + close(flush_fd); + return 0; +} + +static void iproute_reset_filter(void) +{ + memset(&filter, 0, sizeof(filter)); + filter.mdst.bitlen = -1; + filter.msrc.bitlen = -1; +} + +static int iproute_list_or_flush(int argc, char **argv, int flush) +{ + int do_ipv6 = preferred_family; + struct rtnl_handle rth; + char *id = NULL; + char *od = NULL; + + iproute_reset_filter(); + filter.tb = RT_TABLE_MAIN; + + if (flush && argc <= 0) { + bb_error_msg(bb_msg_requires_arg, "\"ip route flush\""); + return -1; + } + + while (argc > 0) { + if (matches(*argv, "protocol") == 0) { + uint32_t prot = 0; + NEXT_ARG(); + filter.protocolmask = -1; + if (rtnl_rtprot_a2n(&prot, *argv)) { + if (strcmp(*argv, "all") != 0) { + invarg(*argv, "protocol"); + } + prot = 0; + filter.protocolmask = 0; + } + filter.protocol = prot; + } 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 (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, "table") == 0) { + NEXT_ARG(); + if (matches(*argv, "cache") == 0) { + filter.tb = -1; +#if 0 && ENABLE_FEATURE_IP_RULE + +#else + } else if (matches(*argv, "main") != 0) { + invarg(*argv, "table"); + } +#endif + } else if (matches(*argv, "cache") == 0) { + filter.tb = -1; + } 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; + } + + if (rtnl_open(&rth, 0) < 0) { + exit(1); + } + + ll_init_map(&rth); + + if (id || od) { + int idx; + + if (id) { + if ((idx = ll_name_to_index(id)) == 0) { + bb_error_msg("cannot find device \"%s\"", id); + return -1; + } + filter.iif = idx; + filter.iifmask = -1; + } + if (od) { + if ((idx = ll_name_to_index(od)) == 0) { + bb_error_msg("cannot find device \"%s\"", od); + } + filter.oif = idx; + filter.oifmask = -1; + } + } + + if (flush) { + char flushb[4096-512]; + + if (filter.tb == -1) { + if (do_ipv6 != AF_INET6) + iproute_flush_cache(); + if (do_ipv6 == AF_INET) + return 0; + } + + filter.flushb = flushb; + filter.flushp = 0; + filter.flushe = sizeof(flushb); + filter.rth = &rth; + + for (;;) { + if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) { + perror("Cannot send dump request"); + return -1; + } + filter.flushed = 0; + if (rtnl_dump_filter(&rth, print_route, stdout, NULL, NULL) < 0) { + bb_error_msg("flush terminated"); + return -1; + } + if (filter.flushed == 0) { + fflush(stdout); + return 0; + } + if (flush_update() < 0) + exit(1); + } + } + + if (filter.tb != -1) { + if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) { + bb_perror_msg_and_die("cannot send dump request"); + } + } else { + if (rtnl_rtcache_request(&rth, do_ipv6) < 0) { + bb_perror_msg_and_die("cannot send dump request"); + } + } + + if (rtnl_dump_filter(&rth, print_route, stdout, NULL, NULL) < 0) { + bb_error_msg_and_die("dump terminated"); + } + + exit(0); +} + + +static int iproute_get(int argc, char **argv) +{ + struct rtnl_handle rth; + struct { + struct nlmsghdr n; + struct rtmsg r; + char buf[1024]; + } req; + char *idev = NULL; + char *odev = NULL; + int connected = 0; + int from_ok = 0; + static const char * const options[] = + { "from", "iif", "oif", "dev", "notify", "connected", "to", 0 }; + + memset(&req, 0, sizeof(req)); + + iproute_reset_filter(); + + 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) { + switch (index_in_str_array(options, *argv)) { + case 0: /* from */ + { + inet_prefix addr; + NEXT_ARG(); + 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; + break; + } + case 1: /* iif */ + NEXT_ARG(); + idev = *argv; + break; + case 2: /* oif */ + case 3: /* dev */ + NEXT_ARG(); + odev = *argv; + break; + case 4: /* notify */ + req.r.rtm_flags |= RTM_F_NOTIFY; + break; + case 5: /* connected */ + connected = 1; + break; + case 6: /* to */ + NEXT_ARG(); + default: + { + inet_prefix addr; + 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) { + bb_error_msg_and_die("need at least destination address"); + } + + if (rtnl_open(&rth, 0) < 0) + exit(1); + + ll_init_map(&rth); + + if (idev || odev) { + int idx; + + if (idev) { + if ((idx = ll_name_to_index(idev)) == 0) { + bb_error_msg("cannot find device \"%s\"", idev); + return -1; + } + addattr32(&req.n, sizeof(req), RTA_IIF, idx); + } + if (odev) { + if ((idx = ll_name_to_index(odev)) == 0) { + bb_error_msg("cannot find device \"%s\"", odev); + return -1; + } + addattr32(&req.n, sizeof(req), RTA_OIF, idx); + } + } + + if (req.r.rtm_family == AF_UNSPEC) { + req.r.rtm_family = AF_INET; + } + + if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 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) { + bb_error_msg_and_die("an error :-)"); + } + + if (req.n.nlmsg_type != RTM_NEWROUTE) { + bb_error_msg("not a route?"); + return -1; + } + len -= NLMSG_LENGTH(sizeof(*r)); + if (len < 0) { + bb_error_msg("wrong len %d", len); + return -1; + } + + memset(tb, 0, sizeof(tb)); + 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]) { + bb_error_msg("failed to connect the route"); + 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, NULL, NULL) < 0) { + exit(2); + } + } + + if (print_route(NULL, &req.n, (void*)stdout) < 0) { + bb_error_msg_and_die("an error :-)"); + } + + exit(0); +} + +int do_iproute(int argc, char **argv) +{ + static const char * const ip_route_commands[] = { + /*0-3*/ "add", "append", "change", "chg", + /*4-7*/ "delete", "get", "list", "show", + /*8..*/ "prepend", "replace", "test", "flush", 0 + }; + int command_num = 6; + unsigned int flags = 0; + int cmd = RTM_NEWROUTE; + + /* "Standard" 'ip r a' treats 'a' as 'add', not 'append' */ + /* It probably means that it is using "first match" rule */ + if (*argv) { + command_num = index_in_substr_array(ip_route_commands, *argv); + } + switch (command_num) { + case 0: /* add */ + flags = NLM_F_CREATE|NLM_F_EXCL; + break; + case 1: /* append */ + flags = NLM_F_CREATE|NLM_F_APPEND; + break; + case 2: /* change */ + case 3: /* chg */ + flags = NLM_F_REPLACE; + break; + case 4: /* delete */ + cmd = RTM_DELROUTE; + break; + case 5: /* get */ + return iproute_get(argc-1, argv+1); + case 6: /* list */ + case 7: /* show */ + return iproute_list_or_flush(argc-1, argv+1, 0); + case 8: /* prepend */ + flags = NLM_F_CREATE; + case 9: /* replace */ + flags = NLM_F_CREATE|NLM_F_REPLACE; + case 10: /* test */ + flags = NLM_F_EXCL; + case 11: /* flush */ + return iproute_list_or_flush(argc-1, argv+1, 1); + default: + bb_error_msg_and_die("unknown command %s", *argv); + } + + return iproute_modify(cmd, flags, argc-1, argv+1); +} diff --git a/i/pc104/initrd/conf/busybox/networking/libiproute/iprule.c b/i/pc104/initrd/conf/busybox/networking/libiproute/iprule.c new file mode 100644 index 0000000..4b31303 --- /dev/null +++ b/i/pc104/initrd/conf/busybox/networking/libiproute/iprule.c @@ -0,0 +1,334 @@ +/* vi: set sw=4 ts=4: */ +/* + * 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, + * + * + * Changes: + * + * Rani Assaf 980929: resolve addresses + * initially integrated into busybox by Bernhard Fischer + */ + +#include "libbb.h" +#include +#include +#include +#include +#include + +#include "rt_names.h" +#include "utils.h" +#include "ip_common.h" +/* +static void usage(void) __attribute__((noreturn)); + +static void usage(void) +{ + fprintf(stderr, "Usage: ip rule [ list | add | del ] SELECTOR ACTION\n"); + fprintf(stderr, "SELECTOR := [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK ]\n"); + fprintf(stderr, " [ dev STRING ] [ pref NUMBER ]\n"); + fprintf(stderr, "ACTION := [ table TABLE_ID ] [ nat ADDRESS ]\n"); + fprintf(stderr, " [ prohibit | reject | unreachable ]\n"); + fprintf(stderr, " [ realms [SRCREALM/]DSTREALM ]\n"); + fprintf(stderr, "TABLE_ID := [ local | main | default | NUMBER ]\n"); + exit(-1); +} +*/ +static int print_rule(struct sockaddr_nl *who ATTRIBUTE_UNUSED, + struct nlmsghdr *n, void *arg) +{ + FILE *fp = (FILE*)arg; + struct rtmsg *r = NLMSG_DATA(n); + int len = n->nlmsg_len; + int host_len = -1; + struct rtattr * tb[RTA_MAX+1]; + char abuf[256]; + SPRINT_BUF(b1); + + if (n->nlmsg_type != RTM_NEWRULE) + return 0; + + len -= NLMSG_LENGTH(sizeof(*r)); + if (len < 0) + return -1; + + memset(tb, 0, sizeof(tb)); + parse_rtattr(tb, RTA_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 (tb[RTA_PRIORITY]) + fprintf(fp, "%u:\t", *(unsigned*)RTA_DATA(tb[RTA_PRIORITY])); + else + fprintf(fp, "0:\t"); + + fprintf(fp, "from "); + if (tb[RTA_SRC]) { + if (r->rtm_src_len != host_len) { + fprintf(fp, "%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, "%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, "0/%d", r->rtm_src_len); + } else { + fprintf(fp, "all"); + } + fprintf(fp, " "); + + if (tb[RTA_DST]) { + if (r->rtm_dst_len != host_len) { + fprintf(fp, "to %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, "to %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, "to 0/%d ", r->rtm_dst_len); + } + + if (r->rtm_tos) { + fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1))); + } + if (tb[RTA_PROTOINFO]) { + fprintf(fp, "fwmark %#x ", *(uint32_t*)RTA_DATA(tb[RTA_PROTOINFO])); + } + + if (tb[RTA_IIF]) { + fprintf(fp, "iif %s ", (char*)RTA_DATA(tb[RTA_IIF])); + } + + if (r->rtm_table) + fprintf(fp, "lookup %s ", rtnl_rttable_n2a(r->rtm_table, b1, sizeof(b1))); + + if (tb[RTA_FLOW]) { + uint32_t to = *(uint32_t*)RTA_DATA(tb[RTA_FLOW]); + uint32_t 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 != 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) +{ + struct rtnl_handle rth; + int af = preferred_family; + + if (af == AF_UNSPEC) + af = AF_INET; + + if (argc > 0) { + //bb_error_msg("\"rule show\" needs no arguments"); + bb_warn_ignoring_args(argc); + return -1; + } + + if (rtnl_open(&rth, 0) < 0) + return 1; + + if (rtnl_wilddump_request(&rth, af, RTM_GETRULE) < 0) { + bb_perror_msg("Cannot send dump request"); + return 1; + } + + if (rtnl_dump_filter(&rth, print_rule, stdout, NULL, NULL) < 0) { + bb_error_msg("Dump terminated"); + return 1; + } + + return 0; +} + + +static int iprule_modify(int cmd, int argc, char **argv) +{ + int table_ok = 0; + struct rtnl_handle rth; + 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; + + 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, "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), RTA_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), RTA_DST, &dst.data, dst.bytelen); + } else if (matches(*argv, "preference") == 0 || + matches(*argv, "order") == 0 || + matches(*argv, "priority") == 0) { + uint32_t pref; + NEXT_ARG(); + if (get_u32(&pref, *argv, 0)) + invarg("preference value", *argv); + addattr32(&req.n, sizeof(req), RTA_PRIORITY, pref); + } else if (strcmp(*argv, "tos") == 0) { + uint32_t tos; + NEXT_ARG(); + if (rtnl_dsfield_a2n(&tos, *argv)) + invarg("TOS value", *argv); + req.r.rtm_tos = tos; + } else if (strcmp(*argv, "fwmark") == 0) { + uint32_t fwmark; + NEXT_ARG(); + if (get_u32(&fwmark, *argv, 0)) + invarg("fwmark value", *argv); + addattr32(&req.n, sizeof(req), RTA_PROTOINFO, fwmark); + } else if (matches(*argv, "realms") == 0) { + uint32_t realm; + NEXT_ARG(); + if (get_rt_realms(&realm, *argv)) + invarg("realms", *argv); + addattr32(&req.n, sizeof(req), RTA_FLOW, realm); + } else if (matches(*argv, "table") == 0 || + strcmp(*argv, "lookup") == 0) { + uint32_t tid; + NEXT_ARG(); + if (rtnl_rttable_a2n(&tid, *argv)) + invarg("table ID", *argv); + req.r.rtm_table = tid; + table_ok = 1; + } else if (strcmp(*argv, "dev") == 0 || + strcmp(*argv, "iif") == 0) { + NEXT_ARG(); + addattr_l(&req.n, sizeof(req), RTA_IIF, *argv, strlen(*argv)+1); + } else if (strcmp(*argv, "nat") == 0 || + matches(*argv, "map-to") == 0) { + NEXT_ARG(); + 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) + bb_show_usage(); + if (rtnl_rtntype_a2n(&type, *argv)) + invarg("Failed to parse rule type", *argv); + req.r.rtm_type = type; + } + 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_open(&rth, 0) < 0) + return 1; + + if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) + return 2; + + return 0; +} + +int do_iprule(int argc, char **argv) +{ + static const char * const ip_rule_commands[] = + {"add", "delete", "list", "show", 0}; + int cmd = 2; /* list */ + + if (argc < 1) + return iprule_list(0, NULL); + if (*argv) + cmd = index_in_substr_array(ip_rule_commands, *argv); + + switch (cmd) { + case 0: /* add */ + cmd = RTM_NEWRULE; + break; + case 1: /* delete */ + cmd = RTM_DELRULE; + break; + case 2: /* list */ + case 3: /* show */ + return iprule_list(argc-1, argv+1); + break; + default: + bb_error_msg_and_die("unknown command %s", *argv); + } + return iprule_modify(cmd, argc-1, argv+1); +} + diff --git a/i/pc104/initrd/conf/busybox/networking/libiproute/iptunnel.c b/i/pc104/initrd/conf/busybox/networking/libiproute/iptunnel.c new file mode 100644 index 0000000..e2e75fc --- /dev/null +++ b/i/pc104/initrd/conf/busybox/networking/libiproute/iptunnel.c @@ -0,0 +1,547 @@ +/* vi: set sw=4 ts=4: */ +/* + * iptunnel.c "ip tunnel" + * + * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * + * Authors: Alexey Kuznetsov, + * + * + * Changes: + * + * Rani Assaf 980929: resolve addresses + * Rani Assaf 980930: do not allow key for ipip/sit + * Phil Karn 990408: "pmtudisc" flag + */ + +#include "libbb.h" +#include +#include + +#include +#include + +#include + +#include +#include + +#include +#ifndef __constant_htons +#define __constant_htons htons +#endif +#include + +#include "rt_names.h" +#include "utils.h" +#include "ip_common.h" + + +static int do_ioctl_get_ifindex(char *dev) +{ + struct ifreq ifr; + int fd; + + strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); + fd = xsocket(AF_INET, SOCK_DGRAM, 0); + if (ioctl(fd, SIOCGIFINDEX, &ifr)) { + bb_perror_msg("ioctl"); + return 0; + } + close(fd); + return ifr.ifr_ifindex; +} + +static int do_ioctl_get_iftype(char *dev) +{ + struct ifreq ifr; + int fd; + + strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); + fd = xsocket(AF_INET, SOCK_DGRAM, 0); + if (ioctl(fd, SIOCGIFHWADDR, &ifr)) { + bb_perror_msg("ioctl"); + return -1; + } + close(fd); + return ifr.ifr_addr.sa_family; +} + + +static char *do_ioctl_get_ifname(int idx) +{ + static struct ifreq ifr; + int fd; + + ifr.ifr_ifindex = idx; + fd = xsocket(AF_INET, SOCK_DGRAM, 0); + if (ioctl(fd, SIOCGIFNAME, &ifr)) { + bb_perror_msg("ioctl"); + return NULL; + } + close(fd); + return ifr.ifr_name; +} + + + +static int do_get_ioctl(const char *basedev, struct ip_tunnel_parm *p) +{ + struct ifreq ifr; + int fd; + int err; + + strncpy(ifr.ifr_name, basedev, sizeof(ifr.ifr_name)); + ifr.ifr_ifru.ifru_data = (void*)p; + fd = xsocket(AF_INET, SOCK_DGRAM, 0); + err = ioctl(fd, SIOCGETTUNNEL, &ifr); + if (err) { + bb_perror_msg("ioctl"); + } + close(fd); + return err; +} + +static int do_add_ioctl(int cmd, const char *basedev, struct ip_tunnel_parm *p) +{ + struct ifreq ifr; + int fd; + int err; + + if (cmd == SIOCCHGTUNNEL && p->name[0]) { + strncpy(ifr.ifr_name, p->name, sizeof(ifr.ifr_name)); + } else { + strncpy(ifr.ifr_name, basedev, sizeof(ifr.ifr_name)); + } + ifr.ifr_ifru.ifru_data = (void*)p; + fd = xsocket(AF_INET, SOCK_DGRAM, 0); + err = ioctl(fd, cmd, &ifr); + if (err) { + bb_perror_msg("ioctl"); + } + close(fd); + return err; +} + +static int do_del_ioctl(const char *basedev, struct ip_tunnel_parm *p) +{ + struct ifreq ifr; + int fd; + int err; + + if (p->name[0]) { + strncpy(ifr.ifr_name, p->name, sizeof(ifr.ifr_name)); + } else { + strncpy(ifr.ifr_name, basedev, sizeof(ifr.ifr_name)); + } + ifr.ifr_ifru.ifru_data = (void*)p; + fd = xsocket(AF_INET, SOCK_DGRAM, 0); + err = ioctl(fd, SIOCDELTUNNEL, &ifr); + if (err) { + bb_perror_msg("ioctl"); + } + close(fd); + return err; +} + +static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p) +{ + int count = 0; + char medium[IFNAMSIZ]; + 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) { + bb_error_msg("you managed to ask for more than one tunnel mode"); + 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) { + bb_error_msg("you managed to ask for more than one tunnel mode"); + 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) { + bb_error_msg("you managed to ask for more than one tunnel mode"); + exit(-1); + } + p->iph.protocol = IPPROTO_IPV6; + } else { + bb_error_msg("cannot guess tunnel mode"); + 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) { + bb_error_msg("invalid value of \"key\""); + 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->o_key = get_addr32(*argv); + else { + if (get_unsigned(&uval, *argv, 0)<0) { + bb_error_msg("invalid value of \"ikey\""); + 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) { + bb_error_msg("invalid value of \"okey\""); + 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) { + unsigned uval; + NEXT_ARG(); + if (strcmp(*argv, "inherit") != 0) { + if (get_unsigned(&uval, *argv, 0)) + invarg(*argv, "TTL"); + if (uval > 255) + invarg(*argv, "TTL must be <=255"); + p->iph.ttl = uval; + } + } else if (strcmp(*argv, "tos") == 0 || + matches(*argv, "dsfield") == 0) { + uint32_t uval; + NEXT_ARG(); + if (strcmp(*argv, "inherit") != 0) { + if (rtnl_dsfield_a2n(&uval, *argv)) + invarg(*argv, "TOS"); + p->iph.tos = uval; + } else + p->iph.tos = 1; + } else { + if (strcmp(*argv, "name") == 0) { + NEXT_ARG(); + } + 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 (do_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; + } + + if (p->iph.protocol == IPPROTO_IPIP || p->iph.protocol == IPPROTO_IPV6) { + if ((p->i_flags & GRE_KEY) || (p->o_flags & GRE_KEY)) { + bb_error_msg("keys are not allowed with ipip and sit"); + return -1; + } + } + + if (medium[0]) { + p->link = do_ioctl_get_ifindex(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) { + bb_error_msg("broadcast tunnel requires a source address"); + return -1; + } + 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) { + bb_error_msg("ttl != 0 and noptmudisc are incompatible"); + return -1; + } + + switch (p.iph.protocol) { + case IPPROTO_IPIP: + return do_add_ioctl(cmd, "tunl0", &p); + case IPPROTO_GRE: + return do_add_ioctl(cmd, "gre0", &p); + case IPPROTO_IPV6: + return do_add_ioctl(cmd, "sit0", &p); + default: + bb_error_msg("cannot determine tunnel mode (ipip, gre or sit)"); + 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 do_del_ioctl("tunl0", &p); + case IPPROTO_GRE: + return do_del_ioctl("gre0", &p); + case IPPROTO_IPV6: + return do_del_ioctl("sit0", &p); + default: + return do_del_ioctl(p.name, &p); + } + return -1; +} + +static void print_tunnel(struct ip_tunnel_parm *p) +{ + char s1[256]; + char s2[256]; + char s3[64]; + char s4[64]; + + format_host(AF_INET, 4, &p->iph.daddr, s1, sizeof(s1)); + format_host(AF_INET, 4, &p->iph.saddr, s2, sizeof(s2)); + inet_ntop(AF_INET, &p->i_key, s3, sizeof(s3)); + inet_ntop(AF_INET, &p->o_key, s4, sizeof(s4)); + + printf("%s: %s/ip remote %s local %s ", + p->name, + p->iph.protocol == IPPROTO_IPIP ? "ip" : + (p->iph.protocol == IPPROTO_GRE ? "gre" : + (p->iph.protocol == IPPROTO_IPV6 ? "ipv6" : "unknown")), + p->iph.daddr ? s1 : "any", p->iph.saddr ? s2 : "any"); + if (p->link) { + char *n = do_ioctl_get_ifname(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->i_flags & GRE_KEY) && (p->o_flags & GRE_KEY) && p->o_key == p->i_key) + printf(" key %s", s3); + else if ((p->i_flags | p->o_flags) & GRE_KEY) { + if (p->i_flags & GRE_KEY) + printf(" ikey %s ", s3); + if (p->o_flags & GRE_KEY) + printf(" okey %s ", s4); + } + + 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; + int type; + struct ip_tunnel_parm p1; + char buf[512]; + FILE *fp = fopen("/proc/net/dev", "r"); + + if (fp == NULL) { + perror("fopen"); + return -1; + } + + fgets(buf, sizeof(buf), fp); + fgets(buf, sizeof(buf), fp); + + while (fgets(buf, sizeof(buf), fp) != NULL) { + char *ptr; + + /*buf[sizeof(buf) - 1] = 0; - fgets is safe anyway */ + ptr = strchr(buf, ':'); + if (ptr == NULL || + (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) { + bb_error_msg("wrong format of /proc/net/dev. Sorry"); + return -1; + } + if (sscanf(ptr, "%lu%lu%lu%lu%lu%lu%lu%*d%lu%lu%lu%lu%lu%lu%lu", + &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; + type = do_ioctl_get_iftype(name); + if (type == -1) { + bb_error_msg("failed to get type of [%s]", name); + continue; + } + if (type != ARPHRD_TUNNEL && type != ARPHRD_IPGRE && type != ARPHRD_SIT) + continue; + memset(&p1, 0, sizeof(p1)); + if (do_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); + puts(""); + } + return 0; +} + +static int do_show(int argc, char **argv) +{ + int err; + struct ip_tunnel_parm p; + + if (parse_args(argc, argv, SIOCGETTUNNEL, &p) < 0) + return -1; + + switch (p.iph.protocol) { + case IPPROTO_IPIP: + err = do_get_ioctl(p.name[0] ? p.name : "tunl0", &p); + break; + case IPPROTO_GRE: + err = do_get_ioctl(p.name[0] ? p.name : "gre0", &p); + break; + case IPPROTO_IPV6: + err = do_get_ioctl(p.name[0] ? p.name : "sit0", &p); + break; + default: + do_tunnels_list(&p); + return 0; + } + if (err) + return -1; + + print_tunnel(&p); + puts(""); + return 0; +} + +int do_iptunnel(int argc, char **argv) +{ + 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); + } else + return do_show(0, NULL); + + bb_error_msg_and_die("command \"%s\" is unknown", *argv); +} diff --git a/i/pc104/initrd/conf/busybox/networking/libiproute/libnetlink.c b/i/pc104/initrd/conf/busybox/networking/libiproute/libnetlink.c new file mode 100644 index 0000000..9696480 --- /dev/null +++ b/i/pc104/initrd/conf/busybox/networking/libiproute/libnetlink.c @@ -0,0 +1,396 @@ +/* vi: set sw=4 ts=4: */ +/* + * libnetlink.c RTnetlink service routines. + * + * 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, + * + */ + +#include "libbb.h" +#include + +#include +#include +#include +#include + +#include + +#include "libnetlink.h" + +void rtnl_close(struct rtnl_handle *rth) +{ + close(rth->fd); +} + +int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions) +{ + socklen_t addr_len; + + memset(rth, 0, sizeof(rth)); + + rth->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (rth->fd < 0) { + bb_perror_msg("cannot open netlink socket"); + return -1; + } + + memset(&rth->local, 0, sizeof(rth->local)); + rth->local.nl_family = AF_NETLINK; + rth->local.nl_groups = subscriptions; + + if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) { + bb_perror_msg("cannot bind netlink socket"); + return -1; + } + addr_len = sizeof(rth->local); + if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) { + bb_perror_msg("cannot getsockname"); + return -1; + } + if (addr_len != sizeof(rth->local)) { + bb_error_msg("wrong address length %d", addr_len); + return -1; + } + if (rth->local.nl_family != AF_NETLINK) { + bb_error_msg("wrong address family %d", rth->local.nl_family); + return -1; + } + rth->seq = time(NULL); + return 0; +} + +int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type) +{ + struct { + struct nlmsghdr nlh; + struct rtgenmsg g; + } req; + struct sockaddr_nl nladdr; + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + + req.nlh.nlmsg_len = sizeof(req); + req.nlh.nlmsg_type = type; + req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; + req.nlh.nlmsg_pid = 0; + req.nlh.nlmsg_seq = rth->dump = ++rth->seq; + req.g.rtgen_family = family; + + return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr)); +} + +int rtnl_send(struct rtnl_handle *rth, char *buf, int len) +{ + struct sockaddr_nl nladdr; + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + + return sendto(rth->fd, buf, len, 0, (struct sockaddr*)&nladdr, sizeof(nladdr)); +} + +int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) +{ + struct nlmsghdr nlh; + struct sockaddr_nl nladdr; + struct iovec iov[2] = { { &nlh, sizeof(nlh) }, { req, len } }; + struct msghdr msg = { + (void*)&nladdr, sizeof(nladdr), + iov, 2, + NULL, 0, + 0 + }; + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + + nlh.nlmsg_len = NLMSG_LENGTH(len); + nlh.nlmsg_type = type; + nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; + nlh.nlmsg_pid = 0; + nlh.nlmsg_seq = rth->dump = ++rth->seq; + + return sendmsg(rth->fd, &msg, 0); +} + +int rtnl_dump_filter(struct rtnl_handle *rth, + int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *), + void *arg1, + int (*junk)(struct sockaddr_nl *, struct nlmsghdr *n, void *), + void *arg2) +{ + char buf[8192]; + struct sockaddr_nl nladdr; + struct iovec iov = { buf, sizeof(buf) }; + + while (1) { + int status; + struct nlmsghdr *h; + + struct msghdr msg = { + (void*)&nladdr, sizeof(nladdr), + &iov, 1, + NULL, 0, + 0 + }; + + status = recvmsg(rth->fd, &msg, 0); + + if (status < 0) { + if (errno == EINTR) + continue; + bb_perror_msg("OVERRUN"); + continue; + } + if (status == 0) { + bb_error_msg("EOF on netlink"); + return -1; + } + if (msg.msg_namelen != sizeof(nladdr)) { + bb_error_msg_and_die("sender address length == %d", msg.msg_namelen); + } + + h = (struct nlmsghdr*)buf; + while (NLMSG_OK(h, status)) { + int err; + + if (nladdr.nl_pid != 0 || + h->nlmsg_pid != rth->local.nl_pid || + h->nlmsg_seq != rth->dump) { + if (junk) { + err = junk(&nladdr, h, arg2); + if (err < 0) { + return err; + } + } + goto skip_it; + } + + if (h->nlmsg_type == NLMSG_DONE) { + return 0; + } + if (h->nlmsg_type == NLMSG_ERROR) { + struct nlmsgerr *l_err = (struct nlmsgerr*)NLMSG_DATA(h); + if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { + bb_error_msg("ERROR truncated"); + } else { + errno = -l_err->error; + bb_perror_msg("RTNETLINK answers"); + } + return -1; + } + err = filter(&nladdr, h, arg1); + if (err < 0) { + return err; + } + +skip_it: + h = NLMSG_NEXT(h, status); + } + if (msg.msg_flags & MSG_TRUNC) { + bb_error_msg("message truncated"); + continue; + } + if (status) { + bb_error_msg_and_die("remnant of size %d!", status); + } + } +} + +int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, + unsigned groups, struct nlmsghdr *answer, + int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), + void *jarg) +{ + int status; + unsigned seq; + struct nlmsghdr *h; + struct sockaddr_nl nladdr; + struct iovec iov = { (void*)n, n->nlmsg_len }; + char buf[8192]; + struct msghdr msg = { + (void*)&nladdr, sizeof(nladdr), + &iov, 1, + NULL, 0, + 0 + }; + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + nladdr.nl_pid = peer; + nladdr.nl_groups = groups; + + n->nlmsg_seq = seq = ++rtnl->seq; + if (answer == NULL) { + n->nlmsg_flags |= NLM_F_ACK; + } + status = sendmsg(rtnl->fd, &msg, 0); + + if (status < 0) { + bb_perror_msg("cannot talk to rtnetlink"); + return -1; + } + + iov.iov_base = buf; + + while (1) { + iov.iov_len = sizeof(buf); + status = recvmsg(rtnl->fd, &msg, 0); + + if (status < 0) { + if (errno == EINTR) { + continue; + } + bb_perror_msg("OVERRUN"); + continue; + } + if (status == 0) { + bb_error_msg("EOF on netlink"); + return -1; + } + if (msg.msg_namelen != sizeof(nladdr)) { + bb_error_msg_and_die("sender address length == %d", msg.msg_namelen); + } + for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { + int l_err; + int len = h->nlmsg_len; + int l = len - sizeof(*h); + + if (l<0 || len>status) { + if (msg.msg_flags & MSG_TRUNC) { + bb_error_msg("truncated message"); + return -1; + } + bb_error_msg_and_die("malformed message: len=%d!", len); + } + + if (nladdr.nl_pid != peer || + h->nlmsg_pid != rtnl->local.nl_pid || + h->nlmsg_seq != seq) { + if (junk) { + l_err = junk(&nladdr, h, jarg); + if (l_err < 0) { + return l_err; + } + } + continue; + } + + if (h->nlmsg_type == NLMSG_ERROR) { + struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); + if (l < sizeof(struct nlmsgerr)) { + bb_error_msg("ERROR truncated"); + } else { + errno = -err->error; + if (errno == 0) { + if (answer) { + memcpy(answer, h, h->nlmsg_len); + } + return 0; + } + bb_perror_msg("RTNETLINK answers"); + } + return -1; + } + if (answer) { + memcpy(answer, h, h->nlmsg_len); + return 0; + } + + bb_error_msg("unexpected reply!"); + + status -= NLMSG_ALIGN(len); + h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); + } + if (msg.msg_flags & MSG_TRUNC) { + bb_error_msg("message truncated"); + continue; + } + if (status) { + bb_error_msg_and_die("remnant of size %d!", status); + } + } +} + +int addattr32(struct nlmsghdr *n, int maxlen, int type, uint32_t data) +{ + int len = RTA_LENGTH(4); + struct rtattr *rta; + if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) + return -1; + rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len)); + rta->rta_type = type; + rta->rta_len = len; + memcpy(RTA_DATA(rta), &data, 4); + n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len; + return 0; +} + +int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen) +{ + int len = RTA_LENGTH(alen); + struct rtattr *rta; + + if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) + return -1; + rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len)); + rta->rta_type = type; + rta->rta_len = len; + memcpy(RTA_DATA(rta), data, alen); + n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len; + return 0; +} + +int rta_addattr32(struct rtattr *rta, int maxlen, int type, uint32_t data) +{ + int len = RTA_LENGTH(4); + struct rtattr *subrta; + + if (RTA_ALIGN(rta->rta_len) + len > maxlen) { + return -1; + } + subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); + subrta->rta_type = type; + subrta->rta_len = len; + memcpy(RTA_DATA(subrta), &data, 4); + rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len; + return 0; +} + +int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen) +{ + struct rtattr *subrta; + int len = RTA_LENGTH(alen); + + if (RTA_ALIGN(rta->rta_len) + len > maxlen) { + return -1; + } + subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); + subrta->rta_type = type; + subrta->rta_len = len; + memcpy(RTA_DATA(subrta), data, alen); + rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len; + return 0; +} + + +int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) +{ + while (RTA_OK(rta, len)) { + if (rta->rta_type <= max) { + tb[rta->rta_type] = rta; + } + rta = RTA_NEXT(rta,len); + } + if (len) { + bb_error_msg("deficit %d, rta_len=%d!", len, rta->rta_len); + } + return 0; +} diff --git a/i/pc104/initrd/conf/busybox/networking/libiproute/libnetlink.h b/i/pc104/initrd/conf/busybox/networking/libiproute/libnetlink.h new file mode 100644 index 0000000..9a5a9d3 --- /dev/null +++ b/i/pc104/initrd/conf/busybox/networking/libiproute/libnetlink.h @@ -0,0 +1,43 @@ +/* vi: set sw=4 ts=4: */ +#ifndef __LIBNETLINK_H__ +#define __LIBNETLINK_H__ 1 + +#include +/* We need linux/types.h because older kernels use __u32 etc + * in linux/[rt]netlink.h. 2.6.19 seems to be ok, though */ +#include +#include + +struct rtnl_handle +{ + int fd; + struct sockaddr_nl local; + struct sockaddr_nl peer; + uint32_t seq; + uint32_t dump; +}; + +extern int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions); +extern void rtnl_close(struct rtnl_handle *rth); +extern int rtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type); +extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len); +extern int rtnl_dump_filter(struct rtnl_handle *rth, + int (*filter)(struct sockaddr_nl*, struct nlmsghdr *n, void*), + void *arg1, + int (*junk)(struct sockaddr_nl *, struct nlmsghdr *n, void *), + void *arg2); +extern int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, + unsigned groups, struct nlmsghdr *answer, + int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), + void *jarg); +extern int rtnl_send(struct rtnl_handle *rth, char *buf, int); + + +extern int addattr32(struct nlmsghdr *n, int maxlen, int type, uint32_t data); +extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen); +extern int rta_addattr32(struct rtattr *rta, int maxlen, int type, uint32_t data); +extern int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen); + +extern int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len); + +#endif /* __LIBNETLINK_H__ */ diff --git a/i/pc104/initrd/conf/busybox/networking/libiproute/ll_addr.c b/i/pc104/initrd/conf/busybox/networking/libiproute/ll_addr.c new file mode 100644 index 0000000..b4a2187 --- /dev/null +++ b/i/pc104/initrd/conf/busybox/networking/libiproute/ll_addr.c @@ -0,0 +1,85 @@ +/* vi: set sw=4 ts=4: */ +/* + * ll_addr.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, + */ + +#include "libbb.h" + +#include +#include + +#include "rt_names.h" +#include "utils.h" + + +const char *ll_addr_n2a(unsigned char *addr, int alen, int type, char *buf, int blen) +{ + int i; + int l; + + if (alen == 4 && + (type == ARPHRD_TUNNEL || type == ARPHRD_SIT || type == ARPHRD_IPGRE)) { + return inet_ntop(AF_INET, addr, buf, blen); + } + l = 0; + for (i=0; i 255) { + bb_error_msg("\"%s\" is invalid lladdr", arg); + return -1; + } + lladdr[i] = temp; + if (!cp) { + break; + } + arg = cp; + } + return i+1; + } +} diff --git a/i/pc104/initrd/conf/busybox/networking/libiproute/ll_map.c b/i/pc104/initrd/conf/busybox/networking/libiproute/ll_map.c new file mode 100644 index 0000000..f429763 --- /dev/null +++ b/i/pc104/initrd/conf/busybox/networking/libiproute/ll_map.c @@ -0,0 +1,186 @@ +/* vi: set sw=4 ts=4: */ +/* + * ll_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, + * + */ + +#include "libbb.h" +#include + +#include "libnetlink.h" +#include "ll_map.h" + +#include /* socket() */ +#include /* struct ifreq and co. */ +#include /* ioctl() & SIOCGIFINDEX */ + +struct idxmap { + struct idxmap * next; + int index; + int type; + int alen; + unsigned flags; + unsigned char addr[8]; + char name[16]; +}; + +static struct idxmap *idxmap[16]; + +int ll_remember_index(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) +{ + int h; + struct ifinfomsg *ifi = NLMSG_DATA(n); + struct idxmap *im, **imp; + struct rtattr *tb[IFLA_MAX+1]; + + if (n->nlmsg_type != RTM_NEWLINK) + return 0; + + if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi))) + return -1; + + + memset(tb, 0, sizeof(tb)); + parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n)); + if (tb[IFLA_IFNAME] == NULL) + return 0; + + h = ifi->ifi_index&0xF; + + for (imp=&idxmap[h]; (im=*imp)!=NULL; imp = &im->next) + if (im->index == ifi->ifi_index) + break; + + if (im == NULL) { + im = xmalloc(sizeof(*im)); + im->next = *imp; + im->index = ifi->ifi_index; + *imp = im; + } + + im->type = ifi->ifi_type; + im->flags = ifi->ifi_flags; + if (tb[IFLA_ADDRESS]) { + int alen; + im->alen = alen = RTA_PAYLOAD(tb[IFLA_ADDRESS]); + if (alen > sizeof(im->addr)) + alen = sizeof(im->addr); + memcpy(im->addr, RTA_DATA(tb[IFLA_ADDRESS]), alen); + } else { + im->alen = 0; + memset(im->addr, 0, sizeof(im->addr)); + } + strcpy(im->name, RTA_DATA(tb[IFLA_IFNAME])); + return 0; +} + +const char *ll_idx_n2a(int idx, char *buf) +{ + struct idxmap *im; + + if (idx == 0) + return "*"; + for (im = idxmap[idx&0xF]; im; im = im->next) + if (im->index == idx) + return im->name; + snprintf(buf, 16, "if%d", idx); + return buf; +} + + +const char *ll_index_to_name(int idx) +{ + static char nbuf[16]; + + return ll_idx_n2a(idx, nbuf); +} + +int ll_index_to_type(int idx) +{ + struct idxmap *im; + + if (idx == 0) + return -1; + for (im = idxmap[idx&0xF]; im; im = im->next) + if (im->index == idx) + return im->type; + return -1; +} + +unsigned ll_index_to_flags(int idx) +{ + struct idxmap *im; + + if (idx == 0) + return 0; + + for (im = idxmap[idx&0xF]; im; im = im->next) + if (im->index == idx) + return im->flags; + return 0; +} + +int ll_name_to_index(char *name) +{ + static char ncache[16]; + static int icache; + struct idxmap *im; + int sock_fd; + int i; + + if (name == NULL) + return 0; + if (icache && strcmp(name, ncache) == 0) + return icache; + for (i=0; i<16; i++) { + for (im = idxmap[i]; im; im = im->next) { + if (strcmp(im->name, name) == 0) { + icache = im->index; + strcpy(ncache, name); + return im->index; + } + } + } + /* We have not found the interface in our cache, but the kernel + * may still know about it. One reason is that we may be using + * module on-demand loading, which means that the kernel will + * load the module and make the interface exist only when + * we explicitely request it (check for dev_load() in net/core/dev.c). + * I can think of other similar scenario, but they are less common... + * Jean II */ + sock_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (sock_fd) { + struct ifreq ifr; + int ret; + strncpy(ifr.ifr_name, name, IFNAMSIZ); + ifr.ifr_ifindex = -1; + ret = ioctl(sock_fd, SIOCGIFINDEX, &ifr); + close(sock_fd); + if (ret >= 0) + /* In theory, we should redump the interface list + * to update our cache, this is left as an exercise + * to the reader... Jean II */ + return ifr.ifr_ifindex; + } + + return 0; +} + +int ll_init_map(struct rtnl_handle *rth) +{ + if (rtnl_wilddump_request(rth, AF_UNSPEC, RTM_GETLINK) < 0) { + bb_perror_msg_and_die("cannot send dump request"); + } + + if (rtnl_dump_filter(rth, ll_remember_index, &idxmap, NULL, NULL) < 0) { + bb_error_msg_and_die("dump terminated"); + } + return 0; +} diff --git a/i/pc104/initrd/conf/busybox/networking/libiproute/ll_map.h b/i/pc104/initrd/conf/busybox/networking/libiproute/ll_map.h new file mode 100644 index 0000000..226d48f --- /dev/null +++ b/i/pc104/initrd/conf/busybox/networking/libiproute/ll_map.h @@ -0,0 +1,13 @@ +/* vi: set sw=4 ts=4: */ +#ifndef __LL_MAP_H__ +#define __LL_MAP_H__ 1 + +extern int ll_remember_index(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); +extern int ll_init_map(struct rtnl_handle *rth); +extern int ll_name_to_index(char *name); +extern const char *ll_index_to_name(int idx); +extern const char *ll_idx_n2a(int idx, char *buf); +extern int ll_index_to_type(int idx); +extern unsigned ll_index_to_flags(int idx); + +#endif /* __LL_MAP_H__ */ diff --git a/i/pc104/initrd/conf/busybox/networking/libiproute/ll_proto.c b/i/pc104/initrd/conf/busybox/networking/libiproute/ll_proto.c new file mode 100644 index 0000000..aad460b --- /dev/null +++ b/i/pc104/initrd/conf/busybox/networking/libiproute/ll_proto.c @@ -0,0 +1,121 @@ +/* vi: set sw=4 ts=4: */ +/* + * ll_proto.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, + */ + +#include "libbb.h" + +#include "rt_names.h" +#include "utils.h" + +#if defined(__GLIBC__) && __GLIBC__ >=2 && __GLIBC_MINOR__ >= 1 +#include +#else +#include +#endif + +#define __PF(f,n) { ETH_P_##f, #n }, +static struct { + int id; + const char *name; +} llproto_names[] = { +__PF(LOOP,loop) +__PF(PUP,pup) +#ifdef ETH_P_PUPAT +__PF(PUPAT,pupat) +#endif +__PF(IP,ip) +__PF(X25,x25) +__PF(ARP,arp) +__PF(BPQ,bpq) +#ifdef ETH_P_IEEEPUP +__PF(IEEEPUP,ieeepup) +#endif +#ifdef ETH_P_IEEEPUPAT +__PF(IEEEPUPAT,ieeepupat) +#endif +__PF(DEC,dec) +__PF(DNA_DL,dna_dl) +__PF(DNA_RC,dna_rc) +__PF(DNA_RT,dna_rt) +__PF(LAT,lat) +__PF(DIAG,diag) +__PF(CUST,cust) +__PF(SCA,sca) +__PF(RARP,rarp) +__PF(ATALK,atalk) +__PF(AARP,aarp) +__PF(IPX,ipx) +__PF(IPV6,ipv6) +#ifdef ETH_P_PPP_DISC +__PF(PPP_DISC,ppp_disc) +#endif +#ifdef ETH_P_PPP_SES +__PF(PPP_SES,ppp_ses) +#endif +#ifdef ETH_P_ATMMPOA +__PF(ATMMPOA,atmmpoa) +#endif +#ifdef ETH_P_ATMFATE +__PF(ATMFATE,atmfate) +#endif + +__PF(802_3,802_3) +__PF(AX25,ax25) +__PF(ALL,all) +__PF(802_2,802_2) +__PF(SNAP,snap) +__PF(DDCMP,ddcmp) +__PF(WAN_PPP,wan_ppp) +__PF(PPP_MP,ppp_mp) +__PF(LOCALTALK,localtalk) +__PF(PPPTALK,ppptalk) +__PF(TR_802_2,tr_802_2) +__PF(MOBITEX,mobitex) +__PF(CONTROL,control) +__PF(IRDA,irda) +#ifdef ETH_P_ECONET +__PF(ECONET,econet) +#endif + +{ 0x8100, "802.1Q" }, +{ ETH_P_IP, "ipv4" }, +}; +#undef __PF + + +const char * ll_proto_n2a(unsigned short id, char *buf, int len) +{ + int i; + + id = ntohs(id); + + for (i=0; i + */ +#include +#include +#include + +#include "rt_names.h" + +const char* ll_type_n2a(int type, char *buf, int len) +{ +#define __PF(f,n) { ARPHRD_##f, #n }, +static const struct { + int type; + const char *name; +} arphrd_names[] = { +{ 0, "generic" }, +__PF(ETHER,ether) +__PF(EETHER,eether) +__PF(AX25,ax25) +__PF(PRONET,pronet) +__PF(CHAOS,chaos) +#ifdef ARPHRD_IEEE802_TR +__PF(IEEE802,ieee802) +#else +__PF(IEEE802,tr) +#endif +__PF(ARCNET,arcnet) +__PF(APPLETLK,atalk) +__PF(DLCI,dlci) +#ifdef ARPHRD_ATM +__PF(ATM,atm) +#endif +__PF(METRICOM,metricom) +#ifdef ARPHRD_IEEE1394 +__PF(IEEE1394,ieee1394) +#endif + +__PF(SLIP,slip) +__PF(CSLIP,cslip) +__PF(SLIP6,slip6) +__PF(CSLIP6,cslip6) +__PF(RSRVD,rsrvd) +__PF(ADAPT,adapt) +__PF(ROSE,rose) +__PF(X25,x25) +#ifdef ARPHRD_HWX25 +__PF(HWX25,hwx25) +#endif +__PF(PPP,ppp) +__PF(HDLC,hdlc) +__PF(LAPB,lapb) +#ifdef ARPHRD_DDCMP +__PF(DDCMP,ddcmp) +__PF(RAWHDLC,rawhdlc) +#endif + +__PF(TUNNEL,ipip) +__PF(TUNNEL6,tunnel6) +__PF(FRAD,frad) +__PF(SKIP,skip) +__PF(LOOPBACK,loopback) +__PF(LOCALTLK,ltalk) +__PF(FDDI,fddi) +__PF(BIF,bif) +__PF(SIT,sit) +__PF(IPDDP,ip/ddp) +__PF(IPGRE,gre) +__PF(PIMREG,pimreg) +__PF(HIPPI,hippi) +__PF(ASH,ash) +__PF(ECONET,econet) +__PF(IRDA,irda) +__PF(FCPP,fcpp) +__PF(FCAL,fcal) +__PF(FCPL,fcpl) +__PF(FCFABRIC,fcfb0) +__PF(FCFABRIC+1,fcfb1) +__PF(FCFABRIC+2,fcfb2) +__PF(FCFABRIC+3,fcfb3) +__PF(FCFABRIC+4,fcfb4) +__PF(FCFABRIC+5,fcfb5) +__PF(FCFABRIC+6,fcfb6) +__PF(FCFABRIC+7,fcfb7) +__PF(FCFABRIC+8,fcfb8) +__PF(FCFABRIC+9,fcfb9) +__PF(FCFABRIC+10,fcfb10) +__PF(FCFABRIC+11,fcfb11) +__PF(FCFABRIC+12,fcfb12) +#ifdef ARPHRD_IEEE802_TR +__PF(IEEE802_TR,tr) +#endif +#ifdef ARPHRD_IEEE80211 +__PF(IEEE80211,ieee802.11) +#endif +#ifdef ARPHRD_VOID +__PF(VOID,void) +#endif +}; +#undef __PF + + int i; + for (i = 0; i < sizeof(arphrd_names)/sizeof(arphrd_names[0]); i++) { + if (arphrd_names[i].type == type) + return arphrd_names[i].name; + } + snprintf(buf, len, "[%d]", type); + return buf; +} diff --git a/i/pc104/initrd/conf/busybox/networking/libiproute/rt_names.c b/i/pc104/initrd/conf/busybox/networking/libiproute/rt_names.c new file mode 100644 index 0000000..797c83b --- /dev/null +++ b/i/pc104/initrd/conf/busybox/networking/libiproute/rt_names.c @@ -0,0 +1,365 @@ +/* vi: set sw=4 ts=4: */ +/* + * rt_names.c rtnetlink names DB. + * + * 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, + */ + +#include "libbb.h" +#include "rt_names.h" + +static void rtnl_tab_initialize(const char *file, const char **tab, int size) +{ + char buf[512]; + FILE *fp; + + fp = fopen(file, "r"); + if (!fp) + return; + while (fgets(buf, sizeof(buf), fp)) { + char *p = buf; + int id; + char namebuf[512]; + + while (*p == ' ' || *p == '\t') + p++; + if (*p == '#' || *p == '\n' || *p == 0) + continue; + if (sscanf(p, "0x%x %s\n", &id, namebuf) != 2 + && sscanf(p, "0x%x %s #", &id, namebuf) != 2 + && sscanf(p, "%d %s\n", &id, namebuf) != 2 + && sscanf(p, "%d %s #", &id, namebuf) != 2 + ) { + bb_error_msg("database %s is corrupted at %s", + file, p); + return; + } + + if (id < 0 || id > size) + continue; + + tab[id] = xstrdup(namebuf); + } + fclose(fp); +} + + +static const char **rtnl_rtprot_tab; /* [256] */ + +static void rtnl_rtprot_initialize(void) +{ + static const char *const init_tab[] = { + "none", + "redirect", + "kernel", + "boot", + "static", + NULL, + NULL, + NULL, + "gated", + "ra", + "mrt", + "zebra", + "bird", + }; + if (rtnl_rtprot_tab) return; + rtnl_rtprot_tab = xzalloc(256 * sizeof(rtnl_rtprot_tab[0])); + memcpy(rtnl_rtprot_tab, init_tab, sizeof(init_tab)); + rtnl_tab_initialize("/etc/iproute2/rt_protos", + rtnl_rtprot_tab, 256); +} + + +const char* rtnl_rtprot_n2a(int id, char *buf, int len) +{ + if (id < 0 || id >= 256) { + snprintf(buf, len, "%d", id); + return buf; + } + + rtnl_rtprot_initialize(); + + if (rtnl_rtprot_tab[id]) + return rtnl_rtprot_tab[id]; + snprintf(buf, len, "%d", id); + return buf; +} + +int rtnl_rtprot_a2n(uint32_t *id, char *arg) +{ + static const char *cache = NULL; + static unsigned long res; + int i; + + if (cache && strcmp(cache, arg) == 0) { + *id = res; + return 0; + } + + rtnl_rtprot_initialize(); + + for (i = 0; i < 256; i++) { + if (rtnl_rtprot_tab[i] && + strcmp(rtnl_rtprot_tab[i], arg) == 0) { + cache = rtnl_rtprot_tab[i]; + res = i; + *id = res; + return 0; + } + } + + res = bb_strtoul(arg, NULL, 0); + if (errno || res > 255) + return -1; + *id = res; + return 0; +} + + +static const char **rtnl_rtscope_tab; /* [256] */ + +static void rtnl_rtscope_initialize(void) +{ + if (rtnl_rtscope_tab) return; + rtnl_rtscope_tab = xzalloc(256 * sizeof(rtnl_rtscope_tab[0])); + rtnl_rtscope_tab[0] = "global"; + rtnl_rtscope_tab[255] = "nowhere"; + rtnl_rtscope_tab[254] = "host"; + rtnl_rtscope_tab[253] = "link"; + rtnl_rtscope_tab[200] = "site"; + rtnl_tab_initialize("/etc/iproute2/rt_scopes", + rtnl_rtscope_tab, 256); +} + + +const char* rtnl_rtscope_n2a(int id, char *buf, int len) +{ + if (id < 0 || id >= 256) { + snprintf(buf, len, "%d", id); + return buf; + } + + rtnl_rtscope_initialize(); + + if (rtnl_rtscope_tab[id]) + return rtnl_rtscope_tab[id]; + snprintf(buf, len, "%d", id); + return buf; +} + +int rtnl_rtscope_a2n(uint32_t *id, char *arg) +{ + static const char *cache = NULL; + static unsigned long res; + int i; + + if (cache && strcmp(cache, arg) == 0) { + *id = res; + return 0; + } + + rtnl_rtscope_initialize(); + + for (i = 0; i < 256; i++) { + if (rtnl_rtscope_tab[i] && + strcmp(rtnl_rtscope_tab[i], arg) == 0) { + cache = rtnl_rtscope_tab[i]; + res = i; + *id = res; + return 0; + } + } + + res = bb_strtoul(arg, NULL, 0); + if (errno || res > 255) + return -1; + *id = res; + return 0; +} + + +static const char **rtnl_rtrealm_tab; /* [256] */ + +static void rtnl_rtrealm_initialize(void) +{ + if (rtnl_rtrealm_tab) return; + rtnl_rtrealm_tab = xzalloc(256 * sizeof(rtnl_rtrealm_tab[0])); + rtnl_rtrealm_tab[0] = "unknown"; + rtnl_tab_initialize("/etc/iproute2/rt_realms", + rtnl_rtrealm_tab, 256); +} + + +int rtnl_rtrealm_a2n(uint32_t *id, char *arg) +{ + static const char *cache = NULL; + static unsigned long res; + int i; + + if (cache && strcmp(cache, arg) == 0) { + *id = res; + return 0; + } + + rtnl_rtrealm_initialize(); + + for (i = 0; i < 256; i++) { + if (rtnl_rtrealm_tab[i] && + strcmp(rtnl_rtrealm_tab[i], arg) == 0) { + cache = rtnl_rtrealm_tab[i]; + res = i; + *id = res; + return 0; + } + } + + res = bb_strtoul(arg, NULL, 0); + if (errno || res > 255) + return -1; + *id = res; + return 0; +} + +#if ENABLE_FEATURE_IP_RULE +const char* rtnl_rtrealm_n2a(int id, char *buf, int len) +{ + if (id < 0 || id >= 256) { + snprintf(buf, len, "%d", id); + return buf; + } + + rtnl_rtrealm_initialize(); + + if (rtnl_rtrealm_tab[id]) + return rtnl_rtrealm_tab[id]; + snprintf(buf, len, "%d", id); + return buf; +} +#endif + + +static const char **rtnl_rtdsfield_tab; /* [256] */ + +static void rtnl_rtdsfield_initialize(void) +{ + if (rtnl_rtdsfield_tab) return; + rtnl_rtdsfield_tab = xzalloc(256 * sizeof(rtnl_rtdsfield_tab[0])); + rtnl_rtdsfield_tab[0] = "0"; + rtnl_tab_initialize("/etc/iproute2/rt_dsfield", + rtnl_rtdsfield_tab, 256); +} + + +const char * rtnl_dsfield_n2a(int id, char *buf, int len) +{ + if (id < 0 || id >= 256) { + snprintf(buf, len, "%d", id); + return buf; + } + + rtnl_rtdsfield_initialize(); + + if (rtnl_rtdsfield_tab[id]) + return rtnl_rtdsfield_tab[id]; + snprintf(buf, len, "0x%02x", id); + return buf; +} + + +int rtnl_dsfield_a2n(uint32_t *id, char *arg) +{ + static const char *cache = NULL; + static unsigned long res; + int i; + + if (cache && strcmp(cache, arg) == 0) { + *id = res; + return 0; + } + + rtnl_rtdsfield_initialize(); + + for (i = 0; i < 256; i++) { + if (rtnl_rtdsfield_tab[i] && + strcmp(rtnl_rtdsfield_tab[i], arg) == 0) { + cache = rtnl_rtdsfield_tab[i]; + res = i; + *id = res; + return 0; + } + } + + res = bb_strtoul(arg, NULL, 16); + if (errno || res > 255) + return -1; + *id = res; + return 0; +} + + +#if ENABLE_FEATURE_IP_RULE +static const char **rtnl_rttable_tab; /* [256] */ + +static void rtnl_rttable_initialize(void) +{ + if (rtnl_rtdsfield_tab) return; + rtnl_rttable_tab = xzalloc(256 * sizeof(rtnl_rttable_tab[0])); + rtnl_rttable_tab[0] = "unspec"; + rtnl_rttable_tab[255] = "local"; + rtnl_rttable_tab[254] = "main"; + rtnl_rttable_tab[253] = "default"; + rtnl_tab_initialize("/etc/iproute2/rt_tables", rtnl_rttable_tab, 256); +} + + +const char *rtnl_rttable_n2a(int id, char *buf, int len) +{ + if (id < 0 || id >= 256) { + snprintf(buf, len, "%d", id); + return buf; + } + + rtnl_rttable_initialize(); + + if (rtnl_rttable_tab[id]) + return rtnl_rttable_tab[id]; + snprintf(buf, len, "%d", id); + return buf; +} + +int rtnl_rttable_a2n(uint32_t * id, char *arg) +{ + static char *cache = NULL; + static unsigned long res; + int i; + + if (cache && strcmp(cache, arg) == 0) { + *id = res; + return 0; + } + + rtnl_rttable_initialize(); + + for (i = 0; i < 256; i++) { + if (rtnl_rttable_tab[i] && strcmp(rtnl_rttable_tab[i], arg) == 0) { + cache = (char*)rtnl_rttable_tab[i]; + res = i; + *id = res; + return 0; + } + } + + i = bb_strtoul(arg, NULL, 0); + if (errno || i > 255) + return -1; + *id = i; + return 0; +} + +#endif diff --git a/i/pc104/initrd/conf/busybox/networking/libiproute/rt_names.h b/i/pc104/initrd/conf/busybox/networking/libiproute/rt_names.h new file mode 100644 index 0000000..98c22b0 --- /dev/null +++ b/i/pc104/initrd/conf/busybox/networking/libiproute/rt_names.h @@ -0,0 +1,28 @@ +/* vi: set sw=4 ts=4: */ +#ifndef RT_NAMES_H_ +#define RT_NAMES_H_ 1 + +#include + +extern const char* rtnl_rtprot_n2a(int id, char *buf, int len); +extern const char* rtnl_rtscope_n2a(int id, char *buf, int len); +extern const char* rtnl_rtrealm_n2a(int id, char *buf, int len); +extern const char* rtnl_dsfield_n2a(int id, char *buf, int len); +extern const char* rtnl_rttable_n2a(int id, char *buf, int len); +extern int rtnl_rtprot_a2n(uint32_t *id, char *arg); +extern int rtnl_rtscope_a2n(uint32_t *id, char *arg); +extern int rtnl_rtrealm_a2n(uint32_t *id, char *arg); +extern int rtnl_dsfield_a2n(uint32_t *id, char *arg); +extern int rtnl_rttable_a2n(uint32_t *id, char *arg); + + +extern const char* ll_type_n2a(int type, char *buf, int len); + +extern const char* ll_addr_n2a(unsigned char *addr, int alen, int type, + char *buf, int blen); +extern int ll_addr_a2n(unsigned char *lladdr, int len, char *arg); + +extern const char* ll_proto_n2a(unsigned short id, char *buf, int len); +extern int ll_proto_a2n(unsigned short *id, char *buf); + +#endif diff --git a/i/pc104/initrd/conf/busybox/networking/libiproute/rtm_map.c b/i/pc104/initrd/conf/busybox/networking/libiproute/rtm_map.c new file mode 100644 index 0000000..c16406b --- /dev/null +++ b/i/pc104/initrd/conf/busybox/networking/libiproute/rtm_map.c @@ -0,0 +1,110 @@ +/* vi: set sw=4 ts=4: */ +/* + * 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, + * + */ + +#include +#include +#include "rt_names.h" +#include "utils.h" + +const 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(uint32_t *realms, char *arg) +{ + uint32_t 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/i/pc104/initrd/conf/busybox/networking/libiproute/rtm_map.h b/i/pc104/initrd/conf/busybox/networking/libiproute/rtm_map.h new file mode 100644 index 0000000..cbbcc21 --- /dev/null +++ b/i/pc104/initrd/conf/busybox/networking/libiproute/rtm_map.h @@ -0,0 +1,11 @@ +/* vi: set sw=4 ts=4: */ +#ifndef __RTM_MAP_H__ +#define __RTM_MAP_H__ 1 + +const char *rtnl_rtntype_n2a(int id, char *buf, int len); +int rtnl_rtntype_a2n(int *id, char *arg); + +int get_rt_realms(uint32_t *realms, char *arg); + + +#endif /* __RTM_MAP_H__ */ diff --git a/i/pc104/initrd/conf/busybox/networking/libiproute/utils.c b/i/pc104/initrd/conf/busybox/networking/libiproute/utils.c new file mode 100644 index 0000000..591c893 --- /dev/null +++ b/i/pc104/initrd/conf/busybox/networking/libiproute/utils.c @@ -0,0 +1,330 @@ +/* vi: set sw=4 ts=4: */ +/* + * utils.c + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * + * Authors: Alexey Kuznetsov, + * + * Changes: + * + * Rani Assaf 980929: resolve addresses + */ + +#include "libbb.h" + +#include +#include + +#include "utils.h" +#include "inet_common.h" + +int get_integer(int *val, char *arg, int base) +{ + long res; + char *ptr; + + if (!arg || !*arg) + return -1; + res = strtol(arg, &ptr, base); + if (!ptr || ptr == arg || *ptr || res > INT_MAX || res < INT_MIN) + return -1; + *val = res; + return 0; +} + +int get_unsigned(unsigned *val, char *arg, int base) +{ + unsigned long res; + char *ptr; + + if (!arg || !*arg) + return -1; + res = strtoul(arg, &ptr, base); + if (!ptr || ptr == arg || *ptr || res > UINT_MAX) + return -1; + *val = res; + return 0; +} + +int get_u32(uint32_t * val, char *arg, int base) +{ + unsigned long res; + char *ptr; + + if (!arg || !*arg) + return -1; + res = strtoul(arg, &ptr, base); + if (!ptr || ptr == arg || *ptr || res > 0xFFFFFFFFUL) + return -1; + *val = res; + return 0; +} + +int get_u16(uint16_t * val, char *arg, int base) +{ + unsigned long res; + char *ptr; + + if (!arg || !*arg) + return -1; + res = strtoul(arg, &ptr, base); + if (!ptr || ptr == arg || *ptr || res > 0xFFFF) + return -1; + *val = res; + return 0; +} + +int get_u8(uint8_t * val, char *arg, int base) +{ + unsigned long res; + char *ptr; + + if (!arg || !*arg) + return -1; + res = strtoul(arg, &ptr, base); + if (!ptr || ptr == arg || *ptr || res > 0xFF) + return -1; + *val = res; + return 0; +} + +int get_s16(int16_t * val, char *arg, int base) +{ + long res; + char *ptr; + + if (!arg || !*arg) + return -1; + res = strtol(arg, &ptr, base); + if (!ptr || ptr == arg || *ptr || res > 0x7FFF || res < -0x8000) + return -1; + *val = res; + return 0; +} + +int get_s8(int8_t * val, char *arg, int base) +{ + long res; + char *ptr; + + if (!arg || !*arg) + return -1; + res = strtol(arg, &ptr, base); + if (!ptr || ptr == arg || *ptr || res > 0x7F || res < -0x80) + return -1; + *val = res; + return 0; +} + +int get_addr_1(inet_prefix * addr, char *name, int family) +{ + char *cp; + unsigned char *ap = (unsigned char *) addr->data; + int i; + + memset(addr, 0, sizeof(*addr)); + + if (strcmp(name, bb_str_default) == 0 || + strcmp(name, "all") == 0 || strcmp(name, "any") == 0) { + addr->family = family; + addr->bytelen = (family == AF_INET6 ? 16 : 4); + addr->bitlen = -1; + return 0; + } + + if (strchr(name, ':')) { + addr->family = AF_INET6; + if (family != AF_UNSPEC && family != AF_INET6) + return -1; + if (inet_pton(AF_INET6, name, addr->data) <= 0) + return -1; + addr->bytelen = 16; + addr->bitlen = -1; + return 0; + } + + addr->family = AF_INET; + if (family != AF_UNSPEC && family != AF_INET) + return -1; + addr->bytelen = 4; + addr->bitlen = -1; + for (cp = name, i = 0; *cp; cp++) { + if (*cp <= '9' && *cp >= '0') { + ap[i] = 10 * ap[i] + (*cp - '0'); + continue; + } + if (*cp == '.' && ++i <= 3) + continue; + return -1; + } + return 0; +} + +int get_prefix_1(inet_prefix * dst, char *arg, int family) +{ + int err; + int plen; + char *slash; + + memset(dst, 0, sizeof(*dst)); + + if (strcmp(arg, bb_str_default) == 0 || strcmp(arg, "any") == 0) { + dst->family = family; + dst->bytelen = 0; + dst->bitlen = 0; + return 0; + } + + slash = strchr(arg, '/'); + if (slash) + *slash = '\0'; + err = get_addr_1(dst, arg, family); + if (err == 0) { + switch (dst->family) { + case AF_INET6: + dst->bitlen = 128; + break; + default: + case AF_INET: + dst->bitlen = 32; + } + if (slash) { + if (get_integer(&plen, slash + 1, 0) || plen > dst->bitlen) { + err = -1; + goto done; + } + dst->bitlen = plen; + } + } + done: + if (slash) + *slash = '/'; + return err; +} + +int get_addr(inet_prefix * dst, char *arg, int family) +{ + if (family == AF_PACKET) { + bb_error_msg_and_die("\"%s\" may be inet address, but it is not allowed in this context", arg); + } + if (get_addr_1(dst, arg, family)) { + bb_error_msg_and_die("an inet address is expected rather than \"%s\"", arg); + } + return 0; +} + +int get_prefix(inet_prefix * dst, char *arg, int family) +{ + if (family == AF_PACKET) { + bb_error_msg_and_die("\"%s\" may be inet address, but it is not allowed in this context", arg); + } + if (get_prefix_1(dst, arg, family)) { + bb_error_msg_and_die("an inet address is expected rather than \"%s\"", arg); + } + return 0; +} + +uint32_t get_addr32(char *name) +{ + inet_prefix addr; + + if (get_addr_1(&addr, name, AF_INET)) { + bb_error_msg_and_die("an IP address is expected rather than \"%s\"", name); + } + return addr.data[0]; +} + +void incomplete_command(void) +{ + bb_error_msg_and_die("command line is not complete, try option \"help\""); +} + +void invarg(const char *arg, const char *opt) +{ + bb_error_msg_and_die(bb_msg_invalid_arg, arg, opt); +} + +void duparg(const char *key, const char *arg) +{ + bb_error_msg_and_die("duplicate \"%s\": \"%s\" is the second value", key, arg); +} + +void duparg2(const char *key, const char *arg) +{ + bb_error_msg_and_die("either \"%s\" is duplicate, or \"%s\" is garbage", key, arg); +} + +int matches(const char *cmd, const char *pattern) +{ + int len = strlen(cmd); + + return strncmp(pattern, cmd, len); +} + +int inet_addr_match(inet_prefix * a, inet_prefix * b, int bits) +{ + uint32_t *a1 = a->data; + uint32_t *a2 = b->data; + int words = bits >> 0x05; + + bits &= 0x1f; + + if (words) + if (memcmp(a1, a2, words << 2)) + return -1; + + if (bits) { + uint32_t w1, w2; + uint32_t mask; + + w1 = a1[words]; + w2 = a2[words]; + + mask = htonl((0xffffffff) << (0x20 - bits)); + + if ((w1 ^ w2) & mask) + return 1; + } + + return 0; +} + +const char *rt_addr_n2a(int af, int ATTRIBUTE_UNUSED len, + void *addr, char *buf, int buflen) +{ + switch (af) { + case AF_INET: + case AF_INET6: + return inet_ntop(af, addr, buf, buflen); + default: + return "???"; + } +} + + +const char *format_host(int af, int len, void *addr, char *buf, int buflen) +{ +#ifdef RESOLVE_HOSTNAMES + if (resolve_hosts) { + struct hostent *h_ent; + + if (len <= 0) { + switch (af) { + case AF_INET: + len = 4; + break; + case AF_INET6: + len = 16; + break; + default:; + } + } + if (len > 0 && (h_ent = gethostbyaddr(addr, len, af)) != NULL) { + snprintf(buf, buflen - 1, "%s", h_ent->h_name); + return buf; + } + } +#endif + return rt_addr_n2a(af, len, addr, buf, buflen); +} diff --git a/i/pc104/initrd/conf/busybox/networking/libiproute/utils.h b/i/pc104/initrd/conf/busybox/networking/libiproute/utils.h new file mode 100644 index 0000000..556541f --- /dev/null +++ b/i/pc104/initrd/conf/busybox/networking/libiproute/utils.h @@ -0,0 +1,91 @@ +/* vi: set sw=4 ts=4: */ +#ifndef __UTILS_H__ +#define __UTILS_H__ 1 + +#include "libbb.h" + +#include "libnetlink.h" +#include "ll_map.h" +#include "rtm_map.h" + +extern int preferred_family; +extern int show_stats; +extern int show_details; +extern int show_raw; +extern int resolve_hosts; +extern int oneline; +//FIXME! Appears in two .h files! +extern const char * _SL_; + +#ifndef IPPROTO_ESP +#define IPPROTO_ESP 50 +#endif +#ifndef IPPROTO_AH +#define IPPROTO_AH 51 +#endif + +#define SPRINT_BSIZE 64 +#define SPRINT_BUF(x) char x[SPRINT_BSIZE] + +extern void incomplete_command(void) ATTRIBUTE_NORETURN; + +#define NEXT_ARG() do { argv++; if (--argc <= 0) incomplete_command(); } while (0) + +typedef struct +{ + uint8_t family; + uint8_t bytelen; + int16_t bitlen; + uint32_t data[4]; +} inet_prefix; + +#define DN_MAXADDL 20 +#ifndef AF_DECnet +#define AF_DECnet 12 +#endif + +struct dn_naddr { + unsigned short a_len; + unsigned char a_addr[DN_MAXADDL]; +}; + +#define IPX_NODE_LEN 6 + +struct ipx_addr { + uint32_t ipx_net; + uint8_t ipx_node[IPX_NODE_LEN]; +}; + +extern uint32_t get_addr32(char *name); +extern int get_addr_1(inet_prefix *dst, char *arg, int family); +extern int get_prefix_1(inet_prefix *dst, char *arg, int family); +extern int get_addr(inet_prefix *dst, char *arg, int family); +extern int get_prefix(inet_prefix *dst, char *arg, int family); + +extern int get_integer(int *val, char *arg, int base); +extern int get_unsigned(unsigned *val, char *arg, int base); +#define get_byte get_u8 +#define get_ushort get_u16 +#define get_short get_s16 +extern int get_u32(uint32_t *val, char *arg, int base); +extern int get_u16(uint16_t *val, char *arg, int base); +extern int get_s16(int16_t *val, char *arg, int base); +extern int get_u8(uint8_t *val, char *arg, int base); +extern int get_s8(int8_t *val, char *arg, int base); + +extern const char *format_host(int af, int len, void *addr, char *buf, int buflen); +extern const char *rt_addr_n2a(int af, int len, void *addr, char *buf, int buflen); + +void invarg(const char *, const char *) ATTRIBUTE_NORETURN; +void duparg(const char *, const char *) ATTRIBUTE_NORETURN; +void duparg2(const char *, const char *) ATTRIBUTE_NORETURN; +int matches(const char *arg, const char *pattern); +extern int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits); + +const char *dnet_ntop(int af, const void *addr, char *str, size_t len); +int dnet_pton(int af, const char *src, void *addr); + +const char *ipx_ntop(int af, const void *addr, char *str, size_t len); +int ipx_pton(int af, const char *src, void *addr); + +#endif /* __UTILS_H__ */ -- cgit v1.2.3