kern/83807: [patch] Wake On Lan support for FreeBSD
Stefan Sperling
stsp at stsp.in-berlin.de
Wed Jul 20 22:30:27 GMT 2005
The following reply was made to PR kern/83807; it has been noted by GNATS.
From: Stefan Sperling <stsp at stsp.in-berlin.de>
To: FreeBSD-gnats-submit at 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 at 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 ---
More information about the freebsd-bugs
mailing list