[[email protected]: Power Save Mode w/ FreeBSD HostAP]

Matt Peterson <[email protected]> Wed, 2 Apr 2003 16:58:47 -0800
Newsgroups gmane.network.wireless.bsd.general
Message-ID <[email protected]>
I've been using Kevin's latest patches (against FreeBSD 4-STABLE) with
good luck against an Intel Centrino STA.  If others could give these a
whirl, we can move forward with getting them committed ;)

Index: if_wavelan_ieee.h
===================================================================
RCS file: /home/ncvs/src/sys/dev/wi/if_wavelan_ieee.h,v
retrieving revision 1.12.2.2
diff -c -r1.12.2.2 if_wavelan_ieee.h
*** if_wavelan_ieee.h	2002/08/02 07:11:34	1.12.2.2
--- if_wavelan_ieee.h	2003/03/31 05:20:48
***************
*** 219,224 ****
--- 219,225 ----
  #define WI_RID_WEP_MAPTABLE	0xFC29
  #define WI_RID_CNFAUTHMODE	0xFC2A
  #define WI_RID_ROAMING_MODE	0xFC2D
+ #define WI_RID_SET_TIM		0xFC40
  #define WI_RID_CNF_DBM_ADJUST	0xFC46
  #define WI_RID_BASIC_RATE	0xFCB3
  #define WI_RID_SUPPORT_RATE	0xFCB4
Index: if_wi.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/wi/if_wi.c,v
retrieving revision 1.103.2.2
diff -c -r1.103.2.2 if_wi.c
*** if_wi.c	2002/08/02 07:11:34	1.103.2.2
--- if_wi.c	2003/03/31 05:20:53
***************
*** 695,701 ****
  		eh = mtod(m, struct ether_header *);
  		m->m_pkthdr.rcvif = ifp;
  
