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