kernel: Sync ACPICA with Intel's version 20140424.
[dragonfly.git] / sys / netproto / atm / atm_aal5.c
1 /*
2  *
3  * ===================================
4  * HARP  |  Host ATM Research Platform
5  * ===================================
6  *
7  *
8  * This Host ATM Research Platform ("HARP") file (the "Software") is
9  * made available by Network Computing Services, Inc. ("NetworkCS")
10  * "AS IS".  NetworkCS does not provide maintenance, improvements or
11  * support of any kind.
12  *
13  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17  * In no event shall NetworkCS be responsible for any damages, including
18  * but not limited to consequential damages, arising from or relating to
19  * any use of the Software or related support.
20  *
21  * Copyright 1994-1998 Network Computing Services, Inc.
22  *
23  * Copies of this Software may be made, however, the above copyright
24  * notice must be reproduced on all copies.
25  *
26  *      @(#) $FreeBSD: src/sys/netatm/atm_aal5.c,v 1.6 1999/10/09 23:24:59 green Exp $
27  *      @(#) $DragonFly: src/sys/netproto/atm/atm_aal5.c,v 1.13 2007/04/22 01:13:15 dillon Exp $
28  */
29
30 /*
31  * Core ATM Services
32  * -----------------
33  *
34  * ATM AAL5 socket protocol processing
35  *
36  */
37
38 #include "kern_include.h"
39 #include <sys/stat.h>
40
41 /*
42  * Global variables
43  */
44 u_long          atm_aal5_sendspace = 64 * 1024; /* XXX */
45 u_long          atm_aal5_recvspace = 64 * 1024; /* XXX */
46
47
48 /*
49  * Local functions
50  */
51 static void     atm_aal5_abort(netmsg_t);
52 static void     atm_aal5_accept(netmsg_t);
53 static void     atm_aal5_attach(netmsg_t);
54 static void     atm_aal5_bind(netmsg_t);
55 static void     atm_aal5_connect(netmsg_t);
56 static void     atm_aal5_control(netmsg_t);
57 static void     atm_aal5_detach(netmsg_t);
58 static void     atm_aal5_listen(netmsg_t);
59 static void     atm_aal5_peeraddr(netmsg_t);
60 static void     atm_aal5_send(netmsg_t);
61 static void     atm_aal5_sense(netmsg_t);
62 static void     atm_aal5_disconnect(netmsg_t);
63 static void     atm_aal5_shutdown(netmsg_t);
64 static void     atm_aal5_sockaddr(netmsg_t);
65
66 static int      atm_aal5_incoming (void *, Atm_connection *,
67                         Atm_attributes *, void **);
68 static void     atm_aal5_cpcs_data (void *, KBuffer *);
69 static caddr_t  atm_aal5_getname (void *);
70
71
72 /*
73  * New-style socket request routines
74  */
75 struct pr_usrreqs       atm_aal5_usrreqs = {
76         .pru_abort = atm_aal5_abort,
77         .pru_accept = atm_aal5_accept,
78         .pru_attach = atm_aal5_attach,
79         .pru_bind = atm_aal5_bind,
80         .pru_connect = atm_aal5_connect,
81         .pru_connect2 = pr_generic_notsupp,
82         .pru_control = atm_aal5_control,
83         .pru_detach = atm_aal5_detach,
84         .pru_disconnect = atm_aal5_disconnect,
85         .pru_listen = atm_aal5_listen,
86         .pru_peeraddr = atm_aal5_peeraddr,
87         .pru_rcvd = pr_generic_notsupp,
88         .pru_rcvoob = pr_generic_notsupp,
89         .pru_send = atm_aal5_send,
90         .pru_sense = atm_aal5_sense,
91         .pru_shutdown = atm_aal5_shutdown,
92         .pru_sockaddr = atm_aal5_sockaddr,
93         .pru_sosend = sosend,
94         .pru_soreceive = soreceive
95 };
96
97 /*
98  * Local variables
99  */
100 static Atm_endpoint     atm_aal5_endpt = {
101         NULL,
102         ENDPT_SOCK_AAL5,
103         NULL,
104         atm_aal5_getname,
105         atm_sock_connected,
106         atm_sock_cleared,
107         atm_aal5_incoming,
108         NULL,
109         NULL,
110         NULL,
111         atm_aal5_cpcs_data,
112         NULL,
113         NULL,
114         NULL,
115         NULL
116 };
117
118 static Atm_attributes   atm_aal5_defattr = {
119         NULL,                   /* nif */
120         CMAPI_CPCS,             /* api */
121         0,                      /* api_init */
122         0,                      /* headin */
123         0,                      /* headout */
124         {                       /* aal */
125                 T_ATM_PRESENT,
126                 ATM_AAL5
127         },
128         {                       /* traffic */
129                 T_ATM_ABSENT,
130         },
131         {                       /* bearer */
132                 T_ATM_ABSENT,
133         },
134         {                       /* bhli */
135                 T_ATM_ABSENT
136         },
137         {                       /* blli */
138                 T_ATM_ABSENT,
139                 T_ATM_ABSENT,
140         },
141         {                       /* llc */
142                 T_ATM_ABSENT,
143         },
144         {                       /* called */
145                 T_ATM_ABSENT,
146                 {
147                         T_ATM_ABSENT,
148                         0
149                 },
150                 {
151                         T_ATM_ABSENT,
152                         0
153                 }
154         },
155         {                       /* calling */
156                 T_ATM_ABSENT
157         },
158         {                       /* qos */
159                 T_ATM_ABSENT,
160         },
161         {                       /* transit */
162                 T_ATM_ABSENT
163         },
164         {                       /* cause */
165                 T_ATM_ABSENT
166         }
167 };
168
169
170 /*
171  * Handy common code macros
172  */
173 #ifdef DIAGNOSTIC
174
175 #define ATM_INTRO(f)                                            \
176     do {                                                        \
177         crit_enter();                                           \
178         ATM_DEBUG2("aal5 socket %s (%p)\n", f, so);             \
179         /*                                                      \
180          * Stack queue should have been drained                 \
181          */                                                     \
182         if (atm_stackq_head != NULL)                            \
183                 panic("atm_aal5: stack queue not empty");       \
184     } while(0)
185
186 #else /* !DIAGNOSTIC */
187
188 #define ATM_INTRO(f)                                            \
189     do {                                                        \
190         crit_enter();                                           \
191     } while(0)
192
193 #endif /* DIAGNOSTIC */
194
195 #define ATM_OUTRO()                                             \
196     out: do {                                                   \
197         /*                                                      \
198          * Drain any deferred calls                             \
199          */                                                     \
200         STACK_DRAIN();                                          \
201         crit_exit();                                            \
202         lwkt_replymsg(&msg->lmsg, error);                       \
203         return;                                                 \
204         goto out;                                               \
205     } while(0)                                                  \
206
207 /*
208  * Abnormally terminate service
209  *
210  * Arguments:
211  *      so      pointer to socket
212  *
213  * Returns:
214  *      0       request processed
215  *      error   error processing request - reason indicated
216  *
217  * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
218  *       will sofree() it when we return.
219  */
220 static void
221 atm_aal5_abort(netmsg_t msg)
222 {
223         struct socket *so = msg->abort.base.nm_so;
224         int error;
225
226         ATM_INTRO("abort");
227         so->so_error = ECONNABORTED;
228         error = atm_sock_detach(so);
229         ATM_OUTRO();
230 }
231
232 /*
233  * Accept pending connection
234  *
235  * Arguments:
236  *      so      pointer to socket
237  *      addr    pointer to pointer to contain protocol address
238  *
239  * Returns:
240  *      0       request processed
241  *      error   error processing request - reason indicated
242  *
243  */
244 static void
245 atm_aal5_accept(netmsg_t msg)
246 {
247         struct socket *so = msg->accept.base.nm_so;
248         int error;
249
250         ATM_INTRO("accept");
251
252         /*
253          * Everything is pretty much done already, we just need to
254          * return the caller's address to the user.
255          */
256         error = atm_sock_peeraddr(so, msg->accept.nm_nam);
257         ATM_OUTRO();
258 }
259
260 /*
261  * Attach protocol to socket
262  *
263  * Arguments:
264  *      so      pointer to socket
265  *      proto   protocol identifier
266  *      p       pointer to process
267  *
268  * Returns:
269  *      0       request processed
270  *      error   error processing request - reason indicated
271  *
272  */
273 static void
274 atm_aal5_attach(netmsg_t msg)
275 {
276         struct socket *so = msg->attach.base.nm_so;
277         struct pru_attach_info *ai = msg->attach.nm_ai;
278         Atm_pcb *atp;
279         int error;
280
281         ATM_INTRO("attach");
282
283         /*
284          * Do general attach stuff
285          */
286         error = atm_sock_attach(so, atm_aal5_sendspace, atm_aal5_recvspace,
287                                 ai->sb_rlimit);
288         if (error)
289                 goto out;
290
291         /*
292          * Finish up any protocol specific stuff
293          */
294         atp = sotoatmpcb(so);
295         atp->atp_type = ATPT_AAL5;
296
297         /*
298          * Set default connection attributes
299          */
300         atp->atp_attr = atm_aal5_defattr;
301         strncpy(atp->atp_name, "(AAL5)", T_ATM_APP_NAME_LEN);
302
303         ATM_OUTRO();
304 }
305
306 /*
307  * Detach protocol from socket
308  *
309  * Arguments:
310  *      so      pointer to socket
311  *
312  * Returns:
313  *      0       request processed
314  *      error   error processing request - reason indicated
315  *
316  */
317 static void
318 atm_aal5_detach(netmsg_t msg)
319 {
320         struct socket *so = msg->detach.base.nm_so;
321         int error;
322
323         ATM_INTRO("detach");
324
325         error = atm_sock_detach(so);
326
327         ATM_OUTRO();
328 }
329
330 /*
331  * Bind address to socket
332  *
333  * Arguments:
334  *      so      pointer to socket
335  *      addr    pointer to protocol address
336  *      p       pointer to process
337  *
338  * Returns:
339  *      0       request processed
340  *      error   error processing request - reason indicated
341  *
342  */
343 static void
344 atm_aal5_bind(netmsg_t msg)
345 {
346         struct socket *so = msg->bind.base.nm_so;
347         int error;
348
349         ATM_INTRO("bind");
350
351         error = atm_sock_bind(so, msg->bind.nm_nam);
352
353         ATM_OUTRO();
354 }
355
356 /*
357  * Listen for incoming connections
358  *
359  * Arguments:
360  *      so      pointer to socket
361  *      p       pointer to process
362  *
363  * Returns:
364  *      0       request processed
365  *      error   error processing request - reason indicated
366  *
367  */
368 static void
369 atm_aal5_listen(netmsg_t msg)
370 {
371         struct socket *so = msg->listen.base.nm_so;
372         int error;
373
374         ATM_INTRO("listen");
375
376         error = atm_sock_listen(so, &atm_aal5_endpt);
377
378         ATM_OUTRO();
379 }
380
381
382 /*
383  * Connect socket to peer
384  *
385  * Arguments:
386  *      so      pointer to socket
387  *      addr    pointer to protocol address
388  *      p       pointer to process
389  *
390  * Returns:
391  *      0       request processed
392  *      error   error processing request - reason indicated
393  *
394  */
395 static void
396 atm_aal5_connect(netmsg_t msg)
397 {
398         struct socket *so = msg->connect.base.nm_so;
399         struct thread *td = msg->connect.nm_td;
400         Atm_pcb *atp;
401         int error;
402
403         ATM_INTRO("connect");
404
405         atp = sotoatmpcb(so);
406
407         /*
408          * Resize send socket buffer to maximum sdu size
409          */
410         if (atp->atp_attr.aal.tag == T_ATM_PRESENT) {
411                 long size;
412
413                 size = atp->atp_attr.aal.v.aal5.forward_max_SDU_size;
414                 if (size != T_ATM_ABSENT) {
415                         if (!ssb_reserve(&so->so_snd, size, so,
416                                        &td->td_proc->p_rlimit[RLIMIT_SBSIZE])) {
417                                 error = ENOBUFS;
418                                 goto out;
419                         }
420                 }
421         }
422
423         /*
424          * Now get the socket connected
425          */
426         error = atm_sock_connect(so, msg->connect.nm_nam, &atm_aal5_endpt);
427
428         ATM_OUTRO();
429 }
430
431 /*
432  * Disconnect connected socket
433  *
434  * Arguments:
435  *      so      pointer to socket
436  *
437  * Returns:
438  *      0       request processed
439  *      error   error processing request - reason indicated
440  *
441  */
442 static void
443 atm_aal5_disconnect(netmsg_t msg)
444 {
445         struct socket *so = msg->disconnect.base.nm_so;
446         int error;
447
448         ATM_INTRO("disconnect");
449
450         error = atm_sock_disconnect(so);
451
452         ATM_OUTRO();
453 }
454
455
456 /*
457  * Shut down socket data transmission
458  *
459  * Arguments:
460  *      so      pointer to socket
461  *
462  * Returns:
463  *      0       request processed
464  *      error   error processing request - reason indicated
465  *
466  */
467 static void
468 atm_aal5_shutdown(netmsg_t msg)
469 {
470         struct socket *so = msg->shutdown.base.nm_so;
471         int error;
472
473         ATM_INTRO("shutdown");
474
475         socantsendmore(so);
476         error = 0;
477
478         ATM_OUTRO();
479 }
480
481
482 /*
483  * Send user data
484  *
485  * Arguments:
486  *      so      pointer to socket
487  *      flags   send data flags
488  *      m       pointer to buffer containing user data
489  *      addr    pointer to protocol address
490  *      control pointer to buffer containing protocol control data
491  *      p       pointer to process
492  *
493  * Returns:
494  *      0       request processed
495  *      error   error processing request - reason indicated
496  *
497  */
498 static void
499 atm_aal5_send(netmsg_t msg)
500 {
501         struct socket *so = msg->send.base.nm_so;
502         KBuffer *m = msg->send.nm_m;
503         KBuffer *control = msg->send.nm_control;
504         Atm_pcb *atp;
505         int error;
506
507         ATM_INTRO("send");
508
509         /*
510          * We don't support any control functions
511          */
512         if (control) {
513                 int clen;
514
515                 clen = KB_LEN(control);
516                 KB_FREEALL(control);
517                 if (clen) {
518                         KB_FREEALL(m);
519                         error = EINVAL;
520                         goto out;
521                 }
522         }
523
524         /*
525          * We also don't support any flags or send-level addressing
526          */
527         if (msg->send.nm_flags || msg->send.nm_addr) {
528                 KB_FREEALL(m);
529                 error = EINVAL;
530                 goto out;
531         }
532
533         /*
534          * All we've got left is the data, so push it out
535          */
536         atp = sotoatmpcb(so);
537         error = atm_cm_cpcs_data(atp->atp_conn, m);
538         if (error) {
539                 /*
540                  * Output problem, drop packet
541                  */
542                 atm_sock_stat.as_outdrop[atp->atp_type]++;
543                 KB_FREEALL(m);
544         }
545
546         ATM_OUTRO();
547 }
548
549
550 /*
551  * Do control operation - ioctl system call
552  *
553  * Arguments:
554  *      so      pointer to socket
555  *      cmd     ioctl code
556  *      data    pointer to code specific parameter data area
557  *      ifp     pointer to ifnet structure if it's an interface ioctl
558  *      p       pointer to process
559  *
560  * Returns:
561  *      0       request processed
562  *      error   error processing request - reason indicated
563  *
564  */
565 static void
566 atm_aal5_control(netmsg_t msg)
567 {
568         struct socket *so = msg->control.base.nm_so;
569         int error;
570
571         ATM_INTRO("control");
572
573         switch (msg->control.nm_cmd) {
574         default:
575                 error = EOPNOTSUPP;
576                 break;
577         }
578
579         ATM_OUTRO();
580 }
581
582 /*
583  * Sense socket status - fstat system call
584  *
585  * Arguments:
586  *      so      pointer to socket
587  *      st      pointer to file status structure
588  *
589  * Returns:
590  *      0       request processed
591  *      error   error processing request - reason indicated
592  *
593  */
594 static void
595 atm_aal5_sense(netmsg_t msg)
596 {
597         struct socket *so = msg->sense.base.nm_so;
598         struct stat *st = msg->sense.nm_stat;
599         int error;
600
601         ATM_INTRO("sense");
602
603         /*
604          * Just return the max sdu size for the connection
605          */
606         st->st_blksize = so->so_snd.ssb_hiwat;
607         error = 0;
608
609         ATM_OUTRO();
610 }
611
612
613 /*
614  * Retrieve local socket address
615  *
616  * Arguments:
617  *      so      pointer to socket
618  *      addr    pointer to pointer to contain protocol address
619  *
620  * Returns:
621  *      0       request processed
622  *      error   error processing request - reason indicated
623  *
624  */
625 static void
626 atm_aal5_sockaddr(netmsg_t msg)
627 {
628         struct socket *so = msg->sockaddr.base.nm_so;
629         int error;
630
631         ATM_INTRO("sockaddr");
632
633         error = atm_sock_sockaddr(so, msg->sockaddr.nm_nam);
634
635         ATM_OUTRO();
636 }
637
638
639 /*
640  * Retrieve peer socket address
641  *
642  * Arguments:
643  *      so      pointer to socket
644  *      addr    pointer to pointer to contain protocol address
645  *
646  * Returns:
647  *      0       request processed
648  *      error   error processing request - reason indicated
649  *
650  */
651 static void
652 atm_aal5_peeraddr(netmsg_t msg)
653 {
654         struct socket *so = msg->peeraddr.base.nm_so;
655         int error;
656
657         ATM_INTRO("peeraddr");
658
659         error = atm_sock_peeraddr(so, msg->peeraddr.nm_nam);
660
661         ATM_OUTRO();
662 }
663
664 /*
665  * Process getsockopt/setsockopt system calls
666  *
667  * Arguments:
668  *      so      pointer to socket
669  *      sopt    pointer to socket option info
670  *
671  * Returns:
672  *      0       request processed
673  *      error   error processing request - reason indicated
674  *
675  */
676 void
677 atm_aal5_ctloutput(netmsg_t msg)
678 {
679         struct socket *so = msg->ctloutput.base.nm_so;
680         struct sockopt *sopt = msg->ctloutput.nm_sopt;
681         Atm_pcb *atp;
682         int error;
683
684         ATM_INTRO("ctloutput");
685
686         /*
687          * Make sure this is for us
688          */
689         if (sopt->sopt_level != T_ATM_SIGNALING) {
690                 error = EINVAL;
691                 goto out;
692         }
693         atp = sotoatmpcb(so);
694         if (atp == NULL) {
695                 error = ENOTCONN;
696                 goto out;
697         }
698
699         switch (sopt->sopt_dir) {
700         case SOPT_SET:
701                 /*
702                  * setsockopt()
703                  */
704
705                 /*
706                  * Validate socket state
707                  */
708                 switch (sopt->sopt_name) {
709                 case T_ATM_ADD_LEAF:
710                 case T_ATM_DROP_LEAF:
711                         if ((so->so_state & SS_ISCONNECTED) == 0) {
712                                 error = ENOTCONN;
713                                 goto out;
714                         }
715                         break;
716                 case T_ATM_CAUSE:
717                 case T_ATM_APP_NAME:
718                         break;
719                 default:
720                         if (so->so_state & SS_ISCONNECTED) {
721                                 error = EISCONN;
722                                 goto out;
723                         }
724                         break;
725                 }
726
727                 /*
728                  * Validate and save user-supplied option data
729                  */
730                 error = atm_sock_setopt(so, sopt, atp);
731                 break;
732         case SOPT_GET:
733                 /*
734                  * getsockopt()
735                  */
736
737                 /*
738                  * Return option data
739                  */
740                 error = atm_sock_getopt(so, sopt, atp);
741                 break;
742         default:
743                 error = EINVAL;
744                 break;
745         }
746
747         ATM_OUTRO();
748 }
749
750 /*
751  * Process Incoming Calls
752  *
753  * This function will receive control when an incoming call has been matched
754  * to one of our registered listen parameter blocks.  Assuming the call passes
755  * acceptance criteria and all required resources are available, we will
756  * create a new protocol control block and socket association.  We must
757  * then await notification of the final SVC setup results.  If any
758  * problems are encountered, we will just tell the connection manager to
759  * reject the call.
760  *
761  * Called from a critical section.
762  *
763  * Arguments:
764  *      tok     owner's matched listening token
765  *      cop     pointer to incoming call's connection block
766  *      ap      pointer to incoming call's attributes
767  *      tokp    pointer to location to store our connection token
768  *
769  * Returns:
770  *      0       call is accepted
771  *      error   call rejected - reason indicated
772  *
773  */
774 static int
775 atm_aal5_incoming(void *tok, Atm_connection *cop, Atm_attributes *ap,
776                   void **tokp)
777 {
778         Atm_pcb         *atp0 = tok, *atp;
779         struct socket   *so;
780         int             err = 0;
781
782         /*
783          * Allocate a new socket and pcb for this connection.
784          *
785          * Note that our attach function will be called via sonewconn
786          * and it will allocate and setup most of the pcb.
787          */
788         atm_sock_stat.as_inconn[atp0->atp_type]++;
789         so = sonewconn(atp0->atp_socket, 0);
790
791         if (so) {
792                 /*
793                  * Finish pcb setup and pass pcb back to CM
794                  */
795                 atp = sotoatmpcb(so);
796                 atp->atp_conn = cop;
797                 atp->atp_attr = *atp0->atp_conn->co_lattr;
798                 strncpy(atp->atp_name, atp0->atp_name, T_ATM_APP_NAME_LEN);
799                 *tokp = atp;
800         } else {
801                 err = ECONNABORTED;
802                 atm_sock_stat.as_connfail[atp0->atp_type]++;
803         }
804
805         return (err);
806 }
807
808
809 /*
810  * Process Socket VCC Input Data
811  *
812  * Arguments:
813  *      tok     owner's connection token (atm_pcb)
814  *      m       pointer to input packet buffer chain
815  *
816  * Returns:
817  *      none
818  *
819  */
820 static void
821 atm_aal5_cpcs_data(void *tok, KBuffer *m)
822 {
823         Atm_pcb         *atp = tok;
824         struct socket   *so;
825         int             len;
826
827         so = atp->atp_socket;
828
829         KB_PLENGET(m, len);
830
831         /*
832          * Ensure that the socket is able to receive data and
833          * that there's room in the socket buffer
834          */
835         if (((so->so_state & SS_ISCONNECTED) == 0) ||
836             (so->so_state & SS_CANTRCVMORE) ||
837             (len > ssb_space(&so->so_rcv))) {
838                 atm_sock_stat.as_indrop[atp->atp_type]++;
839                 KB_FREEALL(m);
840                 return;
841         }
842
843         /*
844          * Queue the data and notify the user
845          */
846         ssb_appendrecord(&so->so_rcv, m);
847         sorwakeup(so);
848
849         return;
850 }
851
852 /*
853  * Initialize AAL5 Sockets
854  *
855  * Arguments:
856  *      none
857  *
858  * Returns:
859  *      none
860  *
861  */
862 void
863 atm_aal5_init(void)
864 {
865         /*
866          * Register our endpoint
867          */
868         if (atm_endpoint_register(&atm_aal5_endpt))
869                 panic("atm_aal5_init: register");
870
871         /*
872          * Set default connection attributes
873          */
874         atm_aal5_defattr.aal.v.aal5.forward_max_SDU_size = T_ATM_ABSENT;
875         atm_aal5_defattr.aal.v.aal5.backward_max_SDU_size = T_ATM_ABSENT;
876         atm_aal5_defattr.aal.v.aal5.SSCS_type = T_ATM_NULL;
877 }
878
879
880 /*
881  * Get Connection's Application/Owner Name
882  *
883  * Arguments:
884  *      tok     owner's connection token (atm_pcb)
885  *
886  * Returns:
887  *      addr    pointer to string containing our name
888  *
889  */
890 static caddr_t
891 atm_aal5_getname(void *tok)
892 {
893         Atm_pcb         *atp = tok;
894
895         return (atp->atp_name);
896 }
897