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