Fix UTIME_OMIT handling
[dragonfly.git] / sys / net / dummynet / ip_dummynet_glue.c
bloba52355fa51c55fc46d0c33b31e0ca2475d4f3074
1 /*
2 * Copyright (c) 2007 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Sepherosa Ziehau <sepherosa@gmail.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
35 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/malloc.h>
38 #include <sys/mbuf.h>
39 #include <sys/msgport.h>
40 #include <sys/socketvar.h>
41 #include <sys/sysctl.h>
43 #include <net/if.h>
44 #include <net/if_var.h>
45 #include <net/route.h>
46 #include <net/ethernet.h>
47 #include <net/netisr2.h>
48 #include <net/netmsg2.h>
50 #include <netinet/in.h>
51 #include <netinet/in_var.h>
52 #include <netinet/ip.h>
53 #include <netinet/ip_var.h>
55 #include <net/dummynet/ip_dummynet.h>
57 static void ip_dn_ether_output(netmsg_t);
58 static void ip_dn_ether_demux(netmsg_t);
59 static void ip_dn_ip_input(netmsg_t);
60 static void ip_dn_ip_output(netmsg_t);
62 static void ip_dn_sockopt_dispatch(netmsg_t);
63 static void ip_dn_freepkt_dispatch(netmsg_t);
64 static void ip_dn_dispatch(netmsg_t);
66 static void ip_dn_freepkt(struct dn_pkt *);
68 static int ip_dn_sockopt_flush(struct sockopt *);
69 static int ip_dn_sockopt_get(struct sockopt *);
70 static int ip_dn_sockopt_config(struct sockopt *);
72 ip_dn_io_t *ip_dn_io_ptr;
73 ip_dn_ctl_t *ip_dn_ctl_ptr;
74 int ip_dn_cpu = 0;
76 TUNABLE_INT("net.inet.ip.dummynet.cpu", &ip_dn_cpu);
78 SYSCTL_NODE(_net_inet_ip, OID_AUTO, dummynet, CTLFLAG_RW, 0, "Dummynet");
79 SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, cpu, CTLFLAG_RD,
80 &ip_dn_cpu, 0, "CPU to run dummynet");
82 void
83 ip_dn_queue(struct mbuf *m)
85 struct netmsg_packet *nmp;
86 lwkt_port_t port;
88 M_ASSERTPKTHDR(m);
89 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
90 ("mbuf is not tagged for dummynet!"));
92 nmp = &m->m_hdr.mh_netmsg;
93 netmsg_init(&nmp->base, NULL, &netisr_apanic_rport,
94 0, ip_dn_dispatch);
95 nmp->nm_packet = m;
97 port = netisr_cpuport(ip_dn_cpu);
98 lwkt_sendmsg(port, &nmp->base.lmsg);
101 void
102 ip_dn_packet_free(struct dn_pkt *pkt)
104 struct netmsg_packet *nmp;
105 struct mbuf *m = pkt->dn_m;
107 M_ASSERTPKTHDR(m);
108 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
109 ("mbuf is not tagged for dummynet!"));
111 nmp = &m->m_hdr.mh_netmsg;
112 netmsg_init(&nmp->base, NULL, &netisr_apanic_rport,
113 0, ip_dn_freepkt_dispatch);
114 nmp->nm_packet = m;
116 lwkt_sendmsg(pkt->msgport, &nmp->base.lmsg);
119 void
120 ip_dn_packet_redispatch(struct dn_pkt *pkt)
122 static const netisr_fn_t dispatches[DN_TO_MAX] = {
123 [DN_TO_IP_OUT] = ip_dn_ip_output,
124 [DN_TO_IP_IN] = ip_dn_ip_input,
125 [DN_TO_ETH_DEMUX] = ip_dn_ether_demux,
126 [DN_TO_ETH_OUT] = ip_dn_ether_output
129 struct netmsg_packet *nmp;
130 struct mbuf *m;
131 netisr_fn_t dispatch;
132 int dir;
134 dir = (pkt->dn_flags & DN_FLAGS_DIR_MASK);
135 KASSERT(dir < DN_TO_MAX,
136 ("unknown dummynet redispatch dir %d", dir));
138 dispatch = dispatches[dir];
139 KASSERT(dispatch != NULL,
140 ("unsupported dummynet redispatch dir %d", dir));
142 m = pkt->dn_m;
143 M_ASSERTPKTHDR(m);
144 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
145 ("mbuf is not tagged for dummynet!"));
147 nmp = &m->m_hdr.mh_netmsg;
148 netmsg_init(&nmp->base, NULL, &netisr_apanic_rport, 0, dispatch);
149 nmp->nm_packet = m;
151 lwkt_sendmsg(pkt->msgport, &nmp->base.lmsg);
155 ip_dn_sockopt(struct sockopt *sopt)
157 int error = 0;
159 /* Disallow sets in really-really secure mode. */
160 if (sopt->sopt_dir == SOPT_SET) {
161 if (securelevel >= 3)
162 return EPERM;
165 switch (sopt->sopt_name) {
166 case IP_DUMMYNET_GET:
167 error = ip_dn_sockopt_get(sopt);
168 break;
170 case IP_DUMMYNET_FLUSH:
171 error = ip_dn_sockopt_flush(sopt);
172 break;
174 case IP_DUMMYNET_DEL:
175 case IP_DUMMYNET_CONFIGURE:
176 error = ip_dn_sockopt_config(sopt);
177 break;
179 default:
180 kprintf("%s -- unknown option %d\n", __func__, sopt->sopt_name);
181 error = EINVAL;
182 break;
184 return error;
187 static void
188 ip_dn_freepkt(struct dn_pkt *pkt)
190 struct rtentry *rt = pkt->ro.ro_rt;
192 /* Unreference route entry */
193 if (rt != NULL) {
194 if (rt->rt_refcnt <= 0) { /* XXX assert? */
195 kprintf("-- warning, refcnt now %ld, decreasing\n",
196 rt->rt_refcnt);
198 RTFREE(rt);
201 /* Unreference packet private data */
202 if (pkt->dn_unref_priv)
203 pkt->dn_unref_priv(pkt->dn_priv);
205 /* Free the parent mbuf, this will free 'pkt' as well */
206 m_freem(pkt->dn_m);
209 static void
210 ip_dn_freepkt_dispatch(netmsg_t nmsg)
212 struct netmsg_packet *nmp;
213 struct mbuf *m;
214 struct m_tag *mtag;
215 struct dn_pkt *pkt;
217 nmp = &nmsg->packet;
218 m = nmp->nm_packet;
219 M_ASSERTPKTHDR(m);
220 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
221 ("mbuf is not tagged for dummynet!"));
223 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
224 KKASSERT(mtag != NULL);
226 pkt = m_tag_data(mtag);
227 KASSERT(pkt->cpuid == mycpuid,
228 ("%s: dummynet packet was delivered to wrong cpu! "
229 "target cpuid %d, mycpuid %d", __func__,
230 pkt->cpuid, mycpuid));
232 ip_dn_freepkt(pkt);
235 static void
236 ip_dn_dispatch(netmsg_t nmsg)
238 struct netmsg_packet *nmp;
239 struct mbuf *m;
240 struct m_tag *mtag;
241 struct dn_pkt *pkt;
243 KASSERT(ip_dn_cpu == mycpuid,
244 ("%s: dummynet packet was delivered to wrong cpu! "
245 "dummynet cpuid %d, mycpuid %d", __func__,
246 ip_dn_cpu, mycpuid));
248 nmp = &nmsg->packet;
249 m = nmp->nm_packet;
250 M_ASSERTPKTHDR(m);
251 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
252 ("mbuf is not tagged for dummynet!"));
254 if (DUMMYNET_LOADED) {
255 if (ip_dn_io_ptr(m) == 0)
256 return;
260 * ip_dn_io_ptr() failed or dummynet(4) is not loaded
262 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
263 KKASSERT(mtag != NULL);
265 pkt = m_tag_data(mtag);
266 ip_dn_packet_free(pkt);
269 static void
270 ip_dn_ip_output(netmsg_t nmsg)
272 struct netmsg_packet *nmp;
273 struct mbuf *m;
274 struct m_tag *mtag;
275 struct dn_pkt *pkt;
276 struct rtentry *rt;
277 ip_dn_unref_priv_t unref_priv;
278 void *priv;
280 nmp = &nmsg->packet;
281 m = nmp->nm_packet;
282 M_ASSERTPKTHDR(m);
283 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
284 ("mbuf is not tagged for dummynet!"));
286 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
287 KKASSERT(mtag != NULL);
289 pkt = m_tag_data(mtag);
290 KASSERT(pkt->cpuid == mycpuid,
291 ("%s: dummynet packet was delivered to wrong cpu! "
292 "target cpuid %d, mycpuid %d", __func__,
293 pkt->cpuid, mycpuid));
294 KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_IP_OUT,
295 ("wrong direction %d, should be %d",
296 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_IP_OUT));
298 priv = pkt->dn_priv;
299 unref_priv = pkt->dn_unref_priv;
300 rt = pkt->ro.ro_rt;
302 if (rt != NULL && !(rt->rt_flags & RTF_UP)) {
304 * Recorded rtentry is gone, when the packet
305 * was on delay line.
307 ip_dn_freepkt(pkt);
308 return;
311 ip_output(pkt->dn_m, NULL, NULL, pkt->flags, NULL, NULL);
312 /* 'rt' will be freed in ip_output */
314 if (unref_priv)
315 unref_priv(priv);
318 static void
319 ip_dn_ip_input(netmsg_t nmsg)
321 struct netmsg_packet *nmp;
322 struct mbuf *m;
323 struct m_tag *mtag;
324 struct dn_pkt *pkt;
325 ip_dn_unref_priv_t unref_priv;
326 void *priv;
327 struct ip *ip;
329 nmp = &nmsg->packet;
330 m = nmp->nm_packet;
331 M_ASSERTPKTHDR(m);
332 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
333 ("mbuf is not tagged for dummynet!"));
335 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
336 KKASSERT(mtag != NULL);
338 pkt = m_tag_data(mtag);
339 KASSERT(pkt->cpuid == mycpuid,
340 ("%s: dummynet packet was delivered to wrong cpu! "
341 "target cpuid %d, mycpuid %d", __func__,
342 pkt->cpuid, mycpuid));
343 KASSERT(pkt->ro.ro_rt == NULL,
344 ("route entry is not NULL for ip_input"));
345 KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_IP_IN,
346 ("wrong direction %d, should be %d",
347 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_IP_IN));
349 priv = pkt->dn_priv;
350 unref_priv = pkt->dn_unref_priv;
352 KKASSERT(m->m_len >= sizeof(*ip));
354 ip_input(m);
356 if (unref_priv)
357 unref_priv(priv);
360 static void
361 ip_dn_ether_demux(netmsg_t nmsg)
363 struct netmsg_packet *nmp;
364 struct mbuf *m;
365 struct m_tag *mtag;
366 struct dn_pkt *pkt;
367 ip_dn_unref_priv_t unref_priv;
368 void *priv;
370 nmp = &nmsg->packet;
371 m = nmp->nm_packet;
372 M_ASSERTPKTHDR(m);
373 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
374 ("mbuf is not tagged for dummynet!"));
376 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
377 KKASSERT(mtag != NULL);
379 pkt = m_tag_data(mtag);
380 KASSERT(pkt->cpuid == mycpuid,
381 ("%s: dummynet packet was delivered to wrong cpu! "
382 "target cpuid %d, mycpuid %d", __func__,
383 pkt->cpuid, mycpuid));
384 KASSERT(pkt->ro.ro_rt == NULL,
385 ("route entry is not NULL for ether_demux"));
386 KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_ETH_DEMUX,
387 ("wrong direction %d, should be %d",
388 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_ETH_DEMUX));
390 priv = pkt->dn_priv;
391 unref_priv = pkt->dn_unref_priv;
394 * Make sure that ether header is contiguous
396 if (m->m_len < ETHER_HDR_LEN &&
397 (m = m_pullup(m, ETHER_HDR_LEN)) == NULL) {
398 kprintf("%s: pullup fail, dropping pkt\n", __func__);
399 goto back;
401 ether_demux_oncpu(m->m_pkthdr.rcvif, m);
402 back:
403 if (unref_priv)
404 unref_priv(priv);
407 static void
408 ip_dn_ether_output(netmsg_t nmsg)
410 struct netmsg_packet *nmp;
411 struct mbuf *m;
412 struct m_tag *mtag;
413 struct dn_pkt *pkt;
414 ip_dn_unref_priv_t unref_priv;
415 void *priv;
417 nmp = &nmsg->packet;
418 m = nmp->nm_packet;
419 M_ASSERTPKTHDR(m);
420 KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
421 ("mbuf is not tagged for dummynet!"));
423 mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
424 KKASSERT(mtag != NULL);
426 pkt = m_tag_data(mtag);
427 KASSERT(pkt->cpuid == mycpuid,
428 ("%s: dummynet packet was delivered to wrong cpu! "
429 "target cpuid %d, mycpuid %d", __func__,
430 pkt->cpuid, mycpuid));
431 KASSERT(pkt->ro.ro_rt == NULL,
432 ("route entry is not NULL for ether_output_frame"));
433 KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_ETH_OUT,
434 ("wrong direction %d, should be %d",
435 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_ETH_OUT));
437 priv = pkt->dn_priv;
438 unref_priv = pkt->dn_unref_priv;
440 ether_output_frame(pkt->ifp, m);
442 if (unref_priv)
443 unref_priv(priv);
446 static void
447 ip_dn_sockopt_dispatch(netmsg_t nmsg)
449 lwkt_msg *msg = &nmsg->lmsg;
450 struct dn_sopt *dn_sopt = msg->u.ms_resultp;
451 int error;
453 KASSERT(ip_dn_cpu == mycpuid,
454 ("%s: dummynet sockopt is done on wrong cpu! "
455 "dummynet cpuid %d, mycpuid %d", __func__,
456 ip_dn_cpu, mycpuid));
458 if (DUMMYNET_LOADED)
459 error = ip_dn_ctl_ptr(dn_sopt);
460 else
461 error = ENOPROTOOPT;
462 lwkt_replymsg(msg, error);
465 static int
466 ip_dn_sockopt_flush(struct sockopt *sopt)
468 struct dn_sopt dn_sopt;
469 struct netmsg_base smsg;
471 bzero(&dn_sopt, sizeof(dn_sopt));
472 dn_sopt.dn_sopt_name = sopt->sopt_name;
474 netmsg_init(&smsg, NULL, &curthread->td_msgport,
475 0, ip_dn_sockopt_dispatch);
476 smsg.lmsg.u.ms_resultp = &dn_sopt;
477 lwkt_domsg(netisr_cpuport(ip_dn_cpu), &smsg.lmsg, 0);
479 return smsg.lmsg.ms_error;
482 static int
483 ip_dn_sockopt_get(struct sockopt *sopt)
485 struct dn_sopt dn_sopt;
486 struct netmsg_base smsg;
487 int error;
489 bzero(&dn_sopt, sizeof(dn_sopt));
490 dn_sopt.dn_sopt_name = sopt->sopt_name;
492 netmsg_init(&smsg, NULL, &curthread->td_msgport,
493 0, ip_dn_sockopt_dispatch);
494 smsg.lmsg.u.ms_resultp = &dn_sopt;
495 lwkt_domsg(netisr_cpuport(ip_dn_cpu), &smsg.lmsg, 0);
497 error = smsg.lmsg.ms_error;
498 if (error) {
499 KKASSERT(dn_sopt.dn_sopt_arg == NULL);
500 KKASSERT(dn_sopt.dn_sopt_arglen == 0);
501 return error;
504 soopt_from_kbuf(sopt, dn_sopt.dn_sopt_arg, dn_sopt.dn_sopt_arglen);
505 kfree(dn_sopt.dn_sopt_arg, M_TEMP);
506 return 0;
509 static int
510 ip_dn_sockopt_config(struct sockopt *sopt)
512 struct dn_ioc_pipe tmp_ioc_pipe;
513 struct dn_sopt dn_sopt;
514 struct netmsg_base smsg;
515 int error;
517 error = soopt_to_kbuf(sopt, &tmp_ioc_pipe, sizeof tmp_ioc_pipe,
518 sizeof tmp_ioc_pipe);
519 if (error)
520 return error;
522 bzero(&dn_sopt, sizeof(dn_sopt));
523 dn_sopt.dn_sopt_name = sopt->sopt_name;
524 dn_sopt.dn_sopt_arg = &tmp_ioc_pipe;
525 dn_sopt.dn_sopt_arglen = sizeof(tmp_ioc_pipe);
527 netmsg_init(&smsg, NULL, &curthread->td_msgport,
528 0, ip_dn_sockopt_dispatch);
529 smsg.lmsg.u.ms_resultp = &dn_sopt;
530 lwkt_domsg(netisr_cpuport(ip_dn_cpu), &smsg.lmsg, 0);
532 return smsg.lmsg.ms_error;