xref: /csrg-svn/sys/net/rtsock.c (revision 37517)
136352Ssklower /*
236352Ssklower  * Copyright (c) 1988 Regents of the University of California.
336352Ssklower  * All rights reserved.
436352Ssklower  *
536352Ssklower  * Redistribution and use in source and binary forms are permitted
636352Ssklower  * provided that the above copyright notice and this paragraph are
736352Ssklower  * duplicated in all such forms and that any documentation,
836352Ssklower  * advertising materials, and other materials related to such
936352Ssklower  * distribution and use acknowledge that the software was developed
1036352Ssklower  * by the University of California, Berkeley.  The name of the
1136352Ssklower  * University may not be used to endorse or promote products derived
1236352Ssklower  * from this software without specific prior written permission.
1336352Ssklower  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1436352Ssklower  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1536352Ssklower  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1636352Ssklower  *
17*37517Smckusick  *	@(#)rtsock.c	7.3 (Berkeley) 04/25/89
1836352Ssklower  */
1936352Ssklower 
2036352Ssklower #ifndef RTF_UP
2136352Ssklower #include "param.h"
2236352Ssklower #include "mbuf.h"
2336352Ssklower #include "dir.h"
2436352Ssklower #include "user.h"
2536352Ssklower #include "proc.h"
2636352Ssklower #include "socket.h"
2736352Ssklower #include "socketvar.h"
2836352Ssklower #include "domain.h"
2936352Ssklower #include "protosw.h"
3036352Ssklower #include "errno.h"
3136352Ssklower 
3236352Ssklower #include "af.h"
3336352Ssklower #include "route.h"
3436352Ssklower #include "raw_cb.h"
3536352Ssklower 
36*37517Smckusick #include "machine/mtpr.h"
3736352Ssklower #endif
3836352Ssklower 
3937472Ssklower struct sockaddr route_dst = { 0, PF_ROUTE, };
4037472Ssklower struct sockaddr route_src = { 0, PF_ROUTE, };
4137472Ssklower struct sockproto route_proto = { PF_ROUTE, };
4237472Ssklower 
4336352Ssklower /*ARGSUSED*/
4436352Ssklower route_usrreq(so, req, m, nam, rights, control)
4536352Ssklower 	register struct socket *so;
4636352Ssklower 	int req;
4736352Ssklower 	struct mbuf *m, *nam, *rights, *control;
4836352Ssklower {
4936352Ssklower 	register int error = 0;
5036352Ssklower 	register struct rawcb *rp = sotorawcb(so);
5137472Ssklower 	if (req == PRU_ATTACH) {
5237472Ssklower 		MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK);
5337472Ssklower 		if (so->so_pcb = (caddr_t)rp)
5437472Ssklower 			bzero(so->so_pcb, sizeof(*rp));
5537472Ssklower 
5637472Ssklower 	}
5736352Ssklower 	if (req == PRU_DETACH && rp) {
5836352Ssklower 		int af = rp->rcb_proto.sp_protocol;
5936352Ssklower 		if (af == AF_INET)
6036352Ssklower 			route_cb.ip_count--;
6136352Ssklower 		else if (af == AF_NS)
6236352Ssklower 			route_cb.ns_count--;
6336352Ssklower 		else if (af == AF_ISO)
6436352Ssklower 			route_cb.iso_count--;
6536352Ssklower 		route_cb.any_count--;
6636352Ssklower 	}
6736352Ssklower 	error = raw_usrreq(so, req, m, nam, rights, control);
6836352Ssklower 	rp = sotorawcb(so);
6937472Ssklower 	if (req == PRU_ATTACH && rp) {
7036352Ssklower 		int af = rp->rcb_proto.sp_protocol;
7137472Ssklower 		if (error) {
7237472Ssklower 			free((caddr_t)rp, M_PCB);
7337472Ssklower 			return (error);
7437472Ssklower 		}
7536352Ssklower 		if (af == AF_INET)
7636352Ssklower 			route_cb.ip_count++;
7736352Ssklower 		else if (af == AF_NS)
7836352Ssklower 			route_cb.ns_count++;
7936352Ssklower 		else if (af == AF_ISO)
8036352Ssklower 			route_cb.iso_count++;
8137472Ssklower 		rp->rcb_faddr = &route_src;
8236352Ssklower 		route_cb.any_count++;
8336352Ssklower 		soisconnected(so);
8436352Ssklower 	}
8536352Ssklower 	return (error);
8636352Ssklower }
8736352Ssklower #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
8836352Ssklower 
8937472Ssklower /*ARGSUSED*/
9036352Ssklower route_output(m, so)
9136352Ssklower 	register struct mbuf *m;
9236352Ssklower 	struct socket *so;
9336352Ssklower {
9436352Ssklower 	register struct rt_msghdr *rtm = 0;
9536352Ssklower 	register struct rtentry *rt = 0;
9636352Ssklower 	struct mbuf *m0 = m;
9736352Ssklower 	struct rtentry *saved_nrt;
9836352Ssklower 	struct sockaddr *dst = 0, *gate = 0, *netmask = 0, *author;
9936352Ssklower 	struct rt_metrics *rmm = 0;
10036352Ssklower 	caddr_t cp = 0;
10137472Ssklower 	int len, error = 0;
10236352Ssklower 
10336352Ssklower #define FLUSH(e) { error = e; goto flush;}
10436352Ssklower 	if (m == 0 || (m = m_pullup(m, sizeof(long))) == 0)
10536352Ssklower 		FLUSH(ENOBUFS);
10636352Ssklower 	if ((m->m_flags & M_PKTHDR) == 0)
10736352Ssklower 		return (EOPNOTSUPP);
10836352Ssklower 	len = m->m_pkthdr.len;
10936352Ssklower 	rtm = mtod(m, struct rt_msghdr *);
11036352Ssklower 	if (len < rtm->rtm_msglen)
11136352Ssklower 		FLUSH(EINVAL);
11236352Ssklower 	R_Malloc(rtm, struct rt_msghdr *, len);
11336352Ssklower 	if (rtm == 0)
11436352Ssklower 		FLUSH(ENOBUFS);
11536352Ssklower 	m_copydata(m, 0, len, (caddr_t)rtm);
11636352Ssklower 	if (rtm->rtm_version != 1)
11736352Ssklower 		FLUSH(EPROTONOSUPPORT);
11836352Ssklower 	rtm->rtm_pid = u.u_procp->p_pid;
11936352Ssklower 	cp = (caddr_t) (rtm + 1);
12036352Ssklower #ifdef notyet
12136352Ssklower 	switch (rtm->rtm_type) {
12236352Ssklower 
12336352Ssklower 	case RTM_ADD: case RTM_CHANGE: case RTM_GET:
12436352Ssklower 		rmm = (struct rt_metrics *)cp ;
12536352Ssklower 		cp = (caddr_t) (rmm + 1);
12636352Ssklower 	}
12736352Ssklower #endif
12836352Ssklower 	if (rtm->rtm_count > 0) {
12936352Ssklower 		dst = (struct sockaddr *)cp;
13036352Ssklower 		cp += ROUNDUP(dst->sa_len);
13136352Ssklower 	}
13236352Ssklower 	if (rtm->rtm_count > 1)  {
13336352Ssklower 		gate = (struct sockaddr *)cp;
13436352Ssklower 		cp += ROUNDUP(gate->sa_len);
13536352Ssklower 	}
13636352Ssklower 	if (rtm->rtm_count > 2)  {
13736352Ssklower 		netmask = (struct sockaddr *)cp;
13837472Ssklower 		if (*cp)
13937472Ssklower 			cp += ROUNDUP(netmask->sa_len);
14037472Ssklower 		else
14137472Ssklower 			cp += sizeof(long);
14237472Ssklower 
14336352Ssklower 	}
14436352Ssklower 	if (rtm->rtm_count > 3)  {
14536352Ssklower 		author = (struct sockaddr *)cp;
14636352Ssklower 	}
14736352Ssklower 	switch (rtm->rtm_type) {
14836352Ssklower 	case RTM_ADD:
14936352Ssklower 		error = rtrequest(RTM_ADD, dst, gate, netmask,
15036352Ssklower 					rtm->rtm_flags, &saved_nrt);
15136352Ssklower 		/* XXX -- add metrics !!! */
15236352Ssklower 		break;
15336352Ssklower 
15436352Ssklower 	case RTM_DELETE:
15536352Ssklower 		error = rtrequest(RTM_DELETE, dst, gate, netmask,
15637472Ssklower 				rtm->rtm_flags, (struct rtentry **)0);
15736352Ssklower 		break;
15836352Ssklower 
15936352Ssklower 	case RTM_GET:
16036352Ssklower 	case RTM_CHANGE:
16136352Ssklower 	case RTM_LOCK:
16236352Ssklower 		rt = rtalloc1(dst, 0);
16336352Ssklower 		if (rt == 0)
16436352Ssklower 			FLUSH(ESRCH);
16536352Ssklower 		switch(rtm->rtm_type) {
16636352Ssklower 			 struct	sockaddr *outmask;
16736352Ssklower 
16836352Ssklower 		case RTM_GET:
16936352Ssklower 			netmask = rt_mask(rt);
17036352Ssklower 			len = sizeof(*rtm) + ROUNDUP(rt_key(rt)->sa_len)
17136352Ssklower 					+ ROUNDUP(rt->rt_gateway->sa_len);
17236352Ssklower 			if (netmask)
17337472Ssklower 				len += netmask->sa_len;
17436352Ssklower 			if (len > rtm->rtm_msglen) {
17536352Ssklower 				struct rt_msghdr *new_rtm;
17636352Ssklower 				R_Malloc(new_rtm, struct rt_msghdr *, len);
17736352Ssklower 				if (new_rtm == 0)
17836352Ssklower 					FLUSH(ENOBUFS);
17936352Ssklower 				Bcopy(rtm, new_rtm, rtm->rtm_msglen);
18036352Ssklower 				Free(rtm); rtm = new_rtm;
18136352Ssklower 				gate = (struct sockaddr *)
18236352Ssklower 				    (ROUNDUP(rt->rt_gateway->sa_len)
18336352Ssklower 								+ (char *)dst);
18436352Ssklower 				Bcopy(&rt->rt_gateway, gate,
18536352Ssklower 						rt->rt_gateway->sa_len);
18636352Ssklower 				rtm->rtm_flags = rt->rt_flags;
18736352Ssklower 				rtm->rtm_count = 2;
18836352Ssklower 				if (netmask) {
18936352Ssklower 				    outmask = (struct sockaddr *)
19036352Ssklower 				       (ROUNDUP(netmask->sa_len)+(char *)gate);
19136352Ssklower 				    Bcopy(netmask, outmask, netmask->sa_len);
19236352Ssklower 				    rtm->rtm_count = 3;
19336352Ssklower 				}
19436352Ssklower 			}
19536352Ssklower 			break;
19636352Ssklower 
19736352Ssklower 		case RTM_CHANGE:
19836352Ssklower 			if (gate->sa_len > (len = rt->rt_gateway->sa_len))
19936352Ssklower 				FLUSH(EDQUOT);
20036352Ssklower 			if (gate->sa_family != rt->rt_gateway->sa_family)
20136352Ssklower 				FLUSH(EADDRINUSE);
20236352Ssklower 			Bcopy(gate, rt->rt_gateway, len);
20336352Ssklower 			rt->rt_gateway->sa_len = len;
20436352Ssklower 
20536352Ssklower #ifdef notdef
20636352Ssklower #define metric(f, e) if (rtm->rtm_inits & (f)) rt->rt_m.e = rtm->e;
20736352Ssklower 			metric(RTM_RPIPE, rtm_recvpipe);
20836352Ssklower 			metric(RTM_SPIPE, rtm_sendpipe);
20936352Ssklower 			metric(RTM_SSTHRESH, rtm_ssthresh);
21036352Ssklower 			metric(RTM_RTT, rtm_rtt);
21136352Ssklower 			metric(RTM_RTTVAR, rtm_rttvar);
21236352Ssklower 			metric(RTM_HOPCOUNT, rtm_hopcount);
21336352Ssklower 			metric(RTM_MTU, rtm_mtu);
21436352Ssklower 			/*
21536352Ssklower 			 * Fall into
21636352Ssklower 			 */
21736352Ssklower 		case RTM_LOCKS:
21836352Ssklower 			rt->rt_locks |= (rtm->rtm_inits & rtm->rtm_locks);
21936352Ssklower 			rt->rt_locks &= ~(rtm->rtm_inits);
22036352Ssklower 			break;
22136352Ssklower #endif
22236352Ssklower 		}
22336352Ssklower 		goto cleanup;
22436352Ssklower 
22536352Ssklower 	default:
22636352Ssklower 		FLUSH(EOPNOTSUPP);
22736352Ssklower 	}
22836352Ssklower 
22936352Ssklower flush:
23036352Ssklower 	if (rtm) {
23136352Ssklower 		if (error)
23236352Ssklower 			rtm->rtm_errno = error;
23336352Ssklower 		else
23436352Ssklower 			rtm->rtm_flags |= RTF_DONE;
23536352Ssklower 	}
23636352Ssklower cleanup:
23736352Ssklower 	if (rt)
23836352Ssklower 		rtfree(rt);
23936352Ssklower 	cp = (caddr_t)rtm;
24036352Ssklower 	m_copyback(m = m0, 0, len, cp);
24136352Ssklower 	/*if (m->m_pkthdr.len != len) {
24236352Ssklower 		m_freem(m);
24336352Ssklower 		return (error);
24436352Ssklower 	} */
24536352Ssklower 	route_proto.sp_protocol = dst->sa_family;
24636352Ssklower 	raw_input(m0, &route_proto, &route_src, &route_dst);
24736352Ssklower 	return (error);
24836352Ssklower }
24936352Ssklower 
25036352Ssklower /*
25136352Ssklower  * Copy data from a buffer back into the indicated mbuf chain,
25236352Ssklower  * starting "off" bytes from the beginning, extending the mbuf
25336352Ssklower  * chain if necessary.
25436352Ssklower  */
25536352Ssklower m_copyback(m0, off, len, cp)
25636352Ssklower 	struct	mbuf *m0;
25736352Ssklower 	register int off;
25836352Ssklower 	register int len;
25936352Ssklower 	caddr_t cp;
26036352Ssklower 
26136352Ssklower {
26236352Ssklower 	register int mlen;
26336352Ssklower 	register struct mbuf *m = m0, *n;
26436352Ssklower 	int totlen = 0;
26536352Ssklower 
26636352Ssklower 	if (m0 == 0)
26736352Ssklower 		return;
26836352Ssklower 	while (off >= (mlen = m->m_len)) {
26936352Ssklower 		off -= mlen;
27036352Ssklower 		totlen += mlen;
27136352Ssklower 		if (m->m_next == 0) {
27236352Ssklower 			n = m_getclr(M_DONTWAIT, m->m_type);
27336352Ssklower 			if (n == 0)
27436352Ssklower 				goto out;
27536352Ssklower 			n->m_len = min(MLEN, len + off);
27636352Ssklower 			m->m_next = n;
27736352Ssklower 		}
27836352Ssklower 		m = m->m_next;
27936352Ssklower 	}
28036352Ssklower 	while (len > 0) {
28136352Ssklower 		mlen = min (m->m_len - off, len);
28237472Ssklower 		bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);
28336352Ssklower 		cp += mlen;
28436352Ssklower 		len -= mlen;
28536352Ssklower 		mlen += off;
28636352Ssklower 		off = 0;
28736352Ssklower 		totlen += mlen;
28836352Ssklower 		if (len == 0)
28936352Ssklower 			break;
29036352Ssklower 		if (m->m_next == 0) {
29136352Ssklower 			n = m_get(M_DONTWAIT, m->m_type);
29236352Ssklower 			if (n == 0)
29336352Ssklower 				break;
29436352Ssklower 			n->m_len = min(MLEN, len);
29536352Ssklower 			m->m_next = n;
29636352Ssklower 		}
29736352Ssklower 		m = m->m_next;
29836352Ssklower 	}
29936352Ssklower out:	if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
30036352Ssklower 		m->m_pkthdr.len = totlen;
30136352Ssklower }
30236352Ssklower 
30336352Ssklower /*
30436352Ssklower  * The miss message and losing message are very similar.
30536352Ssklower  */
30636352Ssklower 
30737472Ssklower rt_missmsg(type, dst, gate, mask, src, flags, error)
30836352Ssklower register struct sockaddr *dst;
30936352Ssklower struct sockaddr *gate, *mask, *src;
31036352Ssklower {
31136352Ssklower 	register struct rt_msghdr *rtm;
31236352Ssklower 	register struct mbuf *m;
31336352Ssklower 	int dlen = ROUNDUP(dst->sa_len);
31436352Ssklower 	int len = dlen + sizeof(*rtm);
31536352Ssklower 
31636352Ssklower 	if (route_cb.any_count == 0)
31736352Ssklower 		return;
31836352Ssklower 	m = m_gethdr(M_DONTWAIT, MT_DATA);
31936352Ssklower 	if (m == 0)
32036352Ssklower 		return;
32136352Ssklower 	m->m_pkthdr.len = m->m_len = min(len, MHLEN);
32236352Ssklower 	m->m_pkthdr.rcvif = 0;
32336352Ssklower 	rtm = mtod(m, struct rt_msghdr *);
32436352Ssklower 	bzero((caddr_t)rtm, sizeof(*rtm)); /*XXX assumes sizeof(*rtm) < MHLEN*/
32536352Ssklower 	rtm->rtm_flags = RTF_DONE | flags;
32636352Ssklower 	rtm->rtm_msglen = len;
32736352Ssklower 	rtm->rtm_version = 1;
32836352Ssklower 	rtm->rtm_type = type;
32936352Ssklower 	rtm->rtm_count = 1;
33036352Ssklower 	if (type == RTM_OLDADD || type == RTM_OLDDEL) {
33136352Ssklower 		rtm->rtm_pid = u.u_procp->p_pid;
33236352Ssklower 	}
33336352Ssklower 	m_copyback(m, sizeof (*rtm), dlen, (caddr_t)dst);
33436352Ssklower 	if (gate) {
33536352Ssklower 		dlen = ROUNDUP(gate->sa_len);
33636352Ssklower 		m_copyback(m, len ,  dlen, (caddr_t)gate);
33736352Ssklower 		len += dlen;
33836352Ssklower 		rtm->rtm_count++;
33936352Ssklower 	}
34036352Ssklower 	if (mask) {
34137472Ssklower 		if (mask->sa_len)
34237472Ssklower 			dlen = ROUNDUP(mask->sa_len);
34337472Ssklower 		else
34437472Ssklower 			dlen = sizeof(long);
34536352Ssklower 		m_copyback(m, len ,  dlen, (caddr_t)mask);
34636352Ssklower 		len += dlen;
34736352Ssklower 		rtm->rtm_count++;
34836352Ssklower 	}
34936352Ssklower 	if (src) {
35036352Ssklower 		dlen = ROUNDUP(src->sa_len);
35136352Ssklower 		m_copyback(m, len ,  dlen, (caddr_t)src);
35236352Ssklower 		len += dlen;
35336352Ssklower 		rtm->rtm_count++;
35436352Ssklower 	}
35536352Ssklower 	if (m->m_pkthdr.len != len) {
35636352Ssklower 		m_freem(m);
35736352Ssklower 		return;
35836352Ssklower 	}
35937472Ssklower 	rtm->rtm_errno = error;
36036352Ssklower 	rtm->rtm_msglen = len;
36136352Ssklower 	route_proto.sp_protocol = dst->sa_family;
36236352Ssklower 	raw_input(m, &route_proto, &route_src, &route_dst);
36336352Ssklower }
36436352Ssklower 
36536352Ssklower /*
36636352Ssklower  * Definitions of protocols supported in the ROUTE domain.
36736352Ssklower  */
36836352Ssklower 
36936352Ssklower int	route_output();
37036352Ssklower int	raw_init(),raw_usrreq(),raw_input(),raw_ctlinput();
37136352Ssklower extern	struct domain routedomain;		/* or at least forward */
37236352Ssklower 
37336352Ssklower struct protosw routesw[] = {
37436352Ssklower { SOCK_RAW,	&routedomain,	0,		PR_ATOMIC|PR_ADDR,
37536352Ssklower   raw_input,	route_output,	raw_ctlinput,	0,
37636352Ssklower   route_usrreq,
37736352Ssklower   raw_init,	0,		0,		0,
37836352Ssklower },
37936352Ssklower { 0,		0,		0,		0,
38036352Ssklower   raw_input,	0,		raw_ctlinput,	0,
38136352Ssklower   raw_usrreq,
38236352Ssklower   raw_init,	0,		0,		0,
38336352Ssklower }
38436352Ssklower };
38536352Ssklower 
38636352Ssklower int	unp_externalize(), unp_dispose();
38736352Ssklower 
38836352Ssklower struct domain routedomain =
38936352Ssklower     { PF_ROUTE, "route", 0, 0, 0,
39036352Ssklower       routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] };
391