1998-01-29 00:49:32 +00:00
|
|
|
/*
|
|
|
|
* Written by Eivind Eklund <eivind@yes.no>
|
|
|
|
* for Yes Interactive
|
|
|
|
*
|
|
|
|
* Copyright (C) 1998, Yes Interactive. All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in any form is permitted. Redistribution in
|
|
|
|
* source form should include the above copyright and this set of
|
|
|
|
* conditions, because large sections american law seems to have been
|
|
|
|
* created by a bunch of jerks on drugs that are now illegal, forcing
|
|
|
|
* me to include this copyright-stuff instead of placing this in the
|
|
|
|
* public domain. The name of of 'Yes Interactive' or 'Eivind Eklund'
|
|
|
|
* may not be used to endorse or promote products derived from this
|
|
|
|
* software without specific prior written permission.
|
|
|
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
|
|
|
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
|
|
|
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
*
|
1999-08-28 01:35:59 +00:00
|
|
|
* $FreeBSD$
|
1998-01-29 00:49:32 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
1999-05-08 11:07:56 +00:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/in_systm.h>
|
|
|
|
#include <netinet/ip.h>
|
2001-08-14 16:05:52 +00:00
|
|
|
#include <sys/socket.h>
|
2010-01-13 17:54:32 +00:00
|
|
|
#include <sys/time.h>
|
1999-05-08 11:07:56 +00:00
|
|
|
#include <sys/un.h>
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <paths.h>
|
2004-09-05 01:46:52 +00:00
|
|
|
#ifdef NOSUID
|
|
|
|
#include <signal.h>
|
|
|
|
#endif
|
2002-08-27 20:11:58 +00:00
|
|
|
#include <stdarg.h>
|
1998-01-29 00:49:32 +00:00
|
|
|
#include <stdio.h>
|
1998-04-30 23:53:56 +00:00
|
|
|
#include <stdlib.h>
|
1998-01-29 00:49:32 +00:00
|
|
|
#include <string.h>
|
1999-05-08 11:07:56 +00:00
|
|
|
#include <sys/uio.h>
|
2004-10-11 09:45:58 +00:00
|
|
|
#include <sysexits.h>
|
2008-06-05 17:46:32 +00:00
|
|
|
#include <termios.h>
|
1998-03-10 03:06:07 +00:00
|
|
|
#include <time.h>
|
1998-01-29 00:49:32 +00:00
|
|
|
#include <unistd.h>
|
2010-01-13 17:54:32 +00:00
|
|
|
#include <utmpx.h>
|
1999-05-08 11:07:56 +00:00
|
|
|
#if defined(__OpenBSD__) || defined(__NetBSD__)
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <util.h>
|
|
|
|
#else
|
|
|
|
#include <libutil.h>
|
|
|
|
#endif
|
1998-01-29 00:49:32 +00:00
|
|
|
|
1999-05-08 11:07:56 +00:00
|
|
|
#include "layer.h"
|
1999-08-19 18:15:52 +00:00
|
|
|
#ifndef NONAT
|
1999-09-08 07:34:52 +00:00
|
|
|
#include "nat_cmd.h"
|
1999-05-08 11:07:56 +00:00
|
|
|
#endif
|
|
|
|
#include "proto.h"
|
|
|
|
#include "acf.h"
|
|
|
|
#include "vjcomp.h"
|
1998-01-29 00:49:32 +00:00
|
|
|
#include "defs.h"
|
1999-05-08 11:07:56 +00:00
|
|
|
#include "command.h"
|
1998-01-29 00:49:32 +00:00
|
|
|
#include "mbuf.h"
|
1999-05-08 11:07:56 +00:00
|
|
|
#include "log.h"
|
|
|
|
#include "id.h"
|
1998-01-29 00:49:32 +00:00
|
|
|
#include "timer.h"
|
1999-05-08 11:07:56 +00:00
|
|
|
#include "fsm.h"
|
1998-03-13 00:44:26 +00:00
|
|
|
#include "lqr.h"
|
1998-02-18 19:35:59 +00:00
|
|
|
#include "hdlc.h"
|
1998-02-02 19:33:40 +00:00
|
|
|
#include "lcp.h"
|
1999-05-08 11:07:56 +00:00
|
|
|
#include "throughput.h"
|
|
|
|
#include "sync.h"
|
1998-02-02 19:33:40 +00:00
|
|
|
#include "async.h"
|
1999-05-08 11:07:56 +00:00
|
|
|
#include "iplist.h"
|
|
|
|
#include "slcompress.h"
|
2001-08-14 16:05:52 +00:00
|
|
|
#include "ncpaddr.h"
|
1999-05-08 11:07:56 +00:00
|
|
|
#include "ipcp.h"
|
|
|
|
#include "filter.h"
|
|
|
|
#include "descriptor.h"
|
1998-04-03 19:21:56 +00:00
|
|
|
#include "ccp.h"
|
1998-01-30 19:46:07 +00:00
|
|
|
#include "link.h"
|
1998-01-29 00:49:32 +00:00
|
|
|
#include "physical.h"
|
1999-05-08 11:07:56 +00:00
|
|
|
#include "mp.h"
|
|
|
|
#ifndef NORADIUS
|
|
|
|
#include "radius.h"
|
|
|
|
#endif
|
2001-08-14 16:05:52 +00:00
|
|
|
#include "ipv6cp.h"
|
|
|
|
#include "ncp.h"
|
1999-05-08 11:07:56 +00:00
|
|
|
#include "bundle.h"
|
|
|
|
#include "prompt.h"
|
|
|
|
#include "chat.h"
|
|
|
|
#include "auth.h"
|
2004-10-11 09:45:58 +00:00
|
|
|
#include "main.h"
|
1999-05-08 11:07:56 +00:00
|
|
|
#include "chap.h"
|
|
|
|
#include "cbcp.h"
|
|
|
|
#include "datalink.h"
|
|
|
|
#include "tcp.h"
|
1999-05-12 09:49:12 +00:00
|
|
|
#include "udp.h"
|
1999-05-08 11:07:56 +00:00
|
|
|
#include "exec.h"
|
|
|
|
#include "tty.h"
|
1999-11-06 22:50:59 +00:00
|
|
|
#ifndef NONETGRAPH
|
|
|
|
#include "ether.h"
|
2002-03-30 12:30:09 +00:00
|
|
|
#include "netgraph.h"
|
1999-11-06 22:50:59 +00:00
|
|
|
#endif
|
2000-11-28 13:18:35 +00:00
|
|
|
#include "tcpmss.h"
|
1999-05-08 11:07:56 +00:00
|
|
|
|
2000-03-14 01:46:09 +00:00
|
|
|
static int physical_DescriptorWrite(struct fdescriptor *, struct bundle *,
|
1999-05-08 11:07:56 +00:00
|
|
|
const fd_set *);
|
|
|
|
|
2004-09-05 01:46:52 +00:00
|
|
|
static unsigned
|
1999-06-05 21:36:00 +00:00
|
|
|
physical_DeviceSize(void)
|
|
|
|
{
|
|
|
|
return sizeof(struct device);
|
|
|
|
}
|
|
|
|
|
1999-05-12 09:49:12 +00:00
|
|
|
struct {
|
|
|
|
struct device *(*create)(struct physical *);
|
1999-11-06 22:50:59 +00:00
|
|
|
struct device *(*iov2device)(int, struct physical *, struct iovec *,
|
|
|
|
int *, int, int *, int *);
|
2004-09-05 01:46:52 +00:00
|
|
|
unsigned (*DeviceSize)(void);
|
1999-05-12 09:49:12 +00:00
|
|
|
} devices[] = {
|
1999-06-05 21:36:00 +00:00
|
|
|
{ tty_Create, tty_iov2device, tty_DeviceSize },
|
1999-11-06 22:50:59 +00:00
|
|
|
#ifndef NONETGRAPH
|
2001-01-14 00:54:48 +00:00
|
|
|
/*
|
|
|
|
* This must come before ``udp'' so that the probe routine is
|
|
|
|
* able to identify it as a more specific type of SOCK_DGRAM.
|
|
|
|
*/
|
1999-11-06 22:50:59 +00:00
|
|
|
{ ether_Create, ether_iov2device, ether_DeviceSize },
|
2002-03-30 12:30:09 +00:00
|
|
|
#ifdef EXPERIMENTAL_NETGRAPH
|
|
|
|
{ ng_Create, ng_iov2device, ng_DeviceSize },
|
|
|
|
#endif
|
1999-11-06 22:50:59 +00:00
|
|
|
#endif
|
1999-06-05 21:36:00 +00:00
|
|
|
{ tcp_Create, tcp_iov2device, tcp_DeviceSize },
|
|
|
|
{ udp_Create, udp_iov2device, udp_DeviceSize },
|
|
|
|
{ exec_Create, exec_iov2device, exec_DeviceSize }
|
1999-05-08 11:07:56 +00:00
|
|
|
};
|
|
|
|
|
1999-05-12 09:49:12 +00:00
|
|
|
#define NDEVICES (sizeof devices / sizeof devices[0])
|
1999-05-08 11:07:56 +00:00
|
|
|
|
|
|
|
static int
|
2000-03-14 01:46:09 +00:00
|
|
|
physical_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e,
|
1999-05-08 11:07:56 +00:00
|
|
|
int *n)
|
|
|
|
{
|
|
|
|
return physical_doUpdateSet(d, r, w, e, n, 0);
|
|
|
|
}
|
|
|
|
|
1999-11-06 22:50:59 +00:00
|
|
|
void
|
|
|
|
physical_SetDescriptor(struct physical *p)
|
|
|
|
{
|
|
|
|
p->desc.type = PHYSICAL_DESCRIPTOR;
|
|
|
|
p->desc.UpdateSet = physical_UpdateSet;
|
|
|
|
p->desc.IsSet = physical_IsSet;
|
|
|
|
p->desc.Read = physical_DescriptorRead;
|
|
|
|
p->desc.Write = physical_DescriptorWrite;
|
|
|
|
}
|
|
|
|
|
1999-05-08 11:07:56 +00:00
|
|
|
struct physical *
|
|
|
|
physical_Create(struct datalink *dl, int type)
|
|
|
|
{
|
|
|
|
struct physical *p;
|
|
|
|
|
|
|
|
p = (struct physical *)malloc(sizeof(struct physical));
|
|
|
|
if (!p)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
p->link.type = PHYSICAL_LINK;
|
|
|
|
p->link.name = dl->name;
|
|
|
|
p->link.len = sizeof *p;
|
1999-08-05 10:32:16 +00:00
|
|
|
|
|
|
|
/* The sample period is fixed - see physical2iov() & iov2physical() */
|
2000-08-15 00:59:21 +00:00
|
|
|
throughput_init(&p->link.stats.total, SAMPLE_PERIOD);
|
|
|
|
p->link.stats.parent = dl->bundle->ncp.mp.active ?
|
|
|
|
&dl->bundle->ncp.mp.link.stats.total : NULL;
|
|
|
|
p->link.stats.gather = 1;
|
1999-05-08 11:07:56 +00:00
|
|
|
|
|
|
|
memset(p->link.Queue, '\0', sizeof p->link.Queue);
|
|
|
|
memset(p->link.proto_in, '\0', sizeof p->link.proto_in);
|
|
|
|
memset(p->link.proto_out, '\0', sizeof p->link.proto_out);
|
|
|
|
link_EmptyStack(&p->link);
|
|
|
|
|
|
|
|
p->handler = NULL;
|
1999-11-06 22:50:59 +00:00
|
|
|
physical_SetDescriptor(p);
|
1999-05-08 11:07:56 +00:00
|
|
|
p->type = type;
|
1998-01-29 00:49:32 +00:00
|
|
|
|
1999-05-08 11:07:56 +00:00
|
|
|
hdlc_Init(&p->hdlc, &p->link.lcp);
|
|
|
|
async_Init(&p->async);
|
|
|
|
|
|
|
|
p->fd = -1;
|
|
|
|
p->out = NULL;
|
|
|
|
p->connect_count = 0;
|
|
|
|
p->dl = dl;
|
|
|
|
p->input.sz = 0;
|
|
|
|
*p->name.full = '\0';
|
|
|
|
p->name.base = p->name.full;
|
|
|
|
|
|
|
|
p->Utmp = 0;
|
|
|
|
p->session_owner = (pid_t)-1;
|
|
|
|
|
|
|
|
p->cfg.rts_cts = MODEM_CTSRTS;
|
|
|
|
p->cfg.speed = MODEM_SPEED;
|
|
|
|
p->cfg.parity = CS8;
|
|
|
|
memcpy(p->cfg.devlist, MODEM_LIST, sizeof MODEM_LIST);
|
|
|
|
p->cfg.ndev = NMODEMS;
|
1999-11-26 22:44:33 +00:00
|
|
|
p->cfg.cd.necessity = CD_DEFAULT;
|
|
|
|
p->cfg.cd.delay = 0; /* reconfigured or device specific default */
|
1999-05-08 11:07:56 +00:00
|
|
|
|
|
|
|
lcp_Init(&p->link.lcp, dl->bundle, &p->link, &dl->fsmp);
|
|
|
|
ccp_Init(&p->link.ccp, dl->bundle, &p->link, &dl->fsmp);
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct parity {
|
|
|
|
const char *name;
|
|
|
|
const char *name1;
|
|
|
|
int set;
|
|
|
|
} validparity[] = {
|
|
|
|
{ "even", "P_EVEN", CS7 | PARENB },
|
|
|
|
{ "odd", "P_ODD", CS7 | PARENB | PARODD },
|
|
|
|
{ "none", "P_ZERO", CS8 },
|
2004-09-05 01:46:52 +00:00
|
|
|
{ NULL, NULL, 0 },
|
1999-05-08 11:07:56 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
GetParityValue(const char *str)
|
|
|
|
{
|
|
|
|
const struct parity *pp;
|
|
|
|
|
|
|
|
for (pp = validparity; pp->name; pp++) {
|
|
|
|
if (strcasecmp(pp->name, str) == 0 ||
|
|
|
|
strcasecmp(pp->name1, str) == 0) {
|
|
|
|
return pp->set;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
physical_SetParity(struct physical *p, const char *str)
|
|
|
|
{
|
|
|
|
struct termios rstio;
|
|
|
|
int val;
|
|
|
|
|
|
|
|
val = GetParityValue(str);
|
|
|
|
if (val > 0) {
|
|
|
|
p->cfg.parity = val;
|
|
|
|
if (p->fd >= 0) {
|
|
|
|
tcgetattr(p->fd, &rstio);
|
|
|
|
rstio.c_cflag &= ~(CSIZE | PARODD | PARENB);
|
|
|
|
rstio.c_cflag |= val;
|
|
|
|
tcsetattr(p->fd, TCSADRAIN, &rstio);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
log_Printf(LogWARN, "%s: %s: Invalid parity\n", p->link.name, str);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2004-09-05 01:46:52 +00:00
|
|
|
unsigned
|
1999-05-08 11:07:56 +00:00
|
|
|
physical_GetSpeed(struct physical *p)
|
|
|
|
{
|
|
|
|
if (p->handler && p->handler->speed)
|
|
|
|
return (*p->handler->speed)(p);
|
1998-01-29 00:49:32 +00:00
|
|
|
|
1999-08-05 10:32:16 +00:00
|
|
|
return 0;
|
1999-05-08 11:07:56 +00:00
|
|
|
}
|
1998-01-29 00:49:32 +00:00
|
|
|
|
|
|
|
int
|
2004-09-05 01:46:52 +00:00
|
|
|
physical_SetSpeed(struct physical *p, unsigned speed)
|
1999-05-08 11:07:56 +00:00
|
|
|
{
|
2004-09-05 01:46:52 +00:00
|
|
|
if (UnsignedToSpeed(speed) != B0) {
|
1999-05-08 11:07:56 +00:00
|
|
|
p->cfg.speed = speed;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
1998-01-29 00:49:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
1999-05-08 11:07:56 +00:00
|
|
|
physical_Raw(struct physical *p)
|
|
|
|
{
|
|
|
|
if (p->handler && p->handler->raw)
|
|
|
|
return (*p->handler->raw)(p);
|
|
|
|
|
|
|
|
return 1;
|
1998-01-29 00:49:32 +00:00
|
|
|
}
|
|
|
|
|
1999-05-08 11:07:56 +00:00
|
|
|
void
|
|
|
|
physical_Offline(struct physical *p)
|
1998-03-06 00:34:47 +00:00
|
|
|
{
|
1999-05-08 11:07:56 +00:00
|
|
|
if (p->handler && p->handler->offline)
|
|
|
|
(*p->handler->offline)(p);
|
|
|
|
log_Printf(LogPHASE, "%s: Disconnected!\n", p->link.name);
|
|
|
|
}
|
|
|
|
|
1999-05-18 01:37:46 +00:00
|
|
|
static int
|
|
|
|
physical_Lock(struct physical *p)
|
1999-05-08 11:07:56 +00:00
|
|
|
{
|
1999-05-18 01:37:46 +00:00
|
|
|
int res;
|
1999-05-08 11:07:56 +00:00
|
|
|
|
1999-05-18 01:37:46 +00:00
|
|
|
if (*p->name.full == '/' && p->type != PHYS_DIRECT &&
|
|
|
|
(res = ID0uu_lock(p->name.base)) != UU_LOCK_OK) {
|
|
|
|
if (res == UU_LOCK_INUSE)
|
|
|
|
log_Printf(LogPHASE, "%s: %s is in use\n", p->link.name, p->name.full);
|
|
|
|
else
|
|
|
|
log_Printf(LogPHASE, "%s: %s is in use: uu_lock: %s\n",
|
|
|
|
p->link.name, p->name.full, uu_lockerr(res));
|
|
|
|
return 0;
|
1999-05-08 11:07:56 +00:00
|
|
|
}
|
1999-05-18 01:37:46 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
physical_Unlock(struct physical *p)
|
|
|
|
{
|
|
|
|
if (*p->name.full == '/' && p->type != PHYS_DIRECT &&
|
|
|
|
ID0uu_unlock(p->name.base) == -1)
|
2001-03-08 23:51:50 +00:00
|
|
|
log_Printf(LogALERT, "%s: Can't uu_unlock %s\n", p->link.name,
|
|
|
|
p->name.base);
|
1999-05-08 11:07:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
physical_Close(struct physical *p)
|
|
|
|
{
|
1999-05-18 01:37:46 +00:00
|
|
|
int newsid;
|
2001-03-08 23:51:50 +00:00
|
|
|
char fn[PATH_MAX];
|
2010-01-13 17:54:32 +00:00
|
|
|
struct utmpx ut;
|
1999-05-18 01:37:46 +00:00
|
|
|
|
1999-05-08 11:07:56 +00:00
|
|
|
if (p->fd < 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
log_Printf(LogDEBUG, "%s: Close\n", p->link.name);
|
|
|
|
|
|
|
|
if (p->handler && p->handler->cooked)
|
|
|
|
(*p->handler->cooked)(p);
|
|
|
|
|
1999-05-18 01:37:46 +00:00
|
|
|
physical_StopDeviceTimer(p);
|
|
|
|
if (p->Utmp) {
|
2010-01-13 17:54:32 +00:00
|
|
|
memset(&ut, 0, sizeof ut);
|
|
|
|
ut.ut_type = DEAD_PROCESS;
|
|
|
|
gettimeofday(&ut.ut_tv, NULL);
|
|
|
|
snprintf(ut.ut_id, sizeof ut.ut_id, "%xppp", (int)getpid());
|
|
|
|
ID0logout(&ut);
|
1999-05-18 01:37:46 +00:00
|
|
|
p->Utmp = 0;
|
|
|
|
}
|
|
|
|
newsid = tcgetpgrp(p->fd) == getpgrp();
|
|
|
|
close(p->fd);
|
|
|
|
p->fd = -1;
|
|
|
|
log_SetTtyCommandMode(p->dl);
|
|
|
|
|
2000-08-15 00:59:21 +00:00
|
|
|
throughput_stop(&p->link.stats.total);
|
|
|
|
throughput_log(&p->link.stats.total, LogPHASE, p->link.name);
|
1999-05-18 01:37:46 +00:00
|
|
|
|
|
|
|
if (p->session_owner != (pid_t)-1) {
|
2002-05-27 23:19:53 +00:00
|
|
|
log_Printf(LogPHASE, "%s: HUPing %ld\n", p->link.name,
|
|
|
|
(long)p->session_owner);
|
1999-05-18 01:37:46 +00:00
|
|
|
ID0kill(p->session_owner, SIGHUP);
|
|
|
|
p->session_owner = (pid_t)-1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (newsid)
|
|
|
|
bundle_setsid(p->dl->bundle, 0);
|
|
|
|
|
|
|
|
if (*p->name.full == '/') {
|
|
|
|
snprintf(fn, sizeof fn, "%s%s.if", _PATH_VARRUN, p->name.base);
|
|
|
|
if (ID0unlink(fn) == -1)
|
|
|
|
log_Printf(LogALERT, "%s: Can't remove %s: %s\n",
|
|
|
|
p->link.name, fn, strerror(errno));
|
|
|
|
}
|
|
|
|
physical_Unlock(p);
|
|
|
|
if (p->handler && p->handler->destroy)
|
|
|
|
(*p->handler->destroy)(p);
|
|
|
|
p->handler = NULL;
|
|
|
|
p->name.base = p->name.full;
|
|
|
|
*p->name.full = '\0';
|
1999-05-08 11:07:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
physical_Destroy(struct physical *p)
|
|
|
|
{
|
|
|
|
physical_Close(p);
|
2000-08-15 00:59:21 +00:00
|
|
|
throughput_destroy(&p->link.stats.total);
|
1999-05-08 11:07:56 +00:00
|
|
|
free(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2004-09-05 01:46:52 +00:00
|
|
|
physical_DescriptorWrite(struct fdescriptor *d, struct bundle *bundle __unused,
|
|
|
|
const fd_set *fdset __unused)
|
1999-05-08 11:07:56 +00:00
|
|
|
{
|
|
|
|
struct physical *p = descriptor2physical(d);
|
|
|
|
int nw, result = 0;
|
|
|
|
|
|
|
|
if (p->out == NULL)
|
|
|
|
p->out = link_Dequeue(&p->link);
|
|
|
|
|
|
|
|
if (p->out) {
|
1999-12-20 20:29:47 +00:00
|
|
|
nw = physical_Write(p, MBUF_CTOP(p->out), p->out->m_len);
|
2000-03-14 01:47:19 +00:00
|
|
|
log_Printf(LogDEBUG, "%s: DescriptorWrite: wrote %d(%lu) to %d\n",
|
|
|
|
p->link.name, nw, (unsigned long)p->out->m_len, p->fd);
|
1999-05-08 11:07:56 +00:00
|
|
|
if (nw > 0) {
|
1999-12-20 20:29:47 +00:00
|
|
|
p->out->m_len -= nw;
|
|
|
|
p->out->m_offset += nw;
|
|
|
|
if (p->out->m_len == 0)
|
|
|
|
p->out = m_free(p->out);
|
1999-05-08 11:07:56 +00:00
|
|
|
result = 1;
|
|
|
|
} else if (nw < 0) {
|
2000-10-09 22:49:44 +00:00
|
|
|
if (errno == EAGAIN)
|
|
|
|
result = 1;
|
|
|
|
else if (errno != ENOBUFS) {
|
2004-09-06 00:07:58 +00:00
|
|
|
log_Printf(LogPHASE, "%s: write (fd %d, len %zd): %s\n", p->link.name,
|
2004-07-20 01:42:30 +00:00
|
|
|
p->fd, p->out->m_len, strerror(errno));
|
1999-05-08 11:07:56 +00:00
|
|
|
datalink_Down(p->dl, CLOSE_NORMAL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* else we shouldn't really have been called ! select() is broken ! */
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
physical_ShowStatus(struct cmdargs const *arg)
|
|
|
|
{
|
|
|
|
struct physical *p = arg->cx->physical;
|
1999-11-26 22:44:33 +00:00
|
|
|
struct cd *cd;
|
1999-05-08 11:07:56 +00:00
|
|
|
const char *dev;
|
2002-06-30 01:46:22 +00:00
|
|
|
int n, slot;
|
1999-05-08 11:07:56 +00:00
|
|
|
|
|
|
|
prompt_Printf(arg->prompt, "Name: %s\n", p->link.name);
|
|
|
|
prompt_Printf(arg->prompt, " State: ");
|
|
|
|
if (p->fd < 0)
|
|
|
|
prompt_Printf(arg->prompt, "closed\n");
|
2002-06-30 01:46:22 +00:00
|
|
|
else {
|
|
|
|
slot = physical_Slot(p);
|
|
|
|
if (p->handler && p->handler->openinfo) {
|
|
|
|
if (slot == -1)
|
|
|
|
prompt_Printf(arg->prompt, "open (%s)\n", (*p->handler->openinfo)(p));
|
|
|
|
else
|
|
|
|
prompt_Printf(arg->prompt, "open (%s, port %d)\n",
|
|
|
|
(*p->handler->openinfo)(p), slot);
|
|
|
|
} else if (slot == -1)
|
|
|
|
prompt_Printf(arg->prompt, "open\n");
|
|
|
|
else
|
|
|
|
prompt_Printf(arg->prompt, "open (port %d)\n", slot);
|
|
|
|
}
|
1999-05-08 11:07:56 +00:00
|
|
|
|
|
|
|
prompt_Printf(arg->prompt, " Device: %s",
|
|
|
|
*p->name.full ? p->name.full :
|
|
|
|
p->type == PHYS_DIRECT ? "unknown" : "N/A");
|
|
|
|
if (p->session_owner != (pid_t)-1)
|
2002-05-27 23:19:53 +00:00
|
|
|
prompt_Printf(arg->prompt, " (session owner: %ld)", (long)p->session_owner);
|
1999-05-08 11:07:56 +00:00
|
|
|
|
|
|
|
prompt_Printf(arg->prompt, "\n Link Type: %s\n", mode2Nam(p->type));
|
|
|
|
prompt_Printf(arg->prompt, " Connect Count: %d\n", p->connect_count);
|
|
|
|
#ifdef TIOCOUTQ
|
|
|
|
if (p->fd >= 0 && ioctl(p->fd, TIOCOUTQ, &n) >= 0)
|
|
|
|
prompt_Printf(arg->prompt, " Physical outq: %d\n", n);
|
|
|
|
#endif
|
|
|
|
|
1999-12-20 20:29:47 +00:00
|
|
|
prompt_Printf(arg->prompt, " Queued Packets: %lu\n",
|
|
|
|
(u_long)link_QueueLen(&p->link));
|
1999-05-08 11:07:56 +00:00
|
|
|
prompt_Printf(arg->prompt, " Phone Number: %s\n", arg->cx->phone.chosen);
|
|
|
|
|
|
|
|
prompt_Printf(arg->prompt, "\nDefaults:\n");
|
|
|
|
|
|
|
|
prompt_Printf(arg->prompt, " Device List: ");
|
|
|
|
dev = p->cfg.devlist;
|
|
|
|
for (n = 0; n < p->cfg.ndev; n++) {
|
|
|
|
if (n)
|
|
|
|
prompt_Printf(arg->prompt, ", ");
|
|
|
|
prompt_Printf(arg->prompt, "\"%s\"", dev);
|
|
|
|
dev += strlen(dev) + 1;
|
|
|
|
}
|
2002-06-15 08:03:30 +00:00
|
|
|
|
1999-05-08 11:07:56 +00:00
|
|
|
prompt_Printf(arg->prompt, "\n Characteristics: ");
|
|
|
|
if (physical_IsSync(arg->cx->physical))
|
|
|
|
prompt_Printf(arg->prompt, "sync");
|
|
|
|
else
|
|
|
|
prompt_Printf(arg->prompt, "%dbps", p->cfg.speed);
|
|
|
|
|
|
|
|
switch (p->cfg.parity & CSIZE) {
|
|
|
|
case CS7:
|
|
|
|
prompt_Printf(arg->prompt, ", cs7");
|
|
|
|
break;
|
|
|
|
case CS8:
|
|
|
|
prompt_Printf(arg->prompt, ", cs8");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (p->cfg.parity & PARENB) {
|
|
|
|
if (p->cfg.parity & PARODD)
|
|
|
|
prompt_Printf(arg->prompt, ", odd parity");
|
|
|
|
else
|
|
|
|
prompt_Printf(arg->prompt, ", even parity");
|
|
|
|
} else
|
|
|
|
prompt_Printf(arg->prompt, ", no parity");
|
|
|
|
|
|
|
|
prompt_Printf(arg->prompt, ", CTS/RTS %s\n", (p->cfg.rts_cts ? "on" : "off"));
|
|
|
|
|
1999-09-26 23:02:18 +00:00
|
|
|
prompt_Printf(arg->prompt, " CD check delay: ");
|
1999-11-26 22:44:33 +00:00
|
|
|
cd = p->handler ? &p->handler->cd : &p->cfg.cd;
|
|
|
|
if (cd->necessity == CD_NOTREQUIRED)
|
1999-09-26 23:02:18 +00:00
|
|
|
prompt_Printf(arg->prompt, "no cd");
|
1999-11-26 22:44:33 +00:00
|
|
|
else if (p->cfg.cd.necessity == CD_DEFAULT) {
|
|
|
|
prompt_Printf(arg->prompt, "device specific");
|
|
|
|
} else {
|
1999-09-26 23:02:18 +00:00
|
|
|
prompt_Printf(arg->prompt, "%d second%s", p->cfg.cd.delay,
|
|
|
|
p->cfg.cd.delay == 1 ? "" : "s");
|
|
|
|
if (p->cfg.cd.necessity == CD_REQUIRED)
|
|
|
|
prompt_Printf(arg->prompt, " (required!)");
|
|
|
|
}
|
|
|
|
prompt_Printf(arg->prompt, "\n\n");
|
1999-05-08 11:07:56 +00:00
|
|
|
|
2000-08-15 00:59:21 +00:00
|
|
|
throughput_disp(&p->link.stats.total, arg->prompt);
|
1999-05-08 11:07:56 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1999-11-06 22:50:59 +00:00
|
|
|
void
|
2000-03-14 01:46:09 +00:00
|
|
|
physical_DescriptorRead(struct fdescriptor *d, struct bundle *bundle,
|
2004-09-05 01:46:52 +00:00
|
|
|
const fd_set *fdset __unused)
|
1999-05-08 11:07:56 +00:00
|
|
|
{
|
|
|
|
struct physical *p = descriptor2physical(d);
|
|
|
|
u_char *rbuff;
|
|
|
|
int n, found;
|
|
|
|
|
|
|
|
rbuff = p->input.buf + p->input.sz;
|
|
|
|
|
|
|
|
/* something to read */
|
|
|
|
n = physical_Read(p, rbuff, sizeof p->input.buf - p->input.sz);
|
|
|
|
log_Printf(LogDEBUG, "%s: DescriptorRead: read %d/%d from %d\n",
|
|
|
|
p->link.name, n, (int)(sizeof p->input.buf - p->input.sz), p->fd);
|
|
|
|
if (n <= 0) {
|
|
|
|
if (n < 0)
|
|
|
|
log_Printf(LogPHASE, "%s: read (%d): %s\n", p->link.name, p->fd,
|
|
|
|
strerror(errno));
|
|
|
|
else
|
|
|
|
log_Printf(LogPHASE, "%s: read (%d): Got zero bytes\n",
|
|
|
|
p->link.name, p->fd);
|
|
|
|
datalink_Down(p->dl, CLOSE_NORMAL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
rbuff -= p->input.sz;
|
|
|
|
n += p->input.sz;
|
|
|
|
|
|
|
|
if (p->link.lcp.fsm.state <= ST_CLOSED) {
|
|
|
|
if (p->type != PHYS_DEDICATED) {
|
|
|
|
found = hdlc_Detect((u_char const **)&rbuff, n, physical_IsSync(p));
|
|
|
|
if (rbuff != p->input.buf)
|
|
|
|
log_WritePrompts(p->dl, "%.*s", (int)(rbuff - p->input.buf),
|
|
|
|
p->input.buf);
|
|
|
|
p->input.sz = n - (rbuff - p->input.buf);
|
|
|
|
|
|
|
|
if (found) {
|
|
|
|
/* LCP packet is detected. Turn ourselves into packet mode */
|
|
|
|
log_Printf(LogPHASE, "%s: PPP packet detected, coming up\n",
|
|
|
|
p->link.name);
|
|
|
|
log_SetTtyCommandMode(p->dl);
|
|
|
|
datalink_Up(p->dl, 0, 1);
|
|
|
|
link_PullPacket(&p->link, rbuff, p->input.sz, bundle);
|
|
|
|
p->input.sz = 0;
|
|
|
|
} else
|
|
|
|
bcopy(rbuff, p->input.buf, p->input.sz);
|
|
|
|
} else
|
|
|
|
/* In -dedicated mode, we just discard input until LCP is started */
|
|
|
|
p->input.sz = 0;
|
|
|
|
} else if (n > 0)
|
|
|
|
link_PullPacket(&p->link, rbuff, n, bundle);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct physical *
|
|
|
|
iov2physical(struct datalink *dl, struct iovec *iov, int *niov, int maxiov,
|
1999-11-06 22:50:59 +00:00
|
|
|
int fd, int *auxfd, int *nauxfd)
|
1999-05-08 11:07:56 +00:00
|
|
|
{
|
|
|
|
struct physical *p;
|
2012-01-20 01:37:49 +00:00
|
|
|
int type;
|
2004-09-05 01:46:52 +00:00
|
|
|
unsigned h;
|
1999-05-08 11:07:56 +00:00
|
|
|
|
|
|
|
p = (struct physical *)iov[(*niov)++].iov_base;
|
|
|
|
p->link.name = dl->name;
|
|
|
|
memset(p->link.Queue, '\0', sizeof p->link.Queue);
|
|
|
|
|
|
|
|
p->desc.UpdateSet = physical_UpdateSet;
|
|
|
|
p->desc.IsSet = physical_IsSet;
|
|
|
|
p->desc.Read = physical_DescriptorRead;
|
|
|
|
p->desc.Write = physical_DescriptorWrite;
|
|
|
|
p->type = PHYS_DIRECT;
|
|
|
|
p->dl = dl;
|
|
|
|
p->out = NULL;
|
|
|
|
p->connect_count = 1;
|
|
|
|
|
1999-06-01 19:08:59 +00:00
|
|
|
physical_SetDevice(p, p->name.full);
|
|
|
|
|
1999-05-08 11:07:56 +00:00
|
|
|
p->link.lcp.fsm.bundle = dl->bundle;
|
|
|
|
p->link.lcp.fsm.link = &p->link;
|
|
|
|
memset(&p->link.lcp.fsm.FsmTimer, '\0', sizeof p->link.lcp.fsm.FsmTimer);
|
|
|
|
memset(&p->link.lcp.fsm.OpenTimer, '\0', sizeof p->link.lcp.fsm.OpenTimer);
|
|
|
|
memset(&p->link.lcp.fsm.StoppedTimer, '\0',
|
|
|
|
sizeof p->link.lcp.fsm.StoppedTimer);
|
|
|
|
p->link.lcp.fsm.parent = &dl->fsmp;
|
|
|
|
lcp_SetupCallbacks(&p->link.lcp);
|
|
|
|
|
|
|
|
p->link.ccp.fsm.bundle = dl->bundle;
|
|
|
|
p->link.ccp.fsm.link = &p->link;
|
|
|
|
/* Our in.state & out.state are NULL (no link-level ccp yet) */
|
|
|
|
memset(&p->link.ccp.fsm.FsmTimer, '\0', sizeof p->link.ccp.fsm.FsmTimer);
|
|
|
|
memset(&p->link.ccp.fsm.OpenTimer, '\0', sizeof p->link.ccp.fsm.OpenTimer);
|
|
|
|
memset(&p->link.ccp.fsm.StoppedTimer, '\0',
|
|
|
|
sizeof p->link.ccp.fsm.StoppedTimer);
|
|
|
|
p->link.ccp.fsm.parent = &dl->fsmp;
|
|
|
|
ccp_SetupCallbacks(&p->link.ccp);
|
|
|
|
|
|
|
|
p->hdlc.lqm.owner = &p->link.lcp;
|
|
|
|
p->hdlc.ReportTimer.state = TIMER_STOPPED;
|
|
|
|
p->hdlc.lqm.timer.state = TIMER_STOPPED;
|
|
|
|
|
|
|
|
p->fd = fd;
|
2000-08-15 10:25:42 +00:00
|
|
|
p->link.stats.total.in.SampleOctets = (long long *)iov[(*niov)++].iov_base;
|
|
|
|
p->link.stats.total.out.SampleOctets = (long long *)iov[(*niov)++].iov_base;
|
2000-08-15 00:59:21 +00:00
|
|
|
p->link.stats.parent = dl->bundle->ncp.mp.active ?
|
|
|
|
&dl->bundle->ncp.mp.link.stats.total : NULL;
|
|
|
|
p->link.stats.gather = 1;
|
1999-05-08 11:07:56 +00:00
|
|
|
|
1999-06-05 21:36:00 +00:00
|
|
|
type = (long)p->handler;
|
|
|
|
p->handler = NULL;
|
|
|
|
for (h = 0; h < NDEVICES && p->handler == NULL; h++)
|
1999-11-06 22:50:59 +00:00
|
|
|
p->handler = (*devices[h].iov2device)(type, p, iov, niov, maxiov,
|
|
|
|
auxfd, nauxfd);
|
1999-06-05 21:36:00 +00:00
|
|
|
if (p->handler == NULL) {
|
1999-11-06 22:50:59 +00:00
|
|
|
log_Printf(LogPHASE, "%s: Unknown link type\n", p->link.name);
|
1999-06-05 21:36:00 +00:00
|
|
|
free(iov[(*niov)++].iov_base);
|
|
|
|
physical_SetupStack(p, "unknown", PHYSICAL_NOFORCE);
|
|
|
|
} else
|
|
|
|
log_Printf(LogPHASE, "%s: Device %s, link type is %s\n",
|
|
|
|
p->link.name, p->name.full, p->handler->name);
|
|
|
|
|
1999-05-08 11:07:56 +00:00
|
|
|
if (p->hdlc.lqm.method && p->hdlc.lqm.timer.load)
|
|
|
|
lqr_reStart(&p->link.lcp);
|
|
|
|
hdlc_StartTimer(&p->hdlc);
|
|
|
|
|
2000-08-15 00:59:21 +00:00
|
|
|
throughput_restart(&p->link.stats.total, "physical throughput",
|
1999-08-05 10:32:16 +00:00
|
|
|
Enabled(dl->bundle, OPT_THROUGHPUT));
|
1999-05-12 09:49:12 +00:00
|
|
|
|
1999-06-05 21:36:00 +00:00
|
|
|
return p;
|
|
|
|
}
|
1999-05-12 09:49:12 +00:00
|
|
|
|
2004-09-05 01:46:52 +00:00
|
|
|
unsigned
|
1999-06-05 21:36:00 +00:00
|
|
|
physical_MaxDeviceSize()
|
|
|
|
{
|
2004-09-05 01:46:52 +00:00
|
|
|
unsigned biggest, sz, n;
|
1999-06-05 21:36:00 +00:00
|
|
|
|
|
|
|
biggest = sizeof(struct device);
|
2004-09-05 01:46:52 +00:00
|
|
|
for (n = 0; n < NDEVICES; n++)
|
1999-06-05 21:36:00 +00:00
|
|
|
if (devices[n].DeviceSize) {
|
|
|
|
sz = (*devices[n].DeviceSize)();
|
|
|
|
if (biggest < sz)
|
|
|
|
biggest = sz;
|
|
|
|
}
|
1999-05-08 11:07:56 +00:00
|
|
|
|
1999-06-05 21:36:00 +00:00
|
|
|
return biggest;
|
1999-05-08 11:07:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
physical2iov(struct physical *p, struct iovec *iov, int *niov, int maxiov,
|
Rewrite the link descriptor transfer code in MP mode.
Previously, ppp attempted to bind() to a local domain tcp socket
based on the peer authname & enddisc. If it succeeded, it listen()ed
and became MP server. If it failed, it connect()ed and became MP
client. The server then select()ed on the descriptor, accept()ed
it and wrote its pid to it then read the link data & link file descriptor,
and finally sent an ack (``!''). The client would read() the server
pid, transfer the link lock to that pid, send the link data & descriptor
and read the ack. It would then close the descriptor and clean up.
There was a race between the bind() and listen() where someone could
attempt to connect() and fail.
This change removes the race. Now ppp makes the RCVBUF big enough on a
socket descriptor and attempts to bind() to a local domain *udp* socket
(same name as before). If it succeeds, it becomes MP server. If it
fails, it sets the SNDBUF and connect()s, becoming MP client. The server
select()s on the descriptor and recvmsg()s the message, insisting on at
least two descriptors (plus the link data). It uses the second descriptor
to write() its pid then read()s an ack (``!''). The client creates a
socketpair() and sendmsg()s the link data, link descriptor and one of
the socketpair descriptors. It then read()s the server pid from the
other socketpair descriptor, transfers any locks and write()s an ack.
Now, there can be no race, and a connect() failure indicates a stale
socket file.
This also fixes MP ppp over ethernet, where the struct msghdr was being
misconstructed when transferring the control socket descriptor.
Also, if we fail to send the link, don't hang around in a ``session
owner'' state, just do the setsid() and fork() if it's required to
disown a tty.
UDP idea suggested by: Chris Bennet from Mindspring at FreeBSDCon
1999-11-25 02:47:04 +00:00
|
|
|
int *auxfd, int *nauxfd)
|
1999-05-08 11:07:56 +00:00
|
|
|
{
|
1999-06-05 21:36:00 +00:00
|
|
|
struct device *h;
|
|
|
|
int sz;
|
|
|
|
|
|
|
|
h = NULL;
|
1999-05-08 11:07:56 +00:00
|
|
|
if (p) {
|
|
|
|
hdlc_StopTimer(&p->hdlc);
|
|
|
|
lqr_StopTimer(p);
|
|
|
|
timer_Stop(&p->link.lcp.fsm.FsmTimer);
|
|
|
|
timer_Stop(&p->link.ccp.fsm.FsmTimer);
|
|
|
|
timer_Stop(&p->link.lcp.fsm.OpenTimer);
|
|
|
|
timer_Stop(&p->link.ccp.fsm.OpenTimer);
|
|
|
|
timer_Stop(&p->link.lcp.fsm.StoppedTimer);
|
|
|
|
timer_Stop(&p->link.ccp.fsm.StoppedTimer);
|
1999-05-12 09:49:12 +00:00
|
|
|
if (p->handler) {
|
Rewrite the link descriptor transfer code in MP mode.
Previously, ppp attempted to bind() to a local domain tcp socket
based on the peer authname & enddisc. If it succeeded, it listen()ed
and became MP server. If it failed, it connect()ed and became MP
client. The server then select()ed on the descriptor, accept()ed
it and wrote its pid to it then read the link data & link file descriptor,
and finally sent an ack (``!''). The client would read() the server
pid, transfer the link lock to that pid, send the link data & descriptor
and read the ack. It would then close the descriptor and clean up.
There was a race between the bind() and listen() where someone could
attempt to connect() and fail.
This change removes the race. Now ppp makes the RCVBUF big enough on a
socket descriptor and attempts to bind() to a local domain *udp* socket
(same name as before). If it succeeds, it becomes MP server. If it
fails, it sets the SNDBUF and connect()s, becoming MP client. The server
select()s on the descriptor and recvmsg()s the message, insisting on at
least two descriptors (plus the link data). It uses the second descriptor
to write() its pid then read()s an ack (``!''). The client creates a
socketpair() and sendmsg()s the link data, link descriptor and one of
the socketpair descriptors. It then read()s the server pid from the
other socketpair descriptor, transfers any locks and write()s an ack.
Now, there can be no race, and a connect() failure indicates a stale
socket file.
This also fixes MP ppp over ethernet, where the struct msghdr was being
misconstructed when transferring the control socket descriptor.
Also, if we fail to send the link, don't hang around in a ``session
owner'' state, just do the setsid() and fork() if it's required to
disown a tty.
UDP idea suggested by: Chris Bennet from Mindspring at FreeBSDCon
1999-11-25 02:47:04 +00:00
|
|
|
h = p->handler;
|
1999-05-12 09:49:12 +00:00
|
|
|
p->handler = (struct device *)(long)p->handler->type;
|
1999-05-08 11:07:56 +00:00
|
|
|
}
|
1999-05-12 09:49:12 +00:00
|
|
|
|
1999-06-02 00:46:55 +00:00
|
|
|
if (Enabled(p->dl->bundle, OPT_KEEPSESSION) ||
|
|
|
|
tcgetpgrp(p->fd) == getpgrp())
|
1999-05-08 11:07:56 +00:00
|
|
|
p->session_owner = getpid(); /* So I'll eventually get HUP'd */
|
1999-06-02 00:46:55 +00:00
|
|
|
else
|
|
|
|
p->session_owner = (pid_t)-1;
|
2000-08-15 00:59:21 +00:00
|
|
|
timer_Stop(&p->link.stats.total.Timer);
|
1999-05-08 11:07:56 +00:00
|
|
|
}
|
|
|
|
|
1999-08-05 10:32:16 +00:00
|
|
|
if (*niov + 2 >= maxiov) {
|
|
|
|
log_Printf(LogERROR, "physical2iov: No room for physical + throughput"
|
|
|
|
" + device !\n");
|
1999-05-08 11:07:56 +00:00
|
|
|
if (p)
|
|
|
|
free(p);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
Rewrite the link descriptor transfer code in MP mode.
Previously, ppp attempted to bind() to a local domain tcp socket
based on the peer authname & enddisc. If it succeeded, it listen()ed
and became MP server. If it failed, it connect()ed and became MP
client. The server then select()ed on the descriptor, accept()ed
it and wrote its pid to it then read the link data & link file descriptor,
and finally sent an ack (``!''). The client would read() the server
pid, transfer the link lock to that pid, send the link data & descriptor
and read the ack. It would then close the descriptor and clean up.
There was a race between the bind() and listen() where someone could
attempt to connect() and fail.
This change removes the race. Now ppp makes the RCVBUF big enough on a
socket descriptor and attempts to bind() to a local domain *udp* socket
(same name as before). If it succeeds, it becomes MP server. If it
fails, it sets the SNDBUF and connect()s, becoming MP client. The server
select()s on the descriptor and recvmsg()s the message, insisting on at
least two descriptors (plus the link data). It uses the second descriptor
to write() its pid then read()s an ack (``!''). The client creates a
socketpair() and sendmsg()s the link data, link descriptor and one of
the socketpair descriptors. It then read()s the server pid from the
other socketpair descriptor, transfers any locks and write()s an ack.
Now, there can be no race, and a connect() failure indicates a stale
socket file.
This also fixes MP ppp over ethernet, where the struct msghdr was being
misconstructed when transferring the control socket descriptor.
Also, if we fail to send the link, don't hang around in a ``session
owner'' state, just do the setsid() and fork() if it's required to
disown a tty.
UDP idea suggested by: Chris Bennet from Mindspring at FreeBSDCon
1999-11-25 02:47:04 +00:00
|
|
|
iov[*niov].iov_base = (void *)p;
|
1999-05-08 11:07:56 +00:00
|
|
|
iov[*niov].iov_len = sizeof *p;
|
|
|
|
(*niov)++;
|
|
|
|
|
2000-08-15 10:25:42 +00:00
|
|
|
iov[*niov].iov_base = p ? (void *)p->link.stats.total.in.SampleOctets : NULL;
|
|
|
|
iov[*niov].iov_len = SAMPLE_PERIOD * sizeof(long long);
|
|
|
|
(*niov)++;
|
|
|
|
iov[*niov].iov_base = p ? (void *)p->link.stats.total.out.SampleOctets : NULL;
|
1999-08-05 10:32:16 +00:00
|
|
|
iov[*niov].iov_len = SAMPLE_PERIOD * sizeof(long long);
|
|
|
|
(*niov)++;
|
|
|
|
|
1999-06-05 21:36:00 +00:00
|
|
|
sz = physical_MaxDeviceSize();
|
|
|
|
if (p) {
|
Rewrite the link descriptor transfer code in MP mode.
Previously, ppp attempted to bind() to a local domain tcp socket
based on the peer authname & enddisc. If it succeeded, it listen()ed
and became MP server. If it failed, it connect()ed and became MP
client. The server then select()ed on the descriptor, accept()ed
it and wrote its pid to it then read the link data & link file descriptor,
and finally sent an ack (``!''). The client would read() the server
pid, transfer the link lock to that pid, send the link data & descriptor
and read the ack. It would then close the descriptor and clean up.
There was a race between the bind() and listen() where someone could
attempt to connect() and fail.
This change removes the race. Now ppp makes the RCVBUF big enough on a
socket descriptor and attempts to bind() to a local domain *udp* socket
(same name as before). If it succeeds, it becomes MP server. If it
fails, it sets the SNDBUF and connect()s, becoming MP client. The server
select()s on the descriptor and recvmsg()s the message, insisting on at
least two descriptors (plus the link data). It uses the second descriptor
to write() its pid then read()s an ack (``!''). The client creates a
socketpair() and sendmsg()s the link data, link descriptor and one of
the socketpair descriptors. It then read()s the server pid from the
other socketpair descriptor, transfers any locks and write()s an ack.
Now, there can be no race, and a connect() failure indicates a stale
socket file.
This also fixes MP ppp over ethernet, where the struct msghdr was being
misconstructed when transferring the control socket descriptor.
Also, if we fail to send the link, don't hang around in a ``session
owner'' state, just do the setsid() and fork() if it's required to
disown a tty.
UDP idea suggested by: Chris Bennet from Mindspring at FreeBSDCon
1999-11-25 02:47:04 +00:00
|
|
|
if (h && h->device2iov)
|
|
|
|
(*h->device2iov)(h, iov, niov, maxiov, auxfd, nauxfd);
|
1999-06-05 21:36:00 +00:00
|
|
|
else {
|
2004-10-11 09:45:58 +00:00
|
|
|
if ((iov[*niov].iov_base = malloc(sz)) == NULL) {
|
|
|
|
log_Printf(LogALERT, "physical2iov: Out of memory (%d bytes)\n", sz);
|
|
|
|
AbortProgram(EX_OSERR);
|
|
|
|
}
|
Rewrite the link descriptor transfer code in MP mode.
Previously, ppp attempted to bind() to a local domain tcp socket
based on the peer authname & enddisc. If it succeeded, it listen()ed
and became MP server. If it failed, it connect()ed and became MP
client. The server then select()ed on the descriptor, accept()ed
it and wrote its pid to it then read the link data & link file descriptor,
and finally sent an ack (``!''). The client would read() the server
pid, transfer the link lock to that pid, send the link data & descriptor
and read the ack. It would then close the descriptor and clean up.
There was a race between the bind() and listen() where someone could
attempt to connect() and fail.
This change removes the race. Now ppp makes the RCVBUF big enough on a
socket descriptor and attempts to bind() to a local domain *udp* socket
(same name as before). If it succeeds, it becomes MP server. If it
fails, it sets the SNDBUF and connect()s, becoming MP client. The server
select()s on the descriptor and recvmsg()s the message, insisting on at
least two descriptors (plus the link data). It uses the second descriptor
to write() its pid then read()s an ack (``!''). The client creates a
socketpair() and sendmsg()s the link data, link descriptor and one of
the socketpair descriptors. It then read()s the server pid from the
other socketpair descriptor, transfers any locks and write()s an ack.
Now, there can be no race, and a connect() failure indicates a stale
socket file.
This also fixes MP ppp over ethernet, where the struct msghdr was being
misconstructed when transferring the control socket descriptor.
Also, if we fail to send the link, don't hang around in a ``session
owner'' state, just do the setsid() and fork() if it's required to
disown a tty.
UDP idea suggested by: Chris Bennet from Mindspring at FreeBSDCon
1999-11-25 02:47:04 +00:00
|
|
|
if (h)
|
|
|
|
memcpy(iov[*niov].iov_base, h, sizeof *h);
|
1999-06-05 21:36:00 +00:00
|
|
|
iov[*niov].iov_len = sz;
|
|
|
|
(*niov)++;
|
|
|
|
}
|
|
|
|
} else {
|
Rewrite the link descriptor transfer code in MP mode.
Previously, ppp attempted to bind() to a local domain tcp socket
based on the peer authname & enddisc. If it succeeded, it listen()ed
and became MP server. If it failed, it connect()ed and became MP
client. The server then select()ed on the descriptor, accept()ed
it and wrote its pid to it then read the link data & link file descriptor,
and finally sent an ack (``!''). The client would read() the server
pid, transfer the link lock to that pid, send the link data & descriptor
and read the ack. It would then close the descriptor and clean up.
There was a race between the bind() and listen() where someone could
attempt to connect() and fail.
This change removes the race. Now ppp makes the RCVBUF big enough on a
socket descriptor and attempts to bind() to a local domain *udp* socket
(same name as before). If it succeeds, it becomes MP server. If it
fails, it sets the SNDBUF and connect()s, becoming MP client. The server
select()s on the descriptor and recvmsg()s the message, insisting on at
least two descriptors (plus the link data). It uses the second descriptor
to write() its pid then read()s an ack (``!''). The client creates a
socketpair() and sendmsg()s the link data, link descriptor and one of
the socketpair descriptors. It then read()s the server pid from the
other socketpair descriptor, transfers any locks and write()s an ack.
Now, there can be no race, and a connect() failure indicates a stale
socket file.
This also fixes MP ppp over ethernet, where the struct msghdr was being
misconstructed when transferring the control socket descriptor.
Also, if we fail to send the link, don't hang around in a ``session
owner'' state, just do the setsid() and fork() if it's required to
disown a tty.
UDP idea suggested by: Chris Bennet from Mindspring at FreeBSDCon
1999-11-25 02:47:04 +00:00
|
|
|
iov[*niov].iov_base = NULL;
|
1999-06-05 21:36:00 +00:00
|
|
|
iov[*niov].iov_len = sz;
|
|
|
|
(*niov)++;
|
|
|
|
}
|
|
|
|
|
1999-05-08 11:07:56 +00:00
|
|
|
return p ? p->fd : 0;
|
|
|
|
}
|
|
|
|
|
Rewrite the link descriptor transfer code in MP mode.
Previously, ppp attempted to bind() to a local domain tcp socket
based on the peer authname & enddisc. If it succeeded, it listen()ed
and became MP server. If it failed, it connect()ed and became MP
client. The server then select()ed on the descriptor, accept()ed
it and wrote its pid to it then read the link data & link file descriptor,
and finally sent an ack (``!''). The client would read() the server
pid, transfer the link lock to that pid, send the link data & descriptor
and read the ack. It would then close the descriptor and clean up.
There was a race between the bind() and listen() where someone could
attempt to connect() and fail.
This change removes the race. Now ppp makes the RCVBUF big enough on a
socket descriptor and attempts to bind() to a local domain *udp* socket
(same name as before). If it succeeds, it becomes MP server. If it
fails, it sets the SNDBUF and connect()s, becoming MP client. The server
select()s on the descriptor and recvmsg()s the message, insisting on at
least two descriptors (plus the link data). It uses the second descriptor
to write() its pid then read()s an ack (``!''). The client creates a
socketpair() and sendmsg()s the link data, link descriptor and one of
the socketpair descriptors. It then read()s the server pid from the
other socketpair descriptor, transfers any locks and write()s an ack.
Now, there can be no race, and a connect() failure indicates a stale
socket file.
This also fixes MP ppp over ethernet, where the struct msghdr was being
misconstructed when transferring the control socket descriptor.
Also, if we fail to send the link, don't hang around in a ``session
owner'' state, just do the setsid() and fork() if it's required to
disown a tty.
UDP idea suggested by: Chris Bennet from Mindspring at FreeBSDCon
1999-11-25 02:47:04 +00:00
|
|
|
const char *
|
|
|
|
physical_LockedDevice(struct physical *p)
|
|
|
|
{
|
|
|
|
if (p->fd >= 0 && *p->name.full == '/' && p->type != PHYS_DIRECT)
|
|
|
|
return p->name.base;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
1999-05-08 11:07:56 +00:00
|
|
|
void
|
|
|
|
physical_ChangedPid(struct physical *p, pid_t newpid)
|
|
|
|
{
|
Rewrite the link descriptor transfer code in MP mode.
Previously, ppp attempted to bind() to a local domain tcp socket
based on the peer authname & enddisc. If it succeeded, it listen()ed
and became MP server. If it failed, it connect()ed and became MP
client. The server then select()ed on the descriptor, accept()ed
it and wrote its pid to it then read the link data & link file descriptor,
and finally sent an ack (``!''). The client would read() the server
pid, transfer the link lock to that pid, send the link data & descriptor
and read the ack. It would then close the descriptor and clean up.
There was a race between the bind() and listen() where someone could
attempt to connect() and fail.
This change removes the race. Now ppp makes the RCVBUF big enough on a
socket descriptor and attempts to bind() to a local domain *udp* socket
(same name as before). If it succeeds, it becomes MP server. If it
fails, it sets the SNDBUF and connect()s, becoming MP client. The server
select()s on the descriptor and recvmsg()s the message, insisting on at
least two descriptors (plus the link data). It uses the second descriptor
to write() its pid then read()s an ack (``!''). The client creates a
socketpair() and sendmsg()s the link data, link descriptor and one of
the socketpair descriptors. It then read()s the server pid from the
other socketpair descriptor, transfers any locks and write()s an ack.
Now, there can be no race, and a connect() failure indicates a stale
socket file.
This also fixes MP ppp over ethernet, where the struct msghdr was being
misconstructed when transferring the control socket descriptor.
Also, if we fail to send the link, don't hang around in a ``session
owner'' state, just do the setsid() and fork() if it's required to
disown a tty.
UDP idea suggested by: Chris Bennet from Mindspring at FreeBSDCon
1999-11-25 02:47:04 +00:00
|
|
|
if (physical_LockedDevice(p)) {
|
1999-05-08 11:07:56 +00:00
|
|
|
int res;
|
|
|
|
|
|
|
|
if ((res = ID0uu_lock_txfr(p->name.base, newpid)) != UU_LOCK_OK)
|
|
|
|
log_Printf(LogPHASE, "uu_lock_txfr: %s\n", uu_lockerr(res));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
physical_IsSync(struct physical *p)
|
|
|
|
{
|
|
|
|
return p->cfg.speed == 0;
|
|
|
|
}
|
|
|
|
|
2001-06-18 14:59:36 +00:00
|
|
|
u_short
|
|
|
|
physical_DeviceMTU(struct physical *p)
|
|
|
|
{
|
|
|
|
return p->handler ? p->handler->mtu : 0;
|
|
|
|
}
|
|
|
|
|
1999-05-08 11:07:56 +00:00
|
|
|
const char *physical_GetDevice(struct physical *p)
|
|
|
|
{
|
|
|
|
return p->name.full;
|
1998-01-29 00:49:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1998-05-01 19:26:12 +00:00
|
|
|
physical_SetDeviceList(struct physical *p, int argc, const char *const *argv)
|
1998-04-10 23:51:33 +00:00
|
|
|
{
|
2004-09-05 01:46:52 +00:00
|
|
|
unsigned pos;
|
|
|
|
int f;
|
1998-04-10 23:51:33 +00:00
|
|
|
|
|
|
|
p->cfg.devlist[sizeof p->cfg.devlist - 1] = '\0';
|
|
|
|
for (f = 0, pos = 0; f < argc && pos < sizeof p->cfg.devlist - 1; f++) {
|
|
|
|
if (pos)
|
1999-04-27 00:23:57 +00:00
|
|
|
p->cfg.devlist[pos++] = '\0';
|
1998-04-10 23:51:33 +00:00
|
|
|
strncpy(p->cfg.devlist + pos, argv[f], sizeof p->cfg.devlist - pos - 1);
|
|
|
|
pos += strlen(p->cfg.devlist + pos);
|
|
|
|
}
|
1999-04-27 00:23:57 +00:00
|
|
|
p->cfg.ndev = f;
|
1998-01-29 00:49:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-05-08 11:07:56 +00:00
|
|
|
physical_SetSync(struct physical *p)
|
|
|
|
{
|
|
|
|
p->cfg.speed = 0;
|
1998-01-29 00:49:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
1999-05-08 11:07:56 +00:00
|
|
|
physical_SetRtsCts(struct physical *p, int enable)
|
|
|
|
{
|
|
|
|
p->cfg.rts_cts = enable ? 1 : 0;
|
1998-01-29 00:49:32 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t
|
1999-05-08 11:07:56 +00:00
|
|
|
physical_Read(struct physical *p, void *buf, size_t nbytes)
|
|
|
|
{
|
1999-05-12 09:49:12 +00:00
|
|
|
ssize_t ret;
|
|
|
|
|
|
|
|
if (p->handler && p->handler->read)
|
|
|
|
ret = (*p->handler->read)(p, buf, nbytes);
|
|
|
|
else
|
|
|
|
ret = read(p->fd, buf, nbytes);
|
|
|
|
|
|
|
|
log_DumpBuff(LogPHYSICAL, "read", buf, ret);
|
|
|
|
|
|
|
|
return ret;
|
1998-01-29 00:49:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t
|
1999-05-08 11:07:56 +00:00
|
|
|
physical_Write(struct physical *p, const void *buf, size_t nbytes)
|
|
|
|
{
|
1999-05-12 09:49:12 +00:00
|
|
|
log_DumpBuff(LogPHYSICAL, "write", buf, nbytes);
|
|
|
|
|
|
|
|
if (p->handler && p->handler->write)
|
|
|
|
return (*p->handler->write)(p, buf, nbytes);
|
|
|
|
|
|
|
|
return write(p->fd, buf, nbytes);
|
1998-01-29 00:49:32 +00:00
|
|
|
}
|
1998-02-06 02:22:28 +00:00
|
|
|
|
1998-02-09 19:21:11 +00:00
|
|
|
int
|
2000-03-14 01:46:09 +00:00
|
|
|
physical_doUpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e,
|
1999-05-08 11:07:56 +00:00
|
|
|
int *n, int force)
|
1998-02-09 19:21:11 +00:00
|
|
|
{
|
|
|
|
struct physical *p = descriptor2physical(d);
|
|
|
|
int sets;
|
|
|
|
|
1998-02-13 05:10:26 +00:00
|
|
|
sets = 0;
|
1998-02-09 19:21:11 +00:00
|
|
|
if (p->fd >= 0) {
|
1998-02-13 05:10:26 +00:00
|
|
|
if (r) {
|
|
|
|
FD_SET(p->fd, r);
|
1998-05-10 22:20:20 +00:00
|
|
|
log_Printf(LogTIMER, "%s: fdset(r) %d\n", p->link.name, p->fd);
|
1998-02-13 05:10:26 +00:00
|
|
|
sets++;
|
|
|
|
}
|
|
|
|
if (e) {
|
|
|
|
FD_SET(p->fd, e);
|
1998-05-10 22:20:20 +00:00
|
|
|
log_Printf(LogTIMER, "%s: fdset(e) %d\n", p->link.name, p->fd);
|
1998-02-13 05:10:26 +00:00
|
|
|
sets++;
|
|
|
|
}
|
1998-05-23 22:24:50 +00:00
|
|
|
if (w && (force || link_QueueLen(&p->link) || p->out)) {
|
1998-02-09 19:21:11 +00:00
|
|
|
FD_SET(p->fd, w);
|
1998-05-10 22:20:20 +00:00
|
|
|
log_Printf(LogTIMER, "%s: fdset(w) %d\n", p->link.name, p->fd);
|
1998-02-13 05:10:26 +00:00
|
|
|
sets++;
|
|
|
|
}
|
|
|
|
if (sets && *n < p->fd + 1)
|
|
|
|
*n = p->fd + 1;
|
|
|
|
}
|
1998-02-09 19:21:11 +00:00
|
|
|
|
|
|
|
return sets;
|
|
|
|
}
|
|
|
|
|
1998-05-15 18:21:45 +00:00
|
|
|
int
|
|
|
|
physical_RemoveFromSet(struct physical *p, fd_set *r, fd_set *w, fd_set *e)
|
|
|
|
{
|
1999-11-06 22:50:59 +00:00
|
|
|
if (p->handler && p->handler->removefromset)
|
|
|
|
return (*p->handler->removefromset)(p, r, w, e);
|
|
|
|
else {
|
|
|
|
int sets;
|
1998-05-15 18:21:45 +00:00
|
|
|
|
1999-11-06 22:50:59 +00:00
|
|
|
sets = 0;
|
|
|
|
if (p->fd >= 0) {
|
|
|
|
if (r && FD_ISSET(p->fd, r)) {
|
|
|
|
FD_CLR(p->fd, r);
|
|
|
|
log_Printf(LogTIMER, "%s: fdunset(r) %d\n", p->link.name, p->fd);
|
|
|
|
sets++;
|
|
|
|
}
|
|
|
|
if (e && FD_ISSET(p->fd, e)) {
|
|
|
|
FD_CLR(p->fd, e);
|
|
|
|
log_Printf(LogTIMER, "%s: fdunset(e) %d\n", p->link.name, p->fd);
|
|
|
|
sets++;
|
|
|
|
}
|
|
|
|
if (w && FD_ISSET(p->fd, w)) {
|
|
|
|
FD_CLR(p->fd, w);
|
|
|
|
log_Printf(LogTIMER, "%s: fdunset(w) %d\n", p->link.name, p->fd);
|
|
|
|
sets++;
|
|
|
|
}
|
1998-05-15 18:21:45 +00:00
|
|
|
}
|
1999-11-06 22:50:59 +00:00
|
|
|
|
|
|
|
return sets;
|
1998-05-15 18:21:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-02-09 19:21:11 +00:00
|
|
|
int
|
2000-03-14 01:46:09 +00:00
|
|
|
physical_IsSet(struct fdescriptor *d, const fd_set *fdset)
|
1998-02-09 19:21:11 +00:00
|
|
|
{
|
|
|
|
struct physical *p = descriptor2physical(d);
|
|
|
|
return p->fd >= 0 && FD_ISSET(p->fd, fdset);
|
|
|
|
}
|
|
|
|
|
1998-03-10 03:06:07 +00:00
|
|
|
void
|
1999-05-08 11:07:56 +00:00
|
|
|
physical_Login(struct physical *p, const char *name)
|
1998-03-10 03:06:07 +00:00
|
|
|
{
|
1999-05-09 20:13:52 +00:00
|
|
|
if (p->type == PHYS_DIRECT && *p->name.base && !p->Utmp) {
|
2010-01-13 17:54:32 +00:00
|
|
|
struct utmpx ut;
|
1999-05-08 11:07:56 +00:00
|
|
|
const char *connstr;
|
1999-10-21 01:19:23 +00:00
|
|
|
char *colon;
|
1999-05-08 11:07:56 +00:00
|
|
|
|
|
|
|
memset(&ut, 0, sizeof ut);
|
2010-01-13 17:54:32 +00:00
|
|
|
ut.ut_type = USER_PROCESS;
|
|
|
|
gettimeofday(&ut.ut_tv, NULL);
|
|
|
|
snprintf(ut.ut_id, sizeof ut.ut_id, "%xppp", (int)getpid());
|
|
|
|
strncpy(ut.ut_user, name, sizeof ut.ut_user);
|
1999-10-21 01:19:23 +00:00
|
|
|
if (p->handler && (p->handler->type == TCP_DEVICE ||
|
|
|
|
p->handler->type == UDP_DEVICE)) {
|
|
|
|
strncpy(ut.ut_host, p->name.base, sizeof ut.ut_host);
|
|
|
|
colon = memchr(ut.ut_host, ':', sizeof ut.ut_host);
|
|
|
|
if (colon)
|
|
|
|
*colon = '\0';
|
|
|
|
} else
|
|
|
|
strncpy(ut.ut_line, p->name.base, sizeof ut.ut_line);
|
1999-05-08 11:07:56 +00:00
|
|
|
if ((connstr = getenv("CONNECT")))
|
|
|
|
/* mgetty sets this to the connection speed */
|
|
|
|
strncpy(ut.ut_host, connstr, sizeof ut.ut_host);
|
|
|
|
ID0login(&ut);
|
2010-01-13 17:54:32 +00:00
|
|
|
p->Utmp = 1;
|
1998-03-10 03:06:07 +00:00
|
|
|
}
|
|
|
|
}
|
1998-05-15 23:58:30 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
physical_SetMode(struct physical *p, int mode)
|
|
|
|
{
|
1998-08-07 18:42:51 +00:00
|
|
|
if ((p->type & (PHYS_DIRECT|PHYS_DEDICATED) ||
|
|
|
|
mode & (PHYS_DIRECT|PHYS_DEDICATED)) &&
|
|
|
|
(!(p->type & PHYS_DIRECT) || !(mode & PHYS_BACKGROUND))) {
|
1999-11-28 15:50:08 +00:00
|
|
|
/* Note: The -direct -> -background is for callback ! */
|
1998-05-15 23:58:30 +00:00
|
|
|
log_Printf(LogWARN, "%s: Cannot change mode %s to %s\n", p->link.name,
|
|
|
|
mode2Nam(p->type), mode2Nam(mode));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
p->type = mode;
|
|
|
|
return 1;
|
|
|
|
}
|
1998-08-25 17:48:43 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
physical_DeleteQueue(struct physical *p)
|
|
|
|
{
|
|
|
|
if (p->out) {
|
1999-12-20 20:29:47 +00:00
|
|
|
m_freem(p->out);
|
1998-08-25 17:48:43 +00:00
|
|
|
p->out = NULL;
|
|
|
|
}
|
|
|
|
link_DeleteQueue(&p->link);
|
|
|
|
}
|
1999-05-08 11:07:56 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
physical_SetDevice(struct physical *p, const char *name)
|
|
|
|
{
|
|
|
|
int len = strlen(_PATH_DEV);
|
|
|
|
|
1999-06-01 19:08:59 +00:00
|
|
|
if (name != p->name.full) {
|
|
|
|
strncpy(p->name.full, name, sizeof p->name.full - 1);
|
|
|
|
p->name.full[sizeof p->name.full - 1] = '\0';
|
|
|
|
}
|
1999-05-08 11:07:56 +00:00
|
|
|
p->name.base = *p->name.full == '!' ? p->name.full + 1 :
|
|
|
|
strncmp(p->name.full, _PATH_DEV, len) ?
|
|
|
|
p->name.full : p->name.full + len;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
physical_Found(struct physical *p)
|
|
|
|
{
|
1999-05-18 01:37:46 +00:00
|
|
|
FILE *lockfile;
|
2001-03-08 23:51:50 +00:00
|
|
|
char fn[PATH_MAX];
|
1999-05-18 01:37:46 +00:00
|
|
|
|
|
|
|
if (*p->name.full == '/') {
|
|
|
|
snprintf(fn, sizeof fn, "%s%s.if", _PATH_VARRUN, p->name.base);
|
|
|
|
lockfile = ID0fopen(fn, "w");
|
|
|
|
if (lockfile != NULL) {
|
|
|
|
fprintf(lockfile, "%s%d\n", TUN_NAME, p->dl->bundle->unit);
|
|
|
|
fclose(lockfile);
|
2019-07-12 06:19:25 +00:00
|
|
|
} else
|
1999-05-18 01:37:46 +00:00
|
|
|
log_Printf(LogALERT, "%s: Can't create %s: %s\n",
|
|
|
|
p->link.name, fn, strerror(errno));
|
|
|
|
}
|
|
|
|
|
2000-08-15 00:59:21 +00:00
|
|
|
throughput_start(&p->link.stats.total, "physical throughput",
|
1999-05-08 11:07:56 +00:00
|
|
|
Enabled(p->dl->bundle, OPT_THROUGHPUT));
|
|
|
|
p->connect_count++;
|
|
|
|
p->input.sz = 0;
|
|
|
|
|
|
|
|
log_Printf(LogPHASE, "%s: Connected!\n", p->link.name);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2004-09-05 01:46:52 +00:00
|
|
|
physical_Open(struct physical *p)
|
1999-05-08 11:07:56 +00:00
|
|
|
{
|
|
|
|
char *dev;
|
2004-09-05 01:46:52 +00:00
|
|
|
int devno, wasfd, err;
|
|
|
|
unsigned h;
|
1999-05-08 11:07:56 +00:00
|
|
|
|
|
|
|
if (p->fd >= 0)
|
|
|
|
log_Printf(LogDEBUG, "%s: Open: Modem is already open!\n", p->link.name);
|
|
|
|
/* We're going back into "term" mode */
|
|
|
|
else if (p->type == PHYS_DIRECT) {
|
1999-05-12 09:49:12 +00:00
|
|
|
physical_SetDevice(p, "");
|
|
|
|
p->fd = STDIN_FILENO;
|
|
|
|
for (h = 0; h < NDEVICES && p->handler == NULL && p->fd >= 0; h++)
|
1999-11-06 22:50:59 +00:00
|
|
|
p->handler = (*devices[h].create)(p);
|
2009-08-24 17:19:45 +00:00
|
|
|
close(STDOUT_FILENO);
|
1999-05-12 09:49:12 +00:00
|
|
|
if (p->fd >= 0) {
|
1999-05-13 19:29:40 +00:00
|
|
|
if (p->handler == NULL) {
|
1999-05-24 16:39:17 +00:00
|
|
|
physical_SetupStack(p, "unknown", PHYSICAL_NOFORCE);
|
1999-05-13 19:29:40 +00:00
|
|
|
log_Printf(LogDEBUG, "%s: stdin is unidentified\n", p->link.name);
|
|
|
|
}
|
1999-05-08 11:07:56 +00:00
|
|
|
physical_Found(p);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
dev = p->cfg.devlist;
|
|
|
|
devno = 0;
|
|
|
|
while (devno < p->cfg.ndev && p->fd < 0) {
|
|
|
|
physical_SetDevice(p, dev);
|
1999-05-18 01:37:46 +00:00
|
|
|
if (physical_Lock(p)) {
|
1999-06-11 13:28:29 +00:00
|
|
|
err = 0;
|
|
|
|
|
|
|
|
if (*p->name.full == '/') {
|
1999-05-18 01:37:46 +00:00
|
|
|
p->fd = ID0open(p->name.full, O_RDWR | O_NONBLOCK);
|
1999-06-11 13:28:29 +00:00
|
|
|
if (p->fd < 0)
|
|
|
|
err = errno;
|
|
|
|
}
|
1999-05-18 01:37:46 +00:00
|
|
|
|
1999-11-06 22:50:59 +00:00
|
|
|
wasfd = p->fd;
|
1999-05-18 01:37:46 +00:00
|
|
|
for (h = 0; h < NDEVICES && p->handler == NULL; h++)
|
1999-11-06 22:50:59 +00:00
|
|
|
if ((p->handler = (*devices[h].create)(p)) == NULL && wasfd != p->fd)
|
1999-05-18 01:37:46 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
if (p->fd < 0) {
|
1999-06-11 13:28:29 +00:00
|
|
|
if (h == NDEVICES) {
|
|
|
|
if (err)
|
|
|
|
log_Printf(LogWARN, "%s: %s: %s\n", p->link.name, p->name.full,
|
|
|
|
strerror(errno));
|
|
|
|
else
|
|
|
|
log_Printf(LogWARN, "%s: Device (%s) must begin with a '/',"
|
1999-11-06 22:50:59 +00:00
|
|
|
" a '!' or contain at least one ':'\n", p->link.name,
|
1999-06-11 13:28:29 +00:00
|
|
|
p->name.full);
|
|
|
|
}
|
1999-05-18 01:37:46 +00:00
|
|
|
physical_Unlock(p);
|
|
|
|
} else
|
|
|
|
physical_Found(p);
|
|
|
|
}
|
1999-05-08 11:07:56 +00:00
|
|
|
dev += strlen(dev) + 1;
|
|
|
|
devno++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return p->fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-05-24 16:39:17 +00:00
|
|
|
physical_SetupStack(struct physical *p, const char *who, int how)
|
1999-05-08 11:07:56 +00:00
|
|
|
{
|
|
|
|
link_EmptyStack(&p->link);
|
1999-11-06 22:50:59 +00:00
|
|
|
if (how == PHYSICAL_FORCE_SYNC || how == PHYSICAL_FORCE_SYNCNOACF ||
|
1999-05-12 09:49:12 +00:00
|
|
|
(how == PHYSICAL_NOFORCE && physical_IsSync(p)))
|
1999-05-08 11:07:56 +00:00
|
|
|
link_Stack(&p->link, &synclayer);
|
|
|
|
else {
|
|
|
|
link_Stack(&p->link, &asynclayer);
|
|
|
|
link_Stack(&p->link, &hdlclayer);
|
|
|
|
}
|
1999-11-06 22:50:59 +00:00
|
|
|
if (how != PHYSICAL_FORCE_SYNCNOACF)
|
|
|
|
link_Stack(&p->link, &acflayer);
|
1999-05-08 11:07:56 +00:00
|
|
|
link_Stack(&p->link, &protolayer);
|
|
|
|
link_Stack(&p->link, &lqrlayer);
|
|
|
|
link_Stack(&p->link, &ccplayer);
|
|
|
|
link_Stack(&p->link, &vjlayer);
|
2000-11-28 13:18:35 +00:00
|
|
|
link_Stack(&p->link, &tcpmsslayer);
|
1999-08-19 18:15:52 +00:00
|
|
|
#ifndef NONAT
|
|
|
|
link_Stack(&p->link, &natlayer);
|
1999-05-08 11:07:56 +00:00
|
|
|
#endif
|
1999-05-12 09:49:12 +00:00
|
|
|
if (how == PHYSICAL_FORCE_ASYNC && physical_IsSync(p)) {
|
1999-05-24 16:39:17 +00:00
|
|
|
log_Printf(LogWARN, "Sync device setting ignored for ``%s'' device\n", who);
|
1999-05-12 09:49:12 +00:00
|
|
|
p->cfg.speed = MODEM_SPEED;
|
|
|
|
} else if (how == PHYSICAL_FORCE_SYNC && !physical_IsSync(p)) {
|
|
|
|
log_Printf(LogWARN, "Async device setting ignored for ``%s'' device\n",
|
1999-05-24 16:39:17 +00:00
|
|
|
who);
|
1999-05-12 09:49:12 +00:00
|
|
|
physical_SetSync(p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
physical_StopDeviceTimer(struct physical *p)
|
|
|
|
{
|
|
|
|
if (p->handler && p->handler->stoptimer)
|
|
|
|
(*p->handler->stoptimer)(p);
|
1999-05-08 11:07:56 +00:00
|
|
|
}
|
1999-08-06 20:04:08 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
physical_AwaitCarrier(struct physical *p)
|
|
|
|
{
|
|
|
|
if (p->handler && p->handler->awaitcarrier)
|
|
|
|
return (*p->handler->awaitcarrier)(p);
|
|
|
|
|
|
|
|
return CARRIER_OK;
|
|
|
|
}
|
2002-03-30 12:30:09 +00:00
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
physical_SetAsyncParams(struct physical *p, u_int32_t mymap, u_int32_t hismap)
|
|
|
|
{
|
|
|
|
if (p->handler && p->handler->setasyncparams)
|
|
|
|
return (*p->handler->setasyncparams)(p, mymap, hismap);
|
|
|
|
|
|
|
|
async_SetLinkParams(&p->async, mymap, hismap);
|
|
|
|
}
|
2002-05-14 12:55:39 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
physical_Slot(struct physical *p)
|
|
|
|
{
|
|
|
|
if (p->handler && p->handler->slot)
|
|
|
|
return (*p->handler->slot)(p);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
2004-07-29 05:59:43 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
physical_SetPPPoEnonstandard(struct physical *p, int enable)
|
|
|
|
{
|
|
|
|
p->cfg.nonstandard_pppoe = enable ? 1 : 0;
|
|
|
|
p->cfg.pppoe_configured = 1;
|
|
|
|
return 1;
|
|
|
|
}
|