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