]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netatm/atm_if.c
This commit was generated by cvs2svn to compensate for changes in r153816,
[FreeBSD/FreeBSD.git] / sys / netatm / atm_if.c
1 /*-
2  * ===================================
3  * HARP  |  Host ATM Research Platform
4  * ===================================
5  *
6  *
7  * This Host ATM Research Platform ("HARP") file (the "Software") is
8  * made available by Network Computing Services, Inc. ("NetworkCS")
9  * "AS IS".  NetworkCS does not provide maintenance, improvements or
10  * support of any kind.
11  *
12  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
13  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
14  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
15  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
16  * In no event shall NetworkCS be responsible for any damages, including
17  * but not limited to consequential damages, arising from or relating to
18  * any use of the Software or related support.
19  *
20  * Copyright 1994-1998 Network Computing Services, Inc.
21  *
22  * Copies of this Software may be made, however, the above copyright
23  * notice must be reproduced on all copies.
24  */
25
26 /*
27  * Core ATM Services
28  * -----------------
29  *
30  * ATM interface management
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/malloc.h>
39 #include <sys/sockio.h>
40 #include <sys/socket.h>
41 #include <sys/socketvar.h>
42 #include <sys/syslog.h>
43 #include <net/if.h>
44 #include <net/if_types.h>
45 #include <net/if_dl.h>
46 #include <net/route.h>
47 #include <net/bpf.h>
48 #include <netinet/in.h>
49 #include <netinet/in_var.h>
50 #include <netatm/port.h>
51 #include <netatm/queue.h>
52 #include <netatm/atm.h>
53 #include <netatm/atm_sys.h>
54 #include <netatm/atm_sap.h>
55 #include <netatm/atm_cm.h>
56 #include <netatm/atm_if.h>
57 #include <netatm/atm_ioctl.h>
58 #include <netatm/atm_sigmgr.h>
59 #include <netatm/atm_stack.h>
60 #include <netatm/atm_pcb.h>
61 #include <netatm/atm_var.h>
62
63 /*
64  * Local functions
65  */
66 static int      atm_physif_ioctl(int, caddr_t, caddr_t);
67 static int      atm_if_ioctl(struct ifnet *, u_long, caddr_t);
68 static int      atm_ifparse(const char *, char *, size_t, int *);
69
70 /*
71  * Local variables
72  */
73 static int      (*atm_ifouttbl[AF_MAX+1])
74                         (struct ifnet *, KBuffer *, struct sockaddr *)
75                                 = {NULL};
76
77
78 /*
79  * Register an ATM physical interface
80  * 
81  * Each ATM device interface must register itself here upon completing
82  * its internal initialization.  This applies to both linked and loaded
83  * device drivers.  The interface must be registered before a signalling
84  * manager can be attached.
85  *
86  * Arguments:
87  *      cup     pointer to interface's common unit structure
88  *      name    pointer to device name string
89  *      sdp     pointer to interface's stack services
90  *
91  * Returns:
92  *      0       registration successful
93  *      errno   registration failed - reason indicated
94  *
95  */
96 int
97 atm_physif_register(cup, name, sdp)
98         Cmn_unit                *cup;
99         const char              *name;
100         struct stack_defn       *sdp;
101 {
102         struct atm_pif  *pip;
103         int             s;
104
105         /*
106          * See if we need to be initialized
107          */
108         if (!atm_init)
109                 atm_initialize();
110
111         /*
112          * Make sure we're not already registered
113          */
114         if (cup->cu_flags & CUF_REGISTER) {
115                 return (EALREADY);
116         }
117
118         s = splnet();
119
120         /*
121          * Make sure an interface is only registered once
122          */
123         for (pip = atm_interface_head; pip != NULL; pip = pip->pif_next) {
124                 if ((cup->cu_unit == pip->pif_unit) && 
125                     (strcmp(name, pip->pif_name) == 0)) {
126                         (void) splx(s);
127                         return (EEXIST);
128                 }
129         }
130
131         /*
132          * Fill in physical interface parameters
133          */
134         pip = &cup->cu_pif;
135         pip->pif_name = name;
136         pip->pif_unit = cup->cu_unit;
137         pip->pif_flags = PIF_UP;
138         pip->pif_services = sdp;
139         pip->pif_ioctl = atm_physif_ioctl;
140
141         /*
142          * Link in the interface and mark us registered
143          */
144         LINK2TAIL(pip, struct atm_pif, atm_interface_head, pif_next);
145         cup->cu_flags |= CUF_REGISTER;
146
147         (void) splx(s);
148         return (0);
149 }
150
151
152 /*
153  * De-register an ATM physical interface
154  * 
155  * Each ATM interface must de-register itself before downing the interface.  
156  * The interface's signalling manager will be detached and any network
157  * interface and VCC control blocks will be freed.  
158  *
159  * Arguments:
160  *      cup     pointer to interface's common unit structure
161  *
162  * Returns:
163  *      0       de-registration successful
164  *      errno   de-registration failed - reason indicated
165  *
166  */
167 int
168 atm_physif_deregister(cup)
169         Cmn_unit        *cup;
170 {
171         struct atm_pif  *pip = (struct atm_pif *)&cup->cu_pif;
172         Cmn_vcc         *cvp;
173         int     err;
174         int     s = splnet();
175
176         /*
177          * Detach and deregister, if needed
178          */
179         if ((cup->cu_flags & CUF_REGISTER)) {
180
181                 /*
182                  * Detach from signalling manager
183                  */
184                 if (pip->pif_sigmgr != NULL) {
185                         err = atm_sigmgr_detach(pip);
186                         if (err && (err != ENOENT)) {
187                                 (void) splx(s);
188                                 return (err);
189                         }
190                 }
191
192                 /*
193                  * Make sure signalling manager is detached
194                  */
195                 if (pip->pif_sigmgr != NULL) {
196                         (void) splx(s);
197                         return (EBUSY);
198                 }
199
200                 /*
201                  * Unlink interface
202                  */
203                 UNLINK(pip, struct atm_pif, atm_interface_head, pif_next);
204
205                 cup->cu_flags &= ~CUF_REGISTER;
206         }
207
208         /*
209          * Free all of our network interfaces
210          */
211         atm_physif_freenifs(pip, cup->cu_nif_zone);
212
213         /*
214          * Free unit's vcc information
215          */
216         cvp = cup->cu_vcc;
217         while (cvp) {
218                 uma_zfree(cup->cu_vcc_zone, cvp);
219                 cvp = cvp->cv_next;
220         }
221         cup->cu_vcc = (Cmn_vcc *)NULL;
222
223         (void) splx(s);
224
225         return (0);
226 }
227
228
229 /*
230  * Free all network interfaces on a physical interface
231  *
232  * Arguments
233  *      pip             pointer to physical interface structure
234  *
235  * Returns
236  *      none
237  *
238  */
239 void
240 atm_physif_freenifs(pip, zone)
241         struct atm_pif  *pip;
242         uma_zone_t      zone;
243 {
244         struct atm_nif  *nip = pip->pif_nif;
245         int     s = splnet();
246
247         while ( nip ) 
248         {
249                 /*
250                  * atm_nif_detach zeros pointers - save so we can
251                  * walk the chain.
252                  */
253                 struct atm_nif  *nipp = nip->nif_pnext;
254
255                 /*
256                  * Clean up network i/f trails
257                  */
258                 atm_nif_detach(nip);
259                 uma_zfree(zone, nip);
260                 nip = nipp;
261         }
262         pip->pif_nif = (struct atm_nif *)NULL;
263
264         (void) splx(s);
265
266         return;
267 }
268
269 /*
270  * Handle physical interface ioctl's
271  *
272  * See <netatm/atm_ioctl.h> for definitions.
273  *
274  * Called at splnet.
275  *
276  * Arguments:
277  *      code                    Ioctl function (sub)code
278  *      data                    Data block. On input contains command,
279  *                                      on output, contains results
280  *      arg                     Optional code specific arguments
281  *
282  * Returns:
283  *      0                       Request processed successfully
284  *      errno                   Request failed - reason code
285  *
286  */
287 static int
288 atm_physif_ioctl(code, data, arg)
289         int     code;
290         caddr_t data;
291         caddr_t arg;
292 {
293         struct atminfreq        *aip = (struct atminfreq *)data;
294         struct atmsetreq        *asr = (struct atmsetreq *)data;
295         struct atm_pif          *pip;
296         struct atm_nif          *nip;
297         struct sigmgr           *smp;
298         struct siginst          *sip;
299         struct ifnet            *ifp;
300         Cmn_unit                *cup;
301         Atm_config              *acp;
302         caddr_t                 buf = aip->air_buf_addr;
303         struct air_phy_stat_rsp *apsp;
304         struct air_int_rsp      apr;
305         struct air_netif_rsp    anr;
306         struct air_cfg_rsp      acr;
307         u_int                   count;
308         size_t                  len;
309         size_t                  buf_len = aip->air_buf_len;
310         int                     err = 0;
311         char                    ifname[2*IFNAMSIZ];
312         struct ifaddr           *ifa;
313         struct in_ifaddr        *ia;
314         struct sockaddr_dl      *sdl;
315  
316
317         switch ( aip->air_opcode ) {
318
319         case AIOCS_INF_INT:
320                 /*
321                  * Get physical interface information
322                  */
323                 aip = (struct atminfreq *)data;
324                 pip = (struct atm_pif *)arg;
325
326                 /*
327                  * Make sure there's room in user buffer
328                  */
329                 if (aip->air_buf_len < sizeof(apr)) {
330                         err = ENOSPC;
331                         break;
332                 }
333
334                 /*
335                  * Fill in info to be returned
336                  */
337                 bzero((caddr_t)&apr, sizeof(apr));
338                 smp = pip->pif_sigmgr;
339                 sip = pip->pif_siginst;
340                 (void) snprintf(apr.anp_intf, sizeof(apr.anp_intf),
341                         "%s%d", pip->pif_name, pip->pif_unit );
342                 if ( pip->pif_nif )
343                 {
344                         strcpy(apr.anp_nif_pref, pip->pif_nif->nif_ifp->if_dname);
345
346                         nip = pip->pif_nif;
347                         while ( nip ) {
348                                 apr.anp_nif_cnt++;
349                                 nip = nip->nif_pnext;
350                         }
351                 }
352                 if (sip) {
353                         ATM_ADDR_COPY(&sip->si_addr, &apr.anp_addr);
354                         ATM_ADDR_COPY(&sip->si_subaddr, &apr.anp_subaddr);
355                         apr.anp_sig_proto = smp->sm_proto;
356                         apr.anp_sig_state = sip->si_state;
357                 }
358
359                 /*
360                  * Copy data to user buffer
361                  */
362                 err = copyout((caddr_t)&apr, aip->air_buf_addr, sizeof(apr));
363                 if (err)
364                         break;
365
366                 /*
367                  * Update buffer pointer/count
368                  */
369                 aip->air_buf_addr += sizeof(apr);
370                 aip->air_buf_len -= sizeof(apr);
371                 break;
372
373         case AIOCS_INF_NIF:
374                 /*
375                  * Get network interface information
376                  */
377                 aip = (struct atminfreq *)data;
378                 nip = (struct atm_nif *)arg;
379                 ifp = nip->nif_ifp;
380                 pip = nip->nif_pif;
381
382                 /*
383                  * Make sure there's room in user buffer
384                  */
385                 if (aip->air_buf_len < sizeof(anr)) {
386                         err = ENOSPC;
387                         break;
388                 }
389
390                 /*
391                  * Fill in info to be returned
392                  */
393                 bzero((caddr_t)&anr, sizeof(anr));
394                 (void) snprintf(anr.anp_intf, sizeof(anr.anp_intf),
395                     "%s%d", ifp->if_dname, ifp->if_dunit);
396                 IFP_TO_IA(ifp, ia);
397                 if (ia) {
398                         anr.anp_proto_addr = *ia->ia_ifa.ifa_addr;
399                 }
400                 (void) snprintf(anr.anp_phy_intf, sizeof(anr.anp_phy_intf),
401                     "%s%d", pip->pif_name, pip->pif_unit);
402
403                 /*
404                  * Copy data to user buffer
405                  */
406                 err = copyout((caddr_t)&anr, aip->air_buf_addr, sizeof(anr));
407                 if (err)
408                         break;
409
410                 /*
411                  * Update buffer pointer/count
412                  */
413                 aip->air_buf_addr += sizeof(anr);
414                 aip->air_buf_len -= sizeof(anr);
415                 break;
416
417         case AIOCS_INF_PIS:
418                 /*
419                  * Get per interface statistics
420                  */
421                 pip = (struct atm_pif *)arg;
422                 if ( pip == NULL )
423                         return ( ENXIO );
424                 snprintf ( ifname, sizeof(ifname),
425                     "%s%d", pip->pif_name, pip->pif_unit );
426
427                 /*
428                  * Cast response into users buffer
429                  */
430                 apsp = (struct air_phy_stat_rsp *)buf;
431
432                 /*
433                  * Sanity check
434                  */
435                 len = sizeof ( struct air_phy_stat_rsp );
436                 if ( buf_len < len )
437                         return ( ENOSPC );
438
439                 /*
440                  * Copy interface name into response
441                  */
442                 if ((err = copyout ( ifname, apsp->app_intf, IFNAMSIZ)) != 0)
443                         break;
444
445                 /*
446                  * Copy counters
447                  */
448                 if ((err = copyout(&pip->pif_ipdus, &apsp->app_ipdus,
449                     len - sizeof(apsp->app_intf))) != 0)
450                         break;
451
452                 /*
453                  * Adjust buffer elements
454                  */
455                 buf += len;
456                 buf_len -= len;
457
458                 aip->air_buf_addr = buf;
459                 aip->air_buf_len = buf_len;
460                 break;
461
462         case AIOCS_SET_NIF:
463                 /*
464                  * Set NIF - allow user to configure 1 or more logical
465                  *      interfaces per physical interface.
466                  */
467
468                 /*
469                  * Get pointer to physical interface structure from
470                  * ioctl argument.
471                  */
472                 pip = (struct atm_pif *)arg;
473                 cup = (Cmn_unit *)pip;
474
475                 /*
476                  * Sanity check - are we already connected to something?
477                  */
478                 if ( pip->pif_sigmgr )
479                 {
480                         err = EBUSY;
481                         break;
482                 }
483
484                 /*
485                  * Free any previously allocated NIFs
486                  */
487                 atm_physif_freenifs(pip, cup->cu_nif_zone);
488
489                 /*
490                  * Add list of interfaces
491                  */
492                 for ( count = 0; count < asr->asr_nif_cnt; count++ )
493                 {
494                         nip = uma_zalloc(cup->cu_nif_zone, M_WAITOK | M_ZERO);
495                         if ( nip == NULL )
496                         {
497                                 /*
498                                  * Destroy any successful nifs
499                                  */
500                                 atm_physif_freenifs(pip, cup->cu_nif_zone);
501                                 err = ENOMEM;
502                                 break;
503                         }
504
505                         nip->nif_pif = pip;
506                         ifp = nip->nif_ifp = if_alloc(IFT_IPOVERATM);
507                         if (ifp == NULL) {
508                                 uma_zfree(cup->cu_nif_zone, nip);
509                                 /*
510                                  * Destroy any successful nifs
511                                  */
512                                 atm_physif_freenifs(pip, cup->cu_nif_zone);
513                                 break;
514                         }
515
516                         strcpy ( nip->nif_name, asr->asr_nif_pref );
517                         nip->nif_sel = count;
518
519                         if_initname(ifp, nip->nif_name, count);
520                         ifp->if_mtu = ATM_NIF_MTU;
521                         ifp->if_flags = IFF_UP | IFF_BROADCAST;
522                         ifp->if_drv_flags = IFF_DRV_RUNNING;
523                         ifp->if_output = atm_ifoutput;
524                         ifp->if_ioctl = atm_if_ioctl;
525                         ifp->if_snd.ifq_maxlen = ifqmaxlen;
526                         switch ( cup->cu_config.ac_media ) {
527                         case MEDIA_TAXI_100:
528                                 ifp->if_baudrate = 100000000;
529                                 break;
530                         case MEDIA_TAXI_140:
531                                 ifp->if_baudrate = 140000000;
532                                 break;
533                         case MEDIA_OC3C:
534                         case MEDIA_OC12C:
535                         case MEDIA_UTP155:
536                                 ifp->if_baudrate = 155000000;
537                                 break;
538                         case MEDIA_UTP25:
539                                 ifp->if_baudrate = 25600000;
540                                 break;
541                         case MEDIA_VIRTUAL:
542                                 ifp->if_baudrate = 100000000;   /* XXX */
543                                 break;
544                         case MEDIA_DSL:
545                                 ifp->if_baudrate = 2500000;     /* XXX */
546                                 break;
547                         case MEDIA_UNKNOWN:
548                                 ifp->if_baudrate = 9600;
549                                 break;
550                         }
551                         if ((err = atm_nif_attach(nip)) != 0) {
552                                 if_free(nip->nif_ifp);
553                                 uma_zfree(cup->cu_nif_zone, nip);
554                                 /*
555                                  * Destroy any successful nifs
556                                  */
557                                 atm_physif_freenifs(pip, cup->cu_nif_zone);
558                                 break;
559                         }
560                         /*
561                          * Set macaddr in <Link> address
562                          */
563                         ifp->if_addrlen = 6;
564                         ifa = ifp->if_addr;
565                         if ( ifa ) {
566                                 sdl = (struct sockaddr_dl *)
567                                         ifa->ifa_addr;
568                                 sdl->sdl_type = IFT_ETHER;
569                                 sdl->sdl_alen = ifp->if_addrlen;
570                                 bcopy ( (caddr_t)&cup->cu_config.ac_macaddr,
571                                         LLADDR(sdl), ifp->if_addrlen );
572                         }
573                 }
574                 break;
575
576         case AIOCS_INF_CFG:
577                 /*
578                  * Get adapter configuration information
579                  */
580                 aip = (struct atminfreq *)data;
581                 pip = (struct atm_pif *)arg;
582                 cup = (Cmn_unit *)pip;
583                 acp = &cup->cu_config;
584
585                 /*
586                  * Make sure there's room in user buffer
587                  */
588                 if (aip->air_buf_len < sizeof(acr)) {
589                         err = ENOSPC;
590                         break;
591                 }
592
593                 /*
594                  * Fill in info to be returned
595                  */
596                 bzero((caddr_t)&acr, sizeof(acr));
597                 (void) snprintf(acr.acp_intf, sizeof(acr.acp_intf),
598                     "%s%d", pip->pif_name, pip->pif_unit);
599                 bcopy((caddr_t)acp, (caddr_t)&acr.acp_cfg,
600                                 sizeof(Atm_config));
601
602                 /*
603                  * Copy data to user buffer
604                  */
605                 err = copyout((caddr_t)&acr, aip->air_buf_addr,
606                                 sizeof(acr));
607                 if (err)
608                         break;
609
610                 /*
611                  * Update buffer pointer/count
612                  */
613                 aip->air_buf_addr += sizeof(acr);
614                 aip->air_buf_len -= sizeof(acr);
615                 break;
616
617         case AIOCS_INF_VST:
618                 /*
619                  * Pass off to device-specific handler
620                  */
621                 cup = (Cmn_unit *)arg;
622                 if (cup == NULL)
623                         err = ENXIO;
624                 else
625                         err = (*cup->cu_ioctl)(code, data, arg);
626                 break;
627
628         default:
629                 err = ENOSYS;
630         }
631
632         return ( err );
633 }
634
635
636 /*
637  * Register a Network Convergence Module
638  * 
639  * Each ATM network convergence module must register itself here before
640  * it will receive network interface status notifications. 
641  *
642  * Arguments:
643  *      ncp     pointer to network convergence definition structure
644  *
645  * Returns:
646  *      0       registration successful
647  *      errno   registration failed - reason indicated
648  *
649  */
650 int
651 atm_netconv_register(ncp)
652         struct atm_ncm  *ncp;
653 {
654         struct atm_ncm  *tdp;
655         int             s = splnet();
656
657         /*
658          * See if we need to be initialized
659          */
660         if (!atm_init)
661                 atm_initialize();
662
663         /*
664          * Validate protocol family
665          */
666         if (ncp->ncm_family > AF_MAX) {
667                 (void) splx(s);
668                 return (EINVAL);
669         }
670
671         /*
672          * Ensure no duplicates
673          */
674         for (tdp = atm_netconv_head; tdp != NULL; tdp = tdp->ncm_next) {
675                 if (tdp->ncm_family == ncp->ncm_family) {
676                         (void) splx(s);
677                         return (EEXIST);
678                 }
679         }
680
681         /*
682          * Add module to list
683          */
684         LINK2TAIL(ncp, struct atm_ncm, atm_netconv_head, ncm_next);
685
686         /*
687          * Add new interface output function
688          */
689         atm_ifouttbl[ncp->ncm_family] = ncp->ncm_ifoutput;
690
691         (void) splx(s);
692         return (0);
693 }
694
695
696 /*
697  * De-register an ATM Network Convergence Module
698  * 
699  * Each ATM network convergence provider must de-register its registered 
700  * service(s) before terminating.  Specifically, loaded kernel modules
701  * must de-register their services before unloading themselves.
702  *
703  * Arguments:
704  *      ncp     pointer to network convergence definition structure
705  *
706  * Returns:
707  *      0       de-registration successful 
708  *      errno   de-registration failed - reason indicated
709  *
710  */
711 int
712 atm_netconv_deregister(ncp)
713         struct atm_ncm  *ncp;
714 {
715         int     found, s = splnet();
716
717         /*
718          * Remove module from list
719          */
720         UNLINKF(ncp, struct atm_ncm, atm_netconv_head, ncm_next, found);
721
722         if (!found) {
723                 (void) splx(s);
724                 return (ENOENT);
725         }
726
727         /*
728          * Remove module's interface output function
729          */
730         atm_ifouttbl[ncp->ncm_family] = NULL;
731
732         (void) splx(s);
733         return (0);
734 }
735
736
737 /*
738  * Attach an ATM Network Interface
739  * 
740  * Before an ATM network interface can be used by the system, the owning
741  * device interface must attach the network interface using this function.
742  * The physical interface for this network interface must have been previously
743  * registered (using atm_interface_register).  The network interface will be
744  * added to the kernel's interface list and to the physical interface's list.
745  * The caller is responsible for initializing the control block fields.
746  *
747  * Arguments:
748  *      nip     pointer to atm network interface control block
749  *
750  * Returns:
751  *      0       attach successful
752  *      errno   attach failed - reason indicated
753  *
754  */
755 int
756 atm_nif_attach(nip)
757         struct atm_nif  *nip;
758 {
759         struct atm_pif  *pip, *pip2;
760         struct ifnet    *ifp;
761         struct atm_ncm  *ncp;
762         int             s;
763
764         ifp = nip->nif_ifp;
765         if (ifp == NULL)
766                 return (ENOSPC);
767         pip = nip->nif_pif;
768
769         s = splimp();
770
771         /*
772          * Verify physical interface is registered
773          */
774         for (pip2 = atm_interface_head; pip2 != NULL; pip2 = pip2->pif_next) {
775                 if (pip == pip2)
776                         break;
777         }
778         if ((pip == NULL) || (pip2 == NULL)) {
779                 (void) splx(s);
780                 return (EFAULT);
781         }
782
783         /*
784          * Add to system interface list 
785          */
786         if_attach(ifp);
787
788         /*
789          * Add to BPF interface list
790          * DLT_ATM_RFC_1483 cannot be used because both NULL and LLC/SNAP could
791          * be provisioned
792          */
793         bpfattach(ifp, DLT_ATM_CLIP, T_ATM_LLC_MAX_LEN);
794
795         /*
796          * Add to physical interface list
797          */
798         LINK2TAIL(nip, struct atm_nif, pip->pif_nif, nif_pnext);
799
800         /*
801          * Notify network convergence modules of new network i/f
802          */
803         for (ncp = atm_netconv_head; ncp; ncp = ncp->ncm_next) {
804                 int     err;
805
806                 err = (*ncp->ncm_stat)(NCM_ATTACH, nip, 0);
807                 if (err) {
808                         atm_nif_detach(nip);
809                         (void) splx(s);
810                         return (err);
811                 }
812         }
813
814         (void) splx(s);
815         return (0);
816 }
817
818
819 /*
820  * Detach an ATM Network Interface
821  * 
822  * Before an ATM network interface control block can be freed, all kernel
823  * references to/from this block must be released.  This function will delete
824  * all routing references to the interface and free all interface addresses
825  * for the interface.  The network interface will then be removed from the
826  * kernel's interface list and from the owning physical interface's list.
827  * The caller is responsible for free'ing the control block.
828  *
829  * Arguments:
830  *      nip     pointer to atm network interface control block
831  *
832  * Returns:
833  *      none
834  *
835  */
836 void
837 atm_nif_detach(nip)
838         struct atm_nif  *nip;
839 {
840         struct atm_ncm  *ncp;
841         int             s;
842         struct ifnet    *ifp = nip->nif_ifp;
843
844         s = splimp();
845
846         /*
847          * Notify convergence modules of network i/f demise
848          */
849         for (ncp = atm_netconv_head; ncp; ncp = ncp->ncm_next) {
850                 (void) (*ncp->ncm_stat)(NCM_DETACH, nip, 0);
851         }
852
853         /*
854          * Remove from BPF interface list
855          */
856         bpfdetach(ifp);
857
858         /*
859          * Free all interface routes and addresses,
860          * delete all remaining routes using this interface,
861          * then remove from the system interface list
862          */
863         if_detach(ifp);
864         if_free(ifp);
865
866         /*
867          * Remove from physical interface list
868          */
869         UNLINK(nip, struct atm_nif, nip->nif_pif->pif_nif, nif_pnext);
870
871         (void) splx(s);
872 }
873
874 /*
875  * Set an ATM Network Interface address
876  * 
877  * This is called from a device interface when processing an SIOCSIFADDR
878  * ioctl request.  We just notify all convergence modules of the new address
879  * and hope everyone has non-overlapping interests, since if someone reports
880  * an error we don't go back and tell everyone to undo the change.
881  *
882  * Arguments:
883  *      nip     pointer to atm network interface control block
884  *      ifa     pointer to new interface address
885  *
886  * Returns:
887  *      0       set successful
888  *      errno   set failed - reason indicated
889  *
890  */
891 int
892 atm_nif_setaddr(nip, ifa)
893         struct atm_nif  *nip;
894         struct ifaddr   *ifa;
895 {
896         struct atm_ncm  *ncp;
897         int     err = 0, s = splnet();
898
899         /*
900          * Notify convergence modules of network i/f change
901          */
902         for (ncp = atm_netconv_head; ncp; ncp = ncp->ncm_next) {
903                 err = (*ncp->ncm_stat)(NCM_SETADDR, nip, (intptr_t)ifa);
904                 if (err)
905                         break;
906         }
907         (void) splx(s);
908
909         return (err);
910 }
911
912
913 /*
914  * ATM Interface Packet Output
915  * 
916  * All ATM network interfaces must have their ifnet if_output address set to
917  * this function.  Since no existing network layer code is to be modified 
918  * for ATM support, this function serves as the hook to allow network output
919  * packets to be assigned to their proper outbound VCC.  Each network address
920  * family which is to be supported over ATM must be assigned an output
921  * packet processing function via atm_netconv_register().
922  *
923  * Arguments:
924  *      ifp     pointer to ifnet structure
925  *      m       pointer to packet buffer chain to be output
926  *      dst     pointer to packet's network destination address
927  *
928  * Returns:
929  *      0       packet queued to interface
930  *      errno   output failed - reason indicated
931  *
932  */
933 int
934 atm_ifoutput(ifp, m, dst, rt)
935         struct ifnet    *ifp;
936         KBuffer         *m;
937         struct sockaddr *dst;
938         struct rtentry  *rt;
939 {
940         u_short         fam = dst->sa_family;
941         int             (*func)(struct ifnet *, KBuffer *,
942                                         struct sockaddr *);
943
944         /*
945          * Validate address family
946          */
947         if (fam > AF_MAX) {
948                 KB_FREEALL(m);
949                 return (EAFNOSUPPORT);
950         }
951
952         /*
953          * Hand packet off for dst-to-VCC mapping
954          */
955         func = atm_ifouttbl[fam];
956         if (func == NULL) {
957                 KB_FREEALL(m);
958                 return (EAFNOSUPPORT);
959         }
960         return ((*func)(ifp, m, dst));
961 }
962
963
964 /*
965  * Handle interface ioctl requests. 
966  *
967  * Arguments:
968  *      ifp             pointer to network interface structure
969  *      cmd             IOCTL cmd
970  *      data            arguments to/from ioctl
971  *
972  * Returns:
973  *      error           errno value
974  */
975 static int
976 atm_if_ioctl(ifp, cmd, data)
977         struct ifnet *ifp;
978         u_long  cmd;
979         caddr_t data;
980 {
981         register struct ifreq *ifr = (struct ifreq *)data;
982         struct atm_nif  *nip = IFP2ANIF(ifp);
983         int     error = 0;
984         int     s = splnet();
985
986         switch ( cmd )
987         {
988         case SIOCGIFADDR:
989                 bcopy ( (caddr_t)&(nip->nif_pif->pif_macaddr),
990                         (caddr_t)ifr->ifr_addr.sa_data, 
991                         sizeof(struct mac_addr) );
992                 break;
993
994         case SIOCSIFADDR:
995                 error = atm_nif_setaddr ( nip, (struct ifaddr *)data);
996                 ifp->if_flags |= IFF_UP | IFF_BROADCAST;
997                 ifp->if_drv_flags |= IFF_DRV_RUNNING;
998                 break;
999
1000         case SIOCGIFFLAGS:
1001                 *(int *)data = ifp->if_flags;
1002                 break;
1003
1004         case SIOCSIFFLAGS:
1005                 break;
1006
1007         default:
1008                 error = EINVAL;
1009                 break;
1010         }
1011
1012         (void) splx(s);
1013         return ( error );
1014 }
1015
1016
1017 /*
1018  * Parse interface name
1019  * 
1020  * Parses an interface name string into a name and a unit component.
1021  *
1022  * Arguments:
1023  *      name    pointer to interface name string
1024  *      namep   address to store interface name
1025  *      size    size available at namep
1026  *      unitp   address to store interface unit number
1027  *
1028  * Returns:
1029  *      0       name parsed
1030  *      else    parse error
1031  *
1032  */
1033 static int
1034 atm_ifparse(const char *name, char *namep, size_t size, int *unitp)
1035 {
1036         const char *cp;
1037         char *np;
1038         size_t len = 0;
1039         int unit = 0;
1040
1041         /*
1042          * Separate supplied string into name and unit parts.
1043          */
1044         cp = name;
1045         np = namep;
1046         while (*cp) {
1047                 if (*cp >= '0' && *cp <= '9')
1048                         break;
1049                 if (++len >= size)
1050                         return (-1);
1051                 *np++ = *cp++;
1052         }
1053         *np = '\0';
1054         while (*cp && *cp >= '0' && *cp <= '9')
1055                 unit = 10 * unit + *cp++ - '0';
1056
1057         *unitp = unit;
1058
1059         return (0);
1060 }
1061
1062
1063 /*
1064  * Locate ATM physical interface via name
1065  * 
1066  * Uses the supplied interface name string to locate a registered
1067  * ATM physical interface.
1068  *
1069  * Arguments:
1070  *      name    pointer to interface name string
1071  *
1072  * Returns:
1073  *      0       interface not found
1074  *      else    pointer to atm physical interface structure
1075  *
1076  */
1077 struct atm_pif *
1078 atm_pifname(name)
1079         char            *name;
1080 {
1081         struct atm_pif  *pip;
1082         char            n[IFNAMSIZ];
1083         int             unit;
1084
1085         /*
1086          * Break down name
1087          */
1088         if (atm_ifparse(name, n, sizeof(n), &unit))
1089                 return ((struct atm_pif *)0);
1090
1091         /*
1092          * Look for the physical interface
1093          */
1094         for (pip = atm_interface_head; pip; pip = pip->pif_next) {
1095                 if ((pip->pif_unit == unit) && (strcmp(pip->pif_name, n) == 0))
1096                         break;
1097         }
1098
1099         return (pip);
1100 }
1101
1102
1103 /*
1104  * Locate ATM network interface via name
1105  * 
1106  * Uses the supplied interface name string to locate an ATM network interface.
1107  *
1108  * Arguments:
1109  *      name    pointer to interface name string
1110  *
1111  * Returns:
1112  *      0       interface not found
1113  *      else    pointer to atm network interface structure
1114  *
1115  */
1116 struct atm_nif *
1117 atm_nifname(name)
1118         char            *name;
1119 {
1120         struct atm_pif  *pip;
1121         struct atm_nif  *nip;
1122         char            n[IFNAMSIZ];
1123         int             unit;
1124
1125         /*
1126          * Break down name
1127          */
1128         if (atm_ifparse(name, n, sizeof(n), &unit))
1129                 return ((struct atm_nif *)0);
1130
1131         /*
1132          * Search thru each physical interface
1133          */
1134         for (pip = atm_interface_head; pip; pip = pip->pif_next) {
1135                 /*
1136                  * Looking for network interface
1137                  */
1138                 for (nip = pip->pif_nif; nip; nip = nip->nif_pnext) {
1139                         struct ifnet    *ifp = (struct ifnet *)nip;
1140                         if ((ifp->if_dunit == unit) && 
1141                             (strcmp(ifp->if_dname, n) == 0))
1142                                 return (nip);
1143                 }
1144         }
1145         return (NULL);
1146 }