136352Ssklower /* 263211Sbostic * Copyright (c) 1988, 1991, 1993 363211Sbostic * The Regents of the University of California. All rights reserved. 436352Ssklower * 544466Sbostic * %sccs.include.redist.c% 636352Ssklower * 7*68026Ssklower * @(#)rtsock.c 8.3.2.1 (Berkeley) 12/02/94 836352Ssklower */ 936352Ssklower 1056529Sbostic #include <sys/param.h> 1156529Sbostic #include <sys/systm.h> 1256529Sbostic #include <sys/proc.h> 1356529Sbostic #include <sys/mbuf.h> 1456529Sbostic #include <sys/socket.h> 1556529Sbostic #include <sys/socketvar.h> 1656529Sbostic #include <sys/domain.h> 1756529Sbostic #include <sys/protosw.h> 1836352Ssklower 1956529Sbostic #include <net/if.h> 2056529Sbostic #include <net/route.h> 2156529Sbostic #include <net/raw_cb.h> 2236352Ssklower 2352564Ssklower struct sockaddr route_dst = { 2, PF_ROUTE, }; 2452564Ssklower struct sockaddr route_src = { 2, PF_ROUTE, }; 2552564Ssklower struct sockproto route_proto = { PF_ROUTE, }; 2637472Ssklower 2752564Ssklower struct walkarg { 2852564Ssklower int w_op, w_arg, w_given, w_needed, w_tmemsize; 2952564Ssklower caddr_t w_where, w_tmem; 3052564Ssklower }; 3152564Ssklower 3261339Sbostic static struct mbuf * 3361339Sbostic rt_msg1 __P((int, struct rt_addrinfo *)); 3461339Sbostic static int rt_msg2 __P((int, 3561339Sbostic struct rt_addrinfo *, caddr_t, struct walkarg *)); 36*68026Ssklower caddr_t rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *)); 37*68026Ssklower void m_copyback __P((struct mbuf *, int, int, caddr_t)); 3852564Ssklower 3952564Ssklower /* Sleazy use of local variables throughout file, warning!!!! */ 4052564Ssklower #define dst info.rti_info[RTAX_DST] 4152564Ssklower #define gate info.rti_info[RTAX_GATEWAY] 4252564Ssklower #define netmask info.rti_info[RTAX_NETMASK] 4352564Ssklower #define genmask info.rti_info[RTAX_GENMASK] 4452564Ssklower #define ifpaddr info.rti_info[RTAX_IFP] 4552564Ssklower #define ifaaddr info.rti_info[RTAX_IFA] 4652564Ssklower #define brdaddr info.rti_info[RTAX_BRD] 4752564Ssklower 4836352Ssklower /*ARGSUSED*/ 4961339Sbostic int 5040446Ssklower route_usrreq(so, req, m, nam, control) 5136352Ssklower register struct socket *so; 5236352Ssklower int req; 5340446Ssklower struct mbuf *m, *nam, *control; 5436352Ssklower { 5536352Ssklower register int error = 0; 5636352Ssklower register struct rawcb *rp = sotorawcb(so); 5744949Ssklower int s; 5837472Ssklower if (req == PRU_ATTACH) { 5937472Ssklower MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK); 6037472Ssklower if (so->so_pcb = (caddr_t)rp) 6137472Ssklower bzero(so->so_pcb, sizeof(*rp)); 6237472Ssklower 6337472Ssklower } 6436352Ssklower if (req == PRU_DETACH && rp) { 6536352Ssklower int af = rp->rcb_proto.sp_protocol; 6636352Ssklower if (af == AF_INET) 6736352Ssklower route_cb.ip_count--; 6836352Ssklower else if (af == AF_NS) 6936352Ssklower route_cb.ns_count--; 7036352Ssklower else if (af == AF_ISO) 7136352Ssklower route_cb.iso_count--; 7236352Ssklower route_cb.any_count--; 7336352Ssklower } 7444949Ssklower s = splnet(); 7540446Ssklower error = raw_usrreq(so, req, m, nam, control); 7636352Ssklower rp = sotorawcb(so); 7737472Ssklower if (req == PRU_ATTACH && rp) { 7836352Ssklower int af = rp->rcb_proto.sp_protocol; 7937472Ssklower if (error) { 8037472Ssklower free((caddr_t)rp, M_PCB); 8144949Ssklower splx(s); 8237472Ssklower return (error); 8337472Ssklower } 8436352Ssklower if (af == AF_INET) 8536352Ssklower route_cb.ip_count++; 8636352Ssklower else if (af == AF_NS) 8736352Ssklower route_cb.ns_count++; 8836352Ssklower else if (af == AF_ISO) 8936352Ssklower route_cb.iso_count++; 9037472Ssklower rp->rcb_faddr = &route_src; 9136352Ssklower route_cb.any_count++; 9236352Ssklower soisconnected(so); 9342356Ssklower so->so_options |= SO_USELOOPBACK; 9436352Ssklower } 9544949Ssklower splx(s); 9636352Ssklower return (error); 9736352Ssklower } 9836352Ssklower 9937472Ssklower /*ARGSUSED*/ 10061339Sbostic int 10136352Ssklower route_output(m, so) 10236352Ssklower register struct mbuf *m; 10336352Ssklower struct socket *so; 10436352Ssklower { 10544949Ssklower register struct rt_msghdr *rtm = 0; 10636352Ssklower register struct rtentry *rt = 0; 10740446Ssklower struct rtentry *saved_nrt = 0; 10852564Ssklower struct rt_addrinfo info; 10937472Ssklower int len, error = 0; 11043336Ssklower struct ifnet *ifp = 0; 11147465Ssklower struct ifaddr *ifa = 0; 112*68026Ssklower caddr_t pkthdr; 113*68026Ssklower struct radix_node_head *rnh; 11436352Ssklower 11540446Ssklower #define senderr(e) { error = e; goto flush;} 11658497Ssklower if (m == 0 || ((m->m_len < sizeof(long)) && 11758497Ssklower (m = m_pullup(m, sizeof(long))) == 0)) 11838847Ssklower return (ENOBUFS); 11936352Ssklower if ((m->m_flags & M_PKTHDR) == 0) 12038847Ssklower panic("route_output"); 12136352Ssklower len = m->m_pkthdr.len; 12244949Ssklower if (len < sizeof(*rtm) || 12352808Sralph len != mtod(m, struct rt_msghdr *)->rtm_msglen) { 12452808Sralph dst = 0; 12540446Ssklower senderr(EINVAL); 12652808Sralph } 12736352Ssklower R_Malloc(rtm, struct rt_msghdr *, len); 12852808Sralph if (rtm == 0) { 12952808Sralph dst = 0; 13040446Ssklower senderr(ENOBUFS); 13152808Sralph } 13236352Ssklower m_copydata(m, 0, len, (caddr_t)rtm); 13352808Sralph if (rtm->rtm_version != RTM_VERSION) { 13452808Sralph dst = 0; 13540446Ssklower senderr(EPROTONOSUPPORT); 13652808Sralph } 13748729Ssklower rtm->rtm_pid = curproc->p_pid; 13852564Ssklower info.rti_addrs = rtm->rtm_addrs; 139*68026Ssklower pkthdr = rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info); 140*68026Ssklower info.rti_flags = rtm->rtm_flags; 14152564Ssklower if (dst == 0) 14240786Ssklower senderr(EINVAL); 14352564Ssklower if (genmask) { 14461339Sbostic struct radix_node *t; 145*68026Ssklower t = rn_addmask((caddr_t)genmask, 1, 2); 14643336Ssklower if (t && Bcmp(genmask, t->rn_key, *(u_char *)genmask) == 0) 14743336Ssklower genmask = (struct sockaddr *)(t->rn_key); 14843336Ssklower else 14943336Ssklower senderr(ENOBUFS); 15036352Ssklower } 15136352Ssklower switch (rtm->rtm_type) { 15252564Ssklower 15336352Ssklower case RTM_ADD: 15440786Ssklower if (gate == 0) 15540786Ssklower senderr(EINVAL); 156*68026Ssklower error = rtrequest1(RTM_ADD, &info, &saved_nrt); 157*68026Ssklower goto add_metrics; 158*68026Ssklower 159*68026Ssklower case RTM_ADDPKT: 160*68026Ssklower if ((rnh = rt_tables[dst->sa_family]) == 0 || 161*68026Ssklower rnh->rnh_addpkt == 0) 162*68026Ssklower senderr(EAFNOSUPPORT); 163*68026Ssklower error = rnh->rnh_addpkt(pkthdr, &info, rnh, 164*68026Ssklower saved_nrt->rt_nodes); 165*68026Ssklower add_metrics: 16640786Ssklower if (error == 0 && saved_nrt) { 16740786Ssklower rt_setmetrics(rtm->rtm_inits, 16840786Ssklower &rtm->rtm_rmx, &saved_nrt->rt_rmx); 16940446Ssklower saved_nrt->rt_refcnt--; 17043336Ssklower saved_nrt->rt_genmask = genmask; 17140786Ssklower } 17236352Ssklower break; 17336352Ssklower 174*68026Ssklower case RTM_DELPKT: 175*68026Ssklower if ((rnh = rt_tables[dst->sa_family]) == 0 || 176*68026Ssklower rnh->rnh_delpkt == 0) 177*68026Ssklower senderr(EAFNOSUPPORT); 178*68026Ssklower error = rnh->rnh_delpkt(pkthdr, &info, rnh); 179*68026Ssklower 18036352Ssklower case RTM_DELETE: 181*68026Ssklower error = rtrequest1(RTM_DELETE, &info, (struct rtentry **)0); 18236352Ssklower break; 18336352Ssklower 184*68026Ssklower case RTM_CHANGE: 18536352Ssklower case RTM_GET: 18636352Ssklower case RTM_LOCK: 187*68026Ssklower rt = rtalloc1(dst, 0); 188*68026Ssklower if (rt == 0) 18940446Ssklower senderr(ESRCH); 190*68026Ssklower if (rtm->rtm_type != RTM_GET) {/* XXX: too grotty */ 191*68026Ssklower struct radix_node *rn; 192*68026Ssklower extern struct radix_node_head *mask_rnhead; 193*68026Ssklower 194*68026Ssklower if (Bcmp(dst, rt_key(rt), dst->sa_len) != 0) 195*68026Ssklower senderr(ESRCH); 196*68026Ssklower if (netmask && (rn = rn_search(netmask, 197*68026Ssklower mask_rnhead->rnh_treetop))) 198*68026Ssklower netmask = (struct sockaddr *)rn->rn_key; 199*68026Ssklower for (rn = rt->rt_nodes; rn; rn = rn->rn_dupedkey) 200*68026Ssklower if (netmask == (struct sockaddr *)rn->rn_mask) 201*68026Ssklower break; 202*68026Ssklower if (rn == 0) 203*68026Ssklower senderr(ETOOMANYREFS); 204*68026Ssklower rt = (struct rtentry *)rn; 205*68026Ssklower } 20636352Ssklower switch(rtm->rtm_type) { 20736352Ssklower 20836352Ssklower case RTM_GET: 20952564Ssklower dst = rt_key(rt); 21052564Ssklower gate = rt->rt_gateway; 21152564Ssklower netmask = rt_mask(rt); 21252564Ssklower genmask = rt->rt_genmask; 21345656Ssklower if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) { 21452564Ssklower if (ifp = rt->rt_ifp) { 21552564Ssklower ifpaddr = ifp->if_addrlist->ifa_addr; 21645656Ssklower ifaaddr = rt->rt_ifa->ifa_addr; 21752564Ssklower rtm->rtm_index = ifp->if_index; 21845656Ssklower } else { 21952564Ssklower ifpaddr = 0; 22052564Ssklower ifaaddr = 0; 22152564Ssklower } 22245656Ssklower } 223*68026Ssklower len = rt_msg2(RTM_GET, &info, (caddr_t)0, 22452564Ssklower (struct walkarg *)0); 22536352Ssklower if (len > rtm->rtm_msglen) { 22636352Ssklower struct rt_msghdr *new_rtm; 22736352Ssklower R_Malloc(new_rtm, struct rt_msghdr *, len); 22836352Ssklower if (new_rtm == 0) 22940446Ssklower senderr(ENOBUFS); 23036352Ssklower Bcopy(rtm, new_rtm, rtm->rtm_msglen); 23136352Ssklower Free(rtm); rtm = new_rtm; 23236352Ssklower } 233*68026Ssklower (void)rt_msg2(RTM_GET, &info, (caddr_t)rtm, 23452564Ssklower (struct walkarg *)0); 23545183Ssklower rtm->rtm_flags = rt->rt_flags; 23645183Ssklower rtm->rtm_rmx = rt->rt_rmx; 23758495Ssklower rtm->rtm_addrs = info.rti_addrs; 23836352Ssklower break; 23936352Ssklower 24036352Ssklower case RTM_CHANGE: 24150229Ssklower if (gate && rt_setgate(rt, rt_key(rt), gate)) 24240446Ssklower senderr(EDQUOT); 24343336Ssklower /* new gateway could require new ifaddr, ifp; 24443336Ssklower flags may also be different; ifp may be specified 24543336Ssklower by ll sockaddr when protocol address is ambiguous */ 24647465Ssklower if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) && 24747465Ssklower (ifp = ifa->ifa_ifp)) 24847465Ssklower ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate, 24947465Ssklower ifp); 25047465Ssklower else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) || 25147465Ssklower (ifa = ifa_ifwithroute(rt->rt_flags, 25247465Ssklower rt_key(rt), gate))) 25347465Ssklower ifp = ifa->ifa_ifp; 25443336Ssklower if (ifa) { 25547465Ssklower register struct ifaddr *oifa = rt->rt_ifa; 25647465Ssklower if (oifa != ifa) { 25747465Ssklower if (oifa && oifa->ifa_rtrequest) 25847465Ssklower oifa->ifa_rtrequest(RTM_DELETE, 25947465Ssklower rt, gate); 26059064Ssklower IFAFREE(rt->rt_ifa); 26143336Ssklower rt->rt_ifa = ifa; 26259064Ssklower ifa->ifa_refcnt++; 26347465Ssklower rt->rt_ifp = ifp; 26443336Ssklower } 26543336Ssklower } 26647465Ssklower rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, 26747465Ssklower &rt->rt_rmx); 26843336Ssklower if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) 26943336Ssklower rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, gate); 27043336Ssklower if (genmask) 27143336Ssklower rt->rt_genmask = genmask; 27236352Ssklower /* 27336352Ssklower * Fall into 27436352Ssklower */ 27540786Ssklower case RTM_LOCK: 27650811Ssklower rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); 27740786Ssklower rt->rt_rmx.rmx_locks |= 27840786Ssklower (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); 27936352Ssklower break; 28036352Ssklower } 28152564Ssklower break; 28236352Ssklower 28336352Ssklower default: 28440446Ssklower senderr(EOPNOTSUPP); 28536352Ssklower } 28636352Ssklower 28736352Ssklower flush: 28836352Ssklower if (rtm) { 28936352Ssklower if (error) 29036352Ssklower rtm->rtm_errno = error; 29136352Ssklower else 29236352Ssklower rtm->rtm_flags |= RTF_DONE; 29336352Ssklower } 294*68026Ssklower cleanup: 29536352Ssklower if (rt) 29636352Ssklower rtfree(rt); 29742356Ssklower { 29842356Ssklower register struct rawcb *rp = 0; 29942356Ssklower /* 30042356Ssklower * Check to see if we don't want our own messages. 30142356Ssklower */ 30242356Ssklower if ((so->so_options & SO_USELOOPBACK) == 0) { 30342356Ssklower if (route_cb.any_count <= 1) { 30442356Ssklower if (rtm) 30542356Ssklower Free(rtm); 30642356Ssklower m_freem(m); 30742356Ssklower return (error); 30842356Ssklower } 30942356Ssklower /* There is another listener, so construct message */ 31042356Ssklower rp = sotorawcb(so); 31142356Ssklower } 31245656Ssklower if (rtm) { 31345656Ssklower m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm); 31438847Ssklower Free(rtm); 31538847Ssklower } 31642356Ssklower if (rp) 31742356Ssklower rp->rcb_proto.sp_family = 0; /* Avoid us */ 31845183Ssklower if (dst) 31945183Ssklower route_proto.sp_protocol = dst->sa_family; 32038847Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 32142356Ssklower if (rp) 32242356Ssklower rp->rcb_proto.sp_family = PF_ROUTE; 32342356Ssklower } 32436352Ssklower return (error); 32536352Ssklower } 32636352Ssklower 32761339Sbostic void 32843336Ssklower rt_setmetrics(which, in, out) 32940786Ssklower u_long which; 33040786Ssklower register struct rt_metrics *in, *out; 33140786Ssklower { 33240786Ssklower #define metric(f, e) if (which & (f)) out->e = in->e; 33340786Ssklower metric(RTV_RPIPE, rmx_recvpipe); 33440786Ssklower metric(RTV_SPIPE, rmx_sendpipe); 33540786Ssklower metric(RTV_SSTHRESH, rmx_ssthresh); 33640786Ssklower metric(RTV_RTT, rmx_rtt); 33740786Ssklower metric(RTV_RTTVAR, rmx_rttvar); 33840786Ssklower metric(RTV_HOPCOUNT, rmx_hopcount); 33940786Ssklower metric(RTV_MTU, rmx_mtu); 34050228Ssklower metric(RTV_EXPIRE, rmx_expire); 34140786Ssklower #undef metric 34240786Ssklower } 34340786Ssklower 34452564Ssklower #define ROUNDUP(a) \ 34552564Ssklower ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 34652564Ssklower #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 34752564Ssklower 348*68026Ssklower caddr_t 34952564Ssklower rt_xaddrs(cp, cplim, rtinfo) 35052564Ssklower register caddr_t cp, cplim; 35152564Ssklower register struct rt_addrinfo *rtinfo; 35252564Ssklower { 35352564Ssklower register struct sockaddr *sa; 35452564Ssklower register int i; 355*68026Ssklower caddr_t cp0 = cp; 35652564Ssklower 35752564Ssklower bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info)); 35852564Ssklower for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { 35952564Ssklower if ((rtinfo->rti_addrs & (1 << i)) == 0) 36052564Ssklower continue; 36152564Ssklower rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; 36252564Ssklower ADVANCE(cp, sa); 36352564Ssklower } 364*68026Ssklower return cp; 36552564Ssklower } 36652808Sralph 36736352Ssklower /* 36836352Ssklower * Copy data from a buffer back into the indicated mbuf chain, 36936352Ssklower * starting "off" bytes from the beginning, extending the mbuf 37036352Ssklower * chain if necessary. 37136352Ssklower */ 37261339Sbostic void 37336352Ssklower m_copyback(m0, off, len, cp) 37436352Ssklower struct mbuf *m0; 37536352Ssklower register int off; 37636352Ssklower register int len; 37736352Ssklower caddr_t cp; 37836352Ssklower { 37936352Ssklower register int mlen; 38036352Ssklower register struct mbuf *m = m0, *n; 38136352Ssklower int totlen = 0; 38236352Ssklower 38336352Ssklower if (m0 == 0) 38436352Ssklower return; 38548729Ssklower while (off > (mlen = m->m_len)) { 38636352Ssklower off -= mlen; 38736352Ssklower totlen += mlen; 38836352Ssklower if (m->m_next == 0) { 38936352Ssklower n = m_getclr(M_DONTWAIT, m->m_type); 39036352Ssklower if (n == 0) 39136352Ssklower goto out; 39236352Ssklower n->m_len = min(MLEN, len + off); 39336352Ssklower m->m_next = n; 39436352Ssklower } 39536352Ssklower m = m->m_next; 39636352Ssklower } 39736352Ssklower while (len > 0) { 39836352Ssklower mlen = min (m->m_len - off, len); 39937472Ssklower bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen); 40036352Ssklower cp += mlen; 40136352Ssklower len -= mlen; 40236352Ssklower mlen += off; 40336352Ssklower off = 0; 40436352Ssklower totlen += mlen; 40536352Ssklower if (len == 0) 40636352Ssklower break; 40736352Ssklower if (m->m_next == 0) { 40836352Ssklower n = m_get(M_DONTWAIT, m->m_type); 40936352Ssklower if (n == 0) 41036352Ssklower break; 41136352Ssklower n->m_len = min(MLEN, len); 41236352Ssklower m->m_next = n; 41336352Ssklower } 41436352Ssklower m = m->m_next; 41536352Ssklower } 41636352Ssklower out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) 41736352Ssklower m->m_pkthdr.len = totlen; 41836352Ssklower } 41936352Ssklower 42052564Ssklower static struct mbuf * 42152564Ssklower rt_msg1(type, rtinfo) 42252564Ssklower int type; 42352564Ssklower register struct rt_addrinfo *rtinfo; 42436352Ssklower { 42536352Ssklower register struct rt_msghdr *rtm; 42636352Ssklower register struct mbuf *m; 42752564Ssklower register int i; 42852564Ssklower register struct sockaddr *sa; 42952564Ssklower int len, dlen; 43036352Ssklower 43136352Ssklower m = m_gethdr(M_DONTWAIT, MT_DATA); 43236352Ssklower if (m == 0) 43352564Ssklower return (m); 43452564Ssklower switch (type) { 43552564Ssklower 43652564Ssklower case RTM_DELADDR: 43752564Ssklower case RTM_NEWADDR: 43852564Ssklower len = sizeof(struct ifa_msghdr); 43952564Ssklower break; 44052564Ssklower 44152564Ssklower case RTM_IFINFO: 44252564Ssklower len = sizeof(struct if_msghdr); 44352564Ssklower break; 44452564Ssklower 44552564Ssklower default: 44652564Ssklower len = sizeof(struct rt_msghdr); 44752564Ssklower } 44852564Ssklower if (len > MHLEN) 44952564Ssklower panic("rt_msg1"); 45052564Ssklower m->m_pkthdr.len = m->m_len = len; 45136352Ssklower m->m_pkthdr.rcvif = 0; 45236352Ssklower rtm = mtod(m, struct rt_msghdr *); 45352564Ssklower bzero((caddr_t)rtm, len); 45452564Ssklower for (i = 0; i < RTAX_MAX; i++) { 45552564Ssklower if ((sa = rtinfo->rti_info[i]) == NULL) 45652564Ssklower continue; 45752564Ssklower rtinfo->rti_addrs |= (1 << i); 45852564Ssklower dlen = ROUNDUP(sa->sa_len); 45952564Ssklower m_copyback(m, len, dlen, (caddr_t)sa); 46052564Ssklower len += dlen; 46152564Ssklower } 46252564Ssklower if (m->m_pkthdr.len != len) { 46352564Ssklower m_freem(m); 46452564Ssklower return (NULL); 46552564Ssklower } 46636352Ssklower rtm->rtm_msglen = len; 46740786Ssklower rtm->rtm_version = RTM_VERSION; 46836352Ssklower rtm->rtm_type = type; 46952564Ssklower return (m); 47052564Ssklower } 47152564Ssklower 47252564Ssklower static int 47352564Ssklower rt_msg2(type, rtinfo, cp, w) 47452564Ssklower int type; 47552564Ssklower register struct rt_addrinfo *rtinfo; 47652564Ssklower caddr_t cp; 47752564Ssklower struct walkarg *w; 47852564Ssklower { 47952564Ssklower register int i; 48052564Ssklower int len, dlen, second_time = 0; 48152564Ssklower caddr_t cp0; 48252564Ssklower 48352564Ssklower rtinfo->rti_addrs = 0; 48452564Ssklower again: 48552564Ssklower switch (type) { 48652564Ssklower 48752564Ssklower case RTM_DELADDR: 48852564Ssklower case RTM_NEWADDR: 48952564Ssklower len = sizeof(struct ifa_msghdr); 49052564Ssklower break; 49152564Ssklower 49252564Ssklower case RTM_IFINFO: 49352564Ssklower len = sizeof(struct if_msghdr); 49452564Ssklower break; 49552564Ssklower 49652564Ssklower default: 49752564Ssklower len = sizeof(struct rt_msghdr); 49836352Ssklower } 49952564Ssklower if (cp0 = cp) 50052564Ssklower cp += len; 50152564Ssklower for (i = 0; i < RTAX_MAX; i++) { 50252564Ssklower register struct sockaddr *sa; 50352564Ssklower 50452564Ssklower if ((sa = rtinfo->rti_info[i]) == 0) 50552564Ssklower continue; 50652564Ssklower rtinfo->rti_addrs |= (1 << i); 50752564Ssklower dlen = ROUNDUP(sa->sa_len); 50852564Ssklower if (cp) { 50952564Ssklower bcopy((caddr_t)sa, cp, (unsigned)dlen); 51052564Ssklower cp += dlen; 51152564Ssklower } 51236352Ssklower len += dlen; 51336352Ssklower } 51452564Ssklower if (cp == 0 && w != NULL && !second_time) { 51552564Ssklower register struct walkarg *rw = w; 51652564Ssklower 51752564Ssklower rw->w_needed += len; 51852564Ssklower if (rw->w_needed <= 0 && rw->w_where) { 51952564Ssklower if (rw->w_tmemsize < len) { 52052564Ssklower if (rw->w_tmem) 52152564Ssklower free(rw->w_tmem, M_RTABLE); 52252564Ssklower if (rw->w_tmem = (caddr_t) 52352564Ssklower malloc(len, M_RTABLE, M_NOWAIT)) 52452564Ssklower rw->w_tmemsize = len; 52552564Ssklower } 52652564Ssklower if (rw->w_tmem) { 52752564Ssklower cp = rw->w_tmem; 52852564Ssklower second_time = 1; 52952564Ssklower goto again; 53052564Ssklower } else 53152564Ssklower rw->w_where = 0; 53252564Ssklower } 53336352Ssklower } 53452564Ssklower if (cp) { 53552564Ssklower register struct rt_msghdr *rtm = (struct rt_msghdr *)cp0; 53652564Ssklower 53752564Ssklower rtm->rtm_version = RTM_VERSION; 53852564Ssklower rtm->rtm_type = type; 53952564Ssklower rtm->rtm_msglen = len; 54036352Ssklower } 54152564Ssklower return (len); 54252564Ssklower } 54352564Ssklower 54452564Ssklower /* 54552564Ssklower * This routine is called to generate a message from the routing 54652564Ssklower * socket indicating that a redirect has occured, a routing lookup 54752564Ssklower * has failed, or that a protocol has detected timeouts to a particular 54852564Ssklower * destination. 54952564Ssklower */ 55061339Sbostic void 55152564Ssklower rt_missmsg(type, rtinfo, flags, error) 55252564Ssklower int type, flags, error; 55352564Ssklower register struct rt_addrinfo *rtinfo; 55452564Ssklower { 55552564Ssklower register struct rt_msghdr *rtm; 55652564Ssklower register struct mbuf *m; 557*68026Ssklower register int i; 55852564Ssklower struct sockaddr *sa = rtinfo->rti_info[RTAX_DST]; 55952564Ssklower 56052564Ssklower if (route_cb.any_count == 0) 56136352Ssklower return; 56252564Ssklower m = rt_msg1(type, rtinfo); 56352564Ssklower if (m == 0) 56452564Ssklower return; 56552564Ssklower rtm = mtod(m, struct rt_msghdr *); 56652564Ssklower rtm->rtm_flags = RTF_DONE | flags; 56737472Ssklower rtm->rtm_errno = error; 56852564Ssklower rtm->rtm_addrs = rtinfo->rti_addrs; 56952564Ssklower route_proto.sp_protocol = sa ? sa->sa_family : 0; 57036352Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 57136352Ssklower } 57236352Ssklower 57352564Ssklower /* 57452564Ssklower * This routine is called to generate a message from the routing 57552564Ssklower * socket indicating that the status of a network interface has changed. 57652564Ssklower */ 57761339Sbostic void 57852564Ssklower rt_ifmsg(ifp) 57952564Ssklower register struct ifnet *ifp; 58052564Ssklower { 58152564Ssklower register struct if_msghdr *ifm; 58252564Ssklower struct mbuf *m; 58352564Ssklower struct rt_addrinfo info; 58452564Ssklower 58552564Ssklower if (route_cb.any_count == 0) 58652564Ssklower return; 58752564Ssklower bzero((caddr_t)&info, sizeof(info)); 58852564Ssklower m = rt_msg1(RTM_IFINFO, &info); 58952564Ssklower if (m == 0) 59052564Ssklower return; 59152564Ssklower ifm = mtod(m, struct if_msghdr *); 59252564Ssklower ifm->ifm_index = ifp->if_index; 59352564Ssklower ifm->ifm_flags = ifp->if_flags; 59452564Ssklower ifm->ifm_data = ifp->if_data; 59552564Ssklower ifm->ifm_addrs = 0; 59652564Ssklower route_proto.sp_protocol = 0; 59752564Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 59852564Ssklower } 59952564Ssklower 60052564Ssklower /* 60152564Ssklower * This is called to generate messages from the routing socket 60252564Ssklower * indicating a network interface has had addresses associated with it. 60352564Ssklower * if we ever reverse the logic and replace messages TO the routing 60452564Ssklower * socket indicate a request to configure interfaces, then it will 60552564Ssklower * be unnecessary as the routing socket will automatically generate 60652564Ssklower * copies of it. 60752564Ssklower */ 60861339Sbostic void 60952564Ssklower rt_newaddrmsg(cmd, ifa, error, rt) 61052564Ssklower int cmd, error; 61152564Ssklower register struct ifaddr *ifa; 61252564Ssklower register struct rtentry *rt; 61352564Ssklower { 61452564Ssklower struct rt_addrinfo info; 61552564Ssklower struct sockaddr *sa; 61652564Ssklower int pass; 61752564Ssklower struct mbuf *m; 61852564Ssklower struct ifnet *ifp = ifa->ifa_ifp; 61952564Ssklower 62052564Ssklower if (route_cb.any_count == 0) 62152564Ssklower return; 62252564Ssklower for (pass = 1; pass < 3; pass++) { 62352564Ssklower bzero((caddr_t)&info, sizeof(info)); 62452564Ssklower if ((cmd == RTM_ADD && pass == 1) || 62552564Ssklower (cmd == RTM_DELETE && pass == 2)) { 62652564Ssklower register struct ifa_msghdr *ifam; 62752564Ssklower int ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR; 62852564Ssklower 62952564Ssklower ifaaddr = sa = ifa->ifa_addr; 63052564Ssklower ifpaddr = ifp->if_addrlist->ifa_addr; 63152564Ssklower netmask = ifa->ifa_netmask; 63252564Ssklower brdaddr = ifa->ifa_dstaddr; 63352564Ssklower if ((m = rt_msg1(ncmd, &info)) == NULL) 63452564Ssklower continue; 63552564Ssklower ifam = mtod(m, struct ifa_msghdr *); 63652564Ssklower ifam->ifam_index = ifp->if_index; 63752564Ssklower ifam->ifam_metric = ifa->ifa_metric; 63854077Ssklower ifam->ifam_flags = ifa->ifa_flags; 63952564Ssklower ifam->ifam_addrs = info.rti_addrs; 64052564Ssklower } 64152564Ssklower if ((cmd == RTM_ADD && pass == 2) || 64252564Ssklower (cmd == RTM_DELETE && pass == 1)) { 64352564Ssklower register struct rt_msghdr *rtm; 64452564Ssklower 64552564Ssklower if (rt == 0) 64652564Ssklower continue; 64752564Ssklower netmask = rt_mask(rt); 64852564Ssklower dst = sa = rt_key(rt); 64952564Ssklower gate = rt->rt_gateway; 65052564Ssklower if ((m = rt_msg1(cmd, &info)) == NULL) 65152564Ssklower continue; 65252564Ssklower rtm = mtod(m, struct rt_msghdr *); 65352564Ssklower rtm->rtm_index = ifp->if_index; 65452564Ssklower rtm->rtm_flags |= rt->rt_flags; 65552564Ssklower rtm->rtm_errno = error; 65652564Ssklower rtm->rtm_addrs = info.rti_addrs; 65752564Ssklower } 65852564Ssklower route_proto.sp_protocol = sa ? sa->sa_family : 0; 65952564Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 66052564Ssklower } 66152564Ssklower } 66252564Ssklower 66336352Ssklower /* 66457836Smckusick * This is used in dumping the kernel table via sysctl(). 66540446Ssklower */ 66661339Sbostic int 66757836Smckusick sysctl_dumpentry(rn, w) 66840446Ssklower struct radix_node *rn; 66940446Ssklower register struct walkarg *w; 67040446Ssklower { 671*68026Ssklower register struct sockaddr *sa; 67240446Ssklower register struct rtentry *rt = (struct rtentry *)rn; 673*68026Ssklower int n, error = 0, size; 67452564Ssklower struct rt_addrinfo info; 67540446Ssklower 67657836Smckusick if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg)) 67750812Ssklower return 0; 67852564Ssklower bzero((caddr_t)&info, sizeof(info)); 67952564Ssklower dst = rt_key(rt); 68052564Ssklower gate = rt->rt_gateway; 68152564Ssklower netmask = rt_mask(rt); 68252564Ssklower genmask = rt->rt_genmask; 68352564Ssklower size = rt_msg2(RTM_GET, &info, 0, w); 68452564Ssklower if (w->w_where && w->w_tmem) { 68552564Ssklower register struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem; 68640446Ssklower 68752564Ssklower rtm->rtm_flags = rt->rt_flags; 68852564Ssklower rtm->rtm_use = rt->rt_use; 68952564Ssklower rtm->rtm_rmx = rt->rt_rmx; 69052564Ssklower rtm->rtm_index = rt->rt_ifp->if_index; 69152564Ssklower rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0; 69252564Ssklower rtm->rtm_addrs = info.rti_addrs; 69352564Ssklower if (error = copyout((caddr_t)rtm, w->w_where, size)) 69452564Ssklower w->w_where = NULL; 69552564Ssklower else 69652564Ssklower w->w_where += size; 69740446Ssklower } 69852564Ssklower return (error); 69952564Ssklower } 70052564Ssklower 70161339Sbostic int 70257836Smckusick sysctl_iflist(af, w) 70352564Ssklower int af; 70452564Ssklower register struct walkarg *w; 70552564Ssklower { 70652564Ssklower register struct ifnet *ifp; 70752564Ssklower register struct ifaddr *ifa; 70852564Ssklower struct rt_addrinfo info; 709*68026Ssklower struct sockaddr *sa; 71052564Ssklower int len, error = 0; 71152564Ssklower 71252564Ssklower bzero((caddr_t)&info, sizeof(info)); 71352564Ssklower for (ifp = ifnet; ifp; ifp = ifp->if_next) { 71452631Ssklower if (w->w_arg && w->w_arg != ifp->if_index) 71552631Ssklower continue; 71652564Ssklower ifa = ifp->if_addrlist; 71752564Ssklower ifpaddr = ifa->ifa_addr; 71852564Ssklower len = rt_msg2(RTM_IFINFO, &info, (caddr_t)0, w); 71952564Ssklower ifpaddr = 0; 72052564Ssklower if (w->w_where && w->w_tmem) { 72152564Ssklower register struct if_msghdr *ifm; 72252564Ssklower 72352564Ssklower ifm = (struct if_msghdr *)w->w_tmem; 72452564Ssklower ifm->ifm_index = ifp->if_index; 72552564Ssklower ifm->ifm_flags = ifp->if_flags; 72652564Ssklower ifm->ifm_data = ifp->if_data; 72752564Ssklower ifm->ifm_addrs = info.rti_addrs; 72852564Ssklower if (error = copyout((caddr_t)ifm, w->w_where, len)) 72952564Ssklower return (error); 73052564Ssklower w->w_where += len; 73152564Ssklower } 73252564Ssklower while (ifa = ifa->ifa_next) { 73352631Ssklower if (af && af != ifa->ifa_addr->sa_family) 73452631Ssklower continue; 73552564Ssklower ifaaddr = ifa->ifa_addr; 73652564Ssklower netmask = ifa->ifa_netmask; 73752564Ssklower brdaddr = ifa->ifa_dstaddr; 73852564Ssklower len = rt_msg2(RTM_NEWADDR, &info, 0, w); 73952564Ssklower if (w->w_where && w->w_tmem) { 74052564Ssklower register struct ifa_msghdr *ifam; 74152564Ssklower 74252564Ssklower ifam = (struct ifa_msghdr *)w->w_tmem; 74352564Ssklower ifam->ifam_index = ifa->ifa_ifp->if_index; 74452564Ssklower ifam->ifam_flags = ifa->ifa_flags; 74552564Ssklower ifam->ifam_metric = ifa->ifa_metric; 74652564Ssklower ifam->ifam_addrs = info.rti_addrs; 74752564Ssklower if (error = copyout(w->w_tmem, w->w_where, len)) 74852564Ssklower return (error); 74952564Ssklower w->w_where += len; 75052564Ssklower } 75152564Ssklower } 75252631Ssklower ifaaddr = netmask = brdaddr = 0; 75352564Ssklower } 75440446Ssklower return (0); 75540446Ssklower } 75640446Ssklower 75761339Sbostic int 75857836Smckusick sysctl_rtable(name, namelen, where, given, new, newlen) 75957836Smckusick int *name; 76057836Smckusick int namelen; 76140446Ssklower caddr_t where; 76258496Sbostic size_t *given; 76357836Smckusick caddr_t *new; 76458496Sbostic size_t newlen; 76540446Ssklower { 76640446Ssklower register struct radix_node_head *rnh; 76752564Ssklower int i, s, error = EINVAL; 76857836Smckusick u_char af; 76940446Ssklower struct walkarg w; 77040446Ssklower 77157836Smckusick if (new) 77257836Smckusick return (EPERM); 77357836Smckusick if (namelen != 3) 77457836Smckusick return (EINVAL); 77557836Smckusick af = name[0]; 77640446Ssklower Bzero(&w, sizeof(w)); 77757836Smckusick w.w_where = where; 77857836Smckusick w.w_given = *given; 77940446Ssklower w.w_needed = 0 - w.w_given; 78057836Smckusick w.w_op = name[1]; 78157836Smckusick w.w_arg = name[2]; 78240446Ssklower 78340446Ssklower s = splnet(); 78457836Smckusick switch (w.w_op) { 78552564Ssklower 78657836Smckusick case NET_RT_DUMP: 78757836Smckusick case NET_RT_FLAGS: 78852564Ssklower for (i = 1; i <= AF_MAX; i++) 78952564Ssklower if ((rnh = rt_tables[i]) && (af == 0 || af == i) && 79059007Ssklower (error = rnh->rnh_walktree(rnh, 79159007Ssklower sysctl_dumpentry, &w))) 79252564Ssklower break; 79352564Ssklower break; 79452564Ssklower 79557836Smckusick case NET_RT_IFLIST: 79657836Smckusick error = sysctl_iflist(af, &w); 79740446Ssklower } 79852564Ssklower splx(s); 79952564Ssklower if (w.w_tmem) 80052564Ssklower free(w.w_tmem, M_RTABLE); 80140446Ssklower w.w_needed += w.w_given; 80257836Smckusick if (where) { 80340446Ssklower *given = w.w_where - where; 80457836Smckusick if (*given < w.w_needed) 80557836Smckusick return (ENOMEM); 80657836Smckusick } else { 80757836Smckusick *given = (11 * w.w_needed) / 10; 80857836Smckusick } 80940446Ssklower return (error); 81040446Ssklower } 81140446Ssklower 81240446Ssklower /* 81336352Ssklower * Definitions of protocols supported in the ROUTE domain. 81436352Ssklower */ 81536352Ssklower 81636352Ssklower extern struct domain routedomain; /* or at least forward */ 81736352Ssklower 81836352Ssklower struct protosw routesw[] = { 81936352Ssklower { SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR, 82036352Ssklower raw_input, route_output, raw_ctlinput, 0, 82136352Ssklower route_usrreq, 82236352Ssklower raw_init, 0, 0, 0, 82357836Smckusick sysctl_rtable, 82436352Ssklower } 82536352Ssklower }; 82636352Ssklower 82736352Ssklower struct domain routedomain = 82854824Ssklower { PF_ROUTE, "route", route_init, 0, 0, 82936352Ssklower routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] }; 830