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
30 /*
31 * This is a simple abstraction of the control channel used to access
32 * device specific data.
33 *
34 * In the past it used a ifnet socket on athX, but since those devices
35 * are now gone, they can use wlanX. However, there are debug cases
36 * where you'll instead want to talk to the hardware before any VAPs are
37 * up, so we should also handle the case of talking to /dev/athX.
38 *
39 * For now this'll be a drop-in replacement for the existing ioctl()
40 * based method until the /dev/athX (and associated new ioctls) land
41 * in the tree.
42 */
43
44 #include <sys/param.h>
45 #include <sys/file.h>
46 #include <sys/sockio.h>
47 #include <sys/socket.h>
48
49 #include <net/if.h>
50 #include <net/if_media.h>
51 #include <net/if_var.h>
52
53 #include <err.h>
54 #include <signal.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <unistd.h>
59
60 #include "ah.h"
61 #include "ah_desc.h"
62 #include "net80211/ieee80211_ioctl.h"
63 #include "net80211/ieee80211_radiotap.h"
64 #include "if_athioctl.h"
65 #include "if_athrate.h"
66
67 #include "ctrl.h"
68
69 int
ath_driver_req_init(struct ath_driver_req * req)70 ath_driver_req_init(struct ath_driver_req *req)
71 {
72
73 bzero(req, sizeof(*req));
74 req->s = -1;
75 return (0);
76 }
77
78 /*
79 * Open a suitable file descriptor and populate the relevant interface
80 * information for ioctls.
81 *
82 * For file path based access the ifreq isn't required; it'll just be
83 * a direct ioctl on the file descriptor.
84 */
85 int
ath_driver_req_open(struct ath_driver_req * req,const char * ifname)86 ath_driver_req_open(struct ath_driver_req *req, const char *ifname)
87 {
88 int s;
89
90 if (s != -1)
91 ath_driver_req_close(req);
92
93 /* For now, netif socket, not /dev/ filedescriptor */
94 s = socket(AF_INET, SOCK_DGRAM, 0);
95 if (s < 0) {
96 warn("%s: socket", __func__);
97 return (-1);
98 }
99 req->ifname = strdup(ifname);
100 req->s = s;
101
102 return (0);
103 }
104
105 /*
106 * Close an open descriptor.
107 */
108 int
ath_driver_req_close(struct ath_driver_req * req)109 ath_driver_req_close(struct ath_driver_req *req)
110 {
111 if (req->s == -1)
112 return (0);
113 close(req->s);
114 free(req->ifname);
115 req->s = -1;
116 req->ifname = NULL;
117 return (0);
118 }
119
120 /*
121 * Issue a diagnostic API request.
122 */
123 int
ath_driver_req_fetch_diag(struct ath_driver_req * req,unsigned long cmd,struct ath_diag * ad)124 ath_driver_req_fetch_diag(struct ath_driver_req *req, unsigned long cmd,
125 struct ath_diag *ad)
126 {
127 int ret;
128
129 ret = ioctl(req->s, cmd, ad);
130 if (ret < 0)
131 warn("%s: ioctl", __func__);
132 return (ret);
133 }
134
135 /*
136 * Issue a zero statistics API request.
137 */
138 int
ath_driver_req_zero_stats(struct ath_driver_req * req)139 ath_driver_req_zero_stats(struct ath_driver_req *req)
140 {
141 struct ifreq ifr;
142 int ret;
143
144 /* Setup ifreq */
145 bzero(&ifr, sizeof(ifr));
146 strncpy(ifr.ifr_name, req->ifname, sizeof (ifr.ifr_name));
147 ifr.ifr_data = NULL;
148
149 /* ioctl */
150 ret = ioctl(req->s, SIOCZATHSTATS, &ifr);
151 if (ret < 0)
152 warn("%s: ioctl", __func__);
153 return (ret);
154 }
155
156 /*
157 * Fetch general statistics.
158 */
159 int
ath_driver_req_fetch_stats(struct ath_driver_req * req,struct ath_stats * st)160 ath_driver_req_fetch_stats(struct ath_driver_req *req, struct ath_stats *st)
161 {
162 struct ifreq ifr;
163 int ret;
164
165 /* Setup ifreq */
166 bzero(&ifr, sizeof(ifr));
167 strncpy(ifr.ifr_name, req->ifname, sizeof (ifr.ifr_name));
168 ifr.ifr_data = (caddr_t) st;
169
170 /* ioctl */
171 ret = ioctl(req->s, SIOCGATHSTATS, &ifr);
172 if (ret < 0)
173 warn("%s: ioctl", __func__);
174 return (ret);
175 }
176
177 /*
178 * Fetch aggregate statistics.
179 */
180 int
ath_drive_req_fetch_aggr_stats(struct ath_driver_req * req,struct ath_tx_aggr_stats * tx)181 ath_drive_req_fetch_aggr_stats(struct ath_driver_req *req,
182 struct ath_tx_aggr_stats *tx)
183 {
184 struct ifreq ifr;
185 int ret;
186
187 /* Setup ifreq */
188 bzero(&ifr, sizeof(ifr));
189 strncpy(ifr.ifr_name, req->ifname, sizeof (ifr.ifr_name));
190 ifr.ifr_data = (caddr_t) tx;
191
192 /* ioctl */
193 ret = ioctl(req->s, SIOCGATHAGSTATS, &ifr);
194 if (ret < 0)
195 warn("%s: ioctl", __func__);
196 return (ret);
197
198 }
199
200 /*
201 * Fetch rate control statistics.
202 *
203 * Caller has to populate the interface name and MAC address.
204 */
205 int
ath_drive_req_fetch_ratectrl_stats(struct ath_driver_req * req,struct ath_rateioctl * r)206 ath_drive_req_fetch_ratectrl_stats(struct ath_driver_req *req,
207 struct ath_rateioctl *r)
208 {
209 int ret;
210
211 /* ioctl */
212 ret = ioctl(req->s, SIOCGATHNODERATESTATS, r);
213 if (ret < 0)
214 warn("%s: ioctl", __func__);
215 return (ret);
216 }
217