network - Major netmsg retooling, part 1
[dragonfly.git] / sys / netproto / atm / atm_usrreq.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_usrreq.c,v 1.6 1999/08/28 00:48:39 peter Exp $
27  *      @(#) $DragonFly: src/sys/netproto/atm/atm_usrreq.c,v 1.13 2007/04/21 02:26:48 dillon Exp $
28  */
29
30 /*
31  * Core ATM Services
32  * -----------------
33  *
34  * ATM DGRAM socket protocol processing
35  *
36  */
37
38 #include "kern_include.h"
39
40 /*
41  * Local functions
42  */
43 static void     atm_dgram_attach(netmsg_t msg);
44 static void     atm_dgram_control(netmsg_t msg);
45 static int      atm_dgram_info (caddr_t);
46
47 /*
48  * New-style socket request routines
49  */
50 struct pr_usrreqs       atm_dgram_usrreqs = {
51         .pru_abort = pr_generic_notsupp,
52         .pru_accept = pr_generic_notsupp,
53         .pru_attach = atm_dgram_attach,
54         .pru_bind = pr_generic_notsupp,
55         .pru_connect = pr_generic_notsupp,
56         .pru_connect2 = pr_generic_notsupp,
57         .pru_control = atm_dgram_control,
58         .pru_detach = pr_generic_notsupp,
59         .pru_disconnect = pr_generic_notsupp,
60         .pru_listen = pr_generic_notsupp,
61         .pru_peeraddr = pr_generic_notsupp,
62         .pru_rcvd = pr_generic_notsupp,
63         .pru_rcvoob = pr_generic_notsupp,
64         .pru_send = pr_generic_notsupp,
65         .pru_sense = pru_sense_null,
66         .pru_shutdown = pr_generic_notsupp,
67         .pru_sockaddr = pr_generic_notsupp,
68         .pru_sosend = sosend,
69         .pru_soreceive = soreceive
70 };
71
72 /*
73  * Handy common code macros
74  */
75 #ifdef DIAGNOSTIC
76
77 #define ATM_INTRO()                                             \
78     do {                                                        \
79         crit_enter();                                           \
80         /*                                                      \
81          * Stack queue should have been drained                 \
82          */                                                     \
83         if (atm_stackq_head != NULL)                            \
84                 panic("atm_usrreq: stack queue not empty");     \
85     } while(0)
86
87 #else
88
89 #define ATM_INTRO()                                             \
90     do {                                                        \
91         crit_enter();                                           \
92     } while(0)
93
94 #endif
95
96 #define ATM_OUTRO()                                             \
97     out: do {                                                   \
98         /*                                                      \
99          * Drain any deferred calls                             \
100          */                                                     \
101         STACK_DRAIN();                                          \
102         crit_exit();                                            \
103         lwkt_replymsg(&msg->lmsg, error);                       \
104         return;                                                 \
105         goto out;                                               \
106     } while(0)
107
108 /*
109  * Attach protocol to socket
110  *
111  * Arguments:
112  *      so      pointer to socket
113  *      proto   protocol identifier
114  *      p       pointer to process
115  *
116  * Returns:
117  *      0       request processed
118  *      errno   error processing request - reason indicated
119  *
120  */
121 static void
122 atm_dgram_attach(netmsg_t msg)
123 {
124         int error;
125
126         ATM_INTRO();
127
128         /*
129          * Nothing to do here for ioctl()-only sockets
130          */
131         error = 0;
132
133         ATM_OUTRO();
134 }
135
136
137 /*
138  * Process ioctl system calls
139  *
140  * Arguments:
141  *      so      pointer to socket
142  *      cmd     ioctl code
143  *      data    pointer to code specific parameter data area
144  *      ifp     pointer to ifnet structure if it's an interface ioctl
145  *      p       pointer to process
146  *
147  * Returns:
148  *      0       request processed
149  *      errno   error processing request - reason indicated
150  *
151  */
152 static void
153 atm_dgram_control(netmsg_t msg)
154 {
155         u_long cmd = msg->control.nm_cmd;
156         caddr_t data = msg->control.nm_data;
157         struct thread *td = msg->control.nm_td;
158         int error;
159
160         error = 0;
161         ATM_INTRO();
162
163         /*
164          * First, figure out which ioctl we're dealing with and
165          * then process it based on the sub-op code
166          */
167         switch (cmd) {
168         case AIOCCFG: {
169                 struct atmcfgreq        *acp = (struct atmcfgreq *)data;
170                 struct atm_pif          *pip;
171
172                 if (priv_check(td, PRIV_ROOT)) {
173                         error = EPERM;
174                         goto out;
175                 }
176
177                 switch (acp->acr_opcode) {
178
179                 case AIOCS_CFG_ATT:
180                         /*
181                          * Attach signalling manager
182                          */
183                         if ((pip = atm_pifname(acp->acr_att_intf)) == NULL) {
184                                 error = ENXIO;
185                                 goto out;
186                         }
187                         error = atm_sigmgr_attach(pip, acp->acr_att_proto);
188                         break;
189
190                 case AIOCS_CFG_DET:
191                         /*
192                          * Detach signalling manager
193                          */
194                         if ((pip = atm_pifname(acp->acr_det_intf)) == NULL) {
195                                 error = ENXIO;
196                                 goto out;
197                         }
198                         error = atm_sigmgr_detach(pip);
199                         break;
200
201                 default:
202                         error = EOPNOTSUPP;
203                         break;
204                 }
205                 break;
206         }
207
208         case AIOCADD: {
209                 struct atmaddreq        *aap = (struct atmaddreq *)data;
210                 Atm_endpoint            *epp;
211
212                 if (priv_check(td, PRIV_ROOT)) {
213                         error = EPERM;
214                         goto out;
215                 }
216
217                 switch (aap->aar_opcode) {
218
219                 case AIOCS_ADD_PVC:
220                         /*
221                          * Add a PVC definition
222                          */
223
224                         /*
225                          * Locate requested endpoint service
226                          */
227                         epp = aap->aar_pvc_sap > ENDPT_MAX ? NULL : 
228                                         atm_endpoints[aap->aar_pvc_sap];
229                         if (epp == NULL) {
230                                 error = ENOPROTOOPT;
231                                 goto out;
232                         }
233
234                         /*
235                          * Let endpoint service handle it from here
236                          */
237                         error = (*epp->ep_ioctl)(AIOCS_ADD_PVC, data, NULL);
238                         break;
239
240                 case AIOCS_ADD_ARP:
241                         /*
242                          * Add an ARP mapping
243                          */
244                         epp = atm_endpoints[ENDPT_IP];
245                         if (epp == NULL) {
246                                 error = ENOPROTOOPT;
247                                 goto out;
248                         }
249
250                         /*
251                          * Let IP/ATM endpoint handle this
252                          */
253                         error = (*epp->ep_ioctl) (AIOCS_ADD_ARP, data, NULL);
254                         break;
255
256                 default:
257                         error = EOPNOTSUPP;
258                 }
259                 break;
260         }
261
262         case AIOCDEL: {
263                 struct atmdelreq        *adp = (struct atmdelreq *)data;
264                 struct atm_pif          *pip;
265                 struct sigmgr           *smp;
266                 Atm_endpoint            *epp;
267
268                 if (priv_check(td, PRIV_ROOT)) {
269                         error = EPERM;
270                         goto out;
271                 }
272
273                 switch (adp->adr_opcode) {
274
275                 case AIOCS_DEL_PVC:
276                 case AIOCS_DEL_SVC:
277                         /*
278                          * Delete a PVC or SVC
279                          */
280
281                         /*
282                          * Locate appropriate sigmgr
283                          */
284                         if ((pip = atm_pifname(adp->adr_pvc_intf)) == NULL) {
285                                 error = ENXIO;
286                                 goto out;
287                         }
288                         if ((smp = pip->pif_sigmgr) == NULL) {
289                                 error = ENOENT;
290                                 goto out;
291                         }
292
293                         /*
294                          * Let sigmgr handle it from here
295                          */
296                         error = (*smp->sm_ioctl)(adp->adr_opcode, data,
297                                         (caddr_t)pip->pif_siginst);
298                         break;
299
300                 case AIOCS_DEL_ARP:
301                         /*
302                          * Delete an ARP mapping
303                          */
304                         epp = atm_endpoints[ENDPT_IP];
305                         if (epp == NULL) {
306                                 error = ENOPROTOOPT;
307                                 goto out;
308                         }
309
310                         /*
311                          * Let IP/ATM endpoint handle this
312                          */
313                         error = (*epp->ep_ioctl) (AIOCS_DEL_ARP, data, NULL);
314                         break;
315
316                 default:
317                         error = EOPNOTSUPP;
318                 }
319                 break;
320         }
321
322         case AIOCSET: {
323                 struct atmsetreq        *asp = (struct atmsetreq *)data;
324                 struct atm_pif          *pip;
325                 struct atm_nif          *nip;
326                 struct sigmgr           *smp;
327                 struct ifnet            *ifp2;
328
329                 if (priv_check(td, PRIV_ROOT)) {
330                         error = EPERM;
331                         goto out;
332                 }
333
334                 switch (asp->asr_opcode) {
335
336                 case AIOCS_SET_ASV:
337                         /*
338                          * Set an ARP server address
339                          */
340
341                         /*
342                          * Locate appropriate sigmgr
343                          */
344                         if ((nip = atm_nifname(asp->asr_arp_intf)) == NULL) {
345                                 error = ENXIO;
346                                 goto out;
347                         }
348                         pip = nip->nif_pif;
349                         if ((smp = pip->pif_sigmgr) == NULL) {
350                                 error = ENOENT;
351                                 goto out;
352                         }
353
354                         /*
355                          * Let sigmgr handle it from here
356                          */
357                         error = (*smp->sm_ioctl)(AIOCS_SET_ASV, data,
358                                         (caddr_t)nip);
359                         break;
360
361                 case AIOCS_SET_MAC:
362                         /*
363                          * Set physical interface MAC/ESI address
364                          */
365
366                         /*
367                          * Locate physical interface
368                          */
369                         if ((pip = atm_pifname(asp->asr_mac_intf)) == NULL) {
370                                 error = ENXIO;
371                                 goto out;
372                         }
373
374                         /*
375                          * Interface must be detached
376                          */
377                         if (pip->pif_sigmgr != NULL) {
378                                 error = EADDRINUSE;
379                                 goto out;
380                         }
381
382                         /*
383                          * Just plunk the address into the pif
384                          */
385                         KM_COPY((caddr_t)&asp->asr_mac_addr,
386                                 (caddr_t)&pip->pif_macaddr,
387                                 sizeof(struct mac_addr));
388                         break;
389
390                 case AIOCS_SET_NIF:
391                         /*
392                          * Define network interfaces
393                          */
394                         if ((pip = atm_pifname(asp->asr_nif_intf)) == NULL) {
395                                 error = ENXIO;
396                                 goto out;
397                         }
398
399                         /*
400                          * Validate interface count - logical interfaces
401                          * are differentiated by the atm address selector.
402                          */
403                         if ((asp->asr_nif_cnt <= 0) ||
404                             (asp->asr_nif_cnt > 256)) {
405                                 error = EINVAL;
406                                 goto out;
407                         }
408
409                         /*
410                          * Make sure prefix name is unique
411                          */
412                         TAILQ_FOREACH(ifp2, &ifnet, if_link) {
413                                 if (!strcmp(ifp2->if_dname, asp->asr_nif_pref)) {
414                                         /*
415                                          * If this is for the interface we're
416                                          * (re-)defining, let it through
417                                          */
418                                         for (nip = pip->pif_nif; nip;
419                                                         nip = nip->nif_pnext) {
420                                                 if (&nip->nif_if == ifp2)
421                                                         break;
422                                         }
423                                         if (nip)
424                                                 continue;
425                                         error = EEXIST;
426                                         goto out;
427                                 }
428                         }
429
430                         /*
431                          * Let interface handle it from here
432                          */
433                         error = (*pip->pif_ioctl)(AIOCS_SET_NIF, data,
434                                                   (caddr_t)pip);
435                         break;
436
437                 case AIOCS_SET_PRF:
438                         /*
439                          * Set interface NSAP Prefix 
440                          */
441
442                         /*
443                          * Locate appropriate sigmgr
444                          */
445                         if ((pip = atm_pifname(asp->asr_prf_intf)) == NULL) {
446                                 error = ENXIO;
447                                 goto out;
448                         }
449                         if ((smp = pip->pif_sigmgr) == NULL) {
450                                 error = ENOENT;
451                                 goto out;
452                         }
453
454                         /*
455                          * Let sigmgr handle it from here
456                          */
457                         error = (*smp->sm_ioctl)(AIOCS_SET_PRF, data,
458                                         (caddr_t)pip->pif_siginst);
459                         break;
460
461                 default:
462                         error = EOPNOTSUPP;
463                         break;
464                 }
465                 break;
466         }
467
468         case AIOCINFO:
469                 error = atm_dgram_info(data);
470                 break;
471
472         default:
473                 error = EOPNOTSUPP;
474         }
475
476         ATM_OUTRO();
477 }
478
479
480 /*
481  * Process AIOCINFO ioctl system calls
482  *
483  * Called from a critical section.
484  *
485  * Arguments:
486  *      data    pointer to AIOCINFO parameter structure
487  *
488  * Returns:
489  *      0       request processed
490  *      errno   error processing request - reason indicated
491  *
492  */
493 static int
494 atm_dgram_info(caddr_t data)
495 {
496         struct atminfreq        *aip = (struct atminfreq *)data;
497         struct atm_pif          *pip;
498         struct atm_nif          *nip;
499         struct sigmgr           *smp;
500         Atm_endpoint            *epp;
501         int             len = aip->air_buf_len;
502         int             err = 0;
503
504         switch (aip->air_opcode) {
505
506         case AIOCS_INF_VST:
507         case AIOCS_INF_CFG:
508                 /*
509                  * Get vendor interface information
510                  */
511                 if (aip->air_vinfo_intf[0] != '\0') {
512                         /*
513                          * Interface specified
514                          */
515                         if ((pip = atm_pifname(aip->air_vinfo_intf))) {
516                                 err = (*pip->pif_ioctl)(aip->air_opcode, data,
517                                                 (caddr_t)pip);
518                         } else {
519                                 err = ENXIO;
520                         }
521                 } else {
522                         /*
523                          * Want info for every interface
524                          */
525                         for (pip = atm_interface_head; pip; 
526                                         pip = pip->pif_next) {
527                                 err = (*pip->pif_ioctl)(aip->air_opcode, data,
528                                                 (caddr_t)pip);
529                                 if (err)
530                                         break;
531                         }
532                 }
533                 break;
534
535         case AIOCS_INF_IPM:
536                 /*
537                  * Get IP Map information
538                  */
539                 epp = atm_endpoints[ENDPT_IP];
540                 if (epp) {
541                         err = (*epp->ep_ioctl) (AIOCS_INF_IPM, data, NULL);
542                 } else {
543                         err = ENOPROTOOPT;
544                 }
545                 break;
546
547         case AIOCS_INF_ARP:
548                 /*
549                  * Get ARP table information
550                  */
551                 for (pip = atm_interface_head; pip; pip = pip->pif_next) {
552                         if ((smp = pip->pif_sigmgr) != NULL) {
553                                 err = (*smp->sm_ioctl)(AIOCS_INF_ARP,
554                                         data, (caddr_t)pip->pif_siginst);
555                         }
556                         if (err)
557                                 break;
558                 }
559                 break;
560
561         case AIOCS_INF_ASV:
562                 /*
563                  * Get ARP server information
564                  */
565                 if (aip->air_asrv_intf[0] != '\0') {
566                         /*
567                          * Interface specified
568                          */
569                         if ((nip = atm_nifname(aip->air_asrv_intf))) {
570                                 if ((smp = nip->nif_pif->pif_sigmgr) != NULL) {
571                                         err = (*smp->sm_ioctl)(AIOCS_INF_ASV,
572                                                 data, (caddr_t)nip);
573                                 }
574                         } else {
575                                 err = ENXIO;
576                         }
577                 } else {
578                         /*
579                          * Want info for all arp servers
580                          */
581                         for (pip = atm_interface_head; pip;
582                                         pip = pip->pif_next) {
583                                 if ((smp = pip->pif_sigmgr) != NULL) {
584                                         for (nip = pip->pif_nif; nip; 
585                                                         nip = nip->nif_pnext) {
586                                                 err = (*smp->sm_ioctl)
587                                                         (AIOCS_INF_ASV, data,
588                                                         (caddr_t)nip);
589                                                 if (err)
590                                                         break;
591                                         }
592                                         if (err)
593                                                 break;
594                                 }
595                         }
596                 }
597                 break;
598
599         case AIOCS_INF_INT:
600                 /*
601                  * Get physical interface info
602                  */
603                 if (aip->air_int_intf[0] != '\0') {
604                         /*
605                          * Interface specified
606                          */
607                         if ((pip = atm_pifname(aip->air_int_intf))) {
608                                 err = (*pip->pif_ioctl)(AIOCS_INF_INT,
609                                         data, (caddr_t)pip);
610                         } else {
611                                 err = ENXIO;
612                         }
613                 } else {
614                         /*
615                          * Want info for every physical interface
616                          */
617                         for (pip = atm_interface_head; pip; 
618                                         pip = pip->pif_next) {
619                                 err = (*pip->pif_ioctl)(AIOCS_INF_INT,
620                                                 data, (caddr_t)pip);
621                                 if (err)
622                                         break;
623                         }
624                 }
625                 break;
626
627         case AIOCS_INF_VCC:
628                 /*
629                  * Get VCC information
630                  */
631                 if (aip->air_vcc_intf[0] != '\0') {
632                         /*
633                          * Interface specified
634                          */
635                         if ((pip = atm_pifname(aip->air_vcc_intf))) {
636                                 if ((smp = pip->pif_sigmgr) != NULL) {
637                                         err = (*smp->sm_ioctl)(AIOCS_INF_VCC,
638                                                 data,
639                                                 (caddr_t)pip->pif_siginst);
640                                 } 
641                         } else {
642                                 err = ENXIO;
643                         }
644                 } else {
645                         /*
646                          * Want info for every interface
647                          */
648                         for (pip = atm_interface_head; pip; 
649                                         pip = pip->pif_next) {
650                                 if ((smp = pip->pif_sigmgr) != NULL) {
651                                         err = (*smp->sm_ioctl)(AIOCS_INF_VCC,
652                                                 data,
653                                                 (caddr_t)pip->pif_siginst);
654                                 }
655                                 if (err)
656                                         break;
657                         }
658                 }
659                 break;
660
661         case AIOCS_INF_NIF:
662                 /*
663                  * Get network interface info
664                  */
665                 if (aip->air_int_intf[0] != '\0') {
666                         /*
667                          * Interface specified
668                          */
669                         if ((nip = atm_nifname(aip->air_int_intf))) {
670                                 pip = nip->nif_pif;
671                                 err = (*pip->pif_ioctl)(AIOCS_INF_NIF,
672                                         data, (caddr_t)nip);
673                         } else {
674                                 err = ENXIO;
675                         }
676                 } else {
677                         /*
678                          * Want info for every network interface
679                          */
680                         for (pip = atm_interface_head; pip; 
681                                         pip = pip->pif_next) {
682                                 for (nip = pip->pif_nif; nip; 
683                                                 nip = nip->nif_pnext) {
684                                         err = (*pip->pif_ioctl)(AIOCS_INF_NIF,
685                                                         data, (caddr_t)nip);
686                                         if (err)
687                                                 break;
688                                 }
689                                 if (err)
690                                         break;
691                         }
692                 }
693                 break;
694
695         case AIOCS_INF_PIS:
696                 /*
697                  * Get physical interface statistics
698                  */
699                 if (aip->air_physt_intf[0] != '\0') {
700                         /*
701                          * Interface specified
702                          */
703                         if ((pip = atm_pifname(aip->air_physt_intf))) {
704                                 err = (*pip->pif_ioctl)(AIOCS_INF_PIS,
705                                         data, (caddr_t)pip);
706                         } else {
707                                 err = ENXIO;
708                         }
709                 } else {
710                         /*
711                          * Want statistics for every physical interface
712                          */
713                         for (pip = atm_interface_head; pip; 
714                                         pip = pip->pif_next) {
715                                 err = (*pip->pif_ioctl)(AIOCS_INF_PIS,
716                                                 data, (caddr_t)pip);
717                                 if (err)
718                                         break;
719                         }
720                 }
721                 break;
722
723         case AIOCS_INF_VER:
724                 /*
725                  * Get ATM software version
726                  */
727                 if (len < sizeof(atm_version)) {
728                         err = ENOSPC;
729                         break;
730                 }
731                 if ((err = copyout((caddr_t)&atm_version,
732                                 aip->air_buf_addr,
733                                 sizeof(atm_version))) != 0) {
734                         break;
735                 }
736                 aip->air_buf_addr += sizeof(atm_version);
737                 aip->air_buf_len -= sizeof(atm_version);
738                 break;
739
740         default:
741                 err = EOPNOTSUPP;
742         }
743
744         /*
745          * Calculate returned buffer length
746          */
747         aip->air_buf_len = len - aip->air_buf_len;
748
749         return (err);
750 }
751