📄 sm_drv.c
字号:
/* * src/sm_drv.c * * Copyright (C) 2003 Conexant Americas Inc. All Rights Reserved. * Copyright (C) 2004, 2005, 2006 Nokia Corporation * Author: Samuel Ortiz <samuel.ortiz@nokia.com> * * * 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. * */#define __KERNEL_SYSCALLS__#include <linux/version.h>#ifdef MODULE#ifdef MODVERSIONS#include <linux/modversions.h>#endif#include <linux/module.h>#else#define MOD_INC_USE_COUNT#define MOD_DEC_USE_COUNT#endif#include <linux/init.h>#include <linux/types.h>#include <linux/sched.h>#include <linux/unistd.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/if_arp.h>#include <linux/string.h>#include <linux/poll.h>#include <linux/platform_device.h>#include <asm/uaccess.h>#include "sm_drv.h"#include "sm_drv_ioctl.h"#include "sm_drv_sysfs.h"extern char driver_name[64];/* for linux/unistd.h */int errno;DECLARE_COMPLETION(softmac_init_comp);extern struct net_device *root_sm_drv_device;/* Timers */void driver_timer_expired(unsigned long handle){ struct net_device *dev = (struct net_device *) handle; struct net_local *lp = dev->priv; int32_t callb_mask; spin_lock_bh(&lp->sm_lock); callb_mask = prism_softmac_service(lp->sm_context); spin_unlock_bh(&lp->sm_lock); if(callb_mask < 0) printk(KERN_INFO "timer_expired: sm_service returned error %d\n", callb_mask); else { handle_sm_callback(dev, callb_mask); } }void sm_drv_disassociate(struct net_device *dev){ struct obj_ssid essid; struct net_local *lp = dev->priv; lp->link_state = DOT11_STATE_NONE; /* * By setting a new essid, UMAC will diassociates from the current * AP. If this is the broadcast SSID, it won't try to reconnect * to another AP. */ memset(essid.octets, 0, 33); essid.length = 0; sm_drv_oid_set(dev, DOT11_OID_SSID, (void*)&essid, sizeof(struct obj_ssid));}/****************************************************************************** * SoftMAC Callback ******************************************************************************/static const char nokia_wireless_biz_oui[3] = {0x00, 0xe0, 0x03};static int32_t handle_sm_trap(struct net_device *dev, struct s_sm_conf *trap){ struct net_local *lp = dev->priv; int32_t result = SM_ENONE, ret; struct obj_mlme *mlme = (struct obj_mlme*)trap->data; struct obj_sta *sta = (struct obj_sta*)trap->data; uint8_t state = DOT11_STATE_ASSOCING; uint8_t null_mac[ETH_ALEN] = {0x0,0x0,0x0,0x0,0x0,0x0}; uint32_t scan_mode = SCAN_MODE_ACTIVE, scan = -1; switch(trap->oid) { case GEN_OID_MACADDRESS: DEBUG(DBG_ALL, "%s: MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", driver_name, trap->data[0], trap->data[1], trap->data[2], trap->data[3], trap->data[4], trap->data[5]); if (!memcmp(dev->dev_addr, null_mac, ETH_ALEN)) memcpy(dev->dev_addr, trap->data, ETH_ALEN); else /* If we set the MAC address before booting, let's not copy the PDA one */ result = sm_drv_oid_set(dev, GEN_OID_MACADDRESS, (void*)dev->dev_addr, ETH_ALEN); /* If we got the MAC address, this means the device has finished booting */ wake_up(&lp->conf_waitq); if(lp->device_state == DEVSTATE_ACTIVE || lp->device_state == DEVSTATE_BOOTING) lp->device_state = DEVSTATE_ACTIVE; break; case GEN_OID_LINKSTATE: link_changed(dev, *((uint32_t*)trap->data)); break; case DOT11_OID_AUTHENTICATE: state = DOT11_STATE_AUTHING; /* Intended */ case DOT11_OID_ASSOCIATE: case DOT11_OID_REASSOCIATE: if(lp->sm_mode == SM_MODE_CLIENT && mlme->state != lp->link_state) { DEBUG(DBG_TRACE, "Authenticate/(Re)Associate trap: state %d\n", mlme->state); lp->link_state = mlme->state; if (mlme->state == DOT11_STATE_ASSOC) { lp->ext = mlme->ext; sm_drv_parse_bssid(dev, mlme->address, DOT11_STATE_ASSOC, NULL); } /* This is the association request. We get the IE from the beacon */ if ((trap->oid == DOT11_OID_REASSOCIATE || trap->oid == DOT11_OID_ASSOCIATE) && (mlme->state == DOT11_STATE_ASSOCING)) { /* * UGLY hack to workaround Nokia's AP bug: * When we set short slots in the capability field of the association request, * A032 thinks that we can _only_ do short. * However, according to 802.11 standard, short slot bit set in the capability * bitfield implies that the device can do _both_ long and short. A032 doesn't * get that. * On the other hand, if we specifically set short slots, we will have trouble * with 11g devices, so we have to lamely check the AP MAC and see if this is * a Nokia one...Sorry. */ if (!memcmp(mlme->address, nokia_wireless_biz_oui, 3)) { uint32_t profile = DOT11_PROFILE_B_WIFI; if (sm_drv_oid_set(dev, DOT11_OID_PROFILES, (void*)&profile, sizeof(uint32_t)) < 0) { result = -1; break; } } sm_drv_process_bss_data(dev, dev->dev_addr, mlme->data, mlme->size, trap->oid); } } break; case DOT11_OID_SCAN: DEBUG(DBG_ALL, "Scan complete, scanned %d channels\n", *((uint16_t*)trap->data)); /* We got the trap, we stop the scan timer.*/ del_timer_sync(&lp->scan_timer); send_scan_complete(dev); break; case DOT11_OID_MICFAILURE: DEBUG(DBG_ALL, "**** MIC FAILURE ****\n"); send_mic_failure(dev, sta); break; case DOT11_OID_DEAUTHENTICATE: DEBUG(DBG_ALL,"DEAUTHENTICATE trap\n"); if (lp->link_state == DOT11_STATE_ASSOC) { DEBUG(DBG_ALL,"Active scanning on >%s<\n", lp->ssid.octets); ret = sm_drv_oid_set(dev, DOT11_OID_SCANMODE, (void*)&scan_mode, sizeof(uint32_t)); if (ret < 0) DEBUG(DBG_ALL, "Couldn't set SCANMODE: %d\n", ret); ret = sm_drv_oid_set(dev, DOT11_OID_SCANSSID, (void*)&lp->ssid, sizeof(struct obj_ssid)); if (ret < 0) DEBUG(DBG_ALL, "Couldn't set SSID: %d\n", ret); ret = sm_drv_oid_set(dev, DOT11_OID_SCAN, (void*)&scan, sizeof(int16_t)); if (ret < 0) DEBUG(DBG_ALL, "Couldn't start scan: %d\n", ret); } break; case DOT11_OID_DISASSOCIATE: DEBUG(DBG_ALL,"DISASSOCIATE trap\n"); break; default: /* do nothing */ DEBUG(DBG_ALL, "Unhandled trap: 0x%x\n", trap->oid); break; } return result; }static void sm_print_callback_mask(int32_t mask){ DEBUG(DBG_TRACE, "SoftMAC Mask: "); if (mask & SM_TRAP) DEBUG(DBG_TRACE, "SM_TRAP "); if (mask & SM_FRAMETXDONE) DEBUG(DBG_TRACE, "SM_FRAMETXDONE "); if (mask & SM_FRAMERX) DEBUG(DBG_TRACE, "SM_FRAMERX "); if (mask & SM_IC) DEBUG(DBG_TRACE, "SM_IC "); DEBUG(DBG_TRACE, "\n");}static inline int sm_monitor_rx(struct net_device *dev, struct sk_buff **skb){ /* We get a 802.11 frame with a PPE sniffer header*/ struct sm_promisc_header *hdr = (struct sm_promisc_header *) (*skb)->data; if (dev->type == ARPHRD_IEEE80211_PRISM) { struct avs_80211_1_header *avs; skb_pull(*skb, sizeof (struct sm_promisc_header)); if (skb_headroom(*skb) < sizeof (struct avs_80211_1_header)) { struct sk_buff *newskb = skb_copy_expand(*skb, sizeof (struct avs_80211_1_header), 0, GFP_ATOMIC); if (newskb) { dev_kfree_skb_irq(*skb); *skb = newskb; } else return -1; /* This behavior is not very subtile... */ } /* make room for the new header and fill it. */ avs = (struct avs_80211_1_header *) skb_push(*skb, sizeof (struct avs_80211_1_header)); avs->version = cpu_to_be32(P80211CAPTURE_VERSION); avs->length = cpu_to_be32(sizeof (struct avs_80211_1_header)); avs->mactime = cpu_to_be64(le64_to_cpu(hdr->clock)); avs->hosttime = cpu_to_be64(jiffies); avs->phytype = cpu_to_be32(6); /*OFDM: 6 for (g), 8 for (a) */ avs->channel = cpu_to_be32(0);//channel_of_freq(freq)); avs->datarate = cpu_to_be32(hdr->rate * 5); avs->antenna = cpu_to_be32(0); /*unknown */ avs->priority = cpu_to_be32(0); /*unknown */ avs->ssi_type = cpu_to_be32(3); /*2: dBm, 3: raw RSSI */ avs->ssi_signal = cpu_to_be32(hdr->rssi & 0x7f); avs->ssi_noise = cpu_to_be32(0);//priv->local_iwstatistics.qual.noise); /*better than 'undefined', I assume */ avs->preamble = cpu_to_be32(0); /*unknown */ avs->encoding = cpu_to_be32(0); /*unknown */ } else skb_pull(*skb, sizeof (struct sm_promisc_header)); (*skb)->protocol = ETH_P_802_2;//htons(ETH_P_802_2); (*skb)->mac.raw = (*skb)->data; (*skb)->pkt_type = PACKET_OTHERHOST; return 0;}void handle_sm_callback(struct net_device *dev, int32_t mask){ struct net_local *lp = dev->priv; struct spi_hif_local_data *hif_lp = HIF_LP(lp); struct s_sm_frame *frame; struct sk_buff *skb; int32_t new_mask, tx_dropped = 0; while(mask) { DEBUG(DBG_TRACE, "%s: callback mask 0x%x\n", driver_name, mask); sm_print_callback_mask(mask); if(mask & SM_FRAMETXDONE) { spin_lock_bh(&lp->sm_lock); new_mask = prism_softmac_frame_tx_done( lp->sm_context, &frame ); spin_unlock_bh(&lp->sm_lock); if( new_mask < 0 ) { printk(KERN_WARNING "handle_sm_callback: sm_frame_tx_done returned error %d\n", new_mask); } else { mask = new_mask; } if(frame != NULL) { if( frame->flags & SM_FRAME_TXDROPPED ) { printk("TX dropped\n"); lp->stats.tx_errors++; lp->stats.tx_dropped++; tx_dropped = 1; } else if(frame->flags & SM_FRAME_TXFAILED) { lp->stats.tx_errors++; tx_dropped = 0; } else { lp->stats.tx_packets++; hif_lp->initial_packets++; lp->stats.tx_bytes += frame->length; tx_dropped = 0; } /* Free the frame and SKB frame in done */ frame_skb_free(dev, frame); /* We have transmitted a frame, so we can wake the queue again */ if(netif_queue_stopped(dev)) netif_wake_queue(dev); } else { mask &= ~SM_FRAMETXDONE; } } if( mask & SM_FRAMERX ) { spin_lock_bh(&lp->sm_lock); new_mask = prism_softmac_frame_rx(lp->sm_context, &frame); spin_unlock_bh(&lp->sm_lock); if( new_mask < 0 ) { printk(KERN_WARNING "handle_sm_callback: sm_frame_rx returned error %d\n", new_mask); } else { mask = new_mask; } if( frame != NULL ) { if( frame->flags & SM_FRAME_RXFAILED ) { printk("RX failed\n"); lp->stats.rx_errors++; } else { lp->stats.rx_packets++; lp->stats.rx_bytes += frame->length; } /* get the skb from the frame */ skb = frame_to_skb(dev, frame); skb->dev = dev; if(skb) { if(unlikely(lp->sm_mode == SM_MODE_PROMISCUOUS)) sm_monitor_rx(dev, &skb); /* set minimal skb parameters and deliver the network packet */ skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); } } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -