]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * The contents of this file constitute Original Code as defined in and | |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
11 | * | |
12 | * This Original Code and all software distributed under the License are | |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the | |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
19 | * | |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | /* $NetBSD: if_atmsubr.c,v 1.10 1997/03/11 23:19:51 chuck Exp $ */ | |
23 | ||
24 | /* | |
25 | * | |
26 | * Copyright (c) 1996 Charles D. Cranor and Washington University. | |
27 | * All rights reserved. | |
28 | * | |
29 | * Redistribution and use in source and binary forms, with or without | |
30 | * modification, are permitted provided that the following conditions | |
31 | * are met: | |
32 | * 1. Redistributions of source code must retain the above copyright | |
33 | * notice, this list of conditions and the following disclaimer. | |
34 | * 2. Redistributions in binary form must reproduce the above copyright | |
35 | * notice, this list of conditions and the following disclaimer in the | |
36 | * documentation and/or other materials provided with the distribution. | |
37 | * 3. All advertising materials mentioning features or use of this software | |
38 | * must display the following acknowledgement: | |
39 | * This product includes software developed by Charles D. Cranor and | |
40 | * Washington University. | |
41 | * 4. The name of the author may not be used to endorse or promote products | |
42 | * derived from this software without specific prior written permission. | |
43 | * | |
44 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
45 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
46 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
47 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
48 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
49 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
50 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
51 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
52 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
53 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
54 | */ | |
55 | ||
56 | /* | |
57 | * if_atmsubr.c | |
58 | */ | |
59 | ||
60 | #include "opt_inet.h" | |
61 | #include "opt_natm.h" | |
62 | ||
63 | #include <sys/param.h> | |
64 | #include <sys/systm.h> | |
65 | #include <sys/mbuf.h> | |
66 | #include <sys/socket.h> | |
67 | #include <sys/sockio.h> | |
68 | #include <sys/malloc.h> | |
69 | #include <sys/errno.h> | |
70 | ||
71 | ||
72 | #include <net/if.h> | |
73 | #include <net/netisr.h> | |
74 | #include <net/route.h> | |
75 | #include <net/if_dl.h> | |
76 | #include <net/if_types.h> | |
77 | #include <net/if_atm.h> | |
78 | ||
79 | #include <netinet/in.h> | |
80 | #include <netinet/if_atm.h> | |
81 | #include <netinet/if_ether.h> /* XXX: for ETHERTYPE_* */ | |
82 | #if defined(INET) || defined(INET6) | |
83 | #include <netinet/in_var.h> | |
84 | #endif | |
85 | #if NATM | |
86 | #include <netnatm/natm.h> | |
87 | #endif | |
88 | ||
89 | #ifndef ETHERTYPE_IPV6 | |
90 | #define ETHERTYPE_IPV6 0x86dd | |
91 | #endif | |
92 | ||
93 | #define senderr(e) { error = (e); goto bad;} | |
94 | ||
95 | /* | |
96 | * atm_output: ATM output routine | |
97 | * inputs: | |
98 | * "ifp" = ATM interface to output to | |
99 | * "m0" = the packet to output | |
100 | * "dst" = the sockaddr to send to (either IP addr, or raw VPI/VCI) | |
101 | * "rt0" = the route to use | |
102 | * returns: error code [0 == ok] | |
103 | * | |
104 | * note: special semantic: if (dst == NULL) then we assume "m" already | |
105 | * has an atm_pseudohdr on it and just send it directly. | |
106 | * [for native mode ATM output] if dst is null, then | |
107 | * rt0 must also be NULL. | |
108 | */ | |
109 | ||
110 | int | |
111 | atm_output(ifp, m0, dst, rt0) | |
112 | register struct ifnet *ifp; | |
113 | struct mbuf *m0; | |
114 | struct sockaddr *dst; | |
115 | struct rtentry *rt0; | |
116 | { | |
117 | u_int16_t etype = 0; /* if using LLC/SNAP */ | |
118 | int s, error = 0, sz; | |
119 | struct atm_pseudohdr atmdst, *ad; | |
120 | register struct mbuf *m = m0; | |
121 | register struct rtentry *rt; | |
122 | struct atmllc *atmllc; | |
123 | struct atmllc *llc_hdr = NULL; | |
124 | u_int32_t atm_flags; | |
125 | ||
126 | if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) | |
127 | senderr(ENETDOWN); | |
128 | ||
129 | /* | |
130 | * check route | |
131 | */ | |
132 | if ((rt = rt0) != NULL) { | |
133 | ||
134 | if ((rt->rt_flags & RTF_UP) == 0) { /* route went down! */ | |
135 | if ((rt0 = rt = RTALLOC1(dst, 0)) != NULL) | |
136 | rt->rt_refcnt--; | |
137 | else | |
138 | senderr(EHOSTUNREACH); | |
139 | } | |
140 | ||
141 | if (rt->rt_flags & RTF_GATEWAY) { | |
142 | if (rt->rt_gwroute == 0) | |
143 | goto lookup; | |
144 | if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { | |
145 | rtfree(rt); rt = rt0; | |
146 | lookup: rt->rt_gwroute = RTALLOC1(rt->rt_gateway, 0); | |
147 | if ((rt = rt->rt_gwroute) == 0) | |
148 | senderr(EHOSTUNREACH); | |
149 | } | |
150 | } | |
151 | ||
152 | /* XXX: put RTF_REJECT code here if doing ATMARP */ | |
153 | ||
154 | } | |
155 | ||
156 | /* | |
157 | * check for non-native ATM traffic (dst != NULL) | |
158 | */ | |
159 | if (dst) { | |
160 | switch (dst->sa_family) { | |
161 | #if defined(INET) || defined(INET6) | |
162 | case AF_INET: | |
163 | case AF_INET6: | |
164 | if (!atmresolve(rt, m, dst, &atmdst)) { | |
165 | m = NULL; | |
166 | /* XXX: atmresolve already free'd it */ | |
167 | senderr(EHOSTUNREACH); | |
168 | /* XXX: put ATMARP stuff here */ | |
169 | /* XXX: watch who frees m on failure */ | |
170 | } | |
171 | if (dst->sa_family == AF_INET6) | |
172 | etype = htons(ETHERTYPE_IPV6); | |
173 | else | |
174 | etype = htons(ETHERTYPE_IP); | |
175 | break; | |
176 | #endif /* INET || INET6 */ | |
177 | ||
178 | case AF_UNSPEC: | |
179 | /* | |
180 | * XXX: bpfwrite or output from a pvc shadow if. | |
181 | * assuming dst contains 12 bytes (atm pseudo | |
182 | * header (4) + LLC/SNAP (8)) | |
183 | */ | |
184 | bcopy(dst->sa_data, &atmdst, sizeof(atmdst)); | |
185 | llc_hdr = (struct atmllc *)(dst->sa_data + sizeof(atmdst)); | |
186 | break; | |
187 | ||
188 | default: | |
189 | #if defined(__NetBSD__) || defined(__OpenBSD__) | |
190 | printf("%s: can't handle af%d\n", ifp->if_xname, | |
191 | dst->sa_family); | |
192 | #elif defined(__FreeBSD__) || defined(__bsdi__) | |
193 | printf("%s%d: can't handle af%d\n", ifp->if_name, | |
194 | ifp->if_unit, dst->sa_family); | |
195 | #endif | |
196 | senderr(EAFNOSUPPORT); | |
197 | } | |
198 | ||
199 | /* | |
200 | * must add atm_pseudohdr to data | |
201 | */ | |
202 | sz = sizeof(atmdst); | |
203 | atm_flags = ATM_PH_FLAGS(&atmdst); | |
204 | if (atm_flags & ATM_PH_LLCSNAP) sz += 8; /* sizeof snap == 8 */ | |
205 | M_PREPEND(m, sz, M_DONTWAIT); | |
206 | if (m == 0) | |
207 | senderr(ENOBUFS); | |
208 | ad = mtod(m, struct atm_pseudohdr *); | |
209 | *ad = atmdst; | |
210 | if (atm_flags & ATM_PH_LLCSNAP) { | |
211 | atmllc = (struct atmllc *)(ad + 1); | |
212 | if (llc_hdr == NULL) { | |
213 | bcopy(ATMLLC_HDR, atmllc->llchdr, | |
214 | sizeof(atmllc->llchdr)); | |
215 | ATM_LLC_SETTYPE(atmllc, etype); | |
216 | /* note: already in network order */ | |
217 | } | |
218 | else | |
219 | bcopy(llc_hdr, atmllc, sizeof(struct atmllc)); | |
220 | } | |
221 | } | |
222 | ||
223 | /* | |
224 | * Queue message on interface, and start output if interface | |
225 | * not yet active. | |
226 | */ | |
227 | s = splimp(); | |
228 | if (IF_QFULL(&ifp->if_snd)) { | |
229 | IF_DROP(&ifp->if_snd); | |
230 | splx(s); | |
231 | senderr(ENOBUFS); | |
232 | } | |
233 | ifp->if_obytes += m->m_pkthdr.len; | |
234 | IF_ENQUEUE(&ifp->if_snd, m); | |
235 | if ((ifp->if_flags & IFF_OACTIVE) == 0) | |
236 | (*ifp->if_start)(ifp); | |
237 | splx(s); | |
238 | return (error); | |
239 | ||
240 | bad: | |
241 | if (m) | |
242 | m_freem(m); | |
243 | return (error); | |
244 | } | |
245 | ||
246 | /* | |
247 | * Process a received ATM packet; | |
248 | * the packet is in the mbuf chain m. | |
249 | */ | |
250 | void | |
251 | atm_input(ifp, ah, m, rxhand) | |
252 | struct ifnet *ifp; | |
253 | register struct atm_pseudohdr *ah; | |
254 | struct mbuf *m; | |
255 | void *rxhand; | |
256 | { | |
257 | register struct ifqueue *inq; | |
258 | u_int16_t etype = ETHERTYPE_IP; /* default */ | |
259 | int s; | |
260 | ||
261 | if ((ifp->if_flags & IFF_UP) == 0) { | |
262 | m_freem(m); | |
263 | return; | |
264 | } | |
265 | ifp->if_ibytes += m->m_pkthdr.len; | |
266 | ||
267 | #if ATM_PVCEXT | |
268 | if (ATM_PH_FLAGS(ah) & ATM_PH_PVCSIF) { | |
269 | /* | |
270 | * when PVC shadow interface is used, pointer to | |
271 | * the shadow interface is passed as rxhand. | |
272 | * override the receive interface of the packet. | |
273 | */ | |
274 | m->m_pkthdr.rcvif = (struct ifnet *)rxhand; | |
275 | rxhand = NULL; | |
276 | } | |
277 | #endif /* ATM_PVCEXT */ | |
278 | ||
279 | if (rxhand) { | |
280 | #if NATM | |
281 | struct natmpcb *npcb = rxhand; | |
282 | s = splimp(); /* in case 2 atm cards @ diff lvls */ | |
283 | npcb->npcb_inq++; /* count # in queue */ | |
284 | splx(s); | |
285 | schednetisr(NETISR_NATM); | |
286 | inq = &natmintrq; | |
287 | m->m_pkthdr.rcvif = rxhand; /* XXX: overload */ | |
288 | #else | |
289 | printf("atm_input: NATM detected but not configured in kernel\n"); | |
290 | m_freem(m); | |
291 | return; | |
292 | #endif | |
293 | } else { | |
294 | /* | |
295 | * handle LLC/SNAP header, if present | |
296 | */ | |
297 | if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) { | |
298 | struct atmllc *alc; | |
299 | if (m->m_len < sizeof(*alc) && | |
300 | (m = m_pullup(m, sizeof(*alc))) == 0) | |
301 | return; /* failed */ | |
302 | alc = mtod(m, struct atmllc *); | |
303 | if (bcmp(alc, ATMLLC_HDR, 6)) { | |
304 | #if defined(__NetBSD__) || defined(__OpenBSD__) | |
305 | printf("%s: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n", | |
306 | ifp->if_xname, ATM_PH_VPI(ah), ATM_PH_VCI(ah)); | |
307 | #elif defined(__FreeBSD__) || defined(__bsdi__) | |
308 | printf("%s%d: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n", | |
309 | ifp->if_name, ifp->if_unit, ATM_PH_VPI(ah), ATM_PH_VCI(ah)); | |
310 | #endif | |
311 | m_freem(m); | |
312 | return; | |
313 | } | |
314 | etype = ATM_LLC_TYPE(alc); | |
315 | m_adj(m, sizeof(*alc)); | |
316 | } | |
317 | ||
318 | switch (etype) { | |
319 | #if INET | |
320 | case ETHERTYPE_IP: | |
321 | schednetisr(NETISR_IP); | |
322 | inq = &ipintrq; | |
323 | break; | |
324 | #endif | |
325 | #if INET6 | |
326 | case ETHERTYPE_IPV6: | |
327 | schednetisr(NETISR_IPV6); | |
328 | inq = &ip6intrq; | |
329 | break; | |
330 | #endif | |
331 | default: | |
332 | m_freem(m); | |
333 | return; | |
334 | } | |
335 | } | |
336 | ||
337 | s = splimp(); | |
338 | if (IF_QFULL(inq)) { | |
339 | IF_DROP(inq); | |
340 | m_freem(m); | |
341 | } else | |
342 | IF_ENQUEUE(inq, m); | |
343 | splx(s); | |
344 | } | |
345 | ||
346 | /* | |
347 | * Perform common duties while attaching to interface list | |
348 | */ | |
349 | void | |
350 | atm_ifattach(ifp) | |
351 | register struct ifnet *ifp; | |
352 | { | |
353 | register struct ifaddr *ifa; | |
354 | register struct sockaddr_dl *sdl; | |
355 | ||
356 | ifp->if_type = IFT_ATM; | |
357 | ifp->if_addrlen = 0; | |
358 | ifp->if_hdrlen = 0; | |
359 | ifp->if_mtu = ATMMTU; | |
360 | ifp->if_output = atm_output; | |
361 | ||
362 | #if defined(__NetBSD__) || defined(__OpenBSD__) | |
363 | for (ifa = ifp->if_addrlist.tqh_first; ifa != 0; | |
364 | ifa = ifa->ifa_list.tqe_next) | |
365 | #elif defined(__FreeBSD__) && (__FreeBSD__ > 2) | |
366 | for (ifa = ifp->if_addrhead.tqh_first; ifa; | |
367 | ifa = ifa->ifa_link.tqe_next) | |
368 | #elif defined(__FreeBSD__) || defined(__bsdi__) | |
369 | for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) | |
370 | #endif | |
371 | if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && | |
372 | sdl->sdl_family == AF_LINK) { | |
373 | sdl->sdl_type = IFT_ATM; | |
374 | sdl->sdl_alen = ifp->if_addrlen; | |
375 | #ifdef notyet /* if using ATMARP, store hardware address using the next line */ | |
376 | bcopy(ifp->hw_addr, LLADDR(sdl), ifp->if_addrlen); | |
377 | #endif | |
378 | break; | |
379 | } | |
380 | ||
381 | } | |
382 | ||
383 | #if ATM_PVCEXT | |
384 | /* | |
385 | * ATM PVC shadow interface: a trick to assign a shadow interface | |
386 | * to a PVC. | |
387 | * with shadow interface, each PVC looks like an individual | |
388 | * Point-to-Point interface. | |
389 | * as oposed to the NBMA model, a shadow interface is inherently | |
390 | * multicast capable (no LANE/MARS required). | |
391 | */ | |
392 | struct pvcsif { | |
393 | struct ifnet sif_shadow; /* shadow ifnet structure per pvc */ | |
394 | struct atm_pseudohdr sif_aph; /* flags + vpi:vci */ | |
395 | struct ifnet *sif_ifp; /* pointer to the genuine interface */ | |
396 | }; | |
397 | ||
398 | static int pvc_output __P((struct ifnet *, struct mbuf *, | |
399 | struct sockaddr *, struct rtentry *)); | |
400 | static int pvc_ioctl __P((struct ifnet *, u_long, caddr_t)); | |
401 | ||
402 | /* | |
403 | * create and attach per pvc shadow interface | |
404 | * (currently detach is not supported) | |
405 | */ | |
406 | static int pvc_number = 0; | |
407 | ||
408 | struct ifnet * | |
409 | pvc_attach(ifp) | |
410 | struct ifnet *ifp; | |
411 | { | |
412 | struct pvcsif *pvcsif; | |
413 | struct ifnet *shadow; | |
414 | struct ifaddr *ifa; | |
415 | struct sockaddr_dl *sdl; | |
416 | int s; | |
417 | ||
418 | MALLOC(pvcsif, struct pvcsif *, sizeof(struct pvcsif), | |
419 | M_DEVBUF, M_WAITOK); | |
420 | bzero(pvcsif, sizeof(struct pvcsif)); | |
421 | ||
422 | pvcsif->sif_ifp = ifp; | |
423 | shadow = &pvcsif->sif_shadow; | |
424 | ||
425 | shadow->if_name = "pvc"; | |
426 | shadow->if_family = APPLE_IF_FAM_PVC; | |
427 | shadow->if_unit = pvc_number++; | |
428 | shadow->if_flags = ifp->if_flags | (IFF_POINTOPOINT | IFF_MULTICAST); | |
429 | shadow->if_ioctl = pvc_ioctl; | |
430 | shadow->if_output = pvc_output; | |
431 | shadow->if_start = NULL; | |
432 | shadow->if_mtu = ifp->if_mtu; | |
433 | shadow->if_type = ifp->if_type; | |
434 | shadow->if_addrlen = ifp->if_addrlen; | |
435 | shadow->if_hdrlen = ifp->if_hdrlen; | |
436 | shadow->if_softc = pvcsif; | |
437 | shadow->if_snd.ifq_maxlen = 50; /* dummy */ | |
438 | ||
439 | s = splimp(); | |
440 | if_attach(shadow); | |
441 | ||
442 | #if defined(__NetBSD__) || defined(__OpenBSD__) | |
443 | for (ifa = shadow->if_addrlist.tqh_first; ifa != 0; | |
444 | ifa = ifa->ifa_list.tqe_next) | |
445 | #elif defined(__FreeBSD__) && (__FreeBSD__ > 2) | |
446 | for (ifa = shadow->if_addrhead.tqh_first; ifa; | |
447 | ifa = ifa->ifa_link.tqe_next) | |
448 | #elif defined(__FreeBSD__) || defined(__bsdi__) | |
449 | for (ifa = shadow->if_addrlist; ifa; ifa = ifa->ifa_next) | |
450 | #endif | |
451 | if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && | |
452 | sdl->sdl_family == AF_LINK) { | |
453 | sdl->sdl_type = IFT_ATM; | |
454 | sdl->sdl_alen = shadow->if_addrlen; | |
455 | break; | |
456 | } | |
457 | splx(s); | |
458 | ||
459 | return (shadow); | |
460 | } | |
461 | ||
462 | /* | |
463 | * pvc_output relays the packet to atm_output along with vpi:vci info. | |
464 | */ | |
465 | static int | |
466 | pvc_output(shadow, m, dst, rt) | |
467 | struct ifnet *shadow; | |
468 | struct mbuf *m; | |
469 | struct sockaddr *dst; | |
470 | struct rtentry *rt; | |
471 | { | |
472 | struct pvcsif *pvcsif; | |
473 | struct sockaddr dst_addr; | |
474 | struct atmllc *atmllc; | |
475 | u_int16_t etype = 0; | |
476 | int error = 0; | |
477 | ||
478 | if ((shadow->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) | |
479 | senderr(ENETDOWN); | |
480 | ||
481 | pvcsif = shadow->if_softc; | |
482 | if (ATM_PH_VCI(&pvcsif->sif_aph) == 0) | |
483 | senderr(ENETDOWN); | |
484 | ||
485 | /* | |
486 | * create a dummy sockaddr: (using bpfwrite interface) | |
487 | * put atm pseudo header and llc/snap into sa_data (12 bytes) | |
488 | * and mark it as AF_UNSPEC. | |
489 | */ | |
490 | if (dst) { | |
491 | switch (dst->sa_family) { | |
492 | #if defined(INET) || defined(INET6) | |
493 | case AF_INET: | |
494 | case AF_INET6: | |
495 | if (dst->sa_family == AF_INET6) | |
496 | etype = htons(ETHERTYPE_IPV6); | |
497 | else | |
498 | etype = htons(ETHERTYPE_IP); | |
499 | break; | |
500 | #endif | |
501 | ||
502 | default: | |
503 | printf("%s%d: can't handle af%d\n", shadow->if_name, | |
504 | shadow->if_unit, dst->sa_family); | |
505 | senderr(EAFNOSUPPORT); | |
506 | } | |
507 | } | |
508 | ||
509 | dst_addr.sa_family = AF_UNSPEC; | |
510 | bcopy(&pvcsif->sif_aph, dst_addr.sa_data, | |
511 | sizeof(struct atm_pseudohdr)); | |
512 | atmllc = (struct atmllc *) | |
513 | (dst_addr.sa_data + sizeof(struct atm_pseudohdr)); | |
514 | bcopy(ATMLLC_HDR, atmllc->llchdr, sizeof(atmllc->llchdr)); | |
515 | ATM_LLC_SETTYPE(atmllc, etype); /* note: already in network order */ | |
516 | ||
517 | return atm_output(pvcsif->sif_ifp, m, &dst_addr, rt); | |
518 | ||
519 | bad: | |
520 | if (m) | |
521 | m_freem(m); | |
522 | return (error); | |
523 | } | |
524 | ||
525 | static int | |
526 | pvc_ioctl(shadow, cmd, data) | |
527 | struct ifnet *shadow; | |
528 | u_long cmd; | |
529 | caddr_t data; | |
530 | { | |
531 | struct ifnet *ifp; | |
532 | struct pvcsif *pvcsif; | |
533 | struct ifreq *ifr = (struct ifreq *) data; | |
534 | void (*ifa_rtrequest)(int, struct rtentry *, struct sockaddr *) = NULL; | |
535 | int error = 0; | |
536 | ||
537 | pvcsif = (struct pvcsif *)shadow->if_softc; | |
538 | ifp = pvcsif->sif_ifp; | |
539 | if (ifp == 0 || ifp->if_ioctl == 0) | |
540 | return (EOPNOTSUPP); | |
541 | ||
542 | /* | |
543 | * pre process | |
544 | */ | |
545 | switch (cmd) { | |
546 | case SIOCGPVCSIF: | |
547 | snprintf(ifr->ifr_name, sizeof(ifr->ifr_name), | |
548 | "%s%d", ifp->if_name, ifp->if_unit); | |
549 | return (0); | |
550 | ||
551 | case SIOCGPVCTX: | |
552 | do { | |
553 | struct pvctxreq *pvcreq = (struct pvctxreq *)data; | |
554 | ||
555 | snprintf(pvcreq->pvc_ifname, | |
556 | sizeof(pvcreq->pvc_ifname), "%s%d", | |
557 | ifp->if_name, ifp->if_unit); | |
558 | pvcreq->pvc_aph = pvcsif->sif_aph; | |
559 | } while (0); | |
560 | break; | |
561 | ||
562 | case SIOCADDMULTI: | |
563 | case SIOCDELMULTI: | |
564 | if (ifr == 0) | |
565 | return (EAFNOSUPPORT); /* XXX */ | |
566 | switch (ifr->ifr_addr.sa_family) { | |
567 | #if INET | |
568 | case AF_INET: | |
569 | return (0); | |
570 | #endif | |
571 | #if INET6 | |
572 | case AF_INET6: | |
573 | return (0); | |
574 | #endif | |
575 | default: | |
576 | return (EAFNOSUPPORT); | |
577 | } | |
578 | break; | |
579 | case SIOCSIFADDR: | |
580 | if (ifp->if_flags & IFF_UP) { | |
581 | /* real if is already up */ | |
582 | shadow->if_flags = ifp->if_flags | | |
583 | (IFF_POINTOPOINT|IFF_MULTICAST); | |
584 | return (0); | |
585 | } | |
586 | /* | |
587 | * XXX: save the rtrequest field since the atm driver | |
588 | * overwrites this field. | |
589 | */ | |
590 | ifa_rtrequest = ((struct ifaddr *)data)->ifa_rtrequest; | |
591 | break; | |
592 | ||
593 | case SIOCSIFFLAGS: | |
594 | if ((shadow->if_flags & IFF_UP) == 0) { | |
595 | /* | |
596 | * interface down. don't pass this to | |
597 | * the real interface. | |
598 | */ | |
599 | return (0); | |
600 | } | |
601 | if (shadow->if_flags & IFF_UP) { | |
602 | /* | |
603 | * interface up. if the real if is already up, | |
604 | * nothing to do. | |
605 | */ | |
606 | if (ifp->if_flags & IFF_UP) { | |
607 | shadow->if_flags = ifp->if_flags | | |
608 | (IFF_POINTOPOINT|IFF_MULTICAST); | |
609 | return (0); | |
610 | } | |
611 | } | |
612 | break; | |
613 | } | |
614 | ||
615 | /* | |
616 | * pass the ioctl to the genuine interface | |
617 | */ | |
618 | error = (*ifp->if_ioctl)(ifp, cmd, data); | |
619 | ||
620 | /* | |
621 | * post process | |
622 | */ | |
623 | switch (cmd) { | |
624 | case SIOCSIFMTU: | |
625 | shadow->if_mtu = ifp->if_mtu; | |
626 | break; | |
627 | case SIOCSIFADDR: | |
628 | /* restore rtrequest */ | |
629 | ((struct ifaddr *)data)->ifa_rtrequest = ifa_rtrequest; | |
630 | /* fall into... */ | |
631 | case SIOCSIFFLAGS: | |
632 | /* update if_flags */ | |
633 | shadow->if_flags = ifp->if_flags | |
634 | | (IFF_POINTOPOINT|IFF_MULTICAST); | |
635 | break; | |
636 | } | |
637 | ||
638 | return (error); | |
639 | } | |
640 | ||
641 | int pvc_setaph(shadow, aph) | |
642 | struct ifnet *shadow; | |
643 | struct atm_pseudohdr *aph; | |
644 | { | |
645 | struct pvcsif *pvcsif; | |
646 | ||
647 | pvcsif = shadow->if_softc; | |
648 | bcopy(aph, &pvcsif->sif_aph, sizeof(struct atm_pseudohdr)); | |
649 | return (0); | |
650 | } | |
651 | ||
652 | #endif /* ATM_PVCEXT */ |