This patch teaches the if_sis driver to enable Wake On Lan (WOL) functionality on the NatSemi DP8381[56] chip. This did not work previously because the driver has to enable WOL functionality explicitely on system shutdown. It also defines new ioctls that allow configuring WOL functionality from user space. These ioctls could also be used by other network drivers implementing WOL features as well (none yet known to me). The ifconfig command has been extended to accept a 'wakeon' command used to configure network packet types that shall trigger wake events. For example: # ifconfig sis0 wakeon magic configures the card to wake upon recieving a MagicPacket(tm). # ifconfig sis0 wakeon broadcast configures the card to wake upon recieving a broadcast packet. Multiple events may be specified, seperated by commas. The WOL capabilities of a network card, if present, are printed by ifconfig: stsp@dice$ ifconfig sis0 sis0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 options=48<VLAN_MTU,POLLING> inet6 fe80::209:5bff:fe8a:d538%sis0 prefixlen 64 scopeid 0x1 inet 192.168.0.1 netmask 0xffffff00 broadcast 192.168.0.255 ether 00:09:5b:8a:d5:38 media: Ethernet autoselect (100baseTX <full-duplex>) status: active supported wake on lan events: unicast multicast broadcast magic If wake up events have been defined (e.g. MagicPacket(tm)), ifconfig also shows the following line: will wake on: magic The patch also updates the ifconfig(8) man page accordingly. Oh, and it also does some s/u_int32_t/uint32_t/
>Submitter-Id: current-users >Originator: Stefan Sperling >Organization: >Confidential: no >Synopsis: Re: kern/83807: [patch] Wake On Lan support for FreeBSD >Severity: non-critical >Priority: low >Category: kern >Class: change-request >Release: FreeBSD 7.0-CURRENT i386 >Environment: System: FreeBSD dice.seeling33.de 7.0-CURRENT FreeBSD 7.0-CURRENT #0: Wed Jul 20 11:35:03 CEST 2005 stsp@dice.seeling33.de:/usr/obj/home/FreeBSD/FreeBSD-wol/src/sys/DICE i386 >Description: Somehow the patch got lost the last time. >How-To-Repeat: >Fix: --- FreeBSD-wol-05-07-20.diff begins here --- Index: sbin/ifconfig/Makefile =================================================================== RCS file: /home/ncvs/src/sbin/ifconfig/Makefile,v retrieving revision 1.29 diff -u -r1.29 Makefile --- sbin/ifconfig/Makefile 5 Jun 2005 03:32:51 -0000 1.29 +++ sbin/ifconfig/Makefile 20 Jul 2005 09:24:53 -0000 @@ -28,6 +28,8 @@ SRCS+= ifbridge.c # bridge support +SRCS+= ifwol.c # wake on lan support + .if !defined(RELEASE_CRUNCH) SRCS+= af_ipx.c # IPX support DPADD= ${LIBIPX} Index: sbin/ifconfig/ifconfig.8 =================================================================== RCS file: /home/ncvs/src/sbin/ifconfig/ifconfig.8,v retrieving revision 1.98 diff -u -r1.98 ifconfig.8 --- sbin/ifconfig/ifconfig.8 14 Jul 2005 18:33:21 -0000 1.98 +++ sbin/ifconfig/ifconfig.8 20 Jul 2005 12:52:57 -0000 @@ -852,6 +852,26 @@ efficient communication of realtime and multimedia data. To disable WME support, use .Fl wme . +.It Cm wakeon Ar events +Enable Wake On Lan support, if available. The +.Ar events +argument is a comma seperated list of package types that shall +trigger wake events. The set of valid package types is +.Dq Li unicast , +.Dq Li multicast , +.Dq Li broadcast , +and +.Dq Li magic . +These enable wake on unicast, multicast, broadcast and Magic Packet(tm), +respectively. +A SecureOn password, if supported, can be be enabled using the +.Dq Li sopasswd:<password> +event. +SecureOn passwords only work in combination with +.Dq Li magic . +The password must consist of 12 hexadecimal digits. +.It Fl wakeon +Disable Wake On Lan. .El .Pp The following parameters are support for compatibility with other systems: Index: sbin/ifconfig/ifwol.c =================================================================== RCS file: sbin/ifconfig/ifwol.c diff -N sbin/ifconfig/ifwol.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sbin/ifconfig/ifwol.c 20 Jul 2005 12:47:44 -0000 @@ -0,0 +1,232 @@ +/* $FreeBSD$ */ + +/* + * Copyright (c) 2005 Stefan Sperling. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/sysctl.h> +#include <sys/time.h> + +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_types.h> +#include <net/if_media.h> +#include <net/route.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sysexits.h> + +#include "ifconfig.h" + +static void wol_status(int s); +static void setwol(const char *, int, int, const struct afswtch *); +static void parse_args(const char *, struct if_wolopts *); +static void parse_sopasswd(char *, u_char *); +static void unsetwol(const char *, int, int, const struct afswtch *); +static void print_wol_events(uint32_t events); + +/* + * Print wake on lan capabilities and events the device currently heeds. + */ +static void +wol_status(int s) +{ + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, name, IFNAMSIZ); + + if (ioctl(s, SIOCGIFWOLCAP, &ifr) < 0) + /* Device does not support wake on lan */ + return; + + printf("\tsupported wake on lan events:"); + print_wol_events(ifr.ifr_wolopts.ifwol_caps); + printf("\n"); + + if (ioctl(s, SIOCGIFWOLOPTS, &ifr) < 0) + err(EX_USAGE, "SIOCGIFWOLOPTS"); + + if (ifr.ifr_wolopts.ifwol_events == 0) + return; + + printf("\twill wake on:"); + print_wol_events(ifr.ifr_wolopts.ifwol_events); + printf("\n"); +} + +static void +print_wol_events(uint32_t events) +{ + if (events & IFWOL_WAKE_ON_UNICAST) + printf(" unicast"); + if (events & IFWOL_WAKE_ON_MULTICAST) + printf(" multicast"); + if (events & IFWOL_WAKE_ON_BROADCAST) + printf(" broadcast"); + if (events & IFWOL_WAKE_ON_MAGIC) { + printf(" magic"); + if (events & IFWOL_ENABLE_SOPASSWD) + printf("[SecureOn password]"); + } +} + +/* + * Set wake on lan events. + */ +static void +setwol(const char *val, int d, int s, const struct afswtch *afp) +{ + char *args; + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, name, IFNAMSIZ); + + if (ioctl(s, SIOCGIFWOLCAP, &ifr) < 0) + err(EX_USAGE, "device does not support wake on lan"); + + args = strdup(val); + parse_args(args, &ifr.ifr_wolopts); + free(args); + if (ioctl(s, SIOCSIFWOLOPTS, &ifr) < 0) + err(EX_USAGE, "SIOCSIFWOLOPTS"); +} + +/* + * Parse the argument string, which may contain one or more of the + * following: + * + * unicast,multicast,broadcast,magic,sopasswd:xxxxxxxxxxxx, + * + * and fill the wolopts structure accordingly. + * + */ +static void +parse_args(const char* args, struct if_wolopts *wolopts) +{ + uint32_t wol_events = 0; + char* opt; + + for (opt = strdup(args); (opt = strtok(opt, ",")) != NULL; opt = NULL) { + if (strcmp(opt, "unicast") == 0) + wol_events |= IFWOL_WAKE_ON_UNICAST; + else if (strcmp(opt, "multicast") == 0) + wol_events |= IFWOL_WAKE_ON_MULTICAST; + else if (strcmp(opt, "broadcast") == 0) + wol_events |= IFWOL_WAKE_ON_BROADCAST; + else if (strcmp(opt, "magic") == 0) + wol_events |= IFWOL_WAKE_ON_MAGIC; + else if (strcmp(opt, "sopasswd") == 0) + errx(EX_USAGE, "no SecureOn password specfied."); + else if (strncmp(opt, "sopasswd:", strlen("sopasswd:")) == 0) { + wol_events |= IFWOL_ENABLE_SOPASSWD; + parse_sopasswd(opt + strlen("sopasswd:"), wolopts->ifwol_sopasswd); + } else { + errx(EX_USAGE, "unknown wake event %s", opt); + } + } + free(opt); + wolopts->ifwol_events = wol_events; +} + +/* SecureOn passwords are not like plain text passwords. Instead, they consist + * of 6 bytes (ie unsigned char). Try to prevent users from giving anything other + * than a string of six concatenated unsigned chars in hex as password. + */ +static void +parse_sopasswd(char *pw, u_char *dest) { + char substr[3]; + int len, i, n; + + len = strlen(pw) / 2; + if (len != 6) + errx(EX_USAGE, "Invalid SecureOn password."); + + for (i = 0; i < len; i++) { + (void)strncpy(substr, pw, 2); + substr[2] = '\0'; + if (sscanf(substr, "%x", &n) != 1) + errx(EX_USAGE, "Invalid SecureOn password."); + if (n < 0x0 || n > 0xff) + /* Should never happen, but just in case... */ + errx(EX_USAGE, "Invalid SecureOn password."); + *dest++ = (u_char)n; + pw += 2; + } +} + +/* + * Unset all wake on lan events. + */ +static void +unsetwol(const char *val, int d, int s, const struct afswtch *afp) +{ + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, name, IFNAMSIZ); + + if (ioctl(s, SIOCGIFWOLCAP, &ifr) < 0) + err(EX_USAGE, "device does not support wake on lan"); + + ifr.ifr_wolopts.ifwol_events = IFWOL_DISABLE; + if (ioctl(s, SIOCSIFWOLOPTS, &ifr) < 0) + err(EX_USAGE, "SIOCSIFWOLOPTS"); +} + +static struct cmd wol_cmds[] = { + DEF_CMD_ARG("wakeon", setwol), + DEF_CMD("-wakeon", 0, unsetwol) +}; +static struct afswtch af_wol = { + .af_name = "af_wol", + .af_af = AF_UNSPEC, + .af_other_status = wol_status, +}; + +static __constructor void +ifwol_ctor(void) +{ +#define N(a) (sizeof(a) / sizeof(a[0])) + int i; + + for (i = 0; i < N(wol_cmds); i++) + cmd_register(&wol_cmds[i]); + af_register(&af_wol); +#undef N +} Index: sys/net/if.c =================================================================== RCS file: /home/ncvs/src/sys/net/if.c,v retrieving revision 1.238 diff -u -r1.238 if.c --- sys/net/if.c 19 Jul 2005 10:12:58 -0000 1.238 +++ sys/net/if.c 20 Jul 2005 09:24:53 -0000 @@ -1452,6 +1452,7 @@ case SIOCSLIFPHYADDR: case SIOCSIFMEDIA: case SIOCSIFGENERIC: + case SIOCSIFWOLOPTS: error = suser(td); if (error) return (error); @@ -1473,6 +1474,8 @@ case SIOCGLIFPHYADDR: case SIOCGIFMEDIA: case SIOCGIFGENERIC: + case SIOCGIFWOLOPTS: + case SIOCGIFWOLCAP: if (ifp->if_ioctl == NULL) return (EOPNOTSUPP); IFF_LOCKGIANT(ifp); Index: sys/net/if.h =================================================================== RCS file: /home/ncvs/src/sys/net/if.h,v retrieving revision 1.96 diff -u -r1.96 if.h --- sys/net/if.h 5 Jun 2005 03:13:11 -0000 1.96 +++ sys/net/if.h 20 Jul 2005 09:24:53 -0000 @@ -224,6 +224,28 @@ #define IFAN_DEPARTURE 1 /* interface departure */ /* + * Wake on Lan related options. + */ +struct if_wolopts { + uint32_t ifwol_caps; /* indicates wol capabilities */ + uint32_t ifwol_events; /* indicates desired wake events */ + + /* Supported wake on lan events. + * A given device may not support all of these, + * or even support wake events not listed here. + * If you add wake more events, make to sure to teach + * ifconfig about them too. */ +#define IFWOL_DISABLE 0x01 /* clears all other events */ +#define IFWOL_WAKE_ON_UNICAST 0x02 +#define IFWOL_WAKE_ON_MULTICAST 0x04 +#define IFWOL_WAKE_ON_BROADCAST 0x08 +#define IFWOL_WAKE_ON_MAGIC 0x10 /* wake on Magic Packet(tm) */ +#define IFWOL_ENABLE_SOPASSWD 0x20 /* whether to set SecureOn password */ + + u_char ifwol_sopasswd[6]; /* SecureOn password */ +}; + +/* * Interface request structure used for socket * ioctl's. All interface ioctl's must have parameter * definitions which begin with ifr_name. The @@ -235,6 +257,7 @@ struct sockaddr ifru_addr; struct sockaddr ifru_dstaddr; struct sockaddr ifru_broadaddr; + struct if_wolopts ifru_wolopts; short ifru_flags[2]; short ifru_index; int ifru_metric; @@ -247,6 +270,7 @@ #define ifr_addr ifr_ifru.ifru_addr /* address */ #define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-to-p link */ #define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ +#define ifr_wolopts ifr_ifru.ifru_wolopts /* wake on lan related options */ #define ifr_flags ifr_ifru.ifru_flags[0] /* flags (low 16 bits) */ #define ifr_flagshigh ifr_ifru.ifru_flags[1] /* flags (high 16 bits) */ #define ifr_metric ifr_ifru.ifru_metric /* metric */ Index: sys/pci/if_sis.c =================================================================== RCS file: /home/ncvs/src/sys/pci/if_sis.c,v retrieving revision 1.132 diff -u -r1.132 if_sis.c --- sys/pci/if_sis.c 10 Jun 2005 16:49:22 -0000 1.132 +++ sys/pci/if_sis.c 20 Jul 2005 09:24:53 -0000 @@ -122,6 +122,10 @@ static void sis_startl(struct ifnet *); static void sis_stop(struct sis_softc *); static void sis_watchdog(struct ifnet *); +static void sis_get_wolopts(struct sis_softc *, struct if_wolopts *); +static int sis_set_wolopts(struct sis_softc *, struct if_wolopts *); +static void sis_enable_wol(struct sis_softc *); +static uint32_t sis_translate_wol_events(uint32_t); #ifdef SIS_USEIOSPACE #define SIS_RES SYS_RES_IOPORT @@ -166,7 +170,7 @@ static void sis_dma_map_ring(void *arg, bus_dma_segment_t *segs, int nseg, int error) { - u_int32_t *p; + uint32_t *p; p = arg; *p = segs->ds_addr; @@ -254,7 +258,7 @@ sis_eeprom_getword(struct sis_softc *sc, int addr, uint16_t *dest) { int i; - u_int16_t word = 0; + uint16_t word = 0; /* Force EEPROM to idle state. */ sis_eeprom_idle(sc); @@ -297,11 +301,11 @@ sis_read_eeprom(struct sis_softc *sc, caddr_t dest, int off, int cnt, int swap) { int i; - u_int16_t word = 0, *ptr; + uint16_t word = 0, *ptr; for (i = 0; i < cnt; i++) { sis_eeprom_getword(sc, off + i, &word); - ptr = (u_int16_t *)(dest + (i * 2)); + ptr = (uint16_t *)(dest + (i * 2)); if (swap) *ptr = ntohs(word); else @@ -350,7 +354,7 @@ sis_read_cmos(struct sis_softc *sc, device_t dev, caddr_t dest, int off, int cnt) { device_t bridge; - u_int8_t reg; + uint8_t reg; int i; bus_space_tag_t btag; @@ -379,7 +383,7 @@ static void sis_read_mac(struct sis_softc *sc, device_t dev, caddr_t dest) { - u_int32_t filtsave, csrsave; + uint32_t filtsave, csrsave; filtsave = CSR_READ_4(sc, SIS_RXFILT_CTL); csrsave = CSR_READ_4(sc, SIS_CSR); @@ -390,11 +394,11 @@ CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave & ~SIS_RXFILTCTL_ENABLE); CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR0); - ((u_int16_t *)dest)[0] = CSR_READ_2(sc, SIS_RXFILT_DATA); + ((uint16_t *)dest)[0] = CSR_READ_2(sc, SIS_RXFILT_DATA); CSR_WRITE_4(sc, SIS_RXFILT_CTL,SIS_FILTADDR_PAR1); - ((u_int16_t *)dest)[1] = CSR_READ_2(sc, SIS_RXFILT_DATA); + ((uint16_t *)dest)[1] = CSR_READ_2(sc, SIS_RXFILT_DATA); CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR2); - ((u_int16_t *)dest)[2] = CSR_READ_2(sc, SIS_RXFILT_DATA); + ((uint16_t *)dest)[2] = CSR_READ_2(sc, SIS_RXFILT_DATA); CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave); CSR_WRITE_4(sc, SIS_CSR, csrsave); @@ -737,7 +741,7 @@ { struct ifnet *ifp; struct ifmultiaddr *ifma; - u_int32_t h = 0, i, filtsave; + uint32_t h = 0, i, filtsave; int bit, index; ifp = sc->sis_ifp; @@ -786,8 +790,8 @@ { struct ifnet *ifp; struct ifmultiaddr *ifma; - u_int32_t h, i, n, ctl; - u_int16_t hashes[16]; + uint32_t h, i, n, ctl; + uint16_t hashes[16]; ifp = sc->sis_ifp; @@ -986,7 +990,7 @@ * Why? Who the hell knows. */ { - u_int16_t tmp[4]; + uint16_t tmp[4]; sis_read_eeprom(sc, (caddr_t)&tmp, NS_EE_NODEADDR, 4, 0); @@ -1410,7 +1414,7 @@ struct ifnet *ifp; struct sis_desc *cur_rx; int total_len = 0; - u_int32_t rxstat; + uint32_t rxstat; SIS_LOCK_ASSERT(sc); @@ -1505,7 +1509,7 @@ sis_txeof(struct sis_softc *sc) { struct ifnet *ifp; - u_int32_t idx; + uint32_t idx; SIS_LOCK_ASSERT(sc); ifp = sc->sis_ifp; @@ -1614,7 +1618,7 @@ sis_startl(ifp); if (sc->rxcycles > 0 || cmd == POLL_AND_CHECK_STATUS) { - u_int32_t status; + uint32_t status; /* Reading the ISR register clears all interrupts. */ status = CSR_READ_4(sc, SIS_ISR); @@ -1640,7 +1644,7 @@ { struct sis_softc *sc; struct ifnet *ifp; - u_int32_t status; + uint32_t status; sc = arg; ifp = sc->sis_ifp; @@ -1800,7 +1804,7 @@ { struct sis_softc *sc; struct mbuf *m_head = NULL; - u_int32_t idx, queued = 0; + uint32_t idx, queued = 0; sc = ifp->if_softc; @@ -1887,23 +1891,23 @@ if (sc->sis_type == SIS_TYPE_83815) { CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR0); CSR_WRITE_4(sc, SIS_RXFILT_DATA, - ((u_int16_t *)IFP2ENADDR(sc->sis_ifp))[0]); + ((uint16_t *)IFP2ENADDR(sc->sis_ifp))[0]); CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR1); CSR_WRITE_4(sc, SIS_RXFILT_DATA, - ((u_int16_t *)IFP2ENADDR(sc->sis_ifp))[1]); + ((uint16_t *)IFP2ENADDR(sc->sis_ifp))[1]); CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR2); CSR_WRITE_4(sc, SIS_RXFILT_DATA, - ((u_int16_t *)IFP2ENADDR(sc->sis_ifp))[2]); + ((uint16_t *)IFP2ENADDR(sc->sis_ifp))[2]); } else { CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR0); CSR_WRITE_4(sc, SIS_RXFILT_DATA, - ((u_int16_t *)IFP2ENADDR(sc->sis_ifp))[0]); + ((uint16_t *)IFP2ENADDR(sc->sis_ifp))[0]); CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR1); CSR_WRITE_4(sc, SIS_RXFILT_DATA, - ((u_int16_t *)IFP2ENADDR(sc->sis_ifp))[1]); + ((uint16_t *)IFP2ENADDR(sc->sis_ifp))[1]); CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR2); CSR_WRITE_4(sc, SIS_RXFILT_DATA, - ((u_int16_t *)IFP2ENADDR(sc->sis_ifp))[2]); + ((uint16_t *)IFP2ENADDR(sc->sis_ifp))[2]); } /* Init circular TX/RX lists. */ @@ -2150,6 +2154,22 @@ case SIOCSIFCAP: ifp->if_capenable &= ~IFCAP_POLLING; ifp->if_capenable |= ifr->ifr_reqcap & IFCAP_POLLING; + error = 0; + break; + case SIOCGIFWOLCAP: + ifr->ifr_wolopts.ifwol_caps = NS_SUPPORTED_WOL_EVENTS; + error = 0; + break; + case SIOCGIFWOLOPTS: + SIS_LOCK(sc); + sis_get_wolopts(sc, &ifr->ifr_wolopts); + SIS_UNLOCK(sc); + error = 0; + break; + case SIOCSIFWOLOPTS: + SIS_LOCK(sc); + error = sis_set_wolopts(sc, &ifr->ifr_wolopts); + SIS_UNLOCK(sc); break; default: error = ether_ioctl(ifp, command, data); @@ -2263,9 +2283,141 @@ SIS_LOCK(sc); sis_reset(sc); sis_stop(sc); + sis_enable_wol(sc); SIS_UNLOCK(sc); } +/* + * Translate wake on lan events defined in if.h + * into flags the chip understands. + */ +static uint32_t +sis_translate_wol_events(uint32_t wol_events) +{ + uint32_t sis_wol_events = 0; + + if (wol_events & IFWOL_WAKE_ON_UNICAST) + sis_wol_events |= NS_WCSR_WAKE_UCAST; + if (wol_events & IFWOL_WAKE_ON_MULTICAST) + sis_wol_events |= NS_WCSR_WAKE_MCAST; + if (wol_events & IFWOL_WAKE_ON_BROADCAST) + sis_wol_events |= NS_WCSR_WAKE_BCAST; + if (wol_events & IFWOL_WAKE_ON_MAGIC) + sis_wol_events |= NS_WCSR_WAKE_MAGIC; + + return sis_wol_events; +} + +/* + * Write current wake on lan settings into an if_wolopts structure. + * Note that the sopasswd field in the structure is cleared, because + * the password is confidential. + */ +static void +sis_get_wolopts(struct sis_softc *sc, struct if_wolopts *wolopts) +{ + int i; + + SIS_LOCK_ASSERT(sc); + + wolopts->ifwol_events = sc->ns_wol_events; + + /* Do not disclose Secure On password. */ +#define N(a) (sizeof(a) / sizeof(a[0])) + for (i = 0; i < N(wolopts->ifwol_sopasswd); i++) + wolopts->ifwol_sopasswd[i] = '\0'; +#undef N +} + +/* + * Set wake on lan options. + */ +static int +sis_set_wolopts(struct sis_softc *sc, struct if_wolopts *wolopts) +{ + SIS_LOCK_ASSERT(sc); + + /* FIXME: handle sopasswd */ + + if (wolopts->ifwol_events == IFWOL_DISABLE) + sc->ns_wol_events = 0; + else { + if ((wolopts->ifwol_events & ~NS_SUPPORTED_WOL_EVENTS) != 0) + return EINVAL; + sc->ns_wol_events = wolopts->ifwol_events; + } + + return 0; +} + +/* + * Enable Wake On Lan on the DP83815, + * if any wake on lan options have been set. + */ +static void +sis_enable_wol(struct sis_softc *sc) +{ + SIS_LOCK_ASSERT(sc); + + if (sc->sis_type != SIS_TYPE_83815) + return; + + /* Check whether any wake on lan events have been set. */ + if (sc->ns_wol_events == 0) + return; + + /* + * Configure the recieve filter to accept potential wake packets, + * configure wake events and enter low-power state. + */ + + /* Stop reciever. */ + SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_DISABLE); + + /* Reset recieve pointer */ + CSR_WRITE_4(sc, SIS_RX_LISTPTR, 0); + + /* Re-enable reciever (now in "silent recieve mode.") */ + SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE); + + /* Clear recieve filter register, so that the enable bit is unset. + * Other bits in this register can only be configured while the enable + * bit is zero. */ + CSR_WRITE_4(sc, SIS_RXFILT_CTL, 0); + + /* + * Accept unicast packets. The datasheet seems to be inaccurate. + * It suggests simply setting the unicast bit in NS_RXFILTCTL, + * but this does not seem to work. Instead, we "perfect match" + * our own mac address, which makes the rx filter accept unicast + * packets. (section below copy pasted from sis_initl routine) + */ + CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR0); + CSR_WRITE_4(sc, SIS_RXFILT_DATA, + ((uint16_t *)IFP2ENADDR(sc->sis_ifp))[0]); + CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR1); + CSR_WRITE_4(sc, SIS_RXFILT_DATA, + ((uint16_t *)IFP2ENADDR(sc->sis_ifp))[1]); + CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR2); + CSR_WRITE_4(sc, SIS_RXFILT_DATA, + ((uint16_t *)IFP2ENADDR(sc->sis_ifp))[2]); + SIS_SETBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_PERFECT); + + /* Allow broadcast and multicast packets, too. */ + SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_BROAD); + SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLMULTI); + + /* Re-enable RX filter. */ + SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ENABLE); + + /* Configure wake on lan events */ + CSR_WRITE_4(sc, NS_WCSR, sis_translate_wol_events(sc->ns_wol_events)); + + /* Set appropriate power state, so the card stays active + * after system shutdown. */ + CSR_WRITE_4(sc, NS_CLKRUN, NS_CLKRUN_PMESTS | NS_CLKRUN_PMEENB); +} + static device_method_t sis_methods[] = { /* Device interface */ DEVMETHOD(device_probe, sis_probe), Index: sys/pci/if_sisreg.h =================================================================== RCS file: /home/ncvs/src/sys/pci/if_sisreg.h,v retrieving revision 1.33 diff -u -r1.33 if_sisreg.h --- sys/pci/if_sisreg.h 10 Jun 2005 16:49:22 -0000 1.33 +++ sys/pci/if_sisreg.h 20 Jul 2005 09:24:53 -0000 @@ -77,6 +77,7 @@ /* NS DP83815/6 registers */ #define NS_IHR 0x1C #define NS_CLKRUN 0x3C +#define NS_WCSR 0x40 #define NS_SRR 0x58 #define NS_BMCR 0x80 #define NS_BMSR 0x84 @@ -464,6 +465,7 @@ #endif int in_tick; struct mtx sis_mtx; + uint32_t ns_wol_events; }; #define SIS_LOCK(_sc) mtx_lock(&(_sc)->sis_mtx) @@ -524,3 +526,17 @@ #define SIS_PSTATE_D3 0x0003 #define SIS_PME_EN 0x0010 #define SIS_PME_STATUS 0x8000 + +/* DP83815 pci config space power management register */ +#define NS_PMCSR 0x44 + +/* DP83815 Wake On Lan Command/Status register */ +#define NS_WCSR_WAKE_UCAST 0x00000002 +#define NS_WCSR_WAKE_MCAST 0x00000004 +#define NS_WCSR_WAKE_BCAST 0x00000008 +#define NS_WCSR_WAKE_MAGIC 0x00000200 + +/* FIXME: handle sopasswd */ +#define NS_SUPPORTED_WOL_EVENTS (IFWOL_WAKE_ON_UNICAST | IFWOL_WAKE_ON_MULTICAST \ + | IFWOL_WAKE_ON_BROADCAST | IFWOL_WAKE_ON_MAGIC) + Index: sys/sys/sockio.h =================================================================== RCS file: /home/ncvs/src/sys/sys/sockio.h,v retrieving revision 1.28 diff -u -r1.28 sockio.h --- sys/sys/sockio.h 5 Jun 2005 03:13:13 -0000 1.28 +++ sys/sys/sockio.h 20 Jul 2005 09:24:53 -0000 @@ -114,4 +114,11 @@ #define SIOCIFDESTROY _IOW('i', 121, struct ifreq) /* destroy clone if */ #define SIOCIFGCLONERS _IOWR('i', 120, struct if_clonereq) /* get cloners */ +#define SIOCGIFWOLOPTS _IOWR('i', 124, struct ifreq) /* get wake on lan + options */ +#define SIOCSIFWOLOPTS _IOW('i', 125, struct ifreq) /* set wake on lan + options */ +#define SIOCGIFWOLCAP _IOWR('i', 126, struct ifreq) /* get wake on lan + modes supported by + device */ #endif /* !_SYS_SOCKIO_H_ */ --- FreeBSD-wol-05-07-20.diff ends here ---
This is just a followup containing an updated version of this patch, which I've been using for several months now. It works very reliably with my NatSemi card, stability of my system is not affected in any way. This version contains support for more chipsets: * NatSemi DP83815 * Via Rhine (VT6102 and up) * Nvidia nForce (nve driver, needs testing, I don't have this hardware) I can add support for more chipsets on request, but I may not have the hardware available to do testing. Also, "secure-on" passwords are still not supported, as I found myself not wanting to use this "security feature" anyway. As I don't run -current anymore, the patch is against RELENG_6. If it does not apply to -current anymore, I can fix this on request. Just in case the attached patch gets mangled, you can find a copy of it here: http://www.stsp.in-berlin.de/wol/ -- stefan http://stsp.in-berlin.de PGP Key: 0xF59D25F0
This is another revision which cleans out some minor issues in the part of the patch affecting /sbin/ifconfig: * Fix several instances of misuse of strncpy that could theoretically lead to buffer overflow. * Remove unnecessary strdup() invocation. One copy operation is enough :) -- stefan http://stsp.in-berlin.de PGP Key: 0xF59D25F0
Will this feature ever be incorporated in mainstream FreeBSD? I'm eagerly waiting for it to land in -CURRENT... Kind regards, Edwin Mons
On Sat, Jun 09, 2007 at 11:08:01AM +0200, Edwin Mons wrote: > Will this feature ever be incorporated in mainstream FreeBSD? I'm eagerly > waiting for it to land in -CURRENT... I have no idea. I haven't got much feedback on this patch, apart from one or two people who sent me a quick thank you note :) So I have no idea how many people are actually using the patch. I know that: * if_sis and if_vr wake on lan support is very stable for me. I've been using this code for nearly 2 years now. * if_nve support has afaik never been tested (plus it's a binary blob driver and will apparently be replaced with OpenBSD's nfe driver soon.) I run a single 6.2 box here that I maintain the patch for. I'd be happy to setup a -current box to port the patch to -CURRENT. But I need to know whether it's worth doing the work. I'd like to get feedback on my patch by someone who is willing and able to help me get it into the tree. I need to know what needs to be done and/or changed to make the patch ready for mainline. There are some small bits in the patch that are incomplete, e.g. "secure on password" support. I've been thinking about simply dropping this feature because I consider it useless but ymmv. I'd also be happy to add WOL support for more chipsets. Adding support is relatively easy as long as another open source OS (e.g. Linux) supports wake on lan for a chipset and even easier if a good datasheet is available (as in case of if_sis). If anyone has a card that does wake on lan after shutdown from Linux but not after shutdown from FreeBSD with my patch applied let me know. You may need to use the ethtool utility to enable WOL on Linux. Cc'ing hackers@ in case someone there is interested in helping out. > Kind regards, > Edwin Mons -- stefan http://stsp.name PGP Key: 0xF59D25F0
Stefan Sperling wrote: > On Sat, Jun 09, 2007 at 11:08:01AM +0200, Edwin Mons wrote: > >> Will this feature ever be incorporated in mainstream FreeBSD? I'm eagerly >> waiting for it to land in -CURRENT... >> > > I have no idea. > > I haven't got much feedback on this patch, apart from one > or two people who sent me a quick thank you note :) > > So I have no idea how many people are actually using the patch. > > I know that: > > * if_sis and if_vr wake on lan support is very stable for me. > I've been using this code for nearly 2 years now. > > * if_nve support has afaik never been tested (plus > it's a binary blob driver and will apparently be > replaced with OpenBSD's nfe driver soon.) > > I run a single 6.2 box here that I maintain the patch for. > I'd be happy to setup a -current box to port the patch to -CURRENT. > I currently have one -CURRENT machine, and several 6.2-STABLE machines. For at least two of them (the -CURRENT and an x86 -STABLE machine) I'd really like to have WoL support, as these are my workstation and a home server, both of them really do not need to be on all the time, but I want to be able to reach them when I need a file from them when I'm elsewhere. > I'd also be happy to add WOL support for more chipsets. > Adding support is relatively easy as long as another open source > OS (e.g. Linux) supports wake on lan for a chipset and even easier > if a good datasheet is available (as in case of if_sis). > I usually use either if_em or if_xl chipsets, so I hoped landing this code in at least -CURRENT (should go there first, I guess) would result in more chipsets supported ;) > If anyone has a card that does wake on lan after shutdown from Linux > but not after shutdown from FreeBSD with my patch applied let me know. > You may need to use the ethtool utility to enable WOL on Linux. > I don't run Linux on either machine. Perhaps I could do some tests on my workstation with a CD-based linux distribution. Edwin
On Sat, Jun 09, 2007 at 05:07:39PM +0200, Edwin Mons wrote: > I currently have one -CURRENT machine, and several 6.2-STABLE machines. For > at least two of them (the -CURRENT and an x86 -STABLE machine) I'd really > like to have WoL support, as these are my workstation and a home server, > both of them really do not need to be on all the time, but I want to be able > to reach them when I need a file from them when I'm elsewhere. Yes, wake on lan, if used properly, makes computers a bit more friendly to the environment :-) > I usually use either if_em or if_xl chipsets, so I hoped landing this code > in at least -CURRENT (should go there first, I guess) would result in more > chipsets supported ;) There is code for enabling wake on lan in the Linux drivers for both if_xl and if_em cards. See drivers/net/3c59x.c and drivers/net/e1000/e1000_ethtool.c in the linux source tree. So I don't think adding support for these cards is a problem. Just need to find some time to do it... If anyone has data sheets for these cards I'd like a copy if possible. By the way if anyone has data sheets for if_vr I'd like a copy as well please because there is something the Linux driver does that I do not understand because the code is not obvious enough. Specifically I need to understand what the hell they mean exactly by "patterns for WOL". > > If anyone has a card that does wake on lan after shutdown from Linux > > but not after shutdown from FreeBSD with my patch applied let me know. > > You may need to use the ethtool utility to enable WOL on Linux. > > I don't run Linux on either machine. Perhaps I could do some tests on my > workstation with a CD-based linux distribution. No need to test your cards with Linux since we know now there is code for this in Linux so it should work anyway. -- stefan http://stsp.name PGP Key: 0xF59D25F0
Responsible Changed From-To: freebsd-bugs->kmacy I don't have sis, so I'll have to pass that off to someone else, but WOL support is worth incorporating into FreeBSD. Don't give up yet Stefan :-).
Possible WOL patch for if_re (based on 6.3-R) is attached. I have no data sheet for Realtek NIC, so the algorithm is stolen from Linux driver with some small modifications. I write new state to EEPROM only when necessary (to save limited number of write cycles). I read the actual mode from card on startup with no modification of it (Linux driver sets NIC to compiled in default state on startup despite of NIC's saved configuration). Unfortunately, I can't test it fully. It didn't work form me. I wish the true reason is that the rest of system doesn't know the driver will WOL, so it remove power from the NIC when system ho to power-off state. As I'm not familiar with power management handling in FreeBSD I have no idea how to tell "you must not remove power from me nor from parents devices" to the system. The system devices has the ACPI method called on power state change which may claim that device's minimal power requirements for it's current specific configuration, but I don't know how to do it on OS driver level. May be a system BIOS configuration may be workaround that can fix OS support deficiency, but I didn't found a configuration that worked for my MB. It may be related to specific BIOS version so it may work for someone other. Dan
On Thu, Jan 31, 2008 at 12:07:04AM +0100, Dan Lukes wrote: > Possible WOL patch for if_re (based on 6.3-R) is attached. > @@ -2614,6 +2639,21 @@ > #endif > } > break; > + case SIOCGIFWOLSUPP: > + ifr->ifr_wolopts.ifwol_supported = RE_SUPPORTED_WOL_EVENTS; > + error = 0; > + break; > + case SIOCGIFWOLOPTS: > + RL_LOCK(sc); > + re_get_wolopts(sc, &ifr->ifr_wolopts); > + RL_UNLOCK(sc); > + error = 0; > + break; > + case SIOCSIFWOLOPTS: > + RL_LOCK(sc); > + error = re_set_wolopts(sc, &ifr->ifr_wolopts); > + RL_UNLOCK(sc); > + break; > default: > error = ether_ioctl(ifp, command, data); > break; Note that the ioctl-based configuration has been made obsolete by a commit Sam Leffler made to -CURRENT, see r1.135 of ifconfig.c: http://www.freebsd.org/cgi/cvsweb.cgi/src/sbin/ifconfig/ifconfig.c (He attributed the patch that was comitted to me, but I didn't actually write it.) Drivers should use ifcaps now instead of ioctls. This reduces WOL-related code size tremendously in both ifconfig and drivers. You should rebase your changes on -CURRENT code and send the patch to Sam Leffler and a copy of it to this PR. See http://people.freebsd.org/~yongari/vr/if_vr.c for an example of a driver that does WOL configuration via ifcaps. -- stefan http://stsp.name PGP Key: 0xF59D25F0
Responsible Changed From-To: kmacy->brucec Take.
State Changed From-To: open->patched WOL support was implemented in HEAD(r212167). Will MFC after a couple of weeks. Thanks!
Responsible Changed From-To: brucec->yongari Track, I implemented WOL feature.
State Changed From-To: patched->closed Close, MFC WOL changes to both stable/8 stable/7 done.