Register keyword removal
[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.3 2003/07/23 02:30:21 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                         default:
520                                 panic("AIOCF_SETNIF: unknown media");
521                         }
522 #endif
523
524                         if ((err = atm_nif_attach(nip)) != 0) {
525                                 atm_free ( (caddr_t)nip );
526
527                                 /*
528                                  * Destroy any successful nifs
529                                  */
530                                 atm_physif_freenifs(pip);
531                                 break;
532                         }
533 #if (defined(BSD) && (BSD >= 199103))
534                         /*
535                          * Set macaddr in <Link> address
536                          */
537                         ifp->if_addrlen = 6;
538                         ifa = ifnet_addrs[ifp->if_index - 1];
539                         if ( ifa ) {
540                                 sdl = (struct sockaddr_dl *)
541                                         ifa->ifa_addr;
542                                 sdl->sdl_type = IFT_ETHER;
543                                 sdl->sdl_alen = ifp->if_addrlen;
544                                 bcopy ( (caddr_t)&cup->cu_config.ac_macaddr,
545                                         LLADDR(sdl), ifp->if_addrlen );
546                         }
547 #endif
548                 }
549                 break;
550
551         case AIOCS_INF_CFG:
552                 /*
553                  * Get adapter configuration information
554                  */
555                 aip = (struct atminfreq *)data;
556                 pip = (struct atm_pif *)arg;
557                 cup = (Cmn_unit *)pip;
558                 acp = &cup->cu_config;
559
560                 /*
561                  * Make sure there's room in user buffer
562                  */
563                 if (aip->air_buf_len < sizeof(acr)) {
564                         err = ENOSPC;
565                         break;
566                 }
567
568                 /*
569                  * Fill in info to be returned
570                  */
571                 KM_ZERO((caddr_t)&acr, sizeof(acr));
572                 (void) snprintf(acr.acp_intf, sizeof(acr.acp_intf),
573                     "%s%d", pip->pif_name, pip->pif_unit);
574                 KM_COPY((caddr_t)acp, (caddr_t)&acr.acp_cfg,
575                                 sizeof(Atm_config));
576
577                 /*
578                  * Copy data to user buffer
579                  */
580                 err = copyout((caddr_t)&acr, aip->air_buf_addr,
581                                 sizeof(acr));
582                 if (err)
583                         break;
584
585                 /*
586                  * Update buffer pointer/count
587                  */
588                 aip->air_buf_addr += sizeof(acr);
589                 aip->air_buf_len -= sizeof(acr);
590                 break;
591
592         case AIOCS_INF_VST:
593                 /*
594                  * Pass off to device-specific handler
595                  */
596                 cup = (Cmn_unit *)arg;
597                 if (cup == NULL)
598                         err = ENXIO;
599                 else
600                         err = (*cup->cu_ioctl)(code, data, arg);
601                 break;
602
603         default:
604                 err = ENOSYS;
605         }
606
607         return ( err );
608 }
609
610
611 /*
612  * Register a Network Convergence Module
613  * 
614  * Each ATM network convergence module must register itself here before
615  * it will receive network interface status notifications. 
616  *
617  * Arguments:
618  *      ncp     pointer to network convergence definition structure
619  *
620  * Returns:
621  *      0       registration successful
622  *      errno   registration failed - reason indicated
623  *
624  */
625 int
626 atm_netconv_register(ncp)
627         struct atm_ncm  *ncp;
628 {
629         struct atm_ncm  *tdp;
630         int             s = splnet();
631
632         /*
633          * See if we need to be initialized
634          */
635         if (!atm_init)
636                 atm_initialize();
637
638         /*
639          * Validate protocol family
640          */
641         if (ncp->ncm_family > AF_MAX) {
642                 (void) splx(s);
643                 return (EINVAL);
644         }
645
646         /*
647          * Ensure no duplicates
648          */
649         for (tdp = atm_netconv_head; tdp != NULL; tdp = tdp->ncm_next) {
650                 if (tdp->ncm_family == ncp->ncm_family) {
651                         (void) splx(s);
652                         return (EEXIST);
653                 }
654         }
655
656         /*
657          * Add module to list
658          */
659         LINK2TAIL(ncp, struct atm_ncm, atm_netconv_head, ncm_next);
660
661         /*
662          * Add new interface output function
663          */
664         atm_ifouttbl[ncp->ncm_family] = ncp->ncm_ifoutput;
665
666         (void) splx(s);
667         return (0);
668 }
669
670
671 /*
672  * De-register an ATM Network Convergence Module
673  * 
674  * Each ATM network convergence provider must de-register its registered 
675  * service(s) before terminating.  Specifically, loaded kernel modules
676  * must de-register their services before unloading themselves.
677  *
678  * Arguments:
679  *      ncp     pointer to network convergence definition structure
680  *
681  * Returns:
682  *      0       de-registration successful 
683  *      errno   de-registration failed - reason indicated
684  *
685  */
686 int
687 atm_netconv_deregister(ncp)
688         struct atm_ncm  *ncp;
689 {
690         int     found, s = splnet();
691
692         /*
693          * Remove module from list
694          */
695         UNLINKF(ncp, struct atm_ncm, atm_netconv_head, ncm_next, found);
696
697         if (!found) {
698                 (void) splx(s);
699                 return (ENOENT);
700         }
701
702         /*
703          * Remove module's interface output function
704          */
705         atm_ifouttbl[ncp->ncm_family] = NULL;
706
707         (void) splx(s);
708         return (0);
709 }
710
711
712 /*
713  * Attach an ATM Network Interface
714  * 
715  * Before an ATM network interface can be used by the system, the owning
716  * device interface must attach the network interface using this function.
717  * The physical interface for this network interface must have been previously
718  * registered (using atm_interface_register).  The network interface will be
719  * added to the kernel's interface list and to the physical interface's list.
720  * The caller is responsible for initializing the control block fields.
721  *
722  * Arguments:
723  *      nip     pointer to atm network interface control block
724  *
725  * Returns:
726  *      0       attach successful
727  *      errno   attach failed - reason indicated
728  *
729  */
730 int
731 atm_nif_attach(nip)
732         struct atm_nif  *nip;
733 {
734         struct atm_pif  *pip, *pip2;
735         struct ifnet    *ifp;
736         struct atm_ncm  *ncp;
737         int             s;
738
739         ifp = &nip->nif_if;
740         pip = nip->nif_pif;
741
742         s = splimp();
743
744         /*
745          * Verify physical interface is registered
746          */
747         for (pip2 = atm_interface_head; pip2 != NULL; pip2 = pip2->pif_next) {
748                 if (pip == pip2)
749                         break;
750         }
751         if ((pip == NULL) || (pip2 == NULL)) {
752                 (void) splx(s);
753                 return (EFAULT);
754         }
755
756         /*
757          * Add to system interface list 
758          */
759         if_attach(ifp);
760
761         /*
762          * Add to physical interface list
763          */
764         LINK2TAIL(nip, struct atm_nif, pip->pif_nif, nif_pnext);
765
766         /*
767          * Notify network convergence modules of new network i/f
768          */
769         for (ncp = atm_netconv_head; ncp; ncp = ncp->ncm_next) {
770                 int     err;
771
772                 err = (*ncp->ncm_stat)(NCM_ATTACH, nip, 0);
773                 if (err) {
774                         atm_nif_detach(nip);
775                         (void) splx(s);
776                         return (err);
777                 }
778         }
779
780         (void) splx(s);
781         return (0);
782 }
783
784
785 /*
786  * Detach an ATM Network Interface
787  * 
788  * Before an ATM network interface control block can be freed, all kernel
789  * references to/from this block must be released.  This function will delete
790  * all routing references to the interface and free all interface addresses
791  * for the interface.  The network interface will then be removed from the
792  * kernel's interface list and from the owning physical interface's list.
793  * The caller is responsible for free'ing the control block.
794  *
795  * Arguments:
796  *      nip     pointer to atm network interface control block
797  *
798  * Returns:
799  *      none
800  *
801  */
802 void
803 atm_nif_detach(nip)
804         struct atm_nif  *nip;
805 {
806         struct atm_ncm  *ncp;
807         int             s, i;
808         struct ifnet    *ifp = &nip->nif_if;
809         struct ifaddr   *ifa;
810         struct in_ifaddr        *ia;
811         struct radix_node_head  *rnh;
812
813
814         s = splimp();
815
816         /*
817          * Notify convergence modules of network i/f demise
818          */
819         for (ncp = atm_netconv_head; ncp; ncp = ncp->ncm_next) {
820                 (void) (*ncp->ncm_stat)(NCM_DETACH, nip, 0);
821         }
822
823         /*
824          * Mark interface down
825          */
826         if_down(ifp);
827
828         /*
829          * Free all interface routes and addresses
830          */
831         while (1) {
832                 IFP_TO_IA(ifp, ia);
833                 if (ia == NULL)
834                         break;
835
836                 /* Delete interface route */
837                 in_ifscrub(ifp, ia);
838
839                 /* Remove interface address from queues */
840                 ifa = &ia->ia_ifa;
841                 TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
842                 TAILQ_REMOVE(&in_ifaddrhead, ia, ia_link);
843
844                 /* Free interface address */
845                 IFAFREE(ifa);
846         }
847
848         /*
849          * Delete all remaining routes using this interface
850          * Unfortuneatly the only way to do this is to slog through
851          * the entire routing table looking for routes which point
852          * to this interface...oh well...
853          */
854         for (i = 1; i <= AF_MAX; i++) {
855                 if ((rnh = rt_tables[i]) == NULL)
856                         continue;
857                 (void) rnh->rnh_walktree(rnh, atm_netif_rtdel, ifp);
858         }
859
860         /*
861          * Remove from system interface list (ie. if_detach())
862          */
863         TAILQ_REMOVE(&ifnet, ifp, if_link);
864
865         /*
866          * Remove from physical interface list
867          */
868         UNLINK(nip, struct atm_nif, nip->nif_pif->pif_nif, nif_pnext);
869
870         (void) splx(s);
871 }
872
873
874 /*
875  * Delete Routes for a Network Interface
876  * 
877  * Called for each routing entry via the rnh->rnh_walktree() call above
878  * to delete all route entries referencing a detaching network interface.
879  *
880  * Arguments:
881  *      rn      pointer to node in the routing table
882  *      arg     argument passed to rnh->rnh_walktree() - detaching interface
883  *
884  * Returns:
885  *      0       successful
886  *      errno   failed - reason indicated
887  *
888  */
889 static int
890 atm_netif_rtdel(rn, arg)
891         struct radix_node       *rn;
892         void                    *arg;
893 {
894         struct rtentry  *rt = (struct rtentry *)rn;
895         struct ifnet    *ifp = arg;
896         int             err;
897
898         if (rt->rt_ifp == ifp) {
899
900                 /*
901                  * Protect (sorta) against walktree recursion problems
902                  * with cloned routes
903                  */
904                 if ((rt->rt_flags & RTF_UP) == 0)
905                         return (0);
906
907                 err = rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway,
908                                 rt_mask(rt), rt->rt_flags,
909                                 (struct rtentry **) NULL);
910                 if (err) {
911                         log(LOG_WARNING, "atm_netif_rtdel: error %d\n", err);
912                 }
913         }
914
915         return (0);
916 }
917
918
919 /*
920  * Set an ATM Network Interface address
921  * 
922  * This is called from a device interface when processing an SIOCSIFADDR
923  * ioctl request.  We just notify all convergence modules of the new address
924  * and hope everyone has non-overlapping interests, since if someone reports
925  * an error we don't go back and tell everyone to undo the change.
926  *
927  * Arguments:
928  *      nip     pointer to atm network interface control block
929  *      ifa     pointer to new interface address
930  *
931  * Returns:
932  *      0       set successful
933  *      errno   set failed - reason indicated
934  *
935  */
936 int
937 atm_nif_setaddr(nip, ifa)
938         struct atm_nif  *nip;
939         struct ifaddr   *ifa;
940 {
941         struct atm_ncm  *ncp;
942         int     err = 0, s = splnet();
943
944         /*
945          * Notify convergence modules of network i/f change
946          */
947         for (ncp = atm_netconv_head; ncp; ncp = ncp->ncm_next) {
948                 err = (*ncp->ncm_stat)(NCM_SETADDR, nip, (int)ifa);
949                 if (err)
950                         break;
951         }
952         (void) splx(s);
953
954         return (err);
955 }
956
957
958 /*
959  * ATM Interface Packet Output
960  * 
961  * All ATM network interfaces must have their ifnet if_output address set to
962  * this function.  Since no existing network layer code is to be modified 
963  * for ATM support, this function serves as the hook to allow network output
964  * packets to be assigned to their proper outbound VCC.  Each network address
965  * family which is to be supported over ATM must be assigned an output
966  * packet processing function via atm_netconv_register().
967  *
968  * Arguments:
969  *      ifp     pointer to ifnet structure
970  *      m       pointer to packet buffer chain to be output
971  *      dst     pointer to packet's network destination address
972  *
973  * Returns:
974  *      0       packet queued to interface
975  *      errno   output failed - reason indicated
976  *
977  */
978 int
979 #if (defined(BSD) && (BSD >= 199103))
980 atm_ifoutput(ifp, m, dst, rt)
981 #else
982 atm_ifoutput(ifp, m, dst)
983 #endif
984         struct ifnet    *ifp;
985         KBuffer         *m;
986         struct sockaddr *dst;
987 #if (defined(BSD) && (BSD >= 199103))
988         struct rtentry  *rt;
989 #endif
990 {
991         u_short         fam = dst->sa_family;
992         int             (*func)__P((struct ifnet *, KBuffer *,
993                                         struct sockaddr *));
994
995         /*
996          * Validate address family
997          */
998         if (fam > AF_MAX) {
999                 KB_FREEALL(m);
1000                 return (EAFNOSUPPORT);
1001         }
1002
1003         /*
1004          * Hand packet off for dst-to-VCC mapping
1005          */
1006         func = atm_ifouttbl[fam];
1007         if (func == NULL) {
1008                 KB_FREEALL(m);
1009                 return (EAFNOSUPPORT);
1010         }
1011         return ((*func)(ifp, m, dst));
1012 }
1013
1014
1015 /*
1016  * Handle interface ioctl requests. 
1017  *
1018  * Arguments:
1019  *      ifp             pointer to network interface structure
1020  *      cmd             IOCTL cmd
1021  *      data            arguments to/from ioctl
1022  *
1023  * Returns:
1024  *      error           errno value
1025  */
1026 static int
1027 atm_if_ioctl(ifp, cmd, data)
1028         struct ifnet *ifp;
1029         u_long  cmd;
1030         caddr_t data;
1031 {
1032         register struct ifreq *ifr = (struct ifreq *)data;
1033         struct atm_nif  *nip = (struct atm_nif *)ifp;
1034         int     error = 0;
1035         int     s = splnet();
1036
1037         switch ( cmd )
1038         {
1039         case SIOCGIFADDR:
1040                 KM_COPY ( (caddr_t)&(nip->nif_pif->pif_macaddr),
1041                         (caddr_t)ifr->ifr_addr.sa_data, 
1042                         sizeof(struct mac_addr) );
1043                 break;
1044
1045         case SIOCSIFADDR:
1046                 error = atm_nif_setaddr ( nip, (struct ifaddr *)data);
1047                 ifp->if_flags |= IFF_UP | IFF_RUNNING | IFF_BROADCAST;
1048                 break;
1049
1050         case SIOCGIFFLAGS:
1051                 *(short *)data = ifp->if_flags;
1052                 break;
1053
1054         case SIOCSIFFLAGS:
1055                 break;
1056
1057         default:
1058                 error = EINVAL;
1059                 break;
1060         }
1061
1062         (void) splx(s);
1063         return ( error );
1064 }
1065
1066
1067 /*
1068  * Parse interface name
1069  * 
1070  * Parses an interface name string into a name and a unit component.
1071  *
1072  * Arguments:
1073  *      name    pointer to interface name string
1074  *      namep   address to store interface name
1075  *      size    size available at namep
1076  *      unitp   address to store interface unit number
1077  *
1078  * Returns:
1079  *      0       name parsed
1080  *      else    parse error
1081  *
1082  */
1083 static int
1084 atm_ifparse(name, namep, size, unitp)
1085         char            *name;
1086         char            *namep;
1087         int             size;
1088         int             *unitp;
1089 {
1090         char            *cp, *np;
1091         int             len = 0, unit = 0;
1092
1093         /*
1094          * Separate supplied string into name and unit parts.
1095          */
1096         cp = name;
1097         np = namep;
1098         while (*cp) {
1099                 if (*cp >= '0' && *cp <= '9')
1100                         break;
1101                 if (++len >= size)
1102                         return (-1);
1103                 *np++ = *cp++;
1104         }
1105         *np = '\0';
1106         while (*cp && *cp >= '0' && *cp <= '9')
1107                 unit = 10 * unit + *cp++ - '0';
1108
1109         *unitp = unit;
1110
1111         return (0);
1112 }
1113
1114
1115 /*
1116  * Locate ATM physical interface via name
1117  * 
1118  * Uses the supplied interface name string to locate a registered
1119  * ATM physical interface.
1120  *
1121  * Arguments:
1122  *      name    pointer to interface name string
1123  *
1124  * Returns:
1125  *      0       interface not found
1126  *      else    pointer to atm physical interface structure
1127  *
1128  */
1129 struct atm_pif *
1130 atm_pifname(name)
1131         char            *name;
1132 {
1133         struct atm_pif  *pip;
1134         char            n[IFNAMSIZ];
1135         int             unit;
1136
1137         /*
1138          * Break down name
1139          */
1140         if (atm_ifparse(name, n, sizeof(n), &unit))
1141                 return ((struct atm_pif *)0);
1142
1143         /*
1144          * Look for the physical interface
1145          */
1146         for (pip = atm_interface_head; pip; pip = pip->pif_next) {
1147                 if ((pip->pif_unit == unit) && (strcmp(pip->pif_name, n) == 0))
1148                         break;
1149         }
1150
1151         return (pip);
1152 }
1153
1154
1155 /*
1156  * Locate ATM network interface via name
1157  * 
1158  * Uses the supplied interface name string to locate an ATM network interface.
1159  *
1160  * Arguments:
1161  *      name    pointer to interface name string
1162  *
1163  * Returns:
1164  *      0       interface not found
1165  *      else    pointer to atm network interface structure
1166  *
1167  */
1168 struct atm_nif *
1169 atm_nifname(name)
1170         char            *name;
1171 {
1172         struct atm_pif  *pip;
1173         struct atm_nif  *nip;
1174         char            n[IFNAMSIZ];
1175         int             unit;
1176
1177         /*
1178          * Break down name
1179          */
1180         if (atm_ifparse(name, n, sizeof(n), &unit))
1181                 return ((struct atm_nif *)0);
1182
1183         /*
1184          * Search thru each physical interface
1185          */
1186         for (pip = atm_interface_head; pip; pip = pip->pif_next) {
1187                 /*
1188                  * Looking for network interface
1189                  */
1190                 for (nip = pip->pif_nif; nip; nip = nip->nif_pnext) {
1191                         struct ifnet    *ifp = (struct ifnet *)nip;
1192                         if ((ifp->if_unit == unit) && 
1193                             (strcmp(ifp->if_name, n) == 0))
1194                                 return (nip);
1195                 }
1196         }
1197         return (NULL);
1198 }
1199