home *** CD-ROM | disk | FTP | other *** search
/ Network PC / Network PC.iso / amiga utilities / communication / internet / amitcp3.0b / src.lha / src / util / route / route.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-08  |  31.5 KB  |  1,352 lines

  1. RCS_ID_C = "$Id: route.c,v 3.1 1994/02/22 03:31:21 ppessi Exp $";
  2. /* 
  3.  * route.c - route command for AmiTCP/IP
  4.  *
  5.  * Author: jraja <Jarno.Rajahalme@hut.fi>
  6.  *
  7.  * Last modified: Tue Feb 22 02:12:47 1994 ppessi
  8.  */
  9.  
  10. #include "route_rev.h"
  11. static const char version[] = VERSTAG " "
  12.   "Copyright © 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>\n"
  13.   "Helsinki University of Technology, Finland.\n"
  14. "@(#) Copyright © 1983, 1989 The Regents of the University of California.\n"
  15.                       "All rights reserved.\n";
  16.  
  17. /*
  18.  * Copyright © 1983, 1989 The Regents of the University of California.
  19.  * All rights reserved.
  20.  *
  21.  * Redistribution and use in source and binary forms, with or without
  22.  * modification, are permitted provided that the following conditions
  23.  * are met:
  24.  * 1. Redistributions of source code must retain the above copyright
  25.  *    notice, this list of conditions and the following disclaimer.
  26.  * 2. Redistributions in binary form must reproduce the above copyright
  27.  *    notice, this list of conditions and the following disclaimer in the
  28.  *    documentation and/or other materials provided with the distribution.
  29.  * 3. All advertising materials mentioning features or use of this software
  30.  *    must display the following acknowledgement:
  31.  *    This product includes software developed by the University of
  32.  *    California, Berkeley and its contributors.
  33.  * 4. Neither the name of the University nor the names of its contributors
  34.  *    may be used to endorse or promote products derived from this software
  35.  *    without specific prior written permission.
  36.  *
  37.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  38.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  39.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  40.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  41.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  42.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  43.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  44.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  45.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  46.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47.  * SUCH DAMAGE.
  48.  */
  49.  
  50. static char sccsid[] = "@(#)route.c    5.35 (Berkeley) 6/27/91";
  51.  
  52. /****** netutil.doc/route ***************************************************
  53. *
  54. *   NAME
  55. *        route - manually manipulate the routing tables
  56. *   
  57. *   SYNOPSIS
  58. *        route [-n] [-q] [-v] command [modifiers] destination gateway
  59. *   
  60. *   DESCRIPTION
  61. *        Route is a program used to manually manipulate the network routing
  62. *        tables. 
  63. *   
  64. *        Options supported by route:
  65. *   
  66. *        -n      Prevent attempts to print host and network names
  67. *                symbolically when reporting actions.
  68. *   
  69. *        -v      (verbose) Print additional details.
  70. *   
  71. *        -q      Suppress all output.
  72. *   
  73. *        Commands accepted by route:
  74. *   
  75. *        add         Add a route.
  76. *        delete      Delete a specific route.
  77. *   
  78. *        The destination is the destination host or network, gateway is the
  79. *        next-hop gateway to which packets should be addressed. Routes to a
  80. *        particular host are distinguished from those to a network by
  81. *        interpreting the Internet address associated with destination. The
  82. *        optional modifiers -net and -host force the destination to be
  83. *        interpreted as a network or a host, respectively.  Otherwise, if the
  84. *        destination has a ``local address part'' of INADDR_ANY, or if the
  85. *        destination is the symbolic name of a network, then the route is
  86. *        assumed to be to a network; otherwise, it is presumed to be a route
  87. *        to a host.
  88. *   
  89. *        For example, 128.32 is interpreted as -host 128.0.0.32; 128.32.130
  90. *        is interpreted as -host 128.32.0.130; -net 128.32 is interpreted as
  91. *        128.32.0.0; and -net 128.32.130 is interpreted as 128.32.130.0.
  92. *   
  93. *        To add a default route, give the destination as 'default'.
  94. *    
  95. *        If the route is via an interface rather than via a gateway, the
  96. *        -interface modifier should be specified; the gateway given is the
  97. *        address of this host on the common network, indicating the interface
  98. *        to be used for transmission.
  99. *   
  100. *        The optional -netmask qualifier is used to specify the netmask of
  101. *        the interface. One specifies an additional ensuing address parameter
  102. *        (to be interpreted as a network mask).  The implicit network mask
  103. *        generated can be overridden by making sure this option follows the
  104. *        destination parameter.
  105. *   
  106. *        All symbolic names specified for a destination or gateway are looked
  107. *        up first as a host name using gethostbyname(). If this lookup fails,
  108. *        getnetbyname() is then used to interpret the name as that of a
  109. *        network.
  110. *   
  111. *   DIAGNOSTICS
  112. *        add [host | network ] %s: gateway %s flags %x
  113. *                The specified route is being added to the tables. The values
  114. *                printed are from the routing table entry supplied in the
  115. *                IoctlSocket() call. If the gateway address used was not the
  116. *                primary address of the gateway (the first one returned by
  117. *                gethostbyname()), the gateway address is printed numerically
  118. *                as well as symbolically.
  119. *   
  120. *        delete [ host | network ] %s: gateway %s flags %x
  121. *                As above, but when deleting an entry.
  122. *   
  123. *        Network is unreachable
  124. *                An attempt to add a route failed because the gateway listed
  125. *                was not on a directly-connected network.  The next-hop
  126. *                gateway must be given.
  127. *   
  128. *        not in table
  129. *                A delete operation was attempted for an entry which wasn't
  130. *                present in the tables.
  131. *   
  132. *        routing table overflow
  133. *                An add operation was attempted, but the system was low on
  134. *                resources and was unable to allocate memory to create the
  135. *                new entry.
  136. *   
  137. *   SEE ALSO
  138. *        ifconfig, protocols/routing
  139. *   
  140. *   HISTORY
  141. *        The route command appeared in 4.2BSD.
  142. *   
  143. *****************************************************************************
  144. *
  145. */
  146.  
  147. #include <sys/param.h>
  148. #include <sys/socket.h>
  149. #include <sys/ioctl.h>
  150.  
  151. #include <net/route.h>
  152. #include <netinet/in.h>
  153. #include <arpa/inet.h>
  154. #include <netdb.h>
  155.  
  156. #include <errno.h>
  157. #include <stdio.h>
  158. #include <ctype.h>
  159. #include <stdlib.h>
  160. #include <string.h>
  161.  
  162. #ifdef AMIGA
  163. #if __SASC
  164. #include <proto/socket.h>
  165. #elif __GNUC__
  166. #include <inline/socket.h>
  167. #else
  168. #include <clib/socket_protos.h>
  169. #endif
  170. #define herror(x) perror(x)
  171. #define ioctl IoctlSocket
  172. #include <clib/netlib_protos.h>
  173. #endif /* AMIGA */
  174.  
  175. struct keytab {
  176.     char    *kt_cp;
  177.     int    kt_i;
  178. } keywords[] = {
  179. #include "keywords.h"
  180. {0, 0}
  181. };
  182.  
  183. struct    ortentry route;
  184. union    sockunion {
  185.     struct    sockaddr sa;
  186.     struct    sockaddr_in sin;
  187. #if 0
  188.     struct    sockaddr_ns sns;
  189.     struct    sockaddr_iso siso;
  190.     struct    sockaddr_dl sdl;
  191.     struct    sockaddr_x25 sx25;
  192. #endif
  193. } so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp;
  194.  
  195. union sockunion *so_addrs[] =
  196.     { &so_dst, &so_gate, &so_mask, &so_genmask, &so_ifp, &so_ifa, 0}; 
  197.  
  198. typedef union sockunion *sup;
  199. int    rtm_addrs;
  200. int    s;
  201. int    forcehost, forcenet, doflush, nflag, af, qflag, tflag, Cflag, 
  202.   keyword(char *cp);
  203. int    iflag, verbose, aflen = sizeof (struct sockaddr_in);
  204. int    locking, lockrest, debugonly;
  205. struct    sockaddr_in sin = { sizeof(sin), AF_INET };
  206. struct    rt_metrics rt_metrics;
  207. u_long  rtm_inits;
  208. #if 0
  209. struct    in_addr inet_makeaddr();
  210. #endif
  211. char    *routename(struct sockaddr *sa), *netname(struct sockaddr *sa);
  212. void    flushroutes(int argc, char *argv[]), 
  213.   newroute(int argc, char **argv), monitor(void), sockaddr();
  214. void    print_getmsg(), print_rtmsg(), pmsg_common(), sodump(), bprintf();
  215. int    getaddr(int which, char *s, struct hostent **hpp), rtmsg();
  216. #if 0
  217. extern    char *inet_ntoa(), *iso_ntoa(), *link_ntoa();
  218. #endif
  219.  
  220. void
  221. usage(char *cp)
  222. {
  223.     if (cp)
  224.         (void) fprintf(stderr, "route: botched keyword: %s\n", cp);
  225.     (void) fprintf(stderr,
  226.         "usage: route [ -Cnqv ] cmd [[ -<qualifers> ] args ]\n");
  227.     exit(1);
  228.     /* NOTREACHED */
  229. }
  230.  
  231. void
  232. quit(char *s)
  233. {
  234.     int sverrno = errno;
  235.  
  236.     (void) fprintf(stderr, "route: ");
  237.     if (s)
  238.         (void) fprintf(stderr, "%s: ", s);
  239.     (void) fprintf(stderr, "%s\n", strerror(sverrno));
  240.     exit(1);
  241.     /* NOTREACHED */
  242. }
  243.  
  244. #define ROUNDUP(a) \
  245.     ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
  246. #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
  247.  
  248. main(argc, argv)
  249.     int argc;
  250.     char **argv;
  251. {
  252.     extern int optind;
  253.     int ch;
  254.     char *argvp;
  255.  
  256.     if (argc < 2)
  257.         usage(NULL);
  258.  
  259.     while ((ch = getopt(argc, argv, "Cnqtv")) != EOF)
  260.         switch(ch) {
  261.         case 'C':
  262.             Cflag = 1;    /* Use old ioctls. */
  263.             break;
  264.         case 'n':
  265.             nflag = 1;
  266.             break;
  267.         case 'q':
  268.             qflag = 1;
  269.             break;
  270.         case 'v':
  271.             verbose = 1;
  272.             break;
  273.         case 't':
  274.             tflag = 1;
  275.             break;
  276.         case '?':
  277.         default:
  278.             usage(NULL);
  279.         }
  280.     argc -= optind;
  281.     argv += optind;
  282.  
  283.     Cflag = 1;    /* Force old ioctls. */
  284.  
  285.     if (Cflag)
  286.         s = socket(AF_INET, SOCK_RAW, 0);
  287.     if (s < 0)
  288.         quit("socket");
  289.     if (*argv)
  290.         switch (keyword(*argv)) {
  291.         case K_GET:
  292. #if 0
  293.             uid = 0;
  294. #endif
  295.             /* FALLTHROUGH */
  296.  
  297.         case K_CHANGE:
  298.             if (Cflag)
  299.                 usage("change or get with -C");
  300.             /* FALLTHROUGH */
  301.  
  302.         case K_ADD:
  303.         case K_DELETE:
  304.             newroute(argc, argv);
  305.             exit(0);
  306.             /* NOTREACHED */
  307.  
  308.         case K_MONITOR:
  309.             monitor();
  310.             /* NOTREACHED */
  311.  
  312.         case K_FLUSH:
  313.             flushroutes(argc, argv);
  314.             exit(0);
  315.             /* NOTREACHED */
  316.         }
  317.     usage(*argv);
  318.     /* NOTREACHED */
  319. }
  320.  
  321. /*
  322.  * Purge all entries in the routing tables not
  323.  * associated with network interfaces.
  324.  */
  325. void
  326. flushroutes(argc, argv)
  327.     int argc;
  328.     char *argv[];
  329. {
  330. #if 0
  331.     int needed, seqno, rlen;
  332.     char *buf, *next, *lim;
  333.     register struct rt_msghdr *rtm;
  334.  
  335.     if (uid)
  336.         quit("must be root to alter routing table");
  337.     shutdown(s, 0); /* Don't want to read back our messages */
  338.     if (argc > 1) {
  339.         argv++;
  340.         if (argc == 2 && **argv == '-')
  341.             switch (keyword(*argv + 1)) {
  342.             case K_INET:
  343.                 af = AF_INET;
  344.                 break;
  345.             case K_XNS:
  346.                 af = AF_NS;
  347.                 break;
  348.             case K_LINK:
  349.                 af = AF_LINK;
  350.                 break;
  351.             case K_ISO:
  352.             case K_OSI:
  353.                 af = AF_ISO;
  354.                 break;
  355.             case K_X25:
  356.                 af = AF_CCITT;
  357.             default:
  358.                 goto bad;
  359.         } else
  360. bad:            usage(*argv);
  361.     }
  362.     if ((needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0)) < 0)
  363.         quit("route-getkerninfo-estimate");
  364.     if ((buf = malloc(needed)) == NULL)
  365.         quit("malloc");
  366.     if ((rlen = getkerninfo(KINFO_RT_DUMP, buf, &needed, 0)) < 0)
  367.         quit("actual retrieval of routing table");
  368.     lim = buf + rlen;
  369.     seqno = 0;        /* ??? */
  370.     for (next = buf; next < lim; next += rtm->rtm_msglen) {
  371.         rtm = (struct rt_msghdr *)next;
  372.         if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
  373.             continue;
  374.         if (af) {
  375.             struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
  376.  
  377.             if (sa->sa_family != af)
  378.                 continue;
  379.         }
  380.         rtm->rtm_type = RTM_DELETE;
  381.         rtm->rtm_seq = seqno;
  382.         rlen = write(s, next, rtm->rtm_msglen);
  383.         if (rlen < (int)rtm->rtm_msglen) {
  384.             (void) fprintf(stderr,
  385.                 "route: write to routing socket: %s\n",
  386.                 strerror(errno));
  387.             (void) printf("got only %d for rlen\n", rlen);
  388.             break;
  389.         }
  390.         seqno++;
  391.         if (qflag)
  392.             continue;
  393.         if (verbose)
  394.             print_rtmsg(rtm, rlen);
  395.         else {
  396.             struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
  397.             (void) printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ?
  398.                 routename(sa) : netname(sa));
  399.             sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
  400.             (void) printf("%-20.20s ", routename(sa));
  401.             (void) printf("done\n");
  402.         }
  403.     }
  404. #endif /* 0 */
  405. }
  406.     
  407. char *
  408. routename(sa)
  409.     struct sockaddr *sa;
  410. {
  411.     register char *cp;
  412.     static char line[50];
  413.     struct hostent *hp;
  414.     static char domain[MAXHOSTNAMELEN + 1];
  415.     static int first = 1;
  416.     char *ns_print();
  417.  
  418.     if (first) {
  419.         first = 0;
  420.         if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
  421.             (cp = index(domain, '.')))
  422.             (void) strcpy(domain, cp + 1);
  423.         else
  424.             domain[0] = 0;
  425.     }
  426.     switch (sa->sa_family) {
  427.  
  428.     case AF_INET:
  429.         {    struct in_addr in;
  430.         in = ((struct sockaddr_in *)sa)->sin_addr;
  431.  
  432.         cp = 0;
  433.         if (in.s_addr == INADDR_ANY)
  434.             cp = "default";
  435.         if (cp == 0 && !nflag) {
  436.             hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
  437.                 AF_INET);
  438.             if (hp) {
  439.                 if ((cp = index(hp->h_name, '.')) &&
  440.                     !strcmp(cp + 1, domain))
  441.                     *cp = 0;
  442.                 cp = hp->h_name;
  443.             }
  444.         }
  445.         if (cp)
  446.             strcpy(line, cp);
  447.         else {
  448. #define C(x)    ((x) & 0xff)
  449.             in.s_addr = ntohl(in.s_addr);
  450.             (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
  451.                C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
  452.         }
  453.         break;
  454.         }
  455. #if 0
  456.     case AF_NS:
  457.         return (ns_print((struct sockaddr_ns *)sa));
  458.  
  459.     case AF_LINK:
  460.         return (link_ntoa((struct sockaddr_dl *)sa));
  461.  
  462.     case AF_ISO:
  463.         (void) sprintf(line, "iso %s",
  464.             iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr));
  465.         break;
  466. #endif
  467.     default:
  468.         {    u_short *s = (u_short *)sa->sa_data;
  469.         u_short *slim = s + ((sa->sa_len + 1) >> 1);
  470.         char *cp = line + sprintf(line, "(%d)", sa->sa_family);
  471.  
  472.         while (s < slim)
  473.             cp += sprintf(cp, " %x", *s++);
  474.         break;
  475.         }
  476.     }
  477.     return (line);
  478. }
  479.  
  480. /*
  481.  * Return the name of the network whose address is given.
  482.  * The address is assumed to be that of a net or subnet, not a host.
  483.  */
  484. char *
  485. netname(sa)
  486.     struct sockaddr *sa;
  487. {
  488.     char *cp = 0;
  489.     static char line[50];
  490.     struct netent *np = 0;
  491.     u_long net, mask;
  492.     register u_long i;
  493.     int subnetshift;
  494.     char *ns_print();
  495.  
  496.     switch (sa->sa_family) {
  497.  
  498.     case AF_INET:
  499.         {    struct in_addr in;
  500.         in = ((struct sockaddr_in *)sa)->sin_addr;
  501.  
  502.         i = in.s_addr = ntohl(in.s_addr);
  503.         if (in.s_addr == 0)
  504.             cp = "default";
  505.         else if (!nflag) {
  506.             if (IN_CLASSA(i)) {
  507.                 mask = IN_CLASSA_NET;
  508.                 subnetshift = 8;
  509.             } else if (IN_CLASSB(i)) {
  510.                 mask = IN_CLASSB_NET;
  511.                 subnetshift = 8;
  512.             } else {
  513.                 mask = IN_CLASSC_NET;
  514.                 subnetshift = 4;
  515.             }
  516.             /*
  517.              * If there are more bits than the standard mask
  518.              * would suggest, subnets must be in use.
  519.              * Guess at the subnet mask, assuming reasonable
  520.              * width subnet fields.
  521.              */
  522.             while (in.s_addr &~ mask)
  523.                 mask = (long)mask >> subnetshift;
  524.             net = in.s_addr & mask;
  525.             while ((mask & 1) == 0)
  526.                 mask >>= 1, net >>= 1;
  527.             np = getnetbyaddr(net, AF_INET);
  528.             if (np)
  529.                 cp = np->n_name;
  530.         }
  531.         if (cp)
  532.             strcpy(line, cp);
  533.         else if ((in.s_addr & 0xffffff) == 0)
  534.             (void) sprintf(line, "%u", C(in.s_addr >> 24));
  535.         else if ((in.s_addr & 0xffff) == 0)
  536.             (void) sprintf(line, "%u.%u", C(in.s_addr >> 24),
  537.                 C(in.s_addr >> 16));
  538.         else if ((in.s_addr & 0xff) == 0)
  539.             (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
  540.                 C(in.s_addr >> 16), C(in.s_addr >> 8));
  541.         else
  542.             (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
  543.                 C(in.s_addr >> 16), C(in.s_addr >> 8),
  544.                 C(in.s_addr));
  545.         break;
  546.         }
  547. #if 0
  548.     case AF_NS:
  549.         return (ns_print((struct sockaddr_ns *)sa));
  550.         break;
  551.  
  552.     case AF_LINK:
  553.         return (link_ntoa((struct sockaddr_dl *)sa));
  554.  
  555.     case AF_ISO:
  556.         (void) sprintf(line, "iso %s",
  557.             iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr));
  558.         break;
  559. #endif
  560.     default:
  561.         {    u_short *s = (u_short *)sa->sa_data;
  562.         u_short *slim = s + ((sa->sa_len + 1)>>1);
  563.         char *cp = line + sprintf(line, "af %d:", sa->sa_family);
  564.  
  565.         while (s < slim)
  566.             cp += sprintf(cp, " %x", *s++);
  567.         break;
  568.         }
  569.     }
  570.     return (line);
  571. }
  572.  
  573. void
  574. set_metric(char *value, int key)
  575. {
  576. #if 0
  577.     int flag = 0; 
  578.     u_long noval, *valp = &noval;
  579.  
  580.     switch (key) {
  581. #define caseof(x, y, z)    case x: valp = &rt_metrics.z; flag = y; break
  582.     caseof(K_MTU, RTV_MTU, rmx_mtu);
  583.     caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
  584.     caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
  585.     caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
  586.     caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
  587.     caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
  588.     caseof(K_RTT, RTV_RTT, rmx_rtt);
  589.     caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
  590.     }
  591.     rtm_inits |= flag;
  592.     if (lockrest || locking)
  593.         rt_metrics.rmx_locks |= flag;
  594.     if (locking)
  595.         locking = 0;
  596.     *valp = atoi(value);
  597. #endif
  598. }
  599.  
  600. void
  601. newroute(argc, argv)
  602.     int argc;
  603.     register char **argv;
  604. {
  605.     char *cmd, *dest = "", *gateway = "", *err;
  606.     int ishost = 0, ret, attempts, oerrno, flags = 0;
  607.     int key;
  608.     struct hostent *hp = 0;
  609.  
  610. #if 0
  611.     if (uid)
  612.         quit("must be root to alter routing table");
  613. #endif
  614.     cmd = argv[0];
  615.     if (*cmd != 'g')
  616.         shutdown(s, 0); /* Don't want to read back our messages */
  617.     while (--argc > 0) {
  618.         if (**(++argv)== '-') {
  619.             switch (key = keyword(1 + *argv)) {
  620. #if 0
  621.             case K_LINK:
  622.                 af = AF_LINK;
  623.                 aflen = sizeof(struct sockaddr_dl);
  624.                 break;
  625.             case K_OSI:
  626.             case K_ISO:
  627.                 af = AF_ISO;
  628.                 aflen = sizeof(struct sockaddr_iso);
  629.                 break;
  630. #endif
  631.             case K_INET:
  632.                 af = AF_INET;
  633.                 aflen = sizeof(struct sockaddr_in);
  634.                 break;
  635. #if 0
  636.             case K_X25:
  637.                 af = AF_CCITT;
  638.                 aflen = sizeof(struct sockaddr_x25);
  639.                 break;
  640.             case K_SA:
  641.                 af = 0;
  642.                 aflen = sizeof(union sockunion);
  643.                 break;
  644.             case K_XNS:
  645.                 af = AF_NS;
  646.                 aflen = sizeof(struct sockaddr_ns);
  647.                 break;
  648. #endif
  649.             case K_IFACE:
  650.             case K_INTERFACE:
  651.                 iflag++;
  652.                 break;
  653.             case K_LOCK:
  654.                 locking = 1;
  655.                 break;
  656.             case K_LOCKREST:
  657.                 lockrest = 1;
  658.                 break;
  659.             case K_HOST:
  660.                 forcehost++;
  661.                 break;
  662.             case K_REJECT:
  663.                 flags |= RTF_REJECT;
  664.                 break;
  665.             case K_PROTO1:
  666.                 flags |= RTF_PROTO1;
  667.                 break;
  668.             case K_PROTO2:
  669.                 flags |= RTF_PROTO2;
  670.                 break;
  671.             case K_CLONING:
  672.                 flags |= RTF_CLONING;
  673.                 break;
  674.             case K_XRESOLVE:
  675.                 flags |= RTF_XRESOLVE;
  676.                 break;
  677.             case K_IFA:
  678.                 argc--;
  679.                 (void) getaddr(RTA_IFA, *++argv, 0);
  680.                 break;
  681.             case K_IFP:
  682.                 argc--;
  683.                 (void) getaddr(RTA_IFP, *++argv, 0);
  684.                 break;
  685.             case K_GENMASK:
  686.                 argc--;
  687.                 (void) getaddr(RTA_GENMASK, *++argv, 0);
  688.                 break;
  689.             case K_GATEWAY:
  690.                 argc--;
  691.                 (void) getaddr(RTA_GATEWAY, *++argv, 0);
  692.                 break;
  693.             case K_DST:
  694.                 argc--;
  695.                 ishost = getaddr(RTA_DST, *++argv, &hp);
  696.                 dest = *argv;
  697.                 break;
  698.             case K_NETMASK:
  699.                 argc--;
  700.                 (void) getaddr(RTA_NETMASK, *++argv, 0);
  701.                 /* FALLTHROUGH */
  702.             case K_NET:
  703.                 forcenet++;
  704.                 break;
  705.             case K_MTU:
  706.             case K_HOPCOUNT:
  707.             case K_EXPIRE:
  708.             case K_RECVPIPE:
  709.             case K_SENDPIPE:
  710.             case K_SSTHRESH:
  711.             case K_RTT:
  712.             case K_RTTVAR:
  713.                 argc--;
  714.                 set_metric(*++argv, key);
  715.                 break;
  716.             default:
  717.                 usage(1+*argv);
  718.             }
  719.         } else {
  720.             if ((rtm_addrs & RTA_DST) == 0) {
  721.                 dest = *argv;
  722.                 ishost = getaddr(RTA_DST, *argv, &hp);
  723.             } else if ((rtm_addrs & RTA_GATEWAY) == 0) {
  724.                 gateway = *argv;
  725.                 (void) getaddr(RTA_GATEWAY, *argv, &hp);
  726.             } else {
  727.                 int ret = atoi(*argv);
  728.                 if (ret == 0) {
  729.                     printf("%s,%s", "old usage of trailing 0",
  730.                        "assuming route to if\n");
  731.                     iflag = 1;
  732.                     continue;
  733.                 } else if (ret > 0 && ret < 10) {
  734.                     printf("old usage of trailing digit, ");
  735.                     printf("assuming route via gateway\n");
  736.                     iflag = 0;
  737.                     continue;
  738.                 }
  739.                 (void) getaddr(RTA_NETMASK, *argv, 0);
  740.             }
  741.         }
  742.     }
  743.     if (forcehost)
  744.         ishost = 1;
  745.     if (forcenet)
  746.         ishost = 0;
  747.     flags |= RTF_UP;
  748.     if (ishost)
  749.         flags |= RTF_HOST;
  750.     if (iflag == 0)
  751.         flags |= RTF_GATEWAY;
  752.     for (attempts = 1; ; attempts++) {
  753.         errno = 0;
  754.         if (Cflag && (af == AF_INET || af == AF_NS)) {
  755.             route.rt_flags = flags;
  756.             route.rt_dst = so_dst.sa;
  757.             route.rt_gateway = so_gate.sa;
  758.             if ((ret = ioctl(s, *cmd == 'a' ? SIOCADDRT : SIOCDELRT,
  759.                  (caddr_t)&route)) == 0)
  760.                 break;
  761. #if 0
  762.         } else {
  763.             if ((ret = rtmsg(*cmd, flags)) == 0)
  764.                 break;
  765. #endif
  766.         }
  767.         if (errno != ENETUNREACH && errno != ESRCH)
  768.             break;
  769.         if (af == AF_INET && hp && hp->h_addr_list[1]) {
  770.             hp->h_addr_list++;
  771.             bcopy(hp->h_addr_list[0], (caddr_t)&so_dst.sin.sin_addr,
  772.                 hp->h_length);
  773.         } else
  774.             break;
  775.     }
  776.     if (*cmd == 'g')
  777.         exit(0);
  778.     oerrno = errno;
  779.     (void) printf("%s %s %s: gateway %s", cmd, ishost? "host" : "net",
  780.         dest, gateway);
  781.     if (attempts > 1 && ret == 0)
  782.         (void) printf(" (%s)",
  783.         inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr));
  784.     if (ret == 0)
  785.         (void) printf("\n");
  786.     else {
  787.         switch (oerrno) {
  788.         case ESRCH:
  789.             err = "not in table";
  790.             break;
  791.         case EBUSY:
  792.             err = "entry in use";
  793.             break;
  794.         case ENOBUFS:
  795.             err = "routing table overflow";
  796.             break;
  797.         default:
  798.             err = strerror(oerrno);
  799.             break;
  800.         }
  801.         (void) printf(": %s\n", err);
  802.     }
  803. }
  804.  
  805. void
  806. inet_makenetandmask(u_long net, register struct sockaddr_in *sin)
  807. {
  808.     u_long addr, mask = 0;
  809.     register char *cp;
  810.  
  811.     rtm_addrs |= RTA_NETMASK;
  812.     if (net == 0)
  813.         mask = addr = 0;
  814.     else if (net < 128) {
  815.         addr = net << IN_CLASSA_NSHIFT;
  816.         mask = IN_CLASSA_NET;
  817.     } else if (net < 65536) {
  818.         addr = net << IN_CLASSB_NSHIFT;
  819.         mask = IN_CLASSB_NET;
  820.     } else if (net < 16777216L) {
  821.         addr = net << IN_CLASSC_NSHIFT;
  822.         mask = IN_CLASSC_NET;
  823.     } else {
  824.         addr = net;
  825.         if ((addr & IN_CLASSA_HOST) == 0)
  826.             mask =  IN_CLASSA_NET;
  827.         else if ((addr & IN_CLASSB_HOST) == 0)
  828.             mask =  IN_CLASSB_NET;
  829.         else if ((addr & IN_CLASSC_HOST) == 0)
  830.             mask =  IN_CLASSC_NET;
  831.         else
  832.             mask = -1;
  833.     }
  834.     sin->sin_addr.s_addr = htonl(addr);
  835.     sin = &so_mask.sin;
  836.     sin->sin_addr.s_addr = htonl(mask);
  837.     sin->sin_len = 0;
  838.     sin->sin_family = 0;
  839.     cp = (char *)(&sin->sin_addr + 1);
  840.     while (*--cp == 0 && cp > (char *)sin)
  841.         ;
  842.     sin->sin_len = 1 + cp - (char *)sin;
  843. }
  844.  
  845. /*
  846.  * Interpret an argument as a network address of some kind,
  847.  * returning 1 if a host address, 0 if a network address.
  848.  */
  849. int
  850. getaddr(which, s, hpp)
  851.     int which;
  852.     char *s;
  853.     struct hostent **hpp;
  854. {
  855.     register sup su;
  856. #if 0
  857.     struct ns_addr ns_addr();
  858.     struct iso_addr *iso_addr();
  859. #endif
  860.     struct hostent *hp;
  861.     struct netent *np;
  862.     u_long val;
  863.  
  864.     if (af == 0) {
  865.         af = AF_INET;
  866.         aflen = sizeof(struct sockaddr_in);
  867.     }
  868.     rtm_addrs |= which;
  869.     switch (which) {
  870.     case RTA_DST:        su = so_addrs[0]; su->sa.sa_family = af; break;
  871.     case RTA_GATEWAY:    su = so_addrs[1]; su->sa.sa_family = af; break;
  872.     case RTA_NETMASK:    su = so_addrs[2]; break;
  873.     case RTA_GENMASK:    su = so_addrs[3]; break;
  874.     case RTA_IFP:        su = so_addrs[4]; su->sa.sa_family = af; break;
  875.     case RTA_IFA:        su = so_addrs[5]; su->sa.sa_family = af; break;
  876.     default:        usage("Internal Error"); /*NOTREACHED*/
  877.     }
  878.     su->sa.sa_len = aflen;
  879.     if (strcmp(s, "default") == 0) {
  880.         switch (which) {
  881.         case RTA_DST:
  882.             forcenet++;
  883.             (void) getaddr(RTA_NETMASK, s, 0);
  884.             break;
  885.         case RTA_NETMASK:
  886.         case RTA_GENMASK:
  887.             su->sa.sa_len = 0;
  888.         }
  889.         return 0;
  890.     }
  891. #if 0
  892.     if (af == AF_NS)
  893.         goto do_xns;
  894.     if (af == AF_OSI)
  895.         goto do_osi;
  896.     if (af == AF_LINK)
  897.         goto do_link;
  898.     if (af == AF_CCITT)
  899.         goto do_ccitt;
  900.     if (af == 0)
  901.         goto do_sa;
  902. #endif
  903.     if (hpp == NULL)
  904.         hpp = &hp;
  905.     *hpp = NULL;
  906.     if (((val = inet_addr(s)) != -1) &&
  907.         (which != RTA_DST || forcenet == 0)) {
  908.         su->sin.sin_addr.s_addr = val;
  909.         if (inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
  910.             return (1);
  911.         else {
  912.             val = ntohl(val);
  913.         out:    if (which == RTA_DST)
  914.                 inet_makenetandmask(val, &su->sin);
  915.             return (0);
  916.         }
  917.     }
  918.     val = inet_network(s);
  919.     if (val != -1) {
  920.         goto out;
  921.     }
  922.     np = getnetbyname(s);
  923.     if (np) {
  924.         val = np->n_net;
  925.         goto out;
  926.     }
  927.     hp = gethostbyname(s);
  928.     if (hp) {
  929.         *hpp = hp;
  930.         su->sin.sin_family = hp->h_addrtype;
  931.         bcopy(hp->h_addr, (char *)&su->sin.sin_addr, hp->h_length);
  932.         return (1);
  933.     }
  934.     (void) fprintf(stderr, "%s: bad value\n", s);
  935.     exit(1);
  936. #if 0
  937. do_xns:
  938.     if (which == RTA_DST) {
  939.         extern short ns_bh[3];
  940.         struct sockaddr_ns *sms = &(so_mask.sns);
  941.         bzero((char *)sms, sizeof(*sms));
  942.         sms->sns_family = 0;
  943.         sms->sns_len = 6;
  944.         sms->sns_addr.x_net = *(union ns_net *)ns_bh;
  945.         rtm_addrs |= RTA_NETMASK;
  946.     }
  947.     su->sns.sns_addr = ns_addr(s);
  948.     return (!ns_nullhost(su->sns.sns_addr));
  949. do_osi:
  950.     su->siso.siso_addr = *iso_addr(s);
  951.     if (which == RTA_NETMASK || which == RTA_GENMASK) {
  952.         register char *cp = (char *)TSEL(&su->siso);
  953.         su->siso.siso_nlen = 0;
  954.         do {--cp ;} while ((cp > (char *)su) && (*cp == 0));
  955.         su->siso.siso_len = 1 + cp - (char *)su;
  956.     }
  957.     return (1);
  958. do_ccitt:
  959.     ccitt_addr(s, &su->sx25);
  960.     return (1);
  961. do_link:
  962.     link_addr(s, &su->sdl);
  963.     return (1);
  964. do_sa:
  965.     su->sa.sa_len = sizeof(*su);
  966.     sockaddr(s, &su->sa);
  967.     return (1);
  968. #endif
  969. }
  970.  
  971. short ns_nullh[] = {0,0,0};
  972. short ns_bh[] = {-1,-1,-1};
  973.  
  974. #if 0
  975. char *
  976. ns_print(sns)
  977.     struct sockaddr_ns *sns;
  978. {
  979.     struct ns_addr work;
  980.     union { union ns_net net_e; u_long long_e; } net;
  981.     u_short port;
  982.     static char mybuf[50], cport[10], chost[25];
  983.     char *host = "";
  984.     register char *p;
  985.     register u_char *q;
  986.  
  987.     work = sns->sns_addr;
  988.     port = ntohs(work.x_port);
  989.     work.x_port = 0;
  990.     net.net_e  = work.x_net;
  991.     if (ns_nullhost(work) && net.long_e == 0) {
  992.         if (!port)
  993.             return ("*.*");
  994.         (void) sprintf(mybuf, "*.%XH", port);
  995.         return (mybuf);
  996.     }
  997.  
  998.     if (bcmp((char *)ns_bh, (char *)work.x_host.c_host, 6) == 0) 
  999.         host = "any";
  1000.     else if (bcmp((char *)ns_nullh, (char *)work.x_host.c_host, 6) == 0)
  1001.         host = "*";
  1002.     else {
  1003.         q = work.x_host.c_host;
  1004.         (void) sprintf(chost, "%02X%02X%02X%02X%02X%02XH",
  1005.             q[0], q[1], q[2], q[3], q[4], q[5]);
  1006.         for (p = chost; *p == '0' && p < chost + 12; p++)
  1007.             /* void */;
  1008.         host = p;
  1009.     }
  1010.     if (port)
  1011.         (void) sprintf(cport, ".%XH", htons(port));
  1012.     else
  1013.         *cport = 0;
  1014.  
  1015.     (void) sprintf(mybuf,"%XH.%s%s", ntohl(net.long_e), host, cport);
  1016.     return (mybuf);
  1017. }
  1018. #endif
  1019.  
  1020. void
  1021. monitor(void)
  1022. {
  1023. #if 0
  1024.     int n;
  1025.     char msg[2048];
  1026.  
  1027.     verbose = 1;
  1028.     for(;;) {
  1029.         n = read(s, msg, 2048);
  1030.         (void) printf("got message of size %d\n", n);
  1031.         print_rtmsg((struct rt_msghdr *)msg);
  1032.     }
  1033. #endif
  1034. }
  1035.  
  1036. #if 0
  1037. struct {
  1038.     struct    rt_msghdr m_rtm;
  1039.     char    m_space[512];
  1040. } m_rtmsg;
  1041.  
  1042. int
  1043. rtmsg(cmd, flags)
  1044.     int cmd, flags;
  1045. {
  1046.     static int seq;
  1047.     int rlen;
  1048.     register char *cp = m_rtmsg.m_space;
  1049.     register int l;
  1050.  
  1051. #define NEXTADDR(w, u) \
  1052.     if (rtm_addrs & (w)) {\
  1053.         l = ROUNDUP(u.sa.sa_len); bcopy((char *)&(u), cp, l); cp += l;\
  1054.         if (verbose) sodump(&(u),"u");\
  1055.     }
  1056.  
  1057.     errno = 0;
  1058.     bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
  1059.     if (cmd == 'a')
  1060.         cmd = RTM_ADD;
  1061.     else if (cmd == 'c')
  1062.         cmd = RTM_CHANGE;
  1063.     else if (cmd == 'g')
  1064.         cmd = RTM_GET;
  1065.     else
  1066.         cmd = RTM_DELETE;
  1067. #define rtm m_rtmsg.m_rtm
  1068.     rtm.rtm_type = cmd;
  1069.     rtm.rtm_flags = flags;
  1070.     rtm.rtm_version = RTM_VERSION;
  1071.     rtm.rtm_seq = ++seq;
  1072.     rtm.rtm_addrs = rtm_addrs;
  1073.     rtm.rtm_rmx = rt_metrics;
  1074.     rtm.rtm_inits = rtm_inits;
  1075.  
  1076.     if (rtm_addrs & RTA_NETMASK)
  1077.         mask_addr();
  1078.     NEXTADDR(RTA_DST, so_dst);
  1079.     NEXTADDR(RTA_GATEWAY, so_gate);
  1080.     NEXTADDR(RTA_NETMASK, so_mask);
  1081.     NEXTADDR(RTA_GENMASK, so_genmask);
  1082.     NEXTADDR(RTA_IFP, so_ifp);
  1083.     NEXTADDR(RTA_IFA, so_ifa);
  1084.     rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
  1085.     if (verbose)
  1086.         print_rtmsg(&rtm, l);
  1087.     if (debugonly)
  1088.         return 0;
  1089.     if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
  1090.         perror("writing to routing socket");
  1091.         return (-1);
  1092.     }
  1093.     if (cmd == RTM_GET) {
  1094.         do {
  1095.             l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
  1096.         } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
  1097.         if (l < 0)
  1098.             (void) fprintf(stderr,
  1099.                 "route: read from routing socket: %s\n",
  1100.                 strerror(errno));
  1101.         else
  1102.             print_getmsg(&rtm, l);
  1103.     }
  1104. #undef rtm
  1105.     return (0);
  1106. }
  1107. #endif
  1108.  
  1109. #if 0
  1110. mask_addr() {
  1111.     register char *cp1, *cp2;
  1112.     int olen;
  1113.  
  1114.     if ((rtm_addrs & RTA_DST) == 0)
  1115.         return;
  1116.     switch(so_dst.sa.sa_family) {
  1117.     case AF_NS: case AF_INET: case 0:
  1118.         return;
  1119.     case AF_ISO:
  1120.         olen = MIN(so_dst.siso.siso_nlen, so_mask.sa.sa_len - 6);
  1121.     }
  1122.     cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst;
  1123.     cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst;
  1124.     while (cp2 > cp1)
  1125.         *--cp2 = 0;
  1126.     cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask;
  1127.     while (cp1 > so_dst.sa.sa_data)
  1128.         *--cp1 &= *--cp2;
  1129.     switch(so_dst.sa.sa_family) {
  1130.     case AF_ISO:
  1131.         so_dst.siso.siso_nlen = olen;
  1132.     }
  1133. }
  1134.  
  1135. char *msgtypes[] = {
  1136.     "",
  1137.     "RTM_ADD: Add Route",
  1138.     "RTM_DELETE: Delete Route",
  1139.     "RTM_CHANGE: Change Metrics or flags",
  1140.     "RTM_GET: Report Metrics",
  1141.     "RTM_LOSING: Kernel Suspects Partitioning",
  1142.     "RTM_REDIRECT: Told to use different route",
  1143.     "RTM_MISS: Lookup failed on this address",
  1144.     "RTM_LOCK: fix specified metrics",
  1145.     "RTM_OLDADD: caused by SIOCADDRT",
  1146.     "RTM_OLDDEL: caused by SIOCDELRT",
  1147.     0,
  1148. };
  1149.  
  1150. char metricnames[] =
  1151. "\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu";
  1152. char routeflags[] = 
  1153. "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT\011CLONING\012XRESOLVE\013LLINFO\017PROTO2\020PROTO1";
  1154.  
  1155.  
  1156. void
  1157. print_rtmsg(rtm, msglen)
  1158.     register struct rt_msghdr *rtm;
  1159.     int msglen;
  1160. {
  1161.     if (verbose == 0)
  1162.         return;
  1163.     if (rtm->rtm_version != RTM_VERSION) {
  1164.         (void) printf("routing message version %d not understood\n",
  1165.             rtm->rtm_version);
  1166.         return;
  1167.     }
  1168.     (void) printf("%s\npid: %d, len %d, seq %d, errno %d, flags:",
  1169.         msgtypes[rtm->rtm_type], rtm->rtm_pid, rtm->rtm_msglen,
  1170.         rtm->rtm_seq, rtm->rtm_errno); 
  1171.     bprintf(stdout, rtm->rtm_flags, routeflags);
  1172.     pmsg_common(rtm);
  1173. }
  1174.  
  1175. void
  1176. print_getmsg(rtm, msglen)
  1177.     register struct rt_msghdr *rtm;
  1178.     int msglen;
  1179. {
  1180.     if (rtm->rtm_version != RTM_VERSION) {
  1181.         (void)printf("routing message version %d not understood\n",
  1182.             rtm->rtm_version);
  1183.         return;
  1184.     }
  1185.     if (rtm->rtm_msglen > msglen) {
  1186.         (void)printf("get length mismatch, in packet %d, returned %d\n",
  1187.             rtm->rtm_msglen, msglen);
  1188.     }
  1189.     (void) printf("RTM_GET: errno %d, flags:", rtm->rtm_errno); 
  1190.     bprintf(stdout, rtm->rtm_flags, routeflags);
  1191.     (void) printf("\nmetric values:\n  ");
  1192. #define metric(f, e)\
  1193.     printf("%s: %d%s", __STRING(f), rtm->rtm_rmx.__CONCAT(rmx_,f), e)
  1194.     metric(recvpipe, ", ");
  1195.     metric(sendpipe, ", ");
  1196.     metric(ssthresh, ", ");
  1197.     metric(rtt, "\n  ");
  1198.     metric(rttvar, ", ");
  1199.     metric(hopcount, ", ");
  1200.     metric(mtu, ", ");
  1201.     metric(expire, "\n");
  1202. #undef metric
  1203.     pmsg_common(rtm);
  1204. }
  1205.  
  1206. void
  1207. pmsg_common(rtm)
  1208.     register struct rt_msghdr *rtm;
  1209. {
  1210.     char *cp;
  1211.     register struct sockaddr *sa;
  1212.     int i;
  1213.  
  1214.     (void) printf("\nlocks: ");
  1215.     bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
  1216.     (void) printf(" inits: ");
  1217.     bprintf(stdout, rtm->rtm_inits, metricnames);
  1218.     (void) printf("\nsockaddrs: ");
  1219.     bprintf(stdout, rtm->rtm_addrs,
  1220.         "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR");
  1221.     (void) putchar('\n');
  1222.     cp = ((char *)(rtm + 1));
  1223.     if (rtm->rtm_addrs)
  1224.         for (i = 1; i; i <<= 1)
  1225.             if (i & rtm->rtm_addrs) {
  1226.                 sa = (struct sockaddr *)cp;
  1227.                 (void) printf(" %s", routename(sa));
  1228.                 ADVANCE(cp, sa);
  1229.             }
  1230.     (void) putchar('\n');
  1231.     (void) fflush(stdout);
  1232. }
  1233.  
  1234. void
  1235. bprintf(fp, b, s)
  1236.     register FILE *fp;
  1237.     register int b;
  1238.     register u_char *s;
  1239. {
  1240.     register int i;
  1241.     int gotsome = 0;
  1242.  
  1243.     if (b == 0)
  1244.         return;
  1245.     while (i = *s++) {
  1246.         if (b & (1 << (i-1))) {
  1247.             if (gotsome == 0)
  1248.                 i = '<';
  1249.             else
  1250.                 i = ',';
  1251.             (void) putc(i, fp);
  1252.             gotsome = 1;
  1253.             for (; (i = *s) > 32; s++)
  1254.                 (void) putc(i, fp);
  1255.         } else
  1256.             while (*s > 32)
  1257.                 s++;
  1258.     }
  1259.     if (gotsome)
  1260.         (void) putc('>', fp);
  1261. }
  1262. #endif
  1263.  
  1264. int
  1265. keyword(cp)
  1266.     char *cp;
  1267. {
  1268.     register struct keytab *kt = keywords;
  1269.  
  1270.     while (kt->kt_cp && strcmp(kt->kt_cp, cp))
  1271.         kt++;
  1272.     return kt->kt_i;
  1273. }
  1274. #if 0
  1275. void
  1276. sodump(su, which)
  1277.     register sup su;
  1278.     char *which;
  1279. {
  1280.     switch (su->sa.sa_family) {
  1281.     case AF_LINK:
  1282.         (void) printf("%s: link %s; ",
  1283.             which, link_ntoa(&su->sdl));
  1284.         break;
  1285.     case AF_ISO:
  1286.         (void) printf("%s: iso %s; ",
  1287.             which, iso_ntoa(&su->siso.siso_addr));
  1288.         break;
  1289.     case AF_INET:
  1290.         (void) printf("%s: inet %s; ",
  1291.             which, inet_ntoa(su->sin.sin_addr));
  1292.         break;
  1293.     case AF_NS:
  1294.         (void) printf("%s: xns %s; ",
  1295.             which, ns_ntoa(su->sns.sns_addr));
  1296.         break;
  1297.     }
  1298.     (void) fflush(stdout);
  1299. }
  1300. /* States*/
  1301. #define VIRGIN    0
  1302. #define GOTONE    1
  1303. #define GOTTWO    2
  1304. /* Inputs */
  1305. #define    DIGIT    (4*0)
  1306. #define    END    (4*1)
  1307. #define DELIM    (4*2)
  1308.  
  1309. void
  1310. sockaddr(addr, sa)
  1311. register char *addr;
  1312. register struct sockaddr *sa;
  1313. {
  1314.     register char *cp = (char *)sa;
  1315.     int size = sa->sa_len;
  1316.     char *cplim = cp + size;
  1317.     register int byte = 0, state = VIRGIN, new;
  1318.  
  1319.     bzero(cp, size);
  1320.     do {
  1321.         if ((*addr >= '0') && (*addr <= '9')) {
  1322.             new = *addr - '0';
  1323.         } else if ((*addr >= 'a') && (*addr <= 'f')) {
  1324.             new = *addr - 'a' + 10;
  1325.         } else if ((*addr >= 'A') && (*addr <= 'F')) {
  1326.             new = *addr - 'A' + 10;
  1327.         } else if (*addr == 0) 
  1328.             state |= END;
  1329.         else
  1330.             state |= DELIM;
  1331.         addr++;
  1332.         switch (state /* | INPUT */) {
  1333.         case GOTTWO | DIGIT:
  1334.             *cp++ = byte; /*FALLTHROUGH*/
  1335.         case VIRGIN | DIGIT:
  1336.             state = GOTONE; byte = new; continue;
  1337.         case GOTONE | DIGIT:
  1338.             state = GOTTWO; byte = new + (byte << 4); continue;
  1339.         default: /* | DELIM */
  1340.             state = VIRGIN; *cp++ = byte; byte = 0; continue;
  1341.         case GOTONE | END:
  1342.         case GOTTWO | END:
  1343.             *cp++ = byte; /* FALLTHROUGH */
  1344.         case VIRGIN | END:
  1345.             break;
  1346.         }
  1347.         break;
  1348.     } while (cp < cplim); 
  1349.     sa->sa_len = cp - (char *)sa;
  1350. }
  1351. #endif
  1352.