📄 wavelan_cs.c
字号:
if(i >= max) return(i); } return(i);}#ifdef WIRELESS_SPY/*------------------------------------------------------------------*//* * Gather wireless spy statistics : for each packet, compare the source * address with out list, and if match, get the stats... * Sorry, but this function really need wireless extensions... */static inline voidwl_spy_gather(device * dev, u_char * mac, /* MAC address */ u_char * stats) /* Statistics to gather */{ net_local * lp = (net_local *) dev->priv; int i; /* Look all addresses */ for(i = 0; i < lp->spy_number; i++) /* If match */ if(!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE)) { /* Update statistics */ lp->spy_stat[i].qual = stats[2] & MMR_SGNL_QUAL; lp->spy_stat[i].level = stats[0] & MMR_SIGNAL_LVL; lp->spy_stat[i].noise = stats[1] & MMR_SILENCE_LVL; lp->spy_stat[i].updated = 0x7; }}#endif /* WIRELESS_SPY */#ifdef HISTOGRAM/*------------------------------------------------------------------*//* * This function calculate an histogram on the signal level. * As the noise is quite constant, it's like doing it on the SNR. * We have defined a set of interval (lp->his_range), and each time * the level goes in that interval, we increment the count (lp->his_sum). * With this histogram you may detect if one wavelan is really weak, * or you may also calculate the mean and standard deviation of the level... */static inline voidwl_his_gather(device * dev, u_char * stats) /* Statistics to gather */{ net_local * lp = (net_local *) dev->priv; u_char level = stats[0] & MMR_SIGNAL_LVL; int i; /* Find the correct interval */ i = 0; while((i < (lp->his_number - 1)) && (level >= lp->his_range[i++])) ; /* Increment interval counter */ (lp->his_sum[i])++;}#endif /* HISTOGRAM *//*------------------------------------------------------------------*//* * Perform ioctl : config & info stuff * This is here that are treated the wireless extensions (iwconfig) */static intwavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */ struct ifreq * rq, /* Data passed */ int cmd) /* Ioctl number */{ ioaddr_t base = dev->base_addr; net_local * lp = (net_local *)dev->priv; /* lp is not unused */ struct iwreq * wrq = (struct iwreq *) rq; psa_t psa; mm_t m; unsigned long flags; int ret = 0;#ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd);#endif /* Disable interrupts & save flags */ wv_splhi(lp, &flags); /* Look what is the request */ switch(cmd) { /* --------------- WIRELESS EXTENSIONS --------------- */ case SIOCGIWNAME: strcpy(wrq->u.name, "Wavelan"); break; case SIOCSIWNWID: /* Set NWID in wavelan */#if WIRELESS_EXT > 8 if(!wrq->u.nwid.disabled) { /* Set NWID in psa */ psa.psa_nwid[0] = (wrq->u.nwid.value & 0xFF00) >> 8; psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF;#else /* WIRELESS_EXT > 8 */ if(wrq->u.nwid.on) { /* Set NWID in psa */ psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8; psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF;#endif /* WIRELESS_EXT > 8 */ psa.psa_nwid_select = 0x01; psa_write(dev, (char *)psa.psa_nwid - (char *)&psa, (unsigned char *)psa.psa_nwid, 3); /* Set NWID in mmc */ m.w.mmw_netw_id_l = psa.psa_nwid[1]; m.w.mmw_netw_id_h = psa.psa_nwid[0]; mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2); mmc_out(base, mmwoff(0, mmw_loopt_sel), 0x00); } else { /* Disable nwid in the psa */ psa.psa_nwid_select = 0x00; psa_write(dev, (char *)&psa.psa_nwid_select - (char *)&psa, (unsigned char *)&psa.psa_nwid_select, 1); /* Disable nwid in the mmc (no filtering) */ mmc_out(base, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID); } /* update the Wavelan checksum */ update_psa_checksum(dev); break; case SIOCGIWNWID: /* Read the NWID */ psa_read(dev, (char *)psa.psa_nwid - (char *)&psa, (unsigned char *)psa.psa_nwid, 3);#if WIRELESS_EXT > 8 wrq->u.nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; wrq->u.nwid.disabled = !(psa.psa_nwid_select); wrq->u.nwid.fixed = 1; /* Superfluous */#else /* WIRELESS_EXT > 8 */ wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; wrq->u.nwid.on = psa.psa_nwid_select;#endif /* WIRELESS_EXT > 8 */ break; case SIOCSIWFREQ: /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */ if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) ret = wv_set_frequency(base, &(wrq->u.freq)); else ret = -EOPNOTSUPP; break; case SIOCGIWFREQ: /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) * (does it work for everybody ? - especially old cards...) */ if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { unsigned short freq; /* Ask the EEprom to read the frequency from the first area */ fee_read(base, 0x00 /* 1st area - frequency... */, &freq, 1); wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000; wrq->u.freq.e = 1; } else { psa_read(dev, (char *)&psa.psa_subband - (char *)&psa, (unsigned char *)&psa.psa_subband, 1); if(psa.psa_subband <= 4) { wrq->u.freq.m = fixed_bands[psa.psa_subband]; wrq->u.freq.e = (psa.psa_subband != 0); } else ret = -EOPNOTSUPP; } break; case SIOCSIWSENS: /* Set the level threshold */#if WIRELESS_EXT > 7 /* We should complain loudly if wrq->u.sens.fixed = 0, because we * can't set auto mode... */ psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F;#else /* WIRELESS_EXT > 7 */ psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F;#endif /* WIRELESS_EXT > 7 */ psa_write(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa, (unsigned char *)&psa.psa_thr_pre_set, 1); /* update the Wavelan checksum */ update_psa_checksum(dev); mmc_out(base, mmwoff(0, mmw_thr_pre_set), psa.psa_thr_pre_set); break; case SIOCGIWSENS: /* Read the level threshold */ psa_read(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa, (unsigned char *)&psa.psa_thr_pre_set, 1);#if WIRELESS_EXT > 7 wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F; wrq->u.sens.fixed = 1;#else /* WIRELESS_EXT > 7 */ wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F;#endif /* WIRELESS_EXT > 7 */ break;#if WIRELESS_EXT > 8 case SIOCSIWENCODE: /* Set encryption key */ if(!mmc_encr(base)) { ret = -EOPNOTSUPP; break; } /* Basic checking... */ if(wrq->u.encoding.pointer != (caddr_t) 0) { /* Check the size of the key */ if(wrq->u.encoding.length != 8) { ret = -EINVAL; break; } /* Copy the key in the driver */ if(copy_from_user(psa.psa_encryption_key, wrq->u.encoding.pointer, wrq->u.encoding.length)) { ret = -EFAULT; break; } psa.psa_encryption_select = 1; psa_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa, (unsigned char *) &psa.psa_encryption_select, 8+1); mmc_out(base, mmwoff(0, mmw_encr_enable), MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE); mmc_write(base, mmwoff(0, mmw_encr_key), (unsigned char *) &psa.psa_encryption_key, 8); } if(wrq->u.encoding.flags & IW_ENCODE_DISABLED) { /* disable encryption */ psa.psa_encryption_select = 0; psa_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa, (unsigned char *) &psa.psa_encryption_select, 1); mmc_out(base, mmwoff(0, mmw_encr_enable), 0); } /* update the Wavelan checksum */ update_psa_checksum(dev); break; case SIOCGIWENCODE: /* Read the encryption key */ if(!mmc_encr(base)) { ret = -EOPNOTSUPP; break; } /* only super-user can see encryption key */ if(!capable(CAP_NET_ADMIN)) { ret = -EPERM; break; } /* Basic checking... */ if(wrq->u.encoding.pointer != (caddr_t) 0) { psa_read(dev, (char *) &psa.psa_encryption_select - (char *) &psa, (unsigned char *) &psa.psa_encryption_select, 1+8); /* encryption is enabled ? */ if(psa.psa_encryption_select) wrq->u.encoding.flags = IW_ENCODE_ENABLED; else wrq->u.encoding.flags = IW_ENCODE_DISABLED; wrq->u.encoding.flags |= mmc_encr(base); /* Copy the key to the user buffer */ wrq->u.encoding.length = 8; if(copy_to_user(wrq->u.encoding.pointer, psa.psa_encryption_key, 8)) ret = -EFAULT; } break;#endif /* WIRELESS_EXT > 8 */#ifdef WAVELAN_ROAMING_EXT#if WIRELESS_EXT > 5 case SIOCSIWESSID: /* Check if disable */ if(wrq->u.data.flags == 0) lp->filter_domains = 0; else /* Basic checking... */ if(wrq->u.data.pointer != (caddr_t) 0) { char essid[IW_ESSID_MAX_SIZE + 1]; char * endp; /* Check the size of the string */ if(wrq->u.data.length > IW_ESSID_MAX_SIZE + 1) { ret = -E2BIG; break; } /* Copy the string in the driver */ if(copy_from_user(essid, wrq->u.data.pointer, wrq->u.data.length)) { ret = -EFAULT; break; } essid[IW_ESSID_MAX_SIZE] = '\0';#ifdef DEBUG_IOCTL_INFO printk(KERN_DEBUG "SetEssid : ``%s''\n", essid);#endif /* DEBUG_IOCTL_INFO */ /* Convert to a number (note : Wavelan specific) */ lp->domain_id = simple_strtoul(essid, &endp, 16); /* Has it worked ? */ if(endp > essid) lp->filter_domains = 1; else { lp->filter_domains = 0; ret = -EINVAL; } } break; case SIOCGIWESSID: /* Basic checking... */ if(wrq->u.data.pointer != (caddr_t) 0) { char essid[IW_ESSID_MAX_SIZE + 1]; /* Is the domain ID active ? */ wrq->u.data.flags = lp->filter_domains; /* Copy Domain ID into a string (Wavelan specific) */ /* Sound crazy, be we can't have a snprintf in the kernel !!! */ sprintf(essid, "%lX", lp->domain_id); essid[IW_ESSID_MAX_SIZE] = '\0'; /* Set the length */ wrq->u.data.length = strlen(essid) + 1; /* Copy structure to the user buffer */ if(copy_to_user(wrq->u.data.pointer, essid, wrq->u.data.length)) ret = -EFAULT; } break; case SIOCSIWAP:#ifdef DEBUG_IOCTL_INFO printk(KERN_DEBUG "Set AP to : %02X:%02X:%02X:%02X:%02X:%02X\n", wrq->u.ap_addr.sa_data[0], wrq->u.ap_addr.sa_data[1], wrq->u.ap_addr.sa_data[2], wrq->u.ap_addr.sa_data[3], wrq->u.ap_addr.sa_data[4], wrq->u.ap_addr.sa_data[5]);#endif /* DEBUG_IOCTL_INFO */ ret = -EOPNOTSUPP; /* Not supported yet */ break; case SIOCGIWAP: /* Should get the real McCoy instead of own Ethernet address */ memcpy(wrq->u.ap_addr.sa_data, dev->dev_addr, WAVELAN_ADDR_SIZE); wrq->u.ap_addr.sa_family = ARPHRD_ETHER; ret = -EOPNOTSUPP; /* Not supported yet */ break;#endif /* WIRELESS_EXT > 5 */#endif /* WAVELAN_ROAMING_EXT */#if WIRELESS_EXT > 8#ifdef WAVELAN_ROAMING case SIOCSIWMODE: switch(wrq->u.mode) { case IW_MODE_ADHOC: if(do_roaming) { wv_roam_cleanup(dev); do_roaming = 0; } break; case IW_MODE_INFRA: if(!do_roaming) { wv_roam_init(dev); do_roaming = 1; } break; default: ret = -EINVAL; } break; case SIOCGIWMODE: if(do_roaming) wrq->u.mode = IW_MODE_INFRA; else wrq->u.mode = IW_MODE_ADHOC; break;#endif /* WAVELAN_ROAMING */#endif /* WIRELESS_EXT > 8 */ case SIOCGIWRANGE: /* Basic checking... */ if(wrq->u.data.pointer != (caddr_t) 0) { struct iw_range range; /* Set the length (very important for backward compatibility) */ wrq->u.data.length = sizeof(struct iw_range); /* Set all the info we don't care or don't know about to zero */ memset(&range, 0, sizeof(range));#if WIRELESS_EXT > 10 /* Set the Wireless Extension versions */ range.we_version_compiled = WIRELESS_EXT; range.we_version_source = 9; /* Nothing for us in v10 and v11 */#endif /* WIRELESS_EXT > 10 */ /* Set information in the range struct */ range.throughput = 1.4 * 1000 * 1000; /* don't argue on this ! */ range.min_nwid = 0x0000; range.max_nwid = 0xFFFF; /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */ if(!(mmc_in(base, mmro
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -