/*
 * WPA Supplicant - driver interaction with WRT54g driver
 * Copyright (c) 2004, Nikki Chumkov <nikki@gattaca.ru>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * Alternatively, this software may be distributed under the terms of BSD
 * license.
 *
 * See README and COPYING for more details.
 */


#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <sys/socket.h>
//#include <netpacket/packet.h>
//#include <net/ethernet.h>     /* the L2 protocols */
#include <linux/if_packet.h>
#include <linux/if_ether.h>   /* The L2 protocols */
#include <netinet/in.h>

#include <net/if.h>
#include <typedefs.h>
#include <wlioctl.h>
// #include <proto/ethernet.h>

#include "common.h"
#include "driver.h"
#include "eloop.h"
#include "wpa_supplicant.h"
// #include "hostap_common.h"
#include "wpa.h"
#include "config.h"

#define WL_DEBUG 0
/* wireless authentication bit vector */
#define WPA_ENABLED	1
#define PSK_ENABLED	2

#define WAUTH_WPA_ENABLED(wauth)	((wauth) & WPA_ENABLED)
#define WAUTH_PSK_ENABLED(wauth)	((wauth) & PSK_ENABLED)
#define WAUTH_ENABLED(wauth)		((wauth) & (WPA_ENABLED | PSK_ENABLED))

#if WL_DEBUG
#include "l2_packet.h"
#endif
static int
wrt54g_ioctl(const char *name, int cmd, void *buf, int len)
{
  struct ifreq ifr;
  wl_ioctl_t ioc;
  int ret = 0;
  int s;
                                                                                
#if WL_DEBUG
char* ss;
wlc_ssid_t* ssid;
wl_wsec_key_t* key;
uint8 keya[164];
                                                                                
fprintf (stderr, "wlioctl(%s,%d,len=%d,val=%p) ", name, cmd, len, buf);
                                                                                
switch (len)
{
  case 4: /* int */
    s = *(int*)buf;
    fprintf(stderr, "val=%d (%x) ", s, s);
    break;
  case 36:
    ssid = (wlc_ssid_t*) buf;
    fprintf (stderr, "val='%.*s' ", ssid->SSID_len, ssid->SSID);
    break;
                                                                                
  case 6:
    ss = (char*) buf;
    fprintf (stderr, "val=[%.2x%.2x%.2x%.2x%.2x%.2x] ",
                            (int)ss[0], (int)ss[1], (int)ss[2],
                            (int)ss[3], (int)ss[4], (int)ss[5]);
    break;
                                                                                
  case sizeof(wl_wsec_key_t):
    key = (wl_wsec_key_t*)buf;
#if 0
    keya = (uint8*)buf;
    for (s=0;s<164;++s)
      fprintf (stderr, "%4.4x ", keya[s]);
    fprintf(stderr,"\n");
#else
    fprintf (stderr, "idx=%dlen=%d,algo=%d,flags=%d,algo_hw=%d,aesmode=%d,"
        "ivlen=%d,ivi=%d,icvlen=%d"
        "key=[%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x] "
        ,
        key->index , key->len, key->algo,key->flags,key->algo_hw,key->aes_mode
,       key->iv_len, key->iv_initialized, key->icv_len
,       key->data[0],key->data[1],key->data[2],key->data[3],
        key->data[4],key->data[5],key->data[6],key->data[7],
        key->data[8],key->data[9],key->data[10],key->data[11]
        );
#endif
    break;
                                                                                
}
#endif
                                                                                
  /* open socket to kernel */
  if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    perror("socket");
    return errno;
  }
  /* do it */
  ioc.cmd = cmd;
  ioc.buf = buf;
  ioc.len = len;
  strncpy(ifr.ifr_name, name, IFNAMSIZ);
  ifr.ifr_data = (caddr_t) &ioc;
  if ((ret = ioctl(s, SIOCDEVPRIVATE, &ifr)) < 0)
    if (cmd != WLC_GET_MAGIC)
      perror(ifr.ifr_name);
                                                                                
  /* cleanup */
  close(s);
#if WL_DEBUG
fprintf (stderr, "= %d\n", ret);
#endif
  return ret;
}

int wpa_driver_wrt54g_get_own_addr(const char *ifname, char *own_addr)
{
  struct ifreq ifr;
  struct sockaddr_ll ll;
  int s;
                                                                                
	memset (own_addr, 0, 6);

  /* open socket to kernel */
  if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    perror("socket");
    return -1;
  }
  /* do it */
  strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
  if (ioctl(s, SIOCGIFINDEX, &ifr) < 0)
  {
      perror(ifr.ifr_name);
      return -1;
  }
                                                                                
  /* cleanup */
  close(s);
                                                                                
  s = socket (PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2));
  if (s < 0) {
    perror("socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2))");
    return -1;
  }
                                                                                
  memset(&ll, 0, sizeof(ll));
  ll.sll_family = AF_PACKET;
  ll.sll_protocol = ntohs(ETH_P_802_2);
  ll.sll_ifindex = ifr.ifr_ifindex;
  ll.sll_hatype = 0;
  ll.sll_pkttype = PACKET_HOST;
  ll.sll_halen = 0;
                                                                                
  if (bind (s, (struct sockaddr*)&ll, sizeof ll) < 0) {
    perror("bind(netlink)");
    close(s);
    return -1;
  }
                                                                                
  if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0) {
    perror("ioctl[SIOCGIFHWADDR]");
    close(s);
    return -1;
  }

	close(s);

	memcpy (own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
  return 0;
}

int wpa_driver_wrt54g_get_bssid(const char *ifname, char *bssid)
{
	if (wrt54g_ioctl (ifname, WLC_GET_BSSID, bssid, 6) == 0)
		return 0;
	
	memset (bssid, 0, 6);
	return -1;
}

int wpa_driver_wrt54g_get_ssid(const char *ifname, char *ssid)
{
	wlc_ssid_t s;
	
	if (wrt54g_ioctl (ifname, WLC_GET_SSID, &s, sizeof s) == -1)
		return -1;

	memcpy (ssid, s.SSID, s.SSID_len);
	return s.SSID_len;
}

int wpa_driver_wrt54g_set_wpa(const char *ifname, int enable)
{
	unsigned int wauth, wsec;
	struct ether_addr ea;
	memset (&ea, enable ? 0xff : 0, sizeof ea);
	if (wrt54g_ioctl (ifname, WLC_GET_WPA_AUTH, &wauth, sizeof wauth) == -1 ||
			wrt54g_ioctl (ifname, WLC_GET_WSEC, &wsec, sizeof wsec) == -1)
		return -1;

	if (enable)
	{
		wauth = PSK_ENABLED;
		wsec  = TKIP_ENABLED;
	}
	else
	{
		wauth = 255;
		wsec  &= ~(TKIP_ENABLED | AES_ENABLED);
	}

	if (wrt54g_ioctl (ifname, WLC_SET_WPA_AUTH, &wauth, sizeof wauth) == -1 ||
			wrt54g_ioctl (ifname, WLC_SET_WSEC, &wsec, sizeof wsec) == -1)
		return -1;
	
  wrt54g_ioctl (ifname, 122, &ea, sizeof (ea));
	return 0;
}

int wpa_driver_wrt54g_set_key(const char *ifname, wpa_alg alg, u8 *addr,
		           int key_idx, int set_tx, u8 *seq, size_t seq_len,
							 u8 *key, size_t key_len)
{
  int i, ret;
  wl_wsec_key_t wkt;

  memset (&wkt, 0, sizeof wkt);
#if WL_DEBUG
	printf ("WRT54G: SET %sKEY[%d]: ", set_tx ? "PRIMARY " : "", key_idx);
	if (key && key_len>0)
  {
    printf ("%d:", key_len);
    for (i=0; i<key_len; ++i)
		  printf ("%02.2x",	key[i]&0xff);
  
  }
	else
  {
		printf ("CLEAR");
  }

 switch (alg)
  {
    case WPA_ALG_NONE:
      printf ("/ALG_NONE(CLEAR?)");
      break;
    case WPA_ALG_WEP:
      printf ("/WEP");
      break;
    case WPA_ALG_TKIP:
      printf ("/TKIP");
      break;
    case WPA_ALG_CCMP:
      printf ("/AES");
      break;
    default:
      printf ("/UNKNOWN(%d)", alg);
      break;
  }
#endif

 switch (alg)
  {
    case WPA_ALG_NONE:
      wkt.algo = CRYPTO_ALGO_OFF;
      break;
    case WPA_ALG_WEP:
      wkt.algo = CRYPTO_ALGO_WEP128; // CRYPTO_ALGO_WEP1?
      break;
    case WPA_ALG_TKIP:
      wkt.algo = 0; // CRYPTO_ALGO_TKIP;
      break;
    case WPA_ALG_CCMP:
      wkt.algo = 0; // CRYPTO_ALGO_AES_CCM; // AES_OCB_MSDU, AES_OCB_MPDU?
      break;
    default:
      wkt.algo = CRYPTO_ALGO_NALG;
      break;
  }

#if WL_DEBUG
  if (seq && seq_len>0)
  {
    printf ("; SEQ: ");
    for (i=0; i<seq_len; ++i)
		  printf ("%02.2x",	seq[i]&0xff);
  }

	if (addr) printf ("; MAC=" MACSTR, MAC2STR (addr));
	printf ("\n");
#endif

  wkt.index = key_idx;
  wkt.len = key_len;
  if (key && key_len > 0) {
		memcpy (wkt.data, key, key_len);
		if (key_len == 32)
		{
			// hack hack hack XXX
			memcpy (&wkt.data[16], &key[24], 8);
			memcpy (&wkt.data[24], &key[16], 8);
		}
	}
  // wkt.algo = CRYPTO_ALGO_...;
  wkt.flags = set_tx ? 0 : WL_PRIMARY_KEY;
  if (addr &&  set_tx) memcpy (&wkt.ea, addr, sizeof (wkt.ea));
  ret = wrt54g_ioctl (ifname, WLC_SET_KEY, &wkt, sizeof (wkt));
	if (addr &&  set_tx) wrt54g_ioctl (ifname, 121, &wkt.ea, sizeof(wkt.ea));
	return ret;
}


struct wpa_driver_wrt54g_events_data {
  int sock;
/*	int br_sock; */
};

static void wpa_driver_wrt54g_event_receive(int sock, void *ctx,
            void *sock_ctx)
{
	char buf[8192];
	int left, i;
	wl_wpa_header_t *wwh;
	union wpa_event_data data;
	
	if ((left=recv(sock, buf, sizeof buf, 0)) == -1) return;

#if WL_DEBUG
	printf ("RECEIVE EVENT\n");
	for (i=0; i<left; ++i)
	{
		printf ("%02.2x", buf[i]&0xff);
		if (i%2) printf (" ");
	}
	printf ("\n");
#endif

	if (left < sizeof (wl_wpa_header_t)) return;
	
	wwh = (wl_wpa_header_t *) buf;

	if (wwh->snap.type != WL_WPA_ETHER_TYPE)
		return;
	if (memcmp (&wwh->snap, wl_wpa_snap_template, 6) != 0)
		return;

	memset(&data, 0, sizeof(data));

	switch (wwh->type)
	{
		case WLC_ASSOC_MSG:
			left -= WL_WPA_HEADER_LEN;
#if WL_DEBUG
			printf ("WRT54G: ASSOC MESSAGE (left: %d)\n", left);
#endif
			if (left>0)
			{
				data.assoc_info.resp_ies = malloc(left);
				if (data.assoc_info.resp_ies == NULL)
					return;
				memcpy (data.assoc_info.resp_ies, buf+WL_WPA_HEADER_LEN, left);
				data.assoc_info.resp_ies_len = left;
#if WL_DEBUG
			printf ("WRT54G: coping %d bytes into resp_ies\n", left);
			for (i=0; i<left; ++i)
			{
				printf ("%02.2x", data.assoc_info.resp_ies[i]&0xff);
				if (i%2) printf (" ");
			}
			printf ("\n");
		
#endif
			}
			//data.assoc_info.req_ies = NULL;
			//data.assoc_info.req_ies_len = 0;

			wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
			wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
			break;
		case WLC_DISASSOC_MSG:
#if WL_DEBUG
			printf ("WRT54G: DISASSOC MESSAGE\n");
#endif
      wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
			break;
		case WLC_PTK_MIC_MSG:
#if WL_DEBUG
			printf ("WRT54G: PTK MIC MSG MESSAGE\n");
#endif
			data.michael_mic_failure.unicast = 1;
			wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
			break;
		case WLC_GTK_MIC_MSG:
#if WL_DEBUG
			printf ("WRT54G: GTK MIC MSG MESSAGE\n");
#endif
			data.michael_mic_failure.unicast = 0;
			wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
			break;
		default:
			printf ("WRT54G: UNKNOWN MESSAGE (%d)\n", wwh->type);
	}
	
}	

void * wpa_driver_wrt54g_events_init(const char *ifname,
																		 void *ctx)
{
	int s;
	struct sockaddr_ll ll;
	struct wpa_driver_wrt54g_events_data *data;
  struct ifreq ifr;

  /* open socket to kernel */
  if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    perror("socket");
    return 0;
  }
  /* do it */
  strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
  if (ioctl(s, SIOCGIFINDEX, &ifr) < 0)
	{
      perror(ifr.ifr_name);
			return 0;
	}
                                                                                
  /* cleanup */
  close(s);

	data = malloc(sizeof(*data));
	if (data == NULL)
		return NULL;
	memset(data, 0, sizeof(*data));

  s = socket (PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2));
  if (s < 0) {
    perror("socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2))");
    free(data);
    return NULL;
  }

  memset(&ll, 0, sizeof(ll));
  ll.sll_family = AF_PACKET;
  ll.sll_protocol = ntohs(ETH_P_802_2);
  ll.sll_ifindex = ifr.ifr_ifindex;
  ll.sll_hatype = 0;
  ll.sll_pkttype = PACKET_HOST;
  ll.sll_halen = 0;

  if (bind (s, (struct sockaddr*)&ll, sizeof ll) < 0) {
    perror("bind(netlink)");
    close(s);
    free(data);
    return NULL;
  }

  eloop_register_read_sock(s, wpa_driver_wrt54g_event_receive, ctx, NULL);
  data->sock = s;

  return data;
}

int wpa_driver_wrt54g_events_deinit(void *ctx, void *priv)
{
  struct wpa_driver_wrt54g_events_data *data = priv;
  close(data->sock);
  free(data);
  return 0;
}

#ifndef WLC_SET_TKIP_COUNTERMEASURES
# define WLC_SET_TKIP_COUNTERMEASURES 202
#endif
int wpa_driver_wrt54g_set_countermeasures(const char *ifname, int enabled)
{
#if 0
	return 
		wrt54g_ioctl (ifname, 
				          WLC_SET_TKIP_COUNTERMEASURES, &enabled, sizeof enabled);
#else
	return 0;
#endif
}

int  wpa_driver_wrt54g_set_drop_unencrypted(const char *ifname, int enabled)
{
	/* SET_EAP_RESTRICT, SET_WEP_RESTRICT */
	int restrict = (enabled ? 1 : 0);
	
	if (wrt54g_ioctl (ifname, WLC_SET_WEP_RESTRICT, 
				&restrict, sizeof restrict) < 0 ||
			wrt54g_ioctl (ifname, WLC_SET_EAP_RESTRICT,
				&restrict, sizeof restrict) < 0)
		return -1;

	return 0;
}

void wpa_driver_wrt54g_scan_timeout(void *eloop_ctx, void *timeout_ctx)
{
#if WL_DEBUG
  wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
#endif
  wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
}

