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*52623Ssklower static char sccsid[] = "@(#)startup.c 5.12 (Berkeley) 02/20/92"; 1335551Sbostic #endif /* not lint */ 1424312Ssklower 1524312Ssklower /* 1624312Ssklower * Routing Table Management Daemon 1724312Ssklower */ 1824312Ssklower #include "defs.h" 1924312Ssklower #include <sys/ioctl.h> 20*52623Ssklower #include <sys/kinfo.h> 2124312Ssklower #include <net/if.h> 22*52623Ssklower #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 34*52623Ssklower void 35*52623Ssklower quit(s) 36*52623Ssklower char *s; 37*52623Ssklower { 38*52623Ssklower extern int errno; 39*52623Ssklower int sverrno = errno; 40*52623Ssklower 41*52623Ssklower (void) fprintf(stderr, "route: "); 42*52623Ssklower if (s) 43*52623Ssklower (void) fprintf(stderr, "%s: ", s); 44*52623Ssklower (void) fprintf(stderr, "%s\n", strerror(sverrno)); 45*52623Ssklower exit(1); 46*52623Ssklower /* NOTREACHED */ 47*52623Ssklower } 48*52623Ssklower 49*52623Ssklower struct rt_addrinfo info; 50*52623Ssklower /* Sleazy use of local variables throughout file, warning!!!! */ 51*52623Ssklower #define netmask info.rti_info[RTAX_NETMASK] 52*52623Ssklower #define ifaaddr info.rti_info[RTAX_IFA] 53*52623Ssklower #define brdaddr info.rti_info[RTAX_BRD] 54*52623Ssklower 55*52623Ssklower #define ROUNDUP(a) \ 56*52623Ssklower ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 57*52623Ssklower #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 58*52623Ssklower 59*52623Ssklower void 60*52623Ssklower rt_xaddrs(cp, cplim, rtinfo) 61*52623Ssklower register caddr_t cp, cplim; 62*52623Ssklower register struct rt_addrinfo *rtinfo; 63*52623Ssklower { 64*52623Ssklower register struct sockaddr *sa; 65*52623Ssklower register int i; 66*52623Ssklower 67*52623Ssklower bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info)); 68*52623Ssklower for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { 69*52623Ssklower if ((rtinfo->rti_addrs & (1 << i)) == 0) 70*52623Ssklower continue; 71*52623Ssklower rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; 72*52623Ssklower ADVANCE(cp, sa); 73*52623Ssklower } 74*52623Ssklower } 75*52623Ssklower 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*52623Ssklower int needed, rlen, no_nsaddr = 0, flags = 0; 86*52623Ssklower char *buf, *cplim, *cp; 87*52623Ssklower register struct if_msghdr *ifm; 88*52623Ssklower register struct ifa_msghdr *ifam; 89*52623Ssklower struct sockaddr_dl *sdl; 9024317Ssklower u_long i; 9124312Ssklower 92*52623Ssklower if ((needed = getkerninfo(KINFO_RT_IFLIST, 0, 0, 0)) < 0) 93*52623Ssklower quit("route-getkerninfo-estimate"); 94*52623Ssklower if ((buf = malloc(needed)) == NULL) 95*52623Ssklower quit("malloc"); 96*52623Ssklower if ((rlen = getkerninfo(KINFO_RT_IFLIST, buf, &needed, 0)) < 0) 97*52623Ssklower quit("actual retrieval of interface table"); 9824312Ssklower lookforinterfaces = 0; 99*52623Ssklower cplim = buf + rlen; 100*52623Ssklower for (cp = buf; cp < cplim; cp += ifm->ifm_msglen) { 101*52623Ssklower ifm = (struct if_msghdr *)cp; 102*52623Ssklower if (ifm->ifm_type == RTM_IFINFO) { 103*52623Ssklower bzero(&ifs, sizeof(ifs)); 104*52623Ssklower ifs.int_flags = flags = ifm->ifm_flags | IFF_INTERFACE; 105*52623Ssklower if ((flags & IFF_UP) == 0 || no_nsaddr) 106*52623Ssklower lookforinterfaces = 1; 107*52623Ssklower sdl = (struct sockaddr_dl *) (ifm + 1); 108*52623Ssklower sdl->sdl_data[sdl->sdl_nlen] = 0; 109*52623Ssklower no_nsaddr = 1; 11024312Ssklower continue; 11124312Ssklower } 112*52623Ssklower if (ifm->ifm_type != RTM_NEWADDR) 113*52623Ssklower quit("ifinit: out of sync"); 114*52623Ssklower if ((flags & IFF_UP) == 0) 115*52623Ssklower continue; 116*52623Ssklower ifam = (struct ifa_msghdr *)ifm; 117*52623Ssklower info.rti_addrs = ifam->ifam_addrs; 118*52623Ssklower rt_xaddrs((char *)(ifam + 1), cp + ifam->ifam_msglen, &info); 119*52623Ssklower if (ifaaddr == 0) { 120*52623Ssklower syslog(LOG_ERR, "%s: (get addr)", sdl->sdl_data); 121*52623Ssklower continue; 122*52623Ssklower } 123*52623Ssklower ifs.int_addr = *ifaaddr; 12424317Ssklower if (ifs.int_addr.sa_family != AF_NS) 12524317Ssklower continue; 126*52623Ssklower no_nsaddr = 0; 127*52623Ssklower if (ifs.int_flags & IFF_POINTOPOINT) { 128*52623Ssklower if (brdaddr == 0) { 129*52623Ssklower syslog(LOG_ERR, "%s: (get dstaddr)", 130*52623Ssklower sdl->sdl_data); 131*52623Ssklower continue; 13224317Ssklower } 133*52623Ssklower if (brdaddr->sa_family == AF_UNSPEC) { 134*52623Ssklower lookforinterfaces = 1; 135*52623Ssklower continue; 136*52623Ssklower } 137*52623Ssklower ifs.int_dstaddr = *brdaddr; 13824312Ssklower } 139*52623Ssklower if (ifs.int_flags & IFF_BROADCAST) { 140*52623Ssklower if (brdaddr == 0) { 141*52623Ssklower syslog(LOG_ERR, "%s: (get broadaddr)", 142*52623Ssklower sdl->sdl_data); 143*52623Ssklower continue; 144*52623Ssklower } 145*52623Ssklower ifs.int_dstaddr = *brdaddr; 14624317Ssklower } 14726170Ssklower /* 14826170Ssklower * already known to us? 14926170Ssklower * what makes a POINTOPOINT if unique is its dst addr, 15026170Ssklower * NOT its source address 15126170Ssklower */ 15226170Ssklower if ( ((ifs.int_flags & IFF_POINTOPOINT) && 15326170Ssklower if_ifwithdstaddr(&ifs.int_dstaddr)) || 15426170Ssklower ( ((ifs.int_flags & IFF_POINTOPOINT) == 0) && 15526170Ssklower if_ifwithaddr(&ifs.int_addr))) 15626170Ssklower continue; 15724317Ssklower /* no one cares about software loopback interfaces */ 158*52623Ssklower if (ifs.int_flags & IFF_LOOPBACK) 15924317Ssklower continue; 160*52623Ssklower ifp = (struct interface *) 161*52623Ssklower malloc(sdl->sdl_nlen + 1 + sizeof(ifs)); 16224312Ssklower if (ifp == 0) { 163*52623Ssklower syslog(LOG_ERR, "XNSrouted: out of memory\n"); 164*52623Ssklower lookforinterfaces = 1; 16524312Ssklower break; 16624312Ssklower } 16724317Ssklower *ifp = ifs; 16824312Ssklower /* 16924312Ssklower * Count the # of directly connected networks 17024312Ssklower * and point to point links which aren't looped 17124312Ssklower * back to ourself. This is used below to 17224312Ssklower * decide if we should be a routing ``supplier''. 17324312Ssklower */ 17424317Ssklower if ((ifs.int_flags & IFF_POINTOPOINT) == 0 || 17524317Ssklower if_ifwithaddr(&ifs.int_dstaddr) == 0) 17624312Ssklower externalinterfaces++; 17726170Ssklower /* 17826170Ssklower * If we have a point-to-point link, we want to act 17926170Ssklower * as a supplier even if it's our only interface, 18026170Ssklower * as that's the only way our peer on the other end 18126170Ssklower * can tell that the link is up. 18226170Ssklower */ 18326170Ssklower if ((ifs.int_flags & IFF_POINTOPOINT) && supplier < 0) 18426170Ssklower supplier = 1; 185*52623Ssklower ifp->int_name = (char *)(ifp + 1); 186*52623Ssklower strcpy(ifp->int_name, sdl->sdl_data); 187*52623Ssklower ifp->int_metric = ifam->ifam_metric; 18824312Ssklower ifp->int_next = ifnet; 18924312Ssklower ifnet = ifp; 19024312Ssklower traceinit(ifp); 19124312Ssklower addrouteforif(ifp); 19224312Ssklower } 19324312Ssklower if (externalinterfaces > 1 && supplier < 0) 19424312Ssklower supplier = 1; 195*52623Ssklower free(buf); 19624312Ssklower } 19724312Ssklower 19824312Ssklower addrouteforif(ifp) 19924312Ssklower struct interface *ifp; 20024312Ssklower { 20124317Ssklower struct sockaddr_ns net; 20224312Ssklower struct sockaddr *dst; 20324312Ssklower int state, metric; 20424312Ssklower struct rt_entry *rt; 20524312Ssklower 20624322Ssklower if (ifp->int_flags & IFF_POINTOPOINT) { 20724322Ssklower int (*match)(); 20824322Ssklower register struct interface *ifp2 = ifnet; 20924322Ssklower register struct interface *ifprev = ifnet; 21024322Ssklower 21124312Ssklower dst = &ifp->int_dstaddr; 21224322Ssklower 21324322Ssklower /* Search for interfaces with the same net */ 21424322Ssklower ifp->int_sq.n = ifp->int_sq.p = &(ifp->int_sq); 21524322Ssklower match = afswitch[dst->sa_family].af_netmatch; 21624322Ssklower if (match) 21724322Ssklower for (ifp2 = ifnet; ifp2; ifp2 =ifp2->int_next) { 21824322Ssklower if (ifp->int_flags & IFF_POINTOPOINT == 0) 21924322Ssklower continue; 22024322Ssklower if ((*match)(&ifp2->int_dstaddr,&ifp->int_dstaddr)) { 22124322Ssklower insque(&ifp2->int_sq,&ifp->int_sq); 22224322Ssklower break; 22324322Ssklower } 22424322Ssklower } 22524322Ssklower } else { 22624317Ssklower dst = &ifp->int_broadaddr; 22724312Ssklower } 22824312Ssklower rt = rtlookup(dst); 22924317Ssklower if (rt) 23024317Ssklower rtdelete(rt); 23126170Ssklower if (tracing) 23226170Ssklower fprintf(stderr, "Adding route to interface %s\n", ifp->int_name); 23326170Ssklower if (ifp->int_transitions++ > 0) 23426170Ssklower syslog(LOG_ERR, "re-installing interface %s", ifp->int_name); 23524312Ssklower rtadd(dst, &ifp->int_addr, ifp->int_metric, 23624312Ssklower ifp->int_flags & (IFF_INTERFACE|IFF_PASSIVE|IFF_REMOTE)); 23724312Ssklower } 23826170Ssklower 239