1 /*- 2 * Copyright (c) 2016 Adrian Chadd <adrian@FreeBSD.org>. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13 * redistribution must be conditioned upon including a substantially 14 * similar Disclaimer requirement for further binary redistribution. 15 * 16 * NO WARRANTY 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 * THE POSSIBILITY OF SUCH DAMAGES. 28 * 29 * $FreeBSD$ 30 */ 31 32 /* 33 * This is a simple abstraction of the control channel used to access 34 * device specific data. 35 * 36 * In the past it used a ifnet socket on athX, but since those devices 37 * are now gone, they can use wlanX. However, there are debug cases 38 * where you'll instead want to talk to the hardware before any VAPs are 39 * up, so we should also handle the case of talking to /dev/athX. 40 * 41 * For now this'll be a drop-in replacement for the existing ioctl() 42 * based method until the /dev/athX (and associated new ioctls) land 43 * in the tree. 44 */ 45 46 #include <sys/param.h> 47 #include <sys/file.h> 48 #include <sys/sockio.h> 49 #include <sys/socket.h> 50 51 #include <net/if.h> 52 #include <net/if_media.h> 53 #include <net/if_var.h> 54 55 #include <err.h> 56 #include <signal.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include <unistd.h> 61 62 #include "ah.h" 63 #include "ah_desc.h" 64 #include "net80211/ieee80211_ioctl.h" 65 #include "net80211/ieee80211_radiotap.h" 66 #include "if_athioctl.h" 67 #include "if_athrate.h" 68 69 #include "ctrl.h" 70 71 int 72 ath_driver_req_init(struct ath_driver_req *req) 73 { 74 75 bzero(req, sizeof(*req)); 76 req->s = -1; 77 return (0); 78 } 79 80 /* 81 * Open a suitable file descriptor and populate the relevant interface 82 * information for ioctls. 83 * 84 * For file path based access the ifreq isn't required; it'll just be 85 * a direct ioctl on the file descriptor. 86 */ 87 int 88 ath_driver_req_open(struct ath_driver_req *req, const char *ifname) 89 { 90 int s; 91 92 if (s != -1) 93 ath_driver_req_close(req); 94 95 /* For now, netif socket, not /dev/ filedescriptor */ 96 s = socket(AF_INET, SOCK_DGRAM, 0); 97 if (s < 0) { 98 warn("%s: socket", __func__); 99 return (-1); 100 } 101 req->ifname = strdup(ifname); 102 req->s = s; 103 104 return (0); 105 } 106 107 /* 108 * Close an open descriptor. 109 */ 110 int 111 ath_driver_req_close(struct ath_driver_req *req) 112 { 113 if (req->s == -1) 114 return (0); 115 close(req->s); 116 free(req->ifname); 117 req->s = -1; 118 req->ifname = NULL; 119 return (0); 120 } 121 122 /* 123 * Issue a diagnostic API request. 124 */ 125 int 126 ath_driver_req_fetch_diag(struct ath_driver_req *req, unsigned long cmd, 127 struct ath_diag *ad) 128 { 129 int ret; 130 131 ret = ioctl(req->s, cmd, ad); 132 if (ret < 0) 133 warn("%s: ioctl", __func__); 134 return (ret); 135 } 136 137 /* 138 * Issue a zero statistics API request. 139 */ 140 int 141 ath_driver_req_zero_stats(struct ath_driver_req *req) 142 { 143 struct ifreq ifr; 144 int ret; 145 146 /* Setup ifreq */ 147 bzero(&ifr, sizeof(ifr)); 148 strncpy(ifr.ifr_name, req->ifname, sizeof (ifr.ifr_name)); 149 ifr.ifr_data = NULL; 150 151 /* ioctl */ 152 ret = ioctl(req->s, SIOCZATHSTATS, &ifr); 153 if (ret < 0) 154 warn("%s: ioctl", __func__); 155 return (ret); 156 } 157 158 /* 159 * Fetch general statistics. 160 */ 161 int 162 ath_driver_req_fetch_stats(struct ath_driver_req *req, struct ath_stats *st) 163 { 164 struct ifreq ifr; 165 int ret; 166 167 /* Setup ifreq */ 168 bzero(&ifr, sizeof(ifr)); 169 strncpy(ifr.ifr_name, req->ifname, sizeof (ifr.ifr_name)); 170 ifr.ifr_data = (caddr_t) st; 171 172 /* ioctl */ 173 ret = ioctl(req->s, SIOCGATHSTATS, &ifr); 174 if (ret < 0) 175 warn("%s: ioctl", __func__); 176 return (ret); 177 } 178 179 /* 180 * Fetch aggregate statistics. 181 */ 182 int 183 ath_drive_req_fetch_aggr_stats(struct ath_driver_req *req, 184 struct ath_tx_aggr_stats *tx) 185 { 186 struct ifreq ifr; 187 int ret; 188 189 /* Setup ifreq */ 190 bzero(&ifr, sizeof(ifr)); 191 strncpy(ifr.ifr_name, req->ifname, sizeof (ifr.ifr_name)); 192 ifr.ifr_data = (caddr_t) tx; 193 194 /* ioctl */ 195 ret = ioctl(req->s, SIOCGATHAGSTATS, &ifr); 196 if (ret < 0) 197 warn("%s: ioctl", __func__); 198 return (ret); 199 200 } 201 202 /* 203 * Fetch rate control statistics. 204 * 205 * Caller has to populate the interface name and MAC address. 206 */ 207 int 208 ath_drive_req_fetch_ratectrl_stats(struct ath_driver_req *req, 209 struct ath_rateioctl *r) 210 { 211 int ret; 212 213 /* ioctl */ 214 ret = ioctl(req->s, SIOCGATHNODERATESTATS, r); 215 if (ret < 0) 216 warn("%s: ioctl", __func__); 217 return (ret); 218 } 219