Imported Debian version 1.1.6
[debian/ipip] / slip.c
1 /* slip.c               SLIP interface unit
2  *
3  * $Id: slip.c,v 1.11 1995/03/19 17:21:06 bdale Exp $
4  *
5  * Copyright 1991, Michael Westerhof, Sun Microsystems, Inc.
6  * This software may be freely used, distributed, or modified, providing
7  * this header is not removed.
8  */
9
10 #include "ipip.h"
11
12 #include <sys/types.h>
13 #include <sys/time.h>
14 #include <sys/socket.h>
15 #include <netinet/in.h>
16 #include <netinet/in_systm.h>
17 #include <netinet/ip.h>
18 #include <netdb.h>
19 #include <fcntl.h>
20 #include <memory.h>
21 #include <stdio.h>
22 #include <string.h>
23 #ifdef __bsdi__
24 # include <stdlib.h>
25 #else
26 # include <malloc.h>
27 #endif
28 #include <errno.h>
29 #include <syslog.h>
30
31 #ifdef __bsdi__
32 #define USE_TERMIOS
33 #endif
34
35 #ifndef USE_TERMIOS
36 #ifndef USE_TERMIO
37 #define USE_SGTTY
38 #endif
39 #endif
40
41 #ifdef USE_TERMIOS
42 # include <termios.h>
43 # include <unistd.h>
44 #endif
45
46 #ifdef USE_TERMIO
47 #include <sys/termio.h>
48 #endif
49
50 #ifdef USE_SGTTY
51 #include <sgtty.h>
52 #endif
53
54 #ifndef FNDELAY
55 #define FNDELAY O_NDELAY
56 #endif
57
58 extern int errno;
59
60 #define IF_NAME "slip"          /* for use with the error checking macros */
61
62 /*
63  * Define the special characters used by SLIP
64  */
65
66 #define FEND  0xc0
67 #define FESC  0xdb
68 #define TFEND 0xdc
69 #define TFESC 0xdd
70
71 /*
72  * This is the routine that assembles a slip packet, and the private
73  * data structure we need to keep track of where we are.
74  */
75
76 static int assemble_slip();
77 struct slippy {
78         unsigned char buffer[MAX_SIZE];         /* buffer from the serial line */
79         int bcount;                             /* number of total chars in buffer */
80         int bnext;                              /* next character to process */
81         unsigned char ipacket[MAX_SIZE];        /* the packet we are assembling */
82         int ifcount;                            /* total size of assembled packet */
83         int iescaped;                           /* flag set if we are escaped */
84 };
85
86 /*
87  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
88  * open and initialize the IO interface.  Return -1 for error.
89  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
90  */
91 int slip_open(ifp)
92 struct interface *ifp;
93 {
94         int baudrate;
95 #ifdef USE_TERMIOS
96         struct termios nterm;
97 #endif
98 #ifdef USE_TERMIO
99         struct termio  nterm;
100 #endif
101 #ifdef USE_SGTTY
102         struct sgttyb  nterm;
103 #endif
104
105         CK_IFNULL(ifp);
106         CK_IFTYPE(ifp,IF_TYPE_SLIP);
107
108         if((ifp->status & IF_STAT_OPEN)) return 1;
109
110 #ifdef __bsdi__
111         /* BSDI cares about the modem control lines, so this won't ever 
112            come back unless we do the open non-blocking, then set CLOCAL. */
113         ifp->fd = open(ifp->devname, O_RDWR | O_NONBLOCK);
114 #else
115         ifp->fd = open(ifp->devname, O_RDWR);
116 #endif
117         if (ifp->fd<0) {
118                 PERR(ifp->devname);
119                 return -1;
120         }
121
122         if (fcntl(ifp->fd, F_SETFL, FNDELAY) < 0) {
123                 PERR("setting non-blocking I/O on tty device");
124                 return -1;
125         }
126
127 #ifdef USE_TERMIOS
128 #if defined(__bsdi__) || defined(linux)
129         if(tcgetattr(ifp->fd, &nterm)<0){
130 #else
131         if(ioctl(ifp->fd, TCGETS, &nterm)<0){
132 #endif /* __bsdi__ */
133 #endif
134 #ifdef USE_TERMIO
135         if(ioctl(ifp->fd, TCGETA, &nterm)<0){
136 #endif
137 #ifdef USE_SGTTY
138         if(ioctl(ifp->fd, TIOCGETP, &nterm)<0){
139 #endif
140                 PERR("fetching tty device parameters");
141                 return -1;
142         }
143
144         if(ifp->unit==50)baudrate=B50;
145         else if(ifp->unit==50)baudrate=B50;
146         else if(ifp->unit==75)baudrate=B75;
147         else if(ifp->unit==110)baudrate=B110;
148         else if(ifp->unit==134)baudrate=B134;
149         else if(ifp->unit==150)baudrate=B150;
150         else if(ifp->unit==200)baudrate=B200;
151         else if(ifp->unit==300)baudrate=B300;
152         else if(ifp->unit==600)baudrate=B600;
153         else if(ifp->unit==1200)baudrate=B1200;
154         else if(ifp->unit==1800)baudrate=B1800;
155         else if(ifp->unit==2400)baudrate=B2400;
156         else if(ifp->unit==4800)baudrate=B4800;
157         else if(ifp->unit==9600)baudrate=B9600;
158 #ifdef B19200
159         else if(ifp->unit==19200)baudrate=B19200;
160 #else
161 #ifdef EXTA
162         else if(ifp->unit==19200)baudrate=EXTA;
163 #endif
164 #endif
165 #ifdef B38400
166         else if(ifp->unit==38400)baudrate=B38400;
167 #else
168 #ifdef EXTB
169         else if(ifp->unit==38400)baudrate=EXTB;
170 #endif
171 #endif
172         else baudrate = B9600;
173
174 #ifdef USE_SGTTY
175         nterm.sg_flags = (RAW | ANYP);
176         nterm.sg_ispeed = baudrate;
177         nterm.sg_ospeed = baudrate;
178 #else
179         nterm.c_iflag = 0;
180         nterm.c_oflag = 0;
181         nterm.c_cflag = baudrate | CS8 | CREAD | CLOCAL;
182         nterm.c_lflag = 0;
183         nterm.c_cc[VMIN] = 0;
184         nterm.c_cc[VTIME] = 0;
185 #endif
186
187 #ifdef USE_TERMIOS
188 #if defined(__bsdi__) || defined(linux)
189         if(tcsetattr(ifp->fd, TCSANOW, &nterm)<0){
190 #else
191         if(ioctl(ifp->fd, TCSETS, &nterm)<0){
192 #endif /* __bsdi__ */
193 #endif
194 #ifdef USE_TERMIO
195         if(ioctl(ifp->fd, TCSETA, &nterm)<0){
196 #endif
197 #ifdef USE_SGTTY
198         if(ioctl(ifp->fd, TIOCSETP, &nterm)<0){
199 #endif
200                 PERR("setting tty device parameters");
201                 return -1;
202         }
203
204         if(ifp->private==NULL)ifp->private = malloc(sizeof(struct slippy));
205         if(ifp->private==NULL){
206                 syslog(LOG_ERR,"cannot allocate private data structure (slip)");
207                 return -1;
208         }
209
210         (void)memset(ifp->private, 0, sizeof(struct slippy));
211
212         ifp->status = IF_STAT_OPEN;
213         return 1;
214 }
215
216 /*
217  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
218  * Read data from the specified interface. Return a complete IP datagram.
219  * If the datagram is not complete, then don't return anything.
220  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
221  */
222 int slip_read(ifp, m)
223 struct interface *ifp;
224 struct message *m;
225 {
226         int n;
227         struct slippy *s;
228
229         CK_IFNULL(ifp);
230         CK_IFTYPE(ifp,IF_TYPE_SLIP);
231         CK_IFOPEN(ifp);
232         CK_MNULL(m);
233
234         s = (struct slippy *)ifp->private;
235         ifp->status &= ~IF_STAT_CALL_AGAIN;
236         m->length = 0;
237
238         for(;;){
239                 if(s->bnext >= s->bcount){      /* we need more data! */
240                         s->bnext = 0;
241                         s->bcount = 0;
242                         n = read(ifp->fd, (char *)s->buffer, MAX_SIZE);
243                         if(n==0)return 0;       /* got nothing */
244                         if(n<0){
245                                 if(errno==EINTR)return 0;       /* SIGHUP! */
246                                 if(errno==EWOULDBLOCK)return 0; /* got nothing */
247                                 PERR("read from tty device");
248                                 return -1;
249                         }
250                         s->bcount = n;
251                 }
252
253                 n = assemble_slip(s, s->buffer[s->bnext]);
254                 s->bnext++;
255
256                 if(n > 0){
257                         (void)memcpy((char *)m->msg, (char *)s->ipacket, n);
258                         m->length = n;
259                         if(s->bnext < s->bcount)
260                                 ifp->status |= IF_STAT_CALL_AGAIN;
261                         return n;
262                 }
263         }
264 }
265
266 /*
267  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
268  * write data from to the specified interface. Return as soon as possible.
269  * The buffer provided will be a complete IP datagram.
270  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
271  */
272
273 #define SLIPEMIT(x) if(ofcount<MAX_SIZE*2){*ofptr=(x);ofptr++;ofcount++;}
274
275 int slip_send(ifp, m)
276 struct interface *ifp;
277 struct message *m;
278 {
279         int n, i, ofcount;
280         unsigned char opacket[MAX_SIZE*2], *ofptr, *mptr;
281
282         CK_IFNULL(ifp);
283         CK_IFTYPE(ifp,IF_TYPE_SLIP);
284         CK_IFOPEN(ifp);
285         CK_MNULL(m);
286
287         if(m->length<=0)return 0;
288
289         ofptr = opacket;
290         ofcount = 0;
291         mptr = m->msg;
292
293         SLIPEMIT(FEND);
294
295         for(i=0;i<m->length;i++,mptr++){
296                 if(*mptr==FEND){
297                         SLIPEMIT(FESC);
298                         SLIPEMIT(TFEND);
299                 }else if (*mptr==FESC){
300                         SLIPEMIT(FESC);
301                         SLIPEMIT(TFESC);
302                 }else {
303                         SLIPEMIT(*mptr);
304                 }
305         }
306
307         SLIPEMIT(FEND);
308
309 /*
310  * WARNING!  It is possible for this write to actually write less data
311  * than expected if the system has, for example, no buffer space left.
312  * We ignore the error (just increment the write overrun counter),
313  * drop the current packet, and expect that the higher level protocols
314  * will recover.
315  *
316  * If we got an "interrupted system call" error we print the diagnostic
317  * and continue.  (the packet gets dropped as above).
318  */
319         n = write(ifp->fd, (char *)opacket, ofcount);
320         if(n<0){
321                 syslog(LOG_ERR,"slip_send(): %s",strerror(errno));
322                 if((errno==EINTR) || (errno==EAGAIN)) return 0;
323                 return -1;
324         }
325         if(n < ofcount)ifp->out_overruns++;
326         return n;
327 }
328
329 /*
330  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
331  * take a character and assemble it into the buffer.  Return the length
332  * of the completed packet, 0 if not yet completed.  Packet can be found
333  * in the private buffer...
334  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
335  */
336 static int
337 assemble_slip(s, c)
338 struct slippy *s;
339 unsigned char c;
340 {
341         int n;
342
343         if(c==FEND){
344                 n = s->ifcount;
345                 s->ifcount = 0;
346                 s->iescaped = 0;
347                 return n;
348         }
349
350         if(c==FESC){
351                 s->iescaped=1;
352                 return 0;
353         }
354
355         if(s->iescaped){
356                 if(c==TFEND)c = FEND;
357                 if(c==TFESC)c = FESC;
358                 s->iescaped = 0;
359         }
360         if(s->ifcount < MAX_SIZE){
361                 s->ipacket[s->ifcount] = c;
362                 s->ifcount++;
363         }
364         return 0;
365 }