136352Ssklower /* 250228Ssklower * Copyright (c) 1988, 1991 Regents of the University of California. 336352Ssklower * All rights reserved. 436352Ssklower * 544466Sbostic * %sccs.include.redist.c% 636352Ssklower * 7*52808Sralph * @(#)rtsock.c 7.27 (Berkeley) 03/02/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) || 119*52808Sralph len != mtod(m, struct rt_msghdr *)->rtm_msglen) { 120*52808Sralph dst = 0; 12140446Ssklower senderr(EINVAL); 122*52808Sralph } 12336352Ssklower R_Malloc(rtm, struct rt_msghdr *, len); 124*52808Sralph if (rtm == 0) { 125*52808Sralph dst = 0; 12640446Ssklower senderr(ENOBUFS); 127*52808Sralph } 12836352Ssklower m_copydata(m, 0, len, (caddr_t)rtm); 129*52808Sralph if (rtm->rtm_version != RTM_VERSION) { 130*52808Sralph dst = 0; 13140446Ssklower senderr(EPROTONOSUPPORT); 132*52808Sralph } 13348729Ssklower rtm->rtm_pid = curproc->p_pid; 13452564Ssklower info.rti_addrs = rtm->rtm_addrs; 13552564Ssklower rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info); 13652564Ssklower if (dst == 0) 13740786Ssklower senderr(EINVAL); 13852564Ssklower if (genmask) { 13943336Ssklower struct radix_node *t, *rn_addmask(); 14043336Ssklower t = rn_addmask(genmask, 1, 2); 14143336Ssklower if (t && Bcmp(genmask, t->rn_key, *(u_char *)genmask) == 0) 14243336Ssklower genmask = (struct sockaddr *)(t->rn_key); 14343336Ssklower else 14443336Ssklower senderr(ENOBUFS); 14536352Ssklower } 14636352Ssklower switch (rtm->rtm_type) { 14752564Ssklower 14836352Ssklower case RTM_ADD: 14940786Ssklower if (gate == 0) 15040786Ssklower senderr(EINVAL); 15136352Ssklower error = rtrequest(RTM_ADD, dst, gate, netmask, 15236352Ssklower rtm->rtm_flags, &saved_nrt); 15340786Ssklower if (error == 0 && saved_nrt) { 15440786Ssklower rt_setmetrics(rtm->rtm_inits, 15540786Ssklower &rtm->rtm_rmx, &saved_nrt->rt_rmx); 15640446Ssklower saved_nrt->rt_refcnt--; 15743336Ssklower saved_nrt->rt_genmask = genmask; 15840786Ssklower } 15936352Ssklower break; 16036352Ssklower 16136352Ssklower case RTM_DELETE: 16236352Ssklower error = rtrequest(RTM_DELETE, dst, gate, netmask, 16337472Ssklower rtm->rtm_flags, (struct rtentry **)0); 16436352Ssklower break; 16536352Ssklower 16636352Ssklower case RTM_GET: 16736352Ssklower case RTM_CHANGE: 16836352Ssklower case RTM_LOCK: 16936352Ssklower rt = rtalloc1(dst, 0); 17036352Ssklower if (rt == 0) 17140446Ssklower senderr(ESRCH); 17252656Ssklower if (rtm->rtm_type != RTM_GET) {/* XXX: too grotty */ 17352656Ssklower struct radix_node *rn, *rn_search(); 17452656Ssklower extern struct radix_node_head *mask_rnhead; 17552656Ssklower 17647465Ssklower if (Bcmp(dst, rt_key(rt), dst->sa_len) != 0) 17747465Ssklower senderr(ESRCH); 17852656Ssklower if (netmask && (rn = rn_search(netmask, 17952656Ssklower mask_rnhead->rnh_treetop))) 18052656Ssklower netmask = (struct sockaddr *)rn->rn_key; 18152656Ssklower for (rn = rt->rt_nodes; rn; rn = rn->rn_dupedkey) 18252656Ssklower if (netmask == (struct sockaddr *)rn->rn_mask) 18352656Ssklower break; 18452656Ssklower if (rn == 0) 18545183Ssklower senderr(ETOOMANYREFS); 18652656Ssklower rt = (struct rtentry *)rn; 18745183Ssklower } 18836352Ssklower switch(rtm->rtm_type) { 18936352Ssklower 19036352Ssklower case RTM_GET: 19152564Ssklower dst = rt_key(rt); 19252564Ssklower gate = rt->rt_gateway; 19352564Ssklower netmask = rt_mask(rt); 19452564Ssklower genmask = rt->rt_genmask; 19545656Ssklower if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) { 19652564Ssklower if (ifp = rt->rt_ifp) { 19752564Ssklower ifpaddr = ifp->if_addrlist->ifa_addr; 19845656Ssklower ifaaddr = rt->rt_ifa->ifa_addr; 19952564Ssklower rtm->rtm_index = ifp->if_index; 20045656Ssklower } else { 20152564Ssklower ifpaddr = 0; 20252564Ssklower ifaaddr = 0; 20352564Ssklower } 20445656Ssklower } 20552564Ssklower len = rt_msg2(RTM_GET, &info, (caddr_t)0, 20652564Ssklower (struct walkarg *)0); 20736352Ssklower if (len > rtm->rtm_msglen) { 20836352Ssklower struct rt_msghdr *new_rtm; 20936352Ssklower R_Malloc(new_rtm, struct rt_msghdr *, len); 21036352Ssklower if (new_rtm == 0) 21140446Ssklower senderr(ENOBUFS); 21236352Ssklower Bcopy(rtm, new_rtm, rtm->rtm_msglen); 21336352Ssklower Free(rtm); rtm = new_rtm; 21436352Ssklower } 21552564Ssklower (void)rt_msg2(RTM_GET, &info, (caddr_t)rtm, 21652564Ssklower (struct walkarg *)0); 21745183Ssklower rtm->rtm_flags = rt->rt_flags; 21845183Ssklower rtm->rtm_rmx = rt->rt_rmx; 21936352Ssklower break; 22036352Ssklower 22136352Ssklower case RTM_CHANGE: 22250229Ssklower if (gate && rt_setgate(rt, rt_key(rt), gate)) 22340446Ssklower senderr(EDQUOT); 22443336Ssklower /* new gateway could require new ifaddr, ifp; 22543336Ssklower flags may also be different; ifp may be specified 22643336Ssklower by ll sockaddr when protocol address is ambiguous */ 22747465Ssklower if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) && 22847465Ssklower (ifp = ifa->ifa_ifp)) 22947465Ssklower ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate, 23047465Ssklower ifp); 23147465Ssklower else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) || 23247465Ssklower (ifa = ifa_ifwithroute(rt->rt_flags, 23347465Ssklower rt_key(rt), gate))) 23447465Ssklower ifp = ifa->ifa_ifp; 23543336Ssklower if (ifa) { 23647465Ssklower register struct ifaddr *oifa = rt->rt_ifa; 23747465Ssklower if (oifa != ifa) { 23847465Ssklower if (oifa && oifa->ifa_rtrequest) 23947465Ssklower oifa->ifa_rtrequest(RTM_DELETE, 24047465Ssklower rt, gate); 24143336Ssklower rt->rt_ifa = ifa; 24247465Ssklower rt->rt_ifp = ifp; 24343336Ssklower } 24443336Ssklower } 24547465Ssklower rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, 24647465Ssklower &rt->rt_rmx); 24743336Ssklower if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) 24843336Ssklower rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, gate); 24943336Ssklower if (genmask) 25043336Ssklower rt->rt_genmask = genmask; 25136352Ssklower /* 25236352Ssklower * Fall into 25336352Ssklower */ 25440786Ssklower case RTM_LOCK: 25550811Ssklower rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); 25640786Ssklower rt->rt_rmx.rmx_locks |= 25740786Ssklower (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); 25836352Ssklower break; 25936352Ssklower } 26052564Ssklower break; 26136352Ssklower 26236352Ssklower default: 26340446Ssklower senderr(EOPNOTSUPP); 26436352Ssklower } 26536352Ssklower 26636352Ssklower flush: 26736352Ssklower if (rtm) { 26836352Ssklower if (error) 26936352Ssklower rtm->rtm_errno = error; 27036352Ssklower else 27136352Ssklower rtm->rtm_flags |= RTF_DONE; 27236352Ssklower } 27336352Ssklower cleanup: 27436352Ssklower if (rt) 27536352Ssklower rtfree(rt); 27642356Ssklower { 27742356Ssklower register struct rawcb *rp = 0; 27842356Ssklower /* 27942356Ssklower * Check to see if we don't want our own messages. 28042356Ssklower */ 28142356Ssklower if ((so->so_options & SO_USELOOPBACK) == 0) { 28242356Ssklower if (route_cb.any_count <= 1) { 28342356Ssklower if (rtm) 28442356Ssklower Free(rtm); 28542356Ssklower m_freem(m); 28642356Ssklower return (error); 28742356Ssklower } 28842356Ssklower /* There is another listener, so construct message */ 28942356Ssklower rp = sotorawcb(so); 29042356Ssklower } 29145656Ssklower if (rtm) { 29245656Ssklower m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm); 29338847Ssklower Free(rtm); 29438847Ssklower } 29542356Ssklower if (rp) 29642356Ssklower rp->rcb_proto.sp_family = 0; /* Avoid us */ 29745183Ssklower if (dst) 29845183Ssklower route_proto.sp_protocol = dst->sa_family; 29938847Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 30042356Ssklower if (rp) 30142356Ssklower rp->rcb_proto.sp_family = PF_ROUTE; 30242356Ssklower } 30336352Ssklower return (error); 30436352Ssklower } 30536352Ssklower 30643336Ssklower rt_setmetrics(which, in, out) 30740786Ssklower u_long which; 30840786Ssklower register struct rt_metrics *in, *out; 30940786Ssklower { 31040786Ssklower #define metric(f, e) if (which & (f)) out->e = in->e; 31140786Ssklower metric(RTV_RPIPE, rmx_recvpipe); 31240786Ssklower metric(RTV_SPIPE, rmx_sendpipe); 31340786Ssklower metric(RTV_SSTHRESH, rmx_ssthresh); 31440786Ssklower metric(RTV_RTT, rmx_rtt); 31540786Ssklower metric(RTV_RTTVAR, rmx_rttvar); 31640786Ssklower metric(RTV_HOPCOUNT, rmx_hopcount); 31740786Ssklower metric(RTV_MTU, rmx_mtu); 31850228Ssklower metric(RTV_EXPIRE, rmx_expire); 31940786Ssklower #undef metric 32040786Ssklower } 32140786Ssklower 32252564Ssklower #define ROUNDUP(a) \ 32352564Ssklower ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 32452564Ssklower #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 32552564Ssklower 32652564Ssklower static void 32752564Ssklower rt_xaddrs(cp, cplim, rtinfo) 32852564Ssklower register caddr_t cp, cplim; 32952564Ssklower register struct rt_addrinfo *rtinfo; 33052564Ssklower { 33152564Ssklower register struct sockaddr *sa; 33252564Ssklower register int i; 33352564Ssklower 33452564Ssklower bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info)); 33552564Ssklower for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { 33652564Ssklower if ((rtinfo->rti_addrs & (1 << i)) == 0) 33752564Ssklower continue; 33852564Ssklower rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; 33952564Ssklower ADVANCE(cp, sa); 34052564Ssklower } 34152564Ssklower } 342*52808Sralph 34336352Ssklower /* 34436352Ssklower * Copy data from a buffer back into the indicated mbuf chain, 34536352Ssklower * starting "off" bytes from the beginning, extending the mbuf 34636352Ssklower * chain if necessary. 34736352Ssklower */ 34836352Ssklower m_copyback(m0, off, len, cp) 34936352Ssklower struct mbuf *m0; 35036352Ssklower register int off; 35136352Ssklower register int len; 35236352Ssklower caddr_t cp; 35336352Ssklower 35436352Ssklower { 35536352Ssklower register int mlen; 35636352Ssklower register struct mbuf *m = m0, *n; 35736352Ssklower int totlen = 0; 35836352Ssklower 35936352Ssklower if (m0 == 0) 36036352Ssklower return; 36148729Ssklower while (off > (mlen = m->m_len)) { 36236352Ssklower off -= mlen; 36336352Ssklower totlen += mlen; 36436352Ssklower if (m->m_next == 0) { 36536352Ssklower n = m_getclr(M_DONTWAIT, m->m_type); 36636352Ssklower if (n == 0) 36736352Ssklower goto out; 36836352Ssklower n->m_len = min(MLEN, len + off); 36936352Ssklower m->m_next = n; 37036352Ssklower } 37136352Ssklower m = m->m_next; 37236352Ssklower } 37336352Ssklower while (len > 0) { 37436352Ssklower mlen = min (m->m_len - off, len); 37537472Ssklower bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen); 37636352Ssklower cp += mlen; 37736352Ssklower len -= mlen; 37836352Ssklower mlen += off; 37936352Ssklower off = 0; 38036352Ssklower totlen += mlen; 38136352Ssklower if (len == 0) 38236352Ssklower break; 38336352Ssklower if (m->m_next == 0) { 38436352Ssklower n = m_get(M_DONTWAIT, m->m_type); 38536352Ssklower if (n == 0) 38636352Ssklower break; 38736352Ssklower n->m_len = min(MLEN, len); 38836352Ssklower m->m_next = n; 38936352Ssklower } 39036352Ssklower m = m->m_next; 39136352Ssklower } 39236352Ssklower out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) 39336352Ssklower m->m_pkthdr.len = totlen; 39436352Ssklower } 39536352Ssklower 39652564Ssklower static struct mbuf * 39752564Ssklower rt_msg1(type, rtinfo) 39852564Ssklower int type; 39952564Ssklower register struct rt_addrinfo *rtinfo; 40036352Ssklower { 40136352Ssklower register struct rt_msghdr *rtm; 40236352Ssklower register struct mbuf *m; 40352564Ssklower register int i; 40452564Ssklower register struct sockaddr *sa; 40552564Ssklower int len, dlen; 40636352Ssklower 40736352Ssklower m = m_gethdr(M_DONTWAIT, MT_DATA); 40836352Ssklower if (m == 0) 40952564Ssklower return (m); 41052564Ssklower switch (type) { 41152564Ssklower 41252564Ssklower case RTM_DELADDR: 41352564Ssklower case RTM_NEWADDR: 41452564Ssklower len = sizeof(struct ifa_msghdr); 41552564Ssklower break; 41652564Ssklower 41752564Ssklower case RTM_IFINFO: 41852564Ssklower len = sizeof(struct if_msghdr); 41952564Ssklower break; 42052564Ssklower 42152564Ssklower default: 42252564Ssklower len = sizeof(struct rt_msghdr); 42352564Ssklower } 42452564Ssklower if (len > MHLEN) 42552564Ssklower panic("rt_msg1"); 42652564Ssklower m->m_pkthdr.len = m->m_len = len; 42736352Ssklower m->m_pkthdr.rcvif = 0; 42836352Ssklower rtm = mtod(m, struct rt_msghdr *); 42952564Ssklower bzero((caddr_t)rtm, len); 43052564Ssklower for (i = 0; i < RTAX_MAX; i++) { 43152564Ssklower if ((sa = rtinfo->rti_info[i]) == NULL) 43252564Ssklower continue; 43352564Ssklower rtinfo->rti_addrs |= (1 << i); 43452564Ssklower dlen = ROUNDUP(sa->sa_len); 43552564Ssklower m_copyback(m, len, dlen, (caddr_t)sa); 43652564Ssklower len += dlen; 43752564Ssklower } 43852564Ssklower if (m->m_pkthdr.len != len) { 43952564Ssklower m_freem(m); 44052564Ssklower return (NULL); 44152564Ssklower } 44236352Ssklower rtm->rtm_msglen = len; 44340786Ssklower rtm->rtm_version = RTM_VERSION; 44436352Ssklower rtm->rtm_type = type; 44552564Ssklower return (m); 44652564Ssklower } 44752564Ssklower 44852564Ssklower static int 44952564Ssklower rt_msg2(type, rtinfo, cp, w) 45052564Ssklower int type; 45152564Ssklower register struct rt_addrinfo *rtinfo; 45252564Ssklower caddr_t cp; 45352564Ssklower struct walkarg *w; 45452564Ssklower { 45552564Ssklower register int i; 45652564Ssklower int len, dlen, second_time = 0; 45752564Ssklower caddr_t cp0; 45852564Ssklower 45952564Ssklower rtinfo->rti_addrs = 0; 46052564Ssklower again: 46152564Ssklower switch (type) { 46252564Ssklower 46352564Ssklower case RTM_DELADDR: 46452564Ssklower case RTM_NEWADDR: 46552564Ssklower len = sizeof(struct ifa_msghdr); 46652564Ssklower break; 46752564Ssklower 46852564Ssklower case RTM_IFINFO: 46952564Ssklower len = sizeof(struct if_msghdr); 47052564Ssklower break; 47152564Ssklower 47252564Ssklower default: 47352564Ssklower len = sizeof(struct rt_msghdr); 47436352Ssklower } 47552564Ssklower if (cp0 = cp) 47652564Ssklower cp += len; 47752564Ssklower for (i = 0; i < RTAX_MAX; i++) { 47852564Ssklower register struct sockaddr *sa; 47952564Ssklower 48052564Ssklower if ((sa = rtinfo->rti_info[i]) == 0) 48152564Ssklower continue; 48252564Ssklower rtinfo->rti_addrs |= (1 << i); 48352564Ssklower dlen = ROUNDUP(sa->sa_len); 48452564Ssklower if (cp) { 48552564Ssklower bcopy((caddr_t)sa, cp, (unsigned)dlen); 48652564Ssklower cp += dlen; 48752564Ssklower } 48836352Ssklower len += dlen; 48936352Ssklower } 49052564Ssklower if (cp == 0 && w != NULL && !second_time) { 49152564Ssklower register struct walkarg *rw = w; 49252564Ssklower 49352564Ssklower rw->w_needed += len; 49452564Ssklower if (rw->w_needed <= 0 && rw->w_where) { 49552564Ssklower if (rw->w_tmemsize < len) { 49652564Ssklower if (rw->w_tmem) 49752564Ssklower free(rw->w_tmem, M_RTABLE); 49852564Ssklower if (rw->w_tmem = (caddr_t) 49952564Ssklower malloc(len, M_RTABLE, M_NOWAIT)) 50052564Ssklower rw->w_tmemsize = len; 50152564Ssklower } 50252564Ssklower if (rw->w_tmem) { 50352564Ssklower cp = rw->w_tmem; 50452564Ssklower second_time = 1; 50552564Ssklower goto again; 50652564Ssklower } else 50752564Ssklower rw->w_where = 0; 50852564Ssklower } 50936352Ssklower } 51052564Ssklower if (cp) { 51152564Ssklower register struct rt_msghdr *rtm = (struct rt_msghdr *)cp0; 51252564Ssklower 51352564Ssklower rtm->rtm_version = RTM_VERSION; 51452564Ssklower rtm->rtm_type = type; 51552564Ssklower rtm->rtm_msglen = len; 51636352Ssklower } 51752564Ssklower return (len); 51852564Ssklower } 51952564Ssklower 52052564Ssklower /* 52152564Ssklower * This routine is called to generate a message from the routing 52252564Ssklower * socket indicating that a redirect has occured, a routing lookup 52352564Ssklower * has failed, or that a protocol has detected timeouts to a particular 52452564Ssklower * destination. 52552564Ssklower */ 52652564Ssklower rt_missmsg(type, rtinfo, flags, error) 52752564Ssklower int type, flags, error; 52852564Ssklower register struct rt_addrinfo *rtinfo; 52952564Ssklower { 53052564Ssklower register struct rt_msghdr *rtm; 53152564Ssklower register struct mbuf *m; 53252564Ssklower register int i; 53352564Ssklower struct sockaddr *sa = rtinfo->rti_info[RTAX_DST]; 53452564Ssklower 53552564Ssklower if (route_cb.any_count == 0) 53636352Ssklower return; 53752564Ssklower m = rt_msg1(type, rtinfo); 53852564Ssklower if (m == 0) 53952564Ssklower return; 54052564Ssklower rtm = mtod(m, struct rt_msghdr *); 54152564Ssklower rtm->rtm_flags = RTF_DONE | flags; 54237472Ssklower rtm->rtm_errno = error; 54352564Ssklower rtm->rtm_addrs = rtinfo->rti_addrs; 54452564Ssklower route_proto.sp_protocol = sa ? sa->sa_family : 0; 54536352Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 54636352Ssklower } 54736352Ssklower 54852564Ssklower /* 54952564Ssklower * This routine is called to generate a message from the routing 55052564Ssklower * socket indicating that the status of a network interface has changed. 55152564Ssklower */ 55252564Ssklower rt_ifmsg(ifp) 55352564Ssklower register struct ifnet *ifp; 55452564Ssklower { 55552564Ssklower register struct if_msghdr *ifm; 55652564Ssklower struct mbuf *m; 55752564Ssklower struct rt_addrinfo info; 55852564Ssklower 55952564Ssklower if (route_cb.any_count == 0) 56052564Ssklower return; 56152564Ssklower bzero((caddr_t)&info, sizeof(info)); 56252564Ssklower m = rt_msg1(RTM_IFINFO, &info); 56352564Ssklower if (m == 0) 56452564Ssklower return; 56552564Ssklower ifm = mtod(m, struct if_msghdr *); 56652564Ssklower ifm->ifm_index = ifp->if_index; 56752564Ssklower ifm->ifm_flags = ifp->if_flags; 56852564Ssklower ifm->ifm_data = ifp->if_data; 56952564Ssklower ifm->ifm_addrs = 0; 57052564Ssklower route_proto.sp_protocol = 0; 57152564Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 57252564Ssklower } 57352564Ssklower 57452564Ssklower /* 57552564Ssklower * This is called to generate messages from the routing socket 57652564Ssklower * indicating a network interface has had addresses associated with it. 57752564Ssklower * if we ever reverse the logic and replace messages TO the routing 57852564Ssklower * socket indicate a request to configure interfaces, then it will 57952564Ssklower * be unnecessary as the routing socket will automatically generate 58052564Ssklower * copies of it. 58152564Ssklower */ 58252564Ssklower rt_newaddrmsg(cmd, ifa, error, rt) 58352564Ssklower int cmd, error; 58452564Ssklower register struct ifaddr *ifa; 58552564Ssklower register struct rtentry *rt; 58652564Ssklower { 58752564Ssklower struct rt_addrinfo info; 58852564Ssklower struct sockaddr *sa; 58952564Ssklower int pass; 59052564Ssklower struct mbuf *m; 59152564Ssklower struct ifnet *ifp = ifa->ifa_ifp; 59252564Ssklower 59352564Ssklower if (route_cb.any_count == 0) 59452564Ssklower return; 59552564Ssklower for (pass = 1; pass < 3; pass++) { 59652564Ssklower bzero((caddr_t)&info, sizeof(info)); 59752564Ssklower if ((cmd == RTM_ADD && pass == 1) || 59852564Ssklower (cmd == RTM_DELETE && pass == 2)) { 59952564Ssklower register struct ifa_msghdr *ifam; 60052564Ssklower int ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR; 60152564Ssklower 60252564Ssklower ifaaddr = sa = ifa->ifa_addr; 60352564Ssklower ifpaddr = ifp->if_addrlist->ifa_addr; 60452564Ssklower netmask = ifa->ifa_netmask; 60552564Ssklower brdaddr = ifa->ifa_dstaddr; 60652564Ssklower if ((m = rt_msg1(ncmd, &info)) == NULL) 60752564Ssklower continue; 60852564Ssklower ifam = mtod(m, struct ifa_msghdr *); 60952564Ssklower ifam->ifam_index = ifp->if_index; 61052564Ssklower ifam->ifam_metric = ifa->ifa_metric; 61152564Ssklower ifam->ifam_addrs = info.rti_addrs; 61252564Ssklower } 61352564Ssklower if ((cmd == RTM_ADD && pass == 2) || 61452564Ssklower (cmd == RTM_DELETE && pass == 1)) { 61552564Ssklower register struct rt_msghdr *rtm; 61652564Ssklower 61752564Ssklower if (rt == 0) 61852564Ssklower continue; 61952564Ssklower netmask = rt_mask(rt); 62052564Ssklower dst = sa = rt_key(rt); 62152564Ssklower gate = rt->rt_gateway; 62252564Ssklower if ((m = rt_msg1(cmd, &info)) == NULL) 62352564Ssklower continue; 62452564Ssklower rtm = mtod(m, struct rt_msghdr *); 62552564Ssklower rtm->rtm_index = ifp->if_index; 62652564Ssklower rtm->rtm_flags |= rt->rt_flags; 62752564Ssklower rtm->rtm_errno = error; 62852564Ssklower rtm->rtm_addrs = info.rti_addrs; 62952564Ssklower } 63052564Ssklower route_proto.sp_protocol = sa ? sa->sa_family : 0; 63152564Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 63252564Ssklower } 63352564Ssklower } 63452564Ssklower 63540446Ssklower #include "kinfo.h" 63636352Ssklower /* 63740446Ssklower * This is used in dumping the kernel table via getkinfo(). 63840446Ssklower */ 63940446Ssklower rt_dumpentry(rn, w) 64040446Ssklower struct radix_node *rn; 64140446Ssklower register struct walkarg *w; 64240446Ssklower { 64340446Ssklower register struct sockaddr *sa; 64440446Ssklower register struct rtentry *rt = (struct rtentry *)rn; 64552564Ssklower int n, error = 0, size; 64652564Ssklower struct rt_addrinfo info; 64740446Ssklower 64840446Ssklower if (w->w_op == KINFO_RT_FLAGS && !(rt->rt_flags & w->w_arg)) 64950812Ssklower return 0; 65052564Ssklower bzero((caddr_t)&info, sizeof(info)); 65152564Ssklower dst = rt_key(rt); 65252564Ssklower gate = rt->rt_gateway; 65352564Ssklower netmask = rt_mask(rt); 65452564Ssklower genmask = rt->rt_genmask; 65552564Ssklower size = rt_msg2(RTM_GET, &info, 0, w); 65652564Ssklower if (w->w_where && w->w_tmem) { 65752564Ssklower register struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem; 65840446Ssklower 65952564Ssklower rtm->rtm_flags = rt->rt_flags; 66052564Ssklower rtm->rtm_use = rt->rt_use; 66152564Ssklower rtm->rtm_rmx = rt->rt_rmx; 66252564Ssklower rtm->rtm_index = rt->rt_ifp->if_index; 66352564Ssklower rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0; 66452564Ssklower rtm->rtm_addrs = info.rti_addrs; 66552564Ssklower if (error = copyout((caddr_t)rtm, w->w_where, size)) 66652564Ssklower w->w_where = NULL; 66752564Ssklower else 66852564Ssklower w->w_where += size; 66940446Ssklower } 67052564Ssklower return (error); 67152564Ssklower } 67252564Ssklower 67352564Ssklower kinfo_iflist(af, w) 67452564Ssklower int af; 67552564Ssklower register struct walkarg *w; 67652564Ssklower { 67752564Ssklower register struct ifnet *ifp; 67852564Ssklower register struct ifaddr *ifa; 67952564Ssklower struct rt_addrinfo info; 68052564Ssklower struct sockaddr *sa; 68152564Ssklower int len, error = 0; 68252564Ssklower 68352564Ssklower bzero((caddr_t)&info, sizeof(info)); 68452564Ssklower for (ifp = ifnet; ifp; ifp = ifp->if_next) { 68552631Ssklower if (w->w_arg && w->w_arg != ifp->if_index) 68652631Ssklower continue; 68752564Ssklower ifa = ifp->if_addrlist; 68852564Ssklower ifpaddr = ifa->ifa_addr; 68952564Ssklower len = rt_msg2(RTM_IFINFO, &info, (caddr_t)0, w); 69052564Ssklower ifpaddr = 0; 69152564Ssklower if (w->w_where && w->w_tmem) { 69252564Ssklower register struct if_msghdr *ifm; 69352564Ssklower 69452564Ssklower ifm = (struct if_msghdr *)w->w_tmem; 69552564Ssklower ifm->ifm_index = ifp->if_index; 69652564Ssklower ifm->ifm_flags = ifp->if_flags; 69752564Ssklower ifm->ifm_data = ifp->if_data; 69852564Ssklower ifm->ifm_addrs = info.rti_addrs; 69952564Ssklower if (error = copyout((caddr_t)ifm, w->w_where, len)) 70052564Ssklower return (error); 70152564Ssklower w->w_where += len; 70252564Ssklower } 70352564Ssklower while (ifa = ifa->ifa_next) { 70452631Ssklower if (af && af != ifa->ifa_addr->sa_family) 70552631Ssklower continue; 70652564Ssklower ifaaddr = ifa->ifa_addr; 70752564Ssklower netmask = ifa->ifa_netmask; 70852564Ssklower brdaddr = ifa->ifa_dstaddr; 70952564Ssklower len = rt_msg2(RTM_NEWADDR, &info, 0, w); 71052564Ssklower if (w->w_where && w->w_tmem) { 71152564Ssklower register struct ifa_msghdr *ifam; 71252564Ssklower 71352564Ssklower ifam = (struct ifa_msghdr *)w->w_tmem; 71452564Ssklower ifam->ifam_index = ifa->ifa_ifp->if_index; 71552564Ssklower ifam->ifam_flags = ifa->ifa_flags; 71652564Ssklower ifam->ifam_metric = ifa->ifa_metric; 71752564Ssklower ifam->ifam_addrs = info.rti_addrs; 71852564Ssklower if (error = copyout(w->w_tmem, w->w_where, len)) 71952564Ssklower return (error); 72052564Ssklower w->w_where += len; 72152564Ssklower } 72252564Ssklower } 72352631Ssklower ifaaddr = netmask = brdaddr = 0; 72452564Ssklower } 72540446Ssklower return (0); 72640446Ssklower } 72740446Ssklower 72840446Ssklower kinfo_rtable(op, where, given, arg, needed) 72940446Ssklower int op, arg; 73040446Ssklower caddr_t where; 73140446Ssklower int *given, *needed; 73240446Ssklower { 73340446Ssklower register struct radix_node_head *rnh; 73452564Ssklower int i, s, error = EINVAL; 73540446Ssklower u_char af = ki_af(op); 73640446Ssklower struct walkarg w; 73740446Ssklower 73840446Ssklower Bzero(&w, sizeof(w)); 73940446Ssklower if ((w.w_where = where) && given) 74040446Ssklower w.w_given = *given; 74140446Ssklower w.w_needed = 0 - w.w_given; 74240446Ssklower w.w_arg = arg; 74352631Ssklower w.w_op = op = ki_op(op); 74440446Ssklower 74540446Ssklower s = splnet(); 74652564Ssklower switch (op) { 74752564Ssklower 74852564Ssklower case KINFO_RT_DUMP: 74952564Ssklower case KINFO_RT_FLAGS: 75052564Ssklower for (i = 1; i <= AF_MAX; i++) 75152564Ssklower if ((rnh = rt_tables[i]) && (af == 0 || af == i) && 75252564Ssklower (error = rnh->rnh_walk(rnh->rnh_treetop, 75352564Ssklower rt_dumpentry, &w))) 75452564Ssklower break; 75552564Ssklower break; 75652564Ssklower 75752564Ssklower case KINFO_RT_IFLIST: 75852564Ssklower error = kinfo_iflist(af, &w); 75940446Ssklower } 76052564Ssklower splx(s); 76152564Ssklower if (w.w_tmem) 76252564Ssklower free(w.w_tmem, M_RTABLE); 76340446Ssklower w.w_needed += w.w_given; 76440446Ssklower if (where && given) 76540446Ssklower *given = w.w_where - where; 76640446Ssklower else 76740446Ssklower w.w_needed = (11 * w.w_needed) / 10; 76840446Ssklower *needed = w.w_needed; 76940446Ssklower return (error); 77040446Ssklower } 77140446Ssklower 77240446Ssklower /* 77336352Ssklower * Definitions of protocols supported in the ROUTE domain. 77436352Ssklower */ 77536352Ssklower 77636352Ssklower int raw_init(),raw_usrreq(),raw_input(),raw_ctlinput(); 77736352Ssklower extern struct domain routedomain; /* or at least forward */ 77836352Ssklower 77936352Ssklower struct protosw routesw[] = { 78036352Ssklower { SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR, 78136352Ssklower raw_input, route_output, raw_ctlinput, 0, 78236352Ssklower route_usrreq, 78336352Ssklower raw_init, 0, 0, 0, 78436352Ssklower } 78536352Ssklower }; 78636352Ssklower 78736352Ssklower int unp_externalize(), unp_dispose(); 78836352Ssklower 78936352Ssklower struct domain routedomain = 79036352Ssklower { PF_ROUTE, "route", 0, 0, 0, 79136352Ssklower routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] }; 792