1 /* $NetBSD: udp6_usrreq.c,v 1.51 2001/11/13 00:57:07 lukem Exp $ */ 2 /* $KAME: udp6_usrreq.c,v 1.86 2001/05/27 17:33:00 itojun Exp $ */ 3 4 /* 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * 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 the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (c) 1982, 1986, 1989, 1993 35 * The Regents of the University of California. All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 3. All advertising materials mentioning features or use of this software 46 * must display the following acknowledgement: 47 * This product includes software developed by the University of 48 * California, Berkeley and its contributors. 49 * 4. Neither the name of the University nor the names of its contributors 50 * may be used to endorse or promote products derived from this software 51 * without specific prior written permission. 52 * 53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63 * SUCH DAMAGE. 64 * 65 * @(#)udp_var.h 8.1 (Berkeley) 6/10/93 66 */ 67 68 #include <sys/cdefs.h> 69 __KERNEL_RCSID(0, "$NetBSD: udp6_usrreq.c,v 1.51 2001/11/13 00:57:07 lukem Exp $"); 70 71 #include "opt_ipsec.h" 72 73 #include <sys/param.h> 74 #include <sys/malloc.h> 75 #include <sys/mbuf.h> 76 #include <sys/protosw.h> 77 #include <sys/socket.h> 78 #include <sys/socketvar.h> 79 #include <sys/errno.h> 80 #include <sys/stat.h> 81 #include <sys/systm.h> 82 #include <sys/proc.h> 83 #include <sys/syslog.h> 84 #include <sys/sysctl.h> 85 86 #include <net/if.h> 87 #include <net/route.h> 88 #include <net/if_types.h> 89 90 #include <netinet/in.h> 91 #include <netinet/in_var.h> 92 #include <netinet/in_systm.h> 93 #include <netinet/ip.h> 94 #include <netinet/ip_var.h> 95 #include <netinet/in_pcb.h> 96 #include <netinet/udp.h> 97 #include <netinet/udp_var.h> 98 #include <netinet/ip6.h> 99 #include <netinet6/ip6_var.h> 100 #include <netinet6/in6_pcb.h> 101 #include <netinet/icmp6.h> 102 #include <netinet6/udp6_var.h> 103 #include <netinet6/ip6protosw.h> 104 105 #ifdef IPSEC 106 #include <netinet6/ipsec.h> 107 #endif /* IPSEC */ 108 109 #include "faith.h" 110 #if defined(NFAITH) && NFAITH > 0 111 #include <net/if_faith.h> 112 #endif 113 114 /* 115 * UDP protocol inplementation. 116 * Per RFC 768, August, 1980. 117 */ 118 119 struct in6pcb *udp6_last_in6pcb = &udb6; 120 121 static void udp6_detach __P((struct in6pcb *)); 122 static void udp6_notify __P((struct in6pcb *, int)); 123 124 void 125 udp6_init() 126 { 127 udb6.in6p_next = udb6.in6p_prev = &udb6; 128 } 129 130 /* 131 * Notify a udp user of an asynchronous error; 132 * just wake up so that he can collect error status. 133 */ 134 static void 135 udp6_notify(in6p, errno) 136 struct in6pcb *in6p; 137 int errno; 138 { 139 in6p->in6p_socket->so_error = errno; 140 sorwakeup(in6p->in6p_socket); 141 sowwakeup(in6p->in6p_socket); 142 } 143 144 void 145 udp6_ctlinput(cmd, sa, d) 146 int cmd; 147 struct sockaddr *sa; 148 void *d; 149 { 150 struct udphdr uh; 151 struct ip6_hdr *ip6; 152 struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa; 153 struct mbuf *m; 154 int off; 155 void *cmdarg; 156 struct ip6ctlparam *ip6cp = NULL; 157 const struct sockaddr_in6 *sa6_src = NULL; 158 void (*notify) __P((struct in6pcb *, int)) = udp6_notify; 159 struct udp_portonly { 160 u_int16_t uh_sport; 161 u_int16_t uh_dport; 162 } *uhp; 163 164 if (sa->sa_family != AF_INET6 || 165 sa->sa_len != sizeof(struct sockaddr_in6)) 166 return; 167 168 if ((unsigned)cmd >= PRC_NCMDS) 169 return; 170 if (PRC_IS_REDIRECT(cmd)) 171 notify = in6_rtchange, d = NULL; 172 else if (cmd == PRC_HOSTDEAD) 173 d = NULL; 174 else if (cmd == PRC_MSGSIZE) { 175 /* special code is present, see below */ 176 notify = in6_rtchange; 177 } 178 else if (inet6ctlerrmap[cmd] == 0) 179 return; 180 181 /* if the parameter is from icmp6, decode it. */ 182 if (d != NULL) { 183 ip6cp = (struct ip6ctlparam *)d; 184 m = ip6cp->ip6c_m; 185 ip6 = ip6cp->ip6c_ip6; 186 off = ip6cp->ip6c_off; 187 cmdarg = ip6cp->ip6c_cmdarg; 188 sa6_src = ip6cp->ip6c_src; 189 } else { 190 m = NULL; 191 ip6 = NULL; 192 cmdarg = NULL; 193 sa6_src = &sa6_any; 194 } 195 196 if (ip6) { 197 /* 198 * XXX: We assume that when IPV6 is non NULL, 199 * M and OFF are valid. 200 */ 201 202 /* check if we can safely examine src and dst ports */ 203 if (m->m_pkthdr.len < off + sizeof(*uhp)) { 204 if (cmd == PRC_MSGSIZE) 205 icmp6_mtudisc_update((struct ip6ctlparam *)d, 0); 206 return; 207 } 208 209 bzero(&uh, sizeof(uh)); 210 m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh); 211 212 if (cmd == PRC_MSGSIZE) { 213 int valid = 0; 214 215 /* 216 * Check to see if we have a valid UDP socket 217 * corresponding to the address in the ICMPv6 message 218 * payload. 219 */ 220 if (in6_pcblookup_connect(&udb6, &sa6->sin6_addr, 221 uh.uh_dport, (struct in6_addr *)&sa6_src->sin6_addr, 222 uh.uh_sport, 0)) 223 valid++; 224 #if 0 225 /* 226 * As the use of sendto(2) is fairly popular, 227 * we may want to allow non-connected pcb too. 228 * But it could be too weak against attacks... 229 * We should at least check if the local address (= s) 230 * is really ours. 231 */ 232 else if (in6_pcblookup_bind(&udb6, &sa6->sin6_addr, 233 uh.uh_dport, 0)) 234 valid++; 235 #endif 236 237 /* 238 * Depending on the value of "valid" and routing table 239 * size (mtudisc_{hi,lo}wat), we will: 240 * - recalculate the new MTU and create the 241 * corresponding routing entry, or 242 * - ignore the MTU change notification. 243 */ 244 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid); 245 246 /* 247 * regardless of if we called icmp6_mtudisc_update(), 248 * we need to call in6_pcbnotify(), to notify path 249 * MTU change to the userland (2292bis-02), because 250 * some unconnected sockets may share the same 251 * destination and want to know the path MTU. 252 */ 253 } 254 255 (void) in6_pcbnotify(&udb6, sa, uh.uh_dport, 256 (struct sockaddr *)sa6_src, uh.uh_sport, cmd, cmdarg, 257 notify); 258 } else { 259 (void) in6_pcbnotify(&udb6, sa, 0, (struct sockaddr *)sa6_src, 260 0, cmd, cmdarg, notify); 261 } 262 } 263 264 extern int udp6_sendspace; 265 extern int udp6_recvspace; 266 267 int 268 udp6_usrreq(so, req, m, addr6, control, p) 269 struct socket *so; 270 int req; 271 struct mbuf *m, *addr6, *control; 272 struct proc *p; 273 { 274 struct in6pcb *in6p = sotoin6pcb(so); 275 int error = 0; 276 int s; 277 278 /* 279 * MAPPED_ADDR implementation info: 280 * Mapped addr support for PRU_CONTROL is not necessary. 281 * Because typical user of PRU_CONTROL is such as ifconfig, 282 * and they don't associate any addr to their socket. Then 283 * socket family is only hint about the PRU_CONTROL'ed address 284 * family, especially when getting addrs from kernel. 285 * So AF_INET socket need to be used to control AF_INET addrs, 286 * and AF_INET6 socket for AF_INET6 addrs. 287 */ 288 if (req == PRU_CONTROL) 289 return(in6_control(so, (u_long)m, (caddr_t)addr6, 290 (struct ifnet *)control, p)); 291 292 if (req == PRU_PURGEIF) { 293 in6_pcbpurgeif0(&udb6, (struct ifnet *)control); 294 in6_purgeif((struct ifnet *)control); 295 in6_pcbpurgeif(&udb6, (struct ifnet *)control); 296 return (0); 297 } 298 299 if (in6p == NULL && req != PRU_ATTACH) { 300 error = EINVAL; 301 goto release; 302 } 303 304 switch (req) { 305 case PRU_ATTACH: 306 /* 307 * MAPPED_ADDR implementation spec: 308 * Always attach for IPv6, 309 * and only when necessary for IPv4. 310 */ 311 if (in6p != NULL) { 312 error = EINVAL; 313 break; 314 } 315 s = splsoftnet(); 316 error = in6_pcballoc(so, &udb6); 317 splx(s); 318 if (error) 319 break; 320 error = soreserve(so, udp6_sendspace, udp6_recvspace); 321 if (error) 322 break; 323 in6p = sotoin6pcb(so); 324 in6p->in6p_cksum = -1; /* just to be sure */ 325 break; 326 327 case PRU_DETACH: 328 udp6_detach(in6p); 329 break; 330 331 case PRU_BIND: 332 s = splsoftnet(); 333 error = in6_pcbbind(in6p, addr6, p); 334 splx(s); 335 break; 336 337 case PRU_LISTEN: 338 error = EOPNOTSUPP; 339 break; 340 341 case PRU_CONNECT: 342 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { 343 error = EISCONN; 344 break; 345 } 346 s = splsoftnet(); 347 error = in6_pcbconnect(in6p, addr6); 348 if (ip6_auto_flowlabel) { 349 in6p->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK; 350 in6p->in6p_flowinfo |= 351 (htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK); 352 } 353 splx(s); 354 if (error == 0) 355 soisconnected(so); 356 break; 357 358 case PRU_CONNECT2: 359 error = EOPNOTSUPP; 360 break; 361 362 case PRU_ACCEPT: 363 error = EOPNOTSUPP; 364 break; 365 366 case PRU_DISCONNECT: 367 if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { 368 error = ENOTCONN; 369 break; 370 } 371 s = splsoftnet(); 372 in6_pcbdisconnect(in6p); 373 bzero((caddr_t)&in6p->in6p_laddr, sizeof(in6p->in6p_laddr)); 374 splx(s); 375 so->so_state &= ~SS_ISCONNECTED; /* XXX */ 376 break; 377 378 case PRU_SHUTDOWN: 379 socantsendmore(so); 380 break; 381 382 case PRU_SEND: 383 return(udp6_output(in6p, m, addr6, control, p)); 384 385 case PRU_ABORT: 386 soisdisconnected(so); 387 udp6_detach(in6p); 388 break; 389 390 case PRU_SOCKADDR: 391 in6_setsockaddr(in6p, addr6); 392 break; 393 394 case PRU_PEERADDR: 395 in6_setpeeraddr(in6p, addr6); 396 break; 397 398 case PRU_SENSE: 399 /* 400 * stat: don't bother with a blocksize 401 */ 402 return(0); 403 404 case PRU_SENDOOB: 405 case PRU_FASTTIMO: 406 case PRU_SLOWTIMO: 407 case PRU_PROTORCV: 408 case PRU_PROTOSEND: 409 error = EOPNOTSUPP; 410 break; 411 412 case PRU_RCVD: 413 case PRU_RCVOOB: 414 return(EOPNOTSUPP); /* do not free mbuf's */ 415 416 default: 417 panic("udp6_usrreq"); 418 } 419 420 release: 421 if (control) 422 m_freem(control); 423 if (m) 424 m_freem(m); 425 return(error); 426 } 427 428 static void 429 udp6_detach(in6p) 430 struct in6pcb *in6p; 431 { 432 int s = splsoftnet(); 433 434 if (in6p == udp6_last_in6pcb) 435 udp6_last_in6pcb = &udb6; 436 in6_pcbdetach(in6p); 437 splx(s); 438 } 439 440 int 441 udp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 442 int *name; 443 u_int namelen; 444 void *oldp; 445 size_t *oldlenp; 446 void *newp; 447 size_t newlen; 448 { 449 /* All sysctl names at this level are terminal. */ 450 if (namelen != 1) 451 return ENOTDIR; 452 453 switch (name[0]) { 454 455 case UDP6CTL_SENDSPACE: 456 return sysctl_int(oldp, oldlenp, newp, newlen, 457 &udp6_sendspace); 458 case UDP6CTL_RECVSPACE: 459 return sysctl_int(oldp, oldlenp, newp, newlen, 460 &udp6_recvspace); 461 default: 462 return ENOPROTOOPT; 463 } 464 /* NOTREACHED */ 465 } 466