📄 airo.c
字号:
spin_lock_irqsave(&ai->main_lock, flags); if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != SUCCESS) { rc = status; goto done; } if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) { rc = ERROR; goto done; } // read the rid length field bap_read(ai, pBuf, 2, BAP1); // length for remaining part of rid len = min(len, (int)le16_to_cpu(*(u16*)pBuf)) - 2; if ( len <= 2 ) { printk( KERN_ERR "airo: Rid %x has a length of %d which is too short\n", (int)rid, (int)len ); rc = ERROR; goto done; } // read remainder of the rid rc = bap_read(ai, ((u16*)pBuf)+1, len, BAP1); done: spin_unlock_irqrestore(&ai->main_lock, flags); return rc;}/* Note, that we are using BAP1 which is also used by transmit, so * make sure this isnt called when a transmit is happening */static int PC4500_writerid(struct airo_info *ai, u16 rid, const void *pBuf, int len){ u16 status; long flags; int rc = SUCCESS; spin_lock_irqsave(&ai->main_lock, flags); // --- first access so that we can write the rid data if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != 0) { rc = status; goto done; } // --- now write the rid data if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) { rc = ERROR; goto done; } bap_write(ai, pBuf, len, BAP1); // ---now commit the rid data rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS); done: spin_unlock_irqrestore(&ai->main_lock, flags); return rc;}/* Allocates a FID to be used for transmitting packets. We only use one for now. */static u16 transmit_allocate(struct airo_info *ai, int lenPayload){ Cmd cmd; Resp rsp; u16 txFid; u16 txControl; long flags; cmd.cmd = CMD_ALLOCATETX; cmd.parm0 = lenPayload; if (lock_issuecommand(ai, &cmd, &rsp) != SUCCESS) return 0; if ( (rsp.status & 0xFF00) != 0) return 0; /* wait for the allocate event/indication * It makes me kind of nervous that this can just sit here and spin, * but in practice it only loops like four times. */ while ( (IN4500(ai, EVSTAT) & EV_ALLOC) == 0) ; // get the allocated fid and acknowledge txFid = IN4500(ai, TXALLOCFID); OUT4500(ai, EVACK, EV_ALLOC); /* The CARD is pretty cool since it converts the ethernet packet * into 802.11. Also note that we don't release the FID since we * will be using the same one over and over again. */ /* We only have to setup the control once since we are not * releasing the fid. */ txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_3 | TXCTL_ETHERNET | TXCTL_NORELEASE); spin_lock_irqsave(&ai->main_lock, flags); if (bap_setup(ai, txFid, 0x0008, BAP1) != SUCCESS) { spin_unlock_irqrestore(&ai->main_lock, flags); return ERROR; } bap_write(ai, &txControl, sizeof(txControl), BAP1); spin_unlock_irqrestore(&ai->main_lock, flags); return txFid;}/* In general BAP1 is dedicated to transmiting packets. However, since we need a BAP when accessing RIDs, we also use BAP1 for that. Make sure the BAP1 spinlock is held when this is called. */static int transmit_802_3_packet(struct airo_info *ai, u16 txFid, char *pPacket, int len){ u16 payloadLen; Cmd cmd; Resp rsp; if (len < 12) { printk( KERN_WARNING "Short packet %d\n", len ); return ERROR; } // packet is destination[6], source[6], payload[len-12] // write the payload length and dst/src/payload if (bap_setup(ai, txFid, 0x0036, BAP1) != SUCCESS) return ERROR; /* The hardware addresses aren't counted as part of the payload, so * we have to subtract the 12 bytes for the addresses off */ payloadLen = cpu_to_le16(len-12); bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1); bap_write(ai, (const u16*)pPacket, len, BAP1); // issue the transmit command memset( &cmd, 0, sizeof( cmd ) ); cmd.cmd = CMD_TRANSMIT; cmd.parm0 = txFid; if (issuecommand(ai, &cmd, &rsp) != SUCCESS) return ERROR; if ( (rsp.status & 0xFF00) != 0) return ERROR; return SUCCESS;}/* * This is the proc_fs routines. It is a bit messier than I would * like! Feel free to clean it up! */static ssize_t proc_read( struct file *file, char *buffer, size_t len, loff_t *offset);static ssize_t proc_write( struct file *file, const char *buffer, size_t len, loff_t *offset );static int proc_close( struct inode *inode, struct file *file );static int proc_stats_open( struct inode *inode, struct file *file );static int proc_statsdelta_open( struct inode *inode, struct file *file );static int proc_status_open( struct inode *inode, struct file *file );static int proc_SSID_open( struct inode *inode, struct file *file );static int proc_APList_open( struct inode *inode, struct file *file );static int proc_BSSList_open( struct inode *inode, struct file *file );static int proc_config_open( struct inode *inode, struct file *file );static int proc_wepkey_open( struct inode *inode, struct file *file );static struct file_operations proc_statsdelta_ops = { read: proc_read, open: proc_statsdelta_open, release: proc_close};static struct file_operations proc_stats_ops = { read: proc_read, open: proc_stats_open, release: proc_close};static struct file_operations proc_status_ops = { read: proc_read, open: proc_status_open, release: proc_close};static struct file_operations proc_SSID_ops = { read: proc_read, write: proc_write, open: proc_SSID_open, release: proc_close};static struct file_operations proc_BSSList_ops = { read: proc_read, write: proc_write, open: proc_BSSList_open, release: proc_close};static struct file_operations proc_APList_ops = { read: proc_read, write: proc_write, open: proc_APList_open, release: proc_close};static struct file_operations proc_config_ops = { read: proc_read, write: proc_write, open: proc_config_open, release: proc_close};static struct file_operations proc_wepkey_ops = { read: proc_read, write: proc_write, open: proc_wepkey_open, release: proc_close};static struct proc_dir_entry *airo_entry = 0;struct proc_data { int release_buffer; int readlen; char *rbuffer; int writelen; int maxwritelen; char *wbuffer; void (*on_close) (struct inode *, struct file *);};#ifndef SETPROC_OPS#define SETPROC_OPS(entry, ops) (entry)->proc_fops = &(ops)#endifstatic int setup_proc_entry( struct net_device *dev, struct airo_info *apriv ) { struct proc_dir_entry *entry; /* First setup the device directory */ apriv->proc_entry = create_proc_entry(dev->name, S_IFDIR|airo_perm, airo_entry); apriv->proc_entry->uid = proc_uid; apriv->proc_entry->gid = proc_gid; /* Setup the StatsDelta */ entry = create_proc_entry("StatsDelta", S_IFREG | (S_IRUGO&proc_perm), apriv->proc_entry); entry->uid = proc_uid; entry->gid = proc_gid; entry->data = dev; SETPROC_OPS(entry, proc_statsdelta_ops); /* Setup the Stats */ entry = create_proc_entry("Stats", S_IFREG | (S_IRUGO&proc_perm), apriv->proc_entry); entry->uid = proc_uid; entry->gid = proc_gid; entry->data = dev; SETPROC_OPS(entry, proc_stats_ops); /* Setup the Status */ entry = create_proc_entry("Status", S_IFREG | (S_IRUGO&proc_perm), apriv->proc_entry); entry->uid = proc_uid; entry->gid = proc_gid; entry->data = dev; SETPROC_OPS(entry, proc_status_ops); /* Setup the Config */ entry = create_proc_entry("Config", S_IFREG | proc_perm, apriv->proc_entry); entry->uid = proc_uid; entry->gid = proc_gid; entry->data = dev; SETPROC_OPS(entry, proc_config_ops); /* Setup the SSID */ entry = create_proc_entry("SSID", S_IFREG | proc_perm, apriv->proc_entry); entry->uid = proc_uid; entry->gid = proc_gid; entry->data = dev; SETPROC_OPS(entry, proc_SSID_ops); /* Setup the APList */ entry = create_proc_entry("APList", S_IFREG | proc_perm, apriv->proc_entry); entry->uid = proc_uid; entry->gid = proc_gid; entry->data = dev; SETPROC_OPS(entry, proc_APList_ops); /* Setup the BSSList */ entry = create_proc_entry("BSSList", S_IFREG | proc_perm, apriv->proc_entry); entry->uid = proc_uid; entry->gid = proc_gid; entry->data = dev; SETPROC_OPS(entry, proc_BSSList_ops); /* Setup the WepKey */ entry = create_proc_entry("WepKey", S_IFREG | proc_perm, apriv->proc_entry); entry->uid = proc_uid; entry->gid = proc_gid; entry->data = dev; SETPROC_OPS(entry, proc_wepkey_ops); return 0;}static int takedown_proc_entry( struct net_device *dev, struct airo_info *apriv ) { if ( !apriv->proc_entry->namelen ) return 0; remove_proc_entry("Stats",apriv->proc_entry); remove_proc_entry("StatsDelta",apriv->proc_entry); remove_proc_entry("Status",apriv->proc_entry); remove_proc_entry("Config",apriv->proc_entry); remove_proc_entry("SSID",apriv->proc_entry); remove_proc_entry("APList",apriv->proc_entry); remove_proc_entry("BSSList",apriv->proc_entry); remove_proc_entry("WepKey",apriv->proc_entry); remove_proc_entry(dev->name,airo_entry); return 0;}/* * What we want from the proc_fs is to be able to efficiently read * and write the configuration. To do this, we want to read the * configuration when the file is opened and write it when the file is * closed. So basically we allocate a read buffer at open and fill it * with data, and allocate a write buffer and read it at close. *//* * The read routine is generic, it relies on the preallocated rbuffer * to supply the data. */static ssize_t proc_read( struct file *file, char *buffer, size_t len, loff_t *offset ){ int i; int pos; struct proc_data *priv = (struct proc_data*)file->private_data; if( !priv->rbuffer ) return -EINVAL; pos = *offset; for( i = 0; i+pos < priv->readlen && i < len; i++ ) { if (put_user( priv->rbuffer[i+pos], buffer+i )) return -EFAULT; } *offset += i; return i;}/* * The write routine is generic, it fills in a preallocated rbuffer * to supply the data. */static ssize_t proc_write( struct file *file, const char *buffer, size_t len, loff_t *offset ){ int i; int pos; struct proc_data *priv = (struct proc_data*)file->private_data; if ( !priv->wbuffer ) { return -EINVAL; } pos = *offset; for( i = 0; i + pos < priv->maxwritelen && i < len; i++ ) { if (get_user( priv->wbuffer[i+pos], buffer + i )) return -EFAULT; } if ( i+pos > priv->writelen ) priv->writelen = i+file->f_pos; *offset += i; return i;}static int proc_status_open( struct inode *inode, struct file *file ) { struct proc_data *data; struct proc_dir_entry *dp = inode->u.generic_ip; struct net_device *dev = dp->data; struct airo_info *apriv = (struct airo_info *)dev->priv; CapabilityRid cap_rid; StatusRid status_rid; int i; MOD_INC_USE_COUNT; dp = inode->u.generic_ip; if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; memset(file->private_data, 0, sizeof(struct proc_data)); data = (struct proc_data *)file->private_data; if ((data->rbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) { kfree (file->private_data); return -ENOMEM; } readStatusRid(apriv, &status_rid); readCapabilityRid(apriv, &cap_rid); i = sprintf(data->rbuffer, "Status: %s%s%s%s%s%s%s%s%s\n", status_rid.mode & 1 ? "CFG ": "", status_rid.mode & 2 ? "ACT ": "", status_rid.mode & 0x10 ? "SYN ": "", status_rid.mode & 0x20 ? "LNK ": "", status_rid.mode & 0x40 ? "LEAP ": "", status_rid.mode & 0x80 ? "PRIV ": "", status_rid.mode & 0x100 ? "KEY ": "", status_rid.mode & 0x200 ? "WEP ": "", status_rid.mode & 0x8000 ? "ERR ": ""); sprintf( data->rbuffer+i, "Mode: %x\n" "Signal Strength: %d\n" "Signal Quality: %d\n" "SSID: %-.*s\n" "AP: %-.16s\n" "Freq: %d\n" "BitRate: %dmbs\n" "Driver Version: %s\n" "Device: %s\nManufacturer: %s\nFirmware Version: %s\n" "Radio type: %x\nCountry: %x\nHardware Version: %x\n" "Software Version: %x\nSoftware Subversion: %x\n" "Boot block version: %x\n", (int)status_rid.mode, (int)status_rid.normalizedSignalStrength, (int)status_rid.signalQuality, (int)status_rid.SSIDlen, status_rid.SSID, status_rid.apName, (int)status_rid.channel, (int)status_rid.currentXmitRate/2, version, cap_rid.prodName, cap_rid.manName, cap_rid.prodVer, cap_rid.radioType, cap_rid.country, cap_rid.hardVer, (int)cap_rid.softVer, (int)cap_rid.softSubVer, (int)cap_rid.bootBlockVer ); data->readlen = strlen( data->rbuffer ); return 0;}static int proc_stats_rid_open(struct inode*, struct file*, u16);static int proc_statsdelta_open( struct inode *inode, struct file *file ) { if (file->f_mode&FMODE_WRITE) { return proc_stats_rid_open(inode, file, RID_STATSDELTACLEAR); } return proc_stats_rid_open(inode, file, RID_STATSDELTA);}static int proc_stats_open( struct inode *inode, struct file *file ) { return proc_stats_rid_open(inode, file, RID_STATS);}static int proc_stats_rid_open( struct inode *inode, struct file *file, u16 rid ) { struct proc_data *data; struct proc_dir_entry *dp = inode->u.generic_ip; struct net_device *dev = dp->data; struct airo_info *ap
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -