借助iwtools工具包以过滤方式获取WiFi状态。

用到的工具有iwconfig、iwlist。给上层提供的函数有get_curwifi_info、get_wifi_list。

我们先看原始的iwtools Makefile快照
# Targets to build
STATIC=libiw.a
DYNAMIC=libiw.so.$(WT_VERSION)
PROGS= iwconfig iwlist iwpriv iwspy iwgetid iwevent ifrename   #PROGS这个变量就是要编译的工具
MANPAGES8=iwconfig.8 iwlist.8 iwpriv.8 iwspy.8 iwgetid.8 iwevent.8 ifrename.8
MANPAGES7=wireless.7
MANPAGES5=iftab.5
EXTRAPROGS= macaddr iwmulticall

# Composition of the library :
OBJS = iwlib.o

# Select which library to build and to link tool with
BUILD_STATIC = 1    #将iwlib编译成.a
ifdef BUILD_STATIC
  IWLIB=$(STATIC)
  IWLIB_INSTALL=install-static
else
  IWLIB=$(DYNAMIC)
  IWLIB_INSTALL=install-dynamic
endif

# Standard compilation targets
all:: $(IWLIB) $(PROGS)

%: %.o
    $(CC) $(LDFLAGS) $(STRIPFLAGS) $(XCFLAGS) -o $@ $^ $(LIBS)

%.o: %.c wireless.h
    $(CC) $(XCFLAGS) -c $<
%.so: %.c wireless.h
    $(CC) $(XCFLAGS) $(PICFLAG) -c -o $@ $<

iwconfig: iwconfig.o $(IWLIB)

iwlist: iwlist.o $(IWLIB)

iwpriv: iwpriv.o $(IWLIB)

iwspy: iwspy.o $(IWLIB)

iwgetid: iwgetid.o $(IWLIB)

iwevent: iwevent.o $(IWLIB)

ifrename: ifrename.o $(IWLIB)

macaddr: macaddr.o $(IWLIB)

# Always do symbol stripping here
iwmulticall: iwmulticall.o
    $(CC) $(LDFLAGS) -Wl,-s $(XCFLAGS) -o $@ $^ $(LIBS)

# It's a kind of magic...
wireless.h:
    cp $(WEXT_HEADER) wireless.h

# Compilation of the dynamic library
$(DYNAMIC): $(OBJS:.o=.so)
    $(CC) -shared -o $@ -Wl,-soname,$@ $(STRIPFLAGS) $(LIBS) -lc $^

# Compilation of the static library
$(STATIC): $(OBJS:.o=.so)
    $(RM) $@
    $(AR) cru $@ $^
    $(RANLIB) $@
按照上面Makefile思路,它将iwxxx.c编译成bin文件。那么,我们可以将iwxxx.c的main函数改掉将之以接口函数的形式暴露出来。

先上修改后的Makefile快照,这个Makefile的目的是选择性的将iwxxx.c链接成wifiopt.a

# Always use local header for wireless extensions
WEXT_HEADER = wireless.$(WE_VERSION).h

# Targets to build
STATIC=libiw.a
DYNAMIC=libiw.so.$(WT_VERSION)
PROGS= iwpriv iwspy iwgetid ifrename    #这里不选编译iwconfig.c iwlist.c iwevent.c iwmulticall.c因为它们的main函数改成接口函数
MANPAGES8=iwconfig.8 iwlist.8 iwpriv.8 iwspy.8 iwgetid.8 iwevent.8 ifrename.8
MANPAGES7=wireless.7
MANPAGES5=iftab.5
EXTRAPROGS= macaddr iwmulticall

# Composition of the library :
OBJS = iwlib.o

OPWIFI = iwconfig.c iwlist.c iwevent.c iwmulticall.c #新增变量将这里的.c编成libwifi_opt.a
SRC_WIFI = $(wildcard $(OPWIFI))
OBJ_WIFI = $(SRC_WIFI:%.c=%.o)

BUILD_STATIC :=1

# Select which library to build and to link tool with
ifdef BUILD_STATIC
  IWLIB=$(STATIC)
  IWLIB_INSTALL=install-static
else
  IWLIB=$(DYNAMIC)
  IWLIB_INSTALL=install-dynamic
endif

# Standard name for dynamic library so that the dynamic linker can pick it.
# We will just create a symbolic link to the real thing.
DYNAMIC_LINK= libiw.so

# Various commands
RM = rm -f
RM_CMD = $(RM) *.BAK *.bak *.d *.o *.so ,* *~ *.a *.orig *.rej *.out ../../../../osdrv/rootfs_scripts/rootfs/usr/lib/libiw.so.29
LDCONFIG = ldconfig

# Do we want to build with or without libm ?
ifdef BUILD_NOLIBM
  LIBS=
  WELIB_FLAG= -DWE_NOLIBM=y
else
  LIBS= -lm
endif

# Other flags
CFLAGS=-Os -W -Wall -Wstrict-prototypes -Wmissing-prototypes -Wshadow \
    -Wpointer-arith -Wcast-qual -Winline -I.
#CFLAGS=-O2 -W -Wall -Wstrict-prototypes -I.
DEPFLAGS=-MMD
XCFLAGS=$(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) $(WELIB_FLAG) $(WEDEF_FLAG)
PICFLAG=-fPIC

# Standard compilation targets
all:: $(IWLIB) $(PROGS)

%: %.o
    $(CC) $(LDFLAGS) $(STRIPFLAGS) $(XCFLAGS) -o $@ $^ $(LIBS)

%.o: %.c wireless.h
    $(CC) $(XCFLAGS) -c $<
%.so: %.c wireless.h
    $(CC) $(XCFLAGS) $(PICFLAG) -c -o $@ $<

iwconfig: iwconfig.o $(IWLIB)

iwlist: iwlist.o $(IWLIB)

iwpriv: iwpriv.o $(IWLIB)

iwspy: iwspy.o $(IWLIB)

iwgetid: iwgetid.o $(IWLIB)

iwevent: iwevent.o $(IWLIB)

ifrename: ifrename.o $(IWLIB)

macaddr: macaddr.o $(IWLIB)

wifiopt: libwifi_opt.a

##############################################################################
libwifi_opt.a: $(OBJ_WIFI) #利用OBJ_WIFI 生成libwifi_opt.a
    $(AR) -r libwifi_opt.a $^

%.o: %.c wireless.h
    $(CC) $(XCFLAGS) -c $<
%.a: %.c wireless.h
    $(CC) $(XCFLAGS) $(PICFLAG) -c -o $@ $<

##############################################################################

# It's a kind of magic... '
wireless.h:
    cp $(WEXT_HEADER) wireless.h

# Compilation of the dynamic library
$(DYNAMIC): $(OBJS:.o=.so)
    $(CC) -shared -o $@ -Wl,-soname,$@ $(STRIPFLAGS) $(LIBS) -lc $^

# Compilation of the static library
$(STATIC): $(OBJS:.o=.so)
    $(RM) $@
    $(AR) cru $@ $^
    $(RANLIB) $@

好了,做到这里已经完成一大半了,剩下的工具只需要在原main函数做入口做过滤驱动就好了。(前提仔细分析iwxxx.c结构)。
这里详细分析如何借助iwlist.c获取搜索WiFi状态,获取WiFi信息的都是大同小异的。(详细请看文末github源码)
先上修改过的iwmulticall.c源码(这个是提供接口.c)

/*create by jinfa 
 *这是一个应用接口,它依赖于iwlist.c iwevent.c iwconfig.c
 *由之前的iwmulticall.c改成
 *
*/

/***************************** INCLUDES *****************************/

#include  /* Basename */
#include "iwlib.h"

#define WITHNO_ACCOUNT      0
#define WITH_ACCOUNT        1

/*
 *获取wifi对象信息
 *operstate fd 为0时 link参数无效。 
*/
struct p_curwifi *get_curwifi_info(struct p_curwifi *cur_wifi, int operstate_fd) //调用iwconfig
{
   if(main_iwconfig(cur_wifi, operstate_fd))
        return NULL;
    return cur_wifi;
}

//获取wifi列表
void get_wifi_list(struct p_wifi_list *wifi_list_head)  //调用iwlist
{
   main_iwlist(wifi_list_head);
}

