14fa8e46eSSepherosa Ziehau /*
2391741ecSSepherosa Ziehau * Copyright (c) 2012 The DragonFly Project. All rights reserved.
34fa8e46eSSepherosa Ziehau *
44fa8e46eSSepherosa Ziehau * This code is derived from software contributed to The DragonFly Project
54fa8e46eSSepherosa Ziehau * by Sepherosa Ziehau <sepherosa@gmail.com>
64fa8e46eSSepherosa Ziehau *
74fa8e46eSSepherosa Ziehau * Redistribution and use in source and binary forms, with or without
84fa8e46eSSepherosa Ziehau * modification, are permitted provided that the following conditions
94fa8e46eSSepherosa Ziehau * are met:
104fa8e46eSSepherosa Ziehau *
114fa8e46eSSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright
124fa8e46eSSepherosa Ziehau * notice, this list of conditions and the following disclaimer.
134fa8e46eSSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright
144fa8e46eSSepherosa Ziehau * notice, this list of conditions and the following disclaimer in
154fa8e46eSSepherosa Ziehau * the documentation and/or other materials provided with the
164fa8e46eSSepherosa Ziehau * distribution.
174fa8e46eSSepherosa Ziehau * 3. Neither the name of The DragonFly Project nor the names of its
184fa8e46eSSepherosa Ziehau * contributors may be used to endorse or promote products derived
194fa8e46eSSepherosa Ziehau * from this software without specific, prior written permission.
204fa8e46eSSepherosa Ziehau *
214fa8e46eSSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
224fa8e46eSSepherosa Ziehau * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
234fa8e46eSSepherosa Ziehau * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
244fa8e46eSSepherosa Ziehau * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
254fa8e46eSSepherosa Ziehau * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
264fa8e46eSSepherosa Ziehau * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
274fa8e46eSSepherosa Ziehau * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
284fa8e46eSSepherosa Ziehau * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
294fa8e46eSSepherosa Ziehau * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
304fa8e46eSSepherosa Ziehau * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
314fa8e46eSSepherosa Ziehau * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
324fa8e46eSSepherosa Ziehau * SUCH DAMAGE.
334fa8e46eSSepherosa Ziehau */
344fa8e46eSSepherosa Ziehau
354fa8e46eSSepherosa Ziehau #define _IP_VHL
364fa8e46eSSepherosa Ziehau
374fa8e46eSSepherosa Ziehau #include <sys/param.h>
384fa8e46eSSepherosa Ziehau #include <sys/conf.h>
394fa8e46eSSepherosa Ziehau #include <sys/device.h>
404fa8e46eSSepherosa Ziehau #include <sys/in_cksum.h>
414fa8e46eSSepherosa Ziehau #include <sys/kernel.h>
424fa8e46eSSepherosa Ziehau #include <sys/malloc.h>
434fa8e46eSSepherosa Ziehau #include <sys/mbuf.h>
444fa8e46eSSepherosa Ziehau #include <sys/proc.h>
45*2b3f93eaSMatthew Dillon #include <sys/caps.h>
46391741ecSSepherosa Ziehau #include <sys/queue.h>
474fa8e46eSSepherosa Ziehau #include <sys/socket.h>
484fa8e46eSSepherosa Ziehau #include <sys/systm.h>
494fa8e46eSSepherosa Ziehau #include <sys/serialize.h>
504fa8e46eSSepherosa Ziehau
514fa8e46eSSepherosa Ziehau #include <net/if.h>
524fa8e46eSSepherosa Ziehau #include <net/if_dl.h>
534fa8e46eSSepherosa Ziehau #include <net/if_var.h>
544fa8e46eSSepherosa Ziehau #include <net/ifq_var.h>
554fa8e46eSSepherosa Ziehau #include <net/ethernet.h>
56391741ecSSepherosa Ziehau #include <net/netmsg2.h>
575337421cSSepherosa Ziehau #include <net/netisr2.h>
584fa8e46eSSepherosa Ziehau
594fa8e46eSSepherosa Ziehau #include <netinet/in.h>
609064712fSSepherosa Ziehau #include <netinet/in_pcb.h>
614fa8e46eSSepherosa Ziehau #include <netinet/ip.h>
624fa8e46eSSepherosa Ziehau #include <netinet/udp_var.h>
634fa8e46eSSepherosa Ziehau
644fa8e46eSSepherosa Ziehau #include "pktgen.h"
654fa8e46eSSepherosa Ziehau
664fa8e46eSSepherosa Ziehau #define CDEV_NAME "pktg"
674fa8e46eSSepherosa Ziehau
68391741ecSSepherosa Ziehau #define PKTGEN_BUFSZ 2048
69391741ecSSepherosa Ziehau
70390d8a05SSepherosa Ziehau #ifndef PKTGEN_DEVCNT
71390d8a05SSepherosa Ziehau #define PKTGEN_DEVCNT 4
72390d8a05SSepherosa Ziehau #endif
73390d8a05SSepherosa Ziehau
74391741ecSSepherosa Ziehau struct pktgen;
75391741ecSSepherosa Ziehau
76b0cd2b4bSSepherosa Ziehau struct netmsg_pktgen {
77b0cd2b4bSSepherosa Ziehau struct netmsg_base np_base;
78b0cd2b4bSSepherosa Ziehau struct pktgen *np_pktg;
79b0cd2b4bSSepherosa Ziehau struct ifaltq_subque *np_ifsq;
80b0cd2b4bSSepherosa Ziehau };
81b0cd2b4bSSepherosa Ziehau
82391741ecSSepherosa Ziehau struct pktgen_buf {
83391741ecSSepherosa Ziehau struct netmsg_base pb_nmsg; /* MUST BE THE FIRST */
84391741ecSSepherosa Ziehau void *pb_buf;
85391741ecSSepherosa Ziehau volatile int pb_done;
864c9906cbSSepherosa Ziehau int pb_inuse;
87391741ecSSepherosa Ziehau struct ifnet *pb_ifp;
882fb36fabSSepherosa Ziehau struct ifaltq_subque *pb_ifsq;
89391741ecSSepherosa Ziehau int pb_len;
90391741ecSSepherosa Ziehau int pb_cpuid;
91391741ecSSepherosa Ziehau struct pktgen *pb_pktg;
92391741ecSSepherosa Ziehau LIST_ENTRY(pktgen_buf) pb_link;
93391741ecSSepherosa Ziehau };
94391741ecSSepherosa Ziehau
951bbaa2adSSepherosa Ziehau struct pktgen_pcpu {
961bbaa2adSSepherosa Ziehau struct callout pktg_stop;
971bbaa2adSSepherosa Ziehau LIST_HEAD(, pktgen_buf) pktg_buflist;
981bbaa2adSSepherosa Ziehau };
991bbaa2adSSepherosa Ziehau
1004fa8e46eSSepherosa Ziehau struct pktgen {
1014fa8e46eSSepherosa Ziehau uint32_t pktg_flags; /* PKTG_F_ */
1024fa8e46eSSepherosa Ziehau int pktg_refcnt;
1034fa8e46eSSepherosa Ziehau
1044fa8e46eSSepherosa Ziehau int pktg_duration;
1054fa8e46eSSepherosa Ziehau
1064fa8e46eSSepherosa Ziehau int pktg_datalen;
1074fa8e46eSSepherosa Ziehau struct ifnet *pktg_ifp;
108c95ebcd6SSepherosa Ziehau
109793f802fSSepherosa Ziehau int pktg_pktenq;
110793f802fSSepherosa Ziehau
111391741ecSSepherosa Ziehau struct sockaddr_in pktg_src;
112391741ecSSepherosa Ziehau int pktg_ndst;
113391741ecSSepherosa Ziehau struct sockaddr_in *pktg_dst;
1144fa8e46eSSepherosa Ziehau uint8_t pktg_dst_lladdr[ETHER_ADDR_LEN];
115391741ecSSepherosa Ziehau
1161bbaa2adSSepherosa Ziehau struct pktgen_pcpu pktg_pcpu[MAXCPU];
1174fa8e46eSSepherosa Ziehau };
1184fa8e46eSSepherosa Ziehau
1194fa8e46eSSepherosa Ziehau #define PKTG_F_CONFIG 0x1
1204fa8e46eSSepherosa Ziehau #define PKTG_F_RUNNING 0x4
121eec66bd4SSepherosa Ziehau #define PKTG_F_SWITCH_SRCDST 0x8
1224fa8e46eSSepherosa Ziehau
1234fa8e46eSSepherosa Ziehau static int pktgen_modevent(module_t, int, void *);
124391741ecSSepherosa Ziehau
125391741ecSSepherosa Ziehau static void pktgen_buf_free(void *);
126391741ecSSepherosa Ziehau static void pktgen_buf_ref(void *);
127391741ecSSepherosa Ziehau static void pktgen_buf_send(netmsg_t);
128391741ecSSepherosa Ziehau
1294fa8e46eSSepherosa Ziehau static int pktgen_config(struct pktgen *,
1304fa8e46eSSepherosa Ziehau const struct pktgen_conf *);
131b0cd2b4bSSepherosa Ziehau static int pktgen_start(struct pktgen *, int);
132391741ecSSepherosa Ziehau static void pktgen_free(struct pktgen *);
133c6830078SSepherosa Ziehau static void pktgen_ref(struct pktgen *);
1341bbaa2adSSepherosa Ziehau static void pktgen_pcpu_stop_cb(void *);
135391741ecSSepherosa Ziehau static void pktgen_mbuf(struct pktgen_buf *, struct mbuf *);
136b0cd2b4bSSepherosa Ziehau static void pktgen_start_ifsq(struct pktgen *,
137b0cd2b4bSSepherosa Ziehau struct ifaltq_subque *);
138b0cd2b4bSSepherosa Ziehau static void pktgen_start_ifsq_handler(netmsg_t);
1394fa8e46eSSepherosa Ziehau
1404fa8e46eSSepherosa Ziehau static d_open_t pktgen_open;
1414fa8e46eSSepherosa Ziehau static d_close_t pktgen_close;
1424fa8e46eSSepherosa Ziehau static d_ioctl_t pktgen_ioctl;
1434fa8e46eSSepherosa Ziehau
1444fa8e46eSSepherosa Ziehau static struct dev_ops pktgen_ops = {
145624409c2SSepherosa Ziehau { CDEV_NAME, 0, D_MPSAFE },
1464fa8e46eSSepherosa Ziehau .d_open = pktgen_open,
1474fa8e46eSSepherosa Ziehau .d_close = pktgen_close,
1484fa8e46eSSepherosa Ziehau .d_ioctl = pktgen_ioctl,
1494fa8e46eSSepherosa Ziehau };
1504fa8e46eSSepherosa Ziehau
1514c9906cbSSepherosa Ziehau static volatile int pktgen_refcnt;
152e3d0d8d7SSepherosa Ziehau static struct lwkt_token pktgen_tok = LWKT_TOKEN_INITIALIZER(pktgen_token);
1534fa8e46eSSepherosa Ziehau
1544fa8e46eSSepherosa Ziehau MALLOC_DECLARE(M_PKTGEN);
1554fa8e46eSSepherosa Ziehau MALLOC_DEFINE(M_PKTGEN, CDEV_NAME, "Packet generator");
1564fa8e46eSSepherosa Ziehau
1574fa8e46eSSepherosa Ziehau DEV_MODULE(pktgen, pktgen_modevent, NULL);
1584fa8e46eSSepherosa Ziehau
1594fa8e46eSSepherosa Ziehau static int
pktgen_modevent(module_t mod,int type,void * data)1604fa8e46eSSepherosa Ziehau pktgen_modevent(module_t mod, int type, void *data)
1614fa8e46eSSepherosa Ziehau {
162390d8a05SSepherosa Ziehau int error = 0, i;
1634fa8e46eSSepherosa Ziehau
1644fa8e46eSSepherosa Ziehau switch (type) {
1654fa8e46eSSepherosa Ziehau case MOD_LOAD:
166390d8a05SSepherosa Ziehau for (i = 0; i < PKTGEN_DEVCNT; ++i) {
1674b3b3198SAlex Hornung make_dev(&pktgen_ops, 0, UID_ROOT, GID_WHEEL, 0600,
168390d8a05SSepherosa Ziehau CDEV_NAME"%d", i);
169390d8a05SSepherosa Ziehau }
1704fa8e46eSSepherosa Ziehau break;
1714fa8e46eSSepherosa Ziehau
1724fa8e46eSSepherosa Ziehau case MOD_UNLOAD:
1734fa8e46eSSepherosa Ziehau if (pktgen_refcnt > 0)
1744fa8e46eSSepherosa Ziehau return EBUSY;
1754b3b3198SAlex Hornung dev_ops_remove_all(&pktgen_ops);
1764fa8e46eSSepherosa Ziehau break;
1774fa8e46eSSepherosa Ziehau
1784fa8e46eSSepherosa Ziehau default:
1794fa8e46eSSepherosa Ziehau error = EOPNOTSUPP;
1804fa8e46eSSepherosa Ziehau break;
1814fa8e46eSSepherosa Ziehau }
1824fa8e46eSSepherosa Ziehau return error;
1834fa8e46eSSepherosa Ziehau }
1844fa8e46eSSepherosa Ziehau
1854fa8e46eSSepherosa Ziehau static int
pktgen_open(struct dev_open_args * ap)1864fa8e46eSSepherosa Ziehau pktgen_open(struct dev_open_args *ap)
1874fa8e46eSSepherosa Ziehau {
1884fa8e46eSSepherosa Ziehau cdev_t dev = ap->a_head.a_dev;
1894fa8e46eSSepherosa Ziehau struct pktgen *pktg;
1901bbaa2adSSepherosa Ziehau int error, i;
1914fa8e46eSSepherosa Ziehau
1929eaf083fSSascha Wildner error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1934fa8e46eSSepherosa Ziehau if (error)
1944fa8e46eSSepherosa Ziehau return error;
1954fa8e46eSSepherosa Ziehau
196e3d0d8d7SSepherosa Ziehau lwkt_gettoken(&pktgen_tok);
1974fa8e46eSSepherosa Ziehau
1984fa8e46eSSepherosa Ziehau if (dev->si_drv1 != NULL) {
199e3d0d8d7SSepherosa Ziehau lwkt_reltoken(&pktgen_tok);
2004fa8e46eSSepherosa Ziehau return EBUSY;
2014fa8e46eSSepherosa Ziehau }
2024fa8e46eSSepherosa Ziehau
2034fa8e46eSSepherosa Ziehau pktg = kmalloc(sizeof(*pktg), M_PKTGEN, M_ZERO | M_WAITOK);
2041bbaa2adSSepherosa Ziehau for (i = 0; i < ncpus; ++i) {
2051bbaa2adSSepherosa Ziehau struct pktgen_pcpu *p = &pktg->pktg_pcpu[i];
2061bbaa2adSSepherosa Ziehau
2071bbaa2adSSepherosa Ziehau callout_init_mp(&p->pktg_stop);
2081bbaa2adSSepherosa Ziehau LIST_INIT(&p->pktg_buflist);
2091bbaa2adSSepherosa Ziehau }
2104fa8e46eSSepherosa Ziehau
2114fa8e46eSSepherosa Ziehau dev->si_drv1 = pktg;
2124fa8e46eSSepherosa Ziehau pktg->pktg_refcnt = 1;
2134fa8e46eSSepherosa Ziehau
2144c9906cbSSepherosa Ziehau atomic_add_int(&pktgen_refcnt, 1);
2154fa8e46eSSepherosa Ziehau
216e3d0d8d7SSepherosa Ziehau lwkt_reltoken(&pktgen_tok);
2174fa8e46eSSepherosa Ziehau return 0;
2184fa8e46eSSepherosa Ziehau }
2194fa8e46eSSepherosa Ziehau
2204fa8e46eSSepherosa Ziehau static int
pktgen_close(struct dev_close_args * ap)2214fa8e46eSSepherosa Ziehau pktgen_close(struct dev_close_args *ap)
2224fa8e46eSSepherosa Ziehau {
2234fa8e46eSSepherosa Ziehau cdev_t dev = ap->a_head.a_dev;
2244fa8e46eSSepherosa Ziehau struct pktgen *pktg = dev->si_drv1;
2254fa8e46eSSepherosa Ziehau
226e3d0d8d7SSepherosa Ziehau lwkt_gettoken(&pktgen_tok);
2274fa8e46eSSepherosa Ziehau dev->si_drv1 = NULL;
228e3d0d8d7SSepherosa Ziehau lwkt_reltoken(&pktgen_tok);
229391741ecSSepherosa Ziehau
2304c9906cbSSepherosa Ziehau pktgen_free(pktg);
2314c9906cbSSepherosa Ziehau
2324fa8e46eSSepherosa Ziehau return 0;
2334fa8e46eSSepherosa Ziehau }
2344fa8e46eSSepherosa Ziehau
2354fa8e46eSSepherosa Ziehau static int
pktgen_ioctl(struct dev_ioctl_args * ap __unused)2364fa8e46eSSepherosa Ziehau pktgen_ioctl(struct dev_ioctl_args *ap __unused)
2374fa8e46eSSepherosa Ziehau {
2384fa8e46eSSepherosa Ziehau cdev_t dev = ap->a_head.a_dev;
2394fa8e46eSSepherosa Ziehau caddr_t data = ap->a_data;
2404fa8e46eSSepherosa Ziehau struct pktgen *pktg = dev->si_drv1;
2414fa8e46eSSepherosa Ziehau int error;
2424fa8e46eSSepherosa Ziehau
243e3d0d8d7SSepherosa Ziehau lwkt_gettoken(&pktgen_tok);
2444fa8e46eSSepherosa Ziehau
2454fa8e46eSSepherosa Ziehau switch (ap->a_cmd) {
2464fa8e46eSSepherosa Ziehau case PKTGENSTART:
247b0cd2b4bSSepherosa Ziehau error = pktgen_start(pktg, 0);
248b0cd2b4bSSepherosa Ziehau break;
249b0cd2b4bSSepherosa Ziehau
250b0cd2b4bSSepherosa Ziehau case PKTGENMQSTART:
251b0cd2b4bSSepherosa Ziehau error = pktgen_start(pktg, 1);
2524fa8e46eSSepherosa Ziehau break;
2534fa8e46eSSepherosa Ziehau
2544fa8e46eSSepherosa Ziehau case PKTGENSCONF:
2554fa8e46eSSepherosa Ziehau error = pktgen_config(pktg, (const struct pktgen_conf *)data);
2564fa8e46eSSepherosa Ziehau break;
2574fa8e46eSSepherosa Ziehau
2584fa8e46eSSepherosa Ziehau default:
2594fa8e46eSSepherosa Ziehau error = EOPNOTSUPP;
2604fa8e46eSSepherosa Ziehau break;
2614fa8e46eSSepherosa Ziehau }
2624fa8e46eSSepherosa Ziehau
263e3d0d8d7SSepherosa Ziehau lwkt_reltoken(&pktgen_tok);
2644fa8e46eSSepherosa Ziehau return error;
2654fa8e46eSSepherosa Ziehau }
2664fa8e46eSSepherosa Ziehau
2674fa8e46eSSepherosa Ziehau static int
pktgen_config(struct pktgen * pktg,const struct pktgen_conf * conf)2684fa8e46eSSepherosa Ziehau pktgen_config(struct pktgen *pktg, const struct pktgen_conf *conf)
2694fa8e46eSSepherosa Ziehau {
2704fa8e46eSSepherosa Ziehau const struct sockaddr_in *sin;
271391741ecSSepherosa Ziehau struct sockaddr_in *dst = NULL;
2724fa8e46eSSepherosa Ziehau const struct sockaddr *sa;
2734fa8e46eSSepherosa Ziehau struct ifnet *ifp;
274391741ecSSepherosa Ziehau size_t dst_size;
275793f802fSSepherosa Ziehau int i, error, pktenq;
2764fa8e46eSSepherosa Ziehau
277391741ecSSepherosa Ziehau if (pktg->pktg_flags & (PKTG_F_RUNNING | PKTG_F_CONFIG))
2784fa8e46eSSepherosa Ziehau return EBUSY;
2794fa8e46eSSepherosa Ziehau
280391741ecSSepherosa Ziehau if (conf->pc_datalen <= 0 ||
281391741ecSSepherosa Ziehau conf->pc_datalen > ETHERMTU - sizeof(struct udpiphdr))
2824fa8e46eSSepherosa Ziehau return EINVAL;
2834fa8e46eSSepherosa Ziehau if (conf->pc_duration <= 0)
2844fa8e46eSSepherosa Ziehau return EINVAL;
2854fa8e46eSSepherosa Ziehau
2864fa8e46eSSepherosa Ziehau sin = &conf->pc_src;
2874fa8e46eSSepherosa Ziehau if (sin->sin_family != AF_INET)
2884fa8e46eSSepherosa Ziehau return EPROTONOSUPPORT;
2894fa8e46eSSepherosa Ziehau if (sin->sin_port == 0)
2904fa8e46eSSepherosa Ziehau return EINVAL;
2914fa8e46eSSepherosa Ziehau
292391741ecSSepherosa Ziehau if (conf->pc_ndst <= 0)
2934fa8e46eSSepherosa Ziehau return EINVAL;
294391741ecSSepherosa Ziehau dst_size = conf->pc_ndst * sizeof(struct sockaddr_in);
2954fa8e46eSSepherosa Ziehau
296391741ecSSepherosa Ziehau dst = kmalloc(dst_size, M_PKTGEN, M_WAITOK | M_NULLOK);
297391741ecSSepherosa Ziehau if (dst == NULL)
298391741ecSSepherosa Ziehau return ENOMEM;
299391741ecSSepherosa Ziehau
300391741ecSSepherosa Ziehau error = copyin(conf->pc_dst, dst, dst_size);
301391741ecSSepherosa Ziehau if (error)
302391741ecSSepherosa Ziehau goto failed;
303391741ecSSepherosa Ziehau
304391741ecSSepherosa Ziehau for (i = 0; i < conf->pc_ndst; ++i) {
305391741ecSSepherosa Ziehau sin = &dst[i];
306391741ecSSepherosa Ziehau if (sin->sin_family != AF_INET) {
307391741ecSSepherosa Ziehau error = EPROTONOSUPPORT;
308391741ecSSepherosa Ziehau goto failed;
309391741ecSSepherosa Ziehau }
310391741ecSSepherosa Ziehau if (sin->sin_port == 0) {
311391741ecSSepherosa Ziehau error = EINVAL;
312391741ecSSepherosa Ziehau goto failed;
313391741ecSSepherosa Ziehau }
314391741ecSSepherosa Ziehau }
315391741ecSSepherosa Ziehau
31673d83e2bSSepherosa Ziehau /*
31773d83e2bSSepherosa Ziehau * XXX NOT MPSAFE.
31873d83e2bSSepherosa Ziehau * Make sure that pc_ifname is not gone.
31973d83e2bSSepherosa Ziehau */
32073d83e2bSSepherosa Ziehau ifnet_lock();
321391741ecSSepherosa Ziehau ifp = ifunit(conf->pc_ifname);
32273d83e2bSSepherosa Ziehau ifnet_unlock();
323391741ecSSepherosa Ziehau if (ifp == NULL) {
324391741ecSSepherosa Ziehau error = ENXIO;
325391741ecSSepherosa Ziehau goto failed;
326391741ecSSepherosa Ziehau }
327391741ecSSepherosa Ziehau
328793f802fSSepherosa Ziehau pktenq = conf->pc_pktenq;
3292fb36fabSSepherosa Ziehau if (pktenq < 0 || pktenq > ifp->if_snd.altq_maxlen) {
330793f802fSSepherosa Ziehau error = ENOBUFS;
331793f802fSSepherosa Ziehau goto failed;
332793f802fSSepherosa Ziehau } else if (pktenq == 0) {
3332fb36fabSSepherosa Ziehau pktenq = (ifp->if_snd.altq_maxlen * 3) / 4;
334793f802fSSepherosa Ziehau }
335793f802fSSepherosa Ziehau
336391741ecSSepherosa Ziehau sa = &conf->pc_dst_lladdr;
337391741ecSSepherosa Ziehau if (sa->sa_family != AF_LINK) {
338391741ecSSepherosa Ziehau error = EPROTONOSUPPORT;
339391741ecSSepherosa Ziehau goto failed;
340391741ecSSepherosa Ziehau }
341391741ecSSepherosa Ziehau if (sa->sa_len != ETHER_ADDR_LEN) {
342391741ecSSepherosa Ziehau error = EPROTONOSUPPORT;
343391741ecSSepherosa Ziehau goto failed;
344391741ecSSepherosa Ziehau }
345391741ecSSepherosa Ziehau if (ETHER_IS_MULTICAST(sa->sa_data) ||
346391741ecSSepherosa Ziehau bcmp(sa->sa_data, ifp->if_broadcastaddr, ifp->if_addrlen) == 0) {
347391741ecSSepherosa Ziehau error = EADDRNOTAVAIL;
348391741ecSSepherosa Ziehau goto failed;
349391741ecSSepherosa Ziehau }
350391741ecSSepherosa Ziehau
351391741ecSSepherosa Ziehau /*
352391741ecSSepherosa Ziehau * Accept the config
353391741ecSSepherosa Ziehau */
3544fa8e46eSSepherosa Ziehau pktg->pktg_flags |= PKTG_F_CONFIG;
3554fa8e46eSSepherosa Ziehau
356eec66bd4SSepherosa Ziehau if (conf->pc_flags & PKTGEN_FLAG_SWITCH_SRCDST)
357eec66bd4SSepherosa Ziehau pktg->pktg_flags |= PKTG_F_SWITCH_SRCDST;
3584fa8e46eSSepherosa Ziehau pktg->pktg_duration = conf->pc_duration;
3594fa8e46eSSepherosa Ziehau pktg->pktg_datalen = conf->pc_datalen;
360793f802fSSepherosa Ziehau pktg->pktg_pktenq = pktenq;
361391741ecSSepherosa Ziehau pktg->pktg_ifp = ifp;
362391741ecSSepherosa Ziehau pktg->pktg_src = conf->pc_src;
363391741ecSSepherosa Ziehau pktg->pktg_ndst = conf->pc_ndst;
364391741ecSSepherosa Ziehau KKASSERT(pktg->pktg_dst == NULL);
365391741ecSSepherosa Ziehau pktg->pktg_dst = dst;
3664fa8e46eSSepherosa Ziehau bcopy(sa->sa_data, pktg->pktg_dst_lladdr, ETHER_ADDR_LEN);
367c95ebcd6SSepherosa Ziehau
3684fa8e46eSSepherosa Ziehau return 0;
369391741ecSSepherosa Ziehau
370391741ecSSepherosa Ziehau failed:
371391741ecSSepherosa Ziehau if (dst != NULL)
372391741ecSSepherosa Ziehau kfree(dst, M_PKTGEN);
373391741ecSSepherosa Ziehau return error;
3744fa8e46eSSepherosa Ziehau }
3754fa8e46eSSepherosa Ziehau
376b0cd2b4bSSepherosa Ziehau static void
pktgen_start_ifsq(struct pktgen * pktg,struct ifaltq_subque * ifsq)377b0cd2b4bSSepherosa Ziehau pktgen_start_ifsq(struct pktgen *pktg, struct ifaltq_subque *ifsq)
3784fa8e46eSSepherosa Ziehau {
379b0cd2b4bSSepherosa Ziehau struct netmsg_pktgen *np;
380391741ecSSepherosa Ziehau
381b0cd2b4bSSepherosa Ziehau np = kmalloc(sizeof(*np), M_LWKTMSG, M_WAITOK);
382b0cd2b4bSSepherosa Ziehau netmsg_init(&np->np_base, NULL, &netisr_afree_rport, 0,
383b0cd2b4bSSepherosa Ziehau pktgen_start_ifsq_handler);
384b0cd2b4bSSepherosa Ziehau np->np_pktg = pktg;
385b0cd2b4bSSepherosa Ziehau np->np_ifsq = ifsq;
386b0cd2b4bSSepherosa Ziehau
387ec7f7fc8SSepherosa Ziehau lwkt_sendmsg(netisr_cpuport(ifsq_get_cpuid(ifsq)), &np->np_base.lmsg);
388b0cd2b4bSSepherosa Ziehau }
389b0cd2b4bSSepherosa Ziehau
390b0cd2b4bSSepherosa Ziehau static int
pktgen_start(struct pktgen * pktg,int mq)391b0cd2b4bSSepherosa Ziehau pktgen_start(struct pktgen *pktg, int mq)
392b0cd2b4bSSepherosa Ziehau {
393b0cd2b4bSSepherosa Ziehau struct ifaltq *ifq;
394391741ecSSepherosa Ziehau
3954fa8e46eSSepherosa Ziehau if ((pktg->pktg_flags & PKTG_F_CONFIG) == 0)
3964fa8e46eSSepherosa Ziehau return EINVAL;
3974fa8e46eSSepherosa Ziehau if (pktg->pktg_flags & PKTG_F_RUNNING)
3984fa8e46eSSepherosa Ziehau return EBUSY;
3994fa8e46eSSepherosa Ziehau pktg->pktg_flags |= PKTG_F_RUNNING;
4004fa8e46eSSepherosa Ziehau
401b0cd2b4bSSepherosa Ziehau ifq = &pktg->pktg_ifp->if_snd;
402b0cd2b4bSSepherosa Ziehau if (!mq) {
403b0cd2b4bSSepherosa Ziehau pktgen_ref(pktg);
404b0cd2b4bSSepherosa Ziehau pktgen_start_ifsq(pktg, ifq_get_subq_default(ifq));
405b0cd2b4bSSepherosa Ziehau } else {
406b0cd2b4bSSepherosa Ziehau int i;
407391741ecSSepherosa Ziehau
408b0cd2b4bSSepherosa Ziehau for (i = 0; i < ifq->altq_subq_cnt; ++i)
409b0cd2b4bSSepherosa Ziehau pktgen_ref(pktg);
410b0cd2b4bSSepherosa Ziehau for (i = 0; i < ifq->altq_subq_cnt; ++i)
411b0cd2b4bSSepherosa Ziehau pktgen_start_ifsq(pktg, ifq_get_subq(ifq, i));
412b0cd2b4bSSepherosa Ziehau }
413b0cd2b4bSSepherosa Ziehau return 0;
414b0cd2b4bSSepherosa Ziehau }
415b0cd2b4bSSepherosa Ziehau
416b0cd2b4bSSepherosa Ziehau static void
pktgen_start_ifsq_handler(netmsg_t nmsg)417b0cd2b4bSSepherosa Ziehau pktgen_start_ifsq_handler(netmsg_t nmsg)
418b0cd2b4bSSepherosa Ziehau {
419b0cd2b4bSSepherosa Ziehau struct netmsg_pktgen *np = (struct netmsg_pktgen *)nmsg;
420b0cd2b4bSSepherosa Ziehau struct pktgen *pktg = np->np_pktg;
421b0cd2b4bSSepherosa Ziehau struct ifaltq_subque *ifsq = np->np_ifsq;
422b0cd2b4bSSepherosa Ziehau
423b0cd2b4bSSepherosa Ziehau struct mbuf *m, *head = NULL, **next;
424b0cd2b4bSSepherosa Ziehau struct ifnet *ifp;
425b0cd2b4bSSepherosa Ziehau struct pktgen_pcpu *p;
426b0cd2b4bSSepherosa Ziehau int cpuid, i, alloc_cnt, keep_cnt;
427b0cd2b4bSSepherosa Ziehau
428b0cd2b4bSSepherosa Ziehau u_short ulen, psum;
429b0cd2b4bSSepherosa Ziehau int len, ip_len;
430b0cd2b4bSSepherosa Ziehau
431b0cd2b4bSSepherosa Ziehau /* Reply ASAP */
432b0cd2b4bSSepherosa Ziehau lwkt_replymsg(&np->np_base.lmsg, 0);
433b0cd2b4bSSepherosa Ziehau
434b0cd2b4bSSepherosa Ziehau ifp = pktg->pktg_ifp;
435b0cd2b4bSSepherosa Ziehau
4362fb36fabSSepherosa Ziehau cpuid = ifsq_get_cpuid(ifsq);
437b0cd2b4bSSepherosa Ziehau KKASSERT(cpuid == mycpuid);
438391741ecSSepherosa Ziehau
4391bbaa2adSSepherosa Ziehau p = &pktg->pktg_pcpu[cpuid];
4401bbaa2adSSepherosa Ziehau
441793f802fSSepherosa Ziehau keep_cnt = pktg->pktg_pktenq;
442793f802fSSepherosa Ziehau alloc_cnt = keep_cnt * 2;
443391741ecSSepherosa Ziehau
444391741ecSSepherosa Ziehau /*
445391741ecSSepherosa Ziehau * Prefault enough mbuf into mbuf objcache
446391741ecSSepherosa Ziehau */
447391741ecSSepherosa Ziehau next = &head;
448391741ecSSepherosa Ziehau for (i = 0; i < alloc_cnt; ++i) {
449b5523eacSSascha Wildner MGETHDR(m, M_WAITOK, MT_DATA);
450391741ecSSepherosa Ziehau *next = m;
451391741ecSSepherosa Ziehau next = &m->m_nextpkt;
452391741ecSSepherosa Ziehau }
453391741ecSSepherosa Ziehau
454391741ecSSepherosa Ziehau for (i = 0; i < alloc_cnt - keep_cnt; ++i) {
455391741ecSSepherosa Ziehau m = head;
456391741ecSSepherosa Ziehau head = m->m_nextpkt;
457391741ecSSepherosa Ziehau m->m_nextpkt = NULL;
458391741ecSSepherosa Ziehau m_freem(m);
459391741ecSSepherosa Ziehau }
460391741ecSSepherosa Ziehau KKASSERT(head != NULL);
461391741ecSSepherosa Ziehau
462391741ecSSepherosa Ziehau /*
463391741ecSSepherosa Ziehau * Setup the packets' data
464391741ecSSepherosa Ziehau */
465391741ecSSepherosa Ziehau ip_len = pktg->pktg_datalen + sizeof(struct udpiphdr);
466391741ecSSepherosa Ziehau len = ip_len + ETHER_HDR_LEN;
467391741ecSSepherosa Ziehau
468391741ecSSepherosa Ziehau psum = htons((u_short)pktg->pktg_datalen + sizeof(struct udphdr) +
469391741ecSSepherosa Ziehau IPPROTO_UDP);
470391741ecSSepherosa Ziehau ulen = htons(pktg->pktg_datalen + sizeof(struct udphdr));
471391741ecSSepherosa Ziehau
472391741ecSSepherosa Ziehau m = head;
473391741ecSSepherosa Ziehau i = 0;
474391741ecSSepherosa Ziehau while (m != NULL) {
475391741ecSSepherosa Ziehau struct mbuf *nextm;
476391741ecSSepherosa Ziehau const struct sockaddr_in *dst;
477391741ecSSepherosa Ziehau struct pktgen_buf *pb;
478391741ecSSepherosa Ziehau struct ip *ip;
479391741ecSSepherosa Ziehau struct udpiphdr *ui;
480391741ecSSepherosa Ziehau struct ether_header *eh;
481391741ecSSepherosa Ziehau
482c6830078SSepherosa Ziehau pktgen_ref(pktg);
483391741ecSSepherosa Ziehau
484391741ecSSepherosa Ziehau pb = kmalloc(sizeof(*pb), M_PKTGEN, M_WAITOK | M_ZERO);
485391741ecSSepherosa Ziehau pb->pb_ifp = ifp;
4862fb36fabSSepherosa Ziehau pb->pb_ifsq = ifsq;
487391741ecSSepherosa Ziehau pb->pb_inuse = 1;
488391741ecSSepherosa Ziehau pb->pb_buf = kmalloc(PKTGEN_BUFSZ, M_PKTGEN, M_WAITOK);
489391741ecSSepherosa Ziehau pb->pb_len = len;
490391741ecSSepherosa Ziehau pb->pb_cpuid = cpuid;
491391741ecSSepherosa Ziehau pb->pb_pktg = pktg;
492391741ecSSepherosa Ziehau netmsg_init(&pb->pb_nmsg, NULL, &netisr_adone_rport, 0,
493391741ecSSepherosa Ziehau pktgen_buf_send);
4941bbaa2adSSepherosa Ziehau LIST_INSERT_HEAD(&p->pktg_buflist, pb, pb_link);
495391741ecSSepherosa Ziehau
496391741ecSSepherosa Ziehau dst = &pktg->pktg_dst[i % pktg->pktg_ndst];
497391741ecSSepherosa Ziehau ++i;
498391741ecSSepherosa Ziehau
499391741ecSSepherosa Ziehau m->m_ext.ext_arg = pb;
500391741ecSSepherosa Ziehau m->m_ext.ext_buf = pb->pb_buf;
501391741ecSSepherosa Ziehau m->m_ext.ext_free = pktgen_buf_free;
502391741ecSSepherosa Ziehau m->m_ext.ext_ref = pktgen_buf_ref;
503391741ecSSepherosa Ziehau m->m_ext.ext_size = PKTGEN_BUFSZ;
504391741ecSSepherosa Ziehau
505391741ecSSepherosa Ziehau m->m_data = m->m_ext.ext_buf;
506391741ecSSepherosa Ziehau m->m_flags |= M_EXT;
507391741ecSSepherosa Ziehau m->m_len = m->m_pkthdr.len = len;
508391741ecSSepherosa Ziehau
509391741ecSSepherosa Ziehau m->m_data += ETHER_HDR_LEN;
510391741ecSSepherosa Ziehau m->m_len -= ETHER_HDR_LEN;
511391741ecSSepherosa Ziehau m->m_pkthdr.len -= ETHER_HDR_LEN;
512391741ecSSepherosa Ziehau
513391741ecSSepherosa Ziehau ui = mtod(m, struct udpiphdr *);
514391741ecSSepherosa Ziehau ui->ui_pr = IPPROTO_UDP;
515eec66bd4SSepherosa Ziehau if (pktg->pktg_flags & PKTG_F_SWITCH_SRCDST) {
516eec66bd4SSepherosa Ziehau ui->ui_src.s_addr = dst->sin_addr.s_addr;
517eec66bd4SSepherosa Ziehau ui->ui_dst.s_addr = pktg->pktg_src.sin_addr.s_addr;
518eec66bd4SSepherosa Ziehau ui->ui_sport = dst->sin_port;
519eec66bd4SSepherosa Ziehau ui->ui_dport = pktg->pktg_src.sin_port;
520eec66bd4SSepherosa Ziehau } else {
521391741ecSSepherosa Ziehau ui->ui_src.s_addr = pktg->pktg_src.sin_addr.s_addr;
522391741ecSSepherosa Ziehau ui->ui_dst.s_addr = dst->sin_addr.s_addr;
523391741ecSSepherosa Ziehau ui->ui_sport = pktg->pktg_src.sin_port;
524391741ecSSepherosa Ziehau ui->ui_dport = dst->sin_port;
525eec66bd4SSepherosa Ziehau }
526391741ecSSepherosa Ziehau ui->ui_ulen = ulen;
527391741ecSSepherosa Ziehau ui->ui_sum = in_pseudo(ui->ui_src.s_addr, ui->ui_dst.s_addr,
528391741ecSSepherosa Ziehau psum);
52964c94a5fSSepherosa Ziehau m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum);
530391741ecSSepherosa Ziehau
531391741ecSSepherosa Ziehau ip = (struct ip *)ui;
532391741ecSSepherosa Ziehau ip->ip_len = ip_len;
533391741ecSSepherosa Ziehau ip->ip_ttl = 64; /* XXX */
534391741ecSSepherosa Ziehau ip->ip_tos = 0; /* XXX */
535391741ecSSepherosa Ziehau ip->ip_vhl = IP_VHL_BORING;
536391741ecSSepherosa Ziehau ip->ip_off = 0;
5372640b9e5SSepherosa Ziehau ip->ip_sum = 0;
538391741ecSSepherosa Ziehau ip->ip_id = ip_newid();
539391741ecSSepherosa Ziehau
540391741ecSSepherosa Ziehau in_delayed_cksum(m);
541391741ecSSepherosa Ziehau
542391741ecSSepherosa Ziehau ip->ip_len = htons(ip->ip_len);
543391741ecSSepherosa Ziehau ip->ip_sum = in_cksum_hdr(ip);
544391741ecSSepherosa Ziehau
545391741ecSSepherosa Ziehau m->m_data -= ETHER_HDR_LEN;
546391741ecSSepherosa Ziehau m->m_len += ETHER_HDR_LEN;
547391741ecSSepherosa Ziehau m->m_pkthdr.len += ETHER_HDR_LEN;
548391741ecSSepherosa Ziehau
549391741ecSSepherosa Ziehau eh = mtod(m, struct ether_header *);
550391741ecSSepherosa Ziehau bcopy(pktg->pktg_dst_lladdr, eh->ether_dhost, ETHER_ADDR_LEN);
551391741ecSSepherosa Ziehau bcopy(IF_LLADDR(ifp), eh->ether_shost, ETHER_ADDR_LEN);
552391741ecSSepherosa Ziehau eh->ether_type = htons(ETHERTYPE_IP);
553391741ecSSepherosa Ziehau
554391741ecSSepherosa Ziehau nextm = m->m_nextpkt;
555391741ecSSepherosa Ziehau m->m_nextpkt = NULL;
556391741ecSSepherosa Ziehau
557391741ecSSepherosa Ziehau ifq_dispatch(ifp, m, NULL);
558391741ecSSepherosa Ziehau
559391741ecSSepherosa Ziehau m = nextm;
560391741ecSSepherosa Ziehau }
561391741ecSSepherosa Ziehau
5621bbaa2adSSepherosa Ziehau callout_reset(&p->pktg_stop, pktg->pktg_duration * hz,
5631bbaa2adSSepherosa Ziehau pktgen_pcpu_stop_cb, p);
564391741ecSSepherosa Ziehau
565b0cd2b4bSSepherosa Ziehau pktgen_free(pktg);
5664fa8e46eSSepherosa Ziehau }
5674fa8e46eSSepherosa Ziehau
5684fa8e46eSSepherosa Ziehau static void
pktgen_mbuf(struct pktgen_buf * pb,struct mbuf * m)569391741ecSSepherosa Ziehau pktgen_mbuf(struct pktgen_buf *pb, struct mbuf *m)
570391741ecSSepherosa Ziehau {
571391741ecSSepherosa Ziehau m->m_ext.ext_arg = pb;
572391741ecSSepherosa Ziehau m->m_ext.ext_buf = pb->pb_buf;
573391741ecSSepherosa Ziehau m->m_ext.ext_free = pktgen_buf_free;
574391741ecSSepherosa Ziehau m->m_ext.ext_ref = pktgen_buf_ref;
575391741ecSSepherosa Ziehau m->m_ext.ext_size = PKTGEN_BUFSZ;
576391741ecSSepherosa Ziehau
577391741ecSSepherosa Ziehau m->m_data = m->m_ext.ext_buf;
578391741ecSSepherosa Ziehau m->m_flags |= M_EXT;
579391741ecSSepherosa Ziehau m->m_len = m->m_pkthdr.len = pb->pb_len;
580391741ecSSepherosa Ziehau }
581391741ecSSepherosa Ziehau
582391741ecSSepherosa Ziehau static void
pktgen_buf_send(netmsg_t msg)583391741ecSSepherosa Ziehau pktgen_buf_send(netmsg_t msg)
584391741ecSSepherosa Ziehau {
585391741ecSSepherosa Ziehau struct pktgen_buf *pb = (struct pktgen_buf *)msg;
586391741ecSSepherosa Ziehau struct mbuf *m;
587391741ecSSepherosa Ziehau
588ec7f7fc8SSepherosa Ziehau KKASSERT(&curthread->td_msgport == netisr_cpuport(pb->pb_cpuid));
589391741ecSSepherosa Ziehau
590391741ecSSepherosa Ziehau crit_enter();
591391741ecSSepherosa Ziehau lwkt_replymsg(&pb->pb_nmsg.lmsg, 0);
592391741ecSSepherosa Ziehau crit_exit();
593391741ecSSepherosa Ziehau
594b5523eacSSascha Wildner MGETHDR(m, M_WAITOK, MT_DATA);
595391741ecSSepherosa Ziehau pktgen_mbuf(pb, m);
596391741ecSSepherosa Ziehau ifq_dispatch(pb->pb_ifp, m, NULL);
597391741ecSSepherosa Ziehau }
598391741ecSSepherosa Ziehau
599391741ecSSepherosa Ziehau static void
pktgen_buf_free(void * arg)600391741ecSSepherosa Ziehau pktgen_buf_free(void *arg)
601391741ecSSepherosa Ziehau {
602391741ecSSepherosa Ziehau struct pktgen_buf *pb = arg;
603391741ecSSepherosa Ziehau struct mbuf *m;
604391741ecSSepherosa Ziehau
605391741ecSSepherosa Ziehau KKASSERT(pb->pb_inuse > 0);
606391741ecSSepherosa Ziehau if (pb->pb_done) {
607391741ecSSepherosa Ziehau if (atomic_fetchadd_int(&pb->pb_inuse, -1) == 1) {
608391741ecSSepherosa Ziehau struct pktgen *pktg;
609391741ecSSepherosa Ziehau
610391741ecSSepherosa Ziehau pktg = pb->pb_pktg;
6114c9906cbSSepherosa Ziehau crit_enter();
612391741ecSSepherosa Ziehau LIST_REMOVE(pb, pb_link);
6134c9906cbSSepherosa Ziehau crit_exit();
614391741ecSSepherosa Ziehau kfree(pb->pb_buf, M_PKTGEN);
615391741ecSSepherosa Ziehau kfree(pb, M_PKTGEN);
616391741ecSSepherosa Ziehau
617391741ecSSepherosa Ziehau pktgen_free(pktg);
618391741ecSSepherosa Ziehau }
619391741ecSSepherosa Ziehau return;
620391741ecSSepherosa Ziehau }
621391741ecSSepherosa Ziehau
622ec7f7fc8SSepherosa Ziehau if (&curthread->td_msgport != netisr_cpuport(pb->pb_cpuid)) {
623391741ecSSepherosa Ziehau KKASSERT(pb->pb_cpuid == mycpuid);
624391741ecSSepherosa Ziehau crit_enter();
625391741ecSSepherosa Ziehau KKASSERT(pb->pb_nmsg.lmsg.ms_flags & MSGF_DONE);
626ec7f7fc8SSepherosa Ziehau lwkt_sendmsg(netisr_cpuport(pb->pb_cpuid), &pb->pb_nmsg.lmsg);
627391741ecSSepherosa Ziehau crit_exit();
628391741ecSSepherosa Ziehau return;
629391741ecSSepherosa Ziehau }
630391741ecSSepherosa Ziehau
631b5523eacSSascha Wildner MGETHDR(m, M_WAITOK, MT_DATA);
632391741ecSSepherosa Ziehau pktgen_mbuf(pb, m);
6332fb36fabSSepherosa Ziehau ifsq_enqueue(pb->pb_ifsq, m, NULL);
634391741ecSSepherosa Ziehau }
635391741ecSSepherosa Ziehau
636391741ecSSepherosa Ziehau static void
pktgen_buf_ref(void * arg)637391741ecSSepherosa Ziehau pktgen_buf_ref(void *arg)
638391741ecSSepherosa Ziehau {
639391741ecSSepherosa Ziehau struct pktgen_buf *pb = arg;
640391741ecSSepherosa Ziehau
641391741ecSSepherosa Ziehau panic("%s should never be called\n", __func__);
642391741ecSSepherosa Ziehau
643391741ecSSepherosa Ziehau KKASSERT(pb->pb_inuse > 0);
644391741ecSSepherosa Ziehau atomic_add_int(&pb->pb_inuse, 1);
645391741ecSSepherosa Ziehau }
646391741ecSSepherosa Ziehau
647391741ecSSepherosa Ziehau static void
pktgen_free(struct pktgen * pktg)648391741ecSSepherosa Ziehau pktgen_free(struct pktgen *pktg)
649391741ecSSepherosa Ziehau {
650391741ecSSepherosa Ziehau KKASSERT(pktg->pktg_refcnt > 0);
6514c9906cbSSepherosa Ziehau if (atomic_fetchadd_int(&pktg->pktg_refcnt, -1) == 1) {
6521bbaa2adSSepherosa Ziehau int i;
6531bbaa2adSSepherosa Ziehau
654391741ecSSepherosa Ziehau if (pktg->pktg_dst != NULL)
655391741ecSSepherosa Ziehau kfree(pktg->pktg_dst, M_PKTGEN);
6561bbaa2adSSepherosa Ziehau
6571bbaa2adSSepherosa Ziehau for (i = 0; i < ncpus; ++i)
6581bbaa2adSSepherosa Ziehau KKASSERT(LIST_EMPTY(&pktg->pktg_pcpu[i].pktg_buflist));
659391741ecSSepherosa Ziehau kfree(pktg, M_PKTGEN);
660391741ecSSepherosa Ziehau }
661391741ecSSepherosa Ziehau
662391741ecSSepherosa Ziehau KKASSERT(pktgen_refcnt > 0);
6634c9906cbSSepherosa Ziehau atomic_subtract_int(&pktgen_refcnt, 1);
664391741ecSSepherosa Ziehau }
665391741ecSSepherosa Ziehau
666391741ecSSepherosa Ziehau static void
pktgen_pcpu_stop_cb(void * arg)6671bbaa2adSSepherosa Ziehau pktgen_pcpu_stop_cb(void *arg)
6684fa8e46eSSepherosa Ziehau {
6691bbaa2adSSepherosa Ziehau struct pktgen_pcpu *p = arg;
670391741ecSSepherosa Ziehau struct pktgen_buf *pb;
6714fa8e46eSSepherosa Ziehau
6724c9906cbSSepherosa Ziehau crit_enter();
6731bbaa2adSSepherosa Ziehau LIST_FOREACH(pb, &p->pktg_buflist, pb_link)
674391741ecSSepherosa Ziehau pb->pb_done = 1;
6754c9906cbSSepherosa Ziehau crit_exit();
6764fa8e46eSSepherosa Ziehau }
677c6830078SSepherosa Ziehau
678c6830078SSepherosa Ziehau static void
pktgen_ref(struct pktgen * pktg)679c6830078SSepherosa Ziehau pktgen_ref(struct pktgen *pktg)
680c6830078SSepherosa Ziehau {
681c6830078SSepherosa Ziehau atomic_add_int(&pktg->pktg_refcnt, 1);
682c6830078SSepherosa Ziehau atomic_add_int(&pktgen_refcnt, 1);
683c6830078SSepherosa Ziehau }
684