]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ppp/i4b.c
This commit was generated by cvs2svn to compensate for changes in r92422,
[FreeBSD/FreeBSD.git] / usr.sbin / ppp / i4b.c
1 /*-
2  * Copyright (c) 1999 Brian Somers <brian@Awfulhak.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #include <sys/param.h>
30
31 #include <sys/un.h>
32 #if defined(__OpenBSD__) || defined(__NetBSD__)
33 #include <sys/ioctl.h>
34 #endif
35
36 #include <errno.h>
37 #include <fcntl.h>
38 #ifdef __FreeBSD__
39 #include <machine/i4b_ioctl.h>
40 #include <machine/i4b_rbch_ioctl.h>
41 #else
42 #ifdef __NetBSD__
43 #include <netisdn/i4b_ioctl.h>
44 #include <netisdn/i4b_rbch_ioctl.h>
45 #else
46 #include <i4b/i4b_ioctl.h>
47 #include <i4b/i4b_rbch_ioctl.h>
48 #endif
49 #endif
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <sysexits.h>
54 #include <sys/uio.h>
55 #include <termios.h>
56 #include <unistd.h>
57
58 #include "layer.h"
59 #include "defs.h"
60 #include "mbuf.h"
61 #include "log.h"
62 #include "timer.h"
63 #include "lqr.h"
64 #include "hdlc.h"
65 #include "throughput.h"
66 #include "fsm.h"
67 #include "lcp.h"
68 #include "ccp.h"
69 #include "link.h"
70 #include "async.h"
71 #include "descriptor.h"
72 #include "physical.h"
73 #include "mp.h"
74 #include "chat.h"
75 #include "auth.h"
76 #include "chap.h"
77 #include "cbcp.h"
78 #include "datalink.h"
79 #include "main.h"
80 #include "i4b.h"
81
82 #define Online(dev)     ((dev)->mbits & TIOCM_CD)
83
84 struct i4bdevice {
85   struct device dev;            /* What struct physical knows about */
86   struct pppTimer Timer;        /* CD checks */
87   int mbits;                    /* Current DCD status */
88   int carrier_seconds;          /* seconds before CD is *required* */
89 };
90
91 #define device2i4b(d) ((d)->type == I4B_DEVICE ? (struct i4bdevice *)d : NULL)
92
93 int
94 i4b_DeviceSize(void)
95 {
96   return sizeof(struct i4bdevice);
97 }
98
99 /*
100  * i4b_Timeout() watches the DCD signal and mentions it if it's status
101  * changes.
102  */
103 static void
104 i4b_Timeout(void *data)
105 {
106   struct physical *p = data;
107   struct i4bdevice *dev = device2i4b(p->handler);
108   int ombits, change;
109
110   timer_Stop(&dev->Timer);
111   dev->Timer.load = SECTICKS;           /* Once a second please */
112   timer_Start(&dev->Timer);
113   ombits = dev->mbits;
114
115   if (p->fd >= 0) {
116     if (ioctl(p->fd, TIOCMGET, &dev->mbits) < 0) {
117       log_Printf(LogPHASE, "%s: ioctl error (%s)!\n", p->link.name,
118                  strerror(errno));
119       datalink_Down(p->dl, CLOSE_NORMAL);
120       timer_Stop(&dev->Timer);
121       return;
122     }
123   } else
124     dev->mbits = 0;
125
126   if (ombits == -1) {
127     /* First time looking for carrier */
128     if (Online(dev))
129       log_Printf(LogPHASE, "%s: %s: CD detected\n", p->link.name, p->name.full);
130     else if (++dev->carrier_seconds >= dev->dev.cd.delay) {
131       log_Printf(LogPHASE, "%s: %s: No carrier"
132                  " (increase ``set cd'' from %d ?)\n",
133                  p->link.name, p->name.full, dev->dev.cd.delay);
134       timer_Stop(&dev->Timer);
135       /* i4b_AwaitCarrier() will notice */
136     } else {
137       /* Keep waiting */
138       log_Printf(LogDEBUG, "%s: %s: Still no carrier (%d/%d)\n",
139                  p->link.name, p->name.full, dev->carrier_seconds,
140                  dev->dev.cd.delay);
141       dev->mbits = -1;
142     }
143   } else {
144     change = ombits ^ dev->mbits;
145     if (change & TIOCM_CD) {
146       if (dev->mbits & TIOCM_CD)
147         log_Printf(LogDEBUG, "%s: offline -> online\n", p->link.name);
148       else {
149         log_Printf(LogDEBUG, "%s: online -> offline\n", p->link.name);
150         log_Printf(LogPHASE, "%s: Carrier lost\n", p->link.name);
151         datalink_Down(p->dl, CLOSE_NORMAL);
152         timer_Stop(&dev->Timer);
153       }
154     } else
155       log_Printf(LogDEBUG, "%s: Still %sline\n", p->link.name,
156                  Online(dev) ? "on" : "off");
157   }
158 }
159
160 static void
161 i4b_StartTimer(struct physical *p)
162 {
163   struct i4bdevice *dev = device2i4b(p->handler);
164
165   timer_Stop(&dev->Timer);
166   dev->Timer.load = SECTICKS;
167   dev->Timer.func = i4b_Timeout;
168   dev->Timer.name = "i4b CD";
169   dev->Timer.arg = p;
170   log_Printf(LogDEBUG, "%s: Using i4b_Timeout [%p]\n",
171              p->link.name, i4b_Timeout);
172   timer_Start(&dev->Timer);
173 }
174
175 static int
176 i4b_AwaitCarrier(struct physical *p)
177 {
178   struct i4bdevice *dev = device2i4b(p->handler);
179
180   if (dev->mbits == -1) {
181     if (dev->Timer.state == TIMER_STOPPED) {
182       dev->carrier_seconds = 0;
183       i4b_StartTimer(p);
184     }
185     return CARRIER_PENDING;                     /* Not yet ! */
186   }
187
188   return Online(dev) ? CARRIER_OK : CARRIER_LOST;
189 }
190
191 static int
192 i4b_Raw(struct physical *p)
193 {
194   int oldflag;
195
196   log_Printf(LogDEBUG, "%s: Entering i4b_Raw\n", p->link.name);
197
198   oldflag = fcntl(p->fd, F_GETFL, 0);
199   if (oldflag < 0)
200     return 0;
201   fcntl(p->fd, F_SETFL, oldflag | O_NONBLOCK);
202
203   return 1;
204 }
205
206 static void
207 i4b_Offline(struct physical *p)
208 {
209   struct i4bdevice *dev = device2i4b(p->handler);
210
211   if (p->fd >= 0) {
212     timer_Stop(&dev->Timer);
213     if (Online(dev)) {
214       int dummy;
215
216       dummy = 1;
217       ioctl(p->fd, TIOCCDTR, &dummy);
218     }
219   }
220 }
221
222 static void
223 i4b_Cooked(struct physical *p)
224 {
225   int oldflag;
226
227   i4b_Offline(p);       /* In case of emergency close()s */
228
229   if ((oldflag = fcntl(p->fd, F_GETFL, 0)) != -1)
230     fcntl(p->fd, F_SETFL, oldflag & ~O_NONBLOCK);
231 }
232
233 static void
234 i4b_StopTimer(struct physical *p)
235 {
236   struct i4bdevice *dev = device2i4b(p->handler);
237
238   timer_Stop(&dev->Timer);
239 }
240
241 static void
242 i4b_Free(struct physical *p)
243 {
244   struct i4bdevice *dev = device2i4b(p->handler);
245
246   i4b_Offline(p);       /* In case of emergency close()s */
247   free(dev);
248 }
249
250 static int
251 i4b_Speed(struct physical *p)
252 {
253   struct termios ios;
254   int ret;
255
256   if (tcgetattr(p->fd, &ios) == -1 ||
257       (ret = SpeedToInt(cfgetispeed(&ios))) == 0)
258     ret = 64000;
259
260   return ret;
261 }
262
263 static const char *
264 i4b_OpenInfo(struct physical *p)
265 {
266   struct i4bdevice *dev = device2i4b(p->handler);
267   static char buf[26];
268
269   if (Online(dev))
270     snprintf(buf, sizeof buf, "carrier took %ds", dev->carrier_seconds);
271   else
272     *buf = '\0';
273
274   return buf;
275 }
276
277 static void
278 i4b_device2iov(struct device *d, struct iovec *iov, int *niov,
279                int maxiov, int *auxfd, int *nauxfd)
280 {
281   struct i4bdevice *dev = device2i4b(d);
282   int sz = physical_MaxDeviceSize();
283
284   iov[*niov].iov_base = realloc(d, sz);
285   if (iov[*niov].iov_base == NULL) {
286     log_Printf(LogALERT, "Failed to allocate memory: %d\n", sz);
287     AbortProgram(EX_OSERR);
288   }
289   iov[*niov].iov_len = sz;
290   (*niov)++;
291
292   if (dev->Timer.state != TIMER_STOPPED) {
293     timer_Stop(&dev->Timer);
294     dev->Timer.state = TIMER_RUNNING;
295   }
296 }
297
298 static struct device basei4bdevice = {
299   I4B_DEVICE,
300   "i4b",
301   0,
302   { CD_REQUIRED, DEF_I4BCDDELAY },
303   i4b_AwaitCarrier,
304   NULL,
305   i4b_Raw,
306   i4b_Offline,
307   i4b_Cooked,
308   i4b_StopTimer,
309   i4b_Free,
310   NULL,
311   NULL,
312   i4b_device2iov,
313   i4b_Speed,
314   i4b_OpenInfo
315 };
316
317 struct device *
318 i4b_iov2device(int type, struct physical *p, struct iovec *iov, int *niov,
319                int maxiov, int *auxfd, int *nauxfd)
320 {
321   if (type == I4B_DEVICE) {
322     struct i4bdevice *dev = (struct i4bdevice *)iov[(*niov)++].iov_base;
323
324     dev = realloc(dev, sizeof *dev);    /* Reduce to the correct size */
325     if (dev == NULL) {
326       log_Printf(LogALERT, "Failed to allocate memory: %d\n",
327                  (int)(sizeof *dev));
328       AbortProgram(EX_OSERR);
329     }
330
331     /* Refresh function pointers etc */
332     memcpy(&dev->dev, &basei4bdevice, sizeof dev->dev);
333
334     physical_SetupStack(p, dev->dev.name, PHYSICAL_NOFORCE);
335     if (dev->Timer.state != TIMER_STOPPED) {
336       dev->Timer.state = TIMER_STOPPED;
337       p->handler = &dev->dev;           /* For the benefit of StartTimer */
338       i4b_StartTimer(p);
339     }
340     return &dev->dev;
341   }
342
343   return NULL;
344 }
345
346 struct device *
347 i4b_Create(struct physical *p)
348 {
349   struct i4bdevice *dev;
350   int oldflag, dial;
351   msg_vr_req_t req;
352   telno_t number;
353
354   if (p->fd < 0 || ioctl(p->fd, I4B_RBCH_VR_REQ, &req))
355     /* Don't want this */
356     return NULL;
357
358   /*
359    * We don't bother validating the version.... all versions of i4b that
360    * support I4B_RBCH_VR_REQ are fair game :-)
361    */
362
363   if (*p->name.full == '\0') {
364     physical_SetDevice(p, ttyname(p->fd));
365     log_Printf(LogDEBUG, "%s: Input is an i4b version %d.%d.%d isdn "
366                "device (%s)\n", p->link.name, req.version, req.release,
367                req.step, p->name.full);
368     dial = 0;
369   } else {
370     log_Printf(LogDEBUG, "%s: Opened %s (i4b version %d.%d.%d)\n",
371                p->link.name, p->name.full, req.version, req.release, req.step);
372     dial = 1;
373   }
374
375   /* We're gonna return an i4bdevice (unless something goes horribly wrong) */
376
377   if ((dev = malloc(sizeof *dev)) == NULL) {
378     /* Complete failure - parent doesn't continue trying to ``create'' */
379     close(p->fd);
380     p->fd = -1;
381     return NULL;
382   }
383
384   memcpy(&dev->dev, &basei4bdevice, sizeof dev->dev);
385   memset(&dev->Timer, '\0', sizeof dev->Timer);
386   dev->mbits = -1;
387
388   switch (p->cfg.cd.necessity) {
389     case CD_VARIABLE:
390       dev->dev.cd.delay = p->cfg.cd.delay;
391       break;
392     case CD_REQUIRED:
393       dev->dev.cd = p->cfg.cd;
394       break;
395     case CD_NOTREQUIRED:
396       log_Printf(LogWARN, "%s: Carrier must be set, using ``set cd %d!''\n",
397                  p->link.name, dev->dev.cd.delay);
398     case CD_DEFAULT:
399       break;
400   }
401
402   oldflag = fcntl(p->fd, F_GETFL, 0);
403   if (oldflag < 0) {
404     /* Complete failure - parent doesn't continue trying to ``create'' */
405
406     log_Printf(LogWARN, "%s: Open: Cannot get physical flags: %s\n",
407                p->link.name, strerror(errno));
408     i4b_Cooked(p);
409     close(p->fd);
410     p->fd = -1;
411     free(dev);
412     return NULL;
413   } else
414     fcntl(p->fd, F_SETFL, oldflag & ~O_NONBLOCK);
415
416   if (dial) {
417     strncpy(number, datalink_ChoosePhoneNumber(p->dl), sizeof number - 1);
418     number[sizeof number - 1] = '\0';
419     if (number[0] == '\0')
420       dial = 0;
421   }
422   if (dial && ioctl(p->fd, I4B_RBCH_DIALOUT, number) == -1) {
423     /* Complete failure - parent doesn't continue trying to ``create'' */
424
425     log_Printf(LogWARN, "%s: ioctl(I4B_RBCH_DIALOUT): %s\n",
426                p->link.name, strerror(errno));
427     i4b_Cooked(p);
428     close(p->fd);
429     p->fd = -1;
430     free(dev);
431     return NULL;
432   }
433
434   physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNC);
435
436   return &dev->dev;
437 }