OSEC

Neohapsis is currently accepting applications for employment. For more information, please visit our website www.neohapsis.com or email hr@neohapsis.com
Re: WOL for if_vr? (was: Re: freebsd driving porting questions)

From: Stefan Sperling (stspstsp.name)
Date: Sun Mar 02 2008 - 08:21:12 CST


On Sun, Mar 02, 2008 at 12:23:57AM +0000, Stuart Henderson wrote:
> On 2008/03/01 14:36, Stefan Sperling wrote:
> > Would you be interested in trying to port the wake on lan support
> > over as well, instead of removing it from the driver?
>
> Personally, I'm mostly trying to fix what's quite a nasty problem with
> the existing driver, i.e. a nic where tx stops working after certain
> media conditions.
>
> Maybe it's just me (particularly now faced with a 3k+ line diff with a
> bunch of changes in that are unrelated to the problems that it's been
> reported to fix),

Yeah, wading through diffs that large can be a real pain :(

By the way, I would also suggest basing your work on the OpenBSD driver,
not the other way round, if this is feasible. Doing so should certainly
narrow down the diff you are creating for the OpenBSD driver.

> but I think it's quite important to do things step by
> step, the diffs to implement different things should be separated as
> much as possible so it's easier to follow what changes have been made.

I didn't mean to imply that all of your changes should go into the same
diff. WOL is a completely separate issue of course. I just thought you
might be interested in working on WOL for if_vr as well while you are
working on improving the driver anyway. This may well mean a separate diff.

And also, I don't mean to take your focus off the issues you are currently
working on. WOL isn't high priority. It's a long-term issue.

The if_vr PHY issue you are trying to fix is much more important.
I'm also affected by it and would love to see it fixed.

> > It would be great to see a small but serious step towards WOL support
> > in OpenBSD. I would also like to help with coding and testing, time
> > permitting.
>
> Surely the infrastructure would need to come first otherwise we'd
> just be adding code to drivers that can't be tested?

Here is a diff that includes the infrastructure changes necessary,
namely new ioctls and ifconfig commands to use them. This diff is based
on -current code as of today. If anyone could take the time to review
it and provide some comments I would be grateful.

The hard part is of course to make the drivers heed the new ioctls and
configure the chip properly. This isn't particularly hard per se, it's
just a lot of work for a single person given the amount of supported devices.

Yongari's FreeBSD if_vr driver has the necessary code, it needs to be
ported over.

I have prototype WOL code for OpenBSD's if_xl, but I still need to tidy
it up and test it.

Index: sys/net/if.c
===================================================================
RCS file: /usr/OpenBSD-CVS/src/sys/net/if.c,v
retrieving revision 1.168
diff -u -r1.168 if.c
--- sys/net/if.c 5 Jan 2008 19:08:19 -0000 1.168
+++ sys/net/if.c 2 Mar 2008 12:47:52 -0000
-1260,6 +1260,7
         case SIOCADDMULTI:
         case SIOCDELMULTI:
         case SIOCSIFMEDIA:
+ case SIOCSIFWOLCFG:
                 if ((error = suser(p, 0)) != 0)
                         return (error);
                 /* FALLTHROUGH */
-1267,6 +1268,8
         case SIOCGIFPDSTADDR:
         case SIOCGLIFPHYADDR:
         case SIOCGIFMEDIA:
+ case SIOCGIFWOLCFG:
+ case SIOCGIFWOLSUPP:
                 if (ifp->if_ioctl == 0)
                         return (EOPNOTSUPP);
                 error = (*ifp->if_ioctl)(ifp, cmd, data);
Index: sys/net/if.h
===================================================================
RCS file: /usr/OpenBSD-CVS/src/sys/net/if.h,v
retrieving revision 1.93
diff -u -r1.93 if.h
--- sys/net/if.h 18 Nov 2007 12:51:48 -0000 1.93
+++ sys/net/if.h 2 Mar 2008 12:47:52 -0000
-559,6 +559,7
                 short ifru_flags;
                 int ifru_metric;
                 caddr_t ifru_data;
+ u_char ifru_wolcfg;
         } ifr_ifru;
 #define ifr_addr ifr_ifru.ifru_addr /* address */
 #define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-to-p link */
