1167706Sbms/* $KAME: ifmcstat.c,v 1.48 2006/11/15 05:13:59 itojun Exp $ */ 2167706Sbms 355163Sshin/* 4188645Sbms * Copyright (c) 2007-2009 Bruce Simpson. 555163Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 655163Sshin * All rights reserved. 762785Sume * 855163Sshin * Redistribution and use in source and binary forms, with or without 955163Sshin * modification, are permitted provided that the following conditions 1055163Sshin * are met: 1155163Sshin * 1. Redistributions of source code must retain the above copyright 1255163Sshin * notice, this list of conditions and the following disclaimer. 1355163Sshin * 2. Redistributions in binary form must reproduce the above copyright 1455163Sshin * notice, this list of conditions and the following disclaimer in the 1555163Sshin * documentation and/or other materials provided with the distribution. 1655163Sshin * 3. Neither the name of the project nor the names of its contributors 1755163Sshin * may be used to endorse or promote products derived from this software 1855163Sshin * without specific prior written permission. 1962785Sume * 2055163Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2155163Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2255163Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2355163Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2455163Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2555163Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2655163Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2755163Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2855163Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2955163Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3055163Sshin * SUCH DAMAGE. 3155163Sshin */ 3255163Sshin 33167706Sbms#include <sys/cdefs.h> 34167706Sbms__FBSDID("$FreeBSD$"); 35167706Sbms 3655163Sshin#include <sys/types.h> 37167706Sbms#include <sys/param.h> 38189592Sbms#include <sys/sysctl.h> 3955163Sshin#include <sys/socket.h> 4078064Sume#include <sys/queue.h> 41189592Sbms#include <sys/tree.h> 4278064Sume 4355163Sshin#include <net/if.h> 44167712Sbms#include <net/if_var.h> 4555163Sshin#include <net/if_types.h> 4655163Sshin#include <net/if_dl.h> 47167706Sbms#include <net/route.h> 48167712Sbms 4955163Sshin#include <netinet/in.h> 50167712Sbms#include <netinet/in_var.h> 51167706Sbms#include <netinet/in_systm.h> 52167706Sbms#include <netinet/ip.h> 53167706Sbms#include <netinet/igmp.h> 54167712Sbms#define KERNEL 55167706Sbms# include <netinet/if_ether.h> 56167712Sbms#undef KERNEL 57167712Sbms#define _KERNEL 58189592Sbms#define SYSCTL_DECL(x) 59167712Sbms# include <netinet/igmp_var.h> 60189592Sbms#undef SYSCTL_DECL 61167712Sbms#undef _KERNEL 62167712Sbms 63167712Sbms#ifdef INET6 64167706Sbms#include <netinet/icmp6.h> 65167706Sbms#define _KERNEL 66167712Sbms# include <netinet6/mld6_var.h> 67167706Sbms#undef _KERNEL 68167712Sbms#endif /* INET6 */ 69167712Sbms 70168560Sbms#include <arpa/inet.h> 71168560Sbms#include <netdb.h> 72168560Sbms 73168560Sbms#include <stddef.h> 74168560Sbms#include <stdarg.h> 75168560Sbms#include <stdint.h> 76167712Sbms#include <stdio.h> 77167712Sbms#include <stdlib.h> 78168560Sbms#include <string.h> 79168560Sbms 80168560Sbms#include <ctype.h> 81168560Sbms#include <err.h> 82189592Sbms#include <errno.h> 83167712Sbms#include <fcntl.h> 84167712Sbms#include <kvm.h> 85168560Sbms#include <limits.h> 86168560Sbms#include <ifaddrs.h> 87167712Sbms#include <nlist.h> 88168560Sbms#include <sysexits.h> 89167712Sbms#include <unistd.h> 9062785Sume 91168560Sbms/* XXX: This file currently assumes INET and KVM support in the base system. */ 92168560Sbms#ifndef INET 93168560Sbms#define INET 94168560Sbms#endif 9555163Sshin 96189592Sbmsextern void printb(const char *, unsigned int, const char *); 97189592Sbms 98168560Sbmsunion sockunion { 99168560Sbms struct sockaddr_storage ss; 100168560Sbms struct sockaddr sa; 101168560Sbms struct sockaddr_dl sdl; 102168560Sbms#ifdef INET 103168560Sbms struct sockaddr_in sin; 104168560Sbms#endif 105168560Sbms#ifdef INET6 106168560Sbms struct sockaddr_in6 sin6; 107168560Sbms#endif 10855163Sshin}; 109168560Sbmstypedef union sockunion sockunion_t; 11055163Sshin 111168560Sbmsuint32_t ifindex = 0; 112168560Sbmsint af = AF_UNSPEC; 113189592Sbms#ifdef WITH_KVM 114189592Sbmsint Kflag = 0; 115189592Sbms#endif 116188645Sbmsint vflag = 0; 117168560Sbms 118168560Sbms#define sa_equal(a1, a2) \ 119168560Sbms (bcmp((a1), (a2), ((a1))->sa_len) == 0) 120168560Sbms 121168560Sbms#define sa_dl_equal(a1, a2) \ 122168560Sbms ((((struct sockaddr_dl *)(a1))->sdl_len == \ 123168560Sbms ((struct sockaddr_dl *)(a2))->sdl_len) && \ 124168560Sbms (bcmp(LLADDR((struct sockaddr_dl *)(a1)), \ 125168560Sbms LLADDR((struct sockaddr_dl *)(a2)), \ 126168560Sbms ((struct sockaddr_dl *)(a1))->sdl_alen) == 0)) 127168560Sbms 128168560Sbms/* 129168560Sbms * Most of the code in this utility is to support the use of KVM for 130168560Sbms * post-mortem debugging of the multicast code. 131168560Sbms */ 132168560Sbms#ifdef WITH_KVM 133168560Sbms 134168560Sbms#ifdef INET 135168560Sbmsstatic void if_addrlist(struct ifaddr *); 136168560Sbmsstatic struct in_multi * 137168560Sbms in_multientry(struct in_multi *); 138168560Sbms#endif /* INET */ 139168560Sbms 140168560Sbms#ifdef INET6 141168560Sbmsstatic void if6_addrlist(struct ifaddr *); 142168560Sbmsstatic struct in6_multi * 143168560Sbms in6_multientry(struct in6_multi *); 144168560Sbms#endif /* INET6 */ 14555163Sshin 146168560Sbmsstatic void kread(u_long, void *, int); 147188645Sbmsstatic void ll_addrlist(struct ifaddr *); 148188645Sbms 149168560Sbmsstatic int ifmcstat_kvm(const char *kernel, const char *core); 150168560Sbms 15155163Sshin#define KREAD(addr, buf, type) \ 15255163Sshin kread((u_long)addr, (void *)buf, sizeof(type)) 15355163Sshin 154168560Sbmskvm_t *kvmd; 155168560Sbmsstruct nlist nl[] = { 156168560Sbms { "_ifnet", 0, 0, 0, 0, }, 157168560Sbms { "", 0, 0, 0, 0, }, 158168560Sbms}; 159168560Sbms#define N_IFNET 0 16055163Sshin 161168560Sbms#endif /* WITH_KVM */ 16255163Sshin 163168560Sbmsstatic int ifmcstat_getifmaddrs(void); 164189592Sbms#ifdef INET 165189592Sbmsstatic void in_ifinfo(struct igmp_ifinfo *); 166189592Sbmsstatic const char * inm_mode(u_int mode); 167189592Sbms#endif 168188645Sbms#ifdef INET6 169191672Sbmsstatic void in6_ifinfo(struct mld_ifinfo *); 170243441Shrsstatic const char * inet6_n2a(struct in6_addr *, uint32_t); 171188645Sbms#endif 172168560Sbmsint main(int, char **); 173168560Sbms 174188645Sbmsstatic void 175188645Sbmsusage() 176188645Sbms{ 177188645Sbms 178188645Sbms fprintf(stderr, 179188645Sbms "usage: ifmcstat [-i interface] [-f address family]" 180188645Sbms " [-v]" 181188645Sbms#ifdef WITH_KVM 182189592Sbms " [-K] [-M core] [-N system]" 183188645Sbms#endif 184188645Sbms "\n"); 185188645Sbms exit(EX_USAGE); 186188645Sbms} 187188645Sbms 188189592Sbmsstatic const char *options = "i:f:vM:N:" 189189592Sbms#ifdef WITH_KVM 190189592Sbms "K" 191189592Sbms#endif 192189592Sbms ; 193189592Sbms 194168560Sbmsint 195168560Sbmsmain(int argc, char **argv) 19655163Sshin{ 197168560Sbms int c, error; 198168560Sbms#ifdef WITH_KVM 199167706Sbms const char *kernel = NULL; 200167731Sbms const char *core = NULL; 201168560Sbms#endif 202167706Sbms 203189592Sbms while ((c = getopt(argc, argv, options)) != -1) { 204167706Sbms switch (c) { 205167706Sbms case 'i': 206167706Sbms if ((ifindex = if_nametoindex(optarg)) == 0) { 207168560Sbms fprintf(stderr, "%s: unknown interface\n", 208168560Sbms optarg); 209188647Sbms exit(EX_NOHOST); 210167706Sbms } 211167706Sbms break; 212168560Sbms 213167706Sbms case 'f': 214168560Sbms#ifdef INET 215167706Sbms if (strcmp(optarg, "inet") == 0) { 216167706Sbms af = AF_INET; 217167706Sbms break; 218167706Sbms } 219168560Sbms#endif 220168560Sbms#ifdef INET6 221167706Sbms if (strcmp(optarg, "inet6") == 0) { 222167706Sbms af = AF_INET6; 223167706Sbms break; 224167706Sbms } 225168560Sbms#endif 226188645Sbms if (strcmp(optarg, "link") == 0) { 227188645Sbms af = AF_LINK; 228188645Sbms break; 229188645Sbms } 230167706Sbms fprintf(stderr, "%s: unknown address family\n", optarg); 231188647Sbms exit(EX_USAGE); 232167706Sbms /*NOTREACHED*/ 233168560Sbms break; 234168560Sbms 235189592Sbms#ifdef WITH_KVM 236189592Sbms case 'K': 237189592Sbms ++Kflag; 238189592Sbms break; 239189592Sbms#endif 240189592Sbms 241188645Sbms case 'v': 242189592Sbms ++vflag; 243188645Sbms break; 244188645Sbms 245168560Sbms#ifdef WITH_KVM 246167731Sbms case 'M': 247167731Sbms core = strdup(optarg); 248167731Sbms break; 249168560Sbms 250167731Sbms case 'N': 251167706Sbms kernel = strdup(optarg); 252167706Sbms break; 253168560Sbms#endif 254168560Sbms 255167706Sbms default: 256188645Sbms usage(); 257168560Sbms break; 258167706Sbms /*NOTREACHED*/ 259167706Sbms } 260167706Sbms } 261167706Sbms 262188645Sbms if (af == AF_LINK && vflag) 263188645Sbms usage(); 264188645Sbms 265168560Sbms#ifdef WITH_KVM 266192923Sbms if (Kflag) 267189592Sbms error = ifmcstat_kvm(kernel, core); 268168560Sbms /* 269168560Sbms * If KVM failed, and user did not explicitly specify a core file, 270189592Sbms * or force KVM backend to be disabled, try the sysctl backend. 271168560Sbms */ 272192923Sbms if (!Kflag || (error != 0 && (core == NULL && kernel == NULL))) 273168560Sbms#endif 274168560Sbms error = ifmcstat_getifmaddrs(); 275168560Sbms if (error != 0) 276188647Sbms exit(EX_OSERR); 277168560Sbms 278188647Sbms exit(EX_OK); 279168560Sbms /*NOTREACHED*/ 280168560Sbms} 281168560Sbms 282189592Sbms#ifdef INET 283189592Sbms 284189592Sbmsstatic void 285189592Sbmsin_ifinfo(struct igmp_ifinfo *igi) 286189592Sbms{ 287189592Sbms 288189592Sbms printf("\t"); 289189592Sbms switch (igi->igi_version) { 290189592Sbms case IGMP_VERSION_1: 291189592Sbms case IGMP_VERSION_2: 292189592Sbms case IGMP_VERSION_3: 293189592Sbms printf("igmpv%d", igi->igi_version); 294189592Sbms break; 295189592Sbms default: 296189592Sbms printf("igmpv?(%d)", igi->igi_version); 297189592Sbms break; 298189592Sbms } 299245015Shrs if (igi->igi_flags) 300245015Shrs printb(" flags", igi->igi_flags, "\020\1SILENT\2LOOPBACK"); 301189592Sbms if (igi->igi_version == IGMP_VERSION_3) { 302189592Sbms printf(" rv %u qi %u qri %u uri %u", 303189592Sbms igi->igi_rv, igi->igi_qi, igi->igi_qri, igi->igi_uri); 304189592Sbms } 305189592Sbms if (vflag >= 2) { 306189592Sbms printf(" v1timer %u v2timer %u v3timer %u", 307189592Sbms igi->igi_v1_timer, igi->igi_v2_timer, igi->igi_v3_timer); 308189592Sbms } 309189592Sbms printf("\n"); 310189592Sbms} 311189592Sbms 312189592Sbmsstatic const char *inm_modes[] = { 313189592Sbms "undefined", 314189592Sbms "include", 315189592Sbms "exclude", 316189592Sbms}; 317189592Sbms 318189592Sbmsstatic const char * 319189592Sbmsinm_mode(u_int mode) 320189592Sbms{ 321189592Sbms 322189592Sbms if (mode >= MCAST_UNDEFINED && mode <= MCAST_EXCLUDE) 323189592Sbms return (inm_modes[mode]); 324189592Sbms return (NULL); 325189592Sbms} 326189592Sbms 327189592Sbms#endif /* INET */ 328189592Sbms 329168560Sbms#ifdef WITH_KVM 330168560Sbms 331168560Sbmsstatic int 332168560Sbmsifmcstat_kvm(const char *kernel, const char *core) 333168560Sbms{ 334168560Sbms char buf[_POSIX2_LINE_MAX], ifname[IFNAMSIZ]; 335168560Sbms struct ifnet *ifp, *nifp, ifnet; 336168560Sbms 337167731Sbms if ((kvmd = kvm_openfiles(kernel, core, NULL, O_RDONLY, buf)) == 338167731Sbms NULL) { 33955163Sshin perror("kvm_openfiles"); 340168560Sbms return (-1); 34155163Sshin } 34255163Sshin if (kvm_nlist(kvmd, nl) < 0) { 34355163Sshin perror("kvm_nlist"); 344168560Sbms return (-1); 34555163Sshin } 34655163Sshin if (nl[N_IFNET].n_value == 0) { 34755163Sshin printf("symbol %s not found\n", nl[N_IFNET].n_name); 348168560Sbms return (-1); 34955163Sshin } 35055163Sshin KREAD(nl[N_IFNET].n_value, &ifp, struct ifnet *); 35155163Sshin while (ifp) { 35255163Sshin KREAD(ifp, &ifnet, struct ifnet); 353167706Sbms nifp = ifnet.if_link.tqe_next; 354167706Sbms if (ifindex && ifindex != ifnet.if_index) 355167706Sbms goto next; 356167706Sbms 35755163Sshin printf("%s:\n", if_indextoname(ifnet.if_index, ifname)); 358168560Sbms#ifdef INET 359167706Sbms if_addrlist(TAILQ_FIRST(&ifnet.if_addrhead)); 360168560Sbms#endif 361167712Sbms#ifdef INET6 36255163Sshin if6_addrlist(TAILQ_FIRST(&ifnet.if_addrhead)); 363167706Sbms#endif 364188645Sbms if (vflag) 365188645Sbms ll_addrlist(TAILQ_FIRST(&ifnet.if_addrhead)); 366188647Sbms next: 36762785Sume ifp = nifp; 36855163Sshin } 36955163Sshin 370168560Sbms return (0); 37155163Sshin} 37255163Sshin 373168560Sbmsstatic void 374168560Sbmskread(u_long addr, void *buf, int len) 37555163Sshin{ 37655163Sshin 37755163Sshin if (kvm_read(kvmd, addr, buf, len) != len) { 37855163Sshin perror("kvm_read"); 379188647Sbms exit(EX_OSERR); 38055163Sshin } 38155163Sshin} 38255163Sshin 383188645Sbmsstatic void 384188645Sbmsll_addrlist(struct ifaddr *ifap) 38555163Sshin{ 386188645Sbms char addrbuf[NI_MAXHOST]; 387188645Sbms struct ifaddr ifa; 388188645Sbms struct sockaddr sa; 389188645Sbms struct sockaddr_dl sdl; 390188645Sbms struct ifaddr *ifap0; 391168560Sbms 392188645Sbms if (af && af != AF_LINK) 393188645Sbms return; 394188645Sbms 395188645Sbms ifap0 = ifap; 396188645Sbms while (ifap) { 397188645Sbms KREAD(ifap, &ifa, struct ifaddr); 398188645Sbms if (ifa.ifa_addr == NULL) 399188645Sbms goto nextifap; 400188645Sbms KREAD(ifa.ifa_addr, &sa, struct sockaddr); 401188645Sbms if (sa.sa_family != PF_LINK) 402188645Sbms goto nextifap; 403188645Sbms KREAD(ifa.ifa_addr, &sdl, struct sockaddr_dl); 404188645Sbms if (sdl.sdl_alen == 0) 405188645Sbms goto nextifap; 406188645Sbms addrbuf[0] = '\0'; 407237256Seadler getnameinfo((struct sockaddr *)&sdl, sdl.sdl_len, 408188645Sbms addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST); 409188645Sbms printf("\tlink %s\n", addrbuf); 410188645Sbms nextifap: 411188645Sbms ifap = ifa.ifa_link.tqe_next; 412188645Sbms } 413188645Sbms if (ifap0) { 414188645Sbms struct ifnet ifnet; 415188645Sbms struct ifmultiaddr ifm, *ifmp = 0; 416188645Sbms 417188645Sbms KREAD(ifap0, &ifa, struct ifaddr); 418188645Sbms KREAD(ifa.ifa_ifp, &ifnet, struct ifnet); 419188645Sbms if (TAILQ_FIRST(&ifnet.if_multiaddrs)) 420188645Sbms ifmp = TAILQ_FIRST(&ifnet.if_multiaddrs); 421188645Sbms while (ifmp) { 422188645Sbms KREAD(ifmp, &ifm, struct ifmultiaddr); 423188645Sbms if (ifm.ifma_addr == NULL) 424188645Sbms goto nextmulti; 425188645Sbms KREAD(ifm.ifma_addr, &sa, struct sockaddr); 426188645Sbms if (sa.sa_family != AF_LINK) 427188645Sbms goto nextmulti; 428188645Sbms KREAD(ifm.ifma_addr, &sdl, struct sockaddr_dl); 429188645Sbms addrbuf[0] = '\0'; 430237256Seadler getnameinfo((struct sockaddr *)&sdl, 431188645Sbms sdl.sdl_len, addrbuf, sizeof(addrbuf), 432188645Sbms NULL, 0, NI_NUMERICHOST); 433188645Sbms printf("\t\tgroup %s refcnt %d\n", 434188645Sbms addrbuf, ifm.ifma_refcount); 435188645Sbms nextmulti: 436188645Sbms ifmp = TAILQ_NEXT(&ifm, ifma_link); 437168560Sbms } 438168560Sbms } 439168560Sbms} 440168560Sbms 441188645Sbms#ifdef INET6 442188645Sbms 443168560Sbmsstatic void 444168560Sbmsif6_addrlist(struct ifaddr *ifap) 445168560Sbms{ 446191672Sbms struct ifnet ifnet; 44755163Sshin struct ifaddr ifa; 44862785Sume struct sockaddr sa; 44962785Sume struct in6_ifaddr if6a; 45055543Sshin struct ifaddr *ifap0; 45155163Sshin 452167706Sbms if (af && af != AF_INET6) 453167706Sbms return; 45455163Sshin ifap0 = ifap; 45562785Sume while (ifap) { 45655163Sshin KREAD(ifap, &ifa, struct ifaddr); 45755163Sshin if (ifa.ifa_addr == NULL) 45862785Sume goto nextifap; 45955163Sshin KREAD(ifa.ifa_addr, &sa, struct sockaddr); 46055163Sshin if (sa.sa_family != PF_INET6) 46162785Sume goto nextifap; 46255163Sshin KREAD(ifap, &if6a, struct in6_ifaddr); 463243441Shrs printf("\tinet6 %s\n", inet6_n2a(&if6a.ia_addr.sin6_addr, 464243441Shrs if6a.ia_addr.sin6_scope_id)); 465191672Sbms /* 466191672Sbms * Print per-link MLD information, if available. 467191672Sbms */ 468191672Sbms if (ifa.ifa_ifp != NULL) { 469191672Sbms struct in6_ifextra ie; 470191672Sbms struct mld_ifinfo mli; 471191672Sbms 472191672Sbms KREAD(ifa.ifa_ifp, &ifnet, struct ifnet); 473191672Sbms KREAD(ifnet.if_afdata[AF_INET6], &ie, 474191672Sbms struct in6_ifextra); 475191672Sbms if (ie.mld_ifinfo != NULL) { 476191672Sbms KREAD(ie.mld_ifinfo, &mli, struct mld_ifinfo); 477191672Sbms in6_ifinfo(&mli); 478191672Sbms } 479191672Sbms } 48062785Sume nextifap: 481167706Sbms ifap = ifa.ifa_link.tqe_next; 48262785Sume } 48362785Sume if (ifap0) { 48462785Sume struct ifnet ifnet; 48562785Sume struct ifmultiaddr ifm, *ifmp = 0; 48662785Sume struct sockaddr_dl sdl; 48755163Sshin 48862785Sume KREAD(ifap0, &ifa, struct ifaddr); 48962785Sume KREAD(ifa.ifa_ifp, &ifnet, struct ifnet); 49072084Sphk if (TAILQ_FIRST(&ifnet.if_multiaddrs)) 49172084Sphk ifmp = TAILQ_FIRST(&ifnet.if_multiaddrs); 49262785Sume while (ifmp) { 49362785Sume KREAD(ifmp, &ifm, struct ifmultiaddr); 49462785Sume if (ifm.ifma_addr == NULL) 49562785Sume goto nextmulti; 49662785Sume KREAD(ifm.ifma_addr, &sa, struct sockaddr); 49762785Sume if (sa.sa_family != AF_INET6) 49862785Sume goto nextmulti; 49962785Sume (void)in6_multientry((struct in6_multi *) 50062785Sume ifm.ifma_protospec); 50162785Sume if (ifm.ifma_lladdr == 0) 50262785Sume goto nextmulti; 50362785Sume KREAD(ifm.ifma_lladdr, &sdl, struct sockaddr_dl); 504168560Sbms printf("\t\t\tmcast-macaddr %s refcnt %d\n", 50562785Sume ether_ntoa((struct ether_addr *)LLADDR(&sdl)), 50662785Sume ifm.ifma_refcount); 50762785Sume nextmulti: 50872084Sphk ifmp = TAILQ_NEXT(&ifm, ifma_link); 50962785Sume } 51062785Sume } 51155163Sshin} 51255163Sshin 513168560Sbmsstatic struct in6_multi * 514168560Sbmsin6_multientry(struct in6_multi *mc) 51555163Sshin{ 51655163Sshin struct in6_multi multi; 51755163Sshin 51855163Sshin KREAD(mc, &multi, struct in6_multi); 519243441Shrs printf("\t\tgroup %s", inet6_n2a(&multi.in6m_addr, 0)); 52062785Sume printf(" refcnt %u\n", multi.in6m_refcount); 521167706Sbms 522188647Sbms return (multi.in6m_entry.le_next); 52355163Sshin} 52462785Sume 525167712Sbms#endif /* INET6 */ 526167712Sbms 527168560Sbms#ifdef INET 528168560Sbms 529168560Sbmsstatic void 530168560Sbmsif_addrlist(struct ifaddr *ifap) 531167706Sbms{ 532167706Sbms struct ifaddr ifa; 533189592Sbms struct ifnet ifnet; 534167706Sbms struct sockaddr sa; 535167706Sbms struct in_ifaddr ia; 536167706Sbms struct ifaddr *ifap0; 537167706Sbms 538167706Sbms if (af && af != AF_INET) 539167706Sbms return; 540167706Sbms ifap0 = ifap; 541167706Sbms while (ifap) { 542167706Sbms KREAD(ifap, &ifa, struct ifaddr); 543167706Sbms if (ifa.ifa_addr == NULL) 544167706Sbms goto nextifap; 545167706Sbms KREAD(ifa.ifa_addr, &sa, struct sockaddr); 546167706Sbms if (sa.sa_family != PF_INET) 547167706Sbms goto nextifap; 548167706Sbms KREAD(ifap, &ia, struct in_ifaddr); 549167706Sbms printf("\tinet %s\n", inet_ntoa(ia.ia_addr.sin_addr)); 550189592Sbms /* 551189592Sbms * Print per-link IGMP information, if available. 552189592Sbms */ 553189592Sbms if (ifa.ifa_ifp != NULL) { 554189592Sbms struct in_ifinfo ii; 555189592Sbms struct igmp_ifinfo igi; 556189592Sbms 557189592Sbms KREAD(ifa.ifa_ifp, &ifnet, struct ifnet); 558189592Sbms KREAD(ifnet.if_afdata[AF_INET], &ii, struct in_ifinfo); 559189592Sbms if (ii.ii_igmp != NULL) { 560189592Sbms KREAD(ii.ii_igmp, &igi, struct igmp_ifinfo); 561189592Sbms in_ifinfo(&igi); 562189592Sbms } 563189592Sbms } 564167706Sbms nextifap: 565167706Sbms ifap = ifa.ifa_link.tqe_next; 566167706Sbms } 567167706Sbms if (ifap0) { 568167706Sbms struct ifmultiaddr ifm, *ifmp = 0; 569167706Sbms struct sockaddr_dl sdl; 570167706Sbms 571167706Sbms KREAD(ifap0, &ifa, struct ifaddr); 572167706Sbms KREAD(ifa.ifa_ifp, &ifnet, struct ifnet); 573167706Sbms if (TAILQ_FIRST(&ifnet.if_multiaddrs)) 574167706Sbms ifmp = TAILQ_FIRST(&ifnet.if_multiaddrs); 575167706Sbms while (ifmp) { 576167706Sbms KREAD(ifmp, &ifm, struct ifmultiaddr); 577167706Sbms if (ifm.ifma_addr == NULL) 578167706Sbms goto nextmulti; 579167706Sbms KREAD(ifm.ifma_addr, &sa, struct sockaddr); 580167706Sbms if (sa.sa_family != AF_INET) 581167706Sbms goto nextmulti; 582167706Sbms (void)in_multientry((struct in_multi *) 583167706Sbms ifm.ifma_protospec); 584167706Sbms if (ifm.ifma_lladdr == 0) 585167706Sbms goto nextmulti; 586167706Sbms KREAD(ifm.ifma_lladdr, &sdl, struct sockaddr_dl); 587168560Sbms printf("\t\t\tmcast-macaddr %s refcnt %d\n", 588167706Sbms ether_ntoa((struct ether_addr *)LLADDR(&sdl)), 589167706Sbms ifm.ifma_refcount); 590167706Sbms nextmulti: 591167706Sbms ifmp = TAILQ_NEXT(&ifm, ifma_link); 592167706Sbms } 593167706Sbms } 594167706Sbms} 595167706Sbms 596189592Sbmsstatic const char *inm_states[] = { 597189592Sbms "not-member", 598189592Sbms "silent", 599189592Sbms "idle", 600189592Sbms "lazy", 601189592Sbms "sleeping", 602189592Sbms "awakening", 603189592Sbms "query-pending", 604189592Sbms "sg-query-pending", 605189592Sbms "leaving" 606189592Sbms}; 607189592Sbms 608189592Sbmsstatic const char * 609189592Sbmsinm_state(u_int state) 610167706Sbms{ 611167706Sbms 612189592Sbms if (state >= IGMP_NOT_MEMBER && state <= IGMP_LEAVING_MEMBER) 613189592Sbms return (inm_states[state]); 614189592Sbms return (NULL); 615189592Sbms} 616167706Sbms 617189592Sbms#if 0 618189592Sbmsstatic struct ip_msource * 619189592Sbmsims_min_kvm(struct in_multi *pinm) 620189592Sbms{ 621189592Sbms struct ip_msource ims0; 622189592Sbms struct ip_msource *tmp, *parent; 623167706Sbms 624189592Sbms parent = NULL; 625189592Sbms tmp = RB_ROOT(&pinm->inm_srcs); 626189592Sbms while (tmp) { 627189592Sbms parent = tmp; 628189592Sbms KREAD(tmp, &ims0, struct ip_msource); 629189592Sbms tmp = RB_LEFT(&ims0, ims_link); 630189592Sbms } 631189592Sbms return (parent); /* kva */ 632189592Sbms} 633189592Sbms 634189592Sbms/* XXX This routine is buggy. See RB_NEXT in sys/tree.h. */ 635189592Sbmsstatic struct ip_msource * 636189592Sbmsims_next_kvm(struct ip_msource *ims) 637189592Sbms{ 638189592Sbms struct ip_msource ims0, ims1; 639189592Sbms struct ip_msource *tmp; 640189592Sbms 641189592Sbms KREAD(ims, &ims0, struct ip_msource); 642189592Sbms if (RB_RIGHT(&ims0, ims_link)) { 643189592Sbms ims = RB_RIGHT(&ims0, ims_link); 644189592Sbms KREAD(ims, &ims1, struct ip_msource); 645189592Sbms while ((tmp = RB_LEFT(&ims1, ims_link))) { 646189592Sbms KREAD(tmp, &ims0, struct ip_msource); 647189592Sbms ims = RB_LEFT(&ims0, ims_link); 648167706Sbms } 649189592Sbms } else { 650189592Sbms tmp = RB_PARENT(&ims0, ims_link); 651189592Sbms if (tmp) { 652189592Sbms KREAD(tmp, &ims1, struct ip_msource); 653189592Sbms if (ims == RB_LEFT(&ims1, ims_link)) 654189592Sbms ims = tmp; 655189592Sbms } else { 656189592Sbms while ((tmp = RB_PARENT(&ims0, ims_link))) { 657189592Sbms KREAD(tmp, &ims1, struct ip_msource); 658189592Sbms if (ims == RB_RIGHT(&ims1, ims_link)) { 659189592Sbms ims = tmp; 660189592Sbms KREAD(ims, &ims0, struct ip_msource); 661189592Sbms } else 662189592Sbms break; 663189592Sbms } 664189592Sbms ims = RB_PARENT(&ims0, ims_link); 665189592Sbms } 666167706Sbms } 667189592Sbms return (ims); /* kva */ 668167706Sbms} 669167706Sbms 670168560Sbmsstatic void 671189592Sbmsinm_print_sources_kvm(struct in_multi *pinm) 672167706Sbms{ 673189592Sbms struct ip_msource ims0; 674189592Sbms struct ip_msource *ims; 675189592Sbms struct in_addr src; 676189592Sbms int cnt; 677189592Sbms uint8_t fmode; 678167706Sbms 679189592Sbms cnt = 0; 680189592Sbms fmode = pinm->inm_st[1].iss_fmode; 681189592Sbms if (fmode == MCAST_UNDEFINED) 682167706Sbms return; 683189592Sbms for (ims = ims_min_kvm(pinm); ims != NULL; ims = ims_next_kvm(ims)) { 684189592Sbms if (cnt == 0) 685189592Sbms printf(" srcs "); 686189592Sbms KREAD(ims, &ims0, struct ip_msource); 687189592Sbms /* Only print sources in-mode at t1. */ 688189592Sbms if (fmode != ims_get_mode(pinm, ims, 1)) 689189592Sbms continue; 690189592Sbms src.s_addr = htonl(ims0.ims_haddr); 691189592Sbms printf("%s%s", (cnt++ == 0 ? "" : ","), inet_ntoa(src)); 692167706Sbms } 693189592Sbms} 694189592Sbms#endif 695189592Sbms 696189592Sbmsstatic struct in_multi * 697189592Sbmsin_multientry(struct in_multi *pinm) 698189592Sbms{ 699189592Sbms struct in_multi inm; 700189592Sbms const char *state, *mode; 701189592Sbms 702189592Sbms KREAD(pinm, &inm, struct in_multi); 703189592Sbms printf("\t\tgroup %s", inet_ntoa(inm.inm_addr)); 704189592Sbms printf(" refcnt %u", inm.inm_refcount); 705189592Sbms 706189592Sbms state = inm_state(inm.inm_state); 707189592Sbms if (state) 708189592Sbms printf(" state %s", state); 709189592Sbms else 710189592Sbms printf(" state (%d)", inm.inm_state); 711189592Sbms 712189592Sbms mode = inm_mode(inm.inm_st[1].iss_fmode); 713189592Sbms if (mode) 714189592Sbms printf(" mode %s", mode); 715189592Sbms else 716189592Sbms printf(" mode (%d)", inm.inm_st[1].iss_fmode); 717189592Sbms 718189592Sbms if (vflag >= 2) { 719189592Sbms printf(" asm %u ex %u in %u rec %u", 720189592Sbms (u_int)inm.inm_st[1].iss_asm, 721189592Sbms (u_int)inm.inm_st[1].iss_ex, 722189592Sbms (u_int)inm.inm_st[1].iss_in, 723189592Sbms (u_int)inm.inm_st[1].iss_rec); 724167706Sbms } 725167706Sbms 726189592Sbms#if 0 727189592Sbms /* Buggy. */ 728189592Sbms if (vflag) 729189592Sbms inm_print_sources_kvm(&inm); 730189592Sbms#endif 731189592Sbms 732189592Sbms printf("\n"); 733189592Sbms return (NULL); 734167706Sbms} 735168560Sbms 736168560Sbms#endif /* INET */ 737168560Sbms 738168560Sbms#endif /* WITH_KVM */ 739168560Sbms 740188645Sbms#ifdef INET6 741230617Smaxim 742230617Smaximstatic void 743230617Smaximin6_ifinfo(struct mld_ifinfo *mli) 744230617Smaxim{ 745230617Smaxim 746230617Smaxim printf("\t"); 747230617Smaxim switch (mli->mli_version) { 748230617Smaxim case MLD_VERSION_1: 749230617Smaxim case MLD_VERSION_2: 750230617Smaxim printf("mldv%d", mli->mli_version); 751230617Smaxim break; 752230617Smaxim default: 753230617Smaxim printf("mldv?(%d)", mli->mli_version); 754230617Smaxim break; 755230617Smaxim } 756245015Shrs if (mli->mli_flags) 757245015Shrs printb(" flags", mli->mli_flags, "\020\1SILENT\2USEALLOW"); 758230617Smaxim if (mli->mli_version == MLD_VERSION_2) { 759230617Smaxim printf(" rv %u qi %u qri %u uri %u", 760230617Smaxim mli->mli_rv, mli->mli_qi, mli->mli_qri, mli->mli_uri); 761230617Smaxim } 762230617Smaxim if (vflag >= 2) { 763230617Smaxim printf(" v1timer %u v2timer %u", mli->mli_v1_timer, 764230617Smaxim mli->mli_v2_timer); 765230617Smaxim } 766230617Smaxim printf("\n"); 767230617Smaxim} 768230617Smaxim 769188645Sbmsstatic const char * 770243441Shrsinet6_n2a(struct in6_addr *p, uint32_t scope_id) 771188645Sbms{ 772188645Sbms static char buf[NI_MAXHOST]; 773188645Sbms struct sockaddr_in6 sin6; 774188645Sbms const int niflags = NI_NUMERICHOST; 775188645Sbms 776188645Sbms memset(&sin6, 0, sizeof(sin6)); 777188645Sbms sin6.sin6_family = AF_INET6; 778188645Sbms sin6.sin6_len = sizeof(struct sockaddr_in6); 779188645Sbms sin6.sin6_addr = *p; 780243441Shrs sin6.sin6_scope_id = scope_id; 781188645Sbms if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, 782188647Sbms buf, sizeof(buf), NULL, 0, niflags) == 0) { 783188647Sbms return (buf); 784188647Sbms } else { 785188647Sbms return ("(invalid)"); 786188647Sbms } 787188645Sbms} 788188645Sbms#endif /* INET6 */ 789188645Sbms 790189592Sbms#ifdef INET 791189592Sbms/* 792189592Sbms * Retrieve per-group source filter mode and lists via sysctl. 793189592Sbms */ 794189592Sbmsstatic void 795189592Sbmsinm_print_sources_sysctl(uint32_t ifindex, struct in_addr gina) 796189592Sbms{ 797189592Sbms#define MAX_SYSCTL_TRY 5 798189592Sbms int mib[7]; 799189592Sbms int ntry = 0; 800189592Sbms size_t mibsize; 801189592Sbms size_t len; 802189592Sbms size_t needed; 803189592Sbms size_t cnt; 804189592Sbms int i; 805189592Sbms char *buf; 806189592Sbms struct in_addr *pina; 807189592Sbms uint32_t *p; 808189592Sbms uint32_t fmode; 809189592Sbms const char *modestr; 810189592Sbms 811189592Sbms mibsize = sizeof(mib) / sizeof(mib[0]); 812189592Sbms if (sysctlnametomib("net.inet.ip.mcast.filters", mib, &mibsize) == -1) { 813189592Sbms perror("sysctlnametomib"); 814189592Sbms return; 815189592Sbms } 816189592Sbms 817189592Sbms needed = 0; 818189592Sbms mib[5] = ifindex; 819189592Sbms mib[6] = gina.s_addr; /* 32 bits wide */ 820189592Sbms mibsize = sizeof(mib) / sizeof(mib[0]); 821189592Sbms do { 822189592Sbms if (sysctl(mib, mibsize, NULL, &needed, NULL, 0) == -1) { 823189592Sbms perror("sysctl net.inet.ip.mcast.filters"); 824189592Sbms return; 825189592Sbms } 826189592Sbms if ((buf = malloc(needed)) == NULL) { 827189592Sbms perror("malloc"); 828189592Sbms return; 829189592Sbms } 830189592Sbms if (sysctl(mib, mibsize, buf, &needed, NULL, 0) == -1) { 831189592Sbms if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) { 832189592Sbms perror("sysctl"); 833189592Sbms goto out_free; 834189592Sbms } 835189592Sbms free(buf); 836189592Sbms buf = NULL; 837189592Sbms } 838189592Sbms } while (buf == NULL); 839189592Sbms 840189592Sbms len = needed; 841189592Sbms if (len < sizeof(uint32_t)) { 842189592Sbms perror("sysctl"); 843189592Sbms goto out_free; 844189592Sbms } 845189592Sbms 846189592Sbms p = (uint32_t *)buf; 847189592Sbms fmode = *p++; 848189592Sbms len -= sizeof(uint32_t); 849189592Sbms 850189592Sbms modestr = inm_mode(fmode); 851189592Sbms if (modestr) 852189592Sbms printf(" mode %s", modestr); 853189592Sbms else 854189592Sbms printf(" mode (%u)", fmode); 855189592Sbms 856189592Sbms if (vflag == 0) 857189592Sbms goto out_free; 858189592Sbms 859189592Sbms cnt = len / sizeof(struct in_addr); 860189592Sbms pina = (struct in_addr *)p; 861189592Sbms 862189592Sbms for (i = 0; i < cnt; i++) { 863189592Sbms if (i == 0) 864189592Sbms printf(" srcs "); 865189592Sbms fprintf(stdout, "%s%s", (i == 0 ? "" : ","), 866189592Sbms inet_ntoa(*pina++)); 867189592Sbms len -= sizeof(struct in_addr); 868189592Sbms } 869189592Sbms if (len > 0) { 870189592Sbms fprintf(stderr, "warning: %u trailing bytes from %s\n", 871189592Sbms (unsigned int)len, "net.inet.ip.mcast.filters"); 872189592Sbms } 873189592Sbms 874189592Sbmsout_free: 875189592Sbms free(buf); 876189592Sbms#undef MAX_SYSCTL_TRY 877189592Sbms} 878189592Sbms 879189592Sbms#endif /* INET */ 880189592Sbms 881191672Sbms#ifdef INET6 882191672Sbms/* 883191672Sbms * Retrieve MLD per-group source filter mode and lists via sysctl. 884191672Sbms * 885228990Suqs * Note: The 128-bit IPv6 group address needs to be segmented into 886191672Sbms * 32-bit pieces for marshaling to sysctl. So the MIB name ends 887191672Sbms * up looking like this: 888191672Sbms * a.b.c.d.e.ifindex.g[0].g[1].g[2].g[3] 889191672Sbms * Assumes that pgroup originated from the kernel, so its components 890191672Sbms * are already in network-byte order. 891191672Sbms */ 892191672Sbmsstatic void 893191672Sbmsin6m_print_sources_sysctl(uint32_t ifindex, struct in6_addr *pgroup) 894191672Sbms{ 895191672Sbms#define MAX_SYSCTL_TRY 5 896191672Sbms char addrbuf[INET6_ADDRSTRLEN]; 897191672Sbms int mib[10]; 898191672Sbms int ntry = 0; 899191672Sbms int *pi; 900191672Sbms size_t mibsize; 901191672Sbms size_t len; 902191672Sbms size_t needed; 903191672Sbms size_t cnt; 904191672Sbms int i; 905191672Sbms char *buf; 906191672Sbms struct in6_addr *pina; 907191672Sbms uint32_t *p; 908191672Sbms uint32_t fmode; 909191672Sbms const char *modestr; 910191672Sbms 911191672Sbms mibsize = sizeof(mib) / sizeof(mib[0]); 912191672Sbms if (sysctlnametomib("net.inet6.ip6.mcast.filters", mib, 913191672Sbms &mibsize) == -1) { 914191672Sbms perror("sysctlnametomib"); 915191672Sbms return; 916191672Sbms } 917191672Sbms 918191672Sbms needed = 0; 919191672Sbms mib[5] = ifindex; 920191672Sbms pi = (int *)pgroup; 921191672Sbms for (i = 0; i < 4; i++) 922191672Sbms mib[6 + i] = *pi++; 923191672Sbms 924191672Sbms mibsize = sizeof(mib) / sizeof(mib[0]); 925191672Sbms do { 926191672Sbms if (sysctl(mib, mibsize, NULL, &needed, NULL, 0) == -1) { 927191672Sbms perror("sysctl net.inet6.ip6.mcast.filters"); 928191672Sbms return; 929191672Sbms } 930191672Sbms if ((buf = malloc(needed)) == NULL) { 931191672Sbms perror("malloc"); 932191672Sbms return; 933191672Sbms } 934191672Sbms if (sysctl(mib, mibsize, buf, &needed, NULL, 0) == -1) { 935191672Sbms if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) { 936191672Sbms perror("sysctl"); 937191672Sbms goto out_free; 938191672Sbms } 939191672Sbms free(buf); 940191672Sbms buf = NULL; 941191672Sbms } 942191672Sbms } while (buf == NULL); 943191672Sbms 944191672Sbms len = needed; 945191672Sbms if (len < sizeof(uint32_t)) { 946191672Sbms perror("sysctl"); 947191672Sbms goto out_free; 948191672Sbms } 949191672Sbms 950191672Sbms p = (uint32_t *)buf; 951191672Sbms fmode = *p++; 952191672Sbms len -= sizeof(uint32_t); 953191672Sbms 954191672Sbms modestr = inm_mode(fmode); 955191672Sbms if (modestr) 956191672Sbms printf(" mode %s", modestr); 957191672Sbms else 958191672Sbms printf(" mode (%u)", fmode); 959191672Sbms 960191672Sbms if (vflag == 0) 961191672Sbms goto out_free; 962191672Sbms 963191672Sbms cnt = len / sizeof(struct in6_addr); 964191672Sbms pina = (struct in6_addr *)p; 965191672Sbms 966191672Sbms for (i = 0; i < cnt; i++) { 967191672Sbms if (i == 0) 968191672Sbms printf(" srcs "); 969191672Sbms inet_ntop(AF_INET6, (const char *)pina++, addrbuf, 970191672Sbms INET6_ADDRSTRLEN); 971191672Sbms fprintf(stdout, "%s%s", (i == 0 ? "" : ","), addrbuf); 972191672Sbms len -= sizeof(struct in6_addr); 973191672Sbms } 974191672Sbms if (len > 0) { 975191672Sbms fprintf(stderr, "warning: %u trailing bytes from %s\n", 976191672Sbms (unsigned int)len, "net.inet6.ip6.mcast.filters"); 977191672Sbms } 978191672Sbms 979191672Sbmsout_free: 980191672Sbms free(buf); 981191672Sbms#undef MAX_SYSCTL_TRY 982191672Sbms} 983191672Sbms#endif /* INET6 */ 984191672Sbms 985168560Sbmsstatic int 986168560Sbmsifmcstat_getifmaddrs(void) 987168560Sbms{ 988168560Sbms char thisifname[IFNAMSIZ]; 989188645Sbms char addrbuf[NI_MAXHOST]; 990168560Sbms struct ifaddrs *ifap, *ifa; 991168560Sbms struct ifmaddrs *ifmap, *ifma; 992168560Sbms sockunion_t lastifasa; 993168560Sbms sockunion_t *psa, *pgsa, *pllsa, *pifasa; 994168560Sbms char *pcolon; 995168560Sbms char *pafname; 996168560Sbms uint32_t lastifindex, thisifindex; 997168560Sbms int error; 998168560Sbms 999168560Sbms error = 0; 1000168560Sbms ifap = NULL; 1001168560Sbms ifmap = NULL; 1002168560Sbms lastifindex = 0; 1003168560Sbms thisifindex = 0; 1004168560Sbms lastifasa.ss.ss_family = AF_UNSPEC; 1005168560Sbms 1006168560Sbms if (getifaddrs(&ifap) != 0) { 1007168560Sbms warn("getifmaddrs"); 1008168560Sbms return (-1); 1009168560Sbms } 1010168560Sbms 1011168560Sbms if (getifmaddrs(&ifmap) != 0) { 1012168560Sbms warn("getifmaddrs"); 1013168560Sbms error = -1; 1014168560Sbms goto out; 1015168560Sbms } 1016168560Sbms 1017168560Sbms for (ifma = ifmap; ifma; ifma = ifma->ifma_next) { 1018168560Sbms error = 0; 1019168560Sbms if (ifma->ifma_name == NULL || ifma->ifma_addr == NULL) 1020168560Sbms continue; 1021168560Sbms 1022168560Sbms psa = (sockunion_t *)ifma->ifma_name; 1023168560Sbms if (psa->sa.sa_family != AF_LINK) { 1024168560Sbms fprintf(stderr, 1025168560Sbms "WARNING: Kernel returned invalid data.\n"); 1026168560Sbms error = -1; 1027168560Sbms break; 1028168560Sbms } 1029168560Sbms 1030168560Sbms /* Filter on interface name. */ 1031168560Sbms thisifindex = psa->sdl.sdl_index; 1032168560Sbms if (ifindex != 0 && thisifindex != ifindex) 1033168560Sbms continue; 1034168560Sbms 1035168560Sbms /* Filter on address family. */ 1036168560Sbms pgsa = (sockunion_t *)ifma->ifma_addr; 1037168560Sbms if (af != 0 && pgsa->sa.sa_family != af) 1038168560Sbms continue; 1039168560Sbms 1040168560Sbms strlcpy(thisifname, link_ntoa(&psa->sdl), IFNAMSIZ); 1041168560Sbms pcolon = strchr(thisifname, ':'); 1042168560Sbms if (pcolon) 1043168560Sbms *pcolon = '\0'; 1044168560Sbms 1045168560Sbms /* Only print the banner for the first ifmaddrs entry. */ 1046168560Sbms if (lastifindex == 0 || lastifindex != thisifindex) { 1047168560Sbms lastifindex = thisifindex; 1048168560Sbms fprintf(stdout, "%s:\n", thisifname); 1049168560Sbms } 1050168560Sbms 1051168560Sbms /* 1052168560Sbms * Currently, multicast joins only take place on the 1053168560Sbms * primary IPv4 address, and only on the link-local IPv6 1054168560Sbms * address, as per IGMPv2/3 and MLDv1/2 semantics. 1055168560Sbms * Therefore, we only look up the primary address on 1056168560Sbms * the first pass. 1057168560Sbms */ 1058168560Sbms pifasa = NULL; 1059168560Sbms for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 1060168560Sbms if ((strcmp(ifa->ifa_name, thisifname) != 0) || 1061168560Sbms (ifa->ifa_addr == NULL) || 1062168560Sbms (ifa->ifa_addr->sa_family != pgsa->sa.sa_family)) 1063168560Sbms continue; 1064168560Sbms /* 1065168560Sbms * For AF_INET6 only the link-local address should 1066188645Sbms * be returned. If built without IPv6 support, 1067188645Sbms * skip this address entirely. 1068168560Sbms */ 1069168560Sbms pifasa = (sockunion_t *)ifa->ifa_addr; 1070188645Sbms if (pifasa->sa.sa_family == AF_INET6 1071188645Sbms#ifdef INET6 1072188645Sbms && !IN6_IS_ADDR_LINKLOCAL(&pifasa->sin6.sin6_addr) 1073188645Sbms#endif 1074188645Sbms ) { 1075168560Sbms pifasa = NULL; 1076168560Sbms continue; 1077168560Sbms } 1078168560Sbms break; 1079168560Sbms } 1080168560Sbms if (pifasa == NULL) 1081168560Sbms continue; /* primary address not found */ 1082168560Sbms 1083188645Sbms if (!vflag && pifasa->sa.sa_family == AF_LINK) 1084188645Sbms continue; 1085188645Sbms 1086168560Sbms /* Parse and print primary address, if not already printed. */ 1087168560Sbms if (lastifasa.ss.ss_family == AF_UNSPEC || 1088168560Sbms ((lastifasa.ss.ss_family == AF_LINK && 1089168560Sbms !sa_dl_equal(&lastifasa.sa, &pifasa->sa)) || 1090168560Sbms !sa_equal(&lastifasa.sa, &pifasa->sa))) { 1091168560Sbms 1092168560Sbms switch (pifasa->sa.sa_family) { 1093168560Sbms case AF_INET: 1094168560Sbms pafname = "inet"; 1095168560Sbms break; 1096168560Sbms case AF_INET6: 1097168560Sbms pafname = "inet6"; 1098168560Sbms break; 1099168560Sbms case AF_LINK: 1100168560Sbms pafname = "link"; 1101168560Sbms break; 1102168560Sbms default: 1103168560Sbms pafname = "unknown"; 1104168560Sbms break; 1105168560Sbms } 1106168560Sbms 1107168560Sbms switch (pifasa->sa.sa_family) { 1108188645Sbms case AF_INET6: 1109188645Sbms#ifdef INET6 1110188645Sbms { 1111188645Sbms const char *p = 1112243441Shrs inet6_n2a(&pifasa->sin6.sin6_addr, 1113243441Shrs pifasa->sin6.sin6_scope_id); 1114188645Sbms strlcpy(addrbuf, p, sizeof(addrbuf)); 1115188645Sbms break; 1116188645Sbms } 1117188645Sbms#else 1118188645Sbms /* FALLTHROUGH */ 1119188645Sbms#endif 1120168560Sbms case AF_INET: 1121168560Sbms case AF_LINK: 1122168560Sbms error = getnameinfo(&pifasa->sa, 1123168560Sbms pifasa->sa.sa_len, 1124168560Sbms addrbuf, sizeof(addrbuf), NULL, 0, 1125168560Sbms NI_NUMERICHOST); 1126168560Sbms if (error) 1127168560Sbms perror("getnameinfo"); 1128168560Sbms break; 1129168560Sbms default: 1130168560Sbms addrbuf[0] = '\0'; 1131168560Sbms break; 1132168560Sbms } 1133168560Sbms 1134245015Shrs fprintf(stdout, "\t%s %s", pafname, addrbuf); 1135245015Shrs#ifdef INET6 1136245015Shrs if (pifasa->sa.sa_family == AF_INET6 && 1137245015Shrs pifasa->sin6.sin6_scope_id) 1138245015Shrs fprintf(stdout, " scopeid 0x%x", 1139245015Shrs pifasa->sin6.sin6_scope_id); 1140245015Shrs#endif 1141245015Shrs fprintf(stdout, "\n"); 1142189592Sbms#ifdef INET 1143189592Sbms /* 1144189592Sbms * Print per-link IGMP information, if available. 1145189592Sbms */ 1146189592Sbms if (pifasa->sa.sa_family == AF_INET) { 1147189592Sbms struct igmp_ifinfo igi; 1148189592Sbms size_t mibsize, len; 1149189592Sbms int mib[5]; 1150189592Sbms 1151189592Sbms mibsize = sizeof(mib) / sizeof(mib[0]); 1152189592Sbms if (sysctlnametomib("net.inet.igmp.ifinfo", 1153189592Sbms mib, &mibsize) == -1) { 1154189592Sbms perror("sysctlnametomib"); 1155189592Sbms goto next_ifnet; 1156189592Sbms } 1157189592Sbms mib[mibsize] = thisifindex; 1158189592Sbms len = sizeof(struct igmp_ifinfo); 1159189592Sbms if (sysctl(mib, mibsize + 1, &igi, &len, NULL, 1160189592Sbms 0) == -1) { 1161189592Sbms perror("sysctl net.inet.igmp.ifinfo"); 1162189592Sbms goto next_ifnet; 1163189592Sbms } 1164189592Sbms in_ifinfo(&igi); 1165189592Sbms } 1166191672Sbms#endif /* INET */ 1167191672Sbms#ifdef INET6 1168191672Sbms /* 1169191672Sbms * Print per-link MLD information, if available. 1170191672Sbms */ 1171191672Sbms if (pifasa->sa.sa_family == AF_INET6) { 1172191672Sbms struct mld_ifinfo mli; 1173191672Sbms size_t mibsize, len; 1174191672Sbms int mib[5]; 1175191672Sbms 1176191672Sbms mibsize = sizeof(mib) / sizeof(mib[0]); 1177191672Sbms if (sysctlnametomib("net.inet6.mld.ifinfo", 1178191672Sbms mib, &mibsize) == -1) { 1179191672Sbms perror("sysctlnametomib"); 1180191672Sbms goto next_ifnet; 1181191672Sbms } 1182191672Sbms mib[mibsize] = thisifindex; 1183191672Sbms len = sizeof(struct mld_ifinfo); 1184191672Sbms if (sysctl(mib, mibsize + 1, &mli, &len, NULL, 1185191672Sbms 0) == -1) { 1186191672Sbms perror("sysctl net.inet6.mld.ifinfo"); 1187191672Sbms goto next_ifnet; 1188191672Sbms } 1189191672Sbms in6_ifinfo(&mli); 1190191672Sbms } 1191191672Sbms#endif /* INET6 */ 1192191672Sbms#if defined(INET) || defined(INET6) 1193189592Sbmsnext_ifnet: 1194189592Sbms#endif 1195168560Sbms lastifasa = *pifasa; 1196168560Sbms } 1197168560Sbms 1198168560Sbms /* Print this group address. */ 1199188645Sbms#ifdef INET6 1200188645Sbms if (pgsa->sa.sa_family == AF_INET6) { 1201243441Shrs const char *p = inet6_n2a(&pgsa->sin6.sin6_addr, 1202243441Shrs pgsa->sin6.sin6_scope_id); 1203188645Sbms strlcpy(addrbuf, p, sizeof(addrbuf)); 1204188645Sbms } else 1205188645Sbms#endif 1206188645Sbms { 1207188645Sbms error = getnameinfo(&pgsa->sa, pgsa->sa.sa_len, 1208188645Sbms addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST); 1209188645Sbms if (error) 1210188645Sbms perror("getnameinfo"); 1211188645Sbms } 1212188645Sbms 1213189592Sbms fprintf(stdout, "\t\tgroup %s", addrbuf); 1214245015Shrs#ifdef INET6 1215245015Shrs if (pgsa->sa.sa_family == AF_INET6 && 1216245015Shrs pgsa->sin6.sin6_scope_id) 1217245015Shrs fprintf(stdout, " scopeid 0x%x", 1218245015Shrs pgsa->sin6.sin6_scope_id); 1219245015Shrs#endif 1220189592Sbms#ifdef INET 1221189592Sbms if (pgsa->sa.sa_family == AF_INET) { 1222189592Sbms inm_print_sources_sysctl(thisifindex, 1223189592Sbms pgsa->sin.sin_addr); 1224189592Sbms } 1225189592Sbms#endif 1226191672Sbms#ifdef INET6 1227191672Sbms if (pgsa->sa.sa_family == AF_INET6) { 1228191672Sbms in6m_print_sources_sysctl(thisifindex, 1229191672Sbms &pgsa->sin6.sin6_addr); 1230191672Sbms } 1231191672Sbms#endif 1232189592Sbms fprintf(stdout, "\n"); 1233168560Sbms 1234168560Sbms /* Link-layer mapping, if present. */ 1235168560Sbms pllsa = (sockunion_t *)ifma->ifma_lladdr; 1236168560Sbms if (pllsa != NULL) { 1237188643Sbms error = getnameinfo(&pllsa->sa, pllsa->sa.sa_len, 1238168560Sbms addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST); 1239168560Sbms fprintf(stdout, "\t\t\tmcast-macaddr %s\n", addrbuf); 1240168560Sbms } 1241168560Sbms } 1242168560Sbmsout: 1243168560Sbms if (ifmap != NULL) 1244168560Sbms freeifmaddrs(ifmap); 1245168560Sbms if (ifap != NULL) 1246168560Sbms freeifaddrs(ifap); 1247168560Sbms 1248168560Sbms return (error); 1249168560Sbms} 1250