📄 wavelan.c
字号:
break; case SIOCGIWNWID: /* Read the NWID */ psa_read(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa, (unsigned char *)psa.psa_nwid, 3); wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; wrq->u.nwid.on = psa.psa_nwid_select; 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 /* 1st area - frequency... */, &freq, 1); wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000; wrq->u.freq.e = 1; } else { int bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 }; 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 = bands[psa.psa_subband]; wrq->u.freq.e = (psa.psa_subband != 0); } else ret = -EOPNOTSUPP; } break; case SIOCSIWSENS: /* Set the level threshold */ if(!suser()) return -EPERM; psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F; psa_write(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa, (unsigned char *) &psa.psa_thr_pre_set, 1); 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.sensitivity = psa.psa_thr_pre_set & 0x3F; break; case SIOCSIWENCODE: /* Set encryption key */ if(!mmc_encr(ioaddr)) { ret = -EOPNOTSUPP; break; } if(wrq->u.encoding.method) { /* enable encryption */ int i; long long key = wrq->u.encoding.code; for(i = 7; i >= 0; i--) { psa.psa_encryption_key[i] = key & 0xFF; key >>= 8; } 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); } else { /* 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); } break; case SIOCGIWENCODE: /* Read the encryption key */ if(!mmc_encr(ioaddr)) { ret = -EOPNOTSUPP; break; } /* only super-user can see encryption key */ if(!suser()) { ret = -EPERM; break; } else { int i; long long key = 0; psa_read(ioaddr, lp->hacr, (char *) &psa.psa_encryption_select - (char *) &psa, (unsigned char *) &psa.psa_encryption_select, 1+8); for(i = 0; i < 8; i++) { key <<= 8; key += psa.psa_encryption_key[i]; } wrq->u.encoding.code = key; /* encryption is enabled */ if(psa.psa_encryption_select) wrq->u.encoding.method = mmc_encr(ioaddr); else wrq->u.encoding.method = 0; } break; case SIOCGIWRANGE: /* basic checking */ if(wrq->u.data.pointer != (caddr_t) 0) { struct iw_range range; /* Verify the user buffer */ ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(struct iw_range)); if(ret) break; /* Set the length (useless : its constant...) */ wrq->u.data.length = sizeof(struct iw_range); /* Set information in the range struct */ range.throughput = 1.6 * 1024 * 1024; /* 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; /* Copy structure to the user buffer */ copy_to_user(wrq->u.data.pointer, &range, sizeof(struct iw_range)); } 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" }, }; /* Verify the user buffer */ ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(priv)); if(ret) break; /* Set the number of ioctl available */ wrq->u.data.length = 4; /* Copy structure to the user buffer */ copy_to_user(wrq->u.data.pointer, (u_char *) priv, sizeof(priv)); } 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; /* If there is some addresses to copy */ if(lp->spy_number > 0) { struct sockaddr address[IW_MAX_SPY]; int i; /* Verify where the user has set his addresses */ ret = verify_area(VERIFY_READ, wrq->u.data.pointer, sizeof(struct sockaddr) * lp->spy_number); if(ret) break; /* Copy addresses to the driver */ copy_from_user(address, wrq->u.data.pointer, sizeof(struct sockaddr) * lp->spy_number); /* 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; /* If 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; /* Verify the user buffer */ ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer, (sizeof(iw_qual) + sizeof(struct sockaddr)) * IW_MAX_SPY); if(ret) break; /* 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 */ copy_to_user(wrq->u.data.pointer, address, sizeof(struct sockaddr) * lp->spy_number); /* Copy stats to the user buffer (just after) */ copy_to_user(wrq->u.data.pointer + (sizeof(struct sockaddr) * lp->spy_number), lp->spy_stat, sizeof(iw_qual) * lp->spy_number); /* 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(!suser()) return -EPERM; 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); 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: /* Verif if the user is root */ if(!suser()) return -EPERM; /* Check the number of intervals */ if(wrq->u.data.length > 16) { ret = -E2BIG; break; } lp->his_number = wrq->u.data.length; /* If there is some addresses to copy */ if(lp->his_number > 0) { /* Verify where the user has set his addresses */ ret = verify_area(VERIFY_READ, wrq->u.data.pointer, sizeof(char) * lp->his_number); if(ret) break; /* Copy interval ranges to the driver */ copy_from_user(lp->his_range, wrq->u.data.pointer, sizeof(char) * lp->his_number); /* 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)) { /* Verify the user buffer */ ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(long) * 16); if(ret) break; /* Copy data to the user buffer */ copy_to_user(wrq->u.data.pointer, lp->his_sum, sizeof(long) * lp->his_number); } /* if(pointer != NULL) */ break;#endif /* HISTOGRAM */ /* ------------------- OTHER IOCTL ------------------- */ default: ret = -EOPNOTSUPP; } /* Enable interrupts, restore flags */ wv_splx(x);#ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);#endif return ret;}/*------------------------------------------------------------------*//* * Get wireless statistics * Called by /proc/net/wireless */static iw_stats *wavelan_get_wireless_stats(device * dev){ u_long ioaddr = dev->base_addr; net_local * lp = (net_local *) dev->priv; mmr_t m; iw_stats * wstats; unsigned long x;#ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name);#endif /* Disable interrupts & save flags */ x = wv_splhi(); if(lp == (net_local *) NULL) return (iw_stats *) NULL; wstats = &lp->wstats; /* Get data from the mmc */ mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); mmc_read(ioaddr, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1); mmc_read(ioaddr, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l, 2); mmc_read(ioaddr, mmroff(0, mmr_thr_pre_set), &m.mmr_thr_pre_set, 4); mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); /* Copy data to wireless stuff */ wstats->status = m.mmr_dce_status; wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL; wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL; wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL; wstats->qual.updated = (((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 7) | ((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 6) | ((m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) >> 5)); wstats->discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; wstats->discard.code = 0L; wstats->discard.misc = 0L; /* Enable interrupts & restore flags */ wv_splx(x);#ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name);#endif return &lp->wstats;}#endif /* WIRELESS_EXT *//************************* PACKET RECEPTION *************************//* * This part deals with receiving the packets. * The interrupt handler gets an interrupt when a packet has been * successfully received and calls this part. *//*------------------------------------------------------------------*//* * This routine does the actual copying of data (including the Ethernet * header structure) from the WaveLAN card to an sk_buff chain that * will be passed up to the network interface layer. NOTE: we * currently don't handle trailer protocols (neither does the rest of * the network interface), so if that is needed, it will (at least in * part) be added here. The contents of the receive ring buffer are * copied to a message chain that is then passed to the kernel. * * Note: if any errors occur, the packet is "dropped on the floor" * (called by wv_packet_rcv()) */static inline voidwv_packet_read(device * dev, u_short buf_off, int sksize){ net_local * lp = (net_local *) dev->priv; u_long ioaddr = dev->base_addr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -