📄 if_an.c
字号:
case AN_RID_SSIDLIST:
ssid = (struct an_ltv_ssidlist *)areq;
bcopy((char *)ssid, (char *)&sc->an_ssidlist,
sizeof(struct an_ltv_ssidlist));
break;
case AN_RID_APLIST:
ap = (struct an_ltv_aplist *)areq;
bcopy((char *)ap, (char *)&sc->an_aplist,
sizeof(struct an_ltv_aplist));
break;
case AN_RID_TX_SPEED:
sp = (struct an_ltv_gen *)areq;
sc->an_tx_rate = sp->an_val;
break;
case AN_RID_WEP_TEMP:
case AN_RID_WEP_PERM:
/* Disable the MAC. */
/* an_cmd(sc, AN_CMD_DISABLE, 0); */
/* Write the key */
an_write_record(sc, (struct an_ltv_gen *)areq);
/* Turn the MAC back on. */
/* an_cmd(sc, AN_CMD_ENABLE, 0); */
return;
break;
case AN_RID_MONITOR_MODE:
cfg = (struct an_ltv_genconfig *)areq;
bpfdetach(ifp);
if (ng_ether_detach_p != NULL)
(*ng_ether_detach_p) (ifp);
sc->an_monitor = cfg->an_len;
if (sc->an_monitor & AN_MONITOR) {
if (sc->an_monitor & AN_MONITOR_AIRONET_HEADER) {
bpfattach(ifp, DLT_AIRONET_HEADER,
sizeof(struct ether_header));
} else {
bpfattach(ifp, DLT_IEEE802_11,
sizeof(struct ether_header));
}
} else {
bpfattach(ifp, DLT_EN10MB,
sizeof(struct ether_header));
if (ng_ether_attach_p != NULL)
(*ng_ether_attach_p) (ifp);
}
break;
default:
printf("an%d: unknown RID: %x\n", sc->an_unit, areq->an_type);
return;
break;
}
/* Reinitialize the card. */
if (ifp->if_flags)
an_init(sc);
return;
}
/*
* Derived from Linux driver to enable promiscious mode.
*/
static void
an_promisc(sc, promisc)
struct an_softc *sc;
int promisc;
{
if (sc->an_was_monitor)
an_reset(sc);
if (sc->an_monitor || sc->an_was_monitor)
an_init(sc);
sc->an_was_monitor = sc->an_monitor;
an_cmd(sc, AN_CMD_SET_MODE, promisc ? 0xffff : 0);
return;
}
static int
an_ioctl(ifp, command, data)
struct ifnet *ifp;
u_long command;
caddr_t data;
{
int s, error = 0;
int len;
int i;
struct an_softc *sc;
struct an_req areq;
struct ifreq *ifr;
struct proc *p = curproc;
struct ieee80211req *ireq;
u_int8_t tmpstr[IEEE80211_NWID_LEN*2];
u_int8_t *tmpptr;
struct an_ltv_genconfig *config;
struct an_ltv_key *key;
struct an_ltv_status *status;
struct an_ltv_ssidlist *ssids;
s = splimp();
sc = ifp->if_softc;
ifr = (struct ifreq *)data;
ireq = (struct ieee80211req *)data;
config = (struct an_ltv_genconfig *)&areq;
key = (struct an_ltv_key *)&areq;
status = (struct an_ltv_status *)&areq;
ssids = (struct an_ltv_ssidlist *)&areq;
if (sc->an_gone) {
error = ENODEV;
goto out;
}
switch (command) {
case SIOCSIFADDR:
case SIOCGIFADDR:
case SIOCSIFMTU:
error = ether_ioctl(ifp, command, data);
break;
case SIOCSIFFLAGS:
if (ifp->if_flags & IFF_UP) {
if (ifp->if_flags & IFF_RUNNING &&
ifp->if_flags & IFF_PROMISC &&
!(sc->an_if_flags & IFF_PROMISC)) {
an_promisc(sc, 1);
} else if (ifp->if_flags & IFF_RUNNING &&
!(ifp->if_flags & IFF_PROMISC) &&
sc->an_if_flags & IFF_PROMISC) {
an_promisc(sc, 0);
} else
an_init(sc);
} else {
if (ifp->if_flags & IFF_RUNNING)
an_stop(sc);
}
sc->an_if_flags = ifp->if_flags;
error = 0;
break;
case SIOCSIFMEDIA:
case SIOCGIFMEDIA:
error = ifmedia_ioctl(ifp, ifr, &sc->an_ifmedia, command);
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
/* The Aironet has no multicast filter. */
error = 0;
break;
case SIOCGAIRONET:
error = copyin(ifr->ifr_data, &areq, sizeof(areq));
if (error != 0)
break;
#ifdef ANCACHE
if (areq.an_type == AN_RID_ZERO_CACHE) {
sc->an_sigitems = sc->an_nextitem = 0;
break;
} else if (areq.an_type == AN_RID_READ_CACHE) {
char *pt = (char *)&areq.an_val;
bcopy((char *)&sc->an_sigitems, (char *)pt,
sizeof(int));
pt += sizeof(int);
areq.an_len = sizeof(int) / 2;
bcopy((char *)&sc->an_sigcache, (char *)pt,
sizeof(struct an_sigcache) * sc->an_sigitems);
areq.an_len += ((sizeof(struct an_sigcache) *
sc->an_sigitems) / 2) + 1;
} else
#endif
if (an_read_record(sc, (struct an_ltv_gen *)&areq)) {
error = EINVAL;
break;
}
error = copyout(&areq, ifr->ifr_data, sizeof(areq));
break;
case SIOCSAIRONET:
if ((error = suser(p)))
goto out;
error = copyin(ifr->ifr_data, &areq, sizeof(areq));
if (error != 0)
break;
an_setdef(sc, &areq);
break;
case SIOCG80211:
areq.an_len = sizeof(areq);
switch (ireq->i_type) {
case IEEE80211_IOC_SSID:
if (ireq->i_val == -1) {
areq.an_type = AN_RID_STATUS;
if (an_read_record(sc,
(struct an_ltv_gen *)&areq)) {
error = EINVAL;
break;
}
len = status->an_ssidlen;
tmpptr = status->an_ssid;
} else if (ireq->i_val >= 0) {
areq.an_type = AN_RID_SSIDLIST;
if (an_read_record(sc,
(struct an_ltv_gen *)&areq)) {
error = EINVAL;
break;
}
if (ireq->i_val == 0) {
len = ssids->an_ssid1_len;
tmpptr = ssids->an_ssid1;
} else if (ireq->i_val == 1) {
len = ssids->an_ssid2_len;
tmpptr = ssids->an_ssid3;
} else if (ireq->i_val == 1) {
len = ssids->an_ssid3_len;
tmpptr = ssids->an_ssid3;
} else {
error = EINVAL;
break;
}
} else {
error = EINVAL;
break;
}
if (len > IEEE80211_NWID_LEN) {
error = EINVAL;
break;
}
ireq->i_len = len;
bzero(tmpstr, IEEE80211_NWID_LEN);
bcopy(tmpptr, tmpstr, len);
error = copyout(tmpstr, ireq->i_data,
IEEE80211_NWID_LEN);
break;
case IEEE80211_IOC_NUMSSIDS:
ireq->i_val = 3;
break;
case IEEE80211_IOC_WEP:
areq.an_type = AN_RID_ACTUALCFG;
if (an_read_record(sc,
(struct an_ltv_gen *)&areq)) {
error = EINVAL;
break;
}
if (config->an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE) {
if (config->an_authtype &
AN_AUTHTYPE_ALLOW_UNENCRYPTED)
ireq->i_val = IEEE80211_WEP_MIXED;
else
ireq->i_val = IEEE80211_WEP_ON;
} else {
ireq->i_val = IEEE80211_WEP_OFF;
}
break;
case IEEE80211_IOC_WEPKEY:
/*
* XXX: I'm not entierly convinced this is
* correct, but it's what is implemented in
* ancontrol so it will have to do until we get
* access to actual Cisco code.
*/
if (ireq->i_val < 0 || ireq->i_val > 7) {
error = EINVAL;
break;
}
len = 0;
if (ireq->i_val < 4) {
areq.an_type = AN_RID_WEP_TEMP;
for (i = 0; i < 5; i++) {
if (an_read_record(sc,
(struct an_ltv_gen *)&areq)) {
error = EINVAL;
break;
}
if (key->kindex == 0xffff)
break;
if (key->kindex == ireq->i_val)
len = key->klen;
/* Required to get next entry */
areq.an_type = AN_RID_WEP_PERM;
}
if (error != 0)
break;
}
/* We aren't allowed to read the value of the
* key from the card so we just output zeros
* like we would if we could read the card, but
* denied the user access.
*/
bzero(tmpstr, len);
ireq->i_len = len;
error = copyout(tmpstr, ireq->i_data, len);
break;
case IEEE80211_IOC_NUMWEPKEYS:
ireq->i_val = 8;
break;
case IEEE80211_IOC_WEPTXKEY:
/*
* For some strange reason, you have to read all
* keys before you can read the txkey.
*/
areq.an_type = AN_RID_WEP_TEMP;
for (i = 0; i < 5; i++) {
if (an_read_record(sc,
(struct an_ltv_gen *)&areq)) {
error = EINVAL;
break;
}
if (key->kindex == 0xffff)
break;
/* Required to get next entry */
areq.an_type = AN_RID_WEP_PERM;
}
if (error != 0)
break;
areq.an_type = AN_RID_WEP_PERM;
key->kindex = 0xffff;
if (an_read_record(sc,
(struct an_ltv_gen *)&areq)) {
error = EINVAL;
break;
}
ireq->i_val = key->mac[0];
break;
case IEEE80211_IOC_AUTHMODE:
areq.an_type = AN_RID_ACTUALCFG;
if (an_read_record(sc,
(struct an_ltv_gen *)&areq)) {
error = EINVAL;
break;
}
if ((config->an_authtype & AN_AUTHTYPE_MASK) ==
AN_AUTHTYPE_NONE) {
ireq->i_val = IEEE80211_AUTH_NONE;
} else if ((config->an_authtype & AN_AUTHTYPE_MASK) ==
AN_AUTHTYPE_OPEN) {
ireq->i_val = IEEE80211_AUTH_OPEN;
} else if ((config->an_authtype & AN_AUTHTYPE_MASK) ==
AN_AUTHTYPE_SHAREDKEY) {
ireq->i_val = IEEE80211_AUTH_SHARED;
} else
error = EINVAL;
break;
case IEEE80211_IOC_STATIONNAME:
areq.an_type = AN_RID_ACTUALCFG;
if (an_read_record(sc,
(struct an_ltv_gen *)&areq)) {
error = EINVAL;
break;
}
ireq->i_len = sizeof(config->an_nodename);
tmpptr = config->an_nodename;
bzero(tmpstr, IEEE80211_NWID_LEN);
bcopy(tmpptr, tmpstr, ireq->i_len);
error = copyout(tmpstr, ireq->i_data,
IEEE80211_NWID_LEN);
break;
case IEEE80211_IOC_CHANNEL:
areq.an_type = AN_RID_STATUS;
if (an_read_record(sc,
(struct an_ltv_gen *)&areq)) {
error = EINVAL;
break;
}
ireq->i_val = status->an_cur_channel;
break;
case IEEE80211_IOC_POWERSAVE:
areq.an_type = AN_RID_ACTUALCFG;
if (an_read_record(sc,
(struct an_ltv_gen *)&areq)) {
error = EINVAL;
break;
}
if (config->an_psave_mode == AN_PSAVE_NONE) {
ireq->i_val = IEEE80211_POWERSAVE_OFF;
} else if (config->an_psave_mode == AN_PSAVE_CAM) {
ireq->i_val = IEEE80211_POWERSAVE_CAM;
} else if (config->an_psave_mode == AN_PSAVE_PSP) {
ireq->i_val = IEEE80211_POWERSAVE_PSP;
} else if (config->an_psave_mode == AN_PSAVE_PSP_CAM) {
ireq->i_val = IEEE80211_POWERSAVE_PSP_CAM;
} else
error = EINVAL;
break;
case IEEE80211_IOC_POWERSAVESLEEP:
areq.an_type = AN_RID_ACTUALCFG;
if (an_read_record(sc,
(struct an_ltv_gen *)&areq)) {
error = EINVAL;
break;
}
ireq->i_val = config->an_listen_interval;
break;
}
break;
case SIOCS80211:
if ((error = suser(p)))
goto out;
areq.an_len = sizeof(areq);
/*
* We need a config structure for everything but the WEP
* key management and SSIDs so we get it now so avoid
* duplicating this code every time.
*/
if (ireq->i_type != IEEE80211_IOC_SSID &&
ireq->i_type != IEEE80211_IOC_WEPKEY &&
ireq->i_type != IEEE80211_IOC_WEPTXKEY) {
areq.an_type = AN_RID_GENCONFIG;
if (an_read_record(sc,
(struct an_ltv_gen *)&areq)) {
error = EINVAL;
break;
}
}
switch (ireq->i_type) {
case IEEE80211_IOC_SSID:
areq.an_type = AN_RID_SSIDLIST;
if (an_read_record(sc,
(struct an_ltv_gen *)&areq)) {
error = EINVAL;
break;
}
if (ireq->i_len > IEEE80211_NWID_LEN) {
error = EINVAL;
break;
}
switch (ireq->i_val) {
case 0:
error = copyin(ireq->i_data,
ssids->an_ssid1, ireq->i_len);
ssids->an_ssid1_len = ireq->i_len;
break;
case 1:
error = copyin(ireq->i_data,
ssids->an_ssid2, ireq->i_len);
ssids->an_ssid2_len = ireq->i_len;
break;
case 2:
error = copyin(ireq->i_data,
ssids->an_ssid3, ireq->i_len);
ssids->an_ssid3_len = ireq->i_len;
break;
default:
error = EINVAL;
break;
}
break;
case IEEE80211_IOC_WEP:
switch (ireq->i_val) {
case IEEE80211_WEP_OFF:
config->an_authtype &=
~(AN_AUTHTYPE_PRIVACY_IN_USE |
AN_AUTHTYPE_ALLOW_UNENCRYPTED);
break;
case IEEE80211_WEP_ON:
config->an_authtype |=
AN_AUTHTYPE_PRIVACY_IN_USE;
config->an_authtype &=
~AN_AUTHTYPE_ALLOW_UNENCRYPTED;
break;
case IEEE80211_WEP_MIXED:
config->an_authtype |=
AN_AUTHTYPE_PRIVACY_IN_USE |
AN_AUTHTYPE_ALLOW_UNENCRYPTED;
break;
default:
error = EINVAL;
break;
}
break;
case IEEE80211_IOC_WEPKEY:
if (ireq->i_val < 0 || ireq->i_val > 7 ||
ireq->i_len > 13) {
error = EINVAL;
break;
}
error = copyin(ireq->i_data, tmpstr, 13);
if (error != 0)
break;
bzero(&areq, sizeof(struct an_ltv_key));
areq.an_len = sizeof(struct an_ltv_key);
key->mac[0] = 1; /* The others are 0. */
key->kindex = ireq->i_val % 4;
if (ireq->i_val < 4)
areq.an_type = AN_RID_WEP_TEMP;
else
areq.an_type = AN_RID_WEP_PERM;
key->klen = ireq->i_len;
bcopy(tmpstr, key->key, key->klen);
break;
case IEEE80211_IOC_WEPTXKEY:
if (ireq->i_val < 0 || ireq->i_val > 3) {
error = EINVAL;
break;
}
bzero(&areq, sizeof(struct an_ltv_key));
areq.an_len = sizeof(struct an_ltv_key);
areq.an_type = AN_RID_WEP_PERM;
key->kindex = 0xffff;
key->mac[0] = ireq->i_val;
break;
case IEEE80211_IOC_AUTHMODE:
switch (ireq->i_val) {
case IEEE80211_AUTH_NONE:
config->an_authtype = AN_AUTHTYPE_NONE |
(config->an_authtype & ~AN_AUTHTYPE_MASK);
break;
case IEEE80211_AUTH_OPEN:
config->an_authtype = AN_AUTHTYPE_OPEN |
(config->an_authtype & ~AN_AUTHTYPE_MASK);
break;
case IEEE80211_AUTH_SHARED:
config->an_authtype = AN_AUTHTYPE_SHAREDKEY |
(config->an_authtype & ~AN_AUTHTYPE_MASK);
break;
default:
error = EINVAL;
}
break;
case IEEE80211_IOC_STATIONNAME:
if (ireq->i_len > 16) {
error = EINVAL;
break;
}
bzero(config->an_nodename, 16);
error = copyin(ireq->i_data,
config->an_nodename, ireq->i_len);
break;
case IEEE80211_IOC_CHANNEL:
/*
* The actual range is 1-14, but if you set it
* to 0 you get the default so we let that work
* too.
*/
if (ireq->i_val < 0 || ireq->i_val >14) {
error = EINVAL;
break;
}
config->an_ds_channel = ireq->i_val;
break;
case IEEE80211_IOC_POWERSAVE:
switch (ireq->i_val) {
case IEEE80211_POWERSAVE_OFF:
config->an_psave_mode = AN_PSAVE_NONE;
break;
case IEEE80211_POWERSAVE_CAM:
config->an_psave_mode = AN_PSAVE_CAM;
break;
case IEEE80211_POWERSAVE_PSP:
config->an_psave_mode = AN_PSAVE_PSP;
break;
case IEEE80211_POWERSAVE_PSP_CAM:
config->an_psave_mode = AN_PSAVE_PSP_CAM;
break;
default:
error = EINVAL;
break;
}
break;
case IEEE80211_IOC_POWERSAVESLEEP:
config->an_listen_interval = ireq->i_val;
break;
}
if (!error)
an_setdef(sc, &areq);
break;
default:
error = EINVAL;
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -