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