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