Remove spl*() calls from the netproto/atm driver, replacing them with
[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.10 2005/06/02 22:37:45 dillon 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
82         /*
83          * See if we need to be initialized
84          */
85         if (!atm_init)
86                 atm_initialize();
87
88         /*
89          * Make sure we're not already registered
90          */
91         if (cup->cu_flags & CUF_REGISTER) {
92                 return (EALREADY);
93         }
94
95         crit_enter();
96
97         /*
98          * Make sure an interface is only registered once
99          */
100         for (pip = atm_interface_head; pip != NULL; pip = pip->pif_next) {
101                 if ((cup->cu_unit == pip->pif_unit) && 
102                     (strcmp(name, pip->pif_name) == 0)) {
103                         crit_exit();
104                         return (EEXIST);
105                 }
106         }
107
108         /*
109          * Fill in physical interface parameters
110          */
111         pip = &cup->cu_pif;
112         pip->pif_name = name;
113         pip->pif_unit = cup->cu_unit;
114         pip->pif_flags = PIF_UP;
115         pip->pif_services = sdp;
116         pip->pif_ioctl = atm_physif_ioctl;
117
118         /*
119          * Link in the interface and mark us registered
120          */
121         LINK2TAIL(pip, struct atm_pif, atm_interface_head, pif_next);
122         cup->cu_flags |= CUF_REGISTER;
123
124         crit_exit();
125         return (0);
126 }
127
128
129 /*
130  * De-register an ATM physical interface
131  * 
132  * Each ATM interface must de-register itself before downing the interface.  
133  * The interface's signalling manager will be detached and any network
134  * interface and VCC control blocks will be freed.  
135  *
136  * Arguments:
137  *      cup     pointer to interface's common unit structure
138  *
139  * Returns:
140  *      0       de-registration successful
141  *      errno   de-registration failed - reason indicated
142  *
143  */
144 int
145 atm_physif_deregister(cup)
146         Cmn_unit        *cup;
147 {
148         struct atm_pif  *pip = (struct atm_pif *)&cup->cu_pif;
149         Cmn_vcc         *cvp;
150         int     err;
151
152         crit_enter();
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                                 crit_exit();
166                                 return (err);
167                         }
168                 }
169
170                 /*
171                  * Make sure signalling manager is detached
172                  */
173                 if (pip->pif_sigmgr != NULL) {
174                         crit_exit();
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         crit_exit();
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
223         crit_enter();
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         crit_exit();
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 from a critical section.
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
618         crit_enter();
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                 crit_exit();
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                         crit_exit();
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         crit_exit();
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;
678
679         crit_enter();
680
681         /*
682          * Remove module from list
683          */
684         UNLINKF(ncp, struct atm_ncm, atm_netconv_head, ncm_next, found);
685
686         if (!found) {
687                 crit_exit();
688                 return (ENOENT);
689         }
690
691         /*
692          * Remove module's interface output function
693          */
694         atm_ifouttbl[ncp->ncm_family] = NULL;
695
696         crit_exit();
697         return (0);
698 }
699
700
701 /*
702  * Attach an ATM Network Interface
703  * 
704  * Before an ATM network interface can be used by the system, the owning
705  * device interface must attach the network interface using this function.
706  * The physical interface for this network interface must have been previously
707  * registered (using atm_interface_register).  The network interface will be
708  * added to the kernel's interface list and to the physical interface's list.
709  * The caller is responsible for initializing the control block fields.
710  *
711  * Arguments:
712  *      nip     pointer to atm network interface control block
713  *
714  * Returns:
715  *      0       attach successful
716  *      errno   attach failed - reason indicated
717  *
718  */
719 int
720 atm_nif_attach(nip)
721         struct atm_nif  *nip;
722 {
723         struct atm_pif  *pip, *pip2;
724         struct ifnet    *ifp;
725         struct atm_ncm  *ncp;
726
727         ifp = &nip->nif_if;
728         pip = nip->nif_pif;
729
730         crit_enter();
731
732         /*
733          * Verify physical interface is registered
734          */
735         for (pip2 = atm_interface_head; pip2 != NULL; pip2 = pip2->pif_next) {
736                 if (pip == pip2)
737                         break;
738         }
739         if ((pip == NULL) || (pip2 == NULL)) {
740                 crit_exit();
741                 return (EFAULT);
742         }
743
744         /*
745          * Add to system interface list 
746          */
747         if_attach(ifp);
748
749         /*
750          * Add to physical interface list
751          */
752         LINK2TAIL(nip, struct atm_nif, pip->pif_nif, nif_pnext);
753
754         /*
755          * Notify network convergence modules of new network i/f
756          */
757         for (ncp = atm_netconv_head; ncp; ncp = ncp->ncm_next) {
758                 int     err;
759
760                 err = (*ncp->ncm_stat)(NCM_ATTACH, nip, 0);
761                 if (err) {
762                         atm_nif_detach(nip);
763                         crit_exit();
764                         return (err);
765                 }
766         }
767
768         crit_exit();
769         return (0);
770 }
771
772
773 /*
774  * Detach an ATM Network Interface
775  * 
776  * Before an ATM network interface control block can be freed, all kernel
777  * references to/from this block must be released.  This function will delete
778  * all routing references to the interface and free all interface addresses
779  * for the interface.  The network interface will then be removed from the
780  * kernel's interface list and from the owning physical interface's list.
781  * The caller is responsible for free'ing the control block.
782  *
783  * Arguments:
784  *      nip     pointer to atm network interface control block
785  *
786  * Returns:
787  *      none
788  *
789  */
790 void
791 atm_nif_detach(nip)
792         struct atm_nif  *nip;
793 {
794         struct atm_ncm  *ncp;
795         int             i;
796         struct ifnet    *ifp = &nip->nif_if;
797         struct ifaddr   *ifa;
798         struct in_ifaddr        *ia;
799         struct radix_node_head  *rnh;
800
801         crit_enter();
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         crit_exit();
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;
930
931         crit_enter();
932         /*
933          * Notify convergence modules of network i/f change
934          */
935         for (ncp = atm_netconv_head; ncp; ncp = ncp->ncm_next) {
936                 err = (*ncp->ncm_stat)(NCM_SETADDR, nip, (int)ifa);
937                 if (err)
938                         break;
939         }
940         crit_exit();
941
942         return (err);
943 }
944
945
946 /*
947  * ATM Interface Packet Output
948  * 
949  * All ATM network interfaces must have their ifnet if_output address set to
950  * this function.  Since no existing network layer code is to be modified 
951  * for ATM support, this function serves as the hook to allow network output
952  * packets to be assigned to their proper outbound VCC.  Each network address
953  * family which is to be supported over ATM must be assigned an output
954  * packet processing function via atm_netconv_register().
955  *
956  * Arguments:
957  *      ifp     pointer to ifnet structure
958  *      m       pointer to packet buffer chain to be output
959  *      dst     pointer to packet's network destination address
960  *
961  * Returns:
962  *      0       packet queued to interface
963  *      errno   output failed - reason indicated
964  *
965  */
966 int
967 atm_ifoutput(ifp, m, dst, rt)
968         struct ifnet    *ifp;
969         KBuffer         *m;
970         struct sockaddr *dst;
971         struct rtentry  *rt;
972 {
973         u_short         fam = dst->sa_family;
974         int             (*func)(struct ifnet *, KBuffer *,
975                                         struct sockaddr *);
976
977         /*
978          * Validate address family
979          */
980         if (fam > AF_MAX) {
981                 KB_FREEALL(m);
982                 return (EAFNOSUPPORT);
983         }
984
985         /*
986          * Hand packet off for dst-to-VCC mapping
987          */
988         func = atm_ifouttbl[fam];
989         if (func == NULL) {
990                 KB_FREEALL(m);
991                 return (EAFNOSUPPORT);
992         }
993         return ((*func)(ifp, m, dst));
994 }
995
996
997 /*
998  * Handle interface ioctl requests. 
999  *
1000  * Arguments:
1001  *      ifp             pointer to network interface structure
1002  *      cmd             IOCTL cmd
1003  *      data            arguments to/from ioctl
1004  *
1005  * Returns:
1006  *      error           errno value
1007  */
1008 static int
1009 atm_if_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
1010 {
1011         struct ifreq *ifr = (struct ifreq *)data;
1012         struct atm_nif  *nip = (struct atm_nif *)ifp;
1013         int     error = 0;
1014
1015         crit_enter();
1016         switch ( cmd )
1017         {
1018         case SIOCGIFADDR:
1019                 KM_COPY ( (caddr_t)&(nip->nif_pif->pif_macaddr),
1020                         (caddr_t)ifr->ifr_addr.sa_data, 
1021                         sizeof(struct mac_addr) );
1022                 break;
1023
1024         case SIOCSIFADDR:
1025                 error = atm_nif_setaddr ( nip, (struct ifaddr *)data);
1026                 ifp->if_flags |= IFF_UP | IFF_RUNNING | IFF_BROADCAST;
1027                 break;
1028
1029         case SIOCGIFFLAGS:
1030                 *(short *)data = ifp->if_flags;
1031                 break;
1032
1033         case SIOCSIFFLAGS:
1034                 break;
1035
1036         default:
1037                 error = EINVAL;
1038                 break;
1039         }
1040
1041         crit_exit();
1042         return ( error );
1043 }
1044
1045
1046 /*
1047  * Parse interface name
1048  * 
1049  * Parses an interface name string into a name and a unit component.
1050  *
1051  * Arguments:
1052  *      name    pointer to interface name string
1053  *      namep   address to store interface name
1054  *      size    size available at namep
1055  *      unitp   address to store interface unit number
1056  *
1057  * Returns:
1058  *      0       name parsed
1059  *      else    parse error
1060  *
1061  */
1062 static int
1063 atm_ifparse(name, namep, size, unitp)
1064         char            *name;
1065         char            *namep;
1066         int             size;
1067         int             *unitp;
1068 {
1069         char            *cp, *np;
1070         int             len = 0, unit = 0;
1071
1072         /*
1073          * Separate supplied string into name and unit parts.
1074          */
1075         cp = name;
1076         np = namep;
1077         while (*cp) {
1078                 if (*cp >= '0' && *cp <= '9')
1079                         break;
1080                 if (++len >= size)
1081                         return (-1);
1082                 *np++ = *cp++;
1083         }
1084         *np = '\0';
1085         while (*cp && *cp >= '0' && *cp <= '9')
1086                 unit = 10 * unit + *cp++ - '0';
1087
1088         *unitp = unit;
1089
1090         return (0);
1091 }
1092
1093
1094 /*
1095  * Locate ATM physical interface via name
1096  * 
1097  * Uses the supplied interface name string to locate a registered
1098  * ATM physical interface.
1099  *
1100  * Arguments:
1101  *      name    pointer to interface name string
1102  *
1103  * Returns:
1104  *      0       interface not found
1105  *      else    pointer to atm physical interface structure
1106  *
1107  */
1108 struct atm_pif *
1109 atm_pifname(name)
1110         char            *name;
1111 {
1112         struct atm_pif  *pip;
1113         char            n[IFNAMSIZ];
1114         int             unit;
1115
1116         /*
1117          * Break down name
1118          */
1119         if (atm_ifparse(name, n, sizeof(n), &unit))
1120                 return ((struct atm_pif *)0);
1121
1122         /*
1123          * Look for the physical interface
1124          */
1125         for (pip = atm_interface_head; pip; pip = pip->pif_next) {
1126                 if ((pip->pif_unit == unit) && (strcmp(pip->pif_name, n) == 0))
1127                         break;
1128         }
1129
1130         return (pip);
1131 }
1132
1133
1134 /*
1135  * Locate ATM network interface via name
1136  * 
1137  * Uses the supplied interface name string to locate an ATM network interface.
1138  *
1139  * Arguments:
1140  *      name    pointer to interface name string
1141  *
1142  * Returns:
1143  *      0       interface not found
1144  *      else    pointer to atm network interface structure
1145  *
1146  */
1147 struct atm_nif *
1148 atm_nifname(name)
1149         char            *name;
1150 {
1151         struct atm_pif  *pip;
1152         struct atm_nif  *nip;
1153         char            n[IFNAMSIZ];
1154         int             unit;
1155
1156         /*
1157          * Break down name
1158          */
1159         if (atm_ifparse(name, n, sizeof(n), &unit))
1160                 return ((struct atm_nif *)0);
1161
1162         /*
1163          * Search thru each physical interface
1164          */
1165         for (pip = atm_interface_head; pip; pip = pip->pif_next) {
1166                 /*
1167                  * Looking for network interface
1168                  */
1169                 for (nip = pip->pif_nif; nip; nip = nip->nif_pnext) {
1170                         struct ifnet    *ifp = (struct ifnet *)nip;
1171                         if ((ifp->if_dunit == unit) && 
1172                             (strcmp(ifp->if_dname, n) == 0))
1173                                 return (nip);
1174                 }
1175         }
1176         return (NULL);
1177 }
1178