1 /* $KAME: dccp6_usrreq.c,v 1.13 2005/07/27 08:42:56 nishida Exp $ */ 2 /* $NetBSD: dccp6_usrreq.c,v 1.12 2018/09/15 13:33:15 rjs Exp $ */ 3 4 /* 5 * Copyright (C) 2003 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 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: dccp6_usrreq.c,v 1.12 2018/09/15 13:33:15 rjs Exp $"); 35 36 #ifdef _KERNEL_OPT 37 #include "opt_inet.h" 38 #include "opt_dccp.h" 39 #include "opt_net_mpsafe.h" 40 #endif 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/domain.h> 45 #include <sys/kernel.h> 46 #include <sys/pool.h> 47 #include <sys/lock.h> 48 #include <sys/malloc.h> 49 #include <sys/mbuf.h> 50 #include <sys/proc.h> 51 #include <sys/protosw.h> 52 #include <sys/signalvar.h> 53 #include <sys/socket.h> 54 #include <sys/socketvar.h> 55 #include <sys/mutex.h> 56 #include <sys/sysctl.h> 57 #include <sys/syslog.h> 58 #include <sys/queue.h> 59 60 #include <net/if.h> 61 62 #include <netinet/in.h> 63 #include <netinet/in_systm.h> 64 #include <netinet/ip.h> 65 #include <netinet/in_pcb.h> 66 #include <netinet/in_var.h> 67 #include <netinet/ip6.h> 68 #include <netinet/ip_icmp.h> 69 #include <netinet/icmp_var.h> 70 #include <netinet/ip_var.h> 71 #include <netinet6/in6_pcb.h> 72 #include <netinet6/ip6_var.h> 73 #include <netinet/dccp.h> 74 #include <netinet/dccp_var.h> 75 #include <netinet6/dccp6_var.h> 76 #include <netinet/dccp_cc_sw.h> 77 78 #if !defined(__FreeBSD__) || __FreeBSD_version < 500000 79 #define INP_INFO_LOCK_INIT(x,y) 80 #define INP_INFO_WLOCK(x) 81 #define INP_INFO_WUNLOCK(x) 82 #define INP_INFO_RLOCK(x) 83 #define INP_INFO_RUNLOCK(x) 84 #define INP_LOCK(x) 85 #define INP_UNLOCK(x) 86 #endif 87 88 #define PULLDOWN_TEST 89 90 int 91 dccp6_input(struct mbuf **mp, int *offp, int proto) 92 { 93 struct mbuf *m = *mp; 94 DCCP_DEBUG((LOG_INFO, "In dccp6_input!\n")); 95 #ifndef PULLDOWN_TEST 96 IP6_EXTHDR_CHECK(m, *offp, sizeof(struct dccphdr), IPPROTO_DONE); 97 #endif 98 99 dccp_input(m, *offp, proto); 100 return IPPROTO_DONE; 101 } 102 103 void * 104 dccp6_ctlinput(int cmd, const struct sockaddr *sa, void *d) 105 { 106 if (sa->sa_family != AF_INET6 || 107 sa->sa_len != sizeof(struct sockaddr_in6)) 108 return NULL; 109 110 /* FIX LATER */ 111 return NULL; 112 } 113 114 int 115 dccp6_bind(struct socket *so, struct sockaddr *nam, struct lwp *td) 116 { 117 struct in6pcb *in6p; 118 int error; 119 struct sockaddr_in6 *sin6p = (struct sockaddr_in6 *)nam; 120 121 DCCP_DEBUG((LOG_INFO, "Entering dccp6_bind!\n")); 122 INP_INFO_WLOCK(&dccpbinfo); 123 in6p = sotoin6pcb(so); 124 if (in6p == 0) { 125 INP_INFO_WUNLOCK(&dccpbinfo); 126 DCCP_DEBUG((LOG_INFO, "dccp6_bind: in6p == 0!\n")); 127 return EINVAL; 128 } 129 /* Do not bind to multicast addresses! */ 130 if (sin6p->sin6_family == AF_INET6 && 131 IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr)) { 132 INP_INFO_WUNLOCK(&dccpbinfo); 133 return EAFNOSUPPORT; 134 } 135 INP_LOCK(inp); 136 137 in6todccpcb(in6p)->inp_vflag &= ~INP_IPV4; 138 in6todccpcb(in6p)->inp_vflag |= INP_IPV6; 139 140 error = in6_pcbbind(in6p, sin6p, td); 141 INP_UNLOCK(inp); 142 INP_INFO_WUNLOCK(&dccpbinfo); 143 return error; 144 } 145 146 int 147 dccp6_connect(struct socket *so, struct sockaddr *nam, struct lwp *l) 148 { 149 struct in6pcb *in6p; 150 struct dccpcb *dp; 151 int error; 152 struct sockaddr_in6 *sin6; 153 char test[2]; 154 155 DCCP_DEBUG((LOG_INFO, "Entering dccp6_connect!\n")); 156 157 #ifndef __NetBSD__ 158 INP_INFO_WLOCK(&dccpbinfo); 159 inp = sotoinpcb(so); 160 if (inp == 0) { 161 INP_INFO_WUNLOCK(&dccpbinfo); 162 return EINVAL; 163 } 164 INP_LOCK(inp); 165 if (inp->inp_faddr.s_addr != INADDR_ANY) { 166 INP_UNLOCK(inp); 167 INP_INFO_WUNLOCK(&dccpbinfo); 168 return EISCONN; 169 } 170 171 dp = (struct dccpcb *)inp->inp_ppcb; 172 #else 173 in6p = sotoin6pcb(so); 174 if (in6p == 0) { 175 return EINVAL; 176 } 177 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { 178 return EISCONN; 179 } 180 181 dp = (struct dccpcb *)in6p->in6p_ppcb; 182 #endif 183 if (dp->state == DCCPS_ESTAB) { 184 DCCP_DEBUG((LOG_INFO, "Why are we in connect when we already have a established connection?\n")); 185 } 186 187 dp->who = DCCP_CLIENT; 188 dp->seq_snd = (((u_int64_t)random() << 32) | random()) % 281474976710656LL; 189 190 sin6 = (struct sockaddr_in6 *)nam; 191 if (sin6->sin6_family == AF_INET6 192 && IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 193 error = EAFNOSUPPORT; 194 goto bad; 195 } 196 197 dp->inp_vflag &= ~INP_IPV4; 198 dp->inp_vflag |= INP_IPV6; 199 200 error = dccp_doconnect(so, nam, l, 1); 201 202 if (error != 0) 203 goto bad; 204 205 callout_reset(&dp->retrans_timer, dp->retrans, dccp_retrans_t, dp); 206 callout_reset(&dp->connect_timer, DCCP_CONNECT_TIMER, dccp_connect_t, dp); 207 208 test[0] = dp->pref_cc; 209 #if 0 210 /* FIX THIS LATER */ 211 if (dp->pref_cc == 2) { 212 test[1] = 3; 213 } else { 214 test[1] = 2; 215 } 216 dccp_add_feature(dp, DCCP_OPT_CHANGE, DCCP_FEATURE_CC, test, 2); 217 dccp_add_feature(dp, DCCP_OPT_PREFER, DCCP_FEATURE_CC, test, 2); 218 #else 219 /* we only support CCID2 at this moment */ 220 dccp_add_feature(dp, DCCP_OPT_CHANGE_R, DCCP_FEATURE_CC, test, 1); 221 #endif 222 223 error = dccp_output(dp, 0); 224 225 bad: 226 INP_UNLOCK(inp); 227 INP_INFO_WUNLOCK(&dccpbinfo); 228 return error; 229 } 230 231 232 int 233 dccp6_listen(struct socket *so, struct lwp *l) 234 { 235 struct in6pcb *in6p; 236 struct dccpcb *dp; 237 int error = 0; 238 239 DCCP_DEBUG((LOG_INFO, "Entering dccp6_listen!\n")); 240 241 INP_INFO_RLOCK(&dccpbinfo); 242 in6p = sotoin6pcb(so); 243 if (in6p == 0) { 244 INP_INFO_RUNLOCK(&dccpbinfo); 245 return EINVAL; 246 } 247 INP_LOCK(inp); 248 INP_INFO_RUNLOCK(&dccpbinfo); 249 dp = in6todccpcb(in6p); 250 DCCP_DEBUG((LOG_INFO, "Checking in6p->in6p_lport!\n")); 251 if (in6p->in6p_lport == 0) { 252 error = in6_pcbbind(in6p, NULL, l); 253 } 254 if (error == 0) { 255 dp->state = DCCPS_LISTEN; 256 dp->who = DCCP_LISTENER; 257 dp->seq_snd = 512; 258 } 259 INP_UNLOCK(inp); 260 return error; 261 } 262 263 int 264 dccp6_accept(struct socket *so, struct sockaddr *nam) 265 { 266 struct in6pcb *in6p = NULL; 267 int error = 0; 268 269 DCCP_DEBUG((LOG_INFO, "Entering dccp6_accept!\n")); 270 if (nam == NULL) { 271 return EINVAL; 272 } 273 if (so->so_state & SS_ISDISCONNECTED) { 274 DCCP_DEBUG((LOG_INFO, "so_state && SS_ISDISCONNECTED!, so->state = %i\n", so->so_state)); 275 return ECONNABORTED; 276 } 277 278 INP_INFO_RLOCK(&dccpbinfo); 279 in6p = sotoin6pcb(so); 280 if (in6p == 0) { 281 INP_INFO_RUNLOCK(&dccpbinfo); 282 return EINVAL; 283 } 284 INP_LOCK(inp); 285 INP_INFO_RUNLOCK(&dccpbinfo); 286 in6_setpeeraddr(in6p, (struct sockaddr_in6 *)nam); 287 288 INP_UNLOCK(inp); 289 return error; 290 } 291 292 static int 293 dccp6_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp) 294 { 295 int error = 0; 296 int family; 297 298 family = so->so_proto->pr_domain->dom_family; 299 switch (family) { 300 case PF_INET6: 301 error = in6_control(so, cmd, nam, ifp); 302 break; 303 default: 304 error = EAFNOSUPPORT; 305 } 306 return (error); 307 } 308 309 static int 310 dccp6_stat(struct socket *so, struct stat *ub) 311 { 312 return 0; 313 } 314 315 static int 316 dccp6_purgeif(struct socket *so, struct ifnet *ifp) 317 { 318 int s; 319 320 s = splsoftnet(); 321 mutex_enter(softnet_lock); 322 in6_pcbpurgeif0(&dccpbtable, ifp); 323 #ifdef NET_MPSAFE 324 mutex_exit(softnet_lock); 325 #endif 326 in6_purgeif(ifp); 327 #ifdef NET_MPSAFE 328 mutex_enter(softnet_lock); 329 #endif 330 in6_pcbpurgeif(&dccpbtable, ifp); 331 mutex_exit(softnet_lock); 332 splx(s); 333 334 return 0; 335 } 336 337 static int 338 dccp6_attach(struct socket *so, int proto) 339 { 340 return dccp_attach(so, proto); 341 } 342 343 static int 344 dccp6_detach(struct socket *so) 345 { 346 return dccp_detach(so); 347 } 348 349 static int 350 dccp6_connect2(struct socket *so, struct socket *so2) 351 { 352 KASSERT(solocked(so)); 353 354 return EOPNOTSUPP; 355 } 356 357 static int 358 dccp6_disconnect(struct socket *so) 359 { 360 return dccp_disconnect(so); 361 } 362 363 static int 364 dccp6_shutdown(struct socket *so) 365 { 366 return dccp_shutdown(so); 367 } 368 369 static int 370 dccp6_abort(struct socket *so) 371 { 372 return dccp_abort(so); 373 } 374 375 376 static int 377 dccp6_peeraddr(struct socket *so, struct sockaddr *nam) 378 { 379 KASSERT(solocked(so)); 380 KASSERT(sotoinpcb(so) != NULL); 381 KASSERT(nam != NULL); 382 383 in6_setpeeraddr(sotoin6pcb(so), (struct sockaddr_in6 *)nam); 384 return 0; 385 } 386 387 static int 388 dccp6_sockaddr(struct socket *so, struct sockaddr *nam) 389 { 390 KASSERT(solocked(so)); 391 KASSERT(sotoinpcb(so) != NULL); 392 KASSERT(nam != NULL); 393 394 in6_setsockaddr(sotoin6pcb(so), (struct sockaddr_in6 *)nam); 395 return 0; 396 } 397 398 static int 399 dccp6_recvoob(struct socket *so, struct mbuf *m, int flags) 400 { 401 KASSERT(solocked(so)); 402 403 return EOPNOTSUPP; 404 } 405 406 static int 407 dccp6_rcvd(struct socket *so, int flags, struct lwp *l) 408 { 409 KASSERT(solocked(so)); 410 411 return EOPNOTSUPP; 412 } 413 414 static int 415 dccp6_send(struct socket *so, struct mbuf *m, struct sockaddr *nam, 416 struct mbuf *control, struct lwp *l) 417 { 418 return dccp_send(so, m, nam, control, l); 419 } 420 421 static int 422 dccp6_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control) 423 { 424 KASSERT(solocked(so)); 425 426 m_freem(m); 427 m_freem(control); 428 429 return EOPNOTSUPP; 430 } 431 432 433 PR_WRAP_USRREQS(dccp6) 434 #define dccp6_attach dccp6_attach_wrapper 435 #define dccp6_detach dccp6_detach_wrapper 436 #define dccp6_accept dccp6_accept_wrapper 437 #define dccp6_bind dccp6_bind_wrapper 438 #define dccp6_listen dccp6_listen_wrapper 439 #define dccp6_connect dccp6_connect_wrapper 440 #define dccp6_connect2 dccp6_connect2_wrapper 441 #define dccp6_disconnect dccp6_disconnect_wrapper 442 #define dccp6_shutdown dccp6_shutdown_wrapper 443 #define dccp6_abort dccp6_abort_wrapper 444 #define dccp6_ioctl dccp6_ioctl_wrapper 445 #define dccp6_stat dccp6_stat_wrapper 446 #define dccp6_peeraddr dccp6_peeraddr_wrapper 447 #define dccp6_sockaddr dccp6_sockaddr_wrapper 448 #define dccp6_rcvd dccp6_rcvd_wrapper 449 #define dccp6_recvoob dccp6_recvoob_wrapper 450 #define dccp6_send dccp6_send_wrapper 451 #define dccp6_sendoob dccp6_sendoob_wrapper 452 #define dccp6_purgeif dccp6_purgeif_wrapper 453 454 const struct pr_usrreqs dccp6_usrreqs = { 455 .pr_attach = dccp6_attach, 456 .pr_detach = dccp6_detach, 457 .pr_accept = dccp6_accept, 458 .pr_bind = dccp6_bind, 459 .pr_listen = dccp6_listen, 460 .pr_connect = dccp6_connect, 461 .pr_connect2 = dccp6_connect2, 462 .pr_disconnect = dccp6_disconnect, 463 .pr_shutdown = dccp6_shutdown, 464 .pr_abort = dccp6_abort, 465 .pr_ioctl = dccp6_ioctl, 466 .pr_stat = dccp6_stat, 467 .pr_peeraddr = dccp6_peeraddr, 468 .pr_sockaddr = dccp6_sockaddr, 469 .pr_rcvd = dccp6_rcvd, 470 .pr_recvoob = dccp6_recvoob, 471 .pr_send = dccp6_send, 472 .pr_sendoob = dccp6_sendoob, 473 .pr_purgeif = dccp6_purgeif, 474 }; 475