physical.c revision 69303
16059Samurai/* 26059Samurai * Written by Eivind Eklund <eivind@yes.no> 36059Samurai * for Yes Interactive 46059Samurai * 56059Samurai * Copyright (C) 1998, Yes Interactive. All rights reserved. 66059Samurai * 76059Samurai * Redistribution and use in any form is permitted. Redistribution in 86059Samurai * source form should include the above copyright and this set of 96059Samurai * conditions, because large sections american law seems to have been 106059Samurai * created by a bunch of jerks on drugs that are now illegal, forcing 116059Samurai * me to include this copyright-stuff instead of placing this in the 126059Samurai * public domain. The name of of 'Yes Interactive' or 'Eivind Eklund' 136059Samurai * may not be used to endorse or promote products derived from this 146059Samurai * software without specific prior written permission. 156059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 166059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 176059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 186059Samurai * 196059Samurai * $FreeBSD: head/usr.sbin/ppp/physical.c 69303 2000-11-28 13:18:35Z brian $ 2037009Sbrian * 218857Srgrimes */ 226059Samurai 2330715Sbrian#include <sys/param.h> 2436285Sbrian#include <netinet/in.h> 256059Samurai#include <netinet/in_systm.h> 2631176Sbrian#include <netinet/ip.h> 2730715Sbrian#include <sys/un.h> 2830715Sbrian 2930715Sbrian#include <errno.h> 3030715Sbrian#include <fcntl.h> 3131176Sbrian#include <paths.h> 3236285Sbrian#ifdef NOSUID 3336285Sbrian#include <signal.h> 3436285Sbrian#endif 3520287Swollman#include <stdio.h> 3620287Swollman#include <stdlib.h> 3730715Sbrian#include <string.h> 386059Samurai#include <sys/tty.h> /* TIOCOUTQ */ 396059Samurai#include <sys/uio.h> 4030715Sbrian#include <time.h> 4136285Sbrian#include <unistd.h> 4220287Swollman#include <utmp.h> 4337009Sbrian#if defined(__OpenBSD__) || defined(__NetBSD__) 4431343Sbrian#include <sys/ioctl.h> 4530715Sbrian#include <util.h> 469439Samurai#else 4736285Sbrian#include <libutil.h> 4836285Sbrian#endif 4936285Sbrian 5036285Sbrian#include "layer.h" 5136285Sbrian#ifndef NONAT 5236285Sbrian#include "nat_cmd.h" 5336285Sbrian#endif 5436285Sbrian#include "proto.h" 5536285Sbrian#include "acf.h" 5636285Sbrian#include "vjcomp.h" 5731690Sbrian#include "defs.h" 5836285Sbrian#include "command.h" 5936285Sbrian#include "mbuf.h" 6036285Sbrian#include "log.h" 6136285Sbrian#include "id.h" 6230715Sbrian#include "timer.h" 6336285Sbrian#include "fsm.h" 646059Samurai#include "lqr.h" 656059Samurai#include "hdlc.h" 6636285Sbrian#include "lcp.h" 6736285Sbrian#include "throughput.h" 686059Samurai#include "sync.h" 6931343Sbrian#include "async.h" 7031176Sbrian#include "iplist.h" 7131176Sbrian#include "slcompress.h" 7231176Sbrian#include "ipcp.h" 736059Samurai#include "filter.h" 7431176Sbrian#include "descriptor.h" 7531176Sbrian#include "ccp.h" 7631176Sbrian#include "link.h" 7731541Sbrian#include "physical.h" 7831176Sbrian#include "mp.h" 7931541Sbrian#ifndef NORADIUS 8031176Sbrian#include "radius.h" 8131541Sbrian#endif 8231176Sbrian#include "bundle.h" 8331176Sbrian#include "prompt.h" 8431176Sbrian#include "chat.h" 8531176Sbrian#include "auth.h" 8631176Sbrian#include "chap.h" 8731176Sbrian#include "cbcp.h" 8831176Sbrian#include "datalink.h" 8931176Sbrian#include "tcp.h" 9031176Sbrian#include "udp.h" 9131176Sbrian#include "exec.h" 9231176Sbrian#include "tty.h" 9331176Sbrian#ifndef NOI4B 9431176Sbrian#include "i4b.h" 9531176Sbrian#endif 9631176Sbrian#ifndef NONETGRAPH 9731176Sbrian#include "ether.h" 9831791Sbrian#endif 9931176Sbrian#ifndef NOATM 10031176Sbrian#include "atm.h" 10131176Sbrian#endif 10231176Sbrian#include "tcpmss.h" 10331176Sbrian 10431176Sbrian#define PPPOTCPLINE "ppp" 10531176Sbrian 10631176Sbrianstatic int physical_DescriptorWrite(struct fdescriptor *, struct bundle *, 10731176Sbrian const fd_set *); 10831176Sbrian 10931176Sbrianstatic int 11031176Sbrianphysical_DeviceSize(void) 11131541Sbrian{ 11231541Sbrian return sizeof(struct device); 11334536Sbrian} 11434536Sbrian 11531962Sbrianstruct { 11631541Sbrian struct device *(*create)(struct physical *); 11731541Sbrian struct device *(*iov2device)(int, struct physical *, struct iovec *, 11831541Sbrian int *, int, int *, int *); 11931541Sbrian int (*DeviceSize)(void); 12031541Sbrian} devices[] = { 12131541Sbrian#ifndef NOI4B 12231541Sbrian { i4b_Create, i4b_iov2device, i4b_DeviceSize }, 12331541Sbrian#endif 12431791Sbrian { tty_Create, tty_iov2device, tty_DeviceSize }, 12534536Sbrian#ifndef NONETGRAPH 12631541Sbrian /* This must come before ``udp'' & ``tcp'' */ 12736285Sbrian { ether_Create, ether_iov2device, ether_DeviceSize }, 12831541Sbrian#endif 12931541Sbrian#ifndef NOATM 13031176Sbrian /* and so must this */ 13131176Sbrian { atm_Create, atm_iov2device, atm_DeviceSize }, 13231176Sbrian#endif 13331176Sbrian { tcp_Create, tcp_iov2device, tcp_DeviceSize }, 13431541Sbrian { udp_Create, udp_iov2device, udp_DeviceSize }, 13531176Sbrian { exec_Create, exec_iov2device, exec_DeviceSize } 13626516Sbrian}; 13731176Sbrian 13836285Sbrian#define NDEVICES (sizeof devices / sizeof devices[0]) 1396059Samurai 1406059Samuraistatic int 14132663Sbrianphysical_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, 14231176Sbrian int *n) 14328679Sbrian{ 14431176Sbrian return physical_doUpdateSet(d, r, w, e, n, 0); 14531176Sbrian} 14631176Sbrian 14731176Sbrianvoid 14831176Sbrianphysical_SetDescriptor(struct physical *p) 14931176Sbrian{ 15031176Sbrian p->desc.type = PHYSICAL_DESCRIPTOR; 15131176Sbrian p->desc.UpdateSet = physical_UpdateSet; 15231176Sbrian p->desc.IsSet = physical_IsSet; 15331176Sbrian p->desc.Read = physical_DescriptorRead; 15431176Sbrian p->desc.Write = physical_DescriptorWrite; 15531176Sbrian} 15631176Sbrian 15731176Sbrianstruct physical * 15831176Sbrianphysical_Create(struct datalink *dl, int type) 15931739Sbrian{ 16031176Sbrian struct physical *p; 16131739Sbrian 16231739Sbrian p = (struct physical *)malloc(sizeof(struct physical)); 16331176Sbrian if (!p) 16431739Sbrian return NULL; 16531739Sbrian 16631176Sbrian p->link.type = PHYSICAL_LINK; 16731739Sbrian p->link.name = dl->name; 16831739Sbrian p->link.len = sizeof *p; 16931176Sbrian 17031176Sbrian /* The sample period is fixed - see physical2iov() & iov2physical() */ 17131176Sbrian throughput_init(&p->link.stats.total, SAMPLE_PERIOD); 1726059Samurai p->link.stats.parent = dl->bundle->ncp.mp.active ? 1736059Samurai &dl->bundle->ncp.mp.link.stats.total : NULL; 17431739Sbrian p->link.stats.gather = 1; 17531739Sbrian 17631739Sbrian memset(p->link.Queue, '\0', sizeof p->link.Queue); 17731739Sbrian memset(p->link.proto_in, '\0', sizeof p->link.proto_in); 1786059Samurai memset(p->link.proto_out, '\0', sizeof p->link.proto_out); 17936285Sbrian link_EmptyStack(&p->link); 1806059Samurai 18136285Sbrian p->handler = NULL; 18236285Sbrian physical_SetDescriptor(p); 1836059Samurai p->type = type; 18436285Sbrian 18536285Sbrian hdlc_Init(&p->hdlc, &p->link.lcp); 18631827Sbrian async_Init(&p->async); 18736285Sbrian 18836285Sbrian p->fd = -1; 18936285Sbrian p->out = NULL; 19036285Sbrian p->connect_count = 0; 19136285Sbrian p->dl = dl; 1926059Samurai p->input.sz = 0; 1936059Samurai *p->name.full = '\0'; 19432616Sbrian p->name.base = p->name.full; 19531176Sbrian 19631176Sbrian p->Utmp = 0; 19732425Sbrian p->session_owner = (pid_t)-1; 19831354Sbrian 19931176Sbrian p->cfg.rts_cts = MODEM_CTSRTS; 20031176Sbrian p->cfg.speed = MODEM_SPEED; 20132425Sbrian p->cfg.parity = CS8; 20232021Sbrian memcpy(p->cfg.devlist, MODEM_LIST, sizeof MODEM_LIST); 20331176Sbrian p->cfg.ndev = NMODEMS; 20431176Sbrian p->cfg.cd.necessity = CD_DEFAULT; 20531176Sbrian p->cfg.cd.delay = 0; /* reconfigured or device specific default */ 20631176Sbrian 20731176Sbrian lcp_Init(&p->link.lcp, dl->bundle, &p->link, &dl->fsmp); 20831176Sbrian ccp_Init(&p->link.ccp, dl->bundle, &p->link, &dl->fsmp); 20931176Sbrian 21031176Sbrian return p; 21131176Sbrian} 21231176Sbrian 21331176Sbrianstatic const struct parity { 21431176Sbrian const char *name; 21536285Sbrian const char *name1; 21631176Sbrian int set; 21731176Sbrian} validparity[] = { 21831176Sbrian { "even", "P_EVEN", CS7 | PARENB }, 21931176Sbrian { "odd", "P_ODD", CS7 | PARENB | PARODD }, 22031176Sbrian { "none", "P_ZERO", CS8 }, 22131176Sbrian { NULL, 0 }, 22231176Sbrian}; 22331176Sbrian 22431176Sbrianstatic int 22531176SbrianGetParityValue(const char *str) 22632425Sbrian{ 22731354Sbrian const struct parity *pp; 22831176Sbrian 22931176Sbrian for (pp = validparity; pp->name; pp++) { 23032425Sbrian if (strcasecmp(pp->name, str) == 0 || 23132425Sbrian strcasecmp(pp->name1, str) == 0) { 23232425Sbrian return pp->set; 23332425Sbrian } 23432425Sbrian } 23532425Sbrian return (-1); 23632425Sbrian} 23732425Sbrian 23832425Sbrianint 23936285Sbrianphysical_SetParity(struct physical *p, const char *str) 24032425Sbrian{ 24132425Sbrian struct termios rstio; 24232425Sbrian int val; 24332425Sbrian 24432425Sbrian val = GetParityValue(str); 24532425Sbrian if (val > 0) { 24632425Sbrian p->cfg.parity = val; 24732425Sbrian if (p->fd >= 0) { 24832425Sbrian tcgetattr(p->fd, &rstio); 24932425Sbrian rstio.c_cflag &= ~(CSIZE | PARODD | PARENB); 25032425Sbrian rstio.c_cflag |= val; 25132425Sbrian tcsetattr(p->fd, TCSADRAIN, &rstio); 25236285Sbrian } 25336285Sbrian return 0; 25431354Sbrian } 25531176Sbrian log_Printf(LogWARN, "%s: %s: Invalid parity\n", p->link.name, str); 25631176Sbrian return -1; 25731176Sbrian} 25831176Sbrian 25936285Sbrianint 26031354Sbrianphysical_GetSpeed(struct physical *p) 26131354Sbrian{ 26236285Sbrian if (p->handler && p->handler->speed) 26331354Sbrian return (*p->handler->speed)(p); 26432425Sbrian 26536285Sbrian return 0; 26631354Sbrian} 26731354Sbrian 26831354Sbrianint 26932425Sbrianphysical_SetSpeed(struct physical *p, int speed) 27031176Sbrian{ 27131354Sbrian if (IntToSpeed(speed) != B0) { 27231354Sbrian p->cfg.speed = speed; 27331176Sbrian return 1; 27431176Sbrian } 2756059Samurai 27636285Sbrian return 0; 2776059Samurai} 2786059Samurai 27931176Sbrianint 28031176Sbrianphysical_Raw(struct physical *p) 28132021Sbrian{ 2826735Samurai if (p->handler && p->handler->raw) 2836059Samurai return (*p->handler->raw)(p); 2846059Samurai 2856059Samurai return 1; 2866735Samurai} 2876735Samurai 2886059Samuraivoid 2896735Samuraiphysical_Offline(struct physical *p) 2906735Samurai{ 29136285Sbrian if (p->handler && p->handler->offline) 29228679Sbrian (*p->handler->offline)(p); 2936735Samurai log_Printf(LogPHASE, "%s: Disconnected!\n", p->link.name); 2946059Samurai} 2956059Samurai 29628679Sbrianstatic int 2976735Samuraiphysical_Lock(struct physical *p) 29836285Sbrian{ 29918885Sjkh int res; 30028679Sbrian 3016735Samurai if (*p->name.full == '/' && p->type != PHYS_DIRECT && 3026059Samurai (res = ID0uu_lock(p->name.base)) != UU_LOCK_OK) { 3036059Samurai if (res == UU_LOCK_INUSE) 30436285Sbrian log_Printf(LogPHASE, "%s: %s is in use\n", p->link.name, p->name.full); 30536285Sbrian else 3066059Samurai log_Printf(LogPHASE, "%s: %s is in use: uu_lock: %s\n", 30728679Sbrian p->link.name, p->name.full, uu_lockerr(res)); 30831176Sbrian return 0; 30931176Sbrian } 31031176Sbrian 31131176Sbrian return 1; 31231176Sbrian} 31331176Sbrian 31431176Sbrianstatic void 31531176Sbrianphysical_Unlock(struct physical *p) 31631176Sbrian{ 31731176Sbrian char fn[MAXPATHLEN]; 31831176Sbrian if (*p->name.full == '/' && p->type != PHYS_DIRECT && 31931176Sbrian ID0uu_unlock(p->name.base) == -1) 32031176Sbrian log_Printf(LogALERT, "%s: Can't uu_unlock %s\n", p->link.name, fn); 32131176Sbrian} 32231176Sbrian 32331176Sbrianvoid 32431176Sbrianphysical_Close(struct physical *p) 32531176Sbrian{ 32631176Sbrian int newsid; 32731176Sbrian char fn[MAXPATHLEN]; 32836285Sbrian 32936285Sbrian if (p->fd < 0) 33031176Sbrian return; 33136285Sbrian 33236285Sbrian log_Printf(LogDEBUG, "%s: Close\n", p->link.name); 3336059Samurai 33418885Sjkh if (p->handler && p->handler->cooked) 33526516Sbrian (*p->handler->cooked)(p); 3366059Samurai 3376059Samurai physical_StopDeviceTimer(p); 3386059Samurai if (p->Utmp) { 3396059Samurai if (p->handler && (p->handler->type == TCP_DEVICE || 3406059Samurai p->handler->type == UDP_DEVICE)) 3416059Samurai /* Careful - we logged in on line ``ppp'' with IP as our host */ 34236285Sbrian ID0logout(PPPOTCPLINE, 1); 3436059Samurai else 3446059Samurai ID0logout(p->name.base, 0); 3456059Samurai p->Utmp = 0; 34631598Sbrian } 34732021Sbrian newsid = tcgetpgrp(p->fd) == getpgrp(); 34832021Sbrian close(p->fd); 3496059Samurai p->fd = -1; 3506735Samurai log_SetTtyCommandMode(p->dl); 3516059Samurai 35236285Sbrian throughput_stop(&p->link.stats.total); 35331598Sbrian throughput_log(&p->link.stats.total, LogPHASE, p->link.name); 35426516Sbrian 3556059Samurai if (p->session_owner != (pid_t)-1) { 3566059Samurai log_Printf(LogPHASE, "%s: HUPing %d\n", p->link.name, 3576735Samurai (int)p->session_owner); 3586735Samurai ID0kill(p->session_owner, SIGHUP); 3596059Samurai p->session_owner = (pid_t)-1; 3606735Samurai } 3616735Samurai 36236285Sbrian if (newsid) 36328974Sbrian bundle_setsid(p->dl->bundle, 0); 3646735Samurai 3656735Samurai if (*p->name.full == '/') { 3666059Samurai snprintf(fn, sizeof fn, "%s%s.if", _PATH_VARRUN, p->name.base); 3676059Samurai#ifndef RELEASE_CRUNCH 3686059Samurai if (ID0unlink(fn) == -1) 3696059Samurai log_Printf(LogALERT, "%s: Can't remove %s: %s\n", 3706059Samurai p->link.name, fn, strerror(errno)); 3716735Samurai#else 37236285Sbrian ID0unlink(fn); 37328974Sbrian#endif 3746059Samurai } 3756059Samurai physical_Unlock(p); 3766059Samurai if (p->handler && p->handler->destroy) 3776059Samurai (*p->handler->destroy)(p); 3786059Samurai p->handler = NULL; 37931739Sbrian p->name.base = p->name.full; 38031739Sbrian *p->name.full = '\0'; 38131739Sbrian} 38231739Sbrian 38331739Sbrianvoid 38436285Sbrianphysical_Destroy(struct physical *p) 38536285Sbrian{ 38631739Sbrian physical_Close(p); 38731739Sbrian throughput_destroy(&p->link.stats.total); 38831739Sbrian free(p); 38931739Sbrian} 39031739Sbrian 39131739Sbrianstatic int 39231739Sbrianphysical_DescriptorWrite(struct fdescriptor *d, struct bundle *bundle, 39336285Sbrian const fd_set *fdset) 39431739Sbrian{ 39531739Sbrian struct physical *p = descriptor2physical(d); 39631739Sbrian int nw, result = 0; 39731739Sbrian 39836285Sbrian if (p->out == NULL) 39931739Sbrian p->out = link_Dequeue(&p->link); 40031739Sbrian 40131739Sbrian if (p->out) { 40231739Sbrian nw = physical_Write(p, MBUF_CTOP(p->out), p->out->m_len); 40331739Sbrian log_Printf(LogDEBUG, "%s: DescriptorWrite: wrote %d(%lu) to %d\n", 40431739Sbrian p->link.name, nw, (unsigned long)p->out->m_len, p->fd); 40536285Sbrian if (nw > 0) { 40636285Sbrian p->out->m_len -= nw; 40731739Sbrian p->out->m_offset += nw; 40836285Sbrian if (p->out->m_len == 0) 40931739Sbrian p->out = m_free(p->out); 41036285Sbrian result = 1; 41136285Sbrian } else if (nw < 0) { 41231739Sbrian if (errno == EAGAIN) 41331739Sbrian result = 1; 4146059Samurai else if (errno != ENOBUFS) { 4156059Samurai log_Printf(LogPHASE, "%s: write (%d): %s\n", p->link.name, 4166059Samurai p->fd, strerror(errno)); 4176059Samurai datalink_Down(p->dl, CLOSE_NORMAL); 4186059Samurai } 4196059Samurai } 42028679Sbrian /* else we shouldn't really have been called ! select() is broken ! */ 4216059Samurai } 42231176Sbrian 42331343Sbrian return result; 42428679Sbrian} 42531354Sbrian 42631176Sbrianint 42731176Sbrianphysical_ShowStatus(struct cmdargs const *arg) 42836285Sbrian{ 42931176Sbrian struct physical *p = arg->cx->physical; 43031176Sbrian struct cd *cd; 43131176Sbrian const char *dev; 4326059Samurai int n; 43331690Sbrian 43436285Sbrian prompt_Printf(arg->prompt, "Name: %s\n", p->link.name); 43536285Sbrian prompt_Printf(arg->prompt, " State: "); 43636285Sbrian if (p->fd < 0) 43731690Sbrian prompt_Printf(arg->prompt, "closed\n"); 43836285Sbrian else if (p->handler && p->handler->openinfo) 43931690Sbrian prompt_Printf(arg->prompt, "open (%s)\n", (*p->handler->openinfo)(p)); 44036285Sbrian else 44136285Sbrian prompt_Printf(arg->prompt, "open\n"); 44236285Sbrian 44336285Sbrian prompt_Printf(arg->prompt, " Device: %s", 44436285Sbrian *p->name.full ? p->name.full : 44536285Sbrian p->type == PHYS_DIRECT ? "unknown" : "N/A"); 44636285Sbrian if (p->session_owner != (pid_t)-1) 44736285Sbrian prompt_Printf(arg->prompt, " (session owner: %d)", (int)p->session_owner); 44836285Sbrian 44936285Sbrian prompt_Printf(arg->prompt, "\n Link Type: %s\n", mode2Nam(p->type)); 45036285Sbrian prompt_Printf(arg->prompt, " Connect Count: %d\n", p->connect_count); 45136285Sbrian#ifdef TIOCOUTQ 45236285Sbrian if (p->fd >= 0 && ioctl(p->fd, TIOCOUTQ, &n) >= 0) 45336285Sbrian prompt_Printf(arg->prompt, " Physical outq: %d\n", n); 45436285Sbrian#endif 45536285Sbrian 45636285Sbrian prompt_Printf(arg->prompt, " Queued Packets: %lu\n", 45736285Sbrian (u_long)link_QueueLen(&p->link)); 45836285Sbrian prompt_Printf(arg->prompt, " Phone Number: %s\n", arg->cx->phone.chosen); 45936285Sbrian 46036285Sbrian prompt_Printf(arg->prompt, "\nDefaults:\n"); 46136285Sbrian 46236285Sbrian prompt_Printf(arg->prompt, " Device List: "); 46336285Sbrian dev = p->cfg.devlist; 46436285Sbrian for (n = 0; n < p->cfg.ndev; n++) { 46536285Sbrian if (n) 46636285Sbrian prompt_Printf(arg->prompt, ", "); 46736285Sbrian prompt_Printf(arg->prompt, "\"%s\"", dev); 46836285Sbrian dev += strlen(dev) + 1; 46936285Sbrian } 47036285Sbrian 47136285Sbrian prompt_Printf(arg->prompt, "\n Characteristics: "); 47236285Sbrian if (physical_IsSync(arg->cx->physical)) 47336285Sbrian prompt_Printf(arg->prompt, "sync"); 47436285Sbrian else 47536285Sbrian prompt_Printf(arg->prompt, "%dbps", p->cfg.speed); 47636285Sbrian 47736285Sbrian switch (p->cfg.parity & CSIZE) { 47836285Sbrian case CS7: 47936285Sbrian prompt_Printf(arg->prompt, ", cs7"); 48036285Sbrian break; 48136285Sbrian case CS8: 48236285Sbrian prompt_Printf(arg->prompt, ", cs8"); 48336285Sbrian break; 48436285Sbrian } 48536285Sbrian if (p->cfg.parity & PARENB) { 48636285Sbrian if (p->cfg.parity & PARODD) 48736285Sbrian prompt_Printf(arg->prompt, ", odd parity"); 48836285Sbrian else 48936285Sbrian prompt_Printf(arg->prompt, ", even parity"); 49036285Sbrian } else 49136285Sbrian prompt_Printf(arg->prompt, ", no parity"); 49236285Sbrian 49336285Sbrian prompt_Printf(arg->prompt, ", CTS/RTS %s\n", (p->cfg.rts_cts ? "on" : "off")); 49436285Sbrian 49536285Sbrian prompt_Printf(arg->prompt, " CD check delay: "); 49636285Sbrian cd = p->handler ? &p->handler->cd : &p->cfg.cd; 49736285Sbrian if (cd->necessity == CD_NOTREQUIRED) 49836285Sbrian prompt_Printf(arg->prompt, "no cd"); 49936285Sbrian else if (p->cfg.cd.necessity == CD_DEFAULT) { 50036285Sbrian prompt_Printf(arg->prompt, "device specific"); 50136285Sbrian } else { 50236285Sbrian prompt_Printf(arg->prompt, "%d second%s", p->cfg.cd.delay, 50336285Sbrian p->cfg.cd.delay == 1 ? "" : "s"); 50436285Sbrian if (p->cfg.cd.necessity == CD_REQUIRED) 50536285Sbrian prompt_Printf(arg->prompt, " (required!)"); 50636285Sbrian } 50736285Sbrian prompt_Printf(arg->prompt, "\n\n"); 50836285Sbrian 50936285Sbrian throughput_disp(&p->link.stats.total, arg->prompt); 51036285Sbrian 51136285Sbrian return 0; 51236285Sbrian} 51331690Sbrian 51431690Sbrianvoid 51531690Sbrianphysical_DescriptorRead(struct fdescriptor *d, struct bundle *bundle, 51636285Sbrian const fd_set *fdset) 51731690Sbrian{ 51836285Sbrian struct physical *p = descriptor2physical(d); 51936285Sbrian u_char *rbuff; 52036285Sbrian int n, found; 52136285Sbrian 52236285Sbrian rbuff = p->input.buf + p->input.sz; 52336285Sbrian 52436285Sbrian /* something to read */ 52536285Sbrian n = physical_Read(p, rbuff, sizeof p->input.buf - p->input.sz); 52631690Sbrian log_Printf(LogDEBUG, "%s: DescriptorRead: read %d/%d from %d\n", 52736285Sbrian p->link.name, n, (int)(sizeof p->input.buf - p->input.sz), p->fd); 52836285Sbrian if (n <= 0) { 52931690Sbrian if (n < 0) 53036285Sbrian log_Printf(LogPHASE, "%s: read (%d): %s\n", p->link.name, p->fd, 53136285Sbrian strerror(errno)); 53236285Sbrian else 53336285Sbrian log_Printf(LogPHASE, "%s: read (%d): Got zero bytes\n", 53436285Sbrian p->link.name, p->fd); 53536285Sbrian datalink_Down(p->dl, CLOSE_NORMAL); 53636285Sbrian return; 53736285Sbrian } 53836285Sbrian 53936285Sbrian rbuff -= p->input.sz; 54036285Sbrian n += p->input.sz; 54136285Sbrian 54236285Sbrian if (p->link.lcp.fsm.state <= ST_CLOSED) { 54336285Sbrian if (p->type != PHYS_DEDICATED) { 54436285Sbrian found = hdlc_Detect((u_char const **)&rbuff, n, physical_IsSync(p)); 54536285Sbrian if (rbuff != p->input.buf) 54636285Sbrian log_WritePrompts(p->dl, "%.*s", (int)(rbuff - p->input.buf), 54736285Sbrian p->input.buf); 54836285Sbrian p->input.sz = n - (rbuff - p->input.buf); 54936285Sbrian 55036285Sbrian if (found) { 55136285Sbrian /* LCP packet is detected. Turn ourselves into packet mode */ 55236285Sbrian log_Printf(LogPHASE, "%s: PPP packet detected, coming up\n", 55336285Sbrian p->link.name); 55436285Sbrian log_SetTtyCommandMode(p->dl); 55536285Sbrian datalink_Up(p->dl, 0, 1); 55636285Sbrian link_PullPacket(&p->link, rbuff, p->input.sz, bundle); 55731690Sbrian p->input.sz = 0; 558 } else 559 bcopy(rbuff, p->input.buf, p->input.sz); 560 } else 561 /* In -dedicated mode, we just discard input until LCP is started */ 562 p->input.sz = 0; 563 } else if (n > 0) 564 link_PullPacket(&p->link, rbuff, n, bundle); 565} 566 567struct physical * 568iov2physical(struct datalink *dl, struct iovec *iov, int *niov, int maxiov, 569 int fd, int *auxfd, int *nauxfd) 570{ 571 struct physical *p; 572 int len, h, type; 573 574 p = (struct physical *)iov[(*niov)++].iov_base; 575 p->link.name = dl->name; 576 memset(p->link.Queue, '\0', sizeof p->link.Queue); 577 578 p->desc.UpdateSet = physical_UpdateSet; 579 p->desc.IsSet = physical_IsSet; 580 p->desc.Read = physical_DescriptorRead; 581 p->desc.Write = physical_DescriptorWrite; 582 p->type = PHYS_DIRECT; 583 p->dl = dl; 584 len = strlen(_PATH_DEV); 585 p->out = NULL; 586 p->connect_count = 1; 587 588 physical_SetDevice(p, p->name.full); 589 590 p->link.lcp.fsm.bundle = dl->bundle; 591 p->link.lcp.fsm.link = &p->link; 592 memset(&p->link.lcp.fsm.FsmTimer, '\0', sizeof p->link.lcp.fsm.FsmTimer); 593 memset(&p->link.lcp.fsm.OpenTimer, '\0', sizeof p->link.lcp.fsm.OpenTimer); 594 memset(&p->link.lcp.fsm.StoppedTimer, '\0', 595 sizeof p->link.lcp.fsm.StoppedTimer); 596 p->link.lcp.fsm.parent = &dl->fsmp; 597 lcp_SetupCallbacks(&p->link.lcp); 598 599 p->link.ccp.fsm.bundle = dl->bundle; 600 p->link.ccp.fsm.link = &p->link; 601 /* Our in.state & out.state are NULL (no link-level ccp yet) */ 602 memset(&p->link.ccp.fsm.FsmTimer, '\0', sizeof p->link.ccp.fsm.FsmTimer); 603 memset(&p->link.ccp.fsm.OpenTimer, '\0', sizeof p->link.ccp.fsm.OpenTimer); 604 memset(&p->link.ccp.fsm.StoppedTimer, '\0', 605 sizeof p->link.ccp.fsm.StoppedTimer); 606 p->link.ccp.fsm.parent = &dl->fsmp; 607 ccp_SetupCallbacks(&p->link.ccp); 608 609 p->hdlc.lqm.owner = &p->link.lcp; 610 p->hdlc.ReportTimer.state = TIMER_STOPPED; 611 p->hdlc.lqm.timer.state = TIMER_STOPPED; 612 613 p->fd = fd; 614 p->link.stats.total.in.SampleOctets = (long long *)iov[(*niov)++].iov_base; 615 p->link.stats.total.out.SampleOctets = (long long *)iov[(*niov)++].iov_base; 616 p->link.stats.parent = dl->bundle->ncp.mp.active ? 617 &dl->bundle->ncp.mp.link.stats.total : NULL; 618 p->link.stats.gather = 1; 619 620 type = (long)p->handler; 621 p->handler = NULL; 622 for (h = 0; h < NDEVICES && p->handler == NULL; h++) 623 p->handler = (*devices[h].iov2device)(type, p, iov, niov, maxiov, 624 auxfd, nauxfd); 625 if (p->handler == NULL) { 626 log_Printf(LogPHASE, "%s: Unknown link type\n", p->link.name); 627 free(iov[(*niov)++].iov_base); 628 physical_SetupStack(p, "unknown", PHYSICAL_NOFORCE); 629 } else 630 log_Printf(LogPHASE, "%s: Device %s, link type is %s\n", 631 p->link.name, p->name.full, p->handler->name); 632 633 if (p->hdlc.lqm.method && p->hdlc.lqm.timer.load) 634 lqr_reStart(&p->link.lcp); 635 hdlc_StartTimer(&p->hdlc); 636 637 throughput_restart(&p->link.stats.total, "physical throughput", 638 Enabled(dl->bundle, OPT_THROUGHPUT)); 639 640 return p; 641} 642 643int 644physical_MaxDeviceSize() 645{ 646 int biggest, sz, n; 647 648 biggest = sizeof(struct device); 649 for (sz = n = 0; n < NDEVICES; n++) 650 if (devices[n].DeviceSize) { 651 sz = (*devices[n].DeviceSize)(); 652 if (biggest < sz) 653 biggest = sz; 654 } 655 656 return biggest; 657} 658 659int 660physical2iov(struct physical *p, struct iovec *iov, int *niov, int maxiov, 661 int *auxfd, int *nauxfd) 662{ 663 struct device *h; 664 int sz; 665 666 h = NULL; 667 if (p) { 668 hdlc_StopTimer(&p->hdlc); 669 lqr_StopTimer(p); 670 timer_Stop(&p->link.lcp.fsm.FsmTimer); 671 timer_Stop(&p->link.ccp.fsm.FsmTimer); 672 timer_Stop(&p->link.lcp.fsm.OpenTimer); 673 timer_Stop(&p->link.ccp.fsm.OpenTimer); 674 timer_Stop(&p->link.lcp.fsm.StoppedTimer); 675 timer_Stop(&p->link.ccp.fsm.StoppedTimer); 676 if (p->handler) { 677 h = p->handler; 678 p->handler = (struct device *)(long)p->handler->type; 679 } 680 681 if (Enabled(p->dl->bundle, OPT_KEEPSESSION) || 682 tcgetpgrp(p->fd) == getpgrp()) 683 p->session_owner = getpid(); /* So I'll eventually get HUP'd */ 684 else 685 p->session_owner = (pid_t)-1; 686 timer_Stop(&p->link.stats.total.Timer); 687 } 688 689 if (*niov + 2 >= maxiov) { 690 log_Printf(LogERROR, "physical2iov: No room for physical + throughput" 691 " + device !\n"); 692 if (p) 693 free(p); 694 return -1; 695 } 696 697 iov[*niov].iov_base = (void *)p; 698 iov[*niov].iov_len = sizeof *p; 699 (*niov)++; 700 701 iov[*niov].iov_base = p ? (void *)p->link.stats.total.in.SampleOctets : NULL; 702 iov[*niov].iov_len = SAMPLE_PERIOD * sizeof(long long); 703 (*niov)++; 704 iov[*niov].iov_base = p ? (void *)p->link.stats.total.out.SampleOctets : NULL; 705 iov[*niov].iov_len = SAMPLE_PERIOD * sizeof(long long); 706 (*niov)++; 707 708 sz = physical_MaxDeviceSize(); 709 if (p) { 710 if (h && h->device2iov) 711 (*h->device2iov)(h, iov, niov, maxiov, auxfd, nauxfd); 712 else { 713 iov[*niov].iov_base = malloc(sz); 714 if (h) 715 memcpy(iov[*niov].iov_base, h, sizeof *h); 716 iov[*niov].iov_len = sz; 717 (*niov)++; 718 } 719 } else { 720 iov[*niov].iov_base = NULL; 721 iov[*niov].iov_len = sz; 722 (*niov)++; 723 } 724 725 return p ? p->fd : 0; 726} 727 728const char * 729physical_LockedDevice(struct physical *p) 730{ 731 if (p->fd >= 0 && *p->name.full == '/' && p->type != PHYS_DIRECT) 732 return p->name.base; 733 734 return NULL; 735} 736 737void 738physical_ChangedPid(struct physical *p, pid_t newpid) 739{ 740 if (physical_LockedDevice(p)) { 741 int res; 742 743 if ((res = ID0uu_lock_txfr(p->name.base, newpid)) != UU_LOCK_OK) 744 log_Printf(LogPHASE, "uu_lock_txfr: %s\n", uu_lockerr(res)); 745 } 746} 747 748int 749physical_IsSync(struct physical *p) 750{ 751 return p->cfg.speed == 0; 752} 753 754const char *physical_GetDevice(struct physical *p) 755{ 756 return p->name.full; 757} 758 759void 760physical_SetDeviceList(struct physical *p, int argc, const char *const *argv) 761{ 762 int f, pos; 763 764 p->cfg.devlist[sizeof p->cfg.devlist - 1] = '\0'; 765 for (f = 0, pos = 0; f < argc && pos < sizeof p->cfg.devlist - 1; f++) { 766 if (pos) 767 p->cfg.devlist[pos++] = '\0'; 768 strncpy(p->cfg.devlist + pos, argv[f], sizeof p->cfg.devlist - pos - 1); 769 pos += strlen(p->cfg.devlist + pos); 770 } 771 p->cfg.ndev = f; 772} 773 774void 775physical_SetSync(struct physical *p) 776{ 777 p->cfg.speed = 0; 778} 779 780int 781physical_SetRtsCts(struct physical *p, int enable) 782{ 783 p->cfg.rts_cts = enable ? 1 : 0; 784 return 1; 785} 786 787ssize_t 788physical_Read(struct physical *p, void *buf, size_t nbytes) 789{ 790 ssize_t ret; 791 792 if (p->handler && p->handler->read) 793 ret = (*p->handler->read)(p, buf, nbytes); 794 else 795 ret = read(p->fd, buf, nbytes); 796 797 log_DumpBuff(LogPHYSICAL, "read", buf, ret); 798 799 return ret; 800} 801 802ssize_t 803physical_Write(struct physical *p, const void *buf, size_t nbytes) 804{ 805 log_DumpBuff(LogPHYSICAL, "write", buf, nbytes); 806 807 if (p->handler && p->handler->write) 808 return (*p->handler->write)(p, buf, nbytes); 809 810 return write(p->fd, buf, nbytes); 811} 812 813int 814physical_doUpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, 815 int *n, int force) 816{ 817 struct physical *p = descriptor2physical(d); 818 int sets; 819 820 sets = 0; 821 if (p->fd >= 0) { 822 if (r) { 823 FD_SET(p->fd, r); 824 log_Printf(LogTIMER, "%s: fdset(r) %d\n", p->link.name, p->fd); 825 sets++; 826 } 827 if (e) { 828 FD_SET(p->fd, e); 829 log_Printf(LogTIMER, "%s: fdset(e) %d\n", p->link.name, p->fd); 830 sets++; 831 } 832 if (w && (force || link_QueueLen(&p->link) || p->out)) { 833 FD_SET(p->fd, w); 834 log_Printf(LogTIMER, "%s: fdset(w) %d\n", p->link.name, p->fd); 835 sets++; 836 } 837 if (sets && *n < p->fd + 1) 838 *n = p->fd + 1; 839 } 840 841 return sets; 842} 843 844int 845physical_RemoveFromSet(struct physical *p, fd_set *r, fd_set *w, fd_set *e) 846{ 847 if (p->handler && p->handler->removefromset) 848 return (*p->handler->removefromset)(p, r, w, e); 849 else { 850 int sets; 851 852 sets = 0; 853 if (p->fd >= 0) { 854 if (r && FD_ISSET(p->fd, r)) { 855 FD_CLR(p->fd, r); 856 log_Printf(LogTIMER, "%s: fdunset(r) %d\n", p->link.name, p->fd); 857 sets++; 858 } 859 if (e && FD_ISSET(p->fd, e)) { 860 FD_CLR(p->fd, e); 861 log_Printf(LogTIMER, "%s: fdunset(e) %d\n", p->link.name, p->fd); 862 sets++; 863 } 864 if (w && FD_ISSET(p->fd, w)) { 865 FD_CLR(p->fd, w); 866 log_Printf(LogTIMER, "%s: fdunset(w) %d\n", p->link.name, p->fd); 867 sets++; 868 } 869 } 870 871 return sets; 872 } 873} 874 875int 876physical_IsSet(struct fdescriptor *d, const fd_set *fdset) 877{ 878 struct physical *p = descriptor2physical(d); 879 return p->fd >= 0 && FD_ISSET(p->fd, fdset); 880} 881 882void 883physical_Login(struct physical *p, const char *name) 884{ 885 if (p->type == PHYS_DIRECT && *p->name.base && !p->Utmp) { 886 struct utmp ut; 887 const char *connstr; 888 char *colon; 889 890 memset(&ut, 0, sizeof ut); 891 time(&ut.ut_time); 892 strncpy(ut.ut_name, name, sizeof ut.ut_name); 893 if (p->handler && (p->handler->type == TCP_DEVICE || 894 p->handler->type == UDP_DEVICE)) { 895 strncpy(ut.ut_line, PPPOTCPLINE, sizeof ut.ut_line); 896 strncpy(ut.ut_host, p->name.base, sizeof ut.ut_host); 897 colon = memchr(ut.ut_host, ':', sizeof ut.ut_host); 898 if (colon) 899 *colon = '\0'; 900 } else 901 strncpy(ut.ut_line, p->name.base, sizeof ut.ut_line); 902 if ((connstr = getenv("CONNECT"))) 903 /* mgetty sets this to the connection speed */ 904 strncpy(ut.ut_host, connstr, sizeof ut.ut_host); 905 ID0login(&ut); 906 p->Utmp = ut.ut_time; 907 } 908} 909 910int 911physical_SetMode(struct physical *p, int mode) 912{ 913 if ((p->type & (PHYS_DIRECT|PHYS_DEDICATED) || 914 mode & (PHYS_DIRECT|PHYS_DEDICATED)) && 915 (!(p->type & PHYS_DIRECT) || !(mode & PHYS_BACKGROUND))) { 916 /* Note: The -direct -> -background is for callback ! */ 917 log_Printf(LogWARN, "%s: Cannot change mode %s to %s\n", p->link.name, 918 mode2Nam(p->type), mode2Nam(mode)); 919 return 0; 920 } 921 p->type = mode; 922 return 1; 923} 924 925void 926physical_DeleteQueue(struct physical *p) 927{ 928 if (p->out) { 929 m_freem(p->out); 930 p->out = NULL; 931 } 932 link_DeleteQueue(&p->link); 933} 934 935void 936physical_SetDevice(struct physical *p, const char *name) 937{ 938 int len = strlen(_PATH_DEV); 939 940 if (name != p->name.full) { 941 strncpy(p->name.full, name, sizeof p->name.full - 1); 942 p->name.full[sizeof p->name.full - 1] = '\0'; 943 } 944 p->name.base = *p->name.full == '!' ? p->name.full + 1 : 945 strncmp(p->name.full, _PATH_DEV, len) ? 946 p->name.full : p->name.full + len; 947} 948 949static void 950physical_Found(struct physical *p) 951{ 952 FILE *lockfile; 953 char fn[MAXPATHLEN]; 954 955 if (*p->name.full == '/') { 956 snprintf(fn, sizeof fn, "%s%s.if", _PATH_VARRUN, p->name.base); 957 lockfile = ID0fopen(fn, "w"); 958 if (lockfile != NULL) { 959 fprintf(lockfile, "%s%d\n", TUN_NAME, p->dl->bundle->unit); 960 fclose(lockfile); 961 } 962#ifndef RELEASE_CRUNCH 963 else 964 log_Printf(LogALERT, "%s: Can't create %s: %s\n", 965 p->link.name, fn, strerror(errno)); 966#endif 967 } 968 969 throughput_start(&p->link.stats.total, "physical throughput", 970 Enabled(p->dl->bundle, OPT_THROUGHPUT)); 971 p->connect_count++; 972 p->input.sz = 0; 973 974 log_Printf(LogPHASE, "%s: Connected!\n", p->link.name); 975} 976 977int 978physical_Open(struct physical *p, struct bundle *bundle) 979{ 980 int devno, h, wasfd, err; 981 char *dev; 982 983 if (p->fd >= 0) 984 log_Printf(LogDEBUG, "%s: Open: Modem is already open!\n", p->link.name); 985 /* We're going back into "term" mode */ 986 else if (p->type == PHYS_DIRECT) { 987 physical_SetDevice(p, ""); 988 p->fd = STDIN_FILENO; 989 for (h = 0; h < NDEVICES && p->handler == NULL && p->fd >= 0; h++) 990 p->handler = (*devices[h].create)(p); 991 if (p->fd >= 0) { 992 if (p->handler == NULL) { 993 physical_SetupStack(p, "unknown", PHYSICAL_NOFORCE); 994 log_Printf(LogDEBUG, "%s: stdin is unidentified\n", p->link.name); 995 } 996 physical_Found(p); 997 } 998 } else { 999 dev = p->cfg.devlist; 1000 devno = 0; 1001 while (devno < p->cfg.ndev && p->fd < 0) { 1002 physical_SetDevice(p, dev); 1003 if (physical_Lock(p)) { 1004 err = 0; 1005 1006 if (*p->name.full == '/') { 1007 p->fd = ID0open(p->name.full, O_RDWR | O_NONBLOCK); 1008 if (p->fd < 0) 1009 err = errno; 1010 } 1011 1012 wasfd = p->fd; 1013 for (h = 0; h < NDEVICES && p->handler == NULL; h++) 1014 if ((p->handler = (*devices[h].create)(p)) == NULL && wasfd != p->fd) 1015 break; 1016 1017 if (p->fd < 0) { 1018 if (h == NDEVICES) { 1019 if (err) 1020 log_Printf(LogWARN, "%s: %s: %s\n", p->link.name, p->name.full, 1021 strerror(errno)); 1022 else 1023 log_Printf(LogWARN, "%s: Device (%s) must begin with a '/'," 1024 " a '!' or contain at least one ':'\n", p->link.name, 1025 p->name.full); 1026 } 1027 physical_Unlock(p); 1028 } else 1029 physical_Found(p); 1030 } 1031 dev += strlen(dev) + 1; 1032 devno++; 1033 } 1034 } 1035 1036 return p->fd; 1037} 1038 1039void 1040physical_SetupStack(struct physical *p, const char *who, int how) 1041{ 1042 link_EmptyStack(&p->link); 1043 if (how == PHYSICAL_FORCE_SYNC || how == PHYSICAL_FORCE_SYNCNOACF || 1044 (how == PHYSICAL_NOFORCE && physical_IsSync(p))) 1045 link_Stack(&p->link, &synclayer); 1046 else { 1047 link_Stack(&p->link, &asynclayer); 1048 link_Stack(&p->link, &hdlclayer); 1049 } 1050 if (how != PHYSICAL_FORCE_SYNCNOACF) 1051 link_Stack(&p->link, &acflayer); 1052 link_Stack(&p->link, &protolayer); 1053 link_Stack(&p->link, &lqrlayer); 1054 link_Stack(&p->link, &ccplayer); 1055 link_Stack(&p->link, &vjlayer); 1056 link_Stack(&p->link, &tcpmsslayer); 1057#ifndef NONAT 1058 link_Stack(&p->link, &natlayer); 1059#endif 1060 if (how == PHYSICAL_FORCE_ASYNC && physical_IsSync(p)) { 1061 log_Printf(LogWARN, "Sync device setting ignored for ``%s'' device\n", who); 1062 p->cfg.speed = MODEM_SPEED; 1063 } else if (how == PHYSICAL_FORCE_SYNC && !physical_IsSync(p)) { 1064 log_Printf(LogWARN, "Async device setting ignored for ``%s'' device\n", 1065 who); 1066 physical_SetSync(p); 1067 } 1068} 1069 1070void 1071physical_StopDeviceTimer(struct physical *p) 1072{ 1073 if (p->handler && p->handler->stoptimer) 1074 (*p->handler->stoptimer)(p); 1075} 1076 1077int 1078physical_AwaitCarrier(struct physical *p) 1079{ 1080 if (p->handler && p->handler->awaitcarrier) 1081 return (*p->handler->awaitcarrier)(p); 1082 1083 return CARRIER_OK; 1084} 1085