Convert to critical sections.
[dragonfly.git] / sys / netproto / natm / natm.c
CommitLineData
984263bc
MD
1/* $NetBSD: natm.c,v 1.5 1996/11/09 03:26:26 chuck Exp $ */
2/* $FreeBSD: src/sys/netnatm/natm.c,v 1.12 2000/02/13 03:32:03 peter Exp $ */
68b13d6b 3/* $DragonFly: src/sys/netproto/natm/natm.c,v 1.18 2005/06/10 22:34:51 dillon Exp $ */
984263bc
MD
4
5/*
6 *
7 * Copyright (c) 1996 Charles D. Cranor and Washington University.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by Charles D. Cranor and
21 * Washington University.
22 * 4. The name of the author may not be used to endorse or promote products
23 * derived from this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 */
36
37/*
38 * natm.c: native mode ATM access (both aal0 and aal5).
39 */
40
41#include <sys/param.h>
42#include <sys/systm.h>
43#include <sys/kernel.h>
5817e015 44#include <sys/proc.h>
984263bc
MD
45#include <sys/sockio.h>
46#include <sys/protosw.h>
47#include <sys/malloc.h>
48#include <sys/mbuf.h>
49#include <sys/socket.h>
50#include <sys/socketvar.h>
51
a80cf23b
JH
52#include <sys/thread2.h>
53#include <sys/msgport2.h>
54
984263bc
MD
55#include <net/if.h>
56#include <net/if_atm.h>
57#include <net/netisr.h>
58
59#include <netinet/in.h>
60
1f2de5d4 61#include "natm.h"
984263bc
MD
62
63static u_long natm5_sendspace = 16*1024;
64static u_long natm5_recvspace = 16*1024;
65
66static u_long natm0_sendspace = 16*1024;
67static u_long natm0_recvspace = 16*1024;
68
69/*
70 * user requests
71 */
72#ifdef FREEBSD_USRREQS
73/*
74 * FreeBSD new usrreqs supersedes pr_usrreq.
75 */
9eeaa8a9 76static int natm_usr_attach (struct socket *, int, struct pru_attach_info *);
3e0c9cba
RG
77static int natm_usr_detach (struct socket *);
78static int natm_usr_connect (struct socket *, struct sockaddr *,
79 struct thread *);
80static int natm_usr_disconnect (struct socket *);
81static int natm_usr_shutdown (struct socket *);
82static int natm_usr_send (struct socket *, int, struct mbuf *,
984263bc 83 struct sockaddr *, struct mbuf *,
3e0c9cba
RG
84 struct thread *);
85static int natm_usr_peeraddr (struct socket *, struct sockaddr **);
86static int natm_usr_control (struct socket *, u_long, caddr_t,
87 struct ifnet *, struct thread *);
88static int natm_usr_abort (struct socket *);
89static int natm_usr_bind (struct socket *, struct sockaddr *,
90 struct thread *);
91static int natm_usr_sockaddr (struct socket *, struct sockaddr **);
984263bc
MD
92
93static int
e4700d00 94natm_usr_attach(struct socket *so, int proto, struct pru_attach_info *ai)
984263bc
MD
95{
96 struct natmpcb *npcb;
97 int error = 0;
984263bc 98
68b13d6b 99 crit_enter();
984263bc
MD
100 npcb = (struct natmpcb *) so->so_pcb;
101
102 if (npcb) {
103 error = EISCONN;
104 goto out;
105 }
106
107 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
108 if (proto == PROTO_NATMAAL5)
e4700d00
JH
109 error = soreserve(so, natm5_sendspace, natm5_recvspace,
110 ai->sb_rlimit);
984263bc 111 else
e4700d00
JH
112 error = soreserve(so, natm0_sendspace, natm0_recvspace,
113 ai->sb_rlimit);
984263bc
MD
114 if (error)
115 goto out;
116 }
117
118 so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK));
119 npcb->npcb_socket = so;
120 out:
68b13d6b 121 crit_exit();
984263bc
MD
122 return (error);
123}
124
125static int
126natm_usr_detach(struct socket *so)
127{
128 struct natmpcb *npcb;
129 int error = 0;
984263bc 130
68b13d6b 131 crit_enter();
984263bc
MD
132 npcb = (struct natmpcb *) so->so_pcb;
133 if (npcb == NULL) {
134 error = EINVAL;
135 goto out;
136 }
137
138 /*
139 * we turn on 'drain' *before* we sofree.
140 */
141 npcb_free(npcb, NPCB_DESTROY); /* drain */
142 so->so_pcb = NULL;
143 sofree(so);
144 out:
68b13d6b 145 crit_exit();
984263bc
MD
146 return (error);
147}
148
149static int
7b95be2a 150natm_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
984263bc
MD
151{
152 struct natmpcb *npcb;
153 struct sockaddr_natm *snatm;
154 struct atm_pseudoioctl api;
155 struct ifnet *ifp;
156 int error = 0;
68b13d6b 157 int proto;
984263bc 158
68b13d6b
MD
159 crit_enter();
160 proto = so->so_proto->pr_protocol;
984263bc
MD
161 npcb = (struct natmpcb *) so->so_pcb;
162 if (npcb == NULL) {
163 error = EINVAL;
164 goto out;
165 }
166
167 /*
168 * validate nam and npcb
169 */
170
171 snatm = (struct sockaddr_natm *)nam;
172 if (snatm->snatm_len != sizeof(*snatm) ||
173 (npcb->npcb_flags & NPCB_FREE) == 0) {
174 error = EINVAL;
175 goto out;
176 }
177 if (snatm->snatm_family != AF_NATM) {
178 error = EAFNOSUPPORT;
179 goto out;
180 }
181
182 snatm->snatm_if[IFNAMSIZ-1] = '\0'; /* XXX ensure null termination
183 since ifunit() uses strcmp */
184
185 /*
186 * convert interface string to ifp, validate.
187 */
188
189 ifp = ifunit(snatm->snatm_if);
190 if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) {
191 error = ENXIO;
192 goto out;
193 }
194 if (ifp->if_output != atm_output) {
195 error = EAFNOSUPPORT;
196 goto out;
197 }
198
199 /*
200 * register us with the NATM PCB layer
201 */
202
203 if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
204 error = EADDRINUSE;
205 goto out;
206 }
207
208 /*
209 * enable rx
210 */
211
212 ATM_PH_FLAGS(&api.aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
213 ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
214 ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
215 api.rxhand = npcb;
68b13d6b 216 crit_enter();
984263bc 217 if (ifp->if_ioctl == NULL ||
bd4539cc 218 ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api,
65df9187 219 td->td_proc->p_ucred) != 0) {
68b13d6b 220 crit_exit();
984263bc
MD
221 npcb_free(npcb, NPCB_REMOVE);
222 error = EIO;
223 goto out;
224 }
68b13d6b 225 crit_exit();
984263bc
MD
226
227 soisconnected(so);
228
229 out:
68b13d6b 230 crit_exit();
984263bc
MD
231 return (error);
232}
233
234static int
235natm_usr_disconnect(struct socket *so)
236{
237 struct natmpcb *npcb;
238 struct atm_pseudoioctl api;
239 struct ifnet *ifp;
240 int error = 0;
984263bc 241
68b13d6b 242 crit_enter();
984263bc
MD
243 npcb = (struct natmpcb *) so->so_pcb;
244 if (npcb == NULL) {
245 error = EINVAL;
246 goto out;
247 }
248
249 if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) {
250 printf("natm: disconnected check\n");
251 error = EIO;
252 goto out;
253 }
254 ifp = npcb->npcb_ifp;
255
256 /*
257 * disable rx
258 */
259
260 ATM_PH_FLAGS(&api.aph) = ATM_PH_AAL5;
261 ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
262 ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
263 api.rxhand = npcb;
68b13d6b 264 crit_enter();
984263bc 265 if (ifp->if_ioctl != NULL)
bd4539cc 266 ifp->if_ioctl(ifp, SIOCATMDIS, (caddr_t) &api, (struct ucred *)NULL);
68b13d6b 267 crit_exit();
984263bc
MD
268
269 npcb_free(npcb, NPCB_REMOVE);
270 soisdisconnected(so);
271
272 out:
68b13d6b 273 crit_exit();
984263bc
MD
274 return (error);
275}
276
277static int
278natm_usr_shutdown(struct socket *so)
279{
280 socantsendmore(so);
281 return 0;
282}
283
284static int
285natm_usr_send(struct socket *so, int flags, struct mbuf *m,
7b95be2a 286 struct sockaddr *nam, struct mbuf *control, struct thread *td)
984263bc
MD
287{
288 struct natmpcb *npcb;
289 struct atm_pseudohdr *aph;
290 int error = 0;
984263bc
MD
291 int proto = so->so_proto->pr_protocol;
292
68b13d6b
MD
293 crit_enter();
294
984263bc
MD
295 npcb = (struct natmpcb *) so->so_pcb;
296 if (npcb == NULL) {
297 error = EINVAL;
298 goto out;
299 }
300
301 if (control && control->m_len) {
302 m_freem(control);
303 m_freem(m);
304 error = EINVAL;
305 goto out;
306 }
307
308 /*
309 * send the data. we must put an atm_pseudohdr on first
310 */
311
312 M_PREPEND(m, sizeof(*aph), M_WAITOK);
313 if (m == NULL) {
314 error = ENOBUFS;
315 goto out;
316 }
317 aph = mtod(m, struct atm_pseudohdr *);
318 ATM_PH_VPI(aph) = npcb->npcb_vpi;
319 ATM_PH_SETVCI(aph, npcb->npcb_vci);
320 ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
321
322 error = atm_output(npcb->npcb_ifp, m, NULL, NULL);
323
324 out:
68b13d6b 325 crit_exit();
984263bc
MD
326 return (error);
327}
328
329static int
330natm_usr_peeraddr(struct socket *so, struct sockaddr **nam)
331{
332 struct natmpcb *npcb;
333 struct sockaddr_natm *snatm, ssnatm;
334 int error = 0;
984263bc 335
68b13d6b 336 crit_enter();
984263bc
MD
337 npcb = (struct natmpcb *) so->so_pcb;
338 if (npcb == NULL) {
339 error = EINVAL;
340 goto out;
341 }
342
343 snatm = &ssnatm;
344 bzero(snatm, sizeof(*snatm));
345 snatm->snatm_len = sizeof(*snatm);
346 snatm->snatm_family = AF_NATM;
3e4a09e7
MD
347 strlcpy(snatm->snatm_if, npcb->npcb_ifp->if_xname,
348 sizeof(snatm->snatm_if));
984263bc
MD
349 snatm->snatm_vci = npcb->npcb_vci;
350 snatm->snatm_vpi = npcb->npcb_vpi;
cfa2ba21 351 *nam = dup_sockaddr((struct sockaddr *)snatm);
984263bc
MD
352
353 out:
68b13d6b 354 crit_exit();
984263bc
MD
355 return (error);
356}
357
358static int
359natm_usr_control(struct socket *so, u_long cmd, caddr_t arg,
7b95be2a 360 struct ifnet *ifp, struct thread *td)
984263bc
MD
361{
362 struct natmpcb *npcb;
363 struct atm_rawioctl ario;
364 int error = 0;
68b13d6b
MD
365
366 crit_enter();
984263bc
MD
367
368 npcb = (struct natmpcb *) so->so_pcb;
369 if (npcb == NULL) {
370 error = EINVAL;
371 goto out;
372 }
373
374 /*
375 * raw atm ioctl. comes in as a SIOCRAWATM. we convert it to
376 * SIOCXRAWATM and pass it to the driver.
377 */
378 if (cmd == SIOCRAWATM) {
379 if (npcb->npcb_ifp == NULL) {
380 error = ENOTCONN;
381 goto out;
382 }
383 ario.npcb = npcb;
384 ario.rawvalue = *((int *)arg);
385 error = npcb->npcb_ifp->if_ioctl(npcb->npcb_ifp,
bd4539cc 386 SIOCXRAWATM, (caddr_t) &ario,
65df9187 387 td->td_proc->p_ucred);
984263bc
MD
388 if (!error) {
389 if (ario.rawvalue)
390 npcb->npcb_flags |= NPCB_RAW;
391 else
392 npcb->npcb_flags &= ~(NPCB_RAW);
393 }
394 }
395 else
396 error = EOPNOTSUPP;
397
398 out:
68b13d6b 399 crit_exit();
984263bc
MD
400 return (error);
401}
402
403static int
404natm_usr_abort(struct socket *so)
405{
406 return natm_usr_shutdown(so);
407}
408
409static int
7b95be2a 410natm_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
984263bc
MD
411{
412 return EOPNOTSUPP;
413}
414
415static int
416natm_usr_sockaddr(struct socket *so, struct sockaddr **nam)
417{
418 return EOPNOTSUPP;
419}
420
421/* xxx - should be const */
422struct pr_usrreqs natm_usrreqs = {
423 natm_usr_abort, pru_accept_notsupp, natm_usr_attach, natm_usr_bind,
424 natm_usr_connect, pru_connect2_notsupp, natm_usr_control,
425 natm_usr_detach, natm_usr_disconnect, pru_listen_notsupp,
426 natm_usr_peeraddr, pru_rcvd_notsupp, pru_rcvoob_notsupp,
427 natm_usr_send, pru_sense_null, natm_usr_shutdown,
428 natm_usr_sockaddr, sosend, soreceive, sopoll
429};
430
431#else /* !FREEBSD_USRREQS */
432
433#if defined(__NetBSD__) || defined(__OpenBSD__)
434int natm_usrreq(so, req, m, nam, control, p)
9a786592 435#elif defined(__DragonFly__)
984263bc
MD
436int natm_usrreq(so, req, m, nam, control)
437#endif
438
439struct socket *so;
440int req;
441struct mbuf *m, *nam, *control;
442#if defined(__NetBSD__) || defined(__OpenBSD__)
443struct proc *p;
444#endif
445
446{
68b13d6b 447 int error = 0;
984263bc
MD
448 struct natmpcb *npcb;
449 struct sockaddr_natm *snatm;
450 struct atm_pseudoioctl api;
451 struct atm_pseudohdr *aph;
452 struct atm_rawioctl ario;
453 struct ifnet *ifp;
454 int proto = so->so_proto->pr_protocol;
455
68b13d6b 456 crit_enter();
984263bc
MD
457
458 npcb = (struct natmpcb *) so->so_pcb;
459
460 if (npcb == NULL && req != PRU_ATTACH) {
461 error = EINVAL;
462 goto done;
463 }
464
465
466 switch (req) {
467 case PRU_ATTACH: /* attach protocol to up */
468
469 if (npcb) {
470 error = EISCONN;
471 break;
472 }
473
474 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
475 if (proto == PROTO_NATMAAL5)
476 error = soreserve(so, natm5_sendspace, natm5_recvspace);
477 else
478 error = soreserve(so, natm0_sendspace, natm0_recvspace);
479 if (error)
480 break;
481 }
482
483 so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK));
484 npcb->npcb_socket = so;
485
486 break;
487
488 case PRU_DETACH: /* detach protocol from up */
489
490 /*
491 * we turn on 'drain' *before* we sofree.
492 */
493
494 npcb_free(npcb, NPCB_DESTROY); /* drain */
495 so->so_pcb = NULL;
496 sofree(so);
497
498 break;
499
500 case PRU_CONNECT: /* establish connection to peer */
501
502 /*
503 * validate nam and npcb
504 */
505
506 if (nam->m_len != sizeof(*snatm)) {
507 error = EINVAL;
508 break;
509 }
510 snatm = mtod(nam, struct sockaddr_natm *);
511 if (snatm->snatm_len != sizeof(*snatm) ||
512 (npcb->npcb_flags & NPCB_FREE) == 0) {
513 error = EINVAL;
514 break;
515 }
516 if (snatm->snatm_family != AF_NATM) {
517 error = EAFNOSUPPORT;
518 break;
519 }
520
521 snatm->snatm_if[IFNAMSIZ-1] = '\0'; /* XXX ensure null termination
522 since ifunit() uses strcmp */
523
524 /*
525 * convert interface string to ifp, validate.
526 */
527
528 ifp = ifunit(snatm->snatm_if);
529 if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) {
530 error = ENXIO;
531 break;
532 }
533 if (ifp->if_output != atm_output) {
534 error = EAFNOSUPPORT;
535 break;
536 }
537
538
539 /*
540 * register us with the NATM PCB layer
541 */
542
543 if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
544 error = EADDRINUSE;
545 break;
546 }
547
548 /*
549 * enable rx
550 */
551
552 ATM_PH_FLAGS(&api.aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
553 ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
554 ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
555 api.rxhand = npcb;
68b13d6b 556 crit_enter();
984263bc 557 if (ifp->if_ioctl == NULL ||
bd4539cc
JH
558 ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api,
559 (struct ucred *)NULL) != 0) {
68b13d6b 560 crit_exit();
984263bc
MD
561 npcb_free(npcb, NPCB_REMOVE);
562 error = EIO;
563 break;
564 }
68b13d6b 565 crit_exit();
984263bc
MD
566
567 soisconnected(so);
568
569 break;
570
571 case PRU_DISCONNECT: /* disconnect from peer */
572
573 if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) {
574 printf("natm: disconnected check\n");
575 error = EIO;
576 break;
577 }
578 ifp = npcb->npcb_ifp;
579
580 /*
581 * disable rx
582 */
583
584 ATM_PH_FLAGS(&api.aph) = ATM_PH_AAL5;
585 ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
586 ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
587 api.rxhand = npcb;
68b13d6b 588 crit_enter();
984263bc 589 if (ifp->if_ioctl != NULL)
bd4539cc 590 ifp->if_ioctl(ifp, SIOCATMDIS, (caddr_t) &api, (struct ucred *)NULL);
68b13d6b 591 crit_exit();
984263bc
MD
592
593 npcb_free(npcb, NPCB_REMOVE);
594 soisdisconnected(so);
595
596 break;
597
598 case PRU_SHUTDOWN: /* won't send any more data */
599 socantsendmore(so);
600 break;
601
602 case PRU_SEND: /* send this data */
603 if (control && control->m_len) {
604 m_freem(control);
605 m_freem(m);
606 error = EINVAL;
607 break;
608 }
609
610 /*
611 * send the data. we must put an atm_pseudohdr on first
612 */
613
614 M_PREPEND(m, sizeof(*aph), M_WAITOK);
615 if (m == NULL) {
616 error = ENOBUFS;
617 break;
618 }
619 aph = mtod(m, struct atm_pseudohdr *);
620 ATM_PH_VPI(aph) = npcb->npcb_vpi;
621 ATM_PH_SETVCI(aph, npcb->npcb_vci);
622 ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
623
624 error = atm_output(npcb->npcb_ifp, m, NULL, NULL);
625
626 break;
627
628 case PRU_SENSE: /* return status into m */
629 /* return zero? */
630 break;
631
632 case PRU_PEERADDR: /* fetch peer's address */
633 snatm = mtod(nam, struct sockaddr_natm *);
634 bzero(snatm, sizeof(*snatm));
635 nam->m_len = snatm->snatm_len = sizeof(*snatm);
636 snatm->snatm_family = AF_NATM;
3e4a09e7 637#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
984263bc 638 bcopy(npcb->npcb_ifp->if_xname, snatm->snatm_if, sizeof(snatm->snatm_if));
9a786592 639#elif defined(__DragonFly__)
984263bc
MD
640 snprintf(snatm->snatm_if, sizeof(snatm->snatm_if),
641 "%s%d", npcb->npcb_ifp->if_name, npcb->npcb_ifp->if_unit);
642#endif
643 snatm->snatm_vci = npcb->npcb_vci;
644 snatm->snatm_vpi = npcb->npcb_vpi;
645 break;
646
647 case PRU_CONTROL: /* control operations on protocol */
648 /*
649 * raw atm ioctl. comes in as a SIOCRAWATM. we convert it to
650 * SIOCXRAWATM and pass it to the driver.
651 */
652 if ((u_long)m == SIOCRAWATM) {
653 if (npcb->npcb_ifp == NULL) {
654 error = ENOTCONN;
655 break;
656 }
657 ario.npcb = npcb;
658 ario.rawvalue = *((int *)nam);
bd4539cc
JH
659 error = npcb->npcb_ifp->if_ioctl(npcb->npcb_ifp, SIOCXRAWATM,
660 (caddr_t) &ario, (struct ucred *)NULL);
984263bc
MD
661 if (!error) {
662 if (ario.rawvalue)
663 npcb->npcb_flags |= NPCB_RAW;
664 else
665 npcb->npcb_flags &= ~(NPCB_RAW);
666 }
667
668 break;
669 }
670
671 error = EOPNOTSUPP;
672 break;
673
674 case PRU_BIND: /* bind socket to address */
675 case PRU_LISTEN: /* listen for connection */
676 case PRU_ACCEPT: /* accept connection from peer */
677 case PRU_CONNECT2: /* connect two sockets */
678 case PRU_ABORT: /* abort (fast DISCONNECT, DETATCH) */
679 /* (only happens if LISTEN socket) */
680 case PRU_RCVD: /* have taken data; more room now */
681 case PRU_FASTTIMO: /* 200ms timeout */
682 case PRU_SLOWTIMO: /* 500ms timeout */
683 case PRU_RCVOOB: /* retrieve out of band data */
684 case PRU_SENDOOB: /* send out of band data */
685 case PRU_PROTORCV: /* receive from below */
686 case PRU_PROTOSEND: /* send to below */
687 case PRU_SOCKADDR: /* fetch socket's address */
688#ifdef DIAGNOSTIC
689 printf("natm: PRU #%d unsupported\n", req);
690#endif
691 error = EOPNOTSUPP;
692 break;
693
694 default: panic("natm usrreq");
695 }
696
697done:
68b13d6b 698 crit_exit();
984263bc
MD
699 return(error);
700}
701
702#endif /* !FREEBSD_USRREQS */
703
8bde602d
JH
704/*
705 * natm0_sysctl: not used, but here in case we want to add something
706 * later...
707 */
708
709int natm0_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
710 void *newp, size_t newlen)
711{
712 /* All sysctl names at this level are terminal. */
713 if (namelen != 1)
714 return (ENOTDIR);
715 return (ENOPROTOOPT);
716}
717
718/*
719 * natm5_sysctl: not used, but here in case we want to add something
720 * later...
721 */
722
723int natm5_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
724 void *newp, size_t newlen)
725{
726 /* All sysctl names at this level are terminal. */
727 if (namelen != 1)
728 return (ENOTDIR);
729 return (ENOPROTOOPT);
730}
731
b76bed62 732static int natmintr(struct netmsg *);
8bde602d 733
9a786592 734#if defined(__DragonFly__)
8bde602d
JH
735static void
736netisr_natm_setup(void *dummy __unused)
737{
738
bf82f9b7 739 netisr_register(NETISR_NATM, cpu0_portfn, natmintr);
8bde602d
JH
740}
741SYSINIT(natm_setup, SI_SUB_CPU, SI_ORDER_ANY, netisr_natm_setup, NULL);
742#endif
743
744void
745natm_init()
746{
747 LIST_INIT(&natm_pcbs);
8bde602d 748
bf82f9b7 749 netisr_register(NETISR_NATM, cpu0_portfn, natmintr);
8bde602d
JH
750}
751
984263bc 752/*
68b13d6b 753 * natmintr: software interrupt
984263bc
MD
754 *
755 * note: we expect a socket pointer in rcvif rather than an interface
756 * pointer. we can get the interface pointer from the so's PCB if
757 * we really need it.
758 */
b76bed62 759static int
9eeaa8a9 760natmintr(struct netmsg *msg)
984263bc 761{
9eeaa8a9 762 struct mbuf *m = ((struct netmsg_packet *)msg)->nm_packet;
984263bc
MD
763 struct socket *so;
764 struct natmpcb *npcb;
765
984263bc
MD
766#ifdef DIAGNOSTIC
767 if ((m->m_flags & M_PKTHDR) == 0)
768 panic("natmintr no HDR");
769#endif
770
771 npcb = (struct natmpcb *) m->m_pkthdr.rcvif; /* XXX: overloaded */
772 so = npcb->npcb_socket;
773
68b13d6b 774 crit_enter();
984263bc 775 npcb->npcb_inq--;
68b13d6b 776 crit_exit();
984263bc
MD
777
778 if (npcb->npcb_flags & NPCB_DRAIN) {
779 m_freem(m);
780 if (npcb->npcb_inq == 0)
781 FREE(npcb, M_PCB); /* done! */
a80cf23b 782 goto out;
984263bc
MD
783 }
784
785 if (npcb->npcb_flags & NPCB_FREE) {
786 m_freem(m); /* drop */
a80cf23b 787 goto out;
984263bc
MD
788 }
789
790#ifdef NEED_TO_RESTORE_IFP
791 m->m_pkthdr.rcvif = npcb->npcb_ifp;
792#else
793#ifdef DIAGNOSTIC
794m->m_pkthdr.rcvif = NULL; /* null it out to be safe */
795#endif
796#endif
797
798 if (sbspace(&so->so_rcv) > m->m_pkthdr.len ||
799 ((npcb->npcb_flags & NPCB_RAW) != 0 && so->so_rcv.sb_cc < NPCB_RAWCC) ) {
800#ifdef NATM_STAT
801 natm_sookcnt++;
802 natm_sookbytes += m->m_pkthdr.len;
803#endif
804 sbappendrecord(&so->so_rcv, m);
805 sorwakeup(so);
806 } else {
807#ifdef NATM_STAT
808 natm_sodropcnt++;
809 natm_sodropbytes += m->m_pkthdr.len;
810#endif
811 m_freem(m);
812 }
a80cf23b
JH
813out:
814 lwkt_replymsg(&msg->nm_lmsg, 0);
b76bed62 815 return(EASYNC);
984263bc 816}
984263bc 817