1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <sys/types.h> 26 #include <sys/sysmacros.h> 27 #include <sys/random.h> 28 #include <sys/rds.h> 29 30 #include <sys/ib/clients/rdsv3/rdsv3.h> 31 #include <sys/ib/clients/rdsv3/rdsv3_debug.h> 32 33 /* 34 * XXX this probably still needs more work.. no INADDR_ANY, and rbtrees aren't 35 * particularly zippy. 36 * 37 * This is now called for every incoming frame so we arguably care much more 38 * about it than we used to. 39 */ 40 kmutex_t rdsv3_bind_lock; 41 avl_tree_t rdsv3_bind_tree; 42 43 static struct rdsv3_sock * 44 rdsv3_bind_tree_walk(uint32_be_t addr, uint16_be_t port, 45 struct rdsv3_sock *insert) 46 { 47 struct rdsv3_sock *rs; 48 avl_index_t where; 49 50 rs = avl_find(&rdsv3_bind_tree, &port, &where); 51 if ((rs == NULL) && (insert != NULL)) { 52 insert->rs_bound_addr = addr; 53 insert->rs_bound_port = port; 54 avl_insert(&rdsv3_bind_tree, insert, where); 55 } 56 57 return (rs); 58 } 59 60 /* 61 * Return the rdsv3_sock bound at the given local address. 62 * 63 * The rx path can race with rdsv3_release. We notice if rdsv3_release() has 64 * marked this socket and don't return a rs ref to the rx path. 65 */ 66 struct rdsv3_sock * 67 rdsv3_find_bound(uint32_be_t addr, uint16_be_t port) 68 { 69 struct rdsv3_sock *rs; 70 71 RDSV3_DPRINTF4("rdsv3_find_bound", "Enter(port: %x)", port); 72 73 mutex_enter(&rdsv3_bind_lock); 74 rs = rdsv3_bind_tree_walk(addr, port, NULL); 75 if (rs && !rdsv3_sk_sock_flag(rdsv3_rs_to_sk(rs), SOCK_DEAD)) 76 rdsv3_sock_addref(rs); 77 else 78 rs = NULL; 79 mutex_exit(&rdsv3_bind_lock); 80 81 RDSV3_DPRINTF5("rdsv3_find_bound", "returning rs %p for %u.%u.%u.%u:%x", 82 rs, NIPQUAD(addr), port); 83 return (rs); 84 } 85 86 /* returns -ve errno or +ve port */ 87 static int 88 rdsv3_add_bound(struct rdsv3_sock *rs, uint32_be_t addr, uint16_be_t *port) 89 { 90 int ret = -EADDRINUSE; 91 uint16_t rover, last; 92 93 RDSV3_DPRINTF4("rdsv3_add_bound", "Enter(port: %x)", *port); 94 95 if (*port != 0) { 96 rover = ntohs(*port); 97 last = rover; 98 } else { 99 (void) random_get_pseudo_bytes((uint8_t *)&rover, 100 sizeof (uint16_t)); 101 rover = MAX(rover, 2); 102 last = rover - 1; 103 } 104 105 mutex_enter(&rdsv3_bind_lock); 106 107 do { 108 if (rover == 0) 109 rover++; 110 if (rdsv3_bind_tree_walk(addr, htons(rover), rs) == NULL) { 111 *port = htons(rover); 112 ret = 0; 113 break; 114 } 115 } while (rover++ != last); 116 117 if (ret == 0) { 118 rs->rs_bound_addr = addr; 119 rs->rs_bound_port = *port; 120 rdsv3_sock_addref(rs); 121 122 RDSV3_DPRINTF5("rdsv3_add_bound", 123 "rs %p binding to %u.%u.%u.%u:%x", 124 rs, NIPQUAD(addr), *port); 125 126 } 127 128 mutex_exit(&rdsv3_bind_lock); 129 130 RDSV3_DPRINTF4("rdsv3_add_bound", "Return(port: %x)", *port); 131 132 return (ret); 133 } 134 135 void 136 rdsv3_remove_bound(struct rdsv3_sock *rs) 137 { 138 RDSV3_DPRINTF4("rdsv3_remove_bound", "Enter(rs: %p)", rs); 139 140 mutex_enter(&rdsv3_bind_lock); 141 142 if (rs->rs_bound_addr) { 143 RDSV3_DPRINTF5("rdsv3_remove_bound", 144 "rs %p unbinding from %u.%u.%u.%u:%x", 145 rs, NIPQUAD(rs->rs_bound_addr), rs->rs_bound_port); 146 147 avl_remove(&rdsv3_bind_tree, rs); 148 rdsv3_sock_put(rs); 149 rs->rs_bound_addr = 0; 150 } 151 152 mutex_exit(&rdsv3_bind_lock); 153 154 RDSV3_DPRINTF4("rdsv3_remove_bound", "Return(rs: %p)", rs); 155 } 156 157 /* ARGSUSED */ 158 int 159 rdsv3_bind(sock_lower_handle_t proto_handle, struct sockaddr *sa, 160 socklen_t len, cred_t *cr) 161 { 162 struct rsock *sk = (struct rsock *)proto_handle; 163 sin_t *sin = (sin_t *)sa; 164 struct rdsv3_sock *rs = rdsv3_sk_to_rs(sk); 165 int ret; 166 167 if (len != sizeof (sin_t) || (sin == NULL) || 168 !OK_32PTR((char *)sin)) { 169 RDSV3_DPRINTF2("rdsv3_bind", "address to bind not specified"); 170 return (EINVAL); 171 } 172 173 RDSV3_DPRINTF4("rdsv3_bind", "Enter(rs: %p, addr: 0x%x, port: %x)", 174 rs, ntohl(sin->sin_addr.s_addr), htons(sin->sin_port)); 175 176 if (sin->sin_addr.s_addr == INADDR_ANY) { 177 RDSV3_DPRINTF2("rdsv3_bind", "Invalid address"); 178 return (EINVAL); 179 } 180 181 /* We don't allow multiple binds */ 182 if (rs->rs_bound_addr) { 183 RDSV3_DPRINTF2("rdsv3_bind", "Multiple binds not allowed"); 184 return (EINVAL); 185 } 186 187 ret = rdsv3_add_bound(rs, sin->sin_addr.s_addr, &sin->sin_port); 188 if (ret) { 189 return (ret); 190 } 191 192 rs->rs_transport = rdsv3_trans_get_preferred(sin->sin_addr.s_addr); 193 if (rs->rs_transport == NULL) { 194 rdsv3_remove_bound(rs); 195 return (EADDRNOTAVAIL); 196 } 197 198 RDSV3_DPRINTF4("rdsv3_bind", "Return: Assigned port: %x to sock: %p", 199 sin->sin_port, rs); 200 201 return (0); 202 } 203