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
71int
72ath_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 */
87int
88ath_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 */
110int
111ath_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 */
125int
126ath_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 */
140int
141ath_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 */
161int
162ath_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 */
182int
183ath_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 */
207int
208ath_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