xref: /csrg-svn/sys/net/raw_usrreq.c (revision 21531)
1*21531Skarels /*	raw_usrreq.c	6.6	85/05/30	*/
25121Swnj 
317037Sbloom #include "param.h"
417037Sbloom #include "mbuf.h"
517037Sbloom #include "domain.h"
617037Sbloom #include "protosw.h"
717037Sbloom #include "socket.h"
817037Sbloom #include "socketvar.h"
917037Sbloom #include "errno.h"
1010890Ssam 
1117037Sbloom #include "if.h"
1217037Sbloom #include "route.h"
1317037Sbloom #include "netisr.h"
1417037Sbloom #include "raw_cb.h"
155121Swnj 
1610890Ssam #include "../vax/mtpr.h"
1710890Ssam 
185121Swnj /*
195612Swnj  * Initialize raw connection block q.
206211Swnj  */
215612Swnj raw_init()
225612Swnj {
236211Swnj 
245612Swnj 	rawcb.rcb_next = rawcb.rcb_prev = &rawcb;
256211Swnj 	rawintrq.ifq_maxlen = IFQ_MAXLEN;
265612Swnj }
275612Swnj 
285612Swnj /*
295121Swnj  * Raw protocol interface.
305121Swnj  */
316529Ssam raw_input(m0, proto, src, dst)
325612Swnj 	struct mbuf *m0;
336509Ssam 	struct sockproto *proto;
346529Ssam 	struct sockaddr *src, *dst;
355121Swnj {
365612Swnj 	register struct mbuf *m;
375612Swnj 	struct raw_header *rh;
385121Swnj 	int s;
395121Swnj 
405612Swnj 	/*
415612Swnj 	 * Rip off an mbuf for a generic header.
425612Swnj 	 */
439638Ssam 	m = m_get(M_DONTWAIT, MT_HEADER);
445612Swnj 	if (m == 0) {
455612Swnj 		m_freem(m0);
465612Swnj 		return;
475612Swnj 	}
485612Swnj 	m->m_next = m0;
495612Swnj 	m->m_len = sizeof(struct raw_header);
505612Swnj 	rh = mtod(m, struct raw_header *);
516509Ssam 	rh->raw_dst = *dst;
526509Ssam 	rh->raw_src = *src;
536509Ssam 	rh->raw_proto = *proto;
545612Swnj 
555612Swnj 	/*
565612Swnj 	 * Header now contains enough info to decide
575612Swnj 	 * which socket to place packet in (if any).
585612Swnj 	 * Queue it up for the raw protocol process
595612Swnj 	 * running at software interrupt level.
605612Swnj 	 */
615121Swnj 	s = splimp();
626211Swnj 	if (IF_QFULL(&rawintrq))
636211Swnj 		m_freem(m);
646211Swnj 	else
656211Swnj 		IF_ENQUEUE(&rawintrq, m);
665121Swnj 	splx(s);
676263Swnj 	schednetisr(NETISR_RAW);
685121Swnj }
695121Swnj 
705612Swnj /*
715612Swnj  * Raw protocol input routine.  Process packets entered
725612Swnj  * into the queue at interrupt time.  Find the socket
735612Swnj  * associated with the packet(s) and move them over.  If
745612Swnj  * nothing exists for this packet, drop it.
755612Swnj  */
765121Swnj rawintr()
775121Swnj {
785121Swnj 	int s;
795121Swnj 	struct mbuf *m;
805612Swnj 	register struct rawcb *rp;
816509Ssam 	register struct protosw *lproto;
826529Ssam 	register struct raw_header *rh;
835612Swnj 	struct socket *last;
845121Swnj 
855121Swnj next:
865121Swnj 	s = splimp();
875121Swnj 	IF_DEQUEUE(&rawintrq, m);
885121Swnj 	splx(s);
895121Swnj 	if (m == 0)
905121Swnj 		return;
916509Ssam 	rh = mtod(m, struct raw_header *);
925612Swnj 	last = 0;
935612Swnj 	for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) {
946509Ssam 		lproto = rp->rcb_socket->so_proto;
9516987Skarels 		if (lproto->pr_domain->dom_family != rh->raw_proto.sp_family)
965612Swnj 			continue;
976509Ssam 		if (lproto->pr_protocol &&
986509Ssam 		    lproto->pr_protocol != rh->raw_proto.sp_protocol)
995612Swnj 			continue;
1005612Swnj 		/*
1015612Swnj 		 * We assume the lower level routines have
1025612Swnj 		 * placed the address in a canonical format
1036509Ssam 		 * suitable for a structure comparison.
1045612Swnj 		 */
1056529Ssam #define equal(a1, a2) \
1066529Ssam 	(bcmp((caddr_t)&(a1), (caddr_t)&(a2), sizeof (struct sockaddr)) == 0)
1076509Ssam 		if ((rp->rcb_flags & RAW_LADDR) &&
1086529Ssam 		    !equal(rp->rcb_laddr, rh->raw_dst))
1095612Swnj 			continue;
1106509Ssam 		if ((rp->rcb_flags & RAW_FADDR) &&
1116529Ssam 		    !equal(rp->rcb_faddr, rh->raw_src))
1126509Ssam 			continue;
1135612Swnj 		if (last) {
1145612Swnj 			struct mbuf *n;
115*21531Skarels 			if (n = m_copy(m->m_next, 0, (int)M_COPYALL)) {
116*21531Skarels 				if (sbappendaddr(&last->so_rcv, &rh->raw_src,
117*21531Skarels 				    n, (struct mbuf *)0) == 0)
118*21531Skarels 					/* should notify about lost packet */
119*21531Skarels 					m_freem(n);
120*21531Skarels 				else
121*21531Skarels 					sorwakeup(last);
1225646Ssam 			}
1235612Swnj 		}
1246509Ssam 		last = rp->rcb_socket;
1255612Swnj 	}
1266584Ssam 	if (last) {
12712783Ssam 		if (sbappendaddr(&last->so_rcv, &rh->raw_src,
128*21531Skarels 		    m->m_next, (struct mbuf *)0) == 0)
129*21531Skarels 			m_freem(m->m_next);
130*21531Skarels 		else
131*21531Skarels 			sorwakeup(last);
132*21531Skarels 		(void) m_free(m);		/* header */
133*21531Skarels 	} else
134*21531Skarels 		m_freem(m);
1355121Swnj 	goto next;
1365121Swnj }
1375121Swnj 
1388636Sroot /*ARGSUSED*/
1396584Ssam raw_ctlinput(cmd, arg)
1406584Ssam 	int cmd;
1416584Ssam 	caddr_t arg;
1426584Ssam {
1436591Ssam 
1446591Ssam 	if (cmd < 0 || cmd > PRC_NCMDS)
1456591Ssam 		return;
1468636Sroot 	/* INCOMPLETE */
1476584Ssam }
1486584Ssam 
1495121Swnj /*ARGSUSED*/
15012783Ssam raw_usrreq(so, req, m, nam, rights)
1515121Swnj 	struct socket *so;
1525121Swnj 	int req;
15312783Ssam 	struct mbuf *m, *nam, *rights;
1545121Swnj {
1555612Swnj 	register struct rawcb *rp = sotorawcb(so);
15612783Ssam 	register int error = 0;
1575121Swnj 
15812783Ssam 	if (rights && rights->m_len) {
15912783Ssam 		error = EOPNOTSUPP;
16012783Ssam 		goto release;
16112783Ssam 	}
16212783Ssam 	if (rp == 0 && req != PRU_ATTACH) {
16312783Ssam 		error = EINVAL;
16412783Ssam 		goto release;
16512783Ssam 	}
1665612Swnj 	switch (req) {
1675612Swnj 
1685612Swnj 	/*
1695612Swnj 	 * Allocate a raw control block and fill in the
1705612Swnj 	 * necessary info to allow packets to be routed to
1715612Swnj 	 * the appropriate raw interface routine.
1725612Swnj 	 */
1735612Swnj 	case PRU_ATTACH:
17412783Ssam 		if ((so->so_state & SS_PRIV) == 0) {
17512783Ssam 			error = EACCES;
17613116Ssam 			break;
17712783Ssam 		}
17812783Ssam 		if (rp) {
17912783Ssam 			error = EINVAL;
18013116Ssam 			break;
18112783Ssam 		}
1828395Swnj 		error = raw_attach(so);
1835612Swnj 		break;
1845612Swnj 
1855612Swnj 	/*
1865612Swnj 	 * Destroy state just before socket deallocation.
1875612Swnj 	 * Flush data or not depending on the options.
1885612Swnj 	 */
1895612Swnj 	case PRU_DETACH:
19012783Ssam 		if (rp == 0) {
19112783Ssam 			error = ENOTCONN;
19213116Ssam 			break;
19312783Ssam 		}
1945612Swnj 		raw_detach(rp);
1955612Swnj 		break;
1965612Swnj 
1975612Swnj 	/*
1985612Swnj 	 * If a socket isn't bound to a single address,
1995612Swnj 	 * the raw input routine will hand it anything
2005612Swnj 	 * within that protocol family (assuming there's
2015612Swnj 	 * nothing else around it should go to).
2025612Swnj 	 */
2035612Swnj 	case PRU_CONNECT:
20412783Ssam 		if (rp->rcb_flags & RAW_FADDR) {
20512783Ssam 			error = EISCONN;
20613116Ssam 			break;
20712783Ssam 		}
2088395Swnj 		raw_connaddr(rp, nam);
2095612Swnj 		soisconnected(so);
2105612Swnj 		break;
2115612Swnj 
21213116Ssam 	case PRU_CONNECT2:
21313116Ssam 		error = EOPNOTSUPP;
21413116Ssam 		goto release;
21513116Ssam 
21612783Ssam 	case PRU_BIND:
21712783Ssam 		if (rp->rcb_flags & RAW_LADDR) {
21812783Ssam 			error = EINVAL;			/* XXX */
21913116Ssam 			break;
22012783Ssam 		}
22112783Ssam 		error = raw_bind(so, nam);
22212783Ssam 		break;
22312783Ssam 
2245612Swnj 	case PRU_DISCONNECT:
22512783Ssam 		if ((rp->rcb_flags & RAW_FADDR) == 0) {
22612783Ssam 			error = ENOTCONN;
22713116Ssam 			break;
22812783Ssam 		}
22913451Ssam 		if (rp->rcb_route.ro_rt)
23013451Ssam 			rtfree(rp->rcb_route.ro_rt);
2315612Swnj 		raw_disconnect(rp);
2325612Swnj 		soisdisconnected(so);
2335612Swnj 		break;
2345612Swnj 
2355612Swnj 	/*
2365612Swnj 	 * Mark the connection as being incapable of further input.
2375612Swnj 	 */
2385612Swnj 	case PRU_SHUTDOWN:
2395612Swnj 		socantsendmore(so);
2405612Swnj 		break;
2415612Swnj 
2425612Swnj 	/*
2435612Swnj 	 * Ship a packet out.  The appropriate raw output
2445612Swnj 	 * routine handles any massaging necessary.
2455612Swnj 	 */
2465612Swnj 	case PRU_SEND:
2478395Swnj 		if (nam) {
24812783Ssam 			if (rp->rcb_flags & RAW_FADDR) {
24912783Ssam 				error = EISCONN;
25013116Ssam 				break;
25112783Ssam 			}
2528395Swnj 			raw_connaddr(rp, nam);
25312783Ssam 		} else if ((rp->rcb_flags & RAW_FADDR) == 0) {
25412783Ssam 			error = ENOTCONN;
25513116Ssam 			break;
25612783Ssam 		}
25713451Ssam 		/*
25813451Ssam 		 * Check for routing.  If new foreign address, or
25913451Ssam 		 * no route presently in use, try to allocate new
26013451Ssam 		 * route.  On failure, just hand packet to output
26113451Ssam 		 * routine anyway in case it can handle it.
26213451Ssam 		 */
26313451Ssam 		if ((rp->rcb_flags & RAW_DONTROUTE) == 0)
26413451Ssam 			if (!equal(rp->rcb_faddr, rp->rcb_route.ro_dst) ||
26513451Ssam 			    rp->rcb_route.ro_rt == 0) {
26616773Sbloom 				if (rp->rcb_route.ro_rt) {
26716773Sbloom 					RTFREE(rp->rcb_route.ro_rt);
26816773Sbloom 					rp->rcb_route.ro_rt = NULL;
26916773Sbloom 				}
27013451Ssam 				rp->rcb_route.ro_dst = rp->rcb_faddr;
27113451Ssam 				rtalloc(&rp->rcb_route);
27213451Ssam 			}
2736505Ssam 		error = (*so->so_proto->pr_output)(m, so);
27412783Ssam 		m = NULL;
2758395Swnj 		if (nam)
2766509Ssam 			rp->rcb_flags &= ~RAW_FADDR;
2775612Swnj 		break;
2785612Swnj 
2795612Swnj 	case PRU_ABORT:
2805612Swnj 		raw_disconnect(rp);
2815612Swnj 		sofree(so);
2825612Swnj 		soisdisconnected(so);
2835612Swnj 		break;
2845612Swnj 
28516974Skarels 	case PRU_SENSE:
28616974Skarels 		/*
28716974Skarels 		 * stat: don't bother with a blocksize.
28816974Skarels 		 */
28916974Skarels 		return (0);
29016974Skarels 
2915612Swnj 	/*
2925612Swnj 	 * Not supported.
2935612Swnj 	 */
29416773Sbloom 	case PRU_CONTROL:
29516773Sbloom 	case PRU_RCVOOB:
2965612Swnj 	case PRU_RCVD:
29716773Sbloom 		return(EOPNOTSUPP);
29816773Sbloom 
29916773Sbloom 	case PRU_ACCEPT:
3005612Swnj 	case PRU_SENDOOB:
3015612Swnj 		error = EOPNOTSUPP;
3025612Swnj 		break;
3035612Swnj 
3046509Ssam 	case PRU_SOCKADDR:
3058723Sroot 		bcopy((caddr_t)&rp->rcb_laddr, mtod(nam, caddr_t),
3068395Swnj 		    sizeof (struct sockaddr));
3078395Swnj 		nam->m_len = sizeof (struct sockaddr);
3086509Ssam 		break;
3096509Ssam 
31014122Ssam 	case PRU_PEERADDR:
31114122Ssam 		bcopy((caddr_t)&rp->rcb_faddr, mtod(nam, caddr_t),
31214122Ssam 		    sizeof (struct sockaddr));
31314122Ssam 		nam->m_len = sizeof (struct sockaddr);
31414122Ssam 		break;
31514122Ssam 
3165612Swnj 	default:
3175612Swnj 		panic("raw_usrreq");
3185612Swnj 	}
31912783Ssam release:
32012783Ssam 	if (m != NULL)
32112783Ssam 		m_freem(m);
3225612Swnj 	return (error);
3235121Swnj }
324