17c478bd9Sstevel@tonic-gate /* 2*aee32e3dScarlsonj * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 37c478bd9Sstevel@tonic-gate * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate */ 57c478bd9Sstevel@tonic-gate 67c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 77c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 87c478bd9Sstevel@tonic-gate 97c478bd9Sstevel@tonic-gate /* Copyright (c) 1990 Mentat Inc. */ 107c478bd9Sstevel@tonic-gate 117c478bd9Sstevel@tonic-gate /* 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * Copyright (c) 1983, 1989, 1991, 1993 147c478bd9Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 157c478bd9Sstevel@tonic-gate * 167c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 177c478bd9Sstevel@tonic-gate * modification, are permitted provided that the following conditions 187c478bd9Sstevel@tonic-gate * are met: 197c478bd9Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 207c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 217c478bd9Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 227c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 237c478bd9Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 247c478bd9Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this software 257c478bd9Sstevel@tonic-gate * must display the following acknowledgement: 267c478bd9Sstevel@tonic-gate * This product includes software developed by the University of 277c478bd9Sstevel@tonic-gate * California, Berkeley and its contributors. 287c478bd9Sstevel@tonic-gate * 4. Neither the name of the University nor the names of its contributors 297c478bd9Sstevel@tonic-gate * may be used to endorse or promote products derived from this software 307c478bd9Sstevel@tonic-gate * without specific prior written permission. 317c478bd9Sstevel@tonic-gate * 327c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 337c478bd9Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 347c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 357c478bd9Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 367c478bd9Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 377c478bd9Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 387c478bd9Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 397c478bd9Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 407c478bd9Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 417c478bd9Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 427c478bd9Sstevel@tonic-gate * SUCH DAMAGE. 437c478bd9Sstevel@tonic-gate * 447c478bd9Sstevel@tonic-gate * @(#)route.c 8.6 (Berkeley) 4/28/95 457c478bd9Sstevel@tonic-gate * @(#)linkaddr.c 8.1 (Berkeley) 6/4/93 467c478bd9Sstevel@tonic-gate */ 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate #include <sys/param.h> 517c478bd9Sstevel@tonic-gate #include <sys/file.h> 527c478bd9Sstevel@tonic-gate #include <sys/socket.h> 537c478bd9Sstevel@tonic-gate #include <sys/ioctl.h> 547c478bd9Sstevel@tonic-gate #include <sys/stream.h> 553f33f4f7Sjl138328 #include <sys/tihdr.h> 567a23074eSdduvall #include <sys/sysmacros.h> 57*aee32e3dScarlsonj #include <sys/ccompile.h> 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate #include <net/if.h> 607c478bd9Sstevel@tonic-gate #include <net/route.h> 617c478bd9Sstevel@tonic-gate #include <net/if_dl.h> 627c478bd9Sstevel@tonic-gate #include <netinet/in.h> 637c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 647c478bd9Sstevel@tonic-gate #include <netdb.h> 657c478bd9Sstevel@tonic-gate #include <inet/mib2.h> 667c478bd9Sstevel@tonic-gate #include <inet/ip.h> 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate #include <locale.h> 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate #include <errno.h> 717c478bd9Sstevel@tonic-gate #include <unistd.h> 727c478bd9Sstevel@tonic-gate #include <stdio.h> 737c478bd9Sstevel@tonic-gate #include <stdlib.h> 747c478bd9Sstevel@tonic-gate #include <string.h> 757c478bd9Sstevel@tonic-gate #include <stropts.h> 767c478bd9Sstevel@tonic-gate #include <fcntl.h> 777c478bd9Sstevel@tonic-gate #include <assert.h> 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate static struct keytab { 807c478bd9Sstevel@tonic-gate char *kt_cp; 817c478bd9Sstevel@tonic-gate int kt_i; 827c478bd9Sstevel@tonic-gate } keywords[] = { 837c478bd9Sstevel@tonic-gate #define K_ADD 1 847c478bd9Sstevel@tonic-gate {"add", K_ADD}, 857c478bd9Sstevel@tonic-gate #define K_BLACKHOLE 2 867c478bd9Sstevel@tonic-gate {"blackhole", K_BLACKHOLE}, 877c478bd9Sstevel@tonic-gate #define K_CHANGE 3 887c478bd9Sstevel@tonic-gate {"change", K_CHANGE}, 897c478bd9Sstevel@tonic-gate #define K_CLONING 4 907c478bd9Sstevel@tonic-gate {"cloning", K_CLONING}, 917c478bd9Sstevel@tonic-gate #define K_DELETE 5 927c478bd9Sstevel@tonic-gate {"delete", K_DELETE}, 937c478bd9Sstevel@tonic-gate #define K_DST 6 947c478bd9Sstevel@tonic-gate {"dst", K_DST}, 957c478bd9Sstevel@tonic-gate #define K_EXPIRE 7 967c478bd9Sstevel@tonic-gate {"expire", K_EXPIRE}, 977c478bd9Sstevel@tonic-gate #define K_FLUSH 8 987c478bd9Sstevel@tonic-gate {"flush", K_FLUSH}, 997c478bd9Sstevel@tonic-gate #define K_GATEWAY 9 1007c478bd9Sstevel@tonic-gate {"gateway", K_GATEWAY}, 1017c478bd9Sstevel@tonic-gate #define K_GET 11 1027c478bd9Sstevel@tonic-gate {"get", K_GET}, 1037c478bd9Sstevel@tonic-gate #define K_HOPCOUNT 12 1047c478bd9Sstevel@tonic-gate {"hopcount", K_HOPCOUNT}, 1057c478bd9Sstevel@tonic-gate #define K_HOST 13 1067c478bd9Sstevel@tonic-gate {"host", K_HOST}, 1077c478bd9Sstevel@tonic-gate #define K_IFA 14 1087c478bd9Sstevel@tonic-gate {"ifa", K_IFA}, 1097c478bd9Sstevel@tonic-gate #define K_IFACE 15 1107c478bd9Sstevel@tonic-gate {"iface", K_IFACE}, 1117c478bd9Sstevel@tonic-gate #define K_IFP 16 1127c478bd9Sstevel@tonic-gate {"ifp", K_IFP}, 1137c478bd9Sstevel@tonic-gate #define K_INET 17 1147c478bd9Sstevel@tonic-gate {"inet", K_INET}, 1157c478bd9Sstevel@tonic-gate #define K_INET6 18 1167c478bd9Sstevel@tonic-gate {"inet6", K_INET6}, 1177c478bd9Sstevel@tonic-gate #define K_INTERFACE 19 1187c478bd9Sstevel@tonic-gate {"interface", K_INTERFACE}, 1197c478bd9Sstevel@tonic-gate #define K_LINK 20 1207c478bd9Sstevel@tonic-gate {"link", K_LINK}, 1217c478bd9Sstevel@tonic-gate #define K_LOCK 21 1227c478bd9Sstevel@tonic-gate {"lock", K_LOCK}, 1237c478bd9Sstevel@tonic-gate #define K_LOCKREST 22 1247c478bd9Sstevel@tonic-gate {"lockrest", K_LOCKREST}, 1257c478bd9Sstevel@tonic-gate #define K_MASK 23 1267c478bd9Sstevel@tonic-gate {"mask", K_MASK}, 1277c478bd9Sstevel@tonic-gate #define K_MONITOR 24 1287c478bd9Sstevel@tonic-gate {"monitor", K_MONITOR}, 1297c478bd9Sstevel@tonic-gate #define K_MTU 25 1307c478bd9Sstevel@tonic-gate {"mtu", K_MTU}, 1317c478bd9Sstevel@tonic-gate #define K_NET 26 1327c478bd9Sstevel@tonic-gate {"net", K_NET}, 1337c478bd9Sstevel@tonic-gate #define K_NETMASK 27 1347c478bd9Sstevel@tonic-gate {"netmask", K_NETMASK}, 1357c478bd9Sstevel@tonic-gate #define K_NOSTATIC 28 1367c478bd9Sstevel@tonic-gate {"nostatic", K_NOSTATIC}, 1377c478bd9Sstevel@tonic-gate #define K_PRIVATE 29 1387c478bd9Sstevel@tonic-gate {"private", K_PRIVATE}, 1397c478bd9Sstevel@tonic-gate #define K_PROTO1 30 1407c478bd9Sstevel@tonic-gate {"proto1", K_PROTO1}, 1417c478bd9Sstevel@tonic-gate #define K_PROTO2 31 1427c478bd9Sstevel@tonic-gate {"proto2", K_PROTO2}, 1437c478bd9Sstevel@tonic-gate #define K_RECVPIPE 32 1447c478bd9Sstevel@tonic-gate {"recvpipe", K_RECVPIPE}, 1457c478bd9Sstevel@tonic-gate #define K_REJECT 33 1467c478bd9Sstevel@tonic-gate {"reject", K_REJECT}, 1477c478bd9Sstevel@tonic-gate #define K_RTT 34 1487c478bd9Sstevel@tonic-gate {"rtt", K_RTT}, 1497c478bd9Sstevel@tonic-gate #define K_RTTVAR 35 1507c478bd9Sstevel@tonic-gate {"rttvar", K_RTTVAR}, 1517c478bd9Sstevel@tonic-gate #define K_SA 36 1527c478bd9Sstevel@tonic-gate {"sa", K_SA}, 1537c478bd9Sstevel@tonic-gate #define K_SENDPIPE 37 1547c478bd9Sstevel@tonic-gate {"sendpipe", K_SENDPIPE}, 1557c478bd9Sstevel@tonic-gate #define K_SSTHRESH 38 1567c478bd9Sstevel@tonic-gate {"ssthresh", K_SSTHRESH}, 1577c478bd9Sstevel@tonic-gate #define K_STATIC 39 1587c478bd9Sstevel@tonic-gate {"static", K_STATIC}, 1597c478bd9Sstevel@tonic-gate #define K_XRESOLVE 40 1607c478bd9Sstevel@tonic-gate {"xresolve", K_XRESOLVE}, 1617c478bd9Sstevel@tonic-gate #define K_MULTIRT 41 1627c478bd9Sstevel@tonic-gate {"multirt", K_MULTIRT}, 1637c478bd9Sstevel@tonic-gate #define K_SETSRC 42 1647c478bd9Sstevel@tonic-gate {"setsrc", K_SETSRC}, 1657c478bd9Sstevel@tonic-gate {0, 0} 1667c478bd9Sstevel@tonic-gate }; 1677c478bd9Sstevel@tonic-gate 1687a23074eSdduvall static union sockunion { 1697c478bd9Sstevel@tonic-gate struct sockaddr sa; 1707c478bd9Sstevel@tonic-gate struct sockaddr_in sin; 1717c478bd9Sstevel@tonic-gate struct sockaddr_dl sdl; 1727c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin6; 1737a23074eSdduvall } so_dst, so_gate, so_mask, so_ifa, so_ifp, so_src; 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate typedef struct mib_item_s { 1767c478bd9Sstevel@tonic-gate struct mib_item_s *next_item; 1777c478bd9Sstevel@tonic-gate long group; 1787c478bd9Sstevel@tonic-gate long mib_id; 1797c478bd9Sstevel@tonic-gate long length; 1807c478bd9Sstevel@tonic-gate intmax_t *valp; 1817c478bd9Sstevel@tonic-gate } mib_item_t; 1827c478bd9Sstevel@tonic-gate 1837a23074eSdduvall typedef union sockunion *sup; 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate static void bprintf(FILE *fp, int b, char *s); 1867c478bd9Sstevel@tonic-gate static void delRouteEntry(mib2_ipRouteEntry_t *rp, 1877c478bd9Sstevel@tonic-gate mib2_ipv6RouteEntry_t *rp6, int seqno); 1887c478bd9Sstevel@tonic-gate static void flushroutes(int argc, char *argv[]); 1897a23074eSdduvall static boolean_t getaddr(int which, char *s, struct hostent **hpp); 1907c478bd9Sstevel@tonic-gate static boolean_t in6_getaddr(char *s, struct sockaddr_in6 *sin6, 1917c478bd9Sstevel@tonic-gate int *plenp, struct hostent **hpp); 1927c478bd9Sstevel@tonic-gate static boolean_t in_getaddr(char *s, struct sockaddr_in *sin, 1937a23074eSdduvall int *plenp, int which, struct hostent **hpp); 1947c478bd9Sstevel@tonic-gate static int in_getprefixlen(char *addr, int max_plen); 1957c478bd9Sstevel@tonic-gate static boolean_t in_prefixlentomask(int prefixlen, int maxlen, 1967c478bd9Sstevel@tonic-gate uchar_t *mask); 1977a23074eSdduvall static void inet_makenetandmask(in_addr_t net, 1987c478bd9Sstevel@tonic-gate struct sockaddr_in *sin); 1997c478bd9Sstevel@tonic-gate static in_addr_t inet_makesubnetmask(in_addr_t addr, in_addr_t mask); 2007c478bd9Sstevel@tonic-gate static int keyword(char *cp); 2017c478bd9Sstevel@tonic-gate static void link_addr(const char *addr, struct sockaddr_dl *sdl); 2027c478bd9Sstevel@tonic-gate static char *link_ntoa(const struct sockaddr_dl *sdl); 2037c478bd9Sstevel@tonic-gate static mib_item_t *mibget(int sd); 2047c478bd9Sstevel@tonic-gate static char *netname(struct sockaddr *sa); 2057a23074eSdduvall static int newroute(int argc, char **argv); 2067c478bd9Sstevel@tonic-gate static void pmsg_addrs(char *cp, int addrs); 2077c478bd9Sstevel@tonic-gate static void pmsg_common(struct rt_msghdr *rtm); 2087a23074eSdduvall static void print_getmsg(struct rt_msghdr *rtm, int msglen); 2097c478bd9Sstevel@tonic-gate static void print_rtmsg(struct rt_msghdr *rtm, int msglen); 210*aee32e3dScarlsonj static void quit(char *s, int err) __NORETURN; 2117c478bd9Sstevel@tonic-gate static char *routename(struct sockaddr *sa); 2127c478bd9Sstevel@tonic-gate static void rtmonitor(int argc, char *argv[]); 2137a23074eSdduvall static int rtmsg(int cmd, int flags); 2147c478bd9Sstevel@tonic-gate static int salen(struct sockaddr *sa); 2157a23074eSdduvall static void set_metric(char *value, int key); 2167c478bd9Sstevel@tonic-gate static void sockaddr(char *addr, struct sockaddr *sa); 2177a23074eSdduvall static void sodump(sup su, char *which); 2187c478bd9Sstevel@tonic-gate static void usage(char *cp); 2197c478bd9Sstevel@tonic-gate 2207a23074eSdduvall static int pid, rtm_addrs; 2217c478bd9Sstevel@tonic-gate static int s; 2227a23074eSdduvall static boolean_t forcehost, forcenet, nflag; 2237c478bd9Sstevel@tonic-gate static int af = AF_INET; 2247c478bd9Sstevel@tonic-gate static boolean_t qflag, tflag; 2257a23074eSdduvall static boolean_t iflag, verbose; 2267a23074eSdduvall static boolean_t locking, lockrest, debugonly; 2277c478bd9Sstevel@tonic-gate static boolean_t fflag; 2287a23074eSdduvall static struct rt_metrics rt_metrics; 2297a23074eSdduvall static ulong_t rtm_inits; 2307a23074eSdduvall static int masklen; 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate static struct { 2337c478bd9Sstevel@tonic-gate struct rt_msghdr m_rtm; 2347c478bd9Sstevel@tonic-gate char m_space[512]; 2357c478bd9Sstevel@tonic-gate } m_rtmsg; 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate /* 2387c478bd9Sstevel@tonic-gate * Sizes of data structures extracted from the base mib. 2397c478bd9Sstevel@tonic-gate * This allows the size of the tables entries to grow while preserving 2407c478bd9Sstevel@tonic-gate * binary compatibility. 2417c478bd9Sstevel@tonic-gate */ 2427c478bd9Sstevel@tonic-gate static int ipRouteEntrySize; 2437c478bd9Sstevel@tonic-gate static int ipv6RouteEntrySize; 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate #define ROUNDUP_LONG(a) \ 2467c478bd9Sstevel@tonic-gate ((a) > 0 ? (1 + (((a) - 1) | (sizeof (long) - 1))) : sizeof (long)) 2477c478bd9Sstevel@tonic-gate #define ADVANCE(x, n) ((x) += ROUNDUP_LONG(salen(n))) 2487c478bd9Sstevel@tonic-gate #define C(x) ((x) & 0xff) 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate /* 2517c478bd9Sstevel@tonic-gate * return values from in_getprefixlen() 2527c478bd9Sstevel@tonic-gate */ 2537c478bd9Sstevel@tonic-gate #define BAD_ADDR -1 /* prefix is invalid */ 2547c478bd9Sstevel@tonic-gate #define NO_PREFIX -2 /* no prefix was found */ 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate void 2577c478bd9Sstevel@tonic-gate usage(char *cp) 2587c478bd9Sstevel@tonic-gate { 2597a23074eSdduvall if (cp != NULL) 2607c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("route: botched keyword: %s\n"), 2617c478bd9Sstevel@tonic-gate cp); 2627a23074eSdduvall (void) fprintf(stderr, 2637a23074eSdduvall gettext("usage: route [ -fnqv ] cmd [[ -<qualifers> ] args ]\n")); 2647c478bd9Sstevel@tonic-gate exit(1); 2657c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2667c478bd9Sstevel@tonic-gate } 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate void 2697c478bd9Sstevel@tonic-gate quit(char *s, int sverrno) 2707c478bd9Sstevel@tonic-gate { 2717c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "route: "); 2727c478bd9Sstevel@tonic-gate if (s != NULL) 2737c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", s); 2747c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s\n", strerror(sverrno)); 2757c478bd9Sstevel@tonic-gate exit(sverrno); 2767c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2777c478bd9Sstevel@tonic-gate } 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate int 2807c478bd9Sstevel@tonic-gate main(int argc, char **argv) 2817c478bd9Sstevel@tonic-gate { 2827c478bd9Sstevel@tonic-gate extern int optind; 2837c478bd9Sstevel@tonic-gate int ch; 2847c478bd9Sstevel@tonic-gate int key; 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 2897c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 2907c478bd9Sstevel@tonic-gate #endif 2917c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate if (argc < 2) 2947c478bd9Sstevel@tonic-gate usage((char *)NULL); 2957c478bd9Sstevel@tonic-gate 2967a23074eSdduvall while ((ch = getopt(argc, argv, "nqdtvf")) != EOF) { 2977c478bd9Sstevel@tonic-gate switch (ch) { 2987c478bd9Sstevel@tonic-gate case 'n': 2997c478bd9Sstevel@tonic-gate nflag = B_TRUE; 3007c478bd9Sstevel@tonic-gate break; 3017c478bd9Sstevel@tonic-gate case 'q': 3027c478bd9Sstevel@tonic-gate qflag = B_TRUE; 3037c478bd9Sstevel@tonic-gate break; 3047c478bd9Sstevel@tonic-gate case 'v': 3057c478bd9Sstevel@tonic-gate verbose = B_TRUE; 3067c478bd9Sstevel@tonic-gate break; 3077c478bd9Sstevel@tonic-gate case 't': 3087c478bd9Sstevel@tonic-gate tflag = B_TRUE; 3097c478bd9Sstevel@tonic-gate break; 3107c478bd9Sstevel@tonic-gate case 'd': 3117c478bd9Sstevel@tonic-gate debugonly = B_TRUE; 3127c478bd9Sstevel@tonic-gate break; 3137c478bd9Sstevel@tonic-gate case 'f': 3147c478bd9Sstevel@tonic-gate fflag = B_TRUE; 3157c478bd9Sstevel@tonic-gate break; 3167c478bd9Sstevel@tonic-gate case '?': 3177c478bd9Sstevel@tonic-gate default: 3187c478bd9Sstevel@tonic-gate usage((char *)NULL); 3197c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3207c478bd9Sstevel@tonic-gate } 3217c478bd9Sstevel@tonic-gate } 3227c478bd9Sstevel@tonic-gate argc -= optind; 3237c478bd9Sstevel@tonic-gate argv += optind; 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate pid = getpid(); 3267c478bd9Sstevel@tonic-gate if (tflag) 3277c478bd9Sstevel@tonic-gate s = open("/dev/null", O_WRONLY); 3287c478bd9Sstevel@tonic-gate else 3297c478bd9Sstevel@tonic-gate s = socket(PF_ROUTE, SOCK_RAW, 0); 3307c478bd9Sstevel@tonic-gate if (s < 0) 3317c478bd9Sstevel@tonic-gate quit("socket", errno); 3327c478bd9Sstevel@tonic-gate if (fflag) { 3337c478bd9Sstevel@tonic-gate /* 3347c478bd9Sstevel@tonic-gate * Accept an address family keyword after the -f. Since the 3357c478bd9Sstevel@tonic-gate * default address family is AF_INET, reassign af only for the 3367c478bd9Sstevel@tonic-gate * other valid address families. 3377c478bd9Sstevel@tonic-gate */ 3387c478bd9Sstevel@tonic-gate if (*argv != NULL) { 3397c478bd9Sstevel@tonic-gate switch (key = keyword(*argv)) { 3407c478bd9Sstevel@tonic-gate case K_INET: 3417c478bd9Sstevel@tonic-gate case K_INET6: 3427c478bd9Sstevel@tonic-gate if (key == K_INET6) 3437c478bd9Sstevel@tonic-gate af = AF_INET6; 3447c478bd9Sstevel@tonic-gate /* Skip over the address family parameter. */ 3457c478bd9Sstevel@tonic-gate argc--; 3467c478bd9Sstevel@tonic-gate argv++; 3477c478bd9Sstevel@tonic-gate break; 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate flushroutes(0, NULL); 3517c478bd9Sstevel@tonic-gate } 3527c478bd9Sstevel@tonic-gate if (*argv != NULL) { 3537c478bd9Sstevel@tonic-gate switch (keyword(*argv)) { 3547c478bd9Sstevel@tonic-gate case K_GET: 3557c478bd9Sstevel@tonic-gate case K_CHANGE: 3567c478bd9Sstevel@tonic-gate case K_ADD: 3577c478bd9Sstevel@tonic-gate case K_DELETE: 3587a23074eSdduvall return (newroute(argc, argv)); 3597a23074eSdduvall 3607c478bd9Sstevel@tonic-gate case K_MONITOR: 3617c478bd9Sstevel@tonic-gate rtmonitor(argc, argv); 3627c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate case K_FLUSH: 3657c478bd9Sstevel@tonic-gate flushroutes(argc, argv); 3667a23074eSdduvall exit(0); 3677a23074eSdduvall /* NOTREACHED */ 3687c478bd9Sstevel@tonic-gate } 3697c478bd9Sstevel@tonic-gate } 3707c478bd9Sstevel@tonic-gate if (!fflag) 3717c478bd9Sstevel@tonic-gate usage(*argv); 3727c478bd9Sstevel@tonic-gate return (0); 3737c478bd9Sstevel@tonic-gate } 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate /* 3767c478bd9Sstevel@tonic-gate * Purge all entries in the routing tables not 3777c478bd9Sstevel@tonic-gate * associated with network interfaces. 3787c478bd9Sstevel@tonic-gate */ 3797c478bd9Sstevel@tonic-gate void 3807c478bd9Sstevel@tonic-gate flushroutes(int argc, char *argv[]) 3817c478bd9Sstevel@tonic-gate { 3827c478bd9Sstevel@tonic-gate int seqno; 3837c478bd9Sstevel@tonic-gate int sd; /* mib stream */ 3847c478bd9Sstevel@tonic-gate mib_item_t *item; 3857c478bd9Sstevel@tonic-gate mib2_ipRouteEntry_t *rp; 3867c478bd9Sstevel@tonic-gate mib2_ipv6RouteEntry_t *rp6; 3877c478bd9Sstevel@tonic-gate int oerrno; 3887c478bd9Sstevel@tonic-gate int off = 0; 3897c478bd9Sstevel@tonic-gate int on = 1; 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate if (setsockopt(s, SOL_SOCKET, SO_USELOOPBACK, (char *)&off, 3927c478bd9Sstevel@tonic-gate sizeof (off)) < 0) 3937c478bd9Sstevel@tonic-gate quit("setsockopt", errno); 3947c478bd9Sstevel@tonic-gate if (argc > 1) { 3957c478bd9Sstevel@tonic-gate argv++; 3967c478bd9Sstevel@tonic-gate if (argc == 2 && **argv == '-') { 3977c478bd9Sstevel@tonic-gate /* 3987c478bd9Sstevel@tonic-gate * The address family (preceded by a dash) may be used 3997c478bd9Sstevel@tonic-gate * to flush the routes of that particular family. 4007c478bd9Sstevel@tonic-gate */ 4017c478bd9Sstevel@tonic-gate switch (keyword(*argv + 1)) { 4027c478bd9Sstevel@tonic-gate case K_INET: 4037c478bd9Sstevel@tonic-gate af = AF_INET; 4047c478bd9Sstevel@tonic-gate break; 4057c478bd9Sstevel@tonic-gate case K_LINK: 4067c478bd9Sstevel@tonic-gate af = AF_LINK; 4077c478bd9Sstevel@tonic-gate break; 4087c478bd9Sstevel@tonic-gate case K_INET6: 4097c478bd9Sstevel@tonic-gate af = AF_INET6; 4107c478bd9Sstevel@tonic-gate break; 4117c478bd9Sstevel@tonic-gate default: 4127c478bd9Sstevel@tonic-gate usage(*argv); 4137c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4147c478bd9Sstevel@tonic-gate } 4157c478bd9Sstevel@tonic-gate } else { 4167c478bd9Sstevel@tonic-gate usage(*argv); 4177c478bd9Sstevel@tonic-gate } 4187c478bd9Sstevel@tonic-gate } 4197c478bd9Sstevel@tonic-gate sd = open("/dev/ip", O_RDWR); 4207c478bd9Sstevel@tonic-gate oerrno = errno; 4217c478bd9Sstevel@tonic-gate if (sd < 0) { 4227c478bd9Sstevel@tonic-gate switch (errno) { 4237c478bd9Sstevel@tonic-gate case EACCES: 4247c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 4257c478bd9Sstevel@tonic-gate gettext("route: flush: insufficient privileges\n")); 4267c478bd9Sstevel@tonic-gate exit(oerrno); 4277c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4287c478bd9Sstevel@tonic-gate default: 4297c478bd9Sstevel@tonic-gate quit(gettext("can't open mib stream"), oerrno); 4307c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4317c478bd9Sstevel@tonic-gate } 4327c478bd9Sstevel@tonic-gate } 4337c478bd9Sstevel@tonic-gate if ((item = mibget(sd)) == NULL) 4347c478bd9Sstevel@tonic-gate quit("mibget", errno); 4357c478bd9Sstevel@tonic-gate if (verbose) { 4367c478bd9Sstevel@tonic-gate (void) printf("Examining routing table from " 4377c478bd9Sstevel@tonic-gate "T_SVR4_OPTMGMT_REQ\n"); 4387c478bd9Sstevel@tonic-gate } 4397c478bd9Sstevel@tonic-gate seqno = 0; /* ??? */ 4407c478bd9Sstevel@tonic-gate switch (af) { 4417c478bd9Sstevel@tonic-gate case AF_INET: 4427c478bd9Sstevel@tonic-gate /* Extract ipRouteEntrySize */ 4437c478bd9Sstevel@tonic-gate for (; item != NULL; item = item->next_item) { 4447c478bd9Sstevel@tonic-gate if (item->mib_id != 0) 4457c478bd9Sstevel@tonic-gate continue; 4467c478bd9Sstevel@tonic-gate if (item->group == MIB2_IP) { 4477c478bd9Sstevel@tonic-gate ipRouteEntrySize = 4487c478bd9Sstevel@tonic-gate ((mib2_ip_t *)item->valp)->ipRouteEntrySize; 4497c478bd9Sstevel@tonic-gate assert(IS_P2ALIGNED(ipRouteEntrySize, 4507c478bd9Sstevel@tonic-gate sizeof (mib2_ipRouteEntry_t *))); 4517c478bd9Sstevel@tonic-gate break; 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate } 4547c478bd9Sstevel@tonic-gate if (ipRouteEntrySize == 0) { 4557c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 4567c478bd9Sstevel@tonic-gate gettext("ipRouteEntrySize can't be determined.\n")); 4577c478bd9Sstevel@tonic-gate exit(1); 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate for (; item != NULL; item = item->next_item) { 4607c478bd9Sstevel@tonic-gate /* 4617c478bd9Sstevel@tonic-gate * skip all the other trash that comes up the mib stream 4627c478bd9Sstevel@tonic-gate */ 4637c478bd9Sstevel@tonic-gate if (item->group != MIB2_IP || 4647c478bd9Sstevel@tonic-gate item->mib_id != MIB2_IP_ROUTE) 4657c478bd9Sstevel@tonic-gate continue; 4667c478bd9Sstevel@tonic-gate for (rp = (mib2_ipRouteEntry_t *)item->valp; 4677c478bd9Sstevel@tonic-gate (char *)rp < (char *)item->valp + item->length; 4687c478bd9Sstevel@tonic-gate /* LINTED */ 4697c478bd9Sstevel@tonic-gate rp = (mib2_ipRouteEntry_t *) 4707c478bd9Sstevel@tonic-gate ((char *)rp + ipRouteEntrySize)) { 4717c478bd9Sstevel@tonic-gate delRouteEntry(rp, NULL, seqno); 4727c478bd9Sstevel@tonic-gate seqno++; 4737c478bd9Sstevel@tonic-gate } 4747c478bd9Sstevel@tonic-gate break; 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate break; 4777c478bd9Sstevel@tonic-gate case AF_INET6: 4787c478bd9Sstevel@tonic-gate /* Extract ipv6RouteEntrySize */ 4797c478bd9Sstevel@tonic-gate for (; item != NULL; item = item->next_item) { 4807c478bd9Sstevel@tonic-gate if (item->mib_id != 0) 4817c478bd9Sstevel@tonic-gate continue; 4827c478bd9Sstevel@tonic-gate if (item->group == MIB2_IP6) { 4837c478bd9Sstevel@tonic-gate ipv6RouteEntrySize = 4847c478bd9Sstevel@tonic-gate ((mib2_ipv6IfStatsEntry_t *)item->valp)-> 4857c478bd9Sstevel@tonic-gate ipv6RouteEntrySize; 4867c478bd9Sstevel@tonic-gate assert(IS_P2ALIGNED(ipv6RouteEntrySize, 4877c478bd9Sstevel@tonic-gate sizeof (mib2_ipv6RouteEntry_t *))); 4887c478bd9Sstevel@tonic-gate break; 4897c478bd9Sstevel@tonic-gate } 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate if (ipv6RouteEntrySize == 0) { 4927c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4937c478bd9Sstevel@tonic-gate "ipv6RouteEntrySize cannot be determined.\n")); 4947c478bd9Sstevel@tonic-gate exit(1); 4957c478bd9Sstevel@tonic-gate } 4967c478bd9Sstevel@tonic-gate for (; item != NULL; item = item->next_item) { 4977c478bd9Sstevel@tonic-gate /* 4987c478bd9Sstevel@tonic-gate * skip all the other trash that comes up the mib stream 4997c478bd9Sstevel@tonic-gate */ 5007c478bd9Sstevel@tonic-gate if (item->group != MIB2_IP6 || 5017c478bd9Sstevel@tonic-gate item->mib_id != MIB2_IP6_ROUTE) 5027c478bd9Sstevel@tonic-gate continue; 5037c478bd9Sstevel@tonic-gate for (rp6 = (mib2_ipv6RouteEntry_t *)item->valp; 5047c478bd9Sstevel@tonic-gate (char *)rp6 < (char *)item->valp + item->length; 5057c478bd9Sstevel@tonic-gate /* LINTED */ 5067c478bd9Sstevel@tonic-gate rp6 = (mib2_ipv6RouteEntry_t *) 5077c478bd9Sstevel@tonic-gate ((char *)rp6 + ipv6RouteEntrySize)) { 5087c478bd9Sstevel@tonic-gate delRouteEntry(NULL, rp6, seqno); 5097c478bd9Sstevel@tonic-gate seqno++; 5107c478bd9Sstevel@tonic-gate } 5117c478bd9Sstevel@tonic-gate break; 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate break; 5147c478bd9Sstevel@tonic-gate } 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate if (setsockopt(s, SOL_SOCKET, SO_USELOOPBACK, (char *)&on, 5177c478bd9Sstevel@tonic-gate sizeof (on)) < 0) 5187c478bd9Sstevel@tonic-gate quit("setsockopt", errno); 5197c478bd9Sstevel@tonic-gate } 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate /* 5227c478bd9Sstevel@tonic-gate * Given the contents of a mib_item_t of id type MIB2_IP_ROUTE or 5237c478bd9Sstevel@tonic-gate * MIB2_IP6_ROUTE, construct and send an RTM_DELETE routing socket message in 5247c478bd9Sstevel@tonic-gate * order to facilitate the flushing of RTF_GATEWAY routes. 5257c478bd9Sstevel@tonic-gate */ 5267c478bd9Sstevel@tonic-gate static void 5277c478bd9Sstevel@tonic-gate delRouteEntry(mib2_ipRouteEntry_t *rp, mib2_ipv6RouteEntry_t *rp6, int seqno) 5287c478bd9Sstevel@tonic-gate { 5297c478bd9Sstevel@tonic-gate char *cp; 5307c478bd9Sstevel@tonic-gate int ire_type; 5317c478bd9Sstevel@tonic-gate int rlen; 5327c478bd9Sstevel@tonic-gate struct rt_msghdr *rtm; 5337c478bd9Sstevel@tonic-gate struct sockaddr_in sin; 5347c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin6; 5357c478bd9Sstevel@tonic-gate int slen; 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate if (rp != NULL) 5387c478bd9Sstevel@tonic-gate ire_type = rp->ipRouteInfo.re_ire_type; 5397c478bd9Sstevel@tonic-gate else 5407c478bd9Sstevel@tonic-gate ire_type = rp6->ipv6RouteInfo.re_ire_type; 5417c478bd9Sstevel@tonic-gate if (ire_type != IRE_DEFAULT && 5427c478bd9Sstevel@tonic-gate ire_type != IRE_PREFIX && 5437c478bd9Sstevel@tonic-gate ire_type != IRE_HOST && 5447c478bd9Sstevel@tonic-gate ire_type != IRE_HOST_REDIRECT) 5457c478bd9Sstevel@tonic-gate return; 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate rtm = &m_rtmsg.m_rtm; 5487c478bd9Sstevel@tonic-gate (void) memset(rtm, 0, sizeof (m_rtmsg)); 5497c478bd9Sstevel@tonic-gate rtm->rtm_type = RTM_DELETE; 5507c478bd9Sstevel@tonic-gate rtm->rtm_seq = seqno; 5517c478bd9Sstevel@tonic-gate rtm->rtm_flags |= RTF_GATEWAY; 5527c478bd9Sstevel@tonic-gate rtm->rtm_version = RTM_VERSION; 5537c478bd9Sstevel@tonic-gate rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 5547c478bd9Sstevel@tonic-gate cp = m_rtmsg.m_space; 5557c478bd9Sstevel@tonic-gate if (rp != NULL) { 5567c478bd9Sstevel@tonic-gate slen = sizeof (struct sockaddr_in); 5577c478bd9Sstevel@tonic-gate if (rp->ipRouteMask == IP_HOST_MASK) 5587c478bd9Sstevel@tonic-gate rtm->rtm_flags |= RTF_HOST; 5597c478bd9Sstevel@tonic-gate (void) memset(&sin, 0, slen); 5607c478bd9Sstevel@tonic-gate sin.sin_family = AF_INET; 5617c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = rp->ipRouteDest; 5627c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin, slen); 5637c478bd9Sstevel@tonic-gate cp += slen; 5647c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = rp->ipRouteNextHop; 5657c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin, slen); 5667c478bd9Sstevel@tonic-gate cp += slen; 5677c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = rp->ipRouteMask; 5687c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin, slen); 5697c478bd9Sstevel@tonic-gate cp += slen; 5707c478bd9Sstevel@tonic-gate } else { 5717c478bd9Sstevel@tonic-gate slen = sizeof (struct sockaddr_in6); 5727c478bd9Sstevel@tonic-gate if (rp6->ipv6RoutePfxLength == IPV6_ABITS) 5737c478bd9Sstevel@tonic-gate rtm->rtm_flags |= RTF_HOST; 5747c478bd9Sstevel@tonic-gate (void) memset(&sin6, 0, slen); 5757c478bd9Sstevel@tonic-gate sin6.sin6_family = AF_INET6; 5767c478bd9Sstevel@tonic-gate sin6.sin6_addr = rp6->ipv6RouteDest; 5777c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin6, slen); 5787c478bd9Sstevel@tonic-gate cp += slen; 5797c478bd9Sstevel@tonic-gate sin6.sin6_addr = rp6->ipv6RouteNextHop; 5807c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin6, slen); 5817c478bd9Sstevel@tonic-gate cp += slen; 5827c478bd9Sstevel@tonic-gate (void) memset(&sin6.sin6_addr, 0, sizeof (sin6.sin6_addr)); 5837c478bd9Sstevel@tonic-gate (void) in_prefixlentomask(rp6->ipv6RoutePfxLength, IPV6_ABITS, 5847c478bd9Sstevel@tonic-gate (uchar_t *)&sin6.sin6_addr.s6_addr); 5857c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin6, slen); 5867c478bd9Sstevel@tonic-gate cp += slen; 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate rtm->rtm_msglen = cp - (char *)&m_rtmsg; 5897c478bd9Sstevel@tonic-gate if (debugonly) { 5907c478bd9Sstevel@tonic-gate /* 5917c478bd9Sstevel@tonic-gate * In debugonly mode, the routing socket message to delete the 5927c478bd9Sstevel@tonic-gate * current entry is not actually sent. However if verbose is 5937c478bd9Sstevel@tonic-gate * also set, the routing socket message that would have been 5947c478bd9Sstevel@tonic-gate * is printed. 5957c478bd9Sstevel@tonic-gate */ 5967c478bd9Sstevel@tonic-gate if (verbose) 5977c478bd9Sstevel@tonic-gate print_rtmsg(rtm, rtm->rtm_msglen); 5987c478bd9Sstevel@tonic-gate return; 5997c478bd9Sstevel@tonic-gate } 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate rlen = write(s, (char *)&m_rtmsg, rtm->rtm_msglen); 6027c478bd9Sstevel@tonic-gate if (rlen < (int)rtm->rtm_msglen) { 6037c478bd9Sstevel@tonic-gate if (rlen < 0) { 6047c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 6057c478bd9Sstevel@tonic-gate gettext("route: write to routing socket: %s\n"), 6067c478bd9Sstevel@tonic-gate strerror(errno)); 6077c478bd9Sstevel@tonic-gate } else { 6087c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("route: write to " 6097c478bd9Sstevel@tonic-gate "routing socket got only %d for rlen\n"), rlen); 6107c478bd9Sstevel@tonic-gate } 6117c478bd9Sstevel@tonic-gate return; 6127c478bd9Sstevel@tonic-gate } 6137c478bd9Sstevel@tonic-gate if (qflag) { 6147c478bd9Sstevel@tonic-gate /* 6157c478bd9Sstevel@tonic-gate * In quiet mode, nothing is printed at all (unless the write() 6167c478bd9Sstevel@tonic-gate * itself failed. 6177c478bd9Sstevel@tonic-gate */ 6187c478bd9Sstevel@tonic-gate return; 6197c478bd9Sstevel@tonic-gate } 6207c478bd9Sstevel@tonic-gate if (verbose) { 6217c478bd9Sstevel@tonic-gate print_rtmsg(rtm, rlen); 6227c478bd9Sstevel@tonic-gate } else { 6237c478bd9Sstevel@tonic-gate struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate (void) printf("%-20.20s ", 6267c478bd9Sstevel@tonic-gate rtm->rtm_flags & RTF_HOST ? routename(sa) : 6277c478bd9Sstevel@tonic-gate netname(sa)); 6287c478bd9Sstevel@tonic-gate /* LINTED */ 6297c478bd9Sstevel@tonic-gate sa = (struct sockaddr *)(salen(sa) + (char *)sa); 6307c478bd9Sstevel@tonic-gate (void) printf("%-20.20s ", routename(sa)); 6317c478bd9Sstevel@tonic-gate (void) printf("done\n"); 6327c478bd9Sstevel@tonic-gate } 6337c478bd9Sstevel@tonic-gate } 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate /* 6367c478bd9Sstevel@tonic-gate * Return the name of the host whose address is given. 6377c478bd9Sstevel@tonic-gate */ 6387c478bd9Sstevel@tonic-gate char * 6397c478bd9Sstevel@tonic-gate routename(struct sockaddr *sa) 6407c478bd9Sstevel@tonic-gate { 6417c478bd9Sstevel@tonic-gate char *cp; 6427c478bd9Sstevel@tonic-gate static char line[MAXHOSTNAMELEN + 1]; 6437c478bd9Sstevel@tonic-gate struct hostent *hp = NULL; 6447c478bd9Sstevel@tonic-gate static char domain[MAXHOSTNAMELEN + 1]; 6457c478bd9Sstevel@tonic-gate static boolean_t first = B_TRUE; 6467c478bd9Sstevel@tonic-gate struct in_addr in; 6477c478bd9Sstevel@tonic-gate struct in6_addr in6; 6487c478bd9Sstevel@tonic-gate int error_num; 6497c478bd9Sstevel@tonic-gate ushort_t *s; 6507c478bd9Sstevel@tonic-gate ushort_t *slim; 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate if (first) { 6537c478bd9Sstevel@tonic-gate first = B_FALSE; 6547c478bd9Sstevel@tonic-gate if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 6557c478bd9Sstevel@tonic-gate (cp = strchr(domain, '.'))) 6567c478bd9Sstevel@tonic-gate (void) strcpy(domain, cp + 1); 6577c478bd9Sstevel@tonic-gate else 6587c478bd9Sstevel@tonic-gate domain[0] = 0; 6597c478bd9Sstevel@tonic-gate } 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate if (salen(sa) == 0) { 6627c478bd9Sstevel@tonic-gate (void) strcpy(line, "default"); 6637c478bd9Sstevel@tonic-gate return (line); 6647c478bd9Sstevel@tonic-gate } 6657c478bd9Sstevel@tonic-gate switch (sa->sa_family) { 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate case AF_INET: 6687c478bd9Sstevel@tonic-gate /* LINTED */ 6697c478bd9Sstevel@tonic-gate in = ((struct sockaddr_in *)sa)->sin_addr; 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate cp = NULL; 6727c478bd9Sstevel@tonic-gate if (in.s_addr == INADDR_ANY) 6737c478bd9Sstevel@tonic-gate cp = "default"; 6747c478bd9Sstevel@tonic-gate if (cp == NULL && !nflag) { 6757c478bd9Sstevel@tonic-gate hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), 6767c478bd9Sstevel@tonic-gate AF_INET); 6777c478bd9Sstevel@tonic-gate if (hp != NULL) { 6787c478bd9Sstevel@tonic-gate if (((cp = strchr(hp->h_name, '.')) != NULL) && 6797c478bd9Sstevel@tonic-gate (strcmp(cp + 1, domain) == 0)) 6807c478bd9Sstevel@tonic-gate *cp = 0; 6817c478bd9Sstevel@tonic-gate cp = hp->h_name; 6827c478bd9Sstevel@tonic-gate } 6837c478bd9Sstevel@tonic-gate } 6847c478bd9Sstevel@tonic-gate if (cp != NULL) { 6857c478bd9Sstevel@tonic-gate (void) strncpy(line, cp, MAXHOSTNAMELEN); 6867c478bd9Sstevel@tonic-gate line[MAXHOSTNAMELEN] = '\0'; 6877c478bd9Sstevel@tonic-gate } else { 6887c478bd9Sstevel@tonic-gate in.s_addr = ntohl(in.s_addr); 6897c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 6907c478bd9Sstevel@tonic-gate C(in.s_addr >> 16), C(in.s_addr >> 8), 6917c478bd9Sstevel@tonic-gate C(in.s_addr)); 6927c478bd9Sstevel@tonic-gate } 6937c478bd9Sstevel@tonic-gate break; 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate case AF_LINK: 6967c478bd9Sstevel@tonic-gate return (link_ntoa((struct sockaddr_dl *)sa)); 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate case AF_INET6: 6997c478bd9Sstevel@tonic-gate /* LINTED */ 7007c478bd9Sstevel@tonic-gate in6 = ((struct sockaddr_in6 *)sa)->sin6_addr; 7017c478bd9Sstevel@tonic-gate 7027c478bd9Sstevel@tonic-gate cp = NULL; 7037c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&in6)) 7047c478bd9Sstevel@tonic-gate cp = "default"; 7057c478bd9Sstevel@tonic-gate if (cp == NULL && !nflag) { 7067c478bd9Sstevel@tonic-gate hp = getipnodebyaddr((char *)&in6, 7077c478bd9Sstevel@tonic-gate sizeof (struct in6_addr), AF_INET6, &error_num); 7087c478bd9Sstevel@tonic-gate if (hp != NULL) { 7097c478bd9Sstevel@tonic-gate if (((cp = strchr(hp->h_name, '.')) != NULL) && 7107c478bd9Sstevel@tonic-gate (strcmp(cp + 1, domain) == 0)) 7117c478bd9Sstevel@tonic-gate *cp = 0; 7127c478bd9Sstevel@tonic-gate cp = hp->h_name; 7137c478bd9Sstevel@tonic-gate } 7147c478bd9Sstevel@tonic-gate } 7157c478bd9Sstevel@tonic-gate if (cp != NULL) { 7167c478bd9Sstevel@tonic-gate (void) strncpy(line, cp, MAXHOSTNAMELEN); 7177c478bd9Sstevel@tonic-gate line[MAXHOSTNAMELEN] = '\0'; 7187c478bd9Sstevel@tonic-gate } else { 7197c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&in6, line, 7207c478bd9Sstevel@tonic-gate INET6_ADDRSTRLEN); 7217c478bd9Sstevel@tonic-gate } 7227c478bd9Sstevel@tonic-gate if (hp != NULL) 7237c478bd9Sstevel@tonic-gate freehostent(hp); 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate break; 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate default: 7287c478bd9Sstevel@tonic-gate s = (ushort_t *)sa; 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate slim = s + ((salen(sa) + 1) >> 1); 7317c478bd9Sstevel@tonic-gate cp = line + sprintf(line, "(%d)", sa->sa_family); 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate while (++s < slim) /* start with sa->sa_data */ 7347c478bd9Sstevel@tonic-gate cp += sprintf(cp, " %x", *s); 7357c478bd9Sstevel@tonic-gate break; 7367c478bd9Sstevel@tonic-gate } 7377c478bd9Sstevel@tonic-gate return (line); 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate /* 7417c478bd9Sstevel@tonic-gate * Return the name of the network whose address is given. 7427c478bd9Sstevel@tonic-gate * The address is assumed to be that of a net or subnet, not a host. 7437c478bd9Sstevel@tonic-gate */ 7447c478bd9Sstevel@tonic-gate static char * 7457c478bd9Sstevel@tonic-gate netname(struct sockaddr *sa) 7467c478bd9Sstevel@tonic-gate { 7477c478bd9Sstevel@tonic-gate char *cp = NULL; 7487c478bd9Sstevel@tonic-gate static char line[MAXHOSTNAMELEN + 1]; 7497c478bd9Sstevel@tonic-gate struct netent *np; 7507c478bd9Sstevel@tonic-gate in_addr_t net, mask; 7517c478bd9Sstevel@tonic-gate int subnetshift; 7527c478bd9Sstevel@tonic-gate struct in_addr in; 7537c478bd9Sstevel@tonic-gate ushort_t *s; 7547c478bd9Sstevel@tonic-gate ushort_t *slim; 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate switch (sa->sa_family) { 7577c478bd9Sstevel@tonic-gate 7587c478bd9Sstevel@tonic-gate case AF_INET: 7597c478bd9Sstevel@tonic-gate /* LINTED */ 7607c478bd9Sstevel@tonic-gate in = ((struct sockaddr_in *)sa)->sin_addr; 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate in.s_addr = ntohl(in.s_addr); 7637c478bd9Sstevel@tonic-gate if (in.s_addr == INADDR_ANY) { 7647c478bd9Sstevel@tonic-gate cp = "default"; 7657c478bd9Sstevel@tonic-gate } else if (!nflag) { 7667c478bd9Sstevel@tonic-gate if (IN_CLASSA(in.s_addr)) { 7677c478bd9Sstevel@tonic-gate mask = IN_CLASSA_NET; 7687c478bd9Sstevel@tonic-gate subnetshift = 8; 7697c478bd9Sstevel@tonic-gate } else if (IN_CLASSB(in.s_addr)) { 7707c478bd9Sstevel@tonic-gate mask = IN_CLASSB_NET; 7717c478bd9Sstevel@tonic-gate subnetshift = 8; 7727c478bd9Sstevel@tonic-gate } else { 7737c478bd9Sstevel@tonic-gate mask = IN_CLASSC_NET; 7747c478bd9Sstevel@tonic-gate subnetshift = 4; 7757c478bd9Sstevel@tonic-gate } 7767c478bd9Sstevel@tonic-gate /* 7777c478bd9Sstevel@tonic-gate * If there are more bits than the standard mask 7787c478bd9Sstevel@tonic-gate * would suggest, subnets must be in use. 7797c478bd9Sstevel@tonic-gate * Guess at the subnet mask, assuming reasonable 7807c478bd9Sstevel@tonic-gate * width subnet fields. 7817c478bd9Sstevel@tonic-gate */ 7827c478bd9Sstevel@tonic-gate while (in.s_addr &~ mask) 7837c478bd9Sstevel@tonic-gate mask = (long)mask >> subnetshift; 7847c478bd9Sstevel@tonic-gate net = in.s_addr & mask; 7857c478bd9Sstevel@tonic-gate while ((mask & 1) == 0) 7867c478bd9Sstevel@tonic-gate mask >>= 1, net >>= 1; 7877c478bd9Sstevel@tonic-gate np = getnetbyaddr(net, AF_INET); 7887c478bd9Sstevel@tonic-gate if (np != NULL) 7897c478bd9Sstevel@tonic-gate cp = np->n_name; 7907c478bd9Sstevel@tonic-gate } 7917c478bd9Sstevel@tonic-gate if (cp != NULL) { 7927c478bd9Sstevel@tonic-gate (void) strncpy(line, cp, MAXHOSTNAMELEN); 7937c478bd9Sstevel@tonic-gate line[MAXHOSTNAMELEN] = '\0'; 7947c478bd9Sstevel@tonic-gate } else if ((in.s_addr & 0xffffff) == 0) { 7957c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u", C(in.s_addr >> 24)); 7967c478bd9Sstevel@tonic-gate } else if ((in.s_addr & 0xffff) == 0) { 7977c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u.%u", C(in.s_addr >> 24), 7987c478bd9Sstevel@tonic-gate C(in.s_addr >> 16)); 7997c478bd9Sstevel@tonic-gate } else if ((in.s_addr & 0xff) == 0) { 8007c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24), 8017c478bd9Sstevel@tonic-gate C(in.s_addr >> 16), C(in.s_addr >> 8)); 8027c478bd9Sstevel@tonic-gate } else { 8037c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 8047c478bd9Sstevel@tonic-gate C(in.s_addr >> 16), C(in.s_addr >> 8), 8057c478bd9Sstevel@tonic-gate C(in.s_addr)); 8067c478bd9Sstevel@tonic-gate } 8077c478bd9Sstevel@tonic-gate break; 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate case AF_LINK: 8107c478bd9Sstevel@tonic-gate return (link_ntoa((struct sockaddr_dl *)sa)); 8117c478bd9Sstevel@tonic-gate 8127c478bd9Sstevel@tonic-gate case AF_INET6: 8137c478bd9Sstevel@tonic-gate return (routename(sa)); 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate default: 8167c478bd9Sstevel@tonic-gate /* LINTED */ 8177c478bd9Sstevel@tonic-gate s = (ushort_t *)sa->sa_data; 8187c478bd9Sstevel@tonic-gate 8197c478bd9Sstevel@tonic-gate slim = s + ((salen(sa) + 1) >> 1); 8207c478bd9Sstevel@tonic-gate cp = line + sprintf(line, "af %d:", sa->sa_family); 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate while (s < slim) 8237c478bd9Sstevel@tonic-gate cp += sprintf(cp, " %x", *s++); 8247c478bd9Sstevel@tonic-gate break; 8257c478bd9Sstevel@tonic-gate } 8267c478bd9Sstevel@tonic-gate return (line); 8277c478bd9Sstevel@tonic-gate } 8287c478bd9Sstevel@tonic-gate 8297c478bd9Sstevel@tonic-gate void 8307a23074eSdduvall set_metric(char *value, int key) 8317c478bd9Sstevel@tonic-gate { 8327c478bd9Sstevel@tonic-gate int flag = 0; 8337c478bd9Sstevel@tonic-gate uint_t noval, *valp = &noval; 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate switch (key) { 8367a23074eSdduvall #define caseof(x, y, z) case (x): valp = &rt_metrics.z; flag = (y); break 8377c478bd9Sstevel@tonic-gate caseof(K_MTU, RTV_MTU, rmx_mtu); 8387c478bd9Sstevel@tonic-gate caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount); 8397c478bd9Sstevel@tonic-gate caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire); 8407c478bd9Sstevel@tonic-gate caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe); 8417c478bd9Sstevel@tonic-gate caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe); 8427c478bd9Sstevel@tonic-gate caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh); 8437c478bd9Sstevel@tonic-gate caseof(K_RTT, RTV_RTT, rmx_rtt); 8447c478bd9Sstevel@tonic-gate caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar); 8457c478bd9Sstevel@tonic-gate #undef caseof 8467c478bd9Sstevel@tonic-gate } 8477a23074eSdduvall rtm_inits |= flag; 8487a23074eSdduvall if (lockrest || locking) 8497a23074eSdduvall rt_metrics.rmx_locks |= flag; 8507a23074eSdduvall if (locking) 8517a23074eSdduvall locking = B_FALSE; 8527c478bd9Sstevel@tonic-gate *valp = atoi(value); 8537c478bd9Sstevel@tonic-gate } 8547c478bd9Sstevel@tonic-gate 8557a23074eSdduvall int 8567a23074eSdduvall newroute(int argc, char **argv) 8577c478bd9Sstevel@tonic-gate { 8587a23074eSdduvall char *cmd, *dest = "", *gateway = "", *err; 8597a23074eSdduvall boolean_t ishost = B_FALSE; 8607a23074eSdduvall int ret, attempts, oerrno, flags = RTF_STATIC; 8617c478bd9Sstevel@tonic-gate int key; 8627a23074eSdduvall struct hostent *hp = NULL; 8637a23074eSdduvall static char obuf[INET6_ADDRSTRLEN]; 8647c478bd9Sstevel@tonic-gate 8657a23074eSdduvall cmd = argv[0]; 8667a23074eSdduvall if (*cmd != 'g' && !tflag) { 8677a23074eSdduvall /* Don't want to read back our messages */ 8687a23074eSdduvall (void) shutdown(s, 0); 8697c478bd9Sstevel@tonic-gate } 8707a23074eSdduvall while (--argc > 0) { 8717a23074eSdduvall key = keyword(*(++argv)); 8727a23074eSdduvall if (key == K_HOST) { 8737a23074eSdduvall forcehost = B_TRUE; 8747a23074eSdduvall } else if (key == K_NET) { 8757a23074eSdduvall forcenet = B_TRUE; 8767a23074eSdduvall } else if (**(argv) == '-') { 8777a23074eSdduvall switch (key = keyword(1 + *argv)) { 8787c478bd9Sstevel@tonic-gate case K_LINK: 8797a23074eSdduvall af = AF_LINK; 8807c478bd9Sstevel@tonic-gate break; 8817c478bd9Sstevel@tonic-gate case K_INET: 8827a23074eSdduvall af = AF_INET; 8837c478bd9Sstevel@tonic-gate break; 8847c478bd9Sstevel@tonic-gate case K_SA: 8857a23074eSdduvall af = PF_ROUTE; 8867c478bd9Sstevel@tonic-gate break; 8877c478bd9Sstevel@tonic-gate case K_INET6: 8887a23074eSdduvall af = AF_INET6; 8897c478bd9Sstevel@tonic-gate break; 8907c478bd9Sstevel@tonic-gate case K_IFACE: 8917c478bd9Sstevel@tonic-gate case K_INTERFACE: 8927c478bd9Sstevel@tonic-gate iflag = B_TRUE; 8937a23074eSdduvall /* FALLTHROUGH */ 8947c478bd9Sstevel@tonic-gate case K_NOSTATIC: 8957a23074eSdduvall flags &= ~RTF_STATIC; 8967c478bd9Sstevel@tonic-gate break; 8977c478bd9Sstevel@tonic-gate case K_LOCK: 8987a23074eSdduvall locking = B_TRUE; 8997c478bd9Sstevel@tonic-gate break; 9007c478bd9Sstevel@tonic-gate case K_LOCKREST: 9017c478bd9Sstevel@tonic-gate lockrest = B_TRUE; 9027c478bd9Sstevel@tonic-gate break; 9037a23074eSdduvall case K_HOST: 9047a23074eSdduvall forcehost = B_TRUE; 9057a23074eSdduvall break; 9067c478bd9Sstevel@tonic-gate case K_REJECT: 9077a23074eSdduvall flags |= RTF_REJECT; 9087c478bd9Sstevel@tonic-gate break; 9097c478bd9Sstevel@tonic-gate case K_BLACKHOLE: 9107a23074eSdduvall flags |= RTF_BLACKHOLE; 9117c478bd9Sstevel@tonic-gate break; 9127c478bd9Sstevel@tonic-gate case K_PROTO1: 9137a23074eSdduvall flags |= RTF_PROTO1; 9147c478bd9Sstevel@tonic-gate break; 9157c478bd9Sstevel@tonic-gate case K_PROTO2: 9167a23074eSdduvall flags |= RTF_PROTO2; 9177c478bd9Sstevel@tonic-gate break; 9187c478bd9Sstevel@tonic-gate case K_CLONING: 9197a23074eSdduvall flags |= RTF_CLONING; 9207c478bd9Sstevel@tonic-gate break; 9217c478bd9Sstevel@tonic-gate case K_XRESOLVE: 9227a23074eSdduvall flags |= RTF_XRESOLVE; 9237c478bd9Sstevel@tonic-gate break; 9247c478bd9Sstevel@tonic-gate case K_STATIC: 9257a23074eSdduvall flags |= RTF_STATIC; 9267c478bd9Sstevel@tonic-gate break; 9277c478bd9Sstevel@tonic-gate case K_IFA: 9287a23074eSdduvall argc--; 9297a23074eSdduvall (void) getaddr(RTA_IFA, *++argv, NULL); 9307c478bd9Sstevel@tonic-gate break; 9317c478bd9Sstevel@tonic-gate case K_IFP: 9327a23074eSdduvall argc--; 9337a23074eSdduvall (void) getaddr(RTA_IFP, *++argv, NULL); 9347c478bd9Sstevel@tonic-gate break; 9357c478bd9Sstevel@tonic-gate case K_GATEWAY: 9367a23074eSdduvall /* 9377a23074eSdduvall * For the gateway parameter, retrieve the 9387a23074eSdduvall * pointer to the struct hostent so that all 9397a23074eSdduvall * possible addresses can be tried until one 9407a23074eSdduvall * is successful. 9417a23074eSdduvall */ 9427a23074eSdduvall argc--; 9437a23074eSdduvall gateway = *++argv; 9447a23074eSdduvall (void) getaddr(RTA_GATEWAY, *argv, &hp); 9457c478bd9Sstevel@tonic-gate break; 9467c478bd9Sstevel@tonic-gate case K_DST: 9477a23074eSdduvall argc--; 9487a23074eSdduvall ishost = getaddr(RTA_DST, *++argv, NULL); 9497a23074eSdduvall dest = *argv; 9507c478bd9Sstevel@tonic-gate break; 9517c478bd9Sstevel@tonic-gate case K_NETMASK: 9527a23074eSdduvall argc--; 9537a23074eSdduvall (void) getaddr(RTA_NETMASK, *++argv, NULL); 9547a23074eSdduvall /* FALLTHROUGH */ 9557a23074eSdduvall case K_NET: 9567a23074eSdduvall forcenet = B_TRUE; 9577c478bd9Sstevel@tonic-gate break; 9587c478bd9Sstevel@tonic-gate case K_MTU: 9597c478bd9Sstevel@tonic-gate case K_HOPCOUNT: 9607c478bd9Sstevel@tonic-gate case K_EXPIRE: 9617c478bd9Sstevel@tonic-gate case K_RECVPIPE: 9627c478bd9Sstevel@tonic-gate case K_SENDPIPE: 9637c478bd9Sstevel@tonic-gate case K_SSTHRESH: 9647c478bd9Sstevel@tonic-gate case K_RTT: 9657c478bd9Sstevel@tonic-gate case K_RTTVAR: 9667a23074eSdduvall argc--; 9677a23074eSdduvall set_metric(*++argv, key); 9687c478bd9Sstevel@tonic-gate break; 9697c478bd9Sstevel@tonic-gate case K_PRIVATE: 9707a23074eSdduvall flags |= RTF_PRIVATE; 9717c478bd9Sstevel@tonic-gate break; 9727c478bd9Sstevel@tonic-gate case K_MULTIRT: 9737a23074eSdduvall flags |= RTF_MULTIRT; 9747c478bd9Sstevel@tonic-gate break; 9757c478bd9Sstevel@tonic-gate case K_SETSRC: 9767a23074eSdduvall argc--; 9777a23074eSdduvall (void) getaddr(RTA_SRC, *++argv, NULL); 9787a23074eSdduvall flags |= RTF_SETSRC; 9797c478bd9Sstevel@tonic-gate break; 9807c478bd9Sstevel@tonic-gate default: 9817a23074eSdduvall usage(*argv + 1); 9827a23074eSdduvall /* NOTREACHED */ 9837c478bd9Sstevel@tonic-gate } 9847a23074eSdduvall } else { 9857a23074eSdduvall if ((rtm_addrs & RTA_DST) == 0) { 9867a23074eSdduvall dest = *argv; 9877a23074eSdduvall ishost = getaddr(RTA_DST, *argv, NULL); 9887a23074eSdduvall } else if ((rtm_addrs & RTA_GATEWAY) == 0) { 9897c478bd9Sstevel@tonic-gate /* 9907c478bd9Sstevel@tonic-gate * For the gateway parameter, retrieve the 9917c478bd9Sstevel@tonic-gate * pointer to the struct hostent so that all 9927c478bd9Sstevel@tonic-gate * possible addresses can be tried until one 9937c478bd9Sstevel@tonic-gate * is successful. 9947c478bd9Sstevel@tonic-gate */ 9957a23074eSdduvall gateway = *argv; 9967a23074eSdduvall (void) getaddr(RTA_GATEWAY, *argv, &hp); 9977c478bd9Sstevel@tonic-gate } else { 9987a23074eSdduvall ulong_t metric = strtoul(*argv, &err, 10); 9997a23074eSdduvall 10007c478bd9Sstevel@tonic-gate /* 10017c478bd9Sstevel@tonic-gate * Assume that a regular number is a metric. 10027c478bd9Sstevel@tonic-gate * Needed for compatibility with old route 10037c478bd9Sstevel@tonic-gate * command syntax. 10047c478bd9Sstevel@tonic-gate */ 10057a23074eSdduvall if (*argv != err && *err == '\0' && 10067c478bd9Sstevel@tonic-gate metric < 0x80000000ul) { 10077c478bd9Sstevel@tonic-gate iflag = (metric == 0); 10087c478bd9Sstevel@tonic-gate if (verbose) { 10097c478bd9Sstevel@tonic-gate (void) printf("old usage of " 10107c478bd9Sstevel@tonic-gate "trailing number, assuming " 10117c478bd9Sstevel@tonic-gate "route %s\n", iflag ? 10127c478bd9Sstevel@tonic-gate "to if" : "via gateway"); 10137c478bd9Sstevel@tonic-gate } 10147c478bd9Sstevel@tonic-gate continue; 10157c478bd9Sstevel@tonic-gate } 10167a23074eSdduvall (void) getaddr(RTA_NETMASK, *argv, NULL); 10177c478bd9Sstevel@tonic-gate } 10187c478bd9Sstevel@tonic-gate } 10197c478bd9Sstevel@tonic-gate } 10207a23074eSdduvall if ((rtm_addrs & RTA_DST) == 0) { 10213f33f4f7Sjl138328 (void) fprintf(stderr, 10227a23074eSdduvall gettext("route: destination required following command\n")); 10237a23074eSdduvall usage((char *)NULL); 10247a23074eSdduvall } else if ((*cmd == 'a' || *cmd == 'd') && 10257a23074eSdduvall (rtm_addrs & RTA_GATEWAY) == 0) { 10267a23074eSdduvall (void) fprintf(stderr, 10277a23074eSdduvall gettext("route: gateway required for add or delete " 10287a23074eSdduvall "command\n")); 10297a23074eSdduvall usage((char *)NULL); 10303f33f4f7Sjl138328 } 10317a23074eSdduvall 10327a23074eSdduvall /* 10337a23074eSdduvall * If the netmask has been specified use it to determine RTF_HOST. 10347a23074eSdduvall * Otherwise rely on the "-net" and "-host" specifiers. 10357a23074eSdduvall * Final fallback is whether ot not any bits were set in the address 10367a23074eSdduvall * past the classful network component. 10377a23074eSdduvall */ 10387a23074eSdduvall if (rtm_addrs & RTA_NETMASK) { 10397a23074eSdduvall if ((af == AF_INET && 10407a23074eSdduvall so_mask.sin.sin_addr.s_addr == IP_HOST_MASK) || 10417a23074eSdduvall (af == AF_INET6 && masklen == IPV6_ABITS)) 10427a23074eSdduvall forcehost = B_TRUE; 10437a23074eSdduvall else 10447a23074eSdduvall forcenet = B_TRUE; 10453f33f4f7Sjl138328 } 10467a23074eSdduvall if (forcehost) 10477a23074eSdduvall ishost = B_TRUE; 10487a23074eSdduvall if (forcenet) 10497a23074eSdduvall ishost = B_FALSE; 10507a23074eSdduvall flags |= RTF_UP; 10517a23074eSdduvall if (ishost) 10527a23074eSdduvall flags |= RTF_HOST; 10537a23074eSdduvall if (!iflag) 10547a23074eSdduvall flags |= RTF_GATEWAY; 10557c478bd9Sstevel@tonic-gate for (attempts = 1; ; attempts++) { 10567c478bd9Sstevel@tonic-gate errno = 0; 10577a23074eSdduvall if ((ret = rtmsg(*cmd, flags)) == 0) 10587c478bd9Sstevel@tonic-gate break; 10597c478bd9Sstevel@tonic-gate if (errno != ENETUNREACH && errno != ESRCH) 10607c478bd9Sstevel@tonic-gate break; 10617a23074eSdduvall if (*gateway != '\0' && hp != NULL && 10627c478bd9Sstevel@tonic-gate hp->h_addr_list[attempts] != NULL) { 10637c478bd9Sstevel@tonic-gate switch (af) { 10647c478bd9Sstevel@tonic-gate case AF_INET: 10657a23074eSdduvall (void) memmove(&so_gate.sin.sin_addr, 10667c478bd9Sstevel@tonic-gate hp->h_addr_list[attempts], hp->h_length); 10677c478bd9Sstevel@tonic-gate continue; 10687c478bd9Sstevel@tonic-gate case AF_INET6: 10697a23074eSdduvall (void) memmove(&so_gate.sin6.sin6_addr, 10707c478bd9Sstevel@tonic-gate hp->h_addr_list[attempts], hp->h_length); 10717c478bd9Sstevel@tonic-gate continue; 10727c478bd9Sstevel@tonic-gate } 10737c478bd9Sstevel@tonic-gate } 10747c478bd9Sstevel@tonic-gate break; 10757c478bd9Sstevel@tonic-gate } 10767c478bd9Sstevel@tonic-gate oerrno = errno; 10777a23074eSdduvall if (*cmd != 'g') { 10787a23074eSdduvall (void) printf("%s %s %s", cmd, ishost ? "host" : "net", dest); 10797a23074eSdduvall if (*gateway != '\0') { 10807a23074eSdduvall switch (af) { 10817c478bd9Sstevel@tonic-gate case AF_INET: 10827a23074eSdduvall if (nflag) { 10837a23074eSdduvall (void) printf(": gateway %s", 10847a23074eSdduvall inet_ntoa(so_gate.sin.sin_addr)); 10857a23074eSdduvall } else if (attempts > 1 && ret == 0) { 10867a23074eSdduvall (void) printf(": gateway %s (%s)", 10877a23074eSdduvall gateway, 10887a23074eSdduvall inet_ntoa(so_gate.sin.sin_addr)); 10897a23074eSdduvall } else { 10907a23074eSdduvall (void) printf(": gateway %s", gateway); 10917a23074eSdduvall } 10927c478bd9Sstevel@tonic-gate break; 10937c478bd9Sstevel@tonic-gate case AF_INET6: 10947c478bd9Sstevel@tonic-gate if (inet_ntop(AF_INET6, 10957a23074eSdduvall (void *)&so_gate.sin6.sin6_addr, obuf, 10967a23074eSdduvall INET6_ADDRSTRLEN) != NULL) { 10977a23074eSdduvall if (nflag) { 10987a23074eSdduvall (void) printf(": gateway %s", 10997a23074eSdduvall obuf); 11007a23074eSdduvall } else if (attempts > 1 && ret == 0) { 11017a23074eSdduvall (void) printf(": gateway %s " 11027a23074eSdduvall "(%s)", 11037a23074eSdduvall gateway, obuf); 11047a23074eSdduvall } 11057a23074eSdduvall break; 11067a23074eSdduvall } 11077a23074eSdduvall /* FALLTHROUGH */ 11087a23074eSdduvall default: 11097a23074eSdduvall (void) printf(": gateway %s", gateway); 11107a23074eSdduvall break; 11117a23074eSdduvall } 11127a23074eSdduvall } 11137a23074eSdduvall if (ret == 0) 11147a23074eSdduvall (void) printf("\n"); 11157a23074eSdduvall } 11167a23074eSdduvall if (ret != 0) { 11177a23074eSdduvall if (*cmd == 'g') { 11187a23074eSdduvall if (nflag) { 11197a23074eSdduvall switch (af) { 11207a23074eSdduvall case AF_INET: 11217a23074eSdduvall (void) printf(" %s", 11227a23074eSdduvall inet_ntoa(so_dst.sin.sin_addr)); 11237a23074eSdduvall break; 11247a23074eSdduvall case AF_INET6: 11257a23074eSdduvall if (inet_ntop(AF_INET6, 11267a23074eSdduvall (void *)&so_dst.sin6.sin6_addr, 11277c478bd9Sstevel@tonic-gate obuf, INET6_ADDRSTRLEN) != NULL) { 11287c478bd9Sstevel@tonic-gate (void) printf(" %s", obuf); 11297c478bd9Sstevel@tonic-gate break; 11307c478bd9Sstevel@tonic-gate } 11317c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 11327c478bd9Sstevel@tonic-gate default: 11337a23074eSdduvall (void) printf("%s", dest); 11347c478bd9Sstevel@tonic-gate break; 11357c478bd9Sstevel@tonic-gate } 11367c478bd9Sstevel@tonic-gate } else { 11377a23074eSdduvall (void) printf("%s", dest); 11387c478bd9Sstevel@tonic-gate } 11397c478bd9Sstevel@tonic-gate } 11407c478bd9Sstevel@tonic-gate switch (oerrno) { 11417c478bd9Sstevel@tonic-gate case ESRCH: 11427c478bd9Sstevel@tonic-gate err = "not in table"; 11437c478bd9Sstevel@tonic-gate break; 11447c478bd9Sstevel@tonic-gate case EBUSY: 11457c478bd9Sstevel@tonic-gate err = "entry in use"; 11467c478bd9Sstevel@tonic-gate break; 11477c478bd9Sstevel@tonic-gate case ENOBUFS: 11487c478bd9Sstevel@tonic-gate err = "routing table overflow"; 11497c478bd9Sstevel@tonic-gate break; 11507c478bd9Sstevel@tonic-gate case EEXIST: 11517c478bd9Sstevel@tonic-gate err = "entry exists"; 11527c478bd9Sstevel@tonic-gate break; 11537c478bd9Sstevel@tonic-gate case EPERM: 11547c478bd9Sstevel@tonic-gate err = "insufficient privileges"; 11557c478bd9Sstevel@tonic-gate break; 11567c478bd9Sstevel@tonic-gate default: 11577c478bd9Sstevel@tonic-gate err = strerror(oerrno); 11587c478bd9Sstevel@tonic-gate break; 11597c478bd9Sstevel@tonic-gate } 11607c478bd9Sstevel@tonic-gate (void) printf(": %s\n", err); 11617c478bd9Sstevel@tonic-gate } 11627a23074eSdduvall /* 11637a23074eSdduvall * In the case of AF_INET6, one of the getipnodebyX() functions was used 11647a23074eSdduvall * so free the allocated hostent. 11657a23074eSdduvall */ 11667a23074eSdduvall if (af == AF_INET6 && hp != NULL) 11677a23074eSdduvall freehostent(hp); 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate return (oerrno); 11707c478bd9Sstevel@tonic-gate } 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate 11737c478bd9Sstevel@tonic-gate /* 11747c478bd9Sstevel@tonic-gate * Convert a network number to the corresponding IP address. 11757c478bd9Sstevel@tonic-gate * If the RTA_NETMASK hasn't been specified yet set it based 11767c478bd9Sstevel@tonic-gate * on the class of address. 11777c478bd9Sstevel@tonic-gate */ 11787c478bd9Sstevel@tonic-gate static void 11797a23074eSdduvall inet_makenetandmask(in_addr_t net, struct sockaddr_in *sin) 11807c478bd9Sstevel@tonic-gate { 11817c478bd9Sstevel@tonic-gate in_addr_t addr, mask; 11827a23074eSdduvall char *cp; 11837c478bd9Sstevel@tonic-gate 11847c478bd9Sstevel@tonic-gate if (net == 0) { 11857c478bd9Sstevel@tonic-gate mask = addr = 0; 11867c478bd9Sstevel@tonic-gate } else if (net < 128) { 11877c478bd9Sstevel@tonic-gate addr = net << IN_CLASSA_NSHIFT; 11887c478bd9Sstevel@tonic-gate mask = IN_CLASSA_NET; 11897c478bd9Sstevel@tonic-gate } else if (net < 65536) { 11907c478bd9Sstevel@tonic-gate addr = net << IN_CLASSB_NSHIFT; 11917c478bd9Sstevel@tonic-gate mask = IN_CLASSB_NET; 11927c478bd9Sstevel@tonic-gate } else if (net < 16777216L) { 11937c478bd9Sstevel@tonic-gate addr = net << IN_CLASSC_NSHIFT; 11947c478bd9Sstevel@tonic-gate mask = IN_CLASSC_NET; 11957c478bd9Sstevel@tonic-gate } else { 11967c478bd9Sstevel@tonic-gate addr = net; 11977c478bd9Sstevel@tonic-gate if ((addr & IN_CLASSA_HOST) == 0) 11987c478bd9Sstevel@tonic-gate mask = IN_CLASSA_NET; 11997c478bd9Sstevel@tonic-gate else if ((addr & IN_CLASSB_HOST) == 0) 12007c478bd9Sstevel@tonic-gate mask = IN_CLASSB_NET; 12017c478bd9Sstevel@tonic-gate else if ((addr & IN_CLASSC_HOST) == 0) 12027c478bd9Sstevel@tonic-gate mask = IN_CLASSC_NET; 12037c478bd9Sstevel@tonic-gate else { 12047c478bd9Sstevel@tonic-gate if (IN_CLASSA(addr)) 12057c478bd9Sstevel@tonic-gate mask = IN_CLASSA_NET; 12067c478bd9Sstevel@tonic-gate else if (IN_CLASSB(addr)) 12077c478bd9Sstevel@tonic-gate mask = IN_CLASSB_NET; 12087c478bd9Sstevel@tonic-gate else if (IN_CLASSC(addr)) 12097c478bd9Sstevel@tonic-gate mask = IN_CLASSC_NET; 12107c478bd9Sstevel@tonic-gate else 12117c478bd9Sstevel@tonic-gate mask = IP_HOST_MASK; 12127c478bd9Sstevel@tonic-gate mask = inet_makesubnetmask(addr, mask); 12137c478bd9Sstevel@tonic-gate } 12147c478bd9Sstevel@tonic-gate } 12157c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = htonl(addr); 12167c478bd9Sstevel@tonic-gate 12177a23074eSdduvall if (!(rtm_addrs & RTA_NETMASK)) { 12187a23074eSdduvall rtm_addrs |= RTA_NETMASK; 12197a23074eSdduvall sin = &so_mask.sin; 12207c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = htonl(mask); 12217c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET; 12227a23074eSdduvall cp = (char *)(&sin->sin_addr + 1); 12237a23074eSdduvall while (*--cp == 0 && cp > (char *)sin) 12247a23074eSdduvall ; 12257c478bd9Sstevel@tonic-gate } 12267c478bd9Sstevel@tonic-gate } 12277c478bd9Sstevel@tonic-gate 12287c478bd9Sstevel@tonic-gate static in_addr_t 12297c478bd9Sstevel@tonic-gate inet_makesubnetmask(in_addr_t addr, in_addr_t mask) 12307c478bd9Sstevel@tonic-gate { 12317c478bd9Sstevel@tonic-gate int n; 12327c478bd9Sstevel@tonic-gate struct ifconf ifc; 12337c478bd9Sstevel@tonic-gate struct ifreq ifreq; 12347c478bd9Sstevel@tonic-gate struct ifreq *ifr; 12357c478bd9Sstevel@tonic-gate struct sockaddr_in *sin; 12367c478bd9Sstevel@tonic-gate char *buf; 12377c478bd9Sstevel@tonic-gate int numifs; 12387c478bd9Sstevel@tonic-gate size_t bufsize; 12397c478bd9Sstevel@tonic-gate int iosoc; 12407c478bd9Sstevel@tonic-gate in_addr_t if_addr, if_mask; 12417c478bd9Sstevel@tonic-gate in_addr_t if_subnetmask = 0; 12427c478bd9Sstevel@tonic-gate short if_flags; 12437c478bd9Sstevel@tonic-gate 12447c478bd9Sstevel@tonic-gate if (mask == 0) 12457c478bd9Sstevel@tonic-gate return (0); 12467c478bd9Sstevel@tonic-gate if ((iosoc = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 12477c478bd9Sstevel@tonic-gate quit("socket", errno); 12487c478bd9Sstevel@tonic-gate if (ioctl(iosoc, SIOCGIFNUM, (char *)&numifs) < 0) 12497c478bd9Sstevel@tonic-gate quit("ioctl", errno); 12507c478bd9Sstevel@tonic-gate bufsize = numifs * sizeof (struct ifreq); 12517c478bd9Sstevel@tonic-gate buf = malloc(bufsize); 12527c478bd9Sstevel@tonic-gate if (buf == NULL) 12537c478bd9Sstevel@tonic-gate quit("malloc", errno); 12547c478bd9Sstevel@tonic-gate (void) memset(&ifc, 0, sizeof (ifc)); 12557c478bd9Sstevel@tonic-gate ifc.ifc_len = bufsize; 12567c478bd9Sstevel@tonic-gate ifc.ifc_buf = buf; 12577c478bd9Sstevel@tonic-gate if (ioctl(iosoc, SIOCGIFCONF, (char *)&ifc) < 0) 12587c478bd9Sstevel@tonic-gate quit("ioctl (get interface configuration)", errno); 12597c478bd9Sstevel@tonic-gate /* Let's check to see if this is maybe a local subnet route. */ 12607c478bd9Sstevel@tonic-gate ifr = ifc.ifc_req; 12617c478bd9Sstevel@tonic-gate for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) { 12627c478bd9Sstevel@tonic-gate ifreq = *ifr; 12637c478bd9Sstevel@tonic-gate /* LINTED */ 12647c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)&ifr->ifr_addr; 12657c478bd9Sstevel@tonic-gate if_addr = ntohl(sin->sin_addr.s_addr); 12667c478bd9Sstevel@tonic-gate 12677c478bd9Sstevel@tonic-gate if (ioctl(iosoc, SIOCGIFFLAGS, (char *)&ifreq) < 0) 12687c478bd9Sstevel@tonic-gate quit("ioctl (get interface flags)", errno); 12697c478bd9Sstevel@tonic-gate if ((ifreq.ifr_flags & IFF_UP) == 0) 12707c478bd9Sstevel@tonic-gate continue; 12717c478bd9Sstevel@tonic-gate if_flags = ifreq.ifr_flags; 12727c478bd9Sstevel@tonic-gate 12737c478bd9Sstevel@tonic-gate if (ioctl(iosoc, SIOCGIFNETMASK, (char *)&ifreq) < 0) 12747c478bd9Sstevel@tonic-gate quit("ioctl (get netmask)", errno); 12757c478bd9Sstevel@tonic-gate /* LINTED */ 12767c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)&ifreq.ifr_addr; 12777c478bd9Sstevel@tonic-gate if_mask = ntohl(sin->sin_addr.s_addr); 12787c478bd9Sstevel@tonic-gate if ((if_addr & mask) == (addr & mask)) { 12797c478bd9Sstevel@tonic-gate /* 12807c478bd9Sstevel@tonic-gate * Don't trust pt-pt interfaces if there are 12817c478bd9Sstevel@tonic-gate * other interfaces. 12827c478bd9Sstevel@tonic-gate */ 12837c478bd9Sstevel@tonic-gate if (if_flags & IFF_POINTOPOINT) { 12847c478bd9Sstevel@tonic-gate if_subnetmask = if_mask; 12857c478bd9Sstevel@tonic-gate continue; 12867c478bd9Sstevel@tonic-gate } 12877c478bd9Sstevel@tonic-gate /* 12887c478bd9Sstevel@tonic-gate * Fine. Just assume the same net mask as the 12897c478bd9Sstevel@tonic-gate * directly attached subnet interface is using. 12907c478bd9Sstevel@tonic-gate */ 12917c478bd9Sstevel@tonic-gate return (if_mask); 12927c478bd9Sstevel@tonic-gate } 12937c478bd9Sstevel@tonic-gate } 12947c478bd9Sstevel@tonic-gate if (if_subnetmask != 0) 12957c478bd9Sstevel@tonic-gate return (if_subnetmask); 12967c478bd9Sstevel@tonic-gate return (mask); 12977c478bd9Sstevel@tonic-gate } 12987c478bd9Sstevel@tonic-gate 12997c478bd9Sstevel@tonic-gate /* 13007a23074eSdduvall * Interpret an argument as a network address of some kind, 13017a23074eSdduvall * returning B_TRUE if a host address, B_FALSE if a network address. 13027c478bd9Sstevel@tonic-gate * 13037c478bd9Sstevel@tonic-gate * If the address family is one looked up in getaddr() using one of the 13047c478bd9Sstevel@tonic-gate * getipnodebyX() functions (currently only AF_INET6), then callers should 13057c478bd9Sstevel@tonic-gate * freehostent() the returned "struct hostent" pointer if one was passed in. 13067c478bd9Sstevel@tonic-gate */ 13077c478bd9Sstevel@tonic-gate static boolean_t 13087a23074eSdduvall getaddr(int which, char *s, struct hostent **hpp) 13097c478bd9Sstevel@tonic-gate { 13107a23074eSdduvall sup su; 13117c478bd9Sstevel@tonic-gate struct hostent *hp; 13127c478bd9Sstevel@tonic-gate boolean_t ret; 13137c478bd9Sstevel@tonic-gate 13147a23074eSdduvall if (s == NULL) { 13157a23074eSdduvall (void) fprintf(stderr, 13167a23074eSdduvall gettext("route: argument required following keyword\n")); 13177a23074eSdduvall usage((char *)NULL); 13183f33f4f7Sjl138328 } 13197a23074eSdduvall if (hpp == NULL) 13207a23074eSdduvall hpp = &hp; 13217c478bd9Sstevel@tonic-gate *hpp = NULL; 13227a23074eSdduvall rtm_addrs |= which; 13237c478bd9Sstevel@tonic-gate switch (which) { 13247c478bd9Sstevel@tonic-gate case RTA_DST: 13257a23074eSdduvall su = &so_dst; 13267a23074eSdduvall su->sa.sa_family = af; 13277c478bd9Sstevel@tonic-gate break; 13287c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 13297a23074eSdduvall su = &so_gate; 13307a23074eSdduvall su->sa.sa_family = af; 13317c478bd9Sstevel@tonic-gate break; 13327c478bd9Sstevel@tonic-gate case RTA_NETMASK: 13337a23074eSdduvall su = &so_mask; 13347a23074eSdduvall su->sa.sa_family = af; 13357c478bd9Sstevel@tonic-gate break; 13367c478bd9Sstevel@tonic-gate case RTA_IFP: 13377a23074eSdduvall so_ifp.sdl.sdl_index = if_nametoindex(s); 13387a23074eSdduvall if (so_ifp.sdl.sdl_index == 0) { 13397a23074eSdduvall if (errno == ENXIO) { 13407a23074eSdduvall (void) fprintf(stderr, 13417a23074eSdduvall gettext("route: %s: no such interface\n"), 13427a23074eSdduvall s); 13437a23074eSdduvall exit(1); 13447a23074eSdduvall } else { 13457a23074eSdduvall quit("if_nametoindex", errno); 13467a23074eSdduvall } 13477a23074eSdduvall } 13487a23074eSdduvall so_ifp.sdl.sdl_family = AF_LINK; 13497a23074eSdduvall return (B_FALSE); 13507c478bd9Sstevel@tonic-gate /* 13517c478bd9Sstevel@tonic-gate * RTA_SRC has overloaded meaning. It can represent the 13527c478bd9Sstevel@tonic-gate * src address of incoming or outgoing packets. 13537c478bd9Sstevel@tonic-gate */ 13547c478bd9Sstevel@tonic-gate case RTA_IFA: 13557a23074eSdduvall su = &so_ifa; 13567a23074eSdduvall su->sa.sa_family = af; 13577c478bd9Sstevel@tonic-gate break; 13587c478bd9Sstevel@tonic-gate case RTA_SRC: 13597a23074eSdduvall su = &so_src; 13607a23074eSdduvall su->sa.sa_family = af; 13617c478bd9Sstevel@tonic-gate break; 13627c478bd9Sstevel@tonic-gate default: 13637c478bd9Sstevel@tonic-gate /* NOTREACHED */ 13647c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 13657c478bd9Sstevel@tonic-gate /* NOTREACHED */ 13667c478bd9Sstevel@tonic-gate } 13677c478bd9Sstevel@tonic-gate if (strcmp(s, "default") == 0) { 13687c478bd9Sstevel@tonic-gate if (which == RTA_DST) { 13697a23074eSdduvall forcenet = B_TRUE; 13707a23074eSdduvall (void) getaddr(RTA_NETMASK, s, NULL); 13717c478bd9Sstevel@tonic-gate } 13727c478bd9Sstevel@tonic-gate if (which == RTA_SRC) { 13737c478bd9Sstevel@tonic-gate return (B_TRUE); 13747c478bd9Sstevel@tonic-gate } 13757a23074eSdduvall return (B_FALSE); 13767c478bd9Sstevel@tonic-gate } 13777a23074eSdduvall switch (af) { 13787c478bd9Sstevel@tonic-gate case AF_LINK: 13797c478bd9Sstevel@tonic-gate link_addr(s, &su->sdl); 13807c478bd9Sstevel@tonic-gate return (B_TRUE); 13817c478bd9Sstevel@tonic-gate case PF_ROUTE: 13827c478bd9Sstevel@tonic-gate sockaddr(s, &su->sa); 13837c478bd9Sstevel@tonic-gate return (B_TRUE); 13847c478bd9Sstevel@tonic-gate case AF_INET6: 13857c478bd9Sstevel@tonic-gate switch (which) { 13867c478bd9Sstevel@tonic-gate case RTA_DST: 13877c478bd9Sstevel@tonic-gate if (s[0] == '/') { 13887a23074eSdduvall (void) fprintf(stderr, 13897a23074eSdduvall gettext("route: %s: unexpected '/'\n"), s); 13907a23074eSdduvall exit(1); 13917c478bd9Sstevel@tonic-gate } 13927a23074eSdduvall ret = in6_getaddr(s, &su->sin6, &masklen, hpp); 13937a23074eSdduvall switch (masklen) { 13947c478bd9Sstevel@tonic-gate case NO_PREFIX: 13957c478bd9Sstevel@tonic-gate /* Nothing there - ok */ 13967a23074eSdduvall return (ret); 13977c478bd9Sstevel@tonic-gate case BAD_ADDR: 13987a23074eSdduvall (void) fprintf(stderr, 13997a23074eSdduvall gettext("route: bad prefix length in %s\n"), 14007a23074eSdduvall s); 14017a23074eSdduvall exit(1); 14027a23074eSdduvall /* NOTREACHED */ 14037c478bd9Sstevel@tonic-gate default: 14047a23074eSdduvall (void) memset(&so_mask.sin6.sin6_addr, 0, 14057a23074eSdduvall sizeof (so_mask.sin6.sin6_addr)); 14067a23074eSdduvall if (!in_prefixlentomask(masklen, IPV6_ABITS, 14077a23074eSdduvall (uchar_t *)&so_mask.sin6.sin6_addr)) { 14087a23074eSdduvall (void) fprintf(stderr, 14097a23074eSdduvall gettext("route: bad prefix length: " 14107a23074eSdduvall "%d\n"), masklen); 14117a23074eSdduvall exit(1); 14127c478bd9Sstevel@tonic-gate } 14137c478bd9Sstevel@tonic-gate break; 14147c478bd9Sstevel@tonic-gate } 14157a23074eSdduvall so_mask.sin6.sin6_family = af; 14167a23074eSdduvall rtm_addrs |= RTA_NETMASK; 14177a23074eSdduvall return (ret); 14187c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 14197c478bd9Sstevel@tonic-gate case RTA_IFA: 14207c478bd9Sstevel@tonic-gate case RTA_SRC: 14217a23074eSdduvall ret = in6_getaddr(s, &su->sin6, NULL, hpp); 14227a23074eSdduvall return (ret); 14237c478bd9Sstevel@tonic-gate case RTA_NETMASK: 14247a23074eSdduvall (void) fprintf(stderr, 14257c478bd9Sstevel@tonic-gate gettext("route: -netmask not supported for IPv6: " 14267a23074eSdduvall "use <prefix>/<prefix-length> instead")); 14277a23074eSdduvall exit(1); 14287a23074eSdduvall /* NOTREACHED */ 14297c478bd9Sstevel@tonic-gate default: 14307c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 14317c478bd9Sstevel@tonic-gate /* NOTREACHED */ 14327c478bd9Sstevel@tonic-gate } 14337c478bd9Sstevel@tonic-gate case AF_INET: 14347c478bd9Sstevel@tonic-gate switch (which) { 14357c478bd9Sstevel@tonic-gate case RTA_DST: 14367c478bd9Sstevel@tonic-gate if (s[0] == '/') { 14377a23074eSdduvall (void) fprintf(stderr, 14387a23074eSdduvall gettext("route: %s: unexpected '/'\n"), s); 14397a23074eSdduvall exit(1); 14407c478bd9Sstevel@tonic-gate } 14417a23074eSdduvall ret = in_getaddr(s, &su->sin, &masklen, which, hpp); 14427a23074eSdduvall switch (masklen) { 14437c478bd9Sstevel@tonic-gate case NO_PREFIX: 14447c478bd9Sstevel@tonic-gate /* Nothing there - ok */ 14457a23074eSdduvall return (ret); 14467c478bd9Sstevel@tonic-gate case BAD_ADDR: 14477a23074eSdduvall (void) fprintf(stderr, 14487a23074eSdduvall gettext("route: bad prefix length in %s\n"), 14497a23074eSdduvall s); 14507a23074eSdduvall exit(1); 14517a23074eSdduvall /* NOTREACHED */ 14527c478bd9Sstevel@tonic-gate default: 14537a23074eSdduvall (void) memset(&so_mask.sin.sin_addr, 0, 14547a23074eSdduvall sizeof (so_mask.sin.sin_addr)); 14557a23074eSdduvall if (!in_prefixlentomask(masklen, IP_ABITS, 14567a23074eSdduvall (uchar_t *)&so_mask.sin.sin_addr)) { 14577a23074eSdduvall (void) fprintf(stderr, 14587a23074eSdduvall gettext("route: bad prefix length: " 14597a23074eSdduvall "%d\n"), masklen); 14607a23074eSdduvall exit(1); 14617c478bd9Sstevel@tonic-gate } 14627c478bd9Sstevel@tonic-gate break; 14637c478bd9Sstevel@tonic-gate } 14647a23074eSdduvall so_mask.sin.sin_family = af; 14657a23074eSdduvall rtm_addrs |= RTA_NETMASK; 14667a23074eSdduvall return (ret); 14677c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 14687c478bd9Sstevel@tonic-gate case RTA_IFA: 14697c478bd9Sstevel@tonic-gate case RTA_NETMASK: 14707c478bd9Sstevel@tonic-gate case RTA_SRC: 14717a23074eSdduvall ret = in_getaddr(s, &su->sin, NULL, which, hpp); 14727a23074eSdduvall return (ret); 14737c478bd9Sstevel@tonic-gate default: 14747c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 14757c478bd9Sstevel@tonic-gate /* NOTREACHED */ 14767c478bd9Sstevel@tonic-gate } 14777c478bd9Sstevel@tonic-gate default: 14787c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 14797c478bd9Sstevel@tonic-gate /* NOTREACHED */ 14807c478bd9Sstevel@tonic-gate } 14817a23074eSdduvall 14827c478bd9Sstevel@tonic-gate } 14837c478bd9Sstevel@tonic-gate 14847c478bd9Sstevel@tonic-gate /* 14857c478bd9Sstevel@tonic-gate * Interpret an argument as an IPv4 network address of some kind, 14867a23074eSdduvall * returning B_TRUE if a host address, B_FALSE if a network address. 14877c478bd9Sstevel@tonic-gate * Note that this *always* tries host interpretation before network 14887c478bd9Sstevel@tonic-gate * interpretation. 14897c478bd9Sstevel@tonic-gate * 14907c478bd9Sstevel@tonic-gate * If the plenp argument is non-NULL, allow <addr>/<n> syntax and 14917c478bd9Sstevel@tonic-gate * pass out <n> in *plenp. 14927c478bd9Sstevel@tonic-gate * If <n> doesn't parse return BAD_ADDR as *plenp. 14937c478bd9Sstevel@tonic-gate * If no /<n> is present return NO_PREFIX as *plenp. 14947c478bd9Sstevel@tonic-gate */ 14957c478bd9Sstevel@tonic-gate static boolean_t 14967c478bd9Sstevel@tonic-gate in_getaddr(char *s, struct sockaddr_in *sin, int *plenp, int which, 14977a23074eSdduvall struct hostent **hpp) 14987c478bd9Sstevel@tonic-gate { 14997c478bd9Sstevel@tonic-gate struct hostent *hp; 15007c478bd9Sstevel@tonic-gate struct netent *np; 15017c478bd9Sstevel@tonic-gate in_addr_t val; 15027c478bd9Sstevel@tonic-gate char str[BUFSIZ]; 15037c478bd9Sstevel@tonic-gate 15047c478bd9Sstevel@tonic-gate (void) strncpy(str, s, sizeof (str)); 15057c478bd9Sstevel@tonic-gate 15067c478bd9Sstevel@tonic-gate /* 15077c478bd9Sstevel@tonic-gate * Look for '/'<n> is plenp 15087c478bd9Sstevel@tonic-gate */ 15097c478bd9Sstevel@tonic-gate if (plenp != NULL) { 15107c478bd9Sstevel@tonic-gate char *cp; 15117c478bd9Sstevel@tonic-gate 15127c478bd9Sstevel@tonic-gate *plenp = in_getprefixlen(str, IP_ABITS); 15137c478bd9Sstevel@tonic-gate if (*plenp == BAD_ADDR) 15147c478bd9Sstevel@tonic-gate return (B_FALSE); 15157c478bd9Sstevel@tonic-gate cp = strchr(str, '/'); 15167c478bd9Sstevel@tonic-gate if (cp != NULL) 15177c478bd9Sstevel@tonic-gate *cp = '\0'; 15187c478bd9Sstevel@tonic-gate } else if (strchr(str, '/') != NULL) { 15197a23074eSdduvall (void) fprintf(stderr, gettext("route: %s: unexpected '/'\n"), 15207a23074eSdduvall str); 15217a23074eSdduvall exit(1); 15227c478bd9Sstevel@tonic-gate } 15237c478bd9Sstevel@tonic-gate 15247c478bd9Sstevel@tonic-gate (void) memset(sin, 0, sizeof (*sin)); 15257c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET; 15267c478bd9Sstevel@tonic-gate 15277c478bd9Sstevel@tonic-gate /* 15287c478bd9Sstevel@tonic-gate * Note: only the route destination can be a network, so we treat 15297c478bd9Sstevel@tonic-gate * all other addresses as though "-net" was not specified. 15307c478bd9Sstevel@tonic-gate */ 15317c478bd9Sstevel@tonic-gate if ((((val = inet_addr(str)) != (in_addr_t)-1) || 15327c478bd9Sstevel@tonic-gate strcmp(str, "255.255.255.255") == 0) && 15337a23074eSdduvall (which != RTA_DST || !forcenet)) { 15347c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = val; 15357c478bd9Sstevel@tonic-gate if (inet_lnaof(sin->sin_addr) != INADDR_ANY || 15367a23074eSdduvall forcehost) 15377c478bd9Sstevel@tonic-gate return (B_TRUE); 15387c478bd9Sstevel@tonic-gate val = ntohl(val); 15397c478bd9Sstevel@tonic-gate if (which == RTA_DST) 15407a23074eSdduvall inet_makenetandmask(val, sin); 15417a23074eSdduvall return (B_FALSE); 15427c478bd9Sstevel@tonic-gate } 15437a23074eSdduvall if (!forcehost && (val = inet_network(str)) != (in_addr_t)-1) { 15447c478bd9Sstevel@tonic-gate if (which == RTA_DST) 15457a23074eSdduvall inet_makenetandmask(val, sin); 15467a23074eSdduvall return (B_FALSE); 15477c478bd9Sstevel@tonic-gate } 15487a23074eSdduvall if ((which != RTA_DST || !forcenet) && 15497c478bd9Sstevel@tonic-gate (hp = gethostbyname(str)) != NULL) { 15507c478bd9Sstevel@tonic-gate *hpp = hp; 15517c478bd9Sstevel@tonic-gate (void) memmove(&sin->sin_addr, hp->h_addr, 15527c478bd9Sstevel@tonic-gate hp->h_length); 15537c478bd9Sstevel@tonic-gate return (B_TRUE); 15547c478bd9Sstevel@tonic-gate } 15557a23074eSdduvall if (!forcehost && (np = getnetbyname(str)) != NULL && 15567c478bd9Sstevel@tonic-gate (val = np->n_net) != 0) { 15577c478bd9Sstevel@tonic-gate if (which == RTA_DST) 15587a23074eSdduvall inet_makenetandmask(val, sin); 15593f33f4f7Sjl138328 return (B_FALSE); 15607c478bd9Sstevel@tonic-gate } 15617a23074eSdduvall (void) fprintf(stderr, gettext("%s: bad value\n"), s); 15627a23074eSdduvall exit(1); 15637a23074eSdduvall /* NOTREACHED */ 15647a23074eSdduvall } 15657c478bd9Sstevel@tonic-gate 15667c478bd9Sstevel@tonic-gate /* 15677c478bd9Sstevel@tonic-gate * Interpret an argument as an IPv6 network address of some kind, 15687a23074eSdduvall * returning B_TRUE if a host address, B_FALSE if a network address. 15697c478bd9Sstevel@tonic-gate * 15707c478bd9Sstevel@tonic-gate * If the last argument is non-NULL allow a <addr>/<n> syntax and 15717c478bd9Sstevel@tonic-gate * pass out <n> in *plenp. 15727c478bd9Sstevel@tonic-gate * If <n> doesn't parse return BAD_ADDR as *plenp. 15737c478bd9Sstevel@tonic-gate * If no /<n> is present return NO_PREFIX as *plenp. 15747c478bd9Sstevel@tonic-gate */ 15757c478bd9Sstevel@tonic-gate static boolean_t 15767c478bd9Sstevel@tonic-gate in6_getaddr(char *s, struct sockaddr_in6 *sin6, int *plenp, 15777c478bd9Sstevel@tonic-gate struct hostent **hpp) 15787c478bd9Sstevel@tonic-gate { 15797c478bd9Sstevel@tonic-gate struct hostent *hp; 15807c478bd9Sstevel@tonic-gate char str[BUFSIZ]; 15817c478bd9Sstevel@tonic-gate int error_num; 15827c478bd9Sstevel@tonic-gate 15837c478bd9Sstevel@tonic-gate (void) strncpy(str, s, sizeof (str)); 15847c478bd9Sstevel@tonic-gate 15857c478bd9Sstevel@tonic-gate /* 15867c478bd9Sstevel@tonic-gate * Look for '/'<n> is plenp 15877c478bd9Sstevel@tonic-gate */ 15887c478bd9Sstevel@tonic-gate if (plenp != NULL) { 15897c478bd9Sstevel@tonic-gate char *cp; 15907c478bd9Sstevel@tonic-gate 15917c478bd9Sstevel@tonic-gate *plenp = in_getprefixlen(str, IPV6_ABITS); 15927c478bd9Sstevel@tonic-gate if (*plenp == BAD_ADDR) 15937c478bd9Sstevel@tonic-gate return (B_FALSE); 15947c478bd9Sstevel@tonic-gate cp = strchr(str, '/'); 15957c478bd9Sstevel@tonic-gate if (cp != NULL) 15967c478bd9Sstevel@tonic-gate *cp = '\0'; 15977c478bd9Sstevel@tonic-gate } else if (strchr(str, '/') != NULL) { 15987a23074eSdduvall (void) fprintf(stderr, gettext("route: %s: unexpected '/'\n"), 15997a23074eSdduvall str); 16007a23074eSdduvall exit(1); 16017c478bd9Sstevel@tonic-gate } 16027c478bd9Sstevel@tonic-gate 16037c478bd9Sstevel@tonic-gate (void) memset(sin6, 0, sizeof (struct sockaddr_in6)); 16047c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 16057c478bd9Sstevel@tonic-gate 16067c478bd9Sstevel@tonic-gate hp = getipnodebyname(str, AF_INET6, 0, &error_num); 16077c478bd9Sstevel@tonic-gate if (hp != NULL) { 16087c478bd9Sstevel@tonic-gate *hpp = hp; 16097c478bd9Sstevel@tonic-gate (void) memmove(&sin6->sin6_addr, hp->h_addr, hp->h_length); 16107c478bd9Sstevel@tonic-gate return (B_TRUE); 16117c478bd9Sstevel@tonic-gate } 16127c478bd9Sstevel@tonic-gate if (error_num == TRY_AGAIN) { 16137a23074eSdduvall (void) fprintf(stderr, gettext("route: %s: bad address (try " 16143f33f4f7Sjl138328 "again later)\n"), s); 16157a23074eSdduvall } else { 16167a23074eSdduvall (void) fprintf(stderr, gettext("route: %s: bad address\n"), s); 16173f33f4f7Sjl138328 } 16187a23074eSdduvall exit(1); 16197a23074eSdduvall /* NOTREACHED */ 16207c478bd9Sstevel@tonic-gate } 16217c478bd9Sstevel@tonic-gate 16227c478bd9Sstevel@tonic-gate /* 16237c478bd9Sstevel@tonic-gate * If "slash" is zero this parses the whole string as 16247c478bd9Sstevel@tonic-gate * an integer. With "slash" non zero it parses the tail part as an integer. 16257c478bd9Sstevel@tonic-gate * 16267c478bd9Sstevel@tonic-gate * If it is not a valid integer this returns BAD_ADDR. 16277c478bd9Sstevel@tonic-gate * If there is /<n> present this returns NO_PREFIX. 16287c478bd9Sstevel@tonic-gate */ 16297c478bd9Sstevel@tonic-gate int 16307c478bd9Sstevel@tonic-gate in_getprefixlen(char *addr, int max_plen) 16317c478bd9Sstevel@tonic-gate { 16327c478bd9Sstevel@tonic-gate int prefixlen; 16337c478bd9Sstevel@tonic-gate char *str, *end; 16347c478bd9Sstevel@tonic-gate 16357c478bd9Sstevel@tonic-gate str = strchr(addr, '/'); 16367c478bd9Sstevel@tonic-gate if (str == NULL) 16377c478bd9Sstevel@tonic-gate return (NO_PREFIX); 16387c478bd9Sstevel@tonic-gate str++; 16397c478bd9Sstevel@tonic-gate 16407c478bd9Sstevel@tonic-gate prefixlen = strtol(str, &end, 10); 16417c478bd9Sstevel@tonic-gate if (prefixlen < 0) 16427c478bd9Sstevel@tonic-gate return (BAD_ADDR); 16437c478bd9Sstevel@tonic-gate if (str == end) 16447c478bd9Sstevel@tonic-gate return (BAD_ADDR); 16457c478bd9Sstevel@tonic-gate if (max_plen != 0 && max_plen < prefixlen) 16467c478bd9Sstevel@tonic-gate return (BAD_ADDR); 16477c478bd9Sstevel@tonic-gate else 16487c478bd9Sstevel@tonic-gate return (prefixlen); 16497c478bd9Sstevel@tonic-gate } 16507c478bd9Sstevel@tonic-gate 16517c478bd9Sstevel@tonic-gate /* 16527c478bd9Sstevel@tonic-gate * Convert a prefix length to a mask. 16537c478bd9Sstevel@tonic-gate * Returns B_TRUE if ok. B_FALSE otherwise. 16547c478bd9Sstevel@tonic-gate * Assumes the mask array is zeroed by the caller. 16557c478bd9Sstevel@tonic-gate */ 16567c478bd9Sstevel@tonic-gate boolean_t 16577c478bd9Sstevel@tonic-gate in_prefixlentomask(int prefixlen, int maxlen, uchar_t *mask) 16587c478bd9Sstevel@tonic-gate { 16597c478bd9Sstevel@tonic-gate if (prefixlen < 0 || prefixlen > maxlen) 16607c478bd9Sstevel@tonic-gate return (B_FALSE); 16617c478bd9Sstevel@tonic-gate 16627c478bd9Sstevel@tonic-gate while (prefixlen > 0) { 16637c478bd9Sstevel@tonic-gate if (prefixlen >= 8) { 16647c478bd9Sstevel@tonic-gate *mask++ = 0xFF; 16657c478bd9Sstevel@tonic-gate prefixlen -= 8; 16667c478bd9Sstevel@tonic-gate continue; 16677c478bd9Sstevel@tonic-gate } 16687c478bd9Sstevel@tonic-gate *mask |= 1 << (8 - prefixlen); 16697c478bd9Sstevel@tonic-gate prefixlen--; 16707c478bd9Sstevel@tonic-gate } 16717c478bd9Sstevel@tonic-gate return (B_TRUE); 16727c478bd9Sstevel@tonic-gate } 16737c478bd9Sstevel@tonic-gate 16747c478bd9Sstevel@tonic-gate void 16757c478bd9Sstevel@tonic-gate rtmonitor(int argc, char *argv[]) 16767c478bd9Sstevel@tonic-gate { 16777c478bd9Sstevel@tonic-gate int n; 16787c478bd9Sstevel@tonic-gate intmax_t msg[2048 / sizeof (intmax_t)]; 16797c478bd9Sstevel@tonic-gate 16807c478bd9Sstevel@tonic-gate if (tflag) 16817c478bd9Sstevel@tonic-gate exit(0); 16827c478bd9Sstevel@tonic-gate verbose = B_TRUE; 16837c478bd9Sstevel@tonic-gate if (argc > 1) { 16847c478bd9Sstevel@tonic-gate argv++; 16857c478bd9Sstevel@tonic-gate if (argc == 2 && **argv == '-') { 16867c478bd9Sstevel@tonic-gate switch (keyword(*argv + 1)) { 16877c478bd9Sstevel@tonic-gate case K_INET: 16887c478bd9Sstevel@tonic-gate af = AF_INET; 16897c478bd9Sstevel@tonic-gate break; 16907c478bd9Sstevel@tonic-gate case K_LINK: 16917c478bd9Sstevel@tonic-gate af = AF_LINK; 16927c478bd9Sstevel@tonic-gate break; 16937c478bd9Sstevel@tonic-gate case K_INET6: 16947c478bd9Sstevel@tonic-gate af = AF_INET6; 16957c478bd9Sstevel@tonic-gate break; 16967c478bd9Sstevel@tonic-gate default: 16977c478bd9Sstevel@tonic-gate usage(*argv); 16987c478bd9Sstevel@tonic-gate /* NOTREACHED */ 16997c478bd9Sstevel@tonic-gate } 17007c478bd9Sstevel@tonic-gate } else { 17017c478bd9Sstevel@tonic-gate usage(*argv); 17027c478bd9Sstevel@tonic-gate } 17037c478bd9Sstevel@tonic-gate (void) close(s); 17047c478bd9Sstevel@tonic-gate s = socket(PF_ROUTE, SOCK_RAW, af); 17057c478bd9Sstevel@tonic-gate if (s < 0) 17067c478bd9Sstevel@tonic-gate quit("socket", errno); 17077c478bd9Sstevel@tonic-gate } 17087c478bd9Sstevel@tonic-gate for (;;) { 17097c478bd9Sstevel@tonic-gate n = read(s, msg, sizeof (msg)); 17107c478bd9Sstevel@tonic-gate if (n <= 0) 17117c478bd9Sstevel@tonic-gate quit("read", errno); 17127c478bd9Sstevel@tonic-gate (void) printf("got message of size %d\n", n); 17137c478bd9Sstevel@tonic-gate print_rtmsg((struct rt_msghdr *)msg, n); 17147c478bd9Sstevel@tonic-gate } 17157c478bd9Sstevel@tonic-gate } 17167c478bd9Sstevel@tonic-gate 17177c478bd9Sstevel@tonic-gate int 17187a23074eSdduvall rtmsg(int cmd, int flags) 17197c478bd9Sstevel@tonic-gate { 17207c478bd9Sstevel@tonic-gate static int seq; 17217c478bd9Sstevel@tonic-gate int rlen; 17227c478bd9Sstevel@tonic-gate char *cp = m_rtmsg.m_space; 17237c478bd9Sstevel@tonic-gate int l; 17247c478bd9Sstevel@tonic-gate 17257c478bd9Sstevel@tonic-gate errno = 0; 17267c478bd9Sstevel@tonic-gate (void) memset(&m_rtmsg, 0, sizeof (m_rtmsg)); 17277a23074eSdduvall if (cmd == 'a') { 17287a23074eSdduvall cmd = RTM_ADD; 17297a23074eSdduvall } else if (cmd == 'c') { 17307a23074eSdduvall cmd = RTM_CHANGE; 17317a23074eSdduvall } else if (cmd == 'g') { 17327a23074eSdduvall cmd = RTM_GET; 17337a23074eSdduvall if (so_ifp.sa.sa_family == 0) { 17347a23074eSdduvall so_ifp.sa.sa_family = AF_LINK; 17357a23074eSdduvall rtm_addrs |= RTA_IFP; 17367c478bd9Sstevel@tonic-gate } 17377a23074eSdduvall } else { 17387a23074eSdduvall cmd = RTM_DELETE; 17397a23074eSdduvall } 17407c478bd9Sstevel@tonic-gate #define rtm m_rtmsg.m_rtm 17417a23074eSdduvall rtm.rtm_type = cmd; 17427a23074eSdduvall rtm.rtm_flags = flags; 17437c478bd9Sstevel@tonic-gate rtm.rtm_version = RTM_VERSION; 17447c478bd9Sstevel@tonic-gate rtm.rtm_seq = ++seq; 17457a23074eSdduvall rtm.rtm_addrs = rtm_addrs; 17467a23074eSdduvall rtm.rtm_rmx = rt_metrics; 17477a23074eSdduvall rtm.rtm_inits = rtm_inits; 17487c478bd9Sstevel@tonic-gate 17497c478bd9Sstevel@tonic-gate #define NEXTADDR(w, u) \ 17507a23074eSdduvall if (rtm_addrs & (w)) { \ 17517c478bd9Sstevel@tonic-gate l = ROUNDUP_LONG(salen(&u.sa)); \ 17527c478bd9Sstevel@tonic-gate (void) memmove(cp, &(u), l); \ 17537c478bd9Sstevel@tonic-gate cp += l; \ 17547c478bd9Sstevel@tonic-gate if (verbose) \ 17557c478bd9Sstevel@tonic-gate sodump(&(u), #u); \ 17567c478bd9Sstevel@tonic-gate } 17577a23074eSdduvall NEXTADDR(RTA_DST, so_dst); 17587a23074eSdduvall NEXTADDR(RTA_GATEWAY, so_gate); 17597a23074eSdduvall NEXTADDR(RTA_NETMASK, so_mask); 17607a23074eSdduvall NEXTADDR(RTA_IFP, so_ifp); 17617a23074eSdduvall NEXTADDR(RTA_IFA, so_ifa); 17627c478bd9Sstevel@tonic-gate /* 17637c478bd9Sstevel@tonic-gate * RTA_SRC has overloaded meaning. It can represent the 17647c478bd9Sstevel@tonic-gate * src address of incoming or outgoing packets. 17657c478bd9Sstevel@tonic-gate */ 17667a23074eSdduvall NEXTADDR(RTA_SRC, so_src); 17677c478bd9Sstevel@tonic-gate #undef NEXTADDR 17687c478bd9Sstevel@tonic-gate rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; 17697c478bd9Sstevel@tonic-gate if (verbose) 17707c478bd9Sstevel@tonic-gate print_rtmsg(&rtm, l); 17717c478bd9Sstevel@tonic-gate if (debugonly) 17727c478bd9Sstevel@tonic-gate return (0); 17737c478bd9Sstevel@tonic-gate if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 17747c478bd9Sstevel@tonic-gate switch (errno) { 17757c478bd9Sstevel@tonic-gate case ESRCH: 17767c478bd9Sstevel@tonic-gate case EBUSY: 17777c478bd9Sstevel@tonic-gate case ENOBUFS: 17787c478bd9Sstevel@tonic-gate case EEXIST: 17797c478bd9Sstevel@tonic-gate case ENETUNREACH: 17807c478bd9Sstevel@tonic-gate case EHOSTUNREACH: 17817c478bd9Sstevel@tonic-gate case EPERM: 17827c478bd9Sstevel@tonic-gate break; 17837c478bd9Sstevel@tonic-gate default: 17847c478bd9Sstevel@tonic-gate perror(gettext("writing to routing socket")); 17857c478bd9Sstevel@tonic-gate break; 17867c478bd9Sstevel@tonic-gate } 17877c478bd9Sstevel@tonic-gate return (-1); 17887c478bd9Sstevel@tonic-gate } else if (rlen < (int)rtm.rtm_msglen) { 17897c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 17907c478bd9Sstevel@tonic-gate gettext("route: write to routing socket got only %d for " 17917c478bd9Sstevel@tonic-gate "len\n"), rlen); 17927c478bd9Sstevel@tonic-gate return (-1); 17937c478bd9Sstevel@tonic-gate } 17947a23074eSdduvall if (cmd == RTM_GET) { 17957c478bd9Sstevel@tonic-gate do { 17967c478bd9Sstevel@tonic-gate l = read(s, (char *)&m_rtmsg, sizeof (m_rtmsg)); 17977c478bd9Sstevel@tonic-gate } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); 17987c478bd9Sstevel@tonic-gate if (l < 0) { 17997c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 18007c478bd9Sstevel@tonic-gate gettext("route: read from routing socket: %s\n"), 18017c478bd9Sstevel@tonic-gate strerror(errno)); 18027c478bd9Sstevel@tonic-gate } else { 18037a23074eSdduvall print_getmsg(&rtm, l); 18047c478bd9Sstevel@tonic-gate } 18057c478bd9Sstevel@tonic-gate } 18067c478bd9Sstevel@tonic-gate #undef rtm 18077c478bd9Sstevel@tonic-gate return (0); 18087c478bd9Sstevel@tonic-gate } 18097c478bd9Sstevel@tonic-gate 18107c478bd9Sstevel@tonic-gate static char *msgtypes[] = { 18117c478bd9Sstevel@tonic-gate "", 18127c478bd9Sstevel@tonic-gate "RTM_ADD: Add Route", 18137c478bd9Sstevel@tonic-gate "RTM_DELETE: Delete Route", 18147c478bd9Sstevel@tonic-gate "RTM_CHANGE: Change Metrics or flags", 18157c478bd9Sstevel@tonic-gate "RTM_GET: Report Metrics", 18167c478bd9Sstevel@tonic-gate "RTM_LOSING: Kernel Suspects Partitioning", 18177c478bd9Sstevel@tonic-gate "RTM_REDIRECT: Told to use different route", 18187c478bd9Sstevel@tonic-gate "RTM_MISS: Lookup failed on this address", 18197c478bd9Sstevel@tonic-gate "RTM_LOCK: fix specified metrics", 18207c478bd9Sstevel@tonic-gate "RTM_OLDADD: caused by SIOCADDRT", 18217c478bd9Sstevel@tonic-gate "RTM_OLDDEL: caused by SIOCDELRT", 18227c478bd9Sstevel@tonic-gate "RTM_RESOLVE: Route created by cloning", 18237c478bd9Sstevel@tonic-gate "RTM_NEWADDR: address being added to iface", 18247c478bd9Sstevel@tonic-gate "RTM_DELADDR: address being removed from iface", 18257c478bd9Sstevel@tonic-gate "RTM_IFINFO: iface status change", 18267c478bd9Sstevel@tonic-gate 0, 18277c478bd9Sstevel@tonic-gate }; 18287c478bd9Sstevel@tonic-gate 18297c478bd9Sstevel@tonic-gate #define NMSGTYPES (sizeof (msgtypes) / sizeof (msgtypes[0])) 18307c478bd9Sstevel@tonic-gate 18317c478bd9Sstevel@tonic-gate static char metricnames[] = 18327c478bd9Sstevel@tonic-gate "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount" 18337c478bd9Sstevel@tonic-gate "\1mtu"; 18347c478bd9Sstevel@tonic-gate static char routeflags[] = 18357c478bd9Sstevel@tonic-gate "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT" 18367c478bd9Sstevel@tonic-gate "\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE" 18377c478bd9Sstevel@tonic-gate "\016PRIVATE\017PROTO2\020PROTO1\021MULTIRT\022SETSRC"; 18387c478bd9Sstevel@tonic-gate static char ifnetflags[] = 18397c478bd9Sstevel@tonic-gate "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP" 18407c478bd9Sstevel@tonic-gate "\011PPROMISC\012ALLMULTI\013INTELLIGENT\014MULTICAST" 18417c478bd9Sstevel@tonic-gate "\015MULTI_BCAST\016UNNUMBERED\017DHCP\020PRIVATE" 18427c478bd9Sstevel@tonic-gate "\021NOXMIT\022NOLOCAL\023DEPRECATED\024ADDRCONF" 18437c478bd9Sstevel@tonic-gate "\025ROUTER\026NONUD\027ANYCAST\030NORTEXCH\031IPv4\032IPv6" 18447c478bd9Sstevel@tonic-gate "\033MIP\034NOFAILOVER\035FAILED\036STANDBY\037INACTIVE\040OFFLINE" 18457c478bd9Sstevel@tonic-gate "\041XRESOLV\042COS\043PREFERRED\044TEMPORARY"; 18467c478bd9Sstevel@tonic-gate static char addrnames[] = 18477c478bd9Sstevel@tonic-gate "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011SRC"; 18487c478bd9Sstevel@tonic-gate 18497c478bd9Sstevel@tonic-gate void 18507c478bd9Sstevel@tonic-gate print_rtmsg(struct rt_msghdr *rtm, int msglen) 18517c478bd9Sstevel@tonic-gate { 18527c478bd9Sstevel@tonic-gate struct if_msghdr *ifm; 18537c478bd9Sstevel@tonic-gate struct ifa_msghdr *ifam; 18547c478bd9Sstevel@tonic-gate 18557c478bd9Sstevel@tonic-gate if (!verbose) 18567c478bd9Sstevel@tonic-gate return; 18577c478bd9Sstevel@tonic-gate if (rtm->rtm_version != RTM_VERSION) { 18587c478bd9Sstevel@tonic-gate (void) printf("routing message version %d not understood\n", 18597c478bd9Sstevel@tonic-gate rtm->rtm_version); 18607c478bd9Sstevel@tonic-gate return; 18617c478bd9Sstevel@tonic-gate } 18627c478bd9Sstevel@tonic-gate if (rtm->rtm_msglen > (ushort_t)msglen) { 18637c478bd9Sstevel@tonic-gate (void) printf("message length mismatch, in packet %d, " 18647c478bd9Sstevel@tonic-gate "returned %d\n", 18657c478bd9Sstevel@tonic-gate rtm->rtm_msglen, msglen); 18667c478bd9Sstevel@tonic-gate } 18677c478bd9Sstevel@tonic-gate /* 18687c478bd9Sstevel@tonic-gate * Since rtm->rtm_type is unsigned, we'll just check the case of zero 18697c478bd9Sstevel@tonic-gate * and the upper-bound of (NMSGTYPES - 1). 18707c478bd9Sstevel@tonic-gate */ 18717c478bd9Sstevel@tonic-gate if (rtm->rtm_type == 0 || rtm->rtm_type >= (NMSGTYPES - 1)) { 18727c478bd9Sstevel@tonic-gate (void) printf("routing message type %d not understood\n", 18737c478bd9Sstevel@tonic-gate rtm->rtm_type); 18747c478bd9Sstevel@tonic-gate return; 18757c478bd9Sstevel@tonic-gate } 18767c478bd9Sstevel@tonic-gate (void) printf("%s: len %d, ", msgtypes[rtm->rtm_type], rtm->rtm_msglen); 18777c478bd9Sstevel@tonic-gate switch (rtm->rtm_type) { 18787c478bd9Sstevel@tonic-gate case RTM_IFINFO: 18797c478bd9Sstevel@tonic-gate ifm = (struct if_msghdr *)rtm; 18807c478bd9Sstevel@tonic-gate (void) printf("if# %d, flags:", ifm->ifm_index); 18817c478bd9Sstevel@tonic-gate bprintf(stdout, ifm->ifm_flags, ifnetflags); 18827c478bd9Sstevel@tonic-gate pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs); 18837c478bd9Sstevel@tonic-gate break; 18847c478bd9Sstevel@tonic-gate case RTM_NEWADDR: 18857c478bd9Sstevel@tonic-gate case RTM_DELADDR: 18867c478bd9Sstevel@tonic-gate ifam = (struct ifa_msghdr *)rtm; 18877c478bd9Sstevel@tonic-gate (void) printf("metric %d, flags:", ifam->ifam_metric); 18887c478bd9Sstevel@tonic-gate bprintf(stdout, ifam->ifam_flags, routeflags); 18897c478bd9Sstevel@tonic-gate pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs); 18907c478bd9Sstevel@tonic-gate break; 18917c478bd9Sstevel@tonic-gate default: 18927c478bd9Sstevel@tonic-gate (void) printf("pid: %ld, seq %d, errno %d, flags:", 18937c478bd9Sstevel@tonic-gate rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); 18947c478bd9Sstevel@tonic-gate bprintf(stdout, rtm->rtm_flags, routeflags); 18957c478bd9Sstevel@tonic-gate pmsg_common(rtm); 18967c478bd9Sstevel@tonic-gate } 18977c478bd9Sstevel@tonic-gate } 18987c478bd9Sstevel@tonic-gate 18997c478bd9Sstevel@tonic-gate void 19007a23074eSdduvall print_getmsg(struct rt_msghdr *rtm, int msglen) 19017c478bd9Sstevel@tonic-gate { 19027c478bd9Sstevel@tonic-gate struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *src = NULL; 19037c478bd9Sstevel@tonic-gate struct sockaddr_dl *ifp = NULL; 19047c478bd9Sstevel@tonic-gate struct sockaddr *sa; 19057c478bd9Sstevel@tonic-gate char *cp; 19067c478bd9Sstevel@tonic-gate int i; 19077c478bd9Sstevel@tonic-gate 19087a23074eSdduvall (void) printf(" route to: %s\n", routename(&so_dst.sa)); 19097c478bd9Sstevel@tonic-gate if (rtm->rtm_version != RTM_VERSION) { 19107c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 19117c478bd9Sstevel@tonic-gate gettext("routing message version %d not understood\n"), 19127c478bd9Sstevel@tonic-gate rtm->rtm_version); 19137c478bd9Sstevel@tonic-gate return; 19147c478bd9Sstevel@tonic-gate } 19157c478bd9Sstevel@tonic-gate if (rtm->rtm_msglen > (ushort_t)msglen) { 19167c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 19177c478bd9Sstevel@tonic-gate gettext("message length mismatch, in packet %d, " 19187c478bd9Sstevel@tonic-gate "returned %d\n"), rtm->rtm_msglen, msglen); 19197c478bd9Sstevel@tonic-gate } 19207c478bd9Sstevel@tonic-gate if (rtm->rtm_errno) { 19217c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "RTM_GET: %s (errno %d)\n", 19227c478bd9Sstevel@tonic-gate strerror(rtm->rtm_errno), rtm->rtm_errno); 19237c478bd9Sstevel@tonic-gate return; 19247c478bd9Sstevel@tonic-gate } 19257c478bd9Sstevel@tonic-gate cp = ((char *)(rtm + 1)); 19267c478bd9Sstevel@tonic-gate if (rtm->rtm_addrs != 0) { 19277c478bd9Sstevel@tonic-gate for (i = 1; i != 0; i <<= 1) { 19287c478bd9Sstevel@tonic-gate if (i & rtm->rtm_addrs) { 19297c478bd9Sstevel@tonic-gate /* LINTED */ 19307c478bd9Sstevel@tonic-gate sa = (struct sockaddr *)cp; 19317c478bd9Sstevel@tonic-gate switch (i) { 19327c478bd9Sstevel@tonic-gate case RTA_DST: 19337c478bd9Sstevel@tonic-gate dst = sa; 19347c478bd9Sstevel@tonic-gate break; 19357c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 19367c478bd9Sstevel@tonic-gate gate = sa; 19377c478bd9Sstevel@tonic-gate break; 19387c478bd9Sstevel@tonic-gate case RTA_NETMASK: 19397c478bd9Sstevel@tonic-gate mask = sa; 19407c478bd9Sstevel@tonic-gate break; 19417c478bd9Sstevel@tonic-gate case RTA_IFP: 19427c478bd9Sstevel@tonic-gate if (sa->sa_family == AF_LINK && 19437c478bd9Sstevel@tonic-gate ((struct sockaddr_dl *)sa)-> 19447c478bd9Sstevel@tonic-gate sdl_nlen != 0) 19457c478bd9Sstevel@tonic-gate ifp = (struct sockaddr_dl *)sa; 19467c478bd9Sstevel@tonic-gate break; 19477c478bd9Sstevel@tonic-gate case RTA_SRC: 19487c478bd9Sstevel@tonic-gate src = sa; 19497c478bd9Sstevel@tonic-gate break; 19507c478bd9Sstevel@tonic-gate } 19517c478bd9Sstevel@tonic-gate ADVANCE(cp, sa); 19527c478bd9Sstevel@tonic-gate } 19537c478bd9Sstevel@tonic-gate } 19547c478bd9Sstevel@tonic-gate } 19557c478bd9Sstevel@tonic-gate if (dst != NULL && mask != NULL) 19567c478bd9Sstevel@tonic-gate mask->sa_family = dst->sa_family; /* XXX */ 19577c478bd9Sstevel@tonic-gate if (dst != NULL) 19587c478bd9Sstevel@tonic-gate (void) printf("destination: %s\n", routename(dst)); 19597c478bd9Sstevel@tonic-gate if (mask != NULL) { 19607c478bd9Sstevel@tonic-gate boolean_t savenflag = nflag; 19617c478bd9Sstevel@tonic-gate 19627c478bd9Sstevel@tonic-gate nflag = B_TRUE; 19637c478bd9Sstevel@tonic-gate (void) printf(" mask: %s\n", routename(mask)); 19647c478bd9Sstevel@tonic-gate nflag = savenflag; 19657c478bd9Sstevel@tonic-gate } 19667c478bd9Sstevel@tonic-gate if (gate != NULL && rtm->rtm_flags & RTF_GATEWAY) 19677c478bd9Sstevel@tonic-gate (void) printf(" gateway: %s\n", routename(gate)); 19687c478bd9Sstevel@tonic-gate if (src != NULL && rtm->rtm_flags & RTF_SETSRC) 19697c478bd9Sstevel@tonic-gate (void) printf(" setsrc: %s\n", routename(src)); 19707c478bd9Sstevel@tonic-gate if (ifp != NULL) { 19717c478bd9Sstevel@tonic-gate if (verbose) { 19727c478bd9Sstevel@tonic-gate int i; 19737c478bd9Sstevel@tonic-gate 19747c478bd9Sstevel@tonic-gate (void) printf(" interface: %.*s index %d address ", 19757c478bd9Sstevel@tonic-gate ifp->sdl_nlen, ifp->sdl_data, ifp->sdl_index); 19767c478bd9Sstevel@tonic-gate for (i = ifp->sdl_nlen; 19777c478bd9Sstevel@tonic-gate i < ifp->sdl_nlen + ifp->sdl_alen; 19787c478bd9Sstevel@tonic-gate i++) { 19797c478bd9Sstevel@tonic-gate (void) printf("%02x ", 19807c478bd9Sstevel@tonic-gate ifp->sdl_data[i] & 0xFF); 19817c478bd9Sstevel@tonic-gate } 19827c478bd9Sstevel@tonic-gate (void) printf("\n"); 19837c478bd9Sstevel@tonic-gate } else { 19847c478bd9Sstevel@tonic-gate (void) printf(" interface: %.*s\n", 19857c478bd9Sstevel@tonic-gate ifp->sdl_nlen, ifp->sdl_data); 19867c478bd9Sstevel@tonic-gate } 19877c478bd9Sstevel@tonic-gate } 19887c478bd9Sstevel@tonic-gate (void) printf(" flags: "); 19897c478bd9Sstevel@tonic-gate bprintf(stdout, rtm->rtm_flags, routeflags); 19907c478bd9Sstevel@tonic-gate 19917c478bd9Sstevel@tonic-gate #define lock(f) ((rtm->rtm_rmx.rmx_locks & RTV_ ## f) ? 'L' : ' ') 19927c478bd9Sstevel@tonic-gate #define msec(u) (((u) + 500) / 1000) /* usec to msec */ 19937c478bd9Sstevel@tonic-gate 19947c478bd9Sstevel@tonic-gate (void) printf("\n%s\n", " recvpipe sendpipe ssthresh rtt,ms " 19957c478bd9Sstevel@tonic-gate "rttvar,ms hopcount mtu expire"); 19967c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE)); 19977c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE)); 19987c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH)); 19997c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT)); 20007c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR)); 20017c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT)); 20027c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU)); 20037c478bd9Sstevel@tonic-gate if (rtm->rtm_rmx.rmx_expire) 20047c478bd9Sstevel@tonic-gate rtm->rtm_rmx.rmx_expire -= time(0); 20057c478bd9Sstevel@tonic-gate (void) printf("%8d%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE)); 20067c478bd9Sstevel@tonic-gate #undef lock 20077c478bd9Sstevel@tonic-gate #undef msec 20087c478bd9Sstevel@tonic-gate #define RTA_IGN \ 20097c478bd9Sstevel@tonic-gate (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD|RTA_SRC) 20107c478bd9Sstevel@tonic-gate if (verbose) { 20117c478bd9Sstevel@tonic-gate pmsg_common(rtm); 20127c478bd9Sstevel@tonic-gate } else if (rtm->rtm_addrs &~ RTA_IGN) { 20137c478bd9Sstevel@tonic-gate (void) printf("sockaddrs: "); 20147c478bd9Sstevel@tonic-gate bprintf(stdout, rtm->rtm_addrs, addrnames); 20157c478bd9Sstevel@tonic-gate (void) putchar('\n'); 20167c478bd9Sstevel@tonic-gate } 20177c478bd9Sstevel@tonic-gate #undef RTA_IGN 20187c478bd9Sstevel@tonic-gate } 20197c478bd9Sstevel@tonic-gate 20207c478bd9Sstevel@tonic-gate void 20217c478bd9Sstevel@tonic-gate pmsg_common(struct rt_msghdr *rtm) 20227c478bd9Sstevel@tonic-gate { 20237c478bd9Sstevel@tonic-gate (void) printf("\nlocks: "); 20247c478bd9Sstevel@tonic-gate bprintf(stdout, (int)rtm->rtm_rmx.rmx_locks, metricnames); 20257c478bd9Sstevel@tonic-gate (void) printf(" inits: "); 20267c478bd9Sstevel@tonic-gate bprintf(stdout, (int)rtm->rtm_inits, metricnames); 20277c478bd9Sstevel@tonic-gate pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs); 20287c478bd9Sstevel@tonic-gate } 20297c478bd9Sstevel@tonic-gate 20307c478bd9Sstevel@tonic-gate void 20317c478bd9Sstevel@tonic-gate pmsg_addrs(char *cp, int addrs) 20327c478bd9Sstevel@tonic-gate { 20337c478bd9Sstevel@tonic-gate struct sockaddr *sa; 20347c478bd9Sstevel@tonic-gate int i; 20357c478bd9Sstevel@tonic-gate 20367c478bd9Sstevel@tonic-gate if (addrs == 0) 20377c478bd9Sstevel@tonic-gate return; 20387c478bd9Sstevel@tonic-gate (void) printf("\nsockaddrs: "); 20397c478bd9Sstevel@tonic-gate bprintf(stdout, addrs, addrnames); 20407c478bd9Sstevel@tonic-gate (void) putchar('\n'); 20417c478bd9Sstevel@tonic-gate for (i = 1; i != 0; i <<= 1) { 20427c478bd9Sstevel@tonic-gate if (i & addrs) { 20437c478bd9Sstevel@tonic-gate /* LINTED */ 20447c478bd9Sstevel@tonic-gate sa = (struct sockaddr *)cp; 20457c478bd9Sstevel@tonic-gate (void) printf(" %s", routename(sa)); 20467c478bd9Sstevel@tonic-gate ADVANCE(cp, sa); 20477c478bd9Sstevel@tonic-gate } 20487c478bd9Sstevel@tonic-gate } 20497c478bd9Sstevel@tonic-gate (void) putchar('\n'); 20507c478bd9Sstevel@tonic-gate (void) fflush(stdout); 20517c478bd9Sstevel@tonic-gate } 20527c478bd9Sstevel@tonic-gate 20537c478bd9Sstevel@tonic-gate void 20547c478bd9Sstevel@tonic-gate bprintf(FILE *fp, int b, char *s) 20557c478bd9Sstevel@tonic-gate { 20567c478bd9Sstevel@tonic-gate int i; 20577c478bd9Sstevel@tonic-gate boolean_t gotsome = B_FALSE; 20587c478bd9Sstevel@tonic-gate 20597c478bd9Sstevel@tonic-gate if (b == 0) 20607c478bd9Sstevel@tonic-gate return; 20617c478bd9Sstevel@tonic-gate while ((i = *s++) != 0) { 20627c478bd9Sstevel@tonic-gate if (b & (1 << (i - 1))) { 20637c478bd9Sstevel@tonic-gate if (!gotsome) 20647c478bd9Sstevel@tonic-gate i = '<'; 20657c478bd9Sstevel@tonic-gate else 20667c478bd9Sstevel@tonic-gate i = ','; 20677c478bd9Sstevel@tonic-gate (void) putc(i, fp); 20687c478bd9Sstevel@tonic-gate gotsome = B_TRUE; 20697c478bd9Sstevel@tonic-gate for (; (i = *s) > ' '; s++) 20707c478bd9Sstevel@tonic-gate (void) putc(i, fp); 20717c478bd9Sstevel@tonic-gate } else { 20727c478bd9Sstevel@tonic-gate while (*s > ' ') 20737c478bd9Sstevel@tonic-gate s++; 20747c478bd9Sstevel@tonic-gate } 20757c478bd9Sstevel@tonic-gate } 20767c478bd9Sstevel@tonic-gate if (gotsome) 20777c478bd9Sstevel@tonic-gate (void) putc('>', fp); 20787c478bd9Sstevel@tonic-gate } 20797c478bd9Sstevel@tonic-gate 20807c478bd9Sstevel@tonic-gate int 20817c478bd9Sstevel@tonic-gate keyword(char *cp) 20827c478bd9Sstevel@tonic-gate { 20837c478bd9Sstevel@tonic-gate struct keytab *kt = keywords; 20847c478bd9Sstevel@tonic-gate 20857c478bd9Sstevel@tonic-gate while (kt->kt_cp && strcmp(kt->kt_cp, cp)) 20867c478bd9Sstevel@tonic-gate kt++; 20877c478bd9Sstevel@tonic-gate return (kt->kt_i); 20887c478bd9Sstevel@tonic-gate } 20897c478bd9Sstevel@tonic-gate 20907c478bd9Sstevel@tonic-gate void 20917a23074eSdduvall sodump(sup su, char *which) 20927c478bd9Sstevel@tonic-gate { 20937c478bd9Sstevel@tonic-gate static char obuf[INET6_ADDRSTRLEN]; 20947c478bd9Sstevel@tonic-gate 20957c478bd9Sstevel@tonic-gate switch (su->sa.sa_family) { 20967c478bd9Sstevel@tonic-gate case AF_LINK: 20977c478bd9Sstevel@tonic-gate (void) printf("%s: link %s; ", 20987c478bd9Sstevel@tonic-gate which, link_ntoa(&su->sdl)); 20997c478bd9Sstevel@tonic-gate break; 21007c478bd9Sstevel@tonic-gate case AF_INET: 21017c478bd9Sstevel@tonic-gate (void) printf("%s: inet %s; ", 21027c478bd9Sstevel@tonic-gate which, inet_ntoa(su->sin.sin_addr)); 21037c478bd9Sstevel@tonic-gate break; 21047c478bd9Sstevel@tonic-gate case AF_INET6: 21057c478bd9Sstevel@tonic-gate if (inet_ntop(AF_INET6, (void *)&su->sin6.sin6_addr, obuf, 21067c478bd9Sstevel@tonic-gate INET6_ADDRSTRLEN) != NULL) { 21077c478bd9Sstevel@tonic-gate (void) printf("%s: inet6 %s; ", which, obuf); 21087c478bd9Sstevel@tonic-gate break; 21097c478bd9Sstevel@tonic-gate } 21107c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 21117c478bd9Sstevel@tonic-gate default: 21127c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 21137c478bd9Sstevel@tonic-gate /* NOTREACHED */ 21147c478bd9Sstevel@tonic-gate } 21157c478bd9Sstevel@tonic-gate (void) fflush(stdout); 21167c478bd9Sstevel@tonic-gate } 21177c478bd9Sstevel@tonic-gate 21187c478bd9Sstevel@tonic-gate /* States */ 21197c478bd9Sstevel@tonic-gate #define VIRGIN 0 21207c478bd9Sstevel@tonic-gate #define GOTONE 1 21217c478bd9Sstevel@tonic-gate #define GOTTWO 2 21227c478bd9Sstevel@tonic-gate #define RESET 3 21237c478bd9Sstevel@tonic-gate /* Inputs */ 21247c478bd9Sstevel@tonic-gate #define DIGIT (4*0) 21257c478bd9Sstevel@tonic-gate #define END (4*1) 21267c478bd9Sstevel@tonic-gate #define DELIM (4*2) 21277c478bd9Sstevel@tonic-gate #define LETTER (4*3) 21287c478bd9Sstevel@tonic-gate 21297c478bd9Sstevel@tonic-gate void 21307c478bd9Sstevel@tonic-gate sockaddr(char *addr, struct sockaddr *sa) 21317c478bd9Sstevel@tonic-gate { 21327c478bd9Sstevel@tonic-gate char *cp = (char *)sa; 21337c478bd9Sstevel@tonic-gate int size = salen(sa); 21347c478bd9Sstevel@tonic-gate char *cplim = cp + size; 21357c478bd9Sstevel@tonic-gate int byte = 0, state = VIRGIN, new; 21367c478bd9Sstevel@tonic-gate 21377c478bd9Sstevel@tonic-gate (void) memset(cp, 0, size); 21387c478bd9Sstevel@tonic-gate cp++; 21397c478bd9Sstevel@tonic-gate do { 21407c478bd9Sstevel@tonic-gate if ((*addr >= '0') && (*addr <= '9')) { 21417c478bd9Sstevel@tonic-gate new = *addr - '0'; 21427c478bd9Sstevel@tonic-gate } else if ((*addr >= 'a') && (*addr <= 'f')) { 21437c478bd9Sstevel@tonic-gate new = *addr - 'a' + 10; 21447c478bd9Sstevel@tonic-gate } else if ((*addr >= 'A') && (*addr <= 'F')) { 21457c478bd9Sstevel@tonic-gate new = *addr - 'A' + 10; 21467c478bd9Sstevel@tonic-gate } else if (*addr == 0) { 21477c478bd9Sstevel@tonic-gate state |= END; 21487c478bd9Sstevel@tonic-gate } else { 21497c478bd9Sstevel@tonic-gate state |= DELIM; 21507c478bd9Sstevel@tonic-gate } 21517c478bd9Sstevel@tonic-gate addr++; 21527c478bd9Sstevel@tonic-gate switch (state /* | INPUT */) { 21537c478bd9Sstevel@tonic-gate case GOTTWO | DIGIT: 21547c478bd9Sstevel@tonic-gate *cp++ = byte; 21557c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 21567c478bd9Sstevel@tonic-gate case VIRGIN | DIGIT: 21577c478bd9Sstevel@tonic-gate state = GOTONE; byte = new; continue; 21587c478bd9Sstevel@tonic-gate case GOTONE | DIGIT: 21597c478bd9Sstevel@tonic-gate state = GOTTWO; byte = new + (byte << 4); continue; 21607c478bd9Sstevel@tonic-gate default: /* | DELIM */ 21617c478bd9Sstevel@tonic-gate state = VIRGIN; *cp++ = byte; byte = 0; continue; 21627c478bd9Sstevel@tonic-gate case GOTONE | END: 21637c478bd9Sstevel@tonic-gate case GOTTWO | END: 21647c478bd9Sstevel@tonic-gate *cp++ = byte; 21657c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 21667c478bd9Sstevel@tonic-gate case VIRGIN | END: 21677c478bd9Sstevel@tonic-gate break; 21687c478bd9Sstevel@tonic-gate } 21697c478bd9Sstevel@tonic-gate break; 21707c478bd9Sstevel@tonic-gate } while (cp < cplim); 21717c478bd9Sstevel@tonic-gate } 21727c478bd9Sstevel@tonic-gate 21737c478bd9Sstevel@tonic-gate int 21747c478bd9Sstevel@tonic-gate salen(struct sockaddr *sa) 21757c478bd9Sstevel@tonic-gate { 21767c478bd9Sstevel@tonic-gate switch (sa->sa_family) { 21777c478bd9Sstevel@tonic-gate case AF_INET: 21787c478bd9Sstevel@tonic-gate return (sizeof (struct sockaddr_in)); 21797c478bd9Sstevel@tonic-gate case AF_LINK: 21807c478bd9Sstevel@tonic-gate return (sizeof (struct sockaddr_dl)); 21817c478bd9Sstevel@tonic-gate case AF_INET6: 21827c478bd9Sstevel@tonic-gate return (sizeof (struct sockaddr_in6)); 21837c478bd9Sstevel@tonic-gate default: 21847c478bd9Sstevel@tonic-gate return (sizeof (struct sockaddr)); 21857c478bd9Sstevel@tonic-gate } 21867c478bd9Sstevel@tonic-gate } 21877c478bd9Sstevel@tonic-gate 21887c478bd9Sstevel@tonic-gate void 21897c478bd9Sstevel@tonic-gate link_addr(const char *addr, struct sockaddr_dl *sdl) 21907c478bd9Sstevel@tonic-gate { 21917c478bd9Sstevel@tonic-gate char *cp = sdl->sdl_data; 21927c478bd9Sstevel@tonic-gate char *cplim = sizeof (struct sockaddr_dl) + (char *)sdl; 21937c478bd9Sstevel@tonic-gate int byte = 0, state = VIRGIN, new; 21947c478bd9Sstevel@tonic-gate 21957c478bd9Sstevel@tonic-gate (void) memset(sdl, 0, sizeof (struct sockaddr_dl)); 21967c478bd9Sstevel@tonic-gate sdl->sdl_family = AF_LINK; 21977c478bd9Sstevel@tonic-gate do { 21987c478bd9Sstevel@tonic-gate state &= ~LETTER; 21997c478bd9Sstevel@tonic-gate if ((*addr >= '0') && (*addr <= '9')) { 22007c478bd9Sstevel@tonic-gate new = *addr - '0'; 22017c478bd9Sstevel@tonic-gate } else if ((*addr >= 'a') && (*addr <= 'f')) { 22027c478bd9Sstevel@tonic-gate new = *addr - 'a' + 10; 22037c478bd9Sstevel@tonic-gate } else if ((*addr >= 'A') && (*addr <= 'F')) { 22047c478bd9Sstevel@tonic-gate new = *addr - 'A' + 10; 22057c478bd9Sstevel@tonic-gate } else if (*addr == 0) { 22067c478bd9Sstevel@tonic-gate state |= END; 22077c478bd9Sstevel@tonic-gate } else if (state == VIRGIN && 22087c478bd9Sstevel@tonic-gate (((*addr >= 'A') && (*addr <= 'Z')) || 22097c478bd9Sstevel@tonic-gate ((*addr >= 'a') && (*addr <= 'z')))) { 22107c478bd9Sstevel@tonic-gate state |= LETTER; 22117c478bd9Sstevel@tonic-gate } else { 22127c478bd9Sstevel@tonic-gate state |= DELIM; 22137c478bd9Sstevel@tonic-gate } 22147c478bd9Sstevel@tonic-gate addr++; 22157c478bd9Sstevel@tonic-gate switch (state /* | INPUT */) { 22167c478bd9Sstevel@tonic-gate case VIRGIN | DIGIT: 22177c478bd9Sstevel@tonic-gate case VIRGIN | LETTER: 22187c478bd9Sstevel@tonic-gate *cp++ = addr[-1]; 22197c478bd9Sstevel@tonic-gate continue; 22207c478bd9Sstevel@tonic-gate case VIRGIN | DELIM: 22217c478bd9Sstevel@tonic-gate state = RESET; 22227c478bd9Sstevel@tonic-gate sdl->sdl_nlen = cp - sdl->sdl_data; 22237c478bd9Sstevel@tonic-gate continue; 22247c478bd9Sstevel@tonic-gate case GOTTWO | DIGIT: 22257c478bd9Sstevel@tonic-gate *cp++ = byte; 22267c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 22277c478bd9Sstevel@tonic-gate case RESET | DIGIT: 22287c478bd9Sstevel@tonic-gate state = GOTONE; 22297c478bd9Sstevel@tonic-gate byte = new; 22307c478bd9Sstevel@tonic-gate continue; 22317c478bd9Sstevel@tonic-gate case GOTONE | DIGIT: 22327c478bd9Sstevel@tonic-gate state = GOTTWO; 22337c478bd9Sstevel@tonic-gate byte = new + (byte << 4); 22347c478bd9Sstevel@tonic-gate continue; 22357c478bd9Sstevel@tonic-gate default: /* | DELIM */ 22367c478bd9Sstevel@tonic-gate state = RESET; 22377c478bd9Sstevel@tonic-gate *cp++ = byte; 22387c478bd9Sstevel@tonic-gate byte = 0; 22397c478bd9Sstevel@tonic-gate continue; 22407c478bd9Sstevel@tonic-gate case GOTONE | END: 22417c478bd9Sstevel@tonic-gate case GOTTWO | END: 22427c478bd9Sstevel@tonic-gate *cp++ = byte; 22437c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 22447c478bd9Sstevel@tonic-gate case RESET | END: 22457c478bd9Sstevel@tonic-gate break; 22467c478bd9Sstevel@tonic-gate } 22477c478bd9Sstevel@tonic-gate break; 22487c478bd9Sstevel@tonic-gate } while (cp < cplim); 22497c478bd9Sstevel@tonic-gate sdl->sdl_alen = cp - LLADDR(sdl); 22507c478bd9Sstevel@tonic-gate } 22517c478bd9Sstevel@tonic-gate 22527c478bd9Sstevel@tonic-gate static char hexlist[] = "0123456789abcdef"; 22537c478bd9Sstevel@tonic-gate 22547c478bd9Sstevel@tonic-gate char * 22557c478bd9Sstevel@tonic-gate link_ntoa(const struct sockaddr_dl *sdl) 22567c478bd9Sstevel@tonic-gate { 22577c478bd9Sstevel@tonic-gate static char obuf[64]; 22587c478bd9Sstevel@tonic-gate char *out = obuf; 22597c478bd9Sstevel@tonic-gate int i; 22607c478bd9Sstevel@tonic-gate uchar_t *in = (uchar_t *)LLADDR(sdl); 22617c478bd9Sstevel@tonic-gate uchar_t *inlim = in + sdl->sdl_alen; 22627c478bd9Sstevel@tonic-gate boolean_t firsttime = B_TRUE; 22637c478bd9Sstevel@tonic-gate 22647c478bd9Sstevel@tonic-gate if (sdl->sdl_nlen) { 22657c478bd9Sstevel@tonic-gate (void) memcpy(obuf, sdl->sdl_data, sdl->sdl_nlen); 22667c478bd9Sstevel@tonic-gate out += sdl->sdl_nlen; 22677c478bd9Sstevel@tonic-gate if (sdl->sdl_alen) 22687c478bd9Sstevel@tonic-gate *out++ = ':'; 22697c478bd9Sstevel@tonic-gate } 22707c478bd9Sstevel@tonic-gate while (in < inlim) { 22717c478bd9Sstevel@tonic-gate if (firsttime) 22727c478bd9Sstevel@tonic-gate firsttime = B_FALSE; 22737c478bd9Sstevel@tonic-gate else 22747c478bd9Sstevel@tonic-gate *out++ = '.'; 22757c478bd9Sstevel@tonic-gate i = *in++; 22767c478bd9Sstevel@tonic-gate if (i > 0xf) { 22777c478bd9Sstevel@tonic-gate out[1] = hexlist[i & 0xf]; 22787c478bd9Sstevel@tonic-gate i >>= 4; 22797c478bd9Sstevel@tonic-gate out[0] = hexlist[i]; 22807c478bd9Sstevel@tonic-gate out += 2; 22817c478bd9Sstevel@tonic-gate } else { 22827c478bd9Sstevel@tonic-gate *out++ = hexlist[i]; 22837c478bd9Sstevel@tonic-gate } 22847c478bd9Sstevel@tonic-gate } 22857c478bd9Sstevel@tonic-gate *out = 0; 22867c478bd9Sstevel@tonic-gate return (obuf); 22877c478bd9Sstevel@tonic-gate } 22887c478bd9Sstevel@tonic-gate 22897c478bd9Sstevel@tonic-gate static mib_item_t * 22907c478bd9Sstevel@tonic-gate mibget(int sd) 22917c478bd9Sstevel@tonic-gate { 22927c478bd9Sstevel@tonic-gate intmax_t buf[512 / sizeof (intmax_t)]; 22937c478bd9Sstevel@tonic-gate int flags; 22947c478bd9Sstevel@tonic-gate int i, j, getcode; 22957c478bd9Sstevel@tonic-gate struct strbuf ctlbuf, databuf; 22967c478bd9Sstevel@tonic-gate struct T_optmgmt_req *tor = (struct T_optmgmt_req *)buf; 22977c478bd9Sstevel@tonic-gate struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *)buf; 22987c478bd9Sstevel@tonic-gate struct T_error_ack *tea = (struct T_error_ack *)buf; 22997c478bd9Sstevel@tonic-gate struct opthdr *req; 23007c478bd9Sstevel@tonic-gate mib_item_t *first_item = NULL; 23017c478bd9Sstevel@tonic-gate mib_item_t *last_item = NULL; 23027c478bd9Sstevel@tonic-gate mib_item_t *temp; 23037c478bd9Sstevel@tonic-gate 23047c478bd9Sstevel@tonic-gate tor->PRIM_type = T_SVR4_OPTMGMT_REQ; 23057c478bd9Sstevel@tonic-gate tor->OPT_offset = sizeof (struct T_optmgmt_req); 23067c478bd9Sstevel@tonic-gate tor->OPT_length = sizeof (struct opthdr); 23077c478bd9Sstevel@tonic-gate tor->MGMT_flags = T_CURRENT; 23087c478bd9Sstevel@tonic-gate req = (struct opthdr *)&tor[1]; 23097c478bd9Sstevel@tonic-gate req->level = MIB2_IP; /* any MIB2_xxx value ok here */ 23107c478bd9Sstevel@tonic-gate req->name = 0; 23117c478bd9Sstevel@tonic-gate req->len = 0; 23127c478bd9Sstevel@tonic-gate 23137c478bd9Sstevel@tonic-gate ctlbuf.buf = (char *)buf; 23147c478bd9Sstevel@tonic-gate ctlbuf.len = tor->OPT_length + tor->OPT_offset; 23157c478bd9Sstevel@tonic-gate flags = 0; 23167c478bd9Sstevel@tonic-gate if (putmsg(sd, &ctlbuf, NULL, flags) < 0) { 23177c478bd9Sstevel@tonic-gate perror("mibget: putmsg (ctl)"); 23187c478bd9Sstevel@tonic-gate return (NULL); 23197c478bd9Sstevel@tonic-gate } 23207c478bd9Sstevel@tonic-gate /* 23217c478bd9Sstevel@tonic-gate * each reply consists of a ctl part for one fixed structure 23227c478bd9Sstevel@tonic-gate * or table, as defined in mib2.h. The format is a T_OPTMGMT_ACK, 23237c478bd9Sstevel@tonic-gate * containing an opthdr structure. level/name identify the entry, 23247c478bd9Sstevel@tonic-gate * len is the size of the data part of the message. 23257c478bd9Sstevel@tonic-gate */ 23267c478bd9Sstevel@tonic-gate req = (struct opthdr *)&toa[1]; 23277c478bd9Sstevel@tonic-gate ctlbuf.maxlen = sizeof (buf); 23287c478bd9Sstevel@tonic-gate for (j = 1; ; j++) { 23297c478bd9Sstevel@tonic-gate flags = 0; 23307c478bd9Sstevel@tonic-gate getcode = getmsg(sd, &ctlbuf, NULL, &flags); 23317c478bd9Sstevel@tonic-gate if (getcode < 0) { 23327c478bd9Sstevel@tonic-gate perror("mibget: getmsg (ctl)"); 23337c478bd9Sstevel@tonic-gate if (verbose) { 23347c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 23357c478bd9Sstevel@tonic-gate "# level name len\n"); 23367c478bd9Sstevel@tonic-gate i = 0; 23377c478bd9Sstevel@tonic-gate for (last_item = first_item; last_item != NULL; 23387c478bd9Sstevel@tonic-gate last_item = last_item->next_item) { 23397c478bd9Sstevel@tonic-gate (void) printf("%d %4ld %5ld %ld\n", 23407c478bd9Sstevel@tonic-gate ++i, last_item->group, 23417c478bd9Sstevel@tonic-gate last_item->mib_id, 23427c478bd9Sstevel@tonic-gate last_item->length); 23437c478bd9Sstevel@tonic-gate } 23447c478bd9Sstevel@tonic-gate } 23457c478bd9Sstevel@tonic-gate break; 23467c478bd9Sstevel@tonic-gate } 23477c478bd9Sstevel@tonic-gate if (getcode == 0 && 23487c478bd9Sstevel@tonic-gate ctlbuf.len >= sizeof (struct T_optmgmt_ack) && 23497c478bd9Sstevel@tonic-gate toa->PRIM_type == T_OPTMGMT_ACK && 23507c478bd9Sstevel@tonic-gate toa->MGMT_flags == T_SUCCESS && 23517c478bd9Sstevel@tonic-gate req->len == 0) { 23527c478bd9Sstevel@tonic-gate if (verbose) { 23537c478bd9Sstevel@tonic-gate (void) printf("mibget getmsg() %d returned EOD " 23547c478bd9Sstevel@tonic-gate "(level %lu, name %lu)\n", j, req->level, 23557c478bd9Sstevel@tonic-gate req->name); 23567c478bd9Sstevel@tonic-gate } 23577c478bd9Sstevel@tonic-gate return (first_item); /* this is EOD msg */ 23587c478bd9Sstevel@tonic-gate } 23597c478bd9Sstevel@tonic-gate 23607c478bd9Sstevel@tonic-gate if (ctlbuf.len >= sizeof (struct T_error_ack) && 23617c478bd9Sstevel@tonic-gate tea->PRIM_type == T_ERROR_ACK) { 23627c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("mibget %d gives " 23637c478bd9Sstevel@tonic-gate "T_ERROR_ACK: TLI_error = 0x%lx, UNIX_error = " 23647c478bd9Sstevel@tonic-gate "0x%lx\n"), j, tea->TLI_error, tea->UNIX_error); 23657c478bd9Sstevel@tonic-gate errno = (tea->TLI_error == TSYSERR) 23667c478bd9Sstevel@tonic-gate ? tea->UNIX_error : EPROTO; 23677c478bd9Sstevel@tonic-gate break; 23687c478bd9Sstevel@tonic-gate } 23697c478bd9Sstevel@tonic-gate 23707c478bd9Sstevel@tonic-gate if (getcode != MOREDATA || 23717c478bd9Sstevel@tonic-gate ctlbuf.len < sizeof (struct T_optmgmt_ack) || 23727c478bd9Sstevel@tonic-gate toa->PRIM_type != T_OPTMGMT_ACK || 23737c478bd9Sstevel@tonic-gate toa->MGMT_flags != T_SUCCESS) { 23747c478bd9Sstevel@tonic-gate (void) printf("mibget getmsg(ctl) %d returned %d, " 23757c478bd9Sstevel@tonic-gate "ctlbuf.len = %d, PRIM_type = %ld\n", 23767c478bd9Sstevel@tonic-gate j, getcode, ctlbuf.len, toa->PRIM_type); 23777c478bd9Sstevel@tonic-gate if (toa->PRIM_type == T_OPTMGMT_ACK) { 23787c478bd9Sstevel@tonic-gate (void) printf("T_OPTMGMT_ACK: " 23797c478bd9Sstevel@tonic-gate "MGMT_flags = 0x%lx, req->len = %ld\n", 23807c478bd9Sstevel@tonic-gate toa->MGMT_flags, req->len); 23817c478bd9Sstevel@tonic-gate } 23827c478bd9Sstevel@tonic-gate errno = ENOMSG; 23837c478bd9Sstevel@tonic-gate break; 23847c478bd9Sstevel@tonic-gate } 23857c478bd9Sstevel@tonic-gate 23867c478bd9Sstevel@tonic-gate temp = malloc(sizeof (mib_item_t)); 23877c478bd9Sstevel@tonic-gate if (temp == NULL) { 23887c478bd9Sstevel@tonic-gate perror("mibget: malloc"); 23897c478bd9Sstevel@tonic-gate break; 23907c478bd9Sstevel@tonic-gate } 23917c478bd9Sstevel@tonic-gate if (last_item != NULL) 23927c478bd9Sstevel@tonic-gate last_item->next_item = temp; 23937c478bd9Sstevel@tonic-gate else 23947c478bd9Sstevel@tonic-gate first_item = temp; 23957c478bd9Sstevel@tonic-gate last_item = temp; 23967c478bd9Sstevel@tonic-gate last_item->next_item = NULL; 23977c478bd9Sstevel@tonic-gate last_item->group = req->level; 23987c478bd9Sstevel@tonic-gate last_item->mib_id = req->name; 23997c478bd9Sstevel@tonic-gate last_item->length = req->len; 24007c478bd9Sstevel@tonic-gate last_item->valp = malloc(req->len); 24017c478bd9Sstevel@tonic-gate if (verbose) { 24027c478bd9Sstevel@tonic-gate (void) printf("msg %d: group = %4ld mib_id = %5ld " 24037c478bd9Sstevel@tonic-gate "length = %ld\n", 24047c478bd9Sstevel@tonic-gate j, last_item->group, last_item->mib_id, 24057c478bd9Sstevel@tonic-gate last_item->length); 24067c478bd9Sstevel@tonic-gate } 24077c478bd9Sstevel@tonic-gate 24087c478bd9Sstevel@tonic-gate databuf.maxlen = last_item->length; 24097c478bd9Sstevel@tonic-gate databuf.buf = (char *)last_item->valp; 24107c478bd9Sstevel@tonic-gate databuf.len = 0; 24117c478bd9Sstevel@tonic-gate flags = 0; 24127c478bd9Sstevel@tonic-gate getcode = getmsg(sd, NULL, &databuf, &flags); 24137c478bd9Sstevel@tonic-gate if (getcode < 0) { 24147c478bd9Sstevel@tonic-gate perror("mibget: getmsg (data)"); 24157c478bd9Sstevel@tonic-gate break; 24167c478bd9Sstevel@tonic-gate } else if (getcode != 0) { 24177c478bd9Sstevel@tonic-gate (void) printf("mibget getmsg(data) returned %d, " 24187c478bd9Sstevel@tonic-gate "databuf.maxlen = %d, databuf.len = %d\n", 24197c478bd9Sstevel@tonic-gate getcode, databuf.maxlen, databuf.len); 24207c478bd9Sstevel@tonic-gate break; 24217c478bd9Sstevel@tonic-gate } 24227c478bd9Sstevel@tonic-gate } 24237c478bd9Sstevel@tonic-gate 24247c478bd9Sstevel@tonic-gate /* 24257c478bd9Sstevel@tonic-gate * On error, free all the allocated mib_item_t objects. 24267c478bd9Sstevel@tonic-gate */ 24277c478bd9Sstevel@tonic-gate while (first_item != NULL) { 24287c478bd9Sstevel@tonic-gate last_item = first_item; 24297c478bd9Sstevel@tonic-gate first_item = first_item->next_item; 24307c478bd9Sstevel@tonic-gate free(last_item); 24317c478bd9Sstevel@tonic-gate } 24327c478bd9Sstevel@tonic-gate return (NULL); 24337c478bd9Sstevel@tonic-gate } 2434