xref: /csrg-svn/sys/net/raw_usrreq.c (revision 5612)
1*5612Swnj /*	raw_usrreq.c	4.5	82/01/24	*/
25121Swnj 
35121Swnj #include "../h/param.h"
45121Swnj #include "../h/mbuf.h"
5*5612Swnj #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"
12*5612Swnj #include "../net/raw_cb.h"
13*5612Swnj #include "/usr/include/errno.h"
145121Swnj 
155121Swnj /*
16*5612Swnj  * Initialize raw connection block q.
17*5612Swnj */
18*5612Swnj raw_init()
19*5612Swnj {
20*5612Swnj COUNT(RAW_INIT);
21*5612Swnj 	rawcb.rcb_next = rawcb.rcb_prev = &rawcb;
22*5612Swnj }
23*5612Swnj 
24*5612Swnj /*
255121Swnj  * Raw protocol interface.
265121Swnj  */
27*5612Swnj raw_input(m0, pf, af)
28*5612Swnj 	struct mbuf *m0;
295121Swnj 	struct sockproto pf;
305121Swnj 	struct sockaddr af;
315121Swnj {
32*5612Swnj 	register struct mbuf *m;
33*5612Swnj 	struct raw_header *rh;
345121Swnj 	int s;
355121Swnj 
36*5612Swnj 	/*
37*5612Swnj 	 * Rip off an mbuf for a generic header.
38*5612Swnj 	 */
39*5612Swnj 	m = m_get(M_DONTWAIT);
40*5612Swnj 	if (m == 0) {
41*5612Swnj 		m_freem(m0);
42*5612Swnj 		return;
43*5612Swnj 	}
44*5612Swnj 	m->m_next = m0;
45*5612Swnj 	m->m_off = MMINOFF;
46*5612Swnj 	m->m_len = sizeof(struct raw_header);
47*5612Swnj 	rh = mtod(m, struct raw_header *);
48*5612Swnj 	rh->raw_address = af;
49*5612Swnj 	rh->raw_protocol = pf;
50*5612Swnj 
51*5612Swnj 	/*
52*5612Swnj 	 * Header now contains enough info to decide
53*5612Swnj 	 * which socket to place packet in (if any).
54*5612Swnj 	 * Queue it up for the raw protocol process
55*5612Swnj 	 * running at software interrupt level.
56*5612Swnj 	 */
575121Swnj 	s = splimp();
58*5612Swnj 	IF_ENQUEUE(&rawintrq, m);
595121Swnj 	splx(s);
605121Swnj 	setrawintr();
615121Swnj }
625121Swnj 
63*5612Swnj /*
64*5612Swnj  * Raw protocol input routine.  Process packets entered
65*5612Swnj  * into the queue at interrupt time.  Find the socket
66*5612Swnj  * associated with the packet(s) and move them over.  If
67*5612Swnj  * nothing exists for this packet, drop it.
68*5612Swnj  */
695121Swnj rawintr()
705121Swnj {
715121Swnj 	int s;
725121Swnj 	struct mbuf *m;
73*5612Swnj 	register struct rawcb *rp;
74*5612Swnj 	register struct socket *so;
75*5612Swnj 	register struct protosw *pr;
76*5612Swnj 	register struct sockproto *sp;
77*5612Swnj 	register struct sockaddr *sa;
78*5612Swnj 	struct socket *last;
795121Swnj 
805121Swnj COUNT(RAWINTR);
815121Swnj next:
825121Swnj 	s = splimp();
835121Swnj 	IF_DEQUEUE(&rawintrq, m);
845121Swnj 	splx(s);
855121Swnj 	if (m == 0)
865121Swnj 		return;
87*5612Swnj 	sp = &(mtod(m, struct raw_header *)->raw_protocol);
88*5612Swnj 	sa = &(mtod(m, struct raw_header *)->raw_address);
89*5612Swnj 
90*5612Swnj 	/*
91*5612Swnj 	 * Find the appropriate socket(s) in which to place this
92*5612Swnj 	 * packet.  This is done by matching the protocol and
93*5612Swnj 	 * address information prepended by raw_input against
94*5612Swnj 	 * the info stored in the control block structures.
95*5612Swnj 	 */
96*5612Swnj 	last = 0;
97*5612Swnj 	for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) {
98*5612Swnj 		so = rp->rcb_socket;
99*5612Swnj 		pr = so->so_proto;
100*5612Swnj 
101*5612Swnj 		if (so->so_options & SO_DEBUG) {
102*5612Swnj 			printf("rawintr: sp=<%d,%d>, af=<%d,%x>\n",
103*5612Swnj 			 sp->sp_family, sp->sp_protocol, sa->sa_family,
104*5612Swnj 			 ((struct sockaddr_in *)sa)->sin_addr);
105*5612Swnj 			printf("pr=<%d,%d>\n", pr->pr_family, pr->pr_protocol);
106*5612Swnj 		}
107*5612Swnj 		if (pr->pr_family != sp->sp_family ||
108*5612Swnj 		    pr->pr_protocol != sp->sp_protocol)
109*5612Swnj 			continue;
110*5612Swnj 		printf("rawintr: so=<%d,%x>\n", so->so_addr.sa_family,
111*5612Swnj 			((struct sockaddr_in *)&so->so_addr)->sin_addr);
112*5612Swnj 		if (sa->sa_family != so->so_addr.sa_family)
113*5612Swnj 			continue;
114*5612Swnj 		/*
115*5612Swnj 		 * We assume the lower level routines have
116*5612Swnj 		 * placed the address in a canonical format
117*5612Swnj 		 * suitable for a structure comparison. Packets
118*5612Swnj 		 * are duplicated for each receiving socket.
119*5612Swnj 		 */
120*5612Swnj 		if ((rp->rcb_flags & RAW_ADDR) &&
121*5612Swnj 		    bcmp(sa->sa_data, so->so_addr.sa_data, 14) != 0)
122*5612Swnj 			continue;
123*5612Swnj 		/*
124*5612Swnj 		 * To avoid extraneous packet copies, we keep
125*5612Swnj 		 * track of the last socket the packet should be
126*5612Swnj 		 * placed in, and make copies only after finding a
127*5612Swnj 		 * socket which "collides".
128*5612Swnj 		 */
129*5612Swnj 		if (last) {
130*5612Swnj 			struct mbuf *n;
131*5612Swnj 
132*5612Swnj 			if (n = m_copy(m->m_next, 0, M_COPYALL))
133*5612Swnj 				goto nospace;
134*5612Swnj 			sbappend(&last->so_rcv, n);
135*5612Swnj 			sorwakeup(last);
136*5612Swnj 		}
137*5612Swnj nospace:
138*5612Swnj 		last = so;
139*5612Swnj 	}
140*5612Swnj 	if (last == 0)
141*5612Swnj 		goto drop;
142*5612Swnj 	m = m_free(m);		/* drop generic header */
143*5612Swnj 	sbappend(&last->so_rcv, m->m_next);
144*5612Swnj 	sorwakeup(last);
145*5612Swnj 	goto next;
1465121Swnj drop:
1475121Swnj 	m_freem(m);
1485121Swnj 	goto next;
1495121Swnj }
1505121Swnj 
1515121Swnj /*ARGSUSED*/
1525121Swnj raw_usrreq(so, req, m, addr)
1535121Swnj 	struct socket *so;
1545121Swnj 	int req;
1555121Swnj 	struct mbuf *m;
1565121Swnj 	caddr_t addr;
1575121Swnj {
158*5612Swnj 	register struct rawcb *rp = sotorawcb(so);
159*5612Swnj 	int error = 0;
1605121Swnj 
1615121Swnj COUNT(RAW_USRREQ);
162*5612Swnj 	if (so->so_options & SO_DEBUG)
163*5612Swnj 		printf("raw_usrreq: req=%d\n");
164*5612Swnj 	if (rp == 0 && req != PRU_ATTACH)
165*5612Swnj 		return (EINVAL);
1665121Swnj 
167*5612Swnj 	switch (req) {
168*5612Swnj 
169*5612Swnj 	/*
170*5612Swnj 	 * Allocate a raw control block and fill in the
171*5612Swnj 	 * necessary info to allow packets to be routed to
172*5612Swnj 	 * the appropriate raw interface routine.
173*5612Swnj 	 */
174*5612Swnj 	case PRU_ATTACH:
175*5612Swnj 		if (rp)
176*5612Swnj 			return (EINVAL);;
177*5612Swnj 		error = raw_attach(so, (struct sockaddr *)addr);
178*5612Swnj 		break;
179*5612Swnj 
180*5612Swnj 	/*
181*5612Swnj 	 * Destroy state just before socket deallocation.
182*5612Swnj 	 * Flush data or not depending on the options.
183*5612Swnj 	 */
184*5612Swnj 	case PRU_DETACH:
185*5612Swnj 		if (rp == 0)
186*5612Swnj 			return (ENOTCONN);
187*5612Swnj 		raw_detach(rp);
188*5612Swnj 		break;
189*5612Swnj 
190*5612Swnj 	/*
191*5612Swnj 	 * If a socket isn't bound to a single address,
192*5612Swnj 	 * the raw input routine will hand it anything
193*5612Swnj 	 * within that protocol family (assuming there's
194*5612Swnj 	 * nothing else around it should go to).
195*5612Swnj 	 */
196*5612Swnj 	case PRU_CONNECT:
197*5612Swnj 		if (rp->rcb_flags & RAW_ADDR)
198*5612Swnj 			return (EISCONN);
199*5612Swnj 		raw_connaddr(rp, (struct sockaddr *)addr);
200*5612Swnj 		soisconnected(so);
201*5612Swnj 		break;
202*5612Swnj 
203*5612Swnj 	case PRU_DISCONNECT:
204*5612Swnj 		if ((rp->rcb_flags & RAW_ADDR) == 0)
205*5612Swnj 			return (ENOTCONN);
206*5612Swnj 		raw_disconnect(rp);
207*5612Swnj 		soisdisconnected(so);
208*5612Swnj 		break;
209*5612Swnj 
210*5612Swnj 	/*
211*5612Swnj 	 * Mark the connection as being incapable of further input.
212*5612Swnj 	 */
213*5612Swnj 	case PRU_SHUTDOWN:
214*5612Swnj 		socantsendmore(so);
215*5612Swnj 		break;
216*5612Swnj 
217*5612Swnj 	/*
218*5612Swnj 	 * Ship a packet out.  The appropriate raw output
219*5612Swnj 	 * routine handles any massaging necessary.
220*5612Swnj 	 */
221*5612Swnj 	case PRU_SEND:
222*5612Swnj 		if (addr) {
223*5612Swnj 			if (rp->rcb_flags & RAW_ADDR)
224*5612Swnj 				return (EISCONN);
225*5612Swnj 			raw_connaddr(rp, (struct sockaddr *)addr);
226*5612Swnj 		} else if ((rp->rcb_flags & RAW_ADDR) == 0)
227*5612Swnj 			return (ENOTCONN);
228*5612Swnj 		(void) (*so->so_proto->pr_output)(m, so);
229*5612Swnj 		if (addr)
230*5612Swnj 			rp->rcb_flags &= ~RAW_ADDR;
231*5612Swnj 		break;
232*5612Swnj 
233*5612Swnj 	case PRU_ABORT:
234*5612Swnj 		raw_disconnect(rp);
235*5612Swnj 		sofree(so);
236*5612Swnj 		soisdisconnected(so);
237*5612Swnj 		break;
238*5612Swnj 
239*5612Swnj 	/*
240*5612Swnj 	 * Not supported.
241*5612Swnj 	 */
242*5612Swnj 	case PRU_ACCEPT:
243*5612Swnj 	case PRU_RCVD:
244*5612Swnj 	case PRU_CONTROL:
245*5612Swnj 	case PRU_SENSE:
246*5612Swnj 	case PRU_RCVOOB:
247*5612Swnj 	case PRU_SENDOOB:
248*5612Swnj 		error = EOPNOTSUPP;
249*5612Swnj 		break;
250*5612Swnj 
251*5612Swnj 	default:
252*5612Swnj 		panic("raw_usrreq");
253*5612Swnj 	}
254*5612Swnj 	return (error);
2555121Swnj }
256