📄 lib80211.c
字号:
/* Copyright (c) 2003, Tijmen Moerland <moerland@yahoo.com> Code is licensed under the BSD license.*//*! \file lib80211.c \brief The source code for numerous 802.11 get/set functions. Functions The library has been designed to get access to a whole range of settings, parameters and data via a single function call. This would make user programs shorter with respect to code size and easier to understand. As a result, some functions provide similar information or functionality, or perform really simplistic operations. But if these operations are used a lot, it's simpler to have a single function call than two lines of code. Crashtest A lot of functions can make the calling program exit because of wrong parameters being passed. The most common mistake would be to pass a non-existent wireless interface name (e.g. ed0 instead of wi0). Most functions will try to perform a 802.11 specific ioctl call on this interface. If not supported, the function will use the err(1, <message>) function to exit the program. It is the responsibility of the user of these library functions to correctness of parameters, enough functions exist in this lib to do so. Code ripping There's a considerable amount of functions present in this library with code copied from other source files, mostly wicontrol.c, ifieee80211.c. The code has in most cases been modified to suite the special needs of this lib.*/#include "lib80211.h"/******************************************************************** * the functions below will be used to get the number of (wi) * interfaces and their corresponding names *//*! \var int wi_list[IF_MAXNR] \brief This array maps a wifi index to the corresponding interface index \note This array is initialized in getNumIf80211 \warning This variable should not be accessed, certainly not written to. Both indexes start at zero (0). When the wifi index is used as an index of this array, the corresponding row number in the sysctl table, minus one (1) is the result. Use getPtrIf80211 to go from wifi specific to complete interface index.\n Use GetWifiIndex for the inverse. Note that for those functions, indexes start at one (1).*/int wi_list[IF_MAXNR];/*! \var int report_wi \brief Indicates whether certain information about wifi interfaces has been reported yet Initialized to 1, meaning no information has been reported yet. Functions uses this to print information about wifi interfaces. But only once, not at every call.*/int report_wi = 1;/*! \fn int getIfCount() \brief Gets the number of network interfaces on the local machine, of any type. \return Number of network interfaces*/int getIfCount() { int count; size_t len = sizeof(count); static int name[5] = {CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_SYSTEM, IFMIB_IFCOUNT}; if (sysctl(name, 5, &count, &len, (void *)0, 0) < 0) err(1, "sysctl IFMIB_IFCOUNT"); return count;}/*! \fn char *getIfName(int row, char *buf) \brief Finds the name of a specific network interface \param row The (one-based) row number of the network interface entry in sysctl table \param buf A pointer to an allocated chunk of memory large enough to contain the interface name \return The pointer to buf, now containing the interface name*/char *getIfName(int row, char *buf) { struct ifmibdata ifmd; int name[6]; size_t len; name[0] = CTL_NET; name[1] = PF_LINK; name[2] = NETLINK_GENERIC; name[3] = IFMIB_IFDATA; name[4] = row; name[5] = IFDATA_GENERAL; len = sizeof(ifmd); if (sysctl(name, 6, &ifmd, &len, (void *)0, 0) < 0) err(1, "sysctl IFDATA_GENERAL"); memcpy(buf, ifmd.ifmd_name, IF_NAMELEN); return buf;}/*! \fn int testIf80211(int row) \brief Tests whether the specified network interface is wireless (IEEE 802.11) \param row The (one-based) row number of the network interface entry in sysctl table \return 1 when interface is wireless \return 0 otherwise*/int testIf80211(int row) { char name[IF_NAMELEN]; struct ieee80211req req; //first get the name for this interface //sysctl counts from 1 to ifCount getIfName(row, name); //now try a 80211 specific ioctl call int s = socket(AF_INET, SOCK_DGRAM, 0); if (s == -1) err(1, "socket"); strlcpy(req.i_name, name, sizeof(req.i_name)); req.i_type = IEEE80211_IOC_CHANNEL; if (ioctl(s, SIOCG80211, &req) < 0) { if (close(s) < 0) err(1, "close socket"); return 0; } if (close(s) < 0) err(1, "close socket"); if (report_wi) fprintf(stderr, "interface %d, called %s is wireless\n", row, name); return 1;}/*! \fn int getNumIf80211() \brief Gets the number of wireless interfaces on the local machine \return The number of wireless interfaces As a side effect, the wi_list table is initialized for use by other functions. Note that some other functions might produce errors when this function is not called first.*/int getNumIf80211() { int c, i; int j = 0; if (report_wi) fprintf(stderr, "sizeof struct wi_sigextcache = %d\n", sizeof(struct wi_sigextcache)); c = getIfCount(); if (report_wi) fprintf(stderr, "found %d interfaces\n", c); //now we need to find the wireless interfaces from these for (i = 0; i < c; i++) if (testIf80211(i+1)) { wi_list[j] = i; j++; } //wi_list is now an array containing j wireless interfaces if (report_wi) { fprintf(stderr, "found %d wireless interfaces\n", j); // report_wi = 0; } report_wi = 0; return j;}/*! \fn int getPtrIf80211(int if_nr) \brief Translates the wireless interface index number to network interface number \param if_nr The one-based index to the list of wireless interfaces \return The one-based index of the corresponding entry in the sysctl table \warning getNumIf80211 should be called once before this function is called. It initializes the wi_list array. This function is the inverse of getWifiIndex*/int getPtrIf80211(int if_nr) { if (if_nr <= 0) errx(1, "getPtrIf80211: interface nr should be >= 1"); return wi_list[if_nr-1] + 1;}/*! \fn char *getNameIf80211(int if_nr, char *buf) \brief Finds the name of a specific wireless interface \param if_nr The one-based index to the list of wireless interfaces \param buf A pointer to an allocated chunk of memory large enough to contain the interface name \return The pointer to buf, now containing the interface name \warning getNumIf80211 should be called once before this function is called. It initializes the wi_list array. This function simply combinates calls to getIfName and getPtrIf80211.*/char *getNameIf80211(int if_nr, char *buf) { //add 1 to interface number for systctl //(which starts counting at 1) getIfName(getPtrIf80211(if_nr), buf); return buf;}/*! \fn int getWifiIndex(int ifIndex) \brief Translates the network interface index number to wireless interface number \param ifIndex The one-based index of the network interface entry in the sysctl table \return The one-based index to the list of wireless interfaces \return 0 when ifIndex does not correspond to a wireless interface \warning getNumIf80211 should be called once before this function is called. It initializes the wi_list array. This function is the inverse of getPtrIf80211*/int getWifiIndex(int ifIndex) { int i; int c; c = getNumIf80211(); //total number of WIFI interfaces for (i = 0; i < c; i++) if (wi_list[i] + 1 == ifIndex) return i + 1; return 0;}/******************************************************************** * Next four functions are for getting the number of associated * stations when in hostap mode, and for disassociating them or * even deleting (=disassoc, deauth, free mem) *//*! \fn void setStaDisassoc(const char *iface, u_int8_t macaddr[6]) \brief Disassociates a station \param iface The name of the interface \param macaddr The MAC address of the station to be disassociated \warning Interface must be in HostAP mode Disassociates the specified station that is associated with the specified interface. Actually this function is just an interface to the setSta function.*/void setStaDisassoc(const char *iface, u_int8_t macaddr[6]) { return setSta(iface, macaddr, SIOCHOSTAP_DISASSOC);}/*! \fn void setStaDelete(const char *iface, u_int8_t macaddr[6]) \brief Deletes a station \param iface The name of the interface \param macaddr The MAC address to be disassociated \warning Interface must be in HostAP mode If associated, the specified station is disassociated. If authenticated, the specified station is deauthenticated. The station is deleted from the driver's station list (memory structures are freed). Actually this function is just an interface to the setSta function.*/void setStaDelete(const char *iface, u_int8_t macaddr[6]) { return setSta(iface, macaddr, SIOCHOSTAP_DEL);}/*! \fn void setSta(const char *iface, u_int8_t macaddr[6], unsigned long request) \brief Does the work for setStaDelete and setStaDisassociate functions \param iface The name of the interface \param macaddr The MAC address to be deleted or disassociated \param request Specifies disassociate or delete station \warning It's preferred to call setStaDisassoc and setStaDelete instead of calling this directly. \warning Interface must be in HostAP mode*/void setSta(const char *iface, u_int8_t macaddr[6], unsigned long request) { int s; struct ifreq ifr; struct hostap_sta sta; bzero(&ifr, sizeof(ifr)); strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)); bzero(&sta, sizeof(sta)); bcopy(macaddr, sta.addr, 6 * sizeof(u_int8_t)); ifr.ifr_data = (caddr_t) &sta; s = socket(AF_INET, SOCK_DGRAM, 0); if (s == -1) err(1, "socket"); if (ioctl(s, request, &ifr) < 0) if (request == SIOCHOSTAP_DISASSOC) err(1, "SIOCHOSTAP_DISASSOC"); else err(1, "SIOCHOSTAP_DEL"); if (close(s) < 0) err(1, "close socket");}/*! \fn int getStaAssocNumber(const char *iface) \brief Gets the number of associated stations \param iface The name of the interface \return The number of associated stations \warning Interface must be in HostAP mode \note Code has been ripped from wicontrol.c Gets the number of stations that are associated with the interface.*/u_int16_t getStaAssocNumber(const char *iface) { int s; struct ifreq ifr; struct hostap_getall reqall; struct hostap_sta stas[WIHAP_MAX_STATIONS]; bzero(&ifr, sizeof(ifr)); strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)); ifr.ifr_data = (caddr_t) &reqall; bzero(&reqall, sizeof(reqall)); reqall.size = sizeof(stas); reqall.addr = stas; bzero(&stas, sizeof(stas)); s = socket(AF_INET, SOCK_DGRAM, 0); if (s == -1) err(1, "socket"); if (ioctl(s, SIOCHOSTAP_GETALL, &ifr) < 0) err(1, "SIOCHOSTAP_GETALL"); if (close(s) < 0) err(1, "close socket"); return reqall.nstations;} /*! \fn u_int16_t getStaFlags(const char *iface, char macaddr[6]) \brief Gets the flags of a station \param iface The name of the interface \param macaddr The MAC address of the station \return The flags for the specified station \return 0 when interface is not in HostAP mode, MAC address is not in interface's station list, or flags is really zero (i.e. not associated nor authenticated). \note Code has been ripped from wicontrol.c bit0: associated\n bit1: authenticated*/u_int16_t getStaFlags(const char *iface, char macaddr[6]) { struct hostap_getall reqall; struct hostap_sta stas[WIHAP_MAX_STATIONS]; struct ifreq ifr; int i, s;// fprintf(stderr, "getStaFlags... for %x:%x:%x\n", macaddr[3]&0xff, macaddr[4]&0xff, macaddr[5]&0xff); if (getPortType(iface) != 6) // return 0 for non-HostAP interfaces return 0; if (getIfAdminStatus(iface) != 1) //return 0 for down interfaces return 0;// fprintf(stderr, "making siochostap_getall call\n"); bzero(&ifr, sizeof(ifr)); strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)); ifr.ifr_data = (caddr_t) & reqall; bzero(&reqall, sizeof(reqall)); reqall.size = sizeof(stas); reqall.addr = stas; bzero(&stas, sizeof(stas)); s = socket(AF_INET, SOCK_DGRAM, 0); if (s == -1) err(1, "socket"); if (ioctl(s, SIOCHOSTAP_GETALL, &ifr) < 0) err(1, "SIOCHOSTAP_GETALL"); //printf("%d station%s:\n", reqall.nstations, reqall.nstations>1?"s":""); for (i = 0; i < reqall.nstations; i++) { struct hostap_sta *info = &stas[i]; if (bcmp(info->addr, macaddr, 6 * sizeof(char)) == 0) { if (close(s) < 0) err(1, "socket close"); return info->flags; } } if (close(s) < 0) err(1, "close socket"); //no corresponding mac address has been found, return 0// fprintf(stderr, "MAC %x:%x:%x has not been found!\n", macaddr[3]&0xff, macaddr[4]&0xff, macaddr[5]&0xff); return 0;}/*! \fn void getExtendedCache(const char *iface, struct wi_req *wreq, struct wi_sigextcache **cacheptr) \brief reads the extended cache from the driver \param iface The name of the interface \param wreq A pointer to an allocated wi_req structure, which is used in the ioctl call \param cacheptr Used to pass a pointer to the extended cache data \return Nothing, but 'call-by-reference' (not really, we're doing C) variables are set After exit the following holds: The extended cache is stored in the memory block at wreq.\n *cacheptr will point to the extended cache block within the wreq block *items will contain the number of cache items in the wreq block*/void getExtendedCache(const char *iface, struct wi_sigextcache *cacheptr, int items) { char *pt; struct wi_req wreq; int off, tocopy; for (off = 0; off < items; off += MAXCACHE_TRANSFER) { bzero((char *) &wreq, sizeof(struct wi_req)); wreq.wi_len = WI_MAX_DATALEN; wreq.wi_type = WI_RID_READ_EXTCACHE; bcopy((char *) &off, (char *) &wreq.wi_val, sizeof(int)); getVal(iface, &wreq);// *items = (int *) wreq.wi_val; pt = ((char *) wreq.wi_val); pt += sizeof(int); if (items - off < MAXCACHE_TRANSFER) tocopy = items - off; else tocopy = MAXCACHE_TRANSFER; fprintf(stderr, "copying %d items for %s\n", tocopy, iface); bcopy(pt, (char *) cacheptr + sizeof (struct wi_sigextcache) * off, tocopy * sizeof(struct wi_sigextcache)); } }/*! \fn int getCacheItemnr(const char *iface) \brief Gets the number of items in the extended cache \param iface The name of the interface
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -