xref: /csrg-svn/sys/net/raw_usrreq.c (revision 33183)
123162Smckusick /*
229068Smckusick  * Copyright (c) 1980, 1986 Regents of the University of California.
3*33183Sbostic  * All rights reserved.
423162Smckusick  *
5*33183Sbostic  * Redistribution and use in source and binary forms are permitted
6*33183Sbostic  * provided that this notice is preserved and that due credit is given
7*33183Sbostic  * to the University of California at Berkeley. The name of the University
8*33183Sbostic  * may not be used to endorse or promote products derived from this
9*33183Sbostic  * software without specific prior written permission. This software
10*33183Sbostic  * is provided ``as is'' without express or implied warranty.
11*33183Sbostic  *
12*33183Sbostic  *	@(#)raw_usrreq.c	7.3 (Berkeley) 12/30/87
1323162Smckusick  */
145121Swnj 
1517037Sbloom #include "param.h"
1617037Sbloom #include "mbuf.h"
1717037Sbloom #include "domain.h"
1817037Sbloom #include "protosw.h"
1917037Sbloom #include "socket.h"
2017037Sbloom #include "socketvar.h"
2117037Sbloom #include "errno.h"
2210890Ssam 
2317037Sbloom #include "if.h"
2417037Sbloom #include "route.h"
2517037Sbloom #include "netisr.h"
2617037Sbloom #include "raw_cb.h"
275121Swnj 
2829922Skarels #include "../machine/mtpr.h"
2910890Ssam 
305121Swnj /*
315612Swnj  * Initialize raw connection block q.
326211Swnj  */
335612Swnj raw_init()
345612Swnj {
356211Swnj 
365612Swnj 	rawcb.rcb_next = rawcb.rcb_prev = &rawcb;
376211Swnj 	rawintrq.ifq_maxlen = IFQ_MAXLEN;
385612Swnj }
395612Swnj 
405612Swnj /*
415121Swnj  * Raw protocol interface.
425121Swnj  */
436529Ssam raw_input(m0, proto, src, dst)
445612Swnj 	struct mbuf *m0;
456509Ssam 	struct sockproto *proto;
466529Ssam 	struct sockaddr *src, *dst;
475121Swnj {
485612Swnj 	register struct mbuf *m;
495612Swnj 	struct raw_header *rh;
505121Swnj 	int s;
515121Swnj 
525612Swnj 	/*
535612Swnj 	 * Rip off an mbuf for a generic header.
545612Swnj 	 */
559638Ssam 	m = m_get(M_DONTWAIT, MT_HEADER);
565612Swnj 	if (m == 0) {
575612Swnj 		m_freem(m0);
585612Swnj 		return;
595612Swnj 	}
605612Swnj 	m->m_next = m0;
615612Swnj 	m->m_len = sizeof(struct raw_header);
625612Swnj 	rh = mtod(m, struct raw_header *);
636509Ssam 	rh->raw_dst = *dst;
646509Ssam 	rh->raw_src = *src;
656509Ssam 	rh->raw_proto = *proto;
665612Swnj 
675612Swnj 	/*
685612Swnj 	 * Header now contains enough info to decide
695612Swnj 	 * which socket to place packet in (if any).
705612Swnj 	 * Queue it up for the raw protocol process
715612Swnj 	 * running at software interrupt level.
725612Swnj 	 */
735121Swnj 	s = splimp();
746211Swnj 	if (IF_QFULL(&rawintrq))
756211Swnj 		m_freem(m);
766211Swnj 	else
776211Swnj 		IF_ENQUEUE(&rawintrq, m);
785121Swnj 	splx(s);
796263Swnj 	schednetisr(NETISR_RAW);
805121Swnj }
815121Swnj 
825612Swnj /*
835612Swnj  * Raw protocol input routine.  Process packets entered
845612Swnj  * into the queue at interrupt time.  Find the socket
855612Swnj  * associated with the packet(s) and move them over.  If
865612Swnj  * nothing exists for this packet, drop it.
875612Swnj  */
885121Swnj rawintr()
895121Swnj {
905121Swnj 	int s;
915121Swnj 	struct mbuf *m;
925612Swnj 	register struct rawcb *rp;
936529Ssam 	register struct raw_header *rh;
945612Swnj 	struct socket *last;
955121Swnj 
965121Swnj next:
975121Swnj 	s = splimp();
985121Swnj 	IF_DEQUEUE(&rawintrq, m);
995121Swnj 	splx(s);
1005121Swnj 	if (m == 0)
1015121Swnj 		return;
1026509Ssam 	rh = mtod(m, struct raw_header *);
1035612Swnj 	last = 0;
1045612Swnj 	for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) {
10521769Skarels 		if (rp->rcb_proto.sp_family != rh->raw_proto.sp_family)
1065612Swnj 			continue;
10721769Skarels 		if (rp->rcb_proto.sp_protocol  &&
10821769Skarels 		    rp->rcb_proto.sp_protocol != rh->raw_proto.sp_protocol)
1095612Swnj 			continue;
1105612Swnj 		/*
1115612Swnj 		 * We assume the lower level routines have
1125612Swnj 		 * placed the address in a canonical format
1136509Ssam 		 * suitable for a structure comparison.
1145612Swnj 		 */
1156529Ssam #define equal(a1, a2) \
1166529Ssam 	(bcmp((caddr_t)&(a1), (caddr_t)&(a2), sizeof (struct sockaddr)) == 0)
1176509Ssam 		if ((rp->rcb_flags & RAW_LADDR) &&
1186529Ssam 		    !equal(rp->rcb_laddr, rh->raw_dst))
1195612Swnj 			continue;
1206509Ssam 		if ((rp->rcb_flags & RAW_FADDR) &&
1216529Ssam 		    !equal(rp->rcb_faddr, rh->raw_src))
1226509Ssam 			continue;
1235612Swnj 		if (last) {
1245612Swnj 			struct mbuf *n;
12521531Skarels 			if (n = m_copy(m->m_next, 0, (int)M_COPYALL)) {
12621531Skarels 				if (sbappendaddr(&last->so_rcv, &rh->raw_src,
12721531Skarels 				    n, (struct mbuf *)0) == 0)
12821531Skarels 					/* should notify about lost packet */
12921531Skarels 					m_freem(n);
13021531Skarels 				else
13121531Skarels 					sorwakeup(last);
1325646Ssam 			}
1335612Swnj 		}
1346509Ssam 		last = rp->rcb_socket;
1355612Swnj 	}
1366584Ssam 	if (last) {
13712783Ssam 		if (sbappendaddr(&last->so_rcv, &rh->raw_src,
13821531Skarels 		    m->m_next, (struct mbuf *)0) == 0)
13921531Skarels 			m_freem(m->m_next);
14021531Skarels 		else
14121531Skarels 			sorwakeup(last);
14221531Skarels 		(void) m_free(m);		/* header */
14321531Skarels 	} else
14421531Skarels 		m_freem(m);
1455121Swnj 	goto next;
1465121Swnj }
1475121Swnj 
1488636Sroot /*ARGSUSED*/
1496584Ssam raw_ctlinput(cmd, arg)
1506584Ssam 	int cmd;
15126379Skarels 	struct sockaddr *arg;
1526584Ssam {
1536591Ssam 
1546591Ssam 	if (cmd < 0 || cmd > PRC_NCMDS)
1556591Ssam 		return;
1568636Sroot 	/* INCOMPLETE */
1576584Ssam }
1586584Ssam 
1595121Swnj /*ARGSUSED*/
16012783Ssam raw_usrreq(so, req, m, nam, rights)
1615121Swnj 	struct socket *so;
1625121Swnj 	int req;
16312783Ssam 	struct mbuf *m, *nam, *rights;
1645121Swnj {
1655612Swnj 	register struct rawcb *rp = sotorawcb(so);
16612783Ssam 	register int error = 0;
1675121Swnj 
16825501Skarels 	if (req == PRU_CONTROL)
16925501Skarels 		return (EOPNOTSUPP);
17012783Ssam 	if (rights && rights->m_len) {
17112783Ssam 		error = EOPNOTSUPP;
17212783Ssam 		goto release;
17312783Ssam 	}
17412783Ssam 	if (rp == 0 && req != PRU_ATTACH) {
17512783Ssam 		error = EINVAL;
17612783Ssam 		goto release;
17712783Ssam 	}
1785612Swnj 	switch (req) {
1795612Swnj 
1805612Swnj 	/*
1815612Swnj 	 * Allocate a raw control block and fill in the
1825612Swnj 	 * necessary info to allow packets to be routed to
1835612Swnj 	 * the appropriate raw interface routine.
1845612Swnj 	 */
1855612Swnj 	case PRU_ATTACH:
18612783Ssam 		if ((so->so_state & SS_PRIV) == 0) {
18712783Ssam 			error = EACCES;
18813116Ssam 			break;
18912783Ssam 		}
19012783Ssam 		if (rp) {
19112783Ssam 			error = EINVAL;
19213116Ssam 			break;
19312783Ssam 		}
19421769Skarels 		error = raw_attach(so, (int)nam);
1955612Swnj 		break;
1965612Swnj 
1975612Swnj 	/*
1985612Swnj 	 * Destroy state just before socket deallocation.
1995612Swnj 	 * Flush data or not depending on the options.
2005612Swnj 	 */
2015612Swnj 	case PRU_DETACH:
20212783Ssam 		if (rp == 0) {
20312783Ssam 			error = ENOTCONN;
20413116Ssam 			break;
20512783Ssam 		}
2065612Swnj 		raw_detach(rp);
2075612Swnj 		break;
2085612Swnj 
2095612Swnj 	/*
2105612Swnj 	 * If a socket isn't bound to a single address,
2115612Swnj 	 * the raw input routine will hand it anything
2125612Swnj 	 * within that protocol family (assuming there's
2135612Swnj 	 * nothing else around it should go to).
2145612Swnj 	 */
2155612Swnj 	case PRU_CONNECT:
21612783Ssam 		if (rp->rcb_flags & RAW_FADDR) {
21712783Ssam 			error = EISCONN;
21813116Ssam 			break;
21912783Ssam 		}
2208395Swnj 		raw_connaddr(rp, nam);
2215612Swnj 		soisconnected(so);
2225612Swnj 		break;
2235612Swnj 
22413116Ssam 	case PRU_CONNECT2:
22513116Ssam 		error = EOPNOTSUPP;
22613116Ssam 		goto release;
22713116Ssam 
22812783Ssam 	case PRU_BIND:
22912783Ssam 		if (rp->rcb_flags & RAW_LADDR) {
23012783Ssam 			error = EINVAL;			/* XXX */
23113116Ssam 			break;
23212783Ssam 		}
23312783Ssam 		error = raw_bind(so, nam);
23412783Ssam 		break;
23512783Ssam 
2365612Swnj 	case PRU_DISCONNECT:
23712783Ssam 		if ((rp->rcb_flags & RAW_FADDR) == 0) {
23812783Ssam 			error = ENOTCONN;
23913116Ssam 			break;
24012783Ssam 		}
2415612Swnj 		raw_disconnect(rp);
2425612Swnj 		soisdisconnected(so);
2435612Swnj 		break;
2445612Swnj 
2455612Swnj 	/*
2465612Swnj 	 * Mark the connection as being incapable of further input.
2475612Swnj 	 */
2485612Swnj 	case PRU_SHUTDOWN:
2495612Swnj 		socantsendmore(so);
2505612Swnj 		break;
2515612Swnj 
2525612Swnj 	/*
2535612Swnj 	 * Ship a packet out.  The appropriate raw output
2545612Swnj 	 * routine handles any massaging necessary.
2555612Swnj 	 */
2565612Swnj 	case PRU_SEND:
2578395Swnj 		if (nam) {
25812783Ssam 			if (rp->rcb_flags & RAW_FADDR) {
25912783Ssam 				error = EISCONN;
26013116Ssam 				break;
26112783Ssam 			}
2628395Swnj 			raw_connaddr(rp, nam);
26312783Ssam 		} else if ((rp->rcb_flags & RAW_FADDR) == 0) {
26412783Ssam 			error = ENOTCONN;
26513116Ssam 			break;
26612783Ssam 		}
2676505Ssam 		error = (*so->so_proto->pr_output)(m, so);
26812783Ssam 		m = NULL;
2698395Swnj 		if (nam)
2706509Ssam 			rp->rcb_flags &= ~RAW_FADDR;
2715612Swnj 		break;
2725612Swnj 
2735612Swnj 	case PRU_ABORT:
2745612Swnj 		raw_disconnect(rp);
2755612Swnj 		sofree(so);
2765612Swnj 		soisdisconnected(so);
2775612Swnj 		break;
2785612Swnj 
27916974Skarels 	case PRU_SENSE:
28016974Skarels 		/*
28116974Skarels 		 * stat: don't bother with a blocksize.
28216974Skarels 		 */
28316974Skarels 		return (0);
28416974Skarels 
2855612Swnj 	/*
2865612Swnj 	 * Not supported.
2875612Swnj 	 */
28816773Sbloom 	case PRU_RCVOOB:
2895612Swnj 	case PRU_RCVD:
29016773Sbloom 		return(EOPNOTSUPP);
29116773Sbloom 
29225221Skarels 	case PRU_LISTEN:
29316773Sbloom 	case PRU_ACCEPT:
2945612Swnj 	case PRU_SENDOOB:
2955612Swnj 		error = EOPNOTSUPP;
2965612Swnj 		break;
2975612Swnj 
2986509Ssam 	case PRU_SOCKADDR:
2998723Sroot 		bcopy((caddr_t)&rp->rcb_laddr, mtod(nam, caddr_t),
3008395Swnj 		    sizeof (struct sockaddr));
3018395Swnj 		nam->m_len = sizeof (struct sockaddr);
3026509Ssam 		break;
3036509Ssam 
30414122Ssam 	case PRU_PEERADDR:
30514122Ssam 		bcopy((caddr_t)&rp->rcb_faddr, mtod(nam, caddr_t),
30614122Ssam 		    sizeof (struct sockaddr));
30714122Ssam 		nam->m_len = sizeof (struct sockaddr);
30814122Ssam 		break;
30914122Ssam 
3105612Swnj 	default:
3115612Swnj 		panic("raw_usrreq");
3125612Swnj 	}
31312783Ssam release:
31412783Ssam 	if (m != NULL)
31512783Ssam 		m_freem(m);
3165612Swnj 	return (error);
3175121Swnj }
318