136352Ssklower /* 2*63211Sbostic * Copyright (c) 1988, 1991, 1993 3*63211Sbostic * The Regents of the University of California. All rights reserved. 436352Ssklower * 544466Sbostic * %sccs.include.redist.c% 636352Ssklower * 7*63211Sbostic * @(#)rtsock.c 8.1 (Berkeley) 06/10/93 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/af.h> 2056529Sbostic #include <net/if.h> 2156529Sbostic #include <net/route.h> 2256529Sbostic #include <net/raw_cb.h> 2336352Ssklower 2452564Ssklower struct sockaddr route_dst = { 2, PF_ROUTE, }; 2552564Ssklower struct sockaddr route_src = { 2, PF_ROUTE, }; 2652564Ssklower struct sockproto route_proto = { PF_ROUTE, }; 2737472Ssklower 2852564Ssklower struct walkarg { 2952564Ssklower int w_op, w_arg, w_given, w_needed, w_tmemsize; 3052564Ssklower caddr_t w_where, w_tmem; 3152564Ssklower }; 3252564Ssklower 3361339Sbostic static struct mbuf * 3461339Sbostic rt_msg1 __P((int, struct rt_addrinfo *)); 3561339Sbostic static int rt_msg2 __P((int, 3661339Sbostic struct rt_addrinfo *, caddr_t, struct walkarg *)); 3761339Sbostic static void rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *)); 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; 11236352Ssklower 11340446Ssklower #define senderr(e) { error = e; goto flush;} 11458497Ssklower if (m == 0 || ((m->m_len < sizeof(long)) && 11558497Ssklower (m = m_pullup(m, sizeof(long))) == 0)) 11638847Ssklower return (ENOBUFS); 11736352Ssklower if ((m->m_flags & M_PKTHDR) == 0) 11838847Ssklower panic("route_output"); 11936352Ssklower len = m->m_pkthdr.len; 12044949Ssklower if (len < sizeof(*rtm) || 12152808Sralph len != mtod(m, struct rt_msghdr *)->rtm_msglen) { 12252808Sralph dst = 0; 12340446Ssklower senderr(EINVAL); 12452808Sralph } 12536352Ssklower R_Malloc(rtm, struct rt_msghdr *, len); 12652808Sralph if (rtm == 0) { 12752808Sralph dst = 0; 12840446Ssklower senderr(ENOBUFS); 12952808Sralph } 13036352Ssklower m_copydata(m, 0, len, (caddr_t)rtm); 13152808Sralph if (rtm->rtm_version != RTM_VERSION) { 13252808Sralph dst = 0; 13340446Ssklower senderr(EPROTONOSUPPORT); 13452808Sralph } 13548729Ssklower rtm->rtm_pid = curproc->p_pid; 13652564Ssklower info.rti_addrs = rtm->rtm_addrs; 13752564Ssklower rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info); 13852564Ssklower if (dst == 0) 13940786Ssklower senderr(EINVAL); 14052564Ssklower if (genmask) { 14161339Sbostic struct radix_node *t; 14261339Sbostic t = rn_addmask((caddr_t)genmask, 1, 2); 14343336Ssklower if (t && Bcmp(genmask, t->rn_key, *(u_char *)genmask) == 0) 14443336Ssklower genmask = (struct sockaddr *)(t->rn_key); 14543336Ssklower else 14643336Ssklower senderr(ENOBUFS); 14736352Ssklower } 14836352Ssklower switch (rtm->rtm_type) { 14952564Ssklower 15036352Ssklower case RTM_ADD: 15140786Ssklower if (gate == 0) 15240786Ssklower senderr(EINVAL); 15336352Ssklower error = rtrequest(RTM_ADD, dst, gate, netmask, 15436352Ssklower rtm->rtm_flags, &saved_nrt); 15540786Ssklower if (error == 0 && saved_nrt) { 15640786Ssklower rt_setmetrics(rtm->rtm_inits, 15740786Ssklower &rtm->rtm_rmx, &saved_nrt->rt_rmx); 15840446Ssklower saved_nrt->rt_refcnt--; 15943336Ssklower saved_nrt->rt_genmask = genmask; 16040786Ssklower } 16136352Ssklower break; 16236352Ssklower 16336352Ssklower case RTM_DELETE: 16436352Ssklower error = rtrequest(RTM_DELETE, dst, gate, netmask, 16537472Ssklower rtm->rtm_flags, (struct rtentry **)0); 16636352Ssklower break; 16736352Ssklower 16836352Ssklower case RTM_GET: 16936352Ssklower case RTM_CHANGE: 17036352Ssklower case RTM_LOCK: 17136352Ssklower rt = rtalloc1(dst, 0); 17236352Ssklower if (rt == 0) 17340446Ssklower senderr(ESRCH); 17452656Ssklower if (rtm->rtm_type != RTM_GET) {/* XXX: too grotty */ 17561339Sbostic struct radix_node *rn; 17652656Ssklower extern struct radix_node_head *mask_rnhead; 17752656Ssklower 17847465Ssklower if (Bcmp(dst, rt_key(rt), dst->sa_len) != 0) 17947465Ssklower senderr(ESRCH); 18052656Ssklower if (netmask && (rn = rn_search(netmask, 18159064Ssklower mask_rnhead->rnh_treetop))) 18252656Ssklower netmask = (struct sockaddr *)rn->rn_key; 18352656Ssklower for (rn = rt->rt_nodes; rn; rn = rn->rn_dupedkey) 18452656Ssklower if (netmask == (struct sockaddr *)rn->rn_mask) 18552656Ssklower break; 18652656Ssklower if (rn == 0) 18745183Ssklower senderr(ETOOMANYREFS); 18852656Ssklower rt = (struct rtentry *)rn; 18945183Ssklower } 19036352Ssklower switch(rtm->rtm_type) { 19136352Ssklower 19236352Ssklower case RTM_GET: 19352564Ssklower dst = rt_key(rt); 19452564Ssklower gate = rt->rt_gateway; 19552564Ssklower netmask = rt_mask(rt); 19652564Ssklower genmask = rt->rt_genmask; 19745656Ssklower if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) { 19852564Ssklower if (ifp = rt->rt_ifp) { 19952564Ssklower ifpaddr = ifp->if_addrlist->ifa_addr; 20045656Ssklower ifaaddr = rt->rt_ifa->ifa_addr; 20152564Ssklower rtm->rtm_index = ifp->if_index; 20245656Ssklower } else { 20352564Ssklower ifpaddr = 0; 20452564Ssklower ifaaddr = 0; 20552564Ssklower } 20645656Ssklower } 20752564Ssklower len = rt_msg2(RTM_GET, &info, (caddr_t)0, 20852564Ssklower (struct walkarg *)0); 20936352Ssklower if (len > rtm->rtm_msglen) { 21036352Ssklower struct rt_msghdr *new_rtm; 21136352Ssklower R_Malloc(new_rtm, struct rt_msghdr *, len); 21236352Ssklower if (new_rtm == 0) 21340446Ssklower senderr(ENOBUFS); 21436352Ssklower Bcopy(rtm, new_rtm, rtm->rtm_msglen); 21536352Ssklower Free(rtm); rtm = new_rtm; 21636352Ssklower } 21752564Ssklower (void)rt_msg2(RTM_GET, &info, (caddr_t)rtm, 21852564Ssklower (struct walkarg *)0); 21945183Ssklower rtm->rtm_flags = rt->rt_flags; 22045183Ssklower rtm->rtm_rmx = rt->rt_rmx; 22158495Ssklower rtm->rtm_addrs = info.rti_addrs; 22236352Ssklower break; 22336352Ssklower 22436352Ssklower case RTM_CHANGE: 22550229Ssklower if (gate && rt_setgate(rt, rt_key(rt), gate)) 22640446Ssklower senderr(EDQUOT); 22743336Ssklower /* new gateway could require new ifaddr, ifp; 22843336Ssklower flags may also be different; ifp may be specified 22943336Ssklower by ll sockaddr when protocol address is ambiguous */ 23047465Ssklower if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) && 23147465Ssklower (ifp = ifa->ifa_ifp)) 23247465Ssklower ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate, 23347465Ssklower ifp); 23447465Ssklower else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) || 23547465Ssklower (ifa = ifa_ifwithroute(rt->rt_flags, 23647465Ssklower rt_key(rt), gate))) 23747465Ssklower ifp = ifa->ifa_ifp; 23843336Ssklower if (ifa) { 23947465Ssklower register struct ifaddr *oifa = rt->rt_ifa; 24047465Ssklower if (oifa != ifa) { 24147465Ssklower if (oifa && oifa->ifa_rtrequest) 24247465Ssklower oifa->ifa_rtrequest(RTM_DELETE, 24347465Ssklower rt, gate); 24459064Ssklower IFAFREE(rt->rt_ifa); 24543336Ssklower rt->rt_ifa = ifa; 24659064Ssklower ifa->ifa_refcnt++; 24747465Ssklower rt->rt_ifp = ifp; 24843336Ssklower } 24943336Ssklower } 25047465Ssklower rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, 25147465Ssklower &rt->rt_rmx); 25243336Ssklower if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) 25343336Ssklower rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, gate); 25443336Ssklower if (genmask) 25543336Ssklower rt->rt_genmask = genmask; 25636352Ssklower /* 25736352Ssklower * Fall into 25836352Ssklower */ 25940786Ssklower case RTM_LOCK: 26050811Ssklower rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); 26140786Ssklower rt->rt_rmx.rmx_locks |= 26240786Ssklower (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); 26336352Ssklower break; 26436352Ssklower } 26552564Ssklower break; 26636352Ssklower 26736352Ssklower default: 26840446Ssklower senderr(EOPNOTSUPP); 26936352Ssklower } 27036352Ssklower 27136352Ssklower flush: 27236352Ssklower if (rtm) { 27336352Ssklower if (error) 27436352Ssklower rtm->rtm_errno = error; 27536352Ssklower else 27636352Ssklower rtm->rtm_flags |= RTF_DONE; 27736352Ssklower } 27836352Ssklower cleanup: 27936352Ssklower if (rt) 28036352Ssklower rtfree(rt); 28142356Ssklower { 28242356Ssklower register struct rawcb *rp = 0; 28342356Ssklower /* 28442356Ssklower * Check to see if we don't want our own messages. 28542356Ssklower */ 28642356Ssklower if ((so->so_options & SO_USELOOPBACK) == 0) { 28742356Ssklower if (route_cb.any_count <= 1) { 28842356Ssklower if (rtm) 28942356Ssklower Free(rtm); 29042356Ssklower m_freem(m); 29142356Ssklower return (error); 29242356Ssklower } 29342356Ssklower /* There is another listener, so construct message */ 29442356Ssklower rp = sotorawcb(so); 29542356Ssklower } 29645656Ssklower if (rtm) { 29745656Ssklower m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm); 29838847Ssklower Free(rtm); 29938847Ssklower } 30042356Ssklower if (rp) 30142356Ssklower rp->rcb_proto.sp_family = 0; /* Avoid us */ 30245183Ssklower if (dst) 30345183Ssklower route_proto.sp_protocol = dst->sa_family; 30438847Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 30542356Ssklower if (rp) 30642356Ssklower rp->rcb_proto.sp_family = PF_ROUTE; 30742356Ssklower } 30836352Ssklower return (error); 30936352Ssklower } 31036352Ssklower 31161339Sbostic void 31243336Ssklower rt_setmetrics(which, in, out) 31340786Ssklower u_long which; 31440786Ssklower register struct rt_metrics *in, *out; 31540786Ssklower { 31640786Ssklower #define metric(f, e) if (which & (f)) out->e = in->e; 31740786Ssklower metric(RTV_RPIPE, rmx_recvpipe); 31840786Ssklower metric(RTV_SPIPE, rmx_sendpipe); 31940786Ssklower metric(RTV_SSTHRESH, rmx_ssthresh); 32040786Ssklower metric(RTV_RTT, rmx_rtt); 32140786Ssklower metric(RTV_RTTVAR, rmx_rttvar); 32240786Ssklower metric(RTV_HOPCOUNT, rmx_hopcount); 32340786Ssklower metric(RTV_MTU, rmx_mtu); 32450228Ssklower metric(RTV_EXPIRE, rmx_expire); 32540786Ssklower #undef metric 32640786Ssklower } 32740786Ssklower 32852564Ssklower #define ROUNDUP(a) \ 32952564Ssklower ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 33052564Ssklower #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 33152564Ssklower 33252564Ssklower static void 33352564Ssklower rt_xaddrs(cp, cplim, rtinfo) 33452564Ssklower register caddr_t cp, cplim; 33552564Ssklower register struct rt_addrinfo *rtinfo; 33652564Ssklower { 33752564Ssklower register struct sockaddr *sa; 33852564Ssklower register int i; 33952564Ssklower 34052564Ssklower bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info)); 34152564Ssklower for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { 34252564Ssklower if ((rtinfo->rti_addrs & (1 << i)) == 0) 34352564Ssklower continue; 34452564Ssklower rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; 34552564Ssklower ADVANCE(cp, sa); 34652564Ssklower } 34752564Ssklower } 34852808Sralph 34936352Ssklower /* 35036352Ssklower * Copy data from a buffer back into the indicated mbuf chain, 35136352Ssklower * starting "off" bytes from the beginning, extending the mbuf 35236352Ssklower * chain if necessary. 35336352Ssklower */ 35461339Sbostic void 35536352Ssklower m_copyback(m0, off, len, cp) 35636352Ssklower struct mbuf *m0; 35736352Ssklower register int off; 35836352Ssklower register int len; 35936352Ssklower caddr_t cp; 36036352Ssklower { 36136352Ssklower register int mlen; 36236352Ssklower register struct mbuf *m = m0, *n; 36336352Ssklower int totlen = 0; 36436352Ssklower 36536352Ssklower if (m0 == 0) 36636352Ssklower return; 36748729Ssklower while (off > (mlen = m->m_len)) { 36836352Ssklower off -= mlen; 36936352Ssklower totlen += mlen; 37036352Ssklower if (m->m_next == 0) { 37136352Ssklower n = m_getclr(M_DONTWAIT, m->m_type); 37236352Ssklower if (n == 0) 37336352Ssklower goto out; 37436352Ssklower n->m_len = min(MLEN, len + off); 37536352Ssklower m->m_next = n; 37636352Ssklower } 37736352Ssklower m = m->m_next; 37836352Ssklower } 37936352Ssklower while (len > 0) { 38036352Ssklower mlen = min (m->m_len - off, len); 38137472Ssklower bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen); 38236352Ssklower cp += mlen; 38336352Ssklower len -= mlen; 38436352Ssklower mlen += off; 38536352Ssklower off = 0; 38636352Ssklower totlen += mlen; 38736352Ssklower if (len == 0) 38836352Ssklower break; 38936352Ssklower if (m->m_next == 0) { 39036352Ssklower n = m_get(M_DONTWAIT, m->m_type); 39136352Ssklower if (n == 0) 39236352Ssklower break; 39336352Ssklower n->m_len = min(MLEN, len); 39436352Ssklower m->m_next = n; 39536352Ssklower } 39636352Ssklower m = m->m_next; 39736352Ssklower } 39836352Ssklower out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) 39936352Ssklower m->m_pkthdr.len = totlen; 40036352Ssklower } 40136352Ssklower 40252564Ssklower static struct mbuf * 40352564Ssklower rt_msg1(type, rtinfo) 40452564Ssklower int type; 40552564Ssklower register struct rt_addrinfo *rtinfo; 40636352Ssklower { 40736352Ssklower register struct rt_msghdr *rtm; 40836352Ssklower register struct mbuf *m; 40952564Ssklower register int i; 41052564Ssklower register struct sockaddr *sa; 41152564Ssklower int len, dlen; 41236352Ssklower 41336352Ssklower m = m_gethdr(M_DONTWAIT, MT_DATA); 41436352Ssklower if (m == 0) 41552564Ssklower return (m); 41652564Ssklower switch (type) { 41752564Ssklower 41852564Ssklower case RTM_DELADDR: 41952564Ssklower case RTM_NEWADDR: 42052564Ssklower len = sizeof(struct ifa_msghdr); 42152564Ssklower break; 42252564Ssklower 42352564Ssklower case RTM_IFINFO: 42452564Ssklower len = sizeof(struct if_msghdr); 42552564Ssklower break; 42652564Ssklower 42752564Ssklower default: 42852564Ssklower len = sizeof(struct rt_msghdr); 42952564Ssklower } 43052564Ssklower if (len > MHLEN) 43152564Ssklower panic("rt_msg1"); 43252564Ssklower m->m_pkthdr.len = m->m_len = len; 43336352Ssklower m->m_pkthdr.rcvif = 0; 43436352Ssklower rtm = mtod(m, struct rt_msghdr *); 43552564Ssklower bzero((caddr_t)rtm, len); 43652564Ssklower for (i = 0; i < RTAX_MAX; i++) { 43752564Ssklower if ((sa = rtinfo->rti_info[i]) == NULL) 43852564Ssklower continue; 43952564Ssklower rtinfo->rti_addrs |= (1 << i); 44052564Ssklower dlen = ROUNDUP(sa->sa_len); 44152564Ssklower m_copyback(m, len, dlen, (caddr_t)sa); 44252564Ssklower len += dlen; 44352564Ssklower } 44452564Ssklower if (m->m_pkthdr.len != len) { 44552564Ssklower m_freem(m); 44652564Ssklower return (NULL); 44752564Ssklower } 44836352Ssklower rtm->rtm_msglen = len; 44940786Ssklower rtm->rtm_version = RTM_VERSION; 45036352Ssklower rtm->rtm_type = type; 45152564Ssklower return (m); 45252564Ssklower } 45352564Ssklower 45452564Ssklower static int 45552564Ssklower rt_msg2(type, rtinfo, cp, w) 45652564Ssklower int type; 45752564Ssklower register struct rt_addrinfo *rtinfo; 45852564Ssklower caddr_t cp; 45952564Ssklower struct walkarg *w; 46052564Ssklower { 46152564Ssklower register int i; 46252564Ssklower int len, dlen, second_time = 0; 46352564Ssklower caddr_t cp0; 46452564Ssklower 46552564Ssklower rtinfo->rti_addrs = 0; 46652564Ssklower again: 46752564Ssklower switch (type) { 46852564Ssklower 46952564Ssklower case RTM_DELADDR: 47052564Ssklower case RTM_NEWADDR: 47152564Ssklower len = sizeof(struct ifa_msghdr); 47252564Ssklower break; 47352564Ssklower 47452564Ssklower case RTM_IFINFO: 47552564Ssklower len = sizeof(struct if_msghdr); 47652564Ssklower break; 47752564Ssklower 47852564Ssklower default: 47952564Ssklower len = sizeof(struct rt_msghdr); 48036352Ssklower } 48152564Ssklower if (cp0 = cp) 48252564Ssklower cp += len; 48352564Ssklower for (i = 0; i < RTAX_MAX; i++) { 48452564Ssklower register struct sockaddr *sa; 48552564Ssklower 48652564Ssklower if ((sa = rtinfo->rti_info[i]) == 0) 48752564Ssklower continue; 48852564Ssklower rtinfo->rti_addrs |= (1 << i); 48952564Ssklower dlen = ROUNDUP(sa->sa_len); 49052564Ssklower if (cp) { 49152564Ssklower bcopy((caddr_t)sa, cp, (unsigned)dlen); 49252564Ssklower cp += dlen; 49352564Ssklower } 49436352Ssklower len += dlen; 49536352Ssklower } 49652564Ssklower if (cp == 0 && w != NULL && !second_time) { 49752564Ssklower register struct walkarg *rw = w; 49852564Ssklower 49952564Ssklower rw->w_needed += len; 50052564Ssklower if (rw->w_needed <= 0 && rw->w_where) { 50152564Ssklower if (rw->w_tmemsize < len) { 50252564Ssklower if (rw->w_tmem) 50352564Ssklower free(rw->w_tmem, M_RTABLE); 50452564Ssklower if (rw->w_tmem = (caddr_t) 50552564Ssklower malloc(len, M_RTABLE, M_NOWAIT)) 50652564Ssklower rw->w_tmemsize = len; 50752564Ssklower } 50852564Ssklower if (rw->w_tmem) { 50952564Ssklower cp = rw->w_tmem; 51052564Ssklower second_time = 1; 51152564Ssklower goto again; 51252564Ssklower } else 51352564Ssklower rw->w_where = 0; 51452564Ssklower } 51536352Ssklower } 51652564Ssklower if (cp) { 51752564Ssklower register struct rt_msghdr *rtm = (struct rt_msghdr *)cp0; 51852564Ssklower 51952564Ssklower rtm->rtm_version = RTM_VERSION; 52052564Ssklower rtm->rtm_type = type; 52152564Ssklower rtm->rtm_msglen = len; 52236352Ssklower } 52352564Ssklower return (len); 52452564Ssklower } 52552564Ssklower 52652564Ssklower /* 52752564Ssklower * This routine is called to generate a message from the routing 52852564Ssklower * socket indicating that a redirect has occured, a routing lookup 52952564Ssklower * has failed, or that a protocol has detected timeouts to a particular 53052564Ssklower * destination. 53152564Ssklower */ 53261339Sbostic void 53352564Ssklower rt_missmsg(type, rtinfo, flags, error) 53452564Ssklower int type, flags, error; 53552564Ssklower register struct rt_addrinfo *rtinfo; 53652564Ssklower { 53752564Ssklower register struct rt_msghdr *rtm; 53852564Ssklower register struct mbuf *m; 53952564Ssklower register int i; 54052564Ssklower struct sockaddr *sa = rtinfo->rti_info[RTAX_DST]; 54152564Ssklower 54252564Ssklower if (route_cb.any_count == 0) 54336352Ssklower return; 54452564Ssklower m = rt_msg1(type, rtinfo); 54552564Ssklower if (m == 0) 54652564Ssklower return; 54752564Ssklower rtm = mtod(m, struct rt_msghdr *); 54852564Ssklower rtm->rtm_flags = RTF_DONE | flags; 54937472Ssklower rtm->rtm_errno = error; 55052564Ssklower rtm->rtm_addrs = rtinfo->rti_addrs; 55152564Ssklower route_proto.sp_protocol = sa ? sa->sa_family : 0; 55236352Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 55336352Ssklower } 55436352Ssklower 55552564Ssklower /* 55652564Ssklower * This routine is called to generate a message from the routing 55752564Ssklower * socket indicating that the status of a network interface has changed. 55852564Ssklower */ 55961339Sbostic void 56052564Ssklower rt_ifmsg(ifp) 56152564Ssklower register struct ifnet *ifp; 56252564Ssklower { 56352564Ssklower register struct if_msghdr *ifm; 56452564Ssklower struct mbuf *m; 56552564Ssklower struct rt_addrinfo info; 56652564Ssklower 56752564Ssklower if (route_cb.any_count == 0) 56852564Ssklower return; 56952564Ssklower bzero((caddr_t)&info, sizeof(info)); 57052564Ssklower m = rt_msg1(RTM_IFINFO, &info); 57152564Ssklower if (m == 0) 57252564Ssklower return; 57352564Ssklower ifm = mtod(m, struct if_msghdr *); 57452564Ssklower ifm->ifm_index = ifp->if_index; 57552564Ssklower ifm->ifm_flags = ifp->if_flags; 57652564Ssklower ifm->ifm_data = ifp->if_data; 57752564Ssklower ifm->ifm_addrs = 0; 57852564Ssklower route_proto.sp_protocol = 0; 57952564Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 58052564Ssklower } 58152564Ssklower 58252564Ssklower /* 58352564Ssklower * This is called to generate messages from the routing socket 58452564Ssklower * indicating a network interface has had addresses associated with it. 58552564Ssklower * if we ever reverse the logic and replace messages TO the routing 58652564Ssklower * socket indicate a request to configure interfaces, then it will 58752564Ssklower * be unnecessary as the routing socket will automatically generate 58852564Ssklower * copies of it. 58952564Ssklower */ 59061339Sbostic void 59152564Ssklower rt_newaddrmsg(cmd, ifa, error, rt) 59252564Ssklower int cmd, error; 59352564Ssklower register struct ifaddr *ifa; 59452564Ssklower register struct rtentry *rt; 59552564Ssklower { 59652564Ssklower struct rt_addrinfo info; 59752564Ssklower struct sockaddr *sa; 59852564Ssklower int pass; 59952564Ssklower struct mbuf *m; 60052564Ssklower struct ifnet *ifp = ifa->ifa_ifp; 60152564Ssklower 60252564Ssklower if (route_cb.any_count == 0) 60352564Ssklower return; 60452564Ssklower for (pass = 1; pass < 3; pass++) { 60552564Ssklower bzero((caddr_t)&info, sizeof(info)); 60652564Ssklower if ((cmd == RTM_ADD && pass == 1) || 60752564Ssklower (cmd == RTM_DELETE && pass == 2)) { 60852564Ssklower register struct ifa_msghdr *ifam; 60952564Ssklower int ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR; 61052564Ssklower 61152564Ssklower ifaaddr = sa = ifa->ifa_addr; 61252564Ssklower ifpaddr = ifp->if_addrlist->ifa_addr; 61352564Ssklower netmask = ifa->ifa_netmask; 61452564Ssklower brdaddr = ifa->ifa_dstaddr; 61552564Ssklower if ((m = rt_msg1(ncmd, &info)) == NULL) 61652564Ssklower continue; 61752564Ssklower ifam = mtod(m, struct ifa_msghdr *); 61852564Ssklower ifam->ifam_index = ifp->if_index; 61952564Ssklower ifam->ifam_metric = ifa->ifa_metric; 62054077Ssklower ifam->ifam_flags = ifa->ifa_flags; 62152564Ssklower ifam->ifam_addrs = info.rti_addrs; 62252564Ssklower } 62352564Ssklower if ((cmd == RTM_ADD && pass == 2) || 62452564Ssklower (cmd == RTM_DELETE && pass == 1)) { 62552564Ssklower register struct rt_msghdr *rtm; 62652564Ssklower 62752564Ssklower if (rt == 0) 62852564Ssklower continue; 62952564Ssklower netmask = rt_mask(rt); 63052564Ssklower dst = sa = rt_key(rt); 63152564Ssklower gate = rt->rt_gateway; 63252564Ssklower if ((m = rt_msg1(cmd, &info)) == NULL) 63352564Ssklower continue; 63452564Ssklower rtm = mtod(m, struct rt_msghdr *); 63552564Ssklower rtm->rtm_index = ifp->if_index; 63652564Ssklower rtm->rtm_flags |= rt->rt_flags; 63752564Ssklower rtm->rtm_errno = error; 63852564Ssklower rtm->rtm_addrs = info.rti_addrs; 63952564Ssklower } 64052564Ssklower route_proto.sp_protocol = sa ? sa->sa_family : 0; 64152564Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 64252564Ssklower } 64352564Ssklower } 64452564Ssklower 64536352Ssklower /* 64657836Smckusick * This is used in dumping the kernel table via sysctl(). 64740446Ssklower */ 64861339Sbostic int 64957836Smckusick sysctl_dumpentry(rn, w) 65040446Ssklower struct radix_node *rn; 65140446Ssklower register struct walkarg *w; 65240446Ssklower { 65340446Ssklower register struct sockaddr *sa; 65440446Ssklower register struct rtentry *rt = (struct rtentry *)rn; 65552564Ssklower int n, error = 0, size; 65652564Ssklower struct rt_addrinfo info; 65740446Ssklower 65857836Smckusick if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg)) 65950812Ssklower return 0; 66052564Ssklower bzero((caddr_t)&info, sizeof(info)); 66152564Ssklower dst = rt_key(rt); 66252564Ssklower gate = rt->rt_gateway; 66352564Ssklower netmask = rt_mask(rt); 66452564Ssklower genmask = rt->rt_genmask; 66552564Ssklower size = rt_msg2(RTM_GET, &info, 0, w); 66652564Ssklower if (w->w_where && w->w_tmem) { 66752564Ssklower register struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem; 66840446Ssklower 66952564Ssklower rtm->rtm_flags = rt->rt_flags; 67052564Ssklower rtm->rtm_use = rt->rt_use; 67152564Ssklower rtm->rtm_rmx = rt->rt_rmx; 67252564Ssklower rtm->rtm_index = rt->rt_ifp->if_index; 67352564Ssklower rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0; 67452564Ssklower rtm->rtm_addrs = info.rti_addrs; 67552564Ssklower if (error = copyout((caddr_t)rtm, w->w_where, size)) 67652564Ssklower w->w_where = NULL; 67752564Ssklower else 67852564Ssklower w->w_where += size; 67940446Ssklower } 68052564Ssklower return (error); 68152564Ssklower } 68252564Ssklower 68361339Sbostic int 68457836Smckusick sysctl_iflist(af, w) 68552564Ssklower int af; 68652564Ssklower register struct walkarg *w; 68752564Ssklower { 68852564Ssklower register struct ifnet *ifp; 68952564Ssklower register struct ifaddr *ifa; 69052564Ssklower struct rt_addrinfo info; 69152564Ssklower struct sockaddr *sa; 69252564Ssklower int len, error = 0; 69352564Ssklower 69452564Ssklower bzero((caddr_t)&info, sizeof(info)); 69552564Ssklower for (ifp = ifnet; ifp; ifp = ifp->if_next) { 69652631Ssklower if (w->w_arg && w->w_arg != ifp->if_index) 69752631Ssklower continue; 69852564Ssklower ifa = ifp->if_addrlist; 69952564Ssklower ifpaddr = ifa->ifa_addr; 70052564Ssklower len = rt_msg2(RTM_IFINFO, &info, (caddr_t)0, w); 70152564Ssklower ifpaddr = 0; 70252564Ssklower if (w->w_where && w->w_tmem) { 70352564Ssklower register struct if_msghdr *ifm; 70452564Ssklower 70552564Ssklower ifm = (struct if_msghdr *)w->w_tmem; 70652564Ssklower ifm->ifm_index = ifp->if_index; 70752564Ssklower ifm->ifm_flags = ifp->if_flags; 70852564Ssklower ifm->ifm_data = ifp->if_data; 70952564Ssklower ifm->ifm_addrs = info.rti_addrs; 71052564Ssklower if (error = copyout((caddr_t)ifm, w->w_where, len)) 71152564Ssklower return (error); 71252564Ssklower w->w_where += len; 71352564Ssklower } 71452564Ssklower while (ifa = ifa->ifa_next) { 71552631Ssklower if (af && af != ifa->ifa_addr->sa_family) 71652631Ssklower continue; 71752564Ssklower ifaaddr = ifa->ifa_addr; 71852564Ssklower netmask = ifa->ifa_netmask; 71952564Ssklower brdaddr = ifa->ifa_dstaddr; 72052564Ssklower len = rt_msg2(RTM_NEWADDR, &info, 0, w); 72152564Ssklower if (w->w_where && w->w_tmem) { 72252564Ssklower register struct ifa_msghdr *ifam; 72352564Ssklower 72452564Ssklower ifam = (struct ifa_msghdr *)w->w_tmem; 72552564Ssklower ifam->ifam_index = ifa->ifa_ifp->if_index; 72652564Ssklower ifam->ifam_flags = ifa->ifa_flags; 72752564Ssklower ifam->ifam_metric = ifa->ifa_metric; 72852564Ssklower ifam->ifam_addrs = info.rti_addrs; 72952564Ssklower if (error = copyout(w->w_tmem, w->w_where, len)) 73052564Ssklower return (error); 73152564Ssklower w->w_where += len; 73252564Ssklower } 73352564Ssklower } 73452631Ssklower ifaaddr = netmask = brdaddr = 0; 73552564Ssklower } 73640446Ssklower return (0); 73740446Ssklower } 73840446Ssklower 73961339Sbostic int 74057836Smckusick sysctl_rtable(name, namelen, where, given, new, newlen) 74157836Smckusick int *name; 74257836Smckusick int namelen; 74340446Ssklower caddr_t where; 74458496Sbostic size_t *given; 74557836Smckusick caddr_t *new; 74658496Sbostic size_t newlen; 74740446Ssklower { 74840446Ssklower register struct radix_node_head *rnh; 74952564Ssklower int i, s, error = EINVAL; 75057836Smckusick u_char af; 75140446Ssklower struct walkarg w; 75240446Ssklower 75357836Smckusick if (new) 75457836Smckusick return (EPERM); 75557836Smckusick if (namelen != 3) 75657836Smckusick return (EINVAL); 75757836Smckusick af = name[0]; 75840446Ssklower Bzero(&w, sizeof(w)); 75957836Smckusick w.w_where = where; 76057836Smckusick w.w_given = *given; 76140446Ssklower w.w_needed = 0 - w.w_given; 76257836Smckusick w.w_op = name[1]; 76357836Smckusick w.w_arg = name[2]; 76440446Ssklower 76540446Ssklower s = splnet(); 76657836Smckusick switch (w.w_op) { 76752564Ssklower 76857836Smckusick case NET_RT_DUMP: 76957836Smckusick case NET_RT_FLAGS: 77052564Ssklower for (i = 1; i <= AF_MAX; i++) 77152564Ssklower if ((rnh = rt_tables[i]) && (af == 0 || af == i) && 77259007Ssklower (error = rnh->rnh_walktree(rnh, 77359007Ssklower sysctl_dumpentry, &w))) 77452564Ssklower break; 77552564Ssklower break; 77652564Ssklower 77757836Smckusick case NET_RT_IFLIST: 77857836Smckusick error = sysctl_iflist(af, &w); 77940446Ssklower } 78052564Ssklower splx(s); 78152564Ssklower if (w.w_tmem) 78252564Ssklower free(w.w_tmem, M_RTABLE); 78340446Ssklower w.w_needed += w.w_given; 78457836Smckusick if (where) { 78540446Ssklower *given = w.w_where - where; 78657836Smckusick if (*given < w.w_needed) 78757836Smckusick return (ENOMEM); 78857836Smckusick } else { 78957836Smckusick *given = (11 * w.w_needed) / 10; 79057836Smckusick } 79140446Ssklower return (error); 79240446Ssklower } 79340446Ssklower 79440446Ssklower /* 79536352Ssklower * Definitions of protocols supported in the ROUTE domain. 79636352Ssklower */ 79736352Ssklower 79836352Ssklower extern struct domain routedomain; /* or at least forward */ 79936352Ssklower 80036352Ssklower struct protosw routesw[] = { 80136352Ssklower { SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR, 80236352Ssklower raw_input, route_output, raw_ctlinput, 0, 80336352Ssklower route_usrreq, 80436352Ssklower raw_init, 0, 0, 0, 80557836Smckusick sysctl_rtable, 80636352Ssklower } 80736352Ssklower }; 80836352Ssklower 80936352Ssklower struct domain routedomain = 81054824Ssklower { PF_ROUTE, "route", route_init, 0, 0, 81136352Ssklower routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] }; 812