1998-05-21 21:49:08 +00:00
|
|
|
/*-
|
|
|
|
* Copyright (c) 1998 Brian Somers <brian@Awfulhak.org>
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
1999-08-28 01:35:59 +00:00
|
|
|
* $FreeBSD$
|
1998-05-21 21:49:08 +00:00
|
|
|
*/
|
|
|
|
|
1998-05-28 23:17:51 +00:00
|
|
|
#include <sys/param.h>
|
1998-05-21 21:49:08 +00:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <net/if.h>
|
2000-01-23 01:48:19 +00:00
|
|
|
#include <net/if_tun.h> /* For TUNS* ioctls */
|
1998-05-21 21:49:08 +00:00
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <net/route.h>
|
|
|
|
#include <netinet/in_systm.h>
|
|
|
|
#include <netinet/ip.h>
|
|
|
|
#include <sys/un.h>
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
1999-11-17 21:12:35 +00:00
|
|
|
#ifdef __OpenBSD__
|
|
|
|
#include <util.h>
|
|
|
|
#else
|
|
|
|
#include <libutil.h>
|
|
|
|
#endif
|
1998-05-21 21:49:08 +00:00
|
|
|
#include <paths.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/uio.h>
|
1998-05-25 02:22:38 +00:00
|
|
|
#include <sys/wait.h>
|
1999-09-22 00:40:47 +00:00
|
|
|
#if defined(__FreeBSD__) && !defined(NOKLDLOAD)
|
|
|
|
#include <sys/linker.h>
|
1999-11-16 21:57:34 +00:00
|
|
|
#include <sys/module.h>
|
1999-09-22 00:40:47 +00:00
|
|
|
#endif
|
1998-05-21 21:49:08 +00:00
|
|
|
#include <termios.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
1999-05-08 11:07:56 +00:00
|
|
|
#include "layer.h"
|
1998-06-15 19:06:25 +00:00
|
|
|
#include "defs.h"
|
1998-05-21 21:49:08 +00:00
|
|
|
#include "command.h"
|
|
|
|
#include "mbuf.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "id.h"
|
|
|
|
#include "timer.h"
|
|
|
|
#include "fsm.h"
|
|
|
|
#include "iplist.h"
|
|
|
|
#include "lqr.h"
|
|
|
|
#include "hdlc.h"
|
|
|
|
#include "throughput.h"
|
|
|
|
#include "slcompress.h"
|
|
|
|
#include "ipcp.h"
|
|
|
|
#include "filter.h"
|
|
|
|
#include "descriptor.h"
|
|
|
|
#include "route.h"
|
|
|
|
#include "lcp.h"
|
|
|
|
#include "ccp.h"
|
|
|
|
#include "link.h"
|
|
|
|
#include "mp.h"
|
1999-01-28 01:56:34 +00:00
|
|
|
#ifndef NORADIUS
|
|
|
|
#include "radius.h"
|
|
|
|
#endif
|
1998-05-21 21:49:08 +00:00
|
|
|
#include "bundle.h"
|
|
|
|
#include "async.h"
|
|
|
|
#include "physical.h"
|
|
|
|
#include "auth.h"
|
1999-05-08 11:07:56 +00:00
|
|
|
#include "proto.h"
|
1998-05-21 21:49:08 +00:00
|
|
|
#include "chap.h"
|
|
|
|
#include "tun.h"
|
|
|
|
#include "prompt.h"
|
|
|
|
#include "chat.h"
|
1998-08-07 18:42:51 +00:00
|
|
|
#include "cbcp.h"
|
1998-05-21 21:49:08 +00:00
|
|
|
#include "datalink.h"
|
|
|
|
#include "ip.h"
|
1998-10-22 02:32:50 +00:00
|
|
|
#include "iface.h"
|
1998-05-21 21:49:08 +00:00
|
|
|
|
2000-08-15 10:25:42 +00:00
|
|
|
#define SCATTER_SEGMENTS 7 /* version, datalink, name, physical,
|
|
|
|
throughput, throughput, device */
|
1999-11-06 22:50:59 +00:00
|
|
|
|
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
|
|
|
#define SEND_MAXFD 3 /* Max file descriptors passed through
|
|
|
|
the local domain socket */
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
static int bundle_RemainingIdleTime(struct bundle *);
|
|
|
|
|
1999-12-27 11:54:57 +00:00
|
|
|
static const char * const PhaseNames[] = {
|
1998-05-21 21:49:08 +00:00
|
|
|
"Dead", "Establish", "Authenticate", "Network", "Terminate"
|
|
|
|
};
|
|
|
|
|
|
|
|
const char *
|
|
|
|
bundle_PhaseName(struct bundle *bundle)
|
|
|
|
{
|
|
|
|
return bundle->phase <= PHASE_TERMINATE ?
|
|
|
|
PhaseNames[bundle->phase] : "unknown";
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
bundle_NewPhase(struct bundle *bundle, u_int new)
|
|
|
|
{
|
|
|
|
if (new == bundle->phase)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (new <= PHASE_TERMINATE)
|
|
|
|
log_Printf(LogPHASE, "bundle: %s\n", PhaseNames[new]);
|
|
|
|
|
|
|
|
switch (new) {
|
|
|
|
case PHASE_DEAD:
|
1998-05-23 22:24:50 +00:00
|
|
|
log_DisplayPrompts();
|
1998-05-21 21:49:08 +00:00
|
|
|
bundle->phase = new;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PHASE_ESTABLISH:
|
|
|
|
bundle->phase = new;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PHASE_AUTHENTICATE:
|
|
|
|
bundle->phase = new;
|
1998-05-23 22:24:50 +00:00
|
|
|
log_DisplayPrompts();
|
1998-05-21 21:49:08 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case PHASE_NETWORK:
|
|
|
|
fsm_Up(&bundle->ncp.ipcp.fsm);
|
|
|
|
fsm_Open(&bundle->ncp.ipcp.fsm);
|
|
|
|
bundle->phase = new;
|
1998-05-23 22:24:50 +00:00
|
|
|
log_DisplayPrompts();
|
1998-05-21 21:49:08 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case PHASE_TERMINATE:
|
|
|
|
bundle->phase = new;
|
|
|
|
mp_Down(&bundle->ncp.mp);
|
1998-05-23 22:24:50 +00:00
|
|
|
log_DisplayPrompts();
|
1998-05-21 21:49:08 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bundle_LayerStart(void *v, struct fsm *fp)
|
|
|
|
{
|
|
|
|
/* The given FSM is about to start up ! */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-04-07 23:46:14 +00:00
|
|
|
void
|
1998-05-21 21:49:08 +00:00
|
|
|
bundle_Notify(struct bundle *bundle, char c)
|
|
|
|
{
|
|
|
|
if (bundle->notify.fd != -1) {
|
2000-04-07 23:46:14 +00:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = write(bundle->notify.fd, &c, 1);
|
|
|
|
if (c != EX_REDIAL && c != EX_RECONNECT) {
|
|
|
|
if (ret == 1)
|
|
|
|
log_Printf(LogCHAT, "Parent notified of %s\n",
|
|
|
|
c == EX_NORMAL ? "success" : "failure");
|
|
|
|
else
|
|
|
|
log_Printf(LogERROR, "Failed to notify parent of success\n");
|
|
|
|
close(bundle->notify.fd);
|
|
|
|
bundle->notify.fd = -1;
|
|
|
|
} else if (ret == 1)
|
|
|
|
log_Printf(LogCHAT, "Parent notified of %s\n", ex_desc(c));
|
1998-05-21 21:49:08 +00:00
|
|
|
else
|
2000-04-07 23:46:14 +00:00
|
|
|
log_Printf(LogERROR, "Failed to notify parent of %s\n", ex_desc(c));
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-08-25 17:48:43 +00:00
|
|
|
static void
|
|
|
|
bundle_ClearQueues(void *v)
|
|
|
|
{
|
|
|
|
struct bundle *bundle = (struct bundle *)v;
|
|
|
|
struct datalink *dl;
|
|
|
|
|
|
|
|
log_Printf(LogPHASE, "Clearing choked output queue\n");
|
|
|
|
timer_Stop(&bundle->choked.timer);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Emergency time:
|
|
|
|
*
|
|
|
|
* We've had a full queue for PACKET_DEL_SECS seconds without being
|
|
|
|
* able to get rid of any of the packets. We've probably given up
|
|
|
|
* on the redials at this point, and the queued data has almost
|
|
|
|
* definitely been timed out by the layer above. As this is preventing
|
|
|
|
* us from reading the TUN_NAME device (we don't want to buffer stuff
|
|
|
|
* indefinitely), we may as well nuke this data and start with a clean
|
|
|
|
* slate !
|
|
|
|
*
|
|
|
|
* Unfortunately, this has the side effect of shafting any compression
|
|
|
|
* dictionaries in use (causing the relevant RESET_REQ/RESET_ACK).
|
|
|
|
*/
|
|
|
|
|
1998-08-26 17:39:37 +00:00
|
|
|
ip_DeleteQueue(&bundle->ncp.ipcp);
|
1998-08-25 17:48:43 +00:00
|
|
|
mp_DeleteQueue(&bundle->ncp.mp);
|
|
|
|
for (dl = bundle->links; dl; dl = dl->next)
|
|
|
|
physical_DeleteQueue(dl->physical);
|
|
|
|
}
|
|
|
|
|
1998-06-12 17:45:10 +00:00
|
|
|
static void
|
|
|
|
bundle_LinkAdded(struct bundle *bundle, struct datalink *dl)
|
|
|
|
{
|
|
|
|
bundle->phys_type.all |= dl->physical->type;
|
|
|
|
if (dl->state == DATALINK_OPEN)
|
|
|
|
bundle->phys_type.open |= dl->physical->type;
|
|
|
|
|
|
|
|
if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL))
|
|
|
|
!= bundle->phys_type.open && bundle->idle.timer.state == TIMER_STOPPED)
|
|
|
|
/* We may need to start our idle timer */
|
2000-07-11 22:11:36 +00:00
|
|
|
bundle_StartIdleTimer(bundle, 0);
|
1998-06-12 17:45:10 +00:00
|
|
|
}
|
|
|
|
|
1998-08-07 18:42:51 +00:00
|
|
|
void
|
1998-06-12 17:45:10 +00:00
|
|
|
bundle_LinksRemoved(struct bundle *bundle)
|
|
|
|
{
|
|
|
|
struct datalink *dl;
|
|
|
|
|
|
|
|
bundle->phys_type.all = bundle->phys_type.open = 0;
|
|
|
|
for (dl = bundle->links; dl; dl = dl->next)
|
|
|
|
bundle_LinkAdded(bundle, dl);
|
|
|
|
|
1999-08-05 10:32:16 +00:00
|
|
|
bundle_CalculateBandwidth(bundle);
|
|
|
|
mp_CheckAutoloadTimer(&bundle->ncp.mp);
|
|
|
|
|
1998-06-12 17:45:10 +00:00
|
|
|
if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL))
|
|
|
|
== bundle->phys_type.open)
|
|
|
|
bundle_StopIdleTimer(bundle);
|
|
|
|
}
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
bundle_LayerUp(void *v, struct fsm *fp)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* The given fsm is now up
|
1999-08-05 10:32:16 +00:00
|
|
|
* If it's an LCP, adjust our phys_mode.open value and check the
|
|
|
|
* autoload timer.
|
|
|
|
* If it's the first NCP, calculate our bandwidth
|
1999-08-17 17:22:46 +00:00
|
|
|
* If it's the first NCP, set our ``upat'' time
|
1998-05-21 21:49:08 +00:00
|
|
|
* If it's the first NCP, start the idle timer.
|
1999-08-05 10:32:16 +00:00
|
|
|
* If it's an NCP, tell our -background parent to go away.
|
|
|
|
* If it's the first NCP, start the autoload timer
|
1998-05-21 21:49:08 +00:00
|
|
|
*/
|
|
|
|
struct bundle *bundle = (struct bundle *)v;
|
|
|
|
|
|
|
|
if (fp->proto == PROTO_LCP) {
|
1998-06-12 17:45:10 +00:00
|
|
|
struct physical *p = link2physical(fp->link);
|
|
|
|
|
|
|
|
bundle_LinkAdded(bundle, p->dl);
|
1999-08-05 10:32:16 +00:00
|
|
|
mp_CheckAutoloadTimer(&bundle->ncp.mp);
|
1998-05-21 21:49:08 +00:00
|
|
|
} else if (fp->proto == PROTO_IPCP) {
|
1999-08-05 10:32:16 +00:00
|
|
|
bundle_CalculateBandwidth(fp->bundle);
|
1999-08-17 17:22:46 +00:00
|
|
|
time(&bundle->upat);
|
2000-07-11 22:11:36 +00:00
|
|
|
bundle_StartIdleTimer(bundle, 0);
|
1998-05-21 21:49:08 +00:00
|
|
|
bundle_Notify(bundle, EX_NORMAL);
|
1999-08-05 10:32:16 +00:00
|
|
|
mp_CheckAutoloadTimer(&fp->bundle->ncp.mp);
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bundle_LayerDown(void *v, struct fsm *fp)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* The given FSM has been told to come down.
|
|
|
|
* If it's our last NCP, stop the idle timer.
|
1999-08-17 17:22:46 +00:00
|
|
|
* If it's our last NCP, clear our ``upat'' value.
|
1999-08-05 10:32:16 +00:00
|
|
|
* If it's our last NCP, stop the autoload timer
|
1998-06-12 17:45:10 +00:00
|
|
|
* If it's an LCP, adjust our phys_type.open value and any timers.
|
1998-05-23 17:05:28 +00:00
|
|
|
* If it's an LCP and we're in multilink mode, adjust our tun
|
2000-04-06 10:03:48 +00:00
|
|
|
* If it's the last LCP, down all NCPs
|
1998-05-23 17:05:28 +00:00
|
|
|
* speed and make sure our minimum sequence number is adjusted.
|
1998-05-21 21:49:08 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
struct bundle *bundle = (struct bundle *)v;
|
|
|
|
|
1999-08-05 10:32:16 +00:00
|
|
|
if (fp->proto == PROTO_IPCP) {
|
1998-05-21 21:49:08 +00:00
|
|
|
bundle_StopIdleTimer(bundle);
|
1999-08-17 17:22:46 +00:00
|
|
|
bundle->upat = 0;
|
1999-08-05 10:32:16 +00:00
|
|
|
mp_StopAutoloadTimer(&bundle->ncp.mp);
|
|
|
|
} else if (fp->proto == PROTO_LCP) {
|
2000-04-06 10:03:48 +00:00
|
|
|
struct datalink *dl;
|
|
|
|
struct datalink *lost;
|
|
|
|
int others_active;
|
|
|
|
|
1998-06-12 17:45:10 +00:00
|
|
|
bundle_LinksRemoved(bundle); /* adjust timers & phys_type values */
|
1998-05-21 21:49:08 +00:00
|
|
|
|
2000-04-06 10:03:48 +00:00
|
|
|
lost = NULL;
|
|
|
|
others_active = 0;
|
|
|
|
for (dl = bundle->links; dl; dl = dl->next) {
|
|
|
|
if (fp == &dl->physical->link.lcp.fsm)
|
|
|
|
lost = dl;
|
|
|
|
else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP)
|
|
|
|
others_active++;
|
|
|
|
}
|
1998-05-23 17:05:28 +00:00
|
|
|
|
2000-04-06 10:03:48 +00:00
|
|
|
if (bundle->ncp.mp.active) {
|
1999-08-05 10:32:16 +00:00
|
|
|
bundle_CalculateBandwidth(bundle);
|
1998-05-23 17:05:28 +00:00
|
|
|
|
1998-06-12 17:45:10 +00:00
|
|
|
if (lost)
|
|
|
|
mp_LinkLost(&bundle->ncp.mp, lost);
|
|
|
|
else
|
1998-06-16 19:40:42 +00:00
|
|
|
log_Printf(LogALERT, "Oops, lost an unrecognised datalink (%s) !\n",
|
1998-06-12 17:45:10 +00:00
|
|
|
fp->link->name);
|
|
|
|
}
|
2000-04-06 10:03:48 +00:00
|
|
|
|
|
|
|
if (!others_active)
|
|
|
|
/* Down the NCPs. We don't expect to get fsm_Close()d ourself ! */
|
|
|
|
fsm2initial(&bundle->ncp.ipcp.fsm);
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bundle_LayerFinish(void *v, struct fsm *fp)
|
|
|
|
{
|
|
|
|
/* The given fsm is now down (fp cannot be NULL)
|
|
|
|
*
|
|
|
|
* If it's the last NCP, fsm_Close all LCPs
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct bundle *bundle = (struct bundle *)v;
|
|
|
|
struct datalink *dl;
|
|
|
|
|
|
|
|
if (fp->proto == PROTO_IPCP) {
|
|
|
|
if (bundle_Phase(bundle) != PHASE_DEAD)
|
|
|
|
bundle_NewPhase(bundle, PHASE_TERMINATE);
|
|
|
|
for (dl = bundle->links; dl; dl = dl->next)
|
2000-04-06 10:03:48 +00:00
|
|
|
if (dl->state == DATALINK_OPEN)
|
|
|
|
datalink_Close(dl, CLOSE_STAYDOWN);
|
1998-06-20 00:19:42 +00:00
|
|
|
fsm2initial(fp);
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
bundle_LinkIsUp(const struct bundle *bundle)
|
|
|
|
{
|
|
|
|
return bundle->ncp.ipcp.fsm.state == ST_OPENED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1998-06-15 19:05:27 +00:00
|
|
|
bundle_Close(struct bundle *bundle, const char *name, int how)
|
1998-05-21 21:49:08 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Please close the given datalink.
|
|
|
|
* If name == NULL or name is the last datalink, fsm_Close all NCPs
|
|
|
|
* (except our MP)
|
|
|
|
* If it isn't the last datalink, just Close that datalink.
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct datalink *dl, *this_dl;
|
|
|
|
int others_active;
|
|
|
|
|
|
|
|
others_active = 0;
|
|
|
|
this_dl = NULL;
|
|
|
|
|
|
|
|
for (dl = bundle->links; dl; dl = dl->next) {
|
|
|
|
if (name && !strcasecmp(name, dl->name))
|
|
|
|
this_dl = dl;
|
|
|
|
if (name == NULL || this_dl == dl) {
|
1998-06-15 19:05:27 +00:00
|
|
|
switch (how) {
|
|
|
|
case CLOSE_LCP:
|
|
|
|
datalink_DontHangup(dl);
|
|
|
|
/* fall through */
|
|
|
|
case CLOSE_STAYDOWN:
|
|
|
|
datalink_StayDown(dl);
|
|
|
|
break;
|
|
|
|
}
|
1998-05-21 21:49:08 +00:00
|
|
|
} else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP)
|
|
|
|
others_active++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name && this_dl == NULL) {
|
|
|
|
log_Printf(LogWARN, "%s: Invalid datalink name\n", name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!others_active) {
|
|
|
|
bundle_StopIdleTimer(bundle);
|
|
|
|
if (bundle->ncp.ipcp.fsm.state > ST_CLOSED ||
|
|
|
|
bundle->ncp.ipcp.fsm.state == ST_STARTING)
|
|
|
|
fsm_Close(&bundle->ncp.ipcp.fsm);
|
|
|
|
else {
|
1998-06-20 00:19:42 +00:00
|
|
|
fsm2initial(&bundle->ncp.ipcp.fsm);
|
1998-05-21 21:49:08 +00:00
|
|
|
for (dl = bundle->links; dl; dl = dl->next)
|
1998-06-15 19:05:27 +00:00
|
|
|
datalink_Close(dl, how);
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
} else if (this_dl && this_dl->state != DATALINK_CLOSED &&
|
|
|
|
this_dl->state != DATALINK_HANGUP)
|
1998-06-15 19:05:27 +00:00
|
|
|
datalink_Close(this_dl, how);
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1998-06-16 19:40:28 +00:00
|
|
|
bundle_Down(struct bundle *bundle, int how)
|
1998-05-21 21:49:08 +00:00
|
|
|
{
|
|
|
|
struct datalink *dl;
|
|
|
|
|
|
|
|
for (dl = bundle->links; dl; dl = dl->next)
|
1998-06-16 19:40:28 +00:00
|
|
|
datalink_Down(dl, how);
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
|
1999-12-20 20:29:47 +00:00
|
|
|
static size_t
|
|
|
|
bundle_FillQueues(struct bundle *bundle)
|
|
|
|
{
|
|
|
|
size_t total;
|
|
|
|
|
|
|
|
if (bundle->ncp.mp.active)
|
|
|
|
total = mp_FillQueues(bundle);
|
|
|
|
else {
|
|
|
|
struct datalink *dl;
|
|
|
|
size_t add;
|
|
|
|
|
|
|
|
for (total = 0, dl = bundle->links; dl; dl = dl->next)
|
|
|
|
if (dl->state == DATALINK_OPEN) {
|
|
|
|
add = link_QueueLen(&dl->physical->link);
|
|
|
|
if (add == 0 && dl->physical->out == NULL)
|
|
|
|
add = ip_PushPacket(&dl->physical->link, bundle);
|
|
|
|
total += add;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return total + ip_QueueLen(&bundle->ncp.ipcp);
|
|
|
|
}
|
|
|
|
|
1998-05-21 21:49:08 +00:00
|
|
|
static int
|
2000-03-14 01:46:09 +00:00
|
|
|
bundle_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
|
1998-05-21 21:49:08 +00:00
|
|
|
{
|
|
|
|
struct bundle *bundle = descriptor2bundle(d);
|
|
|
|
struct datalink *dl;
|
1999-12-20 20:29:47 +00:00
|
|
|
int result, nlinks;
|
2000-06-11 02:30:51 +00:00
|
|
|
u_short ifqueue;
|
1999-12-20 20:29:47 +00:00
|
|
|
size_t queued;
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
result = 0;
|
|
|
|
|
|
|
|
/* If there are aren't many packets queued, look for some more. */
|
|
|
|
for (nlinks = 0, dl = bundle->links; dl; dl = dl->next)
|
|
|
|
nlinks++;
|
|
|
|
|
|
|
|
if (nlinks) {
|
1998-08-26 17:39:37 +00:00
|
|
|
queued = r ? bundle_FillQueues(bundle) : ip_QueueLen(&bundle->ncp.ipcp);
|
1998-05-21 21:49:08 +00:00
|
|
|
|
1998-06-12 17:45:10 +00:00
|
|
|
if (r && (bundle->phase == PHASE_NETWORK ||
|
|
|
|
bundle->phys_type.all & PHYS_AUTO)) {
|
1998-05-21 21:49:08 +00:00
|
|
|
/* enough surplus so that we can tell if we're getting swamped */
|
2000-06-11 02:30:51 +00:00
|
|
|
ifqueue = nlinks > bundle->cfg.ifqueue ? nlinks : bundle->cfg.ifqueue;
|
|
|
|
if (queued < ifqueue) {
|
1998-05-21 21:49:08 +00:00
|
|
|
/* Not enough - select() for more */
|
1998-08-25 17:48:43 +00:00
|
|
|
if (bundle->choked.timer.state == TIMER_RUNNING)
|
|
|
|
timer_Stop(&bundle->choked.timer); /* Not needed any more */
|
1998-05-21 21:49:08 +00:00
|
|
|
FD_SET(bundle->dev.fd, r);
|
|
|
|
if (*n < bundle->dev.fd + 1)
|
|
|
|
*n = bundle->dev.fd + 1;
|
1998-05-28 23:17:51 +00:00
|
|
|
log_Printf(LogTIMER, "%s: fdset(r) %d\n", TUN_NAME, bundle->dev.fd);
|
1998-05-21 21:49:08 +00:00
|
|
|
result++;
|
1998-08-25 17:48:43 +00:00
|
|
|
} else if (bundle->choked.timer.state == TIMER_STOPPED) {
|
|
|
|
bundle->choked.timer.func = bundle_ClearQueues;
|
|
|
|
bundle->choked.timer.name = "output choke";
|
|
|
|
bundle->choked.timer.load = bundle->cfg.choked.timeout * SECTICKS;
|
|
|
|
bundle->choked.timer.arg = bundle;
|
|
|
|
timer_Start(&bundle->choked.timer);
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-02-06 02:54:47 +00:00
|
|
|
#ifndef NORADIUS
|
|
|
|
result += descriptor_UpdateSet(&bundle->radius.desc, r, w, e, n);
|
|
|
|
#endif
|
|
|
|
|
1998-06-07 00:16:37 +00:00
|
|
|
/* Which links need a select() ? */
|
|
|
|
for (dl = bundle->links; dl; dl = dl->next)
|
|
|
|
result += descriptor_UpdateSet(&dl->desc, r, w, e, n);
|
|
|
|
|
1998-05-21 21:49:08 +00:00
|
|
|
/*
|
|
|
|
* This *MUST* be called after the datalink UpdateSet()s as it
|
|
|
|
* might be ``holding'' one of the datalinks (death-row) and
|
2000-03-14 01:47:07 +00:00
|
|
|
* wants to be able to de-select() it from the descriptor set.
|
1998-05-21 21:49:08 +00:00
|
|
|
*/
|
1998-05-23 22:24:50 +00:00
|
|
|
result += descriptor_UpdateSet(&bundle->ncp.mp.server.desc, r, w, e, n);
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2000-03-14 01:46:09 +00:00
|
|
|
bundle_IsSet(struct fdescriptor *d, const fd_set *fdset)
|
1998-05-21 21:49:08 +00:00
|
|
|
{
|
|
|
|
struct bundle *bundle = descriptor2bundle(d);
|
|
|
|
struct datalink *dl;
|
|
|
|
|
|
|
|
for (dl = bundle->links; dl; dl = dl->next)
|
|
|
|
if (descriptor_IsSet(&dl->desc, fdset))
|
|
|
|
return 1;
|
|
|
|
|
1999-02-06 02:54:47 +00:00
|
|
|
#ifndef NORADIUS
|
|
|
|
if (descriptor_IsSet(&bundle->radius.desc, fdset))
|
|
|
|
return 1;
|
|
|
|
#endif
|
|
|
|
|
1998-05-21 21:49:08 +00:00
|
|
|
if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return FD_ISSET(bundle->dev.fd, fdset);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2000-03-14 01:46:09 +00:00
|
|
|
bundle_DescriptorRead(struct fdescriptor *d, struct bundle *bundle,
|
1998-05-21 21:49:08 +00:00
|
|
|
const fd_set *fdset)
|
|
|
|
{
|
|
|
|
struct datalink *dl;
|
2000-07-11 22:11:36 +00:00
|
|
|
unsigned secs;
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset))
|
|
|
|
descriptor_Read(&bundle->ncp.mp.server.desc, bundle, fdset);
|
|
|
|
|
|
|
|
for (dl = bundle->links; dl; dl = dl->next)
|
|
|
|
if (descriptor_IsSet(&dl->desc, fdset))
|
|
|
|
descriptor_Read(&dl->desc, bundle, fdset);
|
|
|
|
|
1999-02-06 02:54:47 +00:00
|
|
|
#ifndef NORADIUS
|
|
|
|
if (descriptor_IsSet(&bundle->radius.desc, fdset))
|
|
|
|
descriptor_Read(&bundle->radius.desc, bundle, fdset);
|
|
|
|
#endif
|
|
|
|
|
1998-05-21 21:49:08 +00:00
|
|
|
if (FD_ISSET(bundle->dev.fd, fdset)) {
|
|
|
|
struct tun_data tun;
|
|
|
|
int n, pri;
|
2000-01-23 01:48:19 +00:00
|
|
|
char *data;
|
|
|
|
size_t sz;
|
|
|
|
|
|
|
|
if (bundle->dev.header) {
|
|
|
|
data = (char *)&tun;
|
|
|
|
sz = sizeof tun;
|
|
|
|
} else {
|
|
|
|
data = tun.data;
|
|
|
|
sz = sizeof tun.data;
|
|
|
|
}
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
/* something to read from tun */
|
2000-01-23 01:48:19 +00:00
|
|
|
|
|
|
|
n = read(bundle->dev.fd, data, sz);
|
1998-05-21 21:49:08 +00:00
|
|
|
if (n < 0) {
|
2000-01-23 01:48:19 +00:00
|
|
|
log_Printf(LogWARN, "%s: read: %s\n", bundle->dev.Name, strerror(errno));
|
1998-05-21 21:49:08 +00:00
|
|
|
return;
|
|
|
|
}
|
2000-01-23 01:48:19 +00:00
|
|
|
|
|
|
|
if (bundle->dev.header) {
|
|
|
|
n -= sz - sizeof tun.data;
|
|
|
|
if (n <= 0) {
|
|
|
|
log_Printf(LogERROR, "%s: read: Got only %d bytes of data !\n",
|
|
|
|
bundle->dev.Name, n);
|
|
|
|
return;
|
|
|
|
}
|
2000-07-11 22:11:36 +00:00
|
|
|
if (ntohl(tun.header.family) != AF_INET)
|
2000-01-23 01:48:19 +00:00
|
|
|
/* XXX: Should be maintaining drop/family counts ! */
|
|
|
|
return;
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (((struct ip *)tun.data)->ip_dst.s_addr ==
|
|
|
|
bundle->ncp.ipcp.my_ip.s_addr) {
|
|
|
|
/* we've been asked to send something addressed *to* us :( */
|
|
|
|
if (Enabled(bundle, OPT_LOOPBACK)) {
|
2000-07-11 22:11:36 +00:00
|
|
|
pri = PacketCheck(bundle, tun.data, n, &bundle->filter.in, NULL, NULL);
|
1998-05-21 21:49:08 +00:00
|
|
|
if (pri >= 0) {
|
2000-01-23 01:48:19 +00:00
|
|
|
n += sz - sizeof tun.data;
|
|
|
|
write(bundle->dev.fd, data, n);
|
1998-05-21 21:49:08 +00:00
|
|
|
log_Printf(LogDEBUG, "Looped back packet addressed to myself\n");
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
} else
|
|
|
|
log_Printf(LogDEBUG, "Oops - forwarding packet addressed to myself\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Process on-demand dialup. Output packets are queued within tunnel
|
|
|
|
* device until IPCP is opened.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (bundle_Phase(bundle) == PHASE_DEAD) {
|
|
|
|
/*
|
|
|
|
* Note, we must be in AUTO mode :-/ otherwise our interface should
|
|
|
|
* *not* be UP and we can't receive data
|
|
|
|
*/
|
2000-07-11 22:11:36 +00:00
|
|
|
pri = PacketCheck(bundle, tun.data, n, &bundle->filter.dial, NULL, NULL);
|
2000-07-11 09:26:02 +00:00
|
|
|
if (pri >= 0)
|
1998-07-29 18:21:17 +00:00
|
|
|
bundle_Open(bundle, NULL, PHYS_AUTO, 0);
|
1998-05-21 21:49:08 +00:00
|
|
|
else
|
|
|
|
/*
|
|
|
|
* Drop the packet. If we were to queue it, we'd just end up with
|
|
|
|
* a pile of timed-out data in our output queue by the time we get
|
|
|
|
* around to actually dialing. We'd also prematurely reach the
|
|
|
|
* threshold at which we stop select()ing to read() the tun
|
|
|
|
* device - breaking auto-dial.
|
|
|
|
*/
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2000-07-11 22:11:36 +00:00
|
|
|
secs = 0;
|
|
|
|
pri = PacketCheck(bundle, tun.data, n, &bundle->filter.out, NULL, &secs);
|
|
|
|
if (pri >= 0) {
|
|
|
|
/* Prepend the number of seconds timeout given in the filter */
|
|
|
|
tun.header.timeout = secs;
|
|
|
|
ip_Enqueue(&bundle->ncp.ipcp, pri, (char *)&tun, n + sizeof tun.header);
|
|
|
|
}
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-06-24 19:33:36 +00:00
|
|
|
static int
|
2000-03-14 01:46:09 +00:00
|
|
|
bundle_DescriptorWrite(struct fdescriptor *d, struct bundle *bundle,
|
1998-05-21 21:49:08 +00:00
|
|
|
const fd_set *fdset)
|
|
|
|
{
|
|
|
|
struct datalink *dl;
|
1998-06-24 19:33:36 +00:00
|
|
|
int result = 0;
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
/* This is not actually necessary as struct mpserver doesn't Write() */
|
|
|
|
if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset))
|
|
|
|
descriptor_Write(&bundle->ncp.mp.server.desc, bundle, fdset);
|
|
|
|
|
|
|
|
for (dl = bundle->links; dl; dl = dl->next)
|
|
|
|
if (descriptor_IsSet(&dl->desc, fdset))
|
1998-06-24 19:33:36 +00:00
|
|
|
result += descriptor_Write(&dl->desc, bundle, fdset);
|
|
|
|
|
|
|
|
return result;
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
|
1998-06-06 20:50:57 +00:00
|
|
|
void
|
1998-05-28 23:17:51 +00:00
|
|
|
bundle_LockTun(struct bundle *bundle)
|
|
|
|
{
|
|
|
|
FILE *lockfile;
|
|
|
|
char pidfile[MAXPATHLEN];
|
|
|
|
|
|
|
|
snprintf(pidfile, sizeof pidfile, "%stun%d.pid", _PATH_VARRUN, bundle->unit);
|
|
|
|
lockfile = ID0fopen(pidfile, "w");
|
|
|
|
if (lockfile != NULL) {
|
|
|
|
fprintf(lockfile, "%d\n", (int)getpid());
|
|
|
|
fclose(lockfile);
|
|
|
|
}
|
|
|
|
#ifndef RELEASE_CRUNCH
|
|
|
|
else
|
|
|
|
log_Printf(LogERROR, "Warning: Can't create %s: %s\n",
|
|
|
|
pidfile, strerror(errno));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bundle_UnlockTun(struct bundle *bundle)
|
|
|
|
{
|
|
|
|
char pidfile[MAXPATHLEN];
|
|
|
|
|
|
|
|
snprintf(pidfile, sizeof pidfile, "%stun%d.pid", _PATH_VARRUN, bundle->unit);
|
|
|
|
ID0unlink(pidfile);
|
|
|
|
}
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
struct bundle *
|
1999-11-17 21:12:35 +00:00
|
|
|
bundle_Create(const char *prefix, int type, int unit)
|
1998-05-21 21:49:08 +00:00
|
|
|
{
|
|
|
|
static struct bundle bundle; /* there can be only one */
|
1999-10-19 15:21:09 +00:00
|
|
|
int enoentcount, err, minunit, maxunit;
|
1999-05-27 08:42:17 +00:00
|
|
|
const char *ifname;
|
1999-11-16 21:57:34 +00:00
|
|
|
#if defined(__FreeBSD__) && !defined(NOKLDLOAD)
|
1999-09-22 00:40:47 +00:00
|
|
|
int kldtried;
|
|
|
|
#endif
|
2000-01-23 01:48:19 +00:00
|
|
|
#if defined(TUNSIFMODE) || defined(TUNSLMODE) || defined(TUNSIFHEAD)
|
1999-03-25 11:37:51 +00:00
|
|
|
int iff;
|
|
|
|
#endif
|
1998-05-21 21:49:08 +00:00
|
|
|
|
1998-10-22 02:32:50 +00:00
|
|
|
if (bundle.iface != NULL) { /* Already allocated ! */
|
1998-06-16 19:40:42 +00:00
|
|
|
log_Printf(LogALERT, "bundle_Create: There's only one BUNDLE !\n");
|
1998-05-21 21:49:08 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
1999-10-19 15:21:09 +00:00
|
|
|
if (unit == -1) {
|
|
|
|
minunit = 0;
|
|
|
|
maxunit = -1;
|
|
|
|
} else {
|
|
|
|
minunit = unit;
|
|
|
|
maxunit = unit + 1;
|
|
|
|
}
|
1998-05-21 21:49:08 +00:00
|
|
|
err = ENOENT;
|
|
|
|
enoentcount = 0;
|
1999-11-16 21:57:34 +00:00
|
|
|
#if defined(__FreeBSD__) && !defined(NOKLDLOAD)
|
1999-09-22 00:40:47 +00:00
|
|
|
kldtried = 0;
|
|
|
|
#endif
|
1999-10-19 15:21:09 +00:00
|
|
|
for (bundle.unit = minunit; bundle.unit != maxunit; bundle.unit++) {
|
1998-05-21 21:49:08 +00:00
|
|
|
snprintf(bundle.dev.Name, sizeof bundle.dev.Name, "%s%d",
|
|
|
|
prefix, bundle.unit);
|
|
|
|
bundle.dev.fd = ID0open(bundle.dev.Name, O_RDWR);
|
|
|
|
if (bundle.dev.fd >= 0)
|
|
|
|
break;
|
|
|
|
else if (errno == ENXIO) {
|
1999-11-16 21:57:34 +00:00
|
|
|
#if defined(__FreeBSD__) && !defined(NOKLDLOAD)
|
1999-10-19 15:21:09 +00:00
|
|
|
if (bundle.unit == minunit && !kldtried++) {
|
1999-09-22 00:40:47 +00:00
|
|
|
/*
|
1999-11-16 21:57:34 +00:00
|
|
|
* Attempt to load the tunnel interface KLD if it isn't loaded
|
|
|
|
* already.
|
1999-09-22 00:40:47 +00:00
|
|
|
*/
|
1999-11-16 21:57:34 +00:00
|
|
|
if (modfind("if_tun") == -1) {
|
1999-09-22 00:40:47 +00:00
|
|
|
if (ID0kldload("if_tun") != -1) {
|
|
|
|
bundle.unit--;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
log_Printf(LogWARN, "kldload: if_tun: %s\n", strerror(errno));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
1998-05-21 21:49:08 +00:00
|
|
|
err = errno;
|
|
|
|
break;
|
|
|
|
} else if (errno == ENOENT) {
|
|
|
|
if (++enoentcount > 2)
|
|
|
|
break;
|
|
|
|
} else
|
|
|
|
err = errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bundle.dev.fd < 0) {
|
1999-10-19 15:21:09 +00:00
|
|
|
if (unit == -1)
|
|
|
|
log_Printf(LogWARN, "No available tunnel devices found (%s)\n",
|
|
|
|
strerror(err));
|
|
|
|
else
|
|
|
|
log_Printf(LogWARN, "%s%d: %s\n", prefix, unit, strerror(err));
|
1998-05-21 21:49:08 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
log_SetTun(bundle.unit);
|
|
|
|
|
1998-10-22 02:32:50 +00:00
|
|
|
ifname = strrchr(bundle.dev.Name, '/');
|
|
|
|
if (ifname == NULL)
|
|
|
|
ifname = bundle.dev.Name;
|
1998-05-21 21:49:08 +00:00
|
|
|
else
|
1998-10-22 02:32:50 +00:00
|
|
|
ifname++;
|
|
|
|
|
|
|
|
bundle.iface = iface_Create(ifname);
|
|
|
|
if (bundle.iface == NULL) {
|
|
|
|
close(bundle.dev.fd);
|
|
|
|
return NULL;
|
|
|
|
}
|
1998-05-21 21:49:08 +00:00
|
|
|
|
1999-03-25 11:37:51 +00:00
|
|
|
#ifdef TUNSIFMODE
|
|
|
|
/* Make sure we're POINTOPOINT */
|
|
|
|
iff = IFF_POINTOPOINT;
|
|
|
|
if (ID0ioctl(bundle.dev.fd, TUNSIFMODE, &iff) < 0)
|
|
|
|
log_Printf(LogERROR, "bundle_Create: ioctl(TUNSIFMODE): %s\n",
|
|
|
|
strerror(errno));
|
|
|
|
#endif
|
|
|
|
|
1999-06-22 11:31:42 +00:00
|
|
|
#ifdef TUNSLMODE
|
2000-01-23 01:48:19 +00:00
|
|
|
/* Make sure we're not prepending sockaddrs */
|
1999-06-22 11:31:42 +00:00
|
|
|
iff = 0;
|
|
|
|
if (ID0ioctl(bundle.dev.fd, TUNSLMODE, &iff) < 0)
|
|
|
|
log_Printf(LogERROR, "bundle_Create: ioctl(TUNSLMODE): %s\n",
|
|
|
|
strerror(errno));
|
|
|
|
#endif
|
|
|
|
|
2000-01-23 01:48:19 +00:00
|
|
|
#ifdef TUNSIFHEAD
|
|
|
|
/* We want the address family please ! */
|
|
|
|
iff = 1;
|
|
|
|
if (ID0ioctl(bundle.dev.fd, TUNSIFHEAD, &iff) < 0) {
|
|
|
|
log_Printf(LogERROR, "bundle_Create: ioctl(TUNSIFHEAD): %s\n",
|
|
|
|
strerror(errno));
|
|
|
|
bundle.dev.header = 0;
|
|
|
|
} else
|
|
|
|
bundle.dev.header = 1;
|
|
|
|
#else
|
|
|
|
#ifdef __OpenBSD__
|
|
|
|
/* Always present for OpenBSD */
|
|
|
|
bundle.dev.header = 1;
|
|
|
|
#else
|
|
|
|
/*
|
|
|
|
* If TUNSIFHEAD isn't available and we're not OpenBSD, assume
|
|
|
|
* everything's AF_INET (hopefully the tun device won't pass us
|
|
|
|
* anything else !).
|
|
|
|
*/
|
|
|
|
bundle.dev.header = 0;
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
1999-05-27 08:42:17 +00:00
|
|
|
if (!iface_SetFlags(bundle.iface, IFF_UP)) {
|
1998-10-22 02:32:50 +00:00
|
|
|
iface_Destroy(bundle.iface);
|
|
|
|
bundle.iface = NULL;
|
1998-05-21 21:49:08 +00:00
|
|
|
close(bundle.dev.fd);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
1998-10-22 02:32:50 +00:00
|
|
|
log_Printf(LogPHASE, "Using interface: %s\n", ifname);
|
1998-05-21 21:49:08 +00:00
|
|
|
|
1999-08-05 10:32:16 +00:00
|
|
|
bundle.bandwidth = 0;
|
1998-05-21 21:49:08 +00:00
|
|
|
bundle.routing_seq = 0;
|
|
|
|
bundle.phase = PHASE_DEAD;
|
|
|
|
bundle.CleaningUp = 0;
|
1999-08-19 18:15:52 +00:00
|
|
|
bundle.NatEnabled = 0;
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
bundle.fsm.LayerStart = bundle_LayerStart;
|
|
|
|
bundle.fsm.LayerUp = bundle_LayerUp;
|
|
|
|
bundle.fsm.LayerDown = bundle_LayerDown;
|
|
|
|
bundle.fsm.LayerFinish = bundle_LayerFinish;
|
|
|
|
bundle.fsm.object = &bundle;
|
|
|
|
|
1999-08-17 17:22:46 +00:00
|
|
|
bundle.cfg.idle.timeout = NCP_IDLE_TIMEOUT;
|
|
|
|
bundle.cfg.idle.min_timeout = 0;
|
1998-05-21 21:49:08 +00:00
|
|
|
*bundle.cfg.auth.name = '\0';
|
|
|
|
*bundle.cfg.auth.key = '\0';
|
|
|
|
bundle.cfg.opt = OPT_SROUTES | OPT_IDCHECK | OPT_LOOPBACK |
|
|
|
|
OPT_THROUGHPUT | OPT_UTMP;
|
|
|
|
*bundle.cfg.label = '\0';
|
|
|
|
bundle.cfg.mtu = DEF_MTU;
|
2000-06-11 02:30:51 +00:00
|
|
|
bundle.cfg.ifqueue = DEF_IFQUEUE;
|
1998-08-25 17:48:43 +00:00
|
|
|
bundle.cfg.choked.timeout = CHOKED_TIMEOUT;
|
1998-06-12 17:45:10 +00:00
|
|
|
bundle.phys_type.all = type;
|
|
|
|
bundle.phys_type.open = 0;
|
1999-08-17 17:22:46 +00:00
|
|
|
bundle.upat = 0;
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
bundle.links = datalink_Create("deflink", &bundle, type);
|
|
|
|
if (bundle.links == NULL) {
|
1998-06-16 19:40:42 +00:00
|
|
|
log_Printf(LogALERT, "Cannot create data link: %s\n", strerror(errno));
|
1998-10-22 02:32:50 +00:00
|
|
|
iface_Destroy(bundle.iface);
|
|
|
|
bundle.iface = NULL;
|
1998-05-21 21:49:08 +00:00
|
|
|
close(bundle.dev.fd);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bundle.desc.type = BUNDLE_DESCRIPTOR;
|
|
|
|
bundle.desc.UpdateSet = bundle_UpdateSet;
|
|
|
|
bundle.desc.IsSet = bundle_IsSet;
|
|
|
|
bundle.desc.Read = bundle_DescriptorRead;
|
|
|
|
bundle.desc.Write = bundle_DescriptorWrite;
|
|
|
|
|
|
|
|
mp_Init(&bundle.ncp.mp, &bundle);
|
|
|
|
|
|
|
|
/* Send over the first physical link by default */
|
|
|
|
ipcp_Init(&bundle.ncp.ipcp, &bundle, &bundle.links->physical->link,
|
|
|
|
&bundle.fsm);
|
|
|
|
|
|
|
|
memset(&bundle.filter, '\0', sizeof bundle.filter);
|
|
|
|
bundle.filter.in.fragok = bundle.filter.in.logok = 1;
|
|
|
|
bundle.filter.in.name = "IN";
|
|
|
|
bundle.filter.out.fragok = bundle.filter.out.logok = 1;
|
|
|
|
bundle.filter.out.name = "OUT";
|
|
|
|
bundle.filter.dial.name = "DIAL";
|
|
|
|
bundle.filter.dial.logok = 1;
|
|
|
|
bundle.filter.alive.name = "ALIVE";
|
|
|
|
bundle.filter.alive.logok = 1;
|
1999-07-27 23:44:00 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < MAXFILTERS; i++) {
|
|
|
|
bundle.filter.in.rule[i].f_action = A_NONE;
|
|
|
|
bundle.filter.out.rule[i].f_action = A_NONE;
|
|
|
|
bundle.filter.dial.rule[i].f_action = A_NONE;
|
|
|
|
bundle.filter.alive.rule[i].f_action = A_NONE;
|
|
|
|
}
|
|
|
|
}
|
1998-05-21 21:49:08 +00:00
|
|
|
memset(&bundle.idle.timer, '\0', sizeof bundle.idle.timer);
|
|
|
|
bundle.idle.done = 0;
|
|
|
|
bundle.notify.fd = -1;
|
1998-08-25 17:48:43 +00:00
|
|
|
memset(&bundle.choked.timer, '\0', sizeof bundle.choked.timer);
|
1999-01-28 01:56:34 +00:00
|
|
|
#ifndef NORADIUS
|
|
|
|
radius_Init(&bundle.radius);
|
|
|
|
#endif
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
/* Clean out any leftover crud */
|
1998-10-22 02:32:50 +00:00
|
|
|
iface_Clear(bundle.iface, IFACE_CLEAR_ALL);
|
1998-05-21 21:49:08 +00:00
|
|
|
|
1998-05-28 23:17:51 +00:00
|
|
|
bundle_LockTun(&bundle);
|
|
|
|
|
1998-05-21 21:49:08 +00:00
|
|
|
return &bundle;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bundle_DownInterface(struct bundle *bundle)
|
|
|
|
{
|
|
|
|
route_IfDelete(bundle, 1);
|
1999-05-27 08:42:17 +00:00
|
|
|
iface_ClearFlags(bundle->iface, IFF_UP);
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
bundle_Destroy(struct bundle *bundle)
|
|
|
|
{
|
|
|
|
struct datalink *dl;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Clean up the interface. We don't need to timer_Stop()s, mp_Down(),
|
|
|
|
* ipcp_CleanInterface() and bundle_DownInterface() unless we're getting
|
2000-03-14 01:47:07 +00:00
|
|
|
* out under exceptional conditions such as a descriptor exception.
|
1998-05-21 21:49:08 +00:00
|
|
|
*/
|
|
|
|
timer_Stop(&bundle->idle.timer);
|
1998-08-25 17:48:43 +00:00
|
|
|
timer_Stop(&bundle->choked.timer);
|
1998-05-21 21:49:08 +00:00
|
|
|
mp_Down(&bundle->ncp.mp);
|
|
|
|
ipcp_CleanInterface(&bundle->ncp.ipcp);
|
|
|
|
bundle_DownInterface(bundle);
|
1998-05-28 23:17:51 +00:00
|
|
|
|
1999-01-28 01:56:34 +00:00
|
|
|
#ifndef NORADIUS
|
|
|
|
/* Tell the radius server the bad news */
|
|
|
|
radius_Destroy(&bundle->radius);
|
|
|
|
#endif
|
|
|
|
|
1998-05-21 21:49:08 +00:00
|
|
|
/* Again, these are all DATALINK_CLOSED unless we're abending */
|
|
|
|
dl = bundle->links;
|
|
|
|
while (dl)
|
|
|
|
dl = datalink_Destroy(dl);
|
|
|
|
|
1999-09-04 00:00:21 +00:00
|
|
|
ipcp_Destroy(&bundle->ncp.ipcp);
|
|
|
|
|
1998-05-28 23:17:51 +00:00
|
|
|
close(bundle->dev.fd);
|
|
|
|
bundle_UnlockTun(bundle);
|
|
|
|
|
1998-05-21 21:49:08 +00:00
|
|
|
/* In case we never made PHASE_NETWORK */
|
|
|
|
bundle_Notify(bundle, EX_ERRDEAD);
|
|
|
|
|
1998-10-22 02:32:50 +00:00
|
|
|
iface_Destroy(bundle->iface);
|
|
|
|
bundle->iface = NULL;
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct rtmsg {
|
|
|
|
struct rt_msghdr m_rtm;
|
|
|
|
char m_space[64];
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
bundle_SetRoute(struct bundle *bundle, int cmd, struct in_addr dst,
|
1998-07-28 21:54:54 +00:00
|
|
|
struct in_addr gateway, struct in_addr mask, int bang, int ssh)
|
1998-05-21 21:49:08 +00:00
|
|
|
{
|
|
|
|
struct rtmsg rtmes;
|
|
|
|
int s, nb, wb;
|
|
|
|
char *cp;
|
|
|
|
const char *cmdstr;
|
|
|
|
struct sockaddr_in rtdata;
|
|
|
|
int result = 1;
|
|
|
|
|
|
|
|
if (bang)
|
|
|
|
cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!");
|
|
|
|
else
|
|
|
|
cmdstr = (cmd == RTM_ADD ? "Add" : "Delete");
|
|
|
|
s = ID0socket(PF_ROUTE, SOCK_RAW, 0);
|
|
|
|
if (s < 0) {
|
|
|
|
log_Printf(LogERROR, "bundle_SetRoute: socket(): %s\n", strerror(errno));
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
memset(&rtmes, '\0', sizeof rtmes);
|
|
|
|
rtmes.m_rtm.rtm_version = RTM_VERSION;
|
|
|
|
rtmes.m_rtm.rtm_type = cmd;
|
|
|
|
rtmes.m_rtm.rtm_addrs = RTA_DST;
|
|
|
|
rtmes.m_rtm.rtm_seq = ++bundle->routing_seq;
|
|
|
|
rtmes.m_rtm.rtm_pid = getpid();
|
|
|
|
rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
|
|
|
|
|
1998-10-26 19:07:39 +00:00
|
|
|
if (cmd == RTM_ADD || cmd == RTM_CHANGE) {
|
|
|
|
if (bundle->ncp.ipcp.cfg.sendpipe > 0) {
|
|
|
|
rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.ipcp.cfg.sendpipe;
|
|
|
|
rtmes.m_rtm.rtm_inits |= RTV_SPIPE;
|
|
|
|
}
|
|
|
|
if (bundle->ncp.ipcp.cfg.recvpipe > 0) {
|
|
|
|
rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.ipcp.cfg.recvpipe;
|
|
|
|
rtmes.m_rtm.rtm_inits |= RTV_RPIPE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-05-21 21:49:08 +00:00
|
|
|
memset(&rtdata, '\0', sizeof rtdata);
|
|
|
|
rtdata.sin_len = sizeof rtdata;
|
|
|
|
rtdata.sin_family = AF_INET;
|
|
|
|
rtdata.sin_port = 0;
|
|
|
|
rtdata.sin_addr = dst;
|
|
|
|
|
|
|
|
cp = rtmes.m_space;
|
|
|
|
memcpy(cp, &rtdata, rtdata.sin_len);
|
|
|
|
cp += rtdata.sin_len;
|
|
|
|
if (cmd == RTM_ADD) {
|
|
|
|
if (gateway.s_addr == INADDR_ANY) {
|
1999-01-06 00:08:03 +00:00
|
|
|
if (!ssh)
|
|
|
|
log_Printf(LogERROR, "bundle_SetRoute: Cannot add a route with"
|
|
|
|
" destination 0.0.0.0\n");
|
1998-10-22 02:32:50 +00:00
|
|
|
close(s);
|
|
|
|
return result;
|
1998-05-21 21:49:08 +00:00
|
|
|
} else {
|
|
|
|
rtdata.sin_addr = gateway;
|
|
|
|
memcpy(cp, &rtdata, rtdata.sin_len);
|
|
|
|
cp += rtdata.sin_len;
|
|
|
|
rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dst.s_addr == INADDR_ANY)
|
|
|
|
mask.s_addr = INADDR_ANY;
|
|
|
|
|
|
|
|
if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) {
|
|
|
|
rtdata.sin_addr = mask;
|
|
|
|
memcpy(cp, &rtdata, rtdata.sin_len);
|
|
|
|
cp += rtdata.sin_len;
|
|
|
|
rtmes.m_rtm.rtm_addrs |= RTA_NETMASK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nb = cp - (char *) &rtmes;
|
|
|
|
rtmes.m_rtm.rtm_msglen = nb;
|
|
|
|
wb = ID0write(s, &rtmes, nb);
|
|
|
|
if (wb < 0) {
|
|
|
|
log_Printf(LogTCPIP, "bundle_SetRoute failure:\n");
|
|
|
|
log_Printf(LogTCPIP, "bundle_SetRoute: Cmd = %s\n", cmdstr);
|
|
|
|
log_Printf(LogTCPIP, "bundle_SetRoute: Dst = %s\n", inet_ntoa(dst));
|
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
|
|
|
log_Printf(LogTCPIP, "bundle_SetRoute: Gateway = %s\n",
|
|
|
|
inet_ntoa(gateway));
|
1998-05-21 21:49:08 +00:00
|
|
|
log_Printf(LogTCPIP, "bundle_SetRoute: Mask = %s\n", inet_ntoa(mask));
|
|
|
|
failed:
|
|
|
|
if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST ||
|
|
|
|
(rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) {
|
|
|
|
if (!bang) {
|
|
|
|
log_Printf(LogWARN, "Add route failed: %s already exists\n",
|
1998-10-26 19:07:39 +00:00
|
|
|
dst.s_addr == 0 ? "default" : inet_ntoa(dst));
|
1998-05-21 21:49:08 +00:00
|
|
|
result = 0; /* Don't add to our dynamic list */
|
|
|
|
} else {
|
|
|
|
rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE;
|
|
|
|
if ((wb = ID0write(s, &rtmes, nb)) < 0)
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
} else if (cmd == RTM_DELETE &&
|
|
|
|
(rtmes.m_rtm.rtm_errno == ESRCH ||
|
|
|
|
(rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) {
|
|
|
|
if (!bang)
|
|
|
|
log_Printf(LogWARN, "Del route failed: %s: Non-existent\n",
|
|
|
|
inet_ntoa(dst));
|
1998-07-28 21:54:54 +00:00
|
|
|
} else if (rtmes.m_rtm.rtm_errno == 0) {
|
|
|
|
if (!ssh || errno != ENETUNREACH)
|
|
|
|
log_Printf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr,
|
|
|
|
inet_ntoa(dst), strerror(errno));
|
|
|
|
} else
|
1998-05-21 21:49:08 +00:00
|
|
|
log_Printf(LogWARN, "%s route failed: %s: %s\n",
|
1998-07-28 21:54:54 +00:00
|
|
|
cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno));
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n",
|
|
|
|
wb, cmdstr, (unsigned)dst.s_addr, (unsigned)gateway.s_addr);
|
|
|
|
close(s);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
bundle_LinkClosed(struct bundle *bundle, struct datalink *dl)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Our datalink has closed.
|
|
|
|
* CleanDatalinks() (called from DoLoop()) will remove closed
|
1999-11-28 15:50:08 +00:00
|
|
|
* BACKGROUND, FOREGROUND and DIRECT links.
|
1998-05-21 21:49:08 +00:00
|
|
|
* If it's the last data link, enter phase DEAD.
|
|
|
|
*
|
|
|
|
* NOTE: dl may not be in our list (bundle_SendDatalink()) !
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct datalink *odl;
|
|
|
|
int other_links;
|
|
|
|
|
1998-08-09 15:34:11 +00:00
|
|
|
log_SetTtyCommandMode(dl);
|
|
|
|
|
1998-05-21 21:49:08 +00:00
|
|
|
other_links = 0;
|
|
|
|
for (odl = bundle->links; odl; odl = odl->next)
|
|
|
|
if (odl != dl && odl->state != DATALINK_CLOSED)
|
|
|
|
other_links++;
|
|
|
|
|
|
|
|
if (!other_links) {
|
1998-05-29 18:32:11 +00:00
|
|
|
if (dl->physical->type != PHYS_AUTO) /* Not in -auto mode */
|
1998-05-21 21:49:08 +00:00
|
|
|
bundle_DownInterface(bundle);
|
1998-06-20 00:19:42 +00:00
|
|
|
fsm2initial(&bundle->ncp.ipcp.fsm);
|
1998-05-21 21:49:08 +00:00
|
|
|
bundle_NewPhase(bundle, PHASE_DEAD);
|
1998-05-23 22:24:50 +00:00
|
|
|
bundle_StopIdleTimer(bundle);
|
1999-08-05 10:32:16 +00:00
|
|
|
}
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1998-07-29 18:21:17 +00:00
|
|
|
bundle_Open(struct bundle *bundle, const char *name, int mask, int force)
|
1998-05-21 21:49:08 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Please open the given datalink, or all if name == NULL
|
|
|
|
*/
|
|
|
|
struct datalink *dl;
|
|
|
|
|
|
|
|
for (dl = bundle->links; dl; dl = dl->next)
|
|
|
|
if (name == NULL || !strcasecmp(dl->name, name)) {
|
1998-07-29 18:21:17 +00:00
|
|
|
if ((mask & dl->physical->type) &&
|
|
|
|
(dl->state == DATALINK_CLOSED ||
|
|
|
|
(force && dl->state == DATALINK_OPENING &&
|
2000-05-26 08:26:56 +00:00
|
|
|
dl->dial.timer.state == TIMER_RUNNING) ||
|
|
|
|
dl->state == DATALINK_READY)) {
|
|
|
|
timer_Stop(&dl->dial.timer); /* We're finished with this */
|
1998-05-21 21:49:08 +00:00
|
|
|
datalink_Up(dl, 1, 1);
|
1999-08-05 10:32:16 +00:00
|
|
|
if (mask & PHYS_AUTO)
|
2000-05-26 08:26:56 +00:00
|
|
|
break; /* Only one AUTO link at a time */
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
if (name != NULL)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct datalink *
|
|
|
|
bundle2datalink(struct bundle *bundle, const char *name)
|
|
|
|
{
|
|
|
|
struct datalink *dl;
|
|
|
|
|
|
|
|
if (name != NULL) {
|
|
|
|
for (dl = bundle->links; dl; dl = dl->next)
|
|
|
|
if (!strcasecmp(dl->name, name))
|
|
|
|
return dl;
|
|
|
|
} else if (bundle->links && !bundle->links->next)
|
|
|
|
return bundle->links;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
bundle_ShowLinks(struct cmdargs const *arg)
|
|
|
|
{
|
|
|
|
struct datalink *dl;
|
1999-08-05 10:32:16 +00:00
|
|
|
struct pppThroughput *t;
|
2000-08-15 10:25:42 +00:00
|
|
|
unsigned long long octets;
|
1999-08-05 10:32:16 +00:00
|
|
|
int secs;
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
for (dl = arg->bundle->links; dl; dl = dl->next) {
|
2000-08-15 10:25:42 +00:00
|
|
|
octets = MAX(dl->physical->link.stats.total.in.OctetsPerSecond,
|
|
|
|
dl->physical->link.stats.total.out.OctetsPerSecond);
|
|
|
|
|
1998-05-23 22:28:19 +00:00
|
|
|
prompt_Printf(arg->prompt, "Name: %s [%s, %s]",
|
|
|
|
dl->name, mode2Nam(dl->physical->type), datalink_State(dl));
|
2000-08-15 00:59:21 +00:00
|
|
|
if (dl->physical->link.stats.total.rolling && dl->state == DATALINK_OPEN)
|
1999-08-09 22:56:18 +00:00
|
|
|
prompt_Printf(arg->prompt, " bandwidth %d, %llu bps (%llu bytes/sec)",
|
1999-08-05 10:32:16 +00:00
|
|
|
dl->mp.bandwidth ? dl->mp.bandwidth :
|
|
|
|
physical_GetSpeed(dl->physical),
|
2000-08-15 10:25:42 +00:00
|
|
|
octets * 8, octets);
|
1998-05-21 21:49:08 +00:00
|
|
|
prompt_Printf(arg->prompt, "\n");
|
|
|
|
}
|
|
|
|
|
2000-08-15 00:59:21 +00:00
|
|
|
t = &arg->bundle->ncp.mp.link.stats.total;
|
2000-08-15 10:25:42 +00:00
|
|
|
octets = MAX(t->in.OctetsPerSecond, t->out.OctetsPerSecond);
|
1999-08-05 10:32:16 +00:00
|
|
|
secs = t->downtime ? 0 : throughput_uptime(t);
|
|
|
|
if (secs > t->SamplePeriod)
|
|
|
|
secs = t->SamplePeriod;
|
|
|
|
if (secs)
|
1999-08-09 22:56:18 +00:00
|
|
|
prompt_Printf(arg->prompt, "Currently averaging %llu bps (%llu bytes/sec)"
|
2000-08-15 10:25:42 +00:00
|
|
|
" over the last %d secs\n", octets * 8, octets, secs);
|
1999-08-05 10:32:16 +00:00
|
|
|
|
1998-05-21 21:49:08 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
optval(struct bundle *bundle, int bit)
|
|
|
|
{
|
|
|
|
return (bundle->cfg.opt & bit) ? "enabled" : "disabled";
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
bundle_ShowStatus(struct cmdargs const *arg)
|
|
|
|
{
|
|
|
|
int remaining;
|
|
|
|
|
|
|
|
prompt_Printf(arg->prompt, "Phase %s\n", bundle_PhaseName(arg->bundle));
|
|
|
|
prompt_Printf(arg->prompt, " Device: %s\n", arg->bundle->dev.Name);
|
1999-08-17 17:22:46 +00:00
|
|
|
prompt_Printf(arg->prompt, " Interface: %s @ %lubps",
|
1999-08-05 10:32:16 +00:00
|
|
|
arg->bundle->iface->name, arg->bundle->bandwidth);
|
1998-05-21 21:49:08 +00:00
|
|
|
|
1999-08-17 17:22:46 +00:00
|
|
|
if (arg->bundle->upat) {
|
|
|
|
int secs = time(NULL) - arg->bundle->upat;
|
|
|
|
|
|
|
|
prompt_Printf(arg->prompt, ", up time %d:%02d:%02d", secs / 3600,
|
|
|
|
(secs / 60) % 60, secs % 60);
|
|
|
|
}
|
2000-06-18 10:07:53 +00:00
|
|
|
prompt_Printf(arg->prompt, "\n Queued: %lu of %u\n",
|
2000-06-23 09:48:26 +00:00
|
|
|
(unsigned long)ip_QueueLen(&arg->bundle->ncp.ipcp),
|
|
|
|
arg->bundle->cfg.ifqueue);
|
1999-08-17 17:22:46 +00:00
|
|
|
|
2000-06-11 02:30:51 +00:00
|
|
|
prompt_Printf(arg->prompt, "\nDefaults:\n");
|
1998-05-21 21:49:08 +00:00
|
|
|
prompt_Printf(arg->prompt, " Label: %s\n", arg->bundle->cfg.label);
|
|
|
|
prompt_Printf(arg->prompt, " Auth name: %s\n",
|
|
|
|
arg->bundle->cfg.auth.name);
|
|
|
|
|
1998-08-25 17:48:43 +00:00
|
|
|
prompt_Printf(arg->prompt, " Choked Timer: %ds\n",
|
|
|
|
arg->bundle->cfg.choked.timeout);
|
1999-01-28 01:56:34 +00:00
|
|
|
|
|
|
|
#ifndef NORADIUS
|
|
|
|
radius_Show(&arg->bundle->radius, arg->prompt);
|
|
|
|
#endif
|
|
|
|
|
1998-05-21 21:49:08 +00:00
|
|
|
prompt_Printf(arg->prompt, " Idle Timer: ");
|
1999-08-17 17:22:46 +00:00
|
|
|
if (arg->bundle->cfg.idle.timeout) {
|
|
|
|
prompt_Printf(arg->prompt, "%ds", arg->bundle->cfg.idle.timeout);
|
|
|
|
if (arg->bundle->cfg.idle.min_timeout)
|
|
|
|
prompt_Printf(arg->prompt, ", min %ds",
|
|
|
|
arg->bundle->cfg.idle.min_timeout);
|
1998-05-21 21:49:08 +00:00
|
|
|
remaining = bundle_RemainingIdleTime(arg->bundle);
|
|
|
|
if (remaining != -1)
|
|
|
|
prompt_Printf(arg->prompt, " (%ds remaining)", remaining);
|
|
|
|
prompt_Printf(arg->prompt, "\n");
|
|
|
|
} else
|
|
|
|
prompt_Printf(arg->prompt, "disabled\n");
|
|
|
|
prompt_Printf(arg->prompt, " MTU: ");
|
|
|
|
if (arg->bundle->cfg.mtu)
|
|
|
|
prompt_Printf(arg->prompt, "%d\n", arg->bundle->cfg.mtu);
|
|
|
|
else
|
|
|
|
prompt_Printf(arg->prompt, "unspecified\n");
|
|
|
|
|
1998-10-26 19:07:39 +00:00
|
|
|
prompt_Printf(arg->prompt, " sendpipe: ");
|
|
|
|
if (arg->bundle->ncp.ipcp.cfg.sendpipe > 0)
|
1999-08-05 10:32:16 +00:00
|
|
|
prompt_Printf(arg->prompt, "%-20ld", arg->bundle->ncp.ipcp.cfg.sendpipe);
|
1998-10-26 19:07:39 +00:00
|
|
|
else
|
1999-08-05 10:32:16 +00:00
|
|
|
prompt_Printf(arg->prompt, "unspecified ");
|
1998-10-26 19:07:39 +00:00
|
|
|
prompt_Printf(arg->prompt, " recvpipe: ");
|
|
|
|
if (arg->bundle->ncp.ipcp.cfg.recvpipe > 0)
|
|
|
|
prompt_Printf(arg->prompt, "%ld\n", arg->bundle->ncp.ipcp.cfg.recvpipe);
|
|
|
|
else
|
|
|
|
prompt_Printf(arg->prompt, "unspecified\n");
|
|
|
|
|
1999-08-05 10:32:16 +00:00
|
|
|
prompt_Printf(arg->prompt, " Sticky Routes: %-20.20s",
|
1998-05-21 21:49:08 +00:00
|
|
|
optval(arg->bundle, OPT_SROUTES));
|
2000-07-07 14:22:08 +00:00
|
|
|
prompt_Printf(arg->prompt, " Filter Decap: %s\n",
|
|
|
|
optval(arg->bundle, OPT_FILTERDECAP));
|
|
|
|
prompt_Printf(arg->prompt, " ID check: %-20.20s",
|
1998-05-21 21:49:08 +00:00
|
|
|
optval(arg->bundle, OPT_IDCHECK));
|
2000-07-07 14:22:08 +00:00
|
|
|
prompt_Printf(arg->prompt, " Keep-Session: %s\n",
|
1999-06-02 00:46:55 +00:00
|
|
|
optval(arg->bundle, OPT_KEEPSESSION));
|
2000-07-07 14:22:08 +00:00
|
|
|
prompt_Printf(arg->prompt, " Loopback: %-20.20s",
|
1998-05-21 21:49:08 +00:00
|
|
|
optval(arg->bundle, OPT_LOOPBACK));
|
2000-07-07 14:22:08 +00:00
|
|
|
prompt_Printf(arg->prompt, " PasswdAuth: %s\n",
|
1998-05-21 21:49:08 +00:00
|
|
|
optval(arg->bundle, OPT_PASSWDAUTH));
|
2000-07-07 14:22:08 +00:00
|
|
|
prompt_Printf(arg->prompt, " Proxy: %-20.20s",
|
1998-05-21 21:49:08 +00:00
|
|
|
optval(arg->bundle, OPT_PROXY));
|
2000-07-07 14:22:08 +00:00
|
|
|
prompt_Printf(arg->prompt, " Proxyall: %s\n",
|
1998-10-26 19:07:39 +00:00
|
|
|
optval(arg->bundle, OPT_PROXYALL));
|
2000-07-07 14:22:08 +00:00
|
|
|
prompt_Printf(arg->prompt, " Throughput: %-20.20s",
|
1998-05-21 21:49:08 +00:00
|
|
|
optval(arg->bundle, OPT_THROUGHPUT));
|
2000-07-07 14:22:08 +00:00
|
|
|
prompt_Printf(arg->prompt, " Utmp Logging: %s\n",
|
1998-05-21 21:49:08 +00:00
|
|
|
optval(arg->bundle, OPT_UTMP));
|
1998-10-22 02:32:50 +00:00
|
|
|
prompt_Printf(arg->prompt, " Iface-Alias: %s\n",
|
|
|
|
optval(arg->bundle, OPT_IFACEALIAS));
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bundle_IdleTimeout(void *v)
|
|
|
|
{
|
|
|
|
struct bundle *bundle = (struct bundle *)v;
|
|
|
|
|
2000-04-07 23:46:14 +00:00
|
|
|
log_Printf(LogPHASE, "Idle timer expired\n");
|
1998-05-21 21:49:08 +00:00
|
|
|
bundle_StopIdleTimer(bundle);
|
1998-06-15 19:05:27 +00:00
|
|
|
bundle_Close(bundle, NULL, CLOSE_STAYDOWN);
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Start Idle timer. If timeout is reached, we call bundle_Close() to
|
|
|
|
* close LCP and link.
|
|
|
|
*/
|
|
|
|
void
|
2000-07-11 22:11:36 +00:00
|
|
|
bundle_StartIdleTimer(struct bundle *bundle, unsigned secs)
|
1998-05-21 21:49:08 +00:00
|
|
|
{
|
|
|
|
timer_Stop(&bundle->idle.timer);
|
1998-06-12 17:45:10 +00:00
|
|
|
if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) !=
|
1999-08-17 17:22:46 +00:00
|
|
|
bundle->phys_type.open && bundle->cfg.idle.timeout) {
|
2000-07-11 22:11:36 +00:00
|
|
|
time_t now = time(NULL);
|
|
|
|
|
|
|
|
if (secs == 0)
|
|
|
|
secs = bundle->cfg.idle.timeout;
|
1999-08-17 17:22:46 +00:00
|
|
|
|
2000-07-11 22:11:36 +00:00
|
|
|
/* We want at least `secs' */
|
1999-08-17 17:22:46 +00:00
|
|
|
if (bundle->cfg.idle.min_timeout > secs && bundle->upat) {
|
2000-07-11 22:11:36 +00:00
|
|
|
int up = now - bundle->upat;
|
1999-08-17 17:22:46 +00:00
|
|
|
|
|
|
|
if ((long long)bundle->cfg.idle.min_timeout - up > (long long)secs)
|
2000-07-11 22:11:36 +00:00
|
|
|
/* Only increase from the current `remaining' value */
|
1999-08-17 17:22:46 +00:00
|
|
|
secs = bundle->cfg.idle.min_timeout - up;
|
|
|
|
}
|
1998-05-21 21:49:08 +00:00
|
|
|
bundle->idle.timer.func = bundle_IdleTimeout;
|
|
|
|
bundle->idle.timer.name = "idle";
|
1999-08-17 17:22:46 +00:00
|
|
|
bundle->idle.timer.load = secs * SECTICKS;
|
1998-05-21 21:49:08 +00:00
|
|
|
bundle->idle.timer.arg = bundle;
|
|
|
|
timer_Start(&bundle->idle.timer);
|
2000-07-11 22:11:36 +00:00
|
|
|
bundle->idle.done = now + secs;
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-08-17 17:22:46 +00:00
|
|
|
bundle_SetIdleTimer(struct bundle *bundle, int timeout, int min_timeout)
|
1998-05-21 21:49:08 +00:00
|
|
|
{
|
1999-08-17 17:22:46 +00:00
|
|
|
bundle->cfg.idle.timeout = timeout;
|
|
|
|
if (min_timeout >= 0)
|
|
|
|
bundle->cfg.idle.min_timeout = min_timeout;
|
1998-05-21 21:49:08 +00:00
|
|
|
if (bundle_LinkIsUp(bundle))
|
2000-07-11 22:11:36 +00:00
|
|
|
bundle_StartIdleTimer(bundle, 0);
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
bundle_StopIdleTimer(struct bundle *bundle)
|
|
|
|
{
|
|
|
|
timer_Stop(&bundle->idle.timer);
|
|
|
|
bundle->idle.done = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
bundle_RemainingIdleTime(struct bundle *bundle)
|
|
|
|
{
|
|
|
|
if (bundle->idle.done)
|
|
|
|
return bundle->idle.done - time(NULL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
bundle_IsDead(struct bundle *bundle)
|
|
|
|
{
|
|
|
|
return !bundle->links || (bundle->phase == PHASE_DEAD && bundle->CleaningUp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct datalink *
|
|
|
|
bundle_DatalinkLinkout(struct bundle *bundle, struct datalink *dl)
|
|
|
|
{
|
|
|
|
struct datalink **dlp;
|
|
|
|
|
1998-05-23 22:24:50 +00:00
|
|
|
for (dlp = &bundle->links; *dlp; dlp = &(*dlp)->next)
|
|
|
|
if (*dlp == dl) {
|
|
|
|
*dlp = dl->next;
|
|
|
|
dl->next = NULL;
|
|
|
|
bundle_LinksRemoved(bundle);
|
|
|
|
return dl;
|
|
|
|
}
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bundle_DatalinkLinkin(struct bundle *bundle, struct datalink *dl)
|
|
|
|
{
|
|
|
|
struct datalink **dlp = &bundle->links;
|
|
|
|
|
|
|
|
while (*dlp)
|
|
|
|
dlp = &(*dlp)->next;
|
|
|
|
|
|
|
|
*dlp = dl;
|
|
|
|
dl->next = NULL;
|
|
|
|
|
|
|
|
bundle_LinkAdded(bundle, dl);
|
1999-08-05 10:32:16 +00:00
|
|
|
mp_CheckAutoloadTimer(&bundle->ncp.mp);
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
bundle_CleanDatalinks(struct bundle *bundle)
|
|
|
|
{
|
|
|
|
struct datalink **dlp = &bundle->links;
|
|
|
|
int found = 0;
|
|
|
|
|
|
|
|
while (*dlp)
|
|
|
|
if ((*dlp)->state == DATALINK_CLOSED &&
|
1999-11-28 15:50:08 +00:00
|
|
|
(*dlp)->physical->type &
|
|
|
|
(PHYS_DIRECT|PHYS_BACKGROUND|PHYS_FOREGROUND)) {
|
1998-05-21 21:49:08 +00:00
|
|
|
*dlp = datalink_Destroy(*dlp);
|
|
|
|
found++;
|
|
|
|
} else
|
|
|
|
dlp = &(*dlp)->next;
|
|
|
|
|
|
|
|
if (found)
|
|
|
|
bundle_LinksRemoved(bundle);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
bundle_DatalinkClone(struct bundle *bundle, struct datalink *dl,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
if (bundle2datalink(bundle, name)) {
|
|
|
|
log_Printf(LogWARN, "Clone: %s: name already exists\n", name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bundle_DatalinkLinkin(bundle, datalink_Clone(dl, name));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
bundle_DatalinkRemove(struct bundle *bundle, struct datalink *dl)
|
|
|
|
{
|
|
|
|
dl = bundle_DatalinkLinkout(bundle, dl);
|
|
|
|
if (dl)
|
|
|
|
datalink_Destroy(dl);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
bundle_SetLabel(struct bundle *bundle, const char *label)
|
|
|
|
{
|
|
|
|
if (label)
|
|
|
|
strncpy(bundle->cfg.label, label, sizeof bundle->cfg.label - 1);
|
|
|
|
else
|
|
|
|
*bundle->cfg.label = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *
|
|
|
|
bundle_GetLabel(struct bundle *bundle)
|
|
|
|
{
|
|
|
|
return *bundle->cfg.label ? bundle->cfg.label : NULL;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
bundle_LinkSize()
|
|
|
|
{
|
|
|
|
struct iovec iov[SCATTER_SEGMENTS];
|
|
|
|
int niov, expect, f;
|
|
|
|
|
|
|
|
iov[0].iov_len = strlen(Version) + 1;
|
|
|
|
iov[0].iov_base = NULL;
|
|
|
|
niov = 1;
|
|
|
|
if (datalink2iov(NULL, iov, &niov, SCATTER_SEGMENTS, NULL, NULL) == -1) {
|
|
|
|
log_Printf(LogERROR, "Cannot determine space required for link\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (f = expect = 0; f < niov; f++)
|
|
|
|
expect += iov[f].iov_len;
|
|
|
|
|
|
|
|
return expect;
|
|
|
|
}
|
|
|
|
|
1998-05-21 21:49:08 +00:00
|
|
|
void
|
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
|
|
|
bundle_ReceiveDatalink(struct bundle *bundle, int s)
|
1998-05-21 21:49:08 +00:00
|
|
|
{
|
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
|
|
|
char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int) * SEND_MAXFD];
|
1999-11-30 23:52:37 +00:00
|
|
|
int niov, expect, f, *fd, nfd, onfd, got;
|
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
|
|
|
struct iovec iov[SCATTER_SEGMENTS];
|
1999-11-06 22:50:59 +00:00
|
|
|
struct cmsghdr *cmsg;
|
1998-05-21 21:49:08 +00:00
|
|
|
struct msghdr msg;
|
|
|
|
struct datalink *dl;
|
1998-05-28 23:15:40 +00:00
|
|
|
pid_t pid;
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
log_Printf(LogPHASE, "Receiving datalink\n");
|
|
|
|
|
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
|
|
|
/*
|
|
|
|
* Create our scatter/gather array - passing NULL gets the space
|
|
|
|
* allocation requirement rather than actually flattening the
|
|
|
|
* structures.
|
|
|
|
*/
|
1998-05-21 21:49:08 +00:00
|
|
|
iov[0].iov_len = strlen(Version) + 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[0].iov_base = NULL;
|
|
|
|
niov = 1;
|
|
|
|
if (datalink2iov(NULL, iov, &niov, SCATTER_SEGMENTS, NULL, NULL) == -1) {
|
|
|
|
log_Printf(LogERROR, "Cannot determine space required for link\n");
|
1998-05-21 21:49:08 +00:00
|
|
|
return;
|
1998-05-25 02:22:38 +00:00
|
|
|
}
|
1998-05-21 21:49:08 +00:00
|
|
|
|
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
|
|
|
/* Allocate the scatter/gather array for recvmsg() */
|
|
|
|
for (f = expect = 0; f < niov; f++) {
|
|
|
|
if ((iov[f].iov_base = malloc(iov[f].iov_len)) == NULL) {
|
|
|
|
log_Printf(LogERROR, "Cannot allocate space to receive link\n");
|
|
|
|
return;
|
|
|
|
}
|
1999-11-30 23:52:37 +00:00
|
|
|
if (f)
|
|
|
|
expect += iov[f].iov_len;
|
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
|
|
|
}
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
/* Set up our message */
|
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
|
|
|
cmsg = (struct cmsghdr *)cmsgbuf;
|
|
|
|
cmsg->cmsg_len = sizeof cmsgbuf;
|
|
|
|
cmsg->cmsg_level = SOL_SOCKET;
|
|
|
|
cmsg->cmsg_type = 0;
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
memset(&msg, '\0', sizeof msg);
|
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
|
|
|
msg.msg_name = NULL;
|
|
|
|
msg.msg_namelen = 0;
|
1998-05-21 21:49:08 +00:00
|
|
|
msg.msg_iov = iov;
|
1999-11-30 23:52:37 +00:00
|
|
|
msg.msg_iovlen = 1; /* Only send the version at the first pass */
|
1998-05-21 21:49:08 +00:00
|
|
|
msg.msg_control = cmsgbuf;
|
|
|
|
msg.msg_controllen = sizeof cmsgbuf;
|
|
|
|
|
2000-03-14 01:47:19 +00:00
|
|
|
log_Printf(LogDEBUG, "Expecting %u scatter/gather bytes\n",
|
|
|
|
(unsigned)iov[0].iov_len);
|
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
|
|
|
|
1999-11-30 23:52:37 +00:00
|
|
|
if ((got = recvmsg(s, &msg, MSG_WAITALL)) != iov[0].iov_len) {
|
|
|
|
if (got == -1)
|
1998-05-21 21:49:08 +00:00
|
|
|
log_Printf(LogERROR, "Failed recvmsg: %s\n", strerror(errno));
|
|
|
|
else
|
2000-03-14 01:47:19 +00:00
|
|
|
log_Printf(LogERROR, "Failed recvmsg: Got %d, not %u\n",
|
|
|
|
got, (unsigned)iov[0].iov_len);
|
1998-05-21 21:49:08 +00:00
|
|
|
while (niov--)
|
|
|
|
free(iov[niov].iov_base);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
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 (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
|
|
|
|
log_Printf(LogERROR, "Recvmsg: no descriptors received !\n");
|
|
|
|
while (niov--)
|
|
|
|
free(iov[niov].iov_base);
|
|
|
|
return;
|
1999-11-06 22:50:59 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
fd = (int *)(cmsg + 1);
|
|
|
|
nfd = (cmsg->cmsg_len - sizeof *cmsg) / sizeof(int);
|
|
|
|
|
|
|
|
if (nfd < 2) {
|
2000-03-14 01:47:07 +00:00
|
|
|
log_Printf(LogERROR, "Recvmsg: %d descriptor%s received (too few) !\n",
|
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
|
|
|
nfd, nfd == 1 ? "" : "s");
|
|
|
|
while (nfd--)
|
|
|
|
close(fd[nfd]);
|
1998-06-18 23:38:04 +00:00
|
|
|
while (niov--)
|
|
|
|
free(iov[niov].iov_base);
|
|
|
|
return;
|
1998-05-25 02:22:38 +00:00
|
|
|
}
|
1998-05-21 21:49:08 +00:00
|
|
|
|
1999-11-06 22:50:59 +00:00
|
|
|
/*
|
1999-11-30 23:52:37 +00:00
|
|
|
* We've successfully received two or more open file descriptors
|
|
|
|
* through our socket, plus a version string. Make sure it's the
|
|
|
|
* correct version, and drop the connection if it's not.
|
1999-11-06 22:50:59 +00:00
|
|
|
*/
|
1998-05-21 21:49:08 +00:00
|
|
|
if (strncmp(Version, iov[0].iov_base, iov[0].iov_len)) {
|
|
|
|
log_Printf(LogWARN, "Cannot receive datalink, incorrect version"
|
|
|
|
" (\"%.*s\", not \"%s\")\n", (int)iov[0].iov_len,
|
1998-06-27 12:03:46 +00:00
|
|
|
(char *)iov[0].iov_base, Version);
|
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
|
|
|
while (nfd--)
|
|
|
|
close(fd[nfd]);
|
1998-05-21 21:49:08 +00:00
|
|
|
while (niov--)
|
|
|
|
free(iov[niov].iov_base);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-11-30 23:52:37 +00:00
|
|
|
/*
|
|
|
|
* Everything looks good. Send the other side our process id so that
|
|
|
|
* they can transfer lock ownership, and wait for them to send the
|
|
|
|
* actual link data.
|
|
|
|
*/
|
|
|
|
pid = getpid();
|
|
|
|
if ((got = write(fd[1], &pid, sizeof pid)) != sizeof pid) {
|
|
|
|
if (got == -1)
|
|
|
|
log_Printf(LogERROR, "Failed write: %s\n", strerror(errno));
|
|
|
|
else
|
|
|
|
log_Printf(LogERROR, "Failed write: Got %d, not %d\n", got,
|
|
|
|
(int)(sizeof pid));
|
|
|
|
while (nfd--)
|
|
|
|
close(fd[nfd]);
|
|
|
|
while (niov--)
|
|
|
|
free(iov[niov].iov_base);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((got = readv(fd[1], iov + 1, niov - 1)) != expect) {
|
|
|
|
if (got == -1)
|
|
|
|
log_Printf(LogERROR, "Failed write: %s\n", strerror(errno));
|
|
|
|
else
|
|
|
|
log_Printf(LogERROR, "Failed write: Got %d, not %d\n", got, expect);
|
|
|
|
while (nfd--)
|
|
|
|
close(fd[nfd]);
|
|
|
|
while (niov--)
|
|
|
|
free(iov[niov].iov_base);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
close(fd[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
|
|
|
onfd = nfd; /* We've got this many in our array */
|
2000-03-14 01:47:07 +00:00
|
|
|
nfd -= 2; /* Don't include p->fd and our reply descriptor */
|
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
|
|
|
niov = 1; /* Skip the version id */
|
1999-11-06 22:50:59 +00:00
|
|
|
dl = iov2datalink(bundle, iov, &niov, sizeof iov / sizeof *iov, 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
|
|
|
fd + 2, &nfd);
|
1998-05-21 21:49:08 +00:00
|
|
|
if (dl) {
|
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
|
|
|
|
1999-11-06 22:50:59 +00:00
|
|
|
if (nfd) {
|
|
|
|
log_Printf(LogERROR, "bundle_ReceiveDatalink: Failed to handle %d "
|
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
|
|
|
"auxiliary file descriptors (%d remain)\n", onfd, nfd);
|
1999-11-06 22:50:59 +00:00
|
|
|
datalink_Destroy(dl);
|
|
|
|
while (nfd--)
|
|
|
|
close(fd[onfd--]);
|
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
|
|
|
close(fd[0]);
|
1999-11-06 22:50:59 +00:00
|
|
|
} else {
|
|
|
|
bundle_DatalinkLinkin(bundle, dl);
|
|
|
|
datalink_AuthOk(dl);
|
|
|
|
bundle_CalculateBandwidth(dl->bundle);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
while (nfd--)
|
|
|
|
close(fd[onfd--]);
|
|
|
|
close(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
|
|
|
close(fd[1]);
|
1999-11-06 22:50:59 +00:00
|
|
|
}
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
free(iov[0].iov_base);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
bundle_SendDatalink(struct datalink *dl, int s, struct sockaddr_un *sun)
|
|
|
|
{
|
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
|
|
|
char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int) * SEND_MAXFD];
|
|
|
|
const char *constlock;
|
|
|
|
char *lock;
|
1999-11-06 22:50:59 +00:00
|
|
|
struct cmsghdr *cmsg;
|
1998-05-21 21:49:08 +00:00
|
|
|
struct msghdr msg;
|
|
|
|
struct iovec iov[SCATTER_SEGMENTS];
|
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 niov, f, expect, newsid, fd[SEND_MAXFD], nfd, reply[2], got;
|
1998-05-28 23:15:40 +00:00
|
|
|
pid_t newpid;
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
log_Printf(LogPHASE, "Transmitting datalink %s\n", dl->name);
|
|
|
|
|
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
|
|
|
/* Record the base device name for a lock transfer later */
|
|
|
|
constlock = physical_LockedDevice(dl->physical);
|
|
|
|
if (constlock) {
|
|
|
|
lock = alloca(strlen(constlock) + 1);
|
|
|
|
strcpy(lock, constlock);
|
|
|
|
} else
|
|
|
|
lock = NULL;
|
|
|
|
|
1998-05-21 21:49:08 +00:00
|
|
|
bundle_LinkClosed(dl->bundle, dl);
|
1998-05-23 22:24:50 +00:00
|
|
|
bundle_DatalinkLinkout(dl->bundle, dl);
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
/* Build our scatter/gather array */
|
|
|
|
iov[0].iov_len = strlen(Version) + 1;
|
|
|
|
iov[0].iov_base = strdup(Version);
|
|
|
|
niov = 1;
|
1999-11-06 22:50:59 +00:00
|
|
|
nfd = 0;
|
1998-05-21 21:49:08 +00:00
|
|
|
|
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
|
|
|
fd[0] = datalink2iov(dl, iov, &niov, SCATTER_SEGMENTS, fd + 2, &nfd);
|
1999-11-06 22:50:59 +00:00
|
|
|
|
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 (fd[0] != -1 && socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, reply) != -1) {
|
|
|
|
/*
|
|
|
|
* fd[1] is used to get the peer process id back, then to confirm that
|
|
|
|
* we've transferred any device locks to that process id.
|
|
|
|
*/
|
|
|
|
fd[1] = reply[1];
|
1998-05-21 21:49:08 +00:00
|
|
|
|
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
|
|
|
nfd += 2; /* Include fd[0] and fd[1] */
|
1998-05-21 21:49:08 +00:00
|
|
|
memset(&msg, '\0', sizeof msg);
|
1998-05-25 02:22:38 +00:00
|
|
|
|
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
|
|
|
msg.msg_name = NULL;
|
|
|
|
msg.msg_namelen = 0;
|
1999-11-30 23:52:37 +00:00
|
|
|
/*
|
|
|
|
* Only send the version to start... We used to send the whole lot, but
|
|
|
|
* this caused problems with our RECVBUF size as a single link is about
|
|
|
|
* 22k ! This way, we should bump into no limits.
|
|
|
|
*/
|
|
|
|
msg.msg_iovlen = 1;
|
1998-05-21 21:49:08 +00:00
|
|
|
msg.msg_iov = iov;
|
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
|
|
|
msg.msg_control = cmsgbuf;
|
|
|
|
msg.msg_controllen = sizeof *cmsg + sizeof(int) * nfd;
|
|
|
|
msg.msg_flags = 0;
|
1998-05-25 02:22:38 +00:00
|
|
|
|
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
|
|
|
cmsg = (struct cmsghdr *)cmsgbuf;
|
|
|
|
cmsg->cmsg_len = msg.msg_controllen;
|
|
|
|
cmsg->cmsg_level = SOL_SOCKET;
|
|
|
|
cmsg->cmsg_type = SCM_RIGHTS;
|
1999-11-06 22:50:59 +00:00
|
|
|
|
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
|
|
|
for (f = 0; f < nfd; f++)
|
|
|
|
*((int *)(cmsg + 1) + f) = fd[f];
|
1998-05-21 21:49:08 +00:00
|
|
|
|
1999-11-30 23:52:37 +00:00
|
|
|
for (f = 1, expect = 0; f < niov; f++)
|
1998-05-21 21:49:08 +00:00
|
|
|
expect += iov[f].iov_len;
|
|
|
|
|
1999-11-30 23:52:37 +00:00
|
|
|
if (setsockopt(reply[0], SOL_SOCKET, SO_SNDBUF, &expect, sizeof(int)) == -1)
|
|
|
|
log_Printf(LogERROR, "setsockopt(SO_RCVBUF, %d): %s\n", expect,
|
|
|
|
strerror(errno));
|
|
|
|
if (setsockopt(reply[1], SOL_SOCKET, SO_RCVBUF, &expect, sizeof(int)) == -1)
|
|
|
|
log_Printf(LogERROR, "setsockopt(SO_RCVBUF, %d): %s\n", expect,
|
|
|
|
strerror(errno));
|
|
|
|
|
2000-03-14 01:47:19 +00:00
|
|
|
log_Printf(LogDEBUG, "Sending %d descriptor%s and %u bytes in scatter"
|
|
|
|
"/gather array\n", nfd, nfd == 1 ? "" : "s",
|
|
|
|
(unsigned)iov[0].iov_len);
|
1998-05-21 21:49:08 +00:00
|
|
|
|
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 ((got = sendmsg(s, &msg, 0)) == -1)
|
|
|
|
log_Printf(LogERROR, "Failed sendmsg: %s: %s\n",
|
|
|
|
sun->sun_path, strerror(errno));
|
1999-11-30 23:52:37 +00:00
|
|
|
else if (got != iov[0].iov_len)
|
2000-03-14 01:47:19 +00:00
|
|
|
log_Printf(LogERROR, "%s: Failed initial sendmsg: Only sent %d of %u\n",
|
|
|
|
sun->sun_path, got, (unsigned)iov[0].iov_len);
|
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
|
|
|
else {
|
2000-03-14 01:47:07 +00:00
|
|
|
/* We must get the ACK before closing the descriptor ! */
|
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 res;
|
|
|
|
|
1999-11-30 23:52:37 +00:00
|
|
|
if ((got = read(reply[0], &newpid, sizeof newpid)) == sizeof newpid) {
|
|
|
|
log_Printf(LogDEBUG, "Received confirmation from pid %d\n",
|
|
|
|
(int)newpid);
|
|
|
|
if (lock && (res = ID0uu_lock_txfr(lock, newpid)) != UU_LOCK_OK)
|
2000-04-07 23:46:14 +00:00
|
|
|
log_Printf(LogERROR, "uu_lock_txfr: %s\n", uu_lockerr(res));
|
1999-11-30 23:52:37 +00:00
|
|
|
|
|
|
|
log_Printf(LogDEBUG, "Transmitting link (%d bytes)\n", expect);
|
|
|
|
if ((got = writev(reply[0], iov + 1, niov - 1)) != expect) {
|
|
|
|
if (got == -1)
|
|
|
|
log_Printf(LogERROR, "%s: Failed writev: %s\n",
|
|
|
|
sun->sun_path, strerror(errno));
|
|
|
|
else
|
|
|
|
log_Printf(LogERROR, "%s: Failed writev: Wrote %d of %d\n",
|
|
|
|
sun->sun_path, got, expect);
|
|
|
|
}
|
|
|
|
} else if (got == -1)
|
|
|
|
log_Printf(LogERROR, "%s: Failed socketpair read: %s\n",
|
|
|
|
sun->sun_path, strerror(errno));
|
|
|
|
else
|
|
|
|
log_Printf(LogERROR, "%s: Failed socketpair read: Got %d of %d\n",
|
|
|
|
sun->sun_path, got, (int)(sizeof 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
|
|
|
}
|
|
|
|
|
|
|
|
close(reply[0]);
|
|
|
|
close(reply[1]);
|
1998-05-25 02:22:38 +00:00
|
|
|
|
1999-06-02 00:46:55 +00:00
|
|
|
newsid = Enabled(dl->bundle, OPT_KEEPSESSION) ||
|
1999-11-06 22:50:59 +00:00
|
|
|
tcgetpgrp(fd[0]) == getpgrp();
|
|
|
|
while (nfd)
|
|
|
|
close(fd[--nfd]);
|
1998-05-28 23:17:51 +00:00
|
|
|
if (newsid)
|
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
|
|
|
bundle_setsid(dl->bundle, got != -1);
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
1998-05-28 23:15:40 +00:00
|
|
|
close(s);
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
while (niov--)
|
|
|
|
free(iov[niov].iov_base);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
bundle_RenameDatalink(struct bundle *bundle, struct datalink *ndl,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
struct datalink *dl;
|
|
|
|
|
|
|
|
if (!strcasecmp(ndl->name, name))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
for (dl = bundle->links; dl; dl = dl->next)
|
|
|
|
if (!strcasecmp(dl->name, name))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
datalink_Rename(ndl, name);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
bundle_SetMode(struct bundle *bundle, struct datalink *dl, int mode)
|
|
|
|
{
|
|
|
|
int omode;
|
|
|
|
|
|
|
|
omode = dl->physical->type;
|
|
|
|
if (omode == mode)
|
|
|
|
return 1;
|
|
|
|
|
1998-06-12 17:45:10 +00:00
|
|
|
if (mode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO))
|
|
|
|
/* First auto link */
|
1998-05-21 21:49:08 +00:00
|
|
|
if (bundle->ncp.ipcp.peer_ip.s_addr == INADDR_ANY) {
|
1998-06-12 17:45:10 +00:00
|
|
|
log_Printf(LogWARN, "You must `set ifaddr' or `open' before"
|
|
|
|
" changing mode to %s\n", mode2Nam(mode));
|
1998-05-21 21:49:08 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!datalink_SetMode(dl, mode))
|
|
|
|
return 0;
|
|
|
|
|
1998-06-12 17:45:10 +00:00
|
|
|
if (mode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO) &&
|
|
|
|
bundle->phase != PHASE_NETWORK)
|
|
|
|
/* First auto link, we need an interface */
|
1998-05-21 21:49:08 +00:00
|
|
|
ipcp_InterfaceUp(&bundle->ncp.ipcp);
|
|
|
|
|
1999-08-05 10:32:16 +00:00
|
|
|
/* Regenerate phys_type and adjust idle timer */
|
1998-05-21 21:49:08 +00:00
|
|
|
bundle_LinksRemoved(bundle);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
1998-05-28 23:17:51 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
bundle_setsid(struct bundle *bundle, int holdsession)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Lose the current session. This means getting rid of our pid
|
|
|
|
* too so that the tty device will really go away, and any getty
|
|
|
|
* etc will be allowed to restart.
|
|
|
|
*/
|
|
|
|
pid_t pid, orig;
|
|
|
|
int fds[2];
|
|
|
|
char done;
|
|
|
|
struct datalink *dl;
|
|
|
|
|
1999-12-23 21:43:25 +00:00
|
|
|
if (!holdsession && bundle_IsDead(bundle)) {
|
|
|
|
/*
|
|
|
|
* No need to lose our session after all... we're going away anyway
|
|
|
|
*
|
|
|
|
* We should really stop the timer and pause if holdsession is set and
|
|
|
|
* the bundle's dead, but that leaves other resources lying about :-(
|
|
|
|
*/
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1998-05-28 23:17:51 +00:00
|
|
|
orig = getpid();
|
|
|
|
if (pipe(fds) == -1) {
|
|
|
|
log_Printf(LogERROR, "pipe: %s\n", strerror(errno));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
switch ((pid = fork())) {
|
|
|
|
case -1:
|
|
|
|
log_Printf(LogERROR, "fork: %s\n", strerror(errno));
|
|
|
|
close(fds[0]);
|
|
|
|
close(fds[1]);
|
|
|
|
return;
|
|
|
|
case 0:
|
|
|
|
close(fds[1]);
|
1999-03-07 01:41:40 +00:00
|
|
|
read(fds[0], &done, 1); /* uu_locks are mine ! */
|
|
|
|
close(fds[0]);
|
1998-05-28 23:17:51 +00:00
|
|
|
if (pipe(fds) == -1) {
|
|
|
|
log_Printf(LogERROR, "pipe(2): %s\n", strerror(errno));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
switch ((pid = fork())) {
|
|
|
|
case -1:
|
1998-06-16 19:40:42 +00:00
|
|
|
log_Printf(LogERROR, "fork(2): %s\n", strerror(errno));
|
1998-05-28 23:17:51 +00:00
|
|
|
close(fds[0]);
|
|
|
|
close(fds[1]);
|
|
|
|
return;
|
|
|
|
case 0:
|
|
|
|
close(fds[1]);
|
1999-03-07 01:41:40 +00:00
|
|
|
bundle_LockTun(bundle); /* update pid */
|
|
|
|
read(fds[0], &done, 1); /* uu_locks are mine ! */
|
|
|
|
close(fds[0]);
|
1998-05-28 23:17:51 +00:00
|
|
|
setsid();
|
2000-01-21 00:33:27 +00:00
|
|
|
bundle_ChangedPID(bundle);
|
2000-04-07 23:46:14 +00:00
|
|
|
log_Printf(LogDEBUG, "%d -> %d: %s session control\n",
|
1998-05-28 23:17:51 +00:00
|
|
|
(int)orig, (int)getpid(),
|
|
|
|
holdsession ? "Passed" : "Dropped");
|
1998-12-14 19:24:30 +00:00
|
|
|
timer_InitService(0); /* Start the Timer Service */
|
1998-05-28 23:17:51 +00:00
|
|
|
break;
|
|
|
|
default:
|
1999-03-07 01:41:40 +00:00
|
|
|
close(fds[0]);
|
1999-05-08 11:07:56 +00:00
|
|
|
/* Give away all our physical locks (to the final process) */
|
1998-05-28 23:17:51 +00:00
|
|
|
for (dl = bundle->links; dl; dl = dl->next)
|
|
|
|
if (dl->state != DATALINK_CLOSED)
|
1999-05-08 11:07:56 +00:00
|
|
|
physical_ChangedPid(dl->physical, pid);
|
1999-03-07 01:41:40 +00:00
|
|
|
write(fds[1], "!", 1); /* done */
|
|
|
|
close(fds[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
|
|
|
_exit(0);
|
1998-05-28 23:17:51 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
1999-03-07 01:41:40 +00:00
|
|
|
close(fds[0]);
|
1999-05-08 11:07:56 +00:00
|
|
|
/* Give away all our physical locks (to the intermediate process) */
|
1998-05-28 23:17:51 +00:00
|
|
|
for (dl = bundle->links; dl; dl = dl->next)
|
|
|
|
if (dl->state != DATALINK_CLOSED)
|
1999-05-08 11:07:56 +00:00
|
|
|
physical_ChangedPid(dl->physical, pid);
|
1999-03-07 01:41:40 +00:00
|
|
|
write(fds[1], "!", 1); /* done */
|
|
|
|
close(fds[1]);
|
1998-05-28 23:17:51 +00:00
|
|
|
if (holdsession) {
|
|
|
|
int fd, status;
|
|
|
|
|
|
|
|
timer_TermService();
|
|
|
|
signal(SIGPIPE, SIG_DFL);
|
|
|
|
signal(SIGALRM, SIG_DFL);
|
|
|
|
signal(SIGHUP, SIG_DFL);
|
|
|
|
signal(SIGTERM, SIG_DFL);
|
|
|
|
signal(SIGINT, SIG_DFL);
|
|
|
|
signal(SIGQUIT, SIG_DFL);
|
|
|
|
for (fd = getdtablesize(); fd >= 0; fd--)
|
|
|
|
close(fd);
|
|
|
|
/*
|
|
|
|
* Reap the intermediate process. As we're not exiting but the
|
|
|
|
* intermediate is, we don't want it to become defunct.
|
|
|
|
*/
|
|
|
|
waitpid(pid, &status, 0);
|
1998-05-29 18:33:10 +00:00
|
|
|
/* Tweak our process arguments.... */
|
1999-11-17 21:12:35 +00:00
|
|
|
ID0setproctitle("session owner");
|
1999-12-30 03:36:11 +00:00
|
|
|
setuid(ID0realuid());
|
1998-05-28 23:17:51 +00:00
|
|
|
/*
|
|
|
|
* Hang around for a HUP. This should happen as soon as the
|
2000-03-14 01:47:07 +00:00
|
|
|
* ppp that we passed our ctty descriptor to closes it.
|
|
|
|
* NOTE: If this process dies, the passed descriptor becomes
|
1998-05-28 23:17:51 +00:00
|
|
|
* invalid and will give a select() error by setting one
|
|
|
|
* of the error fds, aborting the other ppp. We don't
|
|
|
|
* want that to happen !
|
|
|
|
*/
|
|
|
|
pause();
|
|
|
|
}
|
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
|
|
|
_exit(0);
|
1998-05-28 23:17:51 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
1998-10-24 01:08:45 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
bundle_HighestState(struct bundle *bundle)
|
|
|
|
{
|
|
|
|
struct datalink *dl;
|
|
|
|
int result = DATALINK_CLOSED;
|
|
|
|
|
|
|
|
for (dl = bundle->links; dl; dl = dl->next)
|
|
|
|
if (result < dl->state)
|
|
|
|
result = dl->state;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
1998-12-10 18:36:30 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
bundle_Exception(struct bundle *bundle, int fd)
|
|
|
|
{
|
|
|
|
struct datalink *dl;
|
|
|
|
|
|
|
|
for (dl = bundle->links; dl; dl = dl->next)
|
|
|
|
if (dl->physical->fd == fd) {
|
|
|
|
datalink_Down(dl, CLOSE_NORMAL);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
1999-05-31 23:57:40 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
bundle_AdjustFilters(struct bundle *bundle, struct in_addr *my_ip,
|
|
|
|
struct in_addr *peer_ip)
|
|
|
|
{
|
2000-03-14 01:47:27 +00:00
|
|
|
filter_AdjustAddr(&bundle->filter.in, my_ip, peer_ip, NULL);
|
|
|
|
filter_AdjustAddr(&bundle->filter.out, my_ip, peer_ip, NULL);
|
|
|
|
filter_AdjustAddr(&bundle->filter.dial, my_ip, peer_ip, NULL);
|
|
|
|
filter_AdjustAddr(&bundle->filter.alive, my_ip, peer_ip, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
bundle_AdjustDNS(struct bundle *bundle, struct in_addr dns[2])
|
|
|
|
{
|
|
|
|
filter_AdjustAddr(&bundle->filter.in, NULL, NULL, dns);
|
|
|
|
filter_AdjustAddr(&bundle->filter.out, NULL, NULL, dns);
|
|
|
|
filter_AdjustAddr(&bundle->filter.dial, NULL, NULL, dns);
|
|
|
|
filter_AdjustAddr(&bundle->filter.alive, NULL, NULL, dns);
|
1999-05-31 23:57:40 +00:00
|
|
|
}
|
1999-08-05 10:32:16 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
bundle_CalculateBandwidth(struct bundle *bundle)
|
|
|
|
{
|
|
|
|
struct datalink *dl;
|
|
|
|
int mtu, sp;
|
|
|
|
|
|
|
|
bundle->bandwidth = 0;
|
|
|
|
mtu = 0;
|
|
|
|
for (dl = bundle->links; dl; dl = dl->next)
|
|
|
|
if (dl->state == DATALINK_OPEN) {
|
|
|
|
if ((sp = dl->mp.bandwidth) == 0 &&
|
|
|
|
(sp = physical_GetSpeed(dl->physical)) == 0)
|
|
|
|
log_Printf(LogDEBUG, "%s: %s: Cannot determine bandwidth\n",
|
|
|
|
dl->name, dl->physical->name.full);
|
|
|
|
else
|
|
|
|
bundle->bandwidth += sp;
|
|
|
|
if (!bundle->ncp.mp.active) {
|
|
|
|
mtu = dl->physical->link.lcp.his_mru;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(bundle->bandwidth == 0)
|
|
|
|
bundle->bandwidth = 115200; /* Shrug */
|
|
|
|
|
|
|
|
if (bundle->ncp.mp.active)
|
|
|
|
mtu = bundle->ncp.mp.peer_mrru;
|
|
|
|
else if (!mtu)
|
|
|
|
mtu = 1500;
|
|
|
|
|
|
|
|
#ifndef NORADIUS
|
|
|
|
if (bundle->radius.valid && bundle->radius.mtu && bundle->radius.mtu < mtu) {
|
|
|
|
log_Printf(LogLCP, "Reducing MTU to radius value %lu\n",
|
|
|
|
bundle->radius.mtu);
|
|
|
|
mtu = bundle->radius.mtu;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
tun_configure(bundle, mtu);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
bundle_AutoAdjust(struct bundle *bundle, int percent, int what)
|
|
|
|
{
|
|
|
|
struct datalink *dl, *choice, *otherlinkup;
|
|
|
|
|
|
|
|
choice = otherlinkup = NULL;
|
|
|
|
for (dl = bundle->links; dl; dl = dl->next)
|
|
|
|
if (dl->physical->type == PHYS_AUTO) {
|
|
|
|
if (dl->state == DATALINK_OPEN) {
|
|
|
|
if (what == AUTO_DOWN) {
|
|
|
|
if (choice)
|
|
|
|
otherlinkup = choice;
|
|
|
|
choice = dl;
|
|
|
|
}
|
|
|
|
} else if (dl->state == DATALINK_CLOSED) {
|
|
|
|
if (what == AUTO_UP) {
|
|
|
|
choice = dl;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* An auto link in an intermediate state - forget it for the moment */
|
|
|
|
choice = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (dl->state == DATALINK_OPEN && what == AUTO_DOWN)
|
|
|
|
otherlinkup = dl;
|
|
|
|
|
|
|
|
if (choice) {
|
|
|
|
if (what == AUTO_UP) {
|
|
|
|
log_Printf(LogPHASE, "%d%% saturation -> Opening link ``%s''\n",
|
|
|
|
percent, choice->name);
|
|
|
|
datalink_Up(choice, 1, 1);
|
2000-05-31 15:35:29 +00:00
|
|
|
mp_CheckAutoloadTimer(&bundle->ncp.mp);
|
1999-08-05 10:32:16 +00:00
|
|
|
} else if (otherlinkup) { /* Only bring the second-last link down */
|
|
|
|
log_Printf(LogPHASE, "%d%% saturation -> Closing link ``%s''\n",
|
|
|
|
percent, choice->name);
|
1999-10-05 05:01:44 +00:00
|
|
|
datalink_Close(choice, CLOSE_STAYDOWN);
|
2000-05-31 15:35:29 +00:00
|
|
|
mp_CheckAutoloadTimer(&bundle->ncp.mp);
|
1999-08-05 10:32:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
bundle_WantAutoloadTimer(struct bundle *bundle)
|
|
|
|
{
|
|
|
|
struct datalink *dl;
|
|
|
|
int autolink, opened;
|
|
|
|
|
|
|
|
if (bundle->phase == PHASE_NETWORK) {
|
|
|
|
for (autolink = opened = 0, dl = bundle->links; dl; dl = dl->next)
|
|
|
|
if (dl->physical->type == PHYS_AUTO) {
|
|
|
|
if (++autolink == 2 || (autolink == 1 && opened))
|
|
|
|
/* Two auto links or one auto and one open in NETWORK phase */
|
|
|
|
return 1;
|
|
|
|
} else if (dl->state == DATALINK_OPEN) {
|
|
|
|
opened++;
|
|
|
|
if (autolink)
|
|
|
|
/* One auto and one open link in NETWORK phase */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2000-01-21 00:33:27 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
bundle_ChangedPID(struct bundle *bundle)
|
|
|
|
{
|
|
|
|
#ifdef TUNSIFPID
|
|
|
|
ioctl(bundle->dev.fd, TUNSIFPID, 0);
|
|
|
|
#endif
|
|
|
|
}
|