1 /* $NetBSD: idp_usrreq.c,v 1.24 2005/02/26 22:39:50 perry Exp $ */
2
3 /*
4 * Copyright (c) 1984, 1985, 1986, 1987, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * @(#)idp_usrreq.c 8.2 (Berkeley) 1/9/95
32 */
33
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: idp_usrreq.c,v 1.24 2005/02/26 22:39:50 perry Exp $");
36
37 #include "opt_ns.h" /* NSIP: Xerox NS over IP */
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/malloc.h>
42 #include <sys/mbuf.h>
43 #include <sys/protosw.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
46 #include <sys/errno.h>
47 #include <sys/stat.h>
48 #include <sys/proc.h>
49
50 #include <net/if.h>
51 #include <net/route.h>
52
53 #include <netns/ns.h>
54 #include <netns/ns_pcb.h>
55 #include <netns/ns_if.h>
56 #include <netns/ns_var.h>
57 #include <netns/idp.h>
58 #include <netns/idp_var.h>
59 #include <netns/ns_error.h>
60
61 #include <machine/stdarg.h>
62 /*
63 * IDP protocol implementation.
64 */
65
66 struct sockaddr_ns idp_ns = { sizeof(idp_ns), AF_NS };
67
68 /*
69 * This may also be called for raw listeners.
70 */
71 void
72 idp_input(struct mbuf *m, ...)
73 {
74 struct nspcb *nsp;
75 struct idp *idp = mtod(m, struct idp *);
76 struct ifnet *ifp = m->m_pkthdr.rcvif;
77 va_list ap;
78
79 va_start(ap, m);
80 nsp = va_arg(ap, struct nspcb *);
81 va_end(ap);
82
83 if (nsp==0)
84 panic("No nspcb");
85 /*
86 * Construct sockaddr format source address.
87 * Stuff source address and datagram in user buffer.
88 */
89 idp_ns.sns_addr = idp->idp_sna;
90 if (ns_neteqnn(idp->idp_sna.x_net, ns_zeronet) && ifp) {
91 struct ifaddr *ifa;
92
93 for (ifa = ifp->if_addrlist.tqh_first; ifa != 0;
94 ifa = ifa->ifa_list.tqe_next) {
95 if (ifa->ifa_addr->sa_family == AF_NS) {
96 idp_ns.sns_addr.x_net =
97 IA_SNS(ifa)->sns_addr.x_net;
98 break;
99 }
100 }
101 }
102 nsp->nsp_rpt = idp->idp_pt;
103 if ( ! (nsp->nsp_flags & NSP_RAWIN) ) {
104 m->m_len -= sizeof (struct idp);
105 m->m_pkthdr.len -= sizeof (struct idp);
106 m->m_data += sizeof (struct idp);
107 }
108 if (sbappendaddr(&nsp->nsp_socket->so_rcv, snstosa(&idp_ns), m,
109 (struct mbuf *)0) == 0)
110 goto bad;
111 sorwakeup(nsp->nsp_socket);
112 return;
113 bad:
114 m_freem(m);
115 }
116
117 void
118 idp_abort(struct nspcb *nsp)
119 {
120 struct socket *so = nsp->nsp_socket;
121
122 ns_pcbdisconnect(nsp);
123 soisdisconnected(so);
124 }
125 /*
126 * Drop connection, reporting
127 * the specified error.
128 */
129 void
130 idp_drop(struct nspcb *nsp, int errno)
131 {
132 struct socket *so = nsp->nsp_socket;
133
134 #if 0
135 /*
136 * someday, in the xerox world
137 * we will generate error protocol packets
138 * announcing that the socket has gone away.
139 */
140 if (TCPS_HAVERCVDSYN(tp->t_state)) {
141 tp->t_state = TCPS_CLOSED;
142 (void) tcp_output(tp);
143 }
144 #endif
145 so->so_error = errno;
146 ns_pcbdisconnect(nsp);
147 soisdisconnected(so);
148 }
149
150 int
151 idp_output(struct mbuf *m0, ...)
152 {
153 struct nspcb *nsp;
154 struct mbuf *m;
155 struct idp *idp;
156 int len = m0->m_pkthdr.len;
157 struct mbuf *mprev = NULL;
158 extern int idpcksum;
159 va_list ap;
160
161 va_start(ap, m0);
162 nsp = va_arg(ap, struct nspcb *);
163 va_end(ap);
164
165 /*
166 * Make sure packet is actually of even length.
167 */
168
169 if (len & 1) {
170 m = mprev;
171 if ((m->m_flags & M_EXT) == 0 &&
172 (m->m_len + m->m_data < &m->m_dat[MLEN])) {
173 m->m_len++;
174 } else {
175 struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
176
177 if (m1 == 0) {
178 m_freem(m0);
179 return (ENOBUFS);
180 }
181 m1->m_len = 1;
182 * mtod(m1, char *) = 0;
183 m->m_next = m1;
184 }
185 m0->m_pkthdr.len++;
186 }
187
188 /*
189 * Fill in mbuf with extended IDP header
190 * and addresses and length put into network format.
191 */
192 m = m0;
193 if (nsp->nsp_flags & NSP_RAWOUT) {
194 idp = mtod(m, struct idp *);
195 } else {
196 M_PREPEND(m, sizeof (struct idp), M_DONTWAIT);
197 if (m == 0)
198 return (ENOBUFS);
199 idp = mtod(m, struct idp *);
200 idp->idp_tc = 0;
201 idp->idp_pt = nsp->nsp_dpt;
202 idp->idp_sna = nsp->nsp_laddr;
203 idp->idp_dna = nsp->nsp_faddr;
204 len += sizeof (struct idp);
205 }
206
207 idp->idp_len = htons((u_int16_t)len);
208
209 if (idpcksum) {
210 idp->idp_sum = 0;
211 len = ((len - 1) | 1) + 1;
212 idp->idp_sum = ns_cksum(m, len);
213 } else
214 idp->idp_sum = 0xffff;
215
216 /*
217 * Use cached route for previous datagram if
218 * possible. If the previous net was the same
219 * and the interface was a broadcast medium, or
220 * if the previous destination was identical,
221 * then we are ok.
222 *
223 * NB: We don't handle broadcasts because that
224 * would require 3 subroutine calls.
225 */
226 return (ns_output(m, &nsp->nsp_route,
227 nsp->nsp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)));
228 }
229 /* ARGSUSED */
230 int
231 idp_ctloutput(int req, struct socket *so, int level, int name,
232 struct mbuf **value)
233 {
234 struct mbuf *m;
235 struct nspcb *nsp = sotonspcb(so);
236 int mask, error = 0;
237
238 if (nsp == NULL)
239 return (EINVAL);
240
241 switch (req) {
242
243 case PRCO_GETOPT:
244 if (value==NULL)
245 return (EINVAL);
246 m = m_get(M_DONTWAIT, MT_DATA);
247 if (m==NULL)
248 return (ENOBUFS);
249 switch (name) {
250
251 case SO_ALL_PACKETS:
252 mask = NSP_ALL_PACKETS;
253 goto get_flags;
254
255 case SO_HEADERS_ON_INPUT:
256 mask = NSP_RAWIN;
257 goto get_flags;
258
259 case SO_HEADERS_ON_OUTPUT:
260 mask = NSP_RAWOUT;
261 get_flags:
262 m->m_len = sizeof(short);
263 *mtod(m, short *) = nsp->nsp_flags & mask;
264 break;
265
266 case SO_DEFAULT_HEADERS:
267 m->m_len = sizeof(struct idp);
268 {
269 struct idp *idp = mtod(m, struct idp *);
270 idp->idp_len = 0;
271 idp->idp_sum = 0;
272 idp->idp_tc = 0;
273 idp->idp_pt = nsp->nsp_dpt;
274 idp->idp_dna = nsp->nsp_faddr;
275 idp->idp_sna = nsp->nsp_laddr;
276 }
277 break;
278
279 case SO_SEQNO:
280 m->m_len = sizeof(long);
281 *mtod(m, long *) = ns_pexseq++;
282 break;
283
284 default:
285 error = EINVAL;
286 }
287 *value = m;
288 break;
289
290 case PRCO_SETOPT:
291 switch (name) {
292 int *ok;
293
294 case SO_ALL_PACKETS:
295 mask = NSP_ALL_PACKETS;
296 goto set_head;
297
298 case SO_HEADERS_ON_INPUT:
299 mask = NSP_RAWIN;
300 goto set_head;
301
302 case SO_HEADERS_ON_OUTPUT:
303 mask = NSP_RAWOUT;
304 set_head:
305 if (value && *value) {
306 ok = mtod(*value, int *);
307 if (*ok)
308 nsp->nsp_flags |= mask;
309 else
310 nsp->nsp_flags &= ~mask;
311 } else error = EINVAL;
312 break;
313
314 case SO_DEFAULT_HEADERS:
315 {
316 struct idp *idp
317 = mtod(*value, struct idp *);
318 nsp->nsp_dpt = idp->idp_pt;
319 }
320 break;
321 #ifdef NSIP
322
323 case SO_NSIP_ROUTE:
324 error = nsip_route(*value);
325 break;
326 #endif /* NSIP */
327 default:
328 error = EINVAL;
329 }
330 if (value && *value)
331 m_freem(*value);
332 break;
333 }
334 return (error);
335 }
336
337 u_long idp_sendspace = 2048;
338 u_long idp_recvspace = 2048;
339
340 /*ARGSUSED*/
341 int
342 idp_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
343 struct mbuf *control, struct proc *p)
344 {
345 struct nspcb *nsp;
346 int s;
347 int error = 0;
348
349 if (req == PRU_CONTROL)
350 return (ns_control(so, (u_long)m, (caddr_t)nam,
351 (struct ifnet *)control, p));
352
353 if (req == PRU_PURGEIF) {
354 ns_purgeif((struct ifnet *)control);
355 return (0);
356 }
357
358 s = splsoftnet();
359 nsp = sotonspcb(so);
360 if (nsp == 0 && req != PRU_ATTACH) {
361 error = EINVAL;
362 goto release;
363 }
364
365 switch (req) {
366
367 case PRU_ATTACH:
368 if (nsp != 0) {
369 error = EISCONN;
370 break;
371 }
372 if ((error = soreserve(so, idp_sendspace, idp_recvspace)) ||
373 (error = ns_pcballoc(so, &nspcb)))
374 break;
375 break;
376
377 case PRU_DETACH:
378 ns_pcbdetach(nsp);
379 break;
380
381 case PRU_BIND:
382 error = ns_pcbbind(nsp, nam, p);
383 break;
384
385 case PRU_LISTEN:
386 error = EOPNOTSUPP;
387 break;
388
389 case PRU_CONNECT:
390 error = ns_pcbconnect(nsp, nam);
391 if (error)
392 break;
393 soisconnected(so);
394 break;
395
396 case PRU_CONNECT2:
397 error = EOPNOTSUPP;
398 break;
399
400 case PRU_DISCONNECT:
401 soisdisconnected(so);
402 ns_pcbdisconnect(nsp);
403 break;
404
405 case PRU_SHUTDOWN:
406 socantsendmore(so);
407 break;
408
409 case PRU_RCVD:
410 error = EOPNOTSUPP;
411 break;
412
413 case PRU_SEND:
414 {
415 struct ns_addr laddr;
416
417 if (nam) {
418 laddr = nsp->nsp_laddr;
419 if ((so->so_state & SS_ISCONNECTED) != 0) {
420 error = EISCONN;
421 break;
422 }
423 error = ns_pcbconnect(nsp, nam);
424 if (error)
425 break;
426 } else {
427 if ((so->so_state & SS_ISCONNECTED) == 0) {
428 error = ENOTCONN;
429 break;
430 }
431 }
432 error = idp_output(m, nsp);
433 if (nam) {
434 ns_pcbdisconnect(nsp);
435 nsp->nsp_laddr = laddr;
436 }
437 }
438 break;
439
440 case PRU_SENSE:
441 /*
442 * stat: don't bother with a blocksize.
443 */
444 splx(s);
445 return (0);
446
447 /*
448 * Not supported.
449 */
450 case PRU_RCVOOB:
451 error = EOPNOTSUPP;
452 break;
453
454 case PRU_SENDOOB:
455 m_freem(m);
456 error = EOPNOTSUPP;
457 break;
458
459 case PRU_SOCKADDR:
460 ns_setsockaddr(nsp, nam);
461 break;
462
463 case PRU_PEERADDR:
464 ns_setpeeraddr(nsp, nam);
465 break;
466
467 default:
468 panic("idp_usrreq");
469 }
470
471 release:
472 splx(s);
473 return (error);
474 }
475
476 /*ARGSUSED*/
477 int
478 idp_raw_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
479 struct mbuf *control, struct proc *p)
480 {
481 int error = 0;
482 struct nspcb *nsp = sotonspcb(so);
483
484 switch (req) {
485
486 case PRU_ATTACH:
487 if (nsp != 0) {
488 error = EISCONN;
489 break;
490 }
491 if (p == 0 || (error = suser(p->p_ucred, &p->p_acflag))) {
492 error = EACCES;
493 break;
494 }
495 if ((error = soreserve(so, idp_sendspace, idp_recvspace)) ||
496 (error = ns_pcballoc(so, &nspcb)))
497 break;
498 nsp = sotonspcb(so);
499 nsp->nsp_faddr.x_host = ns_broadhost;
500 nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT;
501 break;
502
503 default:
504 error = idp_usrreq(so, req, m, nam, control, p);
505 break;
506 }
507 return (error);
508 }
Cache object: 67ae68cb1361d2eb562ecc68cfeb9013
|