[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, ¶m);
+}
+
+
+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, ¶m);
+}
+
+
+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, ¶m);
+}
+
+
+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, ¶m);
+}
+
+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, ¶m))
+ 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, ¶m))
+ 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, ¶m);
+}
+
+
+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