[PATCH]: new driver_wired

Gunter Burchardt gbur
Tue Dec 7 04:45:38 PST 2004


Hello,

New wired authentication kernel module is ready. Its to big for mailing
list, so I put it to a web server.

http://www.informatik.uni-rostock.de/~gbur/pae/pae-0.0.2.tar.gz

The patch for latests hostap cvs is attached at this mail.

Station detection is done in kernel now. Hostapd doesn't need receive a
dhcpd-packet anymore! Kernel module can control multiple ethernet
devices.

Jouni, can you add this to hostap?

Any suggestions or commenty are welcome.

regards
gunter
-------------- next part --------------
diff -Nur hostap.old/hostapd/defconfig hostap/hostapd/defconfig
--- hostap.old/hostapd/defconfig	2004-12-07 07:12:41.000000000 +0100
+++ hostap/hostapd/defconfig	2004-12-07 07:55:47.000000000 +0100
@@ -13,7 +13,8 @@
 CONFIG_DRIVER_HOSTAP=y
 
 # Driver interface for wired authenticator
-#CONFIG_DRIVER_WIRED=y
+CONFIG_DRIVER_WIRED=y
+CFLAGS += -I../pae/modules # change to reflect local setup
 
 # Driver interface for madwifi driver
 #CONFIG_DRIVER_MADWIFI=y
diff -Nur hostap.old/hostapd/driver_wired.c hostap/hostapd/driver_wired.c
--- hostap.old/hostapd/driver_wired.c	2004-12-07 06:33:11.000000000 +0100
+++ hostap/hostapd/driver_wired.c	2004-12-07 07:49:59.000000000 +0100
@@ -31,10 +31,12 @@
 #include <linux/if_ether.h>   /* The L2 protocols */
 #include <linux/if_arp.h>
 #include <linux/if.h>
+#include <linux/wireless.h>
 #else /* USE_KERNEL_HEADERS */
 #include <net/if_arp.h>
 #include <net/if.h>
 #include <netpacket/packet.h>
+#include "wireless_copy.h"
 #endif /* USE_KERNEL_HEADERS */
 
 #include "hostapd.h"
@@ -42,15 +44,20 @@
 #include "eloop.h"
 #include "sta_info.h"
 #include "driver.h"
+#include "priv_netlink.h"
 #include "accounting.h"
 
+#include "pae_common.h"
+
+#define PAE_DEV_NAME "pae" /* device name for pae */
 
 struct wired_driver_data {
 	struct driver_ops ops;
 	struct hostapd_data *hapd;
 
+	int ifindex; /* index of device for pae */
 	int sock; /* raw packet socket for driver access */
-	int dhcp_sock; /* socket for dhcp packets */
+	int wext_sock; /* socket for wireless events (station detection) */
 };
 
 static const struct driver_ops wired_driver_ops;
@@ -58,31 +65,6 @@
 
 #define WIRED_EAPOL_MULTICAST_GROUP	{0x01,0x80,0xc2,0x00,0x00,0x03}
 
-
-/* TODO: detecting new devices should eventually be changed from using DHCP
- * snooping to trigger on any packet from a new layer 2 MAC address, e.g.,
- * based on ebtables, etc. */
-
-struct dhcp_message {
-	u_int8_t op;
-	u_int8_t htype;
-	u_int8_t hlen;
-	u_int8_t hops;
-	u_int32_t xid;
-	u_int16_t secs;
-	u_int16_t flags;
-	u_int32_t ciaddr;
-	u_int32_t yiaddr;
-	u_int32_t siaddr;
-	u_int32_t giaddr;
-	u_int8_t chaddr[16];
-	u_int8_t sname[64];
-	u_int8_t file[128];
-	u_int32_t cookie;
-	u_int8_t options[308]; /* 312 - cookie */
-};
-
-
 static void wired_possible_new_sta(struct hostapd_data *hapd, u8 *addr)
 {
 	struct sta_info *sta;
@@ -95,6 +77,13 @@
 		      MACSTR " - adding a new STA\n", MAC2STR(addr));
 	sta = ap_sta_add(hapd, addr);
 	if (sta) {
+		accounting_sta_get_id(hapd, sta);
+		if (hostapd_sta_add(hapd, sta->addr,
+				    sta->aid, sta->capability,
+				    sta->tx_supp_rates)) {
+			printf("Could not add station to kernel driver.\n");
+		}
+		sta->flags |= WLAN_STA_ASSOC;
 		hostapd_new_assoc_sta(hapd, sta);
 		accounting_sta_get_id(hapd, sta);
 	} else {
@@ -158,47 +147,13 @@
 }
 
 
