Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 20 Jul 2005 22:30:26 GMT
From:      Stefan Sperling <stsp@stsp.in-berlin.de>
To:        freebsd-bugs@FreeBSD.org
Subject:   Re: kern/83807: [patch] Wake On Lan support for FreeBSD
Message-ID:  <200507202230.j6KMUQNM081639@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR kern/83807; it has been noted by GNATS.

From: Stefan Sperling <stsp@stsp.in-berlin.de>
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:<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 ---
 
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200507202230.j6KMUQNM081639>