diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8 index be8fd5064631..39761fbe5803 100644 --- a/sbin/ifconfig/ifconfig.8 +++ b/sbin/ifconfig/ifconfig.8 @@ -237,6 +237,10 @@ Enable driver dependent debugging code; usually, this turns on extra console error logging. .It Fl debug Disable driver dependent debugging code. +.It Cm promisc +Put interface into permanently promiscuous mode. +.It Fl promisc +Disable permanently promiscuous mode. .It Cm delete Another name for the .Fl alias diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c index 67c293eb9b5c..c9ab382b42f5 100644 --- a/sbin/ifconfig/ifconfig.c +++ b/sbin/ifconfig/ifconfig.c @@ -202,6 +202,8 @@ struct cmd { { "-arp", IFF_NOARP, setifflags }, { "debug", IFF_DEBUG, setifflags }, { "-debug", -IFF_DEBUG, setifflags }, + { "promisc", IFF_PPROMISC, setifflags }, + { "-promisc", -IFF_PPROMISC, setifflags }, { "add", IFF_UP, notealias }, { "alias", IFF_UP, notealias }, { "-alias", -IFF_UP, notealias }, @@ -999,7 +1001,7 @@ setifflags(const char *vname, int value, int s, const struct afswtch *afp) exit(1); } strncpy(my_ifr.ifr_name, name, sizeof (my_ifr.ifr_name)); - flags = (my_ifr.ifr_flags & 0xffff) | (my_ifr.ifr_flagshigh << 16); + flags = (my_ifr.ifr_flags & 0xffff) | (my_ifr.ifr_flagshigh << 16); if (value < 0) { value = -value; diff --git a/sys/net/if.c b/sys/net/if.c index 969963de5bff..a55114818e07 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -1291,6 +1291,12 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td) } ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | (new_flags &~ IFF_CANTCHANGE); + if (new_flags & IFF_PPROMISC) { + /* Permanently promiscuous mode requested */ + ifp->if_flags |= IFF_PROMISC; + } else if (ifp->if_pcount == 0) { + ifp->if_flags &= ~IFF_PROMISC; + } if (ifp->if_ioctl) (void) (*ifp->if_ioctl)(ifp, cmd, data); getmicrotime(&ifp->if_lastchange); @@ -1561,6 +1567,11 @@ ifpromisc(ifp, pswitch) oldpcount = ifp->if_pcount; oldflags = ifp->if_flags; + if (ifp->if_flags & IFF_PPROMISC) { + /* Do nothing if device is in permanently promiscuous mode */ + ifp->if_pcount += pswitch ? 1 : -1; + return (0); + } if (pswitch) { /* * If the device is not configured up, we cannot put it in diff --git a/sys/net/if.h b/sys/net/if.h index fc95786b7764..8453ff56eba3 100644 --- a/sys/net/if.h +++ b/sys/net/if.h @@ -140,11 +140,12 @@ struct if_data { #define IFF_ALTPHYS IFF_LINK2 /* use alternate physical connection */ #define IFF_MULTICAST 0x8000 /* supports multicast */ #define IFF_POLLING 0x10000 /* Interface is in polling mode. */ +#define IFF_PPROMISC 0x20000 /* user-requested promisc mode */ /* flags set internally only: */ #define IFF_CANTCHANGE \ (IFF_BROADCAST|IFF_POINTOPOINT|IFF_RUNNING|IFF_OACTIVE|\ - IFF_SIMPLEX|IFF_MULTICAST|IFF_ALLMULTI|IFF_SMART) + IFF_SIMPLEX|IFF_MULTICAST|IFF_ALLMULTI|IFF_SMART|IFF_PROMISC) /* Capabilities that interfaces can advertise. */ #define IFCAP_RXCSUM 0x0001 /* can offload checksum on RX */ diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 53c744d7d09e..af1421d29592 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -677,7 +677,8 @@ ether_demux(ifp, eh, m) if ((ifp->if_flags & IFF_PROMISC) != 0 && (eh->ether_dhost[0] & 1) == 0 && bcmp(eh->ether_dhost, - IFP2AC(ifp)->ac_enaddr, ETHER_ADDR_LEN) != 0) { + IFP2AC(ifp)->ac_enaddr, ETHER_ADDR_LEN) != 0 + && (ifp->if_flags && IFF_PPROMISC) == 0) { m_freem(m); return; } @@ -1076,4 +1077,3 @@ ether_resolvemulti(ifp, llsa, sa) return EAFNOSUPPORT; } } -