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