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