xref: /csrg-svn/sys/net/raw_usrreq.c (revision 6509)
1*6509Ssam /*	raw_usrreq.c	4.13	82/04/10	*/
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"
13*6509Ssam #include <errno.h>
145121Swnj 
156211Swnj int	rawqmaxlen = IFQ_MAXLEN;
166211Swnj 
175121Swnj /*
185612Swnj  * Initialize raw connection block q.
196211Swnj  */
205612Swnj raw_init()
215612Swnj {
226211Swnj 
235612Swnj COUNT(RAW_INIT);
245612Swnj 	rawcb.rcb_next = rawcb.rcb_prev = &rawcb;
256211Swnj 	rawintrq.ifq_maxlen = IFQ_MAXLEN;
265612Swnj }
275612Swnj 
285612Swnj /*
295121Swnj  * Raw protocol interface.
305121Swnj  */
31*6509Ssam raw_input(m0, proto, dst, src)
325612Swnj 	struct mbuf *m0;
33*6509Ssam 	struct sockproto *proto;
34*6509Ssam 	struct sockaddr *dst, *src;
355121Swnj {
365612Swnj 	register struct mbuf *m;
375612Swnj 	struct raw_header *rh;
385121Swnj 	int s;
395121Swnj 
405668Ssam COUNT(RAW_INPUT);
415612Swnj 	/*
425612Swnj 	 * Rip off an mbuf for a generic header.
435612Swnj 	 */
445612Swnj 	m = m_get(M_DONTWAIT);
455612Swnj 	if (m == 0) {
465612Swnj 		m_freem(m0);
475612Swnj 		return;
485612Swnj 	}
495612Swnj 	m->m_next = m0;
505612Swnj 	m->m_off = MMINOFF;
515612Swnj 	m->m_len = sizeof(struct raw_header);
525612Swnj 	rh = mtod(m, struct raw_header *);
53*6509Ssam 	rh->raw_dst = *dst;
54*6509Ssam 	rh->raw_src = *src;
55*6509Ssam 	rh->raw_proto = *proto;
565612Swnj 
575612Swnj 	/*
585612Swnj 	 * Header now contains enough info to decide
595612Swnj 	 * which socket to place packet in (if any).
605612Swnj 	 * Queue it up for the raw protocol process
615612Swnj 	 * running at software interrupt level.
625612Swnj 	 */
635121Swnj 	s = splimp();
646211Swnj 	if (IF_QFULL(&rawintrq))
656211Swnj 		m_freem(m);
666211Swnj 	else
676211Swnj 		IF_ENQUEUE(&rawintrq, m);
685121Swnj 	splx(s);
696263Swnj 	schednetisr(NETISR_RAW);
705121Swnj }
715121Swnj 
725612Swnj /*
735612Swnj  * Raw protocol input routine.  Process packets entered
745612Swnj  * into the queue at interrupt time.  Find the socket
755612Swnj  * associated with the packet(s) and move them over.  If
765612Swnj  * nothing exists for this packet, drop it.
775612Swnj  */
785121Swnj rawintr()
795121Swnj {
805121Swnj 	int s;
815121Swnj 	struct mbuf *m;
825612Swnj 	register struct rawcb *rp;
83*6509Ssam 	register struct sockaddr *laddr;
84*6509Ssam 	register struct protosw *lproto;
85*6509Ssam 	struct raw_header *rh;
865612Swnj 	struct socket *last;
875121Swnj 
885121Swnj COUNT(RAWINTR);
895121Swnj next:
905121Swnj 	s = splimp();
915121Swnj 	IF_DEQUEUE(&rawintrq, m);
925121Swnj 	splx(s);
935121Swnj 	if (m == 0)
945121Swnj 		return;
95*6509Ssam 	rh = mtod(m, struct raw_header *);
965612Swnj 
975612Swnj 	/*
985612Swnj 	 * Find the appropriate socket(s) in which to place this
995612Swnj 	 * packet.  This is done by matching the protocol and
1005612Swnj 	 * address information prepended by raw_input against
1015612Swnj 	 * the info stored in the control block structures.
1025612Swnj 	 */
1035612Swnj 	last = 0;
1045612Swnj 	for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) {
105*6509Ssam 		lproto = rp->rcb_socket->so_proto;
106*6509Ssam 		if (lproto->pr_family != rh->raw_proto.sp_family)
1075612Swnj 			continue;
108*6509Ssam 		if (lproto->pr_protocol &&
109*6509Ssam 		    lproto->pr_protocol != rh->raw_proto.sp_protocol)
1105612Swnj 			continue;
111*6509Ssam 		laddr = &rp->rcb_laddr;
112*6509Ssam 		if (laddr->sa_family &&
113*6509Ssam 		    laddr->sa_family != rh->raw_dst.sa_family)
114*6509Ssam 			continue;
1155612Swnj 		/*
1165612Swnj 		 * We assume the lower level routines have
1175612Swnj 		 * placed the address in a canonical format
118*6509Ssam 		 * suitable for a structure comparison.
1195612Swnj 		 */
120*6509Ssam 		if ((rp->rcb_flags & RAW_LADDR) &&
121*6509Ssam 		    bcmp(laddr->sa_data, rh->raw_dst.sa_data, 14) != 0)
1225612Swnj 			continue;
123*6509Ssam 		if ((rp->rcb_flags & RAW_FADDR) &&
124*6509Ssam 		    bcmp(rp->rcb_faddr.sa_data, rh->raw_src.sa_data, 14) != 0)
125*6509Ssam 			continue;
1265612Swnj 		/*
1275612Swnj 		 * To avoid extraneous packet copies, we keep
1285612Swnj 		 * track of the last socket the packet should be
1295612Swnj 		 * placed in, and make copies only after finding a
1305612Swnj 		 * socket which "collides".
1315612Swnj 		 */
1325612Swnj 		if (last) {
1335612Swnj 			struct mbuf *n;
1345612Swnj 
1356161Ssam 			if (n = m_copy(m->m_next, 0, (int)M_COPYALL))
1365612Swnj 				goto nospace;
137*6509Ssam 			if (sbappendaddr(&last->so_rcv, &rh->raw_src, n)==0) {
138*6509Ssam 				/* should notify about lost packet */
1395646Ssam 				m_freem(n);
1405646Ssam 				goto nospace;
1415646Ssam 			}
1425612Swnj 			sorwakeup(last);
1435612Swnj 		}
1445612Swnj nospace:
145*6509Ssam 		last = rp->rcb_socket;
1465612Swnj 	}
1475612Swnj 	if (last == 0)
1485612Swnj 		goto drop;
149*6509Ssam 	m = m_free(m);		/* header */
150*6509Ssam 	if (sbappendaddr(&last->so_rcv, &rh->raw_src, m) == 0)
1515646Ssam 		goto drop;
1525612Swnj 	sorwakeup(last);
1535612Swnj 	goto next;
1545121Swnj drop:
1555121Swnj 	m_freem(m);
1565121Swnj 	goto next;
1575121Swnj }
1585121Swnj 
1595121Swnj /*ARGSUSED*/
1605121Swnj raw_usrreq(so, req, m, addr)
1615121Swnj 	struct socket *so;
1625121Swnj 	int req;
1635121Swnj 	struct mbuf *m;
1645121Swnj 	caddr_t addr;
1655121Swnj {
1665612Swnj 	register struct rawcb *rp = sotorawcb(so);
1675612Swnj 	int error = 0;
1685121Swnj 
1695121Swnj COUNT(RAW_USRREQ);
1705612Swnj 	if (rp == 0 && req != PRU_ATTACH)
1715612Swnj 		return (EINVAL);
1725121Swnj 
1735612Swnj 	switch (req) {
1745612Swnj 
1755612Swnj 	/*
1765612Swnj 	 * Allocate a raw control block and fill in the
1775612Swnj 	 * necessary info to allow packets to be routed to
1785612Swnj 	 * the appropriate raw interface routine.
1795612Swnj 	 */
1805612Swnj 	case PRU_ATTACH:
1816211Swnj 		if ((so->so_state & SS_PRIV) == 0)
1826211Swnj 			return (EPERM);
1835612Swnj 		if (rp)
1846211Swnj 			return (EINVAL);
1855612Swnj 		error = raw_attach(so, (struct sockaddr *)addr);
1865612Swnj 		break;
1875612Swnj 
1885612Swnj 	/*
1895612Swnj 	 * Destroy state just before socket deallocation.
1905612Swnj 	 * Flush data or not depending on the options.
1915612Swnj 	 */
1925612Swnj 	case PRU_DETACH:
1935612Swnj 		if (rp == 0)
1945612Swnj 			return (ENOTCONN);
1955612Swnj 		raw_detach(rp);
1965612Swnj 		break;
1975612Swnj 
1985612Swnj 	/*
1995612Swnj 	 * If a socket isn't bound to a single address,
2005612Swnj 	 * the raw input routine will hand it anything
2015612Swnj 	 * within that protocol family (assuming there's
2025612Swnj 	 * nothing else around it should go to).
2035612Swnj 	 */
2045612Swnj 	case PRU_CONNECT:
205*6509Ssam 		if (rp->rcb_flags & RAW_FADDR)
2065612Swnj 			return (EISCONN);
2075612Swnj 		raw_connaddr(rp, (struct sockaddr *)addr);
2085612Swnj 		soisconnected(so);
2095612Swnj 		break;
2105612Swnj 
2115612Swnj 	case PRU_DISCONNECT:
212*6509Ssam 		if ((rp->rcb_flags & RAW_FADDR) == 0)
2135612Swnj 			return (ENOTCONN);
2145612Swnj 		raw_disconnect(rp);
2155612Swnj 		soisdisconnected(so);
2165612Swnj 		break;
2175612Swnj 
2185612Swnj 	/*
2195612Swnj 	 * Mark the connection as being incapable of further input.
2205612Swnj 	 */
2215612Swnj 	case PRU_SHUTDOWN:
2225612Swnj 		socantsendmore(so);
2235612Swnj 		break;
2245612Swnj 
2255612Swnj 	/*
2265612Swnj 	 * Ship a packet out.  The appropriate raw output
2275612Swnj 	 * routine handles any massaging necessary.
2285612Swnj 	 */
2295612Swnj 	case PRU_SEND:
2305612Swnj 		if (addr) {
231*6509Ssam 			if (rp->rcb_flags & RAW_FADDR)
2325612Swnj 				return (EISCONN);
2335612Swnj 			raw_connaddr(rp, (struct sockaddr *)addr);
234*6509Ssam 		} else if ((rp->rcb_flags & RAW_FADDR) == 0)
2355612Swnj 			return (ENOTCONN);
2366505Ssam 		error = (*so->so_proto->pr_output)(m, so);
2375612Swnj 		if (addr)
238*6509Ssam 			rp->rcb_flags &= ~RAW_FADDR;
2395612Swnj 		break;
2405612Swnj 
2415612Swnj 	case PRU_ABORT:
2425612Swnj 		raw_disconnect(rp);
2435612Swnj 		sofree(so);
2445612Swnj 		soisdisconnected(so);
2455612Swnj 		break;
2465612Swnj 
2475612Swnj 	/*
2485612Swnj 	 * Not supported.
2495612Swnj 	 */
2505612Swnj 	case PRU_ACCEPT:
2515612Swnj 	case PRU_RCVD:
2525612Swnj 	case PRU_CONTROL:
2535612Swnj 	case PRU_SENSE:
2545612Swnj 	case PRU_RCVOOB:
2555612Swnj 	case PRU_SENDOOB:
2565612Swnj 		error = EOPNOTSUPP;
2575612Swnj 		break;
2585612Swnj 
259*6509Ssam 	case PRU_SOCKADDR:
260*6509Ssam 		bcopy(addr, (caddr_t)&rp->rcb_laddr, sizeof (struct sockaddr));
261*6509Ssam 		break;
262*6509Ssam 
2635612Swnj 	default:
2645612Swnj 		panic("raw_usrreq");
2655612Swnj 	}
2665612Swnj 	return (error);
2675121Swnj }
268