blob: 9c03471caf40e4b323952d9ab3e5140add033d1c [file] [log] [blame]
Vadim Iosevichd50ea462017-03-30 16:19:08 +03001/*
2 * Copyright (c) 2017, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <pthread.h>
31#include <stdio.h>
32#include <string.h>
33#include <stdlib.h>
34#include <sstream>
35#include <iostream>
36#include <fstream>
37
38#include "cmdiface.h"
39#include "parser.h"
40#include "debug.h"
41#include "WlctPciAcss.h"
42#include "pmc_file.h"
43#include "udp_server.h"
44
45
46struct open_interface_s *CmdIface::open_interfaces = NULL;
47pthread_mutex_t CmdIface::open_interfaces_mutex = PTHREAD_MUTEX_INITIALIZER;
48int CmdIface::interface_id = 0;
49
50/*
51*/
52void *CmdIface::get_interface(const char *name)
53{
54 struct open_interface_s *s = open_interfaces;
55 LOG_DEBUG << "Looking for interface: " << name << std::endl;
56
57 while(s != NULL)
58 {
59 LOG_VERBOSE << "Checking interface for match: " << s->interface << std::endl;
60 if(0 == strncasecmp(name, s->interface, MAX_INTERFACE_NAME))
61 {
62 LOG_VERBOSE << "Match found" << std::endl;
63 return s->handler;
64 }
65 s = s->next;
66 }
67
68 return NULL;
69}
70
71/*
72*/
73void *CmdIface::add_interface(const char *name, void *handler)
74{
75 LOG_DEBUG << "Adding interface: " << name << std::endl;
76
77 void *h = get_interface(name);
78 if(h != NULL)
79 {
80 LOG_DEBUG << "The interface is already open" << std::endl;
81 return h; // Interface already opened
82 }
83
84 // Add interface to the list
85 struct open_interface_s *s = new struct open_interface_s;
86 if(s == NULL)
87 {
88 return NULL;
89 }
90
91 snprintf(s->interface, MAX_INTERFACE_NAME, "%s", name);
92 s->handler = handler;
93 pthread_mutex_lock(&open_interfaces_mutex);
94 s->next = open_interfaces;
95 open_interfaces = s;
96 pthread_mutex_unlock(&open_interfaces_mutex);
97
98 return handler;
99}
100
101/*
102*/
103void CmdIface::del_interface(void *handler)
104{
105 LOG_DEBUG << "Deleting interfaces by handler" << std::endl;
106
107 struct open_interface_s *s = open_interfaces;
108 struct open_interface_s *prev = NULL;
109
110 while(s != NULL) {
111 if(handler == s->handler) {
112 // Remove the interface from the list
113 pthread_mutex_lock(&open_interfaces_mutex);
114 if(prev != NULL)
115 prev->next = s->next;
116 else
117 open_interfaces = s->next;
118 pthread_mutex_unlock(&open_interfaces_mutex);
119 delete s;
120 }
121 prev = s;
122 s = s->next;
123 }
124}
125
126/*
127*/
128int CmdIface::cmd_get_interfaces()
129{
130 INTERFACE_LIST interfaces;
131 int num_interfaces;
132 int rc;
133
134 LOG_DEBUG << "Getting active WIGIG card interfaces" << std::endl;
135
136 rc = GetInterfaces(&interfaces, &num_interfaces);
137 LOG_DEBUG << "Found " << num_interfaces << " interfaces" << std::endl;
138
139 std::ostringstream replyBuilder;
140
141 if(rc == 0)
142 {
143 for(int i=0; i < num_interfaces; i++)
144 {
145 replyBuilder << interfaces.list[i].ifName << ' ';
146 }
147 }
148
149 replyBuilder << "\r\n";
150 m_Reply = replyBuilder.str();
151
152 return 0;
153}
154
155/*
156*/
157int CmdIface::cmd_open_interface(char *interface)
158{
159 void *handler = NULL;
160 int rc=0;
161
162 LOG_DEBUG << "Opening an interface: " << interface << std::endl;
163
164 if( strstr(interface, "SPARROW")|| strstr(interface, "sparrow")){
165 rc = CreateDeviceAccessHandler(interface, MST_SPARROW, &handler);
166 }
167 else if(strstr(interface, "MARLON") || strstr(interface, "marlon")){
168 rc = CreateDeviceAccessHandler(interface, MST_MARLON, &handler);
169 }
170 else{
171 m_Reply = "0xDEAD\r\n";
172 }
173 if(rc != 0)
174 m_Reply = "0xDEADDEAD\r\n";
175 else {
176
177 std::ostringstream replyBuilder;
178
179 replyBuilder << interface << '_' << interface_id;
180 add_interface(replyBuilder.str().c_str(), handler);
181 replyBuilder << "\r\n";
182 m_Reply = replyBuilder.str();
183 interface_id++; // TODO: Should be protected by a mutex? I didn't see it's being used in the application
184 }
185 return 0;
186}
187
188/*
189*/
190int CmdIface::cmd_close_interface(char *interface)
191{
192 LOG_DEBUG << "Closing interface: " << interface << std::endl;
193
194 void *handler = get_interface(interface);
195
196 if(handler != NULL)
197 {
198 del_interface(handler);
199 interface_id--;
200 }
201 else
202 {
203 LOG_WARNING << "Interface " << interface << " wasn't opened" << std::endl;
204 }
205
206 m_Reply = "0\r\n";
207 return 0;
208}
209
210/*
211*/
212int CmdIface::cmd_r(char *interface, unsigned int address)
213{
214 unsigned int val = 0xDEADDEAD;
215 void *handler = get_interface(interface);
216
217 std::ostringstream replyBuilder;
218 if(handler == NULL)
219 {
220 m_Reply = "0xDEADDEAD";
221 }
222 else
223 {
224 int rc = WlctAccssRead(handler, address, val);
225 (void)rc;
226 replyBuilder << val;
227 }
228
229 replyBuilder << "\r\n";
230 m_Reply = replyBuilder.str();
231
232 return 0;
233}
234
235/*
236*/
237int CmdIface::cmd_w(char *interface, unsigned int address, unsigned int data)
238{
239 int rc;
240 void *handler = get_interface(interface);
241
242 std::ostringstream replyBuilder;
243
244 if(handler == NULL)
245 {
246 replyBuilder << "0xDEADDEAD";
247 }
248 else
249 {
250 rc = WlctAccssWrite(handler, address, data);
251 if(rc == 0)
252 replyBuilder << "0";
253 else
254 replyBuilder << "ERROR";
255 }
256
257 replyBuilder << "\r\n";
258 m_Reply = replyBuilder.str();
259
260 return 0;
261}
262
263/*
264*/
265int CmdIface::cmd_alloc_pmc(char *interface, unsigned int desc_size, unsigned int desc_num)
266{
267 int rc;
268 LOG_DEBUG << "Allocating PMC descriptors:"
269 << " interface = " << interface
270 << " size = " << desc_size
271 << " number = " << desc_num
272 << std::endl;
273
274 std::ostringstream replyBuilder;
275
276 void *handler = get_interface(interface);
277 if(handler == NULL)
278 {
279 LOG_DEBUG << "Cannot get handler for interface " << interface << std::endl;
280 replyBuilder << "0xDEADDEAD";
281 }
282 else
283 {
284 rc = WlctAccssAllocPmc(handler, desc_size, desc_num);
285
286 if(rc == 0)
287 {
288 LOG_DEBUG << "Successfully allocated PMC descriptors" << std::endl;
289 replyBuilder << "0";
290 }
291 else
292 {
293 LOG_ERROR << "Error allocating PMC descriptors" << std::endl;
294 replyBuilder << "ERROR";
295 }
296 }
297
298 replyBuilder << "\r\n";
299 m_Reply = replyBuilder.str();
300
301 return 0;
302}
303
304/*
305*/
306int CmdIface::cmd_read_pmc(char *interface, unsigned int ref_number)
307{
308 LOG_DEBUG << "Reading PMC data:"
309 << " interface = " << interface
310 << " reference number = " << ref_number
311 << std::endl;
312
313 void *handler = get_interface(interface);
314
315 if(handler == NULL)
316 {
317 LOG_ERROR << "No interface found: " << interface << std::endl;
318 m_Reply = "0xDEADDEAD\r\n";
319 return 0;
320 }
321
322 PmcFile pmcFile(ref_number);
323 PmcFileWriter pmcFileWriter(pmcFile);
324 bool status = pmcFileWriter.WriteFile();
325 if (false == status)
326 {
327 LOG_ERROR << "Error creating PMC data file" << std::endl;
328 m_Reply = "0xDEADDEAD\r\n";
329 return 0;
330 }
331
332 // Reply with file size
333 size_t pmcFileSize = pmcFileWriter.GetFileSize();
334
335 std::ostringstream replyBuilder;
336 replyBuilder << pmcFileSize << "\r\n";
337 m_Reply = replyBuilder.str();
338
339 return 0;
340}
341
342/*
343*/
344int CmdIface::cmd_read_pmc_file(unsigned int ref_number)
345{
346 LOG_DEBUG << "Reading PMC File #" << ref_number << std::endl;
347
348 PmcFile pmcFile(ref_number);
349
350 if (NULL == pmcFile.GetFileName())
351 {
352 LOG_ERROR << "Error getting PMC data file #" << ref_number << std::endl;
353 m_Reply = "0xDEADDEAD\r\n";
354 return 0;
355 }
356
357 // Note: No \r\n is needed here, the file name won't be sent to a clientls
358 m_Reply = pmcFile.GetFileName();
359 replyType = REPLY_TYPE_FILE;
360 return 0;
361}
362
363/*
364*/
365int CmdIface::cmd_rb(char *interface, unsigned int address, unsigned int num_regs)
366{
367 void *handler = get_interface(interface);
368
369 if((handler == NULL) || (num_regs > MAX_REGS_LEN))
370 {
371 m_Reply = "0xDEADDEAD\r\n";
372 return 0;
373 }
374
375 unsigned int *val = new unsigned int[num_regs];
376 int rc = readBlock(handler, address, num_regs*sizeof(unsigned int), (char*)val);
377
378 if (rc == 0)
379 {
380 std::ostringstream replyBuilder;
381 replyBuilder << std::hex;
382
383 for(unsigned int i=0; i < num_regs; i++)
384 {
385 replyBuilder << "0x" << val[i];
386 if(i < num_regs -1 )
387 {
388 replyBuilder << ' ';
389 }
390 }
391
392 replyBuilder << "\r\n";
393 m_Reply = replyBuilder.str();
394 }
395 else
396 {
397 m_Reply = "0xDEADDEAD\r\n";
398 }
399
400 delete[] val;
401 return 0;
402}
403
404/*
405*/
406int CmdIface::cmd_wb(char *interface, unsigned int address, unsigned int len, const char *block)
407{
408 void *handler = get_interface(interface);
409
410 if((handler == NULL) || (len > MAX_REGS_LEN))
411 {
412 m_Reply = "0xDEADDEAD\r\n";
413 return 0;
414 }
415
416 LOG_VERBOSE << "current WB is " << block << " length is " << len << std::endl;
417 int rc = writeBlock(handler, address, len, block);
418 if(rc == 0)
419 {
420 m_Reply = "0\r\n";
421 }
422 else
423 {
424 m_Reply = "ERROR\r\n";
425 }
426
427 return 0;
428}
429
430
431int CmdIface::cmd_interface_reset(char *interface)
432{
433 void *handler = get_interface(interface);
434 if(handler == NULL)
435 {
436 m_Reply = "0xDEADDEAD\r\n";
437 }
438 else
439 {
440 int rc = InterfaceReset(handler);
441 if(rc == 0)
442 {
443 m_Reply = "OK\r\n";
444 }
445 else
446 {
447 m_Reply = "0xDEADDEAD\r\n";
448 }
449 }
450
451 return 0;
452}
453
454
455int CmdIface::cmd_sw_reset(char *interface)
456{
457 void *handler = get_interface(interface);
458 if (handler == NULL)
459 {
460 m_Reply = "0xDEADDEAD\r\n";
461 }
462 else
463 {
464 int rc = SwReset(handler);
465 if (rc == 0)
466 {
467 m_Reply = "OK\r\n";
468 }
469 else
470 {
471 m_Reply = "0xDEADDEAD\r\n";
472 }
473 }
474
475 return 0;
476}
477
478int CmdIface::cmd_set_host_alias(char* alias)
479{
480 std::ofstream fd(UdpServer::host_details_file_name.c_str());
481 if (!fd.is_open())
482 {
483 m_Reply = "FAIL : Coudn't set the new alias: failed to open the configuration file";
484 LOG_VERBOSE << m_Reply << std::endl;
485 return -1;
486 }
487 fd << alias;
488 if (fd.bad())
489 {
490 m_Reply = "FAIL : Coudn't set the new alias: failed to write the new alias to the configuration file";
491 LOG_VERBOSE << m_Reply << std::endl;
492 fd.close();
493 return -2;
494 }
495 fd.close();
496
497 UdpServer::SetHostAlias(alias);
498 UdpServer::SendAll(UdpServer::GetHostDetails());
499 return 0;
500}
501
502
503/*
504 Execute command received from a remote client
505 The command of length 'len' is in 'buf'. 'outlen' has
506 the max output buffer size.
507 On return, 'outbuf' may have a reply to be sent to the client,
508 'outlen' should have the reply length or 0 if no reply required.
509 Returns KEEPALIVE_OK if ok, KEEPALIVE_CLOSE to close the connection, KEEPALIVE_SHUTDOWN to shutdown the server (debug mode)
510*/
511int CmdIface::do_command(const char *buf, int len)
512{
513 servercmd_t s;
514 int result = KEEPALIVE_OK;
515 replyType = REPLY_TYPE_BUFFER;
516
517 ((char*)buf)[len] = '\0'; // Make a zero-terminated string
518
519 // Parse the command
520 parse_line(buf, &s);
521 dump_parser(&s);
522
523 // Check for the parser error. Note, not all the commands in the original protocol report about errors. so we check the error
524 // for selected commands only TODO: verify the commands list reporting the error
525 if(s.cmd == CMD_OPEN_INTERFACE || s.cmd == CMD_R || s.cmd == CMD_RB || s.cmd == CMD_W || s.cmd == CMD_WB)
526 {
527 if(s.error != 0)
528 {
529 LOG_ERROR << "Command line parsing error" << std::endl;
530 m_Reply = "0xDEADDEAD\r\n"; // TODO: or should it be "dmtools_error"??
531 return result;
532 }
533 }
534
535 switch(s.cmd)
536 {
537 case CMD_GET_INTERFACES:
538 cmd_get_interfaces();
539 break;
540 case CMD_OPEN_INTERFACE:
541 cmd_open_interface(s.interface);
542 break;
543 case CMD_CLOSE_INTERFACE:
544 cmd_close_interface(s.interface);
545 break;
546 case CMD_R:
547 cmd_r(s.interface, s.address);
548 break;
549 case CMD_RB:
550 cmd_rb(s.interface, s.address, s.value);
551 break;
552 case CMD_W:
553 cmd_w(s.interface, s.address, s.value);
554 break;
555 case CMD_WB:
556 // hexdata_len is in dwords, cmd_wb works in bytes. (hence * 4)
557 cmd_wb(s.interface, s.address, s.hexdata_len * 4, (const char*)s.hexdata);
558 break;
559 case CMD_INTERFACE_RESET:
560 cmd_interface_reset(s.interface);
561 break;
562 case CMD_SW_RESET:
563 cmd_sw_reset(s.interface);
564 break;
565 case CMD_EXIT:
566 result = KEEPALIVE_CLOSE; // Terminate the connection
567 break;
568 case CMD_ALLOC_PMC:
569 cmd_alloc_pmc(s.interface, s.address, s.value);
570 break;
571 case CMD_READ_PMC:
572 cmd_read_pmc(s.interface, s.address);
573 break;
574 case CMD_READ_PMC_FILE:
575 cmd_read_pmc_file(s.address);
576 break;
577 case CMD_SET_HOST_ALIAS:
578 cmd_set_host_alias(s.interface);
579 break;
580 case CMD_COMMAND_UNKNOWN:
581 default:
582 m_Reply = "dmtools_error\r\n";
583
584 }
585 return result;
586}
587
588/*
589 Dump the parser structure, for debugging only
590*/
591void CmdIface::dump_parser(servercmd_t *s)
592{
593 if(s->error)
594 {
595 LOG_ERROR << "Parser error in comand parsing."
596 << " Error: " << s->error
597 << " Message: " << parser_error_to_string(s->error)
598 << std::endl;
599
600 return;
601 }
602
603 LOG_VERBOSE << "Parsed Command: " << command_to_string(s->cmd)
604 << " Interface: " << s->interface << std::endl;
605
606 if(s->address != (unsigned int)-1)
607 {
608 LOG_VERBOSE << "Address: " << s->address << std::endl;
609 }
610 if(s->value != (unsigned int)-1)
611 {
612 LOG_VERBOSE << "Value: " << s->value << std::endl;
613 }
614 if(s->hexdata_len)
615 {
616 for(int i=0; i < s->hexdata_len && i < MAX_REGS_LEN; i++)
617 LOG_VERBOSE << std::hex << "0x" << s->hexdata[i] << std::dec << std::endl;
618 }
619}
620
621/*
622*/
623int CmdIface::get_reply_len()
624{
625 return m_Reply.size();
626}
627
628/*
629*/
630void CmdIface::to_lower(char* string)
631{
632 for (int i = 0; string[i]; i++)
633 {
634 string[i] = tolower(string[i]);
635 }
636
637 return;
638}
639
640/*
641*/
642CmdIface::CmdIface()
643 : replyType(REPLY_TYPE_BUFFER)
644{
645}