(void)take_tlv(&pkt, &len, IEEE80211_ELEMID_VENDOR, challenge, sizeof(challenge));
wihap_auth_req(struct wi_softc *sc, struct wi_frame *rxfrm,    caddr_t pkt, int len){	struct wihap_info	*whi = &sc->wi_hostap_info;	struct wihap_sta_info	*sta;	int			i, s;	u_int16_t		algo;	u_int16_t		seq;	u_int16_t		status;	int			challenge_len;	u_int32_t		challenge[32];	struct wi_80211_hdr	*resp_hdr;	if (len < 6) {		if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)			printf("wihap_auth_req: station %s short request\n",			    ether_sprintf(rxfrm->wi_addr2));		return;	}	/* Break open packet. */	algo = take_hword(&pkt, &len);	seq = take_hword(&pkt, &len);	status = take_hword(&pkt, &len);	if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)		printf("wihap_auth_req: station %s algo=0x%x seq=0x%x\n",		    ether_sprintf(rxfrm->wi_addr2), algo, seq);	challenge_len = 0;	if (len > 0 && (challenge_len = take_tlv(&pkt, &len,	    IEEE80211_ELEMID_CHALLENGE, challenge, sizeof(challenge))) < 0) {		status = IEEE80211_STATUS_CHALLENGE;		goto fail;	}	/* Find or create station info. */	sta = wihap_sta_find(whi, rxfrm->wi_addr2);	if (sta == NULL) {		/* Are we allowing new stations?		 */		if (whi->apflags & WIHAPFL_MAC_FILT) {			status = IEEE80211_STATUS_OTHER; /* XXX */			goto fail;		}		/* Check for too many stations.		 */		if (whi->n_stations >= WIHAP_MAX_STATIONS) {			status = IEEE80211_STATUS_TOOMANY;			goto fail;		}		if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)			printf("wihap_auth_req: new station\n");		/* Create new station. */		s = splimp();		sta = wihap_sta_alloc(sc, rxfrm->wi_addr2);		splx(s);		if (sta == NULL) {			/* Out of memory! */			status = IEEE80211_STATUS_TOOMANY;			goto fail;		}	}	timeout_add(&sta->tmo, hz * whi->inactivity_time);	/* Note: it's okay to leave the station info structure around	 * if the authen fails.  It'll be timed out eventually.	 */	switch (algo) {	case IEEE80211_AUTH_ALG_OPEN:		if (sc->wi_authtype != IEEE80211_AUTH_OPEN) {			status = IEEE80211_STATUS_ALG;			goto fail;		}		if (seq != 1) {			status = IEEE80211_STATUS_SEQUENCE;			goto fail;		}		challenge_len = 0;		sta->flags |= WI_SIFLAGS_AUTHEN;		break;	case IEEE80211_AUTH_ALG_SHARED:		if (sc->wi_authtype != IEEE80211_AUTH_SHARED) {			status = IEEE80211_STATUS_ALG;			goto fail;		}		switch (seq) {		case 1:			/* Create a challenge frame. */			if (!sta->challenge) {				MALLOC(sta->challenge, u_int32_t *, 128,				       M_TEMP, M_NOWAIT);				if (!sta->challenge)					return;			}			for (i = 0; i < 32; i++)				challenge[i] = sta->challenge[i] =					arc4random();						if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)				printf("\tchallenge: 0x%x 0x%x ...\n",				   challenge[0], challenge[1]);			challenge_len = 128;			break;		case 3:			if (challenge_len != 128 || !sta->challenge ||			    !(letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_WEP)) {				status = IEEE80211_STATUS_CHALLENGE;				goto fail;			}			for (i=0; i<32; i++)				if (sta->challenge[i] != challenge[i]) {					status = IEEE80211_STATUS_CHALLENGE;					goto fail;				}			sta->flags |= WI_SIFLAGS_AUTHEN;			FREE(sta->challenge, M_TEMP);			sta->challenge = NULL;			challenge_len = 0;			break;		default:			status = IEEE80211_STATUS_SEQUENCE;			goto fail;		} /* switch (seq) */		break;	default:		if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)			printf("wihap_auth_req: algorithm unsupported: 0x%x\n",			   algo);		status = IEEE80211_STATUS_ALG;		goto fail;	} /* switch (algo) */	status = IEEE80211_STATUS_SUCCESS;fail:	if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)		printf("wihap_auth_req: returns status=0x%x\n", status);	/* Send response. */	resp_hdr = (struct wi_80211_hdr *)&sc->wi_txbuf;	bzero(resp_hdr, sizeof(struct wi_80211_hdr));	resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_AUTH);	bcopy(rxfrm->wi_addr2, resp_hdr->addr1, ETHER_ADDR_LEN);	bcopy(sc->sc_arpcom.ac_enaddr, resp_hdr->addr2, ETHER_ADDR_LEN);	bcopy(sc->sc_arpcom.ac_enaddr, resp_hdr->addr3, ETHER_ADDR_LEN);	pkt = (caddr_t)&sc->wi_txbuf + sizeof(struct wi_80211_hdr);	put_hword(&pkt, algo);	put_hword(&pkt, seq + 1);	put_hword(&pkt, status);	if (challenge_len > 0)		put_tlv(&pkt, IEEE80211_ELEMID_CHALLENGE,			challenge, challenge_len);	wi_mgmt_xmit(sc, (caddr_t)&sc->wi_txbuf,	    6 + sizeof(struct wi_80211_hdr) +	    (challenge_len > 0 ? challenge_len + 2 : 0));}