diff options
author | wpaul <wpaul@FreeBSD.org> | 2004-01-19 07:03:46 +0000 |
---|---|---|
committer | wpaul <wpaul@FreeBSD.org> | 2004-01-19 07:03:46 +0000 |
commit | a5104c2f15ece296848572b856144f35638a27b8 (patch) | |
tree | 71c1c7f7c0717856f499181dc629536ec240e103 /sys/dev/if_ndis/if_ndis.c | |
parent | 5a0431f630ef41b4c8dfbf0aa35c96e9104ea4c3 (diff) | |
download | FreeBSD-src-a5104c2f15ece296848572b856144f35638a27b8.zip FreeBSD-src-a5104c2f15ece296848572b856144f35638a27b8.tar.gz |
Properly program the multicast filter in ndis_setmulti(),
and fix promisc mode in ndis_ioctl().
Diffstat (limited to 'sys/dev/if_ndis/if_ndis.c')
-rw-r--r-- | sys/dev/if_ndis/if_ndis.c | 117 |
1 files changed, 86 insertions, 31 deletions
diff --git a/sys/dev/if_ndis/if_ndis.c b/sys/dev/if_ndis/if_ndis.c index 814f4a8..5de447d 100644 --- a/sys/dev/if_ndis/if_ndis.c +++ b/sys/dev/if_ndis/if_ndis.c @@ -172,10 +172,71 @@ static void ndis_setmulti(sc) struct ndis_softc *sc; { -#ifdef notyet - uint32_t ndis_filter; - int len; -#endif + struct ifnet *ifp; + struct ifmultiaddr *ifma; + int len, mclistsz, error; + uint8_t *mclist; + + ifp = &sc->arpcom.ac_if; + + if (!(ifp->if_flags & IFF_UP)) + return; + + if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { + sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; + len = sizeof(sc->ndis_filter); + error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER, + &sc->ndis_filter, &len); + if (error) + device_printf (sc->ndis_dev, + "set filter failed: %d\n", error); + return; + } + + + len = sizeof(mclistsz); + ndis_get_info(sc, OID_802_3_MAXIMUM_LIST_SIZE, &mclistsz, &len); + + mclist = malloc(ETHER_ADDR_LEN * mclistsz, M_TEMP, M_NOWAIT); + + if (mclist == NULL) { + sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; + goto out; + } + + sc->ndis_filter |= NDIS_PACKET_TYPE_MULTICAST; + + len = 0; + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), + mclist + (ETHER_ADDR_LEN * len), ETHER_ADDR_LEN); + len++; + if (len > mclistsz) { + sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; + sc->ndis_filter &= ~NDIS_PACKET_TYPE_MULTICAST; + goto out; + } + } + + len = len * ETHER_ADDR_LEN; + error = ndis_set_info(sc, OID_802_3_MULTICAST_LIST, mclist, &len); + if (error) { + device_printf (sc->ndis_dev, "set mclist failed: %d\n", error); + sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; + sc->ndis_filter &= ~NDIS_PACKET_TYPE_MULTICAST; + } + +out: + free(mclist, M_TEMP); + + len = sizeof(sc->ndis_filter); + error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER, + &sc->ndis_filter, &len); + if (error) + device_printf (sc->ndis_dev, "set filter failed: %d\n", error); + return; } @@ -1149,9 +1210,6 @@ ndis_init(xsc) struct ndis_softc *sc = xsc; struct ifnet *ifp = &sc->arpcom.ac_if; int i, error; - uint32_t ndis_filter = 0; - - /*NDIS_LOCK(sc);*/ /* * Cancel pending I/O and free all RX/TX buffers. @@ -1161,48 +1219,46 @@ ndis_init(xsc) ndis_init_nic(sc); /* Init our MAC address */ -#ifdef notdef - /* - * Program the multicast filter, if necessary. - */ - ndis_setmulti(sc); -#endif /* Program the packet filter */ - ndis_filter = NDIS_PACKET_TYPE_DIRECTED; + sc->ndis_filter = NDIS_PACKET_TYPE_DIRECTED; if (ifp->if_flags & IFF_BROADCAST) - ndis_filter |= NDIS_PACKET_TYPE_BROADCAST; + sc->ndis_filter |= NDIS_PACKET_TYPE_BROADCAST; if (ifp->if_flags & IFF_PROMISC) - ndis_filter |= NDIS_PACKET_TYPE_PROMISCUOUS; - - if (ifp->if_flags & IFF_MULTICAST) - ndis_filter |= NDIS_PACKET_TYPE_MULTICAST; + sc->ndis_filter |= NDIS_PACKET_TYPE_PROMISCUOUS; - i = sizeof(ndis_filter); + i = sizeof(sc->ndis_filter); error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER, - &ndis_filter, &i); - - sc->ndis_filter = ndis_filter; + &sc->ndis_filter, &i); if (error) device_printf (sc->ndis_dev, "set filter failed: %d\n", error); - sc->ndis_txidx = 0; - sc->ndis_txpending = sc->ndis_maxpkts; - sc->ndis_link = 0; + /* + * Program the multicast filter, if necessary. + */ + ndis_setmulti(sc); ndis_enable_intr(sc); if (sc->ndis_80211) ndis_setstate_80211(sc); + NDIS_LOCK(sc); + + sc->ndis_txidx = 0; + sc->ndis_txpending = sc->ndis_maxpkts; + sc->ndis_link = 0; + ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; + NDIS_UNLOCK(sc); + /* * Some drivers don't set this value. The NDIS spec says * the default checkforhang timeout is approximately 2 @@ -1215,8 +1271,6 @@ ndis_init(xsc) sc->ndis_stat_ch = timeout(ndis_tick, sc, hz * sc->ndis_block.nmb_checkforhangsecs); - /*NDIS_UNLOCK(sc);*/ - return; } @@ -1665,7 +1719,6 @@ ndis_ioctl(ifp, command, data) /*NDIS_LOCK(sc);*/ - switch(command) { case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) { @@ -1674,7 +1727,8 @@ ndis_ioctl(ifp, command, data) !(sc->ndis_if_flags & IFF_PROMISC)) { sc->ndis_filter |= NDIS_PACKET_TYPE_PROMISCUOUS; - ndis_set_info(sc, + i = sizeof(sc->ndis_filter); + error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER, &sc->ndis_filter, &i); } else if (ifp->if_flags & IFF_RUNNING && @@ -1682,7 +1736,8 @@ ndis_ioctl(ifp, command, data) sc->ndis_if_flags & IFF_PROMISC) { sc->ndis_filter &= ~NDIS_PACKET_TYPE_PROMISCUOUS; - ndis_set_info(sc, + i = sizeof(sc->ndis_filter); + error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER, &sc->ndis_filter, &i); } else |