]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ppp/i4b.c
This commit was generated by cvs2svn to compensate for changes in r53796,
[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 #include <i4b/i4b_ioctl.h>
43 #include <i4b/i4b_rbch_ioctl.h>
44 #endif
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <sysexits.h>
49 #include <sys/uio.h>
50 #include <termios.h>
51 #include <unistd.h>
52
53 #include "layer.h"
54 #include "defs.h"
55 #include "mbuf.h"
56 #include "log.h"
57 #include "timer.h"
58 #include "lqr.h"
59 #include "hdlc.h"
60 #include "throughput.h"
61 #include "fsm.h"
62 #include "lcp.h"
63 #include "ccp.h"
64 #include "link.h"
65 #include "async.h"
66 #include "descriptor.h"
67 #include "physical.h"
68 #include "mp.h"
69 #include "chat.h"
70 #include "auth.h"
71 #include "chap.h"
72 #include "cbcp.h"
73 #include "datalink.h"
74 #include "main.h"
75 #include "i4b.h"
76
77 #define Online(dev)     ((dev)->mbits & TIOCM_CD)
78
79 struct i4bdevice {
80   struct device dev;            /* What struct physical knows about */
81   struct pppTimer Timer;        /* CD checks */
82   int mbits;                    /* Current DCD status */
83   int carrier_seconds;          /* seconds before CD is *required* */
84 };
85
86 #define device2i4b(d) ((d)->type == I4B_DEVICE ? (struct i4bdevice *)d : NULL)
87
88 int
89 i4b_DeviceSize(void)
90 {
91   return sizeof(struct i4bdevice);
92 }
93
94 /*
95  * i4b_Timeout() watches the DCD signal and mentions it if it's status
96  * changes.
97  */
98 static void
99 i4b_Timeout(void *data)
100 {
101   struct physical *p = data;
102   struct i4bdevice *dev = device2i4b(p->handler);
103   int ombits, change;
104
105   timer_Stop(&dev->Timer);
106   dev->Timer.load = SECTICKS;           /* Once a second please */
107   timer_Start(&dev->Timer);
108   ombits = dev->mbits;
109
110   if (p->fd >= 0) {
111     if (ioctl(p->fd, TIOCMGET, &dev->mbits) < 0) {
112       log_Printf(LogPHASE, "%s: ioctl error (%s)!\n", p->link.name,
113                  strerror(errno));
114       datalink_Down(p->dl, CLOSE_NORMAL);
115       timer_Stop(&dev->Timer);
116       return;
117     }
118   } else
119     dev->mbits = 0;
120
121   if (ombits == -1) {
122     /* First time looking for carrier */
123     if (Online(dev))
124       log_Printf(LogPHASE, "%s: %s: CD detected\n", p->link.name, p->name.full);
125     else if (++dev->carrier_seconds >= dev->dev.cd.delay) {
126       log_Printf(LogPHASE, "%s: %s: No carrier"
127                  " (increase ``set cd'' from %d ?)\n",
128                  p->link.name, p->name.full, dev->dev.cd.delay);
129       timer_Stop(&dev->Timer);
130       /* i4b_AwaitCarrier() will notice */
131     } else {
132       /* Keep waiting */
133       log_Printf(LogDEBUG, "%s: %s: Still no carrier (%d/%d)\n",
134                  p->link.name, p->name.full, dev->carrier_seconds,
135                  dev->dev.cd.delay);
136       dev->mbits = -1;
137     }
138   } else {
139     change = ombits ^ dev->mbits;
140     if (change & TIOCM_CD) {
141       if (dev->mbits & TIOCM_CD)
142         log_Printf(LogDEBUG, "%s: offline -> online\n", p->link.name);
143       else {
144         log_Printf(LogDEBUG, "%s: online -> offline\n", p->link.name);
145         log_Printf(LogPHASE, "%s: Carrier lost\n", p->link.name);
146         datalink_Down(p->dl, CLOSE_NORMAL);
147         timer_Stop(&dev->Timer);
148       }
149     } else
150       log_Printf(LogDEBUG, "%s: Still %sline\n", p->link.name,
151                  Online(dev) ? "on" : "off");
152   }
153 }
154
155 static void
156 i4b_StartTimer(struct physical *p)
157 {
158   struct i4bdevice *dev = device2i4b(p->handler);
159
160   timer_Stop(&dev->Timer);
161   dev->Timer.load = SECTICKS;
162   dev->Timer.func = i4b_Timeout;
163   dev->Timer.name = "i4b CD";
164   dev->Timer.arg = p;
165   log_Printf(LogDEBUG, "%s: Using i4b_Timeout [%p]\n",
166              p->link.name, i4b_Timeout);
167   timer_Start(&dev->Timer);
168 }
169
170 static int
171 i4b_AwaitCarrier(struct physical *p)
172 {
173   struct i4bdevice *dev = device2i4b(p->handler);
174
175   if (dev->mbits == -1) {
176     if (dev->Timer.state == TIMER_STOPPED) {
177       dev->carrier_seconds = 0;
178       i4b_StartTimer(p);
179     }
180     return CARRIER_PENDING;                     /* Not yet ! */
181   }
182
183   return Online(dev) ? CARRIER_OK : CARRIER_LOST;
184 }
185
186 static int
187 i4b_Raw(struct physical *p)
188 {
189   int oldflag;
190
191   log_Printf(LogDEBUG, "%s: Entering i4b_Raw\n", p->link.name);
192
193   oldflag = fcntl(p->fd, F_GETFL, 0);
194   if (oldflag < 0)
195     return 0;
196   fcntl(p->fd, F_SETFL, oldflag | O_NONBLOCK);
197
198   return 1;
199 }
200
201 static void
202 i4b_Offline(struct physical *p)
203 {
204   struct i4bdevice *dev = device2i4b(p->handler);
205
206   if (p->fd >= 0) {
207     timer_Stop(&dev->Timer);
208     if (Online(dev)) {
209       int dummy;
210
211       dummy = 1;
212       ioctl(p->fd, TIOCCDTR, &dummy);
213     }
214   }
215 }
216
217 static void
218 i4b_Cooked(struct physical *p)
219 {
220   int oldflag;
221
222   i4b_Offline(p);       /* In case of emergency close()s */
223
224   if ((oldflag = fcntl(p->fd, F_GETFL, 0)) != -1)
225     fcntl(p->fd, F_SETFL, oldflag & ~O_NONBLOCK);
226 }
227
228 static void
229 i4b_StopTimer(struct physical *p)
230 {
231   struct i4bdevice *dev = device2i4b(p->handler);
232
233   timer_Stop(&dev->Timer);
234 }
235
236 static void
237 i4b_Free(struct physical *p)
238 {
239   struct i4bdevice *dev = device2i4b(p->handler);
240
241   i4b_Offline(p);       /* In case of emergency close()s */
242   free(dev);
243 }
244
245 static int
246 i4b_Speed(struct physical *p)
247 {
248   struct termios ios;
249
250   if (tcgetattr(p->fd, &ios) == -1)
251     return 0;
252
253   return SpeedToInt(cfgetispeed(&ios));
254 }
255
256 static const char *
257 i4b_OpenInfo(struct physical *p)
258 {
259   struct i4bdevice *dev = device2i4b(p->handler);
260   static char buf[26];
261
262   if (Online(dev))
263     snprintf(buf, sizeof buf, "carrier took %ds", dev->carrier_seconds);
264   else
265     *buf = '\0';
266
267   return buf;
268 }
269
270 static void
271 i4b_device2iov(struct device *d, struct iovec *iov, int *niov,
272                int maxiov, int *auxfd, int *nauxfd)
273 {
274   struct i4bdevice *dev = device2i4b(d);
275   int sz = physical_MaxDeviceSize();
276
277   iov[*niov].iov_base = realloc(d, sz);
278   if (iov[*niov].iov_base == NULL) {
279     log_Printf(LogALERT, "Failed to allocate memory: %d\n", sz);
280     AbortProgram(EX_OSERR);
281   }
282   iov[*niov].iov_len = sz;
283   (*niov)++;
284
285   if (dev->Timer.state != TIMER_STOPPED) {
286     timer_Stop(&dev->Timer);
287     dev->Timer.state = TIMER_RUNNING;
288   }
289 }
290
291 static struct device basei4bdevice = {
292   I4B_DEVICE,
293   "i4b",
294   { CD_REQUIRED, DEF_I4BCDDELAY },
295   i4b_AwaitCarrier,
296   NULL,
297   i4b_Raw,
298   i4b_Offline,
299   i4b_Cooked,
300   i4b_StopTimer,
301   i4b_Free,
302   NULL,
303   NULL,
304   i4b_device2iov,
305   i4b_Speed,
306   i4b_OpenInfo
307 };
308
309 struct device *
310 i4b_iov2device(int type, struct physical *p, struct iovec *iov, int *niov,
311                int maxiov, int *auxfd, int *nauxfd)
312 {
313   if (type == I4B_DEVICE) {
314     struct i4bdevice *dev = (struct i4bdevice *)iov[(*niov)++].iov_base;
315
316     dev = realloc(dev, sizeof *dev);    /* Reduce to the correct size */
317     if (dev == NULL) {
318       log_Printf(LogALERT, "Failed to allocate memory: %d\n",
319                  (int)(sizeof *dev));
320       AbortProgram(EX_OSERR);
321     }
322
323     /* Refresh function pointers etc */
324     memcpy(&dev->dev, &basei4bdevice, sizeof dev->dev);
325
326     physical_SetupStack(p, dev->dev.name, PHYSICAL_NOFORCE);
327     if (dev->Timer.state != TIMER_STOPPED) {
328       dev->Timer.state = TIMER_STOPPED;
329       p->handler = &dev->dev;           /* For the benefit of StartTimer */
330       i4b_StartTimer(p);
331     }
332     return &dev->dev;
333   }
334
335   return NULL;
336 }
337
338 struct device *
339 i4b_Create(struct physical *p)
340 {
341   struct i4bdevice *dev;
342   int oldflag;
343   msg_vr_req_t req;
344   telno_t number;
345
346   if (p->fd < 0 || ioctl(p->fd, I4B_RBCH_VR_REQ, &req))
347     /* Don't want this */
348     return NULL;
349
350   /*
351    * We don't bother validating the version.... all versions of i4b that
352    * support I4B_RBCH_VR_REQ are fair game :-)
353    */
354
355   if (*p->name.full == '\0') {
356     physical_SetDevice(p, ttyname(p->fd));
357     log_Printf(LogDEBUG, "%s: Input is an i4b version %d.%d.%d isdn "
358                "device (%s)\n", p->link.name, req.version, req.release,
359                req.step, p->name.full);
360   } else
361     log_Printf(LogDEBUG, "%s: Opened %s (i4b version %d.%d.%d)\n",
362                p->link.name, p->name.full, req.version, req.release, req.step);
363
364   /* We're gonna return an i4bdevice (unless something goes horribly wrong) */
365
366   if ((dev = malloc(sizeof *dev)) == NULL) {
367     /* Complete failure - parent doesn't continue trying to ``create'' */
368     close(p->fd);
369     p->fd = -1;
370     return NULL;
371   }
372
373   memcpy(&dev->dev, &basei4bdevice, sizeof dev->dev);
374   memset(&dev->Timer, '\0', sizeof dev->Timer);
375   dev->mbits = -1;
376
377   switch (p->cfg.cd.necessity) {
378     case CD_VARIABLE:
379       dev->dev.cd.delay = p->cfg.cd.delay;
380       break;
381     case CD_REQUIRED:
382       dev->dev.cd = p->cfg.cd;
383       break;
384     case CD_NOTREQUIRED:
385       log_Printf(LogWARN, "%s: Carrier must be set, using ``set cd %d!''\n",
386                  p->link.name, dev->dev.cd.delay);
387     case CD_DEFAULT:
388       break;
389   }
390
391   oldflag = fcntl(p->fd, F_GETFL, 0);
392   if (oldflag < 0) {
393     /* Complete failure - parent doesn't continue trying to ``create'' */
394
395     log_Printf(LogWARN, "%s: Open: Cannot get physical flags: %s\n",
396                p->link.name, strerror(errno));
397     i4b_Cooked(p);
398     close(p->fd);
399     p->fd = -1;
400     free(dev);
401     return NULL;
402   } else
403     fcntl(p->fd, F_SETFL, oldflag & ~O_NONBLOCK);
404
405   strncpy(number, datalink_ChoosePhoneNumber(p->dl), sizeof number - 1);
406   number[sizeof number - 1] = '\0';
407   if (ioctl(p->fd, I4B_RBCH_DIALOUT, number) == -1) {
408     /* Complete failure - parent doesn't continue trying to ``create'' */
409
410     log_Printf(LogWARN, "%s: ioctl(I4B_RBCH_DIALOUT): %s\n",
411                p->link.name, strerror(errno));
412     i4b_Cooked(p);
413     close(p->fd);
414     p->fd = -1;
415     free(dev);
416     return NULL;
417   }
418
419   physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNC);
420
421   return &dev->dev;
422 }