blob: b00c2d03cd23734b87a1287a982dbab6dc334d3f [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];
Vadim Iosevich82902242018-02-13 14:07:05 +0200376
377 if (!val)
378 {
379 m_Reply = "0xDEADDEAD\r\n";
380 return 0;
381 }
382
Vadim Iosevichd50ea462017-03-30 16:19:08 +0300383 int rc = readBlock(handler, address, num_regs*sizeof(unsigned int), (char*)val);
384
385 if (rc == 0)
386 {
387 std::ostringstream replyBuilder;
388 replyBuilder << std::hex;
389
390 for(unsigned int i=0; i < num_regs; i++)
391 {
392 replyBuilder << "0x" << val[i];
393 if(i < num_regs -1 )
394 {
395 replyBuilder << ' ';
396 }
397 }
398
399 replyBuilder << "\r\n";
400 m_Reply = replyBuilder.str();
401 }
402 else
403 {
404 m_Reply = "0xDEADDEAD\r\n";
405 }
406
407 delete[] val;
408 return 0;
409}
410
411/*
412*/
413int CmdIface::cmd_wb(char *interface, unsigned int address, unsigned int len, const char *block)
414{
415 void *handler = get_interface(interface);
416
417 if((handler == NULL) || (len > MAX_REGS_LEN))
418 {
419 m_Reply = "0xDEADDEAD\r\n";
420 return 0;
421 }
422
423 LOG_VERBOSE << "current WB is " << block << " length is " << len << std::endl;
424 int rc = writeBlock(handler, address, len, block);
425 if(rc == 0)
426 {
427 m_Reply = "0\r\n";
428 }
429 else
430 {
431 m_Reply = "ERROR\r\n";
432 }
433
434 return 0;
435}
436
437
438int CmdIface::cmd_interface_reset(char *interface)
439{
440 void *handler = get_interface(interface);
441 if(handler == NULL)
442 {
443 m_Reply = "0xDEADDEAD\r\n";
444 }
445 else
446 {
447 int rc = InterfaceReset(handler);
448 if(rc == 0)
449 {
450 m_Reply = "OK\r\n";
451 }
452 else
453 {
454 m_Reply = "0xDEADDEAD\r\n";
455 }
456 }
457
458 return 0;
459}
460
461
462int CmdIface::cmd_sw_reset(char *interface)
463{
464 void *handler = get_interface(interface);
465 if (handler == NULL)
466 {
467 m_Reply = "0xDEADDEAD\r\n";
468 }
469 else
470 {
471 int rc = SwReset(handler);
472 if (rc == 0)
473 {
474 m_Reply = "OK\r\n";
475 }
476 else
477 {
478 m_Reply = "0xDEADDEAD\r\n";
479 }
480 }
481
482 return 0;
483}
484
485int CmdIface::cmd_set_host_alias(char* alias)
486{
487 std::ofstream fd(UdpServer::host_details_file_name.c_str());
488 if (!fd.is_open())
489 {
490 m_Reply = "FAIL : Coudn't set the new alias: failed to open the configuration file";
491 LOG_VERBOSE << m_Reply << std::endl;
492 return -1;
493 }
494 fd << alias;
495 if (fd.bad())
496 {
497 m_Reply = "FAIL : Coudn't set the new alias: failed to write the new alias to the configuration file";
498 LOG_VERBOSE << m_Reply << std::endl;
499 fd.close();
500 return -2;
501 }
502 fd.close();
503
504 UdpServer::SetHostAlias(alias);
505 UdpServer::SendAll(UdpServer::GetHostDetails());
506 return 0;
507}
508
509
510/*
511 Execute command received from a remote client
512 The command of length 'len' is in 'buf'. 'outlen' has
513 the max output buffer size.
514 On return, 'outbuf' may have a reply to be sent to the client,
515 'outlen' should have the reply length or 0 if no reply required.
516 Returns KEEPALIVE_OK if ok, KEEPALIVE_CLOSE to close the connection, KEEPALIVE_SHUTDOWN to shutdown the server (debug mode)
517*/
518int CmdIface::do_command(const char *buf, int len)
519{
520 servercmd_t s;
521 int result = KEEPALIVE_OK;
522 replyType = REPLY_TYPE_BUFFER;
523
524 ((char*)buf)[len] = '\0'; // Make a zero-terminated string
525
526 // Parse the command
527 parse_line(buf, &s);
528 dump_parser(&s);
529
530 // Check for the parser error. Note, not all the commands in the original protocol report about errors. so we check the error
531 // for selected commands only TODO: verify the commands list reporting the error
532 if(s.cmd == CMD_OPEN_INTERFACE || s.cmd == CMD_R || s.cmd == CMD_RB || s.cmd == CMD_W || s.cmd == CMD_WB)
533 {
534 if(s.error != 0)
535 {
536 LOG_ERROR << "Command line parsing error" << std::endl;
537 m_Reply = "0xDEADDEAD\r\n"; // TODO: or should it be "dmtools_error"??
538 return result;
539 }
540 }
541
542 switch(s.cmd)
543 {
544 case CMD_GET_INTERFACES:
545 cmd_get_interfaces();
546 break;
547 case CMD_OPEN_INTERFACE:
548 cmd_open_interface(s.interface);
549 break;
550 case CMD_CLOSE_INTERFACE:
551 cmd_close_interface(s.interface);
552 break;
553 case CMD_R:
554 cmd_r(s.interface, s.address);
555 break;
556 case CMD_RB:
557 cmd_rb(s.interface, s.address, s.value);
558 break;
559 case CMD_W:
560 cmd_w(s.interface, s.address, s.value);
561 break;
562 case CMD_WB:
563 // hexdata_len is in dwords, cmd_wb works in bytes. (hence * 4)
564 cmd_wb(s.interface, s.address, s.hexdata_len * 4, (const char*)s.hexdata);
565 break;
566 case CMD_INTERFACE_RESET:
567 cmd_interface_reset(s.interface);
568 break;
569 case CMD_SW_RESET:
570 cmd_sw_reset(s.interface);
571 break;
572 case CMD_EXIT:
573 result = KEEPALIVE_CLOSE; // Terminate the connection
574 break;
575 case CMD_ALLOC_PMC:
576 cmd_alloc_pmc(s.interface, s.address, s.value);
577 break;
578 case CMD_READ_PMC:
579 cmd_read_pmc(s.interface, s.address);
580 break;
581 case CMD_READ_PMC_FILE:
582 cmd_read_pmc_file(s.address);
583 break;
584 case CMD_SET_HOST_ALIAS:
585 cmd_set_host_alias(s.interface);
586 break;
587 case CMD_COMMAND_UNKNOWN:
588 default:
589 m_Reply = "dmtools_error\r\n";
590
591 }
592 return result;
593}
594
595/*
596 Dump the parser structure, for debugging only
597*/
598void CmdIface::dump_parser(servercmd_t *s)
599{
600 if(s->error)
601 {
602 LOG_ERROR << "Parser error in comand parsing."
603 << " Error: " << s->error
604 << " Message: " << parser_error_to_string(s->error)
605 << std::endl;
606
607 return;
608 }
609
610 LOG_VERBOSE << "Parsed Command: " << command_to_string(s->cmd)
611 << " Interface: " << s->interface << std::endl;
612
613 if(s->address != (unsigned int)-1)
614 {
615 LOG_VERBOSE << "Address: " << s->address << std::endl;
616 }
617 if(s->value != (unsigned int)-1)
618 {
619 LOG_VERBOSE << "Value: " << s->value << std::endl;
620 }
621 if(s->hexdata_len)
622 {
623 for(int i=0; i < s->hexdata_len && i < MAX_REGS_LEN; i++)
624 LOG_VERBOSE << std::hex << "0x" << s->hexdata[i] << std::dec << std::endl;
625 }
626}
627
628/*
629*/
630int CmdIface::get_reply_len()
631{
632 return m_Reply.size();
633}
634
635/*
636*/
637void CmdIface::to_lower(char* string)
638{
639 for (int i = 0; string[i]; i++)
640 {
641 string[i] = tolower(string[i]);
642 }
643
644 return;
645}
646
647/*
648*/
649CmdIface::CmdIface()
650 : replyType(REPLY_TYPE_BUFFER)
651{
652}