Bug 83807 - [sis] [patch] if_sis: Wake On Lan support for FreeBSD
Summary: [sis] [patch] if_sis: Wake On Lan support for FreeBSD
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 7.0-CURRENT
Hardware: Any Any
: Normal Affects Only Me
Assignee: Pyun YongHyeon
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-07-20 20:50 UTC by Stefan Sperling
Modified: 2010-10-11 21:04 UTC (History)
0 users

See Also:


Attachments
FreeBSD-6.0-wol-2006-05-06.diff (31.95 KB, patch)
2006-10-20 10:58 UTC, Stefan Sperling
no flags Details | Diff
FreeBSD-6.1-wol-2006-10-20.diff (31.89 KB, patch)
2006-10-20 11:44 UTC, Stefan Sperling
no flags Details | Diff
patch-re (6.33 KB, text/plain)
2008-01-30 23:07 UTC, Dan Lukes
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Stefan Sperling 2005-07-20 20:50:15 UTC
	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/
Comment 1 Stefan Sperling 2005-07-20 23:25:10 UTC
>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 ---
Comment 2 Stefan Sperling 2006-10-20 10:58:50 UTC
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
Comment 3 Stefan Sperling 2006-10-20 11:44:55 UTC
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
Comment 4 Edwin Mons 2007-06-09 10:08:01 UTC
Will this feature ever be incorporated in mainstream FreeBSD?  I'm 
eagerly waiting for it to land in -CURRENT...
 
Kind regards,
Edwin Mons
Comment 5 Stefan Sperling 2007-06-09 11:38:48 UTC
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
Comment 6 Edwin Mons 2007-06-09 16:07:39 UTC
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
Comment 7 Stefan Sperling 2007-06-10 15:45:04 UTC
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
Comment 8 K. Macy freebsd_committer freebsd_triage 2007-11-18 08:27:46 UTC
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 :-).
Comment 9 Dan Lukes 2008-01-30 23:07:04 UTC
   	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
Comment 10 Stefan Sperling 2008-01-31 11:58:33 UTC
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
Comment 11 Bruce Cran freebsd_committer freebsd_triage 2010-03-05 20:43:58 UTC
Responsible Changed
From-To: kmacy->brucec

Take.
Comment 12 Pyun YongHyeon freebsd_committer freebsd_triage 2010-09-04 00:44:38 UTC
State Changed
From-To: open->patched

WOL support was implemented in HEAD(r212167). 
Will MFC after a couple of weeks. 
Thanks! 


Comment 13 Pyun YongHyeon freebsd_committer freebsd_triage 2010-09-04 00:44:38 UTC
Responsible Changed
From-To: brucec->yongari

Track, I implemented WOL feature.
Comment 14 Pyun YongHyeon freebsd_committer freebsd_triage 2010-10-11 21:04:26 UTC
State Changed
From-To: patched->closed

Close, MFC WOL changes to both stable/8 stable/7 done.