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