Subject: 802.11 Transmit power control
To: None <tech-net@netbsd.org>
From: Dheeraj Reddy <dheeraj@ece.gatech.edu>
List: tech-net
Date: 10/31/2004 13:21:07
--WIyZ46R2i8wDzkSu
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Hello all,
I am attaching essentially barebones of the transmit power control API
(David Young's email to the list in Feb of last year) and a simple
implementation for that on the aironet driver. This includes the patch
I sent yesterday to just get the aironet card working (currently it is
broken in current and in 2.0)
Can someone please comment ? suggestions/brickbats
truely
dheeraj
--
It is better to be silent and be thought a fool than to speak and remove
all doubt
--WIyZ46R2i8wDzkSu
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 18:13:23 -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 *, struct ieee80211_tpc *);
+static int an_get_txpower(struct an_softc *, struct ieee80211_tpc *);
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);
@@ -821,6 +835,12 @@
case SIOCG80211NWKEY:
error = an_get_nwkey(sc, (struct ieee80211_nwkey *)data);
break;
+ case SIOCG80211TPC:
+ error = an_get_txpower(sc, (struct ieee80211_tpc*)data);
+ break;
+ case SIOCS80211TPC:
+ error = an_set_txpower(sc, (struct ieee80211_tpc*)data);
+ break;
default:
error = ieee80211_ioctl(ifp, command, data);
break;
@@ -1213,6 +1233,45 @@
return error;
}
+static int
+an_set_txpower(struct an_softc *sc, struct ieee80211_tpc* power)
+{
+ int i;
+ struct an_rid_genconfig* arg;
+ u_int16_t currval = 0;
+ int error = 0;
+ struct ifnet *ifp = &sc->sc_ic.ic_if;
+
+ arg = &sc->sc_config;
+
+ for(i=0; i< 8; i++)
+ if (power->i_set == sc->sc_caps.an_tx_powerlevels[i]) {
+ currval = arg->an_tx_power;
+ arg->an_tx_power= power->i_set;
+ 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) {
+ printf("an_set_txpower:: error = %d\n", error);
+ arg->an_tx_power = currval;
+ }
+ return error;
+}
+
+static int
+an_get_txpower(struct an_softc *sc, struct ieee80211_tpc* power)
+{
+ int buflen;
+
+ buflen = sizeof(sc->sc_config);
+ an_read_rid(sc, AN_RID_GENCONFIG, &sc->sc_config, &buflen);
+ power->i_set= sc->sc_config.an_tx_power;
+ return 0;
+}
/*
* Low level functions
@@ -1240,20 +1299,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 +1311,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 +1325,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 +1371,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 +1703,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 +1759,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 18:13:24 -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 18:13:24 -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;
--WIyZ46R2i8wDzkSu
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 18:01:52 -0000
@@ -203,6 +203,31 @@
#define SIOCG80211BSSID _IOWR('i', 241, struct ieee80211_bssid)
#define SIOCG80211STATS _IOWR('i', 242, struct ifreq)
+
+struct ieee80211_tpc {
+ char i_name[IFNAMSIZ];
+ u_int32_t i_flags;
+ u_int32_t i_set;
+ union {
+ int32_t db;
+ int32_t mw;
+ } i_hint;
+};
+
+#define IEEE80211_TPC_HINT_DB 0x01
+#define IEEE80211_TPC_HINT_MW 0x02
+#define IEEE80211_TPC_CONVERT 0x04
+#define IEEE80211_TPC_CALIBRATE IEEE80211_TPC_CONVERT
+#define IEEE80211_TPC_ROUNDUP 0x08
+#define IEEE80211_TPC_ROUNDDOWN 0x10
+
+#define IEEE80211_TPCSET_MIN (u_int32_t)0)
+#define IEEE80211_TPCSET_MAX (~IEEE80211_TPCSET_MIN)
+
+#define SIOCS80211TPC _IOW('i', 243, struct ieee80211_tpc)
+#define SIOCG80211TPC _IOWR('i', 244, struct ieee80211_tpc)
+
+
#endif
#endif /* _NET80211_IEEE80211_IOCTL_H_ */
--WIyZ46R2i8wDzkSu
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 18:03:00 -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,18 @@
}
void
+setiftxpower(const char *val, int d)
+{
+ struct ieee80211_tpc tpc;
+
+ memset(&tpc, 0, sizeof(tpc));
+ (void)strncpy(tpc.i_name, name, sizeof(tpc.i_name));
+ tpc.i_set=atoi(val);
+ if (ioctl(s, SIOCS80211TPC, &tpc) == -1)
+ warn("SIOC80211TPC");
+}
+
+void
ieee80211_status(void)
{
int i, nwkey_verbose;
@@ -1485,6 +1499,8 @@
struct ieee80211chanreq channel;
struct ether_addr ea;
static const u_int8_t zero_macaddr[IEEE80211_ADDR_LEN];
+ struct ieee80211_tpc txpower;
+ u_int32_t lflags;
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_data = (void *)&nwid;
@@ -1563,9 +1579,17 @@
printf("on (%dms sleep)", power.i_maxsleep);
else
printf("off");
- printf("\n");
skip_power:
+ memset(&txpower, 0, sizeof(txpower));
+ (void)strncpy(txpower.i_name, name, sizeof(txpower.i_name));
+ if (ioctl(s, SIOCG80211TPC, &txpower) == -1)
+ goto skip_txpower;
+ printf("\t txpower ");
+ lflags = txpower.i_flags;
+ printf("%x \n", txpower.i_set);
+
+ skip_txpower:
(void)strncpy(bssid.i_name, name, sizeof(bssid.i_name));
if (ioctl(s, SIOCG80211BSSID, &bssid) == -1)
return;
--WIyZ46R2i8wDzkSu--