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$");
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, *cvp_next;
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 cvp_next = cvp->cv_next;
219 uma_zfree(cup->cu_vcc_zone, cvp);
220 cvp = cvp_next;
221 }
222 cup->cu_vcc = (Cmn_vcc *)NULL;
223
224 (void) splx(s);
225
226 return (0);
227 }
228
229
230 /*
231 * Free all network interfaces on a physical interface
232 *
233 * Arguments
234 * pip pointer to physical interface structure
235 *
236 * Returns
237 * none
238 *
239 */
240 void
241 atm_physif_freenifs(pip, zone)
242 struct atm_pif *pip;
243 uma_zone_t zone;
244 {
245 struct atm_nif *nip = pip->pif_nif;
246 int s = splnet();
247
248 while ( nip )
249 {
250 /*
251 * atm_nif_detach zeros pointers - save so we can
252 * walk the chain.
253 */
254 struct atm_nif *nipp = nip->nif_pnext;
255
256 /*
257 * Clean up network i/f trails
258 */
259 atm_nif_detach(nip);
260 uma_zfree(zone, nip);
261 nip = nipp;
262 }
263 pip->pif_nif = (struct atm_nif *)NULL;
264
265 (void) splx(s);
266
267 return;
268 }
269
270 /*
271 * Handle physical interface ioctl's
272 *
273 * See <netatm/atm_ioctl.h> for definitions.
274 *
275 * Called at splnet.
276 *
277 * Arguments:
278 * code Ioctl function (sub)code
279 * data Data block. On input contains command,
280 * on output, contains results
281 * arg Optional code specific arguments
282 *
283 * Returns:
284 * 0 Request processed successfully
285 * errno Request failed - reason code
286 *
287 */
288 static int
289 atm_physif_ioctl(code, data, arg)
290 int code;
291 caddr_t data;
292 caddr_t arg;
293 {
294 struct atminfreq *aip = (struct atminfreq *)data;
295 struct atmsetreq *asr = (struct atmsetreq *)data;
296 struct atm_pif *pip;
297 struct atm_nif *nip;
298 struct sigmgr *smp;
299 struct siginst *sip;
300 struct ifnet *ifp;
301 Cmn_unit *cup;
302 Atm_config *acp;
303 caddr_t buf = aip->air_buf_addr;
304 struct air_phy_stat_rsp *apsp;
305 struct air_int_rsp apr;
306 struct air_netif_rsp anr;
307 struct air_cfg_rsp acr;
308 u_int count;
309 size_t len;
310 size_t buf_len = aip->air_buf_len;
311 int err = 0;
312 char ifname[2*IFNAMSIZ];
313 struct ifaddr *ifa;
314 struct in_ifaddr *ia;
315 struct sockaddr_dl *sdl;
316
317
318 switch ( aip->air_opcode ) {
319
320 case AIOCS_INF_INT:
321 /*
322 * Get physical interface information
323 */
324 aip = (struct atminfreq *)data;
325 pip = (struct atm_pif *)arg;
326
327 /*
328 * Make sure there's room in user buffer
329 */
330 if (aip->air_buf_len < sizeof(apr)) {
331 err = ENOSPC;
332 break;
333 }
334
335 /*
336 * Fill in info to be returned
337 */
338 bzero((caddr_t)&apr, sizeof(apr));
339 smp = pip->pif_sigmgr;
340 sip = pip->pif_siginst;
341 (void) snprintf(apr.anp_intf, sizeof(apr.anp_intf),
342 "%s%d", pip->pif_name, pip->pif_unit );
343 if ( pip->pif_nif )
344 {
345 strcpy(apr.anp_nif_pref, pip->pif_nif->nif_ifp->if_dname);
346
347 nip = pip->pif_nif;
348 while ( nip ) {
349 apr.anp_nif_cnt++;
350 nip = nip->nif_pnext;
351 }
352 }
353 if (sip) {
354 ATM_ADDR_COPY(&sip->si_addr, &apr.anp_addr);
355 ATM_ADDR_COPY(&sip->si_subaddr, &apr.anp_subaddr);
356 apr.anp_sig_proto = smp->sm_proto;
357 apr.anp_sig_state = sip->si_state;
358 }
359
360 /*
361 * Copy data to user buffer
362 */
363 err = copyout((caddr_t)&apr, aip->air_buf_addr, sizeof(apr));
364 if (err)
365 break;
366
367 /*
368 * Update buffer pointer/count
369 */
370 aip->air_buf_addr += sizeof(apr);
371 aip->air_buf_len -= sizeof(apr);
372 break;
373
374 case AIOCS_INF_NIF:
375 /*
376 * Get network interface information
377 */
378 aip = (struct atminfreq *)data;
379 nip = (struct atm_nif *)arg;
380 ifp = nip->nif_ifp;
381 pip = nip->nif_pif;
382
383 /*
384 * Make sure there's room in user buffer
385 */
386 if (aip->air_buf_len < sizeof(anr)) {
387 err = ENOSPC;
388 break;
389 }
390
391 /*
392 * Fill in info to be returned
393 */
394 bzero((caddr_t)&anr, sizeof(anr));
395 (void) snprintf(anr.anp_intf, sizeof(anr.anp_intf),
396 "%s%d", ifp->if_dname, ifp->if_dunit);
397 IFP_TO_IA(ifp, ia);
398 if (ia) {
399 anr.anp_proto_addr = *ia->ia_ifa.ifa_addr;
400 }
401 (void) snprintf(anr.anp_phy_intf, sizeof(anr.anp_phy_intf),
402 "%s%d", pip->pif_name, pip->pif_unit);
403
404 /*
405 * Copy data to user buffer
406 */
407 err = copyout((caddr_t)&anr, aip->air_buf_addr, sizeof(anr));
408 if (err)
409 break;
410
411 /*
412 * Update buffer pointer/count
413 */
414 aip->air_buf_addr += sizeof(anr);
415 aip->air_buf_len -= sizeof(anr);
416 break;
417
418 case AIOCS_INF_PIS:
419 /*
420 * Get per interface statistics
421 */
422 pip = (struct atm_pif *)arg;
423 if ( pip == NULL )
424 return ( ENXIO );
425 snprintf ( ifname, sizeof(ifname),
426 "%s%d", pip->pif_name, pip->pif_unit );
427
428 /*
429 * Cast response into users buffer
430 */
431 apsp = (struct air_phy_stat_rsp *)buf;
432
433 /*
434 * Sanity check
435 */
436 len = sizeof ( struct air_phy_stat_rsp );
437 if ( buf_len < len )
438 return ( ENOSPC );
439
440 /*
441 * Copy interface name into response
442 */
443 if ((err = copyout ( ifname, apsp->app_intf, IFNAMSIZ)) != 0)
444 break;
445
446 /*
447 * Copy counters
448 */
449 if ((err = copyout(&pip->pif_ipdus, &apsp->app_ipdus,
450 len - sizeof(apsp->app_intf))) != 0)
451 break;
452
453 /*
454 * Adjust buffer elements
455 */
456 buf += len;
457 buf_len -= len;
458
459 aip->air_buf_addr = buf;
460 aip->air_buf_len = buf_len;
461 break;
462
463 case AIOCS_SET_NIF:
464 /*
465 * Set NIF - allow user to configure 1 or more logical
466 * interfaces per physical interface.
467 */
468
469 /*
470 * Get pointer to physical interface structure from
471 * ioctl argument.
472 */
473 pip = (struct atm_pif *)arg;
474 cup = (Cmn_unit *)pip;
475
476 /*
477 * Sanity check - are we already connected to something?
478 */
479 if ( pip->pif_sigmgr )
480 {
481 err = EBUSY;
482 break;
483 }
484
485 /*
486 * Free any previously allocated NIFs
487 */
488 atm_physif_freenifs(pip, cup->cu_nif_zone);
489
490 /*
491 * Add list of interfaces
492 */
493 for ( count = 0; count < asr->asr_nif_cnt; count++ )
494 {
495 nip = uma_zalloc(cup->cu_nif_zone, M_WAITOK | M_ZERO);
496 if ( nip == NULL )
497 {
498 /*
499 * Destroy any successful nifs
500 */
501 atm_physif_freenifs(pip, cup->cu_nif_zone);
502 err = ENOMEM;
503 break;
504 }
505
506 nip->nif_pif = pip;
507 ifp = nip->nif_ifp = if_alloc(IFT_IPOVERATM);
508 if (ifp == NULL) {
509 uma_zfree(cup->cu_nif_zone, nip);
510 /*
511 * Destroy any successful nifs
512 */
513 atm_physif_freenifs(pip, cup->cu_nif_zone);
514 break;
515 }
516
517 strcpy ( nip->nif_name, asr->asr_nif_pref );
518 nip->nif_sel = count;
519
520 if_initname(ifp, nip->nif_name, count);
521 ifp->if_mtu = ATM_NIF_MTU;
522 ifp->if_flags = IFF_UP | IFF_BROADCAST;
523 ifp->if_drv_flags = IFF_DRV_RUNNING;
524 ifp->if_output = atm_ifoutput;
525 ifp->if_ioctl = atm_if_ioctl;
526 ifp->if_snd.ifq_maxlen = ifqmaxlen;
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_UTP25:
540 ifp->if_baudrate = 25600000;
541 break;
542 case MEDIA_VIRTUAL:
543 ifp->if_baudrate = 100000000; /* XXX */
544 break;
545 case MEDIA_DSL:
546 ifp->if_baudrate = 2500000; /* XXX */
547 break;
548 case MEDIA_UNKNOWN:
549 ifp->if_baudrate = 9600;
550 break;
551 }
552 if ((err = atm_nif_attach(nip)) != 0) {
553 if_free(nip->nif_ifp);
554 uma_zfree(cup->cu_nif_zone, nip);
555 /*
556 * Destroy any successful nifs
557 */
558 atm_physif_freenifs(pip, cup->cu_nif_zone);
559 break;
560 }
561 /*
562 * Set macaddr in <Link> address
563 */
564 ifp->if_addrlen = 6;
565 ifa = ifp->if_addr;
566 if ( ifa ) {
567 sdl = (struct sockaddr_dl *)
568 ifa->ifa_addr;
569 sdl->sdl_type = IFT_ETHER;
570 sdl->sdl_alen = ifp->if_addrlen;
571 bcopy ( (caddr_t)&cup->cu_config.ac_macaddr,
572 LLADDR(sdl), ifp->if_addrlen );
573 }
574 }
575 break;
576
577 case AIOCS_INF_CFG:
578 /*
579 * Get adapter configuration information
580 */
581 aip = (struct atminfreq *)data;
582 pip = (struct atm_pif *)arg;
583 cup = (Cmn_unit *)pip;
584 acp = &cup->cu_config;
585
586 /*
587 * Make sure there's room in user buffer
588 */
589 if (aip->air_buf_len < sizeof(acr)) {
590 err = ENOSPC;
591 break;
592 }
593
594 /*
595 * Fill in info to be returned
596 */
597 bzero((caddr_t)&acr, sizeof(acr));
598 (void) snprintf(acr.acp_intf, sizeof(acr.acp_intf),
599 "%s%d", pip->pif_name, pip->pif_unit);
600 bcopy((caddr_t)acp, (caddr_t)&acr.acp_cfg,
601 sizeof(Atm_config));
602
603 /*
604 * Copy data to user buffer
605 */
606 err = copyout((caddr_t)&acr, aip->air_buf_addr,
607 sizeof(acr));
608 if (err)
609 break;
610
611 /*
612 * Update buffer pointer/count
613 */
614 aip->air_buf_addr += sizeof(acr);
615 aip->air_buf_len -= sizeof(acr);
616 break;
617
618 case AIOCS_INF_VST:
619 /*
620 * Pass off to device-specific handler
621 */
622 cup = (Cmn_unit *)arg;
623 if (cup == NULL)
624 err = ENXIO;
625 else
626 err = (*cup->cu_ioctl)(code, data, arg);
627 break;
628
629 default:
630 err = ENOSYS;
631 }
632
633 return ( err );
634 }
635
636
637 /*
638 * Register a Network Convergence Module
639 *
640 * Each ATM network convergence module must register itself here before
641 * it will receive network interface status notifications.
642 *
643 * Arguments:
644 * ncp pointer to network convergence definition structure
645 *
646 * Returns:
647 * 0 registration successful
648 * errno registration failed - reason indicated
649 *
650 */
651 int
652 atm_netconv_register(ncp)
653 struct atm_ncm *ncp;
654 {
655 struct atm_ncm *tdp;
656 int s = splnet();
657
658 /*
659 * See if we need to be initialized
660 */
661 if (!atm_init)
662 atm_initialize();
663
664 /*
665 * Validate protocol family
666 */
667 if (ncp->ncm_family > AF_MAX) {
668 (void) splx(s);
669 return (EINVAL);
670 }
671
672 /*
673 * Ensure no duplicates
674 */
675 for (tdp = atm_netconv_head; tdp != NULL; tdp = tdp->ncm_next) {
676 if (tdp->ncm_family == ncp->ncm_family) {
677 (void) splx(s);
678 return (EEXIST);
679 }
680 }
681
682 /*
683 * Add module to list
684 */
685 LINK2TAIL(ncp, struct atm_ncm, atm_netconv_head, ncm_next);
686
687 /*
688 * Add new interface output function
689 */
690 atm_ifouttbl[ncp->ncm_family] = ncp->ncm_ifoutput;
691
692 (void) splx(s);
693 return (0);
694 }
695
696
697 /*
698 * De-register an ATM Network Convergence Module
699 *
700 * Each ATM network convergence provider must de-register its registered
701 * service(s) before terminating. Specifically, loaded kernel modules
702 * must de-register their services before unloading themselves.
703 *
704 * Arguments:
705 * ncp pointer to network convergence definition structure
706 *
707 * Returns:
708 * 0 de-registration successful
709 * errno de-registration failed - reason indicated
710 *
711 */
712 int
713 atm_netconv_deregister(ncp)
714 struct atm_ncm *ncp;
715 {
716 int found, s = splnet();
717
718 /*
719 * Remove module from list
720 */
721 UNLINKF(ncp, struct atm_ncm, atm_netconv_head, ncm_next, found);
722
723 if (!found) {
724 (void) splx(s);
725 return (ENOENT);
726 }
727
728 /*
729 * Remove module's interface output function
730 */
731 atm_ifouttbl[ncp->ncm_family] = NULL;
732
733 (void) splx(s);
734 return (0);
735 }
736
737
738 /*
739 * Attach an ATM Network Interface
740 *
741 * Before an ATM network interface can be used by the system, the owning
742 * device interface must attach the network interface using this function.
743 * The physical interface for this network interface must have been previously
744 * registered (using atm_interface_register). The network interface will be
745 * added to the kernel's interface list and to the physical interface's list.
746 * The caller is responsible for initializing the control block fields.
747 *
748 * Arguments:
749 * nip pointer to atm network interface control block
750 *
751 * Returns:
752 * 0 attach successful
753 * errno attach failed - reason indicated
754 *
755 */
756 int
757 atm_nif_attach(nip)
758 struct atm_nif *nip;
759 {
760 struct atm_pif *pip, *pip2;
761 struct ifnet *ifp;
762 struct atm_ncm *ncp;
763 int s;
764
765 ifp = nip->nif_ifp;
766 if (ifp == NULL)
767 return (ENOSPC);
768 pip = nip->nif_pif;
769
770 s = splimp();
771
772 /*
773 * Verify physical interface is registered
774 */
775 for (pip2 = atm_interface_head; pip2 != NULL; pip2 = pip2->pif_next) {
776 if (pip == pip2)
777 break;
778 }
779 if ((pip == NULL) || (pip2 == NULL)) {
780 (void) splx(s);
781 return (EFAULT);
782 }
783
784 /*
785 * Add to system interface list
786 */
787 if_attach(ifp);
788
789 /*
790 * Add to BPF interface list
791 * DLT_ATM_RFC_1483 cannot be used because both NULL and LLC/SNAP could
792 * be provisioned
793 */
794 bpfattach(ifp, DLT_ATM_CLIP, T_ATM_LLC_MAX_LEN);
795
796 /*
797 * Add to physical interface list
798 */
799 LINK2TAIL(nip, struct atm_nif, pip->pif_nif, nif_pnext);
800
801 /*
802 * Notify network convergence modules of new network i/f
803 */
804 for (ncp = atm_netconv_head; ncp; ncp = ncp->ncm_next) {
805 int err;
806
807 err = (*ncp->ncm_stat)(NCM_ATTACH, nip, 0);
808 if (err) {
809 atm_nif_detach(nip);
810 (void) splx(s);
811 return (err);
812 }
813 }
814
815 (void) splx(s);
816 return (0);
817 }
818
819
820 /*
821 * Detach an ATM Network Interface
822 *
823 * Before an ATM network interface control block can be freed, all kernel
824 * references to/from this block must be released. This function will delete
825 * all routing references to the interface and free all interface addresses
826 * for the interface. The network interface will then be removed from the
827 * kernel's interface list and from the owning physical interface's list.
828 * The caller is responsible for free'ing the control block.
829 *
830 * Arguments:
831 * nip pointer to atm network interface control block
832 *
833 * Returns:
834 * none
835 *
836 */
837 void
838 atm_nif_detach(nip)
839 struct atm_nif *nip;
840 {
841 struct atm_ncm *ncp;
842 int s;
843 struct ifnet *ifp = nip->nif_ifp;
844
845 s = splimp();
846
847 /*
848 * Notify convergence modules of network i/f demise
849 */
850 for (ncp = atm_netconv_head; ncp; ncp = ncp->ncm_next) {
851 (void) (*ncp->ncm_stat)(NCM_DETACH, nip, 0);
852 }
853
854 /*
855 * Remove from BPF interface list
856 */
857 bpfdetach(ifp);
858
859 /*
860 * Free all interface routes and addresses,
861 * delete all remaining routes using this interface,
862 * then remove from the system interface list
863 */
864 if_detach(ifp);
865 if_free(ifp);
866
867 /*
868 * Remove from physical interface list
869 */
870 UNLINK(nip, struct atm_nif, nip->nif_pif->pif_nif, nif_pnext);
871
872 (void) splx(s);
873 }
874
875 /*
876 * Set an ATM Network Interface address
877 *
878 * This is called from a device interface when processing an SIOCSIFADDR
879 * ioctl request. We just notify all convergence modules of the new address
880 * and hope everyone has non-overlapping interests, since if someone reports
881 * an error we don't go back and tell everyone to undo the change.
882 *
883 * Arguments:
884 * nip pointer to atm network interface control block
885 * ifa pointer to new interface address
886 *
887 * Returns:
888 * 0 set successful
889 * errno set failed - reason indicated
890 *
891 */
892 int
893 atm_nif_setaddr(nip, ifa)
894 struct atm_nif *nip;
895 struct ifaddr *ifa;
896 {
897 struct atm_ncm *ncp;
898 int err = 0, s = splnet();
899
900 /*
901 * Notify convergence modules of network i/f change
902 */
903 for (ncp = atm_netconv_head; ncp; ncp = ncp->ncm_next) {
904 err = (*ncp->ncm_stat)(NCM_SETADDR, nip, (intptr_t)ifa);
905 if (err)
906 break;
907 }
908 (void) splx(s);
909
910 return (err);
911 }
912
913
914 /*
915 * ATM Interface Packet Output
916 *
917 * All ATM network interfaces must have their ifnet if_output address set to
918 * this function. Since no existing network layer code is to be modified
919 * for ATM support, this function serves as the hook to allow network output
920 * packets to be assigned to their proper outbound VCC. Each network address
921 * family which is to be supported over ATM must be assigned an output
922 * packet processing function via atm_netconv_register().
923 *
924 * Arguments:
925 * ifp pointer to ifnet structure
926 * m pointer to packet buffer chain to be output
927 * dst pointer to packet's network destination address
928 *
929 * Returns:
930 * 0 packet queued to interface
931 * errno output failed - reason indicated
932 *
933 */
934 int
935 atm_ifoutput(ifp, m, dst, rt)
936 struct ifnet *ifp;
937 KBuffer *m;
938 struct sockaddr *dst;
939 struct rtentry *rt;
940 {
941 u_short fam = dst->sa_family;
942 int (*func)(struct ifnet *, KBuffer *,
943 struct sockaddr *);
944
945 /*
946 * Validate address family
947 */
948 if (fam > AF_MAX) {
949 KB_FREEALL(m);
950 return (EAFNOSUPPORT);
951 }
952
953 /*
954 * Hand packet off for dst-to-VCC mapping
955 */
956 func = atm_ifouttbl[fam];
957 if (func == NULL) {
958 KB_FREEALL(m);
959 return (EAFNOSUPPORT);
960 }
961 return ((*func)(ifp, m, dst));
962 }
963
964
965 /*
966 * Handle interface ioctl requests.
967 *
968 * Arguments:
969 * ifp pointer to network interface structure
970 * cmd IOCTL cmd
971 * data arguments to/from ioctl
972 *
973 * Returns:
974 * error errno value
975 */
976 static int
977 atm_if_ioctl(ifp, cmd, data)
978 struct ifnet *ifp;
979 u_long cmd;
980 caddr_t data;
981 {
982 register struct ifreq *ifr = (struct ifreq *)data;
983 struct atm_nif *nip = IFP2ANIF(ifp);
984 int error = 0;
985 int s = splnet();
986
987 switch ( cmd )
988 {
989 case SIOCGIFADDR:
990 bcopy ( (caddr_t)&(nip->nif_pif->pif_macaddr),
991 (caddr_t)ifr->ifr_addr.sa_data,
992 sizeof(struct mac_addr) );
993 break;
994
995 case SIOCSIFADDR:
996 error = atm_nif_setaddr ( nip, (struct ifaddr *)data);
997 ifp->if_flags |= IFF_UP | IFF_BROADCAST;
998 ifp->if_drv_flags |= IFF_DRV_RUNNING;
999 break;
1000
1001 case SIOCGIFFLAGS:
1002 *(int *)data = ifp->if_flags;
1003 break;
1004
1005 case SIOCSIFFLAGS:
1006 break;
1007
1008 default:
1009 error = EINVAL;
1010 break;
1011 }
1012
1013 (void) splx(s);
1014 return ( error );
1015 }
1016
1017
1018 /*
1019 * Parse interface name
1020 *
1021 * Parses an interface name string into a name and a unit component.
1022 *
1023 * Arguments:
1024 * name pointer to interface name string
1025 * namep address to store interface name
1026 * size size available at namep
1027 * unitp address to store interface unit number
1028 *
1029 * Returns:
1030 * 0 name parsed
1031 * else parse error
1032 *
1033 */
1034 static int
1035 atm_ifparse(const char *name, char *namep, size_t size, int *unitp)
1036 {
1037 const char *cp;
1038 char *np;
1039 size_t len = 0;
1040 int unit = 0;
1041
1042 /*
1043 * Separate supplied string into name and unit parts.
1044 */
1045 cp = name;
1046 np = namep;
1047 while (*cp) {
1048 if (*cp >= '' && *cp <= '9')
1049 break;
1050 if (++len >= size)
1051 return (-1);
1052 *np++ = *cp++;
1053 }
1054 *np = '\0';
1055 while (*cp && *cp >= '' && *cp <= '9')
1056 unit = 10 * unit + *cp++ - '';
1057
1058 *unitp = unit;
1059
1060 return (0);
1061 }
1062
1063
1064 /*
1065 * Locate ATM physical interface via name
1066 *
1067 * Uses the supplied interface name string to locate a registered
1068 * ATM physical interface.
1069 *
1070 * Arguments:
1071 * name pointer to interface name string
1072 *
1073 * Returns:
1074 * 0 interface not found
1075 * else pointer to atm physical interface structure
1076 *
1077 */
1078 struct atm_pif *
1079 atm_pifname(name)
1080 char *name;
1081 {
1082 struct atm_pif *pip;
1083 char n[IFNAMSIZ];
1084 int unit;
1085
1086 /*
1087 * Break down name
1088 */
1089 if (atm_ifparse(name, n, sizeof(n), &unit))
1090 return ((struct atm_pif *)0);
1091
1092 /*
1093 * Look for the physical interface
1094 */
1095 for (pip = atm_interface_head; pip; pip = pip->pif_next) {
1096 if ((pip->pif_unit == unit) && (strcmp(pip->pif_name, n) == 0))
1097 break;
1098 }
1099
1100 return (pip);
1101 }
1102
1103
1104 /*
1105 * Locate ATM network interface via name
1106 *
1107 * Uses the supplied interface name string to locate an ATM network interface.
1108 *
1109 * Arguments:
1110 * name pointer to interface name string
1111 *
1112 * Returns:
1113 * 0 interface not found
1114 * else pointer to atm network interface structure
1115 *
1116 */
1117 struct atm_nif *
1118 atm_nifname(name)
1119 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 }
Cache object: b37a8a9d4ab920d6454926bb303b0ace
|