1*e7df7762SCody Peter Mello /* 2*e7df7762SCody Peter Mello * This file and its contents are supplied under the terms of the 3*e7df7762SCody Peter Mello * Common Development and Distribution License ("CDDL"), version 1.0. 4*e7df7762SCody Peter Mello * You may only use this file in accordance with the terms of version 5*e7df7762SCody Peter Mello * 1.0 of the CDDL. 6*e7df7762SCody Peter Mello * 7*e7df7762SCody Peter Mello * A full copy of the text of the CDDL should have accompanied this 8*e7df7762SCody Peter Mello * source. A copy of the CDDL is also available via the Internet at 9*e7df7762SCody Peter Mello * http://www.illumos.org/license/CDDL. 10*e7df7762SCody Peter Mello */ 11*e7df7762SCody Peter Mello 12*e7df7762SCody Peter Mello /* 13*e7df7762SCody Peter Mello * Copyright 2015 Joyent, Inc. All rights reserved. 14*e7df7762SCody Peter Mello */ 15*e7df7762SCody Peter Mello 16*e7df7762SCody Peter Mello /* 17*e7df7762SCody Peter Mello * ndp - display and manipulate Neighbor Cache Entries from NDP 18*e7df7762SCody Peter Mello */ 19*e7df7762SCody Peter Mello 20*e7df7762SCody Peter Mello #include <stdio.h> 21*e7df7762SCody Peter Mello #include <stdarg.h> 22*e7df7762SCody Peter Mello #include <signal.h> 23*e7df7762SCody Peter Mello #include <time.h> 24*e7df7762SCody Peter Mello #include <err.h> 25*e7df7762SCody Peter Mello #include <errno.h> 26*e7df7762SCody Peter Mello #include <stdlib.h> 27*e7df7762SCody Peter Mello #include <strings.h> 28*e7df7762SCody Peter Mello #include <unistd.h> 29*e7df7762SCody Peter Mello #include <libgen.h> 30*e7df7762SCody Peter Mello #include <sys/ioctl.h> 31*e7df7762SCody Peter Mello #include <sys/types.h> 32*e7df7762SCody Peter Mello #include <wait.h> 33*e7df7762SCody Peter Mello #include <sys/mac.h> 34*e7df7762SCody Peter Mello #include <sys/socket.h> 35*e7df7762SCody Peter Mello #include <sys/sockio.h> 36*e7df7762SCody Peter Mello #include <netdb.h> 37*e7df7762SCody Peter Mello #include <net/if_types.h> 38*e7df7762SCody Peter Mello #include <netinet/in.h> 39*e7df7762SCody Peter Mello #include <arpa/inet.h> 40*e7df7762SCody Peter Mello #include <inet/ip.h> 41*e7df7762SCody Peter Mello #include <net/if_dl.h> 42*e7df7762SCody Peter Mello #include <net/route.h> 43*e7df7762SCody Peter Mello 44*e7df7762SCody Peter Mello typedef struct sockaddr_in6 sin6_t; 45*e7df7762SCody Peter Mello 46*e7df7762SCody Peter Mello #define BUF_SIZE 2048 47*e7df7762SCody Peter Mello typedef struct rtmsg_pkt { 48*e7df7762SCody Peter Mello struct rt_msghdr m_rtm; 49*e7df7762SCody Peter Mello char m_space[BUF_SIZE]; 50*e7df7762SCody Peter Mello } rtmsg_pkt_t; 51*e7df7762SCody Peter Mello 52*e7df7762SCody Peter Mello enum ndp_action { 53*e7df7762SCody Peter Mello NDP_A_DEFAULT, 54*e7df7762SCody Peter Mello NDP_A_GET, /* Show a single NDP entry */ 55*e7df7762SCody Peter Mello NDP_A_GET_ALL, /* Show NDP entries */ 56*e7df7762SCody Peter Mello NDP_A_GET_FOREVER, /* Repeatedly show entries */ 57*e7df7762SCody Peter Mello NDP_A_DELETE, /* Delete an NDP entry */ 58*e7df7762SCody Peter Mello NDP_A_SET_NCE, /* Set NDP entry */ 59*e7df7762SCody Peter Mello NDP_A_SET_FILE /* Read in & set NDP entries */ 60*e7df7762SCody Peter Mello }; 61*e7df7762SCody Peter Mello 62*e7df7762SCody Peter Mello typedef int (ndp_addr_f)(int, struct lifreq *, void *); 63*e7df7762SCody Peter Mello typedef void (ndp_void_f)(void); 64*e7df7762SCody Peter Mello 65*e7df7762SCody Peter Mello static void ndp_usage(const char *, ...); 66*e7df7762SCody Peter Mello static void ndp_fatal(const char *, ...); 67*e7df7762SCody Peter Mello static void ndp_badflag(enum ndp_action); 68*e7df7762SCody Peter Mello static void ndp_missingarg(char); 69*e7df7762SCody Peter Mello 70*e7df7762SCody Peter Mello static void ndp_run_in_child(ndp_void_f *); 71*e7df7762SCody Peter Mello static void ndp_do_run(void); 72*e7df7762SCody Peter Mello static void ndp_setup_handler(sigset_t *); 73*e7df7762SCody Peter Mello static void ndp_start_timer(time_t period); 74*e7df7762SCody Peter Mello static void ndp_run_periodically(time_t, ndp_void_f *); 75*e7df7762SCody Peter Mello 76*e7df7762SCody Peter Mello static int ndp_salen(const struct sockaddr *sa); 77*e7df7762SCody Peter Mello static int ndp_extract_sockaddrs(struct rt_msghdr *, struct sockaddr **, 78*e7df7762SCody Peter Mello struct sockaddr **, struct sockaddr **, struct sockaddr **, 79*e7df7762SCody Peter Mello struct sockaddr_dl **); 80*e7df7762SCody Peter Mello static int ndp_rtmsg_get(int, rtmsg_pkt_t *, struct sockaddr *); 81*e7df7762SCody Peter Mello static int ndp_find_interface(int, struct sockaddr *, char *, int); 82*e7df7762SCody Peter Mello 83*e7df7762SCody Peter Mello static int ndp_initialize_lifreq(int, struct lifreq *, struct sockaddr *); 84*e7df7762SCody Peter Mello static int ndp_host_enumerate(char *, ndp_addr_f *, void *); 85*e7df7762SCody Peter Mello 86*e7df7762SCody Peter Mello static int ndp_display(struct lifreq *); 87*e7df7762SCody Peter Mello static int ndp_display_missing(struct lifreq *); 88*e7df7762SCody Peter Mello static void ndp_lifr2ip(struct lifreq *, char *, int); 89*e7df7762SCody Peter Mello 90*e7df7762SCody Peter Mello static int ndp_get(int, struct lifreq *, void *); 91*e7df7762SCody Peter Mello static void ndp_get_all(void); 92*e7df7762SCody Peter Mello static int ndp_delete(int, struct lifreq *, void *); 93*e7df7762SCody Peter Mello static int ndp_set(int, struct lifreq *, void *); 94*e7df7762SCody Peter Mello static int ndp_set_nce(char *, char *, char *[], int); 95*e7df7762SCody Peter Mello static int ndp_set_file(char *); 96*e7df7762SCody Peter Mello 97*e7df7762SCody Peter Mello static char *ndp_iface = NULL; 98*e7df7762SCody Peter Mello static char *netstat_path = "/usr/bin/netstat"; 99*e7df7762SCody Peter Mello static pid_t ndp_pid; 100*e7df7762SCody Peter Mello static boolean_t ndp_noresolve = B_FALSE; /* Don't lookup addresses */ 101*e7df7762SCody Peter Mello static boolean_t ndp_run = B_TRUE; 102*e7df7762SCody Peter Mello 103*e7df7762SCody Peter Mello #define MAX_ATTEMPTS 5 104*e7df7762SCody Peter Mello #define MAX_OPTS 5 105*e7df7762SCody Peter Mello #define WORDSEPS " \t\r\n" 106*e7df7762SCody Peter Mello 107*e7df7762SCody Peter Mello /* 108*e7df7762SCody Peter Mello * Macros borrowed from route(1M) for working with PF_ROUTE messages 109*e7df7762SCody Peter Mello */ 110*e7df7762SCody Peter Mello #define RT_ADVANCE(x, n) ((x) += ndp_salen(n)) 111*e7df7762SCody Peter Mello #define RT_NEXTADDR(cp, w, u) \ 112*e7df7762SCody Peter Mello l = ndp_salen(u); \ 113*e7df7762SCody Peter Mello (void) memmove(cp, u, l); \ 114*e7df7762SCody Peter Mello cp += l; 115*e7df7762SCody Peter Mello 116*e7df7762SCody Peter Mello /* 117*e7df7762SCody Peter Mello * Print an error to stderr and then exit non-zero. 118*e7df7762SCody Peter Mello */ 119*e7df7762SCody Peter Mello static void 120*e7df7762SCody Peter Mello ndp_fatal(const char *format, ...) 121*e7df7762SCody Peter Mello { 122*e7df7762SCody Peter Mello va_list ap; 123*e7df7762SCody Peter Mello 124*e7df7762SCody Peter Mello va_start(ap, format); 125*e7df7762SCody Peter Mello vwarnx(format, ap); 126*e7df7762SCody Peter Mello va_end(ap); 127*e7df7762SCody Peter Mello exit(EXIT_FAILURE); 128*e7df7762SCody Peter Mello } 129*e7df7762SCody Peter Mello 130*e7df7762SCody Peter Mello /* 131*e7df7762SCody Peter Mello * Print out the command usage to stderr, along with any reason why it's being 132*e7df7762SCody Peter Mello * printed, and then exit non-zero. 133*e7df7762SCody Peter Mello */ 134*e7df7762SCody Peter Mello static void 135*e7df7762SCody Peter Mello ndp_usage(const char *reason, ...) 136*e7df7762SCody Peter Mello { 137*e7df7762SCody Peter Mello va_list ap; 138*e7df7762SCody Peter Mello const char *ndp_progname = getprogname(); 139*e7df7762SCody Peter Mello 140*e7df7762SCody Peter Mello if (reason != NULL) { 141*e7df7762SCody Peter Mello va_start(ap, reason); 142*e7df7762SCody Peter Mello (void) fprintf(stderr, "%s: ", ndp_progname); 143*e7df7762SCody Peter Mello (void) vfprintf(stderr, reason, ap); 144*e7df7762SCody Peter Mello (void) fprintf(stderr, "\n"); 145*e7df7762SCody Peter Mello va_end(ap); 146*e7df7762SCody Peter Mello } 147*e7df7762SCody Peter Mello 148*e7df7762SCody Peter Mello (void) fprintf(stderr, 149*e7df7762SCody Peter Mello "Usage: %s [-n] [-i iface] hostname\n" 150*e7df7762SCody Peter Mello " %s [-n] [-i iface] -s nodeaddr etheraddr [temp] [proxy]\n" 151*e7df7762SCody Peter Mello " %s [-n] [-i iface] -d nodeaddr\n" 152*e7df7762SCody Peter Mello " %s [-n] [-i iface] -f filename\n" 153*e7df7762SCody Peter Mello " %s [-n] -a\n" 154*e7df7762SCody Peter Mello " %s [-n] -A period\n", 155*e7df7762SCody Peter Mello ndp_progname, ndp_progname, ndp_progname, 156*e7df7762SCody Peter Mello ndp_progname, ndp_progname, ndp_progname); 157*e7df7762SCody Peter Mello exit(EXIT_FAILURE); 158*e7df7762SCody Peter Mello } 159*e7df7762SCody Peter Mello 160*e7df7762SCody Peter Mello static void 161*e7df7762SCody Peter Mello ndp_badflag(enum ndp_action action) 162*e7df7762SCody Peter Mello { 163*e7df7762SCody Peter Mello switch (action) { 164*e7df7762SCody Peter Mello case NDP_A_DEFAULT: 165*e7df7762SCody Peter Mello case NDP_A_GET: 166*e7df7762SCody Peter Mello ndp_usage("Already going to print an entry, " 167*e7df7762SCody Peter Mello "but extra -%c given", optopt); 168*e7df7762SCody Peter Mello break; 169*e7df7762SCody Peter Mello case NDP_A_GET_ALL: 170*e7df7762SCody Peter Mello ndp_usage("Already going to print all entries (-a), " 171*e7df7762SCody Peter Mello "but extra -%c given", optopt); 172*e7df7762SCody Peter Mello break; 173*e7df7762SCody Peter Mello case NDP_A_GET_FOREVER: 174*e7df7762SCody Peter Mello ndp_usage("Already going to repeatedly print all entries (-A), " 175*e7df7762SCody Peter Mello "but extra -%c given", optopt); 176*e7df7762SCody Peter Mello break; 177*e7df7762SCody Peter Mello case NDP_A_DELETE: 178*e7df7762SCody Peter Mello ndp_usage("Already going to delete an entry (-d), " 179*e7df7762SCody Peter Mello "but extra -%c given", optopt); 180*e7df7762SCody Peter Mello break; 181*e7df7762SCody Peter Mello case NDP_A_SET_NCE: 182*e7df7762SCody Peter Mello ndp_usage("Already going to set an entry (-s), " 183*e7df7762SCody Peter Mello "but extra -%c given", optopt); 184*e7df7762SCody Peter Mello break; 185*e7df7762SCody Peter Mello case NDP_A_SET_FILE: 186*e7df7762SCody Peter Mello ndp_usage("Already going to set from file (-f), " 187*e7df7762SCody Peter Mello "but extra -%c given", optopt); 188*e7df7762SCody Peter Mello break; 189*e7df7762SCody Peter Mello } 190*e7df7762SCody Peter Mello } 191*e7df7762SCody Peter Mello 192*e7df7762SCody Peter Mello static void 193*e7df7762SCody Peter Mello ndp_missingarg(char flag) 194*e7df7762SCody Peter Mello { 195*e7df7762SCody Peter Mello switch (flag) { 196*e7df7762SCody Peter Mello case 'A': 197*e7df7762SCody Peter Mello ndp_usage("Missing time period after -%c", flag); 198*e7df7762SCody Peter Mello break; 199*e7df7762SCody Peter Mello case 'd': 200*e7df7762SCody Peter Mello ndp_usage("Missing node name after -%c", flag); 201*e7df7762SCody Peter Mello break; 202*e7df7762SCody Peter Mello case 'f': 203*e7df7762SCody Peter Mello ndp_usage("Missing filename after -%c", flag); 204*e7df7762SCody Peter Mello break; 205*e7df7762SCody Peter Mello case 's': 206*e7df7762SCody Peter Mello ndp_usage("Missing node name after -%c", flag); 207*e7df7762SCody Peter Mello break; 208*e7df7762SCody Peter Mello case 'i': 209*e7df7762SCody Peter Mello ndp_usage("Missing interface name after -%c", flag); 210*e7df7762SCody Peter Mello break; 211*e7df7762SCody Peter Mello default: 212*e7df7762SCody Peter Mello ndp_usage("Missing option argument after -%c", flag); 213*e7df7762SCody Peter Mello break; 214*e7df7762SCody Peter Mello } 215*e7df7762SCody Peter Mello } 216*e7df7762SCody Peter Mello 217*e7df7762SCody Peter Mello /* 218*e7df7762SCody Peter Mello * Run a function that's going to exec in a child process, and don't return 219*e7df7762SCody Peter Mello * until it exits. 220*e7df7762SCody Peter Mello */ 221*e7df7762SCody Peter Mello static void 222*e7df7762SCody Peter Mello ndp_run_in_child(ndp_void_f *func) 223*e7df7762SCody Peter Mello { 224*e7df7762SCody Peter Mello pid_t child_pid; 225*e7df7762SCody Peter Mello int childstat = 0, status = 0; 226*e7df7762SCody Peter Mello 227*e7df7762SCody Peter Mello child_pid = fork(); 228*e7df7762SCody Peter Mello if (child_pid == (pid_t)-1) { 229*e7df7762SCody Peter Mello ndp_fatal("Unable to fork: %s", strerror(errno)); 230*e7df7762SCody Peter Mello } else if (child_pid == (pid_t)0) { 231*e7df7762SCody Peter Mello func(); 232*e7df7762SCody Peter Mello exit(EXIT_FAILURE); 233*e7df7762SCody Peter Mello } 234*e7df7762SCody Peter Mello 235*e7df7762SCody Peter Mello while (waitpid(child_pid, &childstat, 0) == -1) { 236*e7df7762SCody Peter Mello if (errno == EINTR) 237*e7df7762SCody Peter Mello continue; 238*e7df7762SCody Peter Mello 239*e7df7762SCody Peter Mello ndp_fatal("Failed to wait on child: %s", strerror(errno)); 240*e7df7762SCody Peter Mello } 241*e7df7762SCody Peter Mello 242*e7df7762SCody Peter Mello status = WEXITSTATUS(childstat); 243*e7df7762SCody Peter Mello if (status != 0) { 244*e7df7762SCody Peter Mello ndp_fatal("Child process exited with %d", status); 245*e7df7762SCody Peter Mello } 246*e7df7762SCody Peter Mello } 247*e7df7762SCody Peter Mello 248*e7df7762SCody Peter Mello /* 249*e7df7762SCody Peter Mello * SIGALRM handler to schedule a run. 250*e7df7762SCody Peter Mello */ 251*e7df7762SCody Peter Mello static void 252*e7df7762SCody Peter Mello ndp_do_run(void) 253*e7df7762SCody Peter Mello { 254*e7df7762SCody Peter Mello ndp_run = B_TRUE; 255*e7df7762SCody Peter Mello } 256*e7df7762SCody Peter Mello 257*e7df7762SCody Peter Mello 258*e7df7762SCody Peter Mello /* 259*e7df7762SCody Peter Mello * Prepare signal masks, and install the SIGALRM handler. Return old signal 260*e7df7762SCody Peter Mello * masks through the first argument. 261*e7df7762SCody Peter Mello */ 262*e7df7762SCody Peter Mello static void 263*e7df7762SCody Peter Mello ndp_setup_handler(sigset_t *oset) 264*e7df7762SCody Peter Mello { 265*e7df7762SCody Peter Mello struct sigaction sa; 266*e7df7762SCody Peter Mello 267*e7df7762SCody Peter Mello /* 268*e7df7762SCody Peter Mello * Mask off SIGALRM so we only trigger the handler when we're ready 269*e7df7762SCody Peter Mello * using sigsuspend(3C), in case the child process takes longer to 270*e7df7762SCody Peter Mello * run than the alarm interval. 271*e7df7762SCody Peter Mello */ 272*e7df7762SCody Peter Mello if (sigprocmask(0, NULL, oset) != 0) { 273*e7df7762SCody Peter Mello ndp_fatal("Unable to set signal mask: %s", strerror(errno)); 274*e7df7762SCody Peter Mello } 275*e7df7762SCody Peter Mello 276*e7df7762SCody Peter Mello if (sighold(SIGALRM) != 0) { 277*e7df7762SCody Peter Mello ndp_fatal("Unable to add SIGALRM to signal mask: %s", 278*e7df7762SCody Peter Mello strerror(errno)); 279*e7df7762SCody Peter Mello } 280*e7df7762SCody Peter Mello 281*e7df7762SCody Peter Mello sa.sa_flags = 0; 282*e7df7762SCody Peter Mello sa.sa_handler = ndp_do_run; 283*e7df7762SCody Peter Mello 284*e7df7762SCody Peter Mello if (sigemptyset(&sa.sa_mask) != 0) { 285*e7df7762SCody Peter Mello ndp_fatal("Unable to prepare empty signal set: %s", 286*e7df7762SCody Peter Mello strerror(errno)); 287*e7df7762SCody Peter Mello } 288*e7df7762SCody Peter Mello 289*e7df7762SCody Peter Mello if (sigaction(SIGALRM, &sa, NULL) != 0) { 290*e7df7762SCody Peter Mello ndp_fatal("Unable to install timer handler: %s", 291*e7df7762SCody Peter Mello strerror(errno)); 292*e7df7762SCody Peter Mello } 293*e7df7762SCody Peter Mello } 294*e7df7762SCody Peter Mello 295*e7df7762SCody Peter Mello /* 296*e7df7762SCody Peter Mello * Start the printing timer. 297*e7df7762SCody Peter Mello */ 298*e7df7762SCody Peter Mello static void 299*e7df7762SCody Peter Mello ndp_start_timer(time_t period) 300*e7df7762SCody Peter Mello { 301*e7df7762SCody Peter Mello timer_t timer; 302*e7df7762SCody Peter Mello struct itimerspec interval; 303*e7df7762SCody Peter Mello interval.it_value.tv_sec = interval.it_interval.tv_sec = period; 304*e7df7762SCody Peter Mello interval.it_value.tv_nsec = interval.it_interval.tv_nsec = 0; 305*e7df7762SCody Peter Mello 306*e7df7762SCody Peter Mello if (timer_create(CLOCK_REALTIME, NULL, &timer) != 0) { 307*e7df7762SCody Peter Mello ndp_fatal("Unable to create timer: %s", strerror(errno)); 308*e7df7762SCody Peter Mello } 309*e7df7762SCody Peter Mello 310*e7df7762SCody Peter Mello if (timer_settime(timer, 0, &interval, NULL) != 0) { 311*e7df7762SCody Peter Mello ndp_fatal("Unable to set time on timer: %s", strerror(errno)); 312*e7df7762SCody Peter Mello } 313*e7df7762SCody Peter Mello } 314*e7df7762SCody Peter Mello 315*e7df7762SCody Peter Mello 316*e7df7762SCody Peter Mello /* 317*e7df7762SCody Peter Mello * Run a given function forever periodically in a child process. 318*e7df7762SCody Peter Mello */ 319*e7df7762SCody Peter Mello static void 320*e7df7762SCody Peter Mello ndp_run_periodically(time_t period, ndp_void_f *func) 321*e7df7762SCody Peter Mello { 322*e7df7762SCody Peter Mello sigset_t oset; 323*e7df7762SCody Peter Mello 324*e7df7762SCody Peter Mello ndp_setup_handler(&oset); 325*e7df7762SCody Peter Mello ndp_start_timer(period); 326*e7df7762SCody Peter Mello 327*e7df7762SCody Peter Mello do { 328*e7df7762SCody Peter Mello if (ndp_run) { 329*e7df7762SCody Peter Mello ndp_run = B_FALSE; 330*e7df7762SCody Peter Mello ndp_run_in_child(func); 331*e7df7762SCody Peter Mello } 332*e7df7762SCody Peter Mello (void) sigsuspend(&oset); 333*e7df7762SCody Peter Mello } while (errno == EINTR); 334*e7df7762SCody Peter Mello 335*e7df7762SCody Peter Mello /* 336*e7df7762SCody Peter Mello * Only an EFAULT should get us here. Abort so we get a core dump. 337*e7df7762SCody Peter Mello */ 338*e7df7762SCody Peter Mello warnx("Failure while waiting on timer: %s", strerror(errno)); 339*e7df7762SCody Peter Mello abort(); 340*e7df7762SCody Peter Mello } 341*e7df7762SCody Peter Mello 342*e7df7762SCody Peter Mello /* 343*e7df7762SCody Peter Mello * Given an address, return its size. 344*e7df7762SCody Peter Mello */ 345*e7df7762SCody Peter Mello static int 346*e7df7762SCody Peter Mello ndp_salen(const struct sockaddr *sa) 347*e7df7762SCody Peter Mello { 348*e7df7762SCody Peter Mello switch (sa->sa_family) { 349*e7df7762SCody Peter Mello case AF_INET: 350*e7df7762SCody Peter Mello return (sizeof (struct sockaddr_in)); 351*e7df7762SCody Peter Mello case AF_LINK: 352*e7df7762SCody Peter Mello return (sizeof (struct sockaddr_dl)); 353*e7df7762SCody Peter Mello case AF_INET6: 354*e7df7762SCody Peter Mello return (sizeof (struct sockaddr_in6)); 355*e7df7762SCody Peter Mello default: 356*e7df7762SCody Peter Mello warnx("Unrecognized sockaddr with address family %d!", 357*e7df7762SCody Peter Mello sa->sa_family); 358*e7df7762SCody Peter Mello abort(); 359*e7df7762SCody Peter Mello } 360*e7df7762SCody Peter Mello /*NOTREACHED*/ 361*e7df7762SCody Peter Mello } 362*e7df7762SCody Peter Mello 363*e7df7762SCody Peter Mello /* 364*e7df7762SCody Peter Mello * Extract all socket addresses from a routing message, and return them 365*e7df7762SCody Peter Mello * through the pointers given as arguments to ndp_extract_sockaddrs. None 366*e7df7762SCody Peter Mello * of the pointers should be null. 367*e7df7762SCody Peter Mello */ 368*e7df7762SCody Peter Mello static int 369*e7df7762SCody Peter Mello ndp_extract_sockaddrs(struct rt_msghdr *rtm, struct sockaddr **dst, 370*e7df7762SCody Peter Mello struct sockaddr **gate, struct sockaddr **mask, struct sockaddr **src, 371*e7df7762SCody Peter Mello struct sockaddr_dl **ifp) 372*e7df7762SCody Peter Mello { 373*e7df7762SCody Peter Mello struct sockaddr *sa; 374*e7df7762SCody Peter Mello char *cp; 375*e7df7762SCody Peter Mello int i; 376*e7df7762SCody Peter Mello 377*e7df7762SCody Peter Mello if (rtm->rtm_version != RTM_VERSION) { 378*e7df7762SCody Peter Mello warnx("Routing message version %d not understood", 379*e7df7762SCody Peter Mello rtm->rtm_version); 380*e7df7762SCody Peter Mello return (-1); 381*e7df7762SCody Peter Mello } 382*e7df7762SCody Peter Mello 383*e7df7762SCody Peter Mello if (rtm->rtm_errno != 0) { 384*e7df7762SCody Peter Mello warnx("Routing message couldn't be processed: %s", 385*e7df7762SCody Peter Mello strerror(rtm->rtm_errno)); 386*e7df7762SCody Peter Mello return (-1); 387*e7df7762SCody Peter Mello } 388*e7df7762SCody Peter Mello 389*e7df7762SCody Peter Mello cp = ((char *)(rtm + 1)); 390*e7df7762SCody Peter Mello if (rtm->rtm_addrs != 0) { 391*e7df7762SCody Peter Mello for (i = 1; i != 0; i <<= 1) { 392*e7df7762SCody Peter Mello if ((i & rtm->rtm_addrs) == 0) 393*e7df7762SCody Peter Mello continue; 394*e7df7762SCody Peter Mello 395*e7df7762SCody Peter Mello /*LINTED*/ 396*e7df7762SCody Peter Mello sa = (struct sockaddr *)cp; 397*e7df7762SCody Peter Mello switch (i) { 398*e7df7762SCody Peter Mello case RTA_DST: 399*e7df7762SCody Peter Mello *dst = sa; 400*e7df7762SCody Peter Mello break; 401*e7df7762SCody Peter Mello case RTA_GATEWAY: 402*e7df7762SCody Peter Mello *gate = sa; 403*e7df7762SCody Peter Mello break; 404*e7df7762SCody Peter Mello case RTA_NETMASK: 405*e7df7762SCody Peter Mello *mask = sa; 406*e7df7762SCody Peter Mello break; 407*e7df7762SCody Peter Mello case RTA_IFP: 408*e7df7762SCody Peter Mello if (sa->sa_family == AF_LINK && 409*e7df7762SCody Peter Mello ((struct sockaddr_dl *)sa)->sdl_nlen != 0) 410*e7df7762SCody Peter Mello *ifp = (struct sockaddr_dl *)sa; 411*e7df7762SCody Peter Mello break; 412*e7df7762SCody Peter Mello case RTA_SRC: 413*e7df7762SCody Peter Mello *src = sa; 414*e7df7762SCody Peter Mello break; 415*e7df7762SCody Peter Mello } 416*e7df7762SCody Peter Mello RT_ADVANCE(cp, sa); 417*e7df7762SCody Peter Mello } 418*e7df7762SCody Peter Mello } 419*e7df7762SCody Peter Mello 420*e7df7762SCody Peter Mello return (0); 421*e7df7762SCody Peter Mello } 422*e7df7762SCody Peter Mello 423*e7df7762SCody Peter Mello /* 424*e7df7762SCody Peter Mello * Given an IPv6 address, use routing information to look up 425*e7df7762SCody Peter Mello * the destination and interface it would pass through. 426*e7df7762SCody Peter Mello */ 427*e7df7762SCody Peter Mello static int 428*e7df7762SCody Peter Mello ndp_rtmsg_get(int fd, rtmsg_pkt_t *msg, struct sockaddr *sin6p) 429*e7df7762SCody Peter Mello { 430*e7df7762SCody Peter Mello static int seq = 0; 431*e7df7762SCody Peter Mello struct sockaddr_dl sdl; 432*e7df7762SCody Peter Mello int mlen, l; 433*e7df7762SCody Peter Mello char ipaddr[INET6_ADDRSTRLEN]; 434*e7df7762SCody Peter Mello char *cp = msg->m_space; 435*e7df7762SCody Peter Mello struct rt_msghdr *m_rtm = &msg->m_rtm; 436*e7df7762SCody Peter Mello 437*e7df7762SCody Peter Mello bzero(msg, sizeof (rtmsg_pkt_t)); 438*e7df7762SCody Peter Mello bzero(&sdl, sizeof (struct sockaddr_dl)); 439*e7df7762SCody Peter Mello 440*e7df7762SCody Peter Mello m_rtm->rtm_type = RTM_GET; 441*e7df7762SCody Peter Mello m_rtm->rtm_version = RTM_VERSION; 442*e7df7762SCody Peter Mello m_rtm->rtm_seq = ++seq; 443*e7df7762SCody Peter Mello m_rtm->rtm_addrs = RTA_DST | RTA_IFP; 444*e7df7762SCody Peter Mello m_rtm->rtm_msglen = sizeof (rtmsg_pkt_t); 445*e7df7762SCody Peter Mello 446*e7df7762SCody Peter Mello /* Place the address we're looking up after the header */ 447*e7df7762SCody Peter Mello RT_NEXTADDR(cp, RTA_DST, sin6p); 448*e7df7762SCody Peter Mello 449*e7df7762SCody Peter Mello /* Load an empty link-level address, so we get an interface back */ 450*e7df7762SCody Peter Mello sdl.sdl_family = AF_LINK; 451*e7df7762SCody Peter Mello RT_NEXTADDR(cp, RTA_IFP, (struct sockaddr *)&sdl); 452*e7df7762SCody Peter Mello 453*e7df7762SCody Peter Mello m_rtm->rtm_msglen = cp - (char *)msg; 454*e7df7762SCody Peter Mello 455*e7df7762SCody Peter Mello if ((mlen = write(fd, (char *)msg, m_rtm->rtm_msglen)) < 0) { 456*e7df7762SCody Peter Mello if (errno == ESRCH) { 457*e7df7762SCody Peter Mello /*LINTED*/ 458*e7df7762SCody Peter Mello if (inet_ntop(AF_INET6, &((sin6_t *)sin6p)->sin6_addr, 459*e7df7762SCody Peter Mello ipaddr, sizeof (ipaddr)) == NULL) { 460*e7df7762SCody Peter Mello (void) snprintf(ipaddr, sizeof (ipaddr), 461*e7df7762SCody Peter Mello "(failed to format IP)"); 462*e7df7762SCody Peter Mello }; 463*e7df7762SCody Peter Mello warnx("An appropriate interface for the address %s " 464*e7df7762SCody Peter Mello "is not in the routing table; use -i to force an " 465*e7df7762SCody Peter Mello "interface", ipaddr); 466*e7df7762SCody Peter Mello return (-1); 467*e7df7762SCody Peter Mello } else { 468*e7df7762SCody Peter Mello warnx("Failed to send routing message: %s", 469*e7df7762SCody Peter Mello strerror(errno)); 470*e7df7762SCody Peter Mello return (-1); 471*e7df7762SCody Peter Mello } 472*e7df7762SCody Peter Mello } else if (mlen < (int)m_rtm->rtm_msglen) { 473*e7df7762SCody Peter Mello warnx("Failed to write all bytes to routing socket"); 474*e7df7762SCody Peter Mello return (-1); 475*e7df7762SCody Peter Mello } 476*e7df7762SCody Peter Mello 477*e7df7762SCody Peter Mello /* 478*e7df7762SCody Peter Mello * Keep reading routing messages until we find the response to the one 479*e7df7762SCody Peter Mello * we just sent. Note that we depend on the sequence number being unique 480*e7df7762SCody Peter Mello * to the running program. 481*e7df7762SCody Peter Mello */ 482*e7df7762SCody Peter Mello do { 483*e7df7762SCody Peter Mello mlen = read(fd, (char *)msg, sizeof (rtmsg_pkt_t)); 484*e7df7762SCody Peter Mello } while (mlen > 0 && 485*e7df7762SCody Peter Mello (m_rtm->rtm_seq != seq || m_rtm->rtm_pid != ndp_pid)); 486*e7df7762SCody Peter Mello if (mlen < 0) { 487*e7df7762SCody Peter Mello warnx("Failed to read from routing socket: %s", 488*e7df7762SCody Peter Mello strerror(errno)); 489*e7df7762SCody Peter Mello return (-1); 490*e7df7762SCody Peter Mello } 491*e7df7762SCody Peter Mello 492*e7df7762SCody Peter Mello return (0); 493*e7df7762SCody Peter Mello } 494*e7df7762SCody Peter Mello 495*e7df7762SCody Peter Mello /* 496*e7df7762SCody Peter Mello * Find the interface that the IPv6 address would be routed through, and store 497*e7df7762SCody Peter Mello * the name of the interface in the buffer passed in. 498*e7df7762SCody Peter Mello */ 499*e7df7762SCody Peter Mello static int 500*e7df7762SCody Peter Mello ndp_find_interface(int fd, struct sockaddr *sin6p, char *buf, int buflen) 501*e7df7762SCody Peter Mello { 502*e7df7762SCody Peter Mello struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *src = NULL; 503*e7df7762SCody Peter Mello struct sockaddr_dl *ifp = NULL; 504*e7df7762SCody Peter Mello rtmsg_pkt_t msg; 505*e7df7762SCody Peter Mello 506*e7df7762SCody Peter Mello if (ndp_rtmsg_get(fd, &msg, sin6p) != 0) { 507*e7df7762SCody Peter Mello return (-1); 508*e7df7762SCody Peter Mello } 509*e7df7762SCody Peter Mello 510*e7df7762SCody Peter Mello if (ndp_extract_sockaddrs(&msg.m_rtm, &dst, &gate, 511*e7df7762SCody Peter Mello &mask, &src, &ifp) != 0) { 512*e7df7762SCody Peter Mello return (-1); 513*e7df7762SCody Peter Mello } 514*e7df7762SCody Peter Mello 515*e7df7762SCody Peter Mello if (ifp == NULL) { 516*e7df7762SCody Peter Mello warnx("Unable to find appropriate interface for address"); 517*e7df7762SCody Peter Mello return (-1); 518*e7df7762SCody Peter Mello } else { 519*e7df7762SCody Peter Mello if (ifp->sdl_nlen >= buflen) { 520*e7df7762SCody Peter Mello warnx("The interface name \"%.*s\" is too big for the " 521*e7df7762SCody Peter Mello "available buffer", ifp->sdl_nlen, ifp->sdl_data); 522*e7df7762SCody Peter Mello return (-1); 523*e7df7762SCody Peter Mello } else { 524*e7df7762SCody Peter Mello (void) snprintf(buf, buflen, "%.*s", ifp->sdl_nlen, 525*e7df7762SCody Peter Mello ifp->sdl_data); 526*e7df7762SCody Peter Mello } 527*e7df7762SCody Peter Mello } 528*e7df7762SCody Peter Mello 529*e7df7762SCody Peter Mello return (0); 530*e7df7762SCody Peter Mello } 531*e7df7762SCody Peter Mello 532*e7df7762SCody Peter Mello /* 533*e7df7762SCody Peter Mello * Zero out a lifreq struct for a SIOCLIF*ND ioctl, set the address, and fetch 534*e7df7762SCody Peter Mello * the appropriate interface using the given routing socket. 535*e7df7762SCody Peter Mello */ 536*e7df7762SCody Peter Mello static int 537*e7df7762SCody Peter Mello ndp_initialize_lifreq(int route, struct lifreq *lifrp, struct sockaddr *sap) 538*e7df7762SCody Peter Mello { 539*e7df7762SCody Peter Mello struct sockaddr_storage *lnr_addr; 540*e7df7762SCody Peter Mello /* LINTED E_BAD_PTR_CAST_ALIGN */ 541*e7df7762SCody Peter Mello struct sockaddr_in6 *sin6p = (sin6_t *)sap; 542*e7df7762SCody Peter Mello char *lifr_name = lifrp->lifr_name; 543*e7df7762SCody Peter Mello 544*e7df7762SCody Peter Mello bzero(lifrp, sizeof (struct lifreq)); 545*e7df7762SCody Peter Mello lnr_addr = &lifrp->lifr_nd.lnr_addr; 546*e7df7762SCody Peter Mello 547*e7df7762SCody Peter Mello if (ndp_iface != NULL) { 548*e7df7762SCody Peter Mello (void) strlcpy(lifr_name, ndp_iface, LIFNAMSIZ); 549*e7df7762SCody Peter Mello } else if (sin6p->sin6_scope_id != 0) { 550*e7df7762SCody Peter Mello int zone_id = sin6p->sin6_scope_id; 551*e7df7762SCody Peter Mello if (if_indextoname(zone_id, lifr_name) == NULL) { 552*e7df7762SCody Peter Mello warnx("Invalid zone identifier: %d", zone_id); 553*e7df7762SCody Peter Mello return (-1); 554*e7df7762SCody Peter Mello } 555*e7df7762SCody Peter Mello } else if (IN6_IS_ADDR_LINKSCOPE(&sin6p->sin6_addr)) { 556*e7df7762SCody Peter Mello warnx("Link-scope addresses should specify an interface with " 557*e7df7762SCody Peter Mello "a zone ID, or with -i."); 558*e7df7762SCody Peter Mello return (-1); 559*e7df7762SCody Peter Mello } else { 560*e7df7762SCody Peter Mello if (ndp_find_interface(route, sap, lifr_name, LIFNAMSIZ) != 0) 561*e7df7762SCody Peter Mello return (-1); 562*e7df7762SCody Peter Mello } 563*e7df7762SCody Peter Mello 564*e7df7762SCody Peter Mello (void) memcpy(lnr_addr, sap, sizeof (struct sockaddr_storage)); 565*e7df7762SCody Peter Mello 566*e7df7762SCody Peter Mello return (0); 567*e7df7762SCody Peter Mello } 568*e7df7762SCody Peter Mello 569*e7df7762SCody Peter Mello /* 570*e7df7762SCody Peter Mello * Take a host identifier, find the corresponding IPv6 addresses and then pass 571*e7df7762SCody Peter Mello * them to the specified function, along with any desired data. 572*e7df7762SCody Peter Mello */ 573*e7df7762SCody Peter Mello static int 574*e7df7762SCody Peter Mello ndp_host_enumerate(char *host, ndp_addr_f *addr_func, void *data) 575*e7df7762SCody Peter Mello { 576*e7df7762SCody Peter Mello struct lifreq lifr; 577*e7df7762SCody Peter Mello struct addrinfo hints, *serverinfo, *p; 578*e7df7762SCody Peter Mello int err, attempts = 0; 579*e7df7762SCody Peter Mello int inet6, route; 580*e7df7762SCody Peter Mello 581*e7df7762SCody Peter Mello bzero(&hints, sizeof (struct addrinfo)); 582*e7df7762SCody Peter Mello hints.ai_family = AF_INET6; 583*e7df7762SCody Peter Mello hints.ai_protocol = IPPROTO_IPV6; 584*e7df7762SCody Peter Mello 585*e7df7762SCody Peter Mello while (attempts < MAX_ATTEMPTS) { 586*e7df7762SCody Peter Mello err = getaddrinfo(host, NULL, &hints, &serverinfo); 587*e7df7762SCody Peter Mello 588*e7df7762SCody Peter Mello if (err == 0) { 589*e7df7762SCody Peter Mello break; 590*e7df7762SCody Peter Mello } else if (err == EAI_AGAIN) { 591*e7df7762SCody Peter Mello attempts++; 592*e7df7762SCody Peter Mello } else { 593*e7df7762SCody Peter Mello warnx("Unable to lookup %s: %s", host, 594*e7df7762SCody Peter Mello gai_strerror(err)); 595*e7df7762SCody Peter Mello return (-1); 596*e7df7762SCody Peter Mello } 597*e7df7762SCody Peter Mello } 598*e7df7762SCody Peter Mello 599*e7df7762SCody Peter Mello if (attempts == MAX_ATTEMPTS) { 600*e7df7762SCody Peter Mello warnx("Failed multiple times to lookup %s", host); 601*e7df7762SCody Peter Mello return (-1); 602*e7df7762SCody Peter Mello } 603*e7df7762SCody Peter Mello 604*e7df7762SCody Peter Mello inet6 = socket(PF_INET6, SOCK_DGRAM, 0); 605*e7df7762SCody Peter Mello if (inet6 < 0) { 606*e7df7762SCody Peter Mello warnx("Failed to open IPv6 socket: %s", strerror(errno)); 607*e7df7762SCody Peter Mello err = -1; 608*e7df7762SCody Peter Mello } 609*e7df7762SCody Peter Mello 610*e7df7762SCody Peter Mello route = socket(PF_ROUTE, SOCK_RAW, 0); 611*e7df7762SCody Peter Mello if (route < 0) { 612*e7df7762SCody Peter Mello warnx("Failed to open routing socket: %s", strerror(errno)); 613*e7df7762SCody Peter Mello err = -1; 614*e7df7762SCody Peter Mello } 615*e7df7762SCody Peter Mello 616*e7df7762SCody Peter Mello if (err == 0) { 617*e7df7762SCody Peter Mello for (p = serverinfo; p != NULL; p = p->ai_next) { 618*e7df7762SCody Peter Mello if (ndp_initialize_lifreq(route, &lifr, p->ai_addr) 619*e7df7762SCody Peter Mello != 0) { 620*e7df7762SCody Peter Mello err = -1; 621*e7df7762SCody Peter Mello continue; 622*e7df7762SCody Peter Mello } 623*e7df7762SCody Peter Mello 624*e7df7762SCody Peter Mello if (addr_func(inet6, &lifr, data) != 0) { 625*e7df7762SCody Peter Mello err = -1; 626*e7df7762SCody Peter Mello continue; 627*e7df7762SCody Peter Mello } 628*e7df7762SCody Peter Mello } 629*e7df7762SCody Peter Mello } 630*e7df7762SCody Peter Mello 631*e7df7762SCody Peter Mello if (close(route) != 0) { 632*e7df7762SCody Peter Mello warnx("Failed to close routing socket: %s", strerror(errno)); 633*e7df7762SCody Peter Mello err = -1; 634*e7df7762SCody Peter Mello } 635*e7df7762SCody Peter Mello 636*e7df7762SCody Peter Mello if (close(inet6) != 0) { 637*e7df7762SCody Peter Mello warnx("Failed to close IPv6 socket: %s", strerror(errno)); 638*e7df7762SCody Peter Mello err = -1; 639*e7df7762SCody Peter Mello } 640*e7df7762SCody Peter Mello 641*e7df7762SCody Peter Mello /* Clean up linked list */ 642*e7df7762SCody Peter Mello freeaddrinfo(serverinfo); 643*e7df7762SCody Peter Mello 644*e7df7762SCody Peter Mello return (err); 645*e7df7762SCody Peter Mello } 646*e7df7762SCody Peter Mello 647*e7df7762SCody Peter Mello static int 648*e7df7762SCody Peter Mello ndp_display(struct lifreq *lifrp) 649*e7df7762SCody Peter Mello { 650*e7df7762SCody Peter Mello struct sockaddr_in6 *lnr_addr; 651*e7df7762SCody Peter Mello char ipaddr[INET6_ADDRSTRLEN]; 652*e7df7762SCody Peter Mello char *lladdr = NULL; 653*e7df7762SCody Peter Mello char hostname[NI_MAXHOST]; 654*e7df7762SCody Peter Mello int flags, gni_flags; 655*e7df7762SCody Peter Mello 656*e7df7762SCody Peter Mello lnr_addr = (struct sockaddr_in6 *)&lifrp->lifr_nd.lnr_addr; 657*e7df7762SCody Peter Mello flags = lifrp->lifr_nd.lnr_flags; 658*e7df7762SCody Peter Mello 659*e7df7762SCody Peter Mello if (inet_ntop(AF_INET6, &lnr_addr->sin6_addr, ipaddr, 660*e7df7762SCody Peter Mello sizeof (ipaddr)) == NULL) { 661*e7df7762SCody Peter Mello warnx("Couldn't convert IPv6 address to string: %s", 662*e7df7762SCody Peter Mello strerror(errno)); 663*e7df7762SCody Peter Mello return (-1); 664*e7df7762SCody Peter Mello }; 665*e7df7762SCody Peter Mello 666*e7df7762SCody Peter Mello if ((lladdr = _link_ntoa((uchar_t *)lifrp->lifr_nd.lnr_hdw_addr, 667*e7df7762SCody Peter Mello NULL, lifrp->lifr_nd.lnr_hdw_len, IFT_ETHER)) == NULL) { 668*e7df7762SCody Peter Mello warnx("Couldn't convert link-layer address to string: %s", 669*e7df7762SCody Peter Mello strerror(errno)); 670*e7df7762SCody Peter Mello return (-1); 671*e7df7762SCody Peter Mello } 672*e7df7762SCody Peter Mello 673*e7df7762SCody Peter Mello gni_flags = ndp_noresolve ? NI_NUMERICHOST : 0; 674*e7df7762SCody Peter Mello 675*e7df7762SCody Peter Mello if (getnameinfo((struct sockaddr *)lnr_addr, sizeof (sin6_t), hostname, 676*e7df7762SCody Peter Mello sizeof (hostname), NULL, 0, gni_flags) != 0) { 677*e7df7762SCody Peter Mello warnx("Unable to lookup hostname for %s", ipaddr); 678*e7df7762SCody Peter Mello free(lladdr); 679*e7df7762SCody Peter Mello return (-1); 680*e7df7762SCody Peter Mello } 681*e7df7762SCody Peter Mello 682*e7df7762SCody Peter Mello (void) printf("%s (%s) at %s", ipaddr, hostname, lladdr); 683*e7df7762SCody Peter Mello 684*e7df7762SCody Peter Mello if (flags & NDF_ISROUTER_ON) { 685*e7df7762SCody Peter Mello (void) printf(" router"); 686*e7df7762SCody Peter Mello } 687*e7df7762SCody Peter Mello 688*e7df7762SCody Peter Mello if (flags & NDF_ANYCAST_ON) { 689*e7df7762SCody Peter Mello (void) printf(" any"); 690*e7df7762SCody Peter Mello } 691*e7df7762SCody Peter Mello 692*e7df7762SCody Peter Mello if (!(flags & NDF_STATIC)) { 693*e7df7762SCody Peter Mello (void) printf(" temp"); 694*e7df7762SCody Peter Mello } 695*e7df7762SCody Peter Mello 696*e7df7762SCody Peter Mello if (flags & NDF_PROXY_ON) { 697*e7df7762SCody Peter Mello (void) printf(" proxy"); 698*e7df7762SCody Peter Mello } 699*e7df7762SCody Peter Mello 700*e7df7762SCody Peter Mello (void) printf("\n"); 701*e7df7762SCody Peter Mello 702*e7df7762SCody Peter Mello free(lladdr); 703*e7df7762SCody Peter Mello return (0); 704*e7df7762SCody Peter Mello } 705*e7df7762SCody Peter Mello 706*e7df7762SCody Peter Mello static int 707*e7df7762SCody Peter Mello ndp_display_missing(struct lifreq *lifrp) 708*e7df7762SCody Peter Mello { 709*e7df7762SCody Peter Mello struct sockaddr_in6 *lnr_addr; 710*e7df7762SCody Peter Mello char ipaddr[INET6_ADDRSTRLEN]; 711*e7df7762SCody Peter Mello char hostname[NI_MAXHOST]; 712*e7df7762SCody Peter Mello int flags = ndp_noresolve ? NI_NUMERICHOST : 0; 713*e7df7762SCody Peter Mello lnr_addr = (struct sockaddr_in6 *)&lifrp->lifr_nd.lnr_addr; 714*e7df7762SCody Peter Mello 715*e7df7762SCody Peter Mello if (inet_ntop(AF_INET6, &lnr_addr->sin6_addr, ipaddr, 716*e7df7762SCody Peter Mello sizeof (ipaddr)) == NULL) { 717*e7df7762SCody Peter Mello warnx("Couldn't convert IPv6 address to string: %s", 718*e7df7762SCody Peter Mello strerror(errno)); 719*e7df7762SCody Peter Mello return (-1); 720*e7df7762SCody Peter Mello }; 721*e7df7762SCody Peter Mello 722*e7df7762SCody Peter Mello if (getnameinfo((struct sockaddr *)lnr_addr, sizeof (sin6_t), hostname, 723*e7df7762SCody Peter Mello sizeof (hostname), NULL, 0, flags) != 0) { 724*e7df7762SCody Peter Mello warnx("Unable to lookup hostname for %s", ipaddr); 725*e7df7762SCody Peter Mello return (-1); 726*e7df7762SCody Peter Mello } 727*e7df7762SCody Peter Mello 728*e7df7762SCody Peter Mello (void) printf("%s (%s) -- no entry\n", ipaddr, hostname); 729*e7df7762SCody Peter Mello return (0); 730*e7df7762SCody Peter Mello } 731*e7df7762SCody Peter Mello 732*e7df7762SCody Peter Mello static void 733*e7df7762SCody Peter Mello ndp_lifr2ip(struct lifreq *lifrp, char *ipaddr, int buflen) 734*e7df7762SCody Peter Mello { 735*e7df7762SCody Peter Mello sin6_t *lnr_addr = (sin6_t *)&lifrp->lifr_nd.lnr_addr; 736*e7df7762SCody Peter Mello if (inet_ntop(AF_INET6, &lnr_addr->sin6_addr, ipaddr, 737*e7df7762SCody Peter Mello buflen) == NULL) { 738*e7df7762SCody Peter Mello (void) snprintf(ipaddr, buflen, "(failed to format IP)"); 739*e7df7762SCody Peter Mello }; 740*e7df7762SCody Peter Mello } 741*e7df7762SCody Peter Mello 742*e7df7762SCody Peter Mello /* 743*e7df7762SCody Peter Mello * Perform a SIOCLIFGETND and print out information about it 744*e7df7762SCody Peter Mello */ 745*e7df7762SCody Peter Mello /*ARGSUSED*/ 746*e7df7762SCody Peter Mello static int 747*e7df7762SCody Peter Mello ndp_get(int fd, struct lifreq *lifrp, void *unused) 748*e7df7762SCody Peter Mello { 749*e7df7762SCody Peter Mello char ipaddr[INET6_ADDRSTRLEN]; 750*e7df7762SCody Peter Mello if (ioctl(fd, SIOCLIFGETND, lifrp) < 0) { 751*e7df7762SCody Peter Mello if (errno == ESRCH) { 752*e7df7762SCody Peter Mello return (ndp_display_missing(lifrp)); 753*e7df7762SCody Peter Mello } else { 754*e7df7762SCody Peter Mello ndp_lifr2ip(lifrp, ipaddr, sizeof (ipaddr)); 755*e7df7762SCody Peter Mello warnx("Couldn't lookup %s: %s", 756*e7df7762SCody Peter Mello ipaddr, strerror(errno)); 757*e7df7762SCody Peter Mello return (-1); 758*e7df7762SCody Peter Mello } 759*e7df7762SCody Peter Mello } 760*e7df7762SCody Peter Mello 761*e7df7762SCody Peter Mello return (ndp_display(lifrp)); 762*e7df7762SCody Peter Mello } 763*e7df7762SCody Peter Mello 764*e7df7762SCody Peter Mello /* 765*e7df7762SCody Peter Mello * Print out all NDP entries 766*e7df7762SCody Peter Mello */ 767*e7df7762SCody Peter Mello static void 768*e7df7762SCody Peter Mello ndp_get_all(void) 769*e7df7762SCody Peter Mello { 770*e7df7762SCody Peter Mello (void) execl(netstat_path, "netstat", 771*e7df7762SCody Peter Mello (ndp_noresolve ? "-np" : "-p"), 772*e7df7762SCody Peter Mello "-f", "inet6", (char *)0); 773*e7df7762SCody Peter Mello ndp_fatal("Coudn't exec %s: %s", netstat_path, strerror(errno)); 774*e7df7762SCody Peter Mello } 775*e7df7762SCody Peter Mello 776*e7df7762SCody Peter Mello /* 777*e7df7762SCody Peter Mello * Perform a SIOCLIFDELND ioctl 778*e7df7762SCody Peter Mello */ 779*e7df7762SCody Peter Mello /*ARGSUSED*/ 780*e7df7762SCody Peter Mello static int 781*e7df7762SCody Peter Mello ndp_delete(int fd, struct lifreq *lifrp, void *unused) 782*e7df7762SCody Peter Mello { 783*e7df7762SCody Peter Mello char ipaddr[INET6_ADDRSTRLEN]; 784*e7df7762SCody Peter Mello 785*e7df7762SCody Peter Mello if (ioctl(fd, SIOCLIFDELND, lifrp) < 0) { 786*e7df7762SCody Peter Mello ndp_lifr2ip(lifrp, ipaddr, sizeof (ipaddr)); 787*e7df7762SCody Peter Mello if (errno == ESRCH) { 788*e7df7762SCody Peter Mello warnx("No entry for %s", ipaddr); 789*e7df7762SCody Peter Mello return (-1); 790*e7df7762SCody Peter Mello } else if (errno == EPERM) { 791*e7df7762SCody Peter Mello warnx("Permission denied, " 792*e7df7762SCody Peter Mello "could not delete entry for %s", ipaddr); 793*e7df7762SCody Peter Mello return (-1); 794*e7df7762SCody Peter Mello } else { 795*e7df7762SCody Peter Mello warnx("Couldn't delete mapping for %s: %s", 796*e7df7762SCody Peter Mello ipaddr, strerror(errno)); 797*e7df7762SCody Peter Mello return (-1); 798*e7df7762SCody Peter Mello } 799*e7df7762SCody Peter Mello } 800*e7df7762SCody Peter Mello 801*e7df7762SCody Peter Mello return (0); 802*e7df7762SCody Peter Mello } 803*e7df7762SCody Peter Mello 804*e7df7762SCody Peter Mello /* 805*e7df7762SCody Peter Mello * Perform a SIOCLIFSETND ioctl using properties from the example structure. 806*e7df7762SCody Peter Mello */ 807*e7df7762SCody Peter Mello static int 808*e7df7762SCody Peter Mello ndp_set(int fd, struct lifreq *lifrp, void *data) 809*e7df7762SCody Peter Mello { 810*e7df7762SCody Peter Mello char ipaddr[INET6_ADDRSTRLEN]; 811*e7df7762SCody Peter Mello const lif_nd_req_t *nd_attrs = data; 812*e7df7762SCody Peter Mello 813*e7df7762SCody Peter Mello (void) memcpy(lifrp->lifr_nd.lnr_hdw_addr, nd_attrs->lnr_hdw_addr, 814*e7df7762SCody Peter Mello ND_MAX_HDW_LEN); 815*e7df7762SCody Peter Mello lifrp->lifr_nd.lnr_hdw_len = nd_attrs->lnr_hdw_len; 816*e7df7762SCody Peter Mello lifrp->lifr_nd.lnr_flags = nd_attrs->lnr_flags; 817*e7df7762SCody Peter Mello 818*e7df7762SCody Peter Mello lifrp->lifr_nd.lnr_state_create = nd_attrs->lnr_state_create; 819*e7df7762SCody Peter Mello lifrp->lifr_nd.lnr_state_same_lla = nd_attrs->lnr_state_same_lla; 820*e7df7762SCody Peter Mello lifrp->lifr_nd.lnr_state_diff_lla = nd_attrs->lnr_state_diff_lla; 821*e7df7762SCody Peter Mello 822*e7df7762SCody Peter Mello if (ioctl(fd, SIOCLIFSETND, lifrp) < 0) { 823*e7df7762SCody Peter Mello ndp_lifr2ip(lifrp, ipaddr, sizeof (ipaddr)); 824*e7df7762SCody Peter Mello if (errno == EPERM) { 825*e7df7762SCody Peter Mello warnx("Permission denied, " 826*e7df7762SCody Peter Mello "could not set entry for %s", ipaddr); 827*e7df7762SCody Peter Mello return (-1); 828*e7df7762SCody Peter Mello } else { 829*e7df7762SCody Peter Mello warnx("Failed to set mapping for %s: %s", 830*e7df7762SCody Peter Mello ipaddr, strerror(errno)); 831*e7df7762SCody Peter Mello return (-1); 832*e7df7762SCody Peter Mello } 833*e7df7762SCody Peter Mello } 834*e7df7762SCody Peter Mello 835*e7df7762SCody Peter Mello return (0); 836*e7df7762SCody Peter Mello } 837*e7df7762SCody Peter Mello 838*e7df7762SCody Peter Mello /* 839*e7df7762SCody Peter Mello * Given a host identifier, a link-layer address and possible options, 840*e7df7762SCody Peter Mello * add/update the NDP mappings. 841*e7df7762SCody Peter Mello */ 842*e7df7762SCody Peter Mello static int 843*e7df7762SCody Peter Mello ndp_set_nce(char *host, char *lladdr, char *opts[], int optlen) 844*e7df7762SCody Peter Mello { 845*e7df7762SCody Peter Mello lif_nd_req_t nd_attrs; 846*e7df7762SCody Peter Mello uchar_t *ea; 847*e7df7762SCody Peter Mello char *opt; 848*e7df7762SCody Peter Mello int i; 849*e7df7762SCody Peter Mello boolean_t temp = B_FALSE; 850*e7df7762SCody Peter Mello boolean_t any = B_FALSE; 851*e7df7762SCody Peter Mello boolean_t router = B_FALSE; 852*e7df7762SCody Peter Mello 853*e7df7762SCody Peter Mello bzero(&nd_attrs, sizeof (lif_nd_req_t)); 854*e7df7762SCody Peter Mello 855*e7df7762SCody Peter Mello ea = _link_aton(lladdr, &nd_attrs.lnr_hdw_len); 856*e7df7762SCody Peter Mello 857*e7df7762SCody Peter Mello if (ea == NULL) { 858*e7df7762SCody Peter Mello warnx("Unable to parse link-layer address \"%s\"", lladdr); 859*e7df7762SCody Peter Mello return (-1); 860*e7df7762SCody Peter Mello } 861*e7df7762SCody Peter Mello 862*e7df7762SCody Peter Mello if (nd_attrs.lnr_hdw_len > sizeof (nd_attrs.lnr_hdw_addr)) { 863*e7df7762SCody Peter Mello warnx("The size of the link-layer address is " 864*e7df7762SCody Peter Mello "too large to set\n"); 865*e7df7762SCody Peter Mello free(ea); 866*e7df7762SCody Peter Mello return (-1); 867*e7df7762SCody Peter Mello } 868*e7df7762SCody Peter Mello 869*e7df7762SCody Peter Mello (void) memcpy(nd_attrs.lnr_hdw_addr, ea, nd_attrs.lnr_hdw_len); 870*e7df7762SCody Peter Mello 871*e7df7762SCody Peter Mello free(ea); 872*e7df7762SCody Peter Mello 873*e7df7762SCody Peter Mello nd_attrs.lnr_state_create = ND_REACHABLE; 874*e7df7762SCody Peter Mello nd_attrs.lnr_state_same_lla = ND_UNCHANGED; 875*e7df7762SCody Peter Mello nd_attrs.lnr_state_diff_lla = ND_STALE; 876*e7df7762SCody Peter Mello 877*e7df7762SCody Peter Mello for (i = 0; i < optlen; i++) { 878*e7df7762SCody Peter Mello opt = opts[i]; 879*e7df7762SCody Peter Mello if (strcmp(opt, "temp") == 0) { 880*e7df7762SCody Peter Mello temp = B_TRUE; 881*e7df7762SCody Peter Mello } else if (strcmp(opt, "any") == 0) { 882*e7df7762SCody Peter Mello any = B_TRUE; 883*e7df7762SCody Peter Mello } else if (strcmp(opt, "router") == 0) { 884*e7df7762SCody Peter Mello router = B_TRUE; 885*e7df7762SCody Peter Mello } else if (strcmp(opt, "proxy") == 0) { 886*e7df7762SCody Peter Mello warnx("NDP proxying is currently not supported"); 887*e7df7762SCody Peter Mello return (-1); 888*e7df7762SCody Peter Mello } else { 889*e7df7762SCody Peter Mello warnx("Unrecognized option \"%s\"", opt); 890*e7df7762SCody Peter Mello return (-1); 891*e7df7762SCody Peter Mello } 892*e7df7762SCody Peter Mello } 893*e7df7762SCody Peter Mello 894*e7df7762SCody Peter Mello if (!temp) { 895*e7df7762SCody Peter Mello nd_attrs.lnr_flags |= NDF_STATIC; 896*e7df7762SCody Peter Mello } 897*e7df7762SCody Peter Mello 898*e7df7762SCody Peter Mello if (any) { 899*e7df7762SCody Peter Mello nd_attrs.lnr_flags |= NDF_ANYCAST_ON; 900*e7df7762SCody Peter Mello } else { 901*e7df7762SCody Peter Mello nd_attrs.lnr_flags |= NDF_ANYCAST_OFF; 902*e7df7762SCody Peter Mello } 903*e7df7762SCody Peter Mello 904*e7df7762SCody Peter Mello if (router) { 905*e7df7762SCody Peter Mello nd_attrs.lnr_flags |= NDF_ISROUTER_OFF; 906*e7df7762SCody Peter Mello } else { 907*e7df7762SCody Peter Mello nd_attrs.lnr_flags |= NDF_ISROUTER_OFF; 908*e7df7762SCody Peter Mello } 909*e7df7762SCody Peter Mello 910*e7df7762SCody Peter Mello return (ndp_host_enumerate(host, ndp_set, &nd_attrs)); 911*e7df7762SCody Peter Mello } 912*e7df7762SCody Peter Mello 913*e7df7762SCody Peter Mello /* 914*e7df7762SCody Peter Mello * Read in a file and set the mappings from each line. 915*e7df7762SCody Peter Mello */ 916*e7df7762SCody Peter Mello static int 917*e7df7762SCody Peter Mello ndp_set_file(char *filename) 918*e7df7762SCody Peter Mello { 919*e7df7762SCody Peter Mello char *line = NULL, *lasts = NULL, *curr; 920*e7df7762SCody Peter Mello char *host, *lladdr; 921*e7df7762SCody Peter Mello char *opts[MAX_OPTS]; 922*e7df7762SCody Peter Mello int optlen = 0, lineno = 0; 923*e7df7762SCody Peter Mello size_t cap = 0; 924*e7df7762SCody Peter Mello boolean_t failed_line = B_FALSE; 925*e7df7762SCody Peter Mello FILE *stream = fopen(filename, "r"); 926*e7df7762SCody Peter Mello 927*e7df7762SCody Peter Mello if (stream == NULL) { 928*e7df7762SCody Peter Mello ndp_fatal("Error while opening file %s: %s", 929*e7df7762SCody Peter Mello filename, strerror(errno)); 930*e7df7762SCody Peter Mello } 931*e7df7762SCody Peter Mello 932*e7df7762SCody Peter Mello errno = 0; 933*e7df7762SCody Peter Mello while (getline(&line, &cap, stream) != -1) { 934*e7df7762SCody Peter Mello lineno++; 935*e7df7762SCody Peter Mello 936*e7df7762SCody Peter Mello if (line[0] == '#') 937*e7df7762SCody Peter Mello continue; 938*e7df7762SCody Peter Mello 939*e7df7762SCody Peter Mello host = strtok_r(line, WORDSEPS, &lasts); 940*e7df7762SCody Peter Mello if (host == NULL) { 941*e7df7762SCody Peter Mello warnx("Line %d incomplete, skipping: " 942*e7df7762SCody Peter Mello "missing host identifier", lineno); 943*e7df7762SCody Peter Mello failed_line = B_TRUE; 944*e7df7762SCody Peter Mello continue; 945*e7df7762SCody Peter Mello } 946*e7df7762SCody Peter Mello 947*e7df7762SCody Peter Mello lladdr = strtok_r(NULL, WORDSEPS, &lasts); 948*e7df7762SCody Peter Mello if (lladdr == NULL) { 949*e7df7762SCody Peter Mello warnx("Line %d incomplete, skipping: " 950*e7df7762SCody Peter Mello "missing link-layer address", lineno); 951*e7df7762SCody Peter Mello failed_line = B_TRUE; 952*e7df7762SCody Peter Mello continue; 953*e7df7762SCody Peter Mello } 954*e7df7762SCody Peter Mello 955*e7df7762SCody Peter Mello for (optlen = 0; optlen < MAX_OPTS; optlen++) { 956*e7df7762SCody Peter Mello curr = strtok_r(NULL, WORDSEPS, &lasts); 957*e7df7762SCody Peter Mello if (curr == NULL) 958*e7df7762SCody Peter Mello break; 959*e7df7762SCody Peter Mello opts[optlen] = curr; 960*e7df7762SCody Peter Mello } 961*e7df7762SCody Peter Mello 962*e7df7762SCody Peter Mello if (ndp_set_nce(host, lladdr, opts, optlen) != 0) { 963*e7df7762SCody Peter Mello failed_line = B_TRUE; 964*e7df7762SCody Peter Mello continue; 965*e7df7762SCody Peter Mello } 966*e7df7762SCody Peter Mello } 967*e7df7762SCody Peter Mello 968*e7df7762SCody Peter Mello free(line); 969*e7df7762SCody Peter Mello 970*e7df7762SCody Peter Mello if (errno != 0 || ferror(stream)) { 971*e7df7762SCody Peter Mello ndp_fatal("Error while reading from file %s: %s", filename, 972*e7df7762SCody Peter Mello strerror(errno)); 973*e7df7762SCody Peter Mello } 974*e7df7762SCody Peter Mello 975*e7df7762SCody Peter Mello if (fclose(stream) != 0) { 976*e7df7762SCody Peter Mello ndp_fatal("Error close file %s: %s", filename, strerror(errno)); 977*e7df7762SCody Peter Mello } 978*e7df7762SCody Peter Mello 979*e7df7762SCody Peter Mello return (failed_line ? -1 : 0); 980*e7df7762SCody Peter Mello } 981*e7df7762SCody Peter Mello 982*e7df7762SCody Peter Mello int 983*e7df7762SCody Peter Mello main(int argc, char *argv[]) 984*e7df7762SCody Peter Mello { 985*e7df7762SCody Peter Mello char *flagarg = NULL, *lladdr = NULL; 986*e7df7762SCody Peter Mello char **opts; 987*e7df7762SCody Peter Mello char *endptr; 988*e7df7762SCody Peter Mello int c, argsleft, optlen = 0, err = 0; 989*e7df7762SCody Peter Mello long long period; 990*e7df7762SCody Peter Mello enum ndp_action action = NDP_A_DEFAULT; 991*e7df7762SCody Peter Mello 992*e7df7762SCody Peter Mello setprogname(basename(argv[0])); 993*e7df7762SCody Peter Mello 994*e7df7762SCody Peter Mello if (argc < 2) { 995*e7df7762SCody Peter Mello ndp_usage("No arguments given."); 996*e7df7762SCody Peter Mello } 997*e7df7762SCody Peter Mello 998*e7df7762SCody Peter Mello while ((c = getopt(argc, argv, ":naA:d:f:i:s:")) != -1) { 999*e7df7762SCody Peter Mello switch (c) { 1000*e7df7762SCody Peter Mello case 'n': 1001*e7df7762SCody Peter Mello ndp_noresolve = B_TRUE; 1002*e7df7762SCody Peter Mello break; 1003*e7df7762SCody Peter Mello case 'i': 1004*e7df7762SCody Peter Mello ndp_iface = optarg; 1005*e7df7762SCody Peter Mello break; 1006*e7df7762SCody Peter Mello case 's': 1007*e7df7762SCody Peter Mello if (action != NDP_A_DEFAULT) 1008*e7df7762SCody Peter Mello ndp_badflag(action); 1009*e7df7762SCody Peter Mello action = NDP_A_SET_NCE; 1010*e7df7762SCody Peter Mello flagarg = optarg; 1011*e7df7762SCody Peter Mello 1012*e7df7762SCody Peter Mello if ((argc - optind) < 1) { 1013*e7df7762SCody Peter Mello ndp_usage("Missing link-layer address after " 1014*e7df7762SCody Peter Mello "the node address, \"%s\"", flagarg); 1015*e7df7762SCody Peter Mello } 1016*e7df7762SCody Peter Mello lladdr = argv[optind++]; 1017*e7df7762SCody Peter Mello 1018*e7df7762SCody Peter Mello /* 1019*e7df7762SCody Peter Mello * Grab any following keywords up to the next flag 1020*e7df7762SCody Peter Mello */ 1021*e7df7762SCody Peter Mello opts = argv + optind; 1022*e7df7762SCody Peter Mello while ((argc - optind) > 0) { 1023*e7df7762SCody Peter Mello if (argv[optind][0] == '-') 1024*e7df7762SCody Peter Mello ndp_usage("Encountered \"%s\" after " 1025*e7df7762SCody Peter Mello "flag parsing is done", 1026*e7df7762SCody Peter Mello argv[optind]); 1027*e7df7762SCody Peter Mello optind++; 1028*e7df7762SCody Peter Mello optlen++; 1029*e7df7762SCody Peter Mello } 1030*e7df7762SCody Peter Mello break; 1031*e7df7762SCody Peter Mello case 'a': 1032*e7df7762SCody Peter Mello if (action != NDP_A_DEFAULT) 1033*e7df7762SCody Peter Mello ndp_badflag(action); 1034*e7df7762SCody Peter Mello action = NDP_A_GET_ALL; 1035*e7df7762SCody Peter Mello break; 1036*e7df7762SCody Peter Mello case 'A': 1037*e7df7762SCody Peter Mello if (action != NDP_A_DEFAULT) 1038*e7df7762SCody Peter Mello ndp_badflag(action); 1039*e7df7762SCody Peter Mello action = NDP_A_GET_FOREVER; 1040*e7df7762SCody Peter Mello flagarg = optarg; 1041*e7df7762SCody Peter Mello break; 1042*e7df7762SCody Peter Mello case 'd': 1043*e7df7762SCody Peter Mello if (action != NDP_A_DEFAULT) 1044*e7df7762SCody Peter Mello ndp_badflag(action); 1045*e7df7762SCody Peter Mello action = NDP_A_DELETE; 1046*e7df7762SCody Peter Mello flagarg = optarg; 1047*e7df7762SCody Peter Mello break; 1048*e7df7762SCody Peter Mello case 'f': 1049*e7df7762SCody Peter Mello if (action != NDP_A_DEFAULT) 1050*e7df7762SCody Peter Mello ndp_badflag(action); 1051*e7df7762SCody Peter Mello action = NDP_A_SET_FILE; 1052*e7df7762SCody Peter Mello flagarg = optarg; 1053*e7df7762SCody Peter Mello break; 1054*e7df7762SCody Peter Mello case ':': 1055*e7df7762SCody Peter Mello ndp_missingarg(optopt); 1056*e7df7762SCody Peter Mello break; 1057*e7df7762SCody Peter Mello case '?': 1058*e7df7762SCody Peter Mello ndp_usage("Unrecognized flag \"-%c\"", optopt); 1059*e7df7762SCody Peter Mello default: 1060*e7df7762SCody Peter Mello ndp_usage(NULL); 1061*e7df7762SCody Peter Mello } 1062*e7df7762SCody Peter Mello } 1063*e7df7762SCody Peter Mello 1064*e7df7762SCody Peter Mello argsleft = argc - optind; 1065*e7df7762SCody Peter Mello ndp_pid = getpid(); 1066*e7df7762SCody Peter Mello 1067*e7df7762SCody Peter Mello if (action != NDP_A_DEFAULT && argsleft != 0) { 1068*e7df7762SCody Peter Mello ndp_usage("Extra arguments leftover after parsing flags"); 1069*e7df7762SCody Peter Mello } 1070*e7df7762SCody Peter Mello 1071*e7df7762SCody Peter Mello switch (action) { 1072*e7df7762SCody Peter Mello case NDP_A_DEFAULT: 1073*e7df7762SCody Peter Mello case NDP_A_GET: 1074*e7df7762SCody Peter Mello if (argsleft != 1) { 1075*e7df7762SCody Peter Mello ndp_usage("Multiple arguments given without any flags"); 1076*e7df7762SCody Peter Mello } 1077*e7df7762SCody Peter Mello err = ndp_host_enumerate(argv[optind], ndp_get, NULL); 1078*e7df7762SCody Peter Mello break; 1079*e7df7762SCody Peter Mello case NDP_A_GET_ALL: 1080*e7df7762SCody Peter Mello ndp_get_all(); 1081*e7df7762SCody Peter Mello /*NOTREACHED*/ 1082*e7df7762SCody Peter Mello break; 1083*e7df7762SCody Peter Mello case NDP_A_GET_FOREVER: 1084*e7df7762SCody Peter Mello errno = 0; 1085*e7df7762SCody Peter Mello period = strtoll(flagarg, &endptr, 10); 1086*e7df7762SCody Peter Mello if ((period == 0 && errno != 0) || 1087*e7df7762SCody Peter Mello (endptr[0] != '\0') || 1088*e7df7762SCody Peter Mello (period < 0)) { 1089*e7df7762SCody Peter Mello ndp_usage("Given period should be a positive integer," 1090*e7df7762SCody Peter Mello " not \"%s\"", flagarg); 1091*e7df7762SCody Peter Mello } 1092*e7df7762SCody Peter Mello if (period > 86400) { 1093*e7df7762SCody Peter Mello ndp_usage("Given period should be shorter than a day;" 1094*e7df7762SCody Peter Mello " given \"%s\" seconds", flagarg); 1095*e7df7762SCody Peter Mello } 1096*e7df7762SCody Peter Mello ndp_run_periodically(period, ndp_get_all); 1097*e7df7762SCody Peter Mello /*NOTREACHED*/ 1098*e7df7762SCody Peter Mello break; 1099*e7df7762SCody Peter Mello case NDP_A_DELETE: 1100*e7df7762SCody Peter Mello err = ndp_host_enumerate(flagarg, ndp_delete, NULL); 1101*e7df7762SCody Peter Mello break; 1102*e7df7762SCody Peter Mello case NDP_A_SET_NCE: 1103*e7df7762SCody Peter Mello err = ndp_set_nce(flagarg, lladdr, opts, optlen); 1104*e7df7762SCody Peter Mello break; 1105*e7df7762SCody Peter Mello case NDP_A_SET_FILE: 1106*e7df7762SCody Peter Mello err = ndp_set_file(flagarg); 1107*e7df7762SCody Peter Mello break; 1108*e7df7762SCody Peter Mello } 1109*e7df7762SCody Peter Mello 1110*e7df7762SCody Peter Mello return (err == 0 ? 0 : 1); 1111*e7df7762SCody Peter Mello } 1112