136352Ssklower /* 263211Sbostic * Copyright (c) 1988, 1991, 1993 363211Sbostic * The Regents of the University of California. All rights reserved. 436352Ssklower * 544466Sbostic * %sccs.include.redist.c% 636352Ssklower * 7*68288Ssklower * @(#)rtsock.c 8.6 (Berkeley) 02/11/95 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/if.h> 2056529Sbostic #include <net/route.h> 2156529Sbostic #include <net/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 3261339Sbostic static struct mbuf * 3361339Sbostic rt_msg1 __P((int, struct rt_addrinfo *)); 3461339Sbostic static int rt_msg2 __P((int, 3561339Sbostic struct rt_addrinfo *, caddr_t, struct walkarg *)); 36*68288Ssklower static void rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *)); 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*/ 4861339Sbostic int 4940446Ssklower route_usrreq(so, req, m, nam, control) 5036352Ssklower register struct socket *so; 5136352Ssklower int req; 5240446Ssklower struct mbuf *m, *nam, *control; 5336352Ssklower { 5436352Ssklower register int error = 0; 5536352Ssklower register struct rawcb *rp = sotorawcb(so); 5644949Ssklower int s; 57*68288Ssklower 5837472Ssklower if (req == PRU_ATTACH) { 5937472Ssklower MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK); 6037472Ssklower if (so->so_pcb = (caddr_t)rp) 6137472Ssklower bzero(so->so_pcb, sizeof(*rp)); 6237472Ssklower 6337472Ssklower } 6436352Ssklower if (req == PRU_DETACH && rp) { 6536352Ssklower int af = rp->rcb_proto.sp_protocol; 6636352Ssklower if (af == AF_INET) 6736352Ssklower route_cb.ip_count--; 6836352Ssklower else if (af == AF_NS) 6936352Ssklower route_cb.ns_count--; 7036352Ssklower else if (af == AF_ISO) 7136352Ssklower route_cb.iso_count--; 7236352Ssklower route_cb.any_count--; 7336352Ssklower } 7444949Ssklower s = splnet(); 7540446Ssklower error = raw_usrreq(so, req, m, nam, control); 7636352Ssklower rp = sotorawcb(so); 7737472Ssklower if (req == PRU_ATTACH && rp) { 7836352Ssklower int af = rp->rcb_proto.sp_protocol; 7937472Ssklower if (error) { 8037472Ssklower free((caddr_t)rp, M_PCB); 8144949Ssklower splx(s); 8237472Ssklower return (error); 8337472Ssklower } 8436352Ssklower if (af == AF_INET) 8536352Ssklower route_cb.ip_count++; 8636352Ssklower else if (af == AF_NS) 8736352Ssklower route_cb.ns_count++; 8836352Ssklower else if (af == AF_ISO) 8936352Ssklower route_cb.iso_count++; 9037472Ssklower rp->rcb_faddr = &route_src; 9136352Ssklower route_cb.any_count++; 9236352Ssklower soisconnected(so); 9342356Ssklower so->so_options |= SO_USELOOPBACK; 9436352Ssklower } 9544949Ssklower splx(s); 9636352Ssklower return (error); 9736352Ssklower } 9836352Ssklower 9937472Ssklower /*ARGSUSED*/ 10061339Sbostic int 10136352Ssklower route_output(m, so) 10236352Ssklower register struct mbuf *m; 10336352Ssklower struct socket *so; 10436352Ssklower { 10544949Ssklower register struct rt_msghdr *rtm = 0; 10636352Ssklower register struct rtentry *rt = 0; 10740446Ssklower struct rtentry *saved_nrt = 0; 108*68288Ssklower struct radix_node_head *rnh; 10952564Ssklower struct rt_addrinfo info; 11037472Ssklower int len, error = 0; 11143336Ssklower struct ifnet *ifp = 0; 11247465Ssklower struct ifaddr *ifa = 0; 11336352Ssklower 11440446Ssklower #define senderr(e) { error = e; goto flush;} 11558497Ssklower if (m == 0 || ((m->m_len < sizeof(long)) && 11658497Ssklower (m = m_pullup(m, sizeof(long))) == 0)) 11738847Ssklower return (ENOBUFS); 11836352Ssklower if ((m->m_flags & M_PKTHDR) == 0) 11938847Ssklower panic("route_output"); 12036352Ssklower len = m->m_pkthdr.len; 12144949Ssklower if (len < sizeof(*rtm) || 12252808Sralph len != mtod(m, struct rt_msghdr *)->rtm_msglen) { 12352808Sralph dst = 0; 12440446Ssklower senderr(EINVAL); 12552808Sralph } 12636352Ssklower R_Malloc(rtm, struct rt_msghdr *, len); 12752808Sralph if (rtm == 0) { 12852808Sralph dst = 0; 12940446Ssklower senderr(ENOBUFS); 13052808Sralph } 13136352Ssklower m_copydata(m, 0, len, (caddr_t)rtm); 13252808Sralph if (rtm->rtm_version != RTM_VERSION) { 13352808Sralph dst = 0; 13440446Ssklower senderr(EPROTONOSUPPORT); 13552808Sralph } 13648729Ssklower rtm->rtm_pid = curproc->p_pid; 13752564Ssklower info.rti_addrs = rtm->rtm_addrs; 138*68288Ssklower rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info); 13952564Ssklower if (dst == 0) 14040786Ssklower senderr(EINVAL); 14152564Ssklower if (genmask) { 14261339Sbostic struct radix_node *t; 143*68288Ssklower t = rn_addmask((caddr_t)genmask, 0, 1); 14443336Ssklower if (t && Bcmp(genmask, t->rn_key, *(u_char *)genmask) == 0) 14543336Ssklower genmask = (struct sockaddr *)(t->rn_key); 14643336Ssklower else 14743336Ssklower senderr(ENOBUFS); 14836352Ssklower } 14936352Ssklower switch (rtm->rtm_type) { 15052564Ssklower 15136352Ssklower case RTM_ADD: 15240786Ssklower if (gate == 0) 15340786Ssklower senderr(EINVAL); 154*68288Ssklower error = rtrequest(RTM_ADD, dst, gate, netmask, 155*68288Ssklower rtm->rtm_flags, &saved_nrt); 15640786Ssklower if (error == 0 && saved_nrt) { 15740786Ssklower rt_setmetrics(rtm->rtm_inits, 15840786Ssklower &rtm->rtm_rmx, &saved_nrt->rt_rmx); 15940446Ssklower saved_nrt->rt_refcnt--; 16043336Ssklower saved_nrt->rt_genmask = genmask; 16140786Ssklower } 16236352Ssklower break; 16336352Ssklower 16436352Ssklower case RTM_DELETE: 165*68288Ssklower error = rtrequest(RTM_DELETE, dst, gate, netmask, 166*68288Ssklower rtm->rtm_flags, &saved_nrt); 167*68288Ssklower if (error == 0) { 168*68288Ssklower (rt = saved_nrt)->rt_refcnt++; 169*68288Ssklower goto report; 170*68288Ssklower } 17136352Ssklower break; 17236352Ssklower 173*68288Ssklower case RTM_GET: 17468026Ssklower case RTM_CHANGE: 17536352Ssklower case RTM_LOCK: 176*68288Ssklower if ((rnh = rt_tables[dst->sa_family]) == 0) { 177*68288Ssklower senderr(EAFNOSUPPORT); 178*68288Ssklower } else if (rt = (struct rtentry *) 179*68288Ssklower rnh->rnh_lookup(dst, netmask, rnh)) 180*68288Ssklower rt->rt_refcnt++; 181*68288Ssklower else 18240446Ssklower senderr(ESRCH); 18336352Ssklower switch(rtm->rtm_type) { 18436352Ssklower 18536352Ssklower case RTM_GET: 186*68288Ssklower report: 18752564Ssklower dst = rt_key(rt); 18852564Ssklower gate = rt->rt_gateway; 18952564Ssklower netmask = rt_mask(rt); 19052564Ssklower genmask = rt->rt_genmask; 19145656Ssklower if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) { 19252564Ssklower if (ifp = rt->rt_ifp) { 19352564Ssklower ifpaddr = ifp->if_addrlist->ifa_addr; 19445656Ssklower ifaaddr = rt->rt_ifa->ifa_addr; 195*68288Ssklower if (ifp->if_flags & IFF_POINTOPOINT) 196*68288Ssklower brdaddr = rt->rt_ifa->ifa_dstaddr; 197*68288Ssklower else 198*68288Ssklower brdaddr = 0; 19952564Ssklower rtm->rtm_index = ifp->if_index; 20045656Ssklower } else { 20152564Ssklower ifpaddr = 0; 20252564Ssklower ifaaddr = 0; 20352564Ssklower } 20445656Ssklower } 205*68288Ssklower len = rt_msg2(rtm->rtm_type, &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 } 215*68288Ssklower (void)rt_msg2(rtm->rtm_type, &info, (caddr_t)rtm, 21652564Ssklower (struct walkarg *)0); 21745183Ssklower rtm->rtm_flags = rt->rt_flags; 21845183Ssklower rtm->rtm_rmx = rt->rt_rmx; 21958495Ssklower rtm->rtm_addrs = info.rti_addrs; 22036352Ssklower break; 22136352Ssklower 22236352Ssklower case RTM_CHANGE: 22350229Ssklower if (gate && rt_setgate(rt, rt_key(rt), gate)) 22440446Ssklower senderr(EDQUOT); 22543336Ssklower /* new gateway could require new ifaddr, ifp; 22643336Ssklower flags may also be different; ifp may be specified 22743336Ssklower by ll sockaddr when protocol address is ambiguous */ 22847465Ssklower if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) && 22947465Ssklower (ifp = ifa->ifa_ifp)) 23047465Ssklower ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate, 23147465Ssklower ifp); 23247465Ssklower else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) || 23347465Ssklower (ifa = ifa_ifwithroute(rt->rt_flags, 23447465Ssklower rt_key(rt), gate))) 23547465Ssklower ifp = ifa->ifa_ifp; 23643336Ssklower if (ifa) { 23747465Ssklower register struct ifaddr *oifa = rt->rt_ifa; 23847465Ssklower if (oifa != ifa) { 23947465Ssklower if (oifa && oifa->ifa_rtrequest) 24047465Ssklower oifa->ifa_rtrequest(RTM_DELETE, 24147465Ssklower rt, gate); 24259064Ssklower IFAFREE(rt->rt_ifa); 24343336Ssklower rt->rt_ifa = ifa; 24459064Ssklower ifa->ifa_refcnt++; 24547465Ssklower rt->rt_ifp = ifp; 24643336Ssklower } 24743336Ssklower } 24847465Ssklower rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, 24947465Ssklower &rt->rt_rmx); 25043336Ssklower if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) 25143336Ssklower rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, gate); 25243336Ssklower if (genmask) 25343336Ssklower rt->rt_genmask = genmask; 25436352Ssklower /* 25536352Ssklower * Fall into 25636352Ssklower */ 25740786Ssklower case RTM_LOCK: 25850811Ssklower rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); 25940786Ssklower rt->rt_rmx.rmx_locks |= 26040786Ssklower (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); 26136352Ssklower break; 26236352Ssklower } 26352564Ssklower break; 26436352Ssklower 26536352Ssklower default: 26640446Ssklower senderr(EOPNOTSUPP); 26736352Ssklower } 26836352Ssklower 26936352Ssklower flush: 27036352Ssklower if (rtm) { 27136352Ssklower if (error) 27236352Ssklower rtm->rtm_errno = error; 27336352Ssklower else 27436352Ssklower rtm->rtm_flags |= RTF_DONE; 27536352Ssklower } 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 30861339Sbostic void 30943336Ssklower rt_setmetrics(which, in, out) 31040786Ssklower u_long which; 31140786Ssklower register struct rt_metrics *in, *out; 31240786Ssklower { 31340786Ssklower #define metric(f, e) if (which & (f)) out->e = in->e; 31440786Ssklower metric(RTV_RPIPE, rmx_recvpipe); 31540786Ssklower metric(RTV_SPIPE, rmx_sendpipe); 31640786Ssklower metric(RTV_SSTHRESH, rmx_ssthresh); 31740786Ssklower metric(RTV_RTT, rmx_rtt); 31840786Ssklower metric(RTV_RTTVAR, rmx_rttvar); 31940786Ssklower metric(RTV_HOPCOUNT, rmx_hopcount); 32040786Ssklower metric(RTV_MTU, rmx_mtu); 32150228Ssklower metric(RTV_EXPIRE, rmx_expire); 32240786Ssklower #undef metric 32340786Ssklower } 32440786Ssklower 32552564Ssklower #define ROUNDUP(a) \ 32652564Ssklower ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 32752564Ssklower #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 32852564Ssklower 329*68288Ssklower static void 33052564Ssklower rt_xaddrs(cp, cplim, rtinfo) 33152564Ssklower register caddr_t cp, cplim; 33252564Ssklower register struct rt_addrinfo *rtinfo; 33352564Ssklower { 33452564Ssklower register struct sockaddr *sa; 33552564Ssklower register int i; 33652564Ssklower 33752564Ssklower bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info)); 33852564Ssklower for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { 33952564Ssklower if ((rtinfo->rti_addrs & (1 << i)) == 0) 34052564Ssklower continue; 34152564Ssklower rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; 34252564Ssklower ADVANCE(cp, sa); 34352564Ssklower } 34452564Ssklower } 34552808Sralph 34636352Ssklower /* 34736352Ssklower * Copy data from a buffer back into the indicated mbuf chain, 34836352Ssklower * starting "off" bytes from the beginning, extending the mbuf 34936352Ssklower * chain if necessary. 35036352Ssklower */ 35161339Sbostic void 35236352Ssklower m_copyback(m0, off, len, cp) 35336352Ssklower struct mbuf *m0; 35436352Ssklower register int off; 35536352Ssklower register int len; 35636352Ssklower caddr_t cp; 35736352Ssklower { 35836352Ssklower register int mlen; 35936352Ssklower register struct mbuf *m = m0, *n; 36036352Ssklower int totlen = 0; 36136352Ssklower 36236352Ssklower if (m0 == 0) 36336352Ssklower return; 36448729Ssklower while (off > (mlen = m->m_len)) { 36536352Ssklower off -= mlen; 36636352Ssklower totlen += mlen; 36736352Ssklower if (m->m_next == 0) { 36836352Ssklower n = m_getclr(M_DONTWAIT, m->m_type); 36936352Ssklower if (n == 0) 37036352Ssklower goto out; 37136352Ssklower n->m_len = min(MLEN, len + off); 37236352Ssklower m->m_next = n; 37336352Ssklower } 37436352Ssklower m = m->m_next; 37536352Ssklower } 37636352Ssklower while (len > 0) { 37736352Ssklower mlen = min (m->m_len - off, len); 37837472Ssklower bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen); 37936352Ssklower cp += mlen; 38036352Ssklower len -= mlen; 38136352Ssklower mlen += off; 38236352Ssklower off = 0; 38336352Ssklower totlen += mlen; 38436352Ssklower if (len == 0) 38536352Ssklower break; 38636352Ssklower if (m->m_next == 0) { 38736352Ssklower n = m_get(M_DONTWAIT, m->m_type); 38836352Ssklower if (n == 0) 38936352Ssklower break; 39036352Ssklower n->m_len = min(MLEN, len); 39136352Ssklower m->m_next = n; 39236352Ssklower } 39336352Ssklower m = m->m_next; 39436352Ssklower } 39536352Ssklower out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) 39636352Ssklower m->m_pkthdr.len = totlen; 39736352Ssklower } 39836352Ssklower 39952564Ssklower static struct mbuf * 40052564Ssklower rt_msg1(type, rtinfo) 40152564Ssklower int type; 40252564Ssklower register struct rt_addrinfo *rtinfo; 40336352Ssklower { 40436352Ssklower register struct rt_msghdr *rtm; 40536352Ssklower register struct mbuf *m; 40652564Ssklower register int i; 40752564Ssklower register struct sockaddr *sa; 40852564Ssklower int len, dlen; 40936352Ssklower 41036352Ssklower m = m_gethdr(M_DONTWAIT, MT_DATA); 41136352Ssklower if (m == 0) 41252564Ssklower return (m); 41352564Ssklower switch (type) { 41452564Ssklower 41552564Ssklower case RTM_DELADDR: 41652564Ssklower case RTM_NEWADDR: 41752564Ssklower len = sizeof(struct ifa_msghdr); 41852564Ssklower break; 41952564Ssklower 42052564Ssklower case RTM_IFINFO: 42152564Ssklower len = sizeof(struct if_msghdr); 42252564Ssklower break; 42352564Ssklower 42452564Ssklower default: 42552564Ssklower len = sizeof(struct rt_msghdr); 42652564Ssklower } 42752564Ssklower if (len > MHLEN) 42852564Ssklower panic("rt_msg1"); 42952564Ssklower m->m_pkthdr.len = m->m_len = len; 43036352Ssklower m->m_pkthdr.rcvif = 0; 43136352Ssklower rtm = mtod(m, struct rt_msghdr *); 43252564Ssklower bzero((caddr_t)rtm, len); 43352564Ssklower for (i = 0; i < RTAX_MAX; i++) { 43452564Ssklower if ((sa = rtinfo->rti_info[i]) == NULL) 43552564Ssklower continue; 43652564Ssklower rtinfo->rti_addrs |= (1 << i); 43752564Ssklower dlen = ROUNDUP(sa->sa_len); 43852564Ssklower m_copyback(m, len, dlen, (caddr_t)sa); 43952564Ssklower len += dlen; 44052564Ssklower } 44152564Ssklower if (m->m_pkthdr.len != len) { 44252564Ssklower m_freem(m); 44352564Ssklower return (NULL); 44452564Ssklower } 44536352Ssklower rtm->rtm_msglen = len; 44640786Ssklower rtm->rtm_version = RTM_VERSION; 44736352Ssklower rtm->rtm_type = type; 44852564Ssklower return (m); 44952564Ssklower } 45052564Ssklower 45152564Ssklower static int 45252564Ssklower rt_msg2(type, rtinfo, cp, w) 45352564Ssklower int type; 45452564Ssklower register struct rt_addrinfo *rtinfo; 45552564Ssklower caddr_t cp; 45652564Ssklower struct walkarg *w; 45752564Ssklower { 45852564Ssklower register int i; 45952564Ssklower int len, dlen, second_time = 0; 46052564Ssklower caddr_t cp0; 46152564Ssklower 46252564Ssklower rtinfo->rti_addrs = 0; 46352564Ssklower again: 46452564Ssklower switch (type) { 46552564Ssklower 46652564Ssklower case RTM_DELADDR: 46752564Ssklower case RTM_NEWADDR: 46852564Ssklower len = sizeof(struct ifa_msghdr); 46952564Ssklower break; 47052564Ssklower 47152564Ssklower case RTM_IFINFO: 47252564Ssklower len = sizeof(struct if_msghdr); 47352564Ssklower break; 47452564Ssklower 47552564Ssklower default: 47652564Ssklower len = sizeof(struct rt_msghdr); 47736352Ssklower } 47852564Ssklower if (cp0 = cp) 47952564Ssklower cp += len; 48052564Ssklower for (i = 0; i < RTAX_MAX; i++) { 48152564Ssklower register struct sockaddr *sa; 48252564Ssklower 48352564Ssklower if ((sa = rtinfo->rti_info[i]) == 0) 48452564Ssklower continue; 48552564Ssklower rtinfo->rti_addrs |= (1 << i); 48652564Ssklower dlen = ROUNDUP(sa->sa_len); 48752564Ssklower if (cp) { 48852564Ssklower bcopy((caddr_t)sa, cp, (unsigned)dlen); 48952564Ssklower cp += dlen; 49052564Ssklower } 49136352Ssklower len += dlen; 49236352Ssklower } 49352564Ssklower if (cp == 0 && w != NULL && !second_time) { 49452564Ssklower register struct walkarg *rw = w; 49552564Ssklower 49652564Ssklower rw->w_needed += len; 49752564Ssklower if (rw->w_needed <= 0 && rw->w_where) { 49852564Ssklower if (rw->w_tmemsize < len) { 49952564Ssklower if (rw->w_tmem) 50052564Ssklower free(rw->w_tmem, M_RTABLE); 50152564Ssklower if (rw->w_tmem = (caddr_t) 50252564Ssklower malloc(len, M_RTABLE, M_NOWAIT)) 50352564Ssklower rw->w_tmemsize = len; 50452564Ssklower } 50552564Ssklower if (rw->w_tmem) { 50652564Ssklower cp = rw->w_tmem; 50752564Ssklower second_time = 1; 50852564Ssklower goto again; 50952564Ssklower } else 51052564Ssklower rw->w_where = 0; 51152564Ssklower } 51236352Ssklower } 51352564Ssklower if (cp) { 51452564Ssklower register struct rt_msghdr *rtm = (struct rt_msghdr *)cp0; 51552564Ssklower 51652564Ssklower rtm->rtm_version = RTM_VERSION; 51752564Ssklower rtm->rtm_type = type; 51852564Ssklower rtm->rtm_msglen = len; 51936352Ssklower } 52052564Ssklower return (len); 52152564Ssklower } 52252564Ssklower 52352564Ssklower /* 52452564Ssklower * This routine is called to generate a message from the routing 52552564Ssklower * socket indicating that a redirect has occured, a routing lookup 52652564Ssklower * has failed, or that a protocol has detected timeouts to a particular 52752564Ssklower * destination. 52852564Ssklower */ 52961339Sbostic void 53052564Ssklower rt_missmsg(type, rtinfo, flags, error) 53152564Ssklower int type, flags, error; 53252564Ssklower register struct rt_addrinfo *rtinfo; 53352564Ssklower { 53452564Ssklower register struct rt_msghdr *rtm; 53552564Ssklower register struct mbuf *m; 53652564Ssklower struct sockaddr *sa = rtinfo->rti_info[RTAX_DST]; 53752564Ssklower 53852564Ssklower if (route_cb.any_count == 0) 53936352Ssklower return; 54052564Ssklower m = rt_msg1(type, rtinfo); 54152564Ssklower if (m == 0) 54252564Ssklower return; 54352564Ssklower rtm = mtod(m, struct rt_msghdr *); 54452564Ssklower rtm->rtm_flags = RTF_DONE | flags; 54537472Ssklower rtm->rtm_errno = error; 54652564Ssklower rtm->rtm_addrs = rtinfo->rti_addrs; 54752564Ssklower route_proto.sp_protocol = sa ? sa->sa_family : 0; 54836352Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 54936352Ssklower } 55036352Ssklower 55152564Ssklower /* 55252564Ssklower * This routine is called to generate a message from the routing 55352564Ssklower * socket indicating that the status of a network interface has changed. 55452564Ssklower */ 55561339Sbostic void 55652564Ssklower rt_ifmsg(ifp) 55752564Ssklower register struct ifnet *ifp; 55852564Ssklower { 55952564Ssklower register struct if_msghdr *ifm; 56052564Ssklower struct mbuf *m; 56152564Ssklower struct rt_addrinfo info; 56252564Ssklower 56352564Ssklower if (route_cb.any_count == 0) 56452564Ssklower return; 56552564Ssklower bzero((caddr_t)&info, sizeof(info)); 56652564Ssklower m = rt_msg1(RTM_IFINFO, &info); 56752564Ssklower if (m == 0) 56852564Ssklower return; 56952564Ssklower ifm = mtod(m, struct if_msghdr *); 57052564Ssklower ifm->ifm_index = ifp->if_index; 57152564Ssklower ifm->ifm_flags = ifp->if_flags; 57252564Ssklower ifm->ifm_data = ifp->if_data; 57352564Ssklower ifm->ifm_addrs = 0; 57452564Ssklower route_proto.sp_protocol = 0; 57552564Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 57652564Ssklower } 57752564Ssklower 57852564Ssklower /* 57952564Ssklower * This is called to generate messages from the routing socket 58052564Ssklower * indicating a network interface has had addresses associated with it. 58152564Ssklower * if we ever reverse the logic and replace messages TO the routing 58252564Ssklower * socket indicate a request to configure interfaces, then it will 58352564Ssklower * be unnecessary as the routing socket will automatically generate 58452564Ssklower * copies of it. 58552564Ssklower */ 58661339Sbostic void 58752564Ssklower rt_newaddrmsg(cmd, ifa, error, rt) 58852564Ssklower int cmd, error; 58952564Ssklower register struct ifaddr *ifa; 59052564Ssklower register struct rtentry *rt; 59152564Ssklower { 59252564Ssklower struct rt_addrinfo info; 59352564Ssklower struct sockaddr *sa; 59452564Ssklower int pass; 59552564Ssklower struct mbuf *m; 59652564Ssklower struct ifnet *ifp = ifa->ifa_ifp; 59752564Ssklower 59852564Ssklower if (route_cb.any_count == 0) 59952564Ssklower return; 60052564Ssklower for (pass = 1; pass < 3; pass++) { 60152564Ssklower bzero((caddr_t)&info, sizeof(info)); 60252564Ssklower if ((cmd == RTM_ADD && pass == 1) || 60352564Ssklower (cmd == RTM_DELETE && pass == 2)) { 60452564Ssklower register struct ifa_msghdr *ifam; 60552564Ssklower int ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR; 60652564Ssklower 60752564Ssklower ifaaddr = sa = ifa->ifa_addr; 60852564Ssklower ifpaddr = ifp->if_addrlist->ifa_addr; 60952564Ssklower netmask = ifa->ifa_netmask; 61052564Ssklower brdaddr = ifa->ifa_dstaddr; 61152564Ssklower if ((m = rt_msg1(ncmd, &info)) == NULL) 61252564Ssklower continue; 61352564Ssklower ifam = mtod(m, struct ifa_msghdr *); 61452564Ssklower ifam->ifam_index = ifp->if_index; 61552564Ssklower ifam->ifam_metric = ifa->ifa_metric; 61654077Ssklower ifam->ifam_flags = ifa->ifa_flags; 61752564Ssklower ifam->ifam_addrs = info.rti_addrs; 61852564Ssklower } 61952564Ssklower if ((cmd == RTM_ADD && pass == 2) || 62052564Ssklower (cmd == RTM_DELETE && pass == 1)) { 62152564Ssklower register struct rt_msghdr *rtm; 62252564Ssklower 62352564Ssklower if (rt == 0) 62452564Ssklower continue; 62552564Ssklower netmask = rt_mask(rt); 62652564Ssklower dst = sa = rt_key(rt); 62752564Ssklower gate = rt->rt_gateway; 62852564Ssklower if ((m = rt_msg1(cmd, &info)) == NULL) 62952564Ssklower continue; 63052564Ssklower rtm = mtod(m, struct rt_msghdr *); 63152564Ssklower rtm->rtm_index = ifp->if_index; 63252564Ssklower rtm->rtm_flags |= rt->rt_flags; 63352564Ssklower rtm->rtm_errno = error; 63452564Ssklower rtm->rtm_addrs = info.rti_addrs; 63552564Ssklower } 63652564Ssklower route_proto.sp_protocol = sa ? sa->sa_family : 0; 63752564Ssklower raw_input(m, &route_proto, &route_src, &route_dst); 63852564Ssklower } 63952564Ssklower } 64052564Ssklower 64136352Ssklower /* 64257836Smckusick * This is used in dumping the kernel table via sysctl(). 64340446Ssklower */ 64461339Sbostic int 64557836Smckusick sysctl_dumpentry(rn, w) 64640446Ssklower struct radix_node *rn; 64740446Ssklower register struct walkarg *w; 64840446Ssklower { 64940446Ssklower register struct rtentry *rt = (struct rtentry *)rn; 650*68288Ssklower int error = 0, size; 65152564Ssklower struct rt_addrinfo info; 65240446Ssklower 65357836Smckusick if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg)) 65450812Ssklower return 0; 65552564Ssklower bzero((caddr_t)&info, sizeof(info)); 65652564Ssklower dst = rt_key(rt); 65752564Ssklower gate = rt->rt_gateway; 65852564Ssklower netmask = rt_mask(rt); 65952564Ssklower genmask = rt->rt_genmask; 660*68288Ssklower if (rt->rt_ifp) { 661*68288Ssklower ifpaddr = rt->rt_ifp->if_addrlist->ifa_addr; 662*68288Ssklower ifaaddr = rt->rt_ifa->ifa_addr; 663*68288Ssklower if (rt->rt_ifp->if_flags & IFF_POINTOPOINT) 664*68288Ssklower brdaddr = rt->rt_ifa->ifa_dstaddr; 665*68288Ssklower } 66652564Ssklower size = rt_msg2(RTM_GET, &info, 0, w); 66752564Ssklower if (w->w_where && w->w_tmem) { 66852564Ssklower register struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem; 66940446Ssklower 67052564Ssklower rtm->rtm_flags = rt->rt_flags; 67152564Ssklower rtm->rtm_use = rt->rt_use; 67252564Ssklower rtm->rtm_rmx = rt->rt_rmx; 67352564Ssklower rtm->rtm_index = rt->rt_ifp->if_index; 67452564Ssklower rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0; 67552564Ssklower rtm->rtm_addrs = info.rti_addrs; 67652564Ssklower if (error = copyout((caddr_t)rtm, w->w_where, size)) 67752564Ssklower w->w_where = NULL; 67852564Ssklower else 67952564Ssklower w->w_where += size; 68040446Ssklower } 68152564Ssklower return (error); 68252564Ssklower } 68352564Ssklower 68461339Sbostic int 68557836Smckusick sysctl_iflist(af, w) 68652564Ssklower int af; 68752564Ssklower register struct walkarg *w; 68852564Ssklower { 68952564Ssklower register struct ifnet *ifp; 69052564Ssklower register struct ifaddr *ifa; 69152564Ssklower struct rt_addrinfo info; 69252564Ssklower int len, error = 0; 69352564Ssklower 69452564Ssklower bzero((caddr_t)&info, sizeof(info)); 69552564Ssklower for (ifp = ifnet; ifp; ifp = ifp->if_next) { 69652631Ssklower if (w->w_arg && w->w_arg != ifp->if_index) 69752631Ssklower continue; 69852564Ssklower ifa = ifp->if_addrlist; 69952564Ssklower ifpaddr = ifa->ifa_addr; 70052564Ssklower len = rt_msg2(RTM_IFINFO, &info, (caddr_t)0, w); 70152564Ssklower ifpaddr = 0; 70252564Ssklower if (w->w_where && w->w_tmem) { 70352564Ssklower register struct if_msghdr *ifm; 70452564Ssklower 70552564Ssklower ifm = (struct if_msghdr *)w->w_tmem; 70652564Ssklower ifm->ifm_index = ifp->if_index; 70752564Ssklower ifm->ifm_flags = ifp->if_flags; 70852564Ssklower ifm->ifm_data = ifp->if_data; 70952564Ssklower ifm->ifm_addrs = info.rti_addrs; 71052564Ssklower if (error = copyout((caddr_t)ifm, w->w_where, len)) 71152564Ssklower return (error); 71252564Ssklower w->w_where += len; 71352564Ssklower } 71452564Ssklower while (ifa = ifa->ifa_next) { 71552631Ssklower if (af && af != ifa->ifa_addr->sa_family) 71652631Ssklower continue; 71752564Ssklower ifaaddr = ifa->ifa_addr; 71852564Ssklower netmask = ifa->ifa_netmask; 71952564Ssklower brdaddr = ifa->ifa_dstaddr; 72052564Ssklower len = rt_msg2(RTM_NEWADDR, &info, 0, w); 72152564Ssklower if (w->w_where && w->w_tmem) { 72252564Ssklower register struct ifa_msghdr *ifam; 72352564Ssklower 72452564Ssklower ifam = (struct ifa_msghdr *)w->w_tmem; 72552564Ssklower ifam->ifam_index = ifa->ifa_ifp->if_index; 72652564Ssklower ifam->ifam_flags = ifa->ifa_flags; 72752564Ssklower ifam->ifam_metric = ifa->ifa_metric; 72852564Ssklower ifam->ifam_addrs = info.rti_addrs; 72952564Ssklower if (error = copyout(w->w_tmem, w->w_where, len)) 73052564Ssklower return (error); 73152564Ssklower w->w_where += len; 73252564Ssklower } 73352564Ssklower } 73452631Ssklower ifaaddr = netmask = brdaddr = 0; 73552564Ssklower } 73640446Ssklower return (0); 73740446Ssklower } 73840446Ssklower 73961339Sbostic int 74057836Smckusick sysctl_rtable(name, namelen, where, given, new, newlen) 74157836Smckusick int *name; 74257836Smckusick int namelen; 74340446Ssklower caddr_t where; 74458496Sbostic size_t *given; 74557836Smckusick caddr_t *new; 74658496Sbostic size_t newlen; 74740446Ssklower { 74840446Ssklower register struct radix_node_head *rnh; 74952564Ssklower int i, s, error = EINVAL; 75057836Smckusick u_char af; 75140446Ssklower struct walkarg w; 75240446Ssklower 75357836Smckusick if (new) 75457836Smckusick return (EPERM); 75557836Smckusick if (namelen != 3) 75657836Smckusick return (EINVAL); 75757836Smckusick af = name[0]; 75840446Ssklower Bzero(&w, sizeof(w)); 75957836Smckusick w.w_where = where; 76057836Smckusick w.w_given = *given; 76140446Ssklower w.w_needed = 0 - w.w_given; 76257836Smckusick w.w_op = name[1]; 76357836Smckusick w.w_arg = name[2]; 76440446Ssklower 76540446Ssklower s = splnet(); 76657836Smckusick switch (w.w_op) { 76752564Ssklower 76857836Smckusick case NET_RT_DUMP: 76957836Smckusick case NET_RT_FLAGS: 77052564Ssklower for (i = 1; i <= AF_MAX; i++) 77152564Ssklower if ((rnh = rt_tables[i]) && (af == 0 || af == i) && 77259007Ssklower (error = rnh->rnh_walktree(rnh, 77359007Ssklower sysctl_dumpentry, &w))) 77452564Ssklower break; 77552564Ssklower break; 77652564Ssklower 77757836Smckusick case NET_RT_IFLIST: 77857836Smckusick error = sysctl_iflist(af, &w); 77940446Ssklower } 78052564Ssklower splx(s); 78152564Ssklower if (w.w_tmem) 78252564Ssklower free(w.w_tmem, M_RTABLE); 78340446Ssklower w.w_needed += w.w_given; 78457836Smckusick if (where) { 78540446Ssklower *given = w.w_where - where; 78657836Smckusick if (*given < w.w_needed) 78757836Smckusick return (ENOMEM); 78857836Smckusick } else { 78957836Smckusick *given = (11 * w.w_needed) / 10; 79057836Smckusick } 79140446Ssklower return (error); 79240446Ssklower } 79340446Ssklower 79440446Ssklower /* 79536352Ssklower * Definitions of protocols supported in the ROUTE domain. 79636352Ssklower */ 79736352Ssklower 79836352Ssklower extern struct domain routedomain; /* or at least forward */ 79936352Ssklower 80036352Ssklower struct protosw routesw[] = { 80136352Ssklower { SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR, 80236352Ssklower raw_input, route_output, raw_ctlinput, 0, 80336352Ssklower route_usrreq, 80436352Ssklower raw_init, 0, 0, 0, 80557836Smckusick sysctl_rtable, 80636352Ssklower } 80736352Ssklower }; 80836352Ssklower 80936352Ssklower struct domain routedomain = 81054824Ssklower { PF_ROUTE, "route", route_init, 0, 0, 81136352Ssklower routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] }; 812