-static void handle_dhcp(int sock, void *eloop_ctx, void *sock_ctx)
-{
-	struct hostapd_data *hapd = (struct hostapd_data *) eloop_ctx;
-	int len;
-	unsigned char buf[3000];
-	struct dhcp_message *msg;
-	u8 *mac_address;
-
-	len = recv(sock, buf, sizeof(buf), 0);
-	if (len < 0) {
-		perror("recv"); 
-		return;
-	}
-
-	/* must contain at least dhcp_message->chaddr */
-	if (len < 44) {
-		HOSTAPD_DEBUG(HOSTAPD_DEBUG_VERBOSE, "handle_dhcp: too short "
-			      "(%d)\n", len);
-		return;
-	}
-	
-	msg = (struct dhcp_message *) buf;
-	mac_address = (u8 *) &(msg->chaddr);
-	
-	HOSTAPD_DEBUG(HOSTAPD_DEBUG_VERBOSE,
-		      "Got DHCP broadcast packet from " MACSTR "\n",
-		      MAC2STR(mac_address));
-
-	wired_possible_new_sta(hapd, mac_address);
-}
-
-
 static int wired_init_sockets(struct wired_driver_data *drv)
 {
 	struct hostapd_data *hapd = drv->hapd;
 	struct ifreq ifr;
 	struct sockaddr_ll addr;
-	struct sockaddr_in addr2;
 	struct packet_mreq mreq;
 	u8 multicastgroup_eapol[6] = WIRED_EAPOL_MULTICAST_GROUP;
-	int n = 1;
 
 	drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
 	if (drv->sock < 0) {
@@ -219,7 +174,8 @@
 		return -1;
 	}
 
-	
+	drv->ifindex = ifr.ifr_ifindex;
+
 	memset(&addr, 0, sizeof(addr));
 	addr.sll_family = AF_PACKET;
 	addr.sll_ifindex = ifr.ifr_ifindex;
@@ -259,48 +215,6 @@
 	}
 	memcpy(hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
 
-	/* setup dhcp listen socket for sta detection */
-	if ((drv->dhcp_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
-		perror("socket call failed for dhcp");
-		return -1;
-	}
-
-	if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp, hapd, NULL))
-	{
-		printf("Could not register read socket\n");
-		return -1;
-	}
-	
-	memset(&addr2, 0, sizeof(addr2));
-	addr2.sin_family = AF_INET;
-	addr2.sin_port = htons(67);
-	addr2.sin_addr.s_addr = INADDR_ANY;
-
-	if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_REUSEADDR, (char *) &n,
-		       sizeof(n)) == -1) {
-		perror("setsockopt[SOL_SOCKET,SO_REUSEADDR]");
-		return -1;
-	}
-	if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BROADCAST, (char *) &n,
-		       sizeof(n)) == -1) {
-		perror("setsockopt[SOL_SOCKET,SO_BROADCAST]");
-		return -1;
-	}
-
-	memset(&ifr, 0, sizeof(ifr));
-	strncpy(ifr.ifr_ifrn.ifrn_name, hapd->conf->iface, IFNAMSIZ);
-	if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BINDTODEVICE,
-		       (char *) &ifr, sizeof(ifr)) < 0) {
-		perror("setsockopt[SOL_SOCKET,SO_BINDTODEVICE]");
-		return -1;
-	}
-
-	if (bind(drv->dhcp_sock, (struct sockaddr *) &addr2,
-		 sizeof(struct sockaddr)) == -1) {
-		perror("bind");
-		return -1;
-	}
-
 	return 0;
 }
 
@@ -341,6 +255,299 @@
 	return res;
 }
 
