From owner-freebsd-bugs@FreeBSD.ORG Wed Jul 20 22:30:27 2005 Return-Path: X-Original-To: freebsd-bugs@hub.freebsd.org Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 2B46A16A422 for ; Wed, 20 Jul 2005 22:30:27 +0000 (GMT) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id CCB0843D48 for ; Wed, 20 Jul 2005 22:30:26 +0000 (GMT) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.13.3/8.13.3) with ESMTP id j6KMUQcp081642 for ; Wed, 20 Jul 2005 22:30:26 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.13.3/8.13.1/Submit) id j6KMUQNM081639; Wed, 20 Jul 2005 22:30:26 GMT (envelope-from gnats) Date: Wed, 20 Jul 2005 22:30:26 GMT Message-Id: <200507202230.j6KMUQNM081639@freefall.freebsd.org> To: freebsd-bugs@FreeBSD.org From: Stefan Sperling Cc: Subject: Re: kern/83807: [patch] Wake On Lan support for FreeBSD X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Stefan Sperling List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 20 Jul 2005 22:30:27 -0000 The following reply was made to PR kern/83807; it has been noted by GNATS. From: Stefan Sperling To: FreeBSD-gnats-submit@freebsd.org Cc: Subject: Re: kern/83807: [patch] Wake On Lan support for FreeBSD Date: Thu, 21 Jul 2005 00:25:10 +0200 (CEST) >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: +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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 ---