136352Ssklower /* 250228Ssklower * Copyright (c) 1988, 1991 Regents of the University of California. 336352Ssklower * All rights reserved. 436352Ssklower * 544466Sbostic * %sccs.include.redist.c% 636352Ssklower * 7*58496Sbostic * @(#)rtsock.c 7.34 (Berkeley) 03/05/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; 22058495Ssklower rtm->rtm_addrs = info.rti_addrs; 22136352Ssklower break; 22236352Ssklower 22336352Ssklower case RTM_CHANGE: 22450229Ssklower if (gate && rt_setgate(rt, rt_key(rt), gate)) 22540446Ssklower senderr(EDQUOT); 22643336Ssklower /* new gateway could require new ifaddr, ifp; 22743336Ssklower flags may also be different; ifp may be specified 22843336Ssklower by ll sockaddr when protocol address is ambiguous */ 22947465Ssklower if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) && 23047465Ssklower (ifp = ifa->ifa_ifp)) 23147465Ssklower ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate, 23247465Ssklower ifp); 23347465Ssklower else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) || 23447465Ssklower (ifa = ifa_ifwithroute(rt->rt_flags, 23547465Ssklower rt_key(rt), gate))) 23647465Ssklower ifp = ifa->ifa_ifp; 23743336Ssklower if (ifa) { 23847465Ssklower register struct ifaddr *oifa = rt->rt_ifa; 23947465Ssklower if (oifa != ifa) { 24047465Ssklower if (oifa && oifa->ifa_rtrequest) 24147465Ssklower oifa->ifa_rtrequest(RTM_DELETE, 24247465Ssklower rt, gate); 24343336Ssklower rt->rt_ifa = ifa; 24447465Ssklower rt->rt_ifp = ifp; 24543336Ssklower } 24643336Ssklower } 24747465Ssklower rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, 24847465Ssklower &rt->rt_rmx); 24943336Ssklower if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) 25043336Ssklower rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, gate); 25143336Ssklower if (genmask) 25243336Ssklower rt->rt_genmask = genmask; 25336352Ssklower /* 25436352Ssklower * Fall into 25536352Ssklower */ 25640786Ssklower case RTM_LOCK: 25750811Ssklower rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); 25840786Ssklower rt->rt_rmx.rmx_locks |= 25940786Ssklower (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); 26036352Ssklower break; 26136352Ssklower } 26252564Ssklower break; 26336352Ssklower 26436352Ssklower default: 26540446Ssklower senderr(EOPNOTSUPP); 26636352Ssklower } 26736352Ssklower 26836352Ssklower flush: 26936352Ssklower if (rtm) { 27036352Ssklower if (error) 27136352Ssklower rtm->rtm_errno = error; 27236352Ssklower else 27336352Ssklower rtm->rtm_flags |= RTF_DONE; 27436352Ssklower } 27536352Ssklower cleanup: 27636352Ssklower if (rt) 27736352Ssklower rtfree(rt); 27842356Ssklower { 27942356Ssklower register struct rawcb *rp = 0; 28042356Ssklower /* 28142356Ssklower * Check to see if we don't want our own messages. 28242356Ssklower */ 28342356Ssklower if ((so->so_options & SO_USELOOPBACK) == 0) { 28442356Ssklower if (route_cb.any_count <= 1) { 28542356Ssklower if (rtm) 28642356Ssklower Free(rtm); 28742356Ssklower m_freem(m); 28842356Ssklower return (error); 28942356Ssklower } 29042356Ssklower /* There is another listener, so construct message */ 29142356Ssklower rp = sotorawcb(so); 29242356Ssklower } 29345656Ssklower if (rtm) { 29445656Ssklower m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm); 29538847Ssklower Free(rtm); 29638847Ssklower } 29742356Ssklower if (rp) 29842356Ssklower rp->rcb_proto.sp_family = 0; /* Avoid us */ 29945183Ssklower if (dst) 30045183Ssklower route_proto.sp_protocol = dst->sa_family; 30138847Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 30242356Ssklower if (rp) 30342356Ssklower rp->rcb_proto.sp_family = PF_ROUTE; 30442356Ssklower } 30536352Ssklower return (error); 30636352Ssklower } 30736352Ssklower 30843336Ssklower rt_setmetrics(which, in, out) 30940786Ssklower u_long which; 31040786Ssklower register struct rt_metrics *in, *out; 31140786Ssklower { 31240786Ssklower #define metric(f, e) if (which & (f)) out->e = in->e; 31340786Ssklower metric(RTV_RPIPE, rmx_recvpipe); 31440786Ssklower metric(RTV_SPIPE, rmx_sendpipe); 31540786Ssklower metric(RTV_SSTHRESH, rmx_ssthresh); 31640786Ssklower metric(RTV_RTT, rmx_rtt); 31740786Ssklower metric(RTV_RTTVAR, rmx_rttvar); 31840786Ssklower metric(RTV_HOPCOUNT, rmx_hopcount); 31940786Ssklower metric(RTV_MTU, rmx_mtu); 32050228Ssklower metric(RTV_EXPIRE, rmx_expire); 32140786Ssklower #undef metric 32240786Ssklower } 32340786Ssklower 32452564Ssklower #define ROUNDUP(a) \ 32552564Ssklower ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 32652564Ssklower #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 32752564Ssklower 32852564Ssklower static void 32952564Ssklower rt_xaddrs(cp, cplim, rtinfo) 33052564Ssklower register caddr_t cp, cplim; 33152564Ssklower register struct rt_addrinfo *rtinfo; 33252564Ssklower { 33352564Ssklower register struct sockaddr *sa; 33452564Ssklower register int i; 33552564Ssklower 33652564Ssklower bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info)); 33752564Ssklower for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { 33852564Ssklower if ((rtinfo->rti_addrs & (1 << i)) == 0) 33952564Ssklower continue; 34052564Ssklower rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; 34152564Ssklower ADVANCE(cp, sa); 34252564Ssklower } 34352564Ssklower } 34452808Sralph 34536352Ssklower /* 34636352Ssklower * Copy data from a buffer back into the indicated mbuf chain, 34736352Ssklower * starting "off" bytes from the beginning, extending the mbuf 34836352Ssklower * chain if necessary. 34936352Ssklower */ 35036352Ssklower m_copyback(m0, off, len, cp) 35136352Ssklower struct mbuf *m0; 35236352Ssklower register int off; 35336352Ssklower register int len; 35436352Ssklower caddr_t cp; 35536352Ssklower 35636352Ssklower { 35736352Ssklower register int mlen; 35836352Ssklower register struct mbuf *m = m0, *n; 35936352Ssklower int totlen = 0; 36036352Ssklower 36136352Ssklower if (m0 == 0) 36236352Ssklower return; 36348729Ssklower while (off > (mlen = m->m_len)) { 36436352Ssklower off -= mlen; 36536352Ssklower totlen += mlen; 36636352Ssklower if (m->m_next == 0) { 36736352Ssklower n = m_getclr(M_DONTWAIT, m->m_type); 36836352Ssklower if (n == 0) 36936352Ssklower goto out; 37036352Ssklower n->m_len = min(MLEN, len + off); 37136352Ssklower m->m_next = n; 37236352Ssklower } 37336352Ssklower m = m->m_next; 37436352Ssklower } 37536352Ssklower while (len > 0) { 37636352Ssklower mlen = min (m->m_len - off, len); 37737472Ssklower bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen); 37836352Ssklower cp += mlen; 37936352Ssklower len -= mlen; 38036352Ssklower mlen += off; 38136352Ssklower off = 0; 38236352Ssklower totlen += mlen; 38336352Ssklower if (len == 0) 38436352Ssklower break; 38536352Ssklower if (m->m_next == 0) { 38636352Ssklower n = m_get(M_DONTWAIT, m->m_type); 38736352Ssklower if (n == 0) 38836352Ssklower break; 38936352Ssklower n->m_len = min(MLEN, len); 39036352Ssklower m->m_next = n; 39136352Ssklower } 39236352Ssklower m = m->m_next; 39336352Ssklower } 39436352Ssklower out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) 39536352Ssklower m->m_pkthdr.len = totlen; 39636352Ssklower } 39736352Ssklower 39852564Ssklower static struct mbuf * 39952564Ssklower rt_msg1(type, rtinfo) 40052564Ssklower int type; 40152564Ssklower register struct rt_addrinfo *rtinfo; 40236352Ssklower { 40336352Ssklower register struct rt_msghdr *rtm; 40436352Ssklower register struct mbuf *m; 40552564Ssklower register int i; 40652564Ssklower register struct sockaddr *sa; 40752564Ssklower int len, dlen; 40836352Ssklower 40936352Ssklower m = m_gethdr(M_DONTWAIT, MT_DATA); 41036352Ssklower if (m == 0) 41152564Ssklower return (m); 41252564Ssklower switch (type) { 41352564Ssklower 41452564Ssklower case RTM_DELADDR: 41552564Ssklower case RTM_NEWADDR: 41652564Ssklower len = sizeof(struct ifa_msghdr); 41752564Ssklower break; 41852564Ssklower 41952564Ssklower case RTM_IFINFO: 42052564Ssklower len = sizeof(struct if_msghdr); 42152564Ssklower break; 42252564Ssklower 42352564Ssklower default: 42452564Ssklower len = sizeof(struct rt_msghdr); 42552564Ssklower } 42652564Ssklower if (len > MHLEN) 42752564Ssklower panic("rt_msg1"); 42852564Ssklower m->m_pkthdr.len = m->m_len = len; 42936352Ssklower m->m_pkthdr.rcvif = 0; 43036352Ssklower rtm = mtod(m, struct rt_msghdr *); 43152564Ssklower bzero((caddr_t)rtm, len); 43252564Ssklower for (i = 0; i < RTAX_MAX; i++) { 43352564Ssklower if ((sa = rtinfo->rti_info[i]) == NULL) 43452564Ssklower continue; 43552564Ssklower rtinfo->rti_addrs |= (1 << i); 43652564Ssklower dlen = ROUNDUP(sa->sa_len); 43752564Ssklower m_copyback(m, len, dlen, (caddr_t)sa); 43852564Ssklower len += dlen; 43952564Ssklower } 44052564Ssklower if (m->m_pkthdr.len != len) { 44152564Ssklower m_freem(m); 44252564Ssklower return (NULL); 44352564Ssklower } 44436352Ssklower rtm->rtm_msglen = len; 44540786Ssklower rtm->rtm_version = RTM_VERSION; 44636352Ssklower rtm->rtm_type = type; 44752564Ssklower return (m); 44852564Ssklower } 44952564Ssklower 45052564Ssklower static int 45152564Ssklower rt_msg2(type, rtinfo, cp, w) 45252564Ssklower int type; 45352564Ssklower register struct rt_addrinfo *rtinfo; 45452564Ssklower caddr_t cp; 45552564Ssklower struct walkarg *w; 45652564Ssklower { 45752564Ssklower register int i; 45852564Ssklower int len, dlen, second_time = 0; 45952564Ssklower caddr_t cp0; 46052564Ssklower 46152564Ssklower rtinfo->rti_addrs = 0; 46252564Ssklower again: 46352564Ssklower switch (type) { 46452564Ssklower 46552564Ssklower case RTM_DELADDR: 46652564Ssklower case RTM_NEWADDR: 46752564Ssklower len = sizeof(struct ifa_msghdr); 46852564Ssklower break; 46952564Ssklower 47052564Ssklower case RTM_IFINFO: 47152564Ssklower len = sizeof(struct if_msghdr); 47252564Ssklower break; 47352564Ssklower 47452564Ssklower default: 47552564Ssklower len = sizeof(struct rt_msghdr); 47636352Ssklower } 47752564Ssklower if (cp0 = cp) 47852564Ssklower cp += len; 47952564Ssklower for (i = 0; i < RTAX_MAX; i++) { 48052564Ssklower register struct sockaddr *sa; 48152564Ssklower 48252564Ssklower if ((sa = rtinfo->rti_info[i]) == 0) 48352564Ssklower continue; 48452564Ssklower rtinfo->rti_addrs |= (1 << i); 48552564Ssklower dlen = ROUNDUP(sa->sa_len); 48652564Ssklower if (cp) { 48752564Ssklower bcopy((caddr_t)sa, cp, (unsigned)dlen); 48852564Ssklower cp += dlen; 48952564Ssklower } 49036352Ssklower len += dlen; 49136352Ssklower } 49252564Ssklower if (cp == 0 && w != NULL && !second_time) { 49352564Ssklower register struct walkarg *rw = w; 49452564Ssklower 49552564Ssklower rw->w_needed += len; 49652564Ssklower if (rw->w_needed <= 0 && rw->w_where) { 49752564Ssklower if (rw->w_tmemsize < len) { 49852564Ssklower if (rw->w_tmem) 49952564Ssklower free(rw->w_tmem, M_RTABLE); 50052564Ssklower if (rw->w_tmem = (caddr_t) 50152564Ssklower malloc(len, M_RTABLE, M_NOWAIT)) 50252564Ssklower rw->w_tmemsize = len; 50352564Ssklower } 50452564Ssklower if (rw->w_tmem) { 50552564Ssklower cp = rw->w_tmem; 50652564Ssklower second_time = 1; 50752564Ssklower goto again; 50852564Ssklower } else 50952564Ssklower rw->w_where = 0; 51052564Ssklower } 51136352Ssklower } 51252564Ssklower if (cp) { 51352564Ssklower register struct rt_msghdr *rtm = (struct rt_msghdr *)cp0; 51452564Ssklower 51552564Ssklower rtm->rtm_version = RTM_VERSION; 51652564Ssklower rtm->rtm_type = type; 51752564Ssklower rtm->rtm_msglen = len; 51836352Ssklower } 51952564Ssklower return (len); 52052564Ssklower } 52152564Ssklower 52252564Ssklower /* 52352564Ssklower * This routine is called to generate a message from the routing 52452564Ssklower * socket indicating that a redirect has occured, a routing lookup 52552564Ssklower * has failed, or that a protocol has detected timeouts to a particular 52652564Ssklower * destination. 52752564Ssklower */ 52852564Ssklower rt_missmsg(type, rtinfo, flags, error) 52952564Ssklower int type, flags, error; 53052564Ssklower register struct rt_addrinfo *rtinfo; 53152564Ssklower { 53252564Ssklower register struct rt_msghdr *rtm; 53352564Ssklower register struct mbuf *m; 53452564Ssklower register int i; 53552564Ssklower struct sockaddr *sa = rtinfo->rti_info[RTAX_DST]; 53652564Ssklower 53752564Ssklower if (route_cb.any_count == 0) 53836352Ssklower return; 53952564Ssklower m = rt_msg1(type, rtinfo); 54052564Ssklower if (m == 0) 54152564Ssklower return; 54252564Ssklower rtm = mtod(m, struct rt_msghdr *); 54352564Ssklower rtm->rtm_flags = RTF_DONE | flags; 54437472Ssklower rtm->rtm_errno = error; 54552564Ssklower rtm->rtm_addrs = rtinfo->rti_addrs; 54652564Ssklower route_proto.sp_protocol = sa ? sa->sa_family : 0; 54736352Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 54836352Ssklower } 54936352Ssklower 55052564Ssklower /* 55152564Ssklower * This routine is called to generate a message from the routing 55252564Ssklower * socket indicating that the status of a network interface has changed. 55352564Ssklower */ 55452564Ssklower rt_ifmsg(ifp) 55552564Ssklower register struct ifnet *ifp; 55652564Ssklower { 55752564Ssklower register struct if_msghdr *ifm; 55852564Ssklower struct mbuf *m; 55952564Ssklower struct rt_addrinfo info; 56052564Ssklower 56152564Ssklower if (route_cb.any_count == 0) 56252564Ssklower return; 56352564Ssklower bzero((caddr_t)&info, sizeof(info)); 56452564Ssklower m = rt_msg1(RTM_IFINFO, &info); 56552564Ssklower if (m == 0) 56652564Ssklower return; 56752564Ssklower ifm = mtod(m, struct if_msghdr *); 56852564Ssklower ifm->ifm_index = ifp->if_index; 56952564Ssklower ifm->ifm_flags = ifp->if_flags; 57052564Ssklower ifm->ifm_data = ifp->if_data; 57152564Ssklower ifm->ifm_addrs = 0; 57252564Ssklower route_proto.sp_protocol = 0; 57352564Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 57452564Ssklower } 57552564Ssklower 57652564Ssklower /* 57752564Ssklower * This is called to generate messages from the routing socket 57852564Ssklower * indicating a network interface has had addresses associated with it. 57952564Ssklower * if we ever reverse the logic and replace messages TO the routing 58052564Ssklower * socket indicate a request to configure interfaces, then it will 58152564Ssklower * be unnecessary as the routing socket will automatically generate 58252564Ssklower * copies of it. 58352564Ssklower */ 58452564Ssklower rt_newaddrmsg(cmd, ifa, error, rt) 58552564Ssklower int cmd, error; 58652564Ssklower register struct ifaddr *ifa; 58752564Ssklower register struct rtentry *rt; 58852564Ssklower { 58952564Ssklower struct rt_addrinfo info; 59052564Ssklower struct sockaddr *sa; 59152564Ssklower int pass; 59252564Ssklower struct mbuf *m; 59352564Ssklower struct ifnet *ifp = ifa->ifa_ifp; 59452564Ssklower 59552564Ssklower if (route_cb.any_count == 0) 59652564Ssklower return; 59752564Ssklower for (pass = 1; pass < 3; pass++) { 59852564Ssklower bzero((caddr_t)&info, sizeof(info)); 59952564Ssklower if ((cmd == RTM_ADD && pass == 1) || 60052564Ssklower (cmd == RTM_DELETE && pass == 2)) { 60152564Ssklower register struct ifa_msghdr *ifam; 60252564Ssklower int ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR; 60352564Ssklower 60452564Ssklower ifaaddr = sa = ifa->ifa_addr; 60552564Ssklower ifpaddr = ifp->if_addrlist->ifa_addr; 60652564Ssklower netmask = ifa->ifa_netmask; 60752564Ssklower brdaddr = ifa->ifa_dstaddr; 60852564Ssklower if ((m = rt_msg1(ncmd, &info)) == NULL) 60952564Ssklower continue; 61052564Ssklower ifam = mtod(m, struct ifa_msghdr *); 61152564Ssklower ifam->ifam_index = ifp->if_index; 61252564Ssklower ifam->ifam_metric = ifa->ifa_metric; 61354077Ssklower ifam->ifam_flags = ifa->ifa_flags; 61452564Ssklower ifam->ifam_addrs = info.rti_addrs; 61552564Ssklower } 61652564Ssklower if ((cmd == RTM_ADD && pass == 2) || 61752564Ssklower (cmd == RTM_DELETE && pass == 1)) { 61852564Ssklower register struct rt_msghdr *rtm; 61952564Ssklower 62052564Ssklower if (rt == 0) 62152564Ssklower continue; 62252564Ssklower netmask = rt_mask(rt); 62352564Ssklower dst = sa = rt_key(rt); 62452564Ssklower gate = rt->rt_gateway; 62552564Ssklower if ((m = rt_msg1(cmd, &info)) == NULL) 62652564Ssklower continue; 62752564Ssklower rtm = mtod(m, struct rt_msghdr *); 62852564Ssklower rtm->rtm_index = ifp->if_index; 62952564Ssklower rtm->rtm_flags |= rt->rt_flags; 63052564Ssklower rtm->rtm_errno = error; 63152564Ssklower rtm->rtm_addrs = info.rti_addrs; 63252564Ssklower } 63352564Ssklower route_proto.sp_protocol = sa ? sa->sa_family : 0; 63452564Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 63552564Ssklower } 63652564Ssklower } 63752564Ssklower 63836352Ssklower /* 63957836Smckusick * This is used in dumping the kernel table via sysctl(). 64040446Ssklower */ 64157836Smckusick sysctl_dumpentry(rn, w) 64240446Ssklower struct radix_node *rn; 64340446Ssklower register struct walkarg *w; 64440446Ssklower { 64540446Ssklower register struct sockaddr *sa; 64640446Ssklower register struct rtentry *rt = (struct rtentry *)rn; 64752564Ssklower int n, error = 0, size; 64852564Ssklower struct rt_addrinfo info; 64940446Ssklower 65057836Smckusick if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg)) 65150812Ssklower return 0; 65252564Ssklower bzero((caddr_t)&info, sizeof(info)); 65352564Ssklower dst = rt_key(rt); 65452564Ssklower gate = rt->rt_gateway; 65552564Ssklower netmask = rt_mask(rt); 65652564Ssklower genmask = rt->rt_genmask; 65752564Ssklower size = rt_msg2(RTM_GET, &info, 0, w); 65852564Ssklower if (w->w_where && w->w_tmem) { 65952564Ssklower register struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem; 66040446Ssklower 66152564Ssklower rtm->rtm_flags = rt->rt_flags; 66252564Ssklower rtm->rtm_use = rt->rt_use; 66352564Ssklower rtm->rtm_rmx = rt->rt_rmx; 66452564Ssklower rtm->rtm_index = rt->rt_ifp->if_index; 66552564Ssklower rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0; 66652564Ssklower rtm->rtm_addrs = info.rti_addrs; 66752564Ssklower if (error = copyout((caddr_t)rtm, w->w_where, size)) 66852564Ssklower w->w_where = NULL; 66952564Ssklower else 67052564Ssklower w->w_where += size; 67140446Ssklower } 67252564Ssklower return (error); 67352564Ssklower } 67452564Ssklower 67557836Smckusick sysctl_iflist(af, w) 67652564Ssklower int af; 67752564Ssklower register struct walkarg *w; 67852564Ssklower { 67952564Ssklower register struct ifnet *ifp; 68052564Ssklower register struct ifaddr *ifa; 68152564Ssklower struct rt_addrinfo info; 68252564Ssklower struct sockaddr *sa; 68352564Ssklower int len, error = 0; 68452564Ssklower 68552564Ssklower bzero((caddr_t)&info, sizeof(info)); 68652564Ssklower for (ifp = ifnet; ifp; ifp = ifp->if_next) { 68752631Ssklower if (w->w_arg && w->w_arg != ifp->if_index) 68852631Ssklower continue; 68952564Ssklower ifa = ifp->if_addrlist; 69052564Ssklower ifpaddr = ifa->ifa_addr; 69152564Ssklower len = rt_msg2(RTM_IFINFO, &info, (caddr_t)0, w); 69252564Ssklower ifpaddr = 0; 69352564Ssklower if (w->w_where && w->w_tmem) { 69452564Ssklower register struct if_msghdr *ifm; 69552564Ssklower 69652564Ssklower ifm = (struct if_msghdr *)w->w_tmem; 69752564Ssklower ifm->ifm_index = ifp->if_index; 69852564Ssklower ifm->ifm_flags = ifp->if_flags; 69952564Ssklower ifm->ifm_data = ifp->if_data; 70052564Ssklower ifm->ifm_addrs = info.rti_addrs; 70152564Ssklower if (error = copyout((caddr_t)ifm, w->w_where, len)) 70252564Ssklower return (error); 70352564Ssklower w->w_where += len; 70452564Ssklower } 70552564Ssklower while (ifa = ifa->ifa_next) { 70652631Ssklower if (af && af != ifa->ifa_addr->sa_family) 70752631Ssklower continue; 70852564Ssklower ifaaddr = ifa->ifa_addr; 70952564Ssklower netmask = ifa->ifa_netmask; 71052564Ssklower brdaddr = ifa->ifa_dstaddr; 71152564Ssklower len = rt_msg2(RTM_NEWADDR, &info, 0, w); 71252564Ssklower if (w->w_where && w->w_tmem) { 71352564Ssklower register struct ifa_msghdr *ifam; 71452564Ssklower 71552564Ssklower ifam = (struct ifa_msghdr *)w->w_tmem; 71652564Ssklower ifam->ifam_index = ifa->ifa_ifp->if_index; 71752564Ssklower ifam->ifam_flags = ifa->ifa_flags; 71852564Ssklower ifam->ifam_metric = ifa->ifa_metric; 71952564Ssklower ifam->ifam_addrs = info.rti_addrs; 72052564Ssklower if (error = copyout(w->w_tmem, w->w_where, len)) 72152564Ssklower return (error); 72252564Ssklower w->w_where += len; 72352564Ssklower } 72452564Ssklower } 72552631Ssklower ifaaddr = netmask = brdaddr = 0; 72652564Ssklower } 72740446Ssklower return (0); 72840446Ssklower } 72940446Ssklower 73057836Smckusick sysctl_rtable(name, namelen, where, given, new, newlen) 73157836Smckusick int *name; 73257836Smckusick int namelen; 73340446Ssklower caddr_t where; 734*58496Sbostic size_t *given; 73557836Smckusick caddr_t *new; 736*58496Sbostic size_t newlen; 73740446Ssklower { 73840446Ssklower register struct radix_node_head *rnh; 73952564Ssklower int i, s, error = EINVAL; 74057836Smckusick u_char af; 74140446Ssklower struct walkarg w; 74240446Ssklower 74357836Smckusick if (new) 74457836Smckusick return (EPERM); 74557836Smckusick if (namelen != 3) 74657836Smckusick return (EINVAL); 74757836Smckusick af = name[0]; 74840446Ssklower Bzero(&w, sizeof(w)); 74957836Smckusick w.w_where = where; 75057836Smckusick w.w_given = *given; 75140446Ssklower w.w_needed = 0 - w.w_given; 75257836Smckusick w.w_op = name[1]; 75357836Smckusick w.w_arg = name[2]; 75440446Ssklower 75540446Ssklower s = splnet(); 75657836Smckusick switch (w.w_op) { 75752564Ssklower 75857836Smckusick case NET_RT_DUMP: 75957836Smckusick case NET_RT_FLAGS: 76052564Ssklower for (i = 1; i <= AF_MAX; i++) 76152564Ssklower if ((rnh = rt_tables[i]) && (af == 0 || af == i) && 76252564Ssklower (error = rnh->rnh_walk(rnh->rnh_treetop, 76357836Smckusick sysctl_dumpentry, &w))) 76452564Ssklower break; 76552564Ssklower break; 76652564Ssklower 76757836Smckusick case NET_RT_IFLIST: 76857836Smckusick error = sysctl_iflist(af, &w); 76940446Ssklower } 77052564Ssklower splx(s); 77152564Ssklower if (w.w_tmem) 77252564Ssklower free(w.w_tmem, M_RTABLE); 77340446Ssklower w.w_needed += w.w_given; 77457836Smckusick if (where) { 77540446Ssklower *given = w.w_where - where; 77657836Smckusick if (*given < w.w_needed) 77757836Smckusick return (ENOMEM); 77857836Smckusick } else { 77957836Smckusick *given = (11 * w.w_needed) / 10; 78057836Smckusick } 78140446Ssklower return (error); 78240446Ssklower } 78340446Ssklower 78440446Ssklower /* 78536352Ssklower * Definitions of protocols supported in the ROUTE domain. 78636352Ssklower */ 78736352Ssklower 78854824Ssklower int raw_init(),raw_usrreq(),raw_input(),raw_ctlinput(), route_init(); 78936352Ssklower extern struct domain routedomain; /* or at least forward */ 79036352Ssklower 79136352Ssklower struct protosw routesw[] = { 79236352Ssklower { SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR, 79336352Ssklower raw_input, route_output, raw_ctlinput, 0, 79436352Ssklower route_usrreq, 79536352Ssklower raw_init, 0, 0, 0, 79657836Smckusick sysctl_rtable, 79736352Ssklower } 79836352Ssklower }; 79936352Ssklower 80036352Ssklower int unp_externalize(), unp_dispose(); 80136352Ssklower 80236352Ssklower struct domain routedomain = 80354824Ssklower { PF_ROUTE, "route", route_init, 0, 0, 80436352Ssklower routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] }; 805