| 1 | /****************************************************************************** |
|---|
| 2 | * (c)2011 Broadcom Corporation |
|---|
| 3 | * |
|---|
| 4 | * This program is the proprietary software of Broadcom Corporation and/or its licensors, |
|---|
| 5 | * and may only be used, duplicated, modified or distributed pursuant to the terms and |
|---|
| 6 | * conditions of a separate, written license agreement executed between you and Broadcom |
|---|
| 7 | * (an "Authorized License"). Except as set forth in an Authorized License, Broadcom grants |
|---|
| 8 | * no license (express or implied), right to use, or waiver of any kind with respect to the |
|---|
| 9 | * Software, and Broadcom expressly reserves all rights in and to the Software and all |
|---|
| 10 | * intellectual property rights therein. IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU |
|---|
| 11 | * HAVE NO RIGHT TO USE THIS SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY |
|---|
| 12 | * NOTIFY BROADCOM AND DISCONTINUE ALL USE OF THE SOFTWARE. |
|---|
| 13 | * |
|---|
| 14 | * Except as expressly set forth in the Authorized License, |
|---|
| 15 | * |
|---|
| 16 | * 1. This program, including its structure, sequence and organization, constitutes the valuable trade |
|---|
| 17 | * secrets of Broadcom, and you shall use all reasonable efforts to protect the confidentiality thereof, |
|---|
| 18 | * and to use this information only in connection with your use of Broadcom integrated circuit products. |
|---|
| 19 | |
|---|
| 20 | * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" |
|---|
| 21 | * AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES, REPRESENTATIONS OR |
|---|
| 22 | * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO |
|---|
| 23 | * THE SOFTWARE. BROADCOM SPECIFICALLY DISCLAIMS ANY AND ALL IMPLIED WARRANTIES |
|---|
| 24 | * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, |
|---|
| 25 | * LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION |
|---|
| 26 | * OR CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT OF |
|---|
| 27 | * USE OR PERFORMANCE OF THE SOFTWARE. |
|---|
| 28 | * |
|---|
| 29 | * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR ITS |
|---|
| 30 | * LICENSORS BE LIABLE FOR (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR |
|---|
| 31 | * EXEMPLARY DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO YOUR |
|---|
| 32 | * USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM HAS BEEN ADVISED OF |
|---|
| 33 | * THE POSSIBILITY OF SUCH DAMAGES; OR (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT |
|---|
| 34 | * ACTUALLY PAID FOR THE SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE |
|---|
| 35 | * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF ESSENTIAL PURPOSE OF |
|---|
| 36 | * ANY LIMITED REMEDY. |
|---|
| 37 | * |
|---|
| 38 | * $brcm_Workfile: bipc_server.c $ |
|---|
| 39 | * $brcm_Revision: 1 $ |
|---|
| 40 | * $brcm_Date: 10/4/11 5:44p $ |
|---|
| 41 | * |
|---|
| 42 | * Module Description: |
|---|
| 43 | * |
|---|
| 44 | * Revision History: |
|---|
| 45 | * |
|---|
| 46 | * $brcm_Log: /nexus/lib/ipc/bipc_server.c $ |
|---|
| 47 | * |
|---|
| 48 | * 1 10/4/11 5:44p vsilyaev |
|---|
| 49 | * SW7425-1364: Reference applicaion IPC and reference server |
|---|
| 50 | * |
|---|
| 51 | *****************************************************************************/ |
|---|
| 52 | #include "bstd.h" |
|---|
| 53 | #include "bipc_impl.h" |
|---|
| 54 | |
|---|
| 55 | BDBG_MODULE(bipc_server); |
|---|
| 56 | |
|---|
| 57 | BDBG_OBJECT_ID(bipc_server); |
|---|
| 58 | BDBG_OBJECT_ID(bipc_server_client); |
|---|
| 59 | |
|---|
| 60 | struct bipc_server_client { |
|---|
| 61 | BDBG_OBJECT(bipc_server_client) |
|---|
| 62 | BLST_D_ENTRY(bipc_server_client) link; |
|---|
| 63 | unsigned max_instances; |
|---|
| 64 | unsigned generation; |
|---|
| 65 | bipc_server_client_create_settings create_settings; |
|---|
| 66 | b_ipc_server_instance instances[1]; /* variable length */ |
|---|
| 67 | }; |
|---|
| 68 | |
|---|
| 69 | void bipc_server_get_default_create_settings(bipc_server_create_settings *create_settings) |
|---|
| 70 | { |
|---|
| 71 | BDBG_ASSERT(create_settings); |
|---|
| 72 | BKNI_Memset(create_settings, 0, sizeof(*create_settings)); |
|---|
| 73 | create_settings->max_instances = 4; |
|---|
| 74 | return; |
|---|
| 75 | } |
|---|
| 76 | |
|---|
| 77 | void bipc_server_get_default_client_create_settings(bipc_server_client_create_settings *create_settings) |
|---|
| 78 | { |
|---|
| 79 | BDBG_ASSERT(create_settings); |
|---|
| 80 | BKNI_Memset(create_settings, 0, sizeof(*create_settings)); |
|---|
| 81 | return; |
|---|
| 82 | } |
|---|
| 83 | |
|---|
| 84 | bipc_t bipc_server_create(const bipc_server_create_settings *create_settings) |
|---|
| 85 | { |
|---|
| 86 | bipc_t ipc; |
|---|
| 87 | unsigned i; |
|---|
| 88 | size_t size; |
|---|
| 89 | BERR_Code rc; |
|---|
| 90 | |
|---|
| 91 | BDBG_ASSERT(create_settings); |
|---|
| 92 | BDBG_ASSERT(create_settings->interfaces); |
|---|
| 93 | BDBG_ASSERT(create_settings->interface_count>0); |
|---|
| 94 | for(size=0,i=0;i<create_settings->interface_count;i++) { |
|---|
| 95 | BDBG_ASSERT(create_settings->interfaces[i]); |
|---|
| 96 | BDBG_ASSERT(create_settings->interfaces[i]->process); |
|---|
| 97 | size += create_settings->interfaces[i]->interface.buf_size; |
|---|
| 98 | } |
|---|
| 99 | |
|---|
| 100 | ipc = BKNI_Malloc(size + sizeof(b_ipc_pkt_in) + sizeof(b_ipc_pkt_out)+sizeof(*ipc)); |
|---|
| 101 | if(!ipc) {(void)BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);goto err_alloc;} |
|---|
| 102 | |
|---|
| 103 | BDBG_OBJECT_INIT(&ipc->t.server, bipc_server); |
|---|
| 104 | BLST_D_INIT(&ipc->t.server.clients); |
|---|
| 105 | ipc->t.server.ipc_buf_size = size; |
|---|
| 106 | ipc->t.server.create_settings = *create_settings; |
|---|
| 107 | rc = BKNI_CreateMutex(&ipc->t.server.lock); |
|---|
| 108 | if(rc!=BERR_SUCCESS) {rc=BERR_TRACE(rc);goto err_mutex;} |
|---|
| 109 | |
|---|
| 110 | return ipc; |
|---|
| 111 | err_mutex: |
|---|
| 112 | BKNI_Free(ipc); |
|---|
| 113 | err_alloc: |
|---|
| 114 | return NULL; |
|---|
| 115 | } |
|---|
| 116 | |
|---|
| 117 | |
|---|
| 118 | static void b_ipc_server_clean_client(bipc_t ipc, bipc_server_client_t client) |
|---|
| 119 | { |
|---|
| 120 | BSTD_UNUSED(ipc); |
|---|
| 121 | for(;;) { |
|---|
| 122 | unsigned i; |
|---|
| 123 | b_ipc_server_instance *newest_instance = NULL; |
|---|
| 124 | for(i=0;i<client->max_instances;i++) { |
|---|
| 125 | b_ipc_server_instance *instance = &client->instances[i]; |
|---|
| 126 | if(instance->interface) { |
|---|
| 127 | if(newest_instance==NULL || newest_instance->generation < instance->generation) { |
|---|
| 128 | newest_instance = instance; |
|---|
| 129 | } |
|---|
| 130 | } |
|---|
| 131 | } |
|---|
| 132 | if(newest_instance) { |
|---|
| 133 | size_t send_offset, send_size; |
|---|
| 134 | |
|---|
| 135 | BDBG_WRN(("bipc_server_destroy:%#lx cleaning up object %#lx(%d,%d):%s(%#lx)",(unsigned long)ipc, (unsigned long)client, client->create_settings.recv_fd, client->create_settings.send_fd, newest_instance->interface->interface.name, (unsigned long)newest_instance->object)); |
|---|
| 136 | newest_instance->interface->process(&newest_instance->object, newest_instance->interface->destructor_entry, ipc->t.server.buf, sizeof(unsigned), &send_offset, &send_size); |
|---|
| 137 | newest_instance->interface = NULL; |
|---|
| 138 | newest_instance->object = NULL; |
|---|
| 139 | } else { |
|---|
| 140 | break; |
|---|
| 141 | } |
|---|
| 142 | } |
|---|
| 143 | BDBG_OBJECT_DESTROY(client, bipc_server_client); |
|---|
| 144 | BKNI_Free(client); |
|---|
| 145 | return; |
|---|
| 146 | } |
|---|
| 147 | |
|---|
| 148 | void bipc_server_destroy(bipc_t ipc) |
|---|
| 149 | { |
|---|
| 150 | bipc_server_client_t client; |
|---|
| 151 | |
|---|
| 152 | BDBG_OBJECT_ASSERT(&ipc->t.server, bipc_server); |
|---|
| 153 | BKNI_AcquireMutex(ipc->t.server.lock); |
|---|
| 154 | while(NULL!=(client=BLST_D_FIRST(&ipc->t.server.clients))) { |
|---|
| 155 | BLST_D_REMOVE_HEAD(&ipc->t.server.clients, link); |
|---|
| 156 | BDBG_WRN(("bipc_server_destroy:%#lx leaked client %#lx(%d,%d)",(unsigned long)ipc, (unsigned long)client, client->create_settings.recv_fd, client->create_settings.send_fd)); |
|---|
| 157 | b_ipc_server_clean_client(ipc, client); |
|---|
| 158 | } |
|---|
| 159 | BKNI_ReleaseMutex(ipc->t.server.lock); |
|---|
| 160 | BKNI_DestroyMutex(ipc->t.server.lock); |
|---|
| 161 | BDBG_OBJECT_DESTROY(&ipc->t.server, bipc_server); |
|---|
| 162 | BKNI_Free(ipc); |
|---|
| 163 | return; |
|---|
| 164 | } |
|---|
| 165 | |
|---|
| 166 | |
|---|
| 167 | static bipc_server_client_t b_ipc_server_find_client(bipc_t ipc, int recv_fd, int send_fd) |
|---|
| 168 | { |
|---|
| 169 | bipc_server_client_t client; |
|---|
| 170 | for(client=BLST_D_FIRST(&ipc->t.server.clients);client;client=BLST_D_NEXT(client, link)) { |
|---|
| 171 | if(client->create_settings.recv_fd==recv_fd && client->create_settings.send_fd==send_fd) { |
|---|
| 172 | return client; |
|---|
| 173 | } |
|---|
| 174 | } |
|---|
| 175 | return NULL; |
|---|
| 176 | } |
|---|
| 177 | |
|---|
| 178 | bipc_server_client_t bipc_server_client_create(bipc_t ipc, bipc_server_client_create_settings *create_settings) |
|---|
| 179 | { |
|---|
| 180 | int rc=-1; |
|---|
| 181 | unsigned i; |
|---|
| 182 | bipc_server_client_t client; |
|---|
| 183 | |
|---|
| 184 | BDBG_OBJECT_ASSERT(&ipc->t.server, bipc_server); |
|---|
| 185 | BDBG_ASSERT(create_settings); |
|---|
| 186 | BKNI_AcquireMutex(ipc->t.server.lock); |
|---|
| 187 | client = b_ipc_server_find_client(ipc, create_settings->recv_fd, create_settings->send_fd); |
|---|
| 188 | if(client) { |
|---|
| 189 | (void)BERR_TRACE(BERR_INVALID_PARAMETER); |
|---|
| 190 | BDBG_ERR(("bipc_server_add_client:%lx duplicated client for %d,%d(%#lx)", (unsigned long)ipc, create_settings->recv_fd, create_settings->send_fd, (unsigned long)client)); |
|---|
| 191 | goto done; |
|---|
| 192 | } |
|---|
| 193 | client = BKNI_Malloc(sizeof(*client)+ipc->t.server.create_settings.max_instances*sizeof(client->instances)); |
|---|
| 194 | if(client==NULL) { (void)BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY); goto done;} |
|---|
| 195 | BDBG_OBJECT_INIT(client, bipc_server_client); |
|---|
| 196 | client->create_settings = *create_settings; |
|---|
| 197 | client->max_instances = ipc->t.server.create_settings.max_instances; |
|---|
| 198 | client->generation = 0; |
|---|
| 199 | for(i=0;i<ipc->t.server.create_settings.max_instances;i++) { |
|---|
| 200 | client->instances[i].interface = NULL; |
|---|
| 201 | client->instances[i].object = NULL; |
|---|
| 202 | } |
|---|
| 203 | BLST_D_INSERT_HEAD(&ipc->t.server.clients, client, link); |
|---|
| 204 | rc = 0; |
|---|
| 205 | done: |
|---|
| 206 | BKNI_ReleaseMutex(ipc->t.server.lock); |
|---|
| 207 | return client; |
|---|
| 208 | } |
|---|
| 209 | |
|---|
| 210 | void bipc_server_client_destroy(bipc_t ipc, bipc_server_client_t client) |
|---|
| 211 | { |
|---|
| 212 | BDBG_OBJECT_ASSERT(&ipc->t.server, bipc_server); |
|---|
| 213 | BDBG_OBJECT_ASSERT(client, bipc_server_client); |
|---|
| 214 | BKNI_AcquireMutex(ipc->t.server.lock); |
|---|
| 215 | BLST_D_REMOVE(&ipc->t.server.clients, client, link); |
|---|
| 216 | b_ipc_server_clean_client(ipc, client); |
|---|
| 217 | BKNI_ReleaseMutex(ipc->t.server.lock); |
|---|
| 218 | return; |
|---|
| 219 | } |
|---|
| 220 | |
|---|
| 221 | |
|---|
| 222 | int bipc_server_client_process(bipc_t ipc, bipc_server_client_t client) |
|---|
| 223 | { |
|---|
| 224 | int result = 0; |
|---|
| 225 | b_ipc_pkt_in *in; |
|---|
| 226 | b_ipc_pkt_out out; |
|---|
| 227 | int rc; |
|---|
| 228 | size_t payload; |
|---|
| 229 | const bipc_server_descriptor *descriptor=NULL; |
|---|
| 230 | b_ipc_server_instance *instance=NULL; |
|---|
| 231 | void *process_object; |
|---|
| 232 | size_t send_offset; |
|---|
| 233 | size_t send_size; |
|---|
| 234 | |
|---|
| 235 | BDBG_OBJECT_ASSERT(&ipc->t.server, bipc_server); |
|---|
| 236 | BDBG_OBJECT_ASSERT(client, bipc_server_client); |
|---|
| 237 | |
|---|
| 238 | BKNI_AcquireMutex(ipc->t.server.lock); |
|---|
| 239 | in = (void *)ipc->t.server.buf; |
|---|
| 240 | |
|---|
| 241 | rc = b_safe_read(client->create_settings.recv_fd, in, sizeof(*in)); |
|---|
| 242 | if(rc==0) { |
|---|
| 243 | goto done; |
|---|
| 244 | } else if (rc==-(int)BERR_END_OF_FILE) { |
|---|
| 245 | goto error; |
|---|
| 246 | } else if(rc!=sizeof(*in)) { |
|---|
| 247 | (void)BERR_TRACE(BERR_NOT_SUPPORTED); goto error; |
|---|
| 248 | } |
|---|
| 249 | |
|---|
| 250 | if(in->pkt_size >= ipc->t.server.ipc_buf_size || in->pkt_size<sizeof(*in)) { (void)BERR_TRACE(BERR_NOT_SUPPORTED); goto error; } |
|---|
| 251 | payload = in->pkt_size - sizeof(*in); |
|---|
| 252 | rc = b_safe_read(client->create_settings.recv_fd, ipc->t.server.buf+sizeof(*in), payload); |
|---|
| 253 | if(rc!=(int)payload) { (void)BERR_TRACE(BERR_NOT_SUPPORTED); goto error; } |
|---|
| 254 | if(in->instance==BIPC_INSTANCE_ID_NEW) { |
|---|
| 255 | unsigned i; |
|---|
| 256 | bipc_interface_descriptor *id = (void *)(ipc->t.server.buf+sizeof(*in)); |
|---|
| 257 | |
|---|
| 258 | if(payload<sizeof(bipc_interface_descriptor)) { (void)BERR_TRACE(BERR_NOT_SUPPORTED);goto error;} |
|---|
| 259 | for(i=0;i<ipc->t.server.create_settings.interface_count;i++) { |
|---|
| 260 | descriptor = ipc->t.server.create_settings.interfaces[i]; |
|---|
| 261 | if(BKNI_Memcmp(descriptor->interface.name, id->name, sizeof(id->name))==0) { |
|---|
| 262 | if(BKNI_Memcmp(descriptor->interface.sha1, id->sha1, sizeof(id->sha1))!=0) { |
|---|
| 263 | BDBG_WRN(("bipc_server_process:%#lx mismatched protocol for interface %s client:%#lx", (unsigned long)ipc, descriptor->interface.name, (unsigned long)client)); |
|---|
| 264 | (void)BERR_TRACE(BERR_NOT_SUPPORTED); |
|---|
| 265 | goto error; |
|---|
| 266 | } |
|---|
| 267 | break; |
|---|
| 268 | } |
|---|
| 269 | descriptor = NULL; |
|---|
| 270 | } |
|---|
| 271 | if(descriptor == NULL) { |
|---|
| 272 | BDBG_WRN(("bipc_server_process:%#lx unknown interface client:%#lx", (unsigned long)ipc, (unsigned long)client)); |
|---|
| 273 | (void)BERR_TRACE(BERR_NOT_SUPPORTED); |
|---|
| 274 | BDBG_ASSERT(0); |
|---|
| 275 | goto error; |
|---|
| 276 | } |
|---|
| 277 | if(in->method != descriptor->constructor_entry) { |
|---|
| 278 | BDBG_WRN(("bipc_server_process:%#lx %s invalid constructor %u(%u) client:%#lx", (unsigned long)ipc, descriptor->interface.name, in->method, descriptor->constructor_entry, (unsigned long)client)); |
|---|
| 279 | (void)BERR_TRACE(BERR_NOT_SUPPORTED); |
|---|
| 280 | goto error; |
|---|
| 281 | } |
|---|
| 282 | for(i=0;i<client->max_instances;i++) { |
|---|
| 283 | if(client->instances[i].interface==NULL) { |
|---|
| 284 | instance = &client->instances[i]; |
|---|
| 285 | send_offset = i; /* used as object ID communicated back to the client */ |
|---|
| 286 | break; |
|---|
| 287 | } |
|---|
| 288 | } |
|---|
| 289 | if(instance==NULL) { |
|---|
| 290 | BDBG_WRN(("bipc_server_process:%#lx %s not enough space client:%lx", (unsigned long)ipc, descriptor->interface.name, (unsigned long)client)); |
|---|
| 291 | (void)BERR_TRACE(BERR_NOT_SUPPORTED); |
|---|
| 292 | goto error; |
|---|
| 293 | } |
|---|
| 294 | process_object = client->create_settings.ipc_context; |
|---|
| 295 | } else { |
|---|
| 296 | if(in->instance >= client->max_instances) { |
|---|
| 297 | BDBG_WRN(("bipc_server_process:%#lx invalid instance %u:%u", (unsigned long)ipc, in->instance, client->max_instances)); |
|---|
| 298 | (void)BERR_TRACE(BERR_NOT_SUPPORTED); |
|---|
| 299 | goto error; |
|---|
| 300 | } |
|---|
| 301 | instance = &client->instances[in->instance]; |
|---|
| 302 | process_object = instance->object; |
|---|
| 303 | if(instance == NULL) { |
|---|
| 304 | BDBG_WRN(("bipc_server_process:%#lx unknown instance %u", (unsigned long)ipc, in->instance)); |
|---|
| 305 | (void)BERR_TRACE(BERR_NOT_SUPPORTED); |
|---|
| 306 | goto error; |
|---|
| 307 | } |
|---|
| 308 | descriptor = instance->interface; |
|---|
| 309 | if(in->method == descriptor->constructor_entry) { |
|---|
| 310 | BDBG_WRN(("bipc_server_process:%#lx invalid constructor call %s client:%#lx", (unsigned long)ipc, descriptor->interface.name, (unsigned long)client)); |
|---|
| 311 | (void)BERR_TRACE(BERR_NOT_SUPPORTED); |
|---|
| 312 | goto error; |
|---|
| 313 | } |
|---|
| 314 | } |
|---|
| 315 | BDBG_ASSERT(descriptor); |
|---|
| 316 | BDBG_ASSERT(instance); |
|---|
| 317 | rc = descriptor->process(&process_object, in->method, ipc->t.server.buf+sizeof(*in), payload, &send_offset, &send_size); |
|---|
| 318 | if(rc!=0) { |
|---|
| 319 | BDBG_WRN(("bipc_server_process:%#lx error executing method %s:%u client:%#lx", (unsigned long)ipc, descriptor->interface.name, in->method, (unsigned long)client)); |
|---|
| 320 | (void)BERR_TRACE(BERR_NOT_SUPPORTED); |
|---|
| 321 | goto error; |
|---|
| 322 | } |
|---|
| 323 | out.pkt_size = send_size + sizeof(out); |
|---|
| 324 | rc = b_safe_write(client->create_settings.send_fd, &out, sizeof(out)); |
|---|
| 325 | if(rc!=sizeof(out)) { (void)BERR_TRACE(BERR_NOT_SUPPORTED); goto error; } |
|---|
| 326 | if(in->method == descriptor->constructor_entry) { |
|---|
| 327 | client->generation++; |
|---|
| 328 | instance->generation = client->generation; |
|---|
| 329 | instance->interface = descriptor; |
|---|
| 330 | instance->object = process_object; |
|---|
| 331 | } else if(in->method == descriptor->destructor_entry) { |
|---|
| 332 | instance->interface = NULL; |
|---|
| 333 | instance->object = NULL; |
|---|
| 334 | } |
|---|
| 335 | if(send_size) { |
|---|
| 336 | rc = b_safe_write(client->create_settings.send_fd, ipc->t.server.buf + sizeof(*in) + send_offset , send_size); |
|---|
| 337 | if(rc!=(int)send_size) { (void)BERR_TRACE(BERR_NOT_SUPPORTED); goto error; } |
|---|
| 338 | } |
|---|
| 339 | done: |
|---|
| 340 | BKNI_ReleaseMutex(ipc->t.server.lock); |
|---|
| 341 | return result; |
|---|
| 342 | error: |
|---|
| 343 | result = -1; |
|---|
| 344 | goto done; |
|---|
| 345 | } |
|---|
| 346 | |
|---|