! 		if (rx_frame.wi_status == WI_STAT_MGMT &&
  		    sc->wi_ptype == WI_PORTTYPE_AP) {
  			if ((WI_802_11_OFFSET_RAW + rx_frame.wi_dat_len + 2) >
  			    MCLBYTES) {
--- 695,703 ----
  		eh = mtod(m, struct ether_header *);
  		m->m_pkthdr.rcvif = ifp;
  
! 		if ((rx_frame.wi_status == WI_STAT_MGMT ||
! 		     (rx_frame.wi_frame_ctl & htole16(WI_FCTL_FTYPE)) ==
! 		     htole16(WI_FTYPE_CTL)) &&
  		    sc->wi_ptype == WI_PORTTYPE_AP) {
  			if ((WI_802_11_OFFSET_RAW + rx_frame.wi_dat_len + 2) >
  			    MCLBYTES) {
***************
*** 1080,1085 ****
--- 1082,1101 ----
  	return;
  }
  
+ void
+ wi_set_tim(struct wi_softc *sc, u_int16_t aid, int which)
+ {
+ 	if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
+ 		printf("wi_set_tim: set TIM for 0x%x\n", aid);
+ 
+ 	aid &= ~0xc000;
+ 	if (which)
+ 		aid |= 0x8000;
+ 
+ 	WI_SETVAL(WI_RID_SET_TIM, aid);
+ }
+ 
+ 
  /*
   * Read an LTV record from the NIC.
   */
***************
*** 2248,2253 ****
--- 2264,2271 ----
  	struct ether_header	*eh;
  	int			id;
  	int			s;
+ 	int			power_save;
+ 	int			more;
  
  	sc = ifp->if_softc;
  	WI_LOCK(sc, s);
***************
*** 2263,2272 ****
  	}
  
  nextpkt:
! 	IF_DEQUEUE(&ifp->if_snd, m0);
  	if (m0 == NULL) {
! 		WI_UNLOCK(sc, s);
! 		return;
  	}
  
  	bzero((char *)&tx_frame, sizeof(tx_frame));
--- 2281,2298 ----
  	}
  
  nextpkt:
! 	IF_DEQUEUE(&sc->wi_pwrsaveq, m0);
  	if (m0 == NULL) {
! 		IF_DEQUEUE(&ifp->if_snd, m0);
! 		if (m0 == NULL) {
! 			WI_UNLOCK(sc, s);
! 			return;
! 		}
! 		power_save = 0;
! 		more = 0;
! 	} else {
! 		power_save = 1;
! 		more = 0;
  	}
  
  	bzero((char *)&tx_frame, sizeof(tx_frame));
***************
*** 2275,2288 ****
  	eh = mtod(m0, struct ether_header *);
  
  	if (sc->wi_ptype == WI_PORTTYPE_AP) {
! 		if (!wihap_check_tx(&sc->wi_hostap_info,
! 		    eh->ether_dhost, &tx_frame.wi_tx_rate)) {
  			if (ifp->if_flags & IFF_DEBUG)
! 				printf("wi_start: dropping unassoc "
! 				       "dst %6D\n", eh->ether_dhost, ":");
  			m_freem(m0);
  			goto nextpkt;
  		}
  	}
  	/*
  	 * Use RFC1042 encoding for IP and ARP datagrams,
--- 2301,2322 ----
  	eh = mtod(m0, struct ether_header *);
  
  	if (sc->wi_ptype == WI_PORTTYPE_AP) {
! 		if (!wihap_check_tx(&sc->wi_hostap_info, eh->ether_dhost, 
! 			 &tx_frame.wi_tx_rate)) {
  			if (ifp->if_flags & IFF_DEBUG)
! 				printf("wi_start: dropping unassoc dst %6D\n",
! 				    eh->ether_dhost, ":");
  			m_freem(m0);
  			goto nextpkt;
  		}
+ 		if (!wihap_check_ps_queue(sc, m0, power_save, &more)) {
+ 			if (ifp->if_flags & IFF_DEBUG)
+ 				printf("wi_start: deferred for powersaving on "
+ 				    "dst %6D\n", eh->ether_dhost, ":");
+ 			goto nextpkt;
+ 		}
+ 		if (more)
+ 			tx_frame.wi_frame_ctl |= WI_FCTL_MOREDATA;
  	}
  	/*
  	 * Use RFC1042 encoding for IP and ARP datagrams,
Index: if_wivar.h
===================================================================
RCS file: /home/ncvs/src/sys/dev/wi/if_wivar.h,v
retrieving revision 1.8.2.3
diff -c -r1.8.2.3 if_wivar.h
*** if_wivar.h	2002/08/02 07:11:34	1.8.2.3
--- if_wivar.h	2003/03/31 05:20:54
***************
*** 193,198 ****
--- 193,199 ----
  		u_int16_t               wi_confbits_param0;
  	} wi_debug;
  
+ 	struct ifqueue		wi_pwrsaveq;
  };
  
  struct wi_card_ident {
***************
*** 221,224 ****
--- 222,226 ----
  int wi_alloc(device_t, int);
  void wi_free(device_t);
  extern devclass_t wi_devclass;
+ void wi_set_tim(struct wi_softc *, u_int16_t, int);
  int wi_mgmt_xmit(struct wi_softc *, caddr_t, int);
Index: wi_hostap.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/wi/Attic/wi_hostap.c,v
retrieving revision 1.7.2.4
diff -c -r1.7.2.4 wi_hostap.c
*** wi_hostap.c	2002/08/02 07:11:34	1.7.2.4
--- wi_hostap.c	2003/03/31 05:20:56
***************
*** 302,308 ****
  	s = splnet();
  	sta = LIST_FIRST(&whi->sta_list);
  	while (sta) {
- 		untimeout(wihap_sta_timeout, sta, sta->tmo);
  		if (!sc->wi_gone) {
  			/* Disassociate station. */
  			if (sta->flags & WI_SIFLAGS_ASSOC)
--- 302,307 ----
***************
*** 318,324 ****
  		if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
  			printf("wihap_shutdown: FREE(sta=0x%x)\n", (int)sta);
  		next = LIST_NEXT(sta, list);
! 		FREE(sta, M_HAP_STA);
  		sta = next;
  	}
  
--- 317,323 ----
  		if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
  			printf("wihap_shutdown: FREE(sta=0x%x)\n", (int)sta);
  		next = LIST_NEXT(sta, list);
! 		wihap_sta_delete(sta);
  		sta = next;
  	}
  
***************
*** 358,366 ****
  			    sta->addr, ":");
  
  		/* Disassoc station. */
