Annotation of src/sys/netinet/udp_usrreq.c, Revision 1.190.2.3
1.190.2.3! rmind 1: /* $NetBSD$ */
1.48 itojun 2:
3: /*
4: * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5: * All rights reserved.
1.94 itojun 6: *
1.48 itojun 7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. Neither the name of the project nor the names of its contributors
16: * may be used to endorse or promote products derived from this software
17: * without specific prior written permission.
1.94 itojun 18: *
1.48 itojun 19: * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22: * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: */
1.14 cgd 31:
1.1 cgd 32: /*
1.44 thorpej 33: * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995
1.13 mycroft 34: * The Regents of the University of California. All rights reserved.
1.1 cgd 35: *
36: * Redistribution and use in source and binary forms, with or without
37: * modification, are permitted provided that the following conditions
38: * are met:
39: * 1. Redistributions of source code must retain the above copyright
40: * notice, this list of conditions and the following disclaimer.
41: * 2. Redistributions in binary form must reproduce the above copyright
42: * notice, this list of conditions and the following disclaimer in the
43: * documentation and/or other materials provided with the distribution.
1.104 agc 44: * 3. Neither the name of the University nor the names of its contributors
1.1 cgd 45: * may be used to endorse or promote products derived from this software
46: * without specific prior written permission.
47: *
48: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58: * SUCH DAMAGE.
59: *
1.44 thorpej 60: * @(#)udp_usrreq.c 8.6 (Berkeley) 5/23/95
1.1 cgd 61: */
1.91 lukem 62:
1.190.2.1 rmind 63: /*
64: * UDP protocol implementation.
65: * Per RFC 768, August, 1980.
66: */
67:
1.91 lukem 68: #include <sys/cdefs.h>
1.190.2.3! rmind 69: __KERNEL_RCSID(0, "$NetBSD$");
1.50 thorpej 70:
1.77 soda 71: #include "opt_inet.h"
1.174 christos 72: #include "opt_compat_netbsd.h"
1.50 thorpej 73: #include "opt_ipsec.h"
1.78 thorpej 74: #include "opt_inet_csum.h"
1.64 ws 75: #include "opt_ipkdb.h"
1.101 martin 76: #include "opt_mbuftrace.h"
1.1 cgd 77:
1.5 mycroft 78: #include <sys/param.h>
79: #include <sys/mbuf.h>
80: #include <sys/protosw.h>
81: #include <sys/socket.h>
82: #include <sys/socketvar.h>
1.27 christos 83: #include <sys/systm.h>
1.190.2.1 rmind 84: #include <sys/kmem.h>
1.53 itojun 85: #include <sys/domain.h>
1.27 christos 86: #include <sys/sysctl.h>
1.1 cgd 87:
1.5 mycroft 88: #include <net/if.h>
89: #include <net/route.h>
1.1 cgd 90:
1.5 mycroft 91: #include <netinet/in.h>
92: #include <netinet/in_systm.h>
1.15 cgd 93: #include <netinet/in_var.h>
1.5 mycroft 94: #include <netinet/ip.h>
95: #include <netinet/in_pcb.h>
96: #include <netinet/ip_var.h>
97: #include <netinet/ip_icmp.h>
98: #include <netinet/udp.h>
99: #include <netinet/udp_var.h>
1.166 thorpej 100: #include <netinet/udp_private.h>
1.1 cgd 101:
1.53 itojun 102: #ifdef INET6
103: #include <netinet/ip6.h>
104: #include <netinet/icmp6.h>
105: #include <netinet6/ip6_var.h>
1.167 thorpej 106: #include <netinet6/ip6_private.h>
1.53 itojun 107: #include <netinet6/in6_pcb.h>
108: #include <netinet6/udp6_var.h>
1.168 thorpej 109: #include <netinet6/udp6_private.h>
1.53 itojun 110: #endif
111:
112: #ifndef INET6
113: /* always need ip6.h for IP6_EXTHDR_GET */
114: #include <netinet/ip6.h>
115: #endif
116:
1.190 christos 117: #ifdef IPSEC
1.105 jonathan 118: #include <netipsec/ipsec.h>
1.169 thorpej 119: #include <netipsec/ipsec_var.h>
120: #include <netipsec/ipsec_private.h>
1.147 christos 121: #include <netipsec/esp.h>
1.105 jonathan 122: #ifdef INET6
123: #include <netipsec/ipsec6.h>
124: #endif
1.190 christos 125: #endif /* IPSEC */
1.105 jonathan 126:
1.174 christos 127: #ifdef COMPAT_50
128: #include <compat/sys/socket.h>
129: #endif
130:
1.64 ws 131: #ifdef IPKDB
132: #include <ipkdb/ipkdb.h>
133: #endif
134:
1.8 mycroft 135: int udpcksum = 1;
1.141 yamt 136: int udp_do_loopback_cksum = 0;
1.93 matt 137:
1.190.2.1 rmind 138: inpcbtable_t * udbtable __read_mostly;
139: percpu_t * udpstat_percpu;
1.8 mycroft 140:
1.72 itojun 141: #ifdef INET
1.190 christos 142: #ifdef IPSEC
1.144 manu 143: static int udp4_espinudp (struct mbuf **, int, struct sockaddr *,
1.130 manu 144: struct socket *);
1.189 christos 145: #endif
1.119 matt 146: static void udp4_sendup (struct mbuf *, int, struct sockaddr *,
147: struct socket *);
148: static int udp4_realinput (struct sockaddr_in *, struct sockaddr_in *,
1.144 manu 149: struct mbuf **, int);
1.129 yamt 150: static int udp4_input_checksum(struct mbuf *, const struct udphdr *, int, int);
1.72 itojun 151: #endif
1.7 mycroft 152:
1.26 mycroft 153: #ifndef UDBHASHSIZE
154: #define UDBHASHSIZE 128
155: #endif
156: int udbhashsize = UDBHASHSIZE;
157:
1.190.2.1 rmind 158: static int udp_sendspace = 9216;
159: static int udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
160:
1.98 matt 161: #ifdef MBUFTRACE
1.150 dogcow 162: struct mowner udp_mowner = MOWNER_INIT("udp", "");
163: struct mowner udp_rx_mowner = MOWNER_INIT("udp", "rx");
164: struct mowner udp_tx_mowner = MOWNER_INIT("udp", "tx");
1.98 matt 165: #endif
166:
1.78 thorpej 167: #ifdef UDP_CSUM_COUNTERS
168: #include <sys/device.h>
169:
1.140 yamt 170: #if defined(INET)
1.78 thorpej 171: struct evcnt udp_hwcsum_bad = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
172: NULL, "udp", "hwcsum bad");
173: struct evcnt udp_hwcsum_ok = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
174: NULL, "udp", "hwcsum ok");
175: struct evcnt udp_hwcsum_data = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
176: NULL, "udp", "hwcsum data");
177: struct evcnt udp_swcsum = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
178: NULL, "udp", "swcsum");
179:
1.120 matt 180: EVCNT_ATTACH_STATIC(udp_hwcsum_bad);
181: EVCNT_ATTACH_STATIC(udp_hwcsum_ok);
182: EVCNT_ATTACH_STATIC(udp_hwcsum_data);
183: EVCNT_ATTACH_STATIC(udp_swcsum);
1.140 yamt 184: #endif /* defined(INET) */
185:
186: #define UDP_CSUM_COUNTER_INCR(ev) (ev)->ev_count++
1.78 thorpej 187: #else
188: #define UDP_CSUM_COUNTER_INCR(ev) /* nothing */
189: #endif /* UDP_CSUM_COUNTERS */
190:
1.179 pooka 191: static void sysctl_net_inet_udp_setup(struct sysctllog **);
192:
1.7 mycroft 193: void
1.119 matt 194: udp_init(void)
1.1 cgd 195: {
1.190.2.1 rmind 196: udbtable = inpcb_init(udbhashsize, udbhashsize, 0);
1.179 pooka 197: sysctl_net_inet_udp_setup(NULL);
198:
1.98 matt 199: MOWNER_ATTACH(&udp_tx_mowner);
200: MOWNER_ATTACH(&udp_rx_mowner);
201: MOWNER_ATTACH(&udp_mowner);
1.166 thorpej 202:
1.171 yamt 203: #ifdef INET
1.166 thorpej 204: udpstat_percpu = percpu_alloc(sizeof(uint64_t) * UDP_NSTATS);
1.171 yamt 205: #endif
1.1 cgd 206: }
207:
1.129 yamt 208: /*
209: * Checksum extended UDP header and data.
210: */
211:
212: int
213: udp_input_checksum(int af, struct mbuf *m, const struct udphdr *uh,
214: int iphlen, int len)
215: {
216: switch (af) {
1.72 itojun 217: #ifdef INET
1.129 yamt 218: case AF_INET:
219: return udp4_input_checksum(m, uh, iphlen, len);
220: #endif
221: #ifdef INET6
222: case AF_INET6:
223: return udp6_input_checksum(m, uh, iphlen, len);
224: #endif
1.190.2.1 rmind 225: default:
226: KASSERT(false);
1.129 yamt 227: }
228: return -1;
229: }
230:
231: #ifdef INET
232:
233: /*
234: * Checksum extended UDP header and data.
235: */
236:
237: static int
238: udp4_input_checksum(struct mbuf *m, const struct udphdr *uh,
239: int iphlen, int len)
240: {
241:
242: /*
243: * XXX it's better to record and check if this mbuf is
244: * already checked.
245: */
246:
247: if (uh->uh_sum == 0)
248: return 0;
249:
250: switch (m->m_pkthdr.csum_flags &
251: ((m->m_pkthdr.rcvif->if_csum_flags_rx & M_CSUM_UDPv4) |
252: M_CSUM_TCP_UDP_BAD | M_CSUM_DATA)) {
253: case M_CSUM_UDPv4|M_CSUM_TCP_UDP_BAD:
254: UDP_CSUM_COUNTER_INCR(&udp_hwcsum_bad);
255: goto badcsum;
256:
257: case M_CSUM_UDPv4|M_CSUM_DATA: {
258: u_int32_t hw_csum = m->m_pkthdr.csum_data;
259:
260: UDP_CSUM_COUNTER_INCR(&udp_hwcsum_data);
261: if (m->m_pkthdr.csum_flags & M_CSUM_NO_PSEUDOHDR) {
262: const struct ip *ip =
263: mtod(m, const struct ip *);
264:
265: hw_csum = in_cksum_phdr(ip->ip_src.s_addr,
266: ip->ip_dst.s_addr,
267: htons(hw_csum + len + IPPROTO_UDP));
268: }
269: if ((hw_csum ^ 0xffff) != 0)
270: goto badcsum;
271: break;
272: }
273:
274: case M_CSUM_UDPv4:
275: /* Checksum was okay. */
276: UDP_CSUM_COUNTER_INCR(&udp_hwcsum_ok);
277: break;
278:
279: default:
280: /*
281: * Need to compute it ourselves. Maybe skip checksum
282: * on loopback interfaces.
283: */
284: if (__predict_true(!(m->m_pkthdr.rcvif->if_flags &
285: IFF_LOOPBACK) ||
286: udp_do_loopback_cksum)) {
287: UDP_CSUM_COUNTER_INCR(&udp_swcsum);
288: if (in4_cksum(m, IPPROTO_UDP, iphlen, len) != 0)
289: goto badcsum;
290: }
291: break;
292: }
293:
294: return 0;
295:
296: badcsum:
1.166 thorpej 297: UDP_STATINC(UDP_STAT_BADSUM);
1.129 yamt 298: return -1;
299: }
300:
1.7 mycroft 301: void
1.27 christos 302: udp_input(struct mbuf *m, ...)
1.1 cgd 303: {
1.53 itojun 304: va_list ap;
305: struct sockaddr_in src, dst;
306: struct ip *ip;
307: struct udphdr *uh;
1.97 simonb 308: int iphlen;
1.53 itojun 309: int len;
310: int n;
1.96 itojun 311: u_int16_t ip_len;
1.53 itojun 312:
313: va_start(ap, m);
314: iphlen = va_arg(ap, int);
1.97 simonb 315: (void)va_arg(ap, int); /* ignore value, advance ap */
1.53 itojun 316: va_end(ap);
317:
1.98 matt 318: MCLAIM(m, &udp_rx_mowner);
1.166 thorpej 319: UDP_STATINC(UDP_STAT_IPACKETS);
1.53 itojun 320:
321: /*
322: * Get IP and UDP header together in first mbuf.
323: */
324: ip = mtod(m, struct ip *);
325: IP6_EXTHDR_GET(uh, struct udphdr *, m, iphlen, sizeof(struct udphdr));
326: if (uh == NULL) {
1.166 thorpej 327: UDP_STATINC(UDP_STAT_HDROPS);
1.53 itojun 328: return;
329: }
1.95 thorpej 330: KASSERT(UDP_HDR_ALIGNED_P(uh));
1.53 itojun 331:
1.57 itojun 332: /* destination port of 0 is illegal, based on RFC768. */
333: if (uh->uh_dport == 0)
334: goto bad;
335:
1.53 itojun 336: /*
337: * Make mbuf data length reflect UDP length.
338: * If not enough data to reflect UDP length, drop.
339: */
1.96 itojun 340: ip_len = ntohs(ip->ip_len);
1.53 itojun 341: len = ntohs((u_int16_t)uh->uh_ulen);
1.96 itojun 342: if (ip_len != iphlen + len) {
343: if (ip_len < iphlen + len || len < sizeof(struct udphdr)) {
1.166 thorpej 344: UDP_STATINC(UDP_STAT_BADLEN);
1.53 itojun 345: goto bad;
346: }
1.96 itojun 347: m_adj(m, iphlen + len - ip_len);
1.53 itojun 348: }
349:
350: /*
351: * Checksum extended UDP header and data.
352: */
1.129 yamt 353: if (udp4_input_checksum(m, uh, iphlen, len))
354: goto badcsum;
1.53 itojun 355:
356: /* construct source and dst sockaddrs. */
1.159 dyoung 357: sockaddr_in_init(&src, &ip->ip_src, uh->uh_sport);
358: sockaddr_in_init(&dst, &ip->ip_dst, uh->uh_dport);
1.53 itojun 359:
1.144 manu 360: if ((n = udp4_realinput(&src, &dst, &m, iphlen)) == -1) {
1.166 thorpej 361: UDP_STATINC(UDP_STAT_HDROPS);
1.144 manu 362: return;
363: }
1.188 christos 364: if (m == NULL) {
365: /*
366: * packet has been processed by ESP stuff -
367: * e.g. dropped NAT-T-keep-alive-packet ...
368: */
369: return;
370: }
371: ip = mtod(m, struct ip *);
1.53 itojun 372: #ifdef INET6
373: if (IN_MULTICAST(ip->ip_dst.s_addr) || n == 0) {
374: struct sockaddr_in6 src6, dst6;
375:
1.175 cegger 376: memset(&src6, 0, sizeof(src6));
1.53 itojun 377: src6.sin6_family = AF_INET6;
378: src6.sin6_len = sizeof(struct sockaddr_in6);
379: src6.sin6_addr.s6_addr[10] = src6.sin6_addr.s6_addr[11] = 0xff;
1.177 tsutsui 380: memcpy(&src6.sin6_addr.s6_addr[12], &ip->ip_src,
1.53 itojun 381: sizeof(ip->ip_src));
382: src6.sin6_port = uh->uh_sport;
1.175 cegger 383: memset(&dst6, 0, sizeof(dst6));
1.53 itojun 384: dst6.sin6_family = AF_INET6;
385: dst6.sin6_len = sizeof(struct sockaddr_in6);
386: dst6.sin6_addr.s6_addr[10] = dst6.sin6_addr.s6_addr[11] = 0xff;
1.177 tsutsui 387: memcpy(&dst6.sin6_addr.s6_addr[12], &ip->ip_dst,
1.53 itojun 388: sizeof(ip->ip_dst));
389: dst6.sin6_port = uh->uh_dport;
390:
391: n += udp6_realinput(AF_INET, &src6, &dst6, m, iphlen);
392: }
393: #endif
394:
395: if (n == 0) {
396: if (m->m_flags & (M_BCAST | M_MCAST)) {
1.166 thorpej 397: UDP_STATINC(UDP_STAT_NOPORTBCAST);
1.53 itojun 398: goto bad;
399: }
1.166 thorpej 400: UDP_STATINC(UDP_STAT_NOPORT);
1.64 ws 401: #ifdef IPKDB
1.53 itojun 402: if (checkipkdb(&ip->ip_src, uh->uh_sport, uh->uh_dport,
403: m, iphlen + sizeof(struct udphdr),
404: m->m_pkthdr.len - iphlen - sizeof(struct udphdr))) {
405: /*
406: * It was a debugger connect packet,
407: * just drop it now
408: */
409: goto bad;
410: }
411: #endif
412: icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);
413: m = NULL;
414: }
415:
416: bad:
417: if (m)
418: m_freem(m);
1.78 thorpej 419: return;
420:
421: badcsum:
422: m_freem(m);
1.53 itojun 423: }
424:
425: static void
1.119 matt 426: udp4_sendup(struct mbuf *m, int off /* offset of data portion */,
427: struct sockaddr *src, struct socket *so)
1.53 itojun 428: {
429: struct mbuf *opts = NULL;
430: struct mbuf *n;
1.190.2.1 rmind 431: inpcb_t *inp = NULL;
1.53 itojun 432:
433: if (!so)
434: return;
435: switch (so->so_proto->pr_domain->dom_family) {
436: case AF_INET:
437: inp = sotoinpcb(so);
438: break;
439: #ifdef INET6
440: case AF_INET6:
441: break;
442: #endif
443: default:
444: return;
445: }
446:
1.190 christos 447: #if defined(IPSEC)
1.53 itojun 448: /* check AH/ESP integrity. */
449: if (so != NULL && ipsec4_in_reject_so(m, so)) {
1.169 thorpej 450: IPSEC_STATINC(IPSEC_STAT_IN_POLVIO);
1.162 dyoung 451: if ((n = m_copypacket(m, M_DONTWAIT)) != NULL)
1.110 itojun 452: icmp_error(n, ICMP_UNREACH, ICMP_UNREACH_ADMIN_PROHIBIT,
453: 0, 0);
1.53 itojun 454: return;
455: }
456: #endif /*IPSEC*/
457:
1.162 dyoung 458: if ((n = m_copypacket(m, M_DONTWAIT)) != NULL) {
1.190.2.1 rmind 459: if (inp && ((inpcb_get_flags(inp) & INP_CONTROLOPTS) != 0
1.174 christos 460: #ifdef SO_OTIMESTAMP
461: || so->so_options & SO_OTIMESTAMP
462: #endif
1.53 itojun 463: || so->so_options & SO_TIMESTAMP)) {
464: struct ip *ip = mtod(n, struct ip *);
465: ip_savecontrol(inp, &opts, ip, n);
466: }
467:
468: m_adj(n, off);
469: if (sbappendaddr(&so->so_rcv, src, n,
470: opts) == 0) {
471: m_freem(n);
472: if (opts)
473: m_freem(opts);
1.124 darrenr 474: so->so_rcv.sb_overflowed++;
1.166 thorpej 475: UDP_STATINC(UDP_STAT_FULLSOCK);
1.53 itojun 476: } else
477: sorwakeup(so);
478: }
479: }
480:
1.190.2.1 rmind 481: struct udp_pcb_ctx {
482: struct mbuf * mbuf;
483: struct sockaddr_in * src;
484: struct sockaddr_in * dst;
485: int off;
486: int rcvcnt;
487: };
1.53 itojun 488:
1.190.2.1 rmind 489: static int
490: udp4_pcb_process(inpcb_t *inp, void *arg)
491: {
492: struct udp_pcb_ctx *uctx = arg;
493: struct in_addr dst4 = uctx->dst->sin_addr;
494: in_port_t dport = uctx->dst->sin_port;
495: struct in_addr laddr, faddr;
496: in_port_t lport, fport;
497: struct socket *so;
1.53 itojun 498:
1.190.2.1 rmind 499: inpcb_get_ports(inp, &lport, &fport);
500: if (lport != dport) {
501: return 0;
1.53 itojun 502: }
1.190.2.1 rmind 503: inpcb_get_addrs(inp, &laddr, &faddr);
504: if (!in_nullhost(laddr) && !in_hosteq(laddr, dst4)) {
505: return 0;
506: }
507: if (!in_nullhost(faddr)) {
508: struct in_addr src4 = uctx->src->sin_addr;
509: in_port_t sport = uctx->src->sin_port;
1.53 itojun 510:
1.190.2.1 rmind 511: if (!in_hosteq(faddr, src4) || fport != sport) {
512: return 0;
1.53 itojun 513: }
1.190.2.1 rmind 514: }
1.53 itojun 515:
1.190.2.1 rmind 516: so = inpcb_get_socket(inp);
517: udp4_sendup(uctx->mbuf, uctx->off, (struct sockaddr *)uctx->src, so);
518: uctx->rcvcnt++;
519:
520: /*
521: * Do not look for additional matches if this one does not have
522: * either the SO_REUSEPORT or SO_REUSEADDR socket options set.
523: * This heuristic avoids searching through all PCBs in the common
524: * case of a non-shared port. It assumes that an application will
525: * never clear these options after setting them.
526: */
527: if ((so->so_options & (SO_REUSEPORT|SO_REUSEADDR)) == 0) {
528: return EJUSTRETURN;
1.53 itojun 529: }
1.190.2.1 rmind 530: return 0;
1.53 itojun 531: }
532:
533: static int
1.119 matt 534: udp4_realinput(struct sockaddr_in *src, struct sockaddr_in *dst,
1.190.2.1 rmind 535: struct mbuf **mp, int off /* offset of udphdr */)
1.53 itojun 536: {
1.190.2.1 rmind 537: in_port_t *sport, *dport;
1.53 itojun 538: struct in_addr *src4, *dst4;
1.190.2.1 rmind 539: inpcb_t *inp;
1.144 manu 540: struct mbuf *m = *mp;
1.190.2.1 rmind 541: int rcvcnt;
1.53 itojun 542:
543: rcvcnt = 0;
544: off += sizeof(struct udphdr); /* now, offset of payload */
545:
546: if (src->sin_family != AF_INET || dst->sin_family != AF_INET)
547: goto bad;
548:
549: src4 = &src->sin_addr;
550: sport = &src->sin_port;
551: dst4 = &dst->sin_addr;
552: dport = &dst->sin_port;
553:
1.73 itojun 554: if (IN_MULTICAST(dst4->s_addr) ||
1.53 itojun 555: in_broadcast(*dst4, m->m_pkthdr.rcvif)) {
1.190.2.1 rmind 556: struct udp_pcb_ctx uctx = {
557: .mbuf = m, .src = src, .dst = dst,
558: .off = off, .rcvcnt = 0
559: };
560: int error;
561:
1.53 itojun 562: /*
563: * Deliver a multicast or broadcast datagram to *all* sockets
564: * for which the local and remote addresses and ports match
565: * those of the incoming datagram. This allows more than
566: * one process to receive multi/broadcasts on the same port.
567: */
1.190.2.1 rmind 568: error = inpcb_foreach(udbtable, AF_INET,
569: udp4_pcb_process, &uctx);
570: KASSERT(error == 0 || error == EJUSTRETURN);
571: rcvcnt = uctx.rcvcnt;
1.53 itojun 572: } else {
573: /*
1.190.2.1 rmind 574: * Locate PCB for datagram.
1.53 itojun 575: */
1.190.2.1 rmind 576: struct socket *so;
577:
1.190.2.3! rmind 578: inp = inpcb_lookup(udbtable, *src4, *sport, *dst4, *dport, NULL);
1.190.2.1 rmind 579: if (inp == NULL) {
1.166 thorpej 580: UDP_STATINC(UDP_STAT_PCBHASHMISS);
1.190.2.3! rmind 581: inp = inpcb_lookup_bound(udbtable, *dst4, *dport);
1.190.2.1 rmind 582: if (inp == NULL)
1.53 itojun 583: return rcvcnt;
584: }
1.190.2.1 rmind 585: so = inpcb_get_socket(inp);
1.53 itojun 586:
1.190 christos 587: #ifdef IPSEC
1.130 manu 588: /* Handle ESP over UDP */
1.190.2.1 rmind 589: if (inpcb_get_flags(inp) & INP_ESPINUDP_ALL) {
1.130 manu 590: struct sockaddr *sa = (struct sockaddr *)src;
591:
1.190.2.1 rmind 592: switch (udp4_espinudp(mp, off, sa, so)) {
1.144 manu 593: case -1: /* Error, m was freeed */
594: rcvcnt = -1;
595: goto bad;
596: break;
597:
598: case 1: /* ESP over UDP */
1.130 manu 599: rcvcnt++;
600: goto bad;
1.144 manu 601: break;
602:
603: case 0: /* plain UDP */
604: default: /* Unexpected */
605: /*
606: * Normal UDP processing will take place
607: * m may have changed.
608: */
609: m = *mp;
610: break;
1.130 manu 611: }
612: }
1.189 christos 613: #endif
1.130 manu 614:
1.178 minskim 615: /*
616: * Check the minimum TTL for socket.
617: */
1.190.2.1 rmind 618: if (mtod(m, struct ip *)->ip_ttl < inpcb_get_minttl(inp)) {
1.178 minskim 619: goto bad;
1.53 itojun 620: }
1.190.2.1 rmind 621: udp4_sendup(m, off, (struct sockaddr *)src, so);
1.53 itojun 622: rcvcnt++;
623: }
624:
625: bad:
626: return rcvcnt;
627: }
628: #endif
1.1 cgd 629:
1.72 itojun 630: #ifdef INET
1.1 cgd 631: /*
1.190.2.1 rmind 632: * Notify a UDP user of an asynchronous error;
1.1 cgd 633: * just wake up so that he can collect error status.
634: */
1.7 mycroft 635: static void
1.190.2.1 rmind 636: udp_notify(inpcb_t *inp, int errno)
1.1 cgd 637: {
1.190.2.1 rmind 638: struct socket *so = inpcb_get_socket(inp);
639:
640: so->so_error = errno;
641: sorwakeup(so);
642: sowwakeup(so);
1.1 cgd 643: }
644:
1.27 christos 645: void *
1.157 dyoung 646: udp_ctlinput(int cmd, const struct sockaddr *sa, void *v)
1.1 cgd 647: {
1.66 augustss 648: struct ip *ip = v;
649: struct udphdr *uh;
1.21 mycroft 650: int errno;
1.190.2.1 rmind 651: bool rdr;
1.1 cgd 652:
1.190.2.1 rmind 653: if (sa->sa_family != AF_INET ||
654: sa->sa_len != sizeof(struct sockaddr_in))
1.51 itojun 655: return NULL;
1.20 mycroft 656: if ((unsigned)cmd >= PRC_NCMDS)
1.27 christos 657: return NULL;
1.20 mycroft 658: errno = inetctlerrmap[cmd];
1.190.2.1 rmind 659:
660: rdr = PRC_IS_REDIRECT(cmd);
661: if (rdr || cmd == PRC_HOSTDEAD || ip == NULL) {
662: inpcb_notifyall(udbtable, satocsin(sa)->sin_addr,
663: errno, rdr ? inpcb_rtchange : udp_notify);
1.27 christos 664: return NULL;
1.190.2.1 rmind 665: } else if (errno == 0) {
666: return NULL;
667: }
1.53 itojun 668:
1.190.2.1 rmind 669: /* Note: mapped address case */
670: uh = (struct udphdr *)((char *)ip + (ip->ip_hl << 2));
671: inpcb_notify(udbtable, satocsin(sa)->sin_addr, uh->uh_dport,
672: ip->ip_src, uh->uh_sport, errno, udp_notify);
1.27 christos 673: return NULL;
1.1 cgd 674: }
675:
1.7 mycroft 676: int
1.173 plunky 677: udp_ctloutput(int op, struct socket *so, struct sockopt *sopt)
1.130 manu 678: {
1.190.2.1 rmind 679: int s, family, optval, inpflags, error = 0;
680: inpcb_t *inp;
1.130 manu 681:
682: family = so->so_proto->pr_domain->dom_family;
683:
684: s = splsoftnet();
685: switch (family) {
686: #ifdef INET
687: case PF_INET:
1.173 plunky 688: if (sopt->sopt_level != IPPROTO_UDP) {
689: error = ip_ctloutput(op, so, sopt);
1.130 manu 690: goto end;
691: }
692: break;
693: #endif
694: #ifdef INET6
695: case PF_INET6:
1.173 plunky 696: if (sopt->sopt_level != IPPROTO_UDP) {
697: error = ip6_ctloutput(op, so, sopt);
1.130 manu 698: goto end;
699: }
700: break;
701: #endif
702: default:
703: error = EAFNOSUPPORT;
704: goto end;
705: }
706:
707: switch (op) {
708: case PRCO_SETOPT:
709: inp = sotoinpcb(so);
710:
1.173 plunky 711: switch (sopt->sopt_name) {
1.130 manu 712: case UDP_ENCAP:
1.173 plunky 713: error = sockopt_getint(sopt, &optval);
714: if (error)
1.153 yamt 715: break;
1.131 perry 716:
1.190.2.1 rmind 717: inpflags = inpcb_get_flags(inp);
1.173 plunky 718: switch(optval) {
1.130 manu 719: case 0:
1.190.2.1 rmind 720: inpflags &= ~INP_ESPINUDP_ALL;
1.130 manu 721: break;
722:
723: case UDP_ENCAP_ESPINUDP:
1.190.2.1 rmind 724: inpflags &= ~INP_ESPINUDP_ALL;
725: inpflags |= INP_ESPINUDP;
1.130 manu 726: break;
1.131 perry 727:
1.130 manu 728: case UDP_ENCAP_ESPINUDP_NON_IKE:
1.190.2.1 rmind 729: inpflags &= ~INP_ESPINUDP_ALL;
730: inpflags |= INP_ESPINUDP_NON_IKE;
1.130 manu 731: break;
732: default:
733: error = EINVAL;
734: break;
735: }
1.190.2.1 rmind 736: inpcb_set_flags(inp, inpflags);
1.130 manu 737: break;
1.190.2.1 rmind 738:
1.130 manu 739: default:
740: error = ENOPROTOOPT;
741: break;
742: }
743: break;
744:
745: default:
746: error = EINVAL;
747: break;
1.131 perry 748: }
749:
1.130 manu 750: end:
751: splx(s);
752: return error;
753: }
1.131 perry 754:
1.190.2.3! rmind 755: static int
! 756: udp_output(struct mbuf *m, inpcb_t *inp)
1.27 christos 757: {
1.190.2.1 rmind 758: struct socket *so;
1.66 augustss 759: struct udpiphdr *ui;
1.125 thorpej 760: struct route *ro;
1.66 augustss 761: int len = m->m_pkthdr.len;
1.31 mycroft 762: int error = 0;
1.27 christos 763:
1.98 matt 764: MCLAIM(m, &udp_tx_mowner);
1.190.2.1 rmind 765: so = inpcb_get_socket(inp);
766: KASSERT(solocked(so));
767:
1.1 cgd 768: /*
1.190.2.3! rmind 769: * Calculate data length and get a mbuf for UDP and IP headers.
1.1 cgd 770: */
1.13 mycroft 771: M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
1.190.2.3! rmind 772: if (m == NULL) {
1.13 mycroft 773: error = ENOBUFS;
1.39 thorpej 774: goto release;
775: }
776:
777: /*
778: * Compute the packet length of the IP header, and
779: * punt if the length looks bogus.
780: */
1.96 itojun 781: if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) {
1.39 thorpej 782: error = EMSGSIZE;
1.13 mycroft 783: goto release;
784: }
1.1 cgd 785:
786: /*
1.190.2.3! rmind 787: * Fill in mbuf with extended UDP header.
1.1 cgd 788: */
789: ui = mtod(m, struct udpiphdr *);
790: ui->ui_pr = IPPROTO_UDP;
1.190.2.1 rmind 791: inpcb_get_addrs(inp, &ui->ui_src, &ui->ui_dst);
792: inpcb_get_ports(inp, &ui->ui_sport, &ui->ui_dport);
1.190.2.3! rmind 793: ui->ui_ulen = htons((uint16_t)len + sizeof(struct udphdr));
1.1 cgd 794:
1.190.2.1 rmind 795: ro = inpcb_get_route(inp);
1.125 thorpej 796:
1.1 cgd 797: /*
1.78 thorpej 798: * Set up checksum and output datagram.
1.1 cgd 799: */
800: if (udpcksum) {
1.78 thorpej 801: /*
802: * XXX Cache pseudo-header checksum part for
803: * XXX "connected" UDP sockets.
804: */
805: ui->ui_sum = in_cksum_phdr(ui->ui_src.s_addr,
806: ui->ui_dst.s_addr, htons((u_int16_t)len +
807: sizeof(struct udphdr) + IPPROTO_UDP));
1.135 yamt 808: m->m_pkthdr.csum_flags = M_CSUM_UDPv4;
1.78 thorpej 809: m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum);
810: } else
811: ui->ui_sum = 0;
1.190.2.1 rmind 812:
1.190.2.3! rmind 813: struct ip *ui_ip = (struct ip *)ui;
! 814: ui_ip->ip_len = htons(sizeof (struct udpiphdr) + len);
1.190.2.1 rmind 815:
816: struct ip *inp_ip = in_getiphdr(inp);
1.190.2.3! rmind 817: ui_ip->ip_ttl = inp_ip->ip_ttl; /* XXX */
! 818: ui_ip->ip_tos = inp_ip->ip_tos; /* XXX */
1.166 thorpej 819: UDP_STATINC(UDP_STAT_OPACKETS);
1.48 itojun 820:
1.190.2.1 rmind 821: return (ip_output(m, inpcb_get_options(inp), ro,
822: so->so_options & (SO_DONTROUTE | SO_BROADCAST),
823: inpcb_get_moptions(inp), so));
1.1 cgd 824:
825: release:
826: m_freem(m);
1.190.2.1 rmind 827: return error;
1.1 cgd 828: }
829:
1.190.2.2 rmind 830: static int
831: udp_attach(struct socket *so, int proto)
832: {
833: inpcb_t *inp;
834: struct ip *ip;
835: int s, error;
836:
837: KASSERT(sotoinpcb(so) == NULL);
838:
839: s = splsoftnet();
840: sosetlock(so);
841:
842: #ifdef MBUFTRACE
843: so->so_mowner = &udp_mowner;
844: so->so_rcv.sb_mowner = &udp_rx_mowner;
845: so->so_snd.sb_mowner = &udp_tx_mowner;
846: #endif
847: if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
848: error = soreserve(so, udp_sendspace, udp_recvspace);
849: if (error) {
850: goto out;
851: }
852: }
853:
854: error = inpcb_create(so, udbtable);
855: if (error) {
856: goto out;
857: }
858: inp = sotoinpcb(so);
859: ip = in_getiphdr(inp);
860: ip->ip_ttl = ip_defttl;
861: out:
862: splx(s);
863: return error;
864: }
865:
866: static void
867: udp_detach(struct socket *so)
868: {
869: inpcb_t *inp;
870: int s;
871:
872: KASSERT(solocked(so));
873:
874: s = splsoftnet();
875: inp = sotoinpcb(so);
876: KASSERT(inp != NULL);
877: inpcb_destroy(inp);
878: splx(s);
879: }
880:
881: static int
1.190.2.3! rmind 882: udp_send(struct socket *so, struct mbuf *m, struct mbuf *nam,
! 883: struct mbuf *control)
! 884: {
! 885: inpcb_t *inp;
! 886: struct in_addr laddr;
! 887: int error;
! 888:
! 889: KASSERT(solocked(so));
! 890: inp = sotoinpcb(so);
! 891:
! 892: if (control && control->m_len) {
! 893: m_freem(control);
! 894: m_freem(m);
! 895: return EINVAL;
! 896: }
! 897:
! 898: if ((so->so_state & SS_ISCONNECTED) != 0) {
! 899: m_freem(m);
! 900: return nam ? EISCONN : ENOTCONN;
! 901: }
! 902:
! 903: if (nam) {
! 904: /*
! 905: * XXX: sendto() case - temporarily connect the socket
! 906: * to the destination, send and then disconnect. Also,
! 907: * preserve the local address as it may be changed.
! 908: */
! 909: inpcb_get_addrs(inp, &laddr, NULL);
! 910: if ((error = inpcb_connect(inp, nam, curlwp)) != 0) {
! 911: m_freem(m);
! 912: return error;
! 913: }
! 914: }
! 915: error = udp_output(m, inp);
! 916: if (nam) {
! 917: inpcb_disconnect(inp);
! 918: inpcb_set_addrs(inp, &laddr, NULL);
! 919: inpcb_set_state(inp, INP_BOUND);
! 920: }
! 921: return error;
! 922: }
! 923:
! 924: static int
1.119 matt 925: udp_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
1.190.2.1 rmind 926: struct mbuf *control, struct lwp *l)
1.1 cgd 927: {
1.190.2.1 rmind 928: inpcb_t *inp;
929: int s, error = 0;
1.59 thorpej 930:
1.190.2.2 rmind 931: KASSERT(req != PRU_ATTACH);
932: KASSERT(req != PRU_DETACH);
933:
1.190.2.1 rmind 934: if (req == PRU_CONTROL) {
935: return in_control(so, (long)m, nam, (ifnet_t *)control, l);
936: }
1.149 tls 937: s = splsoftnet();
1.60 thorpej 938: if (req == PRU_PURGEIF) {
1.170 ad 939: mutex_enter(softnet_lock);
1.190.2.1 rmind 940: inpcb_purgeif0(udbtable, (ifnet_t *)control);
941: in_purgeif((ifnet_t *)control);
942: inpcb_purgeif(udbtable, (ifnet_t *)control);
1.170 ad 943: mutex_exit(softnet_lock);
1.149 tls 944: splx(s);
1.59 thorpej 945: return (0);
946: }
1.31 mycroft 947:
1.190.2.2 rmind 948: KASSERT(solocked(so));
1.31 mycroft 949: inp = sotoinpcb(so);
1.190.2.1 rmind 950:
951: KASSERT(!control || (req == PRU_SEND || req == PRU_SENDOOB));
1.190.2.2 rmind 952: if (inp == NULL) {
1.31 mycroft 953: error = EINVAL;
954: goto release;
955: }
956:
1.1 cgd 957: switch (req) {
958: case PRU_BIND:
1.190.2.1 rmind 959: error = inpcb_bind(inp, nam, l);
1.1 cgd 960: break;
961:
962: case PRU_LISTEN:
963: error = EOPNOTSUPP;
964: break;
965:
966: case PRU_CONNECT:
1.190.2.1 rmind 967: error = inpcb_connect(inp, nam, l);
1.31 mycroft 968: if (error)
1.1 cgd 969: break;
1.31 mycroft 970: soisconnected(so);
1.1 cgd 971: break;
972:
973: case PRU_CONNECT2:
974: error = EOPNOTSUPP;
975: break;
976:
977: case PRU_DISCONNECT:
1.31 mycroft 978: /*soisdisconnected(so);*/
1.190.2.1 rmind 979: so->so_state &= ~SS_ISCONNECTED; /* XXX */
980: inpcb_disconnect(inp);
1.1 cgd 981: break;
982:
983: case PRU_SHUTDOWN:
984: socantsendmore(so);
985: break;
986:
1.31 mycroft 987: case PRU_RCVD:
988: error = EOPNOTSUPP;
1.1 cgd 989: break;
990:
1.31 mycroft 991: case PRU_SEND:
1.190.2.3! rmind 992: error = udp_send(so, m, nam, control);
1.1 cgd 993: break;
994:
995: case PRU_SENSE:
996: /*
997: * stat: don't bother with a blocksize.
998: */
1.31 mycroft 999: splx(s);
1.1 cgd 1000: return (0);
1001:
1.31 mycroft 1002: case PRU_RCVOOB:
1003: error = EOPNOTSUPP;
1004: break;
1005:
1.1 cgd 1006: case PRU_SENDOOB:
1.32 mycroft 1007: m_freem(control);
1.31 mycroft 1008: m_freem(m);
1.1 cgd 1009: error = EOPNOTSUPP;
1010: break;
1011:
1.31 mycroft 1012: case PRU_SOCKADDR:
1.190.2.1 rmind 1013: inpcb_fetch_sockaddr(inp, nam);
1.31 mycroft 1014: break;
1015:
1016: case PRU_PEERADDR:
1.190.2.1 rmind 1017: inpcb_fetch_peeraddr(inp, nam);
1.31 mycroft 1018: break;
1.1 cgd 1019:
1020: default:
1021: panic("udp_usrreq");
1022: }
1023:
1024: release:
1.31 mycroft 1025: splx(s);
1.1 cgd 1026: return (error);
1.13 mycroft 1027: }
1028:
1.166 thorpej 1029: static int
1030: sysctl_net_inet_udp_stats(SYSCTLFN_ARGS)
1031: {
1032:
1.172 thorpej 1033: return (NETSTAT_SYSCTL(udpstat_percpu, UDP_NSTATS));
1.166 thorpej 1034: }
1035:
1.13 mycroft 1036: /*
1037: * Sysctl for udp variables.
1038: */
1.179 pooka 1039: static void
1040: sysctl_net_inet_udp_setup(struct sysctllog **clog)
1.13 mycroft 1041: {
1.116 atatat 1042: sysctl_createv(clog, 0, NULL, NULL,
1043: CTLFLAG_PERMANENT,
1.114 atatat 1044: CTLTYPE_NODE, "net", NULL,
1045: NULL, 0, NULL, 0,
1046: CTL_NET, CTL_EOL);
1.116 atatat 1047: sysctl_createv(clog, 0, NULL, NULL,
1048: CTLFLAG_PERMANENT,
1.114 atatat 1049: CTLTYPE_NODE, "inet", NULL,
1050: NULL, 0, NULL, 0,
1051: CTL_NET, PF_INET, CTL_EOL);
1.116 atatat 1052: sysctl_createv(clog, 0, NULL, NULL,
1053: CTLFLAG_PERMANENT,
1.122 atatat 1054: CTLTYPE_NODE, "udp",
1055: SYSCTL_DESCR("UDPv4 related settings"),
1.114 atatat 1056: NULL, 0, NULL, 0,
1057: CTL_NET, PF_INET, IPPROTO_UDP, CTL_EOL);
1058:
1.116 atatat 1059: sysctl_createv(clog, 0, NULL, NULL,
1060: CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
1.122 atatat 1061: CTLTYPE_INT, "checksum",
1.123 heas 1062: SYSCTL_DESCR("Compute UDP checksums"),
1.114 atatat 1063: NULL, 0, &udpcksum, 0,
1064: CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_CHECKSUM,
1065: CTL_EOL);
1.116 atatat 1066: sysctl_createv(clog, 0, NULL, NULL,
1067: CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
1.122 atatat 1068: CTLTYPE_INT, "sendspace",
1069: SYSCTL_DESCR("Default UDP send buffer size"),
1.114 atatat 1070: NULL, 0, &udp_sendspace, 0,
1071: CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_SENDSPACE,
1072: CTL_EOL);
1.116 atatat 1073: sysctl_createv(clog, 0, NULL, NULL,
1074: CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
1.122 atatat 1075: CTLTYPE_INT, "recvspace",
1076: SYSCTL_DESCR("Default UDP receive buffer size"),
1.114 atatat 1077: NULL, 0, &udp_recvspace, 0,
1078: CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_RECVSPACE,
1079: CTL_EOL);
1.125 thorpej 1080: sysctl_createv(clog, 0, NULL, NULL,
1081: CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
1082: CTLTYPE_INT, "do_loopback_cksum",
1083: SYSCTL_DESCR("Perform UDP checksum on loopback"),
1084: NULL, 0, &udp_do_loopback_cksum, 0,
1085: CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_LOOPBACKCKSUM,
1086: CTL_EOL);
1.132 atatat 1087: sysctl_createv(clog, 0, NULL, NULL,
1088: CTLFLAG_PERMANENT,
1.134 atatat 1089: CTLTYPE_STRUCT, "pcblist",
1.132 atatat 1090: SYSCTL_DESCR("UDP protocol control block list"),
1.190.2.1 rmind 1091: sysctl_inpcblist, 0, udbtable, 0,
1.132 atatat 1092: CTL_NET, PF_INET, IPPROTO_UDP, CTL_CREATE,
1093: CTL_EOL);
1.139 elad 1094: sysctl_createv(clog, 0, NULL, NULL,
1095: CTLFLAG_PERMANENT,
1096: CTLTYPE_STRUCT, "stats",
1097: SYSCTL_DESCR("UDP statistics"),
1.166 thorpej 1098: sysctl_net_inet_udp_stats, 0, NULL, 0,
1.139 elad 1099: CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS,
1100: CTL_EOL);
1.1 cgd 1101: }
1.72 itojun 1102: #endif
1.130 manu 1103:
1.166 thorpej 1104: void
1105: udp_statinc(u_int stat)
1106: {
1107:
1108: KASSERT(stat < UDP_NSTATS);
1109: UDP_STATINC(stat);
1110: }
1111:
1.190 christos 1112: #if defined(INET) && defined(IPSEC)
1.130 manu 1113: /*
1114: * Returns:
1115: * 1 if the packet was processed
1116: * 0 if normal UDP processing should take place
1.144 manu 1117: * -1 if an error occurent and m was freed
1.130 manu 1118: */
1119: static int
1.154 yamt 1120: udp4_espinudp(struct mbuf **mp, int off, struct sockaddr *src,
1.151 christos 1121: struct socket *so)
1.130 manu 1122: {
1123: size_t len;
1.158 christos 1124: void *data;
1.190.2.1 rmind 1125: inpcb_t *inp;
1.130 manu 1126: size_t skip = 0;
1127: size_t minlen;
1128: size_t iphdrlen;
1129: struct ip *ip;
1.136 manu 1130: struct m_tag *tag;
1131: struct udphdr *udphdr;
1.190.2.1 rmind 1132: in_port_t sport, dport;
1.144 manu 1133: struct mbuf *m = *mp;
1.190.2.1 rmind 1134: int inpflags;
1.130 manu 1135:
1.131 perry 1136: /*
1.130 manu 1137: * Collapse the mbuf chain if the first mbuf is too short
1138: * The longest case is: UDP + non ESP marker + ESP
1139: */
1140: minlen = off + sizeof(u_int64_t) + sizeof(struct esp);
1141: if (minlen > m->m_pkthdr.len)
1142: minlen = m->m_pkthdr.len;
1143:
1144: if (m->m_len < minlen) {
1.144 manu 1145: if ((*mp = m_pullup(m, minlen)) == NULL) {
1.130 manu 1146: printf("udp4_espinudp: m_pullup failed\n");
1.144 manu 1147: return -1;
1.130 manu 1148: }
1.144 manu 1149: m = *mp;
1.130 manu 1150: }
1151:
1.131 perry 1152: len = m->m_len - off;
1.158 christos 1153: data = mtod(m, char *) + off;
1.130 manu 1154: inp = sotoinpcb(so);
1155:
1156: /* Ignore keepalive packets */
1.158 christos 1157: if ((len == 1) && (*(unsigned char *)data == 0xff)) {
1.188 christos 1158: m_free(m);
1159: *mp = NULL; /* avoid any further processiong by caller ... */
1.130 manu 1160: return 1;
1161: }
1.190.2.1 rmind 1162: inpflags = inpcb_get_flags(inp);
1.130 manu 1163:
1.131 perry 1164: /*
1165: * Check that the payload is long enough to hold
1.130 manu 1166: * an ESP header and compute the length of encapsulation
1.131 perry 1167: * header to remove
1.130 manu 1168: */
1.190.2.1 rmind 1169: if (inpflags & INP_ESPINUDP) {
1.130 manu 1170: u_int32_t *st = (u_int32_t *)data;
1171:
1172: if ((len <= sizeof(struct esp)) || (*st == 0))
1173: return 0; /* Normal UDP processing */
1174:
1175: skip = sizeof(struct udphdr);
1176: }
1177:
1.190.2.1 rmind 1178: if (inpflags & INP_ESPINUDP_NON_IKE) {
1.142 kleink 1179: u_int32_t *st = (u_int32_t *)data;
1.130 manu 1180:
1181: if ((len <= sizeof(u_int64_t) + sizeof(struct esp))
1.142 kleink 1182: || ((st[0] | st[1]) != 0))
1.130 manu 1183: return 0; /* Normal UDP processing */
1.131 perry 1184:
1.130 manu 1185: skip = sizeof(struct udphdr) + sizeof(u_int64_t);
1186: }
1187:
1188: /*
1.136 manu 1189: * Get the UDP ports. They are handled in network
1190: * order everywhere in IPSEC_NAT_T code.
1191: */
1.158 christos 1192: udphdr = (struct udphdr *)((char *)data - skip);
1.136 manu 1193: sport = udphdr->uh_sport;
1194: dport = udphdr->uh_dport;
1195:
1196: /*
1.130 manu 1197: * Remove the UDP header (and possibly the non ESP marker)
1198: * IP header lendth is iphdrlen
1.131 perry 1199: * Before:
1.130 manu 1200: * <--- off --->
1201: * +----+------+-----+
1202: * | IP | UDP | ESP |
1203: * +----+------+-----+
1204: * <-skip->
1205: * After:
1206: * +----+-----+
1207: * | IP | ESP |
1208: * +----+-----+
1209: * <-skip->
1210: */
1211: iphdrlen = off - sizeof(struct udphdr);
1.158 christos 1212: memmove(mtod(m, char *) + skip, mtod(m, void *), iphdrlen);
1.130 manu 1213: m_adj(m, skip);
1214:
1215: ip = mtod(m, struct ip *);
1216: ip->ip_len = htons(ntohs(ip->ip_len) - skip);
1217: ip->ip_p = IPPROTO_ESP;
1218:
1219: /*
1.188 christos 1220: * We have modified the packet - it is now ESP, so we should not
1221: * return to UDP processing ...
1222: *
1.136 manu 1223: * Add a PACKET_TAG_IPSEC_NAT_T_PORT tag to remember
1224: * the source UDP port. This is required if we want
1225: * to select the right SPD for multiple hosts behind
1226: * same NAT
1227: */
1.137 manu 1228: if ((tag = m_tag_get(PACKET_TAG_IPSEC_NAT_T_PORTS,
1229: sizeof(sport) + sizeof(dport), M_DONTWAIT)) == NULL) {
1230: printf("udp4_espinudp: m_tag_get failed\n");
1.188 christos 1231: m_freem(m);
1232: return -1;
1.137 manu 1233: }
1.136 manu 1234: ((u_int16_t *)(tag + 1))[0] = sport;
1235: ((u_int16_t *)(tag + 1))[1] = dport;
1.188 christos 1236: m_tag_prepend(m, tag);
1.136 manu 1237:
1.190 christos 1238: #ifdef IPSEC
1.188 christos 1239: ipsec4_common_input(m, iphdrlen, IPPROTO_ESP);
1.147 christos 1240: #else
1.188 christos 1241: esp4_input(m, iphdrlen);
1.147 christos 1242: #endif
1.130 manu 1243:
1.185 liamjfoy 1244: /* We handled it, it shouldn't be handled by UDP */
1.188 christos 1245: *mp = NULL; /* avoid free by caller ... */
1.130 manu 1246: return 1;
1247: }
1248: #endif
1.190.2.2 rmind 1249:
1250: PR_WRAP_USRREQ(udp_usrreq)
1251:
1252: #define udp_usrreq udp_usrreq_wrapper
1253:
1254: const struct pr_usrreqs udp_usrreqs = {
1255: .pr_attach = udp_attach,
1256: .pr_detach = udp_detach,
1257: .pr_generic = udp_usrreq,
1258: };
CVSweb <webmaster@jp.NetBSD.org>