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> 51c344eff9SAlexander V. Chernikov #include <net/if_strings.h> 524c91a5dfSAlexander V. Chernikov #include <net/if_types.h> 534c91a5dfSAlexander V. Chernikov #include "ifconfig.h" 544c91a5dfSAlexander V. Chernikov #include "ifconfig_netlink.h" 554c91a5dfSAlexander V. Chernikov 564c91a5dfSAlexander V. Chernikov static const char *IFFBITS[] = { 574c91a5dfSAlexander V. Chernikov "UP", /* 00:0x1 IFF_UP*/ 584c91a5dfSAlexander V. Chernikov "BROADCAST", /* 01:0x2 IFF_BROADCAST*/ 594c91a5dfSAlexander V. Chernikov "DEBUG", /* 02:0x4 IFF_DEBUG*/ 604c91a5dfSAlexander V. Chernikov "LOOPBACK", /* 03:0x8 IFF_LOOPBACK*/ 614c91a5dfSAlexander V. Chernikov "POINTOPOINT", /* 04:0x10 IFF_POINTOPOINT*/ 624c91a5dfSAlexander V. Chernikov "NEEDSEPOCH", /* 05:0x20 IFF_NEEDSEPOCH*/ 634c91a5dfSAlexander V. Chernikov "RUNNING", /* 06:0x40 IFF_DRV_RUNNING*/ 644c91a5dfSAlexander V. Chernikov "NOARP", /* 07:0x80 IFF_NOARP*/ 654c91a5dfSAlexander V. Chernikov "PROMISC", /* 08:0x100 IFF_PROMISC*/ 664c91a5dfSAlexander V. Chernikov "ALLMULTI", /* 09:0x200 IFF_ALLMULTI*/ 674c91a5dfSAlexander V. Chernikov "DRV_OACTIVE", /* 10:0x400 IFF_DRV_OACTIVE*/ 684c91a5dfSAlexander V. Chernikov "SIMPLEX", /* 11:0x800 IFF_SIMPLEX*/ 694c91a5dfSAlexander V. Chernikov "LINK0", /* 12:0x1000 IFF_LINK0*/ 704c91a5dfSAlexander V. Chernikov "LINK1", /* 13:0x2000 IFF_LINK1*/ 714c91a5dfSAlexander V. Chernikov "LINK2", /* 14:0x4000 IFF_LINK2*/ 724c91a5dfSAlexander V. Chernikov "MULTICAST", /* 15:0x8000 IFF_MULTICAST*/ 734c91a5dfSAlexander V. Chernikov "CANTCONFIG", /* 16:0x10000 IFF_CANTCONFIG*/ 744c91a5dfSAlexander V. Chernikov "PPROMISC", /* 17:0x20000 IFF_PPROMISC*/ 754c91a5dfSAlexander V. Chernikov "MONITOR", /* 18:0x40000 IFF_MONITOR*/ 764c91a5dfSAlexander V. Chernikov "STATICARP", /* 19:0x80000 IFF_STATICARP*/ 774c91a5dfSAlexander V. Chernikov "STICKYARP", /* 20:0x100000 IFF_STICKYARP*/ 784c91a5dfSAlexander V. Chernikov "DYING", /* 21:0x200000 IFF_DYING*/ 794c91a5dfSAlexander V. Chernikov "RENAMING", /* 22:0x400000 IFF_RENAMING*/ 804c91a5dfSAlexander V. Chernikov "NOGROUP", /* 23:0x800000 IFF_NOGROUP*/ 814c91a5dfSAlexander V. Chernikov "LOWER_UP", /* 24:0x1000000 IFF_NETLINK_1*/ 824c91a5dfSAlexander V. Chernikov }; 834c91a5dfSAlexander V. Chernikov 844c91a5dfSAlexander V. Chernikov static void 854c91a5dfSAlexander V. Chernikov print_bits(const char *btype, uint32_t *v, const int v_count, 864c91a5dfSAlexander V. Chernikov const char **names, const int n_count) 874c91a5dfSAlexander V. Chernikov { 884c91a5dfSAlexander V. Chernikov int num = 0; 894c91a5dfSAlexander V. Chernikov 904c91a5dfSAlexander V. Chernikov for (int i = 0; i < v_count * 32; i++) { 9188284368SNavdeep Parhar bool is_set = v[i / 32] & (1U << (i % 32)); 924c91a5dfSAlexander V. Chernikov if (is_set) { 934c91a5dfSAlexander V. Chernikov if (num++ == 0) 944c91a5dfSAlexander V. Chernikov printf("<"); 954c91a5dfSAlexander V. Chernikov if (num != 1) 964c91a5dfSAlexander V. Chernikov printf(","); 974c91a5dfSAlexander V. Chernikov if (i < n_count) 984c91a5dfSAlexander V. Chernikov printf("%s", names[i]); 994c91a5dfSAlexander V. Chernikov else 1004c91a5dfSAlexander V. Chernikov printf("%s_%d", btype, i); 1014c91a5dfSAlexander V. Chernikov } 1024c91a5dfSAlexander V. Chernikov } 1034c91a5dfSAlexander V. Chernikov if (num > 0) 1044c91a5dfSAlexander V. Chernikov printf(">"); 1054c91a5dfSAlexander V. Chernikov } 1064c91a5dfSAlexander V. Chernikov 1074c91a5dfSAlexander V. Chernikov static void 1084c91a5dfSAlexander V. Chernikov nl_init_socket(struct snl_state *ss) 1094c91a5dfSAlexander V. Chernikov { 1104c91a5dfSAlexander V. Chernikov if (snl_init(ss, NETLINK_ROUTE)) 1114c91a5dfSAlexander V. Chernikov return; 1124c91a5dfSAlexander V. Chernikov 1134c91a5dfSAlexander V. Chernikov if (modfind("netlink") == -1 && errno == ENOENT) { 1144c91a5dfSAlexander V. Chernikov /* Try to load */ 1154c91a5dfSAlexander V. Chernikov if (kldload("netlink") == -1) 1164c91a5dfSAlexander V. Chernikov err(1, "netlink is not loaded and load attempt failed"); 1174c91a5dfSAlexander V. Chernikov if (snl_init(ss, NETLINK_ROUTE)) 1184c91a5dfSAlexander V. Chernikov return; 1194c91a5dfSAlexander V. Chernikov } 1204c91a5dfSAlexander V. Chernikov 1214c91a5dfSAlexander V. Chernikov err(1, "unable to open netlink socket"); 1224c91a5dfSAlexander V. Chernikov } 1234c91a5dfSAlexander V. Chernikov 1244bf44dd7SAlexander V. Chernikov int 125bbad5525SAlexander V. Chernikov ifconfig_nl(if_ctx *ctx, int iscreate, 1264bf44dd7SAlexander V. Chernikov const struct afswtch *uafp) 1274bf44dd7SAlexander V. Chernikov { 1284bf44dd7SAlexander V. Chernikov struct snl_state ss = {}; 1294bf44dd7SAlexander V. Chernikov 1304bf44dd7SAlexander V. Chernikov nl_init_socket(&ss); 13185e0016aSAlexander V. Chernikov ctx->io_ss = &ss; 1324bf44dd7SAlexander V. Chernikov 133bbad5525SAlexander V. Chernikov int error = ifconfig_ioctl(ctx, iscreate, uafp); 1344bf44dd7SAlexander V. Chernikov 1354bf44dd7SAlexander V. Chernikov snl_free(&ss); 136bbad5525SAlexander V. Chernikov ctx->io_ss = NULL; 1374bf44dd7SAlexander V. Chernikov 1384bf44dd7SAlexander V. Chernikov return (error); 1394bf44dd7SAlexander V. Chernikov } 1404bf44dd7SAlexander V. Chernikov 1414c91a5dfSAlexander V. Chernikov struct ifa { 1424c91a5dfSAlexander V. Chernikov struct ifa *next; 1434c91a5dfSAlexander V. Chernikov uint32_t idx; 1444c91a5dfSAlexander V. Chernikov struct snl_parsed_addr addr; 1454c91a5dfSAlexander V. Chernikov }; 1464c91a5dfSAlexander V. Chernikov 1474c91a5dfSAlexander V. Chernikov struct iface { 1484c91a5dfSAlexander V. Chernikov struct snl_parsed_link link; 1494c91a5dfSAlexander V. Chernikov struct ifa *ifa; 1504c91a5dfSAlexander V. Chernikov uint32_t ifa_count; 1514c91a5dfSAlexander V. Chernikov uint32_t idx; 1524c91a5dfSAlexander V. Chernikov }; 1534c91a5dfSAlexander V. Chernikov 1544c91a5dfSAlexander V. Chernikov struct ifmap { 1554c91a5dfSAlexander V. Chernikov uint32_t size; 1564c91a5dfSAlexander V. Chernikov uint32_t count; 1574c91a5dfSAlexander V. Chernikov struct iface **ifaces; 1584c91a5dfSAlexander V. Chernikov }; 1594c91a5dfSAlexander V. Chernikov 1604c91a5dfSAlexander V. Chernikov /* 1614c91a5dfSAlexander V. Chernikov * Returns ifmap ifindex->snl_parsed_link. 1624c91a5dfSAlexander V. Chernikov * Memory is allocated using snl temporary buffers 1634c91a5dfSAlexander V. Chernikov */ 1644c91a5dfSAlexander V. Chernikov static struct ifmap * 1654c91a5dfSAlexander V. Chernikov prepare_ifmap(struct snl_state *ss) 1664c91a5dfSAlexander V. Chernikov { 1674c91a5dfSAlexander V. Chernikov struct snl_writer nw = {}; 1684c91a5dfSAlexander V. Chernikov 1694c91a5dfSAlexander V. Chernikov snl_init_writer(ss, &nw); 1704c91a5dfSAlexander V. Chernikov struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_GETLINK); 1714c91a5dfSAlexander V. Chernikov hdr->nlmsg_flags |= NLM_F_DUMP; 1724c91a5dfSAlexander V. Chernikov snl_reserve_msg_object(&nw, struct ifinfomsg); 1734c91a5dfSAlexander V. Chernikov 174*4f8f43b0SKristof Provost if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(ss, hdr)) 1754c91a5dfSAlexander V. Chernikov return (NULL); 1764c91a5dfSAlexander V. Chernikov 1774c91a5dfSAlexander V. Chernikov uint32_t nlmsg_seq = hdr->nlmsg_seq; 1784c91a5dfSAlexander V. Chernikov struct ifmap *ifmap = snl_allocz(ss, sizeof(*ifmap)); 1794c91a5dfSAlexander V. Chernikov struct snl_errmsg_data e = {}; 1804c91a5dfSAlexander V. Chernikov 1814c91a5dfSAlexander V. Chernikov while ((hdr = snl_read_reply_multi(ss, nlmsg_seq, &e)) != NULL) { 1824c91a5dfSAlexander V. Chernikov struct iface *iface = snl_allocz(ss, sizeof(*iface)); 1834c91a5dfSAlexander V. Chernikov 1844c91a5dfSAlexander V. Chernikov if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_link_parser, &iface->link)) 1854c91a5dfSAlexander V. Chernikov continue; 1864c91a5dfSAlexander V. Chernikov if (iface->link.ifi_index >= ifmap->size) { 1874c91a5dfSAlexander V. Chernikov size_t new_size = MAX(ifmap->size, 32); 1884c91a5dfSAlexander V. Chernikov 1894c91a5dfSAlexander V. Chernikov while (new_size <= iface->link.ifi_index + 1) 1904c91a5dfSAlexander V. Chernikov new_size *= 2; 1914c91a5dfSAlexander V. Chernikov 1924c91a5dfSAlexander V. Chernikov struct iface **ifaces= snl_allocz(ss, new_size * sizeof(void *)); 1934c91a5dfSAlexander V. Chernikov memcpy(ifaces, ifmap->ifaces, ifmap->size * sizeof(void *)); 1944c91a5dfSAlexander V. Chernikov ifmap->ifaces = ifaces; 1954c91a5dfSAlexander V. Chernikov ifmap->size = new_size; 1964c91a5dfSAlexander V. Chernikov } 1974c91a5dfSAlexander V. Chernikov ifmap->ifaces[iface->link.ifi_index] = iface; 1984c91a5dfSAlexander V. Chernikov ifmap->count++; 1994c91a5dfSAlexander V. Chernikov iface->idx = ifmap->count; 2004c91a5dfSAlexander V. Chernikov } 2014c91a5dfSAlexander V. Chernikov return (ifmap); 2024c91a5dfSAlexander V. Chernikov } 2034c91a5dfSAlexander V. Chernikov 2044bf44dd7SAlexander V. Chernikov uint32_t 2054bf44dd7SAlexander V. Chernikov if_nametoindex_nl(struct snl_state *ss, const char *ifname) 2064bf44dd7SAlexander V. Chernikov { 2074bf44dd7SAlexander V. Chernikov struct snl_writer nw = {}; 2084bf44dd7SAlexander V. Chernikov struct snl_parsed_link_simple link = {}; 2094bf44dd7SAlexander V. Chernikov 2104bf44dd7SAlexander V. Chernikov snl_init_writer(ss, &nw); 2114bf44dd7SAlexander V. Chernikov struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_GETLINK); 2124bf44dd7SAlexander V. Chernikov snl_reserve_msg_object(&nw, struct ifinfomsg); 2134bf44dd7SAlexander V. Chernikov snl_add_msg_attr_string(&nw, IFLA_IFNAME, ifname); 2144bf44dd7SAlexander V. Chernikov 215*4f8f43b0SKristof Provost if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(ss, hdr)) 2164bf44dd7SAlexander V. Chernikov return (0); 2174bf44dd7SAlexander V. Chernikov 2184bf44dd7SAlexander V. Chernikov hdr = snl_read_reply(ss, hdr->nlmsg_seq); 2194bf44dd7SAlexander V. Chernikov if (hdr->nlmsg_type != NL_RTM_NEWLINK) 2204bf44dd7SAlexander V. Chernikov return (0); 2214bf44dd7SAlexander V. Chernikov if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_link_parser_simple, &link)) 2224bf44dd7SAlexander V. Chernikov return (0); 2234bf44dd7SAlexander V. Chernikov 2244bf44dd7SAlexander V. Chernikov return (link.ifi_index); 2254bf44dd7SAlexander V. Chernikov } 2264bf44dd7SAlexander V. Chernikov 22731016aa0SGleb Smirnoff ifType 22831016aa0SGleb Smirnoff convert_iftype(ifType iftype) 22931016aa0SGleb Smirnoff { 23031016aa0SGleb Smirnoff switch (iftype) { 23131016aa0SGleb Smirnoff case IFT_IEEE8023ADLAG: 23231016aa0SGleb Smirnoff return (IFT_ETHER); 23331016aa0SGleb Smirnoff case IFT_INFINIBANDLAG: 23431016aa0SGleb Smirnoff return (IFT_INFINIBAND); 23531016aa0SGleb Smirnoff default: 23631016aa0SGleb Smirnoff return (iftype); 23731016aa0SGleb Smirnoff } 23831016aa0SGleb Smirnoff } 23931016aa0SGleb Smirnoff 2404c91a5dfSAlexander V. Chernikov static void 2414c91a5dfSAlexander V. Chernikov prepare_ifaddrs(struct snl_state *ss, struct ifmap *ifmap) 2424c91a5dfSAlexander V. Chernikov { 2434c91a5dfSAlexander V. Chernikov struct snl_writer nw = {}; 2444c91a5dfSAlexander V. Chernikov 2454c91a5dfSAlexander V. Chernikov snl_init_writer(ss, &nw); 2464c91a5dfSAlexander V. Chernikov struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_GETADDR); 2474c91a5dfSAlexander V. Chernikov hdr->nlmsg_flags |= NLM_F_DUMP; 2484c91a5dfSAlexander V. Chernikov snl_reserve_msg_object(&nw, struct ifaddrmsg); 2494c91a5dfSAlexander V. Chernikov 250*4f8f43b0SKristof Provost if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(ss, hdr)) 2514c91a5dfSAlexander V. Chernikov return; 2524c91a5dfSAlexander V. Chernikov 2534c91a5dfSAlexander V. Chernikov uint32_t nlmsg_seq = hdr->nlmsg_seq; 2544c91a5dfSAlexander V. Chernikov struct snl_errmsg_data e = {}; 2554c91a5dfSAlexander V. Chernikov uint32_t count = 0; 2564c91a5dfSAlexander V. Chernikov 2574c91a5dfSAlexander V. Chernikov while ((hdr = snl_read_reply_multi(ss, nlmsg_seq, &e)) != NULL) { 2584c91a5dfSAlexander V. Chernikov struct ifa *ifa = snl_allocz(ss, sizeof(*ifa)); 2594c91a5dfSAlexander V. Chernikov 2604c91a5dfSAlexander V. Chernikov if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_addr_parser, &ifa->addr)) 2614c91a5dfSAlexander V. Chernikov continue; 2624c91a5dfSAlexander V. Chernikov 2634c91a5dfSAlexander V. Chernikov const uint32_t ifindex = ifa->addr.ifa_index; 2644c91a5dfSAlexander V. Chernikov if (ifindex >= ifmap->size || ifmap->ifaces[ifindex] == NULL) 2654c91a5dfSAlexander V. Chernikov continue; 2664c91a5dfSAlexander V. Chernikov struct iface *iface = ifmap->ifaces[ifindex]; 2674c91a5dfSAlexander V. Chernikov ifa->next = iface->ifa; 26812cfa3c1SAlexander V. Chernikov ifa->idx = ++count; 2694c91a5dfSAlexander V. Chernikov iface->ifa = ifa; 2704c91a5dfSAlexander V. Chernikov iface->ifa_count++; 2714c91a5dfSAlexander V. Chernikov } 2724c91a5dfSAlexander V. Chernikov } 2734c91a5dfSAlexander V. Chernikov 2744c91a5dfSAlexander V. Chernikov static bool 2754c91a5dfSAlexander V. Chernikov match_iface(struct ifconfig_args *args, struct iface *iface) 2764c91a5dfSAlexander V. Chernikov { 2774c91a5dfSAlexander V. Chernikov if_link_t *link = &iface->link; 2784c91a5dfSAlexander V. Chernikov 2794c91a5dfSAlexander V. Chernikov if (args->ifname != NULL && strcmp(args->ifname, link->ifla_ifname)) 2804c91a5dfSAlexander V. Chernikov return (false); 2814c91a5dfSAlexander V. Chernikov 2824c91a5dfSAlexander V. Chernikov if (!match_if_flags(args, link->ifi_flags)) 2834c91a5dfSAlexander V. Chernikov return (false); 2844c91a5dfSAlexander V. Chernikov 2854c91a5dfSAlexander V. Chernikov if (!group_member(link->ifla_ifname, args->matchgroup, args->nogroup)) 2864c91a5dfSAlexander V. Chernikov return (false); 2874c91a5dfSAlexander V. Chernikov 2884c91a5dfSAlexander V. Chernikov if (args->afp == NULL) 2894c91a5dfSAlexander V. Chernikov return (true); 2904c91a5dfSAlexander V. Chernikov 2914c91a5dfSAlexander V. Chernikov if (!strcmp(args->afp->af_name, "ether")) { 2924c91a5dfSAlexander V. Chernikov if (link->ifla_address == NULL) 2934c91a5dfSAlexander V. Chernikov return (false); 2944c91a5dfSAlexander V. Chernikov 2954c91a5dfSAlexander V. Chernikov struct sockaddr_dl sdl = { 2964c91a5dfSAlexander V. Chernikov .sdl_len = sizeof(struct sockaddr_dl), 2974c91a5dfSAlexander V. Chernikov .sdl_family = AF_LINK, 29831016aa0SGleb Smirnoff .sdl_type = convert_iftype(link->ifi_type), 2994c91a5dfSAlexander V. Chernikov .sdl_alen = NLA_DATA_LEN(link->ifla_address), 3004c91a5dfSAlexander V. Chernikov }; 3014c91a5dfSAlexander V. Chernikov return (match_ether(&sdl)); 3026f3947beSGleb Smirnoff } else if (args->afp->af_af == AF_LINK) 3036f3947beSGleb Smirnoff /* 3046f3947beSGleb Smirnoff * The rtnetlink(4) RTM_GETADDR does not list link level 3056f3947beSGleb Smirnoff * addresses, so latter cycle won't match anything. Short 3066f3947beSGleb Smirnoff * circuit on RTM_GETLINK has provided us an address. 3076f3947beSGleb Smirnoff */ 3086f3947beSGleb Smirnoff return (link->ifla_address != NULL); 3094c91a5dfSAlexander V. Chernikov 3104c91a5dfSAlexander V. Chernikov for (struct ifa *ifa = iface->ifa; ifa != NULL; ifa = ifa->next) { 3114c91a5dfSAlexander V. Chernikov if (args->afp->af_af == ifa->addr.ifa_family) 3124c91a5dfSAlexander V. Chernikov return (true); 3134c91a5dfSAlexander V. Chernikov } 3144c91a5dfSAlexander V. Chernikov 3154c91a5dfSAlexander V. Chernikov return (false); 3164c91a5dfSAlexander V. Chernikov } 3174c91a5dfSAlexander V. Chernikov 3184c91a5dfSAlexander V. Chernikov /* Sort according to the kernel-provided order */ 3194c91a5dfSAlexander V. Chernikov static int 3204c91a5dfSAlexander V. Chernikov cmp_iface(const void *_a, const void *_b) 3214c91a5dfSAlexander V. Chernikov { 3224c91a5dfSAlexander V. Chernikov const struct iface *a = *((const void * const *)_a); 3234c91a5dfSAlexander V. Chernikov const struct iface *b = *((const void * const *)_b); 3244c91a5dfSAlexander V. Chernikov 3254c91a5dfSAlexander V. Chernikov return ((a->idx > b->idx) * 2 - 1); 3264c91a5dfSAlexander V. Chernikov } 3274c91a5dfSAlexander V. Chernikov 3284c91a5dfSAlexander V. Chernikov static int 3294c91a5dfSAlexander V. Chernikov cmp_ifaddr(const void *_a, const void *_b) 3304c91a5dfSAlexander V. Chernikov { 3314c91a5dfSAlexander V. Chernikov const struct ifa *a = *((const void * const *)_a); 3324c91a5dfSAlexander V. Chernikov const struct ifa *b = *((const void * const *)_b); 3334c91a5dfSAlexander V. Chernikov 3344c91a5dfSAlexander V. Chernikov if (a->addr.ifa_family != b->addr.ifa_family) 3354c91a5dfSAlexander V. Chernikov return ((a->addr.ifa_family > b->addr.ifa_family) * 2 - 1); 3364c91a5dfSAlexander V. Chernikov return ((a->idx > b->idx) * 2 - 1); 3374c91a5dfSAlexander V. Chernikov } 3384c91a5dfSAlexander V. Chernikov 3394c91a5dfSAlexander V. Chernikov static void 3404c91a5dfSAlexander V. Chernikov sort_iface_ifaddrs(struct snl_state *ss, struct iface *iface) 3414c91a5dfSAlexander V. Chernikov { 3424c91a5dfSAlexander V. Chernikov if (iface->ifa_count == 0) 3434c91a5dfSAlexander V. Chernikov return; 3444c91a5dfSAlexander V. Chernikov 3454c91a5dfSAlexander V. Chernikov struct ifa **sorted_ifaddrs = snl_allocz(ss, iface->ifa_count * sizeof(void *)); 3464c91a5dfSAlexander V. Chernikov struct ifa *ifa = iface->ifa; 3474c91a5dfSAlexander V. Chernikov 34844cd85d4SAlexander V. Chernikov for (uint32_t i = 0; i < iface->ifa_count; i++) { 3494c91a5dfSAlexander V. Chernikov struct ifa *ifa_next = ifa->next; 3504c91a5dfSAlexander V. Chernikov 3514c91a5dfSAlexander V. Chernikov sorted_ifaddrs[i] = ifa; 3524c91a5dfSAlexander V. Chernikov ifa->next = NULL; 3534c91a5dfSAlexander V. Chernikov ifa = ifa_next; 3544c91a5dfSAlexander V. Chernikov } 3554c91a5dfSAlexander V. Chernikov qsort(sorted_ifaddrs, iface->ifa_count, sizeof(void *), cmp_ifaddr); 3564c91a5dfSAlexander V. Chernikov ifa = sorted_ifaddrs[0]; 3574c91a5dfSAlexander V. Chernikov iface->ifa = ifa; 35844cd85d4SAlexander V. Chernikov for (uint32_t i = 1; i < iface->ifa_count; i++) { 3594c91a5dfSAlexander V. Chernikov ifa->next = sorted_ifaddrs[i]; 3604c91a5dfSAlexander V. Chernikov ifa = sorted_ifaddrs[i]; 3614c91a5dfSAlexander V. Chernikov } 3624c91a5dfSAlexander V. Chernikov } 3634c91a5dfSAlexander V. Chernikov 3644c91a5dfSAlexander V. Chernikov static void 365c344eff9SAlexander V. Chernikov print_ifcaps(if_ctx *ctx, if_link_t *link) 366c344eff9SAlexander V. Chernikov { 367c344eff9SAlexander V. Chernikov uint32_t sz_u32 = roundup2(link->iflaf_caps.nla_bitset_size, 32) / 32; 368c344eff9SAlexander V. Chernikov 369c344eff9SAlexander V. Chernikov if (sz_u32 > 0) { 370c344eff9SAlexander V. Chernikov uint32_t *caps = link->iflaf_caps.nla_bitset_value; 371c344eff9SAlexander V. Chernikov 372c344eff9SAlexander V. Chernikov printf("\toptions=%x", caps[0]); 373c344eff9SAlexander V. Chernikov print_bits("IFCAPS", caps, sz_u32, ifcap_bit_names, nitems(ifcap_bit_names)); 374c344eff9SAlexander V. Chernikov putchar('\n'); 375c344eff9SAlexander V. Chernikov } 376c344eff9SAlexander V. Chernikov 377c344eff9SAlexander V. Chernikov if (ctx->args->supmedia && sz_u32 > 0) { 378c344eff9SAlexander V. Chernikov uint32_t *caps = link->iflaf_caps.nla_bitset_mask; 379c344eff9SAlexander V. Chernikov 380c344eff9SAlexander V. Chernikov printf("\tcapabilities=%x", caps[0]); 381c344eff9SAlexander V. Chernikov print_bits("IFCAPS", caps, sz_u32, ifcap_bit_names, nitems(ifcap_bit_names)); 382c344eff9SAlexander V. Chernikov putchar('\n'); 383c344eff9SAlexander V. Chernikov } 384c344eff9SAlexander V. Chernikov } 385c344eff9SAlexander V. Chernikov 386c344eff9SAlexander V. Chernikov static void 3876e3a9d7fSAlexander V. Chernikov status_nl(if_ctx *ctx, struct iface *iface) 3884c91a5dfSAlexander V. Chernikov { 3894c91a5dfSAlexander V. Chernikov if_link_t *link = &iface->link; 3906e3a9d7fSAlexander V. Chernikov struct ifconfig_args *args = ctx->args; 3914c91a5dfSAlexander V. Chernikov 3924c91a5dfSAlexander V. Chernikov printf("%s: ", link->ifla_ifname); 3934c91a5dfSAlexander V. Chernikov 3944c91a5dfSAlexander V. Chernikov printf("flags=%x", link->ifi_flags); 3954c91a5dfSAlexander V. Chernikov print_bits("IFF", &link->ifi_flags, 1, IFFBITS, nitems(IFFBITS)); 3964c91a5dfSAlexander V. Chernikov 3977fa282e6SAlexander V. Chernikov print_metric(ctx); 3984c91a5dfSAlexander V. Chernikov printf(" mtu %d\n", link->ifla_mtu); 3994c91a5dfSAlexander V. Chernikov 4004c91a5dfSAlexander V. Chernikov if (link->ifla_ifalias != NULL) 4014c91a5dfSAlexander V. Chernikov printf("\tdescription: %s\n", link->ifla_ifalias); 4024c91a5dfSAlexander V. Chernikov 403c344eff9SAlexander V. Chernikov print_ifcaps(ctx, link); 404c6f0602fSAlexander V. Chernikov tunnel_status(ctx); 4054c91a5dfSAlexander V. Chernikov 4064c91a5dfSAlexander V. Chernikov if (args->allfamilies | (args->afp != NULL && args->afp->af_af == AF_LINK)) { 4074c91a5dfSAlexander V. Chernikov /* Start with link-level */ 4084c91a5dfSAlexander V. Chernikov const struct afswtch *p = af_getbyfamily(AF_LINK); 4094c91a5dfSAlexander V. Chernikov if (p != NULL && link->ifla_address != NULL) 4106e3a9d7fSAlexander V. Chernikov p->af_status(ctx, link, NULL); 4114c91a5dfSAlexander V. Chernikov } 4124c91a5dfSAlexander V. Chernikov 4136e3a9d7fSAlexander V. Chernikov sort_iface_ifaddrs(ctx->io_ss, iface); 4144c91a5dfSAlexander V. Chernikov 4154c91a5dfSAlexander V. Chernikov for (struct ifa *ifa = iface->ifa; ifa != NULL; ifa = ifa->next) { 4164c91a5dfSAlexander V. Chernikov if (args->allfamilies) { 4174c91a5dfSAlexander V. Chernikov const struct afswtch *p = af_getbyfamily(ifa->addr.ifa_family); 4184c91a5dfSAlexander V. Chernikov 4194c91a5dfSAlexander V. Chernikov if (p != NULL) 4206e3a9d7fSAlexander V. Chernikov p->af_status(ctx, link, &ifa->addr); 4214c91a5dfSAlexander V. Chernikov } else if (args->afp->af_af == ifa->addr.ifa_family) { 4224c91a5dfSAlexander V. Chernikov const struct afswtch *p = args->afp; 4234c91a5dfSAlexander V. Chernikov 4246e3a9d7fSAlexander V. Chernikov p->af_status(ctx, link, &ifa->addr); 4254c91a5dfSAlexander V. Chernikov } 4264c91a5dfSAlexander V. Chernikov } 4274c91a5dfSAlexander V. Chernikov 4284c91a5dfSAlexander V. Chernikov /* TODO: convert to netlink */ 4294c91a5dfSAlexander V. Chernikov if (args->allfamilies) 4306e3a9d7fSAlexander V. Chernikov af_other_status(ctx); 4314c91a5dfSAlexander V. Chernikov else if (args->afp->af_other_status != NULL) 4326e3a9d7fSAlexander V. Chernikov args->afp->af_other_status(ctx); 4334c91a5dfSAlexander V. Chernikov 43485e0016aSAlexander V. Chernikov print_ifstatus(ctx); 4354c91a5dfSAlexander V. Chernikov if (args->verbose > 0) 4360c2beef7SAlexander V. Chernikov sfp_status(ctx); 4374c91a5dfSAlexander V. Chernikov } 4384c91a5dfSAlexander V. Chernikov 4394c91a5dfSAlexander V. Chernikov static int 4404c91a5dfSAlexander V. Chernikov get_local_socket(void) 4414c91a5dfSAlexander V. Chernikov { 4424c91a5dfSAlexander V. Chernikov int s = socket(AF_LOCAL, SOCK_DGRAM, 0); 4434c91a5dfSAlexander V. Chernikov 4444c91a5dfSAlexander V. Chernikov if (s < 0) 4454c91a5dfSAlexander V. Chernikov err(1, "socket(family %u,SOCK_DGRAM)", AF_LOCAL); 4464c91a5dfSAlexander V. Chernikov return (s); 4474c91a5dfSAlexander V. Chernikov } 4484c91a5dfSAlexander V. Chernikov 4494c91a5dfSAlexander V. Chernikov void 4504c91a5dfSAlexander V. Chernikov list_interfaces_nl(struct ifconfig_args *args) 4514c91a5dfSAlexander V. Chernikov { 4524c91a5dfSAlexander V. Chernikov struct snl_state ss = {}; 4536e3a9d7fSAlexander V. Chernikov struct ifconfig_context _ctx = { 4546e3a9d7fSAlexander V. Chernikov .args = args, 4556e3a9d7fSAlexander V. Chernikov .io_s = get_local_socket(), 4566e3a9d7fSAlexander V. Chernikov .io_ss = &ss, 4576e3a9d7fSAlexander V. Chernikov }; 4586e3a9d7fSAlexander V. Chernikov struct ifconfig_context *ctx = &_ctx; 4594c91a5dfSAlexander V. Chernikov 4604c91a5dfSAlexander V. Chernikov nl_init_socket(&ss); 4614c91a5dfSAlexander V. Chernikov 4624c91a5dfSAlexander V. Chernikov struct ifmap *ifmap = prepare_ifmap(&ss); 4634c91a5dfSAlexander V. Chernikov struct iface **sorted_ifaces = snl_allocz(&ss, ifmap->count * sizeof(void *)); 46444cd85d4SAlexander V. Chernikov for (uint32_t i = 0, num = 0; i < ifmap->size; i++) { 4654c91a5dfSAlexander V. Chernikov if (ifmap->ifaces[i] != NULL) { 4664c91a5dfSAlexander V. Chernikov sorted_ifaces[num++] = ifmap->ifaces[i]; 4674c91a5dfSAlexander V. Chernikov if (num == ifmap->count) 4684c91a5dfSAlexander V. Chernikov break; 4694c91a5dfSAlexander V. Chernikov } 4704c91a5dfSAlexander V. Chernikov } 4714c91a5dfSAlexander V. Chernikov qsort(sorted_ifaces, ifmap->count, sizeof(void *), cmp_iface); 4724c91a5dfSAlexander V. Chernikov prepare_ifaddrs(&ss, ifmap); 4734c91a5dfSAlexander V. Chernikov 47444cd85d4SAlexander V. Chernikov for (uint32_t i = 0, num = 0; i < ifmap->count; i++) { 4754c91a5dfSAlexander V. Chernikov struct iface *iface = sorted_ifaces[i]; 4764c91a5dfSAlexander V. Chernikov 4774c91a5dfSAlexander V. Chernikov if (!match_iface(args, iface)) 4784c91a5dfSAlexander V. Chernikov continue; 4794c91a5dfSAlexander V. Chernikov 48085e0016aSAlexander V. Chernikov ctx->ifname = iface->link.ifla_ifname; 4814c91a5dfSAlexander V. Chernikov 4824c91a5dfSAlexander V. Chernikov if (args->namesonly) { 4834c91a5dfSAlexander V. Chernikov if (num++ != 0) 4844c91a5dfSAlexander V. Chernikov printf(" "); 4854c91a5dfSAlexander V. Chernikov fputs(iface->link.ifla_ifname, stdout); 4864c91a5dfSAlexander V. Chernikov } else if (args->argc == 0) 4876e3a9d7fSAlexander V. Chernikov status_nl(ctx, iface); 48826056fa8SAlexander V. Chernikov else 489bbad5525SAlexander V. Chernikov ifconfig_ioctl(ctx, 0, args->afp); 4904c91a5dfSAlexander V. Chernikov } 4914c91a5dfSAlexander V. Chernikov if (args->namesonly) 4924c91a5dfSAlexander V. Chernikov printf("\n"); 4934c91a5dfSAlexander V. Chernikov 4946e3a9d7fSAlexander V. Chernikov close(ctx->io_s); 4954c91a5dfSAlexander V. Chernikov snl_free(&ss); 4964c91a5dfSAlexander V. Chernikov } 4974c91a5dfSAlexander V. Chernikov 498