textual
[RRG-proxmark3.git] / client / src / uart / uart_posix.c
blob4a41b7958183de0acb3a68836adcfaa74bcf62ed
1 /*
2 * Generic uart / rs232/ serial port library
4 * Copyright (c) 2013, Roel Verdult
5 * Copyright (c) 2018 Google
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the copyright holders nor the
16 * names of its contributors may be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * @file uart_posix.c
32 * This version of the library has functionality removed which was not used by
33 * proxmark3 project.
36 // Test if we are dealing with posix operating systems
37 #ifndef _WIN32
38 #define _DEFAULT_SOURCE
40 #include "uart.h"
42 #include <stdio.h>
43 #include <string.h>
44 #include <stdlib.h>
45 #include <termios.h>
46 #include <sys/ioctl.h>
47 #include <unistd.h>
48 #include <fcntl.h>
49 #include <netinet/tcp.h>
50 #include <netdb.h>
51 #include <sys/socket.h>
52 #include <sys/un.h>
54 #ifdef HAVE_BLUEZ
55 #include <bluetooth/bluetooth.h>
56 #include <bluetooth/rfcomm.h>
57 #endif
59 #include "comms.h"
60 #include "ui.h"
62 // Taken from https://github.com/unbit/uwsgi/commit/b608eb1772641d525bfde268fe9d6d8d0d5efde7
63 #ifndef SOL_TCP
64 # define SOL_TCP IPPROTO_TCP
65 #endif
67 typedef struct termios term_info;
68 typedef struct {
69 int fd; // Serial port file descriptor
70 term_info tiOld; // Terminal info before using the port
71 term_info tiNew; // Terminal info during the transaction
72 } serial_port_unix;
74 // see pm3_cmd.h
75 struct timeval timeout = {
76 .tv_sec = 0, // 0 second
77 .tv_usec = UART_FPC_CLIENT_RX_TIMEOUT_MS * 1000
80 static uint32_t newtimeout_value = 0;
81 static bool newtimeout_pending = false;
83 int uart_reconfigure_timeouts(uint32_t value) {
84 newtimeout_value = value;
85 newtimeout_pending = true;
86 return PM3_SUCCESS;
89 serial_port uart_open(const char *pcPortName, uint32_t speed) {
90 serial_port_unix *sp = calloc(sizeof(serial_port_unix), sizeof(uint8_t));
92 if (sp == 0) {
93 PrintAndLogEx(ERR, "UART failed to allocate memory");
94 return INVALID_SERIAL_PORT;
97 // init timeouts
98 timeout.tv_usec = UART_FPC_CLIENT_RX_TIMEOUT_MS * 1000;
100 char *prefix = strdup(pcPortName);
101 if (prefix == NULL) {
102 PrintAndLogEx(ERR, "error: malloc");
103 free(sp);
104 return INVALID_SERIAL_PORT;
106 str_lower(prefix);
108 if (memcmp(prefix, "tcp:", 4) == 0) {
109 free(prefix);
111 if (strlen(pcPortName) <= 4) {
112 free(sp);
113 return INVALID_SERIAL_PORT;
116 struct addrinfo *addr = NULL, *rp;
118 char *addrstr = strdup(pcPortName + 4);
119 if (addrstr == NULL) {
120 PrintAndLogEx(ERR, "error: malloc");
121 free(sp);
122 return INVALID_SERIAL_PORT;
125 timeout.tv_usec = UART_TCP_CLIENT_RX_TIMEOUT_MS * 1000;
127 char *colon = strrchr(addrstr, ':');
128 const char *portstr;
129 if (colon) {
130 portstr = colon + 1;
131 *colon = '\0';
132 } else {
133 portstr = "18888";
136 struct addrinfo info;
138 memset(&info, 0, sizeof(info));
140 info.ai_socktype = SOCK_STREAM;
142 int s = getaddrinfo(addrstr, portstr, &info, &addr);
143 if (s != 0) {
144 PrintAndLogEx(ERR, "error: getaddrinfo: %s", gai_strerror(s));
145 freeaddrinfo(addr);
146 free(addrstr);
147 free(sp);
148 return INVALID_SERIAL_PORT;
151 int sfd;
152 for (rp = addr; rp != NULL; rp = rp->ai_next) {
153 sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
155 if (sfd == -1)
156 continue;
158 if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
159 break;
161 close(sfd);
164 if (rp == NULL) { /* No address succeeded */
165 PrintAndLogEx(ERR, "error: Could not connect");
166 freeaddrinfo(addr);
167 free(addrstr);
168 free(sp);
169 return INVALID_SERIAL_PORT;
172 freeaddrinfo(addr);
173 free(addrstr);
175 sp->fd = sfd;
177 int one = 1;
178 int res = setsockopt(sp->fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one));
179 if (res != 0) {
180 free(sp);
181 return INVALID_SERIAL_PORT;
183 return sp;
186 if (memcmp(prefix, "bt:", 3) == 0) {
187 free(prefix);
189 #ifdef HAVE_BLUEZ
190 if (strlen(pcPortName) != 20) {
191 free(sp);
192 return INVALID_SERIAL_PORT;
195 char *addrstr = strndup(pcPortName + 3, 17);
196 if (addrstr == NULL) {
197 PrintAndLogEx(ERR, "error: malloc");
198 free(sp);
199 return INVALID_SERIAL_PORT;
202 struct sockaddr_rc addr = { 0 };
203 addr.rc_family = AF_BLUETOOTH;
204 addr.rc_channel = (uint8_t) 1;
205 if (str2ba(addrstr, &addr.rc_bdaddr) != 0) {
206 PrintAndLogEx(ERR, "Invalid Bluetooth MAC address " _RED_("%s"), addrstr);
207 free(addrstr);
208 free(sp);
209 return INVALID_SERIAL_PORT;
211 int sfd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
212 if (sfd == -1) {
213 PrintAndLogEx(ERR, "Error opening Bluetooth socket");
214 free(addrstr);
215 free(sp);
216 return INVALID_SERIAL_PORT;
218 if (connect(sfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
219 PrintAndLogEx(ERR, "Error: cannot connect device " _YELLOW_("%s") " over Bluetooth", addrstr);
220 close(sfd);
221 free(addrstr);
222 free(sp);
223 return INVALID_SERIAL_PORT;
226 sp->fd = sfd;
227 return sp;
228 #else // HAVE_BLUEZ
229 PrintAndLogEx(ERR, "Sorry, this client doesn't support native Bluetooth addresses");
230 free(sp);
231 return INVALID_SERIAL_PORT;
232 #endif // HAVE_BLUEZ
234 // The socket for abstract namespace implement.
235 // Is local socket buffer, not a TCP or any net connection!
236 // so, you can't connect with address like: 127.0.0.1, or any IP
237 // see http://man7.org/linux/man-pages/man7/unix.7.html
238 if (memcmp(prefix, "socket:", 7) == 0) {
239 free(prefix);
241 if (strlen(pcPortName) <= 7) {
242 free(sp);
243 return INVALID_SERIAL_PORT;
246 // we must use max timeout!
247 timeout.tv_usec = UART_TCP_CLIENT_RX_TIMEOUT_MS * 1000;
249 size_t servernameLen = (strlen(pcPortName) - 7) + 1;
250 char serverNameBuf[servernameLen];
251 memset(serverNameBuf, '\0', servernameLen);
252 for (int i = 7, j = 0; j < servernameLen; ++i, ++j) {
253 serverNameBuf[j] = pcPortName[i];
255 serverNameBuf[servernameLen - 1] = '\0';
257 int localsocket, len;
258 struct sockaddr_un remote;
260 remote.sun_path[0] = '\0'; // abstract namespace
261 strcpy(remote.sun_path + 1, serverNameBuf);
262 remote.sun_family = AF_LOCAL;
263 int nameLen = strlen(serverNameBuf);
264 len = 1 + nameLen + offsetof(struct sockaddr_un, sun_path);
266 if ((localsocket = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1) {
267 free(sp);
268 return INVALID_SERIAL_PORT;
271 if (connect(localsocket, (struct sockaddr *) &remote, len) == -1) {
272 close(localsocket);
273 free(sp);
274 return INVALID_SERIAL_PORT;
277 sp->fd = localsocket;
278 return sp;
281 free(prefix);
283 sp->fd = open(pcPortName, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
284 if (sp->fd == -1) {
285 uart_close(sp);
286 return INVALID_SERIAL_PORT;
289 // Finally figured out a way to claim a serial port interface under unix
290 // We just try to set a (advisory) lock on the file descriptor
291 struct flock fl;
292 fl.l_type = F_WRLCK;
293 fl.l_whence = SEEK_SET;
294 fl.l_start = 0;
295 fl.l_len = 0;
296 fl.l_pid = getpid();
298 // Does the system allows us to place a lock on this file descriptor
299 if (fcntl(sp->fd, F_SETLK, &fl) == -1) {
300 // A conflicting lock is held by another process
301 free(sp);
302 return CLAIMED_SERIAL_PORT;
305 // Try to retrieve the old (current) terminal info struct
306 if (tcgetattr(sp->fd, &sp->tiOld) == -1) {
307 uart_close(sp);
308 return INVALID_SERIAL_PORT;
311 // Duplicate the (old) terminal info struct
312 sp->tiNew = sp->tiOld;
314 // Configure the serial port
315 sp->tiNew.c_cflag = CS8 | CLOCAL | CREAD;
316 sp->tiNew.c_iflag = IGNPAR;
317 sp->tiNew.c_oflag = 0;
318 sp->tiNew.c_lflag = 0;
320 // Block until n bytes are received
321 sp->tiNew.c_cc[VMIN] = 0;
322 // Block until a timer expires (n * 100 mSec.)
323 sp->tiNew.c_cc[VTIME] = 0;
325 // Try to set the new terminal info struct
326 if (tcsetattr(sp->fd, TCSANOW, &sp->tiNew) == -1) {
327 uart_close(sp);
328 return INVALID_SERIAL_PORT;
331 // Flush all lingering data that may exist
332 tcflush(sp->fd, TCIOFLUSH);
334 if (!uart_set_speed(sp, speed)) {
335 // try fallback automatically
336 speed = 115200;
337 if (!uart_set_speed(sp, speed)) {
338 uart_close(sp);
339 PrintAndLogEx(ERR, "UART error while setting baudrate");
340 return INVALID_SERIAL_PORT;
343 conn.uart_speed = uart_get_speed(sp);
344 return sp;
347 void uart_close(const serial_port sp) {
348 serial_port_unix *spu = (serial_port_unix *)sp;
349 tcflush(spu->fd, TCIOFLUSH);
350 tcsetattr(spu->fd, TCSANOW, &(spu->tiOld));
351 struct flock fl;
352 fl.l_type = F_UNLCK;
353 fl.l_whence = SEEK_SET;
354 fl.l_start = 0;
355 fl.l_len = 0;
356 fl.l_pid = getpid();
358 // Does the system allows us to place a lock on this file descriptor
359 int err = fcntl(spu->fd, F_SETLK, &fl);
360 if (err == -1) {
361 //silent error message as it can be called from uart_open failing modes, e.g. when waiting for port to appear
362 //PrintAndLogEx(ERR, "UART error while closing port");
364 close(spu->fd);
365 free(sp);
368 int uart_receive(const serial_port sp, uint8_t *pbtRx, uint32_t pszMaxRxLen, uint32_t *pszRxLen) {
369 uint32_t byteCount; // FIONREAD returns size on 32b
370 fd_set rfds;
371 struct timeval tv;
373 if (newtimeout_pending) {
374 timeout.tv_usec = newtimeout_value * 1000;
375 newtimeout_pending = false;
377 // Reset the output count
378 *pszRxLen = 0;
379 do {
380 // Reset file descriptor
381 FD_ZERO(&rfds);
382 FD_SET(((serial_port_unix *)sp)->fd, &rfds);
383 tv = timeout;
384 int res = select(((serial_port_unix *)sp)->fd + 1, &rfds, NULL, NULL, &tv);
386 // Read error
387 if (res < 0) {
388 return PM3_EIO;
391 // Read time-out
392 if (res == 0) {
393 if (*pszRxLen == 0) {
394 // We received no data
395 return PM3_ENODATA;
396 } else {
397 // We received some data, but nothing more is available
398 return PM3_SUCCESS;
402 // Retrieve the count of the incoming bytes
403 res = ioctl(((serial_port_unix *)sp)->fd, FIONREAD, &byteCount);
404 // PrintAndLogEx(ERR, "UART:: RX ioctl res %d byteCount %u", res, byteCount);
405 if (res < 0) return PM3_ENOTTY;
407 // Cap the number of bytes, so we don't overrun the buffer
408 if (pszMaxRxLen - (*pszRxLen) < byteCount) {
409 // PrintAndLogEx(ERR, "UART:: RX prevent overrun (have %u, need %u)", pszMaxRxLen - (*pszRxLen), byteCount);
410 byteCount = pszMaxRxLen - (*pszRxLen);
413 // There is something available, read the data
414 res = read(((serial_port_unix *)sp)->fd, pbtRx + (*pszRxLen), byteCount);
416 // Stop if the OS has some troubles reading the data
417 if (res <= 0) {
418 return PM3_EIO;
421 *pszRxLen += res;
423 if (*pszRxLen == pszMaxRxLen) {
424 // We have all the data we wanted.
425 return PM3_SUCCESS;
427 } while (byteCount);
429 return PM3_SUCCESS;
432 int uart_send(const serial_port sp, const uint8_t *pbtTx, const uint32_t len) {
433 uint32_t pos = 0;
434 fd_set rfds;
435 struct timeval tv;
437 while (pos < len) {
438 // Reset file descriptor
439 FD_ZERO(&rfds);
440 FD_SET(((serial_port_unix *)sp)->fd, &rfds);
441 tv = timeout;
442 int res = select(((serial_port_unix *)sp)->fd + 1, NULL, &rfds, NULL, &tv);
444 // Write error
445 if (res < 0) {
446 PrintAndLogEx(ERR, "UART:: write error (%d)", res);
447 return PM3_ENOTTY;
450 // Write time-out
451 if (res == 0) {
452 PrintAndLogEx(ERR, "UART:: write time-out");
453 return PM3_ETIMEOUT;
456 // Send away the bytes
457 res = write(((serial_port_unix *)sp)->fd, pbtTx + pos, len - pos);
459 // Stop if the OS has some troubles sending the data
460 if (res <= 0)
461 return PM3_EIO;
463 pos += res;
465 return PM3_SUCCESS;
468 bool uart_set_speed(serial_port sp, const uint32_t uiPortSpeed) {
469 const serial_port_unix *spu = (serial_port_unix *)sp;
470 speed_t stPortSpeed;
471 switch (uiPortSpeed) {
472 case 0:
473 stPortSpeed = B0;
474 break;
475 case 50:
476 stPortSpeed = B50;
477 break;
478 case 75:
479 stPortSpeed = B75;
480 break;
481 case 110:
482 stPortSpeed = B110;
483 break;
484 case 134:
485 stPortSpeed = B134;
486 break;
487 case 150:
488 stPortSpeed = B150;
489 break;
490 case 300:
491 stPortSpeed = B300;
492 break;
493 case 600:
494 stPortSpeed = B600;
495 break;
496 case 1200:
497 stPortSpeed = B1200;
498 break;
499 case 1800:
500 stPortSpeed = B1800;
501 break;
502 case 2400:
503 stPortSpeed = B2400;
504 break;
505 case 4800:
506 stPortSpeed = B4800;
507 break;
508 case 9600:
509 stPortSpeed = B9600;
510 break;
511 case 19200:
512 stPortSpeed = B19200;
513 break;
514 case 38400:
515 stPortSpeed = B38400;
516 break;
517 # ifdef B57600
518 case 57600:
519 stPortSpeed = B57600;
520 break;
521 # endif
522 # ifdef B115200
523 case 115200:
524 stPortSpeed = B115200;
525 break;
526 # endif
527 # ifdef B230400
528 case 230400:
529 stPortSpeed = B230400;
530 break;
531 # endif
532 # ifdef B460800
533 case 460800:
534 stPortSpeed = B460800;
535 break;
536 # endif
537 # ifdef B921600
538 case 921600:
539 stPortSpeed = B921600;
540 break;
541 # endif
542 # ifdef B1382400
543 case 1382400:
544 stPortSpeed = B1382400;
545 break;
546 # endif
548 default:
549 return false;
552 struct termios ti;
553 if (tcgetattr(spu->fd, &ti) == -1)
554 return false;
556 // Set port speed (Input and Output)
557 cfsetispeed(&ti, stPortSpeed);
558 cfsetospeed(&ti, stPortSpeed);
559 bool result = tcsetattr(spu->fd, TCSANOW, &ti) != -1;
560 if (result)
561 conn.uart_speed = uiPortSpeed;
562 return result;
565 uint32_t uart_get_speed(const serial_port sp) {
566 struct termios ti;
567 uint32_t uiPortSpeed;
568 const serial_port_unix *spu = (serial_port_unix *)sp;
570 if (tcgetattr(spu->fd, &ti) == -1)
571 return 0;
573 // Set port speed (Input)
574 speed_t stPortSpeed = cfgetispeed(&ti);
575 switch (stPortSpeed) {
576 case B0:
577 uiPortSpeed = 0;
578 break;
579 case B50:
580 uiPortSpeed = 50;
581 break;
582 case B75:
583 uiPortSpeed = 75;
584 break;
585 case B110:
586 uiPortSpeed = 110;
587 break;
588 case B134:
589 uiPortSpeed = 134;
590 break;
591 case B150:
592 uiPortSpeed = 150;
593 break;
594 case B300:
595 uiPortSpeed = 300;
596 break;
597 case B600:
598 uiPortSpeed = 600;
599 break;
600 case B1200:
601 uiPortSpeed = 1200;
602 break;
603 case B1800:
604 uiPortSpeed = 1800;
605 break;
606 case B2400:
607 uiPortSpeed = 2400;
608 break;
609 case B4800:
610 uiPortSpeed = 4800;
611 break;
612 case B9600:
613 uiPortSpeed = 9600;
614 break;
615 case B19200:
616 uiPortSpeed = 19200;
617 break;
618 case B38400:
619 uiPortSpeed = 38400;
620 break;
621 # ifdef B57600
622 case B57600:
623 uiPortSpeed = 57600;
624 break;
625 # endif
626 # ifdef B115200
627 case B115200:
628 uiPortSpeed = 115200;
629 break;
630 # endif
631 # ifdef B230400
632 case B230400:
633 uiPortSpeed = 230400;
634 break;
635 # endif
636 # ifdef B460800
637 case B460800:
638 uiPortSpeed = 460800;
639 break;
640 # endif
641 # ifdef B921600
642 case B921600:
643 uiPortSpeed = 921600;
644 break;
645 # endif
646 default:
647 return 0;
649 return uiPortSpeed;
651 #endif