+#define NEXTADDR(w, u) \
+ if (rtm_addrs & (w)) {\
+ l = ROUNDUP(u.sa.sa_len); bcopy((char *)&(u), cp, l); cp += l;\
+ if (verbose) sodump(&(u),"u");\
+ }
+
+ errno = 0;
+ bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
+ if (cmd == 'a')
+ cmd = RTM_ADD;
+ else if (cmd == 'c')
+ cmd = RTM_CHANGE;
+ else if (cmd == 'g')
+ cmd = RTM_GET;
+ else
+ cmd = RTM_DELETE;
+#define rtm m_rtmsg.m_rtm
+ rtm.rtm_type = cmd;
+ rtm.rtm_flags = flags;
+ rtm.rtm_version = RTM_VERSION;
+ rtm.rtm_seq = ++seq;
+ rtm.rtm_addrs = rtm_addrs;
+ rtm.rtm_rmx = rt_metrics;
+ rtm.rtm_inits = rtm_inits;
+
+ NEXTADDR(RTA_DST, so_dst);
+ NEXTADDR(RTA_GATEWAY, so_gate);
+ NEXTADDR(RTA_NETMASK, so_mask);
+ NEXTADDR(RTA_GENMASK, so_genmask);
+ NEXTADDR(RTA_IFP, so_ifp);
+ NEXTADDR(RTA_IFA, so_ifa);
+ rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
+ if (verbose)
+ print_rtmsg(&rtm, l);
+ if (debugonly)
+ return 0;
+ if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
+ perror("writing to routing socket");
+ return (-1);
+ }
+ if (cmd == RTM_GET) {
+ do {
+ l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
+ } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
+ if (l < 0)
+ (void) fprintf(stderr,
+ "route: read from routing socket: %s\n",
+ strerror(errno));
+ else
+ print_getmsg(&rtm, l);
+ }
+#undef rtm
+ return (0);
+}
+
+char *msgtypes[] = {
+ "",
+ "RTM_ADD: Add Route",
+ "RTM_DELETE: Delete Route",
+ "RTM_CHANGE: Change Metrics or flags",
+ "RTM_GET: Report Metrics",
+ "RTM_LOSING: Kernel Suspects Partitioning",
+ "RTM_REDIRECT: Told to use different route",
+ "RTM_MISS: Lookup failed on this address",
+ "RTM_LOCK: fix specified metrics",
+ "RTM_OLDADD: caused by SIOCADDRT",
+ "RTM_OLDDEL: caused by SIOCDELRT",
+ 0,
+};
+
+char metricnames[] =
+"\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu";
+char routeflags[] =
+"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT\011CLONING\012XRESOLVE";
+
+
+void
+print_rtmsg(rtm, msglen)
+ register struct rt_msghdr *rtm;
+ int msglen;
+{
+ if (verbose == 0)
+ return;
+ if (rtm->rtm_version != RTM_VERSION) {
+ (void) printf("routing message version %d not understood\n",
+ rtm->rtm_version);
+ return;
+ }
+ (void) printf("%s\npid: %d, len %d, seq %d, errno %d, flags:",
+ msgtypes[rtm->rtm_type], rtm->rtm_pid, rtm->rtm_msglen,
+ rtm->rtm_seq, rtm->rtm_errno);
+ bprintf(stdout, rtm->rtm_flags, routeflags);
+ pmsg_common(rtm);
+}
+
+void
+print_getmsg(rtm, msglen)
+ register struct rt_msghdr *rtm;
+ int msglen;
+{
+ if (rtm->rtm_version != RTM_VERSION) {
+ (void)printf("routing message version %d not understood\n",
+ rtm->rtm_version);
+ return;
+ }
+ if (rtm->rtm_msglen > msglen) {
+ (void)printf("get length mismatch, in packet %d, returned %d\n",
+ rtm->rtm_msglen, msglen);
+ }
+ (void) printf("RTM_GET: errno %d, flags:", rtm->rtm_errno);
+ bprintf(stdout, rtm->rtm_flags, routeflags);
+ (void) printf("\nmetric values:\n\n");
+#define metric(f, e) printf("\t%s:\t%d\n", "f", rtm->rtm_rmx.e)
+ metric(RTV_RPIPE, rmx_recvpipe);
+ metric(RTV_SPIPE, rmx_sendpipe);
+ metric(RTV_SSTHRESH, rmx_ssthresh);
+ metric(RTV_RTT, rmx_rtt);
+ metric(RTV_RTTVAR, rmx_rttvar);
+ metric(RTV_HOPCOUNT, rmx_hopcount);
+ metric(RTV_MTU, rmx_mtu);
+ metric(RTV_EXPIRE, rmx_expire);
+#undef metric
+ pmsg_common(rtm);
+}
+
+void
+pmsg_common(rtm)
+ register struct rt_msghdr *rtm;
+{
+ char *cp;
+ register struct sockaddr *sa;
+ int i;
+
+ (void) printf("\nlocks: ");
+ bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
+ (void) printf(" inits: ");
+ bprintf(stdout, rtm->rtm_inits, metricnames);
+ (void) printf("\nsockaddrs: ");
+ bprintf(stdout, rtm->rtm_addrs,
+ "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR");
+ (void) putchar('\n');
+ cp = ((char *)(rtm + 1));
+ if (rtm->rtm_addrs)
+ for (i = 1; i; i <<= 1)
+ if (i & rtm->rtm_addrs) {
+ sa = (struct sockaddr *)cp;
+ (void) printf(" %s", routename(sa));
+ ADVANCE(cp, sa);
+ }
+ (void) putchar('\n');
+ (void) fflush(stdout);
+}
+
+void
+bprintf(fp, b, s)
+ register FILE *fp;
+ register int b;
+ register u_char *s;
+{
+ register int i;
+ int gotsome = 0;
+
+ if (b == 0)
+ return;
+ while (i = *s++) {
+ if (b & (1 << (i-1))) {
+ if (gotsome == 0)
+ i = '<';
+ else
+ i = ',';
+ (void) putc(i, fp);
+ gotsome = 1;
+ for (; (i = *s) > 32; s++)
+ (void) putc(i, fp);
+ } else
+ while (*s > 32)
+ s++;
+ }
+ if (gotsome)
+ (void) putc('>', fp);
+}
+
+int
+keyword(cp)
+ char *cp;
+{
+ register struct keytab *kt = keywords;
+
+ while (kt->kt_cp && strcmp(kt->kt_cp, cp))
+ kt++;
+ return kt->kt_i;
+}
+
+void
+sodump(su, which)
+ register sup su;
+ char *which;
+{
+ switch (su->sa.sa_family) {
+ case AF_LINK:
+ (void) printf("%s: link %s; ",
+ which, link_ntoa(&su->sdl));
+ break;
+ case AF_ISO:
+ (void) printf("%s: iso %s; ",
+ which, iso_ntoa(&su->siso.siso_addr));
+ break;
+ case AF_INET:
+ (void) printf("%s: inet %s; ",
+ which, inet_ntoa(su->sin.sin_addr));
+ break;
+ case AF_NS:
+ (void) printf("%s: xns %s; ",
+ which, ns_ntoa(su->sns.sns_addr));
+ break;