Subject: Re: 802.11 Transmit power control
To: David Young <dyoung@pobox.com>
From: Dheeraj Reddy <dheeraj@ece.gatech.edu>
List: tech-net
Date: 10/31/2004 16:15:56
--rJwd6BRFiFCcLxzm
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Hello David,
Attached are the new patches. They use the API similar to FreeBSD as you
indicated.(thanks for that bit of hand-holding)
I have not added documentation yet because I haven;t yet checked actually if
the transmit power on air is decreased. I just verified by reading
the relevant rids from the card after the reset.
truely
dheeraj
--
It is better to be silent and be thought a fool than to speak and remove
all doubt
--rJwd6BRFiFCcLxzm
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="diff-an.txt"
Index: an.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/an.c,v
retrieving revision 1.32
diff -u -r1.32 an.c
--- an.c 24 Aug 2004 00:53:29 -0000 1.32
+++ an.c 31 Oct 2004 21:06:09 -0000
@@ -75,9 +75,13 @@
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_compat.h>
+#include <net80211/ieee80211_ioctl.h>
+#include <net80211/ieee80211_radiotap.h>
+#include <net80211/ieee80211_rssadapt.h>
#if NBPFILTER > 0
#include <net/bpf.h>
+#include <net/bpfdesc.h>
#endif
#include <dev/ic/anreg.h>
@@ -99,6 +103,8 @@
static int an_get_nwkey(struct an_softc *, struct ieee80211_nwkey *);
static int an_write_wepkey(struct an_softc *, int, struct an_wepkey *,
int);
+static int an_set_txpower(struct an_softc *, u_int16_t *);
+static int an_get_txpower(struct an_softc *, u_int16_t *);
static void an_rx_intr(struct an_softc *);
static void an_tx_intr(struct an_softc *, int);
@@ -116,14 +122,18 @@
static int an_newstate(struct ieee80211com *, enum ieee80211_state, int);
+static void an_dump_pkt(struct an_rxframe *arf, struct ieee80211_node *ni);
#ifdef AN_DEBUG
int an_debug = 0;
#define DPRINTF(X) if (an_debug) printf X
#define DPRINTF2(X) if (an_debug > 1) printf X
+#define IFF_DUMPPKTS(_ifp) \
+ (((_ifp)->if_flags & (IFF_DEBUG|IFF_LINK2)) == (IFF_DEBUG|IFF_LINK2))
#else
#define DPRINTF(X)
#define DPRINTF2(X)
+#define IFF_DUMPPKTS(_ifp) 0
#endif
int
@@ -283,6 +293,10 @@
ic->ic_newstate = an_newstate;
ieee80211_media_init(ifp, an_media_change, an_media_status);
+#if NBPFILTER > 0
+ bpfattach2(ifp, DLT_IEEE802_11_RADIO,
+ sizeof(struct ieee80211_frame) + 64, &sc->sc_drvbpf);
+#endif
sc->sc_attached = 1;
splx(s);
@@ -785,6 +799,7 @@
{
struct an_softc *sc = ifp->if_softc;
int s, error = 0;
+ struct ieee80211req *ireq;
if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
return ENXIO;
@@ -821,6 +836,26 @@
case SIOCG80211NWKEY:
error = an_get_nwkey(sc, (struct ieee80211_nwkey *)data);
break;
+ case SIOCG80211:
+ ireq = (struct ieee80211req*)(data);
+ switch (ireq->i_type) {
+ case IEEE80211_IOC_TXPOWER:
+ error = an_get_txpower(sc, &ireq->i_txpower);
+ break;
+ default:
+ return EOPNOTSUPP;
+ }
+ break;
+ case SIOCS80211:
+ ireq = (struct ieee80211req*)(data);
+ switch (ireq->i_type) {
+ case IEEE80211_IOC_TXPOWER:
+ error = an_set_txpower(sc, &ireq->i_txpower);
+ break;
+ default:
+ return EOPNOTSUPP;
+ }
+ break;
default:
error = ieee80211_ioctl(ifp, command, data);
break;
@@ -1213,6 +1248,40 @@
return error;
}
+static int
+an_set_txpower(struct an_softc *sc, u_int16_t* power)
+{
+ int i;
+ int error = 0;
+ struct ifnet *ifp = &sc->sc_ic.ic_if;
+ struct an_rid_genconfig* arg = &sc->sc_config;
+ u_int16_t currval=arg->an_tx_power;
+
+ for(i=0; i< 8; i++)
+ if (sc->sc_caps.an_tx_powerlevels[i] == *power) {
+ arg->an_tx_power= *power;
+ an_cmd(sc, AN_CMD_DISABLE, 0);
+ error = an_write_rid(sc, AN_RID_GENCONFIG,
+ arg, sizeof(sc->sc_config));
+ an_reset(sc);
+ an_init(ifp);
+ break;
+ }
+ if (error < 0)
+ arg->an_tx_power=currval; /* restore old value upon failure */
+ return error;
+}
+
+static int
+an_get_txpower(struct an_softc *sc, u_int16_t *power)
+{
+ int buflen;
+
+ buflen = sizeof(sc->sc_config);
+ an_read_rid(sc, AN_RID_GENCONFIG, &sc->sc_config, &buflen);
+ memcpy(power, &sc->sc_config.an_tx_power, sizeof(u_int16_t));
+ return 0;
+}
/*
* Low level functions
@@ -1240,20 +1309,8 @@
return;
}
-#ifdef AN_DEBUG
- if ((ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) == (IFF_DEBUG|IFF_LINK2)) {
- ieee80211_dump_pkt((u_int8_t *)&frmhdr.an_whdr,
- sizeof(struct ieee80211_frame), frmhdr.an_rx_rate,
- frmhdr.an_rx_signal_strength);
- printf(" time 0x%x status 0x%x plen %u chan %u"
- " plcp %02x %02x %02x %02x gap %u\n",
- le32toh(frmhdr.an_rx_time), le16toh(frmhdr.an_rx_status),
- le16toh(frmhdr.an_rx_payload_len), frmhdr.an_rx_chan,
- frmhdr.an_plcp_hdr[0], frmhdr.an_plcp_hdr[1],
- frmhdr.an_plcp_hdr[2], frmhdr.an_plcp_hdr[3],
- le16toh(frmhdr.an_gaplen));
- }
-#endif
+ if (IFF_DUMPPKTS(ifp))
+ an_dump_pkt(&frmhdr, NULL);
status = le16toh(frmhdr.an_rx_status);
if ((status & AN_STAT_ERRSTAT) != 0 &&
@@ -1264,6 +1321,11 @@
return;
}
+ if (frmhdr.an_gaplen > 8) {
+ ifp->if_ierrors++;
+ DPRINTF(("an_rx_intr: gaplen too large: %d", frmhdr.an_gaplen));
+ return;
+ }
len = le16toh(frmhdr.an_rx_payload_len);
off = ALIGN(sizeof(struct ieee80211_frame));
@@ -1273,8 +1335,8 @@
ifp->if_ierrors++;
DPRINTF(("an_rx_intr: oversized packet %d\n", len));
return;
- }
- len = 0;
+ } else
+ len = 0;
}
MGETHDR(m, M_DONTWAIT, MT_DATA);
@@ -1319,8 +1381,10 @@
memcpy(m->m_data, &frmhdr.an_whdr, sizeof(struct ieee80211_frame));
an_read_bap(sc, fid, -1, m->m_data + sizeof(struct ieee80211_frame),
len);
- m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame) + len;
+ m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame) + len;
m->m_pkthdr.rcvif = ifp;
+ m_adj(m, -(le16toh(frmhdr.an_gaplen) + sizeof(u_int16_t)));
+
CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
wh = mtod(m, struct ieee80211_frame *);
@@ -1649,7 +1713,7 @@
error = an_write_bap(sc, rid, sizeof(len), buf, buflen);
if (error)
return error;
-
+
return an_cmd(sc, AN_CMD_ACCESS | AN_ACCESS_WRITE, rid);
}
@@ -1705,3 +1769,20 @@
/* skip standard ieee80211 handling */
return 0;
}
+
+static void
+an_dump_pkt(struct an_rxframe *arf, struct ieee80211_node *ni)
+{
+ ieee80211_dump_pkt((u_int8_t *)&arf->an_whdr,
+ sizeof(struct ieee80211_frame), arf->an_rx_rate,
+ arf->an_rx_signal_strength);
+ printf(" time 0x%x status 0x%x plen %u chan %u"
+ " plcp %02x %02x %02x %02x gap %u\n",
+ le32toh(arf->an_rx_time), le16toh(arf->an_rx_status),
+ le16toh(arf->an_rx_payload_len), arf->an_rx_chan,
+ arf->an_plcp_hdr[0], arf->an_plcp_hdr[1],
+ arf->an_plcp_hdr[2], arf->an_plcp_hdr[3],
+ le16toh(arf->an_gaplen));
+
+ return;
+}
Index: anreg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/anreg.h,v
retrieving revision 1.10
diff -u -r1.10 anreg.h
--- anreg.h 28 Jan 2004 15:07:52 -0000 1.10
+++ anreg.h 31 Oct 2004 21:06:10 -0000
@@ -255,7 +255,7 @@
u_int8_t an_magic_packet_action; /* 0x98 */
u_int8_t an_magic_packet_ctl; /* 0x99 */
u_int16_t an_rsvd9;
- u_int16_t an_spare[16];
+ u_int16_t an_spare[24];
} __attribute__((__packed__));
#define AN_OPMODE_IBSS_ADHOC 0x0000
Index: anvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/anvar.h,v
retrieving revision 1.8
diff -u -r1.8 anvar.h
--- anvar.h 28 Jan 2004 15:07:52 -0000 1.8
+++ anvar.h 31 Oct 2004 21:06:10 -0000
@@ -74,10 +74,9 @@
struct an_softc {
struct device sc_dev;
struct ieee80211com sc_ic;
- bus_space_tag_t sc_iot;
- bus_space_handle_t sc_ioh;
int (*sc_enable)(struct an_softc *);
void (*sc_disable)(struct an_softc *);
+ int (*sc_reset)(struct an_softc *);
int (*sc_newstate)(struct ieee80211com *,
enum ieee80211_state, int);
@@ -85,6 +84,11 @@
int sc_invalid;
int sc_attached;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+
+ caddr_t sc_drvbpf;
+
int sc_bap_id;
int sc_bap_off;
--rJwd6BRFiFCcLxzm
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="diff-net80211.txt"
Index: ieee80211_ioctl.h
===================================================================
RCS file: /cvsroot/src/sys/net80211/ieee80211_ioctl.h,v
retrieving revision 1.7
diff -u -r1.7 ieee80211_ioctl.h
--- ieee80211_ioctl.h 30 Apr 2004 22:51:04 -0000 1.7
+++ ieee80211_ioctl.h 31 Oct 2004 21:07:23 -0000
@@ -203,6 +203,24 @@
#define SIOCG80211BSSID _IOWR('i', 241, struct ieee80211_bssid)
#define SIOCG80211STATS _IOWR('i', 242, struct ifreq)
+
+struct ieee80211req {
+ char i_name[IFNAMSIZ];
+ u_int32_t i_type;
+ union {
+ u_int16_t txpower;
+ } i_u;
+#define i_txpower i_u.txpower
+};
+
+#define SIOCS80211 _IOW('i', 243, struct ieee80211req)
+#define SIOCG80211 _IOWR('i', 244, struct ieee80211req)
+
+#define IEEE80211_TPCSET_MIN (u_int32_t)0)
+#define IEEE80211_TPCSET_MAX (~IEEE80211_TPCSET_MIN)
+
+#define IEEE80211_IOC_TXPOWER 14 /* preserving the numbers from fbsd above */
+
#endif
#endif /* _NET80211_IEEE80211_IOCTL_H_ */
--rJwd6BRFiFCcLxzm
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="diff-ifconfig.txt"
Index: ifconfig.c
===================================================================
RCS file: /cvsroot/src/sbin/ifconfig/ifconfig.c,v
retrieving revision 1.146
diff -u -r1.146 ifconfig.c
--- ifconfig.c 28 Oct 2004 20:10:29 -0000 1.146
+++ ifconfig.c 31 Oct 2004 21:08:54 -0000
@@ -169,6 +169,7 @@
void setifchan(const char *, int);
void setifpowersave(const char *, int);
void setifpowersavesleep(const char *, int);
+void setiftxpower(const char *, int); /* sdr */
void setifnetmask(const char *, int);
void setifprefixlen(const char *, int);
void setnsellength(const char *, int);
@@ -258,6 +259,7 @@
{ "powersave", 1, 0, setifpowersave },
{ "-powersave", 0, 0, setifpowersave },
{ "powersavesleep", NEXTARG, 0, setifpowersavesleep },
+ { "txpower", NEXTARG, 0, setiftxpower }, /*sdr*/
{ "broadcast", NEXTARG, 0, setifbroadaddr },
{ "ipdst", NEXTARG, 0, setifipdst },
{ "prefixlen", NEXTARG, 0, setifprefixlen},
@@ -1474,6 +1476,19 @@
}
void
+setiftxpower(const char *val, int d)
+{
+ struct ieee80211req i_req;
+
+ memset(&i_req, 0, sizeof(i_req));
+ (void)strncpy(i_req.i_name, name, sizeof(i_req.i_name));
+ i_req.i_type = IEEE80211_IOC_TXPOWER;
+ i_req.i_txpower = atoi(val);
+ if (ioctl(s, SIOCS80211, &i_req) == -1)
+ warn("SIOC80211");
+}
+
+void
ieee80211_status(void)
{
int i, nwkey_verbose;
@@ -1485,6 +1500,7 @@
struct ieee80211chanreq channel;
struct ether_addr ea;
static const u_int8_t zero_macaddr[IEEE80211_ADDR_LEN];
+ struct ieee80211req i_req;
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_data = (void *)&nwid;
@@ -1563,9 +1579,16 @@
printf("on (%dms sleep)", power.i_maxsleep);
else
printf("off");
- printf("\n");
skip_power:
+ memset(&i_req, 0, sizeof(i_req));
+ (void)strncpy(i_req.i_name, name, sizeof(i_req.i_name));
+ i_req.i_type = IEEE80211_IOC_TXPOWER;
+ if (ioctl(s, SIOCG80211, &i_req) == -1)
+ goto skip_txpower;
+ printf("\ttxpower %d mW\n", i_req.i_txpower);
+
+ skip_txpower:
(void)strncpy(bssid.i_name, name, sizeof(bssid.i_name));
if (ioctl(s, SIOCG80211BSSID, &bssid) == -1)
return;
--rJwd6BRFiFCcLxzm--