xref: /csrg-svn/sys/net/raw_usrreq.c (revision 14122)
1*14122Ssam /*	raw_usrreq.c	4.31	83/07/25	*/
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"
810890Ssam #include "../h/errno.h"
910890Ssam 
105121Swnj #include "../net/if.h"
1113451Ssam #include "../net/route.h"
128395Swnj #include "../net/netisr.h"
135612Swnj #include "../net/raw_cb.h"
145121Swnj 
1510890Ssam #include "../vax/mtpr.h"
1610890Ssam 
175121Swnj /*
185612Swnj  * Initialize raw connection block q.
196211Swnj  */
205612Swnj raw_init()
215612Swnj {
226211Swnj 
235612Swnj 	rawcb.rcb_next = rawcb.rcb_prev = &rawcb;
246211Swnj 	rawintrq.ifq_maxlen = IFQ_MAXLEN;
255612Swnj }
265612Swnj 
275612Swnj /*
285121Swnj  * Raw protocol interface.
295121Swnj  */
306529Ssam raw_input(m0, proto, src, dst)
315612Swnj 	struct mbuf *m0;
326509Ssam 	struct sockproto *proto;
336529Ssam 	struct sockaddr *src, *dst;
345121Swnj {
355612Swnj 	register struct mbuf *m;
365612Swnj 	struct raw_header *rh;
375121Swnj 	int s;
385121Swnj 
395612Swnj 	/*
405612Swnj 	 * Rip off an mbuf for a generic header.
415612Swnj 	 */
429638Ssam 	m = m_get(M_DONTWAIT, MT_HEADER);
435612Swnj 	if (m == 0) {
445612Swnj 		m_freem(m0);
455612Swnj 		return;
465612Swnj 	}
475612Swnj 	m->m_next = m0;
485612Swnj 	m->m_len = sizeof(struct raw_header);
495612Swnj 	rh = mtod(m, struct raw_header *);
506509Ssam 	rh->raw_dst = *dst;
516509Ssam 	rh->raw_src = *src;
526509Ssam 	rh->raw_proto = *proto;
535612Swnj 
545612Swnj 	/*
555612Swnj 	 * Header now contains enough info to decide
565612Swnj 	 * which socket to place packet in (if any).
575612Swnj 	 * Queue it up for the raw protocol process
585612Swnj 	 * running at software interrupt level.
595612Swnj 	 */
605121Swnj 	s = splimp();
616211Swnj 	if (IF_QFULL(&rawintrq))
626211Swnj 		m_freem(m);
636211Swnj 	else
646211Swnj 		IF_ENQUEUE(&rawintrq, m);
655121Swnj 	splx(s);
666263Swnj 	schednetisr(NETISR_RAW);
675121Swnj }
685121Swnj 
695612Swnj /*
705612Swnj  * Raw protocol input routine.  Process packets entered
715612Swnj  * into the queue at interrupt time.  Find the socket
725612Swnj  * associated with the packet(s) and move them over.  If
735612Swnj  * nothing exists for this packet, drop it.
745612Swnj  */
755121Swnj rawintr()
765121Swnj {
775121Swnj 	int s;
785121Swnj 	struct mbuf *m;
795612Swnj 	register struct rawcb *rp;
806509Ssam 	register struct protosw *lproto;
816529Ssam 	register struct raw_header *rh;
825612Swnj 	struct socket *last;
835121Swnj 
845121Swnj next:
855121Swnj 	s = splimp();
865121Swnj 	IF_DEQUEUE(&rawintrq, m);
875121Swnj 	splx(s);
885121Swnj 	if (m == 0)
895121Swnj 		return;
906509Ssam 	rh = mtod(m, struct raw_header *);
915612Swnj 	last = 0;
925612Swnj 	for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) {
936509Ssam 		lproto = rp->rcb_socket->so_proto;
946509Ssam 		if (lproto->pr_family != rh->raw_proto.sp_family)
955612Swnj 			continue;
966509Ssam 		if (lproto->pr_protocol &&
976509Ssam 		    lproto->pr_protocol != rh->raw_proto.sp_protocol)
985612Swnj 			continue;
995612Swnj 		/*
1005612Swnj 		 * We assume the lower level routines have
1015612Swnj 		 * placed the address in a canonical format
1026509Ssam 		 * suitable for a structure comparison.
1035612Swnj 		 */
1046529Ssam #define equal(a1, a2) \
1056529Ssam 	(bcmp((caddr_t)&(a1), (caddr_t)&(a2), sizeof (struct sockaddr)) == 0)
1066509Ssam 		if ((rp->rcb_flags & RAW_LADDR) &&
1076529Ssam 		    !equal(rp->rcb_laddr, rh->raw_dst))
1085612Swnj 			continue;
1096509Ssam 		if ((rp->rcb_flags & RAW_FADDR) &&
1106529Ssam 		    !equal(rp->rcb_faddr, rh->raw_src))
1116509Ssam 			continue;
1125612Swnj 		if (last) {
1135612Swnj 			struct mbuf *n;
1147517Sroot 			if ((n = m_copy(m->m_next, 0, (int)M_COPYALL)) == 0)
1155612Swnj 				goto nospace;
11612783Ssam 			if (sbappendaddr(&last->so_rcv, &rh->raw_src,
11712783Ssam 			    n, (struct mbuf *)0) == 0) {
1186509Ssam 				/* should notify about lost packet */
1195646Ssam 				m_freem(n);
1205646Ssam 				goto nospace;
1215646Ssam 			}
1225612Swnj 			sorwakeup(last);
1235612Swnj 		}
1245612Swnj nospace:
1256509Ssam 		last = rp->rcb_socket;
1265612Swnj 	}
1276584Ssam 	if (last) {
1286584Ssam 		m = m_free(m);		/* header */
12912783Ssam 		if (sbappendaddr(&last->so_rcv, &rh->raw_src,
13012783Ssam 		    m, (struct mbuf *)0) == 0)
1316584Ssam 			goto drop;
1326584Ssam 		sorwakeup(last);
1336584Ssam 		goto next;
1346584Ssam 	}
1355121Swnj drop:
1365121Swnj 	m_freem(m);
1375121Swnj 	goto next;
1385121Swnj }
1395121Swnj 
1408636Sroot /*ARGSUSED*/
1416584Ssam raw_ctlinput(cmd, arg)
1426584Ssam 	int cmd;
1436584Ssam 	caddr_t arg;
1446584Ssam {
1456591Ssam 
1466591Ssam 	if (cmd < 0 || cmd > PRC_NCMDS)
1476591Ssam 		return;
1488636Sroot 	/* INCOMPLETE */
1496584Ssam }
1506584Ssam 
1515121Swnj /*ARGSUSED*/
15212783Ssam raw_usrreq(so, req, m, nam, rights)
1535121Swnj 	struct socket *so;
1545121Swnj 	int req;
15512783Ssam 	struct mbuf *m, *nam, *rights;
1565121Swnj {
1575612Swnj 	register struct rawcb *rp = sotorawcb(so);
15812783Ssam 	register int error = 0;
1595121Swnj 
16012783Ssam 	if (rights && rights->m_len) {
16112783Ssam 		error = EOPNOTSUPP;
16212783Ssam 		goto release;
16312783Ssam 	}
16412783Ssam 	if (rp == 0 && req != PRU_ATTACH) {
16512783Ssam 		error = EINVAL;
16612783Ssam 		goto release;
16712783Ssam 	}
1685612Swnj 	switch (req) {
1695612Swnj 
1705612Swnj 	/*
1715612Swnj 	 * Allocate a raw control block and fill in the
1725612Swnj 	 * necessary info to allow packets to be routed to
1735612Swnj 	 * the appropriate raw interface routine.
1745612Swnj 	 */
1755612Swnj 	case PRU_ATTACH:
17612783Ssam 		if ((so->so_state & SS_PRIV) == 0) {
17712783Ssam 			error = EACCES;
17813116Ssam 			break;
17912783Ssam 		}
18012783Ssam 		if (rp) {
18112783Ssam 			error = EINVAL;
18213116Ssam 			break;
18312783Ssam 		}
1848395Swnj 		error = raw_attach(so);
1855612Swnj 		break;
1865612Swnj 
1875612Swnj 	/*
1885612Swnj 	 * Destroy state just before socket deallocation.
1895612Swnj 	 * Flush data or not depending on the options.
1905612Swnj 	 */
1915612Swnj 	case PRU_DETACH:
19212783Ssam 		if (rp == 0) {
19312783Ssam 			error = ENOTCONN;
19413116Ssam 			break;
19512783Ssam 		}
1965612Swnj 		raw_detach(rp);
1975612Swnj 		break;
1985612Swnj 
1995612Swnj 	/*
2005612Swnj 	 * If a socket isn't bound to a single address,
2015612Swnj 	 * the raw input routine will hand it anything
2025612Swnj 	 * within that protocol family (assuming there's
2035612Swnj 	 * nothing else around it should go to).
2045612Swnj 	 */
2055612Swnj 	case PRU_CONNECT:
20612783Ssam 		if (rp->rcb_flags & RAW_FADDR) {
20712783Ssam 			error = EISCONN;
20813116Ssam 			break;
20912783Ssam 		}
2108395Swnj 		raw_connaddr(rp, nam);
2115612Swnj 		soisconnected(so);
2125612Swnj 		break;
2135612Swnj 
21413116Ssam 	case PRU_CONNECT2:
21513116Ssam 		error = EOPNOTSUPP;
21613116Ssam 		goto release;
21713116Ssam 
21812783Ssam 	case PRU_BIND:
21912783Ssam 		if (rp->rcb_flags & RAW_LADDR) {
22012783Ssam 			error = EINVAL;			/* XXX */
22113116Ssam 			break;
22212783Ssam 		}
22312783Ssam 		error = raw_bind(so, nam);
22412783Ssam 		break;
22512783Ssam 
2265612Swnj 	case PRU_DISCONNECT:
22712783Ssam 		if ((rp->rcb_flags & RAW_FADDR) == 0) {
22812783Ssam 			error = ENOTCONN;
22913116Ssam 			break;
23012783Ssam 		}
23113451Ssam 		if (rp->rcb_route.ro_rt)
23213451Ssam 			rtfree(rp->rcb_route.ro_rt);
2335612Swnj 		raw_disconnect(rp);
2345612Swnj 		soisdisconnected(so);
2355612Swnj 		break;
2365612Swnj 
2375612Swnj 	/*
2385612Swnj 	 * Mark the connection as being incapable of further input.
2395612Swnj 	 */
2405612Swnj 	case PRU_SHUTDOWN:
2415612Swnj 		socantsendmore(so);
2425612Swnj 		break;
2435612Swnj 
2445612Swnj 	/*
2455612Swnj 	 * Ship a packet out.  The appropriate raw output
2465612Swnj 	 * routine handles any massaging necessary.
2475612Swnj 	 */
2485612Swnj 	case PRU_SEND:
2498395Swnj 		if (nam) {
25012783Ssam 			if (rp->rcb_flags & RAW_FADDR) {
25112783Ssam 				error = EISCONN;
25213116Ssam 				break;
25312783Ssam 			}
2548395Swnj 			raw_connaddr(rp, nam);
25512783Ssam 		} else if ((rp->rcb_flags & RAW_FADDR) == 0) {
25612783Ssam 			error = ENOTCONN;
25713116Ssam 			break;
25812783Ssam 		}
25913451Ssam 		/*
26013451Ssam 		 * Check for routing.  If new foreign address, or
26113451Ssam 		 * no route presently in use, try to allocate new
26213451Ssam 		 * route.  On failure, just hand packet to output
26313451Ssam 		 * routine anyway in case it can handle it.
26413451Ssam 		 */
26513451Ssam 		if ((rp->rcb_flags & RAW_DONTROUTE) == 0)
26613451Ssam 			if (!equal(rp->rcb_faddr, rp->rcb_route.ro_dst) ||
26713451Ssam 			    rp->rcb_route.ro_rt == 0) {
26813451Ssam 				if (rp->rcb_route.ro_rt)
26913451Ssam 					rtfree(rp->rcb_route.ro_rt);
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 
28513049Ssam 	case PRU_CONTROL:
28613116Ssam 		m = NULL;
28713116Ssam 		error = EOPNOTSUPP;
28813116Ssam 		break;
28913049Ssam 
2905612Swnj 	/*
2915612Swnj 	 * Not supported.
2925612Swnj 	 */
2935612Swnj 	case PRU_ACCEPT:
2945612Swnj 	case PRU_RCVD:
2955612Swnj 	case PRU_SENSE:
2965612Swnj 	case PRU_RCVOOB:
2975612Swnj 	case PRU_SENDOOB:
2985612Swnj 		error = EOPNOTSUPP;
2995612Swnj 		break;
3005612Swnj 
3016509Ssam 	case PRU_SOCKADDR:
3028723Sroot 		bcopy((caddr_t)&rp->rcb_laddr, mtod(nam, caddr_t),
3038395Swnj 		    sizeof (struct sockaddr));
3048395Swnj 		nam->m_len = sizeof (struct sockaddr);
3056509Ssam 		break;
3066509Ssam 
307*14122Ssam 	case PRU_PEERADDR:
308*14122Ssam 		bcopy((caddr_t)&rp->rcb_faddr, mtod(nam, caddr_t),
309*14122Ssam 		    sizeof (struct sockaddr));
310*14122Ssam 		nam->m_len = sizeof (struct sockaddr);
311*14122Ssam 		break;
312*14122Ssam 
3135612Swnj 	default:
3145612Swnj 		panic("raw_usrreq");
3155612Swnj 	}
31612783Ssam release:
31712783Ssam 	if (m != NULL)
31812783Ssam 		m_freem(m);
3195612Swnj 	return (error);
3205121Swnj }
321