Now that arp(8) can send Wake On Lan frames (a.k.a. magic packets), it would be nice to have a way to configure WOL from the operating system.
Some network cards need help from the OS to do WOL. Some already do WOL without help from the OS. For the latter it's nice to have a way to disable it. This diff adds code to enable/disable WOL. It's based on earlier diffs I've written for WOL which never went in, and some discussion with Theo and Claudio. If you have an re(4) or vr(4), you are lucky because those are the only drivers supported so far. More drivers will be added later. More often than not, WOL depends on BIOS settings. Sometimes BIOS settings override what the OS wants, and vice versa. Please test if you're interested in WOL. I'm particularly interested in test reports with vr(4). The on-board vr(4) I have doesn't listen to the OS. It only listens to the BIOS. Could someone owning a vr(4) verify that this diff can enable and disable WOL regardless of (or in some combination with) BIOS settings? After booting the patched kernel, don't forget to run 'make includes' in /usr/src before trying to compile ifconfig. Else, the if.h changes won't be seen by ifconfig and it will fail to build. Because this changes struct ifnet, sbin/route and usr.bin/netstat may need to be recompiled, too. Index: sbin/ifconfig/brconfig.h =================================================================== RCS file: /cvs/src/sbin/ifconfig/brconfig.h,v retrieving revision 1.3 diff -u -p -r1.3 brconfig.h --- sbin/ifconfig/brconfig.h 7 Jun 2010 15:05:42 -0000 1.3 +++ sbin/ifconfig/brconfig.h 12 Mar 2011 22:48:05 -0000 @@ -68,7 +68,7 @@ int bridge_rule(int, char **, int); #define IFFBITS \ "\024\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\ -\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST\21TXREADY\22NOINET6\23INET6_PRIVACY\24MPLS" +\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST\21TXREADY\22NOINET6\23INET6_PRIVACY\24MPLS\25WOL" void printb(char *, unsigned int, char *); Index: sbin/ifconfig/ifconfig.8 =================================================================== RCS file: /cvs/src/sbin/ifconfig/ifconfig.8,v retrieving revision 1.213 diff -u -p -r1.213 ifconfig.8 --- sbin/ifconfig/ifconfig.8 17 Feb 2011 08:32:29 -0000 1.213 +++ sbin/ifconfig/ifconfig.8 12 Mar 2011 22:55:55 -0000 @@ -435,6 +435,27 @@ This may be used to enable an interface It happens automatically when setting the first address on an interface. If the interface was reset when previously marked down, the hardware will be re-initialized. +.Pp +.It Cm wol +Enable Wake On Lan. +When enabled, reception of a Wake On Lan frame (a.k.a. Magic Packet) +will cause the network card to power up the system from standby or +suspend mode. +Wake On Lan frames can be sent with +.Xr arp 8 . +Support for Wake On Lan depends on various factors, +some of which may not be under control of the operating system. +Configuration parameters in the system BIOS or firmware can affect Wake On Lan. +.Pp +Wake On Lan should not be enabled on interfaces that can receive traffic +from the internet. +It should only be enabled on dedicated management interfaces connected to +networks where no packets can be injected by untrusted parties. +Wake On Lan frames can be sent in routable IP packets and are not authenticated. +.It Fl wol +Disable Wake On Lan. +Wake On Lan is disabled by default if possible. +The operating system cannot disable Wake On Lan on some machines. .El .Pp .Nm Index: share/man/man4/re.4 =================================================================== RCS file: /cvs/src/share/man/man4/re.4,v retrieving revision 1.44 diff -u -p -r1.44 re.4 --- share/man/man4/re.4 8 Jul 2010 09:19:11 -0000 1.44 +++ share/man/man4/re.4 12 Mar 2011 23:35:47 -0000 @@ -168,6 +168,10 @@ Force full duplex operation. Force half duplex operation. .El .Pp +The +.Nm +driver supports Wake On Lan. +.Pp For more information on configuring this device, see .Xr ifconfig 8 . .Sh SEE ALSO Index: share/man/man4/vr.4 =================================================================== RCS file: /cvs/src/share/man/man4/vr.4,v retrieving revision 1.22 diff -u -p -r1.22 vr.4 --- share/man/man4/vr.4 16 Mar 2009 22:47:45 -0000 1.22 +++ share/man/man4/vr.4 12 Mar 2011 23:36:21 -0000 @@ -104,6 +104,11 @@ Force half duplex operation. .Pp Note that the 100baseTX media type is only available if supported by the adapter. +.Pp +The +.Nm +driver supports Wake On Lan. +.Pp For more information on configuring this device, see .Xr ifconfig 8 . .Sh DIAGNOSTICS Index: sbin/ifconfig/ifconfig.c =================================================================== RCS file: /cvs/src/sbin/ifconfig/ifconfig.c,v retrieving revision 1.244 diff -u -p -r1.244 ifconfig.c --- sbin/ifconfig/ifconfig.c 1 Mar 2011 09:37:31 -0000 1.244 +++ sbin/ifconfig/ifconfig.c 12 Mar 2011 23:10:43 -0000 @@ -461,6 +461,8 @@ const struct cmd { { "descr", NEXTARG, 0, setifdesc }, { "-description", 1, 0, unsetifdesc }, { "-descr", 1, 0, unsetifdesc }, + { "wol", IFXF_WOL, 0, setifxflags }, + { "-wol", -IFXF_WOL, 0, setifxflags }, #else /* SMALL */ { "group", NEXTARG, 0, setignore }, { "powersave", NEXTARG0, 0, setignore }, @@ -474,6 +476,8 @@ const struct cmd { { "-inet6", IFXF_NOINET6, 0, setignore } , { "description", NEXTARG, 0, setignore }, { "descr", NEXTARG, 0, setignore }, + { "wol", IFXF_WOL, 0, setignore }, + { "-wol", -IFXF_WOL, 0, setignore }, #endif /* SMALL */ #if 0 /* XXX `create' special-cased below */ Index: sys/dev/ic/re.c =================================================================== RCS file: /cvs/src/sys/dev/ic/re.c,v retrieving revision 1.132 diff -u -p -r1.132 re.c --- sys/dev/ic/re.c 28 Nov 2010 22:13:48 -0000 1.132 +++ sys/dev/ic/re.c 12 Mar 2011 22:44:08 -0000 @@ -194,6 +194,9 @@ void re_disable_hw_im(struct rl_softc *) void re_disable_sim_im(struct rl_softc *); void re_config_imtype(struct rl_softc *, int); void re_setup_intr(struct rl_softc *, int, int); +#ifndef SMALL_KERNEL +int re_wol(struct ifnet*, int); +#endif #ifdef RE_DIAG int re_diag(struct rl_softc *); @@ -1118,6 +1121,11 @@ re_attach(struct rl_softc *sc, const cha ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; #endif +#ifndef SMALL_KERNEL + ifp->if_capabilities |= IFCAP_WOL; + ifp->if_wol = re_wol; + re_wol(ifp, 0); +#endif timeout_set(&sc->timer_handle, re_tick, sc); /* Take PHY out of power down mode. */ @@ -2335,3 +2343,53 @@ re_setup_intr(struct rl_softc *sc, int e sc->sc_dev.dv_xname, imtype); } } + +#ifndef SMALL_KERNEL +struct re_wolcfg { + u_int8_t enable; + u_int8_t reg; + u_int8_t bit; +} re_wolcfg[] = { + /* Always disable all wake events expect magic packet. */ + {0, RL_CFG5, RL_CFG5_WOL_UCAST}, + {0, RL_CFG5, RL_CFG5_WOL_MCAST}, + {0, RL_CFG5, RL_CFG5_WOL_BCAST}, + {1, RL_CFG3, RL_CFG3_WOL_MAGIC}, + {0, RL_CFG3, RL_CFG3_WOL_LINK} +}; + +int +re_wol(struct ifnet *ifp, int enable) +{ + struct rl_softc *sc = ifp->if_softc; + int i; + u_int8_t val; + + if (enable) { + if ((CSR_READ_1(sc, RL_CFG1) & RL_CFG1_PME) == 0) { + printf("%s: power management is disabled, " + "cannot do WOL\n", sc->sc_dev.dv_xname); + return (EINVAL); + } + if ((CSR_READ_1(sc, RL_CFG2) & RL_CFG2_AUXPWR) == 0) + printf("%s: no auxiliary power, cannot do WOL from D3 " + "(power-off) state\n", sc->sc_dev.dv_xname); + } + + /* Temporarily enable write to configuration registers. */ + CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_WRITECFG); + + for (i = 0; i < nitems(re_wolcfg); i++) { + val = CSR_READ_1(sc, re_wolcfg[i].reg); + if (enable && re_wolcfg[i].enable) + val |= re_wolcfg[i].bit; + else + val &= ~re_wolcfg[i].bit; + CSR_WRITE_1(sc, re_wolcfg[i].reg, val); + } + + CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF); + + return (0); +} +#endif Index: sys/dev/ic/rtl81x9reg.h =================================================================== RCS file: /cvs/src/sys/dev/ic/rtl81x9reg.h,v retrieving revision 1.72 diff -u -p -r1.72 rtl81x9reg.h --- sys/dev/ic/rtl81x9reg.h 28 Nov 2010 22:08:59 -0000 1.72 +++ sys/dev/ic/rtl81x9reg.h 8 Dec 2010 12:57:59 -0000 @@ -987,6 +987,7 @@ struct rl_softc { #define RL_PCI_INTPIN 0x3D #define RL_PCI_MINGNT 0x3E #define RL_PCI_MINLAT 0x0F +#define RL_PCI_PMCSR 0x44 #define RL_PCI_RESETOPT 0x48 #define RL_PCI_EEPROM_DATA 0x4C @@ -1000,7 +1001,7 @@ struct rl_softc { #define RL_PSTATE_D1 0x0001 #define RL_PSTATE_D2 0x0002 #define RL_PSTATE_D3 0x0003 -#define RL_PME_EN 0x0010 +#define RL_PME_EN 0x0100 #define RL_PME_STATUS 0x8000 extern int rl_attach(struct rl_softc *); Index: sys/dev/pci/if_re_pci.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_re_pci.c,v retrieving revision 1.30 diff -u -p -r1.30 if_re_pci.c --- sys/dev/pci/if_re_pci.c 7 Sep 2010 16:21:45 -0000 1.30 +++ sys/dev/pci/if_re_pci.c 21 Sep 2010 08:19:42 -0000 @@ -163,6 +163,11 @@ re_pci_attach(struct device *parent, str pci_conf_write(pc, pa->pa_tag, RL_PCI_INTLINE, irq); } +#ifndef SMALL_KERNEL + /* Enable power management for wake on lan. */ + pci_conf_write(pc, pa->pa_tag, RL_PCI_PMCSR, RL_PME_EN); +#endif + /* * Map control/status registers. */ Index: sys/dev/pci/if_vr.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_vr.c,v retrieving revision 1.107 diff -u -p -r1.107 if_vr.c --- sys/dev/pci/if_vr.c 13 Jan 2011 11:28:14 -0000 1.107 +++ sys/dev/pci/if_vr.c 12 Mar 2011 22:42:47 -0000 @@ -137,6 +137,9 @@ void vr_reset(struct vr_softc *); int vr_list_rx_init(struct vr_softc *); void vr_fill_rx_ring(struct vr_softc *); int vr_list_tx_init(struct vr_softc *); +#ifndef SMALL_KERNEL +int vr_wol(struct ifnet *, int); +#endif int vr_alloc_mbuf(struct vr_softc *, struct vr_chain_onefrag *); @@ -643,6 +646,13 @@ vr_attach(struct device *parent, struct if (sc->vr_quirks & VR_Q_CSUM) ifp->if_capabilities |= IFCAP_CSUM_IPv4|IFCAP_CSUM_TCPv4| IFCAP_CSUM_UDPv4; +#ifndef SMALL_KERNEL + if (sc->vr_revid >= REV_ID_VT3065_A) { + ifp->if_capabilities |= IFCAP_WOL; + ifp->if_wol = vr_wol; + vr_wol(ifp, 0); + } +#endif /* * Do MII setup. @@ -1528,6 +1538,34 @@ vr_stop(struct vr_softc *sc) bzero((char *)&sc->vr_ldata->vr_tx_list, sizeof(sc->vr_ldata->vr_tx_list)); } + +#ifndef SMALL_KERNEL +int +vr_wol(struct ifnet *ifp, int enable) +{ + struct vr_softc *sc = ifp->if_softc; + + /* Clear WOL configuration */ + CSR_WRITE_1(sc, VR_WOLCRCLR, 0xFF); + + /* Clear event status bits. */ + CSR_WRITE_1(sc, VR_PWRCSRCLR, 0xFF); + + /* Disable PME# assertion upon wake event. */ + VR_CLRBIT(sc, VR_STICKHW, VR_STICKHW_WOL_ENB); + VR_SETBIT(sc, VR_WOLCFGCLR, VR_WOLCFG_PMEOVR); + + if (enable) { + VR_SETBIT(sc, VR_WOLCRSET, VR_WOLCR_MAGIC); + + /* Enable PME# assertion upon wake event. */ + VR_SETBIT(sc, VR_STICKHW, VR_STICKHW_WOL_ENB); + VR_SETBIT(sc, VR_WOLCFGSET, VR_WOLCFG_PMEOVR); + } + + return (0); +} +#endif int vr_alloc_mbuf(struct vr_softc *sc, struct vr_chain_onefrag *r) Index: sys/dev/pci/if_vrreg.h =================================================================== RCS file: /cvs/src/sys/dev/pci/if_vrreg.h,v retrieving revision 1.27 diff -u -p -r1.27 if_vrreg.h --- sys/dev/pci/if_vrreg.h 18 Jun 2009 17:48:15 -0000 1.27 +++ sys/dev/pci/if_vrreg.h 12 Mar 2011 23:00:27 -0000 @@ -285,6 +285,21 @@ #define VR_STICKHW_WOL_STS 0x08 #define VR_STICKHW_LEGWOL_ENB 0x80 +/* Wake on Lan */ +#define VR_WOLCRSET 0xA0 +#define VR_PWRCFGSET 0xA1 +#define VR_WOLCFGSET 0xA3 +#define VR_WOLCRCLR 0xA4 +#define VR_PWRCFGCLR 0xA5 +#define VR_WOLCFGCLR 0xA7 +#define VR_PWRCSRSET 0xA8 +#define VR_PWRCSRCLR 0xAC +#define VR_WOLCR_UCAST 0x10 +#define VR_WOLCR_MAGIC 0x20 +#define VR_WOLCR_LINKON 0x40 +#define VR_WOLCR_LINKOFF 0x80 +#define VR_WOLCFG_PMEOVR 0x80 + /* * BCR0 register bits. (At least for the VT6102 chip.) */ Index: sys/net/if.c =================================================================== RCS file: /cvs/src/sys/net/if.c,v retrieving revision 1.233 diff -u -p -r1.233 if.c --- sys/net/if.c 25 Jan 2011 05:44:05 -0000 1.233 +++ sys/net/if.c 12 Mar 2011 23:00:48 -0000 @@ -1356,7 +1356,28 @@ ifioctl(struct socket *so, u_long cmd, c splx(s); } #endif - +#ifndef SMALL_KERNEL + if (ifp->if_capabilities & IFCAP_WOL) { + if (ISSET(ifr->ifr_flags, IFXF_WOL) && + !ISSET(ifp->if_xflags, IFXF_WOL)) { + int s = splnet(); + ifp->if_xflags |= IFXF_WOL; + error = ifp->if_wol(ifp, 1); + splx(s); + if (error) + return (error); + } + if (ISSET(ifp->if_xflags, IFXF_WOL) && + !ISSET(ifr->ifr_flags, IFXF_WOL)) { + int s = splnet(); + ifp->if_xflags &= ~IFXF_WOL; + error = ifp->if_wol(ifp, 0); + splx(s); + if (error) + return (error); + } + } +#endif ifp->if_xflags = (ifp->if_xflags & IFXF_CANTCHANGE) | (ifr->ifr_flags & ~IFXF_CANTCHANGE); Index: sys/net/if.h =================================================================== RCS file: /cvs/src/sys/net/if.h,v retrieving revision 1.121 diff -u -p -r1.121 if.h --- sys/net/if.h 17 Nov 2010 18:51:57 -0000 1.121 +++ sys/net/if.h 12 Mar 2011 22:24:52 -0000 @@ -278,6 +278,7 @@ struct ifnet { /* and the entries */ int (*if_stop)(struct ifnet *, int); /* timer routine */ void (*if_watchdog)(struct ifnet *); + int (*if_wol)(struct ifnet *, int); struct ifaltq if_snd; /* output queue (includes altq) */ struct sockaddr_dl *if_sadl; /* pointer to our sockaddr_dl */ @@ -329,6 +330,7 @@ struct ifnet { /* and the entries */ #define IFXF_NOINET6 0x2 /* don't do inet6 */ #define IFXF_INET6_PRIVACY 0x4 /* autoconf privacy extension */ #define IFXF_MPLS 0x8 /* supports MPLS */ +#define IFXF_WOL 0x10 /* wake on lan enabled */ #define IFXF_CANTCHANGE \ (IFXF_TXREADY) @@ -352,6 +354,7 @@ struct ifnet { /* and the entries */ #define IFCAP_CSUM_UDPv6 0x00000100 /* can do IPv6/UDP checksums */ #define IFCAP_CSUM_TCPv4_Rx 0x00000200 /* can do IPv4/TCP (Rx only) */ #define IFCAP_CSUM_UDPv4_Rx 0x00000400 /* can do IPv4/UDP (Rx only) */ +#define IFCAP_WOL 0x00008000 /* can do wake on lan */ /* * Output queues (ifp->if_snd) and internetwork datagram level (pup level 1)