14c91a5dfSAlexander V. Chernikov /*- 24c91a5dfSAlexander V. Chernikov * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 34c91a5dfSAlexander V. Chernikov * 44c91a5dfSAlexander V. Chernikov * Copyright (c) 2022 Alexander V. Chernikov <melifaro@FreeBSD.org> 54c91a5dfSAlexander V. Chernikov * 64c91a5dfSAlexander V. Chernikov * Redistribution and use in source and binary forms, with or without 74c91a5dfSAlexander V. Chernikov * modification, are permitted provided that the following conditions 84c91a5dfSAlexander V. Chernikov * are met: 94c91a5dfSAlexander V. Chernikov * 1. Redistributions of source code must retain the above copyright 104c91a5dfSAlexander V. Chernikov * notice, this list of conditions and the following disclaimer. 114c91a5dfSAlexander V. Chernikov * 2. Redistributions in binary form must reproduce the above copyright 124c91a5dfSAlexander V. Chernikov * notice, this list of conditions and the following disclaimer in the 134c91a5dfSAlexander V. Chernikov * documentation and/or other materials provided with the distribution. 144c91a5dfSAlexander V. Chernikov * 154c91a5dfSAlexander V. Chernikov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 164c91a5dfSAlexander V. Chernikov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 174c91a5dfSAlexander V. Chernikov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 184c91a5dfSAlexander V. Chernikov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 194c91a5dfSAlexander V. Chernikov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 204c91a5dfSAlexander V. Chernikov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 214c91a5dfSAlexander V. Chernikov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 224c91a5dfSAlexander V. Chernikov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 234c91a5dfSAlexander V. Chernikov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 244c91a5dfSAlexander V. Chernikov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 254c91a5dfSAlexander V. Chernikov * SUCH DAMAGE. 264c91a5dfSAlexander V. Chernikov */ 274c91a5dfSAlexander V. Chernikov 284c91a5dfSAlexander V. Chernikov #include <stdio.h> 294c91a5dfSAlexander V. Chernikov #include <stdlib.h> 304c91a5dfSAlexander V. Chernikov #include <string.h> 314c91a5dfSAlexander V. Chernikov #include <stdbool.h> 324c91a5dfSAlexander V. Chernikov #include <err.h> 334c91a5dfSAlexander V. Chernikov #include <errno.h> 344c91a5dfSAlexander V. Chernikov #include <netdb.h> 354c91a5dfSAlexander V. Chernikov 364c91a5dfSAlexander V. Chernikov #include <sys/bitcount.h> 374c91a5dfSAlexander V. Chernikov #include <sys/param.h> 384c91a5dfSAlexander V. Chernikov #include <sys/linker.h> 394c91a5dfSAlexander V. Chernikov #include <sys/module.h> 404c91a5dfSAlexander V. Chernikov #include <sys/socket.h> 414c91a5dfSAlexander V. Chernikov #include <sys/sysctl.h> 424c91a5dfSAlexander V. Chernikov #include <sys/time.h> 434c91a5dfSAlexander V. Chernikov #include <sys/types.h> 444c91a5dfSAlexander V. Chernikov 454c91a5dfSAlexander V. Chernikov #include <netinet/in.h> 464c91a5dfSAlexander V. Chernikov #include <arpa/inet.h> 474c91a5dfSAlexander V. Chernikov 484c91a5dfSAlexander V. Chernikov #include <net/ethernet.h> 494c91a5dfSAlexander V. Chernikov #include <net/if.h> 504c91a5dfSAlexander V. Chernikov #include <net/if_dl.h> 514c91a5dfSAlexander V. Chernikov #include <net/if_types.h> 524c91a5dfSAlexander V. Chernikov #include "ifconfig.h" 534c91a5dfSAlexander V. Chernikov #include "ifconfig_netlink.h" 544c91a5dfSAlexander V. Chernikov 554c91a5dfSAlexander V. Chernikov static const char *IFFBITS[] = { 564c91a5dfSAlexander V. Chernikov "UP", /* 00:0x1 IFF_UP*/ 574c91a5dfSAlexander V. Chernikov "BROADCAST", /* 01:0x2 IFF_BROADCAST*/ 584c91a5dfSAlexander V. Chernikov "DEBUG", /* 02:0x4 IFF_DEBUG*/ 594c91a5dfSAlexander V. Chernikov "LOOPBACK", /* 03:0x8 IFF_LOOPBACK*/ 604c91a5dfSAlexander V. Chernikov "POINTOPOINT", /* 04:0x10 IFF_POINTOPOINT*/ 614c91a5dfSAlexander V. Chernikov "NEEDSEPOCH", /* 05:0x20 IFF_NEEDSEPOCH*/ 624c91a5dfSAlexander V. Chernikov "RUNNING", /* 06:0x40 IFF_DRV_RUNNING*/ 634c91a5dfSAlexander V. Chernikov "NOARP", /* 07:0x80 IFF_NOARP*/ 644c91a5dfSAlexander V. Chernikov "PROMISC", /* 08:0x100 IFF_PROMISC*/ 654c91a5dfSAlexander V. Chernikov "ALLMULTI", /* 09:0x200 IFF_ALLMULTI*/ 664c91a5dfSAlexander V. Chernikov "DRV_OACTIVE", /* 10:0x400 IFF_DRV_OACTIVE*/ 674c91a5dfSAlexander V. Chernikov "SIMPLEX", /* 11:0x800 IFF_SIMPLEX*/ 684c91a5dfSAlexander V. Chernikov "LINK0", /* 12:0x1000 IFF_LINK0*/ 694c91a5dfSAlexander V. Chernikov "LINK1", /* 13:0x2000 IFF_LINK1*/ 704c91a5dfSAlexander V. Chernikov "LINK2", /* 14:0x4000 IFF_LINK2*/ 714c91a5dfSAlexander V. Chernikov "MULTICAST", /* 15:0x8000 IFF_MULTICAST*/ 724c91a5dfSAlexander V. Chernikov "CANTCONFIG", /* 16:0x10000 IFF_CANTCONFIG*/ 734c91a5dfSAlexander V. Chernikov "PPROMISC", /* 17:0x20000 IFF_PPROMISC*/ 744c91a5dfSAlexander V. Chernikov "MONITOR", /* 18:0x40000 IFF_MONITOR*/ 754c91a5dfSAlexander V. Chernikov "STATICARP", /* 19:0x80000 IFF_STATICARP*/ 764c91a5dfSAlexander V. Chernikov "STICKYARP", /* 20:0x100000 IFF_STICKYARP*/ 774c91a5dfSAlexander V. Chernikov "DYING", /* 21:0x200000 IFF_DYING*/ 784c91a5dfSAlexander V. Chernikov "RENAMING", /* 22:0x400000 IFF_RENAMING*/ 794c91a5dfSAlexander V. Chernikov "NOGROUP", /* 23:0x800000 IFF_NOGROUP*/ 804c91a5dfSAlexander V. Chernikov "LOWER_UP", /* 24:0x1000000 IFF_NETLINK_1*/ 814c91a5dfSAlexander V. Chernikov }; 824c91a5dfSAlexander V. Chernikov 834c91a5dfSAlexander V. Chernikov static void 844c91a5dfSAlexander V. Chernikov print_bits(const char *btype, uint32_t *v, const int v_count, 854c91a5dfSAlexander V. Chernikov const char **names, const int n_count) 864c91a5dfSAlexander V. Chernikov { 874c91a5dfSAlexander V. Chernikov int num = 0; 884c91a5dfSAlexander V. Chernikov 894c91a5dfSAlexander V. Chernikov for (int i = 0; i < v_count * 32; i++) { 904c91a5dfSAlexander V. Chernikov bool is_set = v[i / 32] & (1 << (i % 32)); 914c91a5dfSAlexander V. Chernikov if (i == 31) 924c91a5dfSAlexander V. Chernikov v++; 934c91a5dfSAlexander V. Chernikov if (is_set) { 944c91a5dfSAlexander V. Chernikov if (num++ == 0) 954c91a5dfSAlexander V. Chernikov printf("<"); 964c91a5dfSAlexander V. Chernikov if (num != 1) 974c91a5dfSAlexander V. Chernikov printf(","); 984c91a5dfSAlexander V. Chernikov if (i < n_count) 994c91a5dfSAlexander V. Chernikov printf("%s", names[i]); 1004c91a5dfSAlexander V. Chernikov else 1014c91a5dfSAlexander V. Chernikov printf("%s_%d", btype, i); 1024c91a5dfSAlexander V. Chernikov } 1034c91a5dfSAlexander V. Chernikov } 1044c91a5dfSAlexander V. Chernikov if (num > 0) 1054c91a5dfSAlexander V. Chernikov printf(">"); 1064c91a5dfSAlexander V. Chernikov } 1074c91a5dfSAlexander V. Chernikov 1084c91a5dfSAlexander V. Chernikov static void 1094c91a5dfSAlexander V. Chernikov nl_init_socket(struct snl_state *ss) 1104c91a5dfSAlexander V. Chernikov { 1114c91a5dfSAlexander V. Chernikov if (snl_init(ss, NETLINK_ROUTE)) 1124c91a5dfSAlexander V. Chernikov return; 1134c91a5dfSAlexander V. Chernikov 1144c91a5dfSAlexander V. Chernikov if (modfind("netlink") == -1 && errno == ENOENT) { 1154c91a5dfSAlexander V. Chernikov /* Try to load */ 1164c91a5dfSAlexander V. Chernikov if (kldload("netlink") == -1) 1174c91a5dfSAlexander V. Chernikov err(1, "netlink is not loaded and load attempt failed"); 1184c91a5dfSAlexander V. Chernikov if (snl_init(ss, NETLINK_ROUTE)) 1194c91a5dfSAlexander V. Chernikov return; 1204c91a5dfSAlexander V. Chernikov } 1214c91a5dfSAlexander V. Chernikov 1224c91a5dfSAlexander V. Chernikov err(1, "unable to open netlink socket"); 1234c91a5dfSAlexander V. Chernikov } 1244c91a5dfSAlexander V. Chernikov 125*4bf44dd7SAlexander V. Chernikov int 126*4bf44dd7SAlexander V. Chernikov ifconfig_wrapper_nl(struct ifconfig_args *args, int iscreate, 127*4bf44dd7SAlexander V. Chernikov const struct afswtch *uafp) 128*4bf44dd7SAlexander V. Chernikov { 129*4bf44dd7SAlexander V. Chernikov struct snl_state ss = {}; 130*4bf44dd7SAlexander V. Chernikov struct ifconfig_context ctx = { 131*4bf44dd7SAlexander V. Chernikov .args = args, 132*4bf44dd7SAlexander V. Chernikov .io_s = -1, 133*4bf44dd7SAlexander V. Chernikov .io_ss = &ss, 134*4bf44dd7SAlexander V. Chernikov }; 135*4bf44dd7SAlexander V. Chernikov 136*4bf44dd7SAlexander V. Chernikov nl_init_socket(&ss); 137*4bf44dd7SAlexander V. Chernikov 138*4bf44dd7SAlexander V. Chernikov int error = ifconfig(&ctx, iscreate, uafp); 139*4bf44dd7SAlexander V. Chernikov 140*4bf44dd7SAlexander V. Chernikov snl_free(&ss); 141*4bf44dd7SAlexander V. Chernikov 142*4bf44dd7SAlexander V. Chernikov return (error); 143*4bf44dd7SAlexander V. Chernikov } 144*4bf44dd7SAlexander V. Chernikov 1454c91a5dfSAlexander V. Chernikov struct ifa { 1464c91a5dfSAlexander V. Chernikov struct ifa *next; 1474c91a5dfSAlexander V. Chernikov uint32_t idx; 1484c91a5dfSAlexander V. Chernikov struct snl_parsed_addr addr; 1494c91a5dfSAlexander V. Chernikov }; 1504c91a5dfSAlexander V. Chernikov 1514c91a5dfSAlexander V. Chernikov struct iface { 1524c91a5dfSAlexander V. Chernikov struct snl_parsed_link link; 1534c91a5dfSAlexander V. Chernikov struct ifa *ifa; 1544c91a5dfSAlexander V. Chernikov uint32_t ifa_count; 1554c91a5dfSAlexander V. Chernikov uint32_t idx; 1564c91a5dfSAlexander V. Chernikov }; 1574c91a5dfSAlexander V. Chernikov 1584c91a5dfSAlexander V. Chernikov struct ifmap { 1594c91a5dfSAlexander V. Chernikov uint32_t size; 1604c91a5dfSAlexander V. Chernikov uint32_t count; 1614c91a5dfSAlexander V. Chernikov struct iface **ifaces; 1624c91a5dfSAlexander V. Chernikov }; 1634c91a5dfSAlexander V. Chernikov 1644c91a5dfSAlexander V. Chernikov /* 1654c91a5dfSAlexander V. Chernikov * Returns ifmap ifindex->snl_parsed_link. 1664c91a5dfSAlexander V. Chernikov * Memory is allocated using snl temporary buffers 1674c91a5dfSAlexander V. Chernikov */ 1684c91a5dfSAlexander V. Chernikov static struct ifmap * 1694c91a5dfSAlexander V. Chernikov prepare_ifmap(struct snl_state *ss) 1704c91a5dfSAlexander V. Chernikov { 1714c91a5dfSAlexander V. Chernikov struct snl_writer nw = {}; 1724c91a5dfSAlexander V. Chernikov 1734c91a5dfSAlexander V. Chernikov snl_init_writer(ss, &nw); 1744c91a5dfSAlexander V. Chernikov struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_GETLINK); 1754c91a5dfSAlexander V. Chernikov hdr->nlmsg_flags |= NLM_F_DUMP; 1764c91a5dfSAlexander V. Chernikov snl_reserve_msg_object(&nw, struct ifinfomsg); 1774c91a5dfSAlexander V. Chernikov 1784c91a5dfSAlexander V. Chernikov if (!snl_finalize_msg(&nw) || !snl_send_message(ss, hdr)) 1794c91a5dfSAlexander V. Chernikov return (NULL); 1804c91a5dfSAlexander V. Chernikov 1814c91a5dfSAlexander V. Chernikov uint32_t nlmsg_seq = hdr->nlmsg_seq; 1824c91a5dfSAlexander V. Chernikov struct ifmap *ifmap = snl_allocz(ss, sizeof(*ifmap)); 1834c91a5dfSAlexander V. Chernikov struct snl_errmsg_data e = {}; 1844c91a5dfSAlexander V. Chernikov 1854c91a5dfSAlexander V. Chernikov while ((hdr = snl_read_reply_multi(ss, nlmsg_seq, &e)) != NULL) { 1864c91a5dfSAlexander V. Chernikov struct iface *iface = snl_allocz(ss, sizeof(*iface)); 1874c91a5dfSAlexander V. Chernikov 1884c91a5dfSAlexander V. Chernikov if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_link_parser, &iface->link)) 1894c91a5dfSAlexander V. Chernikov continue; 1904c91a5dfSAlexander V. Chernikov if (iface->link.ifi_index >= ifmap->size) { 1914c91a5dfSAlexander V. Chernikov size_t new_size = MAX(ifmap->size, 32); 1924c91a5dfSAlexander V. Chernikov 1934c91a5dfSAlexander V. Chernikov while (new_size <= iface->link.ifi_index + 1) 1944c91a5dfSAlexander V. Chernikov new_size *= 2; 1954c91a5dfSAlexander V. Chernikov 1964c91a5dfSAlexander V. Chernikov struct iface **ifaces= snl_allocz(ss, new_size * sizeof(void *)); 1974c91a5dfSAlexander V. Chernikov memcpy(ifaces, ifmap->ifaces, ifmap->size * sizeof(void *)); 1984c91a5dfSAlexander V. Chernikov ifmap->ifaces = ifaces; 1994c91a5dfSAlexander V. Chernikov ifmap->size = new_size; 2004c91a5dfSAlexander V. Chernikov } 2014c91a5dfSAlexander V. Chernikov ifmap->ifaces[iface->link.ifi_index] = iface; 2024c91a5dfSAlexander V. Chernikov ifmap->count++; 2034c91a5dfSAlexander V. Chernikov iface->idx = ifmap->count; 2044c91a5dfSAlexander V. Chernikov } 2054c91a5dfSAlexander V. Chernikov return (ifmap); 2064c91a5dfSAlexander V. Chernikov } 2074c91a5dfSAlexander V. Chernikov 208*4bf44dd7SAlexander V. Chernikov uint32_t 209*4bf44dd7SAlexander V. Chernikov if_nametoindex_nl(struct snl_state *ss, const char *ifname) 210*4bf44dd7SAlexander V. Chernikov { 211*4bf44dd7SAlexander V. Chernikov struct snl_writer nw = {}; 212*4bf44dd7SAlexander V. Chernikov struct snl_parsed_link_simple link = {}; 213*4bf44dd7SAlexander V. Chernikov 214*4bf44dd7SAlexander V. Chernikov snl_init_writer(ss, &nw); 215*4bf44dd7SAlexander V. Chernikov struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_GETLINK); 216*4bf44dd7SAlexander V. Chernikov snl_reserve_msg_object(&nw, struct ifinfomsg); 217*4bf44dd7SAlexander V. Chernikov snl_add_msg_attr_string(&nw, IFLA_IFNAME, ifname); 218*4bf44dd7SAlexander V. Chernikov 219*4bf44dd7SAlexander V. Chernikov if (!snl_finalize_msg(&nw) || !snl_send_message(ss, hdr)) 220*4bf44dd7SAlexander V. Chernikov return (0); 221*4bf44dd7SAlexander V. Chernikov 222*4bf44dd7SAlexander V. Chernikov hdr = snl_read_reply(ss, hdr->nlmsg_seq); 223*4bf44dd7SAlexander V. Chernikov if (hdr->nlmsg_type != NL_RTM_NEWLINK) 224*4bf44dd7SAlexander V. Chernikov return (0); 225*4bf44dd7SAlexander V. Chernikov if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_link_parser_simple, &link)) 226*4bf44dd7SAlexander V. Chernikov return (0); 227*4bf44dd7SAlexander V. Chernikov 228*4bf44dd7SAlexander V. Chernikov return (link.ifi_index); 229*4bf44dd7SAlexander V. Chernikov } 230*4bf44dd7SAlexander V. Chernikov 2314c91a5dfSAlexander V. Chernikov static void 2324c91a5dfSAlexander V. Chernikov prepare_ifaddrs(struct snl_state *ss, struct ifmap *ifmap) 2334c91a5dfSAlexander V. Chernikov { 2344c91a5dfSAlexander V. Chernikov struct snl_writer nw = {}; 2354c91a5dfSAlexander V. Chernikov 2364c91a5dfSAlexander V. Chernikov snl_init_writer(ss, &nw); 2374c91a5dfSAlexander V. Chernikov struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_GETADDR); 2384c91a5dfSAlexander V. Chernikov hdr->nlmsg_flags |= NLM_F_DUMP; 2394c91a5dfSAlexander V. Chernikov snl_reserve_msg_object(&nw, struct ifaddrmsg); 2404c91a5dfSAlexander V. Chernikov 2414c91a5dfSAlexander V. Chernikov if (!snl_finalize_msg(&nw) || !snl_send_message(ss, hdr)) 2424c91a5dfSAlexander V. Chernikov return; 2434c91a5dfSAlexander V. Chernikov 2444c91a5dfSAlexander V. Chernikov uint32_t nlmsg_seq = hdr->nlmsg_seq; 2454c91a5dfSAlexander V. Chernikov struct snl_errmsg_data e = {}; 2464c91a5dfSAlexander V. Chernikov uint32_t count = 0; 2474c91a5dfSAlexander V. Chernikov 2484c91a5dfSAlexander V. Chernikov while ((hdr = snl_read_reply_multi(ss, nlmsg_seq, &e)) != NULL) { 2494c91a5dfSAlexander V. Chernikov struct ifa *ifa = snl_allocz(ss, sizeof(*ifa)); 2504c91a5dfSAlexander V. Chernikov 2514c91a5dfSAlexander V. Chernikov if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_addr_parser, &ifa->addr)) 2524c91a5dfSAlexander V. Chernikov continue; 2534c91a5dfSAlexander V. Chernikov 2544c91a5dfSAlexander V. Chernikov const uint32_t ifindex = ifa->addr.ifa_index; 2554c91a5dfSAlexander V. Chernikov if (ifindex >= ifmap->size || ifmap->ifaces[ifindex] == NULL) 2564c91a5dfSAlexander V. Chernikov continue; 2574c91a5dfSAlexander V. Chernikov struct iface *iface = ifmap->ifaces[ifindex]; 2584c91a5dfSAlexander V. Chernikov ifa->next = iface->ifa; 25912cfa3c1SAlexander V. Chernikov ifa->idx = ++count; 2604c91a5dfSAlexander V. Chernikov iface->ifa = ifa; 2614c91a5dfSAlexander V. Chernikov iface->ifa_count++; 2624c91a5dfSAlexander V. Chernikov } 2634c91a5dfSAlexander V. Chernikov } 2644c91a5dfSAlexander V. Chernikov 2654c91a5dfSAlexander V. Chernikov static bool 2664c91a5dfSAlexander V. Chernikov match_iface(struct ifconfig_args *args, struct iface *iface) 2674c91a5dfSAlexander V. Chernikov { 2684c91a5dfSAlexander V. Chernikov if_link_t *link = &iface->link; 2694c91a5dfSAlexander V. Chernikov 2704c91a5dfSAlexander V. Chernikov if (args->ifname != NULL && strcmp(args->ifname, link->ifla_ifname)) 2714c91a5dfSAlexander V. Chernikov return (false); 2724c91a5dfSAlexander V. Chernikov 2734c91a5dfSAlexander V. Chernikov if (!match_if_flags(args, link->ifi_flags)) 2744c91a5dfSAlexander V. Chernikov return (false); 2754c91a5dfSAlexander V. Chernikov 2764c91a5dfSAlexander V. Chernikov if (!group_member(link->ifla_ifname, args->matchgroup, args->nogroup)) 2774c91a5dfSAlexander V. Chernikov return (false); 2784c91a5dfSAlexander V. Chernikov 2794c91a5dfSAlexander V. Chernikov if (args->afp == NULL) 2804c91a5dfSAlexander V. Chernikov return (true); 2814c91a5dfSAlexander V. Chernikov 2824c91a5dfSAlexander V. Chernikov if (!strcmp(args->afp->af_name, "ether")) { 2834c91a5dfSAlexander V. Chernikov if (link->ifla_address == NULL) 2844c91a5dfSAlexander V. Chernikov return (false); 2854c91a5dfSAlexander V. Chernikov 2864c91a5dfSAlexander V. Chernikov struct sockaddr_dl sdl = { 2874c91a5dfSAlexander V. Chernikov .sdl_len = sizeof(struct sockaddr_dl), 2884c91a5dfSAlexander V. Chernikov .sdl_family = AF_LINK, 2894c91a5dfSAlexander V. Chernikov .sdl_type = link->ifi_type, 2904c91a5dfSAlexander V. Chernikov .sdl_alen = NLA_DATA_LEN(link->ifla_address), 2914c91a5dfSAlexander V. Chernikov }; 2924c91a5dfSAlexander V. Chernikov return (match_ether(&sdl)); 2934c91a5dfSAlexander V. Chernikov } 2944c91a5dfSAlexander V. Chernikov 2954c91a5dfSAlexander V. Chernikov for (struct ifa *ifa = iface->ifa; ifa != NULL; ifa = ifa->next) { 2964c91a5dfSAlexander V. Chernikov if (args->afp->af_af == ifa->addr.ifa_family) 2974c91a5dfSAlexander V. Chernikov return (true); 2984c91a5dfSAlexander V. Chernikov } 2994c91a5dfSAlexander V. Chernikov 3004c91a5dfSAlexander V. Chernikov return (false); 3014c91a5dfSAlexander V. Chernikov } 3024c91a5dfSAlexander V. Chernikov 3034c91a5dfSAlexander V. Chernikov /* Sort according to the kernel-provided order */ 3044c91a5dfSAlexander V. Chernikov static int 3054c91a5dfSAlexander V. Chernikov cmp_iface(const void *_a, const void *_b) 3064c91a5dfSAlexander V. Chernikov { 3074c91a5dfSAlexander V. Chernikov const struct iface *a = *((const void * const *)_a); 3084c91a5dfSAlexander V. Chernikov const struct iface *b = *((const void * const *)_b); 3094c91a5dfSAlexander V. Chernikov 3104c91a5dfSAlexander V. Chernikov return ((a->idx > b->idx) * 2 - 1); 3114c91a5dfSAlexander V. Chernikov } 3124c91a5dfSAlexander V. Chernikov 3134c91a5dfSAlexander V. Chernikov static int 3144c91a5dfSAlexander V. Chernikov cmp_ifaddr(const void *_a, const void *_b) 3154c91a5dfSAlexander V. Chernikov { 3164c91a5dfSAlexander V. Chernikov const struct ifa *a = *((const void * const *)_a); 3174c91a5dfSAlexander V. Chernikov const struct ifa *b = *((const void * const *)_b); 3184c91a5dfSAlexander V. Chernikov 3194c91a5dfSAlexander V. Chernikov if (a->addr.ifa_family != b->addr.ifa_family) 3204c91a5dfSAlexander V. Chernikov return ((a->addr.ifa_family > b->addr.ifa_family) * 2 - 1); 3214c91a5dfSAlexander V. Chernikov return ((a->idx > b->idx) * 2 - 1); 3224c91a5dfSAlexander V. Chernikov } 3234c91a5dfSAlexander V. Chernikov 3244c91a5dfSAlexander V. Chernikov static void 3254c91a5dfSAlexander V. Chernikov sort_iface_ifaddrs(struct snl_state *ss, struct iface *iface) 3264c91a5dfSAlexander V. Chernikov { 3274c91a5dfSAlexander V. Chernikov if (iface->ifa_count == 0) 3284c91a5dfSAlexander V. Chernikov return; 3294c91a5dfSAlexander V. Chernikov 3304c91a5dfSAlexander V. Chernikov struct ifa **sorted_ifaddrs = snl_allocz(ss, iface->ifa_count * sizeof(void *)); 3314c91a5dfSAlexander V. Chernikov struct ifa *ifa = iface->ifa; 3324c91a5dfSAlexander V. Chernikov 33344cd85d4SAlexander V. Chernikov for (uint32_t i = 0; i < iface->ifa_count; i++) { 3344c91a5dfSAlexander V. Chernikov struct ifa *ifa_next = ifa->next; 3354c91a5dfSAlexander V. Chernikov 3364c91a5dfSAlexander V. Chernikov sorted_ifaddrs[i] = ifa; 3374c91a5dfSAlexander V. Chernikov ifa->next = NULL; 3384c91a5dfSAlexander V. Chernikov ifa = ifa_next; 3394c91a5dfSAlexander V. Chernikov } 3404c91a5dfSAlexander V. Chernikov qsort(sorted_ifaddrs, iface->ifa_count, sizeof(void *), cmp_ifaddr); 3414c91a5dfSAlexander V. Chernikov ifa = sorted_ifaddrs[0]; 3424c91a5dfSAlexander V. Chernikov iface->ifa = ifa; 34344cd85d4SAlexander V. Chernikov for (uint32_t i = 1; i < iface->ifa_count; i++) { 3444c91a5dfSAlexander V. Chernikov ifa->next = sorted_ifaddrs[i]; 3454c91a5dfSAlexander V. Chernikov ifa = sorted_ifaddrs[i]; 3464c91a5dfSAlexander V. Chernikov } 3474c91a5dfSAlexander V. Chernikov } 3484c91a5dfSAlexander V. Chernikov 3494c91a5dfSAlexander V. Chernikov static void 3506e3a9d7fSAlexander V. Chernikov status_nl(if_ctx *ctx, struct iface *iface) 3514c91a5dfSAlexander V. Chernikov { 3524c91a5dfSAlexander V. Chernikov if_link_t *link = &iface->link; 3536e3a9d7fSAlexander V. Chernikov struct ifconfig_args *args = ctx->args; 3544c91a5dfSAlexander V. Chernikov 3554c91a5dfSAlexander V. Chernikov printf("%s: ", link->ifla_ifname); 3564c91a5dfSAlexander V. Chernikov 3574c91a5dfSAlexander V. Chernikov printf("flags=%x", link->ifi_flags); 3584c91a5dfSAlexander V. Chernikov print_bits("IFF", &link->ifi_flags, 1, IFFBITS, nitems(IFFBITS)); 3594c91a5dfSAlexander V. Chernikov 3606e3a9d7fSAlexander V. Chernikov print_metric(ctx->io_s); 3614c91a5dfSAlexander V. Chernikov printf(" mtu %d\n", link->ifla_mtu); 3624c91a5dfSAlexander V. Chernikov 3634c91a5dfSAlexander V. Chernikov if (link->ifla_ifalias != NULL) 3644c91a5dfSAlexander V. Chernikov printf("\tdescription: %s\n", link->ifla_ifalias); 3654c91a5dfSAlexander V. Chernikov 3664c91a5dfSAlexander V. Chernikov /* TODO: convert to netlink */ 3674c91a5dfSAlexander V. Chernikov strlcpy(ifr.ifr_name, link->ifla_ifname, sizeof(ifr.ifr_name)); 3686e3a9d7fSAlexander V. Chernikov print_ifcap(args, ctx->io_s); 3696e3a9d7fSAlexander V. Chernikov tunnel_status(ctx->io_s); 3704c91a5dfSAlexander V. Chernikov 3714c91a5dfSAlexander V. Chernikov if (args->allfamilies | (args->afp != NULL && args->afp->af_af == AF_LINK)) { 3724c91a5dfSAlexander V. Chernikov /* Start with link-level */ 3734c91a5dfSAlexander V. Chernikov const struct afswtch *p = af_getbyfamily(AF_LINK); 3744c91a5dfSAlexander V. Chernikov if (p != NULL && link->ifla_address != NULL) 3756e3a9d7fSAlexander V. Chernikov p->af_status(ctx, link, NULL); 3764c91a5dfSAlexander V. Chernikov } 3774c91a5dfSAlexander V. Chernikov 3786e3a9d7fSAlexander V. Chernikov sort_iface_ifaddrs(ctx->io_ss, iface); 3794c91a5dfSAlexander V. Chernikov 3804c91a5dfSAlexander V. Chernikov for (struct ifa *ifa = iface->ifa; ifa != NULL; ifa = ifa->next) { 3814c91a5dfSAlexander V. Chernikov if (args->allfamilies) { 3824c91a5dfSAlexander V. Chernikov const struct afswtch *p = af_getbyfamily(ifa->addr.ifa_family); 3834c91a5dfSAlexander V. Chernikov 3844c91a5dfSAlexander V. Chernikov if (p != NULL) 3856e3a9d7fSAlexander V. Chernikov p->af_status(ctx, link, &ifa->addr); 3864c91a5dfSAlexander V. Chernikov } else if (args->afp->af_af == ifa->addr.ifa_family) { 3874c91a5dfSAlexander V. Chernikov const struct afswtch *p = args->afp; 3884c91a5dfSAlexander V. Chernikov 3896e3a9d7fSAlexander V. Chernikov p->af_status(ctx, link, &ifa->addr); 3904c91a5dfSAlexander V. Chernikov } 3914c91a5dfSAlexander V. Chernikov } 3924c91a5dfSAlexander V. Chernikov 3934c91a5dfSAlexander V. Chernikov /* TODO: convert to netlink */ 3944c91a5dfSAlexander V. Chernikov if (args->allfamilies) 3956e3a9d7fSAlexander V. Chernikov af_other_status(ctx); 3964c91a5dfSAlexander V. Chernikov else if (args->afp->af_other_status != NULL) 3976e3a9d7fSAlexander V. Chernikov args->afp->af_other_status(ctx); 3984c91a5dfSAlexander V. Chernikov 3996e3a9d7fSAlexander V. Chernikov print_ifstatus(ctx->io_s); 4004c91a5dfSAlexander V. Chernikov if (args->verbose > 0) 4016e3a9d7fSAlexander V. Chernikov sfp_status(ctx->io_s, &ifr, args->verbose); 4024c91a5dfSAlexander V. Chernikov } 4034c91a5dfSAlexander V. Chernikov 4044c91a5dfSAlexander V. Chernikov static int 4054c91a5dfSAlexander V. Chernikov get_local_socket(void) 4064c91a5dfSAlexander V. Chernikov { 4074c91a5dfSAlexander V. Chernikov int s = socket(AF_LOCAL, SOCK_DGRAM, 0); 4084c91a5dfSAlexander V. Chernikov 4094c91a5dfSAlexander V. Chernikov if (s < 0) 4104c91a5dfSAlexander V. Chernikov err(1, "socket(family %u,SOCK_DGRAM)", AF_LOCAL); 4114c91a5dfSAlexander V. Chernikov return (s); 4124c91a5dfSAlexander V. Chernikov } 4134c91a5dfSAlexander V. Chernikov 4144c91a5dfSAlexander V. Chernikov static void 4154c91a5dfSAlexander V. Chernikov set_global_ifname(if_link_t *link) 4164c91a5dfSAlexander V. Chernikov { 41744cd85d4SAlexander V. Chernikov size_t iflen = strlcpy(name, link->ifla_ifname, sizeof(name)); 41844cd85d4SAlexander V. Chernikov 4194c91a5dfSAlexander V. Chernikov if (iflen >= sizeof(name)) 4204c91a5dfSAlexander V. Chernikov errx(1, "%s: cloning name too long", link->ifla_ifname); 4214c91a5dfSAlexander V. Chernikov strlcpy(ifr.ifr_name, link->ifla_ifname, sizeof(ifr.ifr_name)); 4224c91a5dfSAlexander V. Chernikov } 4234c91a5dfSAlexander V. Chernikov 4244c91a5dfSAlexander V. Chernikov void 4254c91a5dfSAlexander V. Chernikov list_interfaces_nl(struct ifconfig_args *args) 4264c91a5dfSAlexander V. Chernikov { 4274c91a5dfSAlexander V. Chernikov struct snl_state ss = {}; 4286e3a9d7fSAlexander V. Chernikov struct ifconfig_context _ctx = { 4296e3a9d7fSAlexander V. Chernikov .args = args, 4306e3a9d7fSAlexander V. Chernikov .io_s = get_local_socket(), 4316e3a9d7fSAlexander V. Chernikov .io_ss = &ss, 4326e3a9d7fSAlexander V. Chernikov }; 4336e3a9d7fSAlexander V. Chernikov struct ifconfig_context *ctx = &_ctx; 4344c91a5dfSAlexander V. Chernikov 4354c91a5dfSAlexander V. Chernikov nl_init_socket(&ss); 4364c91a5dfSAlexander V. Chernikov 4374c91a5dfSAlexander V. Chernikov struct ifmap *ifmap = prepare_ifmap(&ss); 4384c91a5dfSAlexander V. Chernikov struct iface **sorted_ifaces = snl_allocz(&ss, ifmap->count * sizeof(void *)); 43944cd85d4SAlexander V. Chernikov for (uint32_t i = 0, num = 0; i < ifmap->size; i++) { 4404c91a5dfSAlexander V. Chernikov if (ifmap->ifaces[i] != NULL) { 4414c91a5dfSAlexander V. Chernikov sorted_ifaces[num++] = ifmap->ifaces[i]; 4424c91a5dfSAlexander V. Chernikov if (num == ifmap->count) 4434c91a5dfSAlexander V. Chernikov break; 4444c91a5dfSAlexander V. Chernikov } 4454c91a5dfSAlexander V. Chernikov } 4464c91a5dfSAlexander V. Chernikov qsort(sorted_ifaces, ifmap->count, sizeof(void *), cmp_iface); 4474c91a5dfSAlexander V. Chernikov prepare_ifaddrs(&ss, ifmap); 4484c91a5dfSAlexander V. Chernikov 44944cd85d4SAlexander V. Chernikov for (uint32_t i = 0, num = 0; i < ifmap->count; i++) { 4504c91a5dfSAlexander V. Chernikov struct iface *iface = sorted_ifaces[i]; 4514c91a5dfSAlexander V. Chernikov 4524c91a5dfSAlexander V. Chernikov if (!match_iface(args, iface)) 4534c91a5dfSAlexander V. Chernikov continue; 4544c91a5dfSAlexander V. Chernikov 4554c91a5dfSAlexander V. Chernikov set_global_ifname(&iface->link); 4564c91a5dfSAlexander V. Chernikov 4574c91a5dfSAlexander V. Chernikov if (args->namesonly) { 4584c91a5dfSAlexander V. Chernikov if (num++ != 0) 4594c91a5dfSAlexander V. Chernikov printf(" "); 4604c91a5dfSAlexander V. Chernikov fputs(iface->link.ifla_ifname, stdout); 4614c91a5dfSAlexander V. Chernikov } else if (args->argc == 0) 4626e3a9d7fSAlexander V. Chernikov status_nl(ctx, iface); 46326056fa8SAlexander V. Chernikov else 464*4bf44dd7SAlexander V. Chernikov ifconfig(ctx, 0, args->afp); 4654c91a5dfSAlexander V. Chernikov } 4664c91a5dfSAlexander V. Chernikov if (args->namesonly) 4674c91a5dfSAlexander V. Chernikov printf("\n"); 4684c91a5dfSAlexander V. Chernikov 4696e3a9d7fSAlexander V. Chernikov close(ctx->io_s); 4704c91a5dfSAlexander V. Chernikov snl_free(&ss); 4714c91a5dfSAlexander V. Chernikov } 4724c91a5dfSAlexander V. Chernikov 473