-568,7 +569,19
 #define ifr_mtu ifr_ifru.ifru_metric /* mtu (overload) */
 #define ifr_media ifr_ifru.ifru_metric /* media options (overload) */
 #define ifr_data ifr_ifru.ifru_data /* for use by interface */
+#define ifr_wolcfg ifr_ifru.ifru_wolcfg /* wake on lan config */
 };
+
+/* Wake on Lan events.
+ * If you add wake more events, remember to teach
+ * ifconfig about them, too.
+ */
+#define IFWOL_DISABLE 0x00 /* clear all wake events */
+#define IFWOL_WAKE_UCAST 0x01 /* wake on unicast packet */
+#define IFWOL_WAKE_MCAST 0x02 /* wake on multicast packet */
+#define IFWOL_WAKE_BCAST 0x04 /* wake on broadcast packet */
+#define IFWOL_WAKE_MAGIC 0x08 /* wake on Magic Packet(tm) */
+#define IFWOL_WAKE_LINK 0x10 /* wake on link status (PHY) change */

 struct ifaliasreq {
         char ifra_name[IFNAMSIZ]; /* if name, e.g. "en0" */
Index: sys/sys/sockio.h
===================================================================
RCS file: /usr/OpenBSD-CVS/src/sys/sys/sockio.h,v
retrieving revision 1.39
diff -u -r1.39 sockio.h
--- sys/sys/sockio.h 14 Jun 2007 18:31:50 -0000 1.39
+++ sys/sys/sockio.h 2 Mar 2008 12:47:52 -0000
-170,4 +170,8
 #define SIOCSETPFSYNC _IOW('i', 247, struct ifreq)
 #define SIOCGETPFSYNC _IOWR('i', 248, struct ifreq)

+#define SIOCGIFWOLCFG _IOWR('i', 249, struct ifreq) /* get WOL cfg */
+#define SIOCSIFWOLCFG _IOW('i', 250, struct ifreq) /* set WOL cfg */
+#define SIOCGIFWOLSUPP _IOWR('i', 251, struct ifreq) /* supported wake events
*/
+
 #endif /* !_SYS_SOCKIO_H_ */
Index: sbin/ifconfig/ifconfig.8
===================================================================
RCS file: /usr/OpenBSD-CVS/src/sbin/ifconfig/ifconfig.8,v
retrieving revision 1.153
diff -u -r1.153 ifconfig.8
--- sbin/ifconfig/ifconfig.8 11 Feb 2008 07:58:28 -0000 1.153
+++ sbin/ifconfig/ifconfig.8 2 Mar 2008 12:45:55 -0000
-406,6 +406,23
 It happens automatically when setting the first address on an interface.
 If the interface was reset when previously marked down,
 the hardware will be re-initialized.
+.Pp
+.It Cm wakeon Ar events
+Enable Wake On Lan support, if available. The
+.Ar events
+argument is a comma-seperated list of events that should
+cause the system to wake up. The set of valid events is
+.Dq Li unicast ,
+.Dq Li multicast ,
+.Dq Li broadcast ,
+.Dq Li magic ,
+and
+.Dq Li link .
+They correspond to reception of unicast, multicast and broadcast
+packets, of a Magic Packet(tm), and link state change (e.g. a cable
+plugged in or removed from the network card), respectively.
+.It Fl wakeon
+Disable Wake On Lan.
 .El
 .Pp
 .Nm
Index: sbin/ifconfig/ifconfig.c
===================================================================
RCS file: /usr/OpenBSD-CVS/src/sbin/ifconfig/ifconfig.c,v
retrieving revision 1.193
diff -u -r1.193 ifconfig.c
--- sbin/ifconfig/ifconfig.c 5 Feb 2008 22:57:30 -0000 1.193
+++ sbin/ifconfig/ifconfig.c 2 Mar 2008 13:21:49 -0000
-225,6 +225,11
 void trunk_status(void);
 int main(int, char *[]);
 int prefix(void *val, int);
+void wol_status(void);
+void printwolcfg(u_char);
+void setwolcfg(const char *, int);
+u_char parse_wakeon_args(const char*);
+void unsetwolcfg(const char *, int);

 /*
  * Media stuff. Whenever a media command is first performed, the
-373,6 +378,8
         { "descr", NEXTARG, 0, setifdesc },
         { "-description", 1, 0, unsetifdesc },
         { "-descr", 1, 0, unsetifdesc },
+ { "wakeon", NEXTARG, 0, setwolcfg },
+ { "-wakeon", 0, 0, unsetwolcfg },
         { NULL, /*src*/ 0, 0, setifaddr },
         { NULL, /*dst*/ 0, 0, setifdstaddr },
         { NULL, /*illegal*/0, 0, NULL },
