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