! 		wihap_sta_disassoc(sc, sta->addr,
! 		    IEEE80211_REASON_ASSOC_EXPIRE);
! 		sta->flags &= ~WI_SIFLAGS_ASSOC;
  
  		sta->tmo = timeout(wihap_sta_timeout, sta,
  		    hz * whi->inactivity_time);
--- 357,381 ----
  			    sta->addr, ":");
  
  		/* Disassoc station. */
! 		if (sta->flags & WI_SIFLAGS_PS) {
! 			/* 
! 			 * If in powersave mode, delay sending the mgmt
! 			 * message.  This should be the only kind of mgmt
! 			 * message that can go to an associated station
! 			 * in powersave mode.  A deauthentication message
! 			 * is also possible, but since that is usually
! 			 * followed by the deletion of the station 
! 			 * information, buffering the message wouldn't
! 			 * do us any good.
! 			 */
! 			wi_set_tim(sc, sta->asid, 1);
! 			sta->flags |= WI_SIFLAGS_DEASSOC;
! 			sta->reason = IEEE80211_REASON_ASSOC_EXPIRE;
! 		} else {
! 			wihap_sta_disassoc(sc, sta->addr,
! 					   IEEE80211_REASON_ASSOC_EXPIRE);
! 			sta->flags &= ~WI_SIFLAGS_ASSOC;
! 		}
  
  		sta->tmo = timeout(wihap_sta_timeout, sta,
  		    hz * whi->inactivity_time);
***************
*** 400,405 ****
--- 415,425 ----
  	LIST_REMOVE(sta, hash);
  	if (sta->challenge)
  		FREE(sta->challenge, M_TEMP);
+ 	if (!IF_IS_EMPTY(&sta->savedq)) {
+ 		IF_PURGE(&sta->savedq);
+ 		wi_set_tim(sc, sta->asid, 0);
+ 	}
+ 
  	FREE(sta, M_HAP_STA);
  	whi->n_stations--;
  }
***************
*** 424,433 ****
  
  	bzero(sta, sizeof(struct wihap_sta_info));
  
! 	/* Allocate an ASID. */
! 	i=hash<<4;
! 	while (whi->asid_inuse_mask[i >> 4] & (1UL << (i & 0xf)))
  		i = (i == (WI_STA_HASH_SIZE << 4) - 1) ? 0 : (i + 1);
  	whi->asid_inuse_mask[i >> 4] |= (1UL << (i & 0xf));
  	sta->asid = 0xc001 + i;
  
--- 444,467 ----
  
  	bzero(sta, sizeof(struct wihap_sta_info));
  
! 	/* 
! 	 * Allocate an ASID.  This originally had a clever algorithm to
! 	 * come up with ASIDs that were related to the hash value of
! 	 * the station.  Alas, for power saving mode, we have to use
! 	 * ASIDs that are less than 254 -- the PRISM2 firmware (I've tested
! 	 * this up to 1.4.9) doesn't allow us to report any larger ASIDs
! 	 * in the TIM.  Bummer.  In any case, we'd like to cluster the
! 	 * ASIDs together to reduce the size of the TIM, anyway.
! 	 */
! 	i=0;
! 	while (whi->asid_inuse_mask[i >> 4] & (1UL << (i & 0xf)) && 
! 	       i < WIHAP_MAX_STATIONS)
  		i = (i == (WI_STA_HASH_SIZE << 4) - 1) ? 0 : (i + 1);
+ 	if (i >= WIHAP_MAX_STATIONS) {
+ 		FREE(sta, M_HAP_STA);
+ 		return(NULL);
+ 	}
+ 
  	whi->asid_inuse_mask[i >> 4] |= (1UL << (i & 0xf));
  	sta->asid = 0xc001 + i;
  
***************
*** 460,465 ****
--- 494,546 ----
  	return (NULL);
  }
  
