add IFF_LOCAL
[unix-history] / usr / src / sys / net / raw_usrreq.c
... / ...
CommitLineData
1/* raw_usrreq.c 6.1 83/07/29 */
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 */
20raw_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 */
30raw_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 */
75rawintr()
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
84next:
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 }
124nospace:
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 }
135drop:
136 m_freem(m);
137 goto next;
138}
139
140/*ARGSUSED*/
141raw_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*/
152raw_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 case PRU_PEERADDR:
308 bcopy((caddr_t)&rp->rcb_faddr, mtod(nam, caddr_t),
309 sizeof (struct sockaddr));
310 nam->m_len = sizeof (struct sockaddr);
311 break;
312
313 default:
314 panic("raw_usrreq");
315 }
316release:
317 if (m != NULL)
318 m_freem(m);
319 return (error);
320}