136352Ssklower /* 250228Ssklower * Copyright (c) 1988, 1991 Regents of the University of California. 336352Ssklower * All rights reserved. 436352Ssklower * 544466Sbostic * %sccs.include.redist.c% 636352Ssklower * 7*57836Smckusick * @(#)rtsock.c 7.32 (Berkeley) 02/04/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 3352564Ssklower static void rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *)); 3452564Ssklower static struct mbuf *rt_msg1 __P((int, struct rt_addrinfo *)); 3552564Ssklower static int rt_msg2 __P((int, struct rt_addrinfo *, caddr_t, 3652564Ssklower struct walkarg *)); 3752564Ssklower 3852564Ssklower /* Sleazy use of local variables throughout file, warning!!!! */ 3952564Ssklower #define dst info.rti_info[RTAX_DST] 4052564Ssklower #define gate info.rti_info[RTAX_GATEWAY] 4152564Ssklower #define netmask info.rti_info[RTAX_NETMASK] 4252564Ssklower #define genmask info.rti_info[RTAX_GENMASK] 4352564Ssklower #define ifpaddr info.rti_info[RTAX_IFP] 4452564Ssklower #define ifaaddr info.rti_info[RTAX_IFA] 4552564Ssklower #define brdaddr info.rti_info[RTAX_BRD] 4652564Ssklower 4736352Ssklower /*ARGSUSED*/ 4840446Ssklower route_usrreq(so, req, m, nam, control) 4936352Ssklower register struct socket *so; 5036352Ssklower int req; 5140446Ssklower struct mbuf *m, *nam, *control; 5236352Ssklower { 5336352Ssklower register int error = 0; 5436352Ssklower register struct rawcb *rp = sotorawcb(so); 5544949Ssklower int s; 5637472Ssklower if (req == PRU_ATTACH) { 5737472Ssklower MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK); 5837472Ssklower if (so->so_pcb = (caddr_t)rp) 5937472Ssklower bzero(so->so_pcb, sizeof(*rp)); 6037472Ssklower 6137472Ssklower } 6236352Ssklower if (req == PRU_DETACH && rp) { 6336352Ssklower int af = rp->rcb_proto.sp_protocol; 6436352Ssklower if (af == AF_INET) 6536352Ssklower route_cb.ip_count--; 6636352Ssklower else if (af == AF_NS) 6736352Ssklower route_cb.ns_count--; 6836352Ssklower else if (af == AF_ISO) 6936352Ssklower route_cb.iso_count--; 7036352Ssklower route_cb.any_count--; 7136352Ssklower } 7244949Ssklower s = splnet(); 7340446Ssklower error = raw_usrreq(so, req, m, nam, control); 7436352Ssklower rp = sotorawcb(so); 7537472Ssklower if (req == PRU_ATTACH && rp) { 7636352Ssklower int af = rp->rcb_proto.sp_protocol; 7737472Ssklower if (error) { 7837472Ssklower free((caddr_t)rp, M_PCB); 7944949Ssklower splx(s); 8037472Ssklower return (error); 8137472Ssklower } 8236352Ssklower if (af == AF_INET) 8336352Ssklower route_cb.ip_count++; 8436352Ssklower else if (af == AF_NS) 8536352Ssklower route_cb.ns_count++; 8636352Ssklower else if (af == AF_ISO) 8736352Ssklower route_cb.iso_count++; 8837472Ssklower rp->rcb_faddr = &route_src; 8936352Ssklower route_cb.any_count++; 9036352Ssklower soisconnected(so); 9142356Ssklower so->so_options |= SO_USELOOPBACK; 9236352Ssklower } 9344949Ssklower splx(s); 9436352Ssklower return (error); 9536352Ssklower } 9636352Ssklower 9737472Ssklower /*ARGSUSED*/ 9836352Ssklower route_output(m, so) 9936352Ssklower register struct mbuf *m; 10036352Ssklower struct socket *so; 10136352Ssklower { 10244949Ssklower register struct rt_msghdr *rtm = 0; 10336352Ssklower register struct rtentry *rt = 0; 10440446Ssklower struct rtentry *saved_nrt = 0; 10552564Ssklower struct rt_addrinfo info; 10637472Ssklower int len, error = 0; 10743336Ssklower struct ifnet *ifp = 0; 10847465Ssklower struct ifaddr *ifa = 0; 10947465Ssklower struct ifaddr *ifaof_ifpforaddr(), *ifa_ifwithroute(); 11036352Ssklower 11140446Ssklower #define senderr(e) { error = e; goto flush;} 11240786Ssklower if (m == 0 || m->m_len < sizeof(long)) 11338847Ssklower return (ENOBUFS); 11440786Ssklower if ((m = m_pullup(m, sizeof(long))) == 0) 11540786Ssklower return (ENOBUFS); 11636352Ssklower if ((m->m_flags & M_PKTHDR) == 0) 11738847Ssklower panic("route_output"); 11836352Ssklower len = m->m_pkthdr.len; 11944949Ssklower if (len < sizeof(*rtm) || 12052808Sralph len != mtod(m, struct rt_msghdr *)->rtm_msglen) { 12152808Sralph dst = 0; 12240446Ssklower senderr(EINVAL); 12352808Sralph } 12436352Ssklower R_Malloc(rtm, struct rt_msghdr *, len); 12552808Sralph if (rtm == 0) { 12652808Sralph dst = 0; 12740446Ssklower senderr(ENOBUFS); 12852808Sralph } 12936352Ssklower m_copydata(m, 0, len, (caddr_t)rtm); 13052808Sralph if (rtm->rtm_version != RTM_VERSION) { 13152808Sralph dst = 0; 13240446Ssklower senderr(EPROTONOSUPPORT); 13352808Sralph } 13448729Ssklower rtm->rtm_pid = curproc->p_pid; 13552564Ssklower info.rti_addrs = rtm->rtm_addrs; 13652564Ssklower rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info); 13752564Ssklower if (dst == 0) 13840786Ssklower senderr(EINVAL); 13952564Ssklower if (genmask) { 14043336Ssklower struct radix_node *t, *rn_addmask(); 14143336Ssklower t = rn_addmask(genmask, 1, 2); 14243336Ssklower if (t && Bcmp(genmask, t->rn_key, *(u_char *)genmask) == 0) 14343336Ssklower genmask = (struct sockaddr *)(t->rn_key); 14443336Ssklower else 14543336Ssklower senderr(ENOBUFS); 14636352Ssklower } 14736352Ssklower switch (rtm->rtm_type) { 14852564Ssklower 14936352Ssklower case RTM_ADD: 15040786Ssklower if (gate == 0) 15140786Ssklower senderr(EINVAL); 15236352Ssklower error = rtrequest(RTM_ADD, dst, gate, netmask, 15336352Ssklower rtm->rtm_flags, &saved_nrt); 15440786Ssklower if (error == 0 && saved_nrt) { 15540786Ssklower rt_setmetrics(rtm->rtm_inits, 15640786Ssklower &rtm->rtm_rmx, &saved_nrt->rt_rmx); 15740446Ssklower saved_nrt->rt_refcnt--; 15843336Ssklower saved_nrt->rt_genmask = genmask; 15940786Ssklower } 16036352Ssklower break; 16136352Ssklower 16236352Ssklower case RTM_DELETE: 16336352Ssklower error = rtrequest(RTM_DELETE, dst, gate, netmask, 16437472Ssklower rtm->rtm_flags, (struct rtentry **)0); 16536352Ssklower break; 16636352Ssklower 16736352Ssklower case RTM_GET: 16836352Ssklower case RTM_CHANGE: 16936352Ssklower case RTM_LOCK: 17036352Ssklower rt = rtalloc1(dst, 0); 17136352Ssklower if (rt == 0) 17240446Ssklower senderr(ESRCH); 17352656Ssklower if (rtm->rtm_type != RTM_GET) {/* XXX: too grotty */ 17452656Ssklower struct radix_node *rn, *rn_search(); 17552656Ssklower extern struct radix_node_head *mask_rnhead; 17652656Ssklower 17747465Ssklower if (Bcmp(dst, rt_key(rt), dst->sa_len) != 0) 17847465Ssklower senderr(ESRCH); 17952656Ssklower if (netmask && (rn = rn_search(netmask, 18052656Ssklower mask_rnhead->rnh_treetop))) 18152656Ssklower netmask = (struct sockaddr *)rn->rn_key; 18252656Ssklower for (rn = rt->rt_nodes; rn; rn = rn->rn_dupedkey) 18352656Ssklower if (netmask == (struct sockaddr *)rn->rn_mask) 18452656Ssklower break; 18552656Ssklower if (rn == 0) 18645183Ssklower senderr(ETOOMANYREFS); 18752656Ssklower rt = (struct rtentry *)rn; 18845183Ssklower } 18936352Ssklower switch(rtm->rtm_type) { 19036352Ssklower 19136352Ssklower case RTM_GET: 19252564Ssklower dst = rt_key(rt); 19352564Ssklower gate = rt->rt_gateway; 19452564Ssklower netmask = rt_mask(rt); 19552564Ssklower genmask = rt->rt_genmask; 19645656Ssklower if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) { 19752564Ssklower if (ifp = rt->rt_ifp) { 19852564Ssklower ifpaddr = ifp->if_addrlist->ifa_addr; 19945656Ssklower ifaaddr = rt->rt_ifa->ifa_addr; 20052564Ssklower rtm->rtm_index = ifp->if_index; 20145656Ssklower } else { 20252564Ssklower ifpaddr = 0; 20352564Ssklower ifaaddr = 0; 20452564Ssklower } 20545656Ssklower } 20652564Ssklower len = rt_msg2(RTM_GET, &info, (caddr_t)0, 20752564Ssklower (struct walkarg *)0); 20836352Ssklower if (len > rtm->rtm_msglen) { 20936352Ssklower struct rt_msghdr *new_rtm; 21036352Ssklower R_Malloc(new_rtm, struct rt_msghdr *, len); 21136352Ssklower if (new_rtm == 0) 21240446Ssklower senderr(ENOBUFS); 21336352Ssklower Bcopy(rtm, new_rtm, rtm->rtm_msglen); 21436352Ssklower Free(rtm); rtm = new_rtm; 21536352Ssklower } 21652564Ssklower (void)rt_msg2(RTM_GET, &info, (caddr_t)rtm, 21752564Ssklower (struct walkarg *)0); 21845183Ssklower rtm->rtm_flags = rt->rt_flags; 21945183Ssklower rtm->rtm_rmx = rt->rt_rmx; 22036352Ssklower break; 22136352Ssklower 22236352Ssklower case RTM_CHANGE: 22350229Ssklower if (gate && rt_setgate(rt, rt_key(rt), gate)) 22440446Ssklower senderr(EDQUOT); 22543336Ssklower /* new gateway could require new ifaddr, ifp; 22643336Ssklower flags may also be different; ifp may be specified 22743336Ssklower by ll sockaddr when protocol address is ambiguous */ 22847465Ssklower if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) && 22947465Ssklower (ifp = ifa->ifa_ifp)) 23047465Ssklower ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate, 23147465Ssklower ifp); 23247465Ssklower else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) || 23347465Ssklower (ifa = ifa_ifwithroute(rt->rt_flags, 23447465Ssklower rt_key(rt), gate))) 23547465Ssklower ifp = ifa->ifa_ifp; 23643336Ssklower if (ifa) { 23747465Ssklower register struct ifaddr *oifa = rt->rt_ifa; 23847465Ssklower if (oifa != ifa) { 23947465Ssklower if (oifa && oifa->ifa_rtrequest) 24047465Ssklower oifa->ifa_rtrequest(RTM_DELETE, 24147465Ssklower rt, gate); 24243336Ssklower rt->rt_ifa = ifa; 24347465Ssklower rt->rt_ifp = ifp; 24443336Ssklower } 24543336Ssklower } 24647465Ssklower rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, 24747465Ssklower &rt->rt_rmx); 24843336Ssklower if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) 24943336Ssklower rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, gate); 25043336Ssklower if (genmask) 25143336Ssklower rt->rt_genmask = genmask; 25236352Ssklower /* 25336352Ssklower * Fall into 25436352Ssklower */ 25540786Ssklower case RTM_LOCK: 25650811Ssklower rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); 25740786Ssklower rt->rt_rmx.rmx_locks |= 25840786Ssklower (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); 25936352Ssklower break; 26036352Ssklower } 26152564Ssklower break; 26236352Ssklower 26336352Ssklower default: 26440446Ssklower senderr(EOPNOTSUPP); 26536352Ssklower } 26636352Ssklower 26736352Ssklower flush: 26836352Ssklower if (rtm) { 26936352Ssklower if (error) 27036352Ssklower rtm->rtm_errno = error; 27136352Ssklower else 27236352Ssklower rtm->rtm_flags |= RTF_DONE; 27336352Ssklower } 27436352Ssklower cleanup: 27536352Ssklower if (rt) 27636352Ssklower rtfree(rt); 27742356Ssklower { 27842356Ssklower register struct rawcb *rp = 0; 27942356Ssklower /* 28042356Ssklower * Check to see if we don't want our own messages. 28142356Ssklower */ 28242356Ssklower if ((so->so_options & SO_USELOOPBACK) == 0) { 28342356Ssklower if (route_cb.any_count <= 1) { 28442356Ssklower if (rtm) 28542356Ssklower Free(rtm); 28642356Ssklower m_freem(m); 28742356Ssklower return (error); 28842356Ssklower } 28942356Ssklower /* There is another listener, so construct message */ 29042356Ssklower rp = sotorawcb(so); 29142356Ssklower } 29245656Ssklower if (rtm) { 29345656Ssklower m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm); 29438847Ssklower Free(rtm); 29538847Ssklower } 29642356Ssklower if (rp) 29742356Ssklower rp->rcb_proto.sp_family = 0; /* Avoid us */ 29845183Ssklower if (dst) 29945183Ssklower route_proto.sp_protocol = dst->sa_family; 30038847Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 30142356Ssklower if (rp) 30242356Ssklower rp->rcb_proto.sp_family = PF_ROUTE; 30342356Ssklower } 30436352Ssklower return (error); 30536352Ssklower } 30636352Ssklower 30743336Ssklower rt_setmetrics(which, in, out) 30840786Ssklower u_long which; 30940786Ssklower register struct rt_metrics *in, *out; 31040786Ssklower { 31140786Ssklower #define metric(f, e) if (which & (f)) out->e = in->e; 31240786Ssklower metric(RTV_RPIPE, rmx_recvpipe); 31340786Ssklower metric(RTV_SPIPE, rmx_sendpipe); 31440786Ssklower metric(RTV_SSTHRESH, rmx_ssthresh); 31540786Ssklower metric(RTV_RTT, rmx_rtt); 31640786Ssklower metric(RTV_RTTVAR, rmx_rttvar); 31740786Ssklower metric(RTV_HOPCOUNT, rmx_hopcount); 31840786Ssklower metric(RTV_MTU, rmx_mtu); 31950228Ssklower metric(RTV_EXPIRE, rmx_expire); 32040786Ssklower #undef metric 32140786Ssklower } 32240786Ssklower 32352564Ssklower #define ROUNDUP(a) \ 32452564Ssklower ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 32552564Ssklower #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 32652564Ssklower 32752564Ssklower static void 32852564Ssklower rt_xaddrs(cp, cplim, rtinfo) 32952564Ssklower register caddr_t cp, cplim; 33052564Ssklower register struct rt_addrinfo *rtinfo; 33152564Ssklower { 33252564Ssklower register struct sockaddr *sa; 33352564Ssklower register int i; 33452564Ssklower 33552564Ssklower bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info)); 33652564Ssklower for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { 33752564Ssklower if ((rtinfo->rti_addrs & (1 << i)) == 0) 33852564Ssklower continue; 33952564Ssklower rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; 34052564Ssklower ADVANCE(cp, sa); 34152564Ssklower } 34252564Ssklower } 34352808Sralph 34436352Ssklower /* 34536352Ssklower * Copy data from a buffer back into the indicated mbuf chain, 34636352Ssklower * starting "off" bytes from the beginning, extending the mbuf 34736352Ssklower * chain if necessary. 34836352Ssklower */ 34936352Ssklower m_copyback(m0, off, len, cp) 35036352Ssklower struct mbuf *m0; 35136352Ssklower register int off; 35236352Ssklower register int len; 35336352Ssklower caddr_t cp; 35436352Ssklower 35536352Ssklower { 35636352Ssklower register int mlen; 35736352Ssklower register struct mbuf *m = m0, *n; 35836352Ssklower int totlen = 0; 35936352Ssklower 36036352Ssklower if (m0 == 0) 36136352Ssklower return; 36248729Ssklower while (off > (mlen = m->m_len)) { 36336352Ssklower off -= mlen; 36436352Ssklower totlen += mlen; 36536352Ssklower if (m->m_next == 0) { 36636352Ssklower n = m_getclr(M_DONTWAIT, m->m_type); 36736352Ssklower if (n == 0) 36836352Ssklower goto out; 36936352Ssklower n->m_len = min(MLEN, len + off); 37036352Ssklower m->m_next = n; 37136352Ssklower } 37236352Ssklower m = m->m_next; 37336352Ssklower } 37436352Ssklower while (len > 0) { 37536352Ssklower mlen = min (m->m_len - off, len); 37637472Ssklower bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen); 37736352Ssklower cp += mlen; 37836352Ssklower len -= mlen; 37936352Ssklower mlen += off; 38036352Ssklower off = 0; 38136352Ssklower totlen += mlen; 38236352Ssklower if (len == 0) 38336352Ssklower break; 38436352Ssklower if (m->m_next == 0) { 38536352Ssklower n = m_get(M_DONTWAIT, m->m_type); 38636352Ssklower if (n == 0) 38736352Ssklower break; 38836352Ssklower n->m_len = min(MLEN, len); 38936352Ssklower m->m_next = n; 39036352Ssklower } 39136352Ssklower m = m->m_next; 39236352Ssklower } 39336352Ssklower out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) 39436352Ssklower m->m_pkthdr.len = totlen; 39536352Ssklower } 39636352Ssklower 39752564Ssklower static struct mbuf * 39852564Ssklower rt_msg1(type, rtinfo) 39952564Ssklower int type; 40052564Ssklower register struct rt_addrinfo *rtinfo; 40136352Ssklower { 40236352Ssklower register struct rt_msghdr *rtm; 40336352Ssklower register struct mbuf *m; 40452564Ssklower register int i; 40552564Ssklower register struct sockaddr *sa; 40652564Ssklower int len, dlen; 40736352Ssklower 40836352Ssklower m = m_gethdr(M_DONTWAIT, MT_DATA); 40936352Ssklower if (m == 0) 41052564Ssklower return (m); 41152564Ssklower switch (type) { 41252564Ssklower 41352564Ssklower case RTM_DELADDR: 41452564Ssklower case RTM_NEWADDR: 41552564Ssklower len = sizeof(struct ifa_msghdr); 41652564Ssklower break; 41752564Ssklower 41852564Ssklower case RTM_IFINFO: 41952564Ssklower len = sizeof(struct if_msghdr); 42052564Ssklower break; 42152564Ssklower 42252564Ssklower default: 42352564Ssklower len = sizeof(struct rt_msghdr); 42452564Ssklower } 42552564Ssklower if (len > MHLEN) 42652564Ssklower panic("rt_msg1"); 42752564Ssklower m->m_pkthdr.len = m->m_len = len; 42836352Ssklower m->m_pkthdr.rcvif = 0; 42936352Ssklower rtm = mtod(m, struct rt_msghdr *); 43052564Ssklower bzero((caddr_t)rtm, len); 43152564Ssklower for (i = 0; i < RTAX_MAX; i++) { 43252564Ssklower if ((sa = rtinfo->rti_info[i]) == NULL) 43352564Ssklower continue; 43452564Ssklower rtinfo->rti_addrs |= (1 << i); 43552564Ssklower dlen = ROUNDUP(sa->sa_len); 43652564Ssklower m_copyback(m, len, dlen, (caddr_t)sa); 43752564Ssklower len += dlen; 43852564Ssklower } 43952564Ssklower if (m->m_pkthdr.len != len) { 44052564Ssklower m_freem(m); 44152564Ssklower return (NULL); 44252564Ssklower } 44336352Ssklower rtm->rtm_msglen = len; 44440786Ssklower rtm->rtm_version = RTM_VERSION; 44536352Ssklower rtm->rtm_type = type; 44652564Ssklower return (m); 44752564Ssklower } 44852564Ssklower 44952564Ssklower static int 45052564Ssklower rt_msg2(type, rtinfo, cp, w) 45152564Ssklower int type; 45252564Ssklower register struct rt_addrinfo *rtinfo; 45352564Ssklower caddr_t cp; 45452564Ssklower struct walkarg *w; 45552564Ssklower { 45652564Ssklower register int i; 45752564Ssklower int len, dlen, second_time = 0; 45852564Ssklower caddr_t cp0; 45952564Ssklower 46052564Ssklower rtinfo->rti_addrs = 0; 46152564Ssklower again: 46252564Ssklower switch (type) { 46352564Ssklower 46452564Ssklower case RTM_DELADDR: 46552564Ssklower case RTM_NEWADDR: 46652564Ssklower len = sizeof(struct ifa_msghdr); 46752564Ssklower break; 46852564Ssklower 46952564Ssklower case RTM_IFINFO: 47052564Ssklower len = sizeof(struct if_msghdr); 47152564Ssklower break; 47252564Ssklower 47352564Ssklower default: 47452564Ssklower len = sizeof(struct rt_msghdr); 47536352Ssklower } 47652564Ssklower if (cp0 = cp) 47752564Ssklower cp += len; 47852564Ssklower for (i = 0; i < RTAX_MAX; i++) { 47952564Ssklower register struct sockaddr *sa; 48052564Ssklower 48152564Ssklower if ((sa = rtinfo->rti_info[i]) == 0) 48252564Ssklower continue; 48352564Ssklower rtinfo->rti_addrs |= (1 << i); 48452564Ssklower dlen = ROUNDUP(sa->sa_len); 48552564Ssklower if (cp) { 48652564Ssklower bcopy((caddr_t)sa, cp, (unsigned)dlen); 48752564Ssklower cp += dlen; 48852564Ssklower } 48936352Ssklower len += dlen; 49036352Ssklower } 49152564Ssklower if (cp == 0 && w != NULL && !second_time) { 49252564Ssklower register struct walkarg *rw = w; 49352564Ssklower 49452564Ssklower rw->w_needed += len; 49552564Ssklower if (rw->w_needed <= 0 && rw->w_where) { 49652564Ssklower if (rw->w_tmemsize < len) { 49752564Ssklower if (rw->w_tmem) 49852564Ssklower free(rw->w_tmem, M_RTABLE); 49952564Ssklower if (rw->w_tmem = (caddr_t) 50052564Ssklower malloc(len, M_RTABLE, M_NOWAIT)) 50152564Ssklower rw->w_tmemsize = len; 50252564Ssklower } 50352564Ssklower if (rw->w_tmem) { 50452564Ssklower cp = rw->w_tmem; 50552564Ssklower second_time = 1; 50652564Ssklower goto again; 50752564Ssklower } else 50852564Ssklower rw->w_where = 0; 50952564Ssklower } 51036352Ssklower } 51152564Ssklower if (cp) { 51252564Ssklower register struct rt_msghdr *rtm = (struct rt_msghdr *)cp0; 51352564Ssklower 51452564Ssklower rtm->rtm_version = RTM_VERSION; 51552564Ssklower rtm->rtm_type = type; 51652564Ssklower rtm->rtm_msglen = len; 51736352Ssklower } 51852564Ssklower return (len); 51952564Ssklower } 52052564Ssklower 52152564Ssklower /* 52252564Ssklower * This routine is called to generate a message from the routing 52352564Ssklower * socket indicating that a redirect has occured, a routing lookup 52452564Ssklower * has failed, or that a protocol has detected timeouts to a particular 52552564Ssklower * destination. 52652564Ssklower */ 52752564Ssklower rt_missmsg(type, rtinfo, flags, error) 52852564Ssklower int type, flags, error; 52952564Ssklower register struct rt_addrinfo *rtinfo; 53052564Ssklower { 53152564Ssklower register struct rt_msghdr *rtm; 53252564Ssklower register struct mbuf *m; 53352564Ssklower register int i; 53452564Ssklower struct sockaddr *sa = rtinfo->rti_info[RTAX_DST]; 53552564Ssklower 53652564Ssklower if (route_cb.any_count == 0) 53736352Ssklower return; 53852564Ssklower m = rt_msg1(type, rtinfo); 53952564Ssklower if (m == 0) 54052564Ssklower return; 54152564Ssklower rtm = mtod(m, struct rt_msghdr *); 54252564Ssklower rtm->rtm_flags = RTF_DONE | flags; 54337472Ssklower rtm->rtm_errno = error; 54452564Ssklower rtm->rtm_addrs = rtinfo->rti_addrs; 54552564Ssklower route_proto.sp_protocol = sa ? sa->sa_family : 0; 54636352Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 54736352Ssklower } 54836352Ssklower 54952564Ssklower /* 55052564Ssklower * This routine is called to generate a message from the routing 55152564Ssklower * socket indicating that the status of a network interface has changed. 55252564Ssklower */ 55352564Ssklower rt_ifmsg(ifp) 55452564Ssklower register struct ifnet *ifp; 55552564Ssklower { 55652564Ssklower register struct if_msghdr *ifm; 55752564Ssklower struct mbuf *m; 55852564Ssklower struct rt_addrinfo info; 55952564Ssklower 56052564Ssklower if (route_cb.any_count == 0) 56152564Ssklower return; 56252564Ssklower bzero((caddr_t)&info, sizeof(info)); 56352564Ssklower m = rt_msg1(RTM_IFINFO, &info); 56452564Ssklower if (m == 0) 56552564Ssklower return; 56652564Ssklower ifm = mtod(m, struct if_msghdr *); 56752564Ssklower ifm->ifm_index = ifp->if_index; 56852564Ssklower ifm->ifm_flags = ifp->if_flags; 56952564Ssklower ifm->ifm_data = ifp->if_data; 57052564Ssklower ifm->ifm_addrs = 0; 57152564Ssklower route_proto.sp_protocol = 0; 57252564Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 57352564Ssklower } 57452564Ssklower 57552564Ssklower /* 57652564Ssklower * This is called to generate messages from the routing socket 57752564Ssklower * indicating a network interface has had addresses associated with it. 57852564Ssklower * if we ever reverse the logic and replace messages TO the routing 57952564Ssklower * socket indicate a request to configure interfaces, then it will 58052564Ssklower * be unnecessary as the routing socket will automatically generate 58152564Ssklower * copies of it. 58252564Ssklower */ 58352564Ssklower rt_newaddrmsg(cmd, ifa, error, rt) 58452564Ssklower int cmd, error; 58552564Ssklower register struct ifaddr *ifa; 58652564Ssklower register struct rtentry *rt; 58752564Ssklower { 58852564Ssklower struct rt_addrinfo info; 58952564Ssklower struct sockaddr *sa; 59052564Ssklower int pass; 59152564Ssklower struct mbuf *m; 59252564Ssklower struct ifnet *ifp = ifa->ifa_ifp; 59352564Ssklower 59452564Ssklower if (route_cb.any_count == 0) 59552564Ssklower return; 59652564Ssklower for (pass = 1; pass < 3; pass++) { 59752564Ssklower bzero((caddr_t)&info, sizeof(info)); 59852564Ssklower if ((cmd == RTM_ADD && pass == 1) || 59952564Ssklower (cmd == RTM_DELETE && pass == 2)) { 60052564Ssklower register struct ifa_msghdr *ifam; 60152564Ssklower int ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR; 60252564Ssklower 60352564Ssklower ifaaddr = sa = ifa->ifa_addr; 60452564Ssklower ifpaddr = ifp->if_addrlist->ifa_addr; 60552564Ssklower netmask = ifa->ifa_netmask; 60652564Ssklower brdaddr = ifa->ifa_dstaddr; 60752564Ssklower if ((m = rt_msg1(ncmd, &info)) == NULL) 60852564Ssklower continue; 60952564Ssklower ifam = mtod(m, struct ifa_msghdr *); 61052564Ssklower ifam->ifam_index = ifp->if_index; 61152564Ssklower ifam->ifam_metric = ifa->ifa_metric; 61254077Ssklower ifam->ifam_flags = ifa->ifa_flags; 61352564Ssklower ifam->ifam_addrs = info.rti_addrs; 61452564Ssklower } 61552564Ssklower if ((cmd == RTM_ADD && pass == 2) || 61652564Ssklower (cmd == RTM_DELETE && pass == 1)) { 61752564Ssklower register struct rt_msghdr *rtm; 61852564Ssklower 61952564Ssklower if (rt == 0) 62052564Ssklower continue; 62152564Ssklower netmask = rt_mask(rt); 62252564Ssklower dst = sa = rt_key(rt); 62352564Ssklower gate = rt->rt_gateway; 62452564Ssklower if ((m = rt_msg1(cmd, &info)) == NULL) 62552564Ssklower continue; 62652564Ssklower rtm = mtod(m, struct rt_msghdr *); 62752564Ssklower rtm->rtm_index = ifp->if_index; 62852564Ssklower rtm->rtm_flags |= rt->rt_flags; 62952564Ssklower rtm->rtm_errno = error; 63052564Ssklower rtm->rtm_addrs = info.rti_addrs; 63152564Ssklower } 63252564Ssklower route_proto.sp_protocol = sa ? sa->sa_family : 0; 63352564Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 63452564Ssklower } 63552564Ssklower } 63652564Ssklower 63736352Ssklower /* 638*57836Smckusick * This is used in dumping the kernel table via sysctl(). 63940446Ssklower */ 640*57836Smckusick sysctl_dumpentry(rn, w) 64140446Ssklower struct radix_node *rn; 64240446Ssklower register struct walkarg *w; 64340446Ssklower { 64440446Ssklower register struct sockaddr *sa; 64540446Ssklower register struct rtentry *rt = (struct rtentry *)rn; 64652564Ssklower int n, error = 0, size; 64752564Ssklower struct rt_addrinfo info; 64840446Ssklower 649*57836Smckusick if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg)) 65050812Ssklower return 0; 65152564Ssklower bzero((caddr_t)&info, sizeof(info)); 65252564Ssklower dst = rt_key(rt); 65352564Ssklower gate = rt->rt_gateway; 65452564Ssklower netmask = rt_mask(rt); 65552564Ssklower genmask = rt->rt_genmask; 65652564Ssklower size = rt_msg2(RTM_GET, &info, 0, w); 65752564Ssklower if (w->w_where && w->w_tmem) { 65852564Ssklower register struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem; 65940446Ssklower 66052564Ssklower rtm->rtm_flags = rt->rt_flags; 66152564Ssklower rtm->rtm_use = rt->rt_use; 66252564Ssklower rtm->rtm_rmx = rt->rt_rmx; 66352564Ssklower rtm->rtm_index = rt->rt_ifp->if_index; 66452564Ssklower rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0; 66552564Ssklower rtm->rtm_addrs = info.rti_addrs; 66652564Ssklower if (error = copyout((caddr_t)rtm, w->w_where, size)) 66752564Ssklower w->w_where = NULL; 66852564Ssklower else 66952564Ssklower w->w_where += size; 67040446Ssklower } 67152564Ssklower return (error); 67252564Ssklower } 67352564Ssklower 674*57836Smckusick sysctl_iflist(af, w) 67552564Ssklower int af; 67652564Ssklower register struct walkarg *w; 67752564Ssklower { 67852564Ssklower register struct ifnet *ifp; 67952564Ssklower register struct ifaddr *ifa; 68052564Ssklower struct rt_addrinfo info; 68152564Ssklower struct sockaddr *sa; 68252564Ssklower int len, error = 0; 68352564Ssklower 68452564Ssklower bzero((caddr_t)&info, sizeof(info)); 68552564Ssklower for (ifp = ifnet; ifp; ifp = ifp->if_next) { 68652631Ssklower if (w->w_arg && w->w_arg != ifp->if_index) 68752631Ssklower continue; 68852564Ssklower ifa = ifp->if_addrlist; 68952564Ssklower ifpaddr = ifa->ifa_addr; 69052564Ssklower len = rt_msg2(RTM_IFINFO, &info, (caddr_t)0, w); 69152564Ssklower ifpaddr = 0; 69252564Ssklower if (w->w_where && w->w_tmem) { 69352564Ssklower register struct if_msghdr *ifm; 69452564Ssklower 69552564Ssklower ifm = (struct if_msghdr *)w->w_tmem; 69652564Ssklower ifm->ifm_index = ifp->if_index; 69752564Ssklower ifm->ifm_flags = ifp->if_flags; 69852564Ssklower ifm->ifm_data = ifp->if_data; 69952564Ssklower ifm->ifm_addrs = info.rti_addrs; 70052564Ssklower if (error = copyout((caddr_t)ifm, w->w_where, len)) 70152564Ssklower return (error); 70252564Ssklower w->w_where += len; 70352564Ssklower } 70452564Ssklower while (ifa = ifa->ifa_next) { 70552631Ssklower if (af && af != ifa->ifa_addr->sa_family) 70652631Ssklower continue; 70752564Ssklower ifaaddr = ifa->ifa_addr; 70852564Ssklower netmask = ifa->ifa_netmask; 70952564Ssklower brdaddr = ifa->ifa_dstaddr; 71052564Ssklower len = rt_msg2(RTM_NEWADDR, &info, 0, w); 71152564Ssklower if (w->w_where && w->w_tmem) { 71252564Ssklower register struct ifa_msghdr *ifam; 71352564Ssklower 71452564Ssklower ifam = (struct ifa_msghdr *)w->w_tmem; 71552564Ssklower ifam->ifam_index = ifa->ifa_ifp->if_index; 71652564Ssklower ifam->ifam_flags = ifa->ifa_flags; 71752564Ssklower ifam->ifam_metric = ifa->ifa_metric; 71852564Ssklower ifam->ifam_addrs = info.rti_addrs; 71952564Ssklower if (error = copyout(w->w_tmem, w->w_where, len)) 72052564Ssklower return (error); 72152564Ssklower w->w_where += len; 72252564Ssklower } 72352564Ssklower } 72452631Ssklower ifaaddr = netmask = brdaddr = 0; 72552564Ssklower } 72640446Ssklower return (0); 72740446Ssklower } 72840446Ssklower 729*57836Smckusick sysctl_rtable(name, namelen, where, given, new, newlen) 730*57836Smckusick int *name; 731*57836Smckusick int namelen; 73240446Ssklower caddr_t where; 733*57836Smckusick int *given; 734*57836Smckusick caddr_t *new; 735*57836Smckusick int newlen; 73640446Ssklower { 73740446Ssklower register struct radix_node_head *rnh; 73852564Ssklower int i, s, error = EINVAL; 739*57836Smckusick u_char af; 74040446Ssklower struct walkarg w; 74140446Ssklower 742*57836Smckusick if (new) 743*57836Smckusick return (EPERM); 744*57836Smckusick if (namelen != 3) 745*57836Smckusick return (EINVAL); 746*57836Smckusick af = name[0]; 74740446Ssklower Bzero(&w, sizeof(w)); 748*57836Smckusick w.w_where = where; 749*57836Smckusick w.w_given = *given; 75040446Ssklower w.w_needed = 0 - w.w_given; 751*57836Smckusick w.w_op = name[1]; 752*57836Smckusick w.w_arg = name[2]; 75340446Ssklower 75440446Ssklower s = splnet(); 755*57836Smckusick switch (w.w_op) { 75652564Ssklower 757*57836Smckusick case NET_RT_DUMP: 758*57836Smckusick case NET_RT_FLAGS: 75952564Ssklower for (i = 1; i <= AF_MAX; i++) 76052564Ssklower if ((rnh = rt_tables[i]) && (af == 0 || af == i) && 76152564Ssklower (error = rnh->rnh_walk(rnh->rnh_treetop, 762*57836Smckusick sysctl_dumpentry, &w))) 76352564Ssklower break; 76452564Ssklower break; 76552564Ssklower 766*57836Smckusick case NET_RT_IFLIST: 767*57836Smckusick error = sysctl_iflist(af, &w); 76840446Ssklower } 76952564Ssklower splx(s); 77052564Ssklower if (w.w_tmem) 77152564Ssklower free(w.w_tmem, M_RTABLE); 77240446Ssklower w.w_needed += w.w_given; 773*57836Smckusick if (where) { 77440446Ssklower *given = w.w_where - where; 775*57836Smckusick if (*given < w.w_needed) 776*57836Smckusick return (ENOMEM); 777*57836Smckusick } else { 778*57836Smckusick *given = (11 * w.w_needed) / 10; 779*57836Smckusick } 78040446Ssklower return (error); 78140446Ssklower } 78240446Ssklower 78340446Ssklower /* 78436352Ssklower * Definitions of protocols supported in the ROUTE domain. 78536352Ssklower */ 78636352Ssklower 78754824Ssklower int raw_init(),raw_usrreq(),raw_input(),raw_ctlinput(), route_init(); 78836352Ssklower extern struct domain routedomain; /* or at least forward */ 78936352Ssklower 79036352Ssklower struct protosw routesw[] = { 79136352Ssklower { SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR, 79236352Ssklower raw_input, route_output, raw_ctlinput, 0, 79336352Ssklower route_usrreq, 79436352Ssklower raw_init, 0, 0, 0, 795*57836Smckusick sysctl_rtable, 79636352Ssklower } 79736352Ssklower }; 79836352Ssklower 79936352Ssklower int unp_externalize(), unp_dispose(); 80036352Ssklower 80136352Ssklower struct domain routedomain = 80254824Ssklower { PF_ROUTE, "route", route_init, 0, 0, 80336352Ssklower routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] }; 804