+ /* wihap_check_ps()
+  *
+  * Check to see if this station is going into or coming out of
+  * powersave mode.
+  */
+ static void
+ wihap_check_ps(struct wi_softc *sc, struct wi_frame *rxfrm, 
+     struct wihap_sta_info *sta)
+ {
+ 	struct ifnet		*ifp = &sc->arpcom.ac_if;
+ 
+ 	if (!sta) {
+ 		sta = wihap_sta_find(&sc->wi_hostap_info, rxfrm->wi_addr2);
+ 		if (!sta)
+ 			return;
+ 	}
+ 
+ 	if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_PM)) && 
+ 	    (sta->flags & WI_SIFLAGS_PS) == 0) {
+ 		/* turn on powersave mode */
+ 		sta->flags |= WI_SIFLAGS_PS;
+ 
+ 		if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
+ 			printf("wihap_check_ps: Station %6D going into "
+ 			    "powersaving mode\n", rxfrm->wi_addr2, ":");
+ 
+ 	} else if (!(rxfrm->wi_frame_ctl & htole16(WI_FCTL_PM)) && 
+ 		   (sta->flags & WI_SIFLAGS_PS) == WI_SIFLAGS_PS) {
+ 		struct mbuf *m;
+ 
+ 		/* turn off powersave mode */
+ 		sta->flags &= ~WI_SIFLAGS_PS;
+ 
+ 		if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
+ 			printf("wihap_check_ps: Station %6D leaving "
+ 			    "powersaving mode\n", rxfrm->wi_addr2, ":");
+ 
+ 		wi_set_tim(sc, sta->asid, 0);
+ 		IF_DEQUEUE(&sta->savedq, m);
+ 		while (m != NULL) {
+ 			IF_ENQUEUE(&ifp->if_snd, m);
+ 			(ifp->if_start)(ifp);
+ 			IF_DEQUEUE(&sta->savedq, m);
+ 		}
+ 	}
+ }
+ 
  static int
  wihap_check_rates(struct wihap_sta_info *sta, u_int8_t rates[], int rates_len)
  {
***************
*** 777,783 ****
  
  fail:
  	if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
! 		printf("wihap_assoc_req: returns status=0x%x\n", status);
  
  	/* Send response. */
  	resp_hdr = (struct wi_80211_hdr *) sc->wi_txbuf;
--- 858,865 ----
  
  fail:
  	if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
! 		printf("wihap_assoc_req: returns status=0x%x, asid 0x%x\n", 
! 		    status, asid);
  
  	/* Send response. */
  	resp_hdr = (struct wi_80211_hdr *) sc->wi_txbuf;
***************
*** 863,868 ****
--- 945,1051 ----
  		sta->flags &= ~WI_SIFLAGS_ASSOC;
  }
  
