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