124322Ssklower /* 235551Sbostic * Copyright (c) 1985 The Regents of the University of California. 335551Sbostic * All rights reserved. 424322Ssklower * 535551Sbostic * This file includes significant work done at Cornell University by 635551Sbostic * Bill Nesheim. That work included by permission. 735551Sbostic * 842698Sbostic * %sccs.include.redist.c% 924322Ssklower */ 1024322Ssklower 1124312Ssklower #ifndef lint 12*58928Smckusick static char sccsid[] = "@(#)startup.c 5.13 (Berkeley) 04/01/93"; 1335551Sbostic #endif /* not lint */ 1424312Ssklower 1524312Ssklower /* 1624312Ssklower * Routing Table Management Daemon 1724312Ssklower */ 1824312Ssklower #include "defs.h" 1924312Ssklower #include <sys/ioctl.h> 20*58928Smckusick #include <sys/sysctl.h> 2124312Ssklower #include <net/if.h> 2252623Ssklower #include <net/if_dl.h> 2324312Ssklower #include <nlist.h> 2446705Sbostic #include <stdlib.h> 2524312Ssklower 2624312Ssklower struct interface *ifnet; 2724312Ssklower int lookforinterfaces = 1; 2824312Ssklower int performnlist = 1; 2926170Ssklower int gateway = 0; 3024312Ssklower int externalinterfaces = 0; /* # of remote and local interfaces */ 3124312Ssklower char ether_broadcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 3224312Ssklower 3324312Ssklower 3452623Ssklower void 3552623Ssklower quit(s) 3652623Ssklower char *s; 3752623Ssklower { 3852623Ssklower extern int errno; 3952623Ssklower int sverrno = errno; 4052623Ssklower 4152623Ssklower (void) fprintf(stderr, "route: "); 4252623Ssklower if (s) 4352623Ssklower (void) fprintf(stderr, "%s: ", s); 4452623Ssklower (void) fprintf(stderr, "%s\n", strerror(sverrno)); 4552623Ssklower exit(1); 4652623Ssklower /* NOTREACHED */ 4752623Ssklower } 4852623Ssklower 4952623Ssklower struct rt_addrinfo info; 5052623Ssklower /* Sleazy use of local variables throughout file, warning!!!! */ 5152623Ssklower #define netmask info.rti_info[RTAX_NETMASK] 5252623Ssklower #define ifaaddr info.rti_info[RTAX_IFA] 5352623Ssklower #define brdaddr info.rti_info[RTAX_BRD] 5452623Ssklower 5552623Ssklower #define ROUNDUP(a) \ 5652623Ssklower ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 5752623Ssklower #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 5852623Ssklower 5952623Ssklower void 6052623Ssklower rt_xaddrs(cp, cplim, rtinfo) 6152623Ssklower register caddr_t cp, cplim; 6252623Ssklower register struct rt_addrinfo *rtinfo; 6352623Ssklower { 6452623Ssklower register struct sockaddr *sa; 6552623Ssklower register int i; 6652623Ssklower 6752623Ssklower bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info)); 6852623Ssklower for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { 6952623Ssklower if ((rtinfo->rti_addrs & (1 << i)) == 0) 7052623Ssklower continue; 7152623Ssklower rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; 7252623Ssklower ADVANCE(cp, sa); 7352623Ssklower } 7452623Ssklower } 7552623Ssklower 7624312Ssklower /* 7724317Ssklower * Find the network interfaces which have configured themselves. 7824317Ssklower * If the interface is present but not yet up (for example an 7924312Ssklower * ARPANET IMP), set the lookforinterfaces flag so we'll 8024312Ssklower * come back later and look again. 8124312Ssklower */ 8224312Ssklower ifinit() 8324312Ssklower { 8424317Ssklower struct interface ifs, *ifp; 85*58928Smckusick size_t needed; 86*58928Smckusick int mib[6], no_nsaddr = 0, flags = 0; 8752623Ssklower char *buf, *cplim, *cp; 8852623Ssklower register struct if_msghdr *ifm; 8952623Ssklower register struct ifa_msghdr *ifam; 9052623Ssklower struct sockaddr_dl *sdl; 9124317Ssklower u_long i; 9224312Ssklower 93*58928Smckusick mib[0] = CTL_NET; 94*58928Smckusick mib[1] = PF_ROUTE; 95*58928Smckusick mib[2] = 0; 96*58928Smckusick mib[3] = AF_NS; 97*58928Smckusick mib[4] = NET_RT_IFLIST; 98*58928Smckusick mib[5] = 0; 99*58928Smckusick if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 100*58928Smckusick quit("route-sysctl-estimate"); 10152623Ssklower if ((buf = malloc(needed)) == NULL) 10252623Ssklower quit("malloc"); 103*58928Smckusick if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 10424312Ssklower lookforinterfaces = 0; 105*58928Smckusick cplim = buf + needed; 10652623Ssklower for (cp = buf; cp < cplim; cp += ifm->ifm_msglen) { 10752623Ssklower ifm = (struct if_msghdr *)cp; 10852623Ssklower if (ifm->ifm_type == RTM_IFINFO) { 10952623Ssklower bzero(&ifs, sizeof(ifs)); 11052623Ssklower ifs.int_flags = flags = ifm->ifm_flags | IFF_INTERFACE; 11152623Ssklower if ((flags & IFF_UP) == 0 || no_nsaddr) 11252623Ssklower lookforinterfaces = 1; 11352623Ssklower sdl = (struct sockaddr_dl *) (ifm + 1); 11452623Ssklower sdl->sdl_data[sdl->sdl_nlen] = 0; 11552623Ssklower no_nsaddr = 1; 11624312Ssklower continue; 11724312Ssklower } 11852623Ssklower if (ifm->ifm_type != RTM_NEWADDR) 11952623Ssklower quit("ifinit: out of sync"); 12052623Ssklower if ((flags & IFF_UP) == 0) 12152623Ssklower continue; 12252623Ssklower ifam = (struct ifa_msghdr *)ifm; 12352623Ssklower info.rti_addrs = ifam->ifam_addrs; 12452623Ssklower rt_xaddrs((char *)(ifam + 1), cp + ifam->ifam_msglen, &info); 12552623Ssklower if (ifaaddr == 0) { 12652623Ssklower syslog(LOG_ERR, "%s: (get addr)", sdl->sdl_data); 12752623Ssklower continue; 12852623Ssklower } 12952623Ssklower ifs.int_addr = *ifaaddr; 13024317Ssklower if (ifs.int_addr.sa_family != AF_NS) 13124317Ssklower continue; 13252623Ssklower no_nsaddr = 0; 13352623Ssklower if (ifs.int_flags & IFF_POINTOPOINT) { 13452623Ssklower if (brdaddr == 0) { 13552623Ssklower syslog(LOG_ERR, "%s: (get dstaddr)", 13652623Ssklower sdl->sdl_data); 13752623Ssklower continue; 13824317Ssklower } 13952623Ssklower if (brdaddr->sa_family == AF_UNSPEC) { 14052623Ssklower lookforinterfaces = 1; 14152623Ssklower continue; 14252623Ssklower } 14352623Ssklower ifs.int_dstaddr = *brdaddr; 14424312Ssklower } 14552623Ssklower if (ifs.int_flags & IFF_BROADCAST) { 14652623Ssklower if (brdaddr == 0) { 14752623Ssklower syslog(LOG_ERR, "%s: (get broadaddr)", 14852623Ssklower sdl->sdl_data); 14952623Ssklower continue; 15052623Ssklower } 15152623Ssklower ifs.int_dstaddr = *brdaddr; 15224317Ssklower } 15326170Ssklower /* 15426170Ssklower * already known to us? 15526170Ssklower * what makes a POINTOPOINT if unique is its dst addr, 15626170Ssklower * NOT its source address 15726170Ssklower */ 15826170Ssklower if ( ((ifs.int_flags & IFF_POINTOPOINT) && 15926170Ssklower if_ifwithdstaddr(&ifs.int_dstaddr)) || 16026170Ssklower ( ((ifs.int_flags & IFF_POINTOPOINT) == 0) && 16126170Ssklower if_ifwithaddr(&ifs.int_addr))) 16226170Ssklower continue; 16324317Ssklower /* no one cares about software loopback interfaces */ 16452623Ssklower if (ifs.int_flags & IFF_LOOPBACK) 16524317Ssklower continue; 16652623Ssklower ifp = (struct interface *) 16752623Ssklower malloc(sdl->sdl_nlen + 1 + sizeof(ifs)); 16824312Ssklower if (ifp == 0) { 16952623Ssklower syslog(LOG_ERR, "XNSrouted: out of memory\n"); 17052623Ssklower lookforinterfaces = 1; 17124312Ssklower break; 17224312Ssklower } 17324317Ssklower *ifp = ifs; 17424312Ssklower /* 17524312Ssklower * Count the # of directly connected networks 17624312Ssklower * and point to point links which aren't looped 17724312Ssklower * back to ourself. This is used below to 17824312Ssklower * decide if we should be a routing ``supplier''. 17924312Ssklower */ 18024317Ssklower if ((ifs.int_flags & IFF_POINTOPOINT) == 0 || 18124317Ssklower if_ifwithaddr(&ifs.int_dstaddr) == 0) 18224312Ssklower externalinterfaces++; 18326170Ssklower /* 18426170Ssklower * If we have a point-to-point link, we want to act 18526170Ssklower * as a supplier even if it's our only interface, 18626170Ssklower * as that's the only way our peer on the other end 18726170Ssklower * can tell that the link is up. 18826170Ssklower */ 18926170Ssklower if ((ifs.int_flags & IFF_POINTOPOINT) && supplier < 0) 19026170Ssklower supplier = 1; 19152623Ssklower ifp->int_name = (char *)(ifp + 1); 19252623Ssklower strcpy(ifp->int_name, sdl->sdl_data); 19352623Ssklower ifp->int_metric = ifam->ifam_metric; 19424312Ssklower ifp->int_next = ifnet; 19524312Ssklower ifnet = ifp; 19624312Ssklower traceinit(ifp); 19724312Ssklower addrouteforif(ifp); 19824312Ssklower } 19924312Ssklower if (externalinterfaces > 1 && supplier < 0) 20024312Ssklower supplier = 1; 20152623Ssklower free(buf); 20224312Ssklower } 20324312Ssklower 20424312Ssklower addrouteforif(ifp) 20524312Ssklower struct interface *ifp; 20624312Ssklower { 20724317Ssklower struct sockaddr_ns net; 20824312Ssklower struct sockaddr *dst; 20924312Ssklower int state, metric; 21024312Ssklower struct rt_entry *rt; 21124312Ssklower 21224322Ssklower if (ifp->int_flags & IFF_POINTOPOINT) { 21324322Ssklower int (*match)(); 21424322Ssklower register struct interface *ifp2 = ifnet; 21524322Ssklower register struct interface *ifprev = ifnet; 21624322Ssklower 21724312Ssklower dst = &ifp->int_dstaddr; 21824322Ssklower 21924322Ssklower /* Search for interfaces with the same net */ 22024322Ssklower ifp->int_sq.n = ifp->int_sq.p = &(ifp->int_sq); 22124322Ssklower match = afswitch[dst->sa_family].af_netmatch; 22224322Ssklower if (match) 22324322Ssklower for (ifp2 = ifnet; ifp2; ifp2 =ifp2->int_next) { 22424322Ssklower if (ifp->int_flags & IFF_POINTOPOINT == 0) 22524322Ssklower continue; 22624322Ssklower if ((*match)(&ifp2->int_dstaddr,&ifp->int_dstaddr)) { 22724322Ssklower insque(&ifp2->int_sq,&ifp->int_sq); 22824322Ssklower break; 22924322Ssklower } 23024322Ssklower } 23124322Ssklower } else { 23224317Ssklower dst = &ifp->int_broadaddr; 23324312Ssklower } 23424312Ssklower rt = rtlookup(dst); 23524317Ssklower if (rt) 23624317Ssklower rtdelete(rt); 23726170Ssklower if (tracing) 23826170Ssklower fprintf(stderr, "Adding route to interface %s\n", ifp->int_name); 23926170Ssklower if (ifp->int_transitions++ > 0) 24026170Ssklower syslog(LOG_ERR, "re-installing interface %s", ifp->int_name); 24124312Ssklower rtadd(dst, &ifp->int_addr, ifp->int_metric, 24224312Ssklower ifp->int_flags & (IFF_INTERFACE|IFF_PASSIVE|IFF_REMOTE)); 24324312Ssklower } 24426170Ssklower 245