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