xref: /csrg-svn/sys/net/raw_usrreq.c (revision 16987)
1 /*	raw_usrreq.c	6.4	84/08/21	*/
2 
3 #include "../h/param.h"
4 #include "../h/mbuf.h"
5 #include "../h/domain.h"
6 #include "../h/protosw.h"
7 #include "../h/socket.h"
8 #include "../h/socketvar.h"
9 #include "../h/errno.h"
10 
11 #include "../net/if.h"
12 #include "../net/route.h"
13 #include "../net/netisr.h"
14 #include "../net/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 protosw *lproto;
82 	register struct raw_header *rh;
83 	struct socket *last;
84 
85 next:
86 	s = splimp();
87 	IF_DEQUEUE(&rawintrq, m);
88 	splx(s);
89 	if (m == 0)
90 		return;
91 	rh = mtod(m, struct raw_header *);
92 	last = 0;
93 	for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) {
94 		lproto = rp->rcb_socket->so_proto;
95 		if (lproto->pr_domain->dom_family != rh->raw_proto.sp_family)
96 			continue;
97 		if (lproto->pr_protocol &&
98 		    lproto->pr_protocol != rh->raw_proto.sp_protocol)
99 			continue;
100 		/*
101 		 * We assume the lower level routines have
102 		 * placed the address in a canonical format
103 		 * suitable for a structure comparison.
104 		 */
105 #define equal(a1, a2) \
106 	(bcmp((caddr_t)&(a1), (caddr_t)&(a2), sizeof (struct sockaddr)) == 0)
107 		if ((rp->rcb_flags & RAW_LADDR) &&
108 		    !equal(rp->rcb_laddr, rh->raw_dst))
109 			continue;
110 		if ((rp->rcb_flags & RAW_FADDR) &&
111 		    !equal(rp->rcb_faddr, rh->raw_src))
112 			continue;
113 		if (last) {
114 			struct mbuf *n;
115 			if ((n = m_copy(m->m_next, 0, (int)M_COPYALL)) == 0)
116 				goto nospace;
117 			if (sbappendaddr(&last->so_rcv, &rh->raw_src,
118 			    n, (struct mbuf *)0) == 0) {
119 				/* should notify about lost packet */
120 				m_freem(n);
121 				goto nospace;
122 			}
123 			sorwakeup(last);
124 		}
125 nospace:
126 		last = rp->rcb_socket;
127 	}
128 	if (last) {
129 		m = m_free(m);		/* header */
130 		if (sbappendaddr(&last->so_rcv, &rh->raw_src,
131 		    m, (struct mbuf *)0) == 0)
132 			goto drop;
133 		sorwakeup(last);
134 		goto next;
135 	}
136 drop:
137 	m_freem(m);
138 	goto next;
139 }
140 
141 /*ARGSUSED*/
142 raw_ctlinput(cmd, arg)
143 	int cmd;
144 	caddr_t arg;
145 {
146 
147 	if (cmd < 0 || cmd > PRC_NCMDS)
148 		return;
149 	/* INCOMPLETE */
150 }
151 
152 /*ARGSUSED*/
153 raw_usrreq(so, req, m, nam, rights)
154 	struct socket *so;
155 	int req;
156 	struct mbuf *m, *nam, *rights;
157 {
158 	register struct rawcb *rp = sotorawcb(so);
159 	register int error = 0;
160 
161 	if (rights && rights->m_len) {
162 		error = EOPNOTSUPP;
163 		goto release;
164 	}
165 	if (rp == 0 && req != PRU_ATTACH) {
166 		error = EINVAL;
167 		goto release;
168 	}
169 	switch (req) {
170 
171 	/*
172 	 * Allocate a raw control block and fill in the
173 	 * necessary info to allow packets to be routed to
174 	 * the appropriate raw interface routine.
175 	 */
176 	case PRU_ATTACH:
177 		if ((so->so_state & SS_PRIV) == 0) {
178 			error = EACCES;
179 			break;
180 		}
181 		if (rp) {
182 			error = EINVAL;
183 			break;
184 		}
185 		error = raw_attach(so);
186 		break;
187 
188 	/*
189 	 * Destroy state just before socket deallocation.
190 	 * Flush data or not depending on the options.
191 	 */
192 	case PRU_DETACH:
193 		if (rp == 0) {
194 			error = ENOTCONN;
195 			break;
196 		}
197 		raw_detach(rp);
198 		break;
199 
200 	/*
201 	 * If a socket isn't bound to a single address,
202 	 * the raw input routine will hand it anything
203 	 * within that protocol family (assuming there's
204 	 * nothing else around it should go to).
205 	 */
206 	case PRU_CONNECT:
207 		if (rp->rcb_flags & RAW_FADDR) {
208 			error = EISCONN;
209 			break;
210 		}
211 		raw_connaddr(rp, nam);
212 		soisconnected(so);
213 		break;
214 
215 	case PRU_CONNECT2:
216 		error = EOPNOTSUPP;
217 		goto release;
218 
219 	case PRU_BIND:
220 		if (rp->rcb_flags & RAW_LADDR) {
221 			error = EINVAL;			/* XXX */
222 			break;
223 		}
224 		error = raw_bind(so, nam);
225 		break;
226 
227 	case PRU_DISCONNECT:
228 		if ((rp->rcb_flags & RAW_FADDR) == 0) {
229 			error = ENOTCONN;
230 			break;
231 		}
232 		if (rp->rcb_route.ro_rt)
233 			rtfree(rp->rcb_route.ro_rt);
234 		raw_disconnect(rp);
235 		soisdisconnected(so);
236 		break;
237 
238 	/*
239 	 * Mark the connection as being incapable of further input.
240 	 */
241 	case PRU_SHUTDOWN:
242 		socantsendmore(so);
243 		break;
244 
245 	/*
246 	 * Ship a packet out.  The appropriate raw output
247 	 * routine handles any massaging necessary.
248 	 */
249 	case PRU_SEND:
250 		if (nam) {
251 			if (rp->rcb_flags & RAW_FADDR) {
252 				error = EISCONN;
253 				break;
254 			}
255 			raw_connaddr(rp, nam);
256 		} else if ((rp->rcb_flags & RAW_FADDR) == 0) {
257 			error = ENOTCONN;
258 			break;
259 		}
260 		/*
261 		 * Check for routing.  If new foreign address, or
262 		 * no route presently in use, try to allocate new
263 		 * route.  On failure, just hand packet to output
264 		 * routine anyway in case it can handle it.
265 		 */
266 		if ((rp->rcb_flags & RAW_DONTROUTE) == 0)
267 			if (!equal(rp->rcb_faddr, rp->rcb_route.ro_dst) ||
268 			    rp->rcb_route.ro_rt == 0) {
269 				if (rp->rcb_route.ro_rt) {
270 					RTFREE(rp->rcb_route.ro_rt);
271 					rp->rcb_route.ro_rt = NULL;
272 				}
273 				rp->rcb_route.ro_dst = rp->rcb_faddr;
274 				rtalloc(&rp->rcb_route);
275 			}
276 		error = (*so->so_proto->pr_output)(m, so);
277 		m = NULL;
278 		if (nam)
279 			rp->rcb_flags &= ~RAW_FADDR;
280 		break;
281 
282 	case PRU_ABORT:
283 		raw_disconnect(rp);
284 		sofree(so);
285 		soisdisconnected(so);
286 		break;
287 
288 	case PRU_SENSE:
289 		/*
290 		 * stat: don't bother with a blocksize.
291 		 */
292 		return (0);
293 
294 	/*
295 	 * Not supported.
296 	 */
297 	case PRU_CONTROL:
298 	case PRU_RCVOOB:
299 	case PRU_RCVD:
300 		return(EOPNOTSUPP);
301 
302 	case PRU_ACCEPT:
303 	case PRU_SENDOOB:
304 		error = EOPNOTSUPP;
305 		break;
306 
307 	case PRU_SOCKADDR:
308 		bcopy((caddr_t)&rp->rcb_laddr, mtod(nam, caddr_t),
309 		    sizeof (struct sockaddr));
310 		nam->m_len = sizeof (struct sockaddr);
311 		break;
312 
313 	case PRU_PEERADDR:
314 		bcopy((caddr_t)&rp->rcb_faddr, mtod(nam, caddr_t),
315 		    sizeof (struct sockaddr));
316 		nam->m_len = sizeof (struct sockaddr);
317 		break;
318 
319 	default:
320 		panic("raw_usrreq");
321 	}
322 release:
323 	if (m != NULL)
324 		m_freem(m);
325 	return (error);
326 }
327