/*
 *功能:给用户提供链接wifi接口
 *参数:
 *conn_wifi:用户传入需要链接的对象
 *mode: 用户指定系统是否只使用conn_wifi这个信息链接wifi
 *当mode为WITH_ACCOUNT系统只使用conn_wifi这个信息链接wifi
 *当mode为WITHNO_ACCOUNT系统使用当前wpa2_wpa.conf脚本存留的信息链接wifi \
 *这种情况多用于,用户已经配置wifi并系统刚启动的情况
*/
int link_wifi(struct p_connect *conn_wifi, int mode)
{
    char acount[256] = {0};
    if(mode == WITH_ACCOUNT)
    {
        sprintf(acount, "sed  -i \" s/ssid=.*/ssid=\"\\\"%s\"\\\" / ; s/psk=.*/psk=\"\\\"%s\"\\\" /\" /etc/wpa_wpa2.conf", \
                                        conn_wifi->essid, conn_wifi->password_wifi);
        system(acount);
    }
   system("wpa_supplicant -iwlan0 -B -c /etc/wpa_wpa2.conf");
   return 0;
}

很明显main_iwlist,就是以前iwlist的main函数。
那我们看看iwlist改成啥样了。


/******************************* MAIN ********************************/

/*------------------------------------------------------------------*/
/*
 * The main !
 */
int main_iwlist(struct p_wifi_list *wifi_list_head)
{
  int skfd;         /* generic raw socket desc. */
  char *dev = "wlan0";          /* device name          */
  char **args;          /* Command arguments */
  int count;            /* Number of arguments */
  int argc = 3;

  char *argv[3];
  argv[0] = "iwlist";
  argv[1] = "wlan0";
  argv[2] = "scanning";
  args = argv + 3;
  count = argc - 3;
  //我们不需要让iwlist找寻命令
#if 0
  /* find a command */
  iwcmd = find_command(cmd);
  if(iwcmd == NULL)
    return 1;

  /* Check arg numbers */
  if((iwcmd->max_count >= 0) && (count > iwcmd->max_count))
    {
      fprintf(stderr, "iwlist: command `%s' needs fewer arguments (max %d)\n",
          iwcmd->cmd, iwcmd->max_count);
      return 1;
    }

  /* Create a channel to the NET kernel. */
  if((skfd = iw_sockets_open()) < 0)
    {
      perror("socket");
      return -1;
    }

  /* do the actual work */
  if (dev)
    (*iwcmd->fn)(skfd, dev, args, count);
  else
    iw_enum_devices(skfd, iwcmd->fn, args, count);
#endif
  /* Create a channel to the NET kernel. */
  if((skfd = iw_sockets_open()) < 0)
  {
     perror("socket");
     return -1;
  }
  /* do the actual work */
  print_scanning_info(skfd, dev, args, count, wifi_list_head);  //我们在这里传入wifi_list_head头结点

  /* Close the socket. */
  iw_sockets_close(skfd);

  return 0;
}

继续分析print_scanning_info函数

static int
print_scanning_info(int     skfd,
            char *  ifname,
            char *  args[],     /* Command line args */
            int     count, struct p_wifi_list *wifi_list_head)      /* Args count */
...
...
直接看改动的地方。。大概在865行增加这些。
      struct p_wifi_list *node = NULL;
      do
    {
      /* Extract an event and print it */
      ret = iw_extract_event_stream(&stream, &iwe,
                    range.we_version_compiled);   //扫描一次
      if(ret > 0){
            if(iwe.cmd == SIOCGIWESSID){
                node = creat_wifi_list_node(); //创建节点
            }
            print_scanning_token(&stream, &iwe, &state,
                     &range, has_range, wifi_list_head, node);  //打印一次,通过这个函数能获取我们想要的。
            if(iwe.cmd == IWEVQUAL){
                add_list_tail(wifi_list_head, node); //加入链表头,其实这里完成一次截取。
            }
        }

    }while(ret > 0);
继续分析print_scanning_token函数
print_scanning_token(struct stream_descr *  stream, /* Stream of events */
             struct iw_event *      event,  /* Extracted token */
             struct iwscan_state *  state,
             struct iw_range *  iw_range,   /* Range info */
             int        has_range,
             struct p_wifi_list *wifi_list_head, struct p_wifi_list *node)
...
...
直接看改动的地方。。
在512行增加 strcpy(node->ESSID, essid);
在587行增加node->Singal = event->u.qual.level -256;

我们看下自定义的p_wifi_list结构体

struct p_wifi_list {
        char *ESSID;
        short Singal;
        struct p_wifi_list *next;
};

总结,在这些过滤代码的支持下,应用就可以借助开源软件的优势来达到获取WiFi信息的目的。
github:https://github.com/Mr-jinfa/iwtools4wifi

你可能感兴趣的:(设备驱动)