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--