17c478bd9Sstevel@tonic-gate /* 2*7a23074eSdduvall * Copyright 2003 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> 56*7a23074eSdduvall #include <sys/sysmacros.h> 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate #include <net/if.h> 597c478bd9Sstevel@tonic-gate #include <net/route.h> 607c478bd9Sstevel@tonic-gate #include <net/if_dl.h> 617c478bd9Sstevel@tonic-gate #include <netinet/in.h> 627c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 637c478bd9Sstevel@tonic-gate #include <netdb.h> 647c478bd9Sstevel@tonic-gate #include <inet/mib2.h> 657c478bd9Sstevel@tonic-gate #include <inet/ip.h> 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate #include <locale.h> 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate #include <errno.h> 707c478bd9Sstevel@tonic-gate #include <unistd.h> 717c478bd9Sstevel@tonic-gate #include <stdio.h> 727c478bd9Sstevel@tonic-gate #include <stdlib.h> 737c478bd9Sstevel@tonic-gate #include <string.h> 747c478bd9Sstevel@tonic-gate #include <stropts.h> 757c478bd9Sstevel@tonic-gate #include <fcntl.h> 767c478bd9Sstevel@tonic-gate #include <assert.h> 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate static struct keytab { 797c478bd9Sstevel@tonic-gate char *kt_cp; 807c478bd9Sstevel@tonic-gate int kt_i; 817c478bd9Sstevel@tonic-gate } keywords[] = { 827c478bd9Sstevel@tonic-gate #define K_ADD 1 837c478bd9Sstevel@tonic-gate {"add", K_ADD}, 847c478bd9Sstevel@tonic-gate #define K_BLACKHOLE 2 857c478bd9Sstevel@tonic-gate {"blackhole", K_BLACKHOLE}, 867c478bd9Sstevel@tonic-gate #define K_CHANGE 3 877c478bd9Sstevel@tonic-gate {"change", K_CHANGE}, 887c478bd9Sstevel@tonic-gate #define K_CLONING 4 897c478bd9Sstevel@tonic-gate {"cloning", K_CLONING}, 907c478bd9Sstevel@tonic-gate #define K_DELETE 5 917c478bd9Sstevel@tonic-gate {"delete", K_DELETE}, 927c478bd9Sstevel@tonic-gate #define K_DST 6 937c478bd9Sstevel@tonic-gate {"dst", K_DST}, 947c478bd9Sstevel@tonic-gate #define K_EXPIRE 7 957c478bd9Sstevel@tonic-gate {"expire", K_EXPIRE}, 967c478bd9Sstevel@tonic-gate #define K_FLUSH 8 977c478bd9Sstevel@tonic-gate {"flush", K_FLUSH}, 987c478bd9Sstevel@tonic-gate #define K_GATEWAY 9 997c478bd9Sstevel@tonic-gate {"gateway", K_GATEWAY}, 1007c478bd9Sstevel@tonic-gate #define K_GET 11 1017c478bd9Sstevel@tonic-gate {"get", K_GET}, 1027c478bd9Sstevel@tonic-gate #define K_HOPCOUNT 12 1037c478bd9Sstevel@tonic-gate {"hopcount", K_HOPCOUNT}, 1047c478bd9Sstevel@tonic-gate #define K_HOST 13 1057c478bd9Sstevel@tonic-gate {"host", K_HOST}, 1067c478bd9Sstevel@tonic-gate #define K_IFA 14 1077c478bd9Sstevel@tonic-gate {"ifa", K_IFA}, 1087c478bd9Sstevel@tonic-gate #define K_IFACE 15 1097c478bd9Sstevel@tonic-gate {"iface", K_IFACE}, 1107c478bd9Sstevel@tonic-gate #define K_IFP 16 1117c478bd9Sstevel@tonic-gate {"ifp", K_IFP}, 1127c478bd9Sstevel@tonic-gate #define K_INET 17 1137c478bd9Sstevel@tonic-gate {"inet", K_INET}, 1147c478bd9Sstevel@tonic-gate #define K_INET6 18 1157c478bd9Sstevel@tonic-gate {"inet6", K_INET6}, 1167c478bd9Sstevel@tonic-gate #define K_INTERFACE 19 1177c478bd9Sstevel@tonic-gate {"interface", K_INTERFACE}, 1187c478bd9Sstevel@tonic-gate #define K_LINK 20 1197c478bd9Sstevel@tonic-gate {"link", K_LINK}, 1207c478bd9Sstevel@tonic-gate #define K_LOCK 21 1217c478bd9Sstevel@tonic-gate {"lock", K_LOCK}, 1227c478bd9Sstevel@tonic-gate #define K_LOCKREST 22 1237c478bd9Sstevel@tonic-gate {"lockrest", K_LOCKREST}, 1247c478bd9Sstevel@tonic-gate #define K_MASK 23 1257c478bd9Sstevel@tonic-gate {"mask", K_MASK}, 1267c478bd9Sstevel@tonic-gate #define K_MONITOR 24 1277c478bd9Sstevel@tonic-gate {"monitor", K_MONITOR}, 1287c478bd9Sstevel@tonic-gate #define K_MTU 25 1297c478bd9Sstevel@tonic-gate {"mtu", K_MTU}, 1307c478bd9Sstevel@tonic-gate #define K_NET 26 1317c478bd9Sstevel@tonic-gate {"net", K_NET}, 1327c478bd9Sstevel@tonic-gate #define K_NETMASK 27 1337c478bd9Sstevel@tonic-gate {"netmask", K_NETMASK}, 1347c478bd9Sstevel@tonic-gate #define K_NOSTATIC 28 1357c478bd9Sstevel@tonic-gate {"nostatic", K_NOSTATIC}, 1367c478bd9Sstevel@tonic-gate #define K_PRIVATE 29 1377c478bd9Sstevel@tonic-gate {"private", K_PRIVATE}, 1387c478bd9Sstevel@tonic-gate #define K_PROTO1 30 1397c478bd9Sstevel@tonic-gate {"proto1", K_PROTO1}, 1407c478bd9Sstevel@tonic-gate #define K_PROTO2 31 1417c478bd9Sstevel@tonic-gate {"proto2", K_PROTO2}, 1427c478bd9Sstevel@tonic-gate #define K_RECVPIPE 32 1437c478bd9Sstevel@tonic-gate {"recvpipe", K_RECVPIPE}, 1447c478bd9Sstevel@tonic-gate #define K_REJECT 33 1457c478bd9Sstevel@tonic-gate {"reject", K_REJECT}, 1467c478bd9Sstevel@tonic-gate #define K_RTT 34 1477c478bd9Sstevel@tonic-gate {"rtt", K_RTT}, 1487c478bd9Sstevel@tonic-gate #define K_RTTVAR 35 1497c478bd9Sstevel@tonic-gate {"rttvar", K_RTTVAR}, 1507c478bd9Sstevel@tonic-gate #define K_SA 36 1517c478bd9Sstevel@tonic-gate {"sa", K_SA}, 1527c478bd9Sstevel@tonic-gate #define K_SENDPIPE 37 1537c478bd9Sstevel@tonic-gate {"sendpipe", K_SENDPIPE}, 1547c478bd9Sstevel@tonic-gate #define K_SSTHRESH 38 1557c478bd9Sstevel@tonic-gate {"ssthresh", K_SSTHRESH}, 1567c478bd9Sstevel@tonic-gate #define K_STATIC 39 1577c478bd9Sstevel@tonic-gate {"static", K_STATIC}, 1587c478bd9Sstevel@tonic-gate #define K_XRESOLVE 40 1597c478bd9Sstevel@tonic-gate {"xresolve", K_XRESOLVE}, 1607c478bd9Sstevel@tonic-gate #define K_MULTIRT 41 1617c478bd9Sstevel@tonic-gate {"multirt", K_MULTIRT}, 1627c478bd9Sstevel@tonic-gate #define K_SETSRC 42 1637c478bd9Sstevel@tonic-gate {"setsrc", K_SETSRC}, 1647c478bd9Sstevel@tonic-gate {0, 0} 1657c478bd9Sstevel@tonic-gate }; 1667c478bd9Sstevel@tonic-gate 167*7a23074eSdduvall static union sockunion { 1687c478bd9Sstevel@tonic-gate struct sockaddr sa; 1697c478bd9Sstevel@tonic-gate struct sockaddr_in sin; 1707c478bd9Sstevel@tonic-gate struct sockaddr_dl sdl; 1717c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin6; 172*7a23074eSdduvall } so_dst, so_gate, so_mask, so_ifa, so_ifp, so_src; 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate typedef struct mib_item_s { 1757c478bd9Sstevel@tonic-gate struct mib_item_s *next_item; 1767c478bd9Sstevel@tonic-gate long group; 1777c478bd9Sstevel@tonic-gate long mib_id; 1787c478bd9Sstevel@tonic-gate long length; 1797c478bd9Sstevel@tonic-gate intmax_t *valp; 1807c478bd9Sstevel@tonic-gate } mib_item_t; 1817c478bd9Sstevel@tonic-gate 182*7a23074eSdduvall typedef union sockunion *sup; 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate static void bprintf(FILE *fp, int b, char *s); 1857c478bd9Sstevel@tonic-gate static void delRouteEntry(mib2_ipRouteEntry_t *rp, 1867c478bd9Sstevel@tonic-gate mib2_ipv6RouteEntry_t *rp6, int seqno); 1877c478bd9Sstevel@tonic-gate static void flushroutes(int argc, char *argv[]); 188*7a23074eSdduvall static boolean_t getaddr(int which, char *s, struct hostent **hpp); 1897c478bd9Sstevel@tonic-gate static boolean_t in6_getaddr(char *s, struct sockaddr_in6 *sin6, 1907c478bd9Sstevel@tonic-gate int *plenp, struct hostent **hpp); 1917c478bd9Sstevel@tonic-gate static boolean_t in_getaddr(char *s, struct sockaddr_in *sin, 192*7a23074eSdduvall int *plenp, int which, struct hostent **hpp); 1937c478bd9Sstevel@tonic-gate static int in_getprefixlen(char *addr, int max_plen); 1947c478bd9Sstevel@tonic-gate static boolean_t in_prefixlentomask(int prefixlen, int maxlen, 1957c478bd9Sstevel@tonic-gate uchar_t *mask); 196*7a23074eSdduvall static void inet_makenetandmask(in_addr_t net, 1977c478bd9Sstevel@tonic-gate struct sockaddr_in *sin); 1987c478bd9Sstevel@tonic-gate static in_addr_t inet_makesubnetmask(in_addr_t addr, in_addr_t mask); 1997c478bd9Sstevel@tonic-gate static int keyword(char *cp); 2007c478bd9Sstevel@tonic-gate static void link_addr(const char *addr, struct sockaddr_dl *sdl); 2017c478bd9Sstevel@tonic-gate static char *link_ntoa(const struct sockaddr_dl *sdl); 2027c478bd9Sstevel@tonic-gate static mib_item_t *mibget(int sd); 2037c478bd9Sstevel@tonic-gate static char *netname(struct sockaddr *sa); 204*7a23074eSdduvall static int newroute(int argc, char **argv); 2057c478bd9Sstevel@tonic-gate static void pmsg_addrs(char *cp, int addrs); 2067c478bd9Sstevel@tonic-gate static void pmsg_common(struct rt_msghdr *rtm); 207*7a23074eSdduvall static void print_getmsg(struct rt_msghdr *rtm, int msglen); 2087c478bd9Sstevel@tonic-gate static void print_rtmsg(struct rt_msghdr *rtm, int msglen); 2097c478bd9Sstevel@tonic-gate static void quit(char *s, int err); 2107c478bd9Sstevel@tonic-gate static char *routename(struct sockaddr *sa); 2117c478bd9Sstevel@tonic-gate static void rtmonitor(int argc, char *argv[]); 212*7a23074eSdduvall static int rtmsg(int cmd, int flags); 2137c478bd9Sstevel@tonic-gate static int salen(struct sockaddr *sa); 214*7a23074eSdduvall static void set_metric(char *value, int key); 2157c478bd9Sstevel@tonic-gate static void sockaddr(char *addr, struct sockaddr *sa); 216*7a23074eSdduvall static void sodump(sup su, char *which); 2177c478bd9Sstevel@tonic-gate static void usage(char *cp); 2187c478bd9Sstevel@tonic-gate 219*7a23074eSdduvall static int pid, rtm_addrs; 2207c478bd9Sstevel@tonic-gate static int s; 221*7a23074eSdduvall static boolean_t forcehost, forcenet, nflag; 2227c478bd9Sstevel@tonic-gate static int af = AF_INET; 2237c478bd9Sstevel@tonic-gate static boolean_t qflag, tflag; 224*7a23074eSdduvall static boolean_t iflag, verbose; 225*7a23074eSdduvall static boolean_t locking, lockrest, debugonly; 2267c478bd9Sstevel@tonic-gate static boolean_t fflag; 227*7a23074eSdduvall static struct rt_metrics rt_metrics; 228*7a23074eSdduvall static ulong_t rtm_inits; 229*7a23074eSdduvall static int masklen; 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate static struct { 2327c478bd9Sstevel@tonic-gate struct rt_msghdr m_rtm; 2337c478bd9Sstevel@tonic-gate char m_space[512]; 2347c478bd9Sstevel@tonic-gate } m_rtmsg; 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate /* 2377c478bd9Sstevel@tonic-gate * Sizes of data structures extracted from the base mib. 2387c478bd9Sstevel@tonic-gate * This allows the size of the tables entries to grow while preserving 2397c478bd9Sstevel@tonic-gate * binary compatibility. 2407c478bd9Sstevel@tonic-gate */ 2417c478bd9Sstevel@tonic-gate static int ipRouteEntrySize; 2427c478bd9Sstevel@tonic-gate static int ipv6RouteEntrySize; 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate #define ROUNDUP_LONG(a) \ 2457c478bd9Sstevel@tonic-gate ((a) > 0 ? (1 + (((a) - 1) | (sizeof (long) - 1))) : sizeof (long)) 2467c478bd9Sstevel@tonic-gate #define ADVANCE(x, n) ((x) += ROUNDUP_LONG(salen(n))) 2477c478bd9Sstevel@tonic-gate #define C(x) ((x) & 0xff) 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate /* 2507c478bd9Sstevel@tonic-gate * return values from in_getprefixlen() 2517c478bd9Sstevel@tonic-gate */ 2527c478bd9Sstevel@tonic-gate #define BAD_ADDR -1 /* prefix is invalid */ 2537c478bd9Sstevel@tonic-gate #define NO_PREFIX -2 /* no prefix was found */ 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate void 2567c478bd9Sstevel@tonic-gate usage(char *cp) 2577c478bd9Sstevel@tonic-gate { 258*7a23074eSdduvall if (cp != NULL) 2597c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("route: botched keyword: %s\n"), 2607c478bd9Sstevel@tonic-gate cp); 261*7a23074eSdduvall (void) fprintf(stderr, 262*7a23074eSdduvall gettext("usage: route [ -fnqv ] cmd [[ -<qualifers> ] args ]\n")); 2637c478bd9Sstevel@tonic-gate exit(1); 2647c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2657c478bd9Sstevel@tonic-gate } 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate void 2687c478bd9Sstevel@tonic-gate quit(char *s, int sverrno) 2697c478bd9Sstevel@tonic-gate { 2707c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "route: "); 2717c478bd9Sstevel@tonic-gate if (s != NULL) 2727c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", s); 2737c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s\n", strerror(sverrno)); 2747c478bd9Sstevel@tonic-gate exit(sverrno); 2757c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate int 2797c478bd9Sstevel@tonic-gate main(int argc, char **argv) 2807c478bd9Sstevel@tonic-gate { 2817c478bd9Sstevel@tonic-gate extern int optind; 2827c478bd9Sstevel@tonic-gate int ch; 2837c478bd9Sstevel@tonic-gate int key; 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 2887c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 2897c478bd9Sstevel@tonic-gate #endif 2907c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate if (argc < 2) 2937c478bd9Sstevel@tonic-gate usage((char *)NULL); 2947c478bd9Sstevel@tonic-gate 295*7a23074eSdduvall while ((ch = getopt(argc, argv, "nqdtvf")) != EOF) { 2967c478bd9Sstevel@tonic-gate switch (ch) { 2977c478bd9Sstevel@tonic-gate case 'n': 2987c478bd9Sstevel@tonic-gate nflag = B_TRUE; 2997c478bd9Sstevel@tonic-gate break; 3007c478bd9Sstevel@tonic-gate case 'q': 3017c478bd9Sstevel@tonic-gate qflag = B_TRUE; 3027c478bd9Sstevel@tonic-gate break; 3037c478bd9Sstevel@tonic-gate case 'v': 3047c478bd9Sstevel@tonic-gate verbose = B_TRUE; 3057c478bd9Sstevel@tonic-gate break; 3067c478bd9Sstevel@tonic-gate case 't': 3077c478bd9Sstevel@tonic-gate tflag = B_TRUE; 3087c478bd9Sstevel@tonic-gate break; 3097c478bd9Sstevel@tonic-gate case 'd': 3107c478bd9Sstevel@tonic-gate debugonly = B_TRUE; 3117c478bd9Sstevel@tonic-gate break; 3127c478bd9Sstevel@tonic-gate case 'f': 3137c478bd9Sstevel@tonic-gate fflag = B_TRUE; 3147c478bd9Sstevel@tonic-gate break; 3157c478bd9Sstevel@tonic-gate case '?': 3167c478bd9Sstevel@tonic-gate default: 3177c478bd9Sstevel@tonic-gate usage((char *)NULL); 3187c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3197c478bd9Sstevel@tonic-gate } 3207c478bd9Sstevel@tonic-gate } 3217c478bd9Sstevel@tonic-gate argc -= optind; 3227c478bd9Sstevel@tonic-gate argv += optind; 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate pid = getpid(); 3257c478bd9Sstevel@tonic-gate if (tflag) 3267c478bd9Sstevel@tonic-gate s = open("/dev/null", O_WRONLY); 3277c478bd9Sstevel@tonic-gate else 3287c478bd9Sstevel@tonic-gate s = socket(PF_ROUTE, SOCK_RAW, 0); 3297c478bd9Sstevel@tonic-gate if (s < 0) 3307c478bd9Sstevel@tonic-gate quit("socket", errno); 3317c478bd9Sstevel@tonic-gate if (fflag) { 3327c478bd9Sstevel@tonic-gate /* 3337c478bd9Sstevel@tonic-gate * Accept an address family keyword after the -f. Since the 3347c478bd9Sstevel@tonic-gate * default address family is AF_INET, reassign af only for the 3357c478bd9Sstevel@tonic-gate * other valid address families. 3367c478bd9Sstevel@tonic-gate */ 3377c478bd9Sstevel@tonic-gate if (*argv != NULL) { 3387c478bd9Sstevel@tonic-gate switch (key = keyword(*argv)) { 3397c478bd9Sstevel@tonic-gate case K_INET: 3407c478bd9Sstevel@tonic-gate case K_INET6: 3417c478bd9Sstevel@tonic-gate if (key == K_INET6) 3427c478bd9Sstevel@tonic-gate af = AF_INET6; 3437c478bd9Sstevel@tonic-gate /* Skip over the address family parameter. */ 3447c478bd9Sstevel@tonic-gate argc--; 3457c478bd9Sstevel@tonic-gate argv++; 3467c478bd9Sstevel@tonic-gate break; 3477c478bd9Sstevel@tonic-gate } 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate flushroutes(0, NULL); 3507c478bd9Sstevel@tonic-gate } 3517c478bd9Sstevel@tonic-gate if (*argv != NULL) { 3527c478bd9Sstevel@tonic-gate switch (keyword(*argv)) { 3537c478bd9Sstevel@tonic-gate case K_GET: 3547c478bd9Sstevel@tonic-gate case K_CHANGE: 3557c478bd9Sstevel@tonic-gate case K_ADD: 3567c478bd9Sstevel@tonic-gate case K_DELETE: 357*7a23074eSdduvall return (newroute(argc, argv)); 358*7a23074eSdduvall 3597c478bd9Sstevel@tonic-gate case K_MONITOR: 3607c478bd9Sstevel@tonic-gate rtmonitor(argc, argv); 3617c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate case K_FLUSH: 3647c478bd9Sstevel@tonic-gate flushroutes(argc, argv); 365*7a23074eSdduvall exit(0); 366*7a23074eSdduvall /* NOTREACHED */ 3677c478bd9Sstevel@tonic-gate } 3687c478bd9Sstevel@tonic-gate } 3697c478bd9Sstevel@tonic-gate if (!fflag) 3707c478bd9Sstevel@tonic-gate usage(*argv); 3717c478bd9Sstevel@tonic-gate return (0); 3727c478bd9Sstevel@tonic-gate } 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate /* 3757c478bd9Sstevel@tonic-gate * Purge all entries in the routing tables not 3767c478bd9Sstevel@tonic-gate * associated with network interfaces. 3777c478bd9Sstevel@tonic-gate */ 3787c478bd9Sstevel@tonic-gate void 3797c478bd9Sstevel@tonic-gate flushroutes(int argc, char *argv[]) 3807c478bd9Sstevel@tonic-gate { 3817c478bd9Sstevel@tonic-gate int seqno; 3827c478bd9Sstevel@tonic-gate int sd; /* mib stream */ 3837c478bd9Sstevel@tonic-gate mib_item_t *item; 3847c478bd9Sstevel@tonic-gate mib2_ipRouteEntry_t *rp; 3857c478bd9Sstevel@tonic-gate mib2_ipv6RouteEntry_t *rp6; 3867c478bd9Sstevel@tonic-gate int oerrno; 3877c478bd9Sstevel@tonic-gate int off = 0; 3887c478bd9Sstevel@tonic-gate int on = 1; 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate if (setsockopt(s, SOL_SOCKET, SO_USELOOPBACK, (char *)&off, 3917c478bd9Sstevel@tonic-gate sizeof (off)) < 0) 3927c478bd9Sstevel@tonic-gate quit("setsockopt", errno); 3937c478bd9Sstevel@tonic-gate if (argc > 1) { 3947c478bd9Sstevel@tonic-gate argv++; 3957c478bd9Sstevel@tonic-gate if (argc == 2 && **argv == '-') { 3967c478bd9Sstevel@tonic-gate /* 3977c478bd9Sstevel@tonic-gate * The address family (preceded by a dash) may be used 3987c478bd9Sstevel@tonic-gate * to flush the routes of that particular family. 3997c478bd9Sstevel@tonic-gate */ 4007c478bd9Sstevel@tonic-gate switch (keyword(*argv + 1)) { 4017c478bd9Sstevel@tonic-gate case K_INET: 4027c478bd9Sstevel@tonic-gate af = AF_INET; 4037c478bd9Sstevel@tonic-gate break; 4047c478bd9Sstevel@tonic-gate case K_LINK: 4057c478bd9Sstevel@tonic-gate af = AF_LINK; 4067c478bd9Sstevel@tonic-gate break; 4077c478bd9Sstevel@tonic-gate case K_INET6: 4087c478bd9Sstevel@tonic-gate af = AF_INET6; 4097c478bd9Sstevel@tonic-gate break; 4107c478bd9Sstevel@tonic-gate default: 4117c478bd9Sstevel@tonic-gate usage(*argv); 4127c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4137c478bd9Sstevel@tonic-gate } 4147c478bd9Sstevel@tonic-gate } else { 4157c478bd9Sstevel@tonic-gate usage(*argv); 4167c478bd9Sstevel@tonic-gate } 4177c478bd9Sstevel@tonic-gate } 4187c478bd9Sstevel@tonic-gate sd = open("/dev/ip", O_RDWR); 4197c478bd9Sstevel@tonic-gate oerrno = errno; 4207c478bd9Sstevel@tonic-gate if (sd < 0) { 4217c478bd9Sstevel@tonic-gate switch (errno) { 4227c478bd9Sstevel@tonic-gate case EACCES: 4237c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 4247c478bd9Sstevel@tonic-gate gettext("route: flush: insufficient privileges\n")); 4257c478bd9Sstevel@tonic-gate exit(oerrno); 4267c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4277c478bd9Sstevel@tonic-gate default: 4287c478bd9Sstevel@tonic-gate quit(gettext("can't open mib stream"), oerrno); 4297c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4307c478bd9Sstevel@tonic-gate } 4317c478bd9Sstevel@tonic-gate } 4327c478bd9Sstevel@tonic-gate if ((item = mibget(sd)) == NULL) 4337c478bd9Sstevel@tonic-gate quit("mibget", errno); 4347c478bd9Sstevel@tonic-gate if (verbose) { 4357c478bd9Sstevel@tonic-gate (void) printf("Examining routing table from " 4367c478bd9Sstevel@tonic-gate "T_SVR4_OPTMGMT_REQ\n"); 4377c478bd9Sstevel@tonic-gate } 4387c478bd9Sstevel@tonic-gate seqno = 0; /* ??? */ 4397c478bd9Sstevel@tonic-gate switch (af) { 4407c478bd9Sstevel@tonic-gate case AF_INET: 4417c478bd9Sstevel@tonic-gate /* Extract ipRouteEntrySize */ 4427c478bd9Sstevel@tonic-gate for (; item != NULL; item = item->next_item) { 4437c478bd9Sstevel@tonic-gate if (item->mib_id != 0) 4447c478bd9Sstevel@tonic-gate continue; 4457c478bd9Sstevel@tonic-gate if (item->group == MIB2_IP) { 4467c478bd9Sstevel@tonic-gate ipRouteEntrySize = 4477c478bd9Sstevel@tonic-gate ((mib2_ip_t *)item->valp)->ipRouteEntrySize; 4487c478bd9Sstevel@tonic-gate assert(IS_P2ALIGNED(ipRouteEntrySize, 4497c478bd9Sstevel@tonic-gate sizeof (mib2_ipRouteEntry_t *))); 4507c478bd9Sstevel@tonic-gate break; 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate if (ipRouteEntrySize == 0) { 4547c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 4557c478bd9Sstevel@tonic-gate gettext("ipRouteEntrySize can't be determined.\n")); 4567c478bd9Sstevel@tonic-gate exit(1); 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate for (; item != NULL; item = item->next_item) { 4597c478bd9Sstevel@tonic-gate /* 4607c478bd9Sstevel@tonic-gate * skip all the other trash that comes up the mib stream 4617c478bd9Sstevel@tonic-gate */ 4627c478bd9Sstevel@tonic-gate if (item->group != MIB2_IP || 4637c478bd9Sstevel@tonic-gate item->mib_id != MIB2_IP_ROUTE) 4647c478bd9Sstevel@tonic-gate continue; 4657c478bd9Sstevel@tonic-gate for (rp = (mib2_ipRouteEntry_t *)item->valp; 4667c478bd9Sstevel@tonic-gate (char *)rp < (char *)item->valp + item->length; 4677c478bd9Sstevel@tonic-gate /* LINTED */ 4687c478bd9Sstevel@tonic-gate rp = (mib2_ipRouteEntry_t *) 4697c478bd9Sstevel@tonic-gate ((char *)rp + ipRouteEntrySize)) { 4707c478bd9Sstevel@tonic-gate delRouteEntry(rp, NULL, seqno); 4717c478bd9Sstevel@tonic-gate seqno++; 4727c478bd9Sstevel@tonic-gate } 4737c478bd9Sstevel@tonic-gate break; 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate break; 4767c478bd9Sstevel@tonic-gate case AF_INET6: 4777c478bd9Sstevel@tonic-gate /* Extract ipv6RouteEntrySize */ 4787c478bd9Sstevel@tonic-gate for (; item != NULL; item = item->next_item) { 4797c478bd9Sstevel@tonic-gate if (item->mib_id != 0) 4807c478bd9Sstevel@tonic-gate continue; 4817c478bd9Sstevel@tonic-gate if (item->group == MIB2_IP6) { 4827c478bd9Sstevel@tonic-gate ipv6RouteEntrySize = 4837c478bd9Sstevel@tonic-gate ((mib2_ipv6IfStatsEntry_t *)item->valp)-> 4847c478bd9Sstevel@tonic-gate ipv6RouteEntrySize; 4857c478bd9Sstevel@tonic-gate assert(IS_P2ALIGNED(ipv6RouteEntrySize, 4867c478bd9Sstevel@tonic-gate sizeof (mib2_ipv6RouteEntry_t *))); 4877c478bd9Sstevel@tonic-gate break; 4887c478bd9Sstevel@tonic-gate } 4897c478bd9Sstevel@tonic-gate } 4907c478bd9Sstevel@tonic-gate if (ipv6RouteEntrySize == 0) { 4917c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4927c478bd9Sstevel@tonic-gate "ipv6RouteEntrySize cannot be determined.\n")); 4937c478bd9Sstevel@tonic-gate exit(1); 4947c478bd9Sstevel@tonic-gate } 4957c478bd9Sstevel@tonic-gate for (; item != NULL; item = item->next_item) { 4967c478bd9Sstevel@tonic-gate /* 4977c478bd9Sstevel@tonic-gate * skip all the other trash that comes up the mib stream 4987c478bd9Sstevel@tonic-gate */ 4997c478bd9Sstevel@tonic-gate if (item->group != MIB2_IP6 || 5007c478bd9Sstevel@tonic-gate item->mib_id != MIB2_IP6_ROUTE) 5017c478bd9Sstevel@tonic-gate continue; 5027c478bd9Sstevel@tonic-gate for (rp6 = (mib2_ipv6RouteEntry_t *)item->valp; 5037c478bd9Sstevel@tonic-gate (char *)rp6 < (char *)item->valp + item->length; 5047c478bd9Sstevel@tonic-gate /* LINTED */ 5057c478bd9Sstevel@tonic-gate rp6 = (mib2_ipv6RouteEntry_t *) 5067c478bd9Sstevel@tonic-gate ((char *)rp6 + ipv6RouteEntrySize)) { 5077c478bd9Sstevel@tonic-gate delRouteEntry(NULL, rp6, seqno); 5087c478bd9Sstevel@tonic-gate seqno++; 5097c478bd9Sstevel@tonic-gate } 5107c478bd9Sstevel@tonic-gate break; 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate break; 5137c478bd9Sstevel@tonic-gate } 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate if (setsockopt(s, SOL_SOCKET, SO_USELOOPBACK, (char *)&on, 5167c478bd9Sstevel@tonic-gate sizeof (on)) < 0) 5177c478bd9Sstevel@tonic-gate quit("setsockopt", errno); 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate /* 5217c478bd9Sstevel@tonic-gate * Given the contents of a mib_item_t of id type MIB2_IP_ROUTE or 5227c478bd9Sstevel@tonic-gate * MIB2_IP6_ROUTE, construct and send an RTM_DELETE routing socket message in 5237c478bd9Sstevel@tonic-gate * order to facilitate the flushing of RTF_GATEWAY routes. 5247c478bd9Sstevel@tonic-gate */ 5257c478bd9Sstevel@tonic-gate static void 5267c478bd9Sstevel@tonic-gate delRouteEntry(mib2_ipRouteEntry_t *rp, mib2_ipv6RouteEntry_t *rp6, int seqno) 5277c478bd9Sstevel@tonic-gate { 5287c478bd9Sstevel@tonic-gate char *cp; 5297c478bd9Sstevel@tonic-gate int ire_type; 5307c478bd9Sstevel@tonic-gate int rlen; 5317c478bd9Sstevel@tonic-gate struct rt_msghdr *rtm; 5327c478bd9Sstevel@tonic-gate struct sockaddr_in sin; 5337c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin6; 5347c478bd9Sstevel@tonic-gate int slen; 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate if (rp != NULL) 5377c478bd9Sstevel@tonic-gate ire_type = rp->ipRouteInfo.re_ire_type; 5387c478bd9Sstevel@tonic-gate else 5397c478bd9Sstevel@tonic-gate ire_type = rp6->ipv6RouteInfo.re_ire_type; 5407c478bd9Sstevel@tonic-gate if (ire_type != IRE_DEFAULT && 5417c478bd9Sstevel@tonic-gate ire_type != IRE_PREFIX && 5427c478bd9Sstevel@tonic-gate ire_type != IRE_HOST && 5437c478bd9Sstevel@tonic-gate ire_type != IRE_HOST_REDIRECT) 5447c478bd9Sstevel@tonic-gate return; 5457c478bd9Sstevel@tonic-gate 5467c478bd9Sstevel@tonic-gate rtm = &m_rtmsg.m_rtm; 5477c478bd9Sstevel@tonic-gate (void) memset(rtm, 0, sizeof (m_rtmsg)); 5487c478bd9Sstevel@tonic-gate rtm->rtm_type = RTM_DELETE; 5497c478bd9Sstevel@tonic-gate rtm->rtm_seq = seqno; 5507c478bd9Sstevel@tonic-gate rtm->rtm_flags |= RTF_GATEWAY; 5517c478bd9Sstevel@tonic-gate rtm->rtm_version = RTM_VERSION; 5527c478bd9Sstevel@tonic-gate rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 5537c478bd9Sstevel@tonic-gate cp = m_rtmsg.m_space; 5547c478bd9Sstevel@tonic-gate if (rp != NULL) { 5557c478bd9Sstevel@tonic-gate slen = sizeof (struct sockaddr_in); 5567c478bd9Sstevel@tonic-gate if (rp->ipRouteMask == IP_HOST_MASK) 5577c478bd9Sstevel@tonic-gate rtm->rtm_flags |= RTF_HOST; 5587c478bd9Sstevel@tonic-gate (void) memset(&sin, 0, slen); 5597c478bd9Sstevel@tonic-gate sin.sin_family = AF_INET; 5607c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = rp->ipRouteDest; 5617c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin, slen); 5627c478bd9Sstevel@tonic-gate cp += slen; 5637c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = rp->ipRouteNextHop; 5647c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin, slen); 5657c478bd9Sstevel@tonic-gate cp += slen; 5667c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = rp->ipRouteMask; 5677c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin, slen); 5687c478bd9Sstevel@tonic-gate cp += slen; 5697c478bd9Sstevel@tonic-gate } else { 5707c478bd9Sstevel@tonic-gate slen = sizeof (struct sockaddr_in6); 5717c478bd9Sstevel@tonic-gate if (rp6->ipv6RoutePfxLength == IPV6_ABITS) 5727c478bd9Sstevel@tonic-gate rtm->rtm_flags |= RTF_HOST; 5737c478bd9Sstevel@tonic-gate (void) memset(&sin6, 0, slen); 5747c478bd9Sstevel@tonic-gate sin6.sin6_family = AF_INET6; 5757c478bd9Sstevel@tonic-gate sin6.sin6_addr = rp6->ipv6RouteDest; 5767c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin6, slen); 5777c478bd9Sstevel@tonic-gate cp += slen; 5787c478bd9Sstevel@tonic-gate sin6.sin6_addr = rp6->ipv6RouteNextHop; 5797c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin6, slen); 5807c478bd9Sstevel@tonic-gate cp += slen; 5817c478bd9Sstevel@tonic-gate (void) memset(&sin6.sin6_addr, 0, sizeof (sin6.sin6_addr)); 5827c478bd9Sstevel@tonic-gate (void) in_prefixlentomask(rp6->ipv6RoutePfxLength, IPV6_ABITS, 5837c478bd9Sstevel@tonic-gate (uchar_t *)&sin6.sin6_addr.s6_addr); 5847c478bd9Sstevel@tonic-gate (void) memmove(cp, &sin6, slen); 5857c478bd9Sstevel@tonic-gate cp += slen; 5867c478bd9Sstevel@tonic-gate } 5877c478bd9Sstevel@tonic-gate rtm->rtm_msglen = cp - (char *)&m_rtmsg; 5887c478bd9Sstevel@tonic-gate if (debugonly) { 5897c478bd9Sstevel@tonic-gate /* 5907c478bd9Sstevel@tonic-gate * In debugonly mode, the routing socket message to delete the 5917c478bd9Sstevel@tonic-gate * current entry is not actually sent. However if verbose is 5927c478bd9Sstevel@tonic-gate * also set, the routing socket message that would have been 5937c478bd9Sstevel@tonic-gate * is printed. 5947c478bd9Sstevel@tonic-gate */ 5957c478bd9Sstevel@tonic-gate if (verbose) 5967c478bd9Sstevel@tonic-gate print_rtmsg(rtm, rtm->rtm_msglen); 5977c478bd9Sstevel@tonic-gate return; 5987c478bd9Sstevel@tonic-gate } 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate rlen = write(s, (char *)&m_rtmsg, rtm->rtm_msglen); 6017c478bd9Sstevel@tonic-gate if (rlen < (int)rtm->rtm_msglen) { 6027c478bd9Sstevel@tonic-gate if (rlen < 0) { 6037c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 6047c478bd9Sstevel@tonic-gate gettext("route: write to routing socket: %s\n"), 6057c478bd9Sstevel@tonic-gate strerror(errno)); 6067c478bd9Sstevel@tonic-gate } else { 6077c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("route: write to " 6087c478bd9Sstevel@tonic-gate "routing socket got only %d for rlen\n"), rlen); 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate return; 6117c478bd9Sstevel@tonic-gate } 6127c478bd9Sstevel@tonic-gate if (qflag) { 6137c478bd9Sstevel@tonic-gate /* 6147c478bd9Sstevel@tonic-gate * In quiet mode, nothing is printed at all (unless the write() 6157c478bd9Sstevel@tonic-gate * itself failed. 6167c478bd9Sstevel@tonic-gate */ 6177c478bd9Sstevel@tonic-gate return; 6187c478bd9Sstevel@tonic-gate } 6197c478bd9Sstevel@tonic-gate if (verbose) { 6207c478bd9Sstevel@tonic-gate print_rtmsg(rtm, rlen); 6217c478bd9Sstevel@tonic-gate } else { 6227c478bd9Sstevel@tonic-gate struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate (void) printf("%-20.20s ", 6257c478bd9Sstevel@tonic-gate rtm->rtm_flags & RTF_HOST ? routename(sa) : 6267c478bd9Sstevel@tonic-gate netname(sa)); 6277c478bd9Sstevel@tonic-gate /* LINTED */ 6287c478bd9Sstevel@tonic-gate sa = (struct sockaddr *)(salen(sa) + (char *)sa); 6297c478bd9Sstevel@tonic-gate (void) printf("%-20.20s ", routename(sa)); 6307c478bd9Sstevel@tonic-gate (void) printf("done\n"); 6317c478bd9Sstevel@tonic-gate } 6327c478bd9Sstevel@tonic-gate } 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate /* 6357c478bd9Sstevel@tonic-gate * Return the name of the host whose address is given. 6367c478bd9Sstevel@tonic-gate */ 6377c478bd9Sstevel@tonic-gate char * 6387c478bd9Sstevel@tonic-gate routename(struct sockaddr *sa) 6397c478bd9Sstevel@tonic-gate { 6407c478bd9Sstevel@tonic-gate char *cp; 6417c478bd9Sstevel@tonic-gate static char line[MAXHOSTNAMELEN + 1]; 6427c478bd9Sstevel@tonic-gate struct hostent *hp = NULL; 6437c478bd9Sstevel@tonic-gate static char domain[MAXHOSTNAMELEN + 1]; 6447c478bd9Sstevel@tonic-gate static boolean_t first = B_TRUE; 6457c478bd9Sstevel@tonic-gate struct in_addr in; 6467c478bd9Sstevel@tonic-gate struct in6_addr in6; 6477c478bd9Sstevel@tonic-gate int error_num; 6487c478bd9Sstevel@tonic-gate ushort_t *s; 6497c478bd9Sstevel@tonic-gate ushort_t *slim; 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate if (first) { 6527c478bd9Sstevel@tonic-gate first = B_FALSE; 6537c478bd9Sstevel@tonic-gate if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 6547c478bd9Sstevel@tonic-gate (cp = strchr(domain, '.'))) 6557c478bd9Sstevel@tonic-gate (void) strcpy(domain, cp + 1); 6567c478bd9Sstevel@tonic-gate else 6577c478bd9Sstevel@tonic-gate domain[0] = 0; 6587c478bd9Sstevel@tonic-gate } 6597c478bd9Sstevel@tonic-gate 6607c478bd9Sstevel@tonic-gate if (salen(sa) == 0) { 6617c478bd9Sstevel@tonic-gate (void) strcpy(line, "default"); 6627c478bd9Sstevel@tonic-gate return (line); 6637c478bd9Sstevel@tonic-gate } 6647c478bd9Sstevel@tonic-gate switch (sa->sa_family) { 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate case AF_INET: 6677c478bd9Sstevel@tonic-gate /* LINTED */ 6687c478bd9Sstevel@tonic-gate in = ((struct sockaddr_in *)sa)->sin_addr; 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate cp = NULL; 6717c478bd9Sstevel@tonic-gate if (in.s_addr == INADDR_ANY) 6727c478bd9Sstevel@tonic-gate cp = "default"; 6737c478bd9Sstevel@tonic-gate if (cp == NULL && !nflag) { 6747c478bd9Sstevel@tonic-gate hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), 6757c478bd9Sstevel@tonic-gate AF_INET); 6767c478bd9Sstevel@tonic-gate if (hp != NULL) { 6777c478bd9Sstevel@tonic-gate if (((cp = strchr(hp->h_name, '.')) != NULL) && 6787c478bd9Sstevel@tonic-gate (strcmp(cp + 1, domain) == 0)) 6797c478bd9Sstevel@tonic-gate *cp = 0; 6807c478bd9Sstevel@tonic-gate cp = hp->h_name; 6817c478bd9Sstevel@tonic-gate } 6827c478bd9Sstevel@tonic-gate } 6837c478bd9Sstevel@tonic-gate if (cp != NULL) { 6847c478bd9Sstevel@tonic-gate (void) strncpy(line, cp, MAXHOSTNAMELEN); 6857c478bd9Sstevel@tonic-gate line[MAXHOSTNAMELEN] = '\0'; 6867c478bd9Sstevel@tonic-gate } else { 6877c478bd9Sstevel@tonic-gate in.s_addr = ntohl(in.s_addr); 6887c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 6897c478bd9Sstevel@tonic-gate C(in.s_addr >> 16), C(in.s_addr >> 8), 6907c478bd9Sstevel@tonic-gate C(in.s_addr)); 6917c478bd9Sstevel@tonic-gate } 6927c478bd9Sstevel@tonic-gate break; 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate case AF_LINK: 6957c478bd9Sstevel@tonic-gate return (link_ntoa((struct sockaddr_dl *)sa)); 6967c478bd9Sstevel@tonic-gate 6977c478bd9Sstevel@tonic-gate case AF_INET6: 6987c478bd9Sstevel@tonic-gate /* LINTED */ 6997c478bd9Sstevel@tonic-gate in6 = ((struct sockaddr_in6 *)sa)->sin6_addr; 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate cp = NULL; 7027c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&in6)) 7037c478bd9Sstevel@tonic-gate cp = "default"; 7047c478bd9Sstevel@tonic-gate if (cp == NULL && !nflag) { 7057c478bd9Sstevel@tonic-gate hp = getipnodebyaddr((char *)&in6, 7067c478bd9Sstevel@tonic-gate sizeof (struct in6_addr), AF_INET6, &error_num); 7077c478bd9Sstevel@tonic-gate if (hp != NULL) { 7087c478bd9Sstevel@tonic-gate if (((cp = strchr(hp->h_name, '.')) != NULL) && 7097c478bd9Sstevel@tonic-gate (strcmp(cp + 1, domain) == 0)) 7107c478bd9Sstevel@tonic-gate *cp = 0; 7117c478bd9Sstevel@tonic-gate cp = hp->h_name; 7127c478bd9Sstevel@tonic-gate } 7137c478bd9Sstevel@tonic-gate } 7147c478bd9Sstevel@tonic-gate if (cp != NULL) { 7157c478bd9Sstevel@tonic-gate (void) strncpy(line, cp, MAXHOSTNAMELEN); 7167c478bd9Sstevel@tonic-gate line[MAXHOSTNAMELEN] = '\0'; 7177c478bd9Sstevel@tonic-gate } else { 7187c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&in6, line, 7197c478bd9Sstevel@tonic-gate INET6_ADDRSTRLEN); 7207c478bd9Sstevel@tonic-gate } 7217c478bd9Sstevel@tonic-gate if (hp != NULL) 7227c478bd9Sstevel@tonic-gate freehostent(hp); 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate break; 7257c478bd9Sstevel@tonic-gate 7267c478bd9Sstevel@tonic-gate default: 7277c478bd9Sstevel@tonic-gate s = (ushort_t *)sa; 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate slim = s + ((salen(sa) + 1) >> 1); 7307c478bd9Sstevel@tonic-gate cp = line + sprintf(line, "(%d)", sa->sa_family); 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate while (++s < slim) /* start with sa->sa_data */ 7337c478bd9Sstevel@tonic-gate cp += sprintf(cp, " %x", *s); 7347c478bd9Sstevel@tonic-gate break; 7357c478bd9Sstevel@tonic-gate } 7367c478bd9Sstevel@tonic-gate return (line); 7377c478bd9Sstevel@tonic-gate } 7387c478bd9Sstevel@tonic-gate 7397c478bd9Sstevel@tonic-gate /* 7407c478bd9Sstevel@tonic-gate * Return the name of the network whose address is given. 7417c478bd9Sstevel@tonic-gate * The address is assumed to be that of a net or subnet, not a host. 7427c478bd9Sstevel@tonic-gate */ 7437c478bd9Sstevel@tonic-gate static char * 7447c478bd9Sstevel@tonic-gate netname(struct sockaddr *sa) 7457c478bd9Sstevel@tonic-gate { 7467c478bd9Sstevel@tonic-gate char *cp = NULL; 7477c478bd9Sstevel@tonic-gate static char line[MAXHOSTNAMELEN + 1]; 7487c478bd9Sstevel@tonic-gate struct netent *np; 7497c478bd9Sstevel@tonic-gate in_addr_t net, mask; 7507c478bd9Sstevel@tonic-gate int subnetshift; 7517c478bd9Sstevel@tonic-gate struct in_addr in; 7527c478bd9Sstevel@tonic-gate ushort_t *s; 7537c478bd9Sstevel@tonic-gate ushort_t *slim; 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate switch (sa->sa_family) { 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate case AF_INET: 7587c478bd9Sstevel@tonic-gate /* LINTED */ 7597c478bd9Sstevel@tonic-gate in = ((struct sockaddr_in *)sa)->sin_addr; 7607c478bd9Sstevel@tonic-gate 7617c478bd9Sstevel@tonic-gate in.s_addr = ntohl(in.s_addr); 7627c478bd9Sstevel@tonic-gate if (in.s_addr == INADDR_ANY) { 7637c478bd9Sstevel@tonic-gate cp = "default"; 7647c478bd9Sstevel@tonic-gate } else if (!nflag) { 7657c478bd9Sstevel@tonic-gate if (IN_CLASSA(in.s_addr)) { 7667c478bd9Sstevel@tonic-gate mask = IN_CLASSA_NET; 7677c478bd9Sstevel@tonic-gate subnetshift = 8; 7687c478bd9Sstevel@tonic-gate } else if (IN_CLASSB(in.s_addr)) { 7697c478bd9Sstevel@tonic-gate mask = IN_CLASSB_NET; 7707c478bd9Sstevel@tonic-gate subnetshift = 8; 7717c478bd9Sstevel@tonic-gate } else { 7727c478bd9Sstevel@tonic-gate mask = IN_CLASSC_NET; 7737c478bd9Sstevel@tonic-gate subnetshift = 4; 7747c478bd9Sstevel@tonic-gate } 7757c478bd9Sstevel@tonic-gate /* 7767c478bd9Sstevel@tonic-gate * If there are more bits than the standard mask 7777c478bd9Sstevel@tonic-gate * would suggest, subnets must be in use. 7787c478bd9Sstevel@tonic-gate * Guess at the subnet mask, assuming reasonable 7797c478bd9Sstevel@tonic-gate * width subnet fields. 7807c478bd9Sstevel@tonic-gate */ 7817c478bd9Sstevel@tonic-gate while (in.s_addr &~ mask) 7827c478bd9Sstevel@tonic-gate mask = (long)mask >> subnetshift; 7837c478bd9Sstevel@tonic-gate net = in.s_addr & mask; 7847c478bd9Sstevel@tonic-gate while ((mask & 1) == 0) 7857c478bd9Sstevel@tonic-gate mask >>= 1, net >>= 1; 7867c478bd9Sstevel@tonic-gate np = getnetbyaddr(net, AF_INET); 7877c478bd9Sstevel@tonic-gate if (np != NULL) 7887c478bd9Sstevel@tonic-gate cp = np->n_name; 7897c478bd9Sstevel@tonic-gate } 7907c478bd9Sstevel@tonic-gate if (cp != NULL) { 7917c478bd9Sstevel@tonic-gate (void) strncpy(line, cp, MAXHOSTNAMELEN); 7927c478bd9Sstevel@tonic-gate line[MAXHOSTNAMELEN] = '\0'; 7937c478bd9Sstevel@tonic-gate } else if ((in.s_addr & 0xffffff) == 0) { 7947c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u", C(in.s_addr >> 24)); 7957c478bd9Sstevel@tonic-gate } else if ((in.s_addr & 0xffff) == 0) { 7967c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u.%u", C(in.s_addr >> 24), 7977c478bd9Sstevel@tonic-gate C(in.s_addr >> 16)); 7987c478bd9Sstevel@tonic-gate } else if ((in.s_addr & 0xff) == 0) { 7997c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24), 8007c478bd9Sstevel@tonic-gate C(in.s_addr >> 16), C(in.s_addr >> 8)); 8017c478bd9Sstevel@tonic-gate } else { 8027c478bd9Sstevel@tonic-gate (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 8037c478bd9Sstevel@tonic-gate C(in.s_addr >> 16), C(in.s_addr >> 8), 8047c478bd9Sstevel@tonic-gate C(in.s_addr)); 8057c478bd9Sstevel@tonic-gate } 8067c478bd9Sstevel@tonic-gate break; 8077c478bd9Sstevel@tonic-gate 8087c478bd9Sstevel@tonic-gate case AF_LINK: 8097c478bd9Sstevel@tonic-gate return (link_ntoa((struct sockaddr_dl *)sa)); 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate case AF_INET6: 8127c478bd9Sstevel@tonic-gate return (routename(sa)); 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate default: 8157c478bd9Sstevel@tonic-gate /* LINTED */ 8167c478bd9Sstevel@tonic-gate s = (ushort_t *)sa->sa_data; 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate slim = s + ((salen(sa) + 1) >> 1); 8197c478bd9Sstevel@tonic-gate cp = line + sprintf(line, "af %d:", sa->sa_family); 8207c478bd9Sstevel@tonic-gate 8217c478bd9Sstevel@tonic-gate while (s < slim) 8227c478bd9Sstevel@tonic-gate cp += sprintf(cp, " %x", *s++); 8237c478bd9Sstevel@tonic-gate break; 8247c478bd9Sstevel@tonic-gate } 8257c478bd9Sstevel@tonic-gate return (line); 8267c478bd9Sstevel@tonic-gate } 8277c478bd9Sstevel@tonic-gate 8287c478bd9Sstevel@tonic-gate void 829*7a23074eSdduvall set_metric(char *value, int key) 8307c478bd9Sstevel@tonic-gate { 8317c478bd9Sstevel@tonic-gate int flag = 0; 8327c478bd9Sstevel@tonic-gate uint_t noval, *valp = &noval; 8337c478bd9Sstevel@tonic-gate 8347c478bd9Sstevel@tonic-gate switch (key) { 835*7a23074eSdduvall #define caseof(x, y, z) case (x): valp = &rt_metrics.z; flag = (y); break 8367c478bd9Sstevel@tonic-gate caseof(K_MTU, RTV_MTU, rmx_mtu); 8377c478bd9Sstevel@tonic-gate caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount); 8387c478bd9Sstevel@tonic-gate caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire); 8397c478bd9Sstevel@tonic-gate caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe); 8407c478bd9Sstevel@tonic-gate caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe); 8417c478bd9Sstevel@tonic-gate caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh); 8427c478bd9Sstevel@tonic-gate caseof(K_RTT, RTV_RTT, rmx_rtt); 8437c478bd9Sstevel@tonic-gate caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar); 8447c478bd9Sstevel@tonic-gate #undef caseof 8457c478bd9Sstevel@tonic-gate } 846*7a23074eSdduvall rtm_inits |= flag; 847*7a23074eSdduvall if (lockrest || locking) 848*7a23074eSdduvall rt_metrics.rmx_locks |= flag; 849*7a23074eSdduvall if (locking) 850*7a23074eSdduvall locking = B_FALSE; 8517c478bd9Sstevel@tonic-gate *valp = atoi(value); 8527c478bd9Sstevel@tonic-gate } 8537c478bd9Sstevel@tonic-gate 854*7a23074eSdduvall int 855*7a23074eSdduvall newroute(int argc, char **argv) 8567c478bd9Sstevel@tonic-gate { 857*7a23074eSdduvall char *cmd, *dest = "", *gateway = "", *err; 858*7a23074eSdduvall boolean_t ishost = B_FALSE; 859*7a23074eSdduvall int ret, attempts, oerrno, flags = RTF_STATIC; 8607c478bd9Sstevel@tonic-gate int key; 861*7a23074eSdduvall struct hostent *hp = NULL; 862*7a23074eSdduvall static char obuf[INET6_ADDRSTRLEN]; 8637c478bd9Sstevel@tonic-gate 864*7a23074eSdduvall cmd = argv[0]; 865*7a23074eSdduvall if (*cmd != 'g' && !tflag) { 866*7a23074eSdduvall /* Don't want to read back our messages */ 867*7a23074eSdduvall (void) shutdown(s, 0); 8687c478bd9Sstevel@tonic-gate } 869*7a23074eSdduvall while (--argc > 0) { 870*7a23074eSdduvall key = keyword(*(++argv)); 871*7a23074eSdduvall if (key == K_HOST) { 872*7a23074eSdduvall forcehost = B_TRUE; 873*7a23074eSdduvall } else if (key == K_NET) { 874*7a23074eSdduvall forcenet = B_TRUE; 875*7a23074eSdduvall } else if (**(argv) == '-') { 876*7a23074eSdduvall switch (key = keyword(1 + *argv)) { 8777c478bd9Sstevel@tonic-gate case K_LINK: 878*7a23074eSdduvall af = AF_LINK; 8797c478bd9Sstevel@tonic-gate break; 8807c478bd9Sstevel@tonic-gate case K_INET: 881*7a23074eSdduvall af = AF_INET; 8827c478bd9Sstevel@tonic-gate break; 8837c478bd9Sstevel@tonic-gate case K_SA: 884*7a23074eSdduvall af = PF_ROUTE; 8857c478bd9Sstevel@tonic-gate break; 8867c478bd9Sstevel@tonic-gate case K_INET6: 887*7a23074eSdduvall af = AF_INET6; 8887c478bd9Sstevel@tonic-gate break; 8897c478bd9Sstevel@tonic-gate case K_IFACE: 8907c478bd9Sstevel@tonic-gate case K_INTERFACE: 8917c478bd9Sstevel@tonic-gate iflag = B_TRUE; 892*7a23074eSdduvall /* FALLTHROUGH */ 8937c478bd9Sstevel@tonic-gate case K_NOSTATIC: 894*7a23074eSdduvall flags &= ~RTF_STATIC; 8957c478bd9Sstevel@tonic-gate break; 8967c478bd9Sstevel@tonic-gate case K_LOCK: 897*7a23074eSdduvall locking = B_TRUE; 8987c478bd9Sstevel@tonic-gate break; 8997c478bd9Sstevel@tonic-gate case K_LOCKREST: 9007c478bd9Sstevel@tonic-gate lockrest = B_TRUE; 9017c478bd9Sstevel@tonic-gate break; 902*7a23074eSdduvall case K_HOST: 903*7a23074eSdduvall forcehost = B_TRUE; 904*7a23074eSdduvall break; 9057c478bd9Sstevel@tonic-gate case K_REJECT: 906*7a23074eSdduvall flags |= RTF_REJECT; 9077c478bd9Sstevel@tonic-gate break; 9087c478bd9Sstevel@tonic-gate case K_BLACKHOLE: 909*7a23074eSdduvall flags |= RTF_BLACKHOLE; 9107c478bd9Sstevel@tonic-gate break; 9117c478bd9Sstevel@tonic-gate case K_PROTO1: 912*7a23074eSdduvall flags |= RTF_PROTO1; 9137c478bd9Sstevel@tonic-gate break; 9147c478bd9Sstevel@tonic-gate case K_PROTO2: 915*7a23074eSdduvall flags |= RTF_PROTO2; 9167c478bd9Sstevel@tonic-gate break; 9177c478bd9Sstevel@tonic-gate case K_CLONING: 918*7a23074eSdduvall flags |= RTF_CLONING; 9197c478bd9Sstevel@tonic-gate break; 9207c478bd9Sstevel@tonic-gate case K_XRESOLVE: 921*7a23074eSdduvall flags |= RTF_XRESOLVE; 9227c478bd9Sstevel@tonic-gate break; 9237c478bd9Sstevel@tonic-gate case K_STATIC: 924*7a23074eSdduvall flags |= RTF_STATIC; 9257c478bd9Sstevel@tonic-gate break; 9267c478bd9Sstevel@tonic-gate case K_IFA: 927*7a23074eSdduvall argc--; 928*7a23074eSdduvall (void) getaddr(RTA_IFA, *++argv, NULL); 9297c478bd9Sstevel@tonic-gate break; 9307c478bd9Sstevel@tonic-gate case K_IFP: 931*7a23074eSdduvall argc--; 932*7a23074eSdduvall (void) getaddr(RTA_IFP, *++argv, NULL); 9337c478bd9Sstevel@tonic-gate break; 9347c478bd9Sstevel@tonic-gate case K_GATEWAY: 935*7a23074eSdduvall /* 936*7a23074eSdduvall * For the gateway parameter, retrieve the 937*7a23074eSdduvall * pointer to the struct hostent so that all 938*7a23074eSdduvall * possible addresses can be tried until one 939*7a23074eSdduvall * is successful. 940*7a23074eSdduvall */ 941*7a23074eSdduvall argc--; 942*7a23074eSdduvall gateway = *++argv; 943*7a23074eSdduvall (void) getaddr(RTA_GATEWAY, *argv, &hp); 9447c478bd9Sstevel@tonic-gate break; 9457c478bd9Sstevel@tonic-gate case K_DST: 946*7a23074eSdduvall argc--; 947*7a23074eSdduvall ishost = getaddr(RTA_DST, *++argv, NULL); 948*7a23074eSdduvall dest = *argv; 9497c478bd9Sstevel@tonic-gate break; 9507c478bd9Sstevel@tonic-gate case K_NETMASK: 951*7a23074eSdduvall argc--; 952*7a23074eSdduvall (void) getaddr(RTA_NETMASK, *++argv, NULL); 953*7a23074eSdduvall /* FALLTHROUGH */ 954*7a23074eSdduvall case K_NET: 955*7a23074eSdduvall forcenet = B_TRUE; 9567c478bd9Sstevel@tonic-gate break; 9577c478bd9Sstevel@tonic-gate case K_MTU: 9587c478bd9Sstevel@tonic-gate case K_HOPCOUNT: 9597c478bd9Sstevel@tonic-gate case K_EXPIRE: 9607c478bd9Sstevel@tonic-gate case K_RECVPIPE: 9617c478bd9Sstevel@tonic-gate case K_SENDPIPE: 9627c478bd9Sstevel@tonic-gate case K_SSTHRESH: 9637c478bd9Sstevel@tonic-gate case K_RTT: 9647c478bd9Sstevel@tonic-gate case K_RTTVAR: 965*7a23074eSdduvall argc--; 966*7a23074eSdduvall set_metric(*++argv, key); 9677c478bd9Sstevel@tonic-gate break; 9687c478bd9Sstevel@tonic-gate case K_PRIVATE: 969*7a23074eSdduvall flags |= RTF_PRIVATE; 9707c478bd9Sstevel@tonic-gate break; 9717c478bd9Sstevel@tonic-gate case K_MULTIRT: 972*7a23074eSdduvall flags |= RTF_MULTIRT; 9737c478bd9Sstevel@tonic-gate break; 9747c478bd9Sstevel@tonic-gate case K_SETSRC: 975*7a23074eSdduvall argc--; 976*7a23074eSdduvall (void) getaddr(RTA_SRC, *++argv, NULL); 977*7a23074eSdduvall flags |= RTF_SETSRC; 9787c478bd9Sstevel@tonic-gate break; 9797c478bd9Sstevel@tonic-gate default: 980*7a23074eSdduvall usage(*argv + 1); 981*7a23074eSdduvall /* NOTREACHED */ 9827c478bd9Sstevel@tonic-gate } 983*7a23074eSdduvall } else { 984*7a23074eSdduvall if ((rtm_addrs & RTA_DST) == 0) { 985*7a23074eSdduvall dest = *argv; 986*7a23074eSdduvall ishost = getaddr(RTA_DST, *argv, NULL); 987*7a23074eSdduvall } else if ((rtm_addrs & RTA_GATEWAY) == 0) { 9887c478bd9Sstevel@tonic-gate /* 9897c478bd9Sstevel@tonic-gate * For the gateway parameter, retrieve the 9907c478bd9Sstevel@tonic-gate * pointer to the struct hostent so that all 9917c478bd9Sstevel@tonic-gate * possible addresses can be tried until one 9927c478bd9Sstevel@tonic-gate * is successful. 9937c478bd9Sstevel@tonic-gate */ 994*7a23074eSdduvall gateway = *argv; 995*7a23074eSdduvall (void) getaddr(RTA_GATEWAY, *argv, &hp); 9967c478bd9Sstevel@tonic-gate } else { 997*7a23074eSdduvall ulong_t metric = strtoul(*argv, &err, 10); 998*7a23074eSdduvall 9997c478bd9Sstevel@tonic-gate /* 10007c478bd9Sstevel@tonic-gate * Assume that a regular number is a metric. 10017c478bd9Sstevel@tonic-gate * Needed for compatibility with old route 10027c478bd9Sstevel@tonic-gate * command syntax. 10037c478bd9Sstevel@tonic-gate */ 1004*7a23074eSdduvall if (*argv != err && *err == '\0' && 10057c478bd9Sstevel@tonic-gate metric < 0x80000000ul) { 10067c478bd9Sstevel@tonic-gate iflag = (metric == 0); 10077c478bd9Sstevel@tonic-gate if (verbose) { 10087c478bd9Sstevel@tonic-gate (void) printf("old usage of " 10097c478bd9Sstevel@tonic-gate "trailing number, assuming " 10107c478bd9Sstevel@tonic-gate "route %s\n", iflag ? 10117c478bd9Sstevel@tonic-gate "to if" : "via gateway"); 10127c478bd9Sstevel@tonic-gate } 10137c478bd9Sstevel@tonic-gate continue; 10147c478bd9Sstevel@tonic-gate } 1015*7a23074eSdduvall (void) getaddr(RTA_NETMASK, *argv, NULL); 10167c478bd9Sstevel@tonic-gate } 10177c478bd9Sstevel@tonic-gate } 10187c478bd9Sstevel@tonic-gate } 1019*7a23074eSdduvall if ((rtm_addrs & RTA_DST) == 0) { 10203f33f4f7Sjl138328 (void) fprintf(stderr, 1021*7a23074eSdduvall gettext("route: destination required following command\n")); 1022*7a23074eSdduvall usage((char *)NULL); 1023*7a23074eSdduvall } else if ((*cmd == 'a' || *cmd == 'd') && 1024*7a23074eSdduvall (rtm_addrs & RTA_GATEWAY) == 0) { 1025*7a23074eSdduvall (void) fprintf(stderr, 1026*7a23074eSdduvall gettext("route: gateway required for add or delete " 1027*7a23074eSdduvall "command\n")); 1028*7a23074eSdduvall usage((char *)NULL); 10293f33f4f7Sjl138328 } 1030*7a23074eSdduvall 1031*7a23074eSdduvall /* 1032*7a23074eSdduvall * If the netmask has been specified use it to determine RTF_HOST. 1033*7a23074eSdduvall * Otherwise rely on the "-net" and "-host" specifiers. 1034*7a23074eSdduvall * Final fallback is whether ot not any bits were set in the address 1035*7a23074eSdduvall * past the classful network component. 1036*7a23074eSdduvall */ 1037*7a23074eSdduvall if (rtm_addrs & RTA_NETMASK) { 1038*7a23074eSdduvall if ((af == AF_INET && 1039*7a23074eSdduvall so_mask.sin.sin_addr.s_addr == IP_HOST_MASK) || 1040*7a23074eSdduvall (af == AF_INET6 && masklen == IPV6_ABITS)) 1041*7a23074eSdduvall forcehost = B_TRUE; 1042*7a23074eSdduvall else 1043*7a23074eSdduvall forcenet = B_TRUE; 10443f33f4f7Sjl138328 } 1045*7a23074eSdduvall if (forcehost) 1046*7a23074eSdduvall ishost = B_TRUE; 1047*7a23074eSdduvall if (forcenet) 1048*7a23074eSdduvall ishost = B_FALSE; 1049*7a23074eSdduvall flags |= RTF_UP; 1050*7a23074eSdduvall if (ishost) 1051*7a23074eSdduvall flags |= RTF_HOST; 1052*7a23074eSdduvall if (!iflag) 1053*7a23074eSdduvall flags |= RTF_GATEWAY; 10547c478bd9Sstevel@tonic-gate for (attempts = 1; ; attempts++) { 10557c478bd9Sstevel@tonic-gate errno = 0; 1056*7a23074eSdduvall if ((ret = rtmsg(*cmd, flags)) == 0) 10577c478bd9Sstevel@tonic-gate break; 10587c478bd9Sstevel@tonic-gate if (errno != ENETUNREACH && errno != ESRCH) 10597c478bd9Sstevel@tonic-gate break; 1060*7a23074eSdduvall if (*gateway != '\0' && hp != NULL && 10617c478bd9Sstevel@tonic-gate hp->h_addr_list[attempts] != NULL) { 10627c478bd9Sstevel@tonic-gate switch (af) { 10637c478bd9Sstevel@tonic-gate case AF_INET: 1064*7a23074eSdduvall (void) memmove(&so_gate.sin.sin_addr, 10657c478bd9Sstevel@tonic-gate hp->h_addr_list[attempts], hp->h_length); 10667c478bd9Sstevel@tonic-gate continue; 10677c478bd9Sstevel@tonic-gate case AF_INET6: 1068*7a23074eSdduvall (void) memmove(&so_gate.sin6.sin6_addr, 10697c478bd9Sstevel@tonic-gate hp->h_addr_list[attempts], hp->h_length); 10707c478bd9Sstevel@tonic-gate continue; 10717c478bd9Sstevel@tonic-gate } 10727c478bd9Sstevel@tonic-gate } 10737c478bd9Sstevel@tonic-gate break; 10747c478bd9Sstevel@tonic-gate } 10757c478bd9Sstevel@tonic-gate oerrno = errno; 1076*7a23074eSdduvall if (*cmd != 'g') { 1077*7a23074eSdduvall (void) printf("%s %s %s", cmd, ishost ? "host" : "net", dest); 1078*7a23074eSdduvall if (*gateway != '\0') { 1079*7a23074eSdduvall switch (af) { 10807c478bd9Sstevel@tonic-gate case AF_INET: 1081*7a23074eSdduvall if (nflag) { 1082*7a23074eSdduvall (void) printf(": gateway %s", 1083*7a23074eSdduvall inet_ntoa(so_gate.sin.sin_addr)); 1084*7a23074eSdduvall } else if (attempts > 1 && ret == 0) { 1085*7a23074eSdduvall (void) printf(": gateway %s (%s)", 1086*7a23074eSdduvall gateway, 1087*7a23074eSdduvall inet_ntoa(so_gate.sin.sin_addr)); 1088*7a23074eSdduvall } else { 1089*7a23074eSdduvall (void) printf(": gateway %s", gateway); 1090*7a23074eSdduvall } 10917c478bd9Sstevel@tonic-gate break; 10927c478bd9Sstevel@tonic-gate case AF_INET6: 10937c478bd9Sstevel@tonic-gate if (inet_ntop(AF_INET6, 1094*7a23074eSdduvall (void *)&so_gate.sin6.sin6_addr, obuf, 1095*7a23074eSdduvall INET6_ADDRSTRLEN) != NULL) { 1096*7a23074eSdduvall if (nflag) { 1097*7a23074eSdduvall (void) printf(": gateway %s", 1098*7a23074eSdduvall obuf); 1099*7a23074eSdduvall } else if (attempts > 1 && ret == 0) { 1100*7a23074eSdduvall (void) printf(": gateway %s " 1101*7a23074eSdduvall "(%s)", 1102*7a23074eSdduvall gateway, obuf); 1103*7a23074eSdduvall } 1104*7a23074eSdduvall break; 1105*7a23074eSdduvall } 1106*7a23074eSdduvall /* FALLTHROUGH */ 1107*7a23074eSdduvall default: 1108*7a23074eSdduvall (void) printf(": gateway %s", gateway); 1109*7a23074eSdduvall break; 1110*7a23074eSdduvall } 1111*7a23074eSdduvall } 1112*7a23074eSdduvall if (ret == 0) 1113*7a23074eSdduvall (void) printf("\n"); 1114*7a23074eSdduvall } 1115*7a23074eSdduvall if (ret != 0) { 1116*7a23074eSdduvall if (*cmd == 'g') { 1117*7a23074eSdduvall if (nflag) { 1118*7a23074eSdduvall switch (af) { 1119*7a23074eSdduvall case AF_INET: 1120*7a23074eSdduvall (void) printf(" %s", 1121*7a23074eSdduvall inet_ntoa(so_dst.sin.sin_addr)); 1122*7a23074eSdduvall break; 1123*7a23074eSdduvall case AF_INET6: 1124*7a23074eSdduvall if (inet_ntop(AF_INET6, 1125*7a23074eSdduvall (void *)&so_dst.sin6.sin6_addr, 11267c478bd9Sstevel@tonic-gate obuf, INET6_ADDRSTRLEN) != NULL) { 11277c478bd9Sstevel@tonic-gate (void) printf(" %s", obuf); 11287c478bd9Sstevel@tonic-gate break; 11297c478bd9Sstevel@tonic-gate } 11307c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 11317c478bd9Sstevel@tonic-gate default: 1132*7a23074eSdduvall (void) printf("%s", dest); 11337c478bd9Sstevel@tonic-gate break; 11347c478bd9Sstevel@tonic-gate } 11357c478bd9Sstevel@tonic-gate } else { 1136*7a23074eSdduvall (void) printf("%s", dest); 11377c478bd9Sstevel@tonic-gate } 11387c478bd9Sstevel@tonic-gate } 11397c478bd9Sstevel@tonic-gate switch (oerrno) { 11407c478bd9Sstevel@tonic-gate case ESRCH: 11417c478bd9Sstevel@tonic-gate err = "not in table"; 11427c478bd9Sstevel@tonic-gate break; 11437c478bd9Sstevel@tonic-gate case EBUSY: 11447c478bd9Sstevel@tonic-gate err = "entry in use"; 11457c478bd9Sstevel@tonic-gate break; 11467c478bd9Sstevel@tonic-gate case ENOBUFS: 11477c478bd9Sstevel@tonic-gate err = "routing table overflow"; 11487c478bd9Sstevel@tonic-gate break; 11497c478bd9Sstevel@tonic-gate case EEXIST: 11507c478bd9Sstevel@tonic-gate err = "entry exists"; 11517c478bd9Sstevel@tonic-gate break; 11527c478bd9Sstevel@tonic-gate case EPERM: 11537c478bd9Sstevel@tonic-gate err = "insufficient privileges"; 11547c478bd9Sstevel@tonic-gate break; 11557c478bd9Sstevel@tonic-gate default: 11567c478bd9Sstevel@tonic-gate err = strerror(oerrno); 11577c478bd9Sstevel@tonic-gate break; 11587c478bd9Sstevel@tonic-gate } 11597c478bd9Sstevel@tonic-gate (void) printf(": %s\n", err); 11607c478bd9Sstevel@tonic-gate } 1161*7a23074eSdduvall /* 1162*7a23074eSdduvall * In the case of AF_INET6, one of the getipnodebyX() functions was used 1163*7a23074eSdduvall * so free the allocated hostent. 1164*7a23074eSdduvall */ 1165*7a23074eSdduvall if (af == AF_INET6 && hp != NULL) 1166*7a23074eSdduvall freehostent(hp); 11677c478bd9Sstevel@tonic-gate 11687c478bd9Sstevel@tonic-gate return (oerrno); 11697c478bd9Sstevel@tonic-gate } 11707c478bd9Sstevel@tonic-gate 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate /* 11737c478bd9Sstevel@tonic-gate * Convert a network number to the corresponding IP address. 11747c478bd9Sstevel@tonic-gate * If the RTA_NETMASK hasn't been specified yet set it based 11757c478bd9Sstevel@tonic-gate * on the class of address. 11767c478bd9Sstevel@tonic-gate */ 11777c478bd9Sstevel@tonic-gate static void 1178*7a23074eSdduvall inet_makenetandmask(in_addr_t net, struct sockaddr_in *sin) 11797c478bd9Sstevel@tonic-gate { 11807c478bd9Sstevel@tonic-gate in_addr_t addr, mask; 1181*7a23074eSdduvall char *cp; 11827c478bd9Sstevel@tonic-gate 11837c478bd9Sstevel@tonic-gate if (net == 0) { 11847c478bd9Sstevel@tonic-gate mask = addr = 0; 11857c478bd9Sstevel@tonic-gate } else if (net < 128) { 11867c478bd9Sstevel@tonic-gate addr = net << IN_CLASSA_NSHIFT; 11877c478bd9Sstevel@tonic-gate mask = IN_CLASSA_NET; 11887c478bd9Sstevel@tonic-gate } else if (net < 65536) { 11897c478bd9Sstevel@tonic-gate addr = net << IN_CLASSB_NSHIFT; 11907c478bd9Sstevel@tonic-gate mask = IN_CLASSB_NET; 11917c478bd9Sstevel@tonic-gate } else if (net < 16777216L) { 11927c478bd9Sstevel@tonic-gate addr = net << IN_CLASSC_NSHIFT; 11937c478bd9Sstevel@tonic-gate mask = IN_CLASSC_NET; 11947c478bd9Sstevel@tonic-gate } else { 11957c478bd9Sstevel@tonic-gate addr = net; 11967c478bd9Sstevel@tonic-gate if ((addr & IN_CLASSA_HOST) == 0) 11977c478bd9Sstevel@tonic-gate mask = IN_CLASSA_NET; 11987c478bd9Sstevel@tonic-gate else if ((addr & IN_CLASSB_HOST) == 0) 11997c478bd9Sstevel@tonic-gate mask = IN_CLASSB_NET; 12007c478bd9Sstevel@tonic-gate else if ((addr & IN_CLASSC_HOST) == 0) 12017c478bd9Sstevel@tonic-gate mask = IN_CLASSC_NET; 12027c478bd9Sstevel@tonic-gate else { 12037c478bd9Sstevel@tonic-gate if (IN_CLASSA(addr)) 12047c478bd9Sstevel@tonic-gate mask = IN_CLASSA_NET; 12057c478bd9Sstevel@tonic-gate else if (IN_CLASSB(addr)) 12067c478bd9Sstevel@tonic-gate mask = IN_CLASSB_NET; 12077c478bd9Sstevel@tonic-gate else if (IN_CLASSC(addr)) 12087c478bd9Sstevel@tonic-gate mask = IN_CLASSC_NET; 12097c478bd9Sstevel@tonic-gate else 12107c478bd9Sstevel@tonic-gate mask = IP_HOST_MASK; 12117c478bd9Sstevel@tonic-gate mask = inet_makesubnetmask(addr, mask); 12127c478bd9Sstevel@tonic-gate } 12137c478bd9Sstevel@tonic-gate } 12147c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = htonl(addr); 12157c478bd9Sstevel@tonic-gate 1216*7a23074eSdduvall if (!(rtm_addrs & RTA_NETMASK)) { 1217*7a23074eSdduvall rtm_addrs |= RTA_NETMASK; 1218*7a23074eSdduvall sin = &so_mask.sin; 12197c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = htonl(mask); 12207c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET; 1221*7a23074eSdduvall cp = (char *)(&sin->sin_addr + 1); 1222*7a23074eSdduvall while (*--cp == 0 && cp > (char *)sin) 1223*7a23074eSdduvall ; 12247c478bd9Sstevel@tonic-gate } 12257c478bd9Sstevel@tonic-gate } 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate static in_addr_t 12287c478bd9Sstevel@tonic-gate inet_makesubnetmask(in_addr_t addr, in_addr_t mask) 12297c478bd9Sstevel@tonic-gate { 12307c478bd9Sstevel@tonic-gate int n; 12317c478bd9Sstevel@tonic-gate struct ifconf ifc; 12327c478bd9Sstevel@tonic-gate struct ifreq ifreq; 12337c478bd9Sstevel@tonic-gate struct ifreq *ifr; 12347c478bd9Sstevel@tonic-gate struct sockaddr_in *sin; 12357c478bd9Sstevel@tonic-gate char *buf; 12367c478bd9Sstevel@tonic-gate int numifs; 12377c478bd9Sstevel@tonic-gate size_t bufsize; 12387c478bd9Sstevel@tonic-gate int iosoc; 12397c478bd9Sstevel@tonic-gate in_addr_t if_addr, if_mask; 12407c478bd9Sstevel@tonic-gate in_addr_t if_subnetmask = 0; 12417c478bd9Sstevel@tonic-gate short if_flags; 12427c478bd9Sstevel@tonic-gate 12437c478bd9Sstevel@tonic-gate if (mask == 0) 12447c478bd9Sstevel@tonic-gate return (0); 12457c478bd9Sstevel@tonic-gate if ((iosoc = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 12467c478bd9Sstevel@tonic-gate quit("socket", errno); 12477c478bd9Sstevel@tonic-gate if (ioctl(iosoc, SIOCGIFNUM, (char *)&numifs) < 0) 12487c478bd9Sstevel@tonic-gate quit("ioctl", errno); 12497c478bd9Sstevel@tonic-gate bufsize = numifs * sizeof (struct ifreq); 12507c478bd9Sstevel@tonic-gate buf = malloc(bufsize); 12517c478bd9Sstevel@tonic-gate if (buf == NULL) 12527c478bd9Sstevel@tonic-gate quit("malloc", errno); 12537c478bd9Sstevel@tonic-gate (void) memset(&ifc, 0, sizeof (ifc)); 12547c478bd9Sstevel@tonic-gate ifc.ifc_len = bufsize; 12557c478bd9Sstevel@tonic-gate ifc.ifc_buf = buf; 12567c478bd9Sstevel@tonic-gate if (ioctl(iosoc, SIOCGIFCONF, (char *)&ifc) < 0) 12577c478bd9Sstevel@tonic-gate quit("ioctl (get interface configuration)", errno); 12587c478bd9Sstevel@tonic-gate /* Let's check to see if this is maybe a local subnet route. */ 12597c478bd9Sstevel@tonic-gate ifr = ifc.ifc_req; 12607c478bd9Sstevel@tonic-gate for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) { 12617c478bd9Sstevel@tonic-gate ifreq = *ifr; 12627c478bd9Sstevel@tonic-gate /* LINTED */ 12637c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)&ifr->ifr_addr; 12647c478bd9Sstevel@tonic-gate if_addr = ntohl(sin->sin_addr.s_addr); 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate if (ioctl(iosoc, SIOCGIFFLAGS, (char *)&ifreq) < 0) 12677c478bd9Sstevel@tonic-gate quit("ioctl (get interface flags)", errno); 12687c478bd9Sstevel@tonic-gate if ((ifreq.ifr_flags & IFF_UP) == 0) 12697c478bd9Sstevel@tonic-gate continue; 12707c478bd9Sstevel@tonic-gate if_flags = ifreq.ifr_flags; 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate if (ioctl(iosoc, SIOCGIFNETMASK, (char *)&ifreq) < 0) 12737c478bd9Sstevel@tonic-gate quit("ioctl (get netmask)", errno); 12747c478bd9Sstevel@tonic-gate /* LINTED */ 12757c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)&ifreq.ifr_addr; 12767c478bd9Sstevel@tonic-gate if_mask = ntohl(sin->sin_addr.s_addr); 12777c478bd9Sstevel@tonic-gate if ((if_addr & mask) == (addr & mask)) { 12787c478bd9Sstevel@tonic-gate /* 12797c478bd9Sstevel@tonic-gate * Don't trust pt-pt interfaces if there are 12807c478bd9Sstevel@tonic-gate * other interfaces. 12817c478bd9Sstevel@tonic-gate */ 12827c478bd9Sstevel@tonic-gate if (if_flags & IFF_POINTOPOINT) { 12837c478bd9Sstevel@tonic-gate if_subnetmask = if_mask; 12847c478bd9Sstevel@tonic-gate continue; 12857c478bd9Sstevel@tonic-gate } 12867c478bd9Sstevel@tonic-gate /* 12877c478bd9Sstevel@tonic-gate * Fine. Just assume the same net mask as the 12887c478bd9Sstevel@tonic-gate * directly attached subnet interface is using. 12897c478bd9Sstevel@tonic-gate */ 12907c478bd9Sstevel@tonic-gate return (if_mask); 12917c478bd9Sstevel@tonic-gate } 12927c478bd9Sstevel@tonic-gate } 12937c478bd9Sstevel@tonic-gate if (if_subnetmask != 0) 12947c478bd9Sstevel@tonic-gate return (if_subnetmask); 12957c478bd9Sstevel@tonic-gate return (mask); 12967c478bd9Sstevel@tonic-gate } 12977c478bd9Sstevel@tonic-gate 12987c478bd9Sstevel@tonic-gate /* 1299*7a23074eSdduvall * Interpret an argument as a network address of some kind, 1300*7a23074eSdduvall * returning B_TRUE if a host address, B_FALSE if a network address. 13017c478bd9Sstevel@tonic-gate * 13027c478bd9Sstevel@tonic-gate * If the address family is one looked up in getaddr() using one of the 13037c478bd9Sstevel@tonic-gate * getipnodebyX() functions (currently only AF_INET6), then callers should 13047c478bd9Sstevel@tonic-gate * freehostent() the returned "struct hostent" pointer if one was passed in. 13057c478bd9Sstevel@tonic-gate */ 13067c478bd9Sstevel@tonic-gate static boolean_t 1307*7a23074eSdduvall getaddr(int which, char *s, struct hostent **hpp) 13087c478bd9Sstevel@tonic-gate { 1309*7a23074eSdduvall sup su; 13107c478bd9Sstevel@tonic-gate struct hostent *hp; 13117c478bd9Sstevel@tonic-gate boolean_t ret; 13127c478bd9Sstevel@tonic-gate 1313*7a23074eSdduvall if (s == NULL) { 1314*7a23074eSdduvall (void) fprintf(stderr, 1315*7a23074eSdduvall gettext("route: argument required following keyword\n")); 1316*7a23074eSdduvall usage((char *)NULL); 13173f33f4f7Sjl138328 } 1318*7a23074eSdduvall if (hpp == NULL) 1319*7a23074eSdduvall hpp = &hp; 13207c478bd9Sstevel@tonic-gate *hpp = NULL; 1321*7a23074eSdduvall rtm_addrs |= which; 13227c478bd9Sstevel@tonic-gate switch (which) { 13237c478bd9Sstevel@tonic-gate case RTA_DST: 1324*7a23074eSdduvall su = &so_dst; 1325*7a23074eSdduvall su->sa.sa_family = af; 13267c478bd9Sstevel@tonic-gate break; 13277c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 1328*7a23074eSdduvall su = &so_gate; 1329*7a23074eSdduvall su->sa.sa_family = af; 13307c478bd9Sstevel@tonic-gate break; 13317c478bd9Sstevel@tonic-gate case RTA_NETMASK: 1332*7a23074eSdduvall su = &so_mask; 1333*7a23074eSdduvall su->sa.sa_family = af; 13347c478bd9Sstevel@tonic-gate break; 13357c478bd9Sstevel@tonic-gate case RTA_IFP: 1336*7a23074eSdduvall so_ifp.sdl.sdl_index = if_nametoindex(s); 1337*7a23074eSdduvall if (so_ifp.sdl.sdl_index == 0) { 1338*7a23074eSdduvall if (errno == ENXIO) { 1339*7a23074eSdduvall (void) fprintf(stderr, 1340*7a23074eSdduvall gettext("route: %s: no such interface\n"), 1341*7a23074eSdduvall s); 1342*7a23074eSdduvall exit(1); 1343*7a23074eSdduvall } else { 1344*7a23074eSdduvall quit("if_nametoindex", errno); 1345*7a23074eSdduvall } 1346*7a23074eSdduvall } 1347*7a23074eSdduvall so_ifp.sdl.sdl_family = AF_LINK; 1348*7a23074eSdduvall return (B_FALSE); 13497c478bd9Sstevel@tonic-gate /* 13507c478bd9Sstevel@tonic-gate * RTA_SRC has overloaded meaning. It can represent the 13517c478bd9Sstevel@tonic-gate * src address of incoming or outgoing packets. 13527c478bd9Sstevel@tonic-gate */ 13537c478bd9Sstevel@tonic-gate case RTA_IFA: 1354*7a23074eSdduvall su = &so_ifa; 1355*7a23074eSdduvall su->sa.sa_family = af; 13567c478bd9Sstevel@tonic-gate break; 13577c478bd9Sstevel@tonic-gate case RTA_SRC: 1358*7a23074eSdduvall su = &so_src; 1359*7a23074eSdduvall su->sa.sa_family = af; 13607c478bd9Sstevel@tonic-gate break; 13617c478bd9Sstevel@tonic-gate default: 13627c478bd9Sstevel@tonic-gate /* NOTREACHED */ 13637c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 13647c478bd9Sstevel@tonic-gate /* NOTREACHED */ 13657c478bd9Sstevel@tonic-gate } 13667c478bd9Sstevel@tonic-gate if (strcmp(s, "default") == 0) { 13677c478bd9Sstevel@tonic-gate if (which == RTA_DST) { 1368*7a23074eSdduvall forcenet = B_TRUE; 1369*7a23074eSdduvall (void) getaddr(RTA_NETMASK, s, NULL); 13707c478bd9Sstevel@tonic-gate } 13717c478bd9Sstevel@tonic-gate if (which == RTA_SRC) { 13727c478bd9Sstevel@tonic-gate return (B_TRUE); 13737c478bd9Sstevel@tonic-gate } 1374*7a23074eSdduvall return (B_FALSE); 13757c478bd9Sstevel@tonic-gate } 1376*7a23074eSdduvall switch (af) { 13777c478bd9Sstevel@tonic-gate case AF_LINK: 13787c478bd9Sstevel@tonic-gate link_addr(s, &su->sdl); 13797c478bd9Sstevel@tonic-gate return (B_TRUE); 13807c478bd9Sstevel@tonic-gate case PF_ROUTE: 13817c478bd9Sstevel@tonic-gate sockaddr(s, &su->sa); 13827c478bd9Sstevel@tonic-gate return (B_TRUE); 13837c478bd9Sstevel@tonic-gate case AF_INET6: 13847c478bd9Sstevel@tonic-gate switch (which) { 13857c478bd9Sstevel@tonic-gate case RTA_DST: 13867c478bd9Sstevel@tonic-gate if (s[0] == '/') { 1387*7a23074eSdduvall (void) fprintf(stderr, 1388*7a23074eSdduvall gettext("route: %s: unexpected '/'\n"), s); 1389*7a23074eSdduvall exit(1); 13907c478bd9Sstevel@tonic-gate } 1391*7a23074eSdduvall ret = in6_getaddr(s, &su->sin6, &masklen, hpp); 1392*7a23074eSdduvall switch (masklen) { 13937c478bd9Sstevel@tonic-gate case NO_PREFIX: 13947c478bd9Sstevel@tonic-gate /* Nothing there - ok */ 1395*7a23074eSdduvall return (ret); 13967c478bd9Sstevel@tonic-gate case BAD_ADDR: 1397*7a23074eSdduvall (void) fprintf(stderr, 1398*7a23074eSdduvall gettext("route: bad prefix length in %s\n"), 1399*7a23074eSdduvall s); 1400*7a23074eSdduvall exit(1); 1401*7a23074eSdduvall /* NOTREACHED */ 14027c478bd9Sstevel@tonic-gate default: 1403*7a23074eSdduvall (void) memset(&so_mask.sin6.sin6_addr, 0, 1404*7a23074eSdduvall sizeof (so_mask.sin6.sin6_addr)); 1405*7a23074eSdduvall if (!in_prefixlentomask(masklen, IPV6_ABITS, 1406*7a23074eSdduvall (uchar_t *)&so_mask.sin6.sin6_addr)) { 1407*7a23074eSdduvall (void) fprintf(stderr, 1408*7a23074eSdduvall gettext("route: bad prefix length: " 1409*7a23074eSdduvall "%d\n"), masklen); 1410*7a23074eSdduvall exit(1); 14117c478bd9Sstevel@tonic-gate } 14127c478bd9Sstevel@tonic-gate break; 14137c478bd9Sstevel@tonic-gate } 1414*7a23074eSdduvall so_mask.sin6.sin6_family = af; 1415*7a23074eSdduvall rtm_addrs |= RTA_NETMASK; 1416*7a23074eSdduvall return (ret); 14177c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 14187c478bd9Sstevel@tonic-gate case RTA_IFA: 14197c478bd9Sstevel@tonic-gate case RTA_SRC: 1420*7a23074eSdduvall ret = in6_getaddr(s, &su->sin6, NULL, hpp); 1421*7a23074eSdduvall return (ret); 14227c478bd9Sstevel@tonic-gate case RTA_NETMASK: 1423*7a23074eSdduvall (void) fprintf(stderr, 14247c478bd9Sstevel@tonic-gate gettext("route: -netmask not supported for IPv6: " 1425*7a23074eSdduvall "use <prefix>/<prefix-length> instead")); 1426*7a23074eSdduvall exit(1); 1427*7a23074eSdduvall /* NOTREACHED */ 14287c478bd9Sstevel@tonic-gate default: 14297c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 14307c478bd9Sstevel@tonic-gate /* NOTREACHED */ 14317c478bd9Sstevel@tonic-gate } 14327c478bd9Sstevel@tonic-gate case AF_INET: 14337c478bd9Sstevel@tonic-gate switch (which) { 14347c478bd9Sstevel@tonic-gate case RTA_DST: 14357c478bd9Sstevel@tonic-gate if (s[0] == '/') { 1436*7a23074eSdduvall (void) fprintf(stderr, 1437*7a23074eSdduvall gettext("route: %s: unexpected '/'\n"), s); 1438*7a23074eSdduvall exit(1); 14397c478bd9Sstevel@tonic-gate } 1440*7a23074eSdduvall ret = in_getaddr(s, &su->sin, &masklen, which, hpp); 1441*7a23074eSdduvall switch (masklen) { 14427c478bd9Sstevel@tonic-gate case NO_PREFIX: 14437c478bd9Sstevel@tonic-gate /* Nothing there - ok */ 1444*7a23074eSdduvall return (ret); 14457c478bd9Sstevel@tonic-gate case BAD_ADDR: 1446*7a23074eSdduvall (void) fprintf(stderr, 1447*7a23074eSdduvall gettext("route: bad prefix length in %s\n"), 1448*7a23074eSdduvall s); 1449*7a23074eSdduvall exit(1); 1450*7a23074eSdduvall /* NOTREACHED */ 14517c478bd9Sstevel@tonic-gate default: 1452*7a23074eSdduvall (void) memset(&so_mask.sin.sin_addr, 0, 1453*7a23074eSdduvall sizeof (so_mask.sin.sin_addr)); 1454*7a23074eSdduvall if (!in_prefixlentomask(masklen, IP_ABITS, 1455*7a23074eSdduvall (uchar_t *)&so_mask.sin.sin_addr)) { 1456*7a23074eSdduvall (void) fprintf(stderr, 1457*7a23074eSdduvall gettext("route: bad prefix length: " 1458*7a23074eSdduvall "%d\n"), masklen); 1459*7a23074eSdduvall exit(1); 14607c478bd9Sstevel@tonic-gate } 14617c478bd9Sstevel@tonic-gate break; 14627c478bd9Sstevel@tonic-gate } 1463*7a23074eSdduvall so_mask.sin.sin_family = af; 1464*7a23074eSdduvall rtm_addrs |= RTA_NETMASK; 1465*7a23074eSdduvall return (ret); 14667c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 14677c478bd9Sstevel@tonic-gate case RTA_IFA: 14687c478bd9Sstevel@tonic-gate case RTA_NETMASK: 14697c478bd9Sstevel@tonic-gate case RTA_SRC: 1470*7a23074eSdduvall ret = in_getaddr(s, &su->sin, NULL, which, hpp); 1471*7a23074eSdduvall return (ret); 14727c478bd9Sstevel@tonic-gate default: 14737c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 14747c478bd9Sstevel@tonic-gate /* NOTREACHED */ 14757c478bd9Sstevel@tonic-gate } 14767c478bd9Sstevel@tonic-gate default: 14777c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 14787c478bd9Sstevel@tonic-gate /* NOTREACHED */ 14797c478bd9Sstevel@tonic-gate } 1480*7a23074eSdduvall 14817c478bd9Sstevel@tonic-gate } 14827c478bd9Sstevel@tonic-gate 14837c478bd9Sstevel@tonic-gate /* 14847c478bd9Sstevel@tonic-gate * Interpret an argument as an IPv4 network address of some kind, 1485*7a23074eSdduvall * returning B_TRUE if a host address, B_FALSE if a network address. 14867c478bd9Sstevel@tonic-gate * Note that this *always* tries host interpretation before network 14877c478bd9Sstevel@tonic-gate * interpretation. 14887c478bd9Sstevel@tonic-gate * 14897c478bd9Sstevel@tonic-gate * If the plenp argument is non-NULL, allow <addr>/<n> syntax and 14907c478bd9Sstevel@tonic-gate * pass out <n> in *plenp. 14917c478bd9Sstevel@tonic-gate * If <n> doesn't parse return BAD_ADDR as *plenp. 14927c478bd9Sstevel@tonic-gate * If no /<n> is present return NO_PREFIX as *plenp. 14937c478bd9Sstevel@tonic-gate */ 14947c478bd9Sstevel@tonic-gate static boolean_t 14957c478bd9Sstevel@tonic-gate in_getaddr(char *s, struct sockaddr_in *sin, int *plenp, int which, 1496*7a23074eSdduvall struct hostent **hpp) 14977c478bd9Sstevel@tonic-gate { 14987c478bd9Sstevel@tonic-gate struct hostent *hp; 14997c478bd9Sstevel@tonic-gate struct netent *np; 15007c478bd9Sstevel@tonic-gate in_addr_t val; 15017c478bd9Sstevel@tonic-gate char str[BUFSIZ]; 15027c478bd9Sstevel@tonic-gate 15037c478bd9Sstevel@tonic-gate (void) strncpy(str, s, sizeof (str)); 15047c478bd9Sstevel@tonic-gate 15057c478bd9Sstevel@tonic-gate /* 15067c478bd9Sstevel@tonic-gate * Look for '/'<n> is plenp 15077c478bd9Sstevel@tonic-gate */ 15087c478bd9Sstevel@tonic-gate if (plenp != NULL) { 15097c478bd9Sstevel@tonic-gate char *cp; 15107c478bd9Sstevel@tonic-gate 15117c478bd9Sstevel@tonic-gate *plenp = in_getprefixlen(str, IP_ABITS); 15127c478bd9Sstevel@tonic-gate if (*plenp == BAD_ADDR) 15137c478bd9Sstevel@tonic-gate return (B_FALSE); 15147c478bd9Sstevel@tonic-gate cp = strchr(str, '/'); 15157c478bd9Sstevel@tonic-gate if (cp != NULL) 15167c478bd9Sstevel@tonic-gate *cp = '\0'; 15177c478bd9Sstevel@tonic-gate } else if (strchr(str, '/') != NULL) { 1518*7a23074eSdduvall (void) fprintf(stderr, gettext("route: %s: unexpected '/'\n"), 1519*7a23074eSdduvall str); 1520*7a23074eSdduvall exit(1); 15217c478bd9Sstevel@tonic-gate } 15227c478bd9Sstevel@tonic-gate 15237c478bd9Sstevel@tonic-gate (void) memset(sin, 0, sizeof (*sin)); 15247c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET; 15257c478bd9Sstevel@tonic-gate 15267c478bd9Sstevel@tonic-gate /* 15277c478bd9Sstevel@tonic-gate * Note: only the route destination can be a network, so we treat 15287c478bd9Sstevel@tonic-gate * all other addresses as though "-net" was not specified. 15297c478bd9Sstevel@tonic-gate */ 15307c478bd9Sstevel@tonic-gate if ((((val = inet_addr(str)) != (in_addr_t)-1) || 15317c478bd9Sstevel@tonic-gate strcmp(str, "255.255.255.255") == 0) && 1532*7a23074eSdduvall (which != RTA_DST || !forcenet)) { 15337c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = val; 15347c478bd9Sstevel@tonic-gate if (inet_lnaof(sin->sin_addr) != INADDR_ANY || 1535*7a23074eSdduvall forcehost) 15367c478bd9Sstevel@tonic-gate return (B_TRUE); 15377c478bd9Sstevel@tonic-gate val = ntohl(val); 15387c478bd9Sstevel@tonic-gate if (which == RTA_DST) 1539*7a23074eSdduvall inet_makenetandmask(val, sin); 1540*7a23074eSdduvall return (B_FALSE); 15417c478bd9Sstevel@tonic-gate } 1542*7a23074eSdduvall if (!forcehost && (val = inet_network(str)) != (in_addr_t)-1) { 15437c478bd9Sstevel@tonic-gate if (which == RTA_DST) 1544*7a23074eSdduvall inet_makenetandmask(val, sin); 1545*7a23074eSdduvall return (B_FALSE); 15467c478bd9Sstevel@tonic-gate } 1547*7a23074eSdduvall if ((which != RTA_DST || !forcenet) && 15487c478bd9Sstevel@tonic-gate (hp = gethostbyname(str)) != NULL) { 15497c478bd9Sstevel@tonic-gate *hpp = hp; 15507c478bd9Sstevel@tonic-gate (void) memmove(&sin->sin_addr, hp->h_addr, 15517c478bd9Sstevel@tonic-gate hp->h_length); 15527c478bd9Sstevel@tonic-gate return (B_TRUE); 15537c478bd9Sstevel@tonic-gate } 1554*7a23074eSdduvall if (!forcehost && (np = getnetbyname(str)) != NULL && 15557c478bd9Sstevel@tonic-gate (val = np->n_net) != 0) { 15567c478bd9Sstevel@tonic-gate if (which == RTA_DST) 1557*7a23074eSdduvall inet_makenetandmask(val, sin); 15583f33f4f7Sjl138328 return (B_FALSE); 15597c478bd9Sstevel@tonic-gate } 1560*7a23074eSdduvall (void) fprintf(stderr, gettext("%s: bad value\n"), s); 1561*7a23074eSdduvall exit(1); 1562*7a23074eSdduvall /* NOTREACHED */ 1563*7a23074eSdduvall } 15647c478bd9Sstevel@tonic-gate 15657c478bd9Sstevel@tonic-gate /* 15667c478bd9Sstevel@tonic-gate * Interpret an argument as an IPv6 network address of some kind, 1567*7a23074eSdduvall * returning B_TRUE if a host address, B_FALSE if a network address. 15687c478bd9Sstevel@tonic-gate * 15697c478bd9Sstevel@tonic-gate * If the last argument is non-NULL allow a <addr>/<n> syntax and 15707c478bd9Sstevel@tonic-gate * pass out <n> in *plenp. 15717c478bd9Sstevel@tonic-gate * If <n> doesn't parse return BAD_ADDR as *plenp. 15727c478bd9Sstevel@tonic-gate * If no /<n> is present return NO_PREFIX as *plenp. 15737c478bd9Sstevel@tonic-gate */ 15747c478bd9Sstevel@tonic-gate static boolean_t 15757c478bd9Sstevel@tonic-gate in6_getaddr(char *s, struct sockaddr_in6 *sin6, int *plenp, 15767c478bd9Sstevel@tonic-gate struct hostent **hpp) 15777c478bd9Sstevel@tonic-gate { 15787c478bd9Sstevel@tonic-gate struct hostent *hp; 15797c478bd9Sstevel@tonic-gate char str[BUFSIZ]; 15807c478bd9Sstevel@tonic-gate int error_num; 15817c478bd9Sstevel@tonic-gate 15827c478bd9Sstevel@tonic-gate (void) strncpy(str, s, sizeof (str)); 15837c478bd9Sstevel@tonic-gate 15847c478bd9Sstevel@tonic-gate /* 15857c478bd9Sstevel@tonic-gate * Look for '/'<n> is plenp 15867c478bd9Sstevel@tonic-gate */ 15877c478bd9Sstevel@tonic-gate if (plenp != NULL) { 15887c478bd9Sstevel@tonic-gate char *cp; 15897c478bd9Sstevel@tonic-gate 15907c478bd9Sstevel@tonic-gate *plenp = in_getprefixlen(str, IPV6_ABITS); 15917c478bd9Sstevel@tonic-gate if (*plenp == BAD_ADDR) 15927c478bd9Sstevel@tonic-gate return (B_FALSE); 15937c478bd9Sstevel@tonic-gate cp = strchr(str, '/'); 15947c478bd9Sstevel@tonic-gate if (cp != NULL) 15957c478bd9Sstevel@tonic-gate *cp = '\0'; 15967c478bd9Sstevel@tonic-gate } else if (strchr(str, '/') != NULL) { 1597*7a23074eSdduvall (void) fprintf(stderr, gettext("route: %s: unexpected '/'\n"), 1598*7a23074eSdduvall str); 1599*7a23074eSdduvall exit(1); 16007c478bd9Sstevel@tonic-gate } 16017c478bd9Sstevel@tonic-gate 16027c478bd9Sstevel@tonic-gate (void) memset(sin6, 0, sizeof (struct sockaddr_in6)); 16037c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 16047c478bd9Sstevel@tonic-gate 16057c478bd9Sstevel@tonic-gate hp = getipnodebyname(str, AF_INET6, 0, &error_num); 16067c478bd9Sstevel@tonic-gate if (hp != NULL) { 16077c478bd9Sstevel@tonic-gate *hpp = hp; 16087c478bd9Sstevel@tonic-gate (void) memmove(&sin6->sin6_addr, hp->h_addr, hp->h_length); 16097c478bd9Sstevel@tonic-gate return (B_TRUE); 16107c478bd9Sstevel@tonic-gate } 16117c478bd9Sstevel@tonic-gate if (error_num == TRY_AGAIN) { 1612*7a23074eSdduvall (void) fprintf(stderr, gettext("route: %s: bad address (try " 16133f33f4f7Sjl138328 "again later)\n"), s); 1614*7a23074eSdduvall } else { 1615*7a23074eSdduvall (void) fprintf(stderr, gettext("route: %s: bad address\n"), s); 16163f33f4f7Sjl138328 } 1617*7a23074eSdduvall exit(1); 1618*7a23074eSdduvall /* NOTREACHED */ 16197c478bd9Sstevel@tonic-gate } 16207c478bd9Sstevel@tonic-gate 16217c478bd9Sstevel@tonic-gate /* 16227c478bd9Sstevel@tonic-gate * If "slash" is zero this parses the whole string as 16237c478bd9Sstevel@tonic-gate * an integer. With "slash" non zero it parses the tail part as an integer. 16247c478bd9Sstevel@tonic-gate * 16257c478bd9Sstevel@tonic-gate * If it is not a valid integer this returns BAD_ADDR. 16267c478bd9Sstevel@tonic-gate * If there is /<n> present this returns NO_PREFIX. 16277c478bd9Sstevel@tonic-gate */ 16287c478bd9Sstevel@tonic-gate int 16297c478bd9Sstevel@tonic-gate in_getprefixlen(char *addr, int max_plen) 16307c478bd9Sstevel@tonic-gate { 16317c478bd9Sstevel@tonic-gate int prefixlen; 16327c478bd9Sstevel@tonic-gate char *str, *end; 16337c478bd9Sstevel@tonic-gate 16347c478bd9Sstevel@tonic-gate str = strchr(addr, '/'); 16357c478bd9Sstevel@tonic-gate if (str == NULL) 16367c478bd9Sstevel@tonic-gate return (NO_PREFIX); 16377c478bd9Sstevel@tonic-gate str++; 16387c478bd9Sstevel@tonic-gate 16397c478bd9Sstevel@tonic-gate prefixlen = strtol(str, &end, 10); 16407c478bd9Sstevel@tonic-gate if (prefixlen < 0) 16417c478bd9Sstevel@tonic-gate return (BAD_ADDR); 16427c478bd9Sstevel@tonic-gate if (str == end) 16437c478bd9Sstevel@tonic-gate return (BAD_ADDR); 16447c478bd9Sstevel@tonic-gate if (max_plen != 0 && max_plen < prefixlen) 16457c478bd9Sstevel@tonic-gate return (BAD_ADDR); 16467c478bd9Sstevel@tonic-gate else 16477c478bd9Sstevel@tonic-gate return (prefixlen); 16487c478bd9Sstevel@tonic-gate } 16497c478bd9Sstevel@tonic-gate 16507c478bd9Sstevel@tonic-gate /* 16517c478bd9Sstevel@tonic-gate * Convert a prefix length to a mask. 16527c478bd9Sstevel@tonic-gate * Returns B_TRUE if ok. B_FALSE otherwise. 16537c478bd9Sstevel@tonic-gate * Assumes the mask array is zeroed by the caller. 16547c478bd9Sstevel@tonic-gate */ 16557c478bd9Sstevel@tonic-gate boolean_t 16567c478bd9Sstevel@tonic-gate in_prefixlentomask(int prefixlen, int maxlen, uchar_t *mask) 16577c478bd9Sstevel@tonic-gate { 16587c478bd9Sstevel@tonic-gate if (prefixlen < 0 || prefixlen > maxlen) 16597c478bd9Sstevel@tonic-gate return (B_FALSE); 16607c478bd9Sstevel@tonic-gate 16617c478bd9Sstevel@tonic-gate while (prefixlen > 0) { 16627c478bd9Sstevel@tonic-gate if (prefixlen >= 8) { 16637c478bd9Sstevel@tonic-gate *mask++ = 0xFF; 16647c478bd9Sstevel@tonic-gate prefixlen -= 8; 16657c478bd9Sstevel@tonic-gate continue; 16667c478bd9Sstevel@tonic-gate } 16677c478bd9Sstevel@tonic-gate *mask |= 1 << (8 - prefixlen); 16687c478bd9Sstevel@tonic-gate prefixlen--; 16697c478bd9Sstevel@tonic-gate } 16707c478bd9Sstevel@tonic-gate return (B_TRUE); 16717c478bd9Sstevel@tonic-gate } 16727c478bd9Sstevel@tonic-gate 16737c478bd9Sstevel@tonic-gate void 16747c478bd9Sstevel@tonic-gate rtmonitor(int argc, char *argv[]) 16757c478bd9Sstevel@tonic-gate { 16767c478bd9Sstevel@tonic-gate int n; 16777c478bd9Sstevel@tonic-gate intmax_t msg[2048 / sizeof (intmax_t)]; 16787c478bd9Sstevel@tonic-gate 16797c478bd9Sstevel@tonic-gate if (tflag) 16807c478bd9Sstevel@tonic-gate exit(0); 16817c478bd9Sstevel@tonic-gate verbose = B_TRUE; 16827c478bd9Sstevel@tonic-gate if (argc > 1) { 16837c478bd9Sstevel@tonic-gate argv++; 16847c478bd9Sstevel@tonic-gate if (argc == 2 && **argv == '-') { 16857c478bd9Sstevel@tonic-gate switch (keyword(*argv + 1)) { 16867c478bd9Sstevel@tonic-gate case K_INET: 16877c478bd9Sstevel@tonic-gate af = AF_INET; 16887c478bd9Sstevel@tonic-gate break; 16897c478bd9Sstevel@tonic-gate case K_LINK: 16907c478bd9Sstevel@tonic-gate af = AF_LINK; 16917c478bd9Sstevel@tonic-gate break; 16927c478bd9Sstevel@tonic-gate case K_INET6: 16937c478bd9Sstevel@tonic-gate af = AF_INET6; 16947c478bd9Sstevel@tonic-gate break; 16957c478bd9Sstevel@tonic-gate default: 16967c478bd9Sstevel@tonic-gate usage(*argv); 16977c478bd9Sstevel@tonic-gate /* NOTREACHED */ 16987c478bd9Sstevel@tonic-gate } 16997c478bd9Sstevel@tonic-gate } else { 17007c478bd9Sstevel@tonic-gate usage(*argv); 17017c478bd9Sstevel@tonic-gate } 17027c478bd9Sstevel@tonic-gate (void) close(s); 17037c478bd9Sstevel@tonic-gate s = socket(PF_ROUTE, SOCK_RAW, af); 17047c478bd9Sstevel@tonic-gate if (s < 0) 17057c478bd9Sstevel@tonic-gate quit("socket", errno); 17067c478bd9Sstevel@tonic-gate } 17077c478bd9Sstevel@tonic-gate for (;;) { 17087c478bd9Sstevel@tonic-gate n = read(s, msg, sizeof (msg)); 17097c478bd9Sstevel@tonic-gate if (n <= 0) 17107c478bd9Sstevel@tonic-gate quit("read", errno); 17117c478bd9Sstevel@tonic-gate (void) printf("got message of size %d\n", n); 17127c478bd9Sstevel@tonic-gate print_rtmsg((struct rt_msghdr *)msg, n); 17137c478bd9Sstevel@tonic-gate } 17147c478bd9Sstevel@tonic-gate } 17157c478bd9Sstevel@tonic-gate 17167c478bd9Sstevel@tonic-gate int 1717*7a23074eSdduvall rtmsg(int cmd, int flags) 17187c478bd9Sstevel@tonic-gate { 17197c478bd9Sstevel@tonic-gate static int seq; 17207c478bd9Sstevel@tonic-gate int rlen; 17217c478bd9Sstevel@tonic-gate char *cp = m_rtmsg.m_space; 17227c478bd9Sstevel@tonic-gate int l; 17237c478bd9Sstevel@tonic-gate 17247c478bd9Sstevel@tonic-gate errno = 0; 17257c478bd9Sstevel@tonic-gate (void) memset(&m_rtmsg, 0, sizeof (m_rtmsg)); 1726*7a23074eSdduvall if (cmd == 'a') { 1727*7a23074eSdduvall cmd = RTM_ADD; 1728*7a23074eSdduvall } else if (cmd == 'c') { 1729*7a23074eSdduvall cmd = RTM_CHANGE; 1730*7a23074eSdduvall } else if (cmd == 'g') { 1731*7a23074eSdduvall cmd = RTM_GET; 1732*7a23074eSdduvall if (so_ifp.sa.sa_family == 0) { 1733*7a23074eSdduvall so_ifp.sa.sa_family = AF_LINK; 1734*7a23074eSdduvall rtm_addrs |= RTA_IFP; 17357c478bd9Sstevel@tonic-gate } 1736*7a23074eSdduvall } else { 1737*7a23074eSdduvall cmd = RTM_DELETE; 1738*7a23074eSdduvall } 17397c478bd9Sstevel@tonic-gate #define rtm m_rtmsg.m_rtm 1740*7a23074eSdduvall rtm.rtm_type = cmd; 1741*7a23074eSdduvall rtm.rtm_flags = flags; 17427c478bd9Sstevel@tonic-gate rtm.rtm_version = RTM_VERSION; 17437c478bd9Sstevel@tonic-gate rtm.rtm_seq = ++seq; 1744*7a23074eSdduvall rtm.rtm_addrs = rtm_addrs; 1745*7a23074eSdduvall rtm.rtm_rmx = rt_metrics; 1746*7a23074eSdduvall rtm.rtm_inits = rtm_inits; 17477c478bd9Sstevel@tonic-gate 17487c478bd9Sstevel@tonic-gate #define NEXTADDR(w, u) \ 1749*7a23074eSdduvall if (rtm_addrs & (w)) { \ 17507c478bd9Sstevel@tonic-gate l = ROUNDUP_LONG(salen(&u.sa)); \ 17517c478bd9Sstevel@tonic-gate (void) memmove(cp, &(u), l); \ 17527c478bd9Sstevel@tonic-gate cp += l; \ 17537c478bd9Sstevel@tonic-gate if (verbose) \ 17547c478bd9Sstevel@tonic-gate sodump(&(u), #u); \ 17557c478bd9Sstevel@tonic-gate } 1756*7a23074eSdduvall NEXTADDR(RTA_DST, so_dst); 1757*7a23074eSdduvall NEXTADDR(RTA_GATEWAY, so_gate); 1758*7a23074eSdduvall NEXTADDR(RTA_NETMASK, so_mask); 1759*7a23074eSdduvall NEXTADDR(RTA_IFP, so_ifp); 1760*7a23074eSdduvall NEXTADDR(RTA_IFA, so_ifa); 17617c478bd9Sstevel@tonic-gate /* 17627c478bd9Sstevel@tonic-gate * RTA_SRC has overloaded meaning. It can represent the 17637c478bd9Sstevel@tonic-gate * src address of incoming or outgoing packets. 17647c478bd9Sstevel@tonic-gate */ 1765*7a23074eSdduvall NEXTADDR(RTA_SRC, so_src); 17667c478bd9Sstevel@tonic-gate #undef NEXTADDR 17677c478bd9Sstevel@tonic-gate rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; 17687c478bd9Sstevel@tonic-gate if (verbose) 17697c478bd9Sstevel@tonic-gate print_rtmsg(&rtm, l); 17707c478bd9Sstevel@tonic-gate if (debugonly) 17717c478bd9Sstevel@tonic-gate return (0); 17727c478bd9Sstevel@tonic-gate if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 17737c478bd9Sstevel@tonic-gate switch (errno) { 17747c478bd9Sstevel@tonic-gate case ESRCH: 17757c478bd9Sstevel@tonic-gate case EBUSY: 17767c478bd9Sstevel@tonic-gate case ENOBUFS: 17777c478bd9Sstevel@tonic-gate case EEXIST: 17787c478bd9Sstevel@tonic-gate case ENETUNREACH: 17797c478bd9Sstevel@tonic-gate case EHOSTUNREACH: 17807c478bd9Sstevel@tonic-gate case EPERM: 17817c478bd9Sstevel@tonic-gate break; 17827c478bd9Sstevel@tonic-gate default: 17837c478bd9Sstevel@tonic-gate perror(gettext("writing to routing socket")); 17847c478bd9Sstevel@tonic-gate break; 17857c478bd9Sstevel@tonic-gate } 17867c478bd9Sstevel@tonic-gate return (-1); 17877c478bd9Sstevel@tonic-gate } else if (rlen < (int)rtm.rtm_msglen) { 17887c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 17897c478bd9Sstevel@tonic-gate gettext("route: write to routing socket got only %d for " 17907c478bd9Sstevel@tonic-gate "len\n"), rlen); 17917c478bd9Sstevel@tonic-gate return (-1); 17927c478bd9Sstevel@tonic-gate } 1793*7a23074eSdduvall if (cmd == RTM_GET) { 17947c478bd9Sstevel@tonic-gate do { 17957c478bd9Sstevel@tonic-gate l = read(s, (char *)&m_rtmsg, sizeof (m_rtmsg)); 17967c478bd9Sstevel@tonic-gate } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); 17977c478bd9Sstevel@tonic-gate if (l < 0) { 17987c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 17997c478bd9Sstevel@tonic-gate gettext("route: read from routing socket: %s\n"), 18007c478bd9Sstevel@tonic-gate strerror(errno)); 18017c478bd9Sstevel@tonic-gate } else { 1802*7a23074eSdduvall print_getmsg(&rtm, l); 18037c478bd9Sstevel@tonic-gate } 18047c478bd9Sstevel@tonic-gate } 18057c478bd9Sstevel@tonic-gate #undef rtm 18067c478bd9Sstevel@tonic-gate return (0); 18077c478bd9Sstevel@tonic-gate } 18087c478bd9Sstevel@tonic-gate 18097c478bd9Sstevel@tonic-gate static char *msgtypes[] = { 18107c478bd9Sstevel@tonic-gate "", 18117c478bd9Sstevel@tonic-gate "RTM_ADD: Add Route", 18127c478bd9Sstevel@tonic-gate "RTM_DELETE: Delete Route", 18137c478bd9Sstevel@tonic-gate "RTM_CHANGE: Change Metrics or flags", 18147c478bd9Sstevel@tonic-gate "RTM_GET: Report Metrics", 18157c478bd9Sstevel@tonic-gate "RTM_LOSING: Kernel Suspects Partitioning", 18167c478bd9Sstevel@tonic-gate "RTM_REDIRECT: Told to use different route", 18177c478bd9Sstevel@tonic-gate "RTM_MISS: Lookup failed on this address", 18187c478bd9Sstevel@tonic-gate "RTM_LOCK: fix specified metrics", 18197c478bd9Sstevel@tonic-gate "RTM_OLDADD: caused by SIOCADDRT", 18207c478bd9Sstevel@tonic-gate "RTM_OLDDEL: caused by SIOCDELRT", 18217c478bd9Sstevel@tonic-gate "RTM_RESOLVE: Route created by cloning", 18227c478bd9Sstevel@tonic-gate "RTM_NEWADDR: address being added to iface", 18237c478bd9Sstevel@tonic-gate "RTM_DELADDR: address being removed from iface", 18247c478bd9Sstevel@tonic-gate "RTM_IFINFO: iface status change", 18257c478bd9Sstevel@tonic-gate 0, 18267c478bd9Sstevel@tonic-gate }; 18277c478bd9Sstevel@tonic-gate 18287c478bd9Sstevel@tonic-gate #define NMSGTYPES (sizeof (msgtypes) / sizeof (msgtypes[0])) 18297c478bd9Sstevel@tonic-gate 18307c478bd9Sstevel@tonic-gate static char metricnames[] = 18317c478bd9Sstevel@tonic-gate "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount" 18327c478bd9Sstevel@tonic-gate "\1mtu"; 18337c478bd9Sstevel@tonic-gate static char routeflags[] = 18347c478bd9Sstevel@tonic-gate "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT" 18357c478bd9Sstevel@tonic-gate "\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE" 18367c478bd9Sstevel@tonic-gate "\016PRIVATE\017PROTO2\020PROTO1\021MULTIRT\022SETSRC"; 18377c478bd9Sstevel@tonic-gate static char ifnetflags[] = 18387c478bd9Sstevel@tonic-gate "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP" 18397c478bd9Sstevel@tonic-gate "\011PPROMISC\012ALLMULTI\013INTELLIGENT\014MULTICAST" 18407c478bd9Sstevel@tonic-gate "\015MULTI_BCAST\016UNNUMBERED\017DHCP\020PRIVATE" 18417c478bd9Sstevel@tonic-gate "\021NOXMIT\022NOLOCAL\023DEPRECATED\024ADDRCONF" 18427c478bd9Sstevel@tonic-gate "\025ROUTER\026NONUD\027ANYCAST\030NORTEXCH\031IPv4\032IPv6" 18437c478bd9Sstevel@tonic-gate "\033MIP\034NOFAILOVER\035FAILED\036STANDBY\037INACTIVE\040OFFLINE" 18447c478bd9Sstevel@tonic-gate "\041XRESOLV\042COS\043PREFERRED\044TEMPORARY"; 18457c478bd9Sstevel@tonic-gate static char addrnames[] = 18467c478bd9Sstevel@tonic-gate "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011SRC"; 18477c478bd9Sstevel@tonic-gate 18487c478bd9Sstevel@tonic-gate void 18497c478bd9Sstevel@tonic-gate print_rtmsg(struct rt_msghdr *rtm, int msglen) 18507c478bd9Sstevel@tonic-gate { 18517c478bd9Sstevel@tonic-gate struct if_msghdr *ifm; 18527c478bd9Sstevel@tonic-gate struct ifa_msghdr *ifam; 18537c478bd9Sstevel@tonic-gate 18547c478bd9Sstevel@tonic-gate if (!verbose) 18557c478bd9Sstevel@tonic-gate return; 18567c478bd9Sstevel@tonic-gate if (rtm->rtm_version != RTM_VERSION) { 18577c478bd9Sstevel@tonic-gate (void) printf("routing message version %d not understood\n", 18587c478bd9Sstevel@tonic-gate rtm->rtm_version); 18597c478bd9Sstevel@tonic-gate return; 18607c478bd9Sstevel@tonic-gate } 18617c478bd9Sstevel@tonic-gate if (rtm->rtm_msglen > (ushort_t)msglen) { 18627c478bd9Sstevel@tonic-gate (void) printf("message length mismatch, in packet %d, " 18637c478bd9Sstevel@tonic-gate "returned %d\n", 18647c478bd9Sstevel@tonic-gate rtm->rtm_msglen, msglen); 18657c478bd9Sstevel@tonic-gate } 18667c478bd9Sstevel@tonic-gate /* 18677c478bd9Sstevel@tonic-gate * Since rtm->rtm_type is unsigned, we'll just check the case of zero 18687c478bd9Sstevel@tonic-gate * and the upper-bound of (NMSGTYPES - 1). 18697c478bd9Sstevel@tonic-gate */ 18707c478bd9Sstevel@tonic-gate if (rtm->rtm_type == 0 || rtm->rtm_type >= (NMSGTYPES - 1)) { 18717c478bd9Sstevel@tonic-gate (void) printf("routing message type %d not understood\n", 18727c478bd9Sstevel@tonic-gate rtm->rtm_type); 18737c478bd9Sstevel@tonic-gate return; 18747c478bd9Sstevel@tonic-gate } 18757c478bd9Sstevel@tonic-gate (void) printf("%s: len %d, ", msgtypes[rtm->rtm_type], rtm->rtm_msglen); 18767c478bd9Sstevel@tonic-gate switch (rtm->rtm_type) { 18777c478bd9Sstevel@tonic-gate case RTM_IFINFO: 18787c478bd9Sstevel@tonic-gate ifm = (struct if_msghdr *)rtm; 18797c478bd9Sstevel@tonic-gate (void) printf("if# %d, flags:", ifm->ifm_index); 18807c478bd9Sstevel@tonic-gate bprintf(stdout, ifm->ifm_flags, ifnetflags); 18817c478bd9Sstevel@tonic-gate pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs); 18827c478bd9Sstevel@tonic-gate break; 18837c478bd9Sstevel@tonic-gate case RTM_NEWADDR: 18847c478bd9Sstevel@tonic-gate case RTM_DELADDR: 18857c478bd9Sstevel@tonic-gate ifam = (struct ifa_msghdr *)rtm; 18867c478bd9Sstevel@tonic-gate (void) printf("metric %d, flags:", ifam->ifam_metric); 18877c478bd9Sstevel@tonic-gate bprintf(stdout, ifam->ifam_flags, routeflags); 18887c478bd9Sstevel@tonic-gate pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs); 18897c478bd9Sstevel@tonic-gate break; 18907c478bd9Sstevel@tonic-gate default: 18917c478bd9Sstevel@tonic-gate (void) printf("pid: %ld, seq %d, errno %d, flags:", 18927c478bd9Sstevel@tonic-gate rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); 18937c478bd9Sstevel@tonic-gate bprintf(stdout, rtm->rtm_flags, routeflags); 18947c478bd9Sstevel@tonic-gate pmsg_common(rtm); 18957c478bd9Sstevel@tonic-gate } 18967c478bd9Sstevel@tonic-gate } 18977c478bd9Sstevel@tonic-gate 18987c478bd9Sstevel@tonic-gate void 1899*7a23074eSdduvall print_getmsg(struct rt_msghdr *rtm, int msglen) 19007c478bd9Sstevel@tonic-gate { 19017c478bd9Sstevel@tonic-gate struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *src = NULL; 19027c478bd9Sstevel@tonic-gate struct sockaddr_dl *ifp = NULL; 19037c478bd9Sstevel@tonic-gate struct sockaddr *sa; 19047c478bd9Sstevel@tonic-gate char *cp; 19057c478bd9Sstevel@tonic-gate int i; 19067c478bd9Sstevel@tonic-gate 1907*7a23074eSdduvall (void) printf(" route to: %s\n", routename(&so_dst.sa)); 19087c478bd9Sstevel@tonic-gate if (rtm->rtm_version != RTM_VERSION) { 19097c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 19107c478bd9Sstevel@tonic-gate gettext("routing message version %d not understood\n"), 19117c478bd9Sstevel@tonic-gate rtm->rtm_version); 19127c478bd9Sstevel@tonic-gate return; 19137c478bd9Sstevel@tonic-gate } 19147c478bd9Sstevel@tonic-gate if (rtm->rtm_msglen > (ushort_t)msglen) { 19157c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 19167c478bd9Sstevel@tonic-gate gettext("message length mismatch, in packet %d, " 19177c478bd9Sstevel@tonic-gate "returned %d\n"), rtm->rtm_msglen, msglen); 19187c478bd9Sstevel@tonic-gate } 19197c478bd9Sstevel@tonic-gate if (rtm->rtm_errno) { 19207c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "RTM_GET: %s (errno %d)\n", 19217c478bd9Sstevel@tonic-gate strerror(rtm->rtm_errno), rtm->rtm_errno); 19227c478bd9Sstevel@tonic-gate return; 19237c478bd9Sstevel@tonic-gate } 19247c478bd9Sstevel@tonic-gate cp = ((char *)(rtm + 1)); 19257c478bd9Sstevel@tonic-gate if (rtm->rtm_addrs != 0) { 19267c478bd9Sstevel@tonic-gate for (i = 1; i != 0; i <<= 1) { 19277c478bd9Sstevel@tonic-gate if (i & rtm->rtm_addrs) { 19287c478bd9Sstevel@tonic-gate /* LINTED */ 19297c478bd9Sstevel@tonic-gate sa = (struct sockaddr *)cp; 19307c478bd9Sstevel@tonic-gate switch (i) { 19317c478bd9Sstevel@tonic-gate case RTA_DST: 19327c478bd9Sstevel@tonic-gate dst = sa; 19337c478bd9Sstevel@tonic-gate break; 19347c478bd9Sstevel@tonic-gate case RTA_GATEWAY: 19357c478bd9Sstevel@tonic-gate gate = sa; 19367c478bd9Sstevel@tonic-gate break; 19377c478bd9Sstevel@tonic-gate case RTA_NETMASK: 19387c478bd9Sstevel@tonic-gate mask = sa; 19397c478bd9Sstevel@tonic-gate break; 19407c478bd9Sstevel@tonic-gate case RTA_IFP: 19417c478bd9Sstevel@tonic-gate if (sa->sa_family == AF_LINK && 19427c478bd9Sstevel@tonic-gate ((struct sockaddr_dl *)sa)-> 19437c478bd9Sstevel@tonic-gate sdl_nlen != 0) 19447c478bd9Sstevel@tonic-gate ifp = (struct sockaddr_dl *)sa; 19457c478bd9Sstevel@tonic-gate break; 19467c478bd9Sstevel@tonic-gate case RTA_SRC: 19477c478bd9Sstevel@tonic-gate src = sa; 19487c478bd9Sstevel@tonic-gate break; 19497c478bd9Sstevel@tonic-gate } 19507c478bd9Sstevel@tonic-gate ADVANCE(cp, sa); 19517c478bd9Sstevel@tonic-gate } 19527c478bd9Sstevel@tonic-gate } 19537c478bd9Sstevel@tonic-gate } 19547c478bd9Sstevel@tonic-gate if (dst != NULL && mask != NULL) 19557c478bd9Sstevel@tonic-gate mask->sa_family = dst->sa_family; /* XXX */ 19567c478bd9Sstevel@tonic-gate if (dst != NULL) 19577c478bd9Sstevel@tonic-gate (void) printf("destination: %s\n", routename(dst)); 19587c478bd9Sstevel@tonic-gate if (mask != NULL) { 19597c478bd9Sstevel@tonic-gate boolean_t savenflag = nflag; 19607c478bd9Sstevel@tonic-gate 19617c478bd9Sstevel@tonic-gate nflag = B_TRUE; 19627c478bd9Sstevel@tonic-gate (void) printf(" mask: %s\n", routename(mask)); 19637c478bd9Sstevel@tonic-gate nflag = savenflag; 19647c478bd9Sstevel@tonic-gate } 19657c478bd9Sstevel@tonic-gate if (gate != NULL && rtm->rtm_flags & RTF_GATEWAY) 19667c478bd9Sstevel@tonic-gate (void) printf(" gateway: %s\n", routename(gate)); 19677c478bd9Sstevel@tonic-gate if (src != NULL && rtm->rtm_flags & RTF_SETSRC) 19687c478bd9Sstevel@tonic-gate (void) printf(" setsrc: %s\n", routename(src)); 19697c478bd9Sstevel@tonic-gate if (ifp != NULL) { 19707c478bd9Sstevel@tonic-gate if (verbose) { 19717c478bd9Sstevel@tonic-gate int i; 19727c478bd9Sstevel@tonic-gate 19737c478bd9Sstevel@tonic-gate (void) printf(" interface: %.*s index %d address ", 19747c478bd9Sstevel@tonic-gate ifp->sdl_nlen, ifp->sdl_data, ifp->sdl_index); 19757c478bd9Sstevel@tonic-gate for (i = ifp->sdl_nlen; 19767c478bd9Sstevel@tonic-gate i < ifp->sdl_nlen + ifp->sdl_alen; 19777c478bd9Sstevel@tonic-gate i++) { 19787c478bd9Sstevel@tonic-gate (void) printf("%02x ", 19797c478bd9Sstevel@tonic-gate ifp->sdl_data[i] & 0xFF); 19807c478bd9Sstevel@tonic-gate } 19817c478bd9Sstevel@tonic-gate (void) printf("\n"); 19827c478bd9Sstevel@tonic-gate } else { 19837c478bd9Sstevel@tonic-gate (void) printf(" interface: %.*s\n", 19847c478bd9Sstevel@tonic-gate ifp->sdl_nlen, ifp->sdl_data); 19857c478bd9Sstevel@tonic-gate } 19867c478bd9Sstevel@tonic-gate } 19877c478bd9Sstevel@tonic-gate (void) printf(" flags: "); 19887c478bd9Sstevel@tonic-gate bprintf(stdout, rtm->rtm_flags, routeflags); 19897c478bd9Sstevel@tonic-gate 19907c478bd9Sstevel@tonic-gate #define lock(f) ((rtm->rtm_rmx.rmx_locks & RTV_ ## f) ? 'L' : ' ') 19917c478bd9Sstevel@tonic-gate #define msec(u) (((u) + 500) / 1000) /* usec to msec */ 19927c478bd9Sstevel@tonic-gate 19937c478bd9Sstevel@tonic-gate (void) printf("\n%s\n", " recvpipe sendpipe ssthresh rtt,ms " 19947c478bd9Sstevel@tonic-gate "rttvar,ms hopcount mtu expire"); 19957c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE)); 19967c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE)); 19977c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH)); 19987c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT)); 19997c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR)); 20007c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT)); 20017c478bd9Sstevel@tonic-gate (void) printf("%8d%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU)); 20027c478bd9Sstevel@tonic-gate if (rtm->rtm_rmx.rmx_expire) 20037c478bd9Sstevel@tonic-gate rtm->rtm_rmx.rmx_expire -= time(0); 20047c478bd9Sstevel@tonic-gate (void) printf("%8d%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE)); 20057c478bd9Sstevel@tonic-gate #undef lock 20067c478bd9Sstevel@tonic-gate #undef msec 20077c478bd9Sstevel@tonic-gate #define RTA_IGN \ 20087c478bd9Sstevel@tonic-gate (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD|RTA_SRC) 20097c478bd9Sstevel@tonic-gate if (verbose) { 20107c478bd9Sstevel@tonic-gate pmsg_common(rtm); 20117c478bd9Sstevel@tonic-gate } else if (rtm->rtm_addrs &~ RTA_IGN) { 20127c478bd9Sstevel@tonic-gate (void) printf("sockaddrs: "); 20137c478bd9Sstevel@tonic-gate bprintf(stdout, rtm->rtm_addrs, addrnames); 20147c478bd9Sstevel@tonic-gate (void) putchar('\n'); 20157c478bd9Sstevel@tonic-gate } 20167c478bd9Sstevel@tonic-gate #undef RTA_IGN 20177c478bd9Sstevel@tonic-gate } 20187c478bd9Sstevel@tonic-gate 20197c478bd9Sstevel@tonic-gate void 20207c478bd9Sstevel@tonic-gate pmsg_common(struct rt_msghdr *rtm) 20217c478bd9Sstevel@tonic-gate { 20227c478bd9Sstevel@tonic-gate (void) printf("\nlocks: "); 20237c478bd9Sstevel@tonic-gate bprintf(stdout, (int)rtm->rtm_rmx.rmx_locks, metricnames); 20247c478bd9Sstevel@tonic-gate (void) printf(" inits: "); 20257c478bd9Sstevel@tonic-gate bprintf(stdout, (int)rtm->rtm_inits, metricnames); 20267c478bd9Sstevel@tonic-gate pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs); 20277c478bd9Sstevel@tonic-gate } 20287c478bd9Sstevel@tonic-gate 20297c478bd9Sstevel@tonic-gate void 20307c478bd9Sstevel@tonic-gate pmsg_addrs(char *cp, int addrs) 20317c478bd9Sstevel@tonic-gate { 20327c478bd9Sstevel@tonic-gate struct sockaddr *sa; 20337c478bd9Sstevel@tonic-gate int i; 20347c478bd9Sstevel@tonic-gate 20357c478bd9Sstevel@tonic-gate if (addrs == 0) 20367c478bd9Sstevel@tonic-gate return; 20377c478bd9Sstevel@tonic-gate (void) printf("\nsockaddrs: "); 20387c478bd9Sstevel@tonic-gate bprintf(stdout, addrs, addrnames); 20397c478bd9Sstevel@tonic-gate (void) putchar('\n'); 20407c478bd9Sstevel@tonic-gate for (i = 1; i != 0; i <<= 1) { 20417c478bd9Sstevel@tonic-gate if (i & addrs) { 20427c478bd9Sstevel@tonic-gate /* LINTED */ 20437c478bd9Sstevel@tonic-gate sa = (struct sockaddr *)cp; 20447c478bd9Sstevel@tonic-gate (void) printf(" %s", routename(sa)); 20457c478bd9Sstevel@tonic-gate ADVANCE(cp, sa); 20467c478bd9Sstevel@tonic-gate } 20477c478bd9Sstevel@tonic-gate } 20487c478bd9Sstevel@tonic-gate (void) putchar('\n'); 20497c478bd9Sstevel@tonic-gate (void) fflush(stdout); 20507c478bd9Sstevel@tonic-gate } 20517c478bd9Sstevel@tonic-gate 20527c478bd9Sstevel@tonic-gate void 20537c478bd9Sstevel@tonic-gate bprintf(FILE *fp, int b, char *s) 20547c478bd9Sstevel@tonic-gate { 20557c478bd9Sstevel@tonic-gate int i; 20567c478bd9Sstevel@tonic-gate boolean_t gotsome = B_FALSE; 20577c478bd9Sstevel@tonic-gate 20587c478bd9Sstevel@tonic-gate if (b == 0) 20597c478bd9Sstevel@tonic-gate return; 20607c478bd9Sstevel@tonic-gate while ((i = *s++) != 0) { 20617c478bd9Sstevel@tonic-gate if (b & (1 << (i - 1))) { 20627c478bd9Sstevel@tonic-gate if (!gotsome) 20637c478bd9Sstevel@tonic-gate i = '<'; 20647c478bd9Sstevel@tonic-gate else 20657c478bd9Sstevel@tonic-gate i = ','; 20667c478bd9Sstevel@tonic-gate (void) putc(i, fp); 20677c478bd9Sstevel@tonic-gate gotsome = B_TRUE; 20687c478bd9Sstevel@tonic-gate for (; (i = *s) > ' '; s++) 20697c478bd9Sstevel@tonic-gate (void) putc(i, fp); 20707c478bd9Sstevel@tonic-gate } else { 20717c478bd9Sstevel@tonic-gate while (*s > ' ') 20727c478bd9Sstevel@tonic-gate s++; 20737c478bd9Sstevel@tonic-gate } 20747c478bd9Sstevel@tonic-gate } 20757c478bd9Sstevel@tonic-gate if (gotsome) 20767c478bd9Sstevel@tonic-gate (void) putc('>', fp); 20777c478bd9Sstevel@tonic-gate } 20787c478bd9Sstevel@tonic-gate 20797c478bd9Sstevel@tonic-gate int 20807c478bd9Sstevel@tonic-gate keyword(char *cp) 20817c478bd9Sstevel@tonic-gate { 20827c478bd9Sstevel@tonic-gate struct keytab *kt = keywords; 20837c478bd9Sstevel@tonic-gate 20847c478bd9Sstevel@tonic-gate while (kt->kt_cp && strcmp(kt->kt_cp, cp)) 20857c478bd9Sstevel@tonic-gate kt++; 20867c478bd9Sstevel@tonic-gate return (kt->kt_i); 20877c478bd9Sstevel@tonic-gate } 20887c478bd9Sstevel@tonic-gate 20897c478bd9Sstevel@tonic-gate void 2090*7a23074eSdduvall sodump(sup su, char *which) 20917c478bd9Sstevel@tonic-gate { 20927c478bd9Sstevel@tonic-gate static char obuf[INET6_ADDRSTRLEN]; 20937c478bd9Sstevel@tonic-gate 20947c478bd9Sstevel@tonic-gate switch (su->sa.sa_family) { 20957c478bd9Sstevel@tonic-gate case AF_LINK: 20967c478bd9Sstevel@tonic-gate (void) printf("%s: link %s; ", 20977c478bd9Sstevel@tonic-gate which, link_ntoa(&su->sdl)); 20987c478bd9Sstevel@tonic-gate break; 20997c478bd9Sstevel@tonic-gate case AF_INET: 21007c478bd9Sstevel@tonic-gate (void) printf("%s: inet %s; ", 21017c478bd9Sstevel@tonic-gate which, inet_ntoa(su->sin.sin_addr)); 21027c478bd9Sstevel@tonic-gate break; 21037c478bd9Sstevel@tonic-gate case AF_INET6: 21047c478bd9Sstevel@tonic-gate if (inet_ntop(AF_INET6, (void *)&su->sin6.sin6_addr, obuf, 21057c478bd9Sstevel@tonic-gate INET6_ADDRSTRLEN) != NULL) { 21067c478bd9Sstevel@tonic-gate (void) printf("%s: inet6 %s; ", which, obuf); 21077c478bd9Sstevel@tonic-gate break; 21087c478bd9Sstevel@tonic-gate } 21097c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 21107c478bd9Sstevel@tonic-gate default: 21117c478bd9Sstevel@tonic-gate quit(gettext("Internal Error"), EINVAL); 21127c478bd9Sstevel@tonic-gate /* NOTREACHED */ 21137c478bd9Sstevel@tonic-gate } 21147c478bd9Sstevel@tonic-gate (void) fflush(stdout); 21157c478bd9Sstevel@tonic-gate } 21167c478bd9Sstevel@tonic-gate 21177c478bd9Sstevel@tonic-gate /* States */ 21187c478bd9Sstevel@tonic-gate #define VIRGIN 0 21197c478bd9Sstevel@tonic-gate #define GOTONE 1 21207c478bd9Sstevel@tonic-gate #define GOTTWO 2 21217c478bd9Sstevel@tonic-gate #define RESET 3 21227c478bd9Sstevel@tonic-gate /* Inputs */ 21237c478bd9Sstevel@tonic-gate #define DIGIT (4*0) 21247c478bd9Sstevel@tonic-gate #define END (4*1) 21257c478bd9Sstevel@tonic-gate #define DELIM (4*2) 21267c478bd9Sstevel@tonic-gate #define LETTER (4*3) 21277c478bd9Sstevel@tonic-gate 21287c478bd9Sstevel@tonic-gate void 21297c478bd9Sstevel@tonic-gate sockaddr(char *addr, struct sockaddr *sa) 21307c478bd9Sstevel@tonic-gate { 21317c478bd9Sstevel@tonic-gate char *cp = (char *)sa; 21327c478bd9Sstevel@tonic-gate int size = salen(sa); 21337c478bd9Sstevel@tonic-gate char *cplim = cp + size; 21347c478bd9Sstevel@tonic-gate int byte = 0, state = VIRGIN, new; 21357c478bd9Sstevel@tonic-gate 21367c478bd9Sstevel@tonic-gate (void) memset(cp, 0, size); 21377c478bd9Sstevel@tonic-gate cp++; 21387c478bd9Sstevel@tonic-gate do { 21397c478bd9Sstevel@tonic-gate if ((*addr >= '0') && (*addr <= '9')) { 21407c478bd9Sstevel@tonic-gate new = *addr - '0'; 21417c478bd9Sstevel@tonic-gate } else if ((*addr >= 'a') && (*addr <= 'f')) { 21427c478bd9Sstevel@tonic-gate new = *addr - 'a' + 10; 21437c478bd9Sstevel@tonic-gate } else if ((*addr >= 'A') && (*addr <= 'F')) { 21447c478bd9Sstevel@tonic-gate new = *addr - 'A' + 10; 21457c478bd9Sstevel@tonic-gate } else if (*addr == 0) { 21467c478bd9Sstevel@tonic-gate state |= END; 21477c478bd9Sstevel@tonic-gate } else { 21487c478bd9Sstevel@tonic-gate state |= DELIM; 21497c478bd9Sstevel@tonic-gate } 21507c478bd9Sstevel@tonic-gate addr++; 21517c478bd9Sstevel@tonic-gate switch (state /* | INPUT */) { 21527c478bd9Sstevel@tonic-gate case GOTTWO | DIGIT: 21537c478bd9Sstevel@tonic-gate *cp++ = byte; 21547c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 21557c478bd9Sstevel@tonic-gate case VIRGIN | DIGIT: 21567c478bd9Sstevel@tonic-gate state = GOTONE; byte = new; continue; 21577c478bd9Sstevel@tonic-gate case GOTONE | DIGIT: 21587c478bd9Sstevel@tonic-gate state = GOTTWO; byte = new + (byte << 4); continue; 21597c478bd9Sstevel@tonic-gate default: /* | DELIM */ 21607c478bd9Sstevel@tonic-gate state = VIRGIN; *cp++ = byte; byte = 0; continue; 21617c478bd9Sstevel@tonic-gate case GOTONE | END: 21627c478bd9Sstevel@tonic-gate case GOTTWO | END: 21637c478bd9Sstevel@tonic-gate *cp++ = byte; 21647c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 21657c478bd9Sstevel@tonic-gate case VIRGIN | END: 21667c478bd9Sstevel@tonic-gate break; 21677c478bd9Sstevel@tonic-gate } 21687c478bd9Sstevel@tonic-gate break; 21697c478bd9Sstevel@tonic-gate } while (cp < cplim); 21707c478bd9Sstevel@tonic-gate } 21717c478bd9Sstevel@tonic-gate 21727c478bd9Sstevel@tonic-gate int 21737c478bd9Sstevel@tonic-gate salen(struct sockaddr *sa) 21747c478bd9Sstevel@tonic-gate { 21757c478bd9Sstevel@tonic-gate switch (sa->sa_family) { 21767c478bd9Sstevel@tonic-gate case AF_INET: 21777c478bd9Sstevel@tonic-gate return (sizeof (struct sockaddr_in)); 21787c478bd9Sstevel@tonic-gate case AF_LINK: 21797c478bd9Sstevel@tonic-gate return (sizeof (struct sockaddr_dl)); 21807c478bd9Sstevel@tonic-gate case AF_INET6: 21817c478bd9Sstevel@tonic-gate return (sizeof (struct sockaddr_in6)); 21827c478bd9Sstevel@tonic-gate default: 21837c478bd9Sstevel@tonic-gate return (sizeof (struct sockaddr)); 21847c478bd9Sstevel@tonic-gate } 21857c478bd9Sstevel@tonic-gate } 21867c478bd9Sstevel@tonic-gate 21877c478bd9Sstevel@tonic-gate void 21887c478bd9Sstevel@tonic-gate link_addr(const char *addr, struct sockaddr_dl *sdl) 21897c478bd9Sstevel@tonic-gate { 21907c478bd9Sstevel@tonic-gate char *cp = sdl->sdl_data; 21917c478bd9Sstevel@tonic-gate char *cplim = sizeof (struct sockaddr_dl) + (char *)sdl; 21927c478bd9Sstevel@tonic-gate int byte = 0, state = VIRGIN, new; 21937c478bd9Sstevel@tonic-gate 21947c478bd9Sstevel@tonic-gate (void) memset(sdl, 0, sizeof (struct sockaddr_dl)); 21957c478bd9Sstevel@tonic-gate sdl->sdl_family = AF_LINK; 21967c478bd9Sstevel@tonic-gate do { 21977c478bd9Sstevel@tonic-gate state &= ~LETTER; 21987c478bd9Sstevel@tonic-gate if ((*addr >= '0') && (*addr <= '9')) { 21997c478bd9Sstevel@tonic-gate new = *addr - '0'; 22007c478bd9Sstevel@tonic-gate } else if ((*addr >= 'a') && (*addr <= 'f')) { 22017c478bd9Sstevel@tonic-gate new = *addr - 'a' + 10; 22027c478bd9Sstevel@tonic-gate } else if ((*addr >= 'A') && (*addr <= 'F')) { 22037c478bd9Sstevel@tonic-gate new = *addr - 'A' + 10; 22047c478bd9Sstevel@tonic-gate } else if (*addr == 0) { 22057c478bd9Sstevel@tonic-gate state |= END; 22067c478bd9Sstevel@tonic-gate } else if (state == VIRGIN && 22077c478bd9Sstevel@tonic-gate (((*addr >= 'A') && (*addr <= 'Z')) || 22087c478bd9Sstevel@tonic-gate ((*addr >= 'a') && (*addr <= 'z')))) { 22097c478bd9Sstevel@tonic-gate state |= LETTER; 22107c478bd9Sstevel@tonic-gate } else { 22117c478bd9Sstevel@tonic-gate state |= DELIM; 22127c478bd9Sstevel@tonic-gate } 22137c478bd9Sstevel@tonic-gate addr++; 22147c478bd9Sstevel@tonic-gate switch (state /* | INPUT */) { 22157c478bd9Sstevel@tonic-gate case VIRGIN | DIGIT: 22167c478bd9Sstevel@tonic-gate case VIRGIN | LETTER: 22177c478bd9Sstevel@tonic-gate *cp++ = addr[-1]; 22187c478bd9Sstevel@tonic-gate continue; 22197c478bd9Sstevel@tonic-gate case VIRGIN | DELIM: 22207c478bd9Sstevel@tonic-gate state = RESET; 22217c478bd9Sstevel@tonic-gate sdl->sdl_nlen = cp - sdl->sdl_data; 22227c478bd9Sstevel@tonic-gate continue; 22237c478bd9Sstevel@tonic-gate case GOTTWO | DIGIT: 22247c478bd9Sstevel@tonic-gate *cp++ = byte; 22257c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 22267c478bd9Sstevel@tonic-gate case RESET | DIGIT: 22277c478bd9Sstevel@tonic-gate state = GOTONE; 22287c478bd9Sstevel@tonic-gate byte = new; 22297c478bd9Sstevel@tonic-gate continue; 22307c478bd9Sstevel@tonic-gate case GOTONE | DIGIT: 22317c478bd9Sstevel@tonic-gate state = GOTTWO; 22327c478bd9Sstevel@tonic-gate byte = new + (byte << 4); 22337c478bd9Sstevel@tonic-gate continue; 22347c478bd9Sstevel@tonic-gate default: /* | DELIM */ 22357c478bd9Sstevel@tonic-gate state = RESET; 22367c478bd9Sstevel@tonic-gate *cp++ = byte; 22377c478bd9Sstevel@tonic-gate byte = 0; 22387c478bd9Sstevel@tonic-gate continue; 22397c478bd9Sstevel@tonic-gate case GOTONE | END: 22407c478bd9Sstevel@tonic-gate case GOTTWO | END: 22417c478bd9Sstevel@tonic-gate *cp++ = byte; 22427c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 22437c478bd9Sstevel@tonic-gate case RESET | END: 22447c478bd9Sstevel@tonic-gate break; 22457c478bd9Sstevel@tonic-gate } 22467c478bd9Sstevel@tonic-gate break; 22477c478bd9Sstevel@tonic-gate } while (cp < cplim); 22487c478bd9Sstevel@tonic-gate sdl->sdl_alen = cp - LLADDR(sdl); 22497c478bd9Sstevel@tonic-gate } 22507c478bd9Sstevel@tonic-gate 22517c478bd9Sstevel@tonic-gate static char hexlist[] = "0123456789abcdef"; 22527c478bd9Sstevel@tonic-gate 22537c478bd9Sstevel@tonic-gate char * 22547c478bd9Sstevel@tonic-gate link_ntoa(const struct sockaddr_dl *sdl) 22557c478bd9Sstevel@tonic-gate { 22567c478bd9Sstevel@tonic-gate static char obuf[64]; 22577c478bd9Sstevel@tonic-gate char *out = obuf; 22587c478bd9Sstevel@tonic-gate int i; 22597c478bd9Sstevel@tonic-gate uchar_t *in = (uchar_t *)LLADDR(sdl); 22607c478bd9Sstevel@tonic-gate uchar_t *inlim = in + sdl->sdl_alen; 22617c478bd9Sstevel@tonic-gate boolean_t firsttime = B_TRUE; 22627c478bd9Sstevel@tonic-gate 22637c478bd9Sstevel@tonic-gate if (sdl->sdl_nlen) { 22647c478bd9Sstevel@tonic-gate (void) memcpy(obuf, sdl->sdl_data, sdl->sdl_nlen); 22657c478bd9Sstevel@tonic-gate out += sdl->sdl_nlen; 22667c478bd9Sstevel@tonic-gate if (sdl->sdl_alen) 22677c478bd9Sstevel@tonic-gate *out++ = ':'; 22687c478bd9Sstevel@tonic-gate } 22697c478bd9Sstevel@tonic-gate while (in < inlim) { 22707c478bd9Sstevel@tonic-gate if (firsttime) 22717c478bd9Sstevel@tonic-gate firsttime = B_FALSE; 22727c478bd9Sstevel@tonic-gate else 22737c478bd9Sstevel@tonic-gate *out++ = '.'; 22747c478bd9Sstevel@tonic-gate i = *in++; 22757c478bd9Sstevel@tonic-gate if (i > 0xf) { 22767c478bd9Sstevel@tonic-gate out[1] = hexlist[i & 0xf]; 22777c478bd9Sstevel@tonic-gate i >>= 4; 22787c478bd9Sstevel@tonic-gate out[0] = hexlist[i]; 22797c478bd9Sstevel@tonic-gate out += 2; 22807c478bd9Sstevel@tonic-gate } else { 22817c478bd9Sstevel@tonic-gate *out++ = hexlist[i]; 22827c478bd9Sstevel@tonic-gate } 22837c478bd9Sstevel@tonic-gate } 22847c478bd9Sstevel@tonic-gate *out = 0; 22857c478bd9Sstevel@tonic-gate return (obuf); 22867c478bd9Sstevel@tonic-gate } 22877c478bd9Sstevel@tonic-gate 22887c478bd9Sstevel@tonic-gate static mib_item_t * 22897c478bd9Sstevel@tonic-gate mibget(int sd) 22907c478bd9Sstevel@tonic-gate { 22917c478bd9Sstevel@tonic-gate intmax_t buf[512 / sizeof (intmax_t)]; 22927c478bd9Sstevel@tonic-gate int flags; 22937c478bd9Sstevel@tonic-gate int i, j, getcode; 22947c478bd9Sstevel@tonic-gate struct strbuf ctlbuf, databuf; 22957c478bd9Sstevel@tonic-gate struct T_optmgmt_req *tor = (struct T_optmgmt_req *)buf; 22967c478bd9Sstevel@tonic-gate struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *)buf; 22977c478bd9Sstevel@tonic-gate struct T_error_ack *tea = (struct T_error_ack *)buf; 22987c478bd9Sstevel@tonic-gate struct opthdr *req; 22997c478bd9Sstevel@tonic-gate mib_item_t *first_item = NULL; 23007c478bd9Sstevel@tonic-gate mib_item_t *last_item = NULL; 23017c478bd9Sstevel@tonic-gate mib_item_t *temp; 23027c478bd9Sstevel@tonic-gate 23037c478bd9Sstevel@tonic-gate tor->PRIM_type = T_SVR4_OPTMGMT_REQ; 23047c478bd9Sstevel@tonic-gate tor->OPT_offset = sizeof (struct T_optmgmt_req); 23057c478bd9Sstevel@tonic-gate tor->OPT_length = sizeof (struct opthdr); 23067c478bd9Sstevel@tonic-gate tor->MGMT_flags = T_CURRENT; 23077c478bd9Sstevel@tonic-gate req = (struct opthdr *)&tor[1]; 23087c478bd9Sstevel@tonic-gate req->level = MIB2_IP; /* any MIB2_xxx value ok here */ 23097c478bd9Sstevel@tonic-gate req->name = 0; 23107c478bd9Sstevel@tonic-gate req->len = 0; 23117c478bd9Sstevel@tonic-gate 23127c478bd9Sstevel@tonic-gate ctlbuf.buf = (char *)buf; 23137c478bd9Sstevel@tonic-gate ctlbuf.len = tor->OPT_length + tor->OPT_offset; 23147c478bd9Sstevel@tonic-gate flags = 0; 23157c478bd9Sstevel@tonic-gate if (putmsg(sd, &ctlbuf, NULL, flags) < 0) { 23167c478bd9Sstevel@tonic-gate perror("mibget: putmsg (ctl)"); 23177c478bd9Sstevel@tonic-gate return (NULL); 23187c478bd9Sstevel@tonic-gate } 23197c478bd9Sstevel@tonic-gate /* 23207c478bd9Sstevel@tonic-gate * each reply consists of a ctl part for one fixed structure 23217c478bd9Sstevel@tonic-gate * or table, as defined in mib2.h. The format is a T_OPTMGMT_ACK, 23227c478bd9Sstevel@tonic-gate * containing an opthdr structure. level/name identify the entry, 23237c478bd9Sstevel@tonic-gate * len is the size of the data part of the message. 23247c478bd9Sstevel@tonic-gate */ 23257c478bd9Sstevel@tonic-gate req = (struct opthdr *)&toa[1]; 23267c478bd9Sstevel@tonic-gate ctlbuf.maxlen = sizeof (buf); 23277c478bd9Sstevel@tonic-gate for (j = 1; ; j++) { 23287c478bd9Sstevel@tonic-gate flags = 0; 23297c478bd9Sstevel@tonic-gate getcode = getmsg(sd, &ctlbuf, NULL, &flags); 23307c478bd9Sstevel@tonic-gate if (getcode < 0) { 23317c478bd9Sstevel@tonic-gate perror("mibget: getmsg (ctl)"); 23327c478bd9Sstevel@tonic-gate if (verbose) { 23337c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 23347c478bd9Sstevel@tonic-gate "# level name len\n"); 23357c478bd9Sstevel@tonic-gate i = 0; 23367c478bd9Sstevel@tonic-gate for (last_item = first_item; last_item != NULL; 23377c478bd9Sstevel@tonic-gate last_item = last_item->next_item) { 23387c478bd9Sstevel@tonic-gate (void) printf("%d %4ld %5ld %ld\n", 23397c478bd9Sstevel@tonic-gate ++i, last_item->group, 23407c478bd9Sstevel@tonic-gate last_item->mib_id, 23417c478bd9Sstevel@tonic-gate last_item->length); 23427c478bd9Sstevel@tonic-gate } 23437c478bd9Sstevel@tonic-gate } 23447c478bd9Sstevel@tonic-gate break; 23457c478bd9Sstevel@tonic-gate } 23467c478bd9Sstevel@tonic-gate if (getcode == 0 && 23477c478bd9Sstevel@tonic-gate ctlbuf.len >= sizeof (struct T_optmgmt_ack) && 23487c478bd9Sstevel@tonic-gate toa->PRIM_type == T_OPTMGMT_ACK && 23497c478bd9Sstevel@tonic-gate toa->MGMT_flags == T_SUCCESS && 23507c478bd9Sstevel@tonic-gate req->len == 0) { 23517c478bd9Sstevel@tonic-gate if (verbose) { 23527c478bd9Sstevel@tonic-gate (void) printf("mibget getmsg() %d returned EOD " 23537c478bd9Sstevel@tonic-gate "(level %lu, name %lu)\n", j, req->level, 23547c478bd9Sstevel@tonic-gate req->name); 23557c478bd9Sstevel@tonic-gate } 23567c478bd9Sstevel@tonic-gate return (first_item); /* this is EOD msg */ 23577c478bd9Sstevel@tonic-gate } 23587c478bd9Sstevel@tonic-gate 23597c478bd9Sstevel@tonic-gate if (ctlbuf.len >= sizeof (struct T_error_ack) && 23607c478bd9Sstevel@tonic-gate tea->PRIM_type == T_ERROR_ACK) { 23617c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("mibget %d gives " 23627c478bd9Sstevel@tonic-gate "T_ERROR_ACK: TLI_error = 0x%lx, UNIX_error = " 23637c478bd9Sstevel@tonic-gate "0x%lx\n"), j, tea->TLI_error, tea->UNIX_error); 23647c478bd9Sstevel@tonic-gate errno = (tea->TLI_error == TSYSERR) 23657c478bd9Sstevel@tonic-gate ? tea->UNIX_error : EPROTO; 23667c478bd9Sstevel@tonic-gate break; 23677c478bd9Sstevel@tonic-gate } 23687c478bd9Sstevel@tonic-gate 23697c478bd9Sstevel@tonic-gate if (getcode != MOREDATA || 23707c478bd9Sstevel@tonic-gate ctlbuf.len < sizeof (struct T_optmgmt_ack) || 23717c478bd9Sstevel@tonic-gate toa->PRIM_type != T_OPTMGMT_ACK || 23727c478bd9Sstevel@tonic-gate toa->MGMT_flags != T_SUCCESS) { 23737c478bd9Sstevel@tonic-gate (void) printf("mibget getmsg(ctl) %d returned %d, " 23747c478bd9Sstevel@tonic-gate "ctlbuf.len = %d, PRIM_type = %ld\n", 23757c478bd9Sstevel@tonic-gate j, getcode, ctlbuf.len, toa->PRIM_type); 23767c478bd9Sstevel@tonic-gate if (toa->PRIM_type == T_OPTMGMT_ACK) { 23777c478bd9Sstevel@tonic-gate (void) printf("T_OPTMGMT_ACK: " 23787c478bd9Sstevel@tonic-gate "MGMT_flags = 0x%lx, req->len = %ld\n", 23797c478bd9Sstevel@tonic-gate toa->MGMT_flags, req->len); 23807c478bd9Sstevel@tonic-gate } 23817c478bd9Sstevel@tonic-gate errno = ENOMSG; 23827c478bd9Sstevel@tonic-gate break; 23837c478bd9Sstevel@tonic-gate } 23847c478bd9Sstevel@tonic-gate 23857c478bd9Sstevel@tonic-gate temp = malloc(sizeof (mib_item_t)); 23867c478bd9Sstevel@tonic-gate if (temp == NULL) { 23877c478bd9Sstevel@tonic-gate perror("mibget: malloc"); 23887c478bd9Sstevel@tonic-gate break; 23897c478bd9Sstevel@tonic-gate } 23907c478bd9Sstevel@tonic-gate if (last_item != NULL) 23917c478bd9Sstevel@tonic-gate last_item->next_item = temp; 23927c478bd9Sstevel@tonic-gate else 23937c478bd9Sstevel@tonic-gate first_item = temp; 23947c478bd9Sstevel@tonic-gate last_item = temp; 23957c478bd9Sstevel@tonic-gate last_item->next_item = NULL; 23967c478bd9Sstevel@tonic-gate last_item->group = req->level; 23977c478bd9Sstevel@tonic-gate last_item->mib_id = req->name; 23987c478bd9Sstevel@tonic-gate last_item->length = req->len; 23997c478bd9Sstevel@tonic-gate last_item->valp = malloc(req->len); 24007c478bd9Sstevel@tonic-gate if (verbose) { 24017c478bd9Sstevel@tonic-gate (void) printf("msg %d: group = %4ld mib_id = %5ld " 24027c478bd9Sstevel@tonic-gate "length = %ld\n", 24037c478bd9Sstevel@tonic-gate j, last_item->group, last_item->mib_id, 24047c478bd9Sstevel@tonic-gate last_item->length); 24057c478bd9Sstevel@tonic-gate } 24067c478bd9Sstevel@tonic-gate 24077c478bd9Sstevel@tonic-gate databuf.maxlen = last_item->length; 24087c478bd9Sstevel@tonic-gate databuf.buf = (char *)last_item->valp; 24097c478bd9Sstevel@tonic-gate databuf.len = 0; 24107c478bd9Sstevel@tonic-gate flags = 0; 24117c478bd9Sstevel@tonic-gate getcode = getmsg(sd, NULL, &databuf, &flags); 24127c478bd9Sstevel@tonic-gate if (getcode < 0) { 24137c478bd9Sstevel@tonic-gate perror("mibget: getmsg (data)"); 24147c478bd9Sstevel@tonic-gate break; 24157c478bd9Sstevel@tonic-gate } else if (getcode != 0) { 24167c478bd9Sstevel@tonic-gate (void) printf("mibget getmsg(data) returned %d, " 24177c478bd9Sstevel@tonic-gate "databuf.maxlen = %d, databuf.len = %d\n", 24187c478bd9Sstevel@tonic-gate getcode, databuf.maxlen, databuf.len); 24197c478bd9Sstevel@tonic-gate break; 24207c478bd9Sstevel@tonic-gate } 24217c478bd9Sstevel@tonic-gate } 24227c478bd9Sstevel@tonic-gate 24237c478bd9Sstevel@tonic-gate /* 24247c478bd9Sstevel@tonic-gate * On error, free all the allocated mib_item_t objects. 24257c478bd9Sstevel@tonic-gate */ 24267c478bd9Sstevel@tonic-gate while (first_item != NULL) { 24277c478bd9Sstevel@tonic-gate last_item = first_item; 24287c478bd9Sstevel@tonic-gate first_item = first_item->next_item; 24297c478bd9Sstevel@tonic-gate free(last_item); 24307c478bd9Sstevel@tonic-gate } 24317c478bd9Sstevel@tonic-gate return (NULL); 24327c478bd9Sstevel@tonic-gate } 2433