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