• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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