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