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