136352Ssklower /* 250228Ssklower * Copyright (c) 1988, 1991 Regents of the University of California. 336352Ssklower * All rights reserved. 436352Ssklower * 544466Sbostic * %sccs.include.redist.c% 636352Ssklower * 7*52656Ssklower * @(#)rtsock.c 7.26 (Berkeley) 02/25/92 836352Ssklower */ 936352Ssklower 1036352Ssklower #include "param.h" 1152564Ssklower #include "proc.h" 1236352Ssklower #include "mbuf.h" 1336352Ssklower #include "socket.h" 1436352Ssklower #include "socketvar.h" 1536352Ssklower #include "domain.h" 1636352Ssklower #include "protosw.h" 1736352Ssklower 1836352Ssklower #include "af.h" 1940446Ssklower #include "if.h" 2036352Ssklower #include "route.h" 2136352Ssklower #include "raw_cb.h" 2236352Ssklower 2352564Ssklower struct sockaddr route_dst = { 2, PF_ROUTE, }; 2452564Ssklower struct sockaddr route_src = { 2, PF_ROUTE, }; 2552564Ssklower struct sockproto route_proto = { PF_ROUTE, }; 2637472Ssklower 2752564Ssklower struct walkarg { 2852564Ssklower int w_op, w_arg, w_given, w_needed, w_tmemsize; 2952564Ssklower caddr_t w_where, w_tmem; 3052564Ssklower }; 3152564Ssklower 3252564Ssklower static void rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *)); 3352564Ssklower static struct mbuf *rt_msg1 __P((int, struct rt_addrinfo *)); 3452564Ssklower static int rt_msg2 __P((int, struct rt_addrinfo *, caddr_t, 3552564Ssklower struct walkarg *)); 3652564Ssklower 3752564Ssklower /* Sleazy use of local variables throughout file, warning!!!! */ 3852564Ssklower #define dst info.rti_info[RTAX_DST] 3952564Ssklower #define gate info.rti_info[RTAX_GATEWAY] 4052564Ssklower #define netmask info.rti_info[RTAX_NETMASK] 4152564Ssklower #define genmask info.rti_info[RTAX_GENMASK] 4252564Ssklower #define ifpaddr info.rti_info[RTAX_IFP] 4352564Ssklower #define ifaaddr info.rti_info[RTAX_IFA] 4452564Ssklower #define brdaddr info.rti_info[RTAX_BRD] 4552564Ssklower 4636352Ssklower /*ARGSUSED*/ 4740446Ssklower route_usrreq(so, req, m, nam, control) 4836352Ssklower register struct socket *so; 4936352Ssklower int req; 5040446Ssklower struct mbuf *m, *nam, *control; 5136352Ssklower { 5236352Ssklower register int error = 0; 5336352Ssklower register struct rawcb *rp = sotorawcb(so); 5444949Ssklower int s; 5537472Ssklower if (req == PRU_ATTACH) { 5637472Ssklower MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK); 5737472Ssklower if (so->so_pcb = (caddr_t)rp) 5837472Ssklower bzero(so->so_pcb, sizeof(*rp)); 5937472Ssklower 6037472Ssklower } 6136352Ssklower if (req == PRU_DETACH && rp) { 6236352Ssklower int af = rp->rcb_proto.sp_protocol; 6336352Ssklower if (af == AF_INET) 6436352Ssklower route_cb.ip_count--; 6536352Ssklower else if (af == AF_NS) 6636352Ssklower route_cb.ns_count--; 6736352Ssklower else if (af == AF_ISO) 6836352Ssklower route_cb.iso_count--; 6936352Ssklower route_cb.any_count--; 7036352Ssklower } 7144949Ssklower s = splnet(); 7240446Ssklower error = raw_usrreq(so, req, m, nam, control); 7336352Ssklower rp = sotorawcb(so); 7437472Ssklower if (req == PRU_ATTACH && rp) { 7536352Ssklower int af = rp->rcb_proto.sp_protocol; 7637472Ssklower if (error) { 7737472Ssklower free((caddr_t)rp, M_PCB); 7844949Ssklower splx(s); 7937472Ssklower return (error); 8037472Ssklower } 8136352Ssklower if (af == AF_INET) 8236352Ssklower route_cb.ip_count++; 8336352Ssklower else if (af == AF_NS) 8436352Ssklower route_cb.ns_count++; 8536352Ssklower else if (af == AF_ISO) 8636352Ssklower route_cb.iso_count++; 8737472Ssklower rp->rcb_faddr = &route_src; 8836352Ssklower route_cb.any_count++; 8936352Ssklower soisconnected(so); 9042356Ssklower so->so_options |= SO_USELOOPBACK; 9136352Ssklower } 9244949Ssklower splx(s); 9336352Ssklower return (error); 9436352Ssklower } 9536352Ssklower 9637472Ssklower /*ARGSUSED*/ 9736352Ssklower route_output(m, so) 9836352Ssklower register struct mbuf *m; 9936352Ssklower struct socket *so; 10036352Ssklower { 10144949Ssklower register struct rt_msghdr *rtm = 0; 10236352Ssklower register struct rtentry *rt = 0; 10340446Ssklower struct rtentry *saved_nrt = 0; 10452564Ssklower struct rt_addrinfo info; 10537472Ssklower int len, error = 0; 10643336Ssklower struct ifnet *ifp = 0; 10747465Ssklower struct ifaddr *ifa = 0; 10847465Ssklower struct ifaddr *ifaof_ifpforaddr(), *ifa_ifwithroute(); 10936352Ssklower 11040446Ssklower #define senderr(e) { error = e; goto flush;} 11140786Ssklower if (m == 0 || m->m_len < sizeof(long)) 11238847Ssklower return (ENOBUFS); 11340786Ssklower if ((m = m_pullup(m, sizeof(long))) == 0) 11440786Ssklower return (ENOBUFS); 11536352Ssklower if ((m->m_flags & M_PKTHDR) == 0) 11638847Ssklower panic("route_output"); 11736352Ssklower len = m->m_pkthdr.len; 11844949Ssklower if (len < sizeof(*rtm) || 11944949Ssklower len != mtod(m, struct rt_msghdr *)->rtm_msglen) 12040446Ssklower senderr(EINVAL); 12136352Ssklower R_Malloc(rtm, struct rt_msghdr *, len); 12236352Ssklower if (rtm == 0) 12340446Ssklower senderr(ENOBUFS); 12436352Ssklower m_copydata(m, 0, len, (caddr_t)rtm); 12540786Ssklower if (rtm->rtm_version != RTM_VERSION) 12640446Ssklower senderr(EPROTONOSUPPORT); 12748729Ssklower rtm->rtm_pid = curproc->p_pid; 12852564Ssklower info.rti_addrs = rtm->rtm_addrs; 12952564Ssklower rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info); 13052564Ssklower if (dst == 0) 13140786Ssklower senderr(EINVAL); 13252564Ssklower if (genmask) { 13343336Ssklower struct radix_node *t, *rn_addmask(); 13443336Ssklower t = rn_addmask(genmask, 1, 2); 13543336Ssklower if (t && Bcmp(genmask, t->rn_key, *(u_char *)genmask) == 0) 13643336Ssklower genmask = (struct sockaddr *)(t->rn_key); 13743336Ssklower else 13843336Ssklower senderr(ENOBUFS); 13936352Ssklower } 14036352Ssklower switch (rtm->rtm_type) { 14152564Ssklower 14236352Ssklower case RTM_ADD: 14340786Ssklower if (gate == 0) 14440786Ssklower senderr(EINVAL); 14536352Ssklower error = rtrequest(RTM_ADD, dst, gate, netmask, 14636352Ssklower rtm->rtm_flags, &saved_nrt); 14740786Ssklower if (error == 0 && saved_nrt) { 14840786Ssklower rt_setmetrics(rtm->rtm_inits, 14940786Ssklower &rtm->rtm_rmx, &saved_nrt->rt_rmx); 15040446Ssklower saved_nrt->rt_refcnt--; 15143336Ssklower saved_nrt->rt_genmask = genmask; 15240786Ssklower } 15336352Ssklower break; 15436352Ssklower 15536352Ssklower case RTM_DELETE: 15636352Ssklower error = rtrequest(RTM_DELETE, dst, gate, netmask, 15737472Ssklower rtm->rtm_flags, (struct rtentry **)0); 15836352Ssklower break; 15936352Ssklower 16036352Ssklower case RTM_GET: 16136352Ssklower case RTM_CHANGE: 16236352Ssklower case RTM_LOCK: 16336352Ssklower rt = rtalloc1(dst, 0); 16436352Ssklower if (rt == 0) 16540446Ssklower senderr(ESRCH); 166*52656Ssklower if (rtm->rtm_type != RTM_GET) {/* XXX: too grotty */ 167*52656Ssklower struct radix_node *rn, *rn_search(); 168*52656Ssklower extern struct radix_node_head *mask_rnhead; 169*52656Ssklower 17047465Ssklower if (Bcmp(dst, rt_key(rt), dst->sa_len) != 0) 17147465Ssklower senderr(ESRCH); 172*52656Ssklower if (netmask && (rn = rn_search(netmask, 173*52656Ssklower mask_rnhead->rnh_treetop))) 174*52656Ssklower netmask = (struct sockaddr *)rn->rn_key; 175*52656Ssklower for (rn = rt->rt_nodes; rn; rn = rn->rn_dupedkey) 176*52656Ssklower if (netmask == (struct sockaddr *)rn->rn_mask) 177*52656Ssklower break; 178*52656Ssklower if (rn == 0) 17945183Ssklower senderr(ETOOMANYREFS); 180*52656Ssklower rt = (struct rtentry *)rn; 18145183Ssklower } 18236352Ssklower switch(rtm->rtm_type) { 18336352Ssklower 18436352Ssklower case RTM_GET: 18552564Ssklower dst = rt_key(rt); 18652564Ssklower gate = rt->rt_gateway; 18752564Ssklower netmask = rt_mask(rt); 18852564Ssklower genmask = rt->rt_genmask; 18945656Ssklower if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) { 19052564Ssklower if (ifp = rt->rt_ifp) { 19152564Ssklower ifpaddr = ifp->if_addrlist->ifa_addr; 19245656Ssklower ifaaddr = rt->rt_ifa->ifa_addr; 19352564Ssklower rtm->rtm_index = ifp->if_index; 19445656Ssklower } else { 19552564Ssklower ifpaddr = 0; 19652564Ssklower ifaaddr = 0; 19752564Ssklower } 19845656Ssklower } 19952564Ssklower len = rt_msg2(RTM_GET, &info, (caddr_t)0, 20052564Ssklower (struct walkarg *)0); 20136352Ssklower if (len > rtm->rtm_msglen) { 20236352Ssklower struct rt_msghdr *new_rtm; 20336352Ssklower R_Malloc(new_rtm, struct rt_msghdr *, len); 20436352Ssklower if (new_rtm == 0) 20540446Ssklower senderr(ENOBUFS); 20636352Ssklower Bcopy(rtm, new_rtm, rtm->rtm_msglen); 20736352Ssklower Free(rtm); rtm = new_rtm; 20836352Ssklower } 20952564Ssklower (void)rt_msg2(RTM_GET, &info, (caddr_t)rtm, 21052564Ssklower (struct walkarg *)0); 21145183Ssklower rtm->rtm_flags = rt->rt_flags; 21245183Ssklower rtm->rtm_rmx = rt->rt_rmx; 21336352Ssklower break; 21436352Ssklower 21536352Ssklower case RTM_CHANGE: 21650229Ssklower if (gate && rt_setgate(rt, rt_key(rt), gate)) 21740446Ssklower senderr(EDQUOT); 21843336Ssklower /* new gateway could require new ifaddr, ifp; 21943336Ssklower flags may also be different; ifp may be specified 22043336Ssklower by ll sockaddr when protocol address is ambiguous */ 22147465Ssklower if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) && 22247465Ssklower (ifp = ifa->ifa_ifp)) 22347465Ssklower ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate, 22447465Ssklower ifp); 22547465Ssklower else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) || 22647465Ssklower (ifa = ifa_ifwithroute(rt->rt_flags, 22747465Ssklower rt_key(rt), gate))) 22847465Ssklower ifp = ifa->ifa_ifp; 22943336Ssklower if (ifa) { 23047465Ssklower register struct ifaddr *oifa = rt->rt_ifa; 23147465Ssklower if (oifa != ifa) { 23247465Ssklower if (oifa && oifa->ifa_rtrequest) 23347465Ssklower oifa->ifa_rtrequest(RTM_DELETE, 23447465Ssklower rt, gate); 23543336Ssklower rt->rt_ifa = ifa; 23647465Ssklower rt->rt_ifp = ifp; 23743336Ssklower } 23843336Ssklower } 23947465Ssklower rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, 24047465Ssklower &rt->rt_rmx); 24143336Ssklower if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) 24243336Ssklower rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, gate); 24343336Ssklower if (genmask) 24443336Ssklower rt->rt_genmask = genmask; 24536352Ssklower /* 24636352Ssklower * Fall into 24736352Ssklower */ 24840786Ssklower case RTM_LOCK: 24950811Ssklower rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); 25040786Ssklower rt->rt_rmx.rmx_locks |= 25140786Ssklower (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); 25236352Ssklower break; 25336352Ssklower } 25452564Ssklower break; 25536352Ssklower 25636352Ssklower default: 25740446Ssklower senderr(EOPNOTSUPP); 25836352Ssklower } 25936352Ssklower 26036352Ssklower flush: 26136352Ssklower if (rtm) { 26236352Ssklower if (error) 26336352Ssklower rtm->rtm_errno = error; 26436352Ssklower else 26536352Ssklower rtm->rtm_flags |= RTF_DONE; 26636352Ssklower } 26736352Ssklower cleanup: 26836352Ssklower if (rt) 26936352Ssklower rtfree(rt); 27042356Ssklower { 27142356Ssklower register struct rawcb *rp = 0; 27242356Ssklower /* 27342356Ssklower * Check to see if we don't want our own messages. 27442356Ssklower */ 27542356Ssklower if ((so->so_options & SO_USELOOPBACK) == 0) { 27642356Ssklower if (route_cb.any_count <= 1) { 27742356Ssklower if (rtm) 27842356Ssklower Free(rtm); 27942356Ssklower m_freem(m); 28042356Ssklower return (error); 28142356Ssklower } 28242356Ssklower /* There is another listener, so construct message */ 28342356Ssklower rp = sotorawcb(so); 28442356Ssklower } 28545656Ssklower if (rtm) { 28645656Ssklower m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm); 28738847Ssklower Free(rtm); 28838847Ssklower } 28942356Ssklower if (rp) 29042356Ssklower rp->rcb_proto.sp_family = 0; /* Avoid us */ 29145183Ssklower if (dst) 29245183Ssklower route_proto.sp_protocol = dst->sa_family; 29338847Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 29442356Ssklower if (rp) 29542356Ssklower rp->rcb_proto.sp_family = PF_ROUTE; 29642356Ssklower } 29736352Ssklower return (error); 29836352Ssklower } 29936352Ssklower 30043336Ssklower rt_setmetrics(which, in, out) 30140786Ssklower u_long which; 30240786Ssklower register struct rt_metrics *in, *out; 30340786Ssklower { 30440786Ssklower #define metric(f, e) if (which & (f)) out->e = in->e; 30540786Ssklower metric(RTV_RPIPE, rmx_recvpipe); 30640786Ssklower metric(RTV_SPIPE, rmx_sendpipe); 30740786Ssklower metric(RTV_SSTHRESH, rmx_ssthresh); 30840786Ssklower metric(RTV_RTT, rmx_rtt); 30940786Ssklower metric(RTV_RTTVAR, rmx_rttvar); 31040786Ssklower metric(RTV_HOPCOUNT, rmx_hopcount); 31140786Ssklower metric(RTV_MTU, rmx_mtu); 31250228Ssklower metric(RTV_EXPIRE, rmx_expire); 31340786Ssklower #undef metric 31440786Ssklower } 31540786Ssklower 31652564Ssklower #define ROUNDUP(a) \ 31752564Ssklower ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 31852564Ssklower #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 31952564Ssklower 32052564Ssklower static void 32152564Ssklower rt_xaddrs(cp, cplim, rtinfo) 32252564Ssklower register caddr_t cp, cplim; 32352564Ssklower register struct rt_addrinfo *rtinfo; 32452564Ssklower { 32552564Ssklower register struct sockaddr *sa; 32652564Ssklower register int i; 32752564Ssklower 32852564Ssklower bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info)); 32952564Ssklower for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { 33052564Ssklower if ((rtinfo->rti_addrs & (1 << i)) == 0) 33152564Ssklower continue; 33252564Ssklower rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; 33352564Ssklower ADVANCE(cp, sa); 33452564Ssklower } 33552564Ssklower } 33636352Ssklower /* 33736352Ssklower * Copy data from a buffer back into the indicated mbuf chain, 33836352Ssklower * starting "off" bytes from the beginning, extending the mbuf 33936352Ssklower * chain if necessary. 34036352Ssklower */ 34136352Ssklower m_copyback(m0, off, len, cp) 34236352Ssklower struct mbuf *m0; 34336352Ssklower register int off; 34436352Ssklower register int len; 34536352Ssklower caddr_t cp; 34636352Ssklower 34736352Ssklower { 34836352Ssklower register int mlen; 34936352Ssklower register struct mbuf *m = m0, *n; 35036352Ssklower int totlen = 0; 35136352Ssklower 35236352Ssklower if (m0 == 0) 35336352Ssklower return; 35448729Ssklower while (off > (mlen = m->m_len)) { 35536352Ssklower off -= mlen; 35636352Ssklower totlen += mlen; 35736352Ssklower if (m->m_next == 0) { 35836352Ssklower n = m_getclr(M_DONTWAIT, m->m_type); 35936352Ssklower if (n == 0) 36036352Ssklower goto out; 36136352Ssklower n->m_len = min(MLEN, len + off); 36236352Ssklower m->m_next = n; 36336352Ssklower } 36436352Ssklower m = m->m_next; 36536352Ssklower } 36636352Ssklower while (len > 0) { 36736352Ssklower mlen = min (m->m_len - off, len); 36837472Ssklower bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen); 36936352Ssklower cp += mlen; 37036352Ssklower len -= mlen; 37136352Ssklower mlen += off; 37236352Ssklower off = 0; 37336352Ssklower totlen += mlen; 37436352Ssklower if (len == 0) 37536352Ssklower break; 37636352Ssklower if (m->m_next == 0) { 37736352Ssklower n = m_get(M_DONTWAIT, m->m_type); 37836352Ssklower if (n == 0) 37936352Ssklower break; 38036352Ssklower n->m_len = min(MLEN, len); 38136352Ssklower m->m_next = n; 38236352Ssklower } 38336352Ssklower m = m->m_next; 38436352Ssklower } 38536352Ssklower out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) 38636352Ssklower m->m_pkthdr.len = totlen; 38736352Ssklower } 38836352Ssklower 38952564Ssklower static struct mbuf * 39052564Ssklower rt_msg1(type, rtinfo) 39152564Ssklower int type; 39252564Ssklower register struct rt_addrinfo *rtinfo; 39336352Ssklower { 39436352Ssklower register struct rt_msghdr *rtm; 39536352Ssklower register struct mbuf *m; 39652564Ssklower register int i; 39752564Ssklower register struct sockaddr *sa; 39852564Ssklower int len, dlen; 39936352Ssklower 40036352Ssklower m = m_gethdr(M_DONTWAIT, MT_DATA); 40136352Ssklower if (m == 0) 40252564Ssklower return (m); 40352564Ssklower switch (type) { 40452564Ssklower 40552564Ssklower case RTM_DELADDR: 40652564Ssklower case RTM_NEWADDR: 40752564Ssklower len = sizeof(struct ifa_msghdr); 40852564Ssklower break; 40952564Ssklower 41052564Ssklower case RTM_IFINFO: 41152564Ssklower len = sizeof(struct if_msghdr); 41252564Ssklower break; 41352564Ssklower 41452564Ssklower default: 41552564Ssklower len = sizeof(struct rt_msghdr); 41652564Ssklower } 41752564Ssklower if (len > MHLEN) 41852564Ssklower panic("rt_msg1"); 41952564Ssklower m->m_pkthdr.len = m->m_len = len; 42036352Ssklower m->m_pkthdr.rcvif = 0; 42136352Ssklower rtm = mtod(m, struct rt_msghdr *); 42252564Ssklower bzero((caddr_t)rtm, len); 42352564Ssklower for (i = 0; i < RTAX_MAX; i++) { 42452564Ssklower if ((sa = rtinfo->rti_info[i]) == NULL) 42552564Ssklower continue; 42652564Ssklower rtinfo->rti_addrs |= (1 << i); 42752564Ssklower dlen = ROUNDUP(sa->sa_len); 42852564Ssklower m_copyback(m, len, dlen, (caddr_t)sa); 42952564Ssklower len += dlen; 43052564Ssklower } 43152564Ssklower if (m->m_pkthdr.len != len) { 43252564Ssklower m_freem(m); 43352564Ssklower return (NULL); 43452564Ssklower } 43536352Ssklower rtm->rtm_msglen = len; 43640786Ssklower rtm->rtm_version = RTM_VERSION; 43736352Ssklower rtm->rtm_type = type; 43852564Ssklower return (m); 43952564Ssklower } 44052564Ssklower 44152564Ssklower static int 44252564Ssklower rt_msg2(type, rtinfo, cp, w) 44352564Ssklower int type; 44452564Ssklower register struct rt_addrinfo *rtinfo; 44552564Ssklower caddr_t cp; 44652564Ssklower struct walkarg *w; 44752564Ssklower { 44852564Ssklower register int i; 44952564Ssklower int len, dlen, second_time = 0; 45052564Ssklower caddr_t cp0; 45152564Ssklower 45252564Ssklower rtinfo->rti_addrs = 0; 45352564Ssklower again: 45452564Ssklower switch (type) { 45552564Ssklower 45652564Ssklower case RTM_DELADDR: 45752564Ssklower case RTM_NEWADDR: 45852564Ssklower len = sizeof(struct ifa_msghdr); 45952564Ssklower break; 46052564Ssklower 46152564Ssklower case RTM_IFINFO: 46252564Ssklower len = sizeof(struct if_msghdr); 46352564Ssklower break; 46452564Ssklower 46552564Ssklower default: 46652564Ssklower len = sizeof(struct rt_msghdr); 46736352Ssklower } 46852564Ssklower if (cp0 = cp) 46952564Ssklower cp += len; 47052564Ssklower for (i = 0; i < RTAX_MAX; i++) { 47152564Ssklower register struct sockaddr *sa; 47252564Ssklower 47352564Ssklower if ((sa = rtinfo->rti_info[i]) == 0) 47452564Ssklower continue; 47552564Ssklower rtinfo->rti_addrs |= (1 << i); 47652564Ssklower dlen = ROUNDUP(sa->sa_len); 47752564Ssklower if (cp) { 47852564Ssklower bcopy((caddr_t)sa, cp, (unsigned)dlen); 47952564Ssklower cp += dlen; 48052564Ssklower } 48136352Ssklower len += dlen; 48236352Ssklower } 48352564Ssklower if (cp == 0 && w != NULL && !second_time) { 48452564Ssklower register struct walkarg *rw = w; 48552564Ssklower 48652564Ssklower rw->w_needed += len; 48752564Ssklower if (rw->w_needed <= 0 && rw->w_where) { 48852564Ssklower if (rw->w_tmemsize < len) { 48952564Ssklower if (rw->w_tmem) 49052564Ssklower free(rw->w_tmem, M_RTABLE); 49152564Ssklower if (rw->w_tmem = (caddr_t) 49252564Ssklower malloc(len, M_RTABLE, M_NOWAIT)) 49352564Ssklower rw->w_tmemsize = len; 49452564Ssklower } 49552564Ssklower if (rw->w_tmem) { 49652564Ssklower cp = rw->w_tmem; 49752564Ssklower second_time = 1; 49852564Ssklower goto again; 49952564Ssklower } else 50052564Ssklower rw->w_where = 0; 50152564Ssklower } 50236352Ssklower } 50352564Ssklower if (cp) { 50452564Ssklower register struct rt_msghdr *rtm = (struct rt_msghdr *)cp0; 50552564Ssklower 50652564Ssklower rtm->rtm_version = RTM_VERSION; 50752564Ssklower rtm->rtm_type = type; 50852564Ssklower rtm->rtm_msglen = len; 50936352Ssklower } 51052564Ssklower return (len); 51152564Ssklower } 51252564Ssklower 51352564Ssklower /* 51452564Ssklower * This routine is called to generate a message from the routing 51552564Ssklower * socket indicating that a redirect has occured, a routing lookup 51652564Ssklower * has failed, or that a protocol has detected timeouts to a particular 51752564Ssklower * destination. 51852564Ssklower */ 51952564Ssklower rt_missmsg(type, rtinfo, flags, error) 52052564Ssklower int type, flags, error; 52152564Ssklower register struct rt_addrinfo *rtinfo; 52252564Ssklower { 52352564Ssklower register struct rt_msghdr *rtm; 52452564Ssklower register struct mbuf *m; 52552564Ssklower register int i; 52652564Ssklower struct sockaddr *sa = rtinfo->rti_info[RTAX_DST]; 52752564Ssklower 52852564Ssklower if (route_cb.any_count == 0) 52936352Ssklower return; 53052564Ssklower m = rt_msg1(type, rtinfo); 53152564Ssklower if (m == 0) 53252564Ssklower return; 53352564Ssklower rtm = mtod(m, struct rt_msghdr *); 53452564Ssklower rtm->rtm_flags = RTF_DONE | flags; 53537472Ssklower rtm->rtm_errno = error; 53652564Ssklower rtm->rtm_addrs = rtinfo->rti_addrs; 53752564Ssklower route_proto.sp_protocol = sa ? sa->sa_family : 0; 53836352Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 53936352Ssklower } 54036352Ssklower 54152564Ssklower /* 54252564Ssklower * This routine is called to generate a message from the routing 54352564Ssklower * socket indicating that the status of a network interface has changed. 54452564Ssklower */ 54552564Ssklower rt_ifmsg(ifp) 54652564Ssklower register struct ifnet *ifp; 54752564Ssklower { 54852564Ssklower register struct if_msghdr *ifm; 54952564Ssklower struct mbuf *m; 55052564Ssklower struct rt_addrinfo info; 55152564Ssklower 55252564Ssklower if (route_cb.any_count == 0) 55352564Ssklower return; 55452564Ssklower bzero((caddr_t)&info, sizeof(info)); 55552564Ssklower m = rt_msg1(RTM_IFINFO, &info); 55652564Ssklower if (m == 0) 55752564Ssklower return; 55852564Ssklower ifm = mtod(m, struct if_msghdr *); 55952564Ssklower ifm->ifm_index = ifp->if_index; 56052564Ssklower ifm->ifm_flags = ifp->if_flags; 56152564Ssklower ifm->ifm_data = ifp->if_data; 56252564Ssklower ifm->ifm_addrs = 0; 56352564Ssklower route_proto.sp_protocol = 0; 56452564Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 56552564Ssklower } 56652564Ssklower 56752564Ssklower /* 56852564Ssklower * This is called to generate messages from the routing socket 56952564Ssklower * indicating a network interface has had addresses associated with it. 57052564Ssklower * if we ever reverse the logic and replace messages TO the routing 57152564Ssklower * socket indicate a request to configure interfaces, then it will 57252564Ssklower * be unnecessary as the routing socket will automatically generate 57352564Ssklower * copies of it. 57452564Ssklower */ 57552564Ssklower rt_newaddrmsg(cmd, ifa, error, rt) 57652564Ssklower int cmd, error; 57752564Ssklower register struct ifaddr *ifa; 57852564Ssklower register struct rtentry *rt; 57952564Ssklower { 58052564Ssklower struct rt_addrinfo info; 58152564Ssklower struct sockaddr *sa; 58252564Ssklower int pass; 58352564Ssklower struct mbuf *m; 58452564Ssklower struct ifnet *ifp = ifa->ifa_ifp; 58552564Ssklower 58652564Ssklower if (route_cb.any_count == 0) 58752564Ssklower return; 58852564Ssklower for (pass = 1; pass < 3; pass++) { 58952564Ssklower bzero((caddr_t)&info, sizeof(info)); 59052564Ssklower if ((cmd == RTM_ADD && pass == 1) || 59152564Ssklower (cmd == RTM_DELETE && pass == 2)) { 59252564Ssklower register struct ifa_msghdr *ifam; 59352564Ssklower int ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR; 59452564Ssklower 59552564Ssklower ifaaddr = sa = ifa->ifa_addr; 59652564Ssklower ifpaddr = ifp->if_addrlist->ifa_addr; 59752564Ssklower netmask = ifa->ifa_netmask; 59852564Ssklower brdaddr = ifa->ifa_dstaddr; 59952564Ssklower if ((m = rt_msg1(ncmd, &info)) == NULL) 60052564Ssklower continue; 60152564Ssklower ifam = mtod(m, struct ifa_msghdr *); 60252564Ssklower ifam->ifam_index = ifp->if_index; 60352564Ssklower ifam->ifam_metric = ifa->ifa_metric; 60452564Ssklower ifam->ifam_addrs = info.rti_addrs; 60552564Ssklower } 60652564Ssklower if ((cmd == RTM_ADD && pass == 2) || 60752564Ssklower (cmd == RTM_DELETE && pass == 1)) { 60852564Ssklower register struct rt_msghdr *rtm; 60952564Ssklower 61052564Ssklower if (rt == 0) 61152564Ssklower continue; 61252564Ssklower netmask = rt_mask(rt); 61352564Ssklower dst = sa = rt_key(rt); 61452564Ssklower gate = rt->rt_gateway; 61552564Ssklower if ((m = rt_msg1(cmd, &info)) == NULL) 61652564Ssklower continue; 61752564Ssklower rtm = mtod(m, struct rt_msghdr *); 61852564Ssklower rtm->rtm_index = ifp->if_index; 61952564Ssklower rtm->rtm_flags |= rt->rt_flags; 62052564Ssklower rtm->rtm_errno = error; 62152564Ssklower rtm->rtm_addrs = info.rti_addrs; 62252564Ssklower } 62352564Ssklower route_proto.sp_protocol = sa ? sa->sa_family : 0; 62452564Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 62552564Ssklower } 62652564Ssklower } 62752564Ssklower 62840446Ssklower #include "kinfo.h" 62936352Ssklower /* 63040446Ssklower * This is used in dumping the kernel table via getkinfo(). 63140446Ssklower */ 63240446Ssklower rt_dumpentry(rn, w) 63340446Ssklower struct radix_node *rn; 63440446Ssklower register struct walkarg *w; 63540446Ssklower { 63640446Ssklower register struct sockaddr *sa; 63740446Ssklower register struct rtentry *rt = (struct rtentry *)rn; 63852564Ssklower int n, error = 0, size; 63952564Ssklower struct rt_addrinfo info; 64040446Ssklower 64140446Ssklower if (w->w_op == KINFO_RT_FLAGS && !(rt->rt_flags & w->w_arg)) 64250812Ssklower return 0; 64352564Ssklower bzero((caddr_t)&info, sizeof(info)); 64452564Ssklower dst = rt_key(rt); 64552564Ssklower gate = rt->rt_gateway; 64652564Ssklower netmask = rt_mask(rt); 64752564Ssklower genmask = rt->rt_genmask; 64852564Ssklower size = rt_msg2(RTM_GET, &info, 0, w); 64952564Ssklower if (w->w_where && w->w_tmem) { 65052564Ssklower register struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem; 65140446Ssklower 65252564Ssklower rtm->rtm_flags = rt->rt_flags; 65352564Ssklower rtm->rtm_use = rt->rt_use; 65452564Ssklower rtm->rtm_rmx = rt->rt_rmx; 65552564Ssklower rtm->rtm_index = rt->rt_ifp->if_index; 65652564Ssklower rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0; 65752564Ssklower rtm->rtm_addrs = info.rti_addrs; 65852564Ssklower if (error = copyout((caddr_t)rtm, w->w_where, size)) 65952564Ssklower w->w_where = NULL; 66052564Ssklower else 66152564Ssklower w->w_where += size; 66240446Ssklower } 66352564Ssklower return (error); 66452564Ssklower } 66552564Ssklower 66652564Ssklower kinfo_iflist(af, w) 66752564Ssklower int af; 66852564Ssklower register struct walkarg *w; 66952564Ssklower { 67052564Ssklower register struct ifnet *ifp; 67152564Ssklower register struct ifaddr *ifa; 67252564Ssklower struct rt_addrinfo info; 67352564Ssklower struct sockaddr *sa; 67452564Ssklower int len, error = 0; 67552564Ssklower 67652564Ssklower bzero((caddr_t)&info, sizeof(info)); 67752564Ssklower for (ifp = ifnet; ifp; ifp = ifp->if_next) { 67852631Ssklower if (w->w_arg && w->w_arg != ifp->if_index) 67952631Ssklower continue; 68052564Ssklower ifa = ifp->if_addrlist; 68152564Ssklower ifpaddr = ifa->ifa_addr; 68252564Ssklower len = rt_msg2(RTM_IFINFO, &info, (caddr_t)0, w); 68352564Ssklower ifpaddr = 0; 68452564Ssklower if (w->w_where && w->w_tmem) { 68552564Ssklower register struct if_msghdr *ifm; 68652564Ssklower 68752564Ssklower ifm = (struct if_msghdr *)w->w_tmem; 68852564Ssklower ifm->ifm_index = ifp->if_index; 68952564Ssklower ifm->ifm_flags = ifp->if_flags; 69052564Ssklower ifm->ifm_data = ifp->if_data; 69152564Ssklower ifm->ifm_addrs = info.rti_addrs; 69252564Ssklower if (error = copyout((caddr_t)ifm, w->w_where, len)) 69352564Ssklower return (error); 69452564Ssklower w->w_where += len; 69552564Ssklower } 69652564Ssklower while (ifa = ifa->ifa_next) { 69752631Ssklower if (af && af != ifa->ifa_addr->sa_family) 69852631Ssklower continue; 69952564Ssklower ifaaddr = ifa->ifa_addr; 70052564Ssklower netmask = ifa->ifa_netmask; 70152564Ssklower brdaddr = ifa->ifa_dstaddr; 70252564Ssklower len = rt_msg2(RTM_NEWADDR, &info, 0, w); 70352564Ssklower if (w->w_where && w->w_tmem) { 70452564Ssklower register struct ifa_msghdr *ifam; 70552564Ssklower 70652564Ssklower ifam = (struct ifa_msghdr *)w->w_tmem; 70752564Ssklower ifam->ifam_index = ifa->ifa_ifp->if_index; 70852564Ssklower ifam->ifam_flags = ifa->ifa_flags; 70952564Ssklower ifam->ifam_metric = ifa->ifa_metric; 71052564Ssklower ifam->ifam_addrs = info.rti_addrs; 71152564Ssklower if (error = copyout(w->w_tmem, w->w_where, len)) 71252564Ssklower return (error); 71352564Ssklower w->w_where += len; 71452564Ssklower } 71552564Ssklower } 71652631Ssklower ifaaddr = netmask = brdaddr = 0; 71752564Ssklower } 71840446Ssklower return (0); 71940446Ssklower } 72040446Ssklower 72140446Ssklower kinfo_rtable(op, where, given, arg, needed) 72240446Ssklower int op, arg; 72340446Ssklower caddr_t where; 72440446Ssklower int *given, *needed; 72540446Ssklower { 72640446Ssklower register struct radix_node_head *rnh; 72752564Ssklower int i, s, error = EINVAL; 72840446Ssklower u_char af = ki_af(op); 72940446Ssklower struct walkarg w; 73040446Ssklower 73140446Ssklower Bzero(&w, sizeof(w)); 73240446Ssklower if ((w.w_where = where) && given) 73340446Ssklower w.w_given = *given; 73440446Ssklower w.w_needed = 0 - w.w_given; 73540446Ssklower w.w_arg = arg; 73652631Ssklower w.w_op = op = ki_op(op); 73740446Ssklower 73840446Ssklower s = splnet(); 73952564Ssklower switch (op) { 74052564Ssklower 74152564Ssklower case KINFO_RT_DUMP: 74252564Ssklower case KINFO_RT_FLAGS: 74352564Ssklower for (i = 1; i <= AF_MAX; i++) 74452564Ssklower if ((rnh = rt_tables[i]) && (af == 0 || af == i) && 74552564Ssklower (error = rnh->rnh_walk(rnh->rnh_treetop, 74652564Ssklower rt_dumpentry, &w))) 74752564Ssklower break; 74852564Ssklower break; 74952564Ssklower 75052564Ssklower case KINFO_RT_IFLIST: 75152564Ssklower error = kinfo_iflist(af, &w); 75240446Ssklower } 75352564Ssklower splx(s); 75452564Ssklower if (w.w_tmem) 75552564Ssklower free(w.w_tmem, M_RTABLE); 75640446Ssklower w.w_needed += w.w_given; 75740446Ssklower if (where && given) 75840446Ssklower *given = w.w_where - where; 75940446Ssklower else 76040446Ssklower w.w_needed = (11 * w.w_needed) / 10; 76140446Ssklower *needed = w.w_needed; 76240446Ssklower return (error); 76340446Ssklower } 76440446Ssklower 76540446Ssklower /* 76636352Ssklower * Definitions of protocols supported in the ROUTE domain. 76736352Ssklower */ 76836352Ssklower 76936352Ssklower int raw_init(),raw_usrreq(),raw_input(),raw_ctlinput(); 77036352Ssklower extern struct domain routedomain; /* or at least forward */ 77136352Ssklower 77236352Ssklower struct protosw routesw[] = { 77336352Ssklower { SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR, 77436352Ssklower raw_input, route_output, raw_ctlinput, 0, 77536352Ssklower route_usrreq, 77636352Ssklower raw_init, 0, 0, 0, 77736352Ssklower } 77836352Ssklower }; 77936352Ssklower 78036352Ssklower int unp_externalize(), unp_dispose(); 78136352Ssklower 78236352Ssklower struct domain routedomain = 78336352Ssklower { PF_ROUTE, "route", 0, 0, 0, 78436352Ssklower routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] }; 785