PATCH RFC: wpa_supplicant influencing device operstate

Pedro Ramalhais ramalhais at serrado.net
Thu Mar 9 20:57:51 EST 2006


Stefan Rompf wrote:
> Hi,
> 
> some weeks ago, there has been a quite heated discussion on linux-netdev about 
> extending functionality of netif_carrier_on()/off(). In the end, a patch 
> written by me has been applied for 2.6.17. For an overview, see the 
> documentation at http://www.flamewarmaster.de/software/operstates.txt . The 
> patch itself (applies to 2.6.14+) can be found on this site too. Main point 
> concerning this list is that it allows an userspace supplicant to signal the 
> kernel when the interface is ready for user traffic after authentication, and 
> afterwards, kernel notifies other programs via the existing IFF_RUNNING 
> interface.
> 
> The quagga routing daemon, vrrpd and my new dhcp client 
> (http://www.flamewarmaster.de/software/dhcpclient/) can act on these 
> messages.
> 
> I have attached a patch against wpa_supplicant 0.5.1 to this mail that 
> implements signalling functionality in the WEXT driver. Note that I haven't 
> tested how this affects drivers that rely on WEXT functionality - this is a 
> very first version.
> 
> With this extension, I can start wpa_supplicant and my DHCP client in 
> parallel. Whenever the supplicant has completed association, and WPA 
> authentication if needed, the DHCP client will automatically update the 
> interface IP configuration. Together with a graphical wpa_cli (will try 
> wpa_gui), this increases usability of wireless LANs a lot. In the long run, 
> I'd like this feature to be added to wpa_supplicant.
> 
> Thoughts?
> 
> Stefan
> 
> 
> ------------------------------------------------------------------------
> 
> diff -x '*.o' -x '*.d' -x '*~' -x wpa_cli -x wpa_passphrase -x wpa_supplicant -upr wpa_supplicant-0.5.1.orig/driver.h wpa_supplicant-0.5.1/driver.h
> --- wpa_supplicant-0.5.1.orig/driver.h	2005-10-15 17:36:32.000000000 +0200
> +++ wpa_supplicant-0.5.1/driver.h	2006-03-03 20:03:44.000000000 +0100
> @@ -554,6 +554,13 @@ struct wpa_driver_ops {
>  	 */
>  	int (*send_eapol)(void *priv, const u8 *dest, u16 proto,
>  			  const u8 *data, size_t data_len);
> +
> +	/**
> +	 * set_operstate - Sets device operating state to DORMANT or UP
> +	 * @priv: private driver interface data
> +	 * @state: 0 = dormant, 1 = up
> +	 */
> +	void (*set_operstate)(void *priv, int state); 
>  };
>  
>  #endif /* DRIVER_H */
> diff -x '*.o' -x '*.d' -x '*~' -x wpa_cli -x wpa_passphrase -x wpa_supplicant -upr wpa_supplicant-0.5.1.orig/driver_wext.c wpa_supplicant-0.5.1/driver_wext.c
> --- wpa_supplicant-0.5.1.orig/driver_wext.c	2006-01-30 05:11:48.000000000 +0100
> +++ wpa_supplicant-0.5.1/driver_wext.c	2006-03-03 23:48:09.000000000 +0100
> @@ -47,11 +47,14 @@ struct wpa_driver_wext_data {
>  	struct wpa_driver_capa capa;
>  	int has_capability;
>  	int we_version_compiled;
> +	int operstate;
>  };
>  
>  
>  static int wpa_driver_wext_flush_pmkid(void *priv);
>  static int wpa_driver_wext_get_range(void *priv);
> +static void wpa_driver_wext_send_oper_ifla(struct wpa_driver_wext_data *drv,
> +					   char linkmode, char operstate);
>  
>  
>  static int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
> @@ -559,6 +562,15 @@ static void wpa_driver_wext_event_rtm_ne
>  		return;
>  	}
>  
> +	/* some drivers send the association event before the operup event - 
> +	   in this case, lifting operstate in wpa_driver_wext_set_operstate()
> +	   fails. This will hit us when wpa_supplicant doesn't need to do
> +	   802.1X authentication */
> +	if (drv->ifindex == ifi->ifi_index && drv->operstate == 1 &&
> +	    (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
> +	    !(ifi->ifi_flags & IFF_RUNNING))
> +		wpa_driver_wext_send_oper_ifla(drv, -1, IF_OPER_UP);
> +
>  	nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
>  
>  	attrlen = h->nlmsg_len - nlmsg_len;
> @@ -794,6 +806,8 @@ void * wpa_driver_wext_init(void *ctx, c
>  		wpa_driver_wext_alternative_ifindex(drv, ifname2);
>  	}
>  
> +	wpa_driver_wext_send_oper_ifla(drv, 1, IF_OPER_DORMANT);
> +
>  	return drv;
>  }
>  
> @@ -816,6 +830,8 @@ void wpa_driver_wext_deinit(void *priv)
>  	 */
>  	wpa_driver_wext_set_bssid(drv, (u8 *) "\x00\x00\x00\x00\x00\x00");
>  
> +	wpa_driver_wext_send_oper_ifla(priv, 0, IF_OPER_UP);
> +
>  	eloop_unregister_read_sock(drv->event_sock);
>  
>  	if (wpa_driver_wext_get_ifflags(drv, &flags) == 0)
> @@ -1759,6 +1775,57 @@ int wpa_driver_wext_alternative_ifindex(
>  }
>  
>  
> +static void wpa_driver_wext_send_oper_ifla(struct wpa_driver_wext_data *drv,
> +					   char linkmode, char operstate) {
> +	struct {
> +		struct nlmsghdr hdr;
> +		struct ifinfomsg ifinfo;
> +		char opts[16];
> +	} req;
> +	struct rtattr *rta;
> +	static int nl_seq;
> +
> +	req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
> +	req.hdr.nlmsg_type = RTM_SETLINK;
> +	req.hdr.nlmsg_flags = NLM_F_REQUEST;
> +	req.hdr.nlmsg_seq = ++nl_seq;
> +	req.hdr.nlmsg_pid = 0;
> +
> +	req.ifinfo.ifi_family = AF_UNSPEC;
> +        req.ifinfo.ifi_type = 0;
> +        req.ifinfo.ifi_index = drv->ifindex;
> +        req.ifinfo.ifi_flags = 0;
> +        req.ifinfo.ifi_change = 0;
> +
> +	if (linkmode != -1) {
> +		rta = (struct rtattr *)((char *)&req + NLMSG_ALIGN(req.hdr.nlmsg_len));
> +		rta->rta_type = IFLA_LINKMODE;
> +		rta->rta_len = RTA_LENGTH(sizeof(char));
> +		*((char *)RTA_DATA(rta)) = linkmode;
> +		req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) + RTA_LENGTH(sizeof(char));
> +	}
> +	if (operstate != -1) {
> +		rta = (struct rtattr *)((char *)&req + NLMSG_ALIGN(req.hdr.nlmsg_len));
> +		rta->rta_type = IFLA_OPERSTATE;
> +		rta->rta_len = RTA_LENGTH(sizeof(char));
> +		*((char *)RTA_DATA(rta)) = operstate;
> +		req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) + RTA_LENGTH(sizeof(char));
> +	}
> +
> +	printf("Operstate: linkmode=%d, operstate=%d\n", linkmode, operstate);
> +
> +	(void)send(drv->event_sock, &req, req.hdr.nlmsg_len, 0);
> +}
> +
> +
> +static void wpa_driver_wext_set_operstate(void *priv, int state) {
> +	struct wpa_driver_wext_data *drv = priv;
> +
> +	drv->operstate = state;
> +	wpa_driver_wext_send_oper_ifla(drv, -1, state?IF_OPER_UP:IF_OPER_DORMANT);
> +}
> +
> +
>  const struct wpa_driver_ops wpa_driver_wext_ops = {
>  	.name = "wext",
>  	.desc = "Linux wireless extensions (generic)",
> @@ -1780,4 +1847,5 @@ const struct wpa_driver_ops wpa_driver_w
>  	.remove_pmkid = wpa_driver_wext_remove_pmkid,
>  	.flush_pmkid = wpa_driver_wext_flush_pmkid,
>  	.get_capa = wpa_driver_wext_get_capa,
> +	.set_operstate = wpa_driver_wext_set_operstate,
>  };
> diff -x '*.o' -x '*.d' -x '*~' -x wpa_cli -x wpa_passphrase -x wpa_supplicant -upr wpa_supplicant-0.5.1.orig/priv_netlink.h wpa_supplicant-0.5.1/priv_netlink.h
> --- wpa_supplicant-0.5.1.orig/priv_netlink.h	2005-06-18 19:39:36.000000000 +0200
> +++ wpa_supplicant-0.5.1/priv_netlink.h	2006-03-03 23:26:45.000000000 +0100
> @@ -20,18 +20,36 @@
>   * library, etc..
>   */
>  
> +#ifndef IFF_LOWER_UP
> +#define IFF_LOWER_UP   0x10000         /* driver signals L1 up         */
> +#endif
> +#ifndef IFF_DORMANT
> +#define IFF_DORMANT    0x20000         /* driver signals dormant       */
> +#endif
> +
>  #ifndef IFLA_IFNAME
>  #define IFLA_IFNAME 3
>  #endif
>  #ifndef IFLA_WIRELESS
>  #define IFLA_WIRELESS 11
>  #endif
> +#ifndef IFLA_OPERSTATE
> +#define IFLA_OPERSTATE 16
> +#endif
> +#ifndef IFLA_LINKMODE
> +#define IFLA_LINKMODE 17
> +#define IF_OPER_DORMANT 5
> +#define IF_OPER_UP 6
> +#endif
> +
> +#define NLM_F_REQUEST 1
>  
>  #define NETLINK_ROUTE 0
>  #define RTMGRP_LINK 1
>  #define RTM_BASE 0x10
>  #define RTM_NEWLINK (RTM_BASE + 0)
>  #define RTM_DELLINK (RTM_BASE + 1)
> +#define RTM_SETLINK (RTM_BASE + 3)
>  
>  #define NLMSG_ALIGNTO 4
>  #define NLMSG_ALIGN(len) (((len) + NLMSG_ALIGNTO - 1) & ~(NLMSG_ALIGNTO - 1))
> @@ -46,6 +64,9 @@
>  #define RTA_NEXT(rta,attrlen) \
>  ((attrlen) -= RTA_ALIGN((rta)->rta_len), \
>  (struct rtattr *) (((char *)(rta)) + RTA_ALIGN((rta)->rta_len)))
> +#define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
> +#define RTA_DATA(rta)   ((void*)(((char*)(rta)) + RTA_LENGTH(0)))
> +
>  
>  
>  struct sockaddr_nl
> diff -x '*.o' -x '*.d' -x '*~' -x wpa_cli -x wpa_passphrase -x wpa_supplicant -upr wpa_supplicant-0.5.1.orig/wpa_supplicant.c wpa_supplicant-0.5.1/wpa_supplicant.c
> --- wpa_supplicant-0.5.1.orig/wpa_supplicant.c	2006-01-30 05:24:58.000000000 +0100
> +++ wpa_supplicant-0.5.1/wpa_supplicant.c	2006-03-03 20:20:15.000000000 +0100
> @@ -706,9 +706,11 @@ void wpa_supplicant_set_state(struct wpa
>  			MAC2STR(wpa_s->bssid), wpa_s->reassociated_connection ?
>  			"(reauth)" : "(auth)");
>  		wpa_s->reassociated_connection = 1;
> +		wpa_drv_set_operstate(wpa_s, 1);
>  	} else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
>  		   state == WPA_ASSOCIATED) {
>  		wpa_s->new_connection = 1;
> +		wpa_drv_set_operstate(wpa_s, 0);
>  	}
>  	wpa_s->wpa_state = state;
>  }
> diff -x '*.o' -x '*.d' -x '*~' -x wpa_cli -x wpa_passphrase -x wpa_supplicant -upr wpa_supplicant-0.5.1.orig/wpa_supplicant_i.h wpa_supplicant-0.5.1/wpa_supplicant_i.h
> --- wpa_supplicant-0.5.1.orig/wpa_supplicant_i.h	2005-11-28 05:44:50.000000000 +0100
> +++ wpa_supplicant-0.5.1/wpa_supplicant_i.h	2006-03-03 20:05:17.000000000 +0100
> @@ -484,4 +484,10 @@ static inline int wpa_drv_send_eapol(str
>  	return -1;
>  }
>  
> +static inline void wpa_drv_set_operstate(struct wpa_supplicant *wpa_s,
> +					 int state)
> +{
> +	if (wpa_s->driver->set_operstate)
> +		wpa_s->driver->set_operstate(wpa_s->drv_priv, state);
> +}
>  #endif /* WPA_SUPPLICANT_I_H */
> 
> 
> ------------------------------------------------------------------------
> 
> _______________________________________________
> HostAP mailing list
> HostAP at shmoo.com
> http://lists.shmoo.com/mailman/listinfo/hostap

I think those are great news.
Maybe someone might want to look into adding it to the wired driver too.
I'm assuming that using wpa_supplicant for 802.1X via wired works.
Thanks for your effort!
-- 
Pedro Ramalhais



More information about the HostAP mailing list