1 /* 2 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 3 */ 4 5 /* 6 * This file contains code imported from the OFED rds source file bind.c 7 * Oracle elects to have and use the contents of bind.c under and governed 8 * by the OpenIB.org BSD license (see below for full license text). However, 9 * the following notice accompanied the original version of this file: 10 */ 11 12 /* 13 * Copyright (c) 2006 Oracle. All rights reserved. 14 * 15 * This software is available to you under a choice of one of two 16 * licenses. You may choose to be licensed under the terms of the GNU 17 * General Public License (GPL) Version 2, available from the file 18 * COPYING in the main directory of this source tree, or the 19 * OpenIB.org BSD license below: 20 * 21 * Redistribution and use in source and binary forms, with or 22 * without modification, are permitted provided that the following 23 * conditions are met: 24 * 25 * - Redistributions of source code must retain the above 26 * copyright notice, this list of conditions and the following 27 * disclaimer. 28 * 29 * - Redistributions in binary form must reproduce the above 30 * copyright notice, this list of conditions and the following 31 * disclaimer in the documentation and/or other materials 32 * provided with the distribution. 33 * 34 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 35 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 36 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 37 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 38 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 39 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 40 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 41 * SOFTWARE. 42 * 43 */ 44 #include <sys/types.h> 45 #include <sys/sysmacros.h> 46 #include <sys/random.h> 47 #include <sys/rds.h> 48 49 #include <sys/ib/clients/rdsv3/rdsv3.h> 50 #include <sys/ib/clients/rdsv3/rdsv3_debug.h> 51 52 /* 53 * XXX this probably still needs more work.. no INADDR_ANY, and rbtrees aren't 54 * particularly zippy. 55 * 56 * This is now called for every incoming frame so we arguably care much more 57 * about it than we used to. 58 */ 59 kmutex_t rdsv3_bind_lock; 60 avl_tree_t rdsv3_bind_tree; 61 62 static struct rdsv3_sock * 63 rdsv3_bind_tree_walk(uint32_be_t addr, uint16_be_t port, 64 struct rdsv3_sock *insert) 65 { 66 struct rdsv3_sock *rs; 67 avl_index_t where; 68 uint64_t needle = ((uint64_t)addr << 32) | port; 69 70 rs = avl_find(&rdsv3_bind_tree, &needle, &where); 71 if ((rs == NULL) && (insert != NULL)) { 72 insert->rs_bound_addr = addr; 73 insert->rs_bound_port = port; 74 avl_insert(&rdsv3_bind_tree, insert, where); 75 } 76 77 return (rs); 78 } 79 80 /* 81 * Return the rdsv3_sock bound at the given local address. 82 * 83 * The rx path can race with rdsv3_release. We notice if rdsv3_release() has 84 * marked this socket and don't return a rs ref to the rx path. 85 */ 86 struct rdsv3_sock * 87 rdsv3_find_bound(uint32_be_t addr, uint16_be_t port) 88 { 89 struct rdsv3_sock *rs; 90 91 RDSV3_DPRINTF4("rdsv3_find_bound", "Enter(port: %x)", port); 92 93 mutex_enter(&rdsv3_bind_lock); 94 rs = rdsv3_bind_tree_walk(addr, port, NULL); 95 if (rs && !rdsv3_sk_sock_flag(rdsv3_rs_to_sk(rs), SOCK_DEAD)) 96 rdsv3_sock_addref(rs); 97 else 98 rs = NULL; 99 mutex_exit(&rdsv3_bind_lock); 100 101 RDSV3_DPRINTF5("rdsv3_find_bound", "returning rs %p for %u.%u.%u.%u:%x", 102 rs, NIPQUAD(addr), port); 103 104 return (rs); 105 } 106 107 /* returns -ve errno or +ve port */ 108 static int 109 rdsv3_add_bound(struct rdsv3_sock *rs, uint32_be_t addr, uint16_be_t *port) 110 { 111 int ret = -EADDRINUSE; 112 uint16_t rover, last; 113 114 RDSV3_DPRINTF4("rdsv3_add_bound", "Enter(port: %x)", *port); 115 116 if (*port != 0) { 117 rover = ntohs(*port); 118 last = rover; 119 } else { 120 (void) random_get_pseudo_bytes((uint8_t *)&rover, 121 sizeof (uint16_t)); 122 rover = MAX(rover, 2); 123 last = rover - 1; 124 } 125 126 mutex_enter(&rdsv3_bind_lock); 127 128 do { 129 if (rover == 0) 130 rover++; 131 132 if (rdsv3_bind_tree_walk(addr, htons(rover), rs) == NULL) { 133 *port = htons(rover); 134 ret = 0; 135 break; 136 } 137 } while (rover++ != last); 138 139 if (ret == 0) { 140 rs->rs_bound_addr = addr; 141 rs->rs_bound_port = *port; 142 rdsv3_sock_addref(rs); 143 144 RDSV3_DPRINTF5("rdsv3_add_bound", 145 "rs %p binding to %u.%u.%u.%u:%x", 146 rs, NIPQUAD(addr), *port); 147 } 148 149 mutex_exit(&rdsv3_bind_lock); 150 151 RDSV3_DPRINTF4("rdsv3_add_bound", "Return(port: %x)", *port); 152 153 return (ret); 154 } 155 156 void 157 rdsv3_remove_bound(struct rdsv3_sock *rs) 158 { 159 RDSV3_DPRINTF4("rdsv3_remove_bound", "Enter(rs: %p)", rs); 160 161 mutex_enter(&rdsv3_bind_lock); 162 163 if (rs->rs_bound_addr) { 164 RDSV3_DPRINTF5("rdsv3_remove_bound", 165 "rs %p unbinding from %u.%u.%u.%u:%x", 166 rs, NIPQUAD(rs->rs_bound_addr), rs->rs_bound_port); 167 avl_remove(&rdsv3_bind_tree, rs); 168 rdsv3_sock_put(rs); 169 rs->rs_bound_addr = 0; 170 } 171 172 mutex_exit(&rdsv3_bind_lock); 173 174 RDSV3_DPRINTF4("rdsv3_remove_bound", "Return(rs: %p)", rs); 175 } 176 177 /* ARGSUSED */ 178 int 179 rdsv3_bind(sock_lower_handle_t proto_handle, struct sockaddr *sa, 180 socklen_t len, cred_t *cr) 181 { 182 struct rsock *sk = (struct rsock *)proto_handle; 183 sin_t *sin = (sin_t *)sa; 184 struct rdsv3_sock *rs = rdsv3_sk_to_rs(sk); 185 int ret; 186 187 if (len != sizeof (sin_t) || (sin == NULL) || 188 !OK_32PTR((char *)sin)) { 189 RDSV3_DPRINTF2("rdsv3_bind", "address to bind not specified"); 190 return (EINVAL); 191 } 192 193 RDSV3_DPRINTF4("rdsv3_bind", "Enter(rs: %p, addr: 0x%x, port: %x)", 194 rs, ntohl(sin->sin_addr.s_addr), htons(sin->sin_port)); 195 196 if (sin->sin_addr.s_addr == INADDR_ANY) { 197 RDSV3_DPRINTF2("rdsv3_bind", "Invalid address"); 198 return (EINVAL); 199 } 200 201 /* We don't allow multiple binds */ 202 if (rs->rs_bound_addr) { 203 RDSV3_DPRINTF2("rdsv3_bind", "Multiple binds not allowed"); 204 return (EINVAL); 205 } 206 207 ret = rdsv3_add_bound(rs, sin->sin_addr.s_addr, &sin->sin_port); 208 if (ret) { 209 return (ret); 210 } 211 212 rs->rs_transport = rdsv3_trans_get_preferred(sin->sin_addr.s_addr); 213 if (!rs->rs_transport) { 214 rdsv3_remove_bound(rs); 215 if (rdsv3_printk_ratelimit()) { 216 RDSV3_DPRINTF1("rdsv3_bind", 217 "RDS: rdsv3_bind() could not find a transport.\n"); 218 } 219 return (EADDRNOTAVAIL); 220 } 221 222 RDSV3_DPRINTF4("rdsv3_bind", "Return: Assigned port: %x to sock: %p", 223 sin->sin_port, rs); 224 225 return (0); 226 } 227