1 /* $NetBSD: idp_usrreq.c,v 1.22 2003/08/07 16:33:44 agc 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.22 2003/08/07 16:33:44 agc 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 #if __STDC__
73 idp_input(struct mbuf *m, ...)
74 #else
75 idp_input(m, va_alist)
76 struct mbuf *m;
77 va_dcl
78 #endif
79 {
80 struct nspcb *nsp;
81 struct idp *idp = mtod(m, struct idp *);
82 struct ifnet *ifp = m->m_pkthdr.rcvif;
83 va_list ap;
84
85 va_start(ap, m);
86 nsp = va_arg(ap, struct nspcb *);
87 va_end(ap);
88
89 if (nsp==0)
90 panic("No nspcb");
91 /*
92 * Construct sockaddr format source address.
93 * Stuff source address and datagram in user buffer.
94 */
95 idp_ns.sns_addr = idp->idp_sna;
96 if (ns_neteqnn(idp->idp_sna.x_net, ns_zeronet) && ifp) {
97 struct ifaddr *ifa;
98
99 for (ifa = ifp->if_addrlist.tqh_first; ifa != 0;
100 ifa = ifa->ifa_list.tqe_next) {
101 if (ifa->ifa_addr->sa_family == AF_NS) {
102 idp_ns.sns_addr.x_net =
103 IA_SNS(ifa)->sns_addr.x_net;
104 break;
105 }
106 }
107 }
108 nsp->nsp_rpt = idp->idp_pt;
109 if ( ! (nsp->nsp_flags & NSP_RAWIN) ) {
110 m->m_len -= sizeof (struct idp);
111 m->m_pkthdr.len -= sizeof (struct idp);
112 m->m_data += sizeof (struct idp);
113 }
114 if (sbappendaddr(&nsp->nsp_socket->so_rcv, snstosa(&idp_ns), m,
115 (struct mbuf *)0) == 0)
116 goto bad;
117 sorwakeup(nsp->nsp_socket);
118 return;
119 bad:
120 m_freem(m);
121 }
122
123 void
124 idp_abort(nsp)
125 struct nspcb *nsp;
126 {
127 struct socket *so = nsp->nsp_socket;
128
129 ns_pcbdisconnect(nsp);
130 soisdisconnected(so);
131 }
132 /*
133 * Drop connection, reporting
134 * the specified error.
135 */
136 void
137 idp_drop(nsp, errno)
138 struct nspcb *nsp;
139 int errno;
140 {
141 struct socket *so = nsp->nsp_socket;
142
143 #if 0
144 /*
145 * someday, in the xerox world
146 * we will generate error protocol packets
147 * announcing that the socket has gone away.
148 */
149 if (TCPS_HAVERCVDSYN(tp->t_state)) {
150 tp->t_state = TCPS_CLOSED;
151 (void) tcp_output(tp);
152 }
153 #endif
154 so->so_error = errno;
155 ns_pcbdisconnect(nsp);
156 soisdisconnected(so);
157 }
158
159 int
160 #if __STDC__
161 idp_output(struct mbuf *m0, ...)
162 #else
163 idp_output(m0, va_alist)
164 struct mbuf *m0;
165 va_dcl
166 #endif
167 {
168 struct nspcb *nsp;
169 struct mbuf *m;
170 struct idp *idp;
171 int len = m0->m_pkthdr.len;
172 struct mbuf *mprev = NULL;
173 extern int idpcksum;
174 va_list ap;
175
176 va_start(ap, m0);
177 nsp = va_arg(ap, struct nspcb *);
178 va_end(ap);
179
180 /*
181 * Make sure packet is actually of even length.
182 */
183
184 if (len & 1) {
185 m = mprev;
186 if ((m->m_flags & M_EXT) == 0 &&
187 (m->m_len + m->m_data < &m->m_dat[MLEN])) {
188 m->m_len++;
189 } else {
190 struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
191
192 if (m1 == 0) {
193 m_freem(m0);
194 return (ENOBUFS);
195 }
196 m1->m_len = 1;
197 * mtod(m1, char *) = 0;
198 m->m_next = m1;
199 }
200 m0->m_pkthdr.len++;
201 }
202
203 /*
204 * Fill in mbuf with extended IDP header
205 * and addresses and length put into network format.
206 */
207 m = m0;
208 if (nsp->nsp_flags & NSP_RAWOUT) {
209 idp = mtod(m, struct idp *);
210 } else {
211 M_PREPEND(m, sizeof (struct idp), M_DONTWAIT);
212 if (m == 0)
213 return (ENOBUFS);
214 idp = mtod(m, struct idp *);
215 idp->idp_tc = 0;
216 idp->idp_pt = nsp->nsp_dpt;
217 idp->idp_sna = nsp->nsp_laddr;
218 idp->idp_dna = nsp->nsp_faddr;
219 len += sizeof (struct idp);
220 }
221
222 idp->idp_len = htons((u_int16_t)len);
223
224 if (idpcksum) {
225 idp->idp_sum = 0;
226 len = ((len - 1) | 1) + 1;
227 idp->idp_sum = ns_cksum(m, len);
228 } else
229 idp->idp_sum = 0xffff;
230
231 /*
232 * Use cached route for previous datagram if
233 * possible. If the previous net was the same
234 * and the interface was a broadcast medium, or
235 * if the previous destination was identical,
236 * then we are ok.
237 *
238 * NB: We don't handle broadcasts because that
239 * would require 3 subroutine calls.
240 */
241 return (ns_output(m, &nsp->nsp_route,
242 nsp->nsp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)));
243 }
244 /* ARGSUSED */
245 int
246 idp_ctloutput(req, so, level, name, value)
247 int req, level;
248 struct socket *so;
249 int name;
250 struct mbuf **value;
251 {
252 struct mbuf *m;
253 struct nspcb *nsp = sotonspcb(so);
254 int mask, error = 0;
255
256 if (nsp == NULL)
257 return (EINVAL);
258
259 switch (req) {
260
261 case PRCO_GETOPT:
262 if (value==NULL)
263 return (EINVAL);
264 m = m_get(M_DONTWAIT, MT_DATA);
265 if (m==NULL)
266 return (ENOBUFS);
267 switch (name) {
268
269 case SO_ALL_PACKETS:
270 mask = NSP_ALL_PACKETS;
271 goto get_flags;
272
273 case SO_HEADERS_ON_INPUT:
274 mask = NSP_RAWIN;
275 goto get_flags;
276
277 case SO_HEADERS_ON_OUTPUT:
278 mask = NSP_RAWOUT;
279 get_flags:
280 m->m_len = sizeof(short);
281 *mtod(m, short *) = nsp->nsp_flags & mask;
282 break;
283
284 case SO_DEFAULT_HEADERS:
285 m->m_len = sizeof(struct idp);
286 {
287 struct idp *idp = mtod(m, struct idp *);
288 idp->idp_len = 0;
289 idp->idp_sum = 0;
290 idp->idp_tc = 0;
291 idp->idp_pt = nsp->nsp_dpt;
292 idp->idp_dna = nsp->nsp_faddr;
293 idp->idp_sna = nsp->nsp_laddr;
294 }
295 break;
296
297 case SO_SEQNO:
298 m->m_len = sizeof(long);
299 *mtod(m, long *) = ns_pexseq++;
300 break;
301
302 default:
303 error = EINVAL;
304 }
305 *value = m;
306 break;
307
308 case PRCO_SETOPT:
309 switch (name) {
310 int *ok;
311
312 case SO_ALL_PACKETS:
313 mask = NSP_ALL_PACKETS;
314 goto set_head;
315
316 case SO_HEADERS_ON_INPUT:
317 mask = NSP_RAWIN;
318 goto set_head;
319
320 case SO_HEADERS_ON_OUTPUT:
321 mask = NSP_RAWOUT;
322 set_head:
323 if (value && *value) {
324 ok = mtod(*value, int *);
325 if (*ok)
326 nsp->nsp_flags |= mask;
327 else
328 nsp->nsp_flags &= ~mask;
329 } else error = EINVAL;
330 break;
331
332 case SO_DEFAULT_HEADERS:
333 {
334 struct idp *idp
335 = mtod(*value, struct idp *);
336 nsp->nsp_dpt = idp->idp_pt;
337 }
338 break;
339 #ifdef NSIP
340
341 case SO_NSIP_ROUTE:
342 error = nsip_route(*value);
343 break;
344 #endif /* NSIP */
345 default:
346 error = EINVAL;
347 }
348 if (value && *value)
349 m_freem(*value);
350 break;
351 }
352 return (error);
353 }
354
355 u_long idp_sendspace = 2048;
356 u_long idp_recvspace = 2048;
357
358 /*ARGSUSED*/
359 int
360 idp_usrreq(so, req, m, nam, control, p)
361 struct socket *so;
362 int req;
363 struct mbuf *m, *nam, *control;
364 struct proc *p;
365 {
366 struct nspcb *nsp;
367 int s;
368 int error = 0;
369
370 if (req == PRU_CONTROL)
371 return (ns_control(so, (u_long)m, (caddr_t)nam,
372 (struct ifnet *)control, p));
373
374 if (req == PRU_PURGEIF) {
375 ns_purgeif((struct ifnet *)control);
376 return (0);
377 }
378
379 s = splsoftnet();
380 nsp = sotonspcb(so);
381 if (nsp == 0 && req != PRU_ATTACH) {
382 error = EINVAL;
383 goto release;
384 }
385
386 switch (req) {
387
388 case PRU_ATTACH:
389 if (nsp != 0) {
390 error = EISCONN;
391 break;
392 }
393 if ((error = soreserve(so, idp_sendspace, idp_recvspace)) ||
394 (error = ns_pcballoc(so, &nspcb)))
395 break;
396 break;
397
398 case PRU_DETACH:
399 ns_pcbdetach(nsp);
400 break;
401
402 case PRU_BIND:
403 error = ns_pcbbind(nsp, nam, p);
404 break;
405
406 case PRU_LISTEN:
407 error = EOPNOTSUPP;
408 break;
409
410 case PRU_CONNECT:
411 error = ns_pcbconnect(nsp, nam);
412 if (error)
413 break;
414 soisconnected(so);
415 break;
416
417 case PRU_CONNECT2:
418 error = EOPNOTSUPP;
419 break;
420
421 case PRU_DISCONNECT:
422 soisdisconnected(so);
423 ns_pcbdisconnect(nsp);
424 break;
425
426 case PRU_SHUTDOWN:
427 socantsendmore(so);
428 break;
429
430 case PRU_RCVD:
431 error = EOPNOTSUPP;
432 break;
433
434 case PRU_SEND:
435 {
436 struct ns_addr laddr;
437
438 if (nam) {
439 laddr = nsp->nsp_laddr;
440 if ((so->so_state & SS_ISCONNECTED) != 0) {
441 error = EISCONN;
442 break;
443 }
444 error = ns_pcbconnect(nsp, nam);
445 if (error)
446 break;
447 } else {
448 if ((so->so_state & SS_ISCONNECTED) == 0) {
449 error = ENOTCONN;
450 break;
451 }
452 }
453 error = idp_output(m, nsp);
454 if (nam) {
455 ns_pcbdisconnect(nsp);
456 nsp->nsp_laddr = laddr;
457 }
458 }
459 break;
460
461 case PRU_SENSE:
462 /*
463 * stat: don't bother with a blocksize.
464 */
465 splx(s);
466 return (0);
467
468 /*
469 * Not supported.
470 */
471 case PRU_RCVOOB:
472 error = EOPNOTSUPP;
473 break;
474
475 case PRU_SENDOOB:
476 m_freem(m);
477 error = EOPNOTSUPP;
478 break;
479
480 case PRU_SOCKADDR:
481 ns_setsockaddr(nsp, nam);
482 break;
483
484 case PRU_PEERADDR:
485 ns_setpeeraddr(nsp, nam);
486 break;
487
488 default:
489 panic("idp_usrreq");
490 }
491
492 release:
493 splx(s);
494 return (error);
495 }
496
497 /*ARGSUSED*/
498 int
499 idp_raw_usrreq(so, req, m, nam, control, p)
500 struct socket *so;
501 int req;
502 struct mbuf *m, *nam, *control;
503 struct proc *p;
504 {
505 int error = 0;
506 struct nspcb *nsp = sotonspcb(so);
507
508 switch (req) {
509
510 case PRU_ATTACH:
511 if (nsp != 0) {
512 error = EISCONN;
513 break;
514 }
515 if (p == 0 || (error = suser(p->p_ucred, &p->p_acflag))) {
516 error = EACCES;
517 break;
518 }
519 if ((error = soreserve(so, idp_sendspace, idp_recvspace)) ||
520 (error = ns_pcballoc(so, &nspcb)))
521 break;
522 nsp = sotonspcb(so);
523 nsp->nsp_faddr.x_host = ns_broadhost;
524 nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT;
525 break;
526
527 default:
528 error = idp_usrreq(so, req, m, nam, control, p);
529 break;
530 }
531 return (error);
532 }
533
Cache object: 77dc1b66d70a31ac388c6ea0a5a72d82
|