+ /* wihap_pspoll()
+  *
+  *	Handle power save polls.  Determine if the station has
+  *      any packets queued up for transmission, and send the
+  *	first.  If there are no packets left, clear the TIM bit
+  *	for the station.
+  */
+ static void
+ wihap_pspoll(struct wi_softc *sc, struct wi_frame *rxfrm,
+     caddr_t pkt, int len)
+ {
+ 	struct ifnet		*ifp = &sc->arpcom.ac_if;
+ 	struct wihap_info	*whi = &sc->wi_hostap_info;
+ 	struct wihap_sta_info	*sta;
+ 	struct mbuf		*m;
+ 	u_int16_t		asid;
+ 
+ 	asid = le16toh(rxfrm->wi_id);
+ 
+ 	sta = wihap_sta_find(whi, rxfrm->wi_addr2);
+ 	if (sta == NULL) {
+ 		if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
+ 			printf("wihap_pspoll: unknown station: %6D\n",
+ 			    rxfrm->wi_addr2, ":");
+ 		return;
+ 	}
+ 	if (!(sta->flags & WI_SIFLAGS_AUTHEN)) {
+ 		/*
+ 		 * If station is not authenticated, send deauthentication
+ 		 * frame.
+ 		 */
+ 		wihap_sta_deauth(sc, rxfrm->wi_addr2,
+ 		    IEEE80211_REASON_NOT_AUTHED);
+ 		return;
+ 	}
+ 	if (asid != sta->asid) {
+ 		if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
+ 			printf("wihap_pspoll: station %6D asid %d doesn't "
+ 			       "match asid %d\n", 
+ 			       rxfrm->wi_addr2, ":", sta->asid, asid);
+ 		return;
+ 	}
+ 
+ 	if (sta->flags & WI_SIFLAGS_DEASSOC) {
+ 		wihap_sta_disassoc(sc, sta->addr,
+ 				   sta->reason);
+ 		sta->flags &= ~WI_SIFLAGS_ASSOC;
+ 		sta->flags &= ~WI_SIFLAGS_DEASSOC;
+ 		if (IF_IS_EMPTY(&sta->savedq)) {
+ 			wi_set_tim(sc, sta->asid, 0);
+ 		}
+ 	}
+ 
+ 	IF_DEQUEUE(&sta->savedq, m);
+ 	if (m == NULL) {
+ 		if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
+ 			printf("station %6D sent pspoll, but no packets are "
+ 			       "saved\n", rxfrm->wi_addr2, ":");
+ 		return;
+ 	}
+ 
+ 	/* If this is the last packet, turn off the TIM fields. */
+ 	if (IF_IS_EMPTY(&sta->savedq)) {
+ 		wi_set_tim(sc, sta->asid, 0);
+ 	}
+ 
+ 	if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
+ 		printf("wihap_pspoll:  sending saved packet for station %6D\n",
+ 		    sta->addr, ":");
+ 	
+ 	IF_ENQUEUE(&sc->wi_pwrsaveq, m);
+ 	(ifp->if_start)(ifp);
+ }
+ 
+ 
+ 
+ /* wihap_pwrsave()
+  * 
+  *	Handle packets that need to be saved for this station.
+  *      Set the TIM bit to ensure that they will be picked up
+  *      eventually.
+  */
+ static void
+ wihap_pwrsave(struct wi_softc *sc, struct wihap_sta_info *sta, struct mbuf *m)
+ {
+ 	if (IF_IS_EMPTY(&sta->savedq)) {
+ 		wi_set_tim(sc, sta->asid, 1);
+ 	}
+ 	if (sta->savedq.ifq_len >= WIHAP_PS_BUFFER) {
+ 		IF_DROP(&sta->savedq);
+ 		m_freem(m);
+ 		if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
+ 			printf("wihap_pspoll:  station %6Ds power save queue "
+ 			       "overflow of size %d drops %d\n",
+ 			       sta->addr, ":", WIHAP_PS_BUFFER,
+ 			       sta->savedq.ifq_drops);
+ 	} else {
+ 		IF_ENQUEUE(&sta->savedq, m);
+ 	}
+ }
+ 
  /* wihap_debug_frame_type()
   *
   * Print out frame type.  Used in early debugging.
***************
*** 941,946 ****
--- 1124,1132 ----
  	pkt = mtod(m, caddr_t) + WI_802_11_OFFSET_RAW;
  	len = m->m_len - WI_802_11_OFFSET_RAW;
  
+ 	/* XXX: can the powersaving bit be set on a MGMT frame!? */
+ 	wihap_check_ps(sc, rxfrm, NULL);
+ 
  	if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_FTYPE)) ==
  	    htole16(WI_FTYPE_MGMT)) {
  
***************
*** 976,983 ****
  			break;
  		}
  		splx(s);
  	}
- 
  	m_freem(m);
  }
  
--- 1162,1175 ----
  			break;
  		}
  		splx(s);
+ 	} else if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_FTYPE)) ==
+ 		    htole16(WI_FTYPE_CTL) &&
+ 		   (rxfrm->wi_frame_ctl & htole16(WI_FCTL_STYPE)) ==
+ 		   htole16(WI_STYPE_CTL_PSPOLL)) {
+ 		s = splnet();
+ 		wihap_pspoll(sc, rxfrm, pkt, len);
+ 		splx(s);
  	}
  	m_freem(m);
  }
  
***************
*** 1009,1015 ****
  /* wihap_check_tx()
   *
   *	Determine if a station is assoc'ed, get its tx rate, and update
!  *	its activity.
   */
  int
  wihap_check_tx(struct wihap_info *whi, u_int8_t addr[], u_int8_t *txrate)
--- 1201,1214 ----
  /* wihap_check_tx()
   *
   *	Determine if a station is assoc'ed, get its tx rate, and update
!  *	its activity.  Check to see if the station is in power saving mode,
!  *      in which case we need to buffer the packet rather than sending it.
!  *	If this is a packet being sent in responce to a power-save poll,
!  *      see if there are more packets buffered for this station.
!  *
!  *	XXX:  There are a ridiculous number of arguments to this function;
!  *      it just seemed inefficient to do a second station lookup in another
!  *      function to check power saving.
   */
  int
  wihap_check_tx(struct wihap_info *whi, u_int8_t addr[], u_int8_t *txrate)
