Commit | Line | Data |
---|---|---|
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 | 43 | static int atm_physif_ioctl (int, caddr_t, caddr_t); |
3e0c9cba | 44 | static int atm_netif_rtdel (struct radix_node *, void *); |
9974b71d | 45 | static int atm_if_ioctl (struct ifnet *, u_long, caddr_t, struct ucred *); |
3e0c9cba | 46 | static int atm_ifparse (char *, char *, int, int *); |
984263bc MD |
47 | |
48 | /* | |
49 | * Local variables | |
50 | */ | |
51 | static 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 | */ | |
74 | int | |
9855a82b | 75 | atm_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 | */ | |
141 | int | |
9855a82b | 142 | atm_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 | */ | |
213 | void | |
9855a82b | 214 | atm_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 | */ | |
260 | static int | |
9855a82b | 261 | atm_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 | */ | |
599 | int | |
9855a82b | 600 | atm_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 | */ | |
659 | int | |
9855a82b | 660 | atm_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 | */ | |
704 | int | |
78195a76 | 705 | atm_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 | */ | |
774 | void | |
9855a82b | 775 | atm_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 | */ | |
859 | static int | |
9855a82b | 860 | atm_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 | */ | |
904 | int | |
9855a82b | 905 | atm_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 |
945 | static int |
946 | atm_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 |
972 | int |
973 | atm_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 | */ | |
996 | static int | |
9974b71d | 997 | atm_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 | */ | |
1050 | static int | |
9855a82b | 1051 | atm_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 | */ | |
1092 | struct atm_pif * | |
9855a82b | 1093 | atm_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 | */ | |
1130 | struct atm_nif * | |
9855a82b | 1131 | atm_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 |