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