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