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