+static int drv_dev_ioctl(struct wired_driver_data *drv, 
+			 struct pae_dev_param *param)
+{
+	struct ifreq req;
+
+	param->ifindex = drv->ifindex;
+	strcpy(req.ifr_name,PAE_DEV_NAME);
+	req.ifr_data = (caddr_t)param;
+
+	if( ioctl(drv->sock, PAE_DEV, &req ) < 0) {
+		printf("ioctl(PAE_DEV)\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int drv_sta_ioctl(struct wired_driver_data *drv,
+			 struct pae_sta_param *param)
+{
+	struct ifreq req;
+
+	param->ifindex = drv->ifindex;
+	strcpy(req.ifr_name,PAE_DEV_NAME);
+	req.ifr_data = (caddr_t)param;
+
+	if( ioctl(drv->sock, PAE_STA, &req ) < 0) {
+		printf("ioctl(PAE_STA)\n");
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wired_flush(void *priv) {
+	struct wired_driver_data *drv = priv;
+	struct pae_dev_param param;
+
+	param.command = PAE_DEV_FLUSH;
+
+	return drv_dev_ioctl(drv, &param);
+}
+
+
+static int wired_set_ieee8021x(void *priv, int enabled) {
+	struct wired_driver_data *drv = priv;
+	struct pae_dev_param param;
+
+	if(enabled)
+		param.command = PAE_DEV_ADD;
+	else
+		param.command = PAE_DEV_DEL;
+
+	return drv_dev_ioctl(drv, &param);
+}
+
+
+static int wired_sta_add(void *priv, u8 *addr, u16 aid, u16 capability,
+			 u8 tx_supp_rates) {
+	struct wired_driver_data *drv = priv;
+	struct pae_sta_param param;
+
+	param.command = PAE_STA_ADD;
+	memcpy(param.sta_addr, addr, ETH_ALEN);
+	
+	return drv_sta_ioctl(drv, &param);
+}
+ 
+
+static int wired_sta_remove(void *priv, u8 *addr) {
+	struct wired_driver_data *drv = priv;
+	struct pae_sta_param param;
+
+	param.command = PAE_STA_REMOVE;
+	memcpy(param.sta_addr, addr, ETH_ALEN);
+
+	return drv_sta_ioctl(drv, &param);
+}
+
+static int wired_read_sta_data(void *priv, struct hostap_sta_driver_data *data,
+			       u8 *addr) {
+	struct wired_driver_data *drv = priv;
+	struct pae_sta_param param;
+
+	param.command = PAE_STA_GET_INFO;
+	memcpy(param.sta_addr, addr, ETH_ALEN);
+
+	if (drv_sta_ioctl(drv, &param))
+		return -1;
+
+	data->rx_packets = param.u.get_info.rx_packets;
+	data->tx_packets = param.u.get_info.tx_packets;
+	data->rx_bytes = param.u.get_info.rx_bytes;
+	data->tx_bytes = param.u.get_info.tx_bytes;
+
+	return 0;
+}
+
+
+static int wired_get_inact_sec(void *priv, u8 *addr) {
+	struct wired_driver_data *drv = priv;
+	struct pae_sta_param param;
+
+	param.command = PAE_STA_GET_INFO;
+	memcpy(param.sta_addr, addr, ETH_ALEN);
+
+	if (drv_sta_ioctl(drv, &param))
+		return -1;
+
+	return param.u.get_info.inactive_sec;
+}
+
+
+static int wired_set_sta_authorized(void *priv, u8 *addr, int authorized) {
+	struct wired_driver_data *drv = priv;
+	struct pae_sta_param param;
+
+	if (authorized)
+		param.command = PAE_STA_AUTHORIZE;
+	else
+		param.command = PAE_STA_DEAUTHORIZE;
+
+	memcpy(param.sta_addr, addr, ETH_ALEN);
+
+	return drv_sta_ioctl(drv, &param);
+}
+
+
+static void
+wired_wireless_event_wireless(struct wired_driver_data *drv,
+					    char *data, int len)
+{
+	struct hostapd_data *hapd = drv->hapd;
+	struct iw_event *iwe;
+	char *pos, *end;
+
+	pos = data;
+	end = data + len;
+
+	while (pos + IW_EV_LCP_LEN <= end) {
+		iwe = (struct iw_event *) pos;
+		HOSTAPD_DEBUG(HOSTAPD_DEBUG_VERBOSE, "Wireless event: "
+			      "cmd=0x%x len=%d\n", iwe->cmd, iwe->len);
+		if (iwe->len <= IW_EV_LCP_LEN)
+			return;
+		switch (iwe->cmd) {
+		case IWEVEXPIRED:
+			break;
+		case IWEVREGISTERED:
+			HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Wireless event: "
+				      "Station registered: "MACSTR,
+				      MAC2STR(iwe->u.addr.sa_data));
+			wired_possible_new_sta(hapd, iwe->u.addr.sa_data);
+			break;
+		case IWEVCUSTOM:
+			break;
+		}
+
+		pos += iwe->len;
+	}
+}
+
+ 
+static void
+wired_wireless_event_rtm_newlink(struct wired_driver_data *drv,
+				 struct nlmsghdr *h, int len)
+{
+	struct ifinfomsg *ifi;
+	int attrlen, nlmsg_len, rta_len;
+	struct rtattr * attr;
+
+	if (len < sizeof(*ifi))
+		return;
+
+	ifi = NLMSG_DATA(h);
+
+	if (ifi->ifi_index != drv->ifindex)
+		return;
+
+	nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+	attrlen = h->nlmsg_len - nlmsg_len;
+	if (attrlen < 0)
+		return;
+
+	attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+
+	rta_len = RTA_ALIGN(sizeof(struct rtattr));
+	while (RTA_OK(attr, attrlen)) {
+		if (attr->rta_type == IFLA_WIRELESS) {
+			wired_wireless_event_wireless(
+				drv, ((char *) attr) + rta_len,
+				attr->rta_len - rta_len);
+		}
+		attr = RTA_NEXT(attr, attrlen);
+	}
+}
+
+
+static void
+wired_wireless_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	char buf[256];
+	int left;
+	struct sockaddr_nl from;
+	socklen_t fromlen;
+	struct nlmsghdr *h;
+	struct wired_driver_data *drv = eloop_ctx;
+
+	fromlen = sizeof(from);
+	left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
+			(struct sockaddr *) &from, &fromlen);
+	if (left < 0) {
+		if (errno != EINTR && errno != EAGAIN)
+			perror("recvfrom(netlink)");
+		return;
+	}
+
+	h = (struct nlmsghdr *) buf;
+	while (left >= sizeof(*h)) {
+		int len, plen;
+
+		len = h->nlmsg_len;
+		plen = len - sizeof(*h);
+		if (len > left || plen < 0) {
+			printf("Malformed netlink message: "
+			       "len=%d left=%d plen=%d\n",
+			       len, left, plen);
+			break;
+		}
+
+		switch (h->nlmsg_type) {
+		case RTM_NEWLINK:
+			wired_wireless_event_rtm_newlink(drv, h, plen);
+			break;
+		}
+
+		len = NLMSG_ALIGN(len);
+		left -= len;
+		h = (struct nlmsghdr *) ((char *) h + len);
+	}
+
+	if (left > 0) {
+		printf("%d extra bytes in the end of netlink message\n", left);
+	}
+}
+
+
+static int
+wired_wireless_event_init(void *priv)
+{
+	struct wired_driver_data *drv = priv;
+	int s;
+	struct sockaddr_nl local;
+
+	drv->wext_sock = -1;
+
+	s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+	if (s < 0) {
+		perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
+		return -1;
+	}
+
+	memset(&local, 0, sizeof(local));
+	local.nl_family = AF_NETLINK;
+	local.nl_groups = RTMGRP_LINK;
+	if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
+		perror("bind(netlink)");
+		close(s);
+		return -1;
+	}
+
+	eloop_register_read_sock(s, wired_wireless_event_receive, drv, NULL);
+	drv->wext_sock = s;
+
+	return 0;
+}
+
+
+static void
+wired_wireless_event_deinit(void *priv)
+{
+	struct wired_driver_data *drv = priv;
+
+	if (drv != NULL) {
+		if (drv->wext_sock < 0)
+			return;
+		eloop_unregister_read_sock(drv->wext_sock);
+		close(drv->wext_sock);
+	}
+}
+
 
 static int wired_driver_init(struct hostapd_data *hapd)
 {
@@ -373,9 +580,6 @@
 	if (drv->sock >= 0)
 		close(drv->sock);
 	
-	if (drv->dhcp_sock >= 0)
-		close(drv->dhcp_sock);
-
 	free(drv);
 }
 
@@ -385,6 +589,16 @@
 	.init = wired_driver_init,
 	.deinit = wired_driver_deinit,
 	.send_eapol = wired_send_eapol,
+	.set_sta_authorized = wired_set_sta_authorized,
+	.send_eapol = wired_send_eapol,
+	.read_sta_data = wired_read_sta_data,
+	.sta_remove = wired_sta_remove,
+	.sta_add = wired_sta_add,
+	.wireless_event_init = wired_wireless_event_init,
+	.wireless_event_deinit = wired_wireless_event_deinit,
+	.get_inact_sec = wired_get_inact_sec,
+	.set_ieee8021x = wired_set_ieee8021x,
+	.flush = wired_flush,
 };
 
 void wired_driver_register(void)



More information about the Hostap mailing list