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 uint64_t needle = ((uint64_t)addr << 32) | port; 50 51 rs = avl_find(&rdsv3_bind_tree, &needle, &where); 52 if ((rs == NULL) && (insert != NULL)) { 53 insert->rs_bound_addr = addr; 54 insert->rs_bound_port = port; 55 avl_insert(&rdsv3_bind_tree, insert, where); 56 } 57 58 return (rs); 59 } 60 61 /* 62 * Return the rdsv3_sock bound at the given local address. 63 * 64 * The rx path can race with rdsv3_release. We notice if rdsv3_release() has 65 * marked this socket and don't return a rs ref to the rx path. 66 */ 67 struct rdsv3_sock * 68 rdsv3_find_bound(uint32_be_t addr, uint16_be_t port) 69 { 70 struct rdsv3_sock *rs; 71 72 RDSV3_DPRINTF4("rdsv3_find_bound", "Enter(port: %x)", port); 73 74 mutex_enter(&rdsv3_bind_lock); 75 rs = rdsv3_bind_tree_walk(addr, port, NULL); 76 if (rs && !rdsv3_sk_sock_flag(rdsv3_rs_to_sk(rs), SOCK_DEAD)) 77 rdsv3_sock_addref(rs); 78 else 79 rs = NULL; 80 mutex_exit(&rdsv3_bind_lock); 81 82 RDSV3_DPRINTF5("rdsv3_find_bound", "returning rs %p for %u.%u.%u.%u:%x", 83 rs, NIPQUAD(addr), port); 84 85 return (rs); 86 } 87 88 /* returns -ve errno or +ve port */ 89 static int 90 rdsv3_add_bound(struct rdsv3_sock *rs, uint32_be_t addr, uint16_be_t *port) 91 { 92 int ret = -EADDRINUSE; 93 uint16_t rover, last; 94 95 RDSV3_DPRINTF4("rdsv3_add_bound", "Enter(port: %x)", *port); 96 97 if (*port != 0) { 98 rover = ntohs(*port); 99 last = rover; 100 } else { 101 (void) random_get_pseudo_bytes((uint8_t *)&rover, 102 sizeof (uint16_t)); 103 rover = MAX(rover, 2); 104 last = rover - 1; 105 } 106 107 mutex_enter(&rdsv3_bind_lock); 108 109 do { 110 if (rover == 0) 111 rover++; 112 if (rdsv3_bind_tree_walk(addr, htons(rover), rs) == NULL) { 113 *port = htons(rover); 114 ret = 0; 115 break; 116 } 117 } while (rover++ != last); 118 119 if (ret == 0) { 120 rs->rs_bound_addr = addr; 121 rs->rs_bound_port = *port; 122 rdsv3_sock_addref(rs); 123 124 RDSV3_DPRINTF5("rdsv3_add_bound", 125 "rs %p binding to %u.%u.%u.%u:%x", 126 rs, NIPQUAD(addr), *port); 127 } 128 129 mutex_exit(&rdsv3_bind_lock); 130 131 RDSV3_DPRINTF4("rdsv3_add_bound", "Return(port: %x)", *port); 132 133 return (ret); 134 } 135 136 void 137 rdsv3_remove_bound(struct rdsv3_sock *rs) 138 { 139 RDSV3_DPRINTF4("rdsv3_remove_bound", "Enter(rs: %p)", rs); 140 141 mutex_enter(&rdsv3_bind_lock); 142 143 if (rs->rs_bound_addr) { 144 RDSV3_DPRINTF5("rdsv3_remove_bound", 145 "rs %p unbinding from %u.%u.%u.%u:%x", 146 rs, NIPQUAD(rs->rs_bound_addr), rs->rs_bound_port); 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 if (rdsv3_printk_ratelimit()) { 196 RDSV3_DPRINTF1("rdsv3_bind", 197 "RDS: rdsv3_bind() could not find a transport.\n"); 198 } 199 return (EADDRNOTAVAIL); 200 } 201 202 RDSV3_DPRINTF4("rdsv3_bind", "Return: Assigned port: %x to sock: %p", 203 sin->sin_port, rs); 204 205 return (0); 206 } 207