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