📄 wavelan.c
字号:
(char *) psa.psa_nwid - (char *) &psa, (unsigned char *) psa.psa_nwid, 3); 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 */ break; case SIOCSIWFREQ: /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) ret = wv_set_frequency(ioaddr, &(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(ioaddr, 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(ioaddr, 0x00, &freq, 1); wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000; wrq->u.freq.e = 1; } else { psa_read(ioaddr, lp->hacr, (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. */ /* 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; psa_write(ioaddr, lp->hacr, (char *) &psa.psa_thr_pre_set - (char *) &psa, (unsigned char *) &psa.psa_thr_pre_set, 1); /* update the Wavelan checksum */ update_psa_checksum(dev, ioaddr, lp->hacr); mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set), psa.psa_thr_pre_set); break; case SIOCGIWSENS: /* Read the level threshold. */ psa_read(ioaddr, lp->hacr, (char *) &psa.psa_thr_pre_set - (char *) &psa, (unsigned char *) &psa.psa_thr_pre_set, 1); wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F; wrq->u.sens.fixed = 1; break; case SIOCSIWENCODE: /* Set encryption key */ if (!mmc_encr(ioaddr)) { 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 */ wv_splx(lp, &flags); err = copy_from_user(psa.psa_encryption_key, wrq->u.encoding.pointer, wrq->u.encoding.length); wv_splhi(lp, &flags); if (err) { ret = -EFAULT; break; } psa.psa_encryption_select = 1; psa_write(ioaddr, lp->hacr, (char *) &psa.psa_encryption_select - (char *) &psa, (unsigned char *) &psa. psa_encryption_select, 8 + 1); mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE); mmc_write(ioaddr, 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(ioaddr, lp->hacr, (char *) &psa.psa_encryption_select - (char *) &psa, (unsigned char *) &psa. psa_encryption_select, 1); mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), 0); } /* update the Wavelan checksum */ update_psa_checksum(dev, ioaddr, lp->hacr); break; case SIOCGIWENCODE: /* Read the encryption key */ if (!mmc_encr(ioaddr)) { 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) { /* Verify the user buffer */ ret = verify_area(VERIFY_WRITE, wrq->u.encoding.pointer, 8); if (ret) break; psa_read(ioaddr, lp->hacr, (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(ioaddr); /* Copy the key to the user buffer */ wrq->u.encoding.length = 8; wv_splx(lp, &flags); if (copy_to_user(wrq->u.encoding.pointer, psa.psa_encryption_key, 8)) ret = -EFAULT; wv_splhi(lp, &flags); } break; 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)); /* Set the Wireless Extension versions */ range.we_version_compiled = WIRELESS_EXT; range.we_version_source = 9; /* Set information in the range struct. */ range.throughput = 1.6 * 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(ioaddr, mmroff(0, mmr_fee_status)) & (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { range.num_channels = 10; range.num_frequency = wv_frequency_list(ioaddr, range.freq, IW_MAX_FREQUENCIES); } else range.num_channels = range.num_frequency = 0; range.sensitivity = 0x3F; range.max_qual.qual = MMR_SGNL_QUAL; range.max_qual.level = MMR_SIGNAL_LVL; range.max_qual.noise = MMR_SILENCE_LVL; range.avg_qual.qual = MMR_SGNL_QUAL; /* Always max */ /* Need to get better values for those two */ range.avg_qual.level = 30; range.avg_qual.noise = 8; range.num_bitrates = 1; range.bitrate[0] = 2000000; /* 2 Mb/s */ /* Encryption supported ? */ if (mmc_encr(ioaddr)) { range.encoding_size[0] = 8; /* DES = 64 bits key */ range.num_encoding_sizes = 1; range.max_encoding_tokens = 1; /* Only one key possible */ } else { range.num_encoding_sizes = 0; range.max_encoding_tokens = 0; } /* Copy structure to the user buffer. */ wv_splx(lp, &flags); if (copy_to_user(wrq->u.data.pointer, &range, sizeof(struct iw_range))) ret = -EFAULT; wv_splhi(lp, &flags); } break; case SIOCGIWPRIV: /* Basic checking */ if (wrq->u.data.pointer != (caddr_t) 0) { struct iw_priv_args priv[] = { /* { cmd, set_args, get_args, name } */ { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" }, { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" }, { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" }, { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, }; /* Set the number of available ioctls. */ wrq->u.data.length = 4; /* Copy structure to the user buffer. */ wv_splx(lp, &flags); if (copy_to_user(wrq->u.data.pointer, (u8 *) priv, sizeof(priv))) ret = -EFAULT; wv_splhi(lp, &flags); } break;#ifdef WIRELESS_SPY case SIOCSIWSPY: /* Set the spy list */ /* Check the number of addresses. */ if (wrq->u.data.length > IW_MAX_SPY) { ret = -E2BIG; break; } lp->spy_number = wrq->u.data.length; /* Are there are addresses to copy? */ if (lp->spy_number > 0) { struct sockaddr address[IW_MAX_SPY]; int i; /* Copy addresses to the driver. */ wv_splx(lp, &flags); err = copy_from_user(address, wrq->u.data.pointer, sizeof(struct sockaddr) * lp->spy_number); wv_splhi(lp, &flags); if (err) { ret = -EFAULT; break; } /* Copy addresses to the lp structure. */ for (i = 0; i < lp->spy_number; i++) { memcpy(lp->spy_address[i], address[i].sa_data, WAVELAN_ADDR_SIZE); } /* Reset structure. */ memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);#ifdef DEBUG_IOCTL_INFO printk(KERN_DEBUG "SetSpy: set of new addresses is: \n"); for (i = 0; i < wrq->u.data.length; i++) printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X \n", lp->spy_address[i][0], lp->spy_address[i][1], lp->spy_address[i][2], lp->spy_address[i][3], lp->spy_address[i][4], lp->spy_address[i][5]);#endif /* DEBUG_IOCTL_INFO */ } break; case SIOCGIWSPY: /* Get the spy list and spy stats. */ /* Set the number of addresses */ wrq->u.data.length = lp->spy_number; /* Does the user want to have the addresses back? */ if ((lp->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0)) { struct sockaddr address[IW_MAX_SPY]; int i; /* Copy addresses from the lp structure. */ for (i = 0; i < lp->spy_number; i++) { memcpy(address[i].sa_data, lp->spy_address[i], WAVELAN_ADDR_SIZE); address[i].sa_family = AF_UNIX; } /* Copy addresses to the user buffer. */ wv_splx(lp, &flags); err = copy_to_user(wrq->u.data.pointer, address, sizeof(struct sockaddr) * lp->spy_number); /* Copy stats to the user buffer (just after). */ err |= copy_to_user(wrq->u.data.pointer + (sizeof(struct sockaddr) * lp->spy_number), lp->spy_stat, sizeof(iw_qual) * lp->spy_number); wv_splhi(lp, &flags); if (err) { ret = -EFAULT; break; } /* Reset updated flags. */ for (i = 0; i < lp->spy_number; i++) lp->spy_stat[i].updated = 0x0; } /* if(pointer != NULL) */ break;#endif /* WIRELESS_SPY */ /* ------------------ PRIVATE IOCTL ------------------ */ case SIOCSIPQTHR: if (!capable(CAP_NET_ADMIN)) { ret = -EPERM; break; } psa.psa_quality_thr = *(wrq->u.name) & 0x0F; psa_write(ioaddr, lp->hacr, (char *) &psa.psa_quality_thr - (char *) &psa, (unsigned char *) &psa.psa_quality_thr, 1); /* update the Wavelan checksum */ update_psa_checksum(dev, ioaddr, lp->hacr); mmc_out(ioaddr, mmwoff(0, mmw_quality_thr), psa.psa_quality_thr); break; case SIOCGIPQTHR: psa_read(ioaddr, lp->hacr, (char *) &psa.psa_quality_thr - (char *) &psa, (unsigned char *) &psa.psa_quality_thr, 1); *(wrq->u.name) = psa.psa_quality_thr & 0x0F; break;#ifdef HISTOGRAM case SIOCSIPHISTO: /* Verify that the user is root. */ if (!capable(CAP_NET_ADMIN)) { ret = -EPERM; break; } /* Check the number of intervals. */ if (wrq->u.data.length > 16) { ret = -E2BIG; break; } lp->his_number = wrq->u.data.length; /* Are there addresses to copy? */ if (lp->his_number > 0) { /* Copy interval ranges to the driver */ wv_splx(lp, &flags); err = copy_from_user(lp->his_range, wrq->u.data.pointer, sizeof(char) * lp->his_number); wv_splhi(lp, &flags); if (err) { ret = -EFAULT; break; } /* Reset structure. */ memset(lp->his_sum, 0x00, sizeof(long) * 16); } break; case SIOCGIPHISTO: /* Set the number of intervals. */ wrq->u.data.length = lp->his_number; /* Give back the distribution statistics */ if ((lp->his_number > 0) && (wrq->u.data.pointer != (caddr_t) 0)) { /* Copy data to the user buffer. */ wv_splx(lp, &flags); if (copy_to_user(wrq->u.data.pointer, lp->his_sum, sizeof(long) * lp->his_number); ret = -EFAULT; wv_splhi(lp, &flags); } /* if(pointer != NULL) */ break;#endif /* HISTOGRAM */ /* ------------------- OTHER IOCTL ------------------- */ default: ret = -EOPNOTSUPP; } /* switch (cmd) */ /* Enable interrupts and restore flags. */ wv_splx(lp, &flags);#ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);#endif return ret;}/*------------------------------------------------------------------*//* * Get wireless
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -