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