📄 hostap.c
字号:
/* * Host AP (software wireless LAN access point) driver for * Intersil Prism2/2.5/3 - hostap.o module, common routines * * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen * <jkmaline@cc.hut.fi> * Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.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. See README and COPYING for * more details. */#ifndef EXPORT_SYMTAB#define EXPORT_SYMTAB#endif#include <linux/config.h>#include <linux/version.h>#include <linux/module.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/proc_fs.h>#include <linux/if_arp.h>#include <linux/delay.h>#include <linux/random.h>#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,44))#include <linux/tqueue.h>#else#include <linux/workqueue.h>#endif#include <linux/kmod.h>#include <linux/rtnetlink.h>#include "hostap_wext.h"#include <asm/uaccess.h>#include "hostap_wlan.h"#include "hostap_80211.h"#include "hostap_ap.h"#include "hostap.h"#include "hostap_crypt.h"#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14))#error Host AP driver was added into Linux 2.6.14.#error The version used in the kernel tree should be used instead of this#error external release which is only maintained for old kernel versions.#endifMODULE_AUTHOR("Jouni Malinen");MODULE_DESCRIPTION("Host AP common routines");MODULE_LICENSE("GPL");#ifdef MODULE_VERSIONMODULE_VERSION(PRISM2_VERSION);#endif#ifndef HOSTAP_CRYPT_MODULE/* Old hostap_crypt module is now part of hostap module. */#include "hostap_crypt.c"#else /* HOSTAP_CRYPT_MODULE */#define hostap_crypto_init()#define hostap_crypto_deinit()#endif /* HOSTAP_CRYPT_MODULE */#define TX_TIMEOUT (2 * HZ)#define PRISM2_MAX_FRAME_SIZE 2304#define PRISM2_MIN_MTU 256/* FIX: */#define PRISM2_MAX_MTU (PRISM2_MAX_FRAME_SIZE - (6 /* LLC */ + 8 /* WEP */))/* hostap.c */static int prism2_wds_add(local_info_t *local, u8 *remote_addr, int rtnl_locked);static int prism2_wds_del(local_info_t *local, u8 *remote_addr, int rtnl_locked, int do_not_remove);/* hostap_ap.c */static int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], struct iw_quality qual[], int buf_size, int aplist);static int prism2_ap_translate_scan(struct net_device *dev, char *buffer);static int prism2_hostapd(struct ap_data *ap, struct prism2_hostapd_param *param);static void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, struct prism2_crypt_data ***crypt);static void ap_control_kickall(struct ap_data *ap);#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMTstatic int ap_control_add_mac(struct mac_restrictions *mac_restrictions, u8 *mac);static int ap_control_del_mac(struct mac_restrictions *mac_restrictions, u8 *mac);static void ap_control_flush_macs(struct mac_restrictions *mac_restrictions);static int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, u8 *mac);#endif /* !PRISM2_NO_KERNEL_IEEE80211_MGMT */static const long freq_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484 };#define FREQ_COUNT (sizeof(freq_list) / sizeof(freq_list[0]))/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation *//* Ethernet-II snap header (RFC1042 for most EtherTypes) */static unsigned char rfc1042_header[] ={ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */static unsigned char bridge_tunnel_header[] ={ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };/* No encapsulation header if EtherType < 0x600 (=length) *//* FIX: these could be compiled separately and linked together to hostap.o */#include "hostap_ap.c"#include "hostap_info.c"#include "hostap_ioctl.c"#include "hostap_proc.c"#include "hostap_80211_rx.c"#include "hostap_80211_tx.c"struct net_device * hostap_add_interface(struct local_info *local, int type, int rtnl_locked, const char *prefix, const char *name){ struct net_device *dev, *mdev; struct hostap_interface *iface; int ret; dev = alloc_etherdev(sizeof(struct hostap_interface)); if (dev == NULL) return NULL; iface = dev->priv; iface->dev = dev; iface->local = local; iface->type = type; list_add(&iface->list, &local->hostap_interfaces); mdev = local->dev; memcpy(dev->dev_addr, mdev->dev_addr, ETH_ALEN); dev->base_addr = mdev->base_addr; dev->irq = mdev->irq; dev->mem_start = mdev->mem_start; dev->mem_end = mdev->mem_end; hostap_setup_dev(dev, local, 0);#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) dev->destructor = free_netdev;#else /* Linux 2.4.x uses dev entry (reads dev->features) after * dev->destructor has returned, so must not free struct net_device * here. Set NETIF_F_DYNALLOC flag so that netdev_finish_unregister() * frees the entry. */ dev->features |= NETIF_F_DYNALLOC;#endif sprintf(dev->name, "%s%s", prefix, name); if (!rtnl_locked) rtnl_lock(); ret = 0; if (strchr(dev->name, '%')) ret = dev_alloc_name(dev, dev->name);#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) SET_NETDEV_DEV(dev, mdev->class_dev.dev);#endif if (ret >= 0) ret = register_netdevice(dev); if (!rtnl_locked) rtnl_unlock(); if (ret < 0) { printk(KERN_WARNING "%s: failed to add new netdevice!\n", dev->name); free_netdev(dev); return NULL; } printk(KERN_DEBUG "%s: registered netdevice %s\n", mdev->name, dev->name); return dev;}void hostap_remove_interface(struct net_device *dev, int rtnl_locked, int remove_from_list){ struct hostap_interface *iface; if (!dev) return; iface = dev->priv; if (remove_from_list) { list_del(&iface->list); } if (dev == iface->local->ddev) iface->local->ddev = NULL; else if (dev == iface->local->apdev) iface->local->apdev = NULL; else if (dev == iface->local->stadev) iface->local->stadev = NULL; if (rtnl_locked) unregister_netdevice(dev); else unregister_netdev(dev); /* dev->destructor = free_netdev() will free the device data, including * private data, when removing the device */}static inline int prism2_wds_special_addr(u8 *addr){ if (addr[0] || addr[1] || addr[2] || addr[3] || addr[4] || addr[5]) return 0; return 1;}static int prism2_wds_add(local_info_t *local, u8 *remote_addr, int rtnl_locked){ struct net_device *dev; struct list_head *ptr; struct hostap_interface *iface, *empty, *match; empty = match = NULL; read_lock_bh(&local->iface_lock); list_for_each(ptr, &local->hostap_interfaces) { iface = list_entry(ptr, struct hostap_interface, list); if (iface->type != HOSTAP_INTERFACE_WDS) continue; if (prism2_wds_special_addr(iface->u.wds.remote_addr)) empty = iface; else if (memcmp(iface->u.wds.remote_addr, remote_addr, ETH_ALEN) == 0) { match = iface; break; } } if (!match && empty && !prism2_wds_special_addr(remote_addr)) { /* take pre-allocated entry into use */ memcpy(empty->u.wds.remote_addr, remote_addr, ETH_ALEN); read_unlock_bh(&local->iface_lock); printk(KERN_DEBUG "%s: using pre-allocated WDS netdevice %s\n", local->dev->name, empty->dev->name); return 0; } read_unlock_bh(&local->iface_lock); if (!prism2_wds_special_addr(remote_addr)) { if (match) return -EEXIST; hostap_add_sta(local->ap, remote_addr); } if (local->wds_connections >= local->wds_max_connections) return -ENOBUFS; /* verify that there is room for wds# postfix in the interface name */ if (strlen(local->dev->name) > IFNAMSIZ - 5) { printk(KERN_DEBUG "'%s' too long base device name\n", local->dev->name); return -EINVAL; } dev = hostap_add_interface(local, HOSTAP_INTERFACE_WDS, rtnl_locked, local->ddev->name, "wds%d"); if (dev == NULL) return -ENOMEM; iface = dev->priv; memcpy(iface->u.wds.remote_addr, remote_addr, ETH_ALEN); local->wds_connections++; return 0;}static int prism2_wds_del(local_info_t *local, u8 *remote_addr, int rtnl_locked, int do_not_remove){ unsigned long flags; struct list_head *ptr; struct hostap_interface *iface, *selected = NULL; write_lock_irqsave(&local->iface_lock, flags); list_for_each(ptr, &local->hostap_interfaces) { iface = list_entry(ptr, struct hostap_interface, list); if (iface->type != HOSTAP_INTERFACE_WDS) continue; if (memcmp(iface->u.wds.remote_addr, remote_addr, ETH_ALEN) == 0) { selected = iface; break; } } if (selected && !do_not_remove) list_del(&selected->list); write_unlock_irqrestore(&local->iface_lock, flags); if (selected) { if (do_not_remove) memset(selected->u.wds.remote_addr, 0, ETH_ALEN); else { hostap_remove_interface(selected->dev, rtnl_locked, 0); local->wds_connections--; } } return selected ? 0 : -ENODEV;}u16 hostap_tx_callback_register(local_info_t *local, void (*func)(struct sk_buff *, int ok, void *), void *data){ unsigned long flags; struct hostap_tx_callback_info *entry; entry = (struct hostap_tx_callback_info *) kmalloc(sizeof(*entry), GFP_ATOMIC); if (entry == NULL) return 0; entry->func = func; entry->data = data; spin_lock_irqsave(&local->lock, flags); entry->idx = local->tx_callback ? local->tx_callback->idx + 1 : 1; entry->next = local->tx_callback; local->tx_callback = entry; spin_unlock_irqrestore(&local->lock, flags); return entry->idx;}int hostap_tx_callback_unregister(local_info_t *local, u16 idx){ unsigned long flags; struct hostap_tx_callback_info *cb, *prev = NULL; spin_lock_irqsave(&local->lock, flags); cb = local->tx_callback; while (cb != NULL && cb->idx != idx) { prev = cb; cb = cb->next; } if (cb) { if (prev == NULL) local->tx_callback = cb->next; else prev->next = cb->next; kfree(cb); } spin_unlock_irqrestore(&local->lock, flags); return cb ? 0 : -1;}/* val is in host byte order */int hostap_set_word(struct net_device *dev, int rid, u16 val){ struct hostap_interface *iface = dev->priv; u16 tmp = cpu_to_le16(val); return iface->local->func->set_rid(dev, rid, &tmp, 2);}int hostap_set_string(struct net_device *dev, int rid, const char *val){ struct hostap_interface *iface = dev->priv; char buf[MAX_SSID_LEN + 2]; int len; len = strlen(val); if (len > MAX_SSID_LEN) return -1; memset(buf, 0, sizeof(buf)); buf[0] = len; /* little endian 16 bit word */ memcpy(buf + 2, val, len); return iface->local->func->set_rid(dev, rid, &buf, MAX_SSID_LEN + 2);}u16 hostap_get_porttype(local_info_t *local){ if (local->iw_mode == IW_MODE_ADHOC && local->pseudo_adhoc) return HFA384X_PORTTYPE_PSEUDO_IBSS; if (local->iw_mode == IW_MODE_ADHOC) return HFA384X_PORTTYPE_IBSS; if (local->iw_mode == IW_MODE_INFRA)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -