1/*
2 * Wireless network adapter utilities (linux-specific)
3 *
4 * Copyright (C) 2014, Broadcom Corporation. All Rights Reserved.
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: wl_linux.c 435840 2013-11-12 09:30:26Z $
19 */
20
21#include <stdio.h>
22#include <unistd.h>
23#include <string.h>
24#include <errno.h>
25#include <sys/ioctl.h>
26#include <sys/socket.h>
27#include <net/if.h>
28#include <linux/types.h>
29
30typedef u_int64_t u64;
31typedef u_int32_t u32;
32typedef u_int16_t u16;
33typedef u_int8_t u8;
34#include <linux/sockios.h>
35#include <linux/ethtool.h>
36
37#include <typedefs.h>
38#include <wlioctl.h>
39#include <wlutils.h>
40
41
42int
43wl_ioctl(char *name, int cmd, void *buf, int len)
44{
45	struct ifreq ifr;
46	wl_ioctl_t ioc;
47	int ret = 0;
48	int s;
49	char buffer[100];
50
51	/* open socket to kernel */
52	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
53		perror("socket");
54		return errno;
55	}
56
57	/* do it */
58	ioc.cmd = cmd;
59	ioc.buf = buf;
60	ioc.len = len;
61
62	/* initializing the remaining fields */
63	ioc.set = FALSE;
64	ioc.used = 0;
65	ioc.needed = 0;
66
67	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name) - 1);
68	ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
69	ifr.ifr_data = (caddr_t) &ioc;
70	if ((ret = ioctl(s, SIOCDEVPRIVATE, &ifr)) < 0)
71		if (cmd != WLC_GET_MAGIC && cmd != WLC_GET_BSSID) {
72			if ((cmd == WLC_GET_VAR) || (cmd == WLC_SET_VAR)) {
73				snprintf(buffer, sizeof(buffer), "%s: WLC_%s_VAR(%s)", name,
74				         cmd == WLC_GET_VAR ? "GET" : "SET", (char *)buf);
75			} else {
76				snprintf(buffer, sizeof(buffer), "%s: cmd=%d", name, cmd);
77			}
78			perror(buffer);
79		}
80	/* cleanup */
81	close(s);
82	return ret;
83}
84
85int
86wl_get_dev_type(char *name, void *buf, int len)
87{
88	int s;
89	int ret;
90	struct ifreq ifr;
91	struct ethtool_drvinfo info;
92
93	/* open socket to kernel */
94	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
95		perror("socket");
96		return -1;
97	}
98
99	/* get device type */
100	memset(&info, 0, sizeof(info));
101	info.cmd = ETHTOOL_GDRVINFO;
102	ifr.ifr_data = (caddr_t)&info;
103	strncpy(ifr.ifr_name, name, IFNAMSIZ);
104	if ((ret = ioctl(s, SIOCETHTOOL, &ifr)) < 0) {
105		*(char *)buf = '\0';
106	} else
107		strncpy(buf, info.driver, len);
108
109	close(s);
110	return ret;
111}
112
113int
114wl_hwaddr(char *name, unsigned char *hwaddr)
115{
116	struct ifreq ifr;
117	int ret = 0;
118	int s;
119
120	/* open socket to kernel */
121	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
122		perror("socket");
123		return errno;
124	}
125
126	/* do it */
127	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)-1);
128	ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0';
129	if ((ret = ioctl(s, SIOCGIFHWADDR, &ifr)) == 0)
130		memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN);
131
132	/* cleanup */
133	close(s);
134	return ret;
135}
136