📄 driver_prism54.c
字号:
/* * hostapd / Driver interaction with Prism54 PIMFOR interface * Copyright (c) 2004, Bell Kin <bell_kin@pek.com.tw> * based on hostap driver.c, ieee802_11.c * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */#include "includes.h"#include <sys/ioctl.h>#include <sys/select.h>#ifdef USE_KERNEL_HEADERS/* compat-wireless does not include linux/compiler.h to define __user, so * define it here */#ifndef __user#define __user#endif /* __user */#include <asm/types.h>#include <linux/if_packet.h>#include <linux/if_ether.h> /* The L2 protocols */#include <linux/if_arp.h>#include <linux/wireless.h>#else /* USE_KERNEL_HEADERS */#include <net/if_arp.h>#include <netpacket/packet.h>#include "wireless_copy.h"#endif /* USE_KERNEL_HEADERS */#include "hostapd.h"#include "driver.h"#include "ieee802_1x.h"#include "eloop.h"#include "ieee802_11.h"#include "prism54.h"#include "wpa.h"#include "radius/radius.h"#include "sta_info.h"#include "accounting.h"const int PIM_BUF_SIZE = 4096;struct prism54_driver_data { struct hostapd_data *hapd; char iface[IFNAMSIZ + 1]; int sock; /* raw packet socket for 802.3 access */ int pim_sock; /* socket for pimfor packet */ char macs[2007][6];};static int mac_id_refresh(struct prism54_driver_data *data, int id, char *mac){ if (id < 0 || id > 2006) { return -1; } memcpy(&data->macs[id][0], mac, ETH_ALEN); return 0;}static char * mac_id_get(struct prism54_driver_data *data, int id){ if (id < 0 || id > 2006) { return NULL; } return &data->macs[id][0];}/* wait for a specific pimfor, timeout in 10ms resolution *//* pim_sock must be non-block to prevent dead lock from no response *//* or same response type in series */static int prism54_waitpim(void *priv, unsigned long oid, void *buf, int len, int timeout){ struct prism54_driver_data *drv = priv; struct timeval tv, stv, ctv; fd_set pfd; int rlen; pimdev_hdr *pkt; pkt = malloc(8192); if (pkt == NULL) return -1; FD_ZERO(&pfd); gettimeofday(&stv, NULL); do { FD_SET(drv->pim_sock, &pfd); tv.tv_sec = 0; tv.tv_usec = 10000; if (select(drv->pim_sock + 1, &pfd, NULL, NULL, &tv)) { rlen = recv(drv->pim_sock, pkt, 8192, 0); if (rlen > 0) { if (pkt->oid == htonl(oid)) { if (rlen <= len) { if (buf != NULL) { memcpy(buf, pkt, rlen); } free(pkt); return rlen; } else { printf("buffer too small\n"); free(pkt); return -1; } } else { gettimeofday(&ctv, NULL); continue; } } } gettimeofday(&ctv, NULL); } while (((ctv.tv_sec - stv.tv_sec) * 100 + (ctv.tv_usec - stv.tv_usec) / 10000) > timeout); free(pkt); return 0;}/* send an eapol packet */static int prism54_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, int encrypt, const u8 *own_addr){ struct prism54_driver_data *drv = priv; ieee802_3_hdr *hdr; size_t len; u8 *pos; int res; len = sizeof(*hdr) + data_len; hdr = os_zalloc(len); if (hdr == NULL) { printf("malloc() failed for prism54_send_data(len=%lu)\n", (unsigned long) len); return -1; } memcpy(&hdr->da[0], addr, ETH_ALEN); memcpy(&hdr->sa[0], own_addr, ETH_ALEN); hdr->type = htons(ETH_P_PAE); pos = (u8 *) (hdr + 1); memcpy(pos, data, data_len); res = send(drv->sock, hdr, len, 0); free(hdr); if (res < 0) { perror("hostapd_send_eapol: send"); printf("hostapd_send_eapol - packet len: %lu - failed\n", (unsigned long) len); } return res;}/* open data channel(auth-1) or eapol only(unauth-0) */static int prism54_set_sta_authorized(void *priv, const u8 *addr, int authorized){ struct prism54_driver_data *drv = priv; pimdev_hdr *hdr; char *pos; hdr = malloc(sizeof(*hdr) + ETH_ALEN); if (hdr == NULL) return -1; hdr->op = htonl(PIMOP_SET); if (authorized) { hdr->oid = htonl(DOT11_OID_EAPAUTHSTA); } else { hdr->oid = htonl(DOT11_OID_EAPUNAUTHSTA); } pos = (char *) (hdr + 1); memcpy(pos, addr, ETH_ALEN); send(drv->pim_sock, hdr, sizeof(*hdr) + ETH_ALEN, 0); prism54_waitpim(priv, hdr->oid, hdr, sizeof(*hdr) + ETH_ALEN, 10); free(hdr); return 0;}static intprism54_sta_set_flags(void *priv, const u8 *addr, int total_flags, int flags_or, int flags_and){ /* For now, only support setting Authorized flag */ if (flags_or & WLAN_STA_AUTHORIZED) return prism54_set_sta_authorized(priv, addr, 1); if (flags_and & WLAN_STA_AUTHORIZED) return prism54_set_sta_authorized(priv, addr, 0); return 0;}/* set per station key */static int prism54_set_encryption(const char *ifname, void *priv, const char *alg, const u8 *addr, int idx, const u8 *key, size_t key_len, int txkey){ struct prism54_driver_data *drv = priv; pimdev_hdr *hdr; struct obj_stakey *keys; u8 *buf; size_t blen; int ret = 0; blen = sizeof(struct obj_stakey) + sizeof(pimdev_hdr); hdr = malloc(blen); if (hdr == NULL) { printf("memory low\n"); return -1; } keys = (struct obj_stakey *) &hdr[1]; if (!addr) { memset(&keys->address[0], 0xff, ETH_ALEN); } else { memcpy(&keys->address[0], addr, ETH_ALEN); } if (!strcmp(alg, "WEP")) { keys->type = DOT11_PRIV_WEP; } else if (!strcmp(alg, "TKIP")) { keys->type = DOT11_PRIV_TKIP; } else if (!strcmp(alg, "none")) { /* the only way to clear the key is to deauth it */ /* and prism54 is capable to receive unencrypted packet */ /* so we do nothing here */ free(hdr); return 0; } else { printf("bad auth type: %s\n", alg); } buf = (u8 *) &keys->key[0]; keys->length = key_len; keys->keyid = idx; keys->options = htons(DOT11_STAKEY_OPTION_DEFAULTKEY); keys->reserved = 0; hdr->op = htonl(PIMOP_SET); hdr->oid = htonl(DOT11_OID_STAKEY); memcpy(buf, key, key_len); ret = send(drv->pim_sock, hdr, blen, 0); if (ret < 0) { free(hdr); return ret; } prism54_waitpim(priv, hdr->oid, hdr, blen, 10); free(hdr); return 0;}/* get TKIP station sequence counter, prism54 is only 6 bytes */static int prism54_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, u8 *seq){ struct prism54_driver_data *drv = priv; struct obj_stasc *stasc; pimdev_hdr *hdr; size_t blen; int ret = 0; blen = sizeof(*stasc) + sizeof(*hdr); hdr = malloc(blen); if (hdr == NULL) return -1; stasc = (struct obj_stasc *) &hdr[1]; if (addr == NULL) memset(&stasc->address[0], 0xff, ETH_ALEN); else memcpy(&stasc->address[0], addr, ETH_ALEN); hdr->oid = htonl(DOT11_OID_STASC); hdr->op = htonl(PIMOP_GET); stasc->keyid = idx; if (send(drv->pim_sock,hdr,blen,0) <= 0) { free(hdr); return -1; } if (prism54_waitpim(priv, DOT11_OID_STASC, hdr, blen, 10) <= 0) { ret = -1; } else { if (hdr->op == (int) htonl(PIMOP_RESPONSE)) { memcpy(seq + 2, &stasc->sc_high, ETH_ALEN); memset(seq, 0, 2); } else { ret = -1; } } free(hdr); return ret;}/* include unencrypted, set mlme autolevel to extended */static int prism54_init_1x(void *priv){ struct prism54_driver_data *drv = priv; pimdev_hdr *hdr; unsigned long *ul; int blen = sizeof(*hdr) + sizeof(*ul); hdr = malloc(blen); if (hdr == NULL) return -1; ul = (unsigned long *) &hdr[1]; hdr->op = htonl(PIMOP_SET); hdr->oid = htonl(DOT11_OID_EXUNENCRYPTED); *ul = htonl(DOT11_BOOL_TRUE); /* not accept */ send(drv->pim_sock, hdr, blen, 0); prism54_waitpim(priv, DOT11_OID_EXUNENCRYPTED, hdr, blen, 10); hdr->op = htonl(PIMOP_SET); hdr->oid = htonl(DOT11_OID_MLMEAUTOLEVEL); *ul = htonl(DOT11_MLME_EXTENDED); send(drv->pim_sock, hdr, blen, 0); prism54_waitpim(priv, DOT11_OID_MLMEAUTOLEVEL, hdr, blen, 10); hdr->op = htonl(PIMOP_SET); hdr->oid = htonl(DOT11_OID_DOT1XENABLE); *ul = htonl(DOT11_BOOL_TRUE); send(drv->pim_sock, hdr, blen, 0); prism54_waitpim(priv, DOT11_OID_DOT1XENABLE, hdr, blen, 10); hdr->op = htonl(PIMOP_SET); hdr->oid = htonl(DOT11_OID_AUTHENABLE); *ul = htonl(DOT11_AUTH_OS); /* OS */ send(drv->pim_sock, hdr, blen, 0); prism54_waitpim(priv, DOT11_OID_AUTHENABLE, hdr, blen, 10); free(hdr); return 0;}static int prism54_set_privacy_invoked(const char *ifname, void *priv, int flag){ struct prism54_driver_data *drv = priv; pimdev_hdr *hdr; unsigned long *ul; int ret; int blen = sizeof(*hdr) + sizeof(*ul); hdr = malloc(blen); if (hdr == NULL) return -1; ul = (unsigned long *) &hdr[1]; hdr->op = htonl(PIMOP_SET); hdr->oid = htonl(DOT11_OID_PRIVACYINVOKED); if (flag) { *ul = htonl(DOT11_BOOL_TRUE); /* has privacy */ } else { *ul = 0; } ret = send(drv->pim_sock, hdr, blen, 0); if (ret >= 0) { ret = prism54_waitpim(priv, DOT11_OID_PRIVACYINVOKED, hdr, blen, 10); } free(hdr); return ret;} static int prism54_ioctl_setiwessid(const char *ifname, void *priv, const u8 *buf, int len){#if 0 struct prism54_driver_data *drv = priv; struct iwreq iwr; memset(&iwr, 0, sizeof(iwr)); os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); iwr.u.essid.flags = 1; /* SSID active */ iwr.u.essid.pointer = (caddr_t) buf; iwr.u.essid.length = len + 1; if (ioctl(drv->pim_sock, SIOCSIWESSID, &iwr) < 0) { perror("ioctl[SIOCSIWESSID]"); printf("len=%d\n", len); return -1; }#endif return 0;}/* kick all stations *//* does not work during init, but at least it won't crash firmware */static int prism54_flush(void *priv){ struct prism54_driver_data *drv = priv; struct obj_mlmeex *mlme; pimdev_hdr *hdr; int ret; unsigned int i; long *nsta; int blen = sizeof(*hdr) + sizeof(*mlme); char *mac_id; hdr = os_zalloc(blen); if (hdr == NULL) return -1; mlme = (struct obj_mlmeex *) &hdr[1]; nsta = (long *) &hdr[1]; hdr->op = htonl(PIMOP_GET); hdr->oid = htonl(DOT11_OID_CLIENTS); ret = send(drv->pim_sock, hdr, sizeof(*hdr) + sizeof(long), 0); ret = prism54_waitpim(priv, DOT11_OID_CLIENTS, hdr, blen, 10); if ((ret < 0) || (hdr->op != (int) htonl(PIMOP_RESPONSE)) || (le_to_host32(*nsta) > 2007)) { free(hdr); return 0; } for (i = 0; i < le_to_host32(*nsta); i++) { mlme->id = -1; mac_id = mac_id_get(drv, i); if (mac_id) memcpy(&mlme->address[0], mac_id, ETH_ALEN); mlme->code = host_to_le16(WLAN_REASON_UNSPECIFIED); mlme->state = htons(DOT11_STATE_NONE); mlme->size = 0; hdr->op = htonl(PIMOP_SET); hdr->oid = htonl(DOT11_OID_DISASSOCIATEEX); ret = send(drv->pim_sock, hdr, blen, 0); prism54_waitpim(priv, DOT11_OID_DISASSOCIATEEX, hdr, blen, 100); } for (i = 0; i < le_to_host32(*nsta); i++) { mlme->id = -1; mac_id = mac_id_get(drv, i); if (mac_id) memcpy(&mlme->address[0], mac_id, ETH_ALEN); mlme->code = host_to_le16(WLAN_REASON_UNSPECIFIED); mlme->state = htons(DOT11_STATE_NONE); mlme->size = 0; hdr->op = htonl(PIMOP_SET); hdr->oid = htonl(DOT11_OID_DEAUTHENTICATEEX); ret = send(drv->pim_sock, hdr, blen, 0); prism54_waitpim(priv, DOT11_OID_DEAUTHENTICATEEX, hdr, blen, 100); } free(hdr); return 0;}static int prism54_sta_deauth(void *priv, const u8 *addr, int reason){ struct prism54_driver_data *drv = priv; pimdev_hdr *hdr; struct obj_mlmeex *mlme; int ret; int blen = sizeof(*hdr) + sizeof(*mlme); hdr = malloc(blen); if (hdr == NULL) return -1; mlme = (struct obj_mlmeex *) &hdr[1]; hdr->op = htonl(PIMOP_SET); hdr->oid = htonl(DOT11_OID_DEAUTHENTICATEEX); memcpy(&mlme->address[0], addr, ETH_ALEN); mlme->id = -1; mlme->state = htons(DOT11_STATE_NONE); mlme->code = host_to_le16(reason); mlme->size = 0; ret = send(drv->pim_sock, hdr, blen, 0); prism54_waitpim(priv, DOT11_OID_DEAUTHENTICATEEX, hdr, blen, 10); free(hdr); return ret;}static int prism54_sta_disassoc(void *priv, const u8 *addr, int reason){ struct prism54_driver_data *drv = priv; pimdev_hdr *hdr; struct obj_mlmeex *mlme; int ret; int blen = sizeof(*hdr) + sizeof(*mlme); hdr = malloc(blen); if (hdr == NULL) return -1; mlme = (struct obj_mlmeex *) &hdr[1]; hdr->op = htonl(PIMOP_SET); hdr->oid = htonl(DOT11_OID_DISASSOCIATEEX); memcpy(&mlme->address[0], addr, ETH_ALEN); mlme->id = -1; mlme->state = htons(DOT11_STATE_NONE); mlme->code = host_to_le16(reason); mlme->size = 0; ret = send(drv->pim_sock, hdr, blen, 0); prism54_waitpim(priv, DOT11_OID_DISASSOCIATEEX, hdr, blen, 10); free(hdr); return ret;}static int prism54_get_inact_sec(void *priv, const u8 *addr){ struct prism54_driver_data *drv = priv; pimdev_hdr *hdr; struct obj_sta *sta; int blen = sizeof(*hdr) + sizeof(*sta); int ret; hdr = malloc(blen); if (hdr == NULL) return -1; hdr->op = htonl(PIMOP_GET); hdr->oid = htonl(DOT11_OID_CLIENTFIND); sta = (struct obj_sta *) &hdr[1]; memcpy(&sta->address[0], addr, ETH_ALEN); ret = send(drv->pim_sock, hdr, blen, 0); ret = prism54_waitpim(priv, DOT11_OID_CLIENTFIND, hdr, blen, 10); if (ret != blen) { printf("get_inact_sec: bad return %d\n", ret); free(hdr); return -1; } if (hdr->op != (int) htonl(PIMOP_RESPONSE)) { printf("get_inact_sec: bad resp\n"); free(hdr); return -1; } free(hdr); return le_to_host16(sta->age);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -