📄 cardif_linux_rtnetlink.c
字号:
/**
* File: cardif_linux_rtnetlink.c
*
* Licensed under a dual GPL/BSD license. (See LICENSE file for more info.)
*
* Authors: Chris.Hessing@utah.edu
*
* $Id: cardif_linux_rtnetlink.c,v 1.103.2.21 2007/05/20 22:36:34 chessing Exp $
* $Date: 2007/05/20 22:36:34 $
*
**/
#ifdef LINUX_FRAMER
// Use kernel headers
#define HEADERS_KERNEL
#include <unistd.h>
#include <sys/socket.h>
#include <linux/compiler.h>
#include <iwlib.h>
#include <sys/ioctl.h>
#include "netlink.h"
#include "rtnetlink.h"
#include <linux/if.h>
#include <linux/if_packet.h>
#include <math.h>
#include "wireless_copy.h"
#include "xsupconfig.h"
#include "context.h"
#include "xsup_common.h"
#include "xsup_debug.h"
#include "xsup_err.h"
#include "wireless_sm.h"
#include "cardif_linux.h"
#include "statemachine.h"
#include "../cardif.h"
#include "wpa.h"
#include "wpa2.h"
#include "eap_sm.h"
#include "eap_types/mschapv2/mschapv2.h"
#include "config_ssid.h"
#include "eapol_key_type254.h"
#include "timer.h"
#include "mic.h"
#include "event_core.h"
#include "cardif_linux_wext.h"
#include "cardif_linux_rtnetlink.h"
#ifdef USE_EFENCE
#include <efence.h>
#endif
// Define this, so the compiler doesn't complain.
extern char *if_indextoname(unsigned int, char *);
#define INT_DEL 0
#define INT_NEW 1
static int rtnl_sock=-1;
static struct sockaddr_nl rtnl_data;
#ifndef IWEVCUSTOM
#warning IWEVCUSTOM is not defined! We will define it, and try to continue!
#define IWEVCUSTOM 0x8C02
#endif
#ifndef IW_CUSTOM_MAX
#warning IW_CUSTOM_MAX is not defined! You should upgrade to a more current version of wireless extensions. We will attempt to define it ourselves, but the results may not be good.
#define IW_CUSTOM_MAX 256 // In bytes, matches current WE versions. (11/14/05)
#endif
// Forward defs to avoid compiler warnings.
void cardif_linux_rtnetlink_process_token(context *ctx,
struct iw_event *iwe);
extern unsigned int if_nametoindex(const char *);
/********************************************************
*
* Do whatever is needed to establish a netlink socket so that we can
* catch events, and take action.
*
********************************************************/
void cardif_linux_rtnetlink_init(context *ctx)
{
rtnl_sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (rtnl_sock < 0)
{
debug_printf(DEBUG_NORMAL, "Couldn't establish an rtnetlink socket! Some functionality won't be available!\n");
return;
}
memset((char *)&rtnl_data, 0x00, sizeof(rtnl_data));
rtnl_data.nl_family = AF_NETLINK;
rtnl_data.nl_groups = RTMGRP_LINK;
if (bind(rtnl_sock, (struct sockaddr *)&rtnl_data, sizeof(rtnl_data)) < 0)
{
debug_printf(DEBUG_NORMAL, "Couldn't bind netlink socket! Some functionality won't be available!\n");
close(rtnl_sock);
return;
}
event_core_register(rtnl_sock, ctx, cardif_linux_rtnetlink_check_event,
HIGH_PRIORITY, "rtnetlink handler");
cardif_linux_rtnetlink_set_linkmode(ctx, IF_LINK_MODE_DORMANT);
}
/********************************************************
*
* Do whatever is needed to shutdown the netlink socket that we set up.
*
********************************************************/
void cardif_linux_rtnetlink_cleanup(context *ctx)
{
debug_printf(DEBUG_INT, "Called cardif_linux_rtnetlink_cleanup()!\n");
cardif_linux_rtnetlink_set_operstate(ctx, XIF_OPER_UP);
cardif_linux_rtnetlink_set_linkmode(ctx, XIF_LINK_MODE_DEFAULT);
// Close the rtnetlink socket.
close(rtnl_sock);
}
/*********************************************************************
*
* Get the wireless extensions version that this driver was built with.
*
*********************************************************************/
int cardif_linux_rtnetlink_get_we_ver(context *intdata)
{
struct iwreq iwr;
struct iw_range *range = NULL;
char buffer[sizeof(iwrange)*2];
int sock;
if (!xsup_assert((intdata != NULL), "intdata != NULL", FALSE))
return XEMALLOC;
memset(buffer, 0x00, (sizeof(iwrange)*2));
iwr.u.data.pointer = (caddr_t) buffer;
iwr.u.data.length = sizeof(buffer);
iwr.u.data.flags = 0;
sock = cardif_get_socket(intdata);
if (iw_get_ext(sock, intdata->intName, SIOCGIWRANGE, &iwr) < 0)
{
debug_printf(DEBUG_NORMAL, "Error with ioctl SIOCGIWRANGE (Error: %s)\n",
strerror(errno));
return -1;
}
range = (struct iw_range *)buffer;
return range->we_version_compiled;
}
/********************************************************
*
* Gather the data that was returned from a scan.
*
********************************************************/
void cardif_linux_rtnetlink_reap(context *intdata, char *data, int len)
{
struct stream_descr stream;
struct iw_event iwe;
int retval;
if (!xsup_assert((intdata != NULL), "intdata != NULL", FALSE))
return;
if (!xsup_assert((data != NULL), "data != NULL", FALSE))
return;
xsup_assert((len >= 0), "len >= 0", TRUE);
xsup_assert((len < 65001), "len < 65001", TRUE);
iw_init_event_stream(&stream, data, len);
do
{
#ifdef NEW_IWLIB
retval = iw_extract_event_stream(&stream, &iwe,
cardif_linux_rtnetlink_get_we_ver(intdata));
#else
retval = iw_extract_event_stream(&stream, &iwe);
#endif
if (retval == 1) // Then we got something
{
cardif_linux_rtnetlink_process_token(intdata, &iwe);
} else {
switch (retval)
{
case 0:
// No error.
break;
case -1:debug_printf(DEBUG_NORMAL, "Invalid event!\n");
break;
case 2:debug_printf(DEBUG_NORMAL, "Unknown event found. Skipping."
"(Event %04X) (Not supported in wireless "
"extensions %d?)\n", iwe.cmd, WIRELESS_EXT);
break;
case -2:debug_printf(DEBUG_NORMAL, "Invalid event data. Skipping."
"\n");
break;
default:debug_printf(DEBUG_NORMAL, "Unknown result code from "
"iw_extract_event_stream(). (Result was %d)"
"\n", retval);
break;
}
}
}
while (retval > 0);
}
/*******************************************************
*
* Check to see if we have data in the returned scan buffer, even if
* we didn't get a scan complete event. (Some cards may not send the
* scan complete event.)
*
*******************************************************/
uint8_t cardif_linux_rtnetlink_check_nets(context *idata)
{
struct lin_sock_data *sockData = NULL;
struct iwreq iwr;
char *buffer = NULL;
uint16_t buf_size = 8192;
wireless_ctx *wctx = NULL;
if (!xsup_assert((idata != NULL), "idata != NULL", FALSE))
return XEMALLOC;
if (!xsup_assert((idata->intTypeData != NULL), "idata->intTypeData != NULL",
FALSE))
return XEMALLOC;
wctx = (wireless_ctx *)idata->intTypeData;
if (!TEST_FLAG(wctx->flags, WIRELESS_SCANNING))
{
return XENONE;
}
debug_printf(DEBUG_INT, "Checking for returned SSID information....\n");
sockData = idata->sockData;
if (!xsup_assert((buf_size != 0), "buf_size != 0", TRUE))
return XEMALLOC;
if (!xsup_assert((sockData != NULL), "sockData != NULL", FALSE))
return XEMALLOC;
buffer = (char *)Malloc(buf_size);
if (buffer == NULL)
{
debug_printf(DEBUG_NORMAL, "Couldn't allocate memory for scan buffer!"
"\n");
return XEMALLOC;
}
iwr.u.data.pointer = buffer;
iwr.u.data.flags = 0;
iwr.u.data.length = buf_size;
strcpy(iwr.ifr_name, idata->intName);
if (ioctl(sockData->sockInt, SIOCGIWSCAN, &iwr) < 0)
{
if (errno == E2BIG)
{
// Our return results are too big for our default buffer. So,
// allocate more and try again!
FREE(buffer);
buf_size *= 2;
buffer = (char *)Malloc(buf_size);
if (!buffer)
{
debug_printf(DEBUG_NORMAL, "Couldn't allocate memory for scan "
"buffer!\n");
return XEMALLOC;
}
iwr.u.data.pointer = buffer;
iwr.u.data.length = buf_size;
while (ioctl(sockData->sockInt, SIOCGIWSCAN, &iwr) < 0)
{
FREE(buffer);
if (buf_size > 60000)
{
debug_printf(DEBUG_NORMAL, "Buffer size to allocate has "
"become unreasonable! (If you really have "
"that many SSIDs, you won't get much data "
"across the network anyway!)\n");
return -1;
}
buf_size *= 2;
buffer = (char *)Malloc(buf_size);
if (!buffer)
{
debug_printf(DEBUG_NORMAL, "Couldn't allocate memory for scan buffer!\n");
return XEMALLOC;
}
iwr.u.data.pointer = buffer;
iwr.u.data.length = buf_size;
}
}
else
{
if (errno == EAGAIN)
{
debug_printf(DEBUG_INT, "No data available! (%s)\n",
strerror(errno));
return XENONE;
}
else
{
debug_printf(DEBUG_NORMAL, "Error with scan results!\n");
debug_printf(DEBUG_NORMAL, "Error was : %s\n", strerror(errno));
UNSET_FLAG(wctx->flags, WIRELESS_SCANNING);
return -1;
}
}
}
debug_printf(DEBUG_NORMAL, "Scan complete.\n");
// Cancel the scancheck timer, so it doesn't continue to fire.
timer_cancel(idata, SCANCHECK_TIMER);
if (iwr.u.data.length <= 0)
{
FREE(buffer);
return XENONE;
}
// Then harvest the data.
debug_printf(DEBUG_INT, "Reaping data. (Size : %d)\n", iwr.u.data.length);
debug_hex_dump(DEBUG_INT, (uint8_t *)buffer, iwr.u.data.length);
cardif_linux_rtnetlink_reap(idata, (char *)buffer, iwr.u.data.length);
UNSET_FLAG(wctx->flags, WIRELESS_SCANNING);
// Clean up after ourselves.
FREE(buffer);
return XDATA;
}
/***********************************************************
*
* Check the MAC that we were given. If it is all 0s, 4s, or Fs then the
* event is a disassociation. If it isn't then it is an association.
*
***********************************************************/
int cardif_linux_rtnetlink_validate(context *idata, uint8_t *mac)
{
char newmac[6];
if (!xsup_assert((idata != NULL), "idata != NULL", FALSE))
return XEMALLOC;
if (!xsup_assert((mac != NULL), "mac != NULL", FALSE))
return XEMALLOC;
// Is it a disassociation?
memset(newmac, 0x00, 6);
if (memcmp(newmac, mac, 6) == 0)
{
return FALSE;
}
memset(newmac, 0x44, 6);
if (memcmp(newmac, mac, 6) == 0)
{
return FALSE;
}
memset(newmac, 0xff, 6);
if (memcmp(newmac, mac, 6) == 0)
{
return FALSE;
}
// Otherwise, it was an association
return TRUE;
}
/**********************************************************************
*
* Process a SIOCGIWAP event.
*
**********************************************************************/
void cardif_linux_rtnetlink_process_SIOCGIWAP(context *idata,
struct iw_event *iwe)
{
char mac[6];
int assoc;
struct config_globals *globals = NULL;
wireless_ctx *wctx = NULL;
if (!xsup_assert((idata != NULL), "idata != NULL", FALSE))
return;
if (!xsup_assert((idata->intTypeData != NULL), "idata->intTypeData != NULL",
FALSE))
return;
if (!xsup_assert((iwe != NULL), "iwe != NULL", FALSE))
return;
wctx = (wireless_ctx *)idata->intTypeData;
memcpy(mac, iwe->u.ap_addr.sa_data, 6);
debug_printf(DEBUG_INT, "AP MAC : ");
debug_hex_printf(DEBUG_INT, (uint8_t *)mac, 6);
#warning Check this!
if (TEST_FLAG(wctx->flags, WIRELESS_SCANNING))
{
config_ssid_add_bssid(wctx, mac);
} else {
globals = config_get_globals();
if (!xsup_assert((globals != NULL), "globals != NULL", FALSE))
return;
assoc = cardif_linux_rtnetlink_validate(idata, (uint8_t *)&mac);
if (assoc)
{
// We have changed to associated mode. Populate the destination
// MAC with the BSSID, as long as we are in auto mode.
SET_FLAG(wctx->flags, WIRELESS_SM_ASSOCIATED);
UNSET_FLAG(wctx->flags, WIRELESS_SM_STALE_ASSOCIATION);
if (globals->destination == DEST_AUTO)
memcpy(idata->dest_mac, mac, 6);
} else {
UNSET_FLAG(wctx->flags, WIRELESS_SM_ASSOCIATED);
UNSET_FLAG(wctx->flags, WIRELESS_SM_STALE_ASSOCIATION);
}
}
}
/**********************************************************************
*
* Process a SIOCGIWESSID event.
*
**********************************************************************/
void cardif_linux_rtnetlink_process_SIOCGIWESSID(context *ctx,
struct iw_event *iwe)
{
char essid[IW_ESSID_MAX_SIZE+1];
wireless_ctx *wctx = NULL;
if (!xsup_assert((ctx != NULL), "ctx != NULL", FALSE))
return;
if (!xsup_assert((ctx->intTypeData != NULL), "ctx->intTypeData != NULL",
FALSE))
return;
if (!xsup_assert((iwe != NULL), "iwe != NULL", FALSE))
return;
wctx = (wireless_ctx *)ctx->intTypeData;
memset(essid, 0x00, IW_ESSID_MAX_SIZE+1);
memcpy(essid, iwe->u.essid.pointer, iwe->u.essid.length);
essid[iwe->u.essid.length] = '\0';
#warning Check this!
if (TEST_FLAG(wctx->flags, WIRELESS_SCANNING))
{
debug_printf(DEBUG_INT, "ESSID : %s\n", essid);
config_ssid_add_ssid_name(wctx, essid);
} else {
debug_printf(DEBUG_NORMAL, "Got a get SSID event!? "
"Notify your wireless driver maintainer.\n");
}
}
/*****************************************************************
*
* Process an SIOCSIWESSID.
*
*****************************************************************/
void cardif_linux_rtnetlink_process_SIOCSIWESSID(context *ctx,
struct iw_event *iwe)
{
char essid[IW_ESSID_MAX_SIZE+1];
wireless_ctx *wctx = NULL;
char wpaie[24];
if (!xsup_assert((ctx != NULL), "ctx != NULL", FALSE))
return;
if (!xsup_assert((ctx->intTypeData != NULL), "ctx->intTypeData != NULL",
FALSE))
return;
if (!xsup_assert((iwe != NULL), "iwe != NULL", FALSE))
return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -