freebsd-dev/usr.sbin/ppp/physical.c

235 lines
5.5 KiB
C
Raw Normal View History

/*
* 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.
*
* $Id: physical.c,v 1.6 1998/08/25 17:48:43 brian Exp $
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <utmp.h>
#include <sys/tty.h>
#include "defs.h"
#include "mbuf.h"
#include "timer.h"
#include "lqr.h"
#include "hdlc.h"
#include "throughput.h"
#include "fsm.h"
#include "lcp.h"
#include "async.h"
o Move struct lcp and struct ccp into struct link. o Remove bundle2lcp(), bundle2ccp() and bundle2link(). They're too resource-hungry and we have `owner pointers' to do their job. o Make our FSM understand LCPs that are always ST_OPENED (with a minimum code that != 1). o Send FSM code rejects for invalid codes. o Make our bundle fsm_parent deal with multiple links. o Make timer diagnostics pretty and allow access via ~t in `term' mode (not just when logging debug) and `show timers'. Only show timers every second in debug mode, otherwise we get too many diagnostics to be useful (we probably still do). Also, don't restrict ~m in term mode to depend on debug logging. o Rationalise our bundles' phases. o Create struct mp (multilink protocol). This is both an NCP and a type of struct link. It feeds off other NCPs for output, passing fragmented packets into the queues of available datalinks. It also gets PROTO_MP input, reassembles the fragments into ppp frames, and passes them back to the HDLC layer that the fragments were passed from. ** It's not yet possible to enter multilink mode :-( ** o Add `set weight' (requires context) for deciding on a links weighting in multilink mode. Weighting is simplistic (and probably badly implemented) for now. o Remove the function pointers in struct link. They ended up only applying to physical links. o Configure our tun device with an MTU equal to the MRU from struct mp's LCP and a speed equal to the sum of our link speeds. o `show {lcp,ccp,proto}' and `set deflate' now have optional context and use ChooseLink() to decide on which `struct link' to use. This allows behaviour as before when in non-multilink mode, and allows access to the MP logical link in multilink mode. o Ignore reconnect and redial values when in -direct mode and when cleaning up. Always redial when in -ddial or -dedicated mode (unless cleaning up). o Tell our links to `staydown' when we close them due to a signal. o Remove remaining `#ifdef SIGALRM's (ppp doesn't function without alarms). o Don't bother strdup()ing our physical link name. o Various other cosmetic changes.
1998-04-03 19:21:56 +00:00
#include "ccp.h"
#include "link.h"
#include "descriptor.h"
#include "physical.h"
#include "log.h"
#include "id.h"
/* External calls - should possibly be moved inline */
extern int IntToSpeed(int);
int
physical_GetFD(struct physical *phys) {
return phys->fd;
}
int
physical_IsSync(struct physical *phys) {
return phys->cfg.speed == 0;
}
const char *physical_GetDevice(struct physical *phys)
{
return phys->name.full;
}
void
physical_SetDeviceList(struct physical *p, int argc, const char *const *argv)
{
int f, pos;
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)
p->cfg.devlist[pos++] = ' ';
strncpy(p->cfg.devlist + pos, argv[f], sizeof p->cfg.devlist - pos - 1);
pos += strlen(p->cfg.devlist + pos);
}
}
int
physical_SetSpeed(struct physical *phys, int speed) {
if (IntToSpeed(speed) != B0) {
phys->cfg.speed = speed;
return 1;
} else {
return 0;
}
}
void
physical_SetSync(struct physical *phys) {
phys->cfg.speed = 0;
}
int
physical_SetRtsCts(struct physical *phys, int enable) {
phys->cfg.rts_cts = enable ? 1 : 0;
return 1;
}
/* Encapsulation for a read on the FD. Avoids some exposure, and
concentrates control. */
ssize_t
physical_Read(struct physical *phys, void *buf, size_t nbytes) {
return read(phys->fd, buf, nbytes);
}
ssize_t
physical_Write(struct physical *phys, const void *buf, size_t nbytes) {
return write(phys->fd, buf, nbytes);
}
1998-02-06 02:22:28 +00:00
int
physical_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e,
int *n, int force)
{
struct physical *p = descriptor2physical(d);
int sets;
sets = 0;
if (p->fd >= 0) {
if (r) {
FD_SET(p->fd, r);
log_Printf(LogTIMER, "%s: fdset(r) %d\n", p->link.name, p->fd);
sets++;
}
if (e) {
FD_SET(p->fd, e);
log_Printf(LogTIMER, "%s: fdset(e) %d\n", p->link.name, p->fd);
sets++;
}
if (w && (force || link_QueueLen(&p->link) || p->out)) {
FD_SET(p->fd, w);
log_Printf(LogTIMER, "%s: fdset(w) %d\n", p->link.name, p->fd);
sets++;
}
if (sets && *n < p->fd + 1)
*n = p->fd + 1;
}
return sets;
}
int
physical_RemoveFromSet(struct physical *p, fd_set *r, fd_set *w, fd_set *e)
{
int sets;
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++;
}
}
return sets;
}
int
physical_IsSet(struct descriptor *d, const fd_set *fdset)
{
struct physical *p = descriptor2physical(d);
return p->fd >= 0 && FD_ISSET(p->fd, fdset);
}
void
physical_Login(struct physical *phys, const char *name)
{
if (phys->type == PHYS_DIRECT && phys->isatty) {
if (phys->Utmp)
log_Printf(LogERROR, "Oops, already logged in on %s\n", phys->name.base);
else {
struct utmp ut;
const char *connstr;
memset(&ut, 0, sizeof ut);
time(&ut.ut_time);
strncpy(ut.ut_name, name, sizeof ut.ut_name);
strncpy(ut.ut_line, phys->name.base, sizeof ut.ut_line);
if ((connstr = getenv("CONNECT")))
/* mgetty sets this to the connection speed */
strncpy(ut.ut_host, connstr, sizeof ut.ut_host);
ID0login(&ut);
phys->Utmp = 1;
}
}
}
void
physical_Logout(struct physical *phys)
{
if (phys->Utmp) {
ID0logout(phys->name.base);
phys->Utmp = 0;
}
}
int
physical_SetMode(struct physical *p, int mode)
{
if ((p->type & (PHYS_DIRECT|PHYS_DEDICATED) ||
mode & (PHYS_DIRECT|PHYS_DEDICATED)) &&
(!(p->type & PHYS_DIRECT) || !(mode & PHYS_BACKGROUND))) {
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;
}
void
physical_DeleteQueue(struct physical *p)
{
if (p->out) {
mbuf_Free(p->out);
p->out = NULL;
}
link_DeleteQueue(&p->link);
}