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