1168404Spjd/*-
2168404Spjd * Copyright (c) 2013 Chelsio Communications, Inc.
3168404Spjd * All rights reserved.
4168404Spjd * Written by: Navdeep Parhar <np@FreeBSD.org>
5168404Spjd *
6168404Spjd * Redistribution and use in source and binary forms, with or without
7168404Spjd * modification, are permitted provided that the following conditions
8168404Spjd * are met:
9168404Spjd * 1. Redistributions of source code must retain the above copyright
10168404Spjd *    notice, this list of conditions and the following disclaimer.
11168404Spjd * 2. Redistributions in binary form must reproduce the above copyright
12168404Spjd *    notice, this list of conditions and the following disclaimer in the
13168404Spjd *    documentation and/or other materials provided with the distribution.
14168404Spjd *
15168404Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16168404Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17168404Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18168404Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19168404Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20168404Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21168404Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22219089Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23268657Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24168404Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25168404Spjd * SUCH DAMAGE.
26219089Spjd */
27219089Spjd
28168404Spjd#include <sys/cdefs.h>
29168404Spjd__FBSDID("$FreeBSD: releng/10.3/sys/dev/cxgbe/t4_tracer.c 270297 2014-08-21 19:54:02Z np $");
30168404Spjd
31168404Spjd#include "opt_inet.h"
32168404Spjd#include "opt_inet6.h"
33168404Spjd
34168404Spjd#include <sys/param.h>
35168404Spjd#include <sys/lock.h>
36168404Spjd#include <sys/types.h>
37168404Spjd#include <sys/mbuf.h>
38219089Spjd#include <sys/socket.h>
39168404Spjd#include <sys/sockio.h>
40219089Spjd#include <sys/sx.h>
41168404Spjd#include <net/bpf.h>
42168404Spjd#include <net/ethernet.h>
43168404Spjd#include <net/if.h>
44168404Spjd#include <net/if_clone.h>
45168404Spjd#include <net/if_types.h>
46168404Spjd
47168404Spjd#include "common/common.h"
48168404Spjd#include "common/t4_msg.h"
49168404Spjd#include "common/t4_regs.h"
50168404Spjd#include "t4_ioctl.h"
51168404Spjd
52168404Spjd/*
53168404Spjd * Locking notes
54168404Spjd * =============
55168404Spjd *
56168404Spjd * An interface cloner is registered during mod_load and it can be used to
57168404Spjd * create or destroy the tracing ifnet for an adapter at any time.  It is
58168404Spjd * possible for the cloned interface to outlive the adapter (adapter disappears
59168404Spjd * in t4_detach but the tracing ifnet may live till mod_unload when removal of
60168404Spjd * the cloner finally destroys any remaining cloned interfaces).  When tracing
61168404Spjd * filters are active, this ifnet is also receiving data.  There are potential
62168404Spjd * bad races between ifnet create, ifnet destroy, ifnet rx, ifnet ioctl,
63168404Spjd * cxgbe_detach/t4_detach, mod_unload.
64168404Spjd *
65168404Spjd * a) The driver selects an iq for tracing (sc->traceq) inside a synch op.  The
66168404Spjd *    iq is destroyed inside a synch op too (and sc->traceq updated).
67168404Spjd * b) The cloner looks for an adapter that matches the name of the ifnet it's
68168404Spjd *    been asked to create, starts a synch op on that adapter, and proceeds only
69251631Sdelphij *    if the adapter has a tracing iq.
70168404Spjd * c) The cloned ifnet and the adapter are coupled to each other via
71251631Sdelphij *    ifp->if_softc and sc->ifp.  These can be modified only with the global
72168404Spjd *    t4_trace_lock sx as well as the sc->ifp_lock mutex held.  Holding either
73219089Spjd *    of these will prevent any change.
74219089Spjd *
75219089Spjd * The order in which all the locks involved should be acquired are:
76168404Spjd * t4_list_lock
77168404Spjd * adapter lock
78168404Spjd * (begin synch op and let go of the above two)
79168404Spjd * t4_trace_lock
80168404Spjd * sc->ifp_lock
81168404Spjd */
82168404Spjd
83168404Spjdstatic struct sx t4_trace_lock;
84168404Spjdstatic const char *t4_cloner_name = "tXnex";
85168404Spjdstatic struct if_clone *t4_cloner;
86249921Ssmh
87249921Ssmh/* tracer ifnet routines.  mostly no-ops. */
88249921Ssmhstatic void tracer_init(void *);
89249921Ssmhstatic int tracer_ioctl(struct ifnet *, unsigned long, caddr_t);
90249921Ssmhstatic int tracer_transmit(struct ifnet *, struct mbuf *);
91168404Spjdstatic void tracer_qflush(struct ifnet *);
92168404Spjdstatic int tracer_media_change(struct ifnet *);
93168404Spjdstatic void tracer_media_status(struct ifnet *, struct ifmediareq *);
94219089Spjd
95219089Spjd/* match name (request/response) */
96219089Spjdstruct match_rr {
97219089Spjd	const char *name;
98219089Spjd	int lock;	/* set to 1 to returned sc locked. */
99219089Spjd	struct adapter *sc;
100219089Spjd	int rc;
101219089Spjd};
102219089Spjd
103219089Spjdstatic void
104219089Spjdmatch_name(struct adapter *sc, void *arg)
105219089Spjd{
106219089Spjd	struct match_rr *mrr = arg;
107219089Spjd
108219089Spjd	if (strcmp(device_get_nameunit(sc->dev), mrr->name) != 0)
109168404Spjd		return;
110219089Spjd
111168404Spjd	KASSERT(mrr->sc == NULL, ("%s: multiple matches (%p, %p) for %s",
112219089Spjd	    __func__, mrr->sc, sc, mrr->name));
113219089Spjd
114168404Spjd	mrr->sc = sc;
115168404Spjd	if (mrr->lock)
116168404Spjd		mrr->rc = begin_synchronized_op(mrr->sc, NULL, 0, "t4clon");
117168404Spjd	else
118168404Spjd		mrr->rc = 0;
119168404Spjd}
120168404Spjd
121168404Spjdstatic int
122168404Spjdt4_cloner_match(struct if_clone *ifc, const char *name)
123168404Spjd{
124168404Spjd
125168404Spjd	if (strncmp(name, "t4nex", 5) != 0 &&
126168404Spjd	    strncmp(name, "t5nex", 5) != 0)
127168404Spjd		return (0);
128168404Spjd	if (name[5] < '0' || name[5] > '9')
129219089Spjd		return (0);
130168404Spjd	return (1);
131219089Spjd}
132219089Spjd
133168404Spjdstatic int
134168404Spjdt4_cloner_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
135168404Spjd{
136219089Spjd	struct match_rr mrr;
137168404Spjd	struct adapter *sc;
138219089Spjd	struct ifnet *ifp;
139219089Spjd	int rc, unit;
140168404Spjd	const uint8_t lla[ETHER_ADDR_LEN] = {0, 0, 0, 0, 0, 0};
141168404Spjd
142168404Spjd	mrr.name = name;
143219089Spjd	mrr.lock = 1;
144168404Spjd	mrr.sc = NULL;
145168404Spjd	mrr.rc = ENOENT;
146168404Spjd	t4_iterate(match_name, &mrr);
147168404Spjd
148219089Spjd	if (mrr.rc != 0)
149219089Spjd		return (mrr.rc);
150168404Spjd	sc = mrr.sc;
151219089Spjd
152268649Sdelphij	KASSERT(sc != NULL, ("%s: name (%s) matched but softc is NULL",
153219089Spjd	    __func__, name));
154168404Spjd	ASSERT_SYNCHRONIZED_OP(sc);
155168404Spjd
156268649Sdelphij	sx_xlock(&t4_trace_lock);
157268649Sdelphij
158268649Sdelphij	if (sc->ifp != NULL) {
159268649Sdelphij		rc = EEXIST;
160268649Sdelphij		goto done;
161168404Spjd	}
162249195Smm	if (sc->traceq < 0) {
163168404Spjd		rc = EAGAIN;
164219089Spjd		goto done;
165168404Spjd	}
166168404Spjd
167168404Spjd
168168404Spjd	unit = -1;
169168404Spjd	rc = ifc_alloc_unit(ifc, &unit);
170168404Spjd	if (rc != 0)
171168404Spjd		goto done;
172168404Spjd
173168404Spjd	ifp = if_alloc(IFT_ETHER);
174168404Spjd	if (ifp == NULL) {
175168404Spjd		ifc_free_unit(ifc, unit);
176168404Spjd		rc = ENOMEM;
177168404Spjd		goto done;
178168404Spjd	}
179168404Spjd
180168404Spjd	/* Note that if_xname is not <if_dname><if_dunit>. */
181168404Spjd	strlcpy(ifp->if_xname, name, sizeof(ifp->if_xname));
182168404Spjd	ifp->if_dname = t4_cloner_name;
183168404Spjd	ifp->if_dunit = unit;
184168404Spjd	ifp->if_init = tracer_init;
185168404Spjd	ifp->if_flags = IFF_SIMPLEX | IFF_DRV_RUNNING;
186168404Spjd	ifp->if_ioctl = tracer_ioctl;
187168404Spjd	ifp->if_transmit = tracer_transmit;
188168404Spjd	ifp->if_qflush = tracer_qflush;
189219089Spjd	ifp->if_capabilities = IFCAP_JUMBO_MTU | IFCAP_VLAN_MTU;
190168404Spjd	ifmedia_init(&sc->media, IFM_IMASK, tracer_media_change,
191168404Spjd	    tracer_media_status);
192219089Spjd	ifmedia_add(&sc->media, IFM_ETHER | IFM_FDX | IFM_NONE, 0, NULL);
193219089Spjd	ifmedia_set(&sc->media, IFM_ETHER | IFM_FDX | IFM_NONE);
194168404Spjd	ether_ifattach(ifp, lla);
195219089Spjd
196219089Spjd	mtx_lock(&sc->ifp_lock);
197219089Spjd	ifp->if_softc = sc;
198268657Sdelphij	sc->ifp = ifp;
199168404Spjd	mtx_unlock(&sc->ifp_lock);
200168404Spjddone:
201219089Spjd	sx_xunlock(&t4_trace_lock);
202219089Spjd	end_synchronized_op(sc, 0);
203168404Spjd	return (rc);
204219089Spjd}
205219089Spjd
206168404Spjdstatic int
207219089Spjdt4_cloner_destroy(struct if_clone *ifc, struct ifnet *ifp)
208219089Spjd{
209168404Spjd	struct adapter *sc;
210246666Smm	int unit = ifp->if_dunit;
211219089Spjd
212219089Spjd	sx_xlock(&t4_trace_lock);
213168404Spjd	sc = ifp->if_softc;
214168404Spjd	if (sc != NULL) {
215168404Spjd		mtx_lock(&sc->ifp_lock);
216168404Spjd		sc->ifp = NULL;
217185029Spjd		ifp->if_softc = NULL;
218185029Spjd		mtx_unlock(&sc->ifp_lock);
219168404Spjd		ifmedia_removeall(&sc->media);
220168404Spjd	}
221185029Spjd	ether_ifdetach(ifp);
222185029Spjd	if_free(ifp);
223168404Spjd	ifc_free_unit(ifc, unit);
224168404Spjd	sx_xunlock(&t4_trace_lock);
225168404Spjd
226219089Spjd	return (0);
227219089Spjd}
228219089Spjd
229219089Spjdvoid
230219089Spjdt4_tracer_modload()
231219089Spjd{
232219089Spjd
233249195Smm	sx_init(&t4_trace_lock, "T4/T5 tracer lock");
234219089Spjd	t4_cloner = if_clone_advanced(t4_cloner_name, 0, t4_cloner_match,
235219089Spjd	    t4_cloner_create, t4_cloner_destroy);
236219089Spjd}
237219089Spjd
238219089Spjdvoid
239219089Spjdt4_tracer_modunload()
240219089Spjd{
241219089Spjd
242219089Spjd	if (t4_cloner != NULL) {
243219089Spjd		/*
244219089Spjd		 * The module is being unloaded so the nexus drivers have
245219089Spjd		 * detached.  The tracing interfaces can not outlive the nexus
246219089Spjd		 * (ifp->if_softc is the nexus) and must have been destroyed
247249195Smm		 * already.  XXX: but if_clone is opaque to us and we can't
248219089Spjd		 * assert LIST_EMPTY(&t4_cloner->ifc_iflist) at this time.
249219089Spjd		 */
250219089Spjd		if_clone_detach(t4_cloner);
251219089Spjd	}
252219089Spjd	sx_destroy(&t4_trace_lock);
253185029Spjd}
254168404Spjd
255248571Smmvoid
256168404Spjdt4_tracer_port_detach(struct adapter *sc)
257168404Spjd{
258219089Spjd
259219089Spjd	sx_xlock(&t4_trace_lock);
260168404Spjd	if (sc->ifp != NULL) {
261219089Spjd		mtx_lock(&sc->ifp_lock);
262219089Spjd		sc->ifp->if_softc = NULL;
263219089Spjd		sc->ifp = NULL;
264219089Spjd		mtx_unlock(&sc->ifp_lock);
265219089Spjd	}
266219089Spjd	ifmedia_removeall(&sc->media);
267219089Spjd	sx_xunlock(&t4_trace_lock);
268219089Spjd}
269219089Spjd
270219089Spjdint
271268657Sdelphijt4_get_tracer(struct adapter *sc, struct t4_tracer *t)
272219089Spjd{
273219089Spjd	int rc, i, enabled;
274219089Spjd	struct trace_params tp;
275219089Spjd
276219089Spjd	if (t->idx >= NTRACE) {
277219089Spjd		t->idx = 0xff;
278219089Spjd		t->enabled = 0;
279219089Spjd		t->valid = 0;
280219089Spjd		return (0);
281219089Spjd	}
282219089Spjd
283219089Spjd	rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK,
284219089Spjd	    "t4gett");
285219089Spjd	if (rc)
286246666Smm		return (rc);
287219089Spjd
288219089Spjd	for (i = t->idx; i < NTRACE; i++) {
289219089Spjd		if (isset(&sc->tracer_valid, t->idx)) {
290219089Spjd			t4_get_trace_filter(sc, &tp, i, &enabled);
291219089Spjd			t->idx = i;
292219089Spjd			t->enabled = enabled;
293219089Spjd			t->valid = 1;
294219089Spjd			memcpy(&t->tp.data[0], &tp.data[0], sizeof(t->tp.data));
295168404Spjd			memcpy(&t->tp.mask[0], &tp.mask[0], sizeof(t->tp.mask));
296168404Spjd			t->tp.snap_len = tp.snap_len;
297168404Spjd			t->tp.min_len = tp.min_len;
298168404Spjd			t->tp.skip_ofst = tp.skip_ofst;
299168404Spjd			t->tp.skip_len = tp.skip_len;
300168404Spjd			t->tp.invert = tp.invert;
301219089Spjd
302168404Spjd			/* convert channel to port iff 0 <= port < 8. */
303168404Spjd			if (tp.port < 4)
304168404Spjd				t->tp.port = sc->chan_map[tp.port];
305168404Spjd			else if (tp.port < 8)
306219089Spjd				t->tp.port = sc->chan_map[tp.port - 4] + 4;
307219089Spjd			else
308219089Spjd				t->tp.port = tp.port;
309219089Spjd
310219089Spjd			goto done;
311219089Spjd		}
312219089Spjd	}
313219089Spjd
314168404Spjd	t->idx = 0xff;
315219089Spjd	t->enabled = 0;
316168404Spjd	t->valid = 0;
317219089Spjddone:
318219089Spjd	end_synchronized_op(sc, LOCK_HELD);
319219089Spjd
320219089Spjd	return (rc);
321219089Spjd}
322168404Spjd
323168404Spjdint
324168404Spjdt4_set_tracer(struct adapter *sc, struct t4_tracer *t)
325168404Spjd{
326168404Spjd	int rc;
327168404Spjd	struct trace_params tp, *tpp;
328168404Spjd
329168404Spjd	if (t->idx >= NTRACE)
330168404Spjd		return (EINVAL);
331168404Spjd
332219089Spjd	rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK,
333219089Spjd	    "t4sett");
334168404Spjd	if (rc)
335219089Spjd		return (rc);
336219089Spjd
337219089Spjd	/*
338219089Spjd	 * If no tracing filter is specified this time then check if the filter
339219089Spjd	 * at the index is valid anyway because it was set previously.  If so
340219089Spjd	 * then this is a legitimate enable/disable operation.
341168404Spjd	 */
342219089Spjd	if (t->valid == 0) {
343219089Spjd		if (isset(&sc->tracer_valid, t->idx))
344219089Spjd			tpp = NULL;
345219089Spjd		else
346219089Spjd			rc = EINVAL;
347168404Spjd		goto done;
348219089Spjd	}
349219089Spjd
350168404Spjd	if (t->tp.port > 19 || t->tp.snap_len > 9600 ||
351219089Spjd	    t->tp.min_len > M_TFMINPKTSIZE || t->tp.skip_len > M_TFLENGTH ||
352248571Smm	    t->tp.skip_ofst > M_TFOFFSET) {
353168404Spjd		rc = EINVAL;
354168404Spjd		goto done;
355219089Spjd	}
356168404Spjd
357168404Spjd	memcpy(&tp.data[0], &t->tp.data[0], sizeof(tp.data));
358168404Spjd	memcpy(&tp.mask[0], &t->tp.mask[0], sizeof(tp.mask));
359219089Spjd	tp.snap_len = t->tp.snap_len;
360219089Spjd	tp.min_len = t->tp.min_len;
361219089Spjd	tp.skip_ofst = t->tp.skip_ofst;
362219089Spjd	tp.skip_len = t->tp.skip_len;
363219089Spjd	tp.invert = !!t->tp.invert;
364219089Spjd
365219089Spjd	/* convert port to channel iff 0 <= port < 8. */
366168404Spjd	if (t->tp.port < 4) {
367168404Spjd		if (sc->port[t->tp.port] == NULL) {
368219089Spjd			rc = EINVAL;
369219089Spjd			goto done;
370219089Spjd		}
371219089Spjd		tp.port = sc->port[t->tp.port]->tx_chan;
372219089Spjd	} else if (t->tp.port < 8) {
373219089Spjd		if (sc->port[t->tp.port - 4] == NULL) {
374168404Spjd			rc = EINVAL;
375219089Spjd			goto done;
376219089Spjd		}
377219089Spjd		tp.port = sc->port[t->tp.port - 4]->tx_chan + 4;
378219089Spjd	}
379219089Spjd	tpp = &tp;
380219089Spjddone:
381219089Spjd	if (rc == 0) {
382168404Spjd		rc = -t4_set_trace_filter(sc, tpp, t->idx, t->enabled);
383168404Spjd		if (rc == 0) {
384219089Spjd			if (t->enabled) {
385168404Spjd				setbit(&sc->tracer_valid, t->idx);
386168404Spjd				if (sc->tracer_enabled == 0) {
387168404Spjd					t4_set_reg_field(sc, A_MPS_TRC_CFG,
388168404Spjd					    F_TRCEN, F_TRCEN);
389219089Spjd				}
390168404Spjd				setbit(&sc->tracer_enabled, t->idx);
391263397Sdelphij			} else {
392263397Sdelphij				clrbit(&sc->tracer_enabled, t->idx);
393219089Spjd				if (sc->tracer_enabled == 0) {
394219089Spjd					t4_set_reg_field(sc, A_MPS_TRC_CFG,
395219089Spjd					    F_TRCEN, 0);
396219089Spjd				}
397219089Spjd			}
398168404Spjd		}
399168404Spjd	}
400219089Spjd	end_synchronized_op(sc, LOCK_HELD);
401168404Spjd
402168404Spjd	return (rc);
403219089Spjd}
404219089Spjd
405219089Spjdint
406219089Spjdt4_trace_pkt(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
407219089Spjd{
408219089Spjd	struct adapter *sc = iq->adapter;
409219089Spjd	struct ifnet *ifp;
410219089Spjd
411219089Spjd	KASSERT(m != NULL, ("%s: no payload with opcode %02x", __func__,
412219089Spjd	    rss->opcode));
413219089Spjd
414219089Spjd	mtx_lock(&sc->ifp_lock);
415219089Spjd	ifp = sc->ifp;
416219089Spjd	if (sc->ifp) {
417219089Spjd		m_adj(m, sizeof(struct cpl_trace_pkt));
418219089Spjd		m->m_pkthdr.rcvif = ifp;
419219089Spjd		ETHER_BPF_MTAP(ifp, m);
420219089Spjd	}
421168404Spjd	mtx_unlock(&sc->ifp_lock);
422168404Spjd	m_freem(m);
423168404Spjd
424219089Spjd	return (0);
425168404Spjd}
426168404Spjd
427219089Spjdint
428219089Spjdt5_trace_pkt(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
429219089Spjd{
430168404Spjd	struct adapter *sc = iq->adapter;
431168404Spjd	struct ifnet *ifp;
432219089Spjd
433168404Spjd	KASSERT(m != NULL, ("%s: no payload with opcode %02x", __func__,
434168404Spjd	    rss->opcode));
435219089Spjd
436219089Spjd	mtx_lock(&sc->ifp_lock);
437219089Spjd	ifp = sc->ifp;
438168404Spjd	if (ifp != NULL) {
439168404Spjd		m_adj(m, sizeof(struct cpl_t5_trace_pkt));
440168404Spjd		m->m_pkthdr.rcvif = ifp;
441219089Spjd		ETHER_BPF_MTAP(ifp, m);
442263397Sdelphij	}
443263397Sdelphij	mtx_unlock(&sc->ifp_lock);
444219089Spjd	m_freem(m);
445219089Spjd
446219089Spjd	return (0);
447219089Spjd}
448219089Spjd
449219089Spjd
450219089Spjdstatic void
451219089Spjdtracer_init(void *arg)
452219089Spjd{
453219089Spjd
454219089Spjd	return;
455219089Spjd}
456219089Spjd
457219089Spjdstatic int
458219089Spjdtracer_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data)
459219089Spjd{
460219089Spjd	int rc = 0;
461219089Spjd	struct adapter *sc;
462219089Spjd	struct ifreq *ifr = (struct ifreq *)data;
463219089Spjd
464219089Spjd	switch (cmd) {
465219089Spjd	case SIOCSIFMTU:
466219089Spjd	case SIOCSIFFLAGS:
467168404Spjd	case SIOCADDMULTI:
468219089Spjd	case SIOCDELMULTI:
469219089Spjd	case SIOCSIFCAP:
470219089Spjd		break;
471219089Spjd	case SIOCSIFMEDIA:
472219089Spjd	case SIOCGIFMEDIA:
473219089Spjd		sx_xlock(&t4_trace_lock);
474168404Spjd		sc = ifp->if_softc;
475168404Spjd		if (sc == NULL)
476168404Spjd			rc = EIO;
477239620Smm		else
478239620Smm			rc = ifmedia_ioctl(ifp, ifr, &sc->media, cmd);
479239620Smm		sx_xunlock(&t4_trace_lock);
480239620Smm		break;
481239620Smm	default:
482239620Smm		rc = ether_ioctl(ifp, cmd, data);
483239620Smm	}
484239620Smm
485239620Smm	return (rc);
486239620Smm}
487239620Smm
488239620Smmstatic int
489248571Smmtracer_transmit(struct ifnet *ifp, struct mbuf *m)
490239620Smm{
491239620Smm
492239620Smm	m_freem(m);
493239620Smm	return (0);
494239620Smm}
495239620Smm
496239620Smmstatic void
497239620Smmtracer_qflush(struct ifnet *ifp)
498239620Smm{
499239620Smm
500239620Smm	return;
501239620Smm}
502239620Smm
503239620Smmstatic int
504239620Smmtracer_media_change(struct ifnet *ifp)
505239620Smm{
506239620Smm
507239620Smm	return (EOPNOTSUPP);
508168404Spjd}
509168404Spjd
510219089Spjdstatic void
511168404Spjdtracer_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
512168404Spjd{
513168404Spjd
514219089Spjd	ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
515168404Spjd
516168404Spjd	return;
517168404Spjd}
518168404Spjd