int wpa_driver_wrt54g_scan(const char *ifname, void *ctx
#if 1
													 , u8 *ssid, size_t ssid_len
#endif
													 )
{
	wlc_ssid_t wst = {0, ""};

#if 1
	if (ssid && ssid_len > 0 && ssid_len <= sizeof(wst.SSID))
	{
		wst.SSID_len = ssid_len;
		memcpy (wst.SSID, ssid, ssid_len);
	}
#endif
	
	if (wrt54g_ioctl (ifname, WLC_SCAN, &wst, sizeof wst) < 0)
		return -1;

	eloop_register_timeout(3, 0, wpa_driver_wrt54g_scan_timeout, NULL, ctx);
	return 0;
}


static const int frequency_list[] = { 
	2412, 2417, 2422, 2427, 2432, 2437, 2442,
	2447, 2452, 2457, 2462, 2467, 2472, 2484 
};

struct bss_ie_hdr {
  u8 elem_id;
  u8 len;
  u8 oui[3];
  // u8 oui_type;
  // u16 version;
} __attribute__ ((packed));

int wpa_driver_wrt54g_get_scan_results(const char *ifname,
																	     struct wpa_scan_result *results,
																	     size_t max_size)
{
	char *buf;
	wl_scan_results_t* wsr = (wl_scan_results_t*)buf;
	wl_bss_info_t* wbi;
	int ap_num;

	buf = malloc (WLC_IOCTL_MAXLEN);
	if (buf == NULL)
		return -1;

	wsr = (wl_scan_results_t*)buf;
	
	wsr->buflen = WLC_IOCTL_MAXLEN - (sizeof wsr);
	wsr->version = 107;
	wsr->count = 0;

	if (wrt54g_ioctl (ifname, WLC_SCAN_RESULTS, buf, WLC_IOCTL_MAXLEN) < 0)
		return -1;

	memset(results, 0, max_size * sizeof(struct wpa_scan_result));

	for (ap_num=0, wbi=wsr->bss_info; ap_num<wsr->count; ++ap_num)
	{
		int i, left;
		struct bss_ie_hdr* ie;
		
		memcpy(results[ap_num].bssid, &wbi->BSSID, ETH_ALEN);
		memcpy(results[ap_num].ssid, wbi->SSID, wbi->SSID_len);
		results[ap_num].ssid_len = wbi->SSID_len;
		results[ap_num].freq = frequency_list[wbi->channel-1];
		// get ie's
#if WL_DEBUG
		printf ("AP IEs: ");
		for (i=0; i<wbi->ie_length; ++i)
		{
			printf ("%02.2x", ((u8*)wbi+sizeof(*wbi))[i]&0xff);
			if (i%2) printf (" ");
		}
		printf ("\n");
#endif
		ie = (struct bss_ie_hdr*)((u8*)wbi+sizeof(*wbi));
		for (left = wbi->ie_length; left > 0; 
				left -= (ie->len+2), ie = (struct bss_ie_hdr*)((u8*)ie+2+ie->len))
		{
#if WL_DEBUG
			printf ("IE: id:%x, len:%d", ie->elem_id, ie->len);
			if (ie->len>=3) 
				printf (", oui:%02.2x%02.2x%02.2x", ie->oui[0], ie->oui[1], ie->oui[2]);
			printf ("\n");
#endif					
			if (ie->elem_id != 0xdd ||
					ie->len < 6 ||
					memcmp(ie->oui, WPA_OUI, 3) != 0)
				continue;
			memcpy (results[ap_num].wpa_ie, ie, ie->len+2);
			results[ap_num].wpa_ie_len = ie->len+2;
			break;
		}
		
		
		wbi = (wl_bss_info_t*)((u8*)wbi + wbi->length);
	}
	
  wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%d BSSes)",
			       wsr->buflen, ap_num);

  return ap_num;
}

#ifndef WLC_DEAUTHENTICATE
# define WLC_DEAUTHENTICATE 143
#endif
#ifndef WLC_DEAUTHENTICATE_WITH_REASON
# define WLC_DEAUTHENTICATE_WITH_REASON 201
#endif
typedef struct {
  uint32  val;
  struct ether_addr ea;
	uint16 res;
} wlc_deauth_t;
                                                                                

