xref: /csrg-svn/sys/net/raw_usrreq.c (revision 29922)
1 /*
2  * Copyright (c) 1980, 1986 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)raw_usrreq.c	7.2 (Berkeley) 10/28/86
7  */
8 
9 #include "param.h"
10 #include "mbuf.h"
11 #include "domain.h"
12 #include "protosw.h"
13 #include "socket.h"
14 #include "socketvar.h"
15 #include "errno.h"
16 
17 #include "if.h"
18 #include "route.h"
19 #include "netisr.h"
20 #include "raw_cb.h"
21 
22 #include "../machine/mtpr.h"
23 
24 /*
25  * Initialize raw connection block q.
26  */
27 raw_init()
28 {
29 
30 	rawcb.rcb_next = rawcb.rcb_prev = &rawcb;
31 	rawintrq.ifq_maxlen = IFQ_MAXLEN;
32 }
33 
34 /*
35  * Raw protocol interface.
36  */
37 raw_input(m0, proto, src, dst)
38 	struct mbuf *m0;
39 	struct sockproto *proto;
40 	struct sockaddr *src, *dst;
41 {
42 	register struct mbuf *m;
43 	struct raw_header *rh;
44 	int s;
45 
46 	/*
47 	 * Rip off an mbuf for a generic header.
48 	 */
49 	m = m_get(M_DONTWAIT, MT_HEADER);
50 	if (m == 0) {
51 		m_freem(m0);
52 		return;
53 	}
54 	m->m_next = m0;
55 	m->m_len = sizeof(struct raw_header);
56 	rh = mtod(m, struct raw_header *);
57 	rh->raw_dst = *dst;
58 	rh->raw_src = *src;
59 	rh->raw_proto = *proto;
60 
61 	/*
62 	 * Header now contains enough info to decide
63 	 * which socket to place packet in (if any).
64 	 * Queue it up for the raw protocol process
65 	 * running at software interrupt level.
66 	 */
67 	s = splimp();
68 	if (IF_QFULL(&rawintrq))
69 		m_freem(m);
70 	else
71 		IF_ENQUEUE(&rawintrq, m);
72 	splx(s);
73 	schednetisr(NETISR_RAW);
74 }
75 
76 /*
77  * Raw protocol input routine.  Process packets entered
78  * into the queue at interrupt time.  Find the socket
79  * associated with the packet(s) and move them over.  If
80  * nothing exists for this packet, drop it.
81  */
82 rawintr()
83 {
84 	int s;
85 	struct mbuf *m;
86 	register struct rawcb *rp;
87 	register struct raw_header *rh;
88 	struct socket *last;
89 
90 next:
91 	s = splimp();
92 	IF_DEQUEUE(&rawintrq, m);
93 	splx(s);
94 	if (m == 0)
95 		return;
96 	rh = mtod(m, struct raw_header *);
97 	last = 0;
98 	for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) {
99 		if (rp->rcb_proto.sp_family != rh->raw_proto.sp_family)
100 			continue;
101 		if (rp->rcb_proto.sp_protocol  &&
102 		    rp->rcb_proto.sp_protocol != rh->raw_proto.sp_protocol)
103 			continue;
104 		/*
105 		 * We assume the lower level routines have
106 		 * placed the address in a canonical format
107 		 * suitable for a structure comparison.
108 		 */
109 #define equal(a1, a2) \
110 	(bcmp((caddr_t)&(a1), (caddr_t)&(a2), sizeof (struct sockaddr)) == 0)
111 		if ((rp->rcb_flags & RAW_LADDR) &&
112 		    !equal(rp->rcb_laddr, rh->raw_dst))
113 			continue;
114 		if ((rp->rcb_flags & RAW_FADDR) &&
115 		    !equal(rp->rcb_faddr, rh->raw_src))
116 			continue;
117 		if (last) {
118 			struct mbuf *n;
119 			if (n = m_copy(m->m_next, 0, (int)M_COPYALL)) {
120 				if (sbappendaddr(&last->so_rcv, &rh->raw_src,
121 				    n, (struct mbuf *)0) == 0)
122 					/* should notify about lost packet */
123 					m_freem(n);
124 				else
125 					sorwakeup(last);
126 			}
127 		}
128 		last = rp->rcb_socket;
129 	}
130 	if (last) {
131 		if (sbappendaddr(&last->so_rcv, &rh->raw_src,
132 		    m->m_next, (struct mbuf *)0) == 0)
133 			m_freem(m->m_next);
134 		else
135 			sorwakeup(last);
136 		(void) m_free(m);		/* header */
137 	} else
138 		m_freem(m);
139 	goto next;
140 }
141 
142 /*ARGSUSED*/
143 raw_ctlinput(cmd, arg)
144 	int cmd;
145 	struct sockaddr *arg;
146 {
147 
148 	if (cmd < 0 || cmd > PRC_NCMDS)
149 		return;
150 	/* INCOMPLETE */
151 }
152 
153 /*ARGSUSED*/
154 raw_usrreq(so, req, m, nam, rights)
155 	struct socket *so;
156 	int req;
157 	struct mbuf *m, *nam, *rights;
158 {
159 	register struct rawcb *rp = sotorawcb(so);
160 	register int error = 0;
161 
162 	if (req == PRU_CONTROL)
163 		return (EOPNOTSUPP);
164 	if (rights && rights->m_len) {
165 		error = EOPNOTSUPP;
166 		goto release;
167 	}
168 	if (rp == 0 && req != PRU_ATTACH) {
169 		error = EINVAL;
170 		goto release;
171 	}
172 	switch (req) {
173 
174 	/*
175 	 * Allocate a raw control block and fill in the
176 	 * necessary info to allow packets to be routed to
177 	 * the appropriate raw interface routine.
178 	 */
179 	case PRU_ATTACH:
180 		if ((so->so_state & SS_PRIV) == 0) {
181 			error = EACCES;
182 			break;
183 		}
184 		if (rp) {
185 			error = EINVAL;
186 			break;
187 		}
188 		error = raw_attach(so, (int)nam);
189 		break;
190 
191 	/*
192 	 * Destroy state just before socket deallocation.
193 	 * Flush data or not depending on the options.
194 	 */
195 	case PRU_DETACH:
196 		if (rp == 0) {
197 			error = ENOTCONN;
198 			break;
199 		}
200 		raw_detach(rp);
201 		break;
202 
203 	/*
204 	 * If a socket isn't bound to a single address,
205 	 * the raw input routine will hand it anything
206 	 * within that protocol family (assuming there's
207 	 * nothing else around it should go to).
208 	 */
209 	case PRU_CONNECT:
210 		if (rp->rcb_flags & RAW_FADDR) {
211 			error = EISCONN;
212 			break;
213 		}
214 		raw_connaddr(rp, nam);
215 		soisconnected(so);
216 		break;
217 
218 	case PRU_CONNECT2:
219 		error = EOPNOTSUPP;
220 		goto release;
221 
222 	case PRU_BIND:
223 		if (rp->rcb_flags & RAW_LADDR) {
224 			error = EINVAL;			/* XXX */
225 			break;
226 		}
227 		error = raw_bind(so, nam);
228 		break;
229 
230 	case PRU_DISCONNECT:
231 		if ((rp->rcb_flags & RAW_FADDR) == 0) {
232 			error = ENOTCONN;
233 			break;
234 		}
235 		raw_disconnect(rp);
236 		soisdisconnected(so);
237 		break;
238 
239 	/*
240 	 * Mark the connection as being incapable of further input.
241 	 */
242 	case PRU_SHUTDOWN:
243 		socantsendmore(so);
244 		break;
245 
246 	/*
247 	 * Ship a packet out.  The appropriate raw output
248 	 * routine handles any massaging necessary.
249 	 */
250 	case PRU_SEND:
251 		if (nam) {
252 			if (rp->rcb_flags & RAW_FADDR) {
253 				error = EISCONN;
254 				break;
255 			}
256 			raw_connaddr(rp, nam);
257 		} else if ((rp->rcb_flags & RAW_FADDR) == 0) {
258 			error = ENOTCONN;
259 			break;
260 		}
261 		error = (*so->so_proto->pr_output)(m, so);
262 		m = NULL;
263 		if (nam)
264 			rp->rcb_flags &= ~RAW_FADDR;
265 		break;
266 
267 	case PRU_ABORT:
268 		raw_disconnect(rp);
269 		sofree(so);
270 		soisdisconnected(so);
271 		break;
272 
273 	case PRU_SENSE:
274 		/*
275 		 * stat: don't bother with a blocksize.
276 		 */
277 		return (0);
278 
279 	/*
280 	 * Not supported.
281 	 */
282 	case PRU_RCVOOB:
283 	case PRU_RCVD:
284 		return(EOPNOTSUPP);
285 
286 	case PRU_LISTEN:
287 	case PRU_ACCEPT:
288 	case PRU_SENDOOB:
289 		error = EOPNOTSUPP;
290 		break;
291 
292 	case PRU_SOCKADDR:
293 		bcopy((caddr_t)&rp->rcb_laddr, mtod(nam, caddr_t),
294 		    sizeof (struct sockaddr));
295 		nam->m_len = sizeof (struct sockaddr);
296 		break;
297 
298 	case PRU_PEERADDR:
299 		bcopy((caddr_t)&rp->rcb_faddr, mtod(nam, caddr_t),
300 		    sizeof (struct sockaddr));
301 		nam->m_len = sizeof (struct sockaddr);
302 		break;
303 
304 	default:
305 		panic("raw_usrreq");
306 	}
307 release:
308 	if (m != NULL)
309 		m_freem(m);
310 	return (error);
311 }
312