datalink.c revision 42905
1126304Smtm/*- 2107143Sgordon * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> 3126304Smtm * All rights reserved. 4107143Sgordon * 5107143Sgordon * Redistribution and use in source and binary forms, with or without 6107143Sgordon * modification, are permitted provided that the following conditions 7107143Sgordon * are met: 8107143Sgordon * 1. Redistributions of source code must retain the above copyright 9107143Sgordon * notice, this list of conditions and the following disclaimer. 10107143Sgordon * 2. Redistributions in binary form must reproduce the above copyright 11107143Sgordon * notice, this list of conditions and the following disclaimer in the 12107143Sgordon * documentation and/or other materials provided with the distribution. 13107143Sgordon * 14107143Sgordon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15107143Sgordon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16107143Sgordon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17107143Sgordon * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18107143Sgordon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19107143Sgordon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20107143Sgordon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21107143Sgordon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22107143Sgordon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23107143Sgordon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24107143Sgordon * SUCH DAMAGE. 25107143Sgordon * 26107143Sgordon * $Id: datalink.c,v 1.24 1999/01/12 21:50:20 brian Exp $ 27107143Sgordon */ 28107143Sgordon 29107143Sgordon#include <sys/types.h> 30131866Sru#include <netinet/in.h> 31131866Sru#include <netinet/in_systm.h> 32364008S0mp#include <netinet/ip.h> 33107143Sgordon#include <sys/un.h> 34107143Sgordon 35107143Sgordon#include <ctype.h> 36107143Sgordon#include <stdio.h> 37107143Sgordon#include <stdlib.h> 38107143Sgordon#include <string.h> 39131866Sru#include <sys/uio.h> 40107143Sgordon#include <termios.h> 41131866Sru 42131866Sru#include "mbuf.h" 43107143Sgordon#include "log.h" 44107143Sgordon#include "defs.h" 45107143Sgordon#include "timer.h" 46107143Sgordon#include "fsm.h" 47107143Sgordon#include "lcp.h" 48107143Sgordon#include "descriptor.h" 49107143Sgordon#include "lqr.h" 50107143Sgordon#include "hdlc.h" 51107143Sgordon#include "async.h" 52107143Sgordon#include "throughput.h" 53107143Sgordon#include "ccp.h" 54107143Sgordon#include "link.h" 55107143Sgordon#include "physical.h" 56107143Sgordon#include "iplist.h" 57107143Sgordon#include "slcompress.h" 58107143Sgordon#include "ipcp.h" 59107143Sgordon#include "filter.h" 60159828Syar#include "mp.h" 61159828Syar#include "bundle.h" 62159367Sflz#include "chat.h" 63107143Sgordon#include "auth.h" 64159367Sflz#include "modem.h" 65157473Sflz#include "prompt.h" 66107143Sgordon#include "lcpproto.h" 67107143Sgordon#include "pap.h" 68131866Sru#include "chap.h" 69107143Sgordon#include "command.h" 70131866Sru#include "cbcp.h" 71107143Sgordon#include "datalink.h" 72107143Sgordon 73107143Sgordonstatic void datalink_LoginDone(struct datalink *); 74107143Sgordonstatic void datalink_NewState(struct datalink *, int); 75107143Sgordon 76131866Srustatic void 77107143Sgordondatalink_OpenTimeout(void *v) 78107143Sgordon{ 79107143Sgordon struct datalink *dl = (struct datalink *)v; 80107143Sgordon 81131866Sru timer_Stop(&dl->dial_timer); 82107143Sgordon if (dl->state == DATALINK_OPENING) 83131866Sru log_Printf(LogPHASE, "%s: Redial timer expired.\n", dl->name); 84107143Sgordon} 85107143Sgordon 86107143Sgordonstatic void 87107143Sgordondatalink_StartDialTimer(struct datalink *dl, int Timeout) 88107143Sgordon{ 89107143Sgordon timer_Stop(&dl->dial_timer); 90107143Sgordon 91107143Sgordon if (Timeout) { 92107143Sgordon if (Timeout > 0) 93107143Sgordon dl->dial_timer.load = Timeout * SECTICKS; 94107143Sgordon else 95203102Semaste dl->dial_timer.load = (random() % DIAL_TIMEOUT) * SECTICKS; 96107143Sgordon dl->dial_timer.func = datalink_OpenTimeout; 97203102Semaste dl->dial_timer.name = "dial"; 98107143Sgordon dl->dial_timer.arg = dl; 99107143Sgordon timer_Start(&dl->dial_timer); 100107143Sgordon if (dl->state == DATALINK_OPENING) 101107143Sgordon log_Printf(LogPHASE, "%s: Enter pause (%d) for redialing.\n", 102107143Sgordon dl->name, Timeout); 103131866Sru } 104107143Sgordon} 105107143Sgordon 106107143Sgordonstatic void 107107143Sgordondatalink_HangupDone(struct datalink *dl) 108107143Sgordon{ 109107143Sgordon if (dl->physical->type == PHYS_DEDICATED && !dl->bundle->CleaningUp && 110107143Sgordon physical_GetFD(dl->physical) != -1) { 111131866Sru /* Don't close our modem if the link is dedicated */ 112107143Sgordon datalink_LoginDone(dl); 113131866Sru return; 114107143Sgordon } 115107143Sgordon 116107143Sgordon modem_Close(dl->physical); 117107143Sgordon dl->phone.chosen = "N/A"; 118107143Sgordon 119107143Sgordon if (dl->cbcp.required) { 120107143Sgordon log_Printf(LogPHASE, "Call peer back on %s\n", dl->cbcp.fsm.phone); 121107143Sgordon dl->cfg.callback.opmask = 0; 122107143Sgordon strncpy(dl->cfg.phone.list, dl->cbcp.fsm.phone, 123131866Sru sizeof dl->cfg.phone.list - 1); 124107143Sgordon dl->cfg.phone.list[sizeof dl->cfg.phone.list - 1] = '\0'; 125131866Sru dl->phone.alt = dl->phone.next = NULL; 126107143Sgordon dl->reconnect_tries = dl->cfg.reconnect.max; 127131866Sru dl->dial_tries = dl->cfg.dial.max; 128131866Sru dl->script.run = 1; 129107143Sgordon dl->script.packetmode = 1; 130107143Sgordon if (!physical_SetMode(dl->physical, PHYS_BACKGROUND)) 131107143Sgordon log_Printf(LogERROR, "Oops - can't change mode to BACKGROUND (gulp) !\n"); 132107143Sgordon bundle_LinksRemoved(dl->bundle); 133107143Sgordon if (dl->cbcp.fsm.delay < dl->cfg.dial.timeout) 134107143Sgordon dl->cbcp.fsm.delay = dl->cfg.dial.timeout; 135131866Sru datalink_StartDialTimer(dl, dl->cbcp.fsm.delay); 136107143Sgordon cbcp_Down(&dl->cbcp); 137107143Sgordon datalink_NewState(dl, DATALINK_OPENING); 138107143Sgordon } else if (dl->bundle->CleaningUp || 139107143Sgordon (dl->physical->type == PHYS_DIRECT) || 140107143Sgordon ((!dl->dial_tries || (dl->dial_tries < 0 && !dl->reconnect_tries)) && 141107143Sgordon !(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)))) { 142107143Sgordon datalink_NewState(dl, DATALINK_CLOSED); 143107143Sgordon dl->dial_tries = -1; 144107143Sgordon dl->reconnect_tries = 0; 145107143Sgordon bundle_LinkClosed(dl->bundle, dl); 146107143Sgordon if (!dl->bundle->CleaningUp) 147107143Sgordon datalink_StartDialTimer(dl, dl->cfg.dial.timeout); 148107143Sgordon } else { 149131866Sru datalink_NewState(dl, DATALINK_OPENING); 150107143Sgordon if (dl->dial_tries < 0) { 151107143Sgordon datalink_StartDialTimer(dl, dl->cfg.reconnect.timeout); 152107143Sgordon dl->dial_tries = dl->cfg.dial.max; 153107143Sgordon dl->reconnect_tries--; 154107143Sgordon } else { 155107143Sgordon if (dl->phone.next == NULL) 156107143Sgordon datalink_StartDialTimer(dl, dl->cfg.dial.timeout); 157107143Sgordon else 158107143Sgordon datalink_StartDialTimer(dl, dl->cfg.dial.next_timeout); 159107143Sgordon } 160107143Sgordon } 161107143Sgordon} 162107143Sgordon 163107143Sgordonstatic const char * 164107143Sgordondatalink_ChoosePhoneNumber(struct datalink *dl) 165107143Sgordon{ 166131866Sru char *phone; 167131866Sru 168131866Sru if (dl->phone.alt == NULL) { 169107143Sgordon if (dl->phone.next == NULL) { 170131866Sru strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1); 171107143Sgordon dl->phone.list[sizeof dl->phone.list - 1] = '\0'; 172107143Sgordon dl->phone.next = dl->phone.list; 173107143Sgordon } 174131866Sru dl->phone.alt = strsep(&dl->phone.next, ":"); 175131866Sru } 176131866Sru phone = strsep(&dl->phone.alt, "|"); 177107143Sgordon dl->phone.chosen = *phone ? phone : "[NONE]"; 178131866Sru if (*phone) 179107143Sgordon log_Printf(LogPHASE, "Phone: %s\n", phone); 180107143Sgordon return phone; 181107143Sgordon} 182107143Sgordon 183173013Syarstatic void 184173013Syardatalink_LoginDone(struct datalink *dl) 185173013Syar{ 186173013Syar if (!dl->script.packetmode) { 187173013Syar dl->dial_tries = -1; 188131866Sru datalink_NewState(dl, DATALINK_READY); 189107143Sgordon } else if (modem_Raw(dl->physical, dl->bundle) < 0) { 190107143Sgordon dl->dial_tries = 0; 191107143Sgordon log_Printf(LogWARN, "datalink_LoginDone: Not connected.\n"); 192107143Sgordon if (dl->script.run) { 193107143Sgordon datalink_NewState(dl, DATALINK_HANGUP); 194126304Smtm modem_Offline(dl->physical); 195107143Sgordon chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 196107143Sgordon } else { 197107143Sgordon timer_Stop(&dl->physical->Timer); 198107143Sgordon if (dl->physical->type == PHYS_DEDICATED) 199151686Syar /* force a redial timeout */ 200131866Sru modem_Close(dl->physical); 201131866Sru datalink_HangupDone(dl); 202131866Sru } 203107143Sgordon } else { 204107143Sgordon dl->dial_tries = -1; 205107143Sgordon 206107143Sgordon hdlc_Init(&dl->physical->hdlc, &dl->physical->link.lcp); 207107143Sgordon async_Init(&dl->physical->async); 208107143Sgordon 209107143Sgordon lcp_Setup(&dl->physical->link.lcp, dl->state == DATALINK_READY ? 210107143Sgordon 0 : dl->physical->link.lcp.cfg.openmode); 211107143Sgordon ccp_Setup(&dl->physical->link.ccp); 212107143Sgordon 213107143Sgordon datalink_NewState(dl, DATALINK_LCP); 214107143Sgordon fsm_Up(&dl->physical->link.lcp.fsm); 215107143Sgordon fsm_Open(&dl->physical->link.lcp.fsm); 216107143Sgordon } 217131866Sru} 218107143Sgordon 219107143Sgordonstatic int 220107143Sgordondatalink_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, 221107143Sgordon int *n) 222108317Sschweikh{ 223107143Sgordon struct datalink *dl = descriptor2datalink(d); 224131866Sru int result; 225107143Sgordon 226131866Sru result = 0; 227107143Sgordon switch (dl->state) { 228107143Sgordon case DATALINK_CLOSED: 229107143Sgordon if ((dl->physical->type & 230131530Sru (PHYS_DIRECT|PHYS_DEDICATED|PHYS_BACKGROUND|PHYS_DDIAL)) && 231131530Sru !bundle_IsDead(dl->bundle)) 232107143Sgordon /* 233107143Sgordon * Our first time in - DEDICATED & DDIAL never come down, and 234107143Sgordon * DIRECT & BACKGROUND get deleted when they enter DATALINK_CLOSED. 235131866Sru * Go to DATALINK_OPENING via datalink_Up() and fall through. 236131866Sru */ 237107143Sgordon datalink_Up(dl, 1, 1); 238131866Sru else 239107143Sgordon break; 240107143Sgordon /* fall through */ 241107143Sgordon 242107143Sgordon case DATALINK_OPENING: 243131866Sru if (dl->dial_timer.state != TIMER_RUNNING) { 244107143Sgordon if (--dl->dial_tries < 0) 245107143Sgordon dl->dial_tries = 0; 246107143Sgordon if (modem_Open(dl->physical, dl->bundle) >= 0) { 247107143Sgordon log_WritePrompts(dl, "%s: Entering terminal mode on %s\r\n" 248131866Sru "Type `~?' for help\r\n", dl->name, 249107143Sgordon dl->physical->name.full); 250131866Sru if (dl->script.run) { 251107143Sgordon datalink_NewState(dl, DATALINK_DIAL); 252107143Sgordon chat_Init(&dl->chat, dl->physical, dl->cfg.script.dial, 1, 253180628Slme datalink_ChoosePhoneNumber(dl)); 254107143Sgordon if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 255107143Sgordon dl->cfg.dial.max) 256131530Sru log_Printf(LogCHAT, "%s: Dial attempt %u of %d\n", 257131530Sru dl->name, dl->cfg.dial.max - dl->dial_tries, 258107143Sgordon dl->cfg.dial.max); 259107143Sgordon } else 260131866Sru datalink_LoginDone(dl); 261363727S0mp return datalink_UpdateSet(d, r, w, e, n); 262363727S0mp } else { 263363732S0mp if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 264363727S0mp dl->cfg.dial.max) 265363732S0mp log_Printf(LogCHAT, "Failed to open modem (attempt %u of %d)\n", 266363727S0mp dl->cfg.dial.max - dl->dial_tries, dl->cfg.dial.max); 267363727S0mp else 268107143Sgordon log_Printf(LogCHAT, "Failed to open modem\n"); 269131530Sru 270131530Sru if (dl->bundle->CleaningUp || 271107143Sgordon (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 272107143Sgordon dl->cfg.dial.max && dl->dial_tries == 0)) { 273107143Sgordon datalink_NewState(dl, DATALINK_CLOSED); 274131866Sru dl->reconnect_tries = 0; 275107143Sgordon dl->dial_tries = -1; 276107143Sgordon log_WritePrompts(dl, "Failed to open %s\n", 277107143Sgordon dl->physical->name.full); 278107143Sgordon bundle_LinkClosed(dl->bundle, dl); 279131866Sru } 280107143Sgordon if (!dl->bundle->CleaningUp) { 281131866Sru log_WritePrompts(dl, "Failed to open %s, pause %d seconds\n", 282107143Sgordon dl->physical->name.full, dl->cfg.dial.timeout); 283108317Sschweikh datalink_StartDialTimer(dl, dl->cfg.dial.timeout); 284107143Sgordon } 285107143Sgordon } 286107143Sgordon } 287107143Sgordon break; 288131866Sru 289159828Syar case DATALINK_HANGUP: 290159828Syar case DATALINK_DIAL: 291159828Syar case DATALINK_LOGIN: 292159828Syar result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n); 293159828Syar switch (dl->chat.state) { 294159828Syar case CHAT_DONE: 295159828Syar /* script succeeded */ 296159828Syar chat_Destroy(&dl->chat); 297159828Syar switch(dl->state) { 298159828Syar case DATALINK_HANGUP: 299159828Syar datalink_HangupDone(dl); 300159828Syar break; 301159828Syar case DATALINK_DIAL: 302159828Syar datalink_NewState(dl, DATALINK_LOGIN); 303159367Sflz chat_Init(&dl->chat, dl->physical, dl->cfg.script.login, 0, NULL); 304107143Sgordon return datalink_UpdateSet(d, r, w, e, n); 305159367Sflz case DATALINK_LOGIN: 306107143Sgordon dl->phone.alt = NULL; 307107143Sgordon datalink_LoginDone(dl); 308161530Sflz return datalink_UpdateSet(d, r, w, e, n); 309107143Sgordon } 310161530Sflz break; 311161530Sflz case CHAT_FAILED: 312161530Sflz /* Going down - script failed */ 313107143Sgordon log_Printf(LogWARN, "Chat script failed\n"); 314107143Sgordon chat_Destroy(&dl->chat); 315107143Sgordon switch(dl->state) { 316107143Sgordon case DATALINK_HANGUP: 317107143Sgordon datalink_HangupDone(dl); 318159367Sflz break; 319157473Sflz case DATALINK_DIAL: 320157473Sflz case DATALINK_LOGIN: 321157473Sflz datalink_NewState(dl, DATALINK_HANGUP); 322157473Sflz modem_Offline(dl->physical); /* Is this required ? */ 323157473Sflz chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 324159367Sflz return datalink_UpdateSet(d, r, w, e, n); 325157473Sflz } 326157473Sflz break; 327157473Sflz } 328157473Sflz break; 329107143Sgordon 330107143Sgordon case DATALINK_READY: 331107143Sgordon case DATALINK_LCP: 332107143Sgordon case DATALINK_AUTH: 333107143Sgordon case DATALINK_CBCP: 334131866Sru case DATALINK_OPEN: 335107143Sgordon result = descriptor_UpdateSet(&dl->physical->desc, r, w, e, n); 336107143Sgordon break; 337131866Sru } 338107143Sgordon return result; 339131866Sru} 340107143Sgordon 341107143Sgordonint 342107143Sgordondatalink_RemoveFromSet(struct datalink *dl, fd_set *r, fd_set *w, fd_set *e) 343107143Sgordon{ 344131866Sru return physical_RemoveFromSet(dl->physical, r, w, e); 345230007Srea} 346131866Sru 347131866Srustatic int 348107143Sgordondatalink_IsSet(struct descriptor *d, const fd_set *fdset) 349107143Sgordon{ 350107143Sgordon struct datalink *dl = descriptor2datalink(d); 351107143Sgordon 352107143Sgordon switch (dl->state) { 353107143Sgordon case DATALINK_CLOSED: 354107143Sgordon case DATALINK_OPENING: 355107143Sgordon break; 356107143Sgordon 357107143Sgordon case DATALINK_HANGUP: 358107143Sgordon case DATALINK_DIAL: 359107143Sgordon case DATALINK_LOGIN: 360107143Sgordon return descriptor_IsSet(&dl->chat.desc, fdset); 361107143Sgordon 362107143Sgordon case DATALINK_READY: 363107143Sgordon case DATALINK_LCP: 364107143Sgordon case DATALINK_AUTH: 365131866Sru case DATALINK_CBCP: 366131866Sru case DATALINK_OPEN: 367126304Smtm return descriptor_IsSet(&dl->physical->desc, fdset); 368126304Smtm } 369126304Smtm return 0; 370126304Smtm} 371126304Smtm 372126304Smtmstatic void 373126304Smtmdatalink_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 374126304Smtm{ 375126304Smtm struct datalink *dl = descriptor2datalink(d); 376131866Sru 377126304Smtm switch (dl->state) { 378126304Smtm case DATALINK_CLOSED: 379126304Smtm case DATALINK_OPENING: 380131866Sru break; 381131866Sru 382126304Smtm case DATALINK_HANGUP: 383131866Sru case DATALINK_DIAL: 384126304Smtm case DATALINK_LOGIN: 385131866Sru descriptor_Read(&dl->chat.desc, bundle, fdset); 386126304Smtm break; 387255809Sdes 388255809Sdes case DATALINK_READY: 389255809Sdes case DATALINK_LCP: 390131866Sru case DATALINK_AUTH: 391126304Smtm case DATALINK_CBCP: 392126304Smtm case DATALINK_OPEN: 393126304Smtm descriptor_Read(&dl->physical->desc, bundle, fdset); 394126304Smtm break; 395126304Smtm } 396107143Sgordon} 397131866Sru 398107143Sgordonstatic int 399131866Srudatalink_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 400126304Smtm{ 401131866Sru struct datalink *dl = descriptor2datalink(d); 402131866Sru int result = 0; 403126304Smtm 404131866Sru switch (dl->state) { 405126304Smtm case DATALINK_CLOSED: 406126304Smtm case DATALINK_OPENING: 407107143Sgordon break; 408126304Smtm 409131866Sru case DATALINK_HANGUP: 410126304Smtm case DATALINK_DIAL: 411107143Sgordon case DATALINK_LOGIN: 412107143Sgordon result = descriptor_Write(&dl->chat.desc, bundle, fdset); 413131866Sru break; 414131866Sru 415107143Sgordon case DATALINK_READY: 416107143Sgordon case DATALINK_LCP: 417131866Sru case DATALINK_AUTH: 418131866Sru case DATALINK_CBCP: 419107143Sgordon case DATALINK_OPEN: 420131866Sru result = descriptor_Write(&dl->physical->desc, bundle, fdset); 421131866Sru break; 422131866Sru } 423107143Sgordon 424131866Sru return result; 425107143Sgordon} 426131866Sru 427107143Sgordonstatic void 428131866Srudatalink_ComeDown(struct datalink *dl, int how) 429126304Smtm{ 430131866Sru if (how != CLOSE_NORMAL) { 431126304Smtm dl->dial_tries = -1; 432131866Sru dl->reconnect_tries = 0; 433131866Sru if (dl->state >= DATALINK_READY && how == CLOSE_LCP) 434131866Sru dl->stayonline = 1; 435131866Sru } 436230007Srea 437230007Srea if (dl->state >= DATALINK_READY && dl->stayonline) { 438230007Srea dl->stayonline = 0; 439230007Srea timer_Stop(&dl->physical->Timer); 440230007Srea datalink_NewState(dl, DATALINK_READY); 441230007Srea } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) { 442230007Srea modem_Offline(dl->physical); 443230007Srea chat_Destroy(&dl->chat); 444230007Srea if (dl->script.run && dl->state != DATALINK_OPENING) { 445230007Srea datalink_NewState(dl, DATALINK_HANGUP); 446230007Srea chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 447230007Srea } else 448230007Srea datalink_HangupDone(dl); 449230007Srea } 450230007Srea} 451230007Srea 452107143Sgordonstatic void 453107143Sgordondatalink_LayerStart(void *v, struct fsm *fp) 454107143Sgordon{ 455107143Sgordon /* The given FSM is about to start up ! */ 456107143Sgordon struct datalink *dl = (struct datalink *)v; 457131866Sru 458131866Sru if (fp->proto == PROTO_LCP) 459107143Sgordon (*dl->parent->LayerStart)(dl->parent->object, fp); 460107143Sgordon} 461131866Sru 462107143Sgordonstatic void 463131866Srudatalink_LayerUp(void *v, struct fsm *fp) 464107143Sgordon{ 465107143Sgordon /* The given fsm is now up */ 466107143Sgordon struct datalink *dl = (struct datalink *)v; 467131866Sru 468107143Sgordon if (fp->proto == PROTO_LCP) { 469107143Sgordon datalink_GotAuthname(dl, "", 0); 470131866Sru dl->physical->link.lcp.auth_ineed = dl->physical->link.lcp.want_auth; 471107143Sgordon dl->physical->link.lcp.auth_iwait = dl->physical->link.lcp.his_auth; 472155907Syar if (dl->physical->link.lcp.his_auth || dl->physical->link.lcp.want_auth) { 473155907Syar if (bundle_Phase(dl->bundle) == PHASE_ESTABLISH) 474131866Sru bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE); 475107143Sgordon log_Printf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name, 476131866Sru Auth2Nam(dl->physical->link.lcp.his_auth), 477131866Sru Auth2Nam(dl->physical->link.lcp.want_auth)); 478131866Sru if (dl->physical->link.lcp.his_auth == PROTO_PAP) 479151686Syar auth_StartChallenge(&dl->pap, dl->physical, pap_SendChallenge); 480131866Sru if (dl->physical->link.lcp.want_auth == PROTO_CHAP) 481131866Sru auth_StartChallenge(&dl->chap.auth, dl->physical, chap_SendChallenge); 482151686Syar } else 483107143Sgordon datalink_AuthOk(dl); 484107143Sgordon } 485151686Syar} 486131866Sru 487131866Sruvoid 488131866Srudatalink_GotAuthname(struct datalink *dl, const char *name, int len) 489107143Sgordon{ 490107143Sgordon if (len >= sizeof dl->peer.authname) 491131866Sru len = sizeof dl->peer.authname - 1; 492131866Sru strncpy(dl->peer.authname, name, len); 493107143Sgordon dl->peer.authname[len] = '\0'; 494131866Sru} 495131866Sru 496107143Sgordonvoid 497107143Sgordondatalink_NCPUp(struct datalink *dl) 498131866Sru{ 499151686Syar int ccpok = ccp_SetOpenMode(&dl->physical->link.ccp); 500131866Sru 501131866Sru if (dl->physical->link.lcp.want_mrru && dl->physical->link.lcp.his_mrru) { 502131866Sru /* we've authenticated in multilink mode ! */ 503107143Sgordon switch (mp_Up(&dl->bundle->ncp.mp, dl)) { 504107143Sgordon case MP_LINKSENT: 505131866Sru /* We've handed the link off to another ppp (well, we will soon) ! */ 506151686Syar return; 507131866Sru case MP_UP: 508131866Sru /* First link in the bundle */ 509131866Sru auth_Select(dl->bundle, dl->peer.authname); 510107143Sgordon /* fall through */ 511131866Sru case MP_ADDED: 512107143Sgordon /* We're in multilink mode ! */ 513107143Sgordon dl->physical->link.ccp.fsm.open_mode = OPEN_PASSIVE; /* override */ 514131866Sru break; 515131866Sru case MP_FAILED: 516107143Sgordon datalink_AuthNotOk(dl); 517165566Syar return; 518160615Syar } 519160615Syar } else if (bundle_Phase(dl->bundle) == PHASE_NETWORK) { 520131866Sru log_Printf(LogPHASE, "%s: Already in NETWORK phase\n", dl->name); 521107143Sgordon datalink_NewState(dl, DATALINK_OPEN); 522165566Syar (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 523160615Syar return; 524160615Syar } else { 525165566Syar dl->bundle->ncp.mp.peer = dl->peer; 526165566Syar ipcp_SetLink(&dl->bundle->ncp.ipcp, &dl->physical->link); 527165566Syar auth_Select(dl->bundle, dl->peer.authname); 528165566Syar } 529165566Syar 530165566Syar if (ccpok) { 531165566Syar fsm_Up(&dl->physical->link.ccp.fsm); 532165566Syar fsm_Open(&dl->physical->link.ccp.fsm); 533165566Syar } 534165566Syar datalink_NewState(dl, DATALINK_OPEN); 535165566Syar bundle_NewPhase(dl->bundle, PHASE_NETWORK); 536165566Syar (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 537165566Syar} 538165566Syar 539165566Syarvoid 540165566Syardatalink_CBCPComplete(struct datalink *dl) 541165566Syar{ 542165566Syar datalink_NewState(dl, DATALINK_LCP); 543165566Syar fsm_Close(&dl->physical->link.lcp.fsm); 544165566Syar} 545165566Syar 546165566Syarvoid 547165566Syardatalink_CBCPFailed(struct datalink *dl) 548165566Syar{ 549165566Syar cbcp_Down(&dl->cbcp); 550165566Syar datalink_CBCPComplete(dl); 551165566Syar} 552165566Syar 553131866Sruvoid 554107143Sgordondatalink_AuthOk(struct datalink *dl) 555107143Sgordon{ 556107143Sgordon if ((dl->physical->link.lcp.his_callback.opmask & 557165566Syar CALLBACK_BIT(CALLBACK_CBCP) || 558160615Syar dl->physical->link.lcp.want_callback.opmask & 559160615Syar CALLBACK_BIT(CALLBACK_CBCP)) && 560131866Sru !(dl->physical->link.lcp.want_callback.opmask & 561107143Sgordon CALLBACK_BIT(CALLBACK_AUTH))) { 562107143Sgordon /* We must have agreed CBCP if AUTH isn't there any more */ 563107143Sgordon datalink_NewState(dl, DATALINK_CBCP); 564131866Sru cbcp_Up(&dl->cbcp); 565107143Sgordon } else if (dl->physical->link.lcp.want_callback.opmask) { 566131866Sru /* It's not CBCP */ 567107143Sgordon log_Printf(LogPHASE, "%s: Shutdown and await peer callback\n", dl->name); 568131866Sru datalink_NewState(dl, DATALINK_LCP); 569107143Sgordon fsm_Close(&dl->physical->link.lcp.fsm); 570107143Sgordon } else 571107143Sgordon switch (dl->physical->link.lcp.his_callback.opmask) { 572131866Sru case 0: 573107143Sgordon datalink_NCPUp(dl); 574107143Sgordon break; 575107143Sgordon 576272974Shrs case CALLBACK_BIT(CALLBACK_AUTH): 577272974Shrs auth_SetPhoneList(dl->peer.authname, dl->cbcp.fsm.phone, 578272974Shrs sizeof dl->cbcp.fsm.phone); 579272974Shrs if (*dl->cbcp.fsm.phone == '\0' || !strcmp(dl->cbcp.fsm.phone, "*")) { 580272974Shrs log_Printf(LogPHASE, "%s: %s cannot be called back\n", dl->name, 581272974Shrs dl->peer.authname); 582272974Shrs *dl->cbcp.fsm.phone = '\0'; 583272974Shrs } else { 584272974Shrs char *ptr = strchr(dl->cbcp.fsm.phone, ','); 585272974Shrs if (ptr) 586272974Shrs *ptr = '\0'; /* Call back on the first number */ 587272974Shrs log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, 588272974Shrs dl->cbcp.fsm.phone); 589272974Shrs dl->cbcp.required = 1; 590272974Shrs } 591272974Shrs dl->cbcp.fsm.delay = 0; 592131866Sru datalink_NewState(dl, DATALINK_LCP); 593107143Sgordon fsm_Close(&dl->physical->link.lcp.fsm); 594131866Sru break; 595107143Sgordon 596107143Sgordon case CALLBACK_BIT(CALLBACK_E164): 597107143Sgordon strncpy(dl->cbcp.fsm.phone, dl->physical->link.lcp.his_callback.msg, 598107143Sgordon sizeof dl->cbcp.fsm.phone - 1); 599107143Sgordon dl->cbcp.fsm.phone[sizeof dl->cbcp.fsm.phone - 1] = '\0'; 600107143Sgordon log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, 601107143Sgordon dl->cbcp.fsm.phone); 602107143Sgordon dl->cbcp.required = 1; 603107143Sgordon dl->cbcp.fsm.delay = 0; 604131866Sru datalink_NewState(dl, DATALINK_LCP); 605107143Sgordon fsm_Close(&dl->physical->link.lcp.fsm); 606107143Sgordon break; 607131866Sru 608107143Sgordon default: 609107143Sgordon log_Printf(LogPHASE, "%s: Oops - Should have NAK'd peer callback !\n", 610107143Sgordon dl->name); 611107143Sgordon datalink_NewState(dl, DATALINK_LCP); 612295949Saraujo fsm_Close(&dl->physical->link.lcp.fsm); 613295949Saraujo break; 614295949Saraujo } 615295949Saraujo} 616295949Saraujo 617295949Saraujovoid 618295949Saraujodatalink_AuthNotOk(struct datalink *dl) 619295949Saraujo{ 620295949Saraujo datalink_NewState(dl, DATALINK_LCP); 621295949Saraujo fsm_Close(&dl->physical->link.lcp.fsm); 622155907Syar} 623155907Syar 624155907Syarstatic void 625155907Syardatalink_LayerDown(void *v, struct fsm *fp) 626155907Syar{ 627155907Syar /* The given FSM has been told to come down */ 628155907Syar struct datalink *dl = (struct datalink *)v; 629155907Syar 630155907Syar if (fp->proto == PROTO_LCP) { 631155907Syar switch (dl->state) { 632155907Syar case DATALINK_OPEN: 633155907Syar peerid_Init(&dl->peer); 634155907Syar fsm2initial(&dl->physical->link.ccp.fsm); 635131866Sru datalink_NewState(dl, DATALINK_LCP); /* before parent TLD */ 636107143Sgordon (*dl->parent->LayerDown)(dl->parent->object, fp); 637131866Sru /* fall through (just in case) */ 638107143Sgordon 639177796Sskv case DATALINK_CBCP: 640107143Sgordon if (!dl->cbcp.required) 641131866Sru cbcp_Down(&dl->cbcp); 642107143Sgordon /* fall through (just in case) */ 643107143Sgordon 644107143Sgordon case DATALINK_AUTH: 645107143Sgordon timer_Stop(&dl->pap.authtimer); 646107143Sgordon timer_Stop(&dl->chap.auth.authtimer); 647107143Sgordon } 648131866Sru datalink_NewState(dl, DATALINK_LCP); 649107143Sgordon } 650131866Sru} 651107143Sgordon 652131866Srustatic void 653107143Sgordondatalink_LayerFinish(void *v, struct fsm *fp) 654131866Sru{ 655107143Sgordon /* The given fsm is now down */ 656272974Shrs struct datalink *dl = (struct datalink *)v; 657272974Shrs 658272974Shrs if (fp->proto == PROTO_LCP) { 659272974Shrs fsm2initial(fp); 660272974Shrs (*dl->parent->LayerFinish)(dl->parent->object, fp); 661272974Shrs datalink_ComeDown(dl, CLOSE_NORMAL); 662272974Shrs } else if (fp->state == ST_CLOSED && fp->open_mode == OPEN_PASSIVE) 663272974Shrs fsm_Open(fp); /* CCP goes to ST_STOPPED */ 664131866Sru} 665107143Sgordon 666107143Sgordonstruct datalink * 667131866Srudatalink_Create(const char *name, struct bundle *bundle, int type) 668107143Sgordon{ 669131866Sru struct datalink *dl; 670107143Sgordon 671107143Sgordon dl = (struct datalink *)malloc(sizeof(struct datalink)); 672107143Sgordon if (dl == NULL) 673107143Sgordon return dl; 674107143Sgordon 675131866Sru dl->desc.type = DATALINK_DESCRIPTOR; 676107143Sgordon dl->desc.UpdateSet = datalink_UpdateSet; 677131866Sru dl->desc.IsSet = datalink_IsSet; 678107143Sgordon dl->desc.Read = datalink_Read; 679131866Sru dl->desc.Write = datalink_Write; 680107143Sgordon 681108317Sschweikh dl->state = DATALINK_CLOSED; 682107143Sgordon 683131866Sru *dl->cfg.script.dial = '\0'; 684107143Sgordon *dl->cfg.script.login = '\0'; 685131866Sru *dl->cfg.script.hangup = '\0'; 686107143Sgordon *dl->cfg.phone.list = '\0'; 687107143Sgordon *dl->phone.list = '\0'; 688107143Sgordon dl->phone.next = NULL; 689131866Sru dl->phone.alt = NULL; 690107143Sgordon dl->phone.chosen = "N/A"; 691131866Sru dl->stayonline = 0; 692107143Sgordon dl->script.run = 1; 693107143Sgordon dl->script.packetmode = 1; 694107143Sgordon mp_linkInit(&dl->mp); 695107143Sgordon 696107143Sgordon dl->bundle = bundle; 697107143Sgordon dl->next = NULL; 698107143Sgordon 699107143Sgordon memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 700131866Sru 701107143Sgordon dl->dial_tries = 0; 702131866Sru dl->cfg.dial.max = 1; 703131866Sru dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 704107143Sgordon dl->cfg.dial.timeout = DIAL_TIMEOUT; 705107143Sgordon 706131866Sru dl->reconnect_tries = 0; 707107143Sgordon dl->cfg.reconnect.max = 0; 708131866Sru dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT; 709107143Sgordon 710131866Sru dl->cfg.callback.opmask = 0; 711107143Sgordon dl->cfg.cbcp.delay = 0; 712131866Sru *dl->cfg.cbcp.phone = '\0'; 713131866Sru dl->cfg.cbcp.fsmretry = DEF_FSMRETRY; 714107143Sgordon 715131866Sru dl->name = strdup(name); 716107143Sgordon peerid_Init(&dl->peer); 717107143Sgordon dl->parent = &bundle->fsm; 718107143Sgordon dl->fsmp.LayerStart = datalink_LayerStart; 719107143Sgordon dl->fsmp.LayerUp = datalink_LayerUp; 720107143Sgordon dl->fsmp.LayerDown = datalink_LayerDown; 721131866Sru dl->fsmp.LayerFinish = datalink_LayerFinish; 722107143Sgordon dl->fsmp.object = dl; 723107143Sgordon 724107143Sgordon auth_Init(&dl->pap); 725131866Sru auth_Init(&dl->chap.auth); 726107143Sgordon 727131866Sru if ((dl->physical = modem_Create(dl, type)) == NULL) { 728107143Sgordon free(dl->name); 729131866Sru free(dl); 730131866Sru return NULL; 731107143Sgordon } 732151685Syar cbcp_Init(&dl->cbcp, dl->physical); 733151685Syar chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 734151685Syar 735151685Syar log_Printf(LogPHASE, "%s: Created in %s state\n", 736151685Syar dl->name, datalink_State(dl)); 737151685Syar 738151685Syar return dl; 739151685Syar} 740151685Syar 741151685Syarstruct datalink * 742131866Srudatalink_Clone(struct datalink *odl, const char *name) 743107143Sgordon{ 744131866Sru struct datalink *dl; 745107143Sgordon 746131866Sru dl = (struct datalink *)malloc(sizeof(struct datalink)); 747107143Sgordon if (dl == NULL) 748131866Sru return dl; 749107143Sgordon 750131866Sru dl->desc.type = DATALINK_DESCRIPTOR; 751107143Sgordon dl->desc.UpdateSet = datalink_UpdateSet; 752131866Sru dl->desc.IsSet = datalink_IsSet; 753107143Sgordon dl->desc.Read = datalink_Read; 754131866Sru dl->desc.Write = datalink_Write; 755107143Sgordon 756131866Sru dl->state = DATALINK_CLOSED; 757107143Sgordon 758107143Sgordon memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg); 759107143Sgordon mp_linkInit(&dl->mp); 760107143Sgordon *dl->phone.list = '\0'; 761107143Sgordon dl->phone.next = NULL; 762107143Sgordon dl->phone.alt = NULL; 763131866Sru dl->phone.chosen = "N/A"; 764107143Sgordon dl->bundle = odl->bundle; 765107143Sgordon dl->next = NULL; 766107143Sgordon memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 767107143Sgordon dl->dial_tries = 0; 768131866Sru dl->reconnect_tries = 0; 769107143Sgordon dl->name = strdup(name); 770107143Sgordon peerid_Init(&dl->peer); 771107143Sgordon dl->parent = odl->parent; 772343046Skevans memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp); 773131866Sru dl->fsmp.object = dl; 774107143Sgordon auth_Init(&dl->pap); 775131866Sru dl->pap.cfg.fsmretry = odl->pap.cfg.fsmretry; 776107143Sgordon 777131866Sru auth_Init(&dl->chap.auth); 778108317Sschweikh dl->chap.auth.cfg.fsmretry = odl->chap.auth.cfg.fsmretry; 779107143Sgordon 780131866Sru if ((dl->physical = modem_Create(dl, PHYS_INTERACTIVE)) == NULL) { 781107143Sgordon free(dl->name); 782107143Sgordon free(dl); 783107143Sgordon return NULL; 784131866Sru } 785107143Sgordon memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg); 786343046Skevans memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg, 787343046Skevans sizeof dl->physical->link.lcp.cfg); 788131866Sru memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg, 789107143Sgordon sizeof dl->physical->link.ccp.cfg); 790131866Sru memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg, 791107143Sgordon sizeof dl->physical->async.cfg); 792131866Sru 793107143Sgordon cbcp_Init(&dl->cbcp, dl->physical); 794131866Sru chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 795107143Sgordon 796131866Sru log_Printf(LogPHASE, "%s: Cloned in %s state\n", 797107143Sgordon dl->name, datalink_State(dl)); 798131866Sru 799107143Sgordon return dl; 800107143Sgordon} 801131866Sru 802107143Sgordonstruct datalink * 803107143Sgordondatalink_Destroy(struct datalink *dl) 804107143Sgordon{ 805107143Sgordon struct datalink *result; 806107143Sgordon 807107143Sgordon if (dl->state != DATALINK_CLOSED) { 808107143Sgordon log_Printf(LogERROR, "Oops, destroying a datalink in state %s\n", 809107143Sgordon datalink_State(dl)); 810107143Sgordon switch (dl->state) { 811107143Sgordon case DATALINK_HANGUP: 812131866Sru case DATALINK_DIAL: 813131866Sru case DATALINK_LOGIN: 814131866Sru chat_Destroy(&dl->chat); /* Gotta blat the timers ! */ 815131866Sru break; 816131866Sru } 817131866Sru } 818131866Sru 819131866Sru timer_Stop(&dl->dial_timer); 820131866Sru result = dl->next; 821131866Sru modem_Destroy(dl->physical); 822131866Sru free(dl->name); 823131866Sru free(dl); 824131866Sru 825107143Sgordon return result; 826107143Sgordon} 827107143Sgordon 828107143Sgordonvoid 829107143Sgordondatalink_Up(struct datalink *dl, int runscripts, int packetmode) 830107143Sgordon{ 831107143Sgordon if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 832107143Sgordon /* Ignore scripts */ 833107143Sgordon runscripts = 0; 834107143Sgordon 835107143Sgordon switch (dl->state) { 836107143Sgordon case DATALINK_CLOSED: 837107143Sgordon if (bundle_Phase(dl->bundle) == PHASE_DEAD || 838107143Sgordon bundle_Phase(dl->bundle) == PHASE_TERMINATE) 839107143Sgordon bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 840107143Sgordon datalink_NewState(dl, DATALINK_OPENING); 841107143Sgordon dl->reconnect_tries = 842131866Sru dl->physical->type == PHYS_DIRECT ? 0 : dl->cfg.reconnect.max; 843107143Sgordon dl->dial_tries = dl->cfg.dial.max; 844131866Sru dl->script.run = runscripts; 845107143Sgordon dl->script.packetmode = packetmode; 846107143Sgordon break; 847107143Sgordon 848107143Sgordon case DATALINK_OPENING: 849107143Sgordon if (!dl->script.run && runscripts) 850107143Sgordon dl->script.run = 1; 851107143Sgordon /* fall through */ 852107143Sgordon 853107143Sgordon case DATALINK_DIAL: 854131866Sru case DATALINK_LOGIN: 855107143Sgordon case DATALINK_READY: 856107143Sgordon if (!dl->script.packetmode && packetmode) { 857107143Sgordon dl->script.packetmode = 1; 858107143Sgordon if (dl->state == DATALINK_READY) 859107143Sgordon datalink_LoginDone(dl); 860107143Sgordon } 861107143Sgordon break; 862107143Sgordon } 863169668Smtm} 864169668Smtm 865169668Smtmvoid 866173013Syardatalink_Close(struct datalink *dl, int how) 867173013Syar{ 868364008S0mp /* Please close */ 869364008S0mp switch (dl->state) { 870364008S0mp case DATALINK_OPEN: 871364008S0mp peerid_Init(&dl->peer); 872364008S0mp fsm2initial(&dl->physical->link.ccp.fsm); 873169668Smtm /* fall through */ 874173013Syar 875173013Syar case DATALINK_CBCP: 876173013Syar case DATALINK_AUTH: 877169668Smtm case DATALINK_LCP: 878173013Syar fsm_Close(&dl->physical->link.lcp.fsm); 879173013Syar if (how != CLOSE_NORMAL) { 880173013Syar dl->dial_tries = -1; 881131866Sru dl->reconnect_tries = 0; 882107143Sgordon if (how == CLOSE_LCP) 883107143Sgordon dl->stayonline = 1; 884131866Sru } 885107143Sgordon break; 886107143Sgordon 887107143Sgordon default: 888107143Sgordon datalink_ComeDown(dl, how); 889131866Sru } 890107143Sgordon} 891107143Sgordon 892107143Sgordonvoid 893107143Sgordondatalink_Down(struct datalink *dl, int how) 894107143Sgordon{ 895131866Sru /* Carrier is lost */ 896107143Sgordon switch (dl->state) { 897131866Sru case DATALINK_OPEN: 898107143Sgordon peerid_Init(&dl->peer); 899107143Sgordon fsm2initial(&dl->physical->link.ccp.fsm); 900107143Sgordon /* fall through */ 901107143Sgordon 902131866Sru case DATALINK_CBCP: 903107143Sgordon case DATALINK_AUTH: 904107143Sgordon case DATALINK_LCP: 905107143Sgordon fsm2initial(&dl->physical->link.lcp.fsm); 906107143Sgordon /* fall through */ 907107143Sgordon 908107143Sgordon default: 909107143Sgordon datalink_ComeDown(dl, how); 910107143Sgordon } 911107143Sgordon} 912107143Sgordon 913131866Sruvoid 914107143Sgordondatalink_StayDown(struct datalink *dl) 915131866Sru{ 916107143Sgordon dl->reconnect_tries = 0; 917107143Sgordon} 918107143Sgordon 919107143Sgordonvoid 920107143Sgordondatalink_DontHangup(struct datalink *dl) 921107143Sgordon{ 922131866Sru if (dl->state >= DATALINK_LCP) 923107143Sgordon dl->stayonline = 1; 924131866Sru} 925107143Sgordon 926107143Sgordonint 927datalink_Show(struct cmdargs const *arg) 928{ 929 prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name); 930 prompt_Printf(arg->prompt, " State: %s\n", 931 datalink_State(arg->cx)); 932 prompt_Printf(arg->prompt, " CHAP Encryption: %s\n", 933 arg->cx->chap.using_MSChap ? "MSChap" : "MD5" ); 934 prompt_Printf(arg->prompt, " Peer name: "); 935 if (*arg->cx->peer.authname) 936 prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname); 937 else if (arg->cx->state == DATALINK_OPEN) 938 prompt_Printf(arg->prompt, "None requested\n"); 939 else 940 prompt_Printf(arg->prompt, "N/A\n"); 941 prompt_Printf(arg->prompt, " Discriminator: %s\n", 942 mp_Enddisc(arg->cx->peer.enddisc.class, 943 arg->cx->peer.enddisc.address, 944 arg->cx->peer.enddisc.len)); 945 946 prompt_Printf(arg->prompt, "\nDefaults:\n"); 947 prompt_Printf(arg->prompt, " Phone List: %s\n", 948 arg->cx->cfg.phone.list); 949 if (arg->cx->cfg.dial.max) 950 prompt_Printf(arg->prompt, " Dial tries: %d, delay ", 951 arg->cx->cfg.dial.max); 952 else 953 prompt_Printf(arg->prompt, " Dial tries: infinite, delay "); 954 if (arg->cx->cfg.dial.next_timeout > 0) 955 prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout); 956 else 957 prompt_Printf(arg->prompt, "random/"); 958 if (arg->cx->cfg.dial.timeout > 0) 959 prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout); 960 else 961 prompt_Printf(arg->prompt, "random\n"); 962 prompt_Printf(arg->prompt, " Reconnect tries: %d, delay ", 963 arg->cx->cfg.reconnect.max); 964 if (arg->cx->cfg.reconnect.timeout > 0) 965 prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout); 966 else 967 prompt_Printf(arg->prompt, "random\n"); 968 prompt_Printf(arg->prompt, " Callback %s ", arg->cx->physical->type == 969 PHYS_DIRECT ? "accepted: " : "requested:"); 970 if (!arg->cx->cfg.callback.opmask) 971 prompt_Printf(arg->prompt, "none\n"); 972 else { 973 int comma = 0; 974 975 if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) { 976 prompt_Printf(arg->prompt, "none"); 977 comma = 1; 978 } 979 if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) { 980 prompt_Printf(arg->prompt, "%sauth", comma ? ", " : ""); 981 comma = 1; 982 } 983 if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) { 984 prompt_Printf(arg->prompt, "%sE.164", comma ? ", " : ""); 985 if (arg->cx->physical->type != PHYS_DIRECT) 986 prompt_Printf(arg->prompt, " (%s)", arg->cx->cfg.callback.msg); 987 comma = 1; 988 } 989 if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) { 990 prompt_Printf(arg->prompt, "%scbcp\n", comma ? ", " : ""); 991 prompt_Printf(arg->prompt, " CBCP: delay: %ds\n", 992 arg->cx->cfg.cbcp.delay); 993 prompt_Printf(arg->prompt, " phone: "); 994 if (!strcmp(arg->cx->cfg.cbcp.phone, "*")) { 995 if (arg->cx->physical->type & PHYS_DIRECT) 996 prompt_Printf(arg->prompt, "Caller decides\n"); 997 else 998 prompt_Printf(arg->prompt, "Dialback server decides\n"); 999 } else 1000 prompt_Printf(arg->prompt, "%s\n", arg->cx->cfg.cbcp.phone); 1001 prompt_Printf(arg->prompt, " timeout: %lds\n", 1002 arg->cx->cfg.cbcp.fsmretry); 1003 } else 1004 prompt_Printf(arg->prompt, "\n"); 1005 } 1006 1007 prompt_Printf(arg->prompt, " Dial Script: %s\n", 1008 arg->cx->cfg.script.dial); 1009 prompt_Printf(arg->prompt, " Login Script: %s\n", 1010 arg->cx->cfg.script.login); 1011 prompt_Printf(arg->prompt, " Hangup Script: %s\n", 1012 arg->cx->cfg.script.hangup); 1013 return 0; 1014} 1015 1016int 1017datalink_SetReconnect(struct cmdargs const *arg) 1018{ 1019 if (arg->argc == arg->argn+2) { 1020 arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]); 1021 arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]); 1022 return 0; 1023 } 1024 return -1; 1025} 1026 1027int 1028datalink_SetRedial(struct cmdargs const *arg) 1029{ 1030 int timeout; 1031 int tries; 1032 char *dot; 1033 1034 if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) { 1035 if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 && 1036 (arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) { 1037 arg->cx->cfg.dial.timeout = -1; 1038 randinit(); 1039 } else { 1040 timeout = atoi(arg->argv[arg->argn]); 1041 1042 if (timeout >= 0) 1043 arg->cx->cfg.dial.timeout = timeout; 1044 else { 1045 log_Printf(LogWARN, "Invalid redial timeout\n"); 1046 return -1; 1047 } 1048 } 1049 1050 dot = strchr(arg->argv[arg->argn], '.'); 1051 if (dot) { 1052 if (strcasecmp(++dot, "random") == 0) { 1053 arg->cx->cfg.dial.next_timeout = -1; 1054 randinit(); 1055 } else { 1056 timeout = atoi(dot); 1057 if (timeout >= 0) 1058 arg->cx->cfg.dial.next_timeout = timeout; 1059 else { 1060 log_Printf(LogWARN, "Invalid next redial timeout\n"); 1061 return -1; 1062 } 1063 } 1064 } else 1065 /* Default next timeout */ 1066 arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 1067 1068 if (arg->argc == arg->argn+2) { 1069 tries = atoi(arg->argv[arg->argn+1]); 1070 1071 if (tries >= 0) { 1072 arg->cx->cfg.dial.max = tries; 1073 } else { 1074 log_Printf(LogWARN, "Invalid retry value\n"); 1075 return 1; 1076 } 1077 } 1078 return 0; 1079 } 1080 return -1; 1081} 1082 1083static const char *states[] = { 1084 "closed", 1085 "opening", 1086 "hangup", 1087 "dial", 1088 "login", 1089 "ready", 1090 "lcp", 1091 "auth", 1092 "cbcp", 1093 "open" 1094}; 1095 1096const char * 1097datalink_State(struct datalink *dl) 1098{ 1099 if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0]) 1100 return "unknown"; 1101 return states[dl->state]; 1102} 1103 1104static void 1105datalink_NewState(struct datalink *dl, int state) 1106{ 1107 if (state != dl->state) { 1108 if (state >= 0 && state < sizeof states / sizeof states[0]) { 1109 log_Printf(LogPHASE, "%s: %s -> %s\n", dl->name, datalink_State(dl), 1110 states[state]); 1111 dl->state = state; 1112 } else 1113 log_Printf(LogERROR, "%s: Can't enter state %d !\n", dl->name, state); 1114 } 1115} 1116 1117struct datalink * 1118iov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov, 1119 int fd) 1120{ 1121 struct datalink *dl, *cdl; 1122 u_int retry; 1123 char *oname; 1124 1125 dl = (struct datalink *)iov[(*niov)++].iov_base; 1126 dl->name = iov[*niov].iov_base; 1127 1128 if (dl->name[DATALINK_MAXNAME-1]) { 1129 dl->name[DATALINK_MAXNAME-1] = '\0'; 1130 if (strlen(dl->name) == DATALINK_MAXNAME - 1) 1131 log_Printf(LogWARN, "Datalink name truncated to \"%s\"\n", dl->name); 1132 } 1133 1134 /* Make sure the name is unique ! */ 1135 oname = NULL; 1136 do { 1137 for (cdl = bundle->links; cdl; cdl = cdl->next) 1138 if (!strcasecmp(dl->name, cdl->name)) { 1139 if (oname) 1140 free(datalink_NextName(dl)); 1141 else 1142 oname = datalink_NextName(dl); 1143 break; /* Keep renaming 'till we have no conflicts */ 1144 } 1145 } while (cdl); 1146 1147 if (oname) { 1148 log_Printf(LogPHASE, "Rename link %s to %s\n", oname, dl->name); 1149 free(oname); 1150 } else { 1151 dl->name = strdup(dl->name); 1152 free(iov[*niov].iov_base); 1153 } 1154 (*niov)++; 1155 1156 dl->desc.type = DATALINK_DESCRIPTOR; 1157 dl->desc.UpdateSet = datalink_UpdateSet; 1158 dl->desc.IsSet = datalink_IsSet; 1159 dl->desc.Read = datalink_Read; 1160 dl->desc.Write = datalink_Write; 1161 1162 mp_linkInit(&dl->mp); 1163 *dl->phone.list = '\0'; 1164 dl->phone.next = NULL; 1165 dl->phone.alt = NULL; 1166 dl->phone.chosen = "N/A"; 1167 1168 dl->bundle = bundle; 1169 dl->next = NULL; 1170 memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 1171 dl->dial_tries = 0; 1172 dl->reconnect_tries = 0; 1173 dl->parent = &bundle->fsm; 1174 dl->fsmp.LayerStart = datalink_LayerStart; 1175 dl->fsmp.LayerUp = datalink_LayerUp; 1176 dl->fsmp.LayerDown = datalink_LayerDown; 1177 dl->fsmp.LayerFinish = datalink_LayerFinish; 1178 dl->fsmp.object = dl; 1179 1180 retry = dl->pap.cfg.fsmretry; 1181 auth_Init(&dl->pap); 1182 dl->pap.cfg.fsmretry = retry; 1183 1184 retry = dl->chap.auth.cfg.fsmretry; 1185 auth_Init(&dl->chap.auth); 1186 dl->chap.auth.cfg.fsmretry = retry; 1187 1188 dl->physical = iov2modem(dl, iov, niov, maxiov, fd); 1189 1190 if (!dl->physical) { 1191 free(dl->name); 1192 free(dl); 1193 dl = NULL; 1194 } else { 1195 cbcp_Init(&dl->cbcp, dl->physical); 1196 chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 1197 1198 log_Printf(LogPHASE, "%s: Transferred in %s state\n", 1199 dl->name, datalink_State(dl)); 1200 } 1201 1202 return dl; 1203} 1204 1205int 1206datalink2iov(struct datalink *dl, struct iovec *iov, int *niov, int maxiov, 1207 pid_t newpid) 1208{ 1209 /* If `dl' is NULL, we're allocating before a Fromiov() */ 1210 int link_fd; 1211 1212 if (dl) { 1213 timer_Stop(&dl->dial_timer); 1214 /* The following is purely for the sake of paranoia */ 1215 cbcp_Down(&dl->cbcp); 1216 timer_Stop(&dl->pap.authtimer); 1217 timer_Stop(&dl->chap.auth.authtimer); 1218 } 1219 1220 if (*niov >= maxiov - 1) { 1221 log_Printf(LogERROR, "Toiov: No room for datalink !\n"); 1222 if (dl) { 1223 free(dl->name); 1224 free(dl); 1225 } 1226 return -1; 1227 } 1228 1229 iov[*niov].iov_base = dl ? dl : malloc(sizeof *dl); 1230 iov[(*niov)++].iov_len = sizeof *dl; 1231 iov[*niov].iov_base = 1232 dl ? realloc(dl->name, DATALINK_MAXNAME) : malloc(DATALINK_MAXNAME); 1233 iov[(*niov)++].iov_len = DATALINK_MAXNAME; 1234 1235 link_fd = modem2iov(dl ? dl->physical : NULL, iov, niov, maxiov, newpid); 1236 1237 if (link_fd == -1 && dl) { 1238 free(dl->name); 1239 free(dl); 1240 } 1241 1242 return link_fd; 1243} 1244 1245void 1246datalink_Rename(struct datalink *dl, const char *name) 1247{ 1248 free(dl->name); 1249 dl->physical->link.name = dl->name = strdup(name); 1250} 1251 1252char * 1253datalink_NextName(struct datalink *dl) 1254{ 1255 int f, n; 1256 char *name, *oname; 1257 1258 n = strlen(dl->name); 1259 name = (char *)malloc(n+3); 1260 for (f = n - 1; f >= 0; f--) 1261 if (!isdigit(dl->name[f])) 1262 break; 1263 n = sprintf(name, "%.*s-", dl->name[f] == '-' ? f : f + 1, dl->name); 1264 sprintf(name + n, "%d", atoi(dl->name + f + 1) + 1); 1265 oname = dl->name; 1266 dl->name = name; 1267 /* our physical link name isn't updated (it probably isn't created yet) */ 1268 return oname; 1269} 1270 1271int 1272datalink_SetMode(struct datalink *dl, int mode) 1273{ 1274 if (!physical_SetMode(dl->physical, mode)) 1275 return 0; 1276 if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 1277 dl->script.run = 0; 1278 if (dl->physical->type == PHYS_DIRECT) 1279 dl->reconnect_tries = 0; 1280 if (mode & (PHYS_DDIAL|PHYS_BACKGROUND) && dl->state <= DATALINK_READY) 1281 datalink_Up(dl, 1, 1); 1282 return 1; 1283} 1284