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 84 return (rs); 85 } 86 87 /* returns -ve errno or +ve port */ 88 static int 89 rdsv3_add_bound(struct rdsv3_sock *rs, uint32_be_t addr, uint16_be_t *port) 90 { 91 int ret = -EADDRINUSE; 92 uint16_t rover, last; 93 94 RDSV3_DPRINTF4("rdsv3_add_bound", "Enter(port: %x)", *port); 95 96 if (*port != 0) { 97 rover = ntohs(*port); 98 last = rover; 99 } else { 100 (void) random_get_pseudo_bytes((uint8_t *)&rover, 101 sizeof (uint16_t)); 102 rover = MAX(rover, 2); 103 last = rover - 1; 104 } 105 106 mutex_enter(&rdsv3_bind_lock); 107 108 do { 109 if (rover == 0) 110 rover++; 111 if (rdsv3_bind_tree_walk(addr, htons(rover), rs) == NULL) { 112 *port = htons(rover); 113 ret = 0; 114 break; 115 } 116 } while (rover++ != last); 117 118 if (ret == 0) { 119 rs->rs_bound_addr = addr; 120 rs->rs_bound_port = *port; 121 rdsv3_sock_addref(rs); 122 123 RDSV3_DPRINTF5("rdsv3_add_bound", 124 "rs %p binding to %u.%u.%u.%u:%x", 125 rs, NIPQUAD(addr), *port); 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 avl_remove(&rdsv3_bind_tree, rs); 147 rdsv3_sock_put(rs); 148 rs->rs_bound_addr = 0; 149 } 150 151 mutex_exit(&rdsv3_bind_lock); 152 153 RDSV3_DPRINTF4("rdsv3_remove_bound", "Return(rs: %p)", rs); 154 } 155 156 /* ARGSUSED */ 157 int 158 rdsv3_bind(sock_lower_handle_t proto_handle, struct sockaddr *sa, 159 socklen_t len, cred_t *cr) 160 { 161 struct rsock *sk = (struct rsock *)proto_handle; 162 sin_t *sin = (sin_t *)sa; 163 struct rdsv3_sock *rs = rdsv3_sk_to_rs(sk); 164 int ret; 165 166 if (len != sizeof (sin_t) || (sin == NULL) || 167 !OK_32PTR((char *)sin)) { 168 RDSV3_DPRINTF2("rdsv3_bind", "address to bind not specified"); 169 return (EINVAL); 170 } 171 172 RDSV3_DPRINTF4("rdsv3_bind", "Enter(rs: %p, addr: 0x%x, port: %x)", 173 rs, ntohl(sin->sin_addr.s_addr), htons(sin->sin_port)); 174 175 if (sin->sin_addr.s_addr == INADDR_ANY) { 176 RDSV3_DPRINTF2("rdsv3_bind", "Invalid address"); 177 return (EINVAL); 178 } 179 180 /* We don't allow multiple binds */ 181 if (rs->rs_bound_addr) { 182 RDSV3_DPRINTF2("rdsv3_bind", "Multiple binds not allowed"); 183 return (EINVAL); 184 } 185 186 ret = rdsv3_add_bound(rs, sin->sin_addr.s_addr, &sin->sin_port); 187 if (ret) { 188 return (ret); 189 } 190 191 rs->rs_transport = rdsv3_trans_get_preferred(sin->sin_addr.s_addr); 192 if (rs->rs_transport == NULL) { 193 rdsv3_remove_bound(rs); 194 if (rdsv3_printk_ratelimit()) { 195 RDSV3_DPRINTF1("rdsv3_bind", 196 "RDS: rdsv3_bind() could not find a transport.\n"); 197 } 198 return (EADDRNOTAVAIL); 199 } 200 201 RDSV3_DPRINTF4("rdsv3_bind", "Return: Assigned port: %x to sock: %p", 202 sin->sin_port, rs); 203 204 return (0); 205 } 206