1 /* $OpenBSD: if_gif.c,v 1.20 2001/07/27 15:48:38 itojun Exp $ */ 2 /* $KAME: if_gif.c,v 1.43 2001/02/20 08:51:07 itojun Exp $ */ 3 4 /* 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/kernel.h> 36 #include <sys/mbuf.h> 37 #include <sys/socket.h> 38 #include <sys/sockio.h> 39 #include <sys/syslog.h> 40 41 #include <net/if.h> 42 #include <net/if_types.h> 43 #include <net/route.h> 44 #include <net/bpf.h> 45 46 #ifdef INET 47 #include <netinet/in.h> 48 #include <netinet/in_var.h> 49 #include <netinet/in_gif.h> 50 #endif /* INET */ 51 52 #ifdef INET6 53 #ifndef INET 54 #include <netinet/in.h> 55 #endif 56 #include <netinet6/in6_gif.h> 57 #endif /* INET6 */ 58 59 #include <net/if_gif.h> 60 61 #include "bpfilter.h" 62 #include "bridge.h" 63 64 extern int ifqmaxlen; 65 66 int ngif; 67 void gifattach __P((int)); 68 69 /* 70 * gif global variable definitions 71 */ 72 struct gif_softc *gif_softc = 0; 73 74 void 75 gifattach(n) 76 int n; 77 { 78 register struct gif_softc *sc; 79 register int i; 80 81 ngif = n; 82 gif_softc = sc = malloc (ngif * sizeof(struct gif_softc), 83 M_DEVBUF, M_WAIT); 84 bzero(sc, ngif * sizeof(struct gif_softc)); 85 for (i = 0; i < ngif; sc++, i++) { 86 sprintf(sc->gif_if.if_xname, "gif%d", i); 87 sc->gif_if.if_mtu = GIF_MTU; 88 sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 89 sc->gif_if.if_ioctl = gif_ioctl; 90 sc->gif_if.if_start = gif_start; 91 sc->gif_if.if_output = gif_output; 92 sc->gif_if.if_type = IFT_GIF; 93 sc->gif_if.if_snd.ifq_maxlen = ifqmaxlen; 94 sc->gif_if.if_softc = sc; 95 if_attach(&sc->gif_if); 96 97 #if NBPFILTER > 0 98 bpfattach(&sc->gif_if.if_bpf, &sc->gif_if, DLT_NULL, 99 sizeof(u_int)); 100 #endif 101 } 102 } 103 104 void 105 gif_start(ifp) 106 struct ifnet *ifp; 107 { 108 #if NBRIDGE > 0 109 struct sockaddr dst; 110 #endif /* NBRIDGE */ 111 112 struct mbuf *m; 113 int s; 114 115 #if NBRIDGE > 0 116 bzero(&dst, sizeof(dst)); 117 118 /* 119 * XXX The assumption here is that only the ethernet bridge 120 * uses the start routine of this interface, and it's thus 121 * safe to do this. 122 */ 123 dst.sa_family = AF_LINK; 124 #endif /* NBRIDGE */ 125 126 for (;;) { 127 s = splimp(); 128 IF_DEQUEUE(&ifp->if_snd, m); 129 splx(s); 130 131 if (m == NULL) return; 132 133 #if NBRIDGE > 0 134 /* Sanity check -- interface should be member of a bridge */ 135 if (ifp->if_bridge == NULL) m_freem(m); 136 else gif_output(ifp, m, &dst, NULL); 137 #else 138 m_freem(m); 139 #endif /* NBRIDGE */ 140 } 141 } 142 143 int 144 gif_output(ifp, m, dst, rt) 145 struct ifnet *ifp; 146 struct mbuf *m; 147 struct sockaddr *dst; 148 struct rtentry *rt; /* added in net2 */ 149 { 150 register struct gif_softc *sc = (struct gif_softc*)ifp; 151 int error = 0; 152 struct m_tag *mtag; 153 154 /* 155 * gif may cause infinite recursion calls when misconfigured. 156 * We'll prevent this by detecting loops. 157 */ 158 for (mtag = m_tag_find(m, PACKET_TAG_GIF, NULL); mtag; 159 mtag = m_tag_find(m, PACKET_TAG_GIF, mtag)) { 160 if (!bcmp((caddr_t)(mtag + 1), &ifp, sizeof(struct ifnet *))) { 161 IF_DROP(&ifp->if_snd); 162 log(LOG_NOTICE, 163 "gif_output: recursively called too many times\n"); 164 m_freem(m); 165 error = EIO; /* is there better errno? */ 166 goto end; 167 } 168 } 169 170 mtag = m_tag_get(PACKET_TAG_GIF, sizeof(struct ifnet *), M_NOWAIT); 171 if (mtag == NULL) { 172 IF_DROP(&ifp->if_snd); 173 m_freem(m); 174 error = ENOMEM; 175 goto end; 176 } 177 bcopy(&ifp, (caddr_t)(mtag + 1), sizeof(struct ifnet *)); 178 m_tag_prepend(m, mtag); 179 180 m->m_flags &= ~(M_BCAST|M_MCAST); 181 if (!(ifp->if_flags & IFF_UP) || 182 sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 183 log(LOG_NOTICE, 184 "gif_output: attempt to use unconfigured interface %s\n", 185 ifp->if_xname); 186 m_freem(m); 187 error = ENETDOWN; 188 goto end; 189 } 190 191 #if NBPFILTER > 0 192 if (ifp->if_bpf) { 193 /* 194 * We need to prepend the address family as 195 * a four byte field. Cons up a dummy header 196 * to pacify bpf. This is safe because bpf 197 * will only read from the mbuf (i.e., it won't 198 * try to free it or keep a pointer a to it). 199 */ 200 struct mbuf m0; 201 u_int32_t af = dst->sa_family; 202 203 m0.m_next = m; 204 m0.m_len = 4; 205 m0.m_data = (char *)⁡ 206 207 bpf_mtap(ifp->if_bpf, &m0); 208 } 209 #endif 210 ifp->if_opackets++; 211 ifp->if_obytes += m->m_pkthdr.len; 212 213 switch (sc->gif_psrc->sa_family) { 214 #ifdef INET 215 case AF_INET: 216 error = in_gif_output(ifp, dst->sa_family, m, rt); 217 break; 218 #endif 219 #ifdef INET6 220 case AF_INET6: 221 error = in6_gif_output(ifp, dst->sa_family, m, rt); 222 break; 223 #endif 224 default: 225 m_freem(m); 226 error = ENETDOWN; 227 } 228 229 end: 230 if (error) ifp->if_oerrors++; 231 return error; 232 } 233 234 int 235 gif_ioctl(ifp, cmd, data) 236 struct ifnet *ifp; 237 u_long cmd; 238 caddr_t data; 239 { 240 struct gif_softc *sc = (struct gif_softc*)ifp; 241 struct ifreq *ifr = (struct ifreq*)data; 242 int error = 0, size; 243 struct sockaddr *dst, *src; 244 struct sockaddr *sa; 245 int i; 246 int s; 247 struct gif_softc *sc2; 248 249 switch (cmd) { 250 case SIOCSIFADDR: 251 break; 252 253 case SIOCSIFDSTADDR: 254 break; 255 256 case SIOCADDMULTI: 257 case SIOCDELMULTI: 258 switch (ifr->ifr_addr.sa_family) { 259 #ifdef INET 260 case AF_INET: /* IP supports Multicast */ 261 break; 262 #endif /* INET */ 263 #ifdef INET6 264 case AF_INET6: /* IP6 supports Multicast */ 265 break; 266 #endif /* INET6 */ 267 default: /* Other protocols doesn't support Multicast */ 268 error = EAFNOSUPPORT; 269 break; 270 } 271 break; 272 273 case SIOCSIFPHYADDR: 274 #ifdef INET6 275 case SIOCSIFPHYADDR_IN6: 276 #endif /* INET6 */ 277 case SIOCSLIFPHYADDR: 278 switch (cmd) { 279 #ifdef INET 280 case SIOCSIFPHYADDR: 281 src = (struct sockaddr *) 282 &(((struct in_aliasreq *)data)->ifra_addr); 283 dst = (struct sockaddr *) 284 &(((struct in_aliasreq *)data)->ifra_dstaddr); 285 break; 286 #endif 287 #ifdef INET6 288 case SIOCSIFPHYADDR_IN6: 289 src = (struct sockaddr *) 290 &(((struct in6_aliasreq *)data)->ifra_addr); 291 dst = (struct sockaddr *) 292 &(((struct in6_aliasreq *)data)->ifra_dstaddr); 293 break; 294 #endif 295 case SIOCSLIFPHYADDR: 296 src = (struct sockaddr *) 297 &(((struct if_laddrreq *)data)->addr); 298 dst = (struct sockaddr *) 299 &(((struct if_laddrreq *)data)->dstaddr); 300 } 301 302 /* sa_family must be equal */ 303 if (src->sa_family != dst->sa_family) 304 return EINVAL; 305 306 /* validate sa_len */ 307 switch (src->sa_family) { 308 #ifdef INET 309 case AF_INET: 310 if (src->sa_len != sizeof(struct sockaddr_in)) 311 return EINVAL; 312 break; 313 #endif 314 #ifdef INET6 315 case AF_INET6: 316 if (src->sa_len != sizeof(struct sockaddr_in6)) 317 return EINVAL; 318 break; 319 #endif 320 default: 321 return EAFNOSUPPORT; 322 } 323 switch (dst->sa_family) { 324 #ifdef INET 325 case AF_INET: 326 if (dst->sa_len != sizeof(struct sockaddr_in)) 327 return EINVAL; 328 break; 329 #endif 330 #ifdef INET6 331 case AF_INET6: 332 if (dst->sa_len != sizeof(struct sockaddr_in6)) 333 return EINVAL; 334 break; 335 #endif 336 default: 337 return EAFNOSUPPORT; 338 } 339 340 /* check sa_family looks sane for the cmd */ 341 switch (cmd) { 342 case SIOCSIFPHYADDR: 343 if (src->sa_family == AF_INET) 344 break; 345 return EAFNOSUPPORT; 346 #ifdef INET6 347 case SIOCSIFPHYADDR_IN6: 348 if (src->sa_family == AF_INET6) 349 break; 350 return EAFNOSUPPORT; 351 #endif /* INET6 */ 352 case SIOCSLIFPHYADDR: 353 /* checks done in the above */ 354 break; 355 } 356 357 for (i = 0; i < ngif; i++) { 358 sc2 = gif_softc + i; 359 if (sc2 == sc) 360 continue; 361 if (!sc2->gif_pdst || !sc2->gif_psrc) 362 continue; 363 if (sc2->gif_pdst->sa_family != dst->sa_family || 364 sc2->gif_pdst->sa_len != dst->sa_len || 365 sc2->gif_psrc->sa_family != src->sa_family || 366 sc2->gif_psrc->sa_len != src->sa_len) 367 continue; 368 /* can't configure same pair of address onto two gifs */ 369 if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && 370 bcmp(sc2->gif_psrc, src, src->sa_len) == 0) { 371 error = EADDRNOTAVAIL; 372 goto bad; 373 } 374 375 /* can't configure multiple multi-dest interfaces */ 376 #define multidest(x) \ 377 (((struct sockaddr_in *)(x))->sin_addr.s_addr == INADDR_ANY) 378 #ifdef INET6 379 #define multidest6(x) \ 380 (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(x))->sin6_addr)) 381 #endif 382 if (dst->sa_family == AF_INET && 383 multidest(dst) && multidest(sc2->gif_pdst)) { 384 error = EADDRNOTAVAIL; 385 goto bad; 386 } 387 #ifdef INET6 388 if (dst->sa_family == AF_INET6 && 389 multidest6(dst) && multidest6(sc2->gif_pdst)) { 390 error = EADDRNOTAVAIL; 391 goto bad; 392 } 393 #endif 394 } 395 396 if (sc->gif_psrc) 397 free((caddr_t)sc->gif_psrc, M_IFADDR); 398 sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK); 399 bcopy((caddr_t)src, (caddr_t)sa, src->sa_len); 400 sc->gif_psrc = sa; 401 402 if (sc->gif_pdst) 403 free((caddr_t)sc->gif_pdst, M_IFADDR); 404 sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK); 405 bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len); 406 sc->gif_pdst = sa; 407 408 s = splnet(); 409 ifp->if_flags |= IFF_RUNNING; 410 if_up(ifp); /* send up RTM_IFINFO */ 411 splx(s); 412 413 error = 0; 414 break; 415 416 #ifdef SIOCDIFPHYADDR 417 case SIOCDIFPHYADDR: 418 if (sc->gif_psrc) { 419 free((caddr_t)sc->gif_psrc, M_IFADDR); 420 sc->gif_psrc = NULL; 421 } 422 if (sc->gif_pdst) { 423 free((caddr_t)sc->gif_pdst, M_IFADDR); 424 sc->gif_pdst = NULL; 425 } 426 /* change the IFF_{UP, RUNNING} flag as well? */ 427 break; 428 #endif 429 430 case SIOCGIFPSRCADDR: 431 #ifdef INET6 432 case SIOCGIFPSRCADDR_IN6: 433 #endif /* INET6 */ 434 if (sc->gif_psrc == NULL) { 435 error = EADDRNOTAVAIL; 436 goto bad; 437 } 438 src = sc->gif_psrc; 439 switch (cmd) { 440 #ifdef INET 441 case SIOCGIFPSRCADDR: 442 dst = &ifr->ifr_addr; 443 size = sizeof(ifr->ifr_addr); 444 break; 445 #endif /* INET */ 446 #ifdef INET6 447 case SIOCGIFPSRCADDR_IN6: 448 dst = (struct sockaddr *) 449 &(((struct in6_ifreq *)data)->ifr_addr); 450 size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 451 break; 452 #endif /* INET6 */ 453 default: 454 error = EADDRNOTAVAIL; 455 goto bad; 456 } 457 if (src->sa_len > size) 458 return EINVAL; 459 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 460 break; 461 462 case SIOCGIFPDSTADDR: 463 #ifdef INET6 464 case SIOCGIFPDSTADDR_IN6: 465 #endif /* INET6 */ 466 if (sc->gif_pdst == NULL) { 467 error = EADDRNOTAVAIL; 468 goto bad; 469 } 470 src = sc->gif_pdst; 471 switch (cmd) { 472 #ifdef INET 473 case SIOCGIFPDSTADDR: 474 dst = &ifr->ifr_addr; 475 size = sizeof(ifr->ifr_addr); 476 break; 477 #endif /* INET */ 478 #ifdef INET6 479 case SIOCGIFPDSTADDR_IN6: 480 dst = (struct sockaddr *) 481 &(((struct in6_ifreq *)data)->ifr_addr); 482 size = sizeof(((struct in6_ifreq *)data)->ifr_addr); 483 break; 484 #endif /* INET6 */ 485 default: 486 error = EADDRNOTAVAIL; 487 goto bad; 488 } 489 if (src->sa_len > size) 490 return EINVAL; 491 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 492 break; 493 494 case SIOCGLIFPHYADDR: 495 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { 496 error = EADDRNOTAVAIL; 497 goto bad; 498 } 499 500 /* copy src */ 501 src = sc->gif_psrc; 502 dst = (struct sockaddr *) 503 &(((struct if_laddrreq *)data)->addr); 504 size = sizeof(((struct if_laddrreq *)data)->addr); 505 if (src->sa_len > size) 506 return EINVAL; 507 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 508 509 /* copy dst */ 510 src = sc->gif_pdst; 511 dst = (struct sockaddr *) 512 &(((struct if_laddrreq *)data)->dstaddr); 513 size = sizeof(((struct if_laddrreq *)data)->dstaddr); 514 if (src->sa_len > size) 515 return EINVAL; 516 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); 517 break; 518 519 case SIOCSIFFLAGS: 520 /* if_ioctl() takes care of it */ 521 break; 522 523 default: 524 error = EINVAL; 525 break; 526 } 527 bad: 528 return error; 529 } 530