Merge from vendor branch OPENPAM:
[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.11 2005/06/03 23:23:03 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
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 in_ifaddr        *ia;
289         struct sockaddr_dl      *sdl;
290
291         switch ( aip->air_opcode ) {
292
293         case AIOCS_INF_INT:
294                 /*
295                  * Get physical interface information
296                  */
297                 aip = (struct atminfreq *)data;
298                 pip = (struct atm_pif *)arg;
299
300                 /*
301                  * Make sure there's room in user buffer
302                  */
303                 if (aip->air_buf_len < sizeof(apr)) {
304                         err = ENOSPC;
305                         break;
306                 }
307
308                 /*
309                  * Fill in info to be returned
310                  */
311                 KM_ZERO((caddr_t)&apr, sizeof(apr));
312                 smp = pip->pif_sigmgr;
313                 sip = pip->pif_siginst;
314                 (void) snprintf(apr.anp_intf, sizeof(apr.anp_intf),
315                         "%s%d", pip->pif_name, pip->pif_unit );
316                 if ( pip->pif_nif )
317                 {
318                         strcpy(apr.anp_nif_pref,        /* XXX: strings */
319                              pip->pif_nif->nif_if.if_dname);
320
321                         nip = pip->pif_nif;
322                         while ( nip ) {
323                                 apr.anp_nif_cnt++;
324                                 nip = nip->nif_pnext;
325                         }
326                 }
327                 if (sip) {
328                         ATM_ADDR_COPY(&sip->si_addr, &apr.anp_addr);
329                         ATM_ADDR_COPY(&sip->si_subaddr, &apr.anp_subaddr);
330                         apr.anp_sig_proto = smp->sm_proto;
331                         apr.anp_sig_state = sip->si_state;
332                 }
333
334                 /*
335                  * Copy data to user buffer
336                  */
337                 err = copyout((caddr_t)&apr, aip->air_buf_addr, sizeof(apr));
338                 if (err)
339                         break;
340
341                 /*
342                  * Update buffer pointer/count
343                  */
344                 aip->air_buf_addr += sizeof(apr);
345                 aip->air_buf_len -= sizeof(apr);
346                 break;
347
348         case AIOCS_INF_NIF:
349                 /*
350                  * Get network interface information
351                  */
352                 aip = (struct atminfreq *)data;
353                 nip = (struct atm_nif *)arg;
354                 ifp = &nip->nif_if;
355                 pip = nip->nif_pif;
356
357                 /*
358                  * Make sure there's room in user buffer
359                  */
360                 if (aip->air_buf_len < sizeof(anr)) {
361                         err = ENOSPC;
362                         break;
363                 }
364
365                 /*
366                  * Fill in info to be returned
367                  */
368                 KM_ZERO((caddr_t)&anr, sizeof(anr));
369                 (void) snprintf(anr.anp_intf, sizeof(anr.anp_intf),
370                     "%s", ifp->if_xname);
371                 IFP_TO_IA(ifp, ia);
372                 if (ia) {
373                         anr.anp_proto_addr = *ia->ia_ifa.ifa_addr;
374                 }
375                 (void) snprintf(anr.anp_phy_intf, sizeof(anr.anp_phy_intf),
376                     "%s%d", pip->pif_name, pip->pif_unit);
377
378                 /*
379                  * Copy data to user buffer
380                  */
381                 err = copyout((caddr_t)&anr, aip->air_buf_addr, sizeof(anr));
382                 if (err)
383                         break;
384
385                 /*
386                  * Update buffer pointer/count
387                  */
388                 aip->air_buf_addr += sizeof(anr);
389                 aip->air_buf_len -= sizeof(anr);
390                 break;
391
392         case AIOCS_INF_PIS:
393                 /*
394                  * Get per interface statistics
395                  */
396                 pip = (struct atm_pif *)arg;
397                 if ( pip == NULL )
398                         return ( ENXIO );
399                 snprintf ( ifname, sizeof(ifname),
400                     "%s%d", pip->pif_name, pip->pif_unit );
401
402                 /*
403                  * Cast response into users buffer
404                  */
405                 apsp = (struct air_phy_stat_rsp *)buf;
406
407                 /*
408                  * Sanity check
409                  */
410                 len = sizeof ( struct air_phy_stat_rsp );
411                 if ( buf_len < len )
412                         return ( ENOSPC );
413
414                 /*
415                  * Copy interface name into response
416                  */
417                 if ((err = copyout ( ifname, apsp->app_intf, IFNAMSIZ)) != 0)
418                         break;
419
420                 /*
421                  * Copy counters
422                  */
423                 if ((err = copyout(&pip->pif_ipdus, &apsp->app_ipdus,
424                     len - sizeof(apsp->app_intf))) != 0)
425                         break;
426
427                 /*
428                  * Adjust buffer elements
429                  */
430                 buf += len;
431                 buf_len -= len;
432
433                 aip->air_buf_addr = buf;
434                 aip->air_buf_len = buf_len;
435                 break;
436
437         case AIOCS_SET_NIF:
438                 /*
439                  * Set NIF - allow user to configure 1 or more logical
440                  *      interfaces per physical interface.
441                  */
442
443                 /*
444                  * Get pointer to physical interface structure from
445                  * ioctl argument.
446                  */
447                 pip = (struct atm_pif *)arg;
448                 cup = (Cmn_unit *)pip;
449
450                 /*
451                  * Sanity check - are we already connected to something?
452                  */
453                 if ( pip->pif_sigmgr )
454                 {
455                         err = EBUSY;
456                         break;
457                 }
458
459                 /*
460                  * Free any previously allocated NIFs
461                  */
462                 atm_physif_freenifs(pip);
463
464                 /*
465                  * Add list of interfaces
466                  */
467                 for ( count = 0; count < asr->asr_nif_cnt; count++ )
468                 {
469                         nip = (struct atm_nif *)atm_allocate(cup->cu_nif_pool);
470                         if ( nip == NULL )
471                         {
472                                 /*
473                                  * Destroy any successful nifs
474                                  */
475                                 atm_physif_freenifs(pip);
476                                 err = ENOMEM;
477                                 break;
478                         }
479
480                         nip->nif_pif = pip;
481                         ifp = &nip->nif_if;
482
483                         strcpy ( nip->nif_name, asr->asr_nif_pref );
484                         nip->nif_sel = count;
485
486                         if_initname(ifp, nip->nif_name, count);
487                         ifp->if_mtu = ATM_NIF_MTU;
488                         ifp->if_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING;
489                         ifp->if_output = atm_ifoutput;
490                         ifp->if_ioctl = atm_if_ioctl;
491                         ifp->if_snd.ifq_maxlen = ifqmaxlen;
492                         /*
493                          * Set if_type and if_baudrate
494                          */
495                         ifp->if_type = IFT_ATM;
496                         switch ( cup->cu_config.ac_media ) {
497                         case MEDIA_TAXI_100:
498                                 ifp->if_baudrate = 100000000;
499                                 break;
500                         case MEDIA_TAXI_140:
501                                 ifp->if_baudrate = 140000000;
502                                 break;
503                         case MEDIA_OC3C:
504                         case MEDIA_OC12C:
505                         case MEDIA_UTP155:
506                                 ifp->if_baudrate = 155000000;
507                                 break;
508                         default:
509                                 panic("AIOCF_SETNIF: unknown media");
510                         }
511
512                         if ((err = atm_nif_attach(nip)) != 0) {
513                                 atm_free ( (caddr_t)nip );
514
515                                 /*
516                                  * Destroy any successful nifs
517                                  */
518                                 atm_physif_freenifs(pip);
519                                 break;
520                         }
521                         /*
522                          * Set macaddr in <Link> address
523                          */
524                         ifp->if_addrlen = 6;
525                         sdl = IF_LLSOCKADDR(ifp);
526                         sdl->sdl_type = IFT_ETHER;
527                         sdl->sdl_alen = ifp->if_addrlen;
528                         bcopy ( (caddr_t)&cup->cu_config.ac_macaddr,
529                                 LLADDR(sdl), ifp->if_addrlen );
530                 }
531                 break;
532
533         case AIOCS_INF_CFG:
534                 /*
535                  * Get adapter configuration information
536                  */
537                 aip = (struct atminfreq *)data;
538                 pip = (struct atm_pif *)arg;
539                 cup = (Cmn_unit *)pip;
540                 acp = &cup->cu_config;
541
542                 /*
543                  * Make sure there's room in user buffer
544                  */
545                 if (aip->air_buf_len < sizeof(acr)) {
546                         err = ENOSPC;
547                         break;
548                 }
549
550                 /*
551                  * Fill in info to be returned
552                  */
553                 KM_ZERO((caddr_t)&acr, sizeof(acr));
554                 (void) snprintf(acr.acp_intf, sizeof(acr.acp_intf),
555                     "%s%d", pip->pif_name, pip->pif_unit);
556                 KM_COPY((caddr_t)acp, (caddr_t)&acr.acp_cfg,
557                                 sizeof(Atm_config));
558
559                 /*
560                  * Copy data to user buffer
561                  */
562                 err = copyout((caddr_t)&acr, aip->air_buf_addr,
563                                 sizeof(acr));
564                 if (err)
565                         break;
566
567                 /*
568                  * Update buffer pointer/count
569                  */
570                 aip->air_buf_addr += sizeof(acr);
571                 aip->air_buf_len -= sizeof(acr);
572                 break;
573
574         case AIOCS_INF_VST:
575                 /*
576                  * Pass off to device-specific handler
577                  */
578                 cup = (Cmn_unit *)arg;
579                 if (cup == NULL)
580                         err = ENXIO;
581                 else
582                         err = (*cup->cu_ioctl)(code, data, arg);
583                 break;
584
585         default:
586                 err = ENOSYS;
587         }
588
589         return ( err );
590 }
591
592
593 /*
594  * Register a Network Convergence Module
595  * 
596  * Each ATM network convergence module must register itself here before
597  * it will receive network interface status notifications. 
598  *
599  * Arguments:
600  *      ncp     pointer to network convergence definition structure
601  *
602  * Returns:
603  *      0       registration successful
604  *      errno   registration failed - reason indicated
605  *
606  */
607 int
608 atm_netconv_register(ncp)
609         struct atm_ncm  *ncp;
610 {
611         struct atm_ncm  *tdp;
612
613         crit_enter();
614         /*
615          * See if we need to be initialized
616          */
617         if (!atm_init)
618                 atm_initialize();
619
620         /*
621          * Validate protocol family
622          */
623         if (ncp->ncm_family > AF_MAX) {
624                 crit_exit();
625                 return (EINVAL);
626         }
627
628         /*
629          * Ensure no duplicates
630          */
631         for (tdp = atm_netconv_head; tdp != NULL; tdp = tdp->ncm_next) {
632                 if (tdp->ncm_family == ncp->ncm_family) {
633                         crit_exit();
634                         return (EEXIST);
635                 }
636         }
637
638         /*
639          * Add module to list
640          */
641         LINK2TAIL(ncp, struct atm_ncm, atm_netconv_head, ncm_next);
642
643         /*
644          * Add new interface output function
645          */
646         atm_ifouttbl[ncp->ncm_family] = ncp->ncm_ifoutput;
647
648         crit_exit();
649         return (0);
650 }
651
652
653 /*
654  * De-register an ATM Network Convergence Module
655  * 
656  * Each ATM network convergence provider must de-register its registered 
657  * service(s) before terminating.  Specifically, loaded kernel modules
658  * must de-register their services before unloading themselves.
659  *
660  * Arguments:
661  *      ncp     pointer to network convergence definition structure
662  *
663  * Returns:
664  *      0       de-registration successful 
665  *      errno   de-registration failed - reason indicated
666  *
667  */
668 int
669 atm_netconv_deregister(ncp)
670         struct atm_ncm  *ncp;
671 {
672         int     found;
673
674         crit_enter();
675
676         /*
677          * Remove module from list
678          */
679         UNLINKF(ncp, struct atm_ncm, atm_netconv_head, ncm_next, found);
680
681         if (!found) {
682                 crit_exit();
683                 return (ENOENT);
684         }
685
686         /*
687          * Remove module's interface output function
688          */
689         atm_ifouttbl[ncp->ncm_family] = NULL;
690
691         crit_exit();
692         return (0);
693 }
694
695
696 /*
697  * Attach an ATM Network Interface
698  * 
699  * Before an ATM network interface can be used by the system, the owning
700  * device interface must attach the network interface using this function.
701  * The physical interface for this network interface must have been previously
702  * registered (using atm_interface_register).  The network interface will be
703  * added to the kernel's interface list and to the physical interface's list.
704  * The caller is responsible for initializing the control block fields.
705  *
706  * Arguments:
707  *      nip     pointer to atm network interface control block
708  *
709  * Returns:
710  *      0       attach successful
711  *      errno   attach failed - reason indicated
712  *
713  */
714 int
715 atm_nif_attach(nip)
716         struct atm_nif  *nip;
717 {
718         struct atm_pif  *pip, *pip2;
719         struct ifnet    *ifp;
720         struct atm_ncm  *ncp;
721
722         ifp = &nip->nif_if;
723         pip = nip->nif_pif;
724
725         crit_enter();
726
727         /*
728          * Verify physical interface is registered
729          */
730         for (pip2 = atm_interface_head; pip2 != NULL; pip2 = pip2->pif_next) {
731                 if (pip == pip2)
732                         break;
733         }
734         if ((pip == NULL) || (pip2 == NULL)) {
735                 crit_exit();
736                 return (EFAULT);
737         }
738
739         /*
740          * Add to system interface list 
741          */
742         if_attach(ifp);
743
744         /*
745          * Add to physical interface list
746          */
747         LINK2TAIL(nip, struct atm_nif, pip->pif_nif, nif_pnext);
748
749         /*
750          * Notify network convergence modules of new network i/f
751          */
752         for (ncp = atm_netconv_head; ncp; ncp = ncp->ncm_next) {
753                 int     err;
754
755                 err = (*ncp->ncm_stat)(NCM_ATTACH, nip, 0);
756                 if (err) {
757                         atm_nif_detach(nip);
758                         crit_exit();
759                         return (err);
760                 }
761         }
762
763         crit_exit();
764         return (0);
765 }
766
767
768 /*
769  * Detach an ATM Network Interface
770  * 
771  * Before an ATM network interface control block can be freed, all kernel
772  * references to/from this block must be released.  This function will delete
773  * all routing references to the interface and free all interface addresses
774  * for the interface.  The network interface will then be removed from the
775  * kernel's interface list and from the owning physical interface's list.
776  * The caller is responsible for free'ing the control block.
777  *
778  * Arguments:
779  *      nip     pointer to atm network interface control block
780  *
781  * Returns:
782  *      none
783  *
784  */
785 void
786 atm_nif_detach(nip)
787         struct atm_nif  *nip;
788 {
789         struct atm_ncm  *ncp;
790         int             i;
791         struct ifnet    *ifp = &nip->nif_if;
792         struct ifaddr   *ifa;
793         struct in_ifaddr        *ia;
794         struct radix_node_head  *rnh;
795
796         crit_enter();
797
798         /*
799          * Notify convergence modules of network i/f demise
800          */
801         for (ncp = atm_netconv_head; ncp; ncp = ncp->ncm_next) {
802                 (void) (*ncp->ncm_stat)(NCM_DETACH, nip, 0);
803         }
804
805         /*
806          * Mark interface down
807          */
808         if_down(ifp);
809
810         /*
811          * Free all interface routes and addresses
812          */
813         while (1) {
814                 IFP_TO_IA(ifp, ia);
815                 if (ia == NULL)
816                         break;
817
818                 /* Delete interface route */
819                 in_ifscrub(ifp, ia);
820
821                 /* Remove interface address from queues */
822                 ifa = &ia->ia_ifa;
823                 TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
824                 TAILQ_REMOVE(&in_ifaddrhead, ia, ia_link);
825
826                 /* Free interface address */
827                 IFAFREE(ifa);
828         }
829
830         /*
831          * Delete all remaining routes using this interface
832          * Unfortuneatly the only way to do this is to slog through
833          * the entire routing table looking for routes which point
834          * to this interface...oh well...
835          */
836         for (i = 1; i <= AF_MAX; i++) {
837                 if ((rnh = rt_tables[i]) == NULL)
838                         continue;
839                 (void) rnh->rnh_walktree(rnh, atm_netif_rtdel, ifp);
840         }
841
842         /*
843          * Remove from system interface list (ie. if_detach())
844          */
845         TAILQ_REMOVE(&ifnet, ifp, if_link);
846
847         /*
848          * Remove from physical interface list
849          */
850         UNLINK(nip, struct atm_nif, nip->nif_pif->pif_nif, nif_pnext);
851
852         crit_exit();
853 }
854
855
856 /*
857  * Delete Routes for a Network Interface
858  * 
859  * Called for each routing entry via the rnh->rnh_walktree() call above
860  * to delete all route entries referencing a detaching network interface.
861  *
862  * Arguments:
863  *      rn      pointer to node in the routing table
864  *      arg     argument passed to rnh->rnh_walktree() - detaching interface
865  *
866  * Returns:
867  *      0       successful
868  *      errno   failed - reason indicated
869  *
870  */
871 static int
872 atm_netif_rtdel(rn, arg)
873         struct radix_node       *rn;
874         void                    *arg;
875 {
876         struct rtentry  *rt = (struct rtentry *)rn;
877         struct ifnet    *ifp = arg;
878         int             err;
879
880         if (rt->rt_ifp == ifp) {
881
882                 /*
883                  * Protect (sorta) against walktree recursion problems
884                  * with cloned routes
885                  */
886                 if ((rt->rt_flags & RTF_UP) == 0)
887                         return (0);
888
889                 err = rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway,
890                                 rt_mask(rt), rt->rt_flags,
891                                 (struct rtentry **) NULL);
892                 if (err) {
893                         log(LOG_WARNING, "atm_netif_rtdel: error %d\n", err);
894                 }
895         }
896
897         return (0);
898 }
899
900
901 /*
902  * Set an ATM Network Interface address
903  * 
904  * This is called from a device interface when processing an SIOCSIFADDR
905  * ioctl request.  We just notify all convergence modules of the new address
906  * and hope everyone has non-overlapping interests, since if someone reports
907  * an error we don't go back and tell everyone to undo the change.
908  *
909  * Arguments:
910  *      nip     pointer to atm network interface control block
911  *      ifa     pointer to new interface address
912  *
913  * Returns:
914  *      0       set successful
915  *      errno   set failed - reason indicated
916  *
917  */
918 int
919 atm_nif_setaddr(nip, ifa)
920         struct atm_nif  *nip;
921         struct ifaddr   *ifa;
922 {
923         struct atm_ncm  *ncp;
924         int     err = 0;
925
926         crit_enter();
927         /*
928          * Notify convergence modules of network i/f change
929          */
930         for (ncp = atm_netconv_head; ncp; ncp = ncp->ncm_next) {
931                 err = (*ncp->ncm_stat)(NCM_SETADDR, nip, (int)ifa);
932                 if (err)
933                         break;
934         }
935         crit_exit();
936
937         return (err);
938 }
939
940
941 /*
942  * ATM Interface Packet Output
943  * 
944  * All ATM network interfaces must have their ifnet if_output address set to
945  * this function.  Since no existing network layer code is to be modified 
946  * for ATM support, this function serves as the hook to allow network output
947  * packets to be assigned to their proper outbound VCC.  Each network address
948  * family which is to be supported over ATM must be assigned an output
949  * packet processing function via atm_netconv_register().
950  *
951  * Arguments:
952  *      ifp     pointer to ifnet structure
953  *      m       pointer to packet buffer chain to be output
954  *      dst     pointer to packet's network destination address
955  *
956  * Returns:
957  *      0       packet queued to interface
958  *      errno   output failed - reason indicated
959  *
960  */
961 int
962 atm_ifoutput(ifp, m, dst, rt)
963         struct ifnet    *ifp;
964         KBuffer         *m;
965         struct sockaddr *dst;
966         struct rtentry  *rt;
967 {
968         u_short         fam = dst->sa_family;
969         int             (*func)(struct ifnet *, KBuffer *,
970                                         struct sockaddr *);
971
972         /*
973          * Validate address family
974          */
975         if (fam > AF_MAX) {
976                 KB_FREEALL(m);
977                 return (EAFNOSUPPORT);
978         }
979
980         /*
981          * Hand packet off for dst-to-VCC mapping
982          */
983         func = atm_ifouttbl[fam];
984         if (func == NULL) {
985                 KB_FREEALL(m);
986                 return (EAFNOSUPPORT);
987         }
988         return ((*func)(ifp, m, dst));
989 }
990
991
992 /*
993  * Handle interface ioctl requests. 
994  *
995  * Arguments:
996  *      ifp             pointer to network interface structure
997  *      cmd             IOCTL cmd
998  *      data            arguments to/from ioctl
999  *
1000  * Returns:
1001  *      error           errno value
1002  */
1003 static int
1004 atm_if_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
1005 {
1006         struct ifreq *ifr = (struct ifreq *)data;
1007         struct atm_nif  *nip = (struct atm_nif *)ifp;
1008         int     error = 0;
1009
1010         crit_enter();
1011         switch ( cmd )
1012         {
1013         case SIOCGIFADDR:
1014                 KM_COPY ( (caddr_t)&(nip->nif_pif->pif_macaddr),
1015                         (caddr_t)ifr->ifr_addr.sa_data, 
1016                         sizeof(struct mac_addr) );
1017                 break;
1018
1019         case SIOCSIFADDR:
1020                 error = atm_nif_setaddr ( nip, (struct ifaddr *)data);
1021                 ifp->if_flags |= IFF_UP | IFF_RUNNING | IFF_BROADCAST;
1022                 break;
1023
1024         case SIOCGIFFLAGS:
1025                 *(short *)data = ifp->if_flags;
1026                 break;
1027
1028         case SIOCSIFFLAGS:
1029                 break;
1030
1031         default:
1032                 error = EINVAL;
1033                 break;
1034         }
1035
1036         crit_exit();
1037         return ( error );
1038 }
1039
1040
1041 /*
1042  * Parse interface name
1043  * 
1044  * Parses an interface name string into a name and a unit component.
1045  *
1046  * Arguments:
1047  *      name    pointer to interface name string
1048  *      namep   address to store interface name
1049  *      size    size available at namep
1050  *      unitp   address to store interface unit number
1051  *
1052  * Returns:
1053  *      0       name parsed
1054  *      else    parse error
1055  *
1056  */
1057 static int
1058 atm_ifparse(name, namep, size, unitp)
1059         char            *name;
1060         char            *namep;
1061         int             size;
1062         int             *unitp;
1063 {
1064         char            *cp, *np;
1065         int             len = 0, unit = 0;
1066
1067         /*
1068          * Separate supplied string into name and unit parts.
1069          */
1070         cp = name;
1071         np = namep;
1072         while (*cp) {
1073                 if (*cp >= '0' && *cp <= '9')
1074                         break;
1075                 if (++len >= size)
1076                         return (-1);
1077                 *np++ = *cp++;
1078         }
1079         *np = '\0';
1080         while (*cp && *cp >= '0' && *cp <= '9')
1081                 unit = 10 * unit + *cp++ - '0';
1082
1083         *unitp = unit;
1084
1085         return (0);
1086 }
1087
1088
1089 /*
1090  * Locate ATM physical interface via name
1091  * 
1092  * Uses the supplied interface name string to locate a registered
1093  * ATM physical interface.
1094  *
1095  * Arguments:
1096  *      name    pointer to interface name string
1097  *
1098  * Returns:
1099  *      0       interface not found
1100  *      else    pointer to atm physical interface structure
1101  *
1102  */
1103 struct atm_pif *
1104 atm_pifname(name)
1105         char            *name;
1106 {
1107         struct atm_pif  *pip;
1108         char            n[IFNAMSIZ];
1109         int             unit;
1110
1111         /*
1112          * Break down name
1113          */
1114         if (atm_ifparse(name, n, sizeof(n), &unit))
1115                 return ((struct atm_pif *)0);
1116
1117         /*
1118          * Look for the physical interface
1119          */
1120         for (pip = atm_interface_head; pip; pip = pip->pif_next) {
1121                 if ((pip->pif_unit == unit) && (strcmp(pip->pif_name, n) == 0))
1122                         break;
1123         }
1124
1125         return (pip);
1126 }
1127
1128
1129 /*
1130  * Locate ATM network interface via name
1131  * 
1132  * Uses the supplied interface name string to locate an ATM network interface.
1133  *
1134  * Arguments:
1135  *      name    pointer to interface name string
1136  *
1137  * Returns:
1138  *      0       interface not found
1139  *      else    pointer to atm network interface structure
1140  *
1141  */
1142 struct atm_nif *
1143 atm_nifname(name)
1144         char            *name;
1145 {
1146         struct atm_pif  *pip;
1147         struct atm_nif  *nip;
1148         char            n[IFNAMSIZ];
1149         int             unit;
1150
1151         /*
1152          * Break down name
1153          */
1154         if (atm_ifparse(name, n, sizeof(n), &unit))
1155                 return ((struct atm_nif *)0);
1156
1157         /*
1158          * Search thru each physical interface
1159          */
1160         for (pip = atm_interface_head; pip; pip = pip->pif_next) {
1161                 /*
1162                  * Looking for network interface
1163                  */
1164                 for (nip = pip->pif_nif; nip; nip = nip->nif_pnext) {
1165                         struct ifnet    *ifp = (struct ifnet *)nip;
1166                         if ((ifp->if_dunit == unit) && 
1167                             (strcmp(ifp->if_dname, n) == 0))
1168                                 return (nip);
1169                 }
1170         }
1171         return (NULL);
1172 }
1173