- struct gif_softc *sc = (struct gif_softc*)ifp;
- struct ifreq *ifr = (struct ifreq*)data;
- int error = 0, size;
- struct sockaddr *sa, *dst, *src;
- const struct encaptab *p;
- struct sockaddr_in smask4, dmask4;
-
- switch (cmd) {
- case SIOCSIFFLAGS:
- /*
- * whenever we change our idea about multi-destination mode
- * we need to update encap attachment.
- */
- if (((ifp->if_flags ^ sc->gif_oflags) & IFF_LINK0) == 0)
- break;
- if (sc->gif_psrc == NULL || sc->gif_pdst == NULL ||
- sc->gif_psrc->sa_family != sc->gif_pdst->sa_family)
- break;
- bzero(&smask4, sizeof(smask4));
- smask4.sin_addr.s_addr = ~0;
- dmask4 = smask4;
- if ((ifp->if_flags & IFF_LINK0) != 0 &&
- ((struct sockaddr_in *)dst)->sin_addr.s_addr ==
- INADDR_ANY) {
- bzero(&dmask4, sizeof(dmask4));
- }
- p = encap_attach(sc->gif_psrc->sa_family, -1, sc->gif_psrc,
- (struct sockaddr *)&smask4, sc->gif_pdst,
- (struct sockaddr *)&dmask4,
- (struct protosw *)&in_gif_protosw, &sc->gif_if);
- if (p == NULL) {
- error = EINVAL;
- goto bad;
- }
- if (sc->encap_cookie != NULL)
- (void)encap_detach(sc->encap_cookie);
- sc->encap_cookie = p;
- sc->gif_oflags = ifp->if_flags;
-
- break;
-
- case SIOCSIFPHYADDR:
- switch (ifr->ifr_addr.sa_family) {
- case AF_INET:
- src = (struct sockaddr *)
- &(((struct in_aliasreq *)data)->ifra_addr);
- dst = (struct sockaddr *)
- &(((struct in_aliasreq *)data)->ifra_dstaddr);
-
- bzero(&smask4, sizeof(smask4));
- smask4.sin_addr.s_addr = ~0;
- dmask4 = smask4;
- if ((ifp->if_flags & IFF_LINK0) != 0 &&
- ((struct sockaddr_in *)dst)->sin_addr.s_addr ==
- INADDR_ANY) {
- bzero(&dmask4, sizeof(dmask4));
- }
- size = sizeof(struct sockaddr_in);
- break;
- default:
- error = EAFNOSUPPORT;
- goto bad;
- }
-
- if (sc->encap_cookie)
- (void)encap_detach(sc->encap_cookie);
- if (sc->gif_psrc != NULL) {
- _FREE((caddr_t)sc->gif_psrc, M_IFADDR);
- sc->gif_psrc = NULL;
- }
- if (sc->gif_pdst != NULL) {
- _FREE((caddr_t)sc->gif_pdst, M_IFADDR);
- sc->gif_pdst = NULL;
+ struct ip ip;
+ struct gif_softc *sc;
+ struct sockaddr_in *src, *dst;
+ int addrmatch;
+ struct in_ifaddr *ia4;
+
+ /* sanity check done in caller */
+ sc = (struct gif_softc *)arg;
+ src = (struct sockaddr_in *)sc->gif_psrc;
+ dst = (struct sockaddr_in *)sc->gif_pdst;
+
+ /* LINTED const cast */
+ m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip);
+
+ /* check for address match */
+ addrmatch = 0;
+ if (src->sin_addr.s_addr == ip.ip_dst.s_addr)
+ addrmatch |= 1;
+ if (dst->sin_addr.s_addr == ip.ip_src.s_addr)
+ addrmatch |= 2;
+ if (addrmatch != 3)
+ return 0;
+
+ /* martian filters on outer source - NOT done in ip_input! */
+ if (IN_MULTICAST(ntohl(ip.ip_src.s_addr)))
+ return 0;
+ switch ((ntohl(ip.ip_src.s_addr) & 0xff000000) >> 24) {
+ case 0: case 127: case 255:
+ return 0;
+ }
+ /* reject packets with broadcast on source */
+ lck_mtx_lock(rt_mtx);
+ for (ia4 = TAILQ_FIRST(&in_ifaddrhead); ia4;
+ ia4 = TAILQ_NEXT(ia4, ia_link))
+ {
+ if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0)
+ continue;
+ if (ip.ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr) {
+ lck_mtx_unlock(rt_mtx);
+ return 0;