99d676cf23
a summary.
1162 lines
34 KiB
C
1162 lines
34 KiB
C
/* src/wlancfg/wlancfg.c
|
|
*
|
|
* User utility for setting, saving, and querying the wlan card configuration.
|
|
*
|
|
* Copyright (C) 2001 Rebel.com Inc. All Rights Reserved.
|
|
* --------------------------------------------------------------------
|
|
*
|
|
* linux-wlan
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* Alternatively, the contents of this file may be used under the
|
|
* terms of the GNU Public License version 2 (the "GPL"), in which
|
|
* case the provisions of the GPL are applicable instead of the
|
|
* above. If you wish to allow the use of your version of this file
|
|
* only under the terms of the GPL and not to allow others to use
|
|
* your version of this file under the MPL, indicate your decision
|
|
* by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this
|
|
* file under either the MPL or the GPL.
|
|
*
|
|
* --------------------------------------------------------------------
|
|
*
|
|
* Inquiries regarding the linux-wlan Open Source project can be
|
|
* made directly to:
|
|
*
|
|
* AbsoluteValue Systems Inc.
|
|
* info@linux-wlan.com
|
|
* http://www.linux-wlan.com
|
|
*
|
|
* --------------------------------------------------------------------
|
|
*
|
|
* Originally written 2001 by Robert James.
|
|
*
|
|
* The author may be reached as bob.james@rebel.com, or
|
|
* Robert James
|
|
* Rebel.com Inc.
|
|
* 150 Isabella St., Suite 1000
|
|
* Ottawa, Ontario
|
|
* Canada K1S 5R3
|
|
*
|
|
* --------------------------------------------------------------------
|
|
*/
|
|
|
|
/*
|
|
** The "wlancfg" utility program provides an alternative method to
|
|
** "wlanctl", for manipulating MIB values. It was designed to provide
|
|
** an easier mechanism for saving and restoring the complete wireless
|
|
** configuration (i.e. when re-starting the device driver) and to provide
|
|
** a more efficient mechanism for GUI's to query multiple MIB's.
|
|
**
|
|
** Usage: wlancfg query dev
|
|
** wlancfg show dev [all]
|
|
** wlancfg set dev
|
|
** wlancfg list
|
|
** wlancfg version
|
|
**
|
|
** where: dev - Name of device (e.g. wlan0).
|
|
**
|
|
** The functions are as follows:
|
|
**
|
|
** query - Read MIB names (separated by whitespace) from "stdin"
|
|
** and output their values (separated by carriage returns)
|
|
** to "stdout". The MIB's may be either read/write or
|
|
** read-only.
|
|
** show - Query the values of all supported read/write MIB's and
|
|
** output their values (separated by carriage returns) to
|
|
** "stdout". The syntax of the output will be:
|
|
**
|
|
** name=value
|
|
**
|
|
** If the "all" parameter is specified, then all supported
|
|
** MIB's (i.e. read-only MIB's as well) are output.
|
|
** set - Read MIB name/value pairs (separated by carriage returns)
|
|
** from "stdin" and set the values of the specified MIB's. The
|
|
** pairs must have the same syntax as above. The MIB's must
|
|
** be read/write.
|
|
** list - Display a list of all supported MIB's.
|
|
** version - Display the compiled version of "wlancfg".
|
|
*/
|
|
|
|
/*================================================================*/
|
|
/* System Includes */
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
|
|
/* Ugly hack for LinuxPPC R4, don't have time to figure it out right now */
|
|
#if defined(__WLAN_PPC__)
|
|
#undef __GLIBC__
|
|
#endif
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/socket.h>
|
|
|
|
/*================================================================*/
|
|
/* Project Includes */
|
|
|
|
#include <wlan/wlan_compat.h>
|
|
#include <wlan/version.h>
|
|
#include <wlan/p80211types.h>
|
|
#include <wlan/p80211msg.h>
|
|
#include <wlan/p80211meta.h>
|
|
#include <wlan/p80211metamsg.h>
|
|
#include <wlan/p80211metamib.h>
|
|
#include <wlan/p80211metastruct.h>
|
|
#include <wlan/p80211ioctl.h>
|
|
|
|
/*================================================================*/
|
|
/* Local Types */
|
|
|
|
/*
|
|
** The request specification (req_spec) structure is used to record
|
|
** frequently used information about the "dot11req_mibget" and
|
|
** "dot11req_mibset" request messages. It is used to prevent the
|
|
** necessity of recalculating this information when executing these
|
|
** requests repeatedly.
|
|
*/
|
|
|
|
typedef struct req_spec
|
|
{
|
|
UINT32 msgcode; /* Request message code. */
|
|
UINT32 msglen; /* Length of message. */
|
|
|
|
p80211meta_t *attptr; /* "mibattribute" argument. */
|
|
UINT32 attdid; /* "mibattribute" DID. */
|
|
UINT32 attoff; /* Request message offset. */
|
|
UINT32 attlen; /* Request message data length. */
|
|
|
|
p80211meta_t *resptr; /* "resultcode" argument. */
|
|
UINT32 resdid; /* "resultcode" DID. */
|
|
UINT32 resoff; /* Request message offset. */
|
|
UINT32 reslen; /* Request message data length. */
|
|
} req_spec_t;
|
|
|
|
/*================================================================*/
|
|
/* Local Function Declarations */
|
|
|
|
static void wlancfg_usage(void);
|
|
static int wlancfg_query(char *device);
|
|
static int wlancfg_show(char *device, int all);
|
|
static int wlancfg_set(char *device);
|
|
static void wlancfg_list(void);
|
|
|
|
static int wlancfg_reqspec(char *request, req_spec_t *mibget);
|
|
static int wlancfg_getvalue(char *device, p80211meta_t *item,
|
|
req_spec_t *mibget,
|
|
int skt, p80211ioctl_req_t *req,
|
|
char *value);
|
|
static int wlancfg_setvalue(char *device, req_spec_t *mibset,
|
|
int skt, p80211ioctl_req_t *req,
|
|
char *value);
|
|
static int wlancfg_build(char *device, req_spec_t *spec, char *value,
|
|
p80211msgd_t *msg);
|
|
static void wlancfg_totext(p80211meta_t *item, req_spec_t *mibget,
|
|
p80211msgd_t *msg, char *value);
|
|
static int wlancfg_getreq(char *cat, char *name, int argcnt,
|
|
UINT32 *msgcode, p80211meta_t **arglist);
|
|
|
|
/*****************************************************************
|
|
**
|
|
** main
|
|
**
|
|
** "wlancfg" main entry point.
|
|
**
|
|
** Arguments: argc - Number of command line arguments.
|
|
** argv - Array of argument strings.
|
|
**
|
|
** Returns: 0 - Success.
|
|
** 1 - Failure.
|
|
*/
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int result, all;
|
|
|
|
if (argc < 2) goto usage;
|
|
|
|
if (strcmp(argv[1], "query") == 0)
|
|
{
|
|
if (argc != 3) goto usage;
|
|
result = wlancfg_query(argv[2]);
|
|
goto done;
|
|
}
|
|
|
|
if (strcmp(argv[1], "show") == 0)
|
|
{
|
|
all = 0;
|
|
if (argc != 3)
|
|
{
|
|
if (argc != 4) goto usage;
|
|
if (strcmp(argv[3], "all") != 0) goto usage;
|
|
all = 1;
|
|
}
|
|
result = wlancfg_show(argv[2], all);
|
|
goto done;
|
|
}
|
|
|
|
if (strcmp(argv[1], "set") == 0)
|
|
{
|
|
if (argc != 3) goto usage;
|
|
result = wlancfg_set(argv[2]);
|
|
goto done;
|
|
}
|
|
|
|
if (strcmp(argv[1], "list") == 0)
|
|
{
|
|
if (argc != 2) goto usage;
|
|
wlancfg_list();
|
|
result = 0;
|
|
goto done;
|
|
}
|
|
|
|
if (strcmp(argv[1], "version") == 0)
|
|
{
|
|
if (argc != 2) goto usage;
|
|
printf("%s\n", WLAN_RELEASE);
|
|
result = 0;
|
|
goto done;
|
|
}
|
|
|
|
usage:
|
|
wlancfg_usage();
|
|
result = 0;
|
|
|
|
done:
|
|
|
|
return(result);
|
|
}
|
|
|
|
/*****************************************************************
|
|
**
|
|
** wlancfg_usage
|
|
**
|
|
** Output the command syntax.
|
|
*/
|
|
|
|
static void wlancfg_usage(void)
|
|
{
|
|
printf("\nQuery, show, or set configuration settings.\n\n");
|
|
|
|
printf("Usage: wlancfg query dev\n");
|
|
printf(" wlancfg show dev [all]\n");
|
|
printf(" wlancfg set dev\n");
|
|
printf(" wlancfg list\n");
|
|
printf(" wlancfg version\n\n");
|
|
|
|
printf(" where: dev - Name of device (e.g. wlan0).\n");
|
|
|
|
return;
|
|
}
|
|
|
|
/*****************************************************************
|
|
**
|
|
** wlancfg_query
|
|
**
|
|
** Query specific MIB's and output their values.
|
|
**
|
|
** Returns: 0 - Success.
|
|
** 1 - Failure.
|
|
*/
|
|
|
|
static int wlancfg_query(
|
|
char *device) /* I: Device name. */
|
|
{
|
|
int result;
|
|
req_spec_t mibget;
|
|
p80211ioctl_req_t req;
|
|
UINT8 msg[MSG_BUFF_LEN];
|
|
int skt, cnt;
|
|
char name[100], value[MSG_BUFF_LEN];
|
|
UINT32 did;
|
|
p80211meta_t *item;
|
|
|
|
/*
|
|
** All MIB values will be queried using the "dot11req_mibget" request.
|
|
** Do some initialization for this request.
|
|
*/
|
|
|
|
result = wlancfg_reqspec("dot11req_mibget", &mibget);
|
|
if (result != 0) return(1);
|
|
|
|
/*
|
|
** Get a socket to be used to talk to the device driver and then
|
|
** set up the invariant parts of the "ioctl" request. The variable
|
|
** parts (i.e. length and result code) will be set later when the
|
|
** actual requests are created.
|
|
*/
|
|
|
|
skt = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (skt == -1)
|
|
{
|
|
perror("wlancfg");
|
|
return(1);
|
|
}
|
|
|
|
strncpy(req.name, device, sizeof(req.name));
|
|
req.magic = P80211_IOCTL_MAGIC; /* Set the magic. */
|
|
req.data = msg;
|
|
|
|
/*
|
|
** Read MIB names from "stdin" until there are no more. Make sure
|
|
** that the user hasn't had an "accident" and entered a name which
|
|
** is too long.
|
|
**
|
|
** Note: The "scanf()" documentation is not clear on how strings
|
|
** which are too long are handled. Possibilities are:
|
|
**
|
|
** 1. "n" characters read and no null-termination added.
|
|
** 2. "n" characters read and '\0' added at "name[n]".
|
|
** 3. "n-1" characters read and '\0' added at "name[n-1]".
|
|
**
|
|
** The following code will work in all 3 cases and not overflow
|
|
** the "name" array.
|
|
*/
|
|
|
|
name[sizeof(name)-2] = '\0';
|
|
name[sizeof(name)-1] = '\0';
|
|
|
|
while (1)
|
|
{
|
|
cnt = scanf("%99s", name); /* sizeof(name)-1 = 99 */
|
|
if (cnt == 0 || cnt == EOF) break;
|
|
|
|
if (name[sizeof(name)-2] != '\0' || name[sizeof(name)-1] != '\0')
|
|
{
|
|
fprintf(stderr, "wlancfg: MIB name is too long.\n");
|
|
return(1);
|
|
}
|
|
|
|
/*
|
|
** Find the MIB.
|
|
*/
|
|
|
|
did = p80211_text2did(mib_catlist, NULL, NULL, name);
|
|
if (did == P80211DID_INVALID)
|
|
{
|
|
fprintf(stderr, "wlancfg: Unknown MIB: %s\n", name);
|
|
return(1);
|
|
}
|
|
|
|
item = p80211_did2item(mib_catlist, did);
|
|
if (item == NULL) /* Should never happen. */
|
|
{
|
|
fprintf(stderr, "wlancfg: Internal MIB search error: %s\n", name);
|
|
return(1);
|
|
}
|
|
|
|
/*
|
|
** Query the MIB value and output it. If no value was found
|
|
** (i.e. the MIB is unsupported), then output an empty line so
|
|
** that the input names and output values don't get out of sync.
|
|
** Otherwise, output the actual value...which follows the "=".
|
|
** The "=" will always exist so we don't need to deal with the
|
|
** case where it is not found.
|
|
*/
|
|
|
|
result = wlancfg_getvalue(device, item, &mibget, skt, &req, value);
|
|
if (result != 0) return(1);
|
|
|
|
if (value[0] == '\0')
|
|
printf("\n");
|
|
else
|
|
printf("%s\n", strchr(value, '=')+1);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*****************************************************************
|
|
**
|
|
** wlancfg_show
|
|
**
|
|
** Query all the current writeable MIB's and output them. If the "all"
|
|
** flag is set, then all MIB's (including read-only MIB's) are output.
|
|
**
|
|
** Returns: 0 - Success.
|
|
** 1 - Failure.
|
|
*/
|
|
|
|
static int wlancfg_show(
|
|
char *device, /* I: Device name. */
|
|
int all) /* I: "all" flag. */
|
|
{
|
|
int result;
|
|
req_spec_t mibget;
|
|
p80211ioctl_req_t req;
|
|
UINT8 msg[MSG_BUFF_LEN];
|
|
int skt, i, j, k, ncats, ngrps, nitems, out;
|
|
UINT32 did;
|
|
grplistitem_t *grp;
|
|
p80211meta_t *item;
|
|
char value[MSG_BUFF_LEN];
|
|
|
|
/*
|
|
** All MIB values will be queried using the "dot11req_mibget" request.
|
|
** Do some initialization for this request.
|
|
*/
|
|
|
|
result = wlancfg_reqspec("dot11req_mibget", &mibget);
|
|
if (result != 0) return(1);
|
|
|
|
/*
|
|
** Get a socket to be used to talk to the device driver and then
|
|
** set up the invariant parts of the "ioctl" request. The variable
|
|
** parts (i.e. length and result code) will be set later when the
|
|
** actual requests are created.
|
|
*/
|
|
|
|
skt = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (skt == -1)
|
|
{
|
|
perror("wlancfg");
|
|
return(1);
|
|
}
|
|
|
|
strncpy(req.name, device, sizeof(req.name));
|
|
req.magic = P80211_IOCTL_MAGIC; /* Set the magic. */
|
|
req.data = msg;
|
|
|
|
/*
|
|
** Scan through all the MIB's in all the groups in all the catagories.
|
|
** Output the MIB if it is writeable or if all MIB's are being output.
|
|
** However, DON'T output the MIB if it is not readable!
|
|
*/
|
|
|
|
ncats = GETMETASIZE(mib_catlist);
|
|
|
|
for (i = 1; i < ncats; i++)
|
|
{
|
|
ngrps = GETMETASIZE(mib_catlist[i].grplist);
|
|
|
|
for (j = 1; j < ngrps; j++)
|
|
{
|
|
did = P80211DID_MKSECTION(i) | P80211DID_MKGROUP(j);
|
|
grp = p80211_did2grp(mib_catlist, did);
|
|
if (grp == NULL) /* Should never happen. */
|
|
{
|
|
fprintf(stderr, "wlancfg: DID %lx not found.\n", did);
|
|
return(1);
|
|
}
|
|
|
|
item = grp->itemlist;
|
|
nitems = GETMETASIZE(item);
|
|
|
|
for (item++, k = 1; k < nitems; k++, item++)
|
|
{
|
|
out = all || ((item->did & P80211DID_ACCESS_WRITE) != 0);
|
|
out = out && ((item->did & P80211DID_ACCESS_READ) != 0);
|
|
if (out)
|
|
{
|
|
result = wlancfg_getvalue(device, item, &mibget,
|
|
skt, &req, value);
|
|
if (result != 0) return(1);
|
|
|
|
/*
|
|
** Output the value only if a value was found (i.e. skip
|
|
** unsupported MIB's).
|
|
*/
|
|
|
|
if (value[0] != '\0') printf("%s\n", value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*****************************************************************
|
|
**
|
|
** wlancfg_set
|
|
**
|
|
** Set the wlan parameters.
|
|
**
|
|
** Returns: 0 - Success.
|
|
** 1 - Failure.
|
|
*/
|
|
|
|
static int wlancfg_set(
|
|
char *device) /* I: Device name. */
|
|
{
|
|
int result;
|
|
req_spec_t mibset;
|
|
p80211ioctl_req_t req;
|
|
UINT8 msg[MSG_BUFF_LEN];
|
|
int skt;
|
|
char pair[500], *ch;
|
|
|
|
/*
|
|
** All MIB values will be set using the "dot11req_mibset" request.
|
|
** Do some initialization for this request.
|
|
*/
|
|
|
|
result = wlancfg_reqspec("dot11req_mibset", &mibset);
|
|
if (result != 0) return(1);
|
|
|
|
/*
|
|
** Get a socket to be used to talk to the device driver and then
|
|
** set up the invariant parts of the "ioctl" request. The variable
|
|
** parts (i.e. length and result code) will be set later when the
|
|
** actual requests are created.
|
|
*/
|
|
|
|
skt = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (skt == -1)
|
|
{
|
|
perror("wlancfg");
|
|
return(1);
|
|
}
|
|
|
|
strncpy(req.name, device, sizeof(req.name));
|
|
req.magic = P80211_IOCTL_MAGIC; /* Set the magic. */
|
|
req.data = msg;
|
|
|
|
/*
|
|
** Read MIB name/value pairs from "stdin" until there are no more.
|
|
** There should be one pair per line. The following things can happen
|
|
** with "fgets()":
|
|
**
|
|
** 1. Nothing is read (i.e. end of file). We are done.
|
|
** 2. The last character read is a '\n'. Strip the carriage return
|
|
** off and process the line.
|
|
** 3. No '\n' was read but the buffer was not filled. The last
|
|
** line in the file has been read. Process it. The next read
|
|
** should result in an end-of-file.
|
|
** 4. No '\n' was read and the buffer was filled. The line is
|
|
** too long. Abort things.
|
|
*/
|
|
|
|
while (1)
|
|
{
|
|
if (fgets(pair, sizeof(pair), stdin) == NULL) break;
|
|
ch = strrchr(pair, '\n');
|
|
if (ch != NULL)
|
|
*ch = '\0';
|
|
else
|
|
if (strlen(pair) >= sizeof(pair)-1)
|
|
{
|
|
fprintf(stderr, "wlancfg: MIB name/value is too long.\n");
|
|
return(1);
|
|
}
|
|
|
|
/*
|
|
** Set the MIB value.
|
|
*/
|
|
|
|
result = wlancfg_setvalue(device, &mibset, skt, &req, pair);
|
|
if (result != 0) return(1);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*****************************************************************
|
|
**
|
|
** wlancfg_list
|
|
**
|
|
** List all supported MIB's.
|
|
*/
|
|
|
|
static void wlancfg_list(void)
|
|
{
|
|
int i, j, k, l;
|
|
int ncat, ngrp, nitm;
|
|
int len, cnt, type;
|
|
catlistitem_t *cat;
|
|
grplistitem_t *grp;
|
|
p80211meta_t *mib;
|
|
p80211enum_t *enump;
|
|
|
|
/*
|
|
** Go through every MIB in every group in every catagory and find the
|
|
** maximum MIB name length.
|
|
*/
|
|
|
|
len = 0;
|
|
|
|
ncat = GETMETASIZE(mib_catlist);
|
|
cat = mib_catlist + 1;
|
|
|
|
for (i = 1; i < ncat; i++, cat++)
|
|
{
|
|
ngrp = GETMETASIZE(cat->grplist);
|
|
grp = (cat->grplist) + 1;
|
|
|
|
for (j = 1; j < ngrp; j++, grp++)
|
|
{
|
|
nitm = GETMETASIZE(grp->itemlist);
|
|
mib = grp->itemlist + 1;
|
|
|
|
for (k = 1; k < nitm; k++, mib++)
|
|
{
|
|
l = strlen(mib->name);
|
|
if (len < l) len = l;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Go through each MIB catagory.
|
|
*/
|
|
|
|
ncat = GETMETASIZE(mib_catlist);
|
|
cat = mib_catlist + 1;
|
|
|
|
for (i = 1; i < ncat; i++, cat++)
|
|
{
|
|
cnt = printf("\nCatagory: %s\n", cat->name);
|
|
for (j = 2; j < cnt; j++) printf("=");
|
|
printf("\n");
|
|
|
|
/*
|
|
** Go through each MIB in this group.
|
|
*/
|
|
|
|
ngrp = GETMETASIZE(cat->grplist);
|
|
grp = (cat->grplist) + 1;
|
|
|
|
for (j = 1; j < ngrp; j++, grp++)
|
|
{
|
|
printf("\n%s\n", grp->name);
|
|
nitm = GETMETASIZE(grp->itemlist);
|
|
mib = grp->itemlist + 1;
|
|
|
|
for (k = 1; k < nitm; k++, mib++)
|
|
{
|
|
cnt = printf(" %s", mib->name);
|
|
for (l = cnt-6; l < len; l++) printf(" ");
|
|
|
|
printf((mib->did & P80211DID_ACCESS_READ) ?
|
|
"R" : " ");
|
|
printf((mib->did & P80211DID_ACCESS_WRITE) ?
|
|
"W " : " ");
|
|
|
|
type = p80211item_gettype(mib);
|
|
|
|
if (type == P80211_TYPE_OCTETSTR)
|
|
printf("OCTETSTR{minlen=%ld,maxlen=%ld}\n",
|
|
mib->minlen, mib->maxlen);
|
|
else if (type == P80211_TYPE_DISPLAYSTR)
|
|
printf("DISPLAYSTR{minlen=%ld,maxlen=%ld}\n",
|
|
mib->minlen, mib->maxlen);
|
|
else if (type == P80211_TYPE_BOUNDEDINT)
|
|
printf("BOUNDEDINT{min=%ld,max=%ld}\n", mib->min, mib->max);
|
|
else if (type == P80211_TYPE_INT)
|
|
printf("INT\n");
|
|
else if (type == P80211_TYPE_ENUMINT)
|
|
{
|
|
printf("ENUMINT{");
|
|
enump = mib->enumptr;
|
|
for (l = 0; l < enump->nitems; l++)
|
|
{
|
|
printf("%s", enump->list[l].name);
|
|
if (l < enump->nitems - 1) printf("|");
|
|
}
|
|
printf("}\n");
|
|
}
|
|
else if (type == P80211_TYPE_UNKDATA)
|
|
printf("UNKDATA{maxlen=%ld}\n", mib->maxlen);
|
|
else if (type == P80211_TYPE_INTARRAY)
|
|
printf("INTARRAY{len=%ld}\n", mib->maxlen);
|
|
else if (type == P80211_TYPE_BITARRAY)
|
|
printf("BITARRAY{range=%ld-%ld}\n", mib->min, mib->max);
|
|
else if (type == P80211_TYPE_MACARRAY)
|
|
printf("MACARRAY{maxlen=%ld}\n", mib->maxlen);
|
|
else
|
|
printf("Unknown type!\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*****************************************************************
|
|
**
|
|
** wlancfg_reqspec
|
|
**
|
|
** Build the "request specification" structure for the "dot11req_mibget"
|
|
** or "dot11req_mibset" request. As well, verify that the request is as we
|
|
** expect it. Note that this verification shouldn't be necessary at all
|
|
** if we are sure that there is no bug in the request definition!
|
|
**
|
|
** Returns: 0 - Success.
|
|
** 1 - Failure.
|
|
*/
|
|
|
|
static int wlancfg_reqspec(
|
|
char *request, /* I: "dot11req_mibget" or "dot11req_mibset". */
|
|
req_spec_t *spec) /* O: Request specification. */
|
|
{
|
|
int result;
|
|
p80211meta_t *arglist;
|
|
|
|
/*
|
|
** Find the request message code.
|
|
*/
|
|
|
|
result = wlancfg_getreq("dot11req", request, 2, &spec->msgcode, &arglist);
|
|
if (result != 0) return(1);
|
|
|
|
/*
|
|
** Make sure that the first argument is "mibattribute". If so, then
|
|
** fill in the specification for the "mibattribute" argument. Make
|
|
** sure that the offset and length values are valid. Also, make sure
|
|
** that the "mibattribute" argument is flagged as "request" and that
|
|
** there are conversion functions defined for it.
|
|
*/
|
|
|
|
if (strcmp(arglist[1].name, "mibattribute") != 0)
|
|
{
|
|
fprintf(stderr, "wlancfg: First argument is not MIBATTRIBUTE.\n");
|
|
return(1);
|
|
}
|
|
|
|
spec->attptr = &arglist[1];
|
|
spec->attdid = spec->msgcode | P80211DID_MKITEM(1) | arglist[1].did;
|
|
spec->attoff = p80211item_getoffset(msg_catlist, spec->attdid);
|
|
spec->attlen = p80211item_maxdatalen(msg_catlist, spec->attdid);
|
|
|
|
if (spec->attoff == 0xffffffff || spec->attlen == 0xffffffffUL)
|
|
{
|
|
fprintf(stderr, "wlancfg: Invalid MIBATTRIBUTE offset or length.\n");
|
|
return(1);
|
|
}
|
|
|
|
if (!P80211ITEM_ISREQUEST(arglist[1].flags))
|
|
{
|
|
fprintf(stderr, "wlancfg: MIBATTRIBUTE argument is non-request.\n");
|
|
return(1);
|
|
}
|
|
|
|
if (arglist[1].fromtextptr == NULL || arglist[1].totextptr == NULL)
|
|
{
|
|
fprintf(stderr, "wlancfg: Missing MIBATTRIBUTE conversion function.\n");
|
|
return(1);
|
|
}
|
|
|
|
/*
|
|
** Make sure that the second argument is "resultcode". If so, then
|
|
** fill in the specification for the "resultcode" argument. Make
|
|
** sure that the offset and length values are valid. Also, make sure
|
|
** that it is not a required argument.
|
|
*/
|
|
|
|
if (strcmp(arglist[2].name, "resultcode") != 0)
|
|
{
|
|
fprintf(stderr, "wlancfg: Second argument is not RESULTCODE.\n");
|
|
return(1);
|
|
}
|
|
|
|
spec->resptr = &arglist[2];
|
|
spec->resdid = spec->msgcode | P80211DID_MKITEM(2) | arglist[2].did;
|
|
spec->resoff = p80211item_getoffset(msg_catlist, spec->resdid);
|
|
spec->reslen = p80211item_maxdatalen(msg_catlist, spec->resdid);
|
|
|
|
if (spec->resoff == 0xffffffff || spec->reslen == 0xffffffffUL)
|
|
{
|
|
fprintf(stderr, "wlancfg: Invalid RESULTCODE offset or length.\n");
|
|
return(1);
|
|
}
|
|
|
|
if ((P80211ITEM_ISREQUIRED(arglist[2].flags)) &&
|
|
(P80211ITEM_ISREQUEST(arglist[2].flags)))
|
|
{
|
|
fprintf(stderr, "wlancfg: RESULTCODE argument is required.\n");
|
|
return(1);
|
|
}
|
|
|
|
/*
|
|
** Set the message length. This should correspond to the "resultcode"
|
|
** argument. However, make the check general just in case the arguments
|
|
** were not defined as expected.
|
|
*/
|
|
|
|
spec->msglen = sizeof(p80211msg_t) + sizeof(p80211item_t);
|
|
|
|
if (spec->resoff > spec->attoff)
|
|
spec->msglen += spec->resoff + spec->reslen;
|
|
else
|
|
spec->msglen += spec->attoff + spec->attlen;
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*****************************************************************
|
|
**
|
|
** wlancfg_getvalue
|
|
**
|
|
** Get the value of the specified MIB. The value is returned as
|
|
** a name/value pair in the following syntax:
|
|
**
|
|
** name=value
|
|
**
|
|
** If the MIB is unsupported, then a 0-length string is returned.
|
|
**
|
|
** Returns: 0 - Success.
|
|
** 1 - Failure.
|
|
*/
|
|
|
|
static int wlancfg_getvalue(
|
|
char *device, /* I: Device name. */
|
|
p80211meta_t *item, /* I: Pointer to MIB item. */
|
|
req_spec_t *mibget, /* I: "dot11req_mibget" request spec. */
|
|
int skt, /* I: ioctl() socket. */
|
|
p80211ioctl_req_t *req, /* I: ioctl() request structure. */
|
|
char *value) /* O: MIB value. */
|
|
{
|
|
int result;
|
|
p80211msgd_t *msg;
|
|
|
|
/*
|
|
** Build the "dot11req_mibget" message.
|
|
*/
|
|
|
|
msg = (p80211msgd_t *) (req->data);
|
|
|
|
result = wlancfg_build(device, mibget, item->name, msg);
|
|
if (result != 0) return(1);
|
|
|
|
/*
|
|
** Set up the ioctl request.
|
|
*/
|
|
|
|
req->len = msg->msglen;
|
|
req->result = 0;
|
|
|
|
result = ioctl(skt, P80211_IFREQ, req);
|
|
if (result == -1)
|
|
{
|
|
perror("wlancfg");
|
|
return(1);
|
|
}
|
|
|
|
/*
|
|
** Convert the MIB value to a string.
|
|
*/
|
|
|
|
wlancfg_totext(item, mibget, msg, value);
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*****************************************************************
|
|
**
|
|
** wlancfg_setvalue
|
|
**
|
|
** Set the value of the specified MIB. The MIB must be specified as
|
|
** a name/value pair in the following syntax:
|
|
**
|
|
** name=value
|
|
**
|
|
** Returns: 0 - Success.
|
|
** 1 - Failure.
|
|
*/
|
|
|
|
static int wlancfg_setvalue(
|
|
char *device, /* I: Device name. */
|
|
req_spec_t *mibset, /* I: "dot11req_mibset" request spec. */
|
|
int skt, /* I: ioctl() socket. */
|
|
p80211ioctl_req_t *req, /* I: ioctl() request structure. */
|
|
char *value) /* I: MIB name/value. */
|
|
{
|
|
int result;
|
|
p80211msgd_t *msg;
|
|
p80211itemd_t *itmhdr;
|
|
UINT8 tmpitem[MSG_BUFF_LEN];
|
|
UINT32 resultcode;
|
|
|
|
/*
|
|
** Build the "dot11req_mibset" message.
|
|
*/
|
|
|
|
msg = (p80211msgd_t *) (req->data);
|
|
|
|
result = wlancfg_build(device, mibset, value, msg);
|
|
if (result != 0) return(1);
|
|
|
|
/*
|
|
** Set up the ioctl request.
|
|
*/
|
|
|
|
req->len = msg->msglen;
|
|
req->result = 0;
|
|
|
|
result = ioctl(skt, P80211_IFREQ, req);
|
|
if (result == -1)
|
|
{
|
|
perror("wlancfg");
|
|
return(1);
|
|
}
|
|
|
|
/*
|
|
** Get the result code and make sure that it has a value.
|
|
*/
|
|
|
|
itmhdr = (p80211itemd_t *) (msg->args + mibset->resoff);
|
|
|
|
if (itmhdr->status != P80211ENUM_msgitem_status_data_ok)
|
|
{
|
|
p80211_error2text(itmhdr->status, tmpitem);
|
|
fprintf(stderr, "wlancfg: %s resultcode=%s\n", value, tmpitem);
|
|
return(1);
|
|
}
|
|
|
|
/*
|
|
** Make sure that the request worked.
|
|
*/
|
|
|
|
resultcode = *((UINT32 *) (itmhdr->data));
|
|
|
|
if (resultcode != P80211ENUM_resultcode_success)
|
|
{
|
|
p80211_error2text(resultcode, tmpitem);
|
|
fprintf(stderr, "wlancfg: %s=%s\n", value, tmpitem);
|
|
return(1);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*****************************************************************
|
|
**
|
|
** wlancfg_build
|
|
**
|
|
** Build the request message buffer for either "dot11req_mibget"
|
|
** or "dot11req_mibset". For "dot11req_mibget", "value" should be the
|
|
** name of the MIB. For "dot11req_mibset", "value" should be the
|
|
** MIB name/value pair (i.e. name=value).
|
|
**
|
|
** Returns: 0 - Success.
|
|
** 1 - Failure.
|
|
*/
|
|
|
|
static int wlancfg_build(
|
|
char *device, /* I: Device name. */
|
|
req_spec_t *spec, /* I: Request specification. */
|
|
char *value, /* I: "mibattribute" argument value. */
|
|
p80211msgd_t *msg) /* O: Message buffer. */
|
|
{
|
|
p80211meta_t *arg;
|
|
char tmpstr[MSG_BUFF_LEN];
|
|
p80211itemd_t *itmhdr;
|
|
|
|
/*
|
|
** Initialize the message buffer.
|
|
*/
|
|
|
|
msg->msgcode = spec->msgcode;
|
|
msg->msglen = spec->msglen;
|
|
strncpy(msg->devname, device, WLAN_DEVNAMELEN_MAX - 1);
|
|
|
|
/*
|
|
** Add the "mibattribute" argument to the request buffer. Note that
|
|
** the "fromtextptr" conversion function looks for an "=" so we will
|
|
** need to create a value string that will keep it happy. Actually,
|
|
** what is expected is "mibattribute=....." but only the "=" is
|
|
** necessary.
|
|
*/
|
|
|
|
arg = spec->attptr;
|
|
itmhdr = (p80211itemd_t *) (msg->args + spec->attoff);
|
|
|
|
tmpstr[0] = '=';
|
|
strcpy(tmpstr+1, value);
|
|
|
|
memset(itmhdr, 0, sizeof(p80211item_t) + spec->attlen);
|
|
(*(arg->fromtextptr))(msg_catlist, spec->attdid, (UINT8 *) itmhdr, tmpstr);
|
|
|
|
if (itmhdr->status != (UINT16) P80211ENUM_msgitem_status_data_ok)
|
|
{
|
|
p80211_error2text(itmhdr->status, tmpstr);
|
|
fprintf(stderr, "wlancfg: %s=%s\n", value, tmpstr);
|
|
return(1);
|
|
}
|
|
|
|
/*
|
|
** Set the "resultcode" argument to "no value".
|
|
*/
|
|
|
|
itmhdr = (p80211itemd_t *) (msg->args + spec->resoff);
|
|
|
|
itmhdr->did = spec->resdid;
|
|
itmhdr->status = (UINT16) P80211ENUM_msgitem_status_no_value;
|
|
itmhdr->len = (UINT16) (spec->reslen);
|
|
|
|
memset(itmhdr->data, 0, spec->reslen);
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*****************************************************************
|
|
**
|
|
** wlancfg_totext
|
|
**
|
|
** Convert the MIB to a string. The value is returned as a name/value
|
|
** pair in the following syntax:
|
|
**
|
|
** name=value
|
|
**
|
|
** If the MIB cannot be converted for any reason, then a 0-length string is
|
|
** returned.
|
|
*/
|
|
|
|
static void wlancfg_totext(
|
|
p80211meta_t *item, /* I: Pointer to MIB item. */
|
|
req_spec_t *mibget, /* I: "dot11req_mibget" request specification. */
|
|
p80211msgd_t *msg, /* I: Message buffer. */
|
|
char *value) /* O: Value string. */
|
|
{
|
|
p80211itemd_t *itmhdr;
|
|
UINT8 tmpitem[MSG_BUFF_LEN];
|
|
UINT32 resultcode;
|
|
p80211meta_t *arg;
|
|
char *eq;
|
|
|
|
/*
|
|
** Initialize the string to a 0-length string just in case there
|
|
** is an error.
|
|
*/
|
|
|
|
value[0] = '\0';
|
|
|
|
/*
|
|
** Get the result code and make sure that it has a value.
|
|
*/
|
|
|
|
itmhdr = (p80211itemd_t *) (msg->args + mibget->resoff);
|
|
|
|
if (itmhdr->status != P80211ENUM_msgitem_status_data_ok)
|
|
{
|
|
p80211_error2text(itmhdr->status, tmpitem);
|
|
fprintf(stderr, "wlancfg: %s resultcode=%s\n", item->name, tmpitem);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
** If the result code is "not supported", then return the empty string
|
|
** with no error. Otherwise, there is an error.
|
|
*/
|
|
|
|
resultcode = *((UINT32 *) (itmhdr->data));
|
|
|
|
if (resultcode != P80211ENUM_resultcode_success)
|
|
{
|
|
if (resultcode != P80211ENUM_resultcode_not_supported)
|
|
{
|
|
p80211_error2text(resultcode, tmpitem);
|
|
fprintf(stderr, "wlancfg: %s=%s\n", item->name, tmpitem);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
** Get the MIB value and make sure that it has a value.
|
|
*/
|
|
|
|
arg = mibget->attptr;
|
|
|
|
itmhdr = (p80211itemd_t *) (msg->args + mibget->attoff);
|
|
|
|
if (itmhdr->status != P80211ENUM_msgitem_status_data_ok)
|
|
{
|
|
p80211_error2text(itmhdr->status, tmpitem);
|
|
fprintf(stderr, "wlancfg: %s mibattribute=%s\n", item->name, tmpitem);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
** Convert the MIB to a string. This will have the form:
|
|
**
|
|
** mibattribute=name=value
|
|
**
|
|
** Extract everthing after the first '='. Something went wrong if
|
|
** there is no "="...just return the empty string. Also, in some
|
|
** cases where the value does not exist, "totextptr" appears to
|
|
** neglect to add the "=" after the MIB name. If this happens, then
|
|
** add the "=" ourselves.
|
|
*/
|
|
|
|
(*(arg->totextptr))(msg_catlist, mibget->attdid, (UINT8 *) itmhdr, tmpitem);
|
|
|
|
eq = strchr(tmpitem, '=');
|
|
if (eq != NULL)
|
|
{
|
|
strcpy(value, eq+1);
|
|
if (strchr(value, '=') == NULL) strcat(value, "=");
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*****************************************************************
|
|
**
|
|
** wlancfg_getreq
|
|
**
|
|
** Find a request and verify its arguments.
|
|
**
|
|
** Returns: 0 - Success.
|
|
** 1 - Failure.
|
|
*/
|
|
|
|
static int wlancfg_getreq(
|
|
char *cat, /* I: Request catagory. */
|
|
char *name, /* I: Request name. */
|
|
int argcnt, /* I: Expected number of arguments. */
|
|
UINT32 *msgcode, /* O: Message code for request. */
|
|
p80211meta_t **arglist) /* O: Pointer to argument list. */
|
|
{
|
|
grplistitem_t *grp;
|
|
|
|
/*
|
|
** Find the request message code.
|
|
*/
|
|
|
|
*msgcode = p80211_text2did(msg_catlist, cat, name, NULL);
|
|
if (*msgcode == P80211DID_INVALID)
|
|
{
|
|
fprintf(stderr, "wlancfg: Could not find \"%s\" request.\n", name);
|
|
return(1);
|
|
}
|
|
|
|
/*
|
|
** Find find the argument metadata list for the request.
|
|
*/
|
|
|
|
grp = p80211_did2grp(msg_catlist, *msgcode);
|
|
if (grp == NULL)
|
|
{
|
|
fprintf(stderr, "wlancfg: Could not find \"%s\" arguments.\n", name);
|
|
return(1);
|
|
}
|
|
|
|
*arglist = grp->itemlist;
|
|
|
|
/*
|
|
** Make sure that the number of arguments is correct. Note that the list
|
|
** size is 1 more than the argument count!
|
|
*/
|
|
|
|
if (GETMETASIZE(*arglist) != argcnt+1)
|
|
{
|
|
fprintf(stderr, "wlancfg: \"%s\" argument count is wrong.\n", name);
|
|
return(1);
|
|
}
|
|
|
|
return(0);
|
|
}
|