raw_input(m, &route_proto, &route_src, &route_dst);
if (m) raw_input(m, &route_proto, &route_src, &route_dst);
		rt_msg1 __P((int, struct rt_addrinfo *));static int	rt_msg2 __P((int,		    struct rt_addrinfo *, caddr_t, struct walkarg *));static void	rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *));/* Sleazy use of local variables throughout file, warning!!!! */#define dst	info.rti_info[RTAX_DST]#define gate	info.rti_info[RTAX_GATEWAY]#define netmask	info.rti_info[RTAX_NETMASK]#define genmask	info.rti_info[RTAX_GENMASK]#define ifpaddr	info.rti_info[RTAX_IFP]#define ifaaddr	info.rti_info[RTAX_IFA]#define brdaddr	info.rti_info[RTAX_BRD]/*ARGSUSED*/introute_usrreq(so, req, m, nam, control)	register struct socket *so;	int req;	struct mbuf *m, *nam, *control;{	register int error = 0;	register struct rawcb *rp = sotorawcb(so);	int s;	if (req == PRU_ATTACH) {		MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK);		so->so_pcb = rp;		bzero(so->so_pcb, sizeof(*rp));	}	if (req == PRU_DETACH && rp) {		int af = rp->rcb_proto.sp_protocol;		if (af == AF_INET)			route_cb.ip_count--;		else if (af == AF_INET6)			route_cb.ip6_count--;		else if (af == AF_NS)			route_cb.ns_count--;		else if (af == AF_ISO)			route_cb.iso_count--;		route_cb.any_count--;	}	s = splsoftnet();	/*	 * Don't call raw_usrreq() in the attach case, because	 * we want to allow non-privileged processes to listen on	 * and send "safe" commands to the routing socket.	 */	if (req == PRU_ATTACH) {		if (curproc == 0)			error = EACCES;		else			error = raw_attach(so, (int)(long)nam);	} else		error = raw_usrreq(so, req, m, nam, control);	rp = sotorawcb(so);	if (req == PRU_ATTACH && rp) {		int af = rp->rcb_proto.sp_protocol;		if (error) {			free((caddr_t)rp, M_PCB);			splx(s);			return (error);		}		if (af == AF_INET)			route_cb.ip_count++;		else if (af == AF_INET6)			route_cb.ip6_count++;		else if (af == AF_NS)			route_cb.ns_count++;		else if (af == AF_ISO)			route_cb.iso_count++;		rp->rcb_faddr = &route_src;		route_cb.any_count++;		soisconnected(so);		so->so_options |= SO_USELOOPBACK;	}	splx(s);	return (error);}/*ARGSUSED*/int#if __STDC__route_output(struct mbuf *m, ...)#elseroute_output(m, va_alist)	struct mbuf *m;	va_dcl#endif{	register struct rt_msghdr *rtm = 0;	register struct radix_node *rn = 0;	register struct rtentry *rt = 0;	struct rtentry *saved_nrt = 0;	struct radix_node_head *rnh;	struct rt_addrinfo info;	int len, error = 0;	struct ifnet *ifp = 0;	struct ifaddr *ifa = 0;	struct socket *so;	va_list ap;	va_start(ap, m);	so = va_arg(ap, struct socket *);	va_end(ap);#define senderr(e) do { error = e; goto flush;} while (0)	if (m == 0 || ((m->m_len < sizeof(int32_t)) &&		       (m = m_pullup(m, sizeof(int32_t))) == 0))		return (ENOBUFS);	if ((m->m_flags & M_PKTHDR) == 0)		panic("route_output");	len = m->m_pkthdr.len;	if (len < sizeof(*rtm) ||	    len != mtod(m, struct rt_msghdr *)->rtm_msglen) {		dst = 0;		senderr(EINVAL);	}	R_Malloc(rtm, struct rt_msghdr *, len);	if (rtm == 0) {		dst = 0;		senderr(ENOBUFS);	}	m_copydata(m, 0, len, (caddr_t)rtm);	if (rtm->rtm_version != RTM_VERSION) {		dst = 0;		senderr(EPROTONOSUPPORT);	}	rtm->rtm_pid = curproc->p_pid;	bzero(&info, sizeof(info));	info.rti_addrs = rtm->rtm_addrs;	rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info);	info.rti_flags = rtm->rtm_flags;	if (dst == 0 || (dst->sa_family >= AF_MAX))		senderr(EINVAL);	if (gate != 0 && (gate->sa_family >= AF_MAX))		senderr(EINVAL);	if (genmask) {		struct radix_node *t;		t = rn_addmask((caddr_t)genmask, 0, 1);		if (t && Bcmp(genmask, t->rn_key, *(u_char *)genmask) == 0)			genmask = (struct sockaddr *)(t->rn_key);		else			senderr(ENOBUFS);	}	/*	 * Verify that the caller has the appropriate privilege; RTM_GET	 * is the only operation the non-superuser is allowed.	 */	if (rtm->rtm_type != RTM_GET &&	    suser(curproc->p_ucred, &curproc->p_acflag) != 0)		senderr(EACCES);	switch (rtm->rtm_type) {	case RTM_DELETE:		error = rtrequest1(rtm->rtm_type, &info, &saved_nrt);		if (error == 0) {			(rt = saved_nrt)->rt_refcnt++;			goto report;		}		break;	case RTM_ADD:		if (gate == 0)			senderr(EINVAL);		error = rtrequest1(rtm->rtm_type, &info, &saved_nrt);		if (error == 0 && saved_nrt) {			rt_setmetrics(rtm->rtm_inits,				&rtm->rtm_rmx, &saved_nrt->rt_rmx);			saved_nrt->rt_refcnt--;			saved_nrt->rt_genmask = genmask;		}		/* FALLTHROUGH */	case RTM_GET:	case RTM_CHANGE:	case RTM_LOCK:		if ((rnh = rt_tables[dst->sa_family]) == 0) {			senderr(EAFNOSUPPORT);		}		rn = rnh->rnh_lookup(dst, netmask, rnh);		if (rn == NULL || (rn->rn_flags & RNF_ROOT) != 0) {			senderr(ESRCH);		}		rt = (struct rtentry *)rn;		rt->rt_refcnt++;		switch(rtm->rtm_type) {		case RTM_GET:		report:			dst = rt_key(rt);			gate = rt->rt_gateway;			netmask = rt_mask(rt);			genmask = rt->rt_genmask;			if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) {				if ((ifp = rt->rt_ifp) != NULL) {					ifpaddr = ifp->if_addrlist.tqh_first->ifa_addr;					ifaaddr = rt->rt_ifa->ifa_addr;					if (ifp->if_flags & IFF_POINTOPOINT)						brdaddr = rt->rt_ifa->ifa_dstaddr;					else						brdaddr = 0;					rtm->rtm_index = ifp->if_index;				} else {					ifpaddr = 0;					ifaaddr = 0;				}			}			len = rt_msg2(rtm->rtm_type, &info, (caddr_t)0,				(struct walkarg *)0);			if (len > rtm->rtm_msglen) {				struct rt_msghdr *new_rtm;				R_Malloc(new_rtm, struct rt_msghdr *, len);				if (new_rtm == 0)					senderr(ENOBUFS);				Bcopy(rtm, new_rtm, rtm->rtm_msglen);				Free(rtm); rtm = new_rtm;			}			(void)rt_msg2(rtm->rtm_type, &info, (caddr_t)rtm,				(struct walkarg *)0);			rtm->rtm_flags = rt->rt_flags;			rtm->rtm_rmx = rt->rt_rmx;			rtm->rtm_addrs = info.rti_addrs;			break;		case RTM_CHANGE:			/*			 * new gateway could require new ifaddr, ifp;			 * flags may also be different; ifp may be specified			 * by ll sockaddr when protocol address is ambiguous			 */			if ((error = rt_getifa(&info)) != 0)				senderr(error);			if (gate && rt_setgate(rt, rt_key(rt), gate))				senderr(EDQUOT);			if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) &&			    (ifp = ifa->ifa_ifp) && (ifaaddr || gate))				ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate,							ifp);			else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) ||				 (gate && (ifa = ifa_ifwithroute(rt->rt_flags,							rt_key(rt), gate))))				ifp = ifa->ifa_ifp;			if (ifa) {				register struct ifaddr *oifa = rt->rt_ifa;				if (oifa != ifa) {				    if (oifa && oifa->ifa_rtrequest)					oifa->ifa_rtrequest(RTM_DELETE, rt,					    &info);				    IFAFREE(rt->rt_ifa);				    rt->rt_ifa = ifa;				    ifa->ifa_refcnt++;				    rt->rt_ifp = ifp;				}			}			rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,					&rt->rt_rmx);			if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)			       rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &info);			if (genmask)				rt->rt_genmask = genmask;			/*			 * Fall into			 */		case RTM_ADD:		case RTM_LOCK:			rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);			rt->rt_rmx.rmx_locks |=				(rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);			break;		}		break;	default:		senderr(EOPNOTSUPP);	}flush:	if (rtm) {		if (error)			rtm->rtm_errno = error;		else 			rtm->rtm_flags |= RTF_DONE;	}	if (rt)		rtfree(rt);    {	register struct rawcb *rp = 0;	/*	 * Check to see if we don't want our own messages.	 */	if ((so->so_options & SO_USELOOPBACK) == 0) {		if (route_cb.any_count <= 1) {			if (rtm)				Free(rtm);			m_freem(m);			return (error);		}		/* There is another listener, so construct message */		rp = sotorawcb(so);	}	if (rtm) {		m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm);		Free(rtm);	}	if (rp)		rp->rcb_proto.sp_family = 0; /* Avoid us */	if (dst)		route_proto.sp_protocol = dst->sa_family;	raw_input(m, &route_proto, &route_src, &route_dst);	if (rp)		rp->rcb_proto.sp_family = PF_ROUTE;    }	return (error);}voidrt_setmetrics(which, in, out)	u_long which;	register struct rt_metrics *in, *out;{#define metric(f, e) if (which & (f)) out->e = in->e;	metric(RTV_RPIPE, rmx_recvpipe);	metric(RTV_SPIPE, rmx_sendpipe);	metric(RTV_SSTHRESH, rmx_ssthresh);	metric(RTV_RTT, rmx_rtt);	metric(RTV_RTTVAR, rmx_rttvar);	metric(RTV_HOPCOUNT, rmx_hopcount);	metric(RTV_MTU, rmx_mtu);	metric(RTV_EXPIRE, rmx_expire);#undef metric}#define ROUNDUP(a) \	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))static voidrt_xaddrs(cp, cplim, rtinfo)	register caddr_t cp, cplim;	register struct rt_addrinfo *rtinfo;{	register struct sockaddr *sa;	register int i;	bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info));	for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {		if ((rtinfo->rti_addrs & (1 << i)) == 0)			continue;		rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;		ADVANCE(cp, sa);	}}/* * Copy data from a buffer back into the indicated mbuf chain, * starting "off" bytes from the beginning, extending the mbuf * chain if necessary. The mbuf needs to be properly initalized * including the setting of m_len. */voidm_copyback(m0, off, len, cp)	struct	mbuf *m0;	register int off;	register int len;	caddr_t cp;{	register int mlen;	register struct mbuf *m = m0, *n;	int totlen = 0;	if (m0 == 0)		return;	while (off > (mlen = m->m_len)) {		off -= mlen;		totlen += mlen;		if (m->m_next == 0) {			n = m_getclr(M_DONTWAIT, m->m_type);			if (n == 0)				goto out;			n->m_len = min(MLEN, len + off);			m->m_next = n;		}		m = m->m_next;	}	while (len > 0) {		mlen = min (m->m_len - off, len);		bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);		cp += mlen;		len -= mlen;		mlen += off;		off = 0;		totlen += mlen;		if (len == 0)			break;		if (m->m_next == 0) {			n = m_get(M_DONTWAIT, m->m_type);			if (n == 0)				break;			n->m_len = min(MLEN, len);			m->m_next = n;		}		m = m->m_next;	}out:	if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))		m->m_pkthdr.len = totlen;}static struct mbuf *rt_msg1(type, rtinfo)	int type;	register struct rt_addrinfo *rtinfo;{	register struct rt_msghdr *rtm;	register struct mbuf *m;	register int i;	register struct sockaddr *sa;	int len, dlen;	switch (type) {	case RTM_DELADDR:	case RTM_NEWADDR:		len = sizeof(struct ifa_msghdr);		break;	case RTM_IFINFO:		len = sizeof(struct if_msghdr);		break;	default:		len = sizeof(struct rt_msghdr);	}	if (len > MCLBYTES)		panic("rt_msg1");	m = m_gethdr(M_DONTWAIT, MT_DATA);	if (m && len > MHLEN) {		MCLGET(m, M_DONTWAIT);		if ((m->m_flags & M_EXT) == 0) {			m_free(m);			m = NULL;		}	}	if (m == 0)		return (m);	m->m_pkthdr.len = m->m_len = len;	m->m_pkthdr.rcvif = 0;	rtm = mtod(m, struct rt_msghdr *);	bzero((caddr_t)rtm, len);	for (i = 0; i < RTAX_MAX; i++) {		if ((sa = rtinfo->rti_info[i]) == NULL)			continue;		rtinfo->rti_addrs |= (1 << i);		dlen = ROUNDUP(sa->sa_len);		m_copyback(m, len, dlen, (caddr_t)sa);		len += dlen;	}	if (m->m_pkthdr.len != len) {		m_freem(m);		return (NULL);	}	rtm->rtm_msglen = len;	rtm->rtm_version = RTM_VERSION;	rtm->rtm_type = type;	return (m);}