xref: /csrg-svn/sys/net/raw_usrreq.c (revision 5668)
1*5668Ssam /*	raw_usrreq.c	4.7	82/02/02	*/
25121Swnj 
35121Swnj #include "../h/param.h"
45121Swnj #include "../h/mbuf.h"
55612Swnj #include "../h/protosw.h"
65121Swnj #include "../h/socket.h"
75121Swnj #include "../h/socketvar.h"
85121Swnj #include "../h/mtpr.h"
95121Swnj #include "../net/in.h"
105121Swnj #include "../net/in_systm.h"
115121Swnj #include "../net/if.h"
125612Swnj #include "../net/raw_cb.h"
135612Swnj #include "/usr/include/errno.h"
145121Swnj 
155121Swnj /*
165612Swnj  * Initialize raw connection block q.
175612Swnj */
185612Swnj raw_init()
195612Swnj {
205612Swnj COUNT(RAW_INIT);
215612Swnj 	rawcb.rcb_next = rawcb.rcb_prev = &rawcb;
225612Swnj }
235612Swnj 
245612Swnj /*
255121Swnj  * Raw protocol interface.
265121Swnj  */
275646Ssam raw_input(m0, pf, daf, saf)
285612Swnj 	struct mbuf *m0;
29*5668Ssam 	struct sockproto *pf;
30*5668Ssam 	struct sockaddr *daf, *saf;
315121Swnj {
325612Swnj 	register struct mbuf *m;
335612Swnj 	struct raw_header *rh;
345121Swnj 	int s;
355121Swnj 
36*5668Ssam COUNT(RAW_INPUT);
375612Swnj 	/*
385612Swnj 	 * Rip off an mbuf for a generic header.
395612Swnj 	 */
405612Swnj 	m = m_get(M_DONTWAIT);
415612Swnj 	if (m == 0) {
425612Swnj 		m_freem(m0);
435612Swnj 		return;
445612Swnj 	}
455612Swnj 	m->m_next = m0;
465612Swnj 	m->m_off = MMINOFF;
475612Swnj 	m->m_len = sizeof(struct raw_header);
485612Swnj 	rh = mtod(m, struct raw_header *);
49*5668Ssam 	rh->raw_dst = *daf;
50*5668Ssam 	rh->raw_src = *saf;
51*5668Ssam 	rh->raw_protocol = *pf;
525612Swnj 
535612Swnj 	/*
545612Swnj 	 * Header now contains enough info to decide
555612Swnj 	 * which socket to place packet in (if any).
565612Swnj 	 * Queue it up for the raw protocol process
575612Swnj 	 * running at software interrupt level.
585612Swnj 	 */
595121Swnj 	s = splimp();
605612Swnj 	IF_ENQUEUE(&rawintrq, m);
615121Swnj 	splx(s);
625121Swnj 	setrawintr();
635121Swnj }
645121Swnj 
655612Swnj /*
665612Swnj  * Raw protocol input routine.  Process packets entered
675612Swnj  * into the queue at interrupt time.  Find the socket
685612Swnj  * associated with the packet(s) and move them over.  If
695612Swnj  * nothing exists for this packet, drop it.
705612Swnj  */
715121Swnj rawintr()
725121Swnj {
735121Swnj 	int s;
745121Swnj 	struct mbuf *m;
755612Swnj 	register struct rawcb *rp;
765612Swnj 	register struct socket *so;
775612Swnj 	register struct protosw *pr;
785612Swnj 	register struct sockproto *sp;
795612Swnj 	register struct sockaddr *sa;
805646Ssam 	struct raw_header *rawp;
815612Swnj 	struct socket *last;
825121Swnj 
835121Swnj COUNT(RAWINTR);
845121Swnj next:
855121Swnj 	s = splimp();
865121Swnj 	IF_DEQUEUE(&rawintrq, m);
875121Swnj 	splx(s);
885121Swnj 	if (m == 0)
895121Swnj 		return;
905646Ssam 	rawp = mtod(m, struct raw_header *);
915646Ssam 	sp = &rawp->raw_protocol;
925646Ssam 	sa = &rawp->raw_dst;
935612Swnj 
945612Swnj 	/*
955612Swnj 	 * Find the appropriate socket(s) in which to place this
965612Swnj 	 * packet.  This is done by matching the protocol and
975612Swnj 	 * address information prepended by raw_input against
985612Swnj 	 * the info stored in the control block structures.
995612Swnj 	 */
1005612Swnj 	last = 0;
1015612Swnj 	for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) {
1025612Swnj 		so = rp->rcb_socket;
1035612Swnj 		pr = so->so_proto;
1045612Swnj 		if (pr->pr_family != sp->sp_family ||
1055612Swnj 		    pr->pr_protocol != sp->sp_protocol)
1065612Swnj 			continue;
1075612Swnj 		if (sa->sa_family != so->so_addr.sa_family)
1085612Swnj 			continue;
1095612Swnj 		/*
1105612Swnj 		 * We assume the lower level routines have
1115612Swnj 		 * placed the address in a canonical format
1125612Swnj 		 * suitable for a structure comparison. Packets
1135612Swnj 		 * are duplicated for each receiving socket.
114*5668Ssam 		 *
115*5668Ssam 		 * SHOULD HAVE A NUMBER OF MECHANISMS FOR
116*5668Ssam 		 * MATCHING BASED ON rcb_flags
1175612Swnj 		 */
1185612Swnj 		if ((rp->rcb_flags & RAW_ADDR) &&
1195612Swnj 		    bcmp(sa->sa_data, so->so_addr.sa_data, 14) != 0)
1205612Swnj 			continue;
1215612Swnj 		/*
1225612Swnj 		 * To avoid extraneous packet copies, we keep
1235612Swnj 		 * track of the last socket the packet should be
1245612Swnj 		 * placed in, and make copies only after finding a
1255612Swnj 		 * socket which "collides".
1265612Swnj 		 */
1275612Swnj 		if (last) {
1285612Swnj 			struct mbuf *n;
1295612Swnj 
1305612Swnj 			if (n = m_copy(m->m_next, 0, M_COPYALL))
1315612Swnj 				goto nospace;
1325646Ssam 			if (sbappendaddr(&last->so_rcv, &rawp->raw_src, n) == 0) {
1335646Ssam 				/*
1345646Ssam 				 * Should drop notification of lost packet
1355646Ssam 				 * into this guy's queue, but...
1365646Ssam 				 */
1375646Ssam 				m_freem(n);
1385646Ssam 				goto nospace;
1395646Ssam 			}
1405612Swnj 			sorwakeup(last);
1415612Swnj 		}
1425612Swnj nospace:
1435612Swnj 		last = so;
1445612Swnj 	}
1455612Swnj 	if (last == 0)
1465612Swnj 		goto drop;
1475646Ssam 	if (sbappendaddr(&last->so_rcv, &rawp->raw_src, m->m_next) == 0)
1485646Ssam 		goto drop;
1495646Ssam 	(void) m_free(m);	/* generic header */
1505612Swnj 	sorwakeup(last);
1515612Swnj 	goto next;
1525121Swnj drop:
1535121Swnj 	m_freem(m);
1545121Swnj 	goto next;
1555121Swnj }
1565121Swnj 
1575121Swnj /*ARGSUSED*/
1585121Swnj raw_usrreq(so, req, m, addr)
1595121Swnj 	struct socket *so;
1605121Swnj 	int req;
1615121Swnj 	struct mbuf *m;
1625121Swnj 	caddr_t addr;
1635121Swnj {
1645612Swnj 	register struct rawcb *rp = sotorawcb(so);
1655612Swnj 	int error = 0;
1665121Swnj 
1675121Swnj COUNT(RAW_USRREQ);
1685612Swnj 	if (rp == 0 && req != PRU_ATTACH)
1695612Swnj 		return (EINVAL);
1705121Swnj 
1715612Swnj 	switch (req) {
1725612Swnj 
1735612Swnj 	/*
1745612Swnj 	 * Allocate a raw control block and fill in the
1755612Swnj 	 * necessary info to allow packets to be routed to
1765612Swnj 	 * the appropriate raw interface routine.
1775612Swnj 	 */
1785612Swnj 	case PRU_ATTACH:
1795612Swnj 		if (rp)
1805612Swnj 			return (EINVAL);;
1815612Swnj 		error = raw_attach(so, (struct sockaddr *)addr);
1825612Swnj 		break;
1835612Swnj 
1845612Swnj 	/*
1855612Swnj 	 * Destroy state just before socket deallocation.
1865612Swnj 	 * Flush data or not depending on the options.
1875612Swnj 	 */
1885612Swnj 	case PRU_DETACH:
1895612Swnj 		if (rp == 0)
1905612Swnj 			return (ENOTCONN);
1915612Swnj 		raw_detach(rp);
1925612Swnj 		break;
1935612Swnj 
1945612Swnj 	/*
1955612Swnj 	 * If a socket isn't bound to a single address,
1965612Swnj 	 * the raw input routine will hand it anything
1975612Swnj 	 * within that protocol family (assuming there's
1985612Swnj 	 * nothing else around it should go to).
1995612Swnj 	 */
2005612Swnj 	case PRU_CONNECT:
2015612Swnj 		if (rp->rcb_flags & RAW_ADDR)
2025612Swnj 			return (EISCONN);
2035612Swnj 		raw_connaddr(rp, (struct sockaddr *)addr);
2045612Swnj 		soisconnected(so);
2055612Swnj 		break;
2065612Swnj 
2075612Swnj 	case PRU_DISCONNECT:
2085612Swnj 		if ((rp->rcb_flags & RAW_ADDR) == 0)
2095612Swnj 			return (ENOTCONN);
2105612Swnj 		raw_disconnect(rp);
2115612Swnj 		soisdisconnected(so);
2125612Swnj 		break;
2135612Swnj 
2145612Swnj 	/*
2155612Swnj 	 * Mark the connection as being incapable of further input.
2165612Swnj 	 */
2175612Swnj 	case PRU_SHUTDOWN:
2185612Swnj 		socantsendmore(so);
2195612Swnj 		break;
2205612Swnj 
2215612Swnj 	/*
2225612Swnj 	 * Ship a packet out.  The appropriate raw output
2235612Swnj 	 * routine handles any massaging necessary.
2245612Swnj 	 */
2255612Swnj 	case PRU_SEND:
2265612Swnj 		if (addr) {
2275612Swnj 			if (rp->rcb_flags & RAW_ADDR)
2285612Swnj 				return (EISCONN);
2295612Swnj 			raw_connaddr(rp, (struct sockaddr *)addr);
2305612Swnj 		} else if ((rp->rcb_flags & RAW_ADDR) == 0)
2315612Swnj 			return (ENOTCONN);
2325612Swnj 		(void) (*so->so_proto->pr_output)(m, so);
2335612Swnj 		if (addr)
2345612Swnj 			rp->rcb_flags &= ~RAW_ADDR;
2355612Swnj 		break;
2365612Swnj 
2375612Swnj 	case PRU_ABORT:
2385612Swnj 		raw_disconnect(rp);
2395612Swnj 		sofree(so);
2405612Swnj 		soisdisconnected(so);
2415612Swnj 		break;
2425612Swnj 
2435612Swnj 	/*
2445612Swnj 	 * Not supported.
2455612Swnj 	 */
2465612Swnj 	case PRU_ACCEPT:
2475612Swnj 	case PRU_RCVD:
2485612Swnj 	case PRU_CONTROL:
2495612Swnj 	case PRU_SENSE:
2505612Swnj 	case PRU_RCVOOB:
2515612Swnj 	case PRU_SENDOOB:
2525612Swnj 		error = EOPNOTSUPP;
2535612Swnj 		break;
2545612Swnj 
2555612Swnj 	default:
2565612Swnj 		panic("raw_usrreq");
2575612Swnj 	}
2585612Swnj 	return (error);
2595121Swnj }
260