Deleted Added
full compact
datalink.c (38174) datalink.c (38200)
1/*-
2 * Copyright (c) 1998 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 *
1/*-
2 * Copyright (c) 1998 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 * $Id: datalink.c,v 1.16 1998/07/03 17:24:37 brian Exp $
26 * $Id: datalink.c,v 1.17 1998/08/07 18:42:48 brian Exp $
27 */
28
29#include <sys/types.h>
30#include <netinet/in.h>
31#include <netinet/in_systm.h>
32#include <netinet/ip.h>
33#include <sys/un.h>
34
35#include <ctype.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <sys/uio.h>
40#include <termios.h>
41
42#include "mbuf.h"
43#include "log.h"
44#include "defs.h"
45#include "timer.h"
46#include "fsm.h"
47#include "lcp.h"
48#include "descriptor.h"
49#include "lqr.h"
50#include "hdlc.h"
51#include "async.h"
52#include "throughput.h"
53#include "ccp.h"
54#include "link.h"
55#include "physical.h"
56#include "iplist.h"
57#include "slcompress.h"
58#include "ipcp.h"
59#include "filter.h"
60#include "mp.h"
61#include "bundle.h"
62#include "chat.h"
63#include "auth.h"
64#include "modem.h"
65#include "prompt.h"
66#include "lcpproto.h"
67#include "pap.h"
68#include "chap.h"
69#include "command.h"
70#include "cbcp.h"
71#include "datalink.h"
72
73static void datalink_LoginDone(struct datalink *);
74static void datalink_NewState(struct datalink *, int);
75
76static void
77datalink_OpenTimeout(void *v)
78{
79 struct datalink *dl = (struct datalink *)v;
80
81 timer_Stop(&dl->dial_timer);
82 if (dl->state == DATALINK_OPENING)
83 log_Printf(LogPHASE, "%s: Redial timer expired.\n", dl->name);
84}
85
86static void
87datalink_StartDialTimer(struct datalink *dl, int Timeout)
88{
89 timer_Stop(&dl->dial_timer);
90
91 if (Timeout) {
92 if (Timeout > 0)
93 dl->dial_timer.load = Timeout * SECTICKS;
94 else
95 dl->dial_timer.load = (random() % DIAL_TIMEOUT) * SECTICKS;
96 dl->dial_timer.func = datalink_OpenTimeout;
97 dl->dial_timer.name = "dial";
98 dl->dial_timer.arg = dl;
99 timer_Start(&dl->dial_timer);
100 if (dl->state == DATALINK_OPENING)
101 log_Printf(LogPHASE, "%s: Enter pause (%d) for redialing.\n",
102 dl->name, Timeout);
103 }
104}
105
106static void
107datalink_HangupDone(struct datalink *dl)
108{
109 if (dl->physical->type == PHYS_DEDICATED && !dl->bundle->CleaningUp &&
110 physical_GetFD(dl->physical) != -1) {
111 /* Don't close our modem if the link is dedicated */
112 datalink_LoginDone(dl);
113 return;
114 }
115
116 modem_Close(dl->physical);
117 dl->phone.chosen = "N/A";
118
119 if (dl->cbcp.required) {
120 log_Printf(LogPHASE, "Call peer back on %s\n", dl->cbcp.fsm.phone);
121 dl->cfg.callback.opmask = 0;
122 strncpy(dl->cfg.phone.list, dl->cbcp.fsm.phone,
123 sizeof dl->cfg.phone.list - 1);
124 dl->cfg.phone.list[sizeof dl->cfg.phone.list - 1] = '\0';
125 dl->phone.alt = dl->phone.next = NULL;
126 dl->reconnect_tries = dl->cfg.reconnect.max;
127 dl->dial_tries = dl->cfg.dial.max;
128 dl->script.run = 1;
129 dl->script.packetmode = 1;
130 if (!physical_SetMode(dl->physical, PHYS_BACKGROUND))
131 log_Printf(LogERROR, "Oops - can't change mode to BACKGROUND (gulp) !\n");
132 bundle_LinksRemoved(dl->bundle);
133 if (dl->cbcp.fsm.delay < dl->cfg.dial.timeout)
134 dl->cbcp.fsm.delay = dl->cfg.dial.timeout;
135 datalink_StartDialTimer(dl, dl->cbcp.fsm.delay);
136 cbcp_Down(&dl->cbcp);
137 datalink_NewState(dl, DATALINK_OPENING);
138 } else if (dl->bundle->CleaningUp ||
139 (dl->physical->type == PHYS_DIRECT) ||
140 ((!dl->dial_tries || (dl->dial_tries < 0 && !dl->reconnect_tries)) &&
141 !(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)))) {
142 datalink_NewState(dl, DATALINK_CLOSED);
143 dl->dial_tries = -1;
144 dl->reconnect_tries = 0;
145 bundle_LinkClosed(dl->bundle, dl);
146 if (!dl->bundle->CleaningUp)
147 datalink_StartDialTimer(dl, dl->cfg.dial.timeout);
148 } else {
149 datalink_NewState(dl, DATALINK_OPENING);
150 if (dl->dial_tries < 0) {
151 datalink_StartDialTimer(dl, dl->cfg.reconnect.timeout);
152 dl->dial_tries = dl->cfg.dial.max;
153 dl->reconnect_tries--;
154 } else {
155 if (dl->phone.next == NULL)
156 datalink_StartDialTimer(dl, dl->cfg.dial.timeout);
157 else
158 datalink_StartDialTimer(dl, dl->cfg.dial.next_timeout);
159 }
160 }
161}
162
163static const char *
164datalink_ChoosePhoneNumber(struct datalink *dl)
165{
166 char *phone;
167
168 if (dl->phone.alt == NULL) {
169 if (dl->phone.next == NULL) {
170 strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1);
171 dl->phone.list[sizeof dl->phone.list - 1] = '\0';
172 dl->phone.next = dl->phone.list;
173 }
174 dl->phone.alt = strsep(&dl->phone.next, ":");
175 }
176 phone = strsep(&dl->phone.alt, "|");
177 dl->phone.chosen = *phone ? phone : "[NONE]";
178 if (*phone)
179 log_Printf(LogPHASE, "Phone: %s\n", phone);
180 return phone;
181}
182
183static void
184datalink_LoginDone(struct datalink *dl)
185{
186 if (!dl->script.packetmode) {
187 dl->dial_tries = -1;
188 datalink_NewState(dl, DATALINK_READY);
189 } else if (modem_Raw(dl->physical, dl->bundle) < 0) {
190 dl->dial_tries = 0;
191 log_Printf(LogWARN, "datalink_LoginDone: Not connected.\n");
192 if (dl->script.run) {
193 datalink_NewState(dl, DATALINK_HANGUP);
194 modem_Offline(dl->physical);
195 chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL);
196 } else {
197 timer_Stop(&dl->physical->Timer);
198 if (dl->physical->type == PHYS_DEDICATED)
199 /* force a redial timeout */
200 modem_Close(dl->physical);
201 datalink_HangupDone(dl);
202 }
203 } else {
204 dl->dial_tries = -1;
205
206 hdlc_Init(&dl->physical->hdlc, &dl->physical->link.lcp);
207 async_Init(&dl->physical->async);
208
209 lcp_Setup(&dl->physical->link.lcp, dl->state == DATALINK_READY ?
210 0 : dl->physical->link.lcp.cfg.openmode);
211 ccp_Setup(&dl->physical->link.ccp);
212
213 datalink_NewState(dl, DATALINK_LCP);
214 fsm_Up(&dl->physical->link.lcp.fsm);
215 fsm_Open(&dl->physical->link.lcp.fsm);
216 }
217}
218
219static int
220datalink_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e,
221 int *n)
222{
223 struct datalink *dl = descriptor2datalink(d);
224 int result;
225
226 result = 0;
227 switch (dl->state) {
228 case DATALINK_CLOSED:
229 if ((dl->physical->type &
230 (PHYS_DIRECT|PHYS_DEDICATED|PHYS_BACKGROUND|PHYS_DDIAL)) &&
231 !bundle_IsDead(dl->bundle))
232 /*
233 * Our first time in - DEDICATED & DDIAL never come down, and
234 * DIRECT & BACKGROUND get deleted when they enter DATALINK_CLOSED.
235 * Go to DATALINK_OPENING via datalink_Up() and fall through.
236 */
237 datalink_Up(dl, 1, 1);
238 else
239 break;
240 /* fall through */
241
242 case DATALINK_OPENING:
243 if (dl->dial_timer.state != TIMER_RUNNING) {
244 if (--dl->dial_tries < 0)
245 dl->dial_tries = 0;
246 if (modem_Open(dl->physical, dl->bundle) >= 0) {
27 */
28
29#include <sys/types.h>
30#include <netinet/in.h>
31#include <netinet/in_systm.h>
32#include <netinet/ip.h>
33#include <sys/un.h>
34
35#include <ctype.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <sys/uio.h>
40#include <termios.h>
41
42#include "mbuf.h"
43#include "log.h"
44#include "defs.h"
45#include "timer.h"
46#include "fsm.h"
47#include "lcp.h"
48#include "descriptor.h"
49#include "lqr.h"
50#include "hdlc.h"
51#include "async.h"
52#include "throughput.h"
53#include "ccp.h"
54#include "link.h"
55#include "physical.h"
56#include "iplist.h"
57#include "slcompress.h"
58#include "ipcp.h"
59#include "filter.h"
60#include "mp.h"
61#include "bundle.h"
62#include "chat.h"
63#include "auth.h"
64#include "modem.h"
65#include "prompt.h"
66#include "lcpproto.h"
67#include "pap.h"
68#include "chap.h"
69#include "command.h"
70#include "cbcp.h"
71#include "datalink.h"
72
73static void datalink_LoginDone(struct datalink *);
74static void datalink_NewState(struct datalink *, int);
75
76static void
77datalink_OpenTimeout(void *v)
78{
79 struct datalink *dl = (struct datalink *)v;
80
81 timer_Stop(&dl->dial_timer);
82 if (dl->state == DATALINK_OPENING)
83 log_Printf(LogPHASE, "%s: Redial timer expired.\n", dl->name);
84}
85
86static void
87datalink_StartDialTimer(struct datalink *dl, int Timeout)
88{
89 timer_Stop(&dl->dial_timer);
90
91 if (Timeout) {
92 if (Timeout > 0)
93 dl->dial_timer.load = Timeout * SECTICKS;
94 else
95 dl->dial_timer.load = (random() % DIAL_TIMEOUT) * SECTICKS;
96 dl->dial_timer.func = datalink_OpenTimeout;
97 dl->dial_timer.name = "dial";
98 dl->dial_timer.arg = dl;
99 timer_Start(&dl->dial_timer);
100 if (dl->state == DATALINK_OPENING)
101 log_Printf(LogPHASE, "%s: Enter pause (%d) for redialing.\n",
102 dl->name, Timeout);
103 }
104}
105
106static void
107datalink_HangupDone(struct datalink *dl)
108{
109 if (dl->physical->type == PHYS_DEDICATED && !dl->bundle->CleaningUp &&
110 physical_GetFD(dl->physical) != -1) {
111 /* Don't close our modem if the link is dedicated */
112 datalink_LoginDone(dl);
113 return;
114 }
115
116 modem_Close(dl->physical);
117 dl->phone.chosen = "N/A";
118
119 if (dl->cbcp.required) {
120 log_Printf(LogPHASE, "Call peer back on %s\n", dl->cbcp.fsm.phone);
121 dl->cfg.callback.opmask = 0;
122 strncpy(dl->cfg.phone.list, dl->cbcp.fsm.phone,
123 sizeof dl->cfg.phone.list - 1);
124 dl->cfg.phone.list[sizeof dl->cfg.phone.list - 1] = '\0';
125 dl->phone.alt = dl->phone.next = NULL;
126 dl->reconnect_tries = dl->cfg.reconnect.max;
127 dl->dial_tries = dl->cfg.dial.max;
128 dl->script.run = 1;
129 dl->script.packetmode = 1;
130 if (!physical_SetMode(dl->physical, PHYS_BACKGROUND))
131 log_Printf(LogERROR, "Oops - can't change mode to BACKGROUND (gulp) !\n");
132 bundle_LinksRemoved(dl->bundle);
133 if (dl->cbcp.fsm.delay < dl->cfg.dial.timeout)
134 dl->cbcp.fsm.delay = dl->cfg.dial.timeout;
135 datalink_StartDialTimer(dl, dl->cbcp.fsm.delay);
136 cbcp_Down(&dl->cbcp);
137 datalink_NewState(dl, DATALINK_OPENING);
138 } else if (dl->bundle->CleaningUp ||
139 (dl->physical->type == PHYS_DIRECT) ||
140 ((!dl->dial_tries || (dl->dial_tries < 0 && !dl->reconnect_tries)) &&
141 !(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)))) {
142 datalink_NewState(dl, DATALINK_CLOSED);
143 dl->dial_tries = -1;
144 dl->reconnect_tries = 0;
145 bundle_LinkClosed(dl->bundle, dl);
146 if (!dl->bundle->CleaningUp)
147 datalink_StartDialTimer(dl, dl->cfg.dial.timeout);
148 } else {
149 datalink_NewState(dl, DATALINK_OPENING);
150 if (dl->dial_tries < 0) {
151 datalink_StartDialTimer(dl, dl->cfg.reconnect.timeout);
152 dl->dial_tries = dl->cfg.dial.max;
153 dl->reconnect_tries--;
154 } else {
155 if (dl->phone.next == NULL)
156 datalink_StartDialTimer(dl, dl->cfg.dial.timeout);
157 else
158 datalink_StartDialTimer(dl, dl->cfg.dial.next_timeout);
159 }
160 }
161}
162
163static const char *
164datalink_ChoosePhoneNumber(struct datalink *dl)
165{
166 char *phone;
167
168 if (dl->phone.alt == NULL) {
169 if (dl->phone.next == NULL) {
170 strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1);
171 dl->phone.list[sizeof dl->phone.list - 1] = '\0';
172 dl->phone.next = dl->phone.list;
173 }
174 dl->phone.alt = strsep(&dl->phone.next, ":");
175 }
176 phone = strsep(&dl->phone.alt, "|");
177 dl->phone.chosen = *phone ? phone : "[NONE]";
178 if (*phone)
179 log_Printf(LogPHASE, "Phone: %s\n", phone);
180 return phone;
181}
182
183static void
184datalink_LoginDone(struct datalink *dl)
185{
186 if (!dl->script.packetmode) {
187 dl->dial_tries = -1;
188 datalink_NewState(dl, DATALINK_READY);
189 } else if (modem_Raw(dl->physical, dl->bundle) < 0) {
190 dl->dial_tries = 0;
191 log_Printf(LogWARN, "datalink_LoginDone: Not connected.\n");
192 if (dl->script.run) {
193 datalink_NewState(dl, DATALINK_HANGUP);
194 modem_Offline(dl->physical);
195 chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL);
196 } else {
197 timer_Stop(&dl->physical->Timer);
198 if (dl->physical->type == PHYS_DEDICATED)
199 /* force a redial timeout */
200 modem_Close(dl->physical);
201 datalink_HangupDone(dl);
202 }
203 } else {
204 dl->dial_tries = -1;
205
206 hdlc_Init(&dl->physical->hdlc, &dl->physical->link.lcp);
207 async_Init(&dl->physical->async);
208
209 lcp_Setup(&dl->physical->link.lcp, dl->state == DATALINK_READY ?
210 0 : dl->physical->link.lcp.cfg.openmode);
211 ccp_Setup(&dl->physical->link.ccp);
212
213 datalink_NewState(dl, DATALINK_LCP);
214 fsm_Up(&dl->physical->link.lcp.fsm);
215 fsm_Open(&dl->physical->link.lcp.fsm);
216 }
217}
218
219static int
220datalink_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e,
221 int *n)
222{
223 struct datalink *dl = descriptor2datalink(d);
224 int result;
225
226 result = 0;
227 switch (dl->state) {
228 case DATALINK_CLOSED:
229 if ((dl->physical->type &
230 (PHYS_DIRECT|PHYS_DEDICATED|PHYS_BACKGROUND|PHYS_DDIAL)) &&
231 !bundle_IsDead(dl->bundle))
232 /*
233 * Our first time in - DEDICATED & DDIAL never come down, and
234 * DIRECT & BACKGROUND get deleted when they enter DATALINK_CLOSED.
235 * Go to DATALINK_OPENING via datalink_Up() and fall through.
236 */
237 datalink_Up(dl, 1, 1);
238 else
239 break;
240 /* fall through */
241
242 case DATALINK_OPENING:
243 if (dl->dial_timer.state != TIMER_RUNNING) {
244 if (--dl->dial_tries < 0)
245 dl->dial_tries = 0;
246 if (modem_Open(dl->physical, dl->bundle) >= 0) {
247 log_WritePrompts(dl, "%s: Entering terminal mode on %s\r\n"
248 "Type `~?' for help\r\n", dl->name,
249 dl->physical->name.full);
247 if (dl->script.run) {
248 datalink_NewState(dl, DATALINK_DIAL);
249 chat_Init(&dl->chat, dl->physical, dl->cfg.script.dial, 1,
250 datalink_ChoosePhoneNumber(dl));
251 if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) &&
252 dl->cfg.dial.max)
253 log_Printf(LogCHAT, "%s: Dial attempt %u of %d\n",
254 dl->name, dl->cfg.dial.max - dl->dial_tries,
255 dl->cfg.dial.max);
256 return datalink_UpdateSet(d, r, w, e, n);
257 } else
258 datalink_LoginDone(dl);
259 } else {
260 if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) &&
261 dl->cfg.dial.max)
262 log_Printf(LogCHAT, "Failed to open modem (attempt %u of %d)\n",
250 if (dl->script.run) {
251 datalink_NewState(dl, DATALINK_DIAL);
252 chat_Init(&dl->chat, dl->physical, dl->cfg.script.dial, 1,
253 datalink_ChoosePhoneNumber(dl));
254 if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) &&
255 dl->cfg.dial.max)
256 log_Printf(LogCHAT, "%s: Dial attempt %u of %d\n",
257 dl->name, dl->cfg.dial.max - dl->dial_tries,
258 dl->cfg.dial.max);
259 return datalink_UpdateSet(d, r, w, e, n);
260 } else
261 datalink_LoginDone(dl);
262 } else {
263 if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) &&
264 dl->cfg.dial.max)
265 log_Printf(LogCHAT, "Failed to open modem (attempt %u of %d)\n",
263 dl->cfg.dial.max - dl->dial_tries, dl->cfg.dial.max);
266 dl->cfg.dial.max - dl->dial_tries, dl->cfg.dial.max);
264 else
265 log_Printf(LogCHAT, "Failed to open modem\n");
266
267 if (dl->bundle->CleaningUp ||
268 (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) &&
269 dl->cfg.dial.max && dl->dial_tries == 0)) {
270 datalink_NewState(dl, DATALINK_CLOSED);
271 dl->reconnect_tries = 0;
272 dl->dial_tries = -1;
267 else
268 log_Printf(LogCHAT, "Failed to open modem\n");
269
270 if (dl->bundle->CleaningUp ||
271 (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) &&
272 dl->cfg.dial.max && dl->dial_tries == 0)) {
273 datalink_NewState(dl, DATALINK_CLOSED);
274 dl->reconnect_tries = 0;
275 dl->dial_tries = -1;
276 log_WritePrompts(dl, "Failed to open %s\n",
277 dl->physical->name.full);
273 bundle_LinkClosed(dl->bundle, dl);
274 }
278 bundle_LinkClosed(dl->bundle, dl);
279 }
275 if (!dl->bundle->CleaningUp)
280 if (!dl->bundle->CleaningUp) {
281 log_WritePrompts(dl, "Failed to open %s, pause %d seconds\n",
282 dl->physical->name.full, dl->cfg.dial.timeout);
276 datalink_StartDialTimer(dl, dl->cfg.dial.timeout);
283 datalink_StartDialTimer(dl, dl->cfg.dial.timeout);
284 }
277 }
278 }
279 break;
280
281 case DATALINK_HANGUP:
282 case DATALINK_DIAL:
283 case DATALINK_LOGIN:
284 result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n);
285 switch (dl->chat.state) {
286 case CHAT_DONE:
287 /* script succeeded */
288 chat_Destroy(&dl->chat);
289 switch(dl->state) {
290 case DATALINK_HANGUP:
291 datalink_HangupDone(dl);
292 break;
293 case DATALINK_DIAL:
294 datalink_NewState(dl, DATALINK_LOGIN);
295 chat_Init(&dl->chat, dl->physical, dl->cfg.script.login, 0, NULL);
296 return datalink_UpdateSet(d, r, w, e, n);
297 case DATALINK_LOGIN:
298 datalink_LoginDone(dl);
299 break;
300 }
301 break;
302 case CHAT_FAILED:
303 /* Going down - script failed */
304 log_Printf(LogWARN, "Chat script failed\n");
305 chat_Destroy(&dl->chat);
306 switch(dl->state) {
307 case DATALINK_HANGUP:
308 datalink_HangupDone(dl);
309 break;
310 case DATALINK_DIAL:
311 case DATALINK_LOGIN:
312 datalink_NewState(dl, DATALINK_HANGUP);
313 modem_Offline(dl->physical); /* Is this required ? */
314 chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL);
315 return datalink_UpdateSet(d, r, w, e, n);
316 }
317 break;
318 }
319 break;
320
321 case DATALINK_READY:
322 case DATALINK_LCP:
323 case DATALINK_AUTH:
324 case DATALINK_CBCP:
325 case DATALINK_OPEN:
326 result = descriptor_UpdateSet(&dl->physical->desc, r, w, e, n);
327 break;
328 }
329 return result;
330}
331
332int
333datalink_RemoveFromSet(struct datalink *dl, fd_set *r, fd_set *w, fd_set *e)
334{
335 return physical_RemoveFromSet(dl->physical, r, w, e);
336}
337
338static int
339datalink_IsSet(struct descriptor *d, const fd_set *fdset)
340{
341 struct datalink *dl = descriptor2datalink(d);
342
343 switch (dl->state) {
344 case DATALINK_CLOSED:
345 case DATALINK_OPENING:
346 break;
347
348 case DATALINK_HANGUP:
349 case DATALINK_DIAL:
350 case DATALINK_LOGIN:
351 return descriptor_IsSet(&dl->chat.desc, fdset);
352
353 case DATALINK_READY:
354 case DATALINK_LCP:
355 case DATALINK_AUTH:
356 case DATALINK_CBCP:
357 case DATALINK_OPEN:
358 return descriptor_IsSet(&dl->physical->desc, fdset);
359 }
360 return 0;
361}
362
363static void
364datalink_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
365{
366 struct datalink *dl = descriptor2datalink(d);
367
368 switch (dl->state) {
369 case DATALINK_CLOSED:
370 case DATALINK_OPENING:
371 break;
372
373 case DATALINK_HANGUP:
374 case DATALINK_DIAL:
375 case DATALINK_LOGIN:
376 descriptor_Read(&dl->chat.desc, bundle, fdset);
377 break;
378
379 case DATALINK_READY:
380 case DATALINK_LCP:
381 case DATALINK_AUTH:
382 case DATALINK_CBCP:
383 case DATALINK_OPEN:
384 descriptor_Read(&dl->physical->desc, bundle, fdset);
385 break;
386 }
387}
388
389static int
390datalink_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
391{
392 struct datalink *dl = descriptor2datalink(d);
393 int result = 0;
394
395 switch (dl->state) {
396 case DATALINK_CLOSED:
397 case DATALINK_OPENING:
398 break;
399
400 case DATALINK_HANGUP:
401 case DATALINK_DIAL:
402 case DATALINK_LOGIN:
403 result = descriptor_Write(&dl->chat.desc, bundle, fdset);
404 break;
405
406 case DATALINK_READY:
407 case DATALINK_LCP:
408 case DATALINK_AUTH:
409 case DATALINK_CBCP:
410 case DATALINK_OPEN:
411 result = descriptor_Write(&dl->physical->desc, bundle, fdset);
412 break;
413 }
414
415 return result;
416}
417
418static void
419datalink_ComeDown(struct datalink *dl, int how)
420{
421 if (how != CLOSE_NORMAL) {
422 dl->dial_tries = -1;
423 dl->reconnect_tries = 0;
424 if (dl->state >= DATALINK_READY && how == CLOSE_LCP)
425 dl->stayonline = 1;
426 }
427
428 if (dl->state >= DATALINK_READY && dl->stayonline) {
429 dl->stayonline = 0;
430 timer_Stop(&dl->physical->Timer);
431 datalink_NewState(dl, DATALINK_READY);
432 } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) {
433 modem_Offline(dl->physical);
434 if (dl->script.run && dl->state != DATALINK_OPENING) {
435 datalink_NewState(dl, DATALINK_HANGUP);
436 chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL);
437 } else
438 datalink_HangupDone(dl);
439 }
440}
441
442static void
443datalink_LayerStart(void *v, struct fsm *fp)
444{
445 /* The given FSM is about to start up ! */
446 struct datalink *dl = (struct datalink *)v;
447
448 if (fp->proto == PROTO_LCP)
449 (*dl->parent->LayerStart)(dl->parent->object, fp);
450}
451
452static void
453datalink_LayerUp(void *v, struct fsm *fp)
454{
455 /* The given fsm is now up */
456 struct datalink *dl = (struct datalink *)v;
457
458 if (fp->proto == PROTO_LCP) {
459 datalink_GotAuthname(dl, "", 0);
460 dl->physical->link.lcp.auth_ineed = dl->physical->link.lcp.want_auth;
461 dl->physical->link.lcp.auth_iwait = dl->physical->link.lcp.his_auth;
462 if (dl->physical->link.lcp.his_auth || dl->physical->link.lcp.want_auth) {
463 if (bundle_Phase(dl->bundle) == PHASE_ESTABLISH)
464 bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE);
465 log_Printf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name,
466 Auth2Nam(dl->physical->link.lcp.his_auth),
467 Auth2Nam(dl->physical->link.lcp.want_auth));
468 if (dl->physical->link.lcp.his_auth == PROTO_PAP)
469 auth_StartChallenge(&dl->pap, dl->physical, pap_SendChallenge);
470 if (dl->physical->link.lcp.want_auth == PROTO_CHAP)
471 auth_StartChallenge(&dl->chap.auth, dl->physical, chap_SendChallenge);
472 } else
473 datalink_AuthOk(dl);
474 }
475}
476
477void
478datalink_GotAuthname(struct datalink *dl, const char *name, int len)
479{
480 if (len >= sizeof dl->peer.authname)
481 len = sizeof dl->peer.authname - 1;
482 strncpy(dl->peer.authname, name, len);
483 dl->peer.authname[len] = '\0';
484}
485
486void
487datalink_NCPUp(struct datalink *dl)
488{
489 int ccpok = ccp_SetOpenMode(&dl->physical->link.ccp);
490
491 if (dl->physical->link.lcp.want_mrru && dl->physical->link.lcp.his_mrru) {
492 /* we've authenticated in multilink mode ! */
493 switch (mp_Up(&dl->bundle->ncp.mp, dl)) {
494 case MP_LINKSENT:
495 /* We've handed the link off to another ppp (well, we will soon) ! */
496 return;
497 case MP_UP:
498 /* First link in the bundle */
499 auth_Select(dl->bundle, dl->peer.authname);
500 /* fall through */
501 case MP_ADDED:
502 /* We're in multilink mode ! */
503 dl->physical->link.ccp.fsm.open_mode = OPEN_PASSIVE; /* override */
504 break;
505 case MP_FAILED:
506 datalink_AuthNotOk(dl);
507 return;
508 }
509 } else if (bundle_Phase(dl->bundle) == PHASE_NETWORK) {
510 log_Printf(LogPHASE, "%s: Already in NETWORK phase\n", dl->name);
511 datalink_NewState(dl, DATALINK_OPEN);
512 (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm);
513 return;
514 } else {
515 dl->bundle->ncp.mp.peer = dl->peer;
516 ipcp_SetLink(&dl->bundle->ncp.ipcp, &dl->physical->link);
517 auth_Select(dl->bundle, dl->peer.authname);
518 }
519
520 if (ccpok) {
521 fsm_Up(&dl->physical->link.ccp.fsm);
522 fsm_Open(&dl->physical->link.ccp.fsm);
523 }
524 datalink_NewState(dl, DATALINK_OPEN);
525 bundle_NewPhase(dl->bundle, PHASE_NETWORK);
526 (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm);
527}
528
529void
530datalink_CBCPComplete(struct datalink *dl)
531{
532 datalink_NewState(dl, DATALINK_LCP);
533 fsm_Close(&dl->physical->link.lcp.fsm);
534}
535
536void
537datalink_CBCPFailed(struct datalink *dl)
538{
539 cbcp_Down(&dl->cbcp);
540 datalink_CBCPComplete(dl);
541}
542
543void
544datalink_AuthOk(struct datalink *dl)
545{
546 if (dl->physical->link.lcp.his_callback.opmask ==
547 CALLBACK_BIT(CALLBACK_CBCP) ||
548 dl->physical->link.lcp.want_callback.opmask ==
549 CALLBACK_BIT(CALLBACK_CBCP)) {
550 datalink_NewState(dl, DATALINK_CBCP);
551 cbcp_Up(&dl->cbcp);
552 } else if (dl->physical->link.lcp.want_callback.opmask) {
553 log_Printf(LogPHASE, "%s: Shutdown and await peer callback\n", dl->name);
554 datalink_NewState(dl, DATALINK_LCP);
555 fsm_Close(&dl->physical->link.lcp.fsm);
556 } else
557 switch (dl->physical->link.lcp.his_callback.opmask) {
558 case 0:
559 datalink_NCPUp(dl);
560 break;
561
562 case CALLBACK_BIT(CALLBACK_AUTH):
563 auth_SetPhoneList(dl->peer.authname, dl->cbcp.fsm.phone,
564 sizeof dl->cbcp.fsm.phone);
565 if (*dl->cbcp.fsm.phone == '\0' || !strcmp(dl->cbcp.fsm.phone, "*")) {
566 log_Printf(LogPHASE, "%s: %s cannot be called back\n", dl->name,
567 dl->peer.authname);
568 *dl->cbcp.fsm.phone = '\0';
569 } else {
570 char *ptr = strchr(dl->cbcp.fsm.phone, ',');
571 if (ptr)
572 *ptr = '\0'; /* Call back on the first number */
573 log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name,
574 dl->cbcp.fsm.phone);
575 dl->cbcp.required = 1;
576 }
577 dl->cbcp.fsm.delay = 0;
578 datalink_NewState(dl, DATALINK_LCP);
579 fsm_Close(&dl->physical->link.lcp.fsm);
580 break;
581
582 case CALLBACK_BIT(CALLBACK_E164):
583 strncpy(dl->cbcp.fsm.phone, dl->physical->link.lcp.his_callback.msg,
584 sizeof dl->cbcp.fsm.phone - 1);
585 dl->cbcp.fsm.phone[sizeof dl->cbcp.fsm.phone - 1] = '\0';
586 log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name,
587 dl->cbcp.fsm.phone);
588 dl->cbcp.required = 1;
589 dl->cbcp.fsm.delay = 0;
590 datalink_NewState(dl, DATALINK_LCP);
591 fsm_Close(&dl->physical->link.lcp.fsm);
592 break;
593
594 default:
595 log_Printf(LogPHASE, "%s: Oops - Should have NAK'd peer callback !\n",
596 dl->name);
597 datalink_NewState(dl, DATALINK_LCP);
598 fsm_Close(&dl->physical->link.lcp.fsm);
599 break;
600 }
601}
602
603void
604datalink_AuthNotOk(struct datalink *dl)
605{
606 datalink_NewState(dl, DATALINK_LCP);
607 fsm_Close(&dl->physical->link.lcp.fsm);
608}
609
610static void
611datalink_LayerDown(void *v, struct fsm *fp)
612{
613 /* The given FSM has been told to come down */
614 struct datalink *dl = (struct datalink *)v;
615
616 if (fp->proto == PROTO_LCP) {
617 switch (dl->state) {
618 case DATALINK_OPEN:
619 peerid_Init(&dl->peer);
620 fsm2initial(&dl->physical->link.ccp.fsm);
621 datalink_NewState(dl, DATALINK_LCP); /* before parent TLD */
622 (*dl->parent->LayerDown)(dl->parent->object, fp);
623 /* fall through (just in case) */
624
625 case DATALINK_CBCP:
626 if (!dl->cbcp.required)
627 cbcp_Down(&dl->cbcp);
628 /* fall through (just in case) */
629
630 case DATALINK_AUTH:
631 timer_Stop(&dl->pap.authtimer);
632 timer_Stop(&dl->chap.auth.authtimer);
633 }
634 datalink_NewState(dl, DATALINK_LCP);
635 }
636}
637
638static void
639datalink_LayerFinish(void *v, struct fsm *fp)
640{
641 /* The given fsm is now down */
642 struct datalink *dl = (struct datalink *)v;
643
644 if (fp->proto == PROTO_LCP) {
645 fsm2initial(fp);
646 (*dl->parent->LayerFinish)(dl->parent->object, fp);
647 datalink_ComeDown(dl, CLOSE_NORMAL);
648 } else if (fp->state == ST_CLOSED && fp->open_mode == OPEN_PASSIVE)
649 fsm_Open(fp); /* CCP goes to ST_STOPPED */
650}
651
652struct datalink *
653datalink_Create(const char *name, struct bundle *bundle, int type)
654{
655 struct datalink *dl;
656
657 dl = (struct datalink *)malloc(sizeof(struct datalink));
658 if (dl == NULL)
659 return dl;
660
661 dl->desc.type = DATALINK_DESCRIPTOR;
662 dl->desc.UpdateSet = datalink_UpdateSet;
663 dl->desc.IsSet = datalink_IsSet;
664 dl->desc.Read = datalink_Read;
665 dl->desc.Write = datalink_Write;
666
667 dl->state = DATALINK_CLOSED;
668
669 *dl->cfg.script.dial = '\0';
670 *dl->cfg.script.login = '\0';
671 *dl->cfg.script.hangup = '\0';
672 *dl->cfg.phone.list = '\0';
673 *dl->phone.list = '\0';
674 dl->phone.next = NULL;
675 dl->phone.alt = NULL;
676 dl->phone.chosen = "N/A";
677 dl->stayonline = 0;
678 dl->script.run = 1;
679 dl->script.packetmode = 1;
680 mp_linkInit(&dl->mp);
681
682 dl->bundle = bundle;
683 dl->next = NULL;
684
685 memset(&dl->dial_timer, '\0', sizeof dl->dial_timer);
686
687 dl->dial_tries = 0;
688 dl->cfg.dial.max = 1;
689 dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT;
690 dl->cfg.dial.timeout = DIAL_TIMEOUT;
691
692 dl->reconnect_tries = 0;
693 dl->cfg.reconnect.max = 0;
694 dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT;
695
696 dl->cfg.callback.opmask = 0;
697 dl->cfg.cbcp.delay = 0;
698 *dl->cfg.cbcp.phone = '\0';
699 dl->cfg.cbcp.fsmretry = DEF_FSMRETRY;
700
701 dl->name = strdup(name);
702 peerid_Init(&dl->peer);
703 dl->parent = &bundle->fsm;
704 dl->fsmp.LayerStart = datalink_LayerStart;
705 dl->fsmp.LayerUp = datalink_LayerUp;
706 dl->fsmp.LayerDown = datalink_LayerDown;
707 dl->fsmp.LayerFinish = datalink_LayerFinish;
708 dl->fsmp.object = dl;
709
710 auth_Init(&dl->pap);
711 auth_Init(&dl->chap.auth);
712
713 if ((dl->physical = modem_Create(dl, type)) == NULL) {
714 free(dl->name);
715 free(dl);
716 return NULL;
717 }
718 cbcp_Init(&dl->cbcp, dl->physical);
719 chat_Init(&dl->chat, dl->physical, NULL, 1, NULL);
720
721 log_Printf(LogPHASE, "%s: Created in %s state\n",
722 dl->name, datalink_State(dl));
723
724 return dl;
725}
726
727struct datalink *
728datalink_Clone(struct datalink *odl, const char *name)
729{
730 struct datalink *dl;
731
732 dl = (struct datalink *)malloc(sizeof(struct datalink));
733 if (dl == NULL)
734 return dl;
735
736 dl->desc.type = DATALINK_DESCRIPTOR;
737 dl->desc.UpdateSet = datalink_UpdateSet;
738 dl->desc.IsSet = datalink_IsSet;
739 dl->desc.Read = datalink_Read;
740 dl->desc.Write = datalink_Write;
741
742 dl->state = DATALINK_CLOSED;
743
744 memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg);
745 mp_linkInit(&dl->mp);
746 *dl->phone.list = '\0';
747 dl->phone.next = NULL;
748 dl->phone.alt = NULL;
749 dl->phone.chosen = "N/A";
750 dl->bundle = odl->bundle;
751 dl->next = NULL;
752 memset(&dl->dial_timer, '\0', sizeof dl->dial_timer);
753 dl->dial_tries = 0;
754 dl->reconnect_tries = 0;
755 dl->name = strdup(name);
756 peerid_Init(&dl->peer);
757 dl->parent = odl->parent;
758 memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp);
759 dl->fsmp.object = dl;
760 auth_Init(&dl->pap);
761 dl->pap.cfg.fsmretry = odl->pap.cfg.fsmretry;
762
763 auth_Init(&dl->chap.auth);
764 dl->chap.auth.cfg.fsmretry = odl->chap.auth.cfg.fsmretry;
765
766 if ((dl->physical = modem_Create(dl, PHYS_INTERACTIVE)) == NULL) {
767 free(dl->name);
768 free(dl);
769 return NULL;
770 }
771 memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg);
772 memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg,
773 sizeof dl->physical->link.lcp.cfg);
774 memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg,
775 sizeof dl->physical->link.ccp.cfg);
776 memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg,
777 sizeof dl->physical->async.cfg);
778
779 cbcp_Init(&dl->cbcp, dl->physical);
780 chat_Init(&dl->chat, dl->physical, NULL, 1, NULL);
781
782 log_Printf(LogPHASE, "%s: Cloned in %s state\n",
783 dl->name, datalink_State(dl));
784
785 return dl;
786}
787
788struct datalink *
789datalink_Destroy(struct datalink *dl)
790{
791 struct datalink *result;
792
793 if (dl->state != DATALINK_CLOSED) {
794 log_Printf(LogERROR, "Oops, destroying a datalink in state %s\n",
795 datalink_State(dl));
796 switch (dl->state) {
797 case DATALINK_HANGUP:
798 case DATALINK_DIAL:
799 case DATALINK_LOGIN:
800 chat_Destroy(&dl->chat); /* Gotta blat the timers ! */
801 break;
802 }
803 }
804
805 result = dl->next;
806 modem_Destroy(dl->physical);
807 free(dl->name);
808 free(dl);
809
810 return result;
811}
812
813void
814datalink_Up(struct datalink *dl, int runscripts, int packetmode)
815{
816 if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED))
817 /* Ignore scripts */
818 runscripts = 0;
819
820 switch (dl->state) {
821 case DATALINK_CLOSED:
822 if (bundle_Phase(dl->bundle) == PHASE_DEAD ||
823 bundle_Phase(dl->bundle) == PHASE_TERMINATE)
824 bundle_NewPhase(dl->bundle, PHASE_ESTABLISH);
825 datalink_NewState(dl, DATALINK_OPENING);
826 dl->reconnect_tries =
827 dl->physical->type == PHYS_DIRECT ? 0 : dl->cfg.reconnect.max;
828 dl->dial_tries = dl->cfg.dial.max;
829 dl->script.run = runscripts;
830 dl->script.packetmode = packetmode;
831 break;
832
833 case DATALINK_OPENING:
834 if (!dl->script.run && runscripts)
835 dl->script.run = 1;
836 /* fall through */
837
838 case DATALINK_DIAL:
839 case DATALINK_LOGIN:
840 case DATALINK_READY:
841 if (!dl->script.packetmode && packetmode) {
842 dl->script.packetmode = 1;
843 if (dl->state == DATALINK_READY)
844 datalink_LoginDone(dl);
845 }
846 break;
847 }
848}
849
850void
851datalink_Close(struct datalink *dl, int how)
852{
853 /* Please close */
854 switch (dl->state) {
855 case DATALINK_OPEN:
856 peerid_Init(&dl->peer);
857 fsm2initial(&dl->physical->link.ccp.fsm);
858 /* fall through */
859
860 case DATALINK_CBCP:
861 case DATALINK_AUTH:
862 case DATALINK_LCP:
863 fsm_Close(&dl->physical->link.lcp.fsm);
864 if (how != CLOSE_NORMAL) {
865 dl->dial_tries = -1;
866 dl->reconnect_tries = 0;
867 if (how == CLOSE_LCP)
868 dl->stayonline = 1;
869 }
870 break;
871
872 default:
873 datalink_ComeDown(dl, how);
874 }
875}
876
877void
878datalink_Down(struct datalink *dl, int how)
879{
880 /* Carrier is lost */
881 switch (dl->state) {
882 case DATALINK_OPEN:
883 peerid_Init(&dl->peer);
884 fsm2initial(&dl->physical->link.ccp.fsm);
885 /* fall through */
886
887 case DATALINK_CBCP:
888 case DATALINK_AUTH:
889 case DATALINK_LCP:
890 fsm2initial(&dl->physical->link.lcp.fsm);
891 /* fall through */
892
893 default:
894 datalink_ComeDown(dl, how);
895 }
896}
897
898void
899datalink_StayDown(struct datalink *dl)
900{
901 dl->reconnect_tries = 0;
902}
903
904void
905datalink_DontHangup(struct datalink *dl)
906{
907 if (dl->state >= DATALINK_LCP)
908 dl->stayonline = 1;
909}
910
911int
912datalink_Show(struct cmdargs const *arg)
913{
914 prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name);
915 prompt_Printf(arg->prompt, " State: %s\n",
916 datalink_State(arg->cx));
917 prompt_Printf(arg->prompt, " CHAP Encryption: %s\n",
918 arg->cx->chap.using_MSChap ? "MSChap" : "MD5" );
919 prompt_Printf(arg->prompt, " Peer name: ");
920 if (*arg->cx->peer.authname)
921 prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname);
922 else if (arg->cx->state == DATALINK_OPEN)
923 prompt_Printf(arg->prompt, "None requested\n");
924 else
925 prompt_Printf(arg->prompt, "N/A\n");
926 prompt_Printf(arg->prompt, " Discriminator: %s\n",
927 mp_Enddisc(arg->cx->peer.enddisc.class,
928 arg->cx->peer.enddisc.address,
929 arg->cx->peer.enddisc.len));
930
931 prompt_Printf(arg->prompt, "\nDefaults:\n");
932 prompt_Printf(arg->prompt, " Phone List: %s\n",
933 arg->cx->cfg.phone.list);
934 if (arg->cx->cfg.dial.max)
935 prompt_Printf(arg->prompt, " Dial tries: %d, delay ",
936 arg->cx->cfg.dial.max);
937 else
938 prompt_Printf(arg->prompt, " Dial tries: infinite, delay ");
939 if (arg->cx->cfg.dial.next_timeout > 0)
940 prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout);
941 else
942 prompt_Printf(arg->prompt, "random/");
943 if (arg->cx->cfg.dial.timeout > 0)
944 prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout);
945 else
946 prompt_Printf(arg->prompt, "random\n");
947 prompt_Printf(arg->prompt, " Reconnect tries: %d, delay ",
948 arg->cx->cfg.reconnect.max);
949 if (arg->cx->cfg.reconnect.timeout > 0)
950 prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout);
951 else
952 prompt_Printf(arg->prompt, "random\n");
953 prompt_Printf(arg->prompt, " Callback %s ", arg->cx->physical->type ==
954 PHYS_DIRECT ? "accepted: " : "requested:");
955 if (!arg->cx->cfg.callback.opmask)
956 prompt_Printf(arg->prompt, "none\n");
957 else {
958 int comma = 0;
959
960 if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) {
961 prompt_Printf(arg->prompt, "none");
962 comma = 1;
963 }
964 if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) {
965 prompt_Printf(arg->prompt, "%sauth", comma ? ", " : "");
966 comma = 1;
967 }
968 if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) {
969 prompt_Printf(arg->prompt, "%sE.164", comma ? ", " : "");
970 if (arg->cx->physical->type != PHYS_DIRECT)
971 prompt_Printf(arg->prompt, " (%s)", arg->cx->cfg.callback.msg);
972 comma = 1;
973 }
974 if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) {
975 prompt_Printf(arg->prompt, "%scbcp\n", comma ? ", " : "");
976 prompt_Printf(arg->prompt, " CBCP: delay: %ds\n",
977 arg->cx->cfg.cbcp.delay);
978 prompt_Printf(arg->prompt, " phone: %s\n",
979 arg->cx->cfg.cbcp.phone);
980 prompt_Printf(arg->prompt, " timeout: %lds\n",
981 arg->cx->cfg.cbcp.fsmretry);
982 } else
983 prompt_Printf(arg->prompt, "\n");
984 }
985
986 prompt_Printf(arg->prompt, " Dial Script: %s\n",
987 arg->cx->cfg.script.dial);
988 prompt_Printf(arg->prompt, " Login Script: %s\n",
989 arg->cx->cfg.script.login);
990 prompt_Printf(arg->prompt, " Hangup Script: %s\n",
991 arg->cx->cfg.script.hangup);
992 return 0;
993}
994
995int
996datalink_SetReconnect(struct cmdargs const *arg)
997{
998 if (arg->argc == arg->argn+2) {
999 arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]);
1000 arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]);
1001 return 0;
1002 }
1003 return -1;
1004}
1005
1006int
1007datalink_SetRedial(struct cmdargs const *arg)
1008{
1009 int timeout;
1010 int tries;
1011 char *dot;
1012
1013 if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) {
1014 if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 &&
1015 (arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) {
1016 arg->cx->cfg.dial.timeout = -1;
1017 randinit();
1018 } else {
1019 timeout = atoi(arg->argv[arg->argn]);
1020
1021 if (timeout >= 0)
1022 arg->cx->cfg.dial.timeout = timeout;
1023 else {
1024 log_Printf(LogWARN, "Invalid redial timeout\n");
1025 return -1;
1026 }
1027 }
1028
1029 dot = strchr(arg->argv[arg->argn], '.');
1030 if (dot) {
1031 if (strcasecmp(++dot, "random") == 0) {
1032 arg->cx->cfg.dial.next_timeout = -1;
1033 randinit();
1034 } else {
1035 timeout = atoi(dot);
1036 if (timeout >= 0)
1037 arg->cx->cfg.dial.next_timeout = timeout;
1038 else {
1039 log_Printf(LogWARN, "Invalid next redial timeout\n");
1040 return -1;
1041 }
1042 }
1043 } else
1044 /* Default next timeout */
1045 arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT;
1046
1047 if (arg->argc == arg->argn+2) {
1048 tries = atoi(arg->argv[arg->argn+1]);
1049
1050 if (tries >= 0) {
1051 arg->cx->cfg.dial.max = tries;
1052 } else {
1053 log_Printf(LogWARN, "Invalid retry value\n");
1054 return 1;
1055 }
1056 }
1057 return 0;
1058 }
1059 return -1;
1060}
1061
1062static const char *states[] = {
1063 "closed",
1064 "opening",
1065 "hangup",
1066 "dial",
1067 "login",
1068 "ready",
1069 "lcp",
1070 "auth",
1071 "cbcp",
1072 "open"
1073};
1074
1075const char *
1076datalink_State(struct datalink *dl)
1077{
1078 if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0])
1079 return "unknown";
1080 return states[dl->state];
1081}
1082
1083static void
1084datalink_NewState(struct datalink *dl, int state)
1085{
1086 if (state != dl->state) {
1087 if (state >= 0 && state < sizeof states / sizeof states[0]) {
1088 log_Printf(LogPHASE, "%s: %s -> %s\n", dl->name, datalink_State(dl),
1089 states[state]);
1090 dl->state = state;
1091 } else
1092 log_Printf(LogERROR, "%s: Can't enter state %d !\n", dl->name, state);
1093 }
1094}
1095
1096struct datalink *
1097iov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov,
1098 int fd)
1099{
1100 struct datalink *dl, *cdl;
1101 u_int retry;
1102 char *oname;
1103
1104 dl = (struct datalink *)iov[(*niov)++].iov_base;
1105 dl->name = iov[*niov].iov_base;
1106
1107 if (dl->name[DATALINK_MAXNAME-1]) {
1108 dl->name[DATALINK_MAXNAME-1] = '\0';
1109 if (strlen(dl->name) == DATALINK_MAXNAME - 1)
1110 log_Printf(LogWARN, "Datalink name truncated to \"%s\"\n", dl->name);
1111 }
1112
1113 /* Make sure the name is unique ! */
1114 oname = NULL;
1115 do {
1116 for (cdl = bundle->links; cdl; cdl = cdl->next)
1117 if (!strcasecmp(dl->name, cdl->name)) {
1118 if (oname)
1119 free(datalink_NextName(dl));
1120 else
1121 oname = datalink_NextName(dl);
1122 break; /* Keep renaming 'till we have no conflicts */
1123 }
1124 } while (cdl);
1125
1126 if (oname) {
1127 log_Printf(LogPHASE, "Rename link %s to %s\n", oname, dl->name);
1128 free(oname);
1129 } else {
1130 dl->name = strdup(dl->name);
1131 free(iov[*niov].iov_base);
1132 }
1133 (*niov)++;
1134
1135 dl->desc.type = DATALINK_DESCRIPTOR;
1136 dl->desc.UpdateSet = datalink_UpdateSet;
1137 dl->desc.IsSet = datalink_IsSet;
1138 dl->desc.Read = datalink_Read;
1139 dl->desc.Write = datalink_Write;
1140
1141 mp_linkInit(&dl->mp);
1142 *dl->phone.list = '\0';
1143 dl->phone.next = NULL;
1144 dl->phone.alt = NULL;
1145 dl->phone.chosen = "N/A";
1146
1147 dl->bundle = bundle;
1148 dl->next = NULL;
1149 memset(&dl->dial_timer, '\0', sizeof dl->dial_timer);
1150 dl->dial_tries = 0;
1151 dl->reconnect_tries = 0;
1152 dl->parent = &bundle->fsm;
1153 dl->fsmp.LayerStart = datalink_LayerStart;
1154 dl->fsmp.LayerUp = datalink_LayerUp;
1155 dl->fsmp.LayerDown = datalink_LayerDown;
1156 dl->fsmp.LayerFinish = datalink_LayerFinish;
1157 dl->fsmp.object = dl;
1158
1159 retry = dl->pap.cfg.fsmretry;
1160 auth_Init(&dl->pap);
1161 dl->pap.cfg.fsmretry = retry;
1162
1163 retry = dl->chap.auth.cfg.fsmretry;
1164 auth_Init(&dl->chap.auth);
1165 dl->chap.auth.cfg.fsmretry = retry;
1166
1167 dl->physical = iov2modem(dl, iov, niov, maxiov, fd);
1168
1169 if (!dl->physical) {
1170 free(dl->name);
1171 free(dl);
1172 dl = NULL;
1173 } else {
1174 cbcp_Init(&dl->cbcp, dl->physical);
1175 chat_Init(&dl->chat, dl->physical, NULL, 1, NULL);
1176
1177 log_Printf(LogPHASE, "%s: Transferred in %s state\n",
1178 dl->name, datalink_State(dl));
1179 }
1180
1181 return dl;
1182}
1183
1184int
1185datalink2iov(struct datalink *dl, struct iovec *iov, int *niov, int maxiov,
1186 pid_t newpid)
1187{
1188 /* If `dl' is NULL, we're allocating before a Fromiov() */
1189 int link_fd;
1190
1191 if (dl) {
1192 timer_Stop(&dl->dial_timer);
1193 /* The following is purely for the sake of paranoia */
1194 cbcp_Down(&dl->cbcp);
1195 timer_Stop(&dl->pap.authtimer);
1196 timer_Stop(&dl->chap.auth.authtimer);
1197 }
1198
1199 if (*niov >= maxiov - 1) {
1200 log_Printf(LogERROR, "Toiov: No room for datalink !\n");
1201 if (dl) {
1202 free(dl->name);
1203 free(dl);
1204 }
1205 return -1;
1206 }
1207
1208 iov[*niov].iov_base = dl ? dl : malloc(sizeof *dl);
1209 iov[(*niov)++].iov_len = sizeof *dl;
1210 iov[*niov].iov_base =
1211 dl ? realloc(dl->name, DATALINK_MAXNAME) : malloc(DATALINK_MAXNAME);
1212 iov[(*niov)++].iov_len = DATALINK_MAXNAME;
1213
1214 link_fd = modem2iov(dl ? dl->physical : NULL, iov, niov, maxiov, newpid);
1215
1216 if (link_fd == -1 && dl) {
1217 free(dl->name);
1218 free(dl);
1219 }
1220
1221 return link_fd;
1222}
1223
1224void
1225datalink_Rename(struct datalink *dl, const char *name)
1226{
1227 free(dl->name);
1228 dl->physical->link.name = dl->name = strdup(name);
1229}
1230
1231char *
1232datalink_NextName(struct datalink *dl)
1233{
1234 int f, n;
1235 char *name, *oname;
1236
1237 n = strlen(dl->name);
1238 name = (char *)malloc(n+3);
1239 for (f = n - 1; f >= 0; f--)
1240 if (!isdigit(dl->name[f]))
1241 break;
1242 n = sprintf(name, "%.*s-", dl->name[f] == '-' ? f : f + 1, dl->name);
1243 sprintf(name + n, "%d", atoi(dl->name + f + 1) + 1);
1244 oname = dl->name;
1245 dl->name = name;
1246 /* our physical link name isn't updated (it probably isn't created yet) */
1247 return oname;
1248}
1249
1250int
1251datalink_SetMode(struct datalink *dl, int mode)
1252{
1253 if (!physical_SetMode(dl->physical, mode))
1254 return 0;
1255 if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED))
1256 dl->script.run = 0;
1257 if (dl->physical->type == PHYS_DIRECT)
1258 dl->reconnect_tries = 0;
1259 if (mode & (PHYS_DDIAL|PHYS_BACKGROUND) && dl->state <= DATALINK_READY)
1260 datalink_Up(dl, 1, 1);
1261 return 1;
1262}
285 }
286 }
287 break;
288
289 case DATALINK_HANGUP:
290 case DATALINK_DIAL:
291 case DATALINK_LOGIN:
292 result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n);
293 switch (dl->chat.state) {
294 case CHAT_DONE:
295 /* script succeeded */
296 chat_Destroy(&dl->chat);
297 switch(dl->state) {
298 case DATALINK_HANGUP:
299 datalink_HangupDone(dl);
300 break;
301 case DATALINK_DIAL:
302 datalink_NewState(dl, DATALINK_LOGIN);
303 chat_Init(&dl->chat, dl->physical, dl->cfg.script.login, 0, NULL);
304 return datalink_UpdateSet(d, r, w, e, n);
305 case DATALINK_LOGIN:
306 datalink_LoginDone(dl);
307 break;
308 }
309 break;
310 case CHAT_FAILED:
311 /* Going down - script failed */
312 log_Printf(LogWARN, "Chat script failed\n");
313 chat_Destroy(&dl->chat);
314 switch(dl->state) {
315 case DATALINK_HANGUP:
316 datalink_HangupDone(dl);
317 break;
318 case DATALINK_DIAL:
319 case DATALINK_LOGIN:
320 datalink_NewState(dl, DATALINK_HANGUP);
321 modem_Offline(dl->physical); /* Is this required ? */
322 chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL);
323 return datalink_UpdateSet(d, r, w, e, n);
324 }
325 break;
326 }
327 break;
328
329 case DATALINK_READY:
330 case DATALINK_LCP:
331 case DATALINK_AUTH:
332 case DATALINK_CBCP:
333 case DATALINK_OPEN:
334 result = descriptor_UpdateSet(&dl->physical->desc, r, w, e, n);
335 break;
336 }
337 return result;
338}
339
340int
341datalink_RemoveFromSet(struct datalink *dl, fd_set *r, fd_set *w, fd_set *e)
342{
343 return physical_RemoveFromSet(dl->physical, r, w, e);
344}
345
346static int
347datalink_IsSet(struct descriptor *d, const fd_set *fdset)
348{
349 struct datalink *dl = descriptor2datalink(d);
350
351 switch (dl->state) {
352 case DATALINK_CLOSED:
353 case DATALINK_OPENING:
354 break;
355
356 case DATALINK_HANGUP:
357 case DATALINK_DIAL:
358 case DATALINK_LOGIN:
359 return descriptor_IsSet(&dl->chat.desc, fdset);
360
361 case DATALINK_READY:
362 case DATALINK_LCP:
363 case DATALINK_AUTH:
364 case DATALINK_CBCP:
365 case DATALINK_OPEN:
366 return descriptor_IsSet(&dl->physical->desc, fdset);
367 }
368 return 0;
369}
370
371static void
372datalink_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
373{
374 struct datalink *dl = descriptor2datalink(d);
375
376 switch (dl->state) {
377 case DATALINK_CLOSED:
378 case DATALINK_OPENING:
379 break;
380
381 case DATALINK_HANGUP:
382 case DATALINK_DIAL:
383 case DATALINK_LOGIN:
384 descriptor_Read(&dl->chat.desc, bundle, fdset);
385 break;
386
387 case DATALINK_READY:
388 case DATALINK_LCP:
389 case DATALINK_AUTH:
390 case DATALINK_CBCP:
391 case DATALINK_OPEN:
392 descriptor_Read(&dl->physical->desc, bundle, fdset);
393 break;
394 }
395}
396
397static int
398datalink_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
399{
400 struct datalink *dl = descriptor2datalink(d);
401 int result = 0;
402
403 switch (dl->state) {
404 case DATALINK_CLOSED:
405 case DATALINK_OPENING:
406 break;
407
408 case DATALINK_HANGUP:
409 case DATALINK_DIAL:
410 case DATALINK_LOGIN:
411 result = descriptor_Write(&dl->chat.desc, bundle, fdset);
412 break;
413
414 case DATALINK_READY:
415 case DATALINK_LCP:
416 case DATALINK_AUTH:
417 case DATALINK_CBCP:
418 case DATALINK_OPEN:
419 result = descriptor_Write(&dl->physical->desc, bundle, fdset);
420 break;
421 }
422
423 return result;
424}
425
426static void
427datalink_ComeDown(struct datalink *dl, int how)
428{
429 if (how != CLOSE_NORMAL) {
430 dl->dial_tries = -1;
431 dl->reconnect_tries = 0;
432 if (dl->state >= DATALINK_READY && how == CLOSE_LCP)
433 dl->stayonline = 1;
434 }
435
436 if (dl->state >= DATALINK_READY && dl->stayonline) {
437 dl->stayonline = 0;
438 timer_Stop(&dl->physical->Timer);
439 datalink_NewState(dl, DATALINK_READY);
440 } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) {
441 modem_Offline(dl->physical);
442 if (dl->script.run && dl->state != DATALINK_OPENING) {
443 datalink_NewState(dl, DATALINK_HANGUP);
444 chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL);
445 } else
446 datalink_HangupDone(dl);
447 }
448}
449
450static void
451datalink_LayerStart(void *v, struct fsm *fp)
452{
453 /* The given FSM is about to start up ! */
454 struct datalink *dl = (struct datalink *)v;
455
456 if (fp->proto == PROTO_LCP)
457 (*dl->parent->LayerStart)(dl->parent->object, fp);
458}
459
460static void
461datalink_LayerUp(void *v, struct fsm *fp)
462{
463 /* The given fsm is now up */
464 struct datalink *dl = (struct datalink *)v;
465
466 if (fp->proto == PROTO_LCP) {
467 datalink_GotAuthname(dl, "", 0);
468 dl->physical->link.lcp.auth_ineed = dl->physical->link.lcp.want_auth;
469 dl->physical->link.lcp.auth_iwait = dl->physical->link.lcp.his_auth;
470 if (dl->physical->link.lcp.his_auth || dl->physical->link.lcp.want_auth) {
471 if (bundle_Phase(dl->bundle) == PHASE_ESTABLISH)
472 bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE);
473 log_Printf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name,
474 Auth2Nam(dl->physical->link.lcp.his_auth),
475 Auth2Nam(dl->physical->link.lcp.want_auth));
476 if (dl->physical->link.lcp.his_auth == PROTO_PAP)
477 auth_StartChallenge(&dl->pap, dl->physical, pap_SendChallenge);
478 if (dl->physical->link.lcp.want_auth == PROTO_CHAP)
479 auth_StartChallenge(&dl->chap.auth, dl->physical, chap_SendChallenge);
480 } else
481 datalink_AuthOk(dl);
482 }
483}
484
485void
486datalink_GotAuthname(struct datalink *dl, const char *name, int len)
487{
488 if (len >= sizeof dl->peer.authname)
489 len = sizeof dl->peer.authname - 1;
490 strncpy(dl->peer.authname, name, len);
491 dl->peer.authname[len] = '\0';
492}
493
494void
495datalink_NCPUp(struct datalink *dl)
496{
497 int ccpok = ccp_SetOpenMode(&dl->physical->link.ccp);
498
499 if (dl->physical->link.lcp.want_mrru && dl->physical->link.lcp.his_mrru) {
500 /* we've authenticated in multilink mode ! */
501 switch (mp_Up(&dl->bundle->ncp.mp, dl)) {
502 case MP_LINKSENT:
503 /* We've handed the link off to another ppp (well, we will soon) ! */
504 return;
505 case MP_UP:
506 /* First link in the bundle */
507 auth_Select(dl->bundle, dl->peer.authname);
508 /* fall through */
509 case MP_ADDED:
510 /* We're in multilink mode ! */
511 dl->physical->link.ccp.fsm.open_mode = OPEN_PASSIVE; /* override */
512 break;
513 case MP_FAILED:
514 datalink_AuthNotOk(dl);
515 return;
516 }
517 } else if (bundle_Phase(dl->bundle) == PHASE_NETWORK) {
518 log_Printf(LogPHASE, "%s: Already in NETWORK phase\n", dl->name);
519 datalink_NewState(dl, DATALINK_OPEN);
520 (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm);
521 return;
522 } else {
523 dl->bundle->ncp.mp.peer = dl->peer;
524 ipcp_SetLink(&dl->bundle->ncp.ipcp, &dl->physical->link);
525 auth_Select(dl->bundle, dl->peer.authname);
526 }
527
528 if (ccpok) {
529 fsm_Up(&dl->physical->link.ccp.fsm);
530 fsm_Open(&dl->physical->link.ccp.fsm);
531 }
532 datalink_NewState(dl, DATALINK_OPEN);
533 bundle_NewPhase(dl->bundle, PHASE_NETWORK);
534 (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm);
535}
536
537void
538datalink_CBCPComplete(struct datalink *dl)
539{
540 datalink_NewState(dl, DATALINK_LCP);
541 fsm_Close(&dl->physical->link.lcp.fsm);
542}
543
544void
545datalink_CBCPFailed(struct datalink *dl)
546{
547 cbcp_Down(&dl->cbcp);
548 datalink_CBCPComplete(dl);
549}
550
551void
552datalink_AuthOk(struct datalink *dl)
553{
554 if (dl->physical->link.lcp.his_callback.opmask ==
555 CALLBACK_BIT(CALLBACK_CBCP) ||
556 dl->physical->link.lcp.want_callback.opmask ==
557 CALLBACK_BIT(CALLBACK_CBCP)) {
558 datalink_NewState(dl, DATALINK_CBCP);
559 cbcp_Up(&dl->cbcp);
560 } else if (dl->physical->link.lcp.want_callback.opmask) {
561 log_Printf(LogPHASE, "%s: Shutdown and await peer callback\n", dl->name);
562 datalink_NewState(dl, DATALINK_LCP);
563 fsm_Close(&dl->physical->link.lcp.fsm);
564 } else
565 switch (dl->physical->link.lcp.his_callback.opmask) {
566 case 0:
567 datalink_NCPUp(dl);
568 break;
569
570 case CALLBACK_BIT(CALLBACK_AUTH):
571 auth_SetPhoneList(dl->peer.authname, dl->cbcp.fsm.phone,
572 sizeof dl->cbcp.fsm.phone);
573 if (*dl->cbcp.fsm.phone == '\0' || !strcmp(dl->cbcp.fsm.phone, "*")) {
574 log_Printf(LogPHASE, "%s: %s cannot be called back\n", dl->name,
575 dl->peer.authname);
576 *dl->cbcp.fsm.phone = '\0';
577 } else {
578 char *ptr = strchr(dl->cbcp.fsm.phone, ',');
579 if (ptr)
580 *ptr = '\0'; /* Call back on the first number */
581 log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name,
582 dl->cbcp.fsm.phone);
583 dl->cbcp.required = 1;
584 }
585 dl->cbcp.fsm.delay = 0;
586 datalink_NewState(dl, DATALINK_LCP);
587 fsm_Close(&dl->physical->link.lcp.fsm);
588 break;
589
590 case CALLBACK_BIT(CALLBACK_E164):
591 strncpy(dl->cbcp.fsm.phone, dl->physical->link.lcp.his_callback.msg,
592 sizeof dl->cbcp.fsm.phone - 1);
593 dl->cbcp.fsm.phone[sizeof dl->cbcp.fsm.phone - 1] = '\0';
594 log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name,
595 dl->cbcp.fsm.phone);
596 dl->cbcp.required = 1;
597 dl->cbcp.fsm.delay = 0;
598 datalink_NewState(dl, DATALINK_LCP);
599 fsm_Close(&dl->physical->link.lcp.fsm);
600 break;
601
602 default:
603 log_Printf(LogPHASE, "%s: Oops - Should have NAK'd peer callback !\n",
604 dl->name);
605 datalink_NewState(dl, DATALINK_LCP);
606 fsm_Close(&dl->physical->link.lcp.fsm);
607 break;
608 }
609}
610
611void
612datalink_AuthNotOk(struct datalink *dl)
613{
614 datalink_NewState(dl, DATALINK_LCP);
615 fsm_Close(&dl->physical->link.lcp.fsm);
616}
617
618static void
619datalink_LayerDown(void *v, struct fsm *fp)
620{
621 /* The given FSM has been told to come down */
622 struct datalink *dl = (struct datalink *)v;
623
624 if (fp->proto == PROTO_LCP) {
625 switch (dl->state) {
626 case DATALINK_OPEN:
627 peerid_Init(&dl->peer);
628 fsm2initial(&dl->physical->link.ccp.fsm);
629 datalink_NewState(dl, DATALINK_LCP); /* before parent TLD */
630 (*dl->parent->LayerDown)(dl->parent->object, fp);
631 /* fall through (just in case) */
632
633 case DATALINK_CBCP:
634 if (!dl->cbcp.required)
635 cbcp_Down(&dl->cbcp);
636 /* fall through (just in case) */
637
638 case DATALINK_AUTH:
639 timer_Stop(&dl->pap.authtimer);
640 timer_Stop(&dl->chap.auth.authtimer);
641 }
642 datalink_NewState(dl, DATALINK_LCP);
643 }
644}
645
646static void
647datalink_LayerFinish(void *v, struct fsm *fp)
648{
649 /* The given fsm is now down */
650 struct datalink *dl = (struct datalink *)v;
651
652 if (fp->proto == PROTO_LCP) {
653 fsm2initial(fp);
654 (*dl->parent->LayerFinish)(dl->parent->object, fp);
655 datalink_ComeDown(dl, CLOSE_NORMAL);
656 } else if (fp->state == ST_CLOSED && fp->open_mode == OPEN_PASSIVE)
657 fsm_Open(fp); /* CCP goes to ST_STOPPED */
658}
659
660struct datalink *
661datalink_Create(const char *name, struct bundle *bundle, int type)
662{
663 struct datalink *dl;
664
665 dl = (struct datalink *)malloc(sizeof(struct datalink));
666 if (dl == NULL)
667 return dl;
668
669 dl->desc.type = DATALINK_DESCRIPTOR;
670 dl->desc.UpdateSet = datalink_UpdateSet;
671 dl->desc.IsSet = datalink_IsSet;
672 dl->desc.Read = datalink_Read;
673 dl->desc.Write = datalink_Write;
674
675 dl->state = DATALINK_CLOSED;
676
677 *dl->cfg.script.dial = '\0';
678 *dl->cfg.script.login = '\0';
679 *dl->cfg.script.hangup = '\0';
680 *dl->cfg.phone.list = '\0';
681 *dl->phone.list = '\0';
682 dl->phone.next = NULL;
683 dl->phone.alt = NULL;
684 dl->phone.chosen = "N/A";
685 dl->stayonline = 0;
686 dl->script.run = 1;
687 dl->script.packetmode = 1;
688 mp_linkInit(&dl->mp);
689
690 dl->bundle = bundle;
691 dl->next = NULL;
692
693 memset(&dl->dial_timer, '\0', sizeof dl->dial_timer);
694
695 dl->dial_tries = 0;
696 dl->cfg.dial.max = 1;
697 dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT;
698 dl->cfg.dial.timeout = DIAL_TIMEOUT;
699
700 dl->reconnect_tries = 0;
701 dl->cfg.reconnect.max = 0;
702 dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT;
703
704 dl->cfg.callback.opmask = 0;
705 dl->cfg.cbcp.delay = 0;
706 *dl->cfg.cbcp.phone = '\0';
707 dl->cfg.cbcp.fsmretry = DEF_FSMRETRY;
708
709 dl->name = strdup(name);
710 peerid_Init(&dl->peer);
711 dl->parent = &bundle->fsm;
712 dl->fsmp.LayerStart = datalink_LayerStart;
713 dl->fsmp.LayerUp = datalink_LayerUp;
714 dl->fsmp.LayerDown = datalink_LayerDown;
715 dl->fsmp.LayerFinish = datalink_LayerFinish;
716 dl->fsmp.object = dl;
717
718 auth_Init(&dl->pap);
719 auth_Init(&dl->chap.auth);
720
721 if ((dl->physical = modem_Create(dl, type)) == NULL) {
722 free(dl->name);
723 free(dl);
724 return NULL;
725 }
726 cbcp_Init(&dl->cbcp, dl->physical);
727 chat_Init(&dl->chat, dl->physical, NULL, 1, NULL);
728
729 log_Printf(LogPHASE, "%s: Created in %s state\n",
730 dl->name, datalink_State(dl));
731
732 return dl;
733}
734
735struct datalink *
736datalink_Clone(struct datalink *odl, const char *name)
737{
738 struct datalink *dl;
739
740 dl = (struct datalink *)malloc(sizeof(struct datalink));
741 if (dl == NULL)
742 return dl;
743
744 dl->desc.type = DATALINK_DESCRIPTOR;
745 dl->desc.UpdateSet = datalink_UpdateSet;
746 dl->desc.IsSet = datalink_IsSet;
747 dl->desc.Read = datalink_Read;
748 dl->desc.Write = datalink_Write;
749
750 dl->state = DATALINK_CLOSED;
751
752 memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg);
753 mp_linkInit(&dl->mp);
754 *dl->phone.list = '\0';
755 dl->phone.next = NULL;
756 dl->phone.alt = NULL;
757 dl->phone.chosen = "N/A";
758 dl->bundle = odl->bundle;
759 dl->next = NULL;
760 memset(&dl->dial_timer, '\0', sizeof dl->dial_timer);
761 dl->dial_tries = 0;
762 dl->reconnect_tries = 0;
763 dl->name = strdup(name);
764 peerid_Init(&dl->peer);
765 dl->parent = odl->parent;
766 memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp);
767 dl->fsmp.object = dl;
768 auth_Init(&dl->pap);
769 dl->pap.cfg.fsmretry = odl->pap.cfg.fsmretry;
770
771 auth_Init(&dl->chap.auth);
772 dl->chap.auth.cfg.fsmretry = odl->chap.auth.cfg.fsmretry;
773
774 if ((dl->physical = modem_Create(dl, PHYS_INTERACTIVE)) == NULL) {
775 free(dl->name);
776 free(dl);
777 return NULL;
778 }
779 memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg);
780 memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg,
781 sizeof dl->physical->link.lcp.cfg);
782 memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg,
783 sizeof dl->physical->link.ccp.cfg);
784 memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg,
785 sizeof dl->physical->async.cfg);
786
787 cbcp_Init(&dl->cbcp, dl->physical);
788 chat_Init(&dl->chat, dl->physical, NULL, 1, NULL);
789
790 log_Printf(LogPHASE, "%s: Cloned in %s state\n",
791 dl->name, datalink_State(dl));
792
793 return dl;
794}
795
796struct datalink *
797datalink_Destroy(struct datalink *dl)
798{
799 struct datalink *result;
800
801 if (dl->state != DATALINK_CLOSED) {
802 log_Printf(LogERROR, "Oops, destroying a datalink in state %s\n",
803 datalink_State(dl));
804 switch (dl->state) {
805 case DATALINK_HANGUP:
806 case DATALINK_DIAL:
807 case DATALINK_LOGIN:
808 chat_Destroy(&dl->chat); /* Gotta blat the timers ! */
809 break;
810 }
811 }
812
813 result = dl->next;
814 modem_Destroy(dl->physical);
815 free(dl->name);
816 free(dl);
817
818 return result;
819}
820
821void
822datalink_Up(struct datalink *dl, int runscripts, int packetmode)
823{
824 if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED))
825 /* Ignore scripts */
826 runscripts = 0;
827
828 switch (dl->state) {
829 case DATALINK_CLOSED:
830 if (bundle_Phase(dl->bundle) == PHASE_DEAD ||
831 bundle_Phase(dl->bundle) == PHASE_TERMINATE)
832 bundle_NewPhase(dl->bundle, PHASE_ESTABLISH);
833 datalink_NewState(dl, DATALINK_OPENING);
834 dl->reconnect_tries =
835 dl->physical->type == PHYS_DIRECT ? 0 : dl->cfg.reconnect.max;
836 dl->dial_tries = dl->cfg.dial.max;
837 dl->script.run = runscripts;
838 dl->script.packetmode = packetmode;
839 break;
840
841 case DATALINK_OPENING:
842 if (!dl->script.run && runscripts)
843 dl->script.run = 1;
844 /* fall through */
845
846 case DATALINK_DIAL:
847 case DATALINK_LOGIN:
848 case DATALINK_READY:
849 if (!dl->script.packetmode && packetmode) {
850 dl->script.packetmode = 1;
851 if (dl->state == DATALINK_READY)
852 datalink_LoginDone(dl);
853 }
854 break;
855 }
856}
857
858void
859datalink_Close(struct datalink *dl, int how)
860{
861 /* Please close */
862 switch (dl->state) {
863 case DATALINK_OPEN:
864 peerid_Init(&dl->peer);
865 fsm2initial(&dl->physical->link.ccp.fsm);
866 /* fall through */
867
868 case DATALINK_CBCP:
869 case DATALINK_AUTH:
870 case DATALINK_LCP:
871 fsm_Close(&dl->physical->link.lcp.fsm);
872 if (how != CLOSE_NORMAL) {
873 dl->dial_tries = -1;
874 dl->reconnect_tries = 0;
875 if (how == CLOSE_LCP)
876 dl->stayonline = 1;
877 }
878 break;
879
880 default:
881 datalink_ComeDown(dl, how);
882 }
883}
884
885void
886datalink_Down(struct datalink *dl, int how)
887{
888 /* Carrier is lost */
889 switch (dl->state) {
890 case DATALINK_OPEN:
891 peerid_Init(&dl->peer);
892 fsm2initial(&dl->physical->link.ccp.fsm);
893 /* fall through */
894
895 case DATALINK_CBCP:
896 case DATALINK_AUTH:
897 case DATALINK_LCP:
898 fsm2initial(&dl->physical->link.lcp.fsm);
899 /* fall through */
900
901 default:
902 datalink_ComeDown(dl, how);
903 }
904}
905
906void
907datalink_StayDown(struct datalink *dl)
908{
909 dl->reconnect_tries = 0;
910}
911
912void
913datalink_DontHangup(struct datalink *dl)
914{
915 if (dl->state >= DATALINK_LCP)
916 dl->stayonline = 1;
917}
918
919int
920datalink_Show(struct cmdargs const *arg)
921{
922 prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name);
923 prompt_Printf(arg->prompt, " State: %s\n",
924 datalink_State(arg->cx));
925 prompt_Printf(arg->prompt, " CHAP Encryption: %s\n",
926 arg->cx->chap.using_MSChap ? "MSChap" : "MD5" );
927 prompt_Printf(arg->prompt, " Peer name: ");
928 if (*arg->cx->peer.authname)
929 prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname);
930 else if (arg->cx->state == DATALINK_OPEN)
931 prompt_Printf(arg->prompt, "None requested\n");
932 else
933 prompt_Printf(arg->prompt, "N/A\n");
934 prompt_Printf(arg->prompt, " Discriminator: %s\n",
935 mp_Enddisc(arg->cx->peer.enddisc.class,
936 arg->cx->peer.enddisc.address,
937 arg->cx->peer.enddisc.len));
938
939 prompt_Printf(arg->prompt, "\nDefaults:\n");
940 prompt_Printf(arg->prompt, " Phone List: %s\n",
941 arg->cx->cfg.phone.list);
942 if (arg->cx->cfg.dial.max)
943 prompt_Printf(arg->prompt, " Dial tries: %d, delay ",
944 arg->cx->cfg.dial.max);
945 else
946 prompt_Printf(arg->prompt, " Dial tries: infinite, delay ");
947 if (arg->cx->cfg.dial.next_timeout > 0)
948 prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout);
949 else
950 prompt_Printf(arg->prompt, "random/");
951 if (arg->cx->cfg.dial.timeout > 0)
952 prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout);
953 else
954 prompt_Printf(arg->prompt, "random\n");
955 prompt_Printf(arg->prompt, " Reconnect tries: %d, delay ",
956 arg->cx->cfg.reconnect.max);
957 if (arg->cx->cfg.reconnect.timeout > 0)
958 prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout);
959 else
960 prompt_Printf(arg->prompt, "random\n");
961 prompt_Printf(arg->prompt, " Callback %s ", arg->cx->physical->type ==
962 PHYS_DIRECT ? "accepted: " : "requested:");
963 if (!arg->cx->cfg.callback.opmask)
964 prompt_Printf(arg->prompt, "none\n");
965 else {
966 int comma = 0;
967
968 if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) {
969 prompt_Printf(arg->prompt, "none");
970 comma = 1;
971 }
972 if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) {
973 prompt_Printf(arg->prompt, "%sauth", comma ? ", " : "");
974 comma = 1;
975 }
976 if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) {
977 prompt_Printf(arg->prompt, "%sE.164", comma ? ", " : "");
978 if (arg->cx->physical->type != PHYS_DIRECT)
979 prompt_Printf(arg->prompt, " (%s)", arg->cx->cfg.callback.msg);
980 comma = 1;
981 }
982 if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) {
983 prompt_Printf(arg->prompt, "%scbcp\n", comma ? ", " : "");
984 prompt_Printf(arg->prompt, " CBCP: delay: %ds\n",
985 arg->cx->cfg.cbcp.delay);
986 prompt_Printf(arg->prompt, " phone: %s\n",
987 arg->cx->cfg.cbcp.phone);
988 prompt_Printf(arg->prompt, " timeout: %lds\n",
989 arg->cx->cfg.cbcp.fsmretry);
990 } else
991 prompt_Printf(arg->prompt, "\n");
992 }
993
994 prompt_Printf(arg->prompt, " Dial Script: %s\n",
995 arg->cx->cfg.script.dial);
996 prompt_Printf(arg->prompt, " Login Script: %s\n",
997 arg->cx->cfg.script.login);
998 prompt_Printf(arg->prompt, " Hangup Script: %s\n",
999 arg->cx->cfg.script.hangup);
1000 return 0;
1001}
1002
1003int
1004datalink_SetReconnect(struct cmdargs const *arg)
1005{
1006 if (arg->argc == arg->argn+2) {
1007 arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]);
1008 arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]);
1009 return 0;
1010 }
1011 return -1;
1012}
1013
1014int
1015datalink_SetRedial(struct cmdargs const *arg)
1016{
1017 int timeout;
1018 int tries;
1019 char *dot;
1020
1021 if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) {
1022 if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 &&
1023 (arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) {
1024 arg->cx->cfg.dial.timeout = -1;
1025 randinit();
1026 } else {
1027 timeout = atoi(arg->argv[arg->argn]);
1028
1029 if (timeout >= 0)
1030 arg->cx->cfg.dial.timeout = timeout;
1031 else {
1032 log_Printf(LogWARN, "Invalid redial timeout\n");
1033 return -1;
1034 }
1035 }
1036
1037 dot = strchr(arg->argv[arg->argn], '.');
1038 if (dot) {
1039 if (strcasecmp(++dot, "random") == 0) {
1040 arg->cx->cfg.dial.next_timeout = -1;
1041 randinit();
1042 } else {
1043 timeout = atoi(dot);
1044 if (timeout >= 0)
1045 arg->cx->cfg.dial.next_timeout = timeout;
1046 else {
1047 log_Printf(LogWARN, "Invalid next redial timeout\n");
1048 return -1;
1049 }
1050 }
1051 } else
1052 /* Default next timeout */
1053 arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT;
1054
1055 if (arg->argc == arg->argn+2) {
1056 tries = atoi(arg->argv[arg->argn+1]);
1057
1058 if (tries >= 0) {
1059 arg->cx->cfg.dial.max = tries;
1060 } else {
1061 log_Printf(LogWARN, "Invalid retry value\n");
1062 return 1;
1063 }
1064 }
1065 return 0;
1066 }
1067 return -1;
1068}
1069
1070static const char *states[] = {
1071 "closed",
1072 "opening",
1073 "hangup",
1074 "dial",
1075 "login",
1076 "ready",
1077 "lcp",
1078 "auth",
1079 "cbcp",
1080 "open"
1081};
1082
1083const char *
1084datalink_State(struct datalink *dl)
1085{
1086 if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0])
1087 return "unknown";
1088 return states[dl->state];
1089}
1090
1091static void
1092datalink_NewState(struct datalink *dl, int state)
1093{
1094 if (state != dl->state) {
1095 if (state >= 0 && state < sizeof states / sizeof states[0]) {
1096 log_Printf(LogPHASE, "%s: %s -> %s\n", dl->name, datalink_State(dl),
1097 states[state]);
1098 dl->state = state;
1099 } else
1100 log_Printf(LogERROR, "%s: Can't enter state %d !\n", dl->name, state);
1101 }
1102}
1103
1104struct datalink *
1105iov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov,
1106 int fd)
1107{
1108 struct datalink *dl, *cdl;
1109 u_int retry;
1110 char *oname;
1111
1112 dl = (struct datalink *)iov[(*niov)++].iov_base;
1113 dl->name = iov[*niov].iov_base;
1114
1115 if (dl->name[DATALINK_MAXNAME-1]) {
1116 dl->name[DATALINK_MAXNAME-1] = '\0';
1117 if (strlen(dl->name) == DATALINK_MAXNAME - 1)
1118 log_Printf(LogWARN, "Datalink name truncated to \"%s\"\n", dl->name);
1119 }
1120
1121 /* Make sure the name is unique ! */
1122 oname = NULL;
1123 do {
1124 for (cdl = bundle->links; cdl; cdl = cdl->next)
1125 if (!strcasecmp(dl->name, cdl->name)) {
1126 if (oname)
1127 free(datalink_NextName(dl));
1128 else
1129 oname = datalink_NextName(dl);
1130 break; /* Keep renaming 'till we have no conflicts */
1131 }
1132 } while (cdl);
1133
1134 if (oname) {
1135 log_Printf(LogPHASE, "Rename link %s to %s\n", oname, dl->name);
1136 free(oname);
1137 } else {
1138 dl->name = strdup(dl->name);
1139 free(iov[*niov].iov_base);
1140 }
1141 (*niov)++;
1142
1143 dl->desc.type = DATALINK_DESCRIPTOR;
1144 dl->desc.UpdateSet = datalink_UpdateSet;
1145 dl->desc.IsSet = datalink_IsSet;
1146 dl->desc.Read = datalink_Read;
1147 dl->desc.Write = datalink_Write;
1148
1149 mp_linkInit(&dl->mp);
1150 *dl->phone.list = '\0';
1151 dl->phone.next = NULL;
1152 dl->phone.alt = NULL;
1153 dl->phone.chosen = "N/A";
1154
1155 dl->bundle = bundle;
1156 dl->next = NULL;
1157 memset(&dl->dial_timer, '\0', sizeof dl->dial_timer);
1158 dl->dial_tries = 0;
1159 dl->reconnect_tries = 0;
1160 dl->parent = &bundle->fsm;
1161 dl->fsmp.LayerStart = datalink_LayerStart;
1162 dl->fsmp.LayerUp = datalink_LayerUp;
1163 dl->fsmp.LayerDown = datalink_LayerDown;
1164 dl->fsmp.LayerFinish = datalink_LayerFinish;
1165 dl->fsmp.object = dl;
1166
1167 retry = dl->pap.cfg.fsmretry;
1168 auth_Init(&dl->pap);
1169 dl->pap.cfg.fsmretry = retry;
1170
1171 retry = dl->chap.auth.cfg.fsmretry;
1172 auth_Init(&dl->chap.auth);
1173 dl->chap.auth.cfg.fsmretry = retry;
1174
1175 dl->physical = iov2modem(dl, iov, niov, maxiov, fd);
1176
1177 if (!dl->physical) {
1178 free(dl->name);
1179 free(dl);
1180 dl = NULL;
1181 } else {
1182 cbcp_Init(&dl->cbcp, dl->physical);
1183 chat_Init(&dl->chat, dl->physical, NULL, 1, NULL);
1184
1185 log_Printf(LogPHASE, "%s: Transferred in %s state\n",
1186 dl->name, datalink_State(dl));
1187 }
1188
1189 return dl;
1190}
1191
1192int
1193datalink2iov(struct datalink *dl, struct iovec *iov, int *niov, int maxiov,
1194 pid_t newpid)
1195{
1196 /* If `dl' is NULL, we're allocating before a Fromiov() */
1197 int link_fd;
1198
1199 if (dl) {
1200 timer_Stop(&dl->dial_timer);
1201 /* The following is purely for the sake of paranoia */
1202 cbcp_Down(&dl->cbcp);
1203 timer_Stop(&dl->pap.authtimer);
1204 timer_Stop(&dl->chap.auth.authtimer);
1205 }
1206
1207 if (*niov >= maxiov - 1) {
1208 log_Printf(LogERROR, "Toiov: No room for datalink !\n");
1209 if (dl) {
1210 free(dl->name);
1211 free(dl);
1212 }
1213 return -1;
1214 }
1215
1216 iov[*niov].iov_base = dl ? dl : malloc(sizeof *dl);
1217 iov[(*niov)++].iov_len = sizeof *dl;
1218 iov[*niov].iov_base =
1219 dl ? realloc(dl->name, DATALINK_MAXNAME) : malloc(DATALINK_MAXNAME);
1220 iov[(*niov)++].iov_len = DATALINK_MAXNAME;
1221
1222 link_fd = modem2iov(dl ? dl->physical : NULL, iov, niov, maxiov, newpid);
1223
1224 if (link_fd == -1 && dl) {
1225 free(dl->name);
1226 free(dl);
1227 }
1228
1229 return link_fd;
1230}
1231
1232void
1233datalink_Rename(struct datalink *dl, const char *name)
1234{
1235 free(dl->name);
1236 dl->physical->link.name = dl->name = strdup(name);
1237}
1238
1239char *
1240datalink_NextName(struct datalink *dl)
1241{
1242 int f, n;
1243 char *name, *oname;
1244
1245 n = strlen(dl->name);
1246 name = (char *)malloc(n+3);
1247 for (f = n - 1; f >= 0; f--)
1248 if (!isdigit(dl->name[f]))
1249 break;
1250 n = sprintf(name, "%.*s-", dl->name[f] == '-' ? f : f + 1, dl->name);
1251 sprintf(name + n, "%d", atoi(dl->name + f + 1) + 1);
1252 oname = dl->name;
1253 dl->name = name;
1254 /* our physical link name isn't updated (it probably isn't created yet) */
1255 return oname;
1256}
1257
1258int
1259datalink_SetMode(struct datalink *dl, int mode)
1260{
1261 if (!physical_SetMode(dl->physical, mode))
1262 return 0;
1263 if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED))
1264 dl->script.run = 0;
1265 if (dl->physical->type == PHYS_DIRECT)
1266 dl->reconnect_tries = 0;
1267 if (mode & (PHYS_DDIAL|PHYS_BACKGROUND) && dl->state <= DATALINK_READY)
1268 datalink_Up(dl, 1, 1);
1269 return 1;
1270}