2 * Copyright (c) 1999 Brian Somers <brian@Awfulhak.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
26 * $FreeBSD: src/usr.sbin/ppp/i4b.c,v 1.8.2.3 2002/09/01 02:12:27 brian Exp $
27 * $DragonFly: src/usr.sbin/ppp/i4b.c,v 1.4 2004/02/03 08:11:47 dillon Exp $
30 #include <sys/param.h>
33 #if defined(__OpenBSD__) || defined(__NetBSD__)
34 #include <sys/ioctl.h>
41 #include <i4b_machine/i4b_ioctl.h>
42 #include <i4b_machine/i4b_rbch_ioctl.h>
45 #include <netisdn/i4b_ioctl.h>
46 #include <netisdn/i4b_rbch_ioctl.h>
48 #include <net/i4b/i4b_ioctl.h>
49 #include <net/i4b/i4b_rbch_ioctl.h>
67 #include "throughput.h"
73 #include "descriptor.h"
84 #define Online(dev) ((dev)->mbits & TIOCM_CD)
87 struct device dev
; /* What struct physical knows about */
88 struct pppTimer Timer
; /* CD checks */
89 int mbits
; /* Current DCD status */
90 int carrier_seconds
; /* seconds before CD is *required* */
93 #define device2i4b(d) ((d)->type == I4B_DEVICE ? (struct i4bdevice *)d : NULL)
98 return sizeof(struct i4bdevice
);
102 * i4b_Timeout() watches the DCD signal and mentions it if it's status
106 i4b_Timeout(void *data
)
108 struct physical
*p
= data
;
109 struct i4bdevice
*dev
= device2i4b(p
->handler
);
112 timer_Stop(&dev
->Timer
);
113 dev
->Timer
.load
= SECTICKS
; /* Once a second please */
114 timer_Start(&dev
->Timer
);
118 if (ioctl(p
->fd
, TIOCMGET
, &dev
->mbits
) < 0) {
119 log_Printf(LogPHASE
, "%s: ioctl error (%s)!\n", p
->link
.name
,
121 datalink_Down(p
->dl
, CLOSE_NORMAL
);
122 timer_Stop(&dev
->Timer
);
129 /* First time looking for carrier */
131 log_Printf(LogPHASE
, "%s: %s: CD detected\n", p
->link
.name
, p
->name
.full
);
132 else if (++dev
->carrier_seconds
>= dev
->dev
.cd
.delay
) {
133 log_Printf(LogPHASE
, "%s: %s: No carrier"
134 " (increase ``set cd'' from %d ?)\n",
135 p
->link
.name
, p
->name
.full
, dev
->dev
.cd
.delay
);
136 timer_Stop(&dev
->Timer
);
137 /* i4b_AwaitCarrier() will notice */
140 log_Printf(LogDEBUG
, "%s: %s: Still no carrier (%d/%d)\n",
141 p
->link
.name
, p
->name
.full
, dev
->carrier_seconds
,
146 change
= ombits
^ dev
->mbits
;
147 if (change
& TIOCM_CD
) {
148 if (dev
->mbits
& TIOCM_CD
)
149 log_Printf(LogDEBUG
, "%s: offline -> online\n", p
->link
.name
);
151 log_Printf(LogDEBUG
, "%s: online -> offline\n", p
->link
.name
);
152 log_Printf(LogPHASE
, "%s: Carrier lost\n", p
->link
.name
);
153 datalink_Down(p
->dl
, CLOSE_NORMAL
);
154 timer_Stop(&dev
->Timer
);
157 log_Printf(LogDEBUG
, "%s: Still %sline\n", p
->link
.name
,
158 Online(dev
) ? "on" : "off");
163 i4b_StartTimer(struct physical
*p
)
165 struct i4bdevice
*dev
= device2i4b(p
->handler
);
167 timer_Stop(&dev
->Timer
);
168 dev
->Timer
.load
= SECTICKS
;
169 dev
->Timer
.func
= i4b_Timeout
;
170 dev
->Timer
.name
= "i4b CD";
172 log_Printf(LogDEBUG
, "%s: Using i4b_Timeout [%p]\n",
173 p
->link
.name
, i4b_Timeout
);
174 timer_Start(&dev
->Timer
);
178 i4b_AwaitCarrier(struct physical
*p
)
180 struct i4bdevice
*dev
= device2i4b(p
->handler
);
182 if (dev
->mbits
== -1) {
183 if (dev
->Timer
.state
== TIMER_STOPPED
) {
184 dev
->carrier_seconds
= 0;
187 return CARRIER_PENDING
; /* Not yet ! */
190 return Online(dev
) ? CARRIER_OK
: CARRIER_LOST
;
194 i4b_Raw(struct physical
*p
)
198 log_Printf(LogDEBUG
, "%s: Entering i4b_Raw\n", p
->link
.name
);
200 oldflag
= fcntl(p
->fd
, F_GETFL
, 0);
203 fcntl(p
->fd
, F_SETFL
, oldflag
| O_NONBLOCK
);
209 i4b_Offline(struct physical
*p
)
211 struct i4bdevice
*dev
= device2i4b(p
->handler
);
214 timer_Stop(&dev
->Timer
);
219 ioctl(p
->fd
, TIOCCDTR
, &dummy
);
225 i4b_Cooked(struct physical
*p
)
229 i4b_Offline(p
); /* In case of emergency close()s */
231 if ((oldflag
= fcntl(p
->fd
, F_GETFL
, 0)) != -1)
232 fcntl(p
->fd
, F_SETFL
, oldflag
& ~O_NONBLOCK
);
236 i4b_StopTimer(struct physical
*p
)
238 struct i4bdevice
*dev
= device2i4b(p
->handler
);
240 timer_Stop(&dev
->Timer
);
244 i4b_Free(struct physical
*p
)
246 struct i4bdevice
*dev
= device2i4b(p
->handler
);
248 i4b_Offline(p
); /* In case of emergency close()s */
253 i4b_Speed(struct physical
*p
)
258 if (tcgetattr(p
->fd
, &ios
) == -1 ||
259 (ret
= SpeedToInt(cfgetispeed(&ios
))) == 0)
266 i4b_OpenInfo(struct physical
*p
)
268 struct i4bdevice
*dev
= device2i4b(p
->handler
);
272 snprintf(buf
, sizeof buf
, "carrier took %ds", dev
->carrier_seconds
);
280 i4b_Slot(struct physical
*p
)
284 if (fstat(p
->fd
, &st
) == 0)
285 return minor(st
.st_rdev
);
291 i4b_device2iov(struct device
*d
, struct iovec
*iov
, int *niov
,
292 int maxiov
, int *auxfd
, int *nauxfd
)
294 struct i4bdevice
*dev
= device2i4b(d
);
295 int sz
= physical_MaxDeviceSize();
297 iov
[*niov
].iov_base
= realloc(d
, sz
);
298 if (iov
[*niov
].iov_base
== NULL
) {
299 log_Printf(LogALERT
, "Failed to allocate memory: %d\n", sz
);
300 AbortProgram(EX_OSERR
);
302 iov
[*niov
].iov_len
= sz
;
305 if (dev
->Timer
.state
!= TIMER_STOPPED
) {
306 timer_Stop(&dev
->Timer
);
307 dev
->Timer
.state
= TIMER_RUNNING
;
311 static struct device basei4bdevice
= {
315 { CD_REQUIRED
, DEF_I4BCDDELAY
},
333 i4b_iov2device(int type
, struct physical
*p
, struct iovec
*iov
, int *niov
,
334 int maxiov
, int *auxfd
, int *nauxfd
)
336 if (type
== I4B_DEVICE
) {
337 struct i4bdevice
*dev
= (struct i4bdevice
*)iov
[(*niov
)++].iov_base
;
339 dev
= realloc(dev
, sizeof *dev
); /* Reduce to the correct size */
341 log_Printf(LogALERT
, "Failed to allocate memory: %d\n",
343 AbortProgram(EX_OSERR
);
346 /* Refresh function pointers etc */
347 memcpy(&dev
->dev
, &basei4bdevice
, sizeof dev
->dev
);
349 physical_SetupStack(p
, dev
->dev
.name
, PHYSICAL_NOFORCE
);
350 if (dev
->Timer
.state
!= TIMER_STOPPED
) {
351 dev
->Timer
.state
= TIMER_STOPPED
;
352 p
->handler
= &dev
->dev
; /* For the benefit of StartTimer */
362 i4b_Create(struct physical
*p
)
364 struct i4bdevice
*dev
;
369 if (p
->fd
< 0 || ioctl(p
->fd
, I4B_RBCH_VR_REQ
, &req
))
370 /* Don't want this */
374 * We don't bother validating the version.... all versions of i4b that
375 * support I4B_RBCH_VR_REQ are fair game :-)
378 if (*p
->name
.full
== '\0') {
379 physical_SetDevice(p
, ttyname(p
->fd
));
380 log_Printf(LogDEBUG
, "%s: Input is an i4b version %d.%d.%d isdn "
381 "device (%s)\n", p
->link
.name
, req
.version
, req
.release
,
382 req
.step
, p
->name
.full
);
385 log_Printf(LogDEBUG
, "%s: Opened %s (i4b version %d.%d.%d)\n",
386 p
->link
.name
, p
->name
.full
, req
.version
, req
.release
, req
.step
);
390 /* We're gonna return an i4bdevice (unless something goes horribly wrong) */
392 if ((dev
= malloc(sizeof *dev
)) == NULL
) {
393 /* Complete failure - parent doesn't continue trying to ``create'' */
399 memcpy(&dev
->dev
, &basei4bdevice
, sizeof dev
->dev
);
400 memset(&dev
->Timer
, '\0', sizeof dev
->Timer
);
403 switch (p
->cfg
.cd
.necessity
) {
405 dev
->dev
.cd
.delay
= p
->cfg
.cd
.delay
;
408 dev
->dev
.cd
= p
->cfg
.cd
;
411 log_Printf(LogWARN
, "%s: Carrier must be set, using ``set cd %d!''\n",
412 p
->link
.name
, dev
->dev
.cd
.delay
);
417 oldflag
= fcntl(p
->fd
, F_GETFL
, 0);
419 /* Complete failure - parent doesn't continue trying to ``create'' */
421 log_Printf(LogWARN
, "%s: Open: Cannot get physical flags: %s\n",
422 p
->link
.name
, strerror(errno
));
429 fcntl(p
->fd
, F_SETFL
, oldflag
& ~O_NONBLOCK
);
432 strncpy(number
, datalink_ChoosePhoneNumber(p
->dl
), sizeof number
- 1);
433 number
[sizeof number
- 1] = '\0';
434 if (number
[0] == '\0')
437 if (dial
&& ioctl(p
->fd
, I4B_RBCH_DIALOUT
, number
) == -1) {
438 /* Complete failure - parent doesn't continue trying to ``create'' */
440 log_Printf(LogWARN
, "%s: ioctl(I4B_RBCH_DIALOUT): %s\n",
441 p
->link
.name
, strerror(errno
));
449 physical_SetupStack(p
, dev
->dev
.name
, PHYSICAL_FORCE_SYNC
);