int wpa_driver_wrt54g_deauthenticate(const char *ifname, 
		                                 uint8 *addr, int reason_code)
{
	wlc_deauth_t wdt;
	wdt.val = reason_code;
	memcpy (&wdt.ea, addr, sizeof wdt.ea);
	wdt.res = 0x7fff;
	return wrt54g_ioctl (ifname, WLC_DEAUTHENTICATE_WITH_REASON, &wdt, sizeof wdt);
}

int wpa_driver_wrt54g_disassociate(const char *ifname, uint8 *addr, 
																	 int reason_code)
{
	return wrt54g_ioctl (ifname, WLC_DISASSOC, 0, 0);
}

int wpa_driver_wrt54g_associate(const char *ifname, const char *bssid,
																const char *ssid, size_t ssid_len, int freq,
																const char *wpa_ie, size_t wpa_ie_len
#if 1
																,
																wpa_cipher pairwise_suite, 
																wpa_cipher group_suite,
																wpa_key_mgmt key_mgmt_suite
#endif
																)
{
	wlc_ssid_t s;
	int infra = 1;
	int auth = 0;
	int wsec = 4;
	int dummy;
	int wpa_auth;
	
	s.SSID_len = ssid_len;
	memcpy (s.SSID, ssid, ssid_len);

	switch (pairwise_suite)
	{
		case CIPHER_WEP40:
		case CIPHER_WEP104:
			wsec = 1;
			break;

		case CIPHER_TKIP:
			wsec = 2;
			break;

		case CIPHER_CCMP:
			wsec = 4;
			break;

		default:
			wsec = 0;
			break;
	}

	switch (key_mgmt_suite)
	{
		case KEY_MGMT_802_1X:
			wpa_auth = 1;
			break;

		case KEY_MGMT_PSK:
			wpa_auth = 2;
			break;

		default:
			wpa_auth = 255;
			break;
	}

	// printf ("wrt54g_associate: %u %u %u\n", pairwise_suite, group_suite, key_mgmt_suite);
	// wrt54g_ioctl (ifname, WLC_GET_WSEC, &wsec, sizeof wsec);
	// wl join uses wlc_sec_wep here, not wlc_set_wsec
	
	if (
			wrt54g_ioctl (ifname, WLC_SET_WSEC, &wsec, sizeof wsec) < 0 ||
			wrt54g_ioctl (ifname, WLC_SET_WPA_AUTH, &wpa_auth, sizeof wpa_auth) < 0 ||
			wrt54g_ioctl (ifname, WLC_GET_WEP, &dummy, sizeof dummy) < 0 ||
			wrt54g_ioctl (ifname, WLC_SET_INFRA, &infra, sizeof infra) < 0 ||
			wrt54g_ioctl (ifname, WLC_SET_AUTH, &auth, sizeof auth) < 0 ||
			wrt54g_ioctl (ifname, WLC_SET_WEP, &wsec, sizeof wsec) < 0 ||
			wrt54g_ioctl (ifname, WLC_SET_SSID, &s, sizeof s) < 0
	)
		return -1;
	
	return 0;
}

struct wpa_driver_ops wpa_driver_wrt54g_ops = {
	.get_own_addr = wpa_driver_wrt54g_get_own_addr,
	.get_bssid = wpa_driver_wrt54g_get_bssid,
	.get_ssid = wpa_driver_wrt54g_get_ssid,
	.set_wpa = wpa_driver_wrt54g_set_wpa,
	.set_key = wpa_driver_wrt54g_set_key,
	.events_init = wpa_driver_wrt54g_events_init,
	.events_deinit = wpa_driver_wrt54g_events_deinit,
	.set_countermeasures = wpa_driver_wrt54g_set_countermeasures,
	.set_drop_unencrypted = wpa_driver_wrt54g_set_drop_unencrypted,
	.scan = wpa_driver_wrt54g_scan,
	.get_scan_results = wpa_driver_wrt54g_get_scan_results,
	.deauthenticate = wpa_driver_wrt54g_deauthenticate,
	.disassociate = wpa_driver_wrt54g_disassociate,
	.associate = wpa_driver_wrt54g_associate,
};

