source: rtems-libbsd/freebsd/sbin/route/route.c @ e599318

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since e599318 was e599318, checked in by Sebastian Huber <sebastian.huber@…>, on 10/09/13 at 20:52:54

Update files to match FreeBSD layout

Add compatibility with Newlib header files. Some FreeBSD header files
are mapped by the translation script:

o rtems/bsd/sys/_types.h
o rtems/bsd/sys/errno.h
o rtems/bsd/sys/lock.h
o rtems/bsd/sys/param.h
o rtems/bsd/sys/resource.h
o rtems/bsd/sys/time.h
o rtems/bsd/sys/timespec.h
o rtems/bsd/sys/types.h
o rtems/bsd/sys/unistd.h

It is now possible to include <sys/socket.h> directly for example.

Generate one Makefile which builds everything including tests.

  • Property mode set to 100644
File size: 38.2 KB
Line 
1#ifdef __rtems__
2#define __need_getopt_newlib
3#include <getopt.h>
4#endif
5/*
6 * Copyright (c) 1983, 1989, 1991, 1993
7 *      The Regents of the University of California.  All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static const char copyright[] =
36"@(#) Copyright (c) 1983, 1989, 1991, 1993\n\
37        The Regents of the University of California.  All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41#if 0
42static char sccsid[] = "@(#)route.c     8.6 (Berkeley) 4/28/95";
43#endif
44static const char rcsid[] =
45  "$FreeBSD$";
46#endif /* not lint */
47
48#include <rtems/bsd/sys/param.h>
49#include <sys/file.h>
50#include <sys/socket.h>
51#include <sys/ioctl.h>
52#include <sys/sysctl.h>
53#include <rtems/bsd/sys/types.h>
54
55#include <net/if.h>
56#include <net/route.h>
57#include <net/if_dl.h>
58#include <netinet/in.h>
59#include <netinet/if_ether.h>
60#include <netatalk/at.h>
61#include <arpa/inet.h>
62#include <netdb.h>
63
64#include <ctype.h>
65#include <err.h>
66#include <errno.h>
67#include <paths.h>
68#include <stdio.h>
69#include <stdlib.h>
70#include <string.h>
71#include <sysexits.h>
72#include <unistd.h>
73#include <ifaddrs.h>
74
75struct keytab {
76        char    *kt_cp;
77        int     kt_i;
78} keywords[] = {
79#include "keywords.h"
80        {0, 0}
81};
82
83struct  ortentry route;
84union   sockunion {
85        struct  sockaddr sa;
86        struct  sockaddr_in sin;
87#ifdef INET6
88        struct  sockaddr_in6 sin6;
89#endif
90        struct  sockaddr_at sat;
91        struct  sockaddr_dl sdl;
92        struct  sockaddr_inarp sinarp;
93        struct  sockaddr_storage ss; /* added to avoid memory overrun */
94} so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp;
95
96typedef union sockunion *sup;
97int     pid, rtm_addrs;
98int     s;
99int     forcehost, forcenet, doflush, nflag, af, qflag, tflag, keyword();
100int     iflag, verbose, aflen = sizeof (struct sockaddr_in);
101int     locking, lockrest, debugonly;
102struct  rt_metrics rt_metrics;
103u_long  rtm_inits;
104uid_t   uid;
105int     atalk_aton(const char *, struct at_addr *);
106char    *atalk_ntoa(struct at_addr);
107const char      *routename(), *netname();
108void    flushroutes(), newroute(), monitor(), sockaddr(), sodump(), bprintf();
109void    print_getmsg(), print_rtmsg(), pmsg_common(), pmsg_addrs(), mask_addr();
110#ifdef INET6
111static int inet6_makenetandmask(struct sockaddr_in6 *, char *);
112#endif
113int     getaddr(), rtmsg(), x25_makemask();
114int     prefixlen();
115extern  char *iso_ntoa();
116
117void usage(const char *) __dead2;
118
119#ifdef __rtems__
120
121static int main_route(int argc, char **argv);
122
123static int rtems_shell_main_route(int argc, char *argv[])
124{
125  rtems_shell_globals_t  route_globals;
126  rtems_shell_globals = &route_globals;
127  memset (rtems_shell_globals, 0, sizeof (route_globals));
128  route_globals.exit_code = 1;
129  if (setjmp (route_globals.exit_jmp) == 0)
130    return main_route ( argc, argv);
131  return route_globals.exit_code;
132}
133
134#endif
135
136
137void
138usage(cp)
139        const char *cp;
140{
141        if (cp)
142                warnx("bad keyword: %s", cp);
143        (void) fprintf(stderr,
144            "usage: route [-dnqtv] command [[modifiers] args]\n");
145        exit(EX_USAGE);
146        /* NOTREACHED */
147}
148
149#ifdef __rtems__
150int
151main_route(argc, argv)
152#else
153main(argc, argv)
154#endif
155        int argc;
156        char **argv;
157{
158        int ch;
159#ifdef __rtems__
160        struct getopt_data getopt_reent;
161#define optind getopt_reent.optind
162#define optarg getopt_reent.optarg
163#define opterr getopt_reent.opterr
164#define optopt getopt_reent.optopt
165#endif
166
167        if (argc < 2)
168                usage((char *)NULL);
169
170#ifdef __rtems__
171        memset(&getopt_reent, 0, sizeof(getopt_data));
172        while ((ch = getopt_r(argc, argv, "nqdtv", &getopt_reent)) != -1)
173#else
174        while ((ch = getopt(argc, argv, "nqdtv")) != -1)
175#endif
176                switch(ch) {
177                case 'n':
178                        nflag = 1;
179                        break;
180                case 'q':
181                        qflag = 1;
182                        break;
183                case 'v':
184                        verbose = 1;
185                        break;
186                case 't':
187                        tflag = 1;
188                        break;
189                case 'd':
190                        debugonly = 1;
191                        break;
192                case '?':
193                default:
194                        usage((char *)NULL);
195                }
196        argc -= optind;
197        argv += optind;
198
199        pid = getpid();
200        uid = geteuid();
201        if (tflag)
202                s = open(_PATH_DEVNULL, O_WRONLY, 0);
203        else
204                s = socket(PF_ROUTE, SOCK_RAW, 0);
205        if (s < 0)
206                err(EX_OSERR, "socket");
207        if (*argv)
208                switch (keyword(*argv)) {
209                case K_GET:
210                case K_SHOW:
211                        uid = 0;
212                        /* FALLTHROUGH */
213
214                case K_CHANGE:
215                case K_ADD:
216                case K_DEL:
217                case K_DELETE:
218                        newroute(argc, argv);
219                        /* NOTREACHED */
220
221                case K_MONITOR:
222                        monitor();
223                        /* NOTREACHED */
224
225                case K_FLUSH:
226                        flushroutes(argc, argv);
227                        exit(0);
228                        /* NOTREACHED */
229                }
230        usage(*argv);
231        /* NOTREACHED */
232}
233
234/*
235 * Purge all entries in the routing tables not
236 * associated with network interfaces.
237 */
238void
239flushroutes(argc, argv)
240        int argc;
241        char *argv[];
242{
243        size_t needed;
244        int mib[6], rlen, seqno, count = 0;
245        char *buf, *next, *lim;
246        struct rt_msghdr *rtm;
247
248        if (uid && !debugonly) {
249                errx(EX_NOPERM, "must be root to alter routing table");
250        }
251        shutdown(s, SHUT_RD); /* Don't want to read back our messages */
252        if (argc > 1) {
253                argv++;
254                if (argc == 2 && **argv == '-')
255                    switch (keyword(*argv + 1)) {
256                        case K_INET:
257                                af = AF_INET;
258                                break;
259#ifdef INET6
260                        case K_INET6:
261                                af = AF_INET6;
262                                break;
263#endif
264                        case K_ATALK:
265                                af = AF_APPLETALK;
266                                break;
267                        case K_LINK:
268                                af = AF_LINK;
269                                break;
270                        default:
271                                goto bad;
272                } else
273bad:                    usage(*argv);
274        }
275retry:
276        mib[0] = CTL_NET;
277        mib[1] = PF_ROUTE;
278        mib[2] = 0;             /* protocol */
279        mib[3] = 0;             /* wildcard address family */
280        mib[4] = NET_RT_DUMP;
281        mib[5] = 0;             /* no flags */
282        if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
283                err(EX_OSERR, "route-sysctl-estimate");
284        if ((buf = malloc(needed)) == NULL)
285                errx(EX_OSERR, "malloc failed");
286        if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
287                if (errno == ENOMEM && count++ < 10) {
288                        warnx("Routing table grew, retrying"); 
289                        sleep(1);
290                        free(buf);
291                        goto retry;
292                }
293                err(EX_OSERR, "route-sysctl-get");
294        }
295        lim = buf + needed;
296        if (verbose)
297                (void) printf("Examining routing table from sysctl\n");
298        seqno = 0;              /* ??? */
299        for (next = buf; next < lim; next += rtm->rtm_msglen) {
300                rtm = (struct rt_msghdr *)next;
301                if (verbose)
302                        print_rtmsg(rtm, rtm->rtm_msglen);
303                if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
304                        continue;
305                if (af) {
306                        struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
307
308                        if (sa->sa_family != af)
309                                continue;
310                }
311                if (debugonly)
312                        continue;
313                rtm->rtm_type = RTM_DELETE;
314                rtm->rtm_seq = seqno;
315                rlen = write(s, next, rtm->rtm_msglen);
316                if (rlen < 0 && errno == EPERM)
317                        err(1, "write to routing socket");
318                if (rlen < (int)rtm->rtm_msglen) {
319                        warn("write to routing socket");
320                        (void) printf("got only %d for rlen\n", rlen);
321                        free(buf);
322                        goto retry;
323                        break;
324                }
325                seqno++;
326                if (qflag)
327                        continue;
328                if (verbose)
329                        print_rtmsg(rtm, rlen);
330                else {
331                        struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
332                        (void) printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ?
333                            routename(sa) : netname(sa));
334                        sa = (struct sockaddr *)(SA_SIZE(sa) + (char *)sa);
335                        (void) printf("%-20.20s ", routename(sa));
336                        (void) printf("done\n");
337                }
338        }
339}
340
341const char *
342routename(sa)
343        struct sockaddr *sa;
344{
345        char *cp;
346        static char line[MAXHOSTNAMELEN + 1];
347        struct hostent *hp;
348        static char domain[MAXHOSTNAMELEN + 1];
349        static int first = 1, n;
350
351        if (first) {
352                first = 0;
353                if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
354                    (cp = strchr(domain, '.'))) {
355                        domain[MAXHOSTNAMELEN] = '\0';
356                        (void) strcpy(domain, cp + 1);
357                } else
358                        domain[0] = 0;
359        }
360
361        if (sa->sa_len == 0)
362                strcpy(line, "default");
363        else switch (sa->sa_family) {
364
365        case AF_INET:
366            {   struct in_addr in;
367                in = ((struct sockaddr_in *)sa)->sin_addr;
368
369                cp = 0;
370                if (in.s_addr == INADDR_ANY || sa->sa_len < 4)
371                        cp = "default";
372                if (cp == 0 && !nflag) {
373                        hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
374                                AF_INET);
375                        if (hp) {
376                                if ((cp = strchr(hp->h_name, '.')) &&
377                                    !strcmp(cp + 1, domain))
378                                        *cp = 0;
379                                cp = hp->h_name;
380                        }
381                }
382                if (cp) {
383                        strncpy(line, cp, sizeof(line) - 1);
384                        line[sizeof(line) - 1] = '\0';
385                } else
386                        (void) sprintf(line, "%s", inet_ntoa(in));
387                break;
388            }
389
390#ifdef INET6
391        case AF_INET6:
392        {
393                struct sockaddr_in6 sin6; /* use static var for safety */
394                int niflags = 0;
395
396                memset(&sin6, 0, sizeof(sin6));
397                memcpy(&sin6, sa, sa->sa_len);
398                sin6.sin6_len = sizeof(struct sockaddr_in6);
399                sin6.sin6_family = AF_INET6;
400#ifdef __KAME__
401                if (sa->sa_len == sizeof(struct sockaddr_in6) &&
402                    (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
403                     IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
404                    sin6.sin6_scope_id == 0) {
405                        sin6.sin6_scope_id =
406                            ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
407                        sin6.sin6_addr.s6_addr[2] = 0;
408                        sin6.sin6_addr.s6_addr[3] = 0;
409                }
410#endif
411                if (nflag)
412                        niflags |= NI_NUMERICHOST;
413                if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
414                    line, sizeof(line), NULL, 0, niflags) != 0)
415                        strncpy(line, "invalid", sizeof(line));
416
417                return(line);
418        }
419#endif
420
421        case AF_APPLETALK:
422                (void) snprintf(line, sizeof(line), "atalk %s",
423                        atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr));
424                break;
425
426        case AF_LINK:
427                return (link_ntoa((struct sockaddr_dl *)sa));
428
429        default:
430            {   u_short *s = (u_short *)sa;
431                u_short *slim = s + ((sa->sa_len + 1) >> 1);
432                char *cp = line + sprintf(line, "(%d)", sa->sa_family);
433                char *cpe = line + sizeof(line);
434
435                while (++s < slim && cp < cpe) /* start with sa->sa_data */
436                        if ((n = snprintf(cp, cpe - cp, " %x", *s)) > 0)
437                                cp += n;
438                        else
439                                *cp = '\0';
440                break;
441            }
442        }
443        return (line);
444}
445
446/*
447 * Return the name of the network whose address is given.
448 * The address is assumed to be that of a net or subnet, not a host.
449 */
450const char *
451netname(sa)
452        struct sockaddr *sa;
453{
454        char *cp = 0;
455        static char line[MAXHOSTNAMELEN + 1];
456        struct netent *np = 0;
457        u_long net, mask;
458        u_long i;
459        int n, subnetshift;
460
461        switch (sa->sa_family) {
462
463        case AF_INET:
464            {   struct in_addr in;
465                in = ((struct sockaddr_in *)sa)->sin_addr;
466
467                i = in.s_addr = ntohl(in.s_addr);
468                if (in.s_addr == 0)
469                        cp = "default";
470                else if (!nflag) {
471                        if (IN_CLASSA(i)) {
472                                mask = IN_CLASSA_NET;
473                                subnetshift = 8;
474                        } else if (IN_CLASSB(i)) {
475                                mask = IN_CLASSB_NET;
476                                subnetshift = 8;
477                        } else {
478                                mask = IN_CLASSC_NET;
479                                subnetshift = 4;
480                        }
481                        /*
482                         * If there are more bits than the standard mask
483                         * would suggest, subnets must be in use.
484                         * Guess at the subnet mask, assuming reasonable
485                         * width subnet fields.
486                         */
487                        while (in.s_addr &~ mask)
488                                mask = (long)mask >> subnetshift;
489                        net = in.s_addr & mask;
490                        while ((mask & 1) == 0)
491                                mask >>= 1, net >>= 1;
492                        np = getnetbyaddr(net, AF_INET);
493                        if (np)
494                                cp = np->n_name;
495                }
496#define C(x)    (unsigned)((x) & 0xff)
497                if (cp)
498                        strncpy(line, cp, sizeof(line));
499                else if ((in.s_addr & 0xffffff) == 0)
500                        (void) sprintf(line, "%u", C(in.s_addr >> 24));
501                else if ((in.s_addr & 0xffff) == 0)
502                        (void) sprintf(line, "%u.%u", C(in.s_addr >> 24),
503                            C(in.s_addr >> 16));
504                else if ((in.s_addr & 0xff) == 0)
505                        (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
506                            C(in.s_addr >> 16), C(in.s_addr >> 8));
507                else
508                        (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
509                            C(in.s_addr >> 16), C(in.s_addr >> 8),
510                            C(in.s_addr));
511#undef C
512                break;
513            }
514
515#ifdef INET6
516        case AF_INET6:
517        {
518                struct sockaddr_in6 sin6; /* use static var for safety */
519                int niflags = 0;
520
521                memset(&sin6, 0, sizeof(sin6));
522                memcpy(&sin6, sa, sa->sa_len);
523                sin6.sin6_len = sizeof(struct sockaddr_in6);
524                sin6.sin6_family = AF_INET6;
525#ifdef __KAME__
526                if (sa->sa_len == sizeof(struct sockaddr_in6) &&
527                    (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
528                     IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
529                    sin6.sin6_scope_id == 0) {
530                        sin6.sin6_scope_id =
531                            ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
532                        sin6.sin6_addr.s6_addr[2] = 0;
533                        sin6.sin6_addr.s6_addr[3] = 0;
534                }
535#endif
536                if (nflag)
537                        niflags |= NI_NUMERICHOST;
538                if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
539                    line, sizeof(line), NULL, 0, niflags) != 0)
540                        strncpy(line, "invalid", sizeof(line));
541
542                return(line);
543        }
544#endif
545
546        case AF_APPLETALK:
547                (void) snprintf(line, sizeof(line), "atalk %s",
548                        atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr));
549                break;
550
551        case AF_LINK:
552                return (link_ntoa((struct sockaddr_dl *)sa));
553
554
555        default:
556            {   u_short *s = (u_short *)sa->sa_data;
557                u_short *slim = s + ((sa->sa_len + 1)>>1);
558                char *cp = line + sprintf(line, "af %d:", sa->sa_family);
559                char *cpe = line + sizeof(line);
560
561                while (s < slim && cp < cpe)
562                        if ((n = snprintf(cp, cpe - cp, " %x", *s++)) > 0)
563                                cp += n;
564                        else
565                                *cp = '\0';
566                break;
567            }
568        }
569        return (line);
570}
571
572void
573set_metric(value, key)
574        char *value;
575        int key;
576{
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        caseof(K_WEIGHT, RTV_WEIGHT, rmx_weight);
591        }
592        rtm_inits |= flag;
593        if (lockrest || locking)
594                rt_metrics.rmx_locks |= flag;
595        if (locking)
596                locking = 0;
597        *valp = atoi(value);
598}
599
600void
601newroute(argc, argv)
602        int argc;
603        char **argv;
604{
605        char *cmd, *dest = "", *gateway = "", *err;
606        int ishost = 0, proxy = 0, ret, attempts, oerrno, flags = RTF_STATIC;
607        int key;
608        struct hostent *hp = 0;
609
610        if (uid) {
611                errx(EX_NOPERM, "must be root to alter routing table");
612        }
613        cmd = argv[0];
614        if (*cmd != 'g' && *cmd != 's')
615                shutdown(s, SHUT_RD); /* Don't want to read back our messages */
616
617        while (--argc > 0) {
618                if (**(++argv)== '-') {
619                        switch (key = keyword(1 + *argv)) {
620                        case K_LINK:
621                                af = AF_LINK;
622                                aflen = sizeof(struct sockaddr_dl);
623                                break;
624                        case K_INET:
625                                af = AF_INET;
626                                aflen = sizeof(struct sockaddr_in);
627                                break;
628#ifdef INET6
629                        case K_INET6:
630                                af = AF_INET6;
631                                aflen = sizeof(struct sockaddr_in6);
632                                break;
633#endif
634                        case K_ATALK:
635                                af = AF_APPLETALK;
636                                aflen = sizeof(struct sockaddr_at);
637                                break;
638                        case K_SA:
639                                af = PF_ROUTE;
640                                aflen = sizeof(union sockunion);
641                                break;
642                        case K_IFACE:
643                        case K_INTERFACE:
644                                iflag++;
645                                break;
646                        case K_NOSTATIC:
647                                flags &= ~RTF_STATIC;
648                                break;
649                        case K_LOCK:
650                                locking = 1;
651                                break;
652                        case K_LOCKREST:
653                                lockrest = 1;
654                                break;
655                        case K_HOST:
656                                forcehost++;
657                                break;
658                        case K_REJECT:
659                                flags |= RTF_REJECT;
660                                break;
661                        case K_BLACKHOLE:
662                                flags |= RTF_BLACKHOLE;
663                                break;
664                        case K_PROTO1:
665                                flags |= RTF_PROTO1;
666                                break;
667                        case K_PROTO2:
668                                flags |= RTF_PROTO2;
669                                break;
670                        case K_PROXY:
671                                proxy = 1;
672                                break;
673                        case K_XRESOLVE:
674                                flags |= RTF_XRESOLVE;
675                                break;
676                        case K_STATIC:
677                                flags |= RTF_STATIC;
678                                break;
679                        case K_STICKY:
680                                flags |= RTF_STICKY;
681                                break;
682                        case K_NOSTICK:
683                                flags &= ~RTF_STICKY;
684                                break;
685                        case K_IFA:
686                                if (!--argc)
687                                        usage((char *)NULL);
688                                (void) getaddr(RTA_IFA, *++argv, 0);
689                                break;
690                        case K_IFP:
691                                if (!--argc)
692                                        usage((char *)NULL);
693                                (void) getaddr(RTA_IFP, *++argv, 0);
694                                break;
695                        case K_GENMASK:
696                                if (!--argc)
697                                        usage((char *)NULL);
698                                (void) getaddr(RTA_GENMASK, *++argv, 0);
699                                break;
700                        case K_GATEWAY:
701                                if (!--argc)
702                                        usage((char *)NULL);
703                                (void) getaddr(RTA_GATEWAY, *++argv, 0);
704                                break;
705                        case K_DST:
706                                if (!--argc)
707                                        usage((char *)NULL);
708                                ishost = getaddr(RTA_DST, *++argv, &hp);
709                                dest = *argv;
710                                break;
711                        case K_NETMASK:
712                                if (!--argc)
713                                        usage((char *)NULL);
714                                (void) getaddr(RTA_NETMASK, *++argv, 0);
715                                /* FALLTHROUGH */
716                        case K_NET:
717                                forcenet++;
718                                break;
719                        case K_PREFIXLEN:
720                                if (!--argc)
721                                        usage((char *)NULL);
722                                if (prefixlen(*++argv) == -1) {
723                                        forcenet = 0;
724                                        ishost = 1;
725                                } else {
726                                        forcenet = 1;
727                                        ishost = 0;
728                                }
729                                break;
730                        case K_MTU:
731                        case K_HOPCOUNT:
732                        case K_EXPIRE:
733                        case K_RECVPIPE:
734                        case K_SENDPIPE:
735                        case K_SSTHRESH:
736                        case K_RTT:
737                        case K_RTTVAR:
738                        case K_WEIGHT:
739                                if (!--argc)
740                                        usage((char *)NULL);
741                                set_metric(*++argv, key);
742                                break;
743                        default:
744                                usage(1+*argv);
745                        }
746                } else {
747                        if ((rtm_addrs & RTA_DST) == 0) {
748                                dest = *argv;
749                                ishost = getaddr(RTA_DST, *argv, &hp);
750                        } else if ((rtm_addrs & RTA_GATEWAY) == 0) {
751                                gateway = *argv;
752                                (void) getaddr(RTA_GATEWAY, *argv, &hp);
753                        } else {
754                                (void) getaddr(RTA_NETMASK, *argv, 0);
755                                forcenet = 1;
756                        }
757                }
758        }
759        if (forcehost) {
760                ishost = 1;
761#ifdef INET6
762                if (af == AF_INET6) {
763                        rtm_addrs &= ~RTA_NETMASK;
764                                memset((void *)&so_mask, 0, sizeof(so_mask));
765                }
766#endif
767        }
768        if (forcenet)
769                ishost = 0;
770        flags |= RTF_UP;
771        if (ishost)
772                flags |= RTF_HOST;
773        if (iflag == 0)
774                flags |= RTF_GATEWAY;
775        if (proxy) {
776                so_dst.sinarp.sin_other = SIN_PROXY;
777                flags |= RTF_ANNOUNCE;
778        }
779        for (attempts = 1; ; attempts++) {
780                errno = 0;
781                if ((ret = rtmsg(*cmd, flags)) == 0)
782                        break;
783                if (errno != ENETUNREACH && errno != ESRCH)
784                        break;
785                if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) {
786                        hp->h_addr_list++;
787                        memmove(&so_gate.sin.sin_addr, hp->h_addr_list[0],
788                            MIN(hp->h_length, sizeof(so_gate.sin.sin_addr)));
789                } else
790                        break;
791        }
792        if (*cmd == 'g' || *cmd == 's')
793                exit(ret != 0);
794        if (!qflag) {
795                oerrno = errno;
796                (void) printf("%s %s %s", cmd, ishost? "host" : "net", dest);
797                if (*gateway) {
798                        (void) printf(": gateway %s", gateway);
799                        if (attempts > 1 && ret == 0 && af == AF_INET)
800                            (void) printf(" (%s)",
801                                inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr));
802                }
803                if (ret == 0) {
804                        (void) printf("\n");
805                } else {
806                        switch (oerrno) {
807                        case ESRCH:
808                                err = "not in table";
809                                break;
810                        case EBUSY:
811                                err = "entry in use";
812                                break;
813                        case ENOBUFS:
814                                err = "not enough memory";
815                                break;
816                        case EADDRINUSE:
817                                /* handle recursion avoidance in rt_setgate() */
818                                err = "gateway uses the same route";
819                                break;
820                        case EEXIST:
821                                err = "route already in table";
822                                break;
823                        default:
824                                err = strerror(oerrno);
825                                break;
826                        }
827                        (void) printf(": %s\n", err);
828                }
829        }
830        exit(ret != 0);
831}
832
833void
834inet_makenetandmask(net, sin, bits)
835        u_long net, bits;
836        struct sockaddr_in *sin;
837{
838        u_long addr, mask = 0;
839        char *cp;
840
841        rtm_addrs |= RTA_NETMASK;
842        /*
843         * XXX: This approach unable to handle 0.0.0.1/32 correctly
844         * as inet_network() converts 0.0.0.1 and 1 equally.
845         */
846        if (net <= 0xff)
847                addr = net << IN_CLASSA_NSHIFT;
848        else if (net <= 0xffff)
849                addr = net << IN_CLASSB_NSHIFT;
850        else if (net <= 0xffffff)
851                addr = net << IN_CLASSC_NSHIFT;
852        else
853                addr = net;
854        /*
855         * If no /xx was specified we must cacluate the
856         * CIDR address.
857         */
858        if ((bits == 0)  && (addr != 0)) {
859                u_long i, j;
860                for(i=0,j=0xff; i<4; i++)  {
861                        if (addr & j) {
862                                break;
863                        }
864                        j <<= 8;
865                }
866                /* i holds the first non zero bit */
867                bits = 32 - (i*8);     
868        }
869        if (bits != 0)
870                mask = 0xffffffff << (32 - bits);
871
872        sin->sin_addr.s_addr = htonl(addr);
873        sin = &so_mask.sin;
874        sin->sin_addr.s_addr = htonl(mask);
875        sin->sin_len = 0;
876        sin->sin_family = 0;
877        cp = (char *)(&sin->sin_addr + 1);
878        while (*--cp == 0 && cp > (char *)sin)
879                ;
880        sin->sin_len = 1 + cp - (char *)sin;
881}
882
883#ifdef INET6
884/*
885 * XXX the function may need more improvement...
886 */
887static int
888inet6_makenetandmask(sin6, plen)
889        struct sockaddr_in6 *sin6;
890        char *plen;
891{
892        struct in6_addr in6;
893
894        if (!plen) {
895                if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
896                    sin6->sin6_scope_id == 0) {
897                        plen = "0";
898                } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) {
899                        /* aggregatable global unicast - RFC2374 */
900                        memset(&in6, 0, sizeof(in6));
901                        if (!memcmp(&sin6->sin6_addr.s6_addr[8],
902                                    &in6.s6_addr[8], 8))
903                                plen = "64";
904                }
905        }
906
907        if (!plen || strcmp(plen, "128") == 0)
908                return 1;
909        rtm_addrs |= RTA_NETMASK;
910        (void)prefixlen(plen);
911        return 0;
912}
913#endif
914
915/*
916 * Interpret an argument as a network address of some kind,
917 * returning 1 if a host address, 0 if a network address.
918 */
919int
920getaddr(which, s, hpp)
921        int which;
922        char *s;
923        struct hostent **hpp;
924{
925        sup su;
926        struct hostent *hp;
927        struct netent *np;
928        u_long val;
929        char *q;
930        int afamily;  /* local copy of af so we can change it */
931
932        if (af == 0) {
933                af = AF_INET;
934                aflen = sizeof(struct sockaddr_in);
935        }
936        afamily = af;
937        rtm_addrs |= which;
938        switch (which) {
939        case RTA_DST:
940                su = &so_dst;
941                break;
942        case RTA_GATEWAY:
943                su = &so_gate;
944                if (iflag) {
945                        struct ifaddrs *ifap, *ifa;
946                        struct sockaddr_dl *sdl = NULL;
947
948                        if (getifaddrs(&ifap))
949                                err(1, "getifaddrs");
950
951                        for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
952                                if (ifa->ifa_addr->sa_family != AF_LINK)
953                                        continue;
954
955                                if (strcmp(s, ifa->ifa_name))
956                                        continue;
957
958                                sdl = (struct sockaddr_dl *)ifa->ifa_addr;
959                        }
960                        /* If we found it, then use it */
961                        if (sdl) {
962                                /*
963                                 * Copy is safe since we have a
964                                 * sockaddr_storage member in sockunion{}.
965                                 * Note that we need to copy before calling
966                                 * freeifaddrs().
967                                 */
968                                memcpy(&su->sdl, sdl, sdl->sdl_len);
969                        }
970                        freeifaddrs(ifap);
971                        if (sdl)
972                                return(1);
973                }
974                break;
975        case RTA_NETMASK:
976                su = &so_mask;
977                break;
978        case RTA_GENMASK:
979                su = &so_genmask;
980                break;
981        case RTA_IFP:
982                su = &so_ifp;
983                afamily = AF_LINK;
984                break;
985        case RTA_IFA:
986                su = &so_ifa;
987                break;
988        default:
989                usage("internal error");
990                /*NOTREACHED*/
991        }
992        su->sa.sa_len = aflen;
993        su->sa.sa_family = afamily; /* cases that don't want it have left already */
994        if (strcmp(s, "default") == 0) {
995                /*
996                 * Default is net 0.0.0.0/0
997                 */
998                switch (which) {
999                case RTA_DST:
1000                        forcenet++;
1001#if 0
1002                        bzero(su, sizeof(*su)); /* for readability */
1003#endif
1004                        (void) getaddr(RTA_NETMASK, s, 0);
1005                        break;
1006#if 0
1007                case RTA_NETMASK:
1008                case RTA_GENMASK:
1009                        bzero(su, sizeof(*su)); /* for readability */
1010#endif
1011                }
1012                return (0);
1013        }
1014        switch (afamily) {
1015#ifdef INET6
1016        case AF_INET6:
1017        {
1018                struct addrinfo hints, *res;
1019                int ecode;
1020
1021                q = NULL;
1022                if (which == RTA_DST && (q = strchr(s, '/')) != NULL)
1023                        *q = '\0';
1024                memset(&hints, 0, sizeof(hints));
1025                hints.ai_family = afamily;      /*AF_INET6*/
1026                hints.ai_socktype = SOCK_DGRAM;         /*dummy*/
1027                ecode = getaddrinfo(s, NULL, &hints, &res);
1028                if (ecode != 0 || res->ai_family != AF_INET6 ||
1029                    res->ai_addrlen != sizeof(su->sin6)) {
1030                        (void) fprintf(stderr, "%s: %s\n", s,
1031                            gai_strerror(ecode));
1032                        exit(1);
1033                }
1034                memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6));
1035#ifdef __KAME__
1036                if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) ||
1037                     IN6_IS_ADDR_MC_LINKLOCAL(&su->sin6.sin6_addr)) &&
1038                    su->sin6.sin6_scope_id) {
1039                        *(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] =
1040                                htons(su->sin6.sin6_scope_id);
1041                        su->sin6.sin6_scope_id = 0;
1042                }
1043#endif
1044                freeaddrinfo(res);
1045                if (q != NULL)
1046                        *q++ = '/';
1047                if (which == RTA_DST)
1048                        return (inet6_makenetandmask(&su->sin6, q));
1049                return (0);
1050        }
1051#endif /* INET6 */
1052
1053        case AF_APPLETALK:
1054                if (!atalk_aton(s, &su->sat.sat_addr))
1055                        errx(EX_NOHOST, "bad address: %s", s);
1056                rtm_addrs |= RTA_NETMASK;
1057                return(forcehost || su->sat.sat_addr.s_node != 0);
1058
1059        case AF_LINK:
1060                link_addr(s, &su->sdl);
1061                return (1);
1062
1063
1064        case PF_ROUTE:
1065                su->sa.sa_len = sizeof(*su);
1066                sockaddr(s, &su->sa);
1067                return (1);
1068
1069        case AF_INET:
1070        default:
1071                break;
1072        }
1073
1074        if (hpp == NULL)
1075                hpp = &hp;
1076        *hpp = NULL;
1077
1078        q = strchr(s,'/');
1079        if (q && which == RTA_DST) {
1080                *q = '\0';
1081                if ((val = inet_network(s)) != INADDR_NONE) {
1082                        inet_makenetandmask(
1083                                val, &su->sin, strtoul(q+1, 0, 0));
1084                        return (0);
1085                }
1086                *q = '/';
1087        }
1088        if ((which != RTA_DST || forcenet == 0) &&
1089            inet_aton(s, &su->sin.sin_addr)) {
1090                val = su->sin.sin_addr.s_addr;
1091                if (which != RTA_DST || forcehost ||
1092                    inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
1093                        return (1);
1094                else {
1095                        val = ntohl(val);
1096                        goto netdone;
1097                }
1098        }
1099        if (which == RTA_DST && forcehost == 0 &&
1100            ((val = inet_network(s)) != INADDR_NONE ||
1101            ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0))) {
1102netdone:
1103                inet_makenetandmask(val, &su->sin, 0);
1104                return (0);
1105        }
1106        hp = gethostbyname(s);
1107        if (hp) {
1108                *hpp = hp;
1109                su->sin.sin_family = hp->h_addrtype;
1110                memmove((char *)&su->sin.sin_addr, hp->h_addr,
1111                    MIN(hp->h_length, sizeof(su->sin.sin_addr)));
1112                return (1);
1113        }
1114        errx(EX_NOHOST, "bad address: %s", s);
1115}
1116
1117int
1118prefixlen(s)
1119        char *s;
1120{
1121        int len = atoi(s), q, r;
1122        int max;
1123        char *p;
1124
1125        rtm_addrs |= RTA_NETMASK;       
1126        switch (af) {
1127#ifdef INET6
1128        case AF_INET6:
1129                max = 128;
1130                p = (char *)&so_mask.sin6.sin6_addr;
1131                break;
1132#endif
1133        case AF_INET:
1134                max = 32;
1135                p = (char *)&so_mask.sin.sin_addr;
1136                break;
1137        default:
1138                (void) fprintf(stderr, "prefixlen not supported in this af\n");
1139                exit(1);
1140                /*NOTREACHED*/
1141        }
1142
1143        if (len < 0 || max < len) {
1144                (void) fprintf(stderr, "%s: bad value\n", s);
1145                exit(1);
1146        }
1147       
1148        q = len >> 3;
1149        r = len & 7;
1150        so_mask.sa.sa_family = af;
1151        so_mask.sa.sa_len = aflen;
1152        memset((void *)p, 0, max / 8);
1153        if (q > 0)
1154                memset((void *)p, 0xff, q);
1155        if (r > 0)
1156                *((u_char *)p + q) = (0xff00 >> r) & 0xff;
1157        if (len == max)
1158                return -1;
1159        else
1160                return len;
1161}
1162
1163void
1164interfaces()
1165{
1166        size_t needed;
1167        int mib[6];
1168        char *buf, *lim, *next, count = 0;
1169        struct rt_msghdr *rtm;
1170
1171retry2:
1172        mib[0] = CTL_NET;
1173        mib[1] = PF_ROUTE;
1174        mib[2] = 0;             /* protocol */
1175        mib[3] = 0;             /* wildcard address family */
1176        mib[4] = NET_RT_IFLIST;
1177        mib[5] = 0;             /* no flags */
1178        if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
1179                err(EX_OSERR, "route-sysctl-estimate");
1180        if ((buf = malloc(needed)) == NULL)
1181                errx(EX_OSERR, "malloc failed");
1182        if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
1183                if (errno == ENOMEM && count++ < 10) {
1184                        warnx("Routing table grew, retrying");
1185                        sleep(1);
1186                        free(buf);
1187                        goto retry2;
1188                }
1189                err(EX_OSERR, "actual retrieval of interface table");
1190        }
1191        lim = buf + needed;
1192        for (next = buf; next < lim; next += rtm->rtm_msglen) {
1193                rtm = (struct rt_msghdr *)next;
1194                print_rtmsg(rtm, rtm->rtm_msglen);
1195        }
1196}
1197
1198void
1199monitor()
1200{
1201        int n;
1202        char msg[2048];
1203
1204        verbose = 1;
1205        if (debugonly) {
1206                interfaces();
1207                exit(0);
1208        }
1209        for(;;) {
1210                time_t now;
1211                n = read(s, msg, 2048);
1212                now = time(NULL);
1213                (void) printf("\ngot message of size %d on %s", n, ctime(&now));
1214                print_rtmsg((struct rt_msghdr *)msg, n);
1215        }
1216}
1217
1218struct {
1219        struct  rt_msghdr m_rtm;
1220        char    m_space[512];
1221} m_rtmsg;
1222
1223int
1224rtmsg(cmd, flags)
1225        int cmd, flags;
1226{
1227        static int seq;
1228        int rlen;
1229        char *cp = m_rtmsg.m_space;
1230        int l;
1231
1232#define NEXTADDR(w, u) \
1233        if (rtm_addrs & (w)) {\
1234            l = SA_SIZE(&(u.sa)); memmove(cp, &(u), l); cp += l;\
1235            if (verbose) sodump(&(u),#u);\
1236        }
1237
1238        errno = 0;
1239        memset(&m_rtmsg, 0, sizeof(m_rtmsg));
1240        if (cmd == 'a')
1241                cmd = RTM_ADD;
1242        else if (cmd == 'c')
1243                cmd = RTM_CHANGE;
1244        else if (cmd == 'g' || cmd == 's') {
1245                cmd = RTM_GET;
1246                if (so_ifp.sa.sa_family == 0) {
1247                        so_ifp.sa.sa_family = AF_LINK;
1248                        so_ifp.sa.sa_len = sizeof(struct sockaddr_dl);
1249                        rtm_addrs |= RTA_IFP;
1250                }
1251        } else
1252                cmd = RTM_DELETE;
1253#define rtm m_rtmsg.m_rtm
1254        rtm.rtm_type = cmd;
1255        rtm.rtm_flags = flags;
1256        rtm.rtm_version = RTM_VERSION;
1257        rtm.rtm_seq = ++seq;
1258        rtm.rtm_addrs = rtm_addrs;
1259        rtm.rtm_rmx = rt_metrics;
1260        rtm.rtm_inits = rtm_inits;
1261
1262        if (rtm_addrs & RTA_NETMASK)
1263                mask_addr();
1264        NEXTADDR(RTA_DST, so_dst);
1265        NEXTADDR(RTA_GATEWAY, so_gate);
1266        NEXTADDR(RTA_NETMASK, so_mask);
1267        NEXTADDR(RTA_GENMASK, so_genmask);
1268        NEXTADDR(RTA_IFP, so_ifp);
1269        NEXTADDR(RTA_IFA, so_ifa);
1270        rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
1271        if (verbose)
1272                print_rtmsg(&rtm, l);
1273        if (debugonly)
1274                return (0);
1275        if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
1276                if (errno == EPERM)
1277                        err(1, "writing to routing socket");
1278                warn("writing to routing socket");
1279                return (-1);
1280        }
1281        if (cmd == RTM_GET) {
1282                do {
1283                        l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
1284                } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
1285                if (l < 0)
1286                        warn("read from routing socket");
1287                else
1288                        print_getmsg(&rtm, l);
1289        }
1290#undef rtm
1291        return (0);
1292}
1293
1294void
1295mask_addr()
1296{
1297        int olen = so_mask.sa.sa_len;
1298        char *cp1 = olen + (char *)&so_mask, *cp2;
1299
1300        for (so_mask.sa.sa_len = 0; cp1 > (char *)&so_mask; )
1301                if (*--cp1 != 0) {
1302                        so_mask.sa.sa_len = 1 + cp1 - (char *)&so_mask;
1303                        break;
1304                }
1305        if ((rtm_addrs & RTA_DST) == 0)
1306                return;
1307        switch (so_dst.sa.sa_family) {
1308        case AF_INET:
1309#ifdef INET6
1310        case AF_INET6:
1311#endif
1312        case AF_APPLETALK:
1313        case 0:
1314                return;
1315        }
1316        cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst;
1317        cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst;
1318        while (cp2 > cp1)
1319                *--cp2 = 0;
1320        cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask;
1321        while (cp1 > so_dst.sa.sa_data)
1322                *--cp1 &= *--cp2;
1323}
1324
1325char *msgtypes[] = {
1326        "",
1327        "RTM_ADD: Add Route",
1328        "RTM_DELETE: Delete Route",
1329        "RTM_CHANGE: Change Metrics or flags",
1330        "RTM_GET: Report Metrics",
1331        "RTM_LOSING: Kernel Suspects Partitioning",
1332        "RTM_REDIRECT: Told to use different route",
1333        "RTM_MISS: Lookup failed on this address",
1334        "RTM_LOCK: fix specified metrics",
1335        "RTM_OLDADD: caused by SIOCADDRT",
1336        "RTM_OLDDEL: caused by SIOCDELRT",
1337        "RTM_RESOLVE: Route created by cloning",
1338        "RTM_NEWADDR: address being added to iface",
1339        "RTM_DELADDR: address being removed from iface",
1340        "RTM_IFINFO: iface status change",
1341        "RTM_NEWMADDR: new multicast group membership on iface",
1342        "RTM_DELMADDR: multicast group membership removed from iface",
1343        "RTM_IFANNOUNCE: interface arrival/departure",
1344        0,
1345};
1346
1347char metricnames[] =
1348"\011weight\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire"
1349"\1mtu";
1350char routeflags[] =
1351"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE"
1352"\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE"
1353"\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3"
1354"\025PINNED\026LOCAL\027BROADCAST\030MULTICAST\035STICKY";
1355char ifnetflags[] =
1356"\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
1357"\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
1358"\017LINK2\020MULTICAST";
1359char addrnames[] =
1360"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
1361
1362void
1363print_rtmsg(rtm, msglen)
1364        struct rt_msghdr *rtm;
1365        int msglen;
1366{
1367        struct if_msghdr *ifm;
1368        struct ifa_msghdr *ifam;
1369#ifdef RTM_NEWMADDR
1370        struct ifma_msghdr *ifmam;
1371#endif
1372        struct if_announcemsghdr *ifan;
1373        char *state;
1374
1375        if (verbose == 0)
1376                return;
1377        if (rtm->rtm_version != RTM_VERSION) {
1378                (void) printf("routing message version %d not understood\n",
1379                    rtm->rtm_version);
1380                return;
1381        }
1382        if (msgtypes[rtm->rtm_type] != NULL)
1383                (void)printf("%s: ", msgtypes[rtm->rtm_type]);
1384        else
1385                (void)printf("#%d: ", rtm->rtm_type);
1386        (void)printf("len %d, ", rtm->rtm_msglen);
1387        switch (rtm->rtm_type) {
1388        case RTM_IFINFO:
1389                ifm = (struct if_msghdr *)rtm;
1390                (void) printf("if# %d, ", ifm->ifm_index);
1391                switch (ifm->ifm_data.ifi_link_state) {
1392                case LINK_STATE_DOWN:
1393                        state = "down";
1394                        break;
1395                case LINK_STATE_UP:
1396                        state = "up";
1397                        break;
1398                default:
1399                        state = "unknown";
1400                        break;
1401                }
1402                (void) printf("link: %s, flags:", state);
1403                bprintf(stdout, ifm->ifm_flags, ifnetflags);
1404                pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
1405                break;
1406        case RTM_NEWADDR:
1407        case RTM_DELADDR:
1408                ifam = (struct ifa_msghdr *)rtm;
1409                (void) printf("metric %d, flags:", ifam->ifam_metric);
1410                bprintf(stdout, ifam->ifam_flags, routeflags);
1411                pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs);
1412                break;
1413#ifdef RTM_NEWMADDR
1414        case RTM_NEWMADDR:
1415        case RTM_DELMADDR:
1416                ifmam = (struct ifma_msghdr *)rtm;
1417                pmsg_addrs((char *)(ifmam + 1), ifmam->ifmam_addrs);
1418                break;
1419#endif
1420        case RTM_IFANNOUNCE:
1421                ifan = (struct if_announcemsghdr *)rtm;
1422                (void) printf("if# %d, what: ", ifan->ifan_index);
1423                switch (ifan->ifan_what) {
1424                case IFAN_ARRIVAL:
1425                        printf("arrival");
1426                        break;
1427                case IFAN_DEPARTURE:
1428                        printf("departure");
1429                        break;
1430                default:
1431                        printf("#%d", ifan->ifan_what);
1432                        break;
1433                }
1434                printf("\n");
1435                break;
1436
1437        default:
1438                (void) printf("pid: %ld, seq %d, errno %d, flags:",
1439                        (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
1440                bprintf(stdout, rtm->rtm_flags, routeflags);
1441                pmsg_common(rtm);
1442        }
1443}
1444
1445void
1446print_getmsg(rtm, msglen)
1447        struct rt_msghdr *rtm;
1448        int msglen;
1449{
1450        struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL;
1451        struct sockaddr_dl *ifp = NULL;
1452        struct sockaddr *sa;
1453        char *cp;
1454        int i;
1455
1456        (void) printf("   route to: %s\n", routename(&so_dst));
1457        if (rtm->rtm_version != RTM_VERSION) {
1458                warnx("routing message version %d not understood",
1459                     rtm->rtm_version);
1460                return;
1461        }
1462        if (rtm->rtm_msglen > msglen) {
1463                warnx("message length mismatch, in packet %d, returned %d",
1464                      rtm->rtm_msglen, msglen);
1465        }
1466        if (rtm->rtm_errno)  {
1467                errno = rtm->rtm_errno;
1468                warn("message indicates error %d", errno);
1469                return;
1470        }
1471        cp = ((char *)(rtm + 1));
1472        if (rtm->rtm_addrs)
1473                for (i = 1; i; i <<= 1)
1474                        if (i & rtm->rtm_addrs) {
1475                                sa = (struct sockaddr *)cp;
1476                                switch (i) {
1477                                case RTA_DST:
1478                                        dst = sa;
1479                                        break;
1480                                case RTA_GATEWAY:
1481                                        gate = sa;
1482                                        break;
1483                                case RTA_NETMASK:
1484                                        mask = sa;
1485                                        break;
1486                                case RTA_IFP:
1487                                        if (sa->sa_family == AF_LINK &&
1488                                           ((struct sockaddr_dl *)sa)->sdl_nlen)
1489                                                ifp = (struct sockaddr_dl *)sa;
1490                                        break;
1491                                }
1492                                cp += SA_SIZE(sa);
1493                        }
1494        if (dst && mask)
1495                mask->sa_family = dst->sa_family;       /* XXX */
1496        if (dst)
1497                (void)printf("destination: %s\n", routename(dst));
1498        if (mask) {
1499                int savenflag = nflag;
1500
1501                nflag = 1;
1502                (void)printf("       mask: %s\n", routename(mask));
1503                nflag = savenflag;
1504        }
1505        if (gate && rtm->rtm_flags & RTF_GATEWAY)
1506                (void)printf("    gateway: %s\n", routename(gate));
1507        if (ifp)
1508                (void)printf("  interface: %.*s\n",
1509                    ifp->sdl_nlen, ifp->sdl_data);
1510        (void)printf("      flags: ");
1511        bprintf(stdout, rtm->rtm_flags, routeflags);
1512
1513#define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
1514#define msec(u) (((u) + 500) / 1000)            /* usec to msec */
1515
1516        (void) printf("\n%s\n", "\
1517 recvpipe  sendpipe  ssthresh  rtt,msec    mtu        weight    expire");
1518        printf("%8ld%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
1519        printf("%8ld%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
1520        printf("%8ld%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
1521        printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
1522        printf("%8ld%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
1523        printf("%8ld%c ", rtm->rtm_rmx.rmx_weight, lock(WEIGHT));
1524        if (rtm->rtm_rmx.rmx_expire)
1525                rtm->rtm_rmx.rmx_expire -= time(0);
1526        printf("%8ld%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
1527#undef lock
1528#undef msec
1529#define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
1530        if (verbose)
1531                pmsg_common(rtm);
1532        else if (rtm->rtm_addrs &~ RTA_IGN) {
1533                (void) printf("sockaddrs: ");
1534                bprintf(stdout, rtm->rtm_addrs, addrnames);
1535                putchar('\n');
1536        }
1537#undef  RTA_IGN
1538}
1539
1540void
1541pmsg_common(rtm)
1542        struct rt_msghdr *rtm;
1543{
1544        (void) printf("\nlocks: ");
1545        bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
1546        (void) printf(" inits: ");
1547        bprintf(stdout, rtm->rtm_inits, metricnames);
1548        pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs);
1549}
1550
1551void
1552pmsg_addrs(cp, addrs)
1553        char    *cp;
1554        int     addrs;
1555{
1556        struct sockaddr *sa;
1557        int i;
1558
1559        if (addrs == 0) {
1560                (void) putchar('\n');
1561                return;
1562        }
1563        (void) printf("\nsockaddrs: ");
1564        bprintf(stdout, addrs, addrnames);
1565        (void) putchar('\n');
1566        for (i = 1; i; i <<= 1)
1567                if (i & addrs) {
1568                        sa = (struct sockaddr *)cp;
1569                        (void) printf(" %s", routename(sa));
1570                        cp += SA_SIZE(sa);
1571                }
1572        (void) putchar('\n');
1573        (void) fflush(stdout);
1574}
1575
1576void
1577bprintf(fp, b, s)
1578        FILE *fp;
1579        int b;
1580        u_char *s;
1581{
1582        int i;
1583        int gotsome = 0;
1584
1585        if (b == 0)
1586                return;
1587        while ((i = *s++) != 0) {
1588                if (b & (1 << (i-1))) {
1589                        if (gotsome == 0)
1590                                i = '<';
1591                        else
1592                                i = ',';
1593                        (void) putc(i, fp);
1594                        gotsome = 1;
1595                        for (; (i = *s) > 32; s++)
1596                                (void) putc(i, fp);
1597                } else
1598                        while (*s > 32)
1599                                s++;
1600        }
1601        if (gotsome)
1602                (void) putc('>', fp);
1603}
1604
1605int
1606keyword(cp)
1607        char *cp;
1608{
1609        struct keytab *kt = keywords;
1610
1611        while (kt->kt_cp && strcmp(kt->kt_cp, cp))
1612                kt++;
1613        return kt->kt_i;
1614}
1615
1616void
1617sodump(su, which)
1618        sup su;
1619        char *which;
1620{
1621        switch (su->sa.sa_family) {
1622        case AF_LINK:
1623                (void) printf("%s: link %s; ",
1624                    which, link_ntoa(&su->sdl));
1625                break;
1626        case AF_INET:
1627                (void) printf("%s: inet %s; ",
1628                    which, inet_ntoa(su->sin.sin_addr));
1629                break;
1630        case AF_APPLETALK:
1631                (void) printf("%s: atalk %s; ",
1632                    which, atalk_ntoa(su->sat.sat_addr));
1633                break;
1634        }
1635        (void) fflush(stdout);
1636}
1637
1638/* States*/
1639#define VIRGIN  0
1640#define GOTONE  1
1641#define GOTTWO  2
1642/* Inputs */
1643#define DIGIT   (4*0)
1644#define END     (4*1)
1645#define DELIM   (4*2)
1646
1647void
1648sockaddr(addr, sa)
1649        char *addr;
1650        struct sockaddr *sa;
1651{
1652        char *cp = (char *)sa;
1653        int size = sa->sa_len;
1654        char *cplim = cp + size;
1655        int byte = 0, state = VIRGIN, new = 0 /* foil gcc */;
1656
1657        memset(cp, 0, size);
1658        cp++;
1659        do {
1660                if ((*addr >= '0') && (*addr <= '9')) {
1661                        new = *addr - '0';
1662                } else if ((*addr >= 'a') && (*addr <= 'f')) {
1663                        new = *addr - 'a' + 10;
1664                } else if ((*addr >= 'A') && (*addr <= 'F')) {
1665                        new = *addr - 'A' + 10;
1666                } else if (*addr == 0)
1667                        state |= END;
1668                else
1669                        state |= DELIM;
1670                addr++;
1671                switch (state /* | INPUT */) {
1672                case GOTTWO | DIGIT:
1673                        *cp++ = byte; /*FALLTHROUGH*/
1674                case VIRGIN | DIGIT:
1675                        state = GOTONE; byte = new; continue;
1676                case GOTONE | DIGIT:
1677                        state = GOTTWO; byte = new + (byte << 4); continue;
1678                default: /* | DELIM */
1679                        state = VIRGIN; *cp++ = byte; byte = 0; continue;
1680                case GOTONE | END:
1681                case GOTTWO | END:
1682                        *cp++ = byte; /* FALLTHROUGH */
1683                case VIRGIN | END:
1684                        break;
1685                }
1686                break;
1687        } while (cp < cplim);
1688        sa->sa_len = cp - (char *)sa;
1689}
1690
1691int
1692atalk_aton(const char *text, struct at_addr *addr)
1693{
1694        u_int net, node;
1695
1696        if (sscanf(text, "%u.%u", &net, &node) != 2
1697            || net > 0xffff || node > 0xff)
1698                return(0);
1699        addr->s_net = htons(net);
1700        addr->s_node = node;
1701        return(1);
1702}
1703
1704char *
1705atalk_ntoa(struct at_addr at)
1706{
1707        static char buf[20];
1708
1709        (void) snprintf(buf, sizeof(buf), "%u.%u", ntohs(at.s_net), at.s_node);
1710        return(buf);
1711}
1712
1713#ifdef __rtems__
1714  #include <rtems/shell.h>
1715
1716  rtems_shell_cmd_t rtems_shell_ROUTE_Command = {
1717    "route",                       /* name */
1718    "route [args]",                /* usage */
1719    "net",                         /* topic */
1720    rtems_shell_main_route,        /* command */
1721    NULL,                          /* alias */
1722    NULL                           /* next */
1723  };
1724#endif
Note: See TracBrowser for help on using the repository browser.