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