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 <ctype.h> 26#include <sys/ioctl.h> 27#include <sys/socket.h> 28#include <net/if.h> 29#include <linux/types.h> 30 31typedef u_int64_t u64; 32typedef u_int32_t u32; 33typedef u_int16_t u16; 34typedef u_int8_t u8; 35#include <linux/sockios.h> 36#include <linux/ethtool.h> 37 38#include <shutils.h> 39#include <etutils.h> 40 41static int 42et_check(int s, struct ifreq *ifr) 43{ 44 struct ethtool_drvinfo info; 45 46 memset(&info, 0, sizeof(info)); 47 info.cmd = ETHTOOL_GDRVINFO; 48 ifr->ifr_data = (caddr_t)&info; 49 if (ioctl(s, SIOCETHTOOL, (caddr_t)ifr) < 0) { 50 /* print a good diagnostic if not superuser */ 51 if (errno == EPERM) 52 perror("not permit"); 53 return (-1); 54 } 55 56 if (!strncmp(info.driver, "et", 2)) 57 return (0); 58 else if (!strncmp(info.driver, "bcm57", 5)) 59 return (0); 60 61 return (-1); 62} 63 64static void 65et_find(int s, struct ifreq *ifr) 66{ 67 char proc_net_dev[] = "/proc/net/dev"; 68 FILE *fp = NULL; 69 char buf[512], *c, *name; 70 71 ifr->ifr_name[0] = '\0'; 72 73 /* eat first two lines */ 74 if (!(fp = fopen(proc_net_dev, "r")) || 75 !fgets(buf, sizeof(buf), fp) || 76 !fgets(buf, sizeof(buf), fp)) 77 goto done; 78 79 while (fgets(buf, sizeof(buf), fp)) { 80 c = buf; 81 while (isspace(*c)) 82 c++; 83 if (!(name = strsep(&c, ":"))) 84 continue; 85 if (!strncmp(name, "aux", 3)) 86 continue; 87 strncpy(ifr->ifr_name, name, IFNAMSIZ); 88 ifr->ifr_name[IFNAMSIZ-1] = '\0'; 89 if (et_check(s, ifr) == 0) 90 break; 91 ifr->ifr_name[0] = '\0'; 92 } 93 94done: 95 if (fp) 96 fclose(fp); 97} 98 99int 100et_iovar(char *name, int cmd, void *buf, int len, bool set) 101{ 102 struct ifreq ifr; 103 et_var_t var; 104 int s, ret = 0; 105 106 /* open socket to kernel */ 107 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 108 perror("socket"); 109 return errno; 110 } 111 112 /* get interface name if need */ 113 if (name) { 114 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)-1); 115 ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0'; 116 } 117 else 118 et_find(s, &ifr); 119 120 if (!*ifr.ifr_name) { 121 perror("et interface not found"); 122 ret = -1; 123 goto err; 124 } 125 126 /* do it */ 127 var.cmd = cmd; 128 var.buf = buf; 129 var.len = len; 130 var.set = set; 131 132 ifr.ifr_data = (caddr_t)&var; 133 if (ioctl(s, SIOCSETGETVAR, (caddr_t)&ifr) < 0) { 134 perror("ioctl"); 135 ret = errno; 136 } 137 138err: 139 close(s); 140 return ret; 141} 142 143#define ET_CAP_BUF_LEN (8 * 1024) 144 145bool 146et_capable(char *ifname, char *cap) 147{ 148 char var[32], *next; 149 char caps[ET_CAP_BUF_LEN]; 150 151 if (!cap) 152 return FALSE; 153 154 if (et_iovar(ifname, IOV_CAP, (void *)caps, sizeof(caps), FALSE)) 155 return FALSE; 156 157 foreach(var, caps, next) { 158 if (strncmp(var, cap, sizeof(var)) == 0) 159 return TRUE; 160 } 161 162 return FALSE; 163} 164