***************
*** 1034,1043 ****
  		return(1);
  	}
  	splx(s);
- 
  	return(0);
  }
  
  /*
   * wihap_data_input()
   *
--- 1233,1266 ----
  		return(1);
  	}
  	splx(s);
  	return(0);
  }
  
+ int
+ wihap_check_ps_queue(struct wi_softc *sc, struct mbuf *m, int power_save, 
+     int *more)
+ {
+ 	struct wihap_info *whi = &sc->wi_hostap_info;
+ 	struct wihap_sta_info *sta;
+ 	struct ether_header *eh = mtod(m, struct ether_header *);
+ 	int s;
+ 
+ 	s = splnet();
+ 	sta = wihap_sta_find(whi, eh->ether_dhost);
+ 	if (sta == NULL)
+ 		return 1;
+ 
+ 	if (!power_save && (sta->flags & WI_SIFLAGS_PS)) {
+ 		wihap_pwrsave(sc, sta, m);
+ 		splx(s);
+ 		return 0;
+ 	} else if (power_save && !IF_IS_EMPTY(&sta->savedq)) {
+ 		*more = 1;  /* set "More Data" bit on packet */
+ 	}
+ 	return 1;
+ }
+ 			
+ 
  /*
   * wihap_data_input()
   *
***************
*** 1096,1101 ****
--- 1319,1327 ----
  	    hz * whi->inactivity_time);
  	sta->sig_info = le16toh(rxfrm->wi_q_info);
  
+ 	/* Check to see if we should go into powersaving mode */
+ 	wihap_check_ps(sc, rxfrm, sta);
+ 
  	splx(s);
  
  	/* Repeat this packet to BSS? */
***************
*** 1208,1214 ****
  		sta = wihap_sta_alloc(sc, reqsta.addr);
  		sta->flags = reqsta.flags;
  		sta->tmo = timeout(wihap_sta_timeout, sta,
! 		    hz * whi->inactivity_time);
  		splx(s);
  		break;
  
--- 1434,1440 ----
  		sta = wihap_sta_alloc(sc, reqsta.addr);
  		sta->flags = reqsta.flags;
  		sta->tmo = timeout(wihap_sta_timeout, sta,
! 				   hz * whi->inactivity_time);
  		splx(s);
  		break;
  
Index: wi_hostap.h
===================================================================
RCS file: /home/ncvs/src/sys/dev/wi/Attic/wi_hostap.h,v
retrieving revision 1.3.2.3
diff -c -r1.3.2.3 wi_hostap.h
*** wi_hostap.h	2002/08/02 07:11:34	1.3.2.3
--- wi_hostap.h	2003/03/31 05:20:56
***************
*** 35,41 ****
  #ifndef __WI_HOSTAP_H__
  #define __WI_HOSTAP_H__
  
! #define WIHAP_MAX_STATIONS	1800
  
  struct hostap_sta {
  	u_int8_t	addr[6];
--- 35,41 ----
  #ifndef __WI_HOSTAP_H__
  #define __WI_HOSTAP_H__
  
! #define WIHAP_MAX_STATIONS	254
  
  struct hostap_sta {
  	u_int8_t	addr[6];
***************
*** 49,55 ****
  #define HOSTAP_FLAGS_AUTHEN	0x0001
  #define HOSTAP_FLAGS_ASSOC	0x0002
  #define HOSTAP_FLAGS_PERM	0x0004
! #define	HOSTAP_FLAGS_BITS	"\20\01ASSOC\02AUTH\03PERM"
  
  #define SIOCHOSTAP_GET 		_IOWR('i', 210, struct ifreq)
  #define SIOCHOSTAP_ADD 		_IOWR('i', 211, struct ifreq)
--- 49,57 ----
  #define HOSTAP_FLAGS_AUTHEN	0x0001
  #define HOSTAP_FLAGS_ASSOC	0x0002
  #define HOSTAP_FLAGS_PERM	0x0004
! #define HOSTAP_FLAGS_PS		0x0008
! #define HOSTAP_FLAGS_DEASSOC	0x0010
! #define	HOSTAP_FLAGS_BITS	"\33\01ASSOC\02AUTH\03PERM\04PS\05DEASSOC"
  
  #define SIOCHOSTAP_GET 		_IOWR('i', 210, struct ifreq)
  #define SIOCHOSTAP_ADD 		_IOWR('i', 211, struct ifreq)
***************
*** 91,103 ****
  	u_int8_t	tx_max_rate;
  	u_int32_t	*challenge;
  	struct callout_handle	tmo;
  };
  
  #define WI_SIFLAGS_ASSOC	HOSTAP_FLAGS_ASSOC
  #define WI_SIFLAGS_AUTHEN	HOSTAP_FLAGS_AUTHEN
  #define WI_SIFLAGS_PERM		HOSTAP_FLAGS_PERM
  
! #define WI_STA_HASH_SIZE	113
  
  #if WI_STA_HASH_SIZE*16 >= 2007 /* will generate ASID's too large. */
  #error "WI_STA_HASH_SIZE too big"
--- 93,110 ----
  	u_int8_t	tx_max_rate;
  	u_int32_t	*challenge;
  	struct callout_handle	tmo;
+ 
+ 	u_int16_t	reason;
+ 	struct ifqueue	savedq;
  };
  
  #define WI_SIFLAGS_ASSOC	HOSTAP_FLAGS_ASSOC
  #define WI_SIFLAGS_AUTHEN	HOSTAP_FLAGS_AUTHEN
  #define WI_SIFLAGS_PERM		HOSTAP_FLAGS_PERM
+ #define WI_SIFLAGS_PS		HOSTAP_FLAGS_PS
+ #define WI_SIFLAGS_DEASSOC	HOSTAP_FLAGS_DEASSOC
  
! #define WI_STA_HASH_SIZE	17
  
  #if WI_STA_HASH_SIZE*16 >= 2007 /* will generate ASID's too large. */
  #error "WI_STA_HASH_SIZE too big"
***************
*** 120,125 ****
--- 127,133 ----
  
  #define WIHAP_INTERVAL			5
  #define WIHAP_DFLT_INACTIVITY_TIME	120	/* 2 minutes */
+ #define WIHAP_PS_BUFFER			50
  
  struct wi_softc;
  struct wi_frame;
***************
*** 128,136 ****
--- 136,165 ----
  void wihap_mgmt_input(struct wi_softc *, struct wi_frame *, struct mbuf *);
  int  wihap_data_input(struct wi_softc *, struct wi_frame *, struct mbuf *);
  int  wihap_check_tx(struct wihap_info *, u_int8_t [], u_int8_t *);
+ int  wihap_check_ps_queue(struct wi_softc *, struct mbuf *, int, int *);
  void wihap_init(struct wi_softc *);
  void wihap_shutdown(struct wi_softc *);
  int  wihap_ioctl(struct wi_softc *, u_long, caddr_t);
+ 
+ /* 
+  * KML:  I used these functions from NetBSD in the interests of getting
+  *       this done, pronto.  I'll clean it up later...
+  */
+ 
+ #define IF_PURGE(ifq)                                                   \
+ do {                                                                    \
+         struct mbuf *__m0;                                              \
+                                                                         \
+         for (;;) {                                                      \
+                 IF_DEQUEUE((ifq), __m0);                                \
+                 if (__m0 == NULL)                                       \
+                         break;                                          \
+                 else                                                    \
+                         m_freem(__m0);                                  \
+         }                                                               \
+ } while (/*CONSTCOND*/ 0)
+ #define IF_IS_EMPTY(ifq)        ((ifq)->ifq_len == 0)
+ 
  
  #endif /* _KERNEL */
  #endif /* __WI_HOSTAP_H__ */


----- End forwarded message -----

-- 
Matt Peterson         another.geek.without.a.life
[email protected]       http://matt.peterson.org/
-------------------------------------------------
--
*bsd wireless list, a bawug thing <http://www.bawug.org/>
[un]subscribe: http://lists.bawug.org/mailman/listinfo/bsd-wireless/