blob: 9f716307b1cc84cebabf240c9538704550b13e28 [file] [log] [blame]
Shad Ansari2f7f9be2017-06-07 13:34:53 -07001/*
2<:copyright-BRCM:2016:DUAL/GPL:standard
3
4 Broadcom Proprietary and Confidential.(c) 2016 Broadcom
5 All Rights Reserved
6
7Unless you and Broadcom execute a separate written software license
8agreement governing use of this software, this software is licensed
9to you under the terms of the GNU General Public License version 2
10(the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
11with the following added to such license:
12
13 As a special exception, the copyright holders of this software give
14 you permission to link this software with independent modules, and
15 to copy and distribute the resulting executable under terms of your
16 choice, provided that you also meet, for each linked independent
17 module, the terms and conditions of the license of that module.
18 An independent module is a module which is not derived from this
19 software. The special exception does not apply to any modifications
20 of the software.
21
22Not withstanding the above, under no circumstances may you combine
23this software in any way with any other Broadcom software provided
24under a license other than the GPL, without Broadcom's express prior
25written consent.
26
27:>
28 */
29
30#include <bcmos_system.h>
31#include <bcmtr_interface.h>
32#include <bcmtr_header.h>
33#include <bcmtr_transport_cli.h>
34#include <bcmolt_api.h>
35#include <bcmtr_debug.h>
36#ifdef ENABLE_CLI
37#include <bcmcli.h>
38#endif
39#include "bcmolt_api_proxy.h"
40#ifdef ENABLE_LOG
41#include "bcm_dev_log.h"
42#endif
43
44/* Statistics */
45typedef struct proxy_stats
46{
47 unsigned long rx_packets;
48 unsigned long rx_bytes;
49 unsigned long tx_packets;
50 unsigned long tx_bytes;
51 unsigned long rx_errors;
52 unsigned long tx_errors;
53 unsigned long unpack_errors;
54 unsigned long pack_errors;
55 unsigned long msg_errors;
56} proxy_stats;
57
58typedef struct proxy_control_block
59{
60 bcmos_task proxy_rx_task;
61 struct sockaddr_in client;
62 uint32_t proxy_port;
63 int device_id;
64 int client_socket;
65 bcmos_bool is_running;
66 char *on_ready_cmd;
67
68 /* the maximum amount of memory that could possibly by used by all variable-sized lists within a GET request */
69#define DYNAMIC_LIST_BUFFER_SIZE (32 * 1024)
70 uint8_t dynamic_list_buffer[DYNAMIC_LIST_BUFFER_SIZE];
71
72 dev_log_id proxy_log;
73
74 proxy_stats stats;
75} proxy_control_block;
76
77/* Per device proxy control block */
78static proxy_control_block proxy_data[BCMTR_MAX_OLTS];
79static bcmos_bool is_first_proxy = BCMOS_TRUE;
80
81#ifdef ENABLE_CLI
82/*/proxy/stats command handler
83*/
84static bcmos_errno _proxy_stats_cmd(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t nparms)
85{
86 int device = (int)parm[0].value.number;
87
88 if (device >= BCMTR_MAX_OLTS)
89 return BCM_ERR_RANGE;
90
91 bcmcli_print(session, "%-16s: %lu\n", "rx_packets", proxy_data[device].stats.rx_packets);
92 bcmcli_print(session, "%-16s: %lu\n", "rx_bytes", proxy_data[device].stats.rx_bytes);
93 bcmcli_print(session, "%-16s: %lu\n", "tx_packets", proxy_data[device].stats.tx_packets);
94 bcmcli_print(session, "%-16s: %lu\n", "tx_bytes", proxy_data[device].stats.tx_bytes);
95 bcmcli_print(session, "%-16s: %lu\n", "rx_errors", proxy_data[device].stats.rx_errors);
96 bcmcli_print(session, "%-16s: %lu\n", "tx_errors", proxy_data[device].stats.tx_errors);
97 bcmcli_print(session, "%-16s: %lu\n", "unpack_errors", proxy_data[device].stats.unpack_errors);
98 bcmcli_print(session, "%-16s: %lu\n", "pack_errors", proxy_data[device].stats.pack_errors);
99 bcmcli_print(session, "%-16s: %lu\n", "msg_errors", proxy_data[device].stats.msg_errors);
100 memset(&proxy_data[device].stats, 0, sizeof(proxy_stats));
101
102 return BCM_ERR_OK;
103}
104#endif /* #ifdef ENABLE_CLI */
105
106static bcmos_errno _proxy_msg_error(bcmolt_devid device, bcmolt_msg *proxy_msg)
107{
108 proxy_control_block *proxy = &proxy_data[device];
109 ++proxy->stats.msg_errors;
110 bcmolt_msg_err(proxy_msg, proxy->proxy_log, BCM_ERR_PARM, BCMOLT_ERR_FIELD_NONE, "Message is insane");
111 proxy_msg->dir = BCMOLT_MSG_DIR_RESPONSE;
112 return BCM_ERR_PARM;
113}
114
115static void _proxy_invoke(bcmolt_devid device, bcmolt_msg *proxy_msg)
116{
117 proxy_control_block *proxy = &proxy_data[device];
118 bcmos_errno rc;
119 bcmolt_system_mode system_mode;
120
121 /* Check that the message targets an object that is compatible with our system mode */
122 bcmolt_system_mode_get(device, &system_mode);
123 if (system_mode != BCMOLT_SYSTEM_MODE__NUM_OF && !bcmolt_object_is_supported(system_mode, proxy_msg->obj_type))
124 {
125 ++proxy->stats.msg_errors;
126 proxy_msg->dir = BCMOLT_MSG_DIR_RESPONSE;
127 bcmolt_msg_err(
128 proxy_msg,
129 proxy->proxy_log,
130 BCM_ERR_NOT_SUPPORTED,
131 BCMOLT_ERR_FIELD_NONE,
132 "Object type is not supported in this system mode");
133 return;
134 }
135
136 /* Invoke API */
137 switch (proxy_msg->group)
138 {
139 case BCMOLT_MGT_GROUP_CFG:
140 if ((proxy_msg->type & BCMOLT_MSG_TYPE_CLEAR) != 0)
141 {
142 rc = bcmolt_cfg_clear(device, (bcmolt_cfg *)proxy_msg);
143 }
144 else if ((proxy_msg->type & BCMOLT_MSG_TYPE_GET) != 0)
145 {
146 if ((proxy_msg->type & BCMOLT_MSG_TYPE_MULTI) != 0)
147 {
148 if (proxy_msg->msg_set == NULL)
149 {
150 rc = _proxy_msg_error(device, proxy_msg);
151 }
152 else
153 {
154 rc = bcmolt_cfg_get_multi(device,
155 (bcmolt_cfg *)proxy_msg,
156 proxy_msg->msg_set->filter_flags,
157 proxy_msg->msg_set);
158 }
159 }
160 else
161 {
162 rc = bcmolt_cfg_get(device, (bcmolt_cfg *)proxy_msg);
163 }
164 }
165 else if ((proxy_msg->type & BCMOLT_MSG_TYPE_SET) != 0)
166 {
167 rc = bcmolt_cfg_set(device, (bcmolt_cfg *)proxy_msg);
168 }
169 else
170 {
171 rc = _proxy_msg_error(device, proxy_msg);
172 }
173 break;
174
175 case BCMOLT_MGT_GROUP_STAT:
176 {
177 bcmolt_stat_flags flags;
178
179 flags = ((proxy_msg->type & BCMOLT_MSG_TYPE_CLEAR) != 0) ?
180 BCMOLT_STAT_FLAGS_CLEAR_ON_READ : 0;
181
182 rc = bcmolt_stat_get(device, (bcmolt_stat *)proxy_msg, flags);
183 }
184 break;
185
186 case BCMOLT_MGT_GROUP_OPER:
187 rc = bcmolt_oper_submit(device, (bcmolt_oper *)proxy_msg);
188 break;
189
190 case BCMOLT_MGT_GROUP_PROXY:
191 rc = bcmolt_proxy_send(device, (bcmolt_proxy *)proxy_msg);
192 break;
193
194 case BCMOLT_MGT_GROUP_STAT_CFG:
195 if ((proxy_msg->type & BCMOLT_MSG_TYPE_GET) != 0)
196 {
197 rc = bcmolt_stat_cfg_get(device, (bcmolt_stat_cfg *)proxy_msg);
198 }
199 else if ((proxy_msg->type & BCMOLT_MSG_TYPE_SET) != 0)
200 {
201 rc = bcmolt_stat_cfg_set(device, (bcmolt_stat_cfg *)proxy_msg);
202 }
203 else
204 {
205 rc = _proxy_msg_error(device, proxy_msg);
206 }
207 break;
208
209 case BCMOLT_MGT_GROUP_AUTO_CFG:
210 if ((proxy_msg->type & BCMOLT_MSG_TYPE_GET) != 0)
211 {
212 rc = bcmolt_auto_cfg_get(device, (bcmolt_auto_cfg *)proxy_msg);
213 }
214 else if ((proxy_msg->type & BCMOLT_MSG_TYPE_SET) != 0)
215 {
216 rc = bcmolt_auto_cfg_set(device, (bcmolt_auto_cfg *)proxy_msg);
217 }
218 else
219 {
220 rc = _proxy_msg_error(device, proxy_msg);
221 }
222 break;
223
224 default:
225 rc = _proxy_msg_error(device, proxy_msg);
226 }
227
228 proxy_msg->err = rc;
229}
230
231/* Pack and send message */
232static void _proxy_send(bcmolt_devid device, bcmolt_msg *msg)
233{
234 bcmtr_hdr hdr = {};
235 int32_t packed_length;
236 bcmolt_buf txb = {};
237 int len;
238
239 /* Allocate buffer and pack */
240 packed_length = bcmolt_msg_get_packed_length(msg);
241 if (packed_length <= 0)
242 {
243 ++proxy_data[device].stats.pack_errors;
244 goto done;
245 }
246 packed_length += BCMTR_HDR_SIZE;
247 if (bcmolt_buf_alloc(&txb, packed_length, BCMOLT_BUF_ENDIAN_FIXED) != BCM_ERR_OK)
248 {
249 ++proxy_data[device].stats.pack_errors;
250 goto done;
251 }
252 bcmtr_header_fill(msg, &hdr);
253 bcmtr_header_pack(&hdr, txb.start);
254 bcmolt_buf_skip(&txb, BCMTR_HDR_SIZE);
255 if (bcmolt_msg_pack(msg, &txb) != BCM_ERR_OK)
256 {
257 ++proxy_data[device].stats.pack_errors;
258 goto done;
259 }
260
261 /* Send to client */
262 len = sendto(proxy_data[device].client_socket, txb.start, bcmolt_buf_get_used(&txb), 0,
263 (struct sockaddr *)&proxy_data[device].client, sizeof(proxy_data[device].client));
264 if (len <= 0)
265 {
266 ++proxy_data[device].stats.tx_errors;
267 }
268 else
269 {
270 ++proxy_data[device].stats.tx_packets;
271 proxy_data[device].stats.tx_bytes += len;
272 }
273
274done:
275 bcmolt_buf_free(&txb);
276 return;
277}
278
279/* Task that waits for messages from Maple.
280 * Once message is received, it is forwarded to remote application
281 * via UDP socket.
282 */
283static int _proxy_rx_handler(long data)
284{
285 bcmolt_devid device = (bcmolt_devid)data;
286 bcmos_task *self = bcmos_task_current();
287 proxy_control_block *proxy = &proxy_data[device];
288 struct sockaddr_in sender;
289 socklen_t sendsize = sizeof(sender);
290 uint8_t client_buffer[BCMTR_MAX_MTU_SIZE + 128];
291 bcmolt_msg *proxy_msg;
292 bcmtr_hdr tr_hdr;
293 bcmolt_buf rxb;
294 int len;
295 uint16_t corr_tag;
296 bcmos_errno rc;
297
298 while (!self->destroyed)
299 {
300 memset(&sender, 0, sizeof(sender));
301 len = recvfrom(proxy->client_socket, client_buffer, sizeof(client_buffer), 0,
302 (struct sockaddr *)&sender, &sendsize);
303 if (len < BCMTR_HDR_SIZE)
304 {
305 ++proxy->stats.rx_errors;
306 bcmos_usleep(1000000);
307 continue;
308 }
309 ++proxy->stats.rx_packets;
310 proxy->stats.rx_bytes += len;
311
312 if (proxy->client.sin_addr.s_addr != sender.sin_addr.s_addr ||
313 proxy->client.sin_port != sender.sin_port)
314 {
315#ifdef ENABLE_LOG
316 int client_ip = ntohl(sender.sin_addr.s_addr);
317 int client_port = ntohs(sender.sin_port);
318 BCM_LOG(INFO, proxy->proxy_log, "bcm_api_proxy: device %i connected to %d.%d.%d.%d:%d\n",
319 (int)device,
320 (client_ip >> 24) & 0xff, (client_ip >> 16) & 0xff,
321 (client_ip >> 8) & 0xff, client_ip & 0xff, client_port);
322#endif
323 proxy->client = sender;
324 }
325
326 /* Unpack received message */
327 bcmolt_buf_init(&rxb, len, client_buffer, BCMOLT_BUF_ENDIAN_FIXED);
328 bcmtr_header_unpack(client_buffer, &tr_hdr);
329
330 /* Skip registration messages for now. The proxy has already registered for everything */
331 if (tr_hdr.auto_proxy_reg || tr_hdr.auto_proxy_unreg)
332 continue;
333
334 bcmolt_buf_skip(&rxb, BCMTR_HDR_SIZE);
335 proxy_msg = NULL;
336 rc = bcmolt_msg_unpack(&rxb, &proxy_msg);
337 if (rc)
338 {
339 /* Unpack error. Nothing much we can do */
340 ++proxy->stats.unpack_errors;
341 continue;
342 }
343
344 /* Store correlation tag for later */
345 proxy_msg->corr_tag = tr_hdr.corr_tag;
346 corr_tag = proxy_msg->corr_tag;
347
348 /* Point the message unpacker to local storage for dynamically-sized lists */
349 proxy_msg->list_buf = proxy->dynamic_list_buffer;
350 proxy_msg->list_buf_size = DYNAMIC_LIST_BUFFER_SIZE;
351
352 /* Invoke API */
353 _proxy_invoke(device, proxy_msg);
354
355 /* Pack and send back to the client */
356 proxy_msg->corr_tag = corr_tag;
357 _proxy_send(device, proxy_msg);
358 bcmolt_msg_free(proxy_msg);
359 }
360
361 self->destroyed = BCMOS_TRUE;
362 return 0;
363}
364
365/* Auto / proxy message handler */
366void bcmolt_api_proxy_auto_rx_cb(bcmolt_devid device, bcmolt_msg *msg)
367{
368 if (device >= BCMTR_MAX_OLTS)
369 return;
370
371 if (proxy_data[device].is_running)
372 {
373 if (proxy_data[device].on_ready_cmd &&
374 msg->obj_type == BCMOLT_OBJ_ID_DEVICE &&
375 msg->group == BCMOLT_MGT_GROUP_AUTO &&
376 msg->subgroup == BCMOLT_DEVICE_AUTO_ID_CONNECTION_COMPLETE)
377 {
378 char on_ready_cmd[512];
379 int rc;
380 snprintf(on_ready_cmd, sizeof(on_ready_cmd) - 1, "%s %d", proxy_data[device].on_ready_cmd, (int)device);
381 rc = system(on_ready_cmd);
382#ifdef ENABLE_LOG
383 BCM_LOG(INFO, proxy_data[device].proxy_log, "Executed command %s. rc=%d\n", on_ready_cmd, rc);
384#else
385 (void)rc;
386#endif
387 }
388 _proxy_send(device, msg);
389 }
390}
391
392static bcmos_errno _proxy_start(bcmolt_devid device, uint32_t udp_port, char *on_ready)
393{
394 bcmos_errno rc;
395 bcmos_task_parm proxy_rx_parm =
396 {
397 .name = "proxy_rx",
398 .handler = _proxy_rx_handler,
399 .priority = TASK_PRIORITY_TRANSPORT_PROXY,
400 .data = device
401 };
402 struct sockaddr_in sa = {};
403
404 proxy_data[device].proxy_port = udp_port;
405 proxy_data[device].device_id = device;
406 proxy_data[device].on_ready_cmd = on_ready;
407
408 /* Start listening on proxy port */
409 proxy_data[device].client_socket = socket(AF_INET, SOCK_DGRAM, 0);
410 if (proxy_data[device].client_socket < 0)
411 {
412#ifdef ENABLE_LOG
413 BCM_LOG(ERROR, proxy_data[device].proxy_log, "Can't create UDP socket\n");
414#endif
415 return BCM_ERR_INTERNAL;
416 }
417
418 /* Bind local */
419 sa.sin_family = AF_INET;
420 sa.sin_port = htons(proxy_data[device].proxy_port);
421 sa.sin_addr.s_addr = INADDR_ANY;
422 if (bind(proxy_data[device].client_socket, (struct sockaddr*)&sa, sizeof(sa) ) == -1)
423 {
424 perror("bind");
425#ifdef ENABLE_LOG
426 BCM_LOG(ERROR, proxy_data[device].proxy_log, "Can't bind UDP socket to port %u\n", proxy_data[device].proxy_port);
427#endif
428 close(proxy_data[device].client_socket);
429 return BCM_ERR_INTERNAL;
430 }
431
432 /* Create thread listening for incoming APIs */
433 rc = bcmos_task_create(&proxy_data[device].proxy_rx_task, &proxy_rx_parm);
434 BUG_ON(BCM_ERR_OK != rc);
435
436 proxy_data[device].is_running = BCMOS_TRUE;
437
438#ifdef ENABLE_LOG
439 BCM_LOG(INFO, proxy_data[device].proxy_log, "BCM68620 API proxy for device %d is listening for requests on UDP port %u\n",
440 (int)device, proxy_data[device].proxy_port);
441#endif
442
443 return BCM_ERR_OK;
444}
445
446bcmos_errno bcmolt_api_proxy_init(bcmcli_entry *root, bcmolt_devid device, uint32_t udp_port, char *on_ready)
447{
448#ifdef ENABLE_CLI
449 bcmcli_entry *dir;
450#endif
451
452 if (device >= BCMTR_MAX_OLTS)
453 return BCM_ERR_PARM;
454
455 if (proxy_data[device].is_running)
456 return BCM_ERR_ALREADY;
457
458#ifdef ENABLE_LOG
459 {
460 char log_id[32];
461 snprintf(log_id, sizeof(log_id) - 1, "proxy_%d", (int)device);
462 proxy_data[device].proxy_log = bcm_dev_log_id_register(log_id, DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH);
463 }
464#else
465 proxy_data[device].proxy_log = DEV_LOG_INVALID_ID;
466#endif
467
468 if (is_first_proxy)
469 {
470#ifdef ENABLE_CLI
471 dir = bcmcli_dir_add(root, "proxy", "API proxy", BCMCLI_ACCESS_GUEST, NULL);
472 if (!dir)
473 {
474 BCM_LOG(ERROR, proxy_data[device].proxy_log, "Can't create proxy directory\n");
475 BUG();
476 }
477
478 BCMCLI_MAKE_CMD(dir, "stat", "Proxy statistics", _proxy_stats_cmd,
479 BCMCLI_MAKE_PARM_RANGE("device", "Device index", BCMCLI_PARM_NUMBER, BCMCLI_PARM_FLAG_OPTIONAL,
480 0, BCMTR_MAX_OLTS-1));
481
482#endif
483 is_first_proxy = BCMOS_FALSE;
484 }
485 return _proxy_start(device, udp_port, on_ready);
486}
487
488void bcmolt_api_proxy_stop(void)
489{
490 int i;
491
492 for (i = 0; i < BCMTR_MAX_OLTS; i++)
493 {
494 if (proxy_data[i].is_running)
495 {
496 bcmos_task_destroy(&proxy_data[i].proxy_rx_task);
497 close(proxy_data[i].client_socket);
498 }
499 }
500}
501