Home | History | Annotate | Download | only in dhdutil
      1 /*
      2  * Linux port of dhd command line utility, hacked from wl utility.
      3  *
      4  * Copyright (C) 1999-2013, Broadcom Corporation
      5  *
      6  * Permission to use, copy, modify, and/or distribute this software for any
      7  * purpose with or without fee is hereby granted, provided that the above
      8  * copyright notice and this permission notice appear in all copies.
      9  *
     10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
     13  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
     15  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
     16  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17  *
     18  * $Id: dhdu_linux.c 378962 2013-01-15 13:18:28Z $
     19  */
     20 
     21 #include <stdio.h>
     22 #include <stdlib.h>
     23 #include <unistd.h>
     24 #include <ctype.h>
     25 #include <string.h>
     26 #include <errno.h>
     27 #include <sys/types.h>
     28 #include <sys/wait.h>
     29 #include <sys/socket.h>
     30 #include <proto/ethernet.h>
     31 #include <proto/bcmip.h>
     32 #include <arpa/inet.h>
     33 #include <sys/ioctl.h>
     34 #include <net/if.h>
     35 #include <fcntl.h>
     36 #include <sys/ioctl.h>
     37 #include <unistd.h>
     38 
     39 #ifndef TARGETENV_android
     40 #include <error.h>
     41 typedef u_int64_t u64;
     42 typedef u_int32_t u32;
     43 typedef u_int16_t u16;
     44 typedef u_int8_t u8;
     45 #endif /* TARGETENV_android */
     46 #include <linux/sockios.h>
     47 #include <linux/types.h>
     48 #include <linux/ethtool.h>
     49 
     50 #include <typedefs.h>
     51 #include <signal.h>
     52 #include <dhdioctl.h>
     53 #include <wlioctl.h>
     54 #include <bcmcdc.h>
     55 #include <bcmutils.h>
     56 
     57 #if defined(RWL_WIFI) || defined(RWL_SOCKET) ||defined(RWL_SERIAL)
     58 #define RWL_ENABLE
     59 #endif
     60 
     61 #include "dhdu.h"
     62 #ifdef RWL_ENABLE
     63 #include "wlu_remote.h"
     64 #include "wlu_client_shared.h"
     65 #include "wlu_pipe.h"
     66 #endif /* RWL_ENABLE */
     67 #include <netdb.h>
     68 #include <netinet/in.h>
     69 #include <dhdioctl.h>
     70 #include "dhdu_common.h"
     71 #include "dhdu_nl80211.h"
     72 
     73 char *av0;
     74 static int rwl_os_type = LINUX_OS;
     75 /* Search the dhd_cmds table for a matching command name.
     76  * Return the matching command or NULL if no match found.
     77  */
     78 static cmd_t *
     79 dhd_find_cmd(char* name)
     80 {
     81 	cmd_t *cmd = NULL;
     82 	/* search the dhd_cmds for a matching name */
     83 	for (cmd = dhd_cmds; cmd->name && strcmp(cmd->name, name); cmd++);
     84 	if (cmd->name == NULL)
     85 		cmd = NULL;
     86 	return cmd;
     87 }
     88 
     89 static void
     90 syserr(const char *s)
     91 {
     92 	fprintf(stderr, "%s: ", av0);
     93 	perror(s);
     94 	exit(errno);
     95 }
     96 
     97 #ifdef NL80211
     98 static int __dhd_driver_io(void *dhd, dhd_ioctl_t *ioc)
     99 {
    100 	struct dhd_netlink_info dhd_nli;
    101 	struct ifreq *ifr = (struct ifreq *)dhd;
    102 	int ret = 0;
    103 
    104 	dhd_nli.ifidx = if_nametoindex(ifr->ifr_name);
    105 	if (!dhd_nli.ifidx) {
    106 		fprintf(stderr, "invalid device %s\n", ifr->ifr_name);
    107 		return BCME_IOCTL_ERROR;
    108 	}
    109 
    110 	if (dhd_nl_sock_connect(&dhd_nli) < 0)
    111 		syserr("socket");
    112 
    113 	ret = dhd_nl_do_testmode(&dhd_nli, ioc);
    114 	dhd_nl_sock_disconnect(&dhd_nli);
    115 	return ret;
    116 }
    117 #else
    118 static int __dhd_driver_io(void *dhd, dhd_ioctl_t *ioc)
    119 {
    120 	struct ifreq *ifr = (struct ifreq *)dhd;
    121 	int s;
    122 	int ret = 0;
    123 
    124 	/* pass ioctl data */
    125 	ifr->ifr_data = (caddr_t)ioc;
    126 
    127 	/* open socket to kernel */
    128 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    129 		syserr("socket");
    130 
    131 	ret = ioctl(s, SIOCDEVPRIVATE, ifr);
    132 	if (ret < 0 && errno != EAGAIN)
    133 		syserr(__FUNCTION__);
    134 
    135 	/* cleanup */
    136 	close(s);
    137 	return ret;
    138 }
    139 #endif /* NL80211 */
    140 
    141 /* This function is called by ioctl_setinformation_fe or ioctl_queryinformation_fe
    142  * for executing  remote commands or local commands
    143  */
    144 static int
    145 dhd_ioctl(void *dhd, int cmd, void *buf, int len, bool set)
    146 {
    147 	dhd_ioctl_t ioc;
    148 	int ret = 0;
    149 
    150 	/* By default try to execute wl commands */
    151 	int driver_magic = WLC_IOCTL_MAGIC;
    152 	int get_magic = WLC_GET_MAGIC;
    153 
    154 	/* For local dhd commands execute dhd. For wifi transport we still
    155 	 * execute wl commands.
    156 	 */
    157 	if (remote_type == NO_REMOTE && strncmp (buf, RWL_WIFI_ACTION_CMD,
    158 		strlen(RWL_WIFI_ACTION_CMD)) && strncmp(buf, RWL_WIFI_GET_ACTION_CMD,
    159 		strlen(RWL_WIFI_GET_ACTION_CMD))) {
    160 		driver_magic = DHD_IOCTL_MAGIC;
    161 		get_magic = DHD_GET_MAGIC;
    162 	}
    163 
    164 	/* do it */
    165 	ioc.cmd = cmd;
    166 	ioc.buf = buf;
    167 	ioc.len = len;
    168 	ioc.set = set;
    169 	ioc.driver = driver_magic;
    170 
    171 	ret = __dhd_driver_io(dhd, &ioc);
    172 	if (ret < 0 && cmd != get_magic)
    173 		ret = BCME_IOCTL_ERROR;
    174 	return ret;
    175 }
    176 
    177 /* This function is called in wlu_pipe.c remote_wifi_ser_init() to execute
    178  * the initial set of wl commands for wifi transport (e.g slow_timer, fast_timer etc)
    179  */
    180 int wl_ioctl(void *wl, int cmd, void *buf, int len, bool set)
    181 {
    182 	return dhd_ioctl(wl, cmd, buf, len, set); /* Call actual wl_ioctl here: Shubhro */
    183 }
    184 
    185 /* Search if dhd adapter or wl adapter is present
    186  * This is called by dhd_find to check if it supports wl or dhd
    187  * The reason for checking wl adapter is that we can still send remote dhd commands over
    188  * wifi transport.
    189  */
    190 static int
    191 dhd_get_dev_type(char *name, void *buf, char *type)
    192 {
    193 	int s;
    194 	int ret;
    195 	struct ifreq ifr;
    196 	struct ethtool_drvinfo info;
    197 
    198 	/* open socket to kernel */
    199 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    200 		syserr("socket");
    201 
    202 	/* get device type */
    203 	memset(&info, 0, sizeof(info));
    204 	info.cmd = ETHTOOL_GDRVINFO;
    205 	strcpy(info.driver, "?");
    206 	strcat(info.driver, type);
    207 	ifr.ifr_data = (caddr_t)&info;
    208 	strncpy(ifr.ifr_name, name, IFNAMSIZ);
    209 	if ((ret = ioctl(s, SIOCETHTOOL, &ifr)) < 0) {
    210 
    211 		if (errno != EAGAIN)
    212 			syserr(__FUNCTION__);
    213 
    214 		*(char *)buf = '\0';
    215 	}
    216 	else
    217 		strcpy(buf, info.driver);
    218 
    219 	close(s);
    220 	return ret;
    221 }
    222 
    223 /* dhd_get/dhd_set is called by several functions in dhdu.c. This used to call dhd_ioctl
    224  * directly. However now we need to execute the dhd commands remotely.
    225  * So we make use of wl pipes to execute this.
    226  * wl_get or wl_set functions also check if it is a local command hence they in turn
    227  * call dhd_ioctl if required. Name wl_get/wl_set is retained because these functions are
    228  * also called by wlu_pipe.c wlu_client_shared.c
    229  */
    230 int
    231 dhd_get(void *dhd, int cmd, void *buf, int len)
    232 {
    233 	return wl_get(dhd, cmd, buf, len);
    234 }
    235 
    236 /*
    237  * To use /dev/node interface:
    238  *   1.  mknod /dev/hnd0 c 248 0
    239  *   2.  chmod 777 /dev/hnd0
    240  */
    241 #define NODE "/dev/hnd0"
    242 
    243 int
    244 dhd_set(void *dhd, int cmd, void *buf, int len)
    245 {
    246 	static int dnode = -1;
    247 
    248 	switch (cmd) {
    249 	case DHD_DLDN_ST:
    250 		if (dnode == -1)
    251 			dnode = open(NODE, O_RDWR);
    252 		else
    253 			fprintf(stderr, "devnode already opened!\n");
    254 
    255 		return dnode;
    256 		break;
    257 	case DHD_DLDN_WRITE:
    258 		if (dnode > 0)
    259 			return write(dnode, buf, len);
    260 		break;
    261 	case DHD_DLDN_END:
    262 		if (dnode > 0)
    263 			return close(dnode);
    264 		break;
    265 	default:
    266 		return wl_set(dhd, cmd, buf, len);
    267 
    268 	}
    269 
    270 	return -1;
    271 }
    272 
    273 /* Verify the wl adapter found.
    274  * This is called by dhd_find to check if it supports wl
    275  * The reason for checking wl adapter is that we can still send remote dhd commands over
    276  * wifi transport. The function is copied from wlu.c.
    277  */
    278 int
    279 wl_check(void *wl)
    280 {
    281 	int ret;
    282 	int val = 0;
    283 
    284 	if (!dhd_check (wl))
    285 		return 0;
    286 
    287 	/*
    288 	 *  If dhd_check() fails then go for a regular wl driver verification
    289 	 */
    290 	if ((ret = wl_get(wl, WLC_GET_MAGIC, &val, sizeof(int))) < 0)
    291 		return ret;
    292 	if (val != WLC_IOCTL_MAGIC)
    293 		return BCME_ERROR;
    294 	if ((ret = wl_get(wl, WLC_GET_VERSION, &val, sizeof(int))) < 0)
    295 		return ret;
    296 	if (val > WLC_IOCTL_VERSION) {
    297 		fprintf(stderr, "Version mismatch, please upgrade\n");
    298 		return BCME_ERROR;
    299 	}
    300 	return 0;
    301 }
    302 /* Search and verify the request type of adapter (wl or dhd)
    303  * This is called by main before executing local dhd commands
    304  * or sending remote dhd commands over wifi transport
    305  */
    306 void
    307 dhd_find(struct ifreq *ifr, char *type)
    308 {
    309 	char proc_net_dev[] = "/proc/net/dev";
    310 	FILE *fp;
    311 	static char buf[400];
    312 	char *c, *name;
    313 	char dev_type[32];
    314 
    315 	ifr->ifr_name[0] = '\0';
    316 	/* eat first two lines */
    317 	if (!(fp = fopen(proc_net_dev, "r")) ||
    318 	    !fgets(buf, sizeof(buf), fp) ||
    319 	    !fgets(buf, sizeof(buf), fp))
    320 		return;
    321 
    322 	while (fgets(buf, sizeof(buf), fp)) {
    323 		c = buf;
    324 		while (isspace(*c))
    325 			c++;
    326 		if (!(name = strsep(&c, ":")))
    327 			continue;
    328 		strncpy(ifr->ifr_name, name, IFNAMSIZ);
    329 		if (dhd_get_dev_type(name, dev_type, type) >= 0 &&
    330 			!strncmp(dev_type, type, strlen(dev_type) - 1))
    331 		{
    332 			if (!wl_check((void*)ifr))
    333 				break;
    334 		}
    335 		ifr->ifr_name[0] = '\0';
    336 	}
    337 
    338 	fclose(fp);
    339 }
    340 /* This function is called by wl_get to execute either local dhd command
    341  * or send a dhd command over wl transport
    342  */
    343 static int
    344 ioctl_queryinformation_fe(void *wl, int cmd, void* input_buf, int *input_len)
    345 {
    346 	if (remote_type == NO_REMOTE) {
    347 		return dhd_ioctl(wl, cmd, input_buf, *input_len, FALSE);
    348 	}
    349 #ifdef RWL_ENABLE
    350 	else {
    351 		return rwl_queryinformation_fe(wl, cmd, input_buf,
    352 			(unsigned long*)input_len, 0, RDHD_GET_IOCTL);
    353 	}
    354 #else /* RWL_ENABLE */
    355 	return BCME_IOCTL_ERROR;
    356 #endif /* RWL_ENABLE */
    357 }
    358 
    359 /* This function is called by wl_set to execute either local dhd command
    360  * or send a dhd command over wl transport
    361  */
    362 static int
    363 ioctl_setinformation_fe(void *wl, int cmd, void* buf, int *len)
    364 {
    365 	if (remote_type == NO_REMOTE) {
    366 		return dhd_ioctl(wl,  cmd, buf, *len, TRUE);
    367 	}
    368 #ifdef RWL_ENABLE
    369 	else {
    370 		return rwl_setinformation_fe(wl, cmd, buf, (unsigned long*)len, 0, RDHD_SET_IOCTL);
    371 
    372 	}
    373 #else /* RWL_ENABLE */
    374 	return BCME_IOCTL_ERROR;
    375 #endif /* RWL_ENABLE */
    376 }
    377 
    378 /* The function is replica of wl_get in wlu_linux.c. Optimize when we have some
    379  * common code between wlu_linux.c and dhdu_linux.c
    380  */
    381 int
    382 wl_get(void *wl, int cmd, void *buf, int len)
    383 {
    384 	int error = BCME_OK;
    385 	/* For RWL: When interfacing to a Windows client, need t add in OID_BASE */
    386 	if ((rwl_os_type == WIN32_OS) && (remote_type != NO_REMOTE)) {
    387 		error = (int)ioctl_queryinformation_fe(wl, WL_OID_BASE + cmd, buf, &len);
    388 	} else {
    389 		error = (int)ioctl_queryinformation_fe(wl, cmd, buf, &len);
    390 	}
    391 	if (error == BCME_SERIAL_PORT_ERR)
    392 		return BCME_SERIAL_PORT_ERR;
    393 
    394 	if (error != 0)
    395 		return BCME_IOCTL_ERROR;
    396 
    397 	return error;
    398 }
    399 
    400 /* The function is replica of wl_set in wlu_linux.c. Optimize when we have some
    401  * common code between wlu_linux.c and dhdu_linux.c
    402  */
    403 int
    404 wl_set(void *wl, int cmd, void *buf, int len)
    405 {
    406 	int error = BCME_OK;
    407 
    408 	/* For RWL: When interfacing to a Windows client, need t add in OID_BASE */
    409 	if ((rwl_os_type == WIN32_OS) && (remote_type != NO_REMOTE)) {
    410 		error = (int)ioctl_setinformation_fe(wl, WL_OID_BASE + cmd, buf, &len);
    411 	} else {
    412 		error = (int)ioctl_setinformation_fe(wl, cmd, buf, &len);
    413 	}
    414 
    415 	if (error == BCME_SERIAL_PORT_ERR)
    416 		return BCME_SERIAL_PORT_ERR;
    417 
    418 	if (error != 0) {
    419 		return BCME_IOCTL_ERROR;
    420 	}
    421 	return error;
    422 }
    423 
    424 int
    425 wl_validatedev(void *dev_handle)
    426 {
    427 	int retval = 1;
    428 	struct ifreq *ifr = (struct ifreq *)dev_handle;
    429 	/* validate the interface */
    430 	if (!ifr->ifr_name || wl_check((void *)ifr)) {
    431 		retval = 0;
    432 	}
    433 	return retval;
    434 }
    435 
    436 /* Main client function
    437  * The code is mostly from wlu_linux.c. This function takes care of executing remote dhd commands
    438  * along with the local dhd commands now.
    439  */
    440 int
    441 main(int argc, char **argv)
    442 {
    443 	struct ifreq ifr;
    444 	char *ifname = NULL;
    445 	int err = 0;
    446 	int help = 0;
    447 	int status = CMD_DHD;
    448 #ifdef RWL_SOCKET
    449 	struct ipv4_addr temp;
    450 #endif /* RWL_SOCKET */
    451 
    452 	UNUSED_PARAMETER(argc);
    453 
    454 	av0 = argv[0];
    455 	memset(&ifr, 0, sizeof(ifr));
    456 	argv++;
    457 
    458 	if ((status = dhd_option(&argv, &ifname, &help)) == CMD_OPT) {
    459 		if (ifname)
    460 			strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
    461 	}
    462 	/* Linux client looking for a Win32 server */
    463 	if (*argv && strncmp (*argv, "--wince", strlen(*argv)) == 0) {
    464 		rwl_os_type = WIN32_OS;
    465 		argv++;
    466 	}
    467 
    468 	/* RWL socket transport Usage: --socket ipaddr [port num] */
    469 	if (*argv && strncmp (*argv, "--socket", strlen(*argv)) == 0) {
    470 		argv++;
    471 
    472 		remote_type = REMOTE_SOCKET;
    473 #ifdef RWL_SOCKET
    474 		if (!(*argv)) {
    475 			rwl_usage(remote_type);
    476 			return err;
    477 		}
    478 
    479 		if (!dhd_atoip(*argv, &temp)) {
    480 			rwl_usage(remote_type);
    481 			return err;
    482 		}
    483 		g_rwl_servIP = *argv;
    484 		argv++;
    485 
    486 		g_rwl_servport = DEFAULT_SERVER_PORT;
    487 		if ((*argv) && isdigit(**argv)) {
    488 			g_rwl_servport = atoi(*argv);
    489 			argv++;
    490 		}
    491 #endif /* RWL_SOCKET */
    492 	}
    493 
    494 	/* RWL from system serial port on client to uart dongle port on server */
    495 	/* Usage: --dongle /dev/ttyS0 */
    496 	if (*argv && strncmp (*argv, "--dongle", strlen(*argv)) == 0) {
    497 		argv++;
    498 		remote_type = REMOTE_DONGLE;
    499 	}
    500 
    501 	/* RWL over wifi.  Usage: --wifi mac_address */
    502 	if (*argv && strncmp (*argv, "--wifi", strlen(*argv)) == 0) {
    503 		argv++;
    504 #ifdef RWL_WIFI
    505 		remote_type = NO_REMOTE;
    506 		if (!ifr.ifr_name[0])
    507 		{
    508 			dhd_find(&ifr, "wl");
    509 		}
    510 		/* validate the interface */
    511 		if (!ifr.ifr_name[0] || wl_check((void*)&ifr)) {
    512 			fprintf(stderr, "%s: wl driver adapter not found\n", av0);
    513 			exit(1);
    514 		}
    515 		remote_type = REMOTE_WIFI;
    516 
    517 		if (argc < 4) {
    518 			rwl_usage(remote_type);
    519 			return err;
    520 		}
    521 		/* copy server mac address to local buffer for later use by findserver cmd */
    522 		if (!dhd_ether_atoe(*argv, (struct ether_addr *)g_rwl_buf_mac)) {
    523 			fprintf(stderr,
    524 			        "could not parse as an ethernet MAC address\n");
    525 			return FAIL;
    526 		}
    527 		argv++;
    528 #else /* RWL_WIFI */
    529 		remote_type = REMOTE_WIFI;
    530 #endif /* RWL_WIFI */
    531 	}
    532 
    533 	/* Process for local dhd */
    534 	if (remote_type == NO_REMOTE) {
    535 		err = process_args(&ifr, argv);
    536 		return err;
    537 	}
    538 
    539 #ifdef RWL_ENABLE
    540 	if (*argv) {
    541 		err = process_args(&ifr, argv);
    542 		if ((err == BCME_SERIAL_PORT_ERR) && (remote_type == REMOTE_DONGLE)) {
    543 			DPRINT_ERR(ERR, "\n Retry again\n");
    544 			err = process_args((struct ifreq*)&ifr, argv);
    545 		}
    546 		return err;
    547 	}
    548 	rwl_usage(remote_type);
    549 #endif /* RWL_ENABLE */
    550 
    551 	return err;
    552 }
    553 /*
    554  * Function called for  'local' execution and for 'remote' non-interactive session
    555  * (shell cmd, wl cmd) .The code is mostly from wlu_linux.c. This code can be
    556  * common to wlu_linux.c and dhdu_linux.c
    557  */
    558 static int
    559 process_args(struct ifreq* ifr, char **argv)
    560 {
    561 	char *ifname = NULL;
    562 	int help = 0;
    563 	int status = 0;
    564 	int err = BCME_OK;
    565 	cmd_t *cmd = NULL;
    566 	while (*argv) {
    567 #ifdef RWL_ENABLE
    568 		if ((strcmp (*argv, "sh") == 0) && (remote_type != NO_REMOTE)) {
    569 			argv++; /* Get the shell command */
    570 			if (*argv) {
    571 				/* Register handler in case of shell command only */
    572 				signal(SIGINT, ctrlc_handler);
    573 				err = rwl_shell_cmd_proc((void*)ifr, argv, SHELL_CMD);
    574 			} else {
    575 				DPRINT_ERR(ERR,
    576 				"Enter the shell command (e.g ls(Linux) or dir(Win CE) \n");
    577 				err = BCME_ERROR;
    578 			}
    579 			return err;
    580 		}
    581 #endif /* RWL_ENABLE */
    582 		if ((status = dhd_option(&argv, &ifname, &help)) == CMD_OPT) {
    583 			if (help)
    584 				break;
    585 			if (ifname)
    586 				strncpy(ifr->ifr_name, ifname, IFNAMSIZ);
    587 			continue;
    588 		}
    589 		/* parse error */
    590 		else if (status == CMD_ERR)
    591 		    break;
    592 
    593 		if (remote_type == NO_REMOTE) {
    594 			int ret;
    595 
    596 			/* use default interface */
    597 			if (!ifr->ifr_name[0])
    598 				dhd_find(ifr, "dhd");
    599 			/* validate the interface */
    600 			if (!ifr->ifr_name[0]) {
    601 				if (strcmp("dldn", *argv) != 0) {
    602 					exit(ENXIO);
    603 					syserr("interface");
    604 				}
    605 			}
    606 			if ((ret = dhd_check((void *)ifr)) != 0) {
    607 				if (strcmp("dldn", *argv) != 0) {
    608 					errno = -ret;
    609 					syserr("dhd_check");
    610 				}
    611 			}
    612 		}
    613 		/* search for command */
    614 		cmd = dhd_find_cmd(*argv);
    615 		/* if not found, use default set_var and get_var commands */
    616 		if (!cmd) {
    617 			cmd = &dhd_varcmd;
    618 		}
    619 
    620 		/* do command */
    621 		err = (*cmd->func)((void *) ifr, cmd, argv);
    622 		break;
    623 	} /* while loop end */
    624 
    625 	/* provide for help on a particular command */
    626 	if (help && *argv) {
    627 		cmd = dhd_find_cmd(*argv);
    628 		if (cmd) {
    629 			dhd_cmd_usage(cmd);
    630 		} else {
    631 			DPRINT_ERR(ERR, "%s: Unrecognized command \"%s\", type -h for help\n",
    632 			           av0, *argv);
    633 		}
    634 	} else if (!cmd)
    635 		dhd_usage(NULL);
    636 	else if (err == BCME_USAGE_ERROR)
    637 		dhd_cmd_usage(cmd);
    638 	else if (err == BCME_IOCTL_ERROR)
    639 		dhd_printlasterror((void *) ifr);
    640 
    641 	return err;
    642 }
    643 
    644 int
    645 rwl_shell_createproc(void *wl)
    646 {
    647 	UNUSED_PARAMETER(wl);
    648 	return fork();
    649 }
    650 
    651 void
    652 rwl_shell_killproc(int pid)
    653 {
    654 	kill(pid, SIGKILL);
    655 }
    656 
    657 #ifdef RWL_SOCKET
    658 /* validate hostname/ip given by the client */
    659 int
    660 validate_server_address()
    661 {
    662 	struct hostent *he;
    663 	struct ipv4_addr temp;
    664 
    665 	if (!dhd_atoip(g_rwl_servIP, &temp)) {
    666 	/* Wrong IP address format check for hostname */
    667 		if ((he = gethostbyname(g_rwl_servIP)) != NULL) {
    668 			if (!dhd_atoip(*he->h_addr_list, &temp)) {
    669 				g_rwl_servIP = inet_ntoa(*(struct in_addr *)*he->h_addr_list);
    670 				if (g_rwl_servIP == NULL) {
    671 					DPRINT_ERR(ERR, "Error at inet_ntoa \n");
    672 					return FAIL;
    673 				}
    674 			} else {
    675 				DPRINT_ERR(ERR, "Error in IP address \n");
    676 				return FAIL;
    677 			}
    678 		} else {
    679 			DPRINT_ERR(ERR, "Enter correct IP address/hostname format\n");
    680 			return FAIL;
    681 		}
    682 	}
    683 	return SUCCESS;
    684 }
    685 #endif /* RWL_SOCKET */
    686