1 /* Author: Magnus Ivarsson <magnus.ivarsson@volvo.com> */
2
3 /* to get rid of implicit function declarations */
4 #ifndef __FreeBSD__
5 /* defining this on FreeBSD hides non-standard defines that sio.c depends on */
6 #define _XOPEN_SOURCE 600
7 #endif
8 #define _GNU_SOURCE
9
10 /* build with Darwin C extensions not part of POSIX, i.e. FASYNC, SIGIO.
11 we can't use LWIP_UNIX_MACH because extensions need to be turned
12 on before any system headers (which are pulled in through cc.h)
13 are included */
14 #if defined(__APPLE__)
15 #define _DARWIN_C_SOURCE
16 #endif
17
18 #include "netif/sio.h"
19 #include "netif/fifo.h"
20 #include "lwip/debug.h"
21 #include "lwip/def.h"
22 #include "lwip/sys.h"
23 #include "lwip/arch.h"
24 #include "lwip/sio.h"
25 #include "netif/ppp/ppp_opts.h"
26
27 /* Following #undefs are here to keep compiler from issuing warnings
28 about them being double defined. (They are defined in lwip/inet.h
29 as well as the Unix #includes below.) */
30 #undef htonl
31 #undef ntohl
32 #undef htons
33 #undef ntohs
34 #undef HTONL
35 #undef NTOHL
36 #undef HTONS
37 #undef NTOHS
38
39 #include <stdlib.h>
40 #include <stdio.h>
41 #if defined(LWIP_UNIX_OPENBSD) || defined(LWIP_UNIX_MACH)
42 #include <util.h>
43 #elif defined(LWIP_UNIX_FREEBSD)
44 #include <libutil.h>
45 #endif
46 #include <termios.h>
47 #include <stdio.h>
48 #include <unistd.h>
49 #include <fcntl.h>
50 #include <signal.h>
51 #include <string.h>
52 #include <sys/signal.h>
53 #include <sys/types.h>
54
55 #ifndef LWIP_HAVE_SLIPIF
56 #define LWIP_HAVE_SLIPIF 0
57 #endif
58
59 #if (PPP_SUPPORT || LWIP_HAVE_SLIPIF) && defined(LWIP_UNIX_LINUX)
60 #include <pty.h>
61 #endif
62
63 /*#define BAUDRATE B19200 */
64 /*#define BAUDRATE B57600 */
65 #define BAUDRATE B115200
66
67 #ifndef TRUE
68 #define TRUE 1
69 #endif
70 #ifndef FALSE
71 #define FALSE 0
72 #endif
73
74 /* for all of you who don't define SIO_DEBUG in debug.h */
75 #ifndef SIO_DEBUG
76 #define SIO_DEBUG 0
77 #endif
78
79
80 /* typedef struct siostruct_t */
81 /* { */
82 /* sio_status_t *sio; */
83 /* } siostruct_t; */
84
85 /** array of ((siostruct*)netif->state)->sio structs */
86 static sio_status_t statusar[4];
87
88 #if ! (PPP_SUPPORT || LWIP_HAVE_SLIPIF)
89 /* --private-functions----------------------------------------------------------------- */
90 /**
91 * Signal handler for ttyXX0 to indicate bytes received
92 * one per interface is needed since we cannot send a instance number / pointer as callback argument (?)
93 */
signal_handler_IO_0(int status)94 static void signal_handler_IO_0( int status )
95 {
96 LWIP_UNUSED_ARG(status);
97 LWIP_DEBUGF(SIO_DEBUG, ("SigHand: rxSignal channel 0\n"));
98 fifoPut( &statusar[0].myfifo, statusar[0].fd );
99 }
100
101 /**
102 * Signal handler for ttyXX1 to indicate bytes received
103 * one per interface is needed since we cannot send a instance number / pointer as callback argument (?)
104 */
signal_handler_IO_1(int status)105 static void signal_handler_IO_1( int status )
106 {
107 LWIP_UNUSED_ARG(status);
108 LWIP_DEBUGF(SIO_DEBUG, ("SigHand: rxSignal channel 1\n"));
109 fifoPut( &statusar[1].myfifo, statusar[1].fd );
110 }
111 #endif /* ! (PPP_SUPPORT || LWIP_HAVE_SLIPIF) */
112
113 /**
114 * Initiation of serial device
115 * @param device string with the device name and path, eg. "/dev/ttyS0"
116 * @param devnum device number
117 * @param siostat status
118 * @return file handle to serial dev.
119 */
sio_init(char * device,int devnum,sio_status_t * siostat)120 static int sio_init( char * device, int devnum, sio_status_t * siostat )
121 {
122 struct termios oldtio,newtio;
123 #if ! (PPP_SUPPORT || LWIP_HAVE_SLIPIF)
124 struct sigaction saio; /* definition of signal action */
125 #endif
126 int fd;
127 LWIP_UNUSED_ARG(siostat);
128 LWIP_UNUSED_ARG(devnum);
129
130 /* open the device to be non-blocking (read will return immediately) */
131 fd = open( device, O_RDWR | O_NOCTTY | O_NONBLOCK );
132 if ( fd < 0 )
133 {
134 perror( device );
135 exit( -1 );
136 }
137
138 #if ! (PPP_SUPPORT || LWIP_HAVE_SLIPIF)
139 memset(&saio, 0, sizeof(struct sigaction));
140 /* install the signal handler before making the device asynchronous */
141 switch ( devnum )
142 {
143 case 0:
144 LWIP_DEBUGF( SIO_DEBUG, ("sioinit, signal_handler_IO_0\n") );
145 saio.sa_handler = signal_handler_IO_0;
146 break;
147 case 1:
148 LWIP_DEBUGF( SIO_DEBUG, ("sioinit, signal_handler_IO_1\n") );
149 saio.sa_handler = signal_handler_IO_1;
150 break;
151 default:
152 LWIP_DEBUGF( SIO_DEBUG,("sioinit, devnum not allowed\n") );
153 break;
154 }
155
156 sigaction( SIGIO,&saio,NULL );
157
158 /* allow the process to receive SIGIO */
159 if ( fcntl( fd, F_SETOWN, getpid( ) ) != 0)
160 {
161 perror( device );
162 exit( -1 );
163 }
164 /* Make the file descriptor asynchronous (the manual page says only
165 O_APPEND and O_NONBLOCK, will work with F_SETFL...) */
166 if ( fcntl( fd, F_SETFL, FASYNC ) != 0)
167 {
168 perror( device );
169 exit( -1 );
170 }
171 #else
172 if ( fcntl( fd, F_SETFL, 0 ) != 0)
173 {
174 perror( device );
175 exit( -1 );
176 }
177
178 #endif /* ! (PPP_SUPPORT || LWIP_HAVE_SLIPIF) */
179
180 tcgetattr( fd,&oldtio ); /* save current port settings */
181 /* set new port settings */
182 /* see 'man termios' for further settings */
183 memset(&newtio, 0, sizeof(newtio));
184 newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD | CRTSCTS;
185 newtio.c_iflag = 0;
186 newtio.c_oflag = 0;
187 newtio.c_lflag = 0; /*ECHO; */
188 newtio.c_cc[VMIN] = 1; /* Read 1 byte at a time, no timer */
189 newtio.c_cc[VTIME] = 0;
190
191 tcsetattr( fd,TCSANOW,&newtio );
192 tcflush( fd, TCIOFLUSH );
193
194 return fd;
195 }
196
197 /**
198 *
199 */
sio_speed(int fd,int speed)200 static void sio_speed( int fd, int speed )
201 {
202 struct termios oldtio,newtio;
203 /* int fd; */
204
205 LWIP_DEBUGF(SIO_DEBUG, ("sio_speed[%d]: baudcode:%d enter\n", fd, speed));
206
207 if ( fd < 0 )
208 {
209 LWIP_DEBUGF(SIO_DEBUG, ("sio_speed[%d]: fd ERROR\n", fd));
210 exit( -1 );
211 }
212
213 tcgetattr( fd,&oldtio ); /* get current port settings */
214
215 /* set new port settings
216 * see 'man termios' for further settings */
217 memset(&newtio, 0, sizeof(newtio));
218 newtio.c_cflag = speed | CS8 | CLOCAL | CREAD; /* | CRTSCTS; */
219 newtio.c_iflag = 0;
220 newtio.c_oflag = 0;
221 newtio.c_lflag = 0; /*ECHO; */
222 newtio.c_cc[VMIN] = 1; /* Read 1 byte at a time, no timer */
223 newtio.c_cc[VTIME] = 0;
224
225 tcsetattr( fd,TCSANOW,&newtio );
226 tcflush( fd, TCIOFLUSH );
227
228 LWIP_DEBUGF(SIO_DEBUG, ("sio_speed[%d]: leave\n", fd));
229 }
230
231 /* --public-functions----------------------------------------------------------------------------- */
sio_send(u8_t c,sio_status_t * siostat)232 void sio_send( u8_t c, sio_status_t * siostat )
233 {
234 /* sio_status_t * siostat = ((siostruct_t*)netif->state)->sio; */
235
236 if ( write( siostat->fd, &c, 1 ) <= 0 )
237 {
238 LWIP_DEBUGF(SIO_DEBUG, ("sio_send[%d]: write refused\n", siostat->fd));
239 }
240 }
241
sio_send_string(u8_t * str,sio_status_t * siostat)242 void sio_send_string( u8_t *str, sio_status_t * siostat )
243 {
244 /* sio_status_t * siostat = ((siostruct_t*)netif->state)->sio; */
245 int len = strlen( (const char *)str );
246
247 if ( write( siostat->fd, str, len ) <= 0 )
248 {
249 LWIP_DEBUGF(SIO_DEBUG, ("sio_send_string[%d]: write refused\n", siostat->fd));
250 }
251 LWIP_DEBUGF(SIO_DEBUG, ("sio_send_string[%d]: sent: %s\n", siostat->fd, str));
252 }
253
254
sio_flush(sio_status_t * siostat)255 void sio_flush( sio_status_t * siostat )
256 {
257 LWIP_UNUSED_ARG(siostat);
258 /* not implemented in unix as it is not needed */
259 /*sio_status_t * siostat = ((siostruct_t*)netif->state)->sio; */
260 }
261
262
263 #if ! (PPP_SUPPORT || LWIP_HAVE_SLIPIF)
264 /*u8_t sio_recv( struct netif * netif )*/
sio_recv(sio_status_t * siostat)265 u8_t sio_recv( sio_status_t * siostat )
266 {
267 /* sio_status_t * siostat = ((siostruct_t*)netif->state)->sio; */
268 return fifoGet( &(siostat->myfifo) );
269 }
270
sio_poll(sio_status_t * siostat)271 s16_t sio_poll(sio_status_t * siostat)
272 {
273 /* sio_status_t * siostat = ((siostruct_t*)netif->state)->sio;*/
274 return fifoGetNonBlock( &(siostat->myfifo) );
275 }
276
277
sio_expect_string(u8_t * str,sio_status_t * siostat)278 void sio_expect_string( u8_t *str, sio_status_t * siostat )
279 {
280 /* sio_status_t * siostat = ((siostruct_t*)netif->state)->sio;*/
281 u8_t c;
282 int finger=0;
283
284 LWIP_DEBUGF(SIO_DEBUG, ("sio_expect_string[%d]: %s\n", siostat->fd, str));
285 while ( 1 )
286 {
287 c=fifoGet( &(siostat->myfifo) );
288 LWIP_DEBUGF(SIO_DEBUG, ("_%c", c));
289 if ( c==str[finger] )
290 {
291 finger++;
292 } else if ( finger > 0 )
293 {
294 /*it might fit in the beginning? */
295 if ( str[0] == c )
296 {
297 finger = 1;
298 }
299 }
300 if ( 0 == str[finger] )
301 break; /* done, we have a match */
302 }
303 LWIP_DEBUGF(SIO_DEBUG, ("sio_expect_string[%d]: [match]\n", siostat->fd));
304 }
305 #endif /* ! (PPP_SUPPORT || LWIP_HAVE_SLIPIF) */
306
307 #if (PPP_SUPPORT || LWIP_HAVE_SLIPIF)
sio_write(sio_status_t * siostat,const u8_t * buf,u32_t size)308 u32_t sio_write(sio_status_t * siostat, const u8_t *buf, u32_t size)
309 {
310 ssize_t wsz = write( siostat->fd, buf, size );
311 return wsz < 0 ? 0 : wsz;
312 }
313
sio_read(sio_status_t * siostat,u8_t * buf,u32_t size)314 u32_t sio_read(sio_status_t * siostat, u8_t *buf, u32_t size)
315 {
316 ssize_t rsz = read( siostat->fd, buf, size );
317 return rsz < 0 ? 0 : rsz;
318 }
319
sio_read_abort(sio_status_t * siostat)320 void sio_read_abort(sio_status_t * siostat)
321 {
322 LWIP_UNUSED_ARG(siostat);
323 printf("sio_read_abort[%d]: not yet implemented for unix\n", siostat->fd);
324 }
325 #endif /* (PPP_SUPPORT || LWIP_HAVE_SLIPIF) */
326
sio_open(u8_t devnum)327 sio_fd_t sio_open(u8_t devnum)
328 {
329 char dev[20];
330
331 /* would be nice with dynamic memory alloc */
332 sio_status_t * siostate = &statusar[ devnum ];
333 /* siostruct_t * tmp; */
334
335
336 /* tmp = (siostruct_t*)(netif->state); */
337 /* tmp->sio = siostate; */
338
339 /* tmp = (siostruct_t*)(netif->state); */
340
341 /* ((sio_status_t*)(tmp->sio))->fd = 0; */
342
343 LWIP_DEBUGF(SIO_DEBUG, ("sio_open: for devnum %d\n", devnum));
344
345 #if ! (PPP_SUPPORT || LWIP_HAVE_SLIPIF)
346 fifoInit( &siostate->myfifo );
347 #endif /* ! PPP_SUPPORT */
348
349 snprintf( dev, sizeof(dev), "/dev/ttyS%d", devnum );
350
351 if ( (devnum == 1) || (devnum == 0) )
352 {
353 if ( ( siostate->fd = sio_init( dev, devnum, siostate ) ) == 0 )
354 {
355 LWIP_DEBUGF(SIO_DEBUG, ("sio_open: ERROR opening serial device dev=%s\n", dev));
356 abort( );
357 return NULL;
358 }
359 LWIP_DEBUGF(SIO_DEBUG, ("sio_open[%d]: dev=%s open.\n", siostate->fd, dev));
360 }
361 #if PPP_SUPPORT
362 else if (devnum == 2) {
363 pid_t childpid;
364 char name[256];
365 childpid = forkpty(&siostate->fd, name, NULL, NULL);
366 if(childpid < 0) {
367 perror("forkpty");
368 exit (1);
369 }
370 if(childpid == 0) {
371 execl("/usr/sbin/pppd", "pppd",
372 "ms-dns", "198.168.100.7",
373 "local", "crtscts",
374 "debug",
375 #ifdef LWIP_PPP_CHAP_TEST
376 "auth",
377 "require-chap",
378 "remotename", "lwip",
379 #else
380 "noauth",
381 #endif
382 #if LWIP_IPV6
383 "+ipv6",
384 #endif
385 "192.168.1.1:192.168.1.2",
386 NULL);
387 perror("execl pppd");
388 exit (1);
389 } else {
390 LWIP_DEBUGF(SIO_DEBUG, ("sio_open[%d]: spawned pppd pid %d on %s\n",
391 siostate->fd, childpid, name));
392 }
393
394 }
395 #endif
396 #if LWIP_HAVE_SLIPIF
397 else if (devnum == 3) {
398 pid_t childpid;
399 /* create PTY pair */
400 siostate->fd = posix_openpt(O_RDWR | O_NOCTTY);
401 if (siostate->fd < 0) {
402 perror("open pty master");
403 exit (1);
404 }
405 if (grantpt(siostate->fd) != 0) {
406 perror("grant pty master");
407 exit (1);
408 }
409 if (unlockpt(siostate->fd) != 0) {
410 perror("unlock pty master");
411 exit (1);
412 }
413 LWIP_DEBUGF(SIO_DEBUG, ("sio_open[%d]: for %s\n",
414 siostate->fd, ptsname(siostate->fd)));
415 /* fork for slattach */
416 childpid = fork();
417 if(childpid < 0) {
418 perror("fork");
419 exit (1);
420 }
421 if(childpid == 0) {
422 /* esteblish SLIP interface on host side connected to PTY slave */
423 execl("/sbin/slattach", "slattach",
424 "-d", "-v", "-L", "-p", "slip",
425 ptsname(siostate->fd),
426 NULL);
427 perror("execl slattach");
428 exit (1);
429 } else {
430 int ret;
431 char buf[1024];
432 LWIP_DEBUGF(SIO_DEBUG, ("sio_open[%d]: spawned slattach pid %d on %s\n",
433 siostate->fd, childpid, ptsname(siostate->fd)));
434 /* wait a moment for slattach startup */
435 sleep(1);
436 /* configure SLIP interface on host side as P2P interface */
437 snprintf(buf, sizeof(buf),
438 "/sbin/ifconfig sl0 mtu %d %s pointopoint %s up",
439 SLIP_MAX_SIZE, "192.168.2.1", "192.168.2.2");
440 LWIP_DEBUGF(SIO_DEBUG, ("sio_open[%d]: system(\"%s\");\n", siostate->fd, buf));
441 ret = system(buf);
442 if (ret < 0) {
443 perror("ifconfig failed");
444 exit(1);
445 }
446 }
447 }
448 #endif /* LWIP_HAVE_SLIPIF */
449 else
450 {
451 LWIP_DEBUGF(SIO_DEBUG, ("sio_open: device %s (%d) is not supported\n", dev, devnum));
452 return NULL;
453 }
454
455 return siostate;
456 }
457
458 /**
459 *
460 */
sio_change_baud(sioBaudrates baud,sio_status_t * siostat)461 void sio_change_baud( sioBaudrates baud, sio_status_t * siostat )
462 {
463 /* sio_status_t * siostat = ((siostruct_t*)netif->state)->sio;*/
464
465 LWIP_DEBUGF(SIO_DEBUG, ("sio_change_baud[%d]\n", siostat->fd));
466
467 switch ( baud )
468 {
469 case SIO_BAUD_9600:
470 sio_speed( siostat->fd, B9600 );
471 break;
472 case SIO_BAUD_19200:
473 sio_speed( siostat->fd, B19200 );
474 break;
475 case SIO_BAUD_38400:
476 sio_speed( siostat->fd, B38400 );
477 break;
478 case SIO_BAUD_57600:
479 sio_speed( siostat->fd, B57600 );
480 break;
481 case SIO_BAUD_115200:
482 sio_speed( siostat->fd, B115200 );
483 break;
484
485 default:
486 LWIP_DEBUGF(SIO_DEBUG, ("sio_change_baud[%d]: Unknown baudrate, code:%d\n",
487 siostat->fd, baud));
488 break;
489 }
490 }
491