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