-2393,6 +2400,7
         }

         phys_status(0);
+ wol_status();
 }

 /* ARGSUSED */
-4028,3 +4036,94
                 warn("SIOCSIFLLADDR");
 }

+void
+wol_status(void)
+{
+ memset(&ifr, 0, sizeof(ifr));
+ (void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ if (ioctl(s, SIOCGIFWOLSUPP, &ifr) < 0)
+ return;
+
+ printf("\tsupported wake events:");
+ printwolcfg(ifr.ifr_wolcfg);
+ printf("\n");
+
+ if (ioctl(s, SIOCGIFWOLCFG, &ifr) < 0)
+ err(1, "SIOCGIFWOLCFG");
+
+ if (ifr.ifr_wolcfg) {
+ printf("\twill wake on:");
+ printwolcfg(ifr.ifr_wolcfg);
+ printf("\n");
+ }
+}
+
+void
+printwolcfg(u_char wolcfg)
+{
+ if (wolcfg & IFWOL_WAKE_UCAST)
+ printf(" unicast");
+ if (wolcfg & IFWOL_WAKE_MCAST)
+ printf(" multicast");
+ if (wolcfg & IFWOL_WAKE_BCAST)
+ printf(" broadcast");
+ if (wolcfg & IFWOL_WAKE_MAGIC)
+ printf(" magic");
+ if (wolcfg & IFWOL_WAKE_LINK)
+ printf(" link");
+}
+
+/*ARGSUSED*/
+void
+setwolcfg(const char *val, int ignored)
+{
+ memset(&ifr, 0, sizeof(ifr));
+ (void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ if (ioctl(s, SIOCGIFWOLSUPP, &ifr) < 0)
+ err(1, "device does not support wake on lan");
+
+ ifr.ifr_wolcfg = parse_wakeon_args(val);
+
+ if (ioctl(s, SIOCSIFWOLCFG, &ifr) < 0)
+ err(1, "SIOCSIFWOLCFG");
+}
+
+u_char
+parse_wakeon_args(const char* args)
+{
+ char* opt;
+ u_char wolcfg;
+
+ wolcfg = 0;
+
+ for (opt = strdup(args); (opt = strtok(opt, ",")) != NULL; opt = NULL) {
+ if (strcmp(opt, "unicast") == 0)
+ wolcfg |= IFWOL_WAKE_UCAST;
+ else if (strcmp(opt, "multicast") == 0)
+ wolcfg |= IFWOL_WAKE_MCAST;
+ else if (strcmp(opt, "broadcast") == 0)
+ wolcfg |= IFWOL_WAKE_BCAST;
+ else if (strcmp(opt, "magic") == 0)
+ wolcfg |= IFWOL_WAKE_MAGIC;
+ else if (strcmp(opt, "link") == 0)
+ wolcfg |= IFWOL_WAKE_LINK;
+ else
+ errx(1, "unknown wake event '%s'", opt);
+ }
+ free(opt);
+ return wolcfg;
+}
+
+/*ARGSUSED*/
+void
+unsetwolcfg(const char *addr, int ignored)
+{
+ memset(&ifr, 0, sizeof(ifr));
+ (void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ ifr.ifr_wolcfg = IFWOL_DISABLE;
+ if (ioctl(s, SIOCSIFWOLCFG, &ifr) < 0)
+ err(1, "SIOCSIFWOLCFG");
+}

--
stefan
http://stsp.name PGP Key: 0xF59D25F0

[demime 1.01d removed an attachment of type application/pgp-signature]