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

398 lines
10 KiB
C
Raw Normal View History

1995-01-31 06:29:58 +00:00
/*
* PPP OS Layer Interface Module
*
* Written by Toshiharu OHNO (tony-o@iij.ad.jp)
*
* Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the Internet Initiative Japan, Inc. The name of the
* IIJ may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1995-05-30 03:57:47 +00:00
*
* $Id: os.c,v 1.41 1998/01/19 02:59:33 brian Exp $
1995-05-30 03:57:47 +00:00
*
1995-01-31 06:29:58 +00:00
*/
#include <sys/param.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
1995-01-31 06:29:58 +00:00
#include <net/if.h>
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <unistd.h>
#include "command.h"
#include "mbuf.h"
#include "log.h"
#include "id.h"
#include "defs.h"
#include "timer.h"
#include "fsm.h"
1995-01-31 06:29:58 +00:00
#include "ipcp.h"
#include "os.h"
#include "loadalias.h"
#include "vars.h"
#include "arp.h"
#include "systems.h"
#include "route.h"
#include "lcp.h"
#include "ccp.h"
char *IfDevName;
1995-01-31 06:29:58 +00:00
static struct ifaliasreq ifra;
static struct ifreq ifrq;
static struct in_addr oldmine, oldhis;
static int linkup;
enum set_method { SET_UP, SET_DOWN, SET_TRY };
1995-01-31 06:29:58 +00:00
static int
SetIpDevice(struct in_addr myaddr,
struct in_addr hisaddr,
struct in_addr netmask,
enum set_method how)
1995-01-31 06:29:58 +00:00
{
struct sockaddr_in *sock_in;
1995-01-31 06:29:58 +00:00
int s;
u_long mask, addr;
s = ID0socket(AF_INET, SOCK_DGRAM, 0);
1995-01-31 06:29:58 +00:00
if (s < 0) {
LogPrintf(LogERROR, "SetIpDevice: socket(): %s\n", strerror(errno));
return (-1);
1995-01-31 06:29:58 +00:00
}
if (how == SET_DOWN) {
if (Enabled(ConfProxy))
cifproxyarp(s, oldhis);
1995-01-31 06:29:58 +00:00
if (oldmine.s_addr == 0 && oldhis.s_addr == 0) {
close(s);
return (0);
1995-01-31 06:29:58 +00:00
}
memset(&ifra.ifra_addr, '\0', sizeof ifra.ifra_addr);
memset(&ifra.ifra_broadaddr, '\0', sizeof ifra.ifra_broadaddr);
memset(&ifra.ifra_mask, '\0', sizeof ifra.ifra_mask);
if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) {
LogPrintf(LogERROR, "SetIpDevice: ioctl(SIOCDIFADDR): %s\n",
strerror(errno));
close(s);
return (-1);
1995-01-31 06:29:58 +00:00
}
oldmine.s_addr = oldhis.s_addr = 0;
} else {
/* If given addresses are alreay set, then ignore this request */
if (oldmine.s_addr == myaddr.s_addr && oldhis.s_addr == hisaddr.s_addr) {
close(s);
return (0);
}
1995-01-31 06:29:58 +00:00
/*
* If different address has been set, then delete it first.
*/
if (oldmine.s_addr || oldhis.s_addr) {
memset(&ifra.ifra_addr, '\0', sizeof ifra.ifra_addr);
memset(&ifra.ifra_broadaddr, '\0', sizeof ifra.ifra_broadaddr);
memset(&ifra.ifra_mask, '\0', sizeof ifra.ifra_mask);
if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) {
LogPrintf(LogERROR, "SetIpDevice: ioctl(SIOCDIFADDR): %s\n",
strerror(errno));
close(s);
return (-1);
}
1995-01-31 06:29:58 +00:00
}
/* Set interface address */
sock_in = (struct sockaddr_in *) & (ifra.ifra_addr);
sock_in->sin_family = AF_INET;
sock_in->sin_addr = myaddr;
sock_in->sin_len = sizeof *sock_in;
/* Set destination address */
sock_in = (struct sockaddr_in *) & (ifra.ifra_broadaddr);
sock_in->sin_family = AF_INET;
sock_in->sin_addr = hisaddr;
sock_in->sin_len = sizeof *sock_in;
1995-01-31 06:29:58 +00:00
addr = ntohl(myaddr.s_addr);
if (IN_CLASSA(addr))
mask = IN_CLASSA_NET;
else if (IN_CLASSB(addr))
mask = IN_CLASSB_NET;
else
mask = IN_CLASSC_NET;
1995-01-31 06:29:58 +00:00
/*
* if subnet mask is given, use it instead of class mask.
1995-01-31 06:29:58 +00:00
*/
if (netmask.s_addr && (ntohl(netmask.s_addr) & mask) == mask)
mask = ntohl(netmask.s_addr);
sock_in = (struct sockaddr_in *) & (ifra.ifra_mask);
sock_in->sin_family = AF_INET;
sock_in->sin_addr.s_addr = htonl(mask);
sock_in->sin_len = sizeof *sock_in;
1995-01-31 06:29:58 +00:00
if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0) {
if (how != SET_TRY)
LogPrintf(LogERROR, "SetIpDevice: ioctl(SIOCAIFADDR): %s\n",
strerror(errno));
close(s);
return (-1);
1995-01-31 06:29:58 +00:00
}
oldhis.s_addr = hisaddr.s_addr;
oldmine.s_addr = myaddr.s_addr;
if (Enabled(ConfProxy))
sifproxyarp(s, hisaddr);
1995-01-31 06:29:58 +00:00
}
close(s);
return (0);
1995-01-31 06:29:58 +00:00
}
int
CleanInterface(const char *name)
{
int s;
s = ID0socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0) {
LogPrintf(LogERROR, "SetIpDevice: socket(): %s\n", strerror(errno));
return (-1);
}
strncpy(ifrq.ifr_name, name, sizeof ifrq.ifr_name - 1);
ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0';
while (ID0ioctl(s, SIOCGIFADDR, &ifrq) == 0) {
memset(&ifra.ifra_mask, '\0', sizeof ifra.ifra_mask);
ifra.ifra_addr = ifrq.ifr_addr;
if (ID0ioctl(s, SIOCGIFDSTADDR, &ifrq) < 0) {
if (ifra.ifra_addr.sa_family == AF_INET)
LogPrintf(LogERROR, "tun_configure: Can't get dst for %s on %s !\n",
inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr),
name);
return 0;
}
ifra.ifra_broadaddr = ifrq.ifr_dstaddr;
if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) {
if (ifra.ifra_addr.sa_family == AF_INET)
LogPrintf(LogERROR, "tun_configure: Can't delete %s address on %s !\n",
inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr),
name);
return 0;
}
}
return 1;
}
1995-01-31 06:29:58 +00:00
int
OsTrySetIpaddress(struct in_addr myaddr, struct in_addr hisaddr)
{
return (SetIpDevice(myaddr, hisaddr, ifnetmask, SET_TRY));
}
int
OsSetIpaddress(struct in_addr myaddr, struct in_addr hisaddr)
1995-01-31 06:29:58 +00:00
{
return (SetIpDevice(myaddr, hisaddr, ifnetmask, SET_UP));
1995-01-31 06:29:58 +00:00
}
static struct in_addr peer_addr;
void
OsLinkup()
{
char *s;
if (linkup == 0) {
reconnectState = RECON_UNKNOWN;
if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) {
char c = EX_NORMAL;
if (write(BGFiledes[1], &c, 1) == 1)
LogPrintf(LogPHASE, "Parent notified of success.\n");
else
LogPrintf(LogPHASE, "Failed to notify parent of success.\n");
close(BGFiledes[1]);
BGFiledes[1] = -1;
}
1995-01-31 06:29:58 +00:00
peer_addr = IpcpInfo.his_ipaddr;
s = (char *) inet_ntoa(peer_addr);
if (LogIsKept(LogLINK))
LogPrintf(LogLINK, "OsLinkup: %s\n", s);
else
LogPrintf(LogLCP, "OsLinkup: %s\n", s);
1995-01-31 06:29:58 +00:00
if (SelectSystem(inet_ntoa(IpcpInfo.want_ipaddr), LINKUPFILE) < 0) {
if (GetLabel()) {
if (SelectSystem(GetLabel(), LINKUPFILE) < 0)
SelectSystem("MYADDR", LINKUPFILE);
1995-01-31 06:29:58 +00:00
} else
SelectSystem("MYADDR", LINKUPFILE);
1995-01-31 06:29:58 +00:00
}
linkup = 1;
}
}
int
OsLinkIsUp()
{
return linkup;
}
1995-01-31 06:29:58 +00:00
void
OsLinkdown()
{
char *s;
int Level;
1995-01-31 06:29:58 +00:00
if (linkup) {
s = (char *) inet_ntoa(peer_addr);
Level = LogIsKept(LogLINK) ? LogLINK : LogIPCP;
LogPrintf(Level, "OsLinkdown: %s\n", s);
FsmDown(&IpcpFsm); /* IPCP must come down */
FsmDown(&CcpFsm); /* CCP must come down */
1995-01-31 06:29:58 +00:00
linkup = 0;
if (SelectSystem(s, LINKDOWNFILE) < 0) {
if (GetLabel()) {
if (SelectSystem(GetLabel(), LINKDOWNFILE) < 0)
SelectSystem("MYADDR", LINKDOWNFILE);
} else
SelectSystem("MYADDR", LINKDOWNFILE);
}
1995-01-31 06:29:58 +00:00
}
}
int
OsInterfaceDown(int final)
1995-01-31 06:29:58 +00:00
{
struct in_addr zeroaddr;
int s;
OsLinkdown();
if (!final && (mode & MODE_DAEMON)) /* We still want interface alive */
return (0);
1995-01-31 06:29:58 +00:00
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0) {
LogPrintf(LogERROR, "OsInterfaceDown: socket: %s\n", strerror(errno));
return (-1);
1995-01-31 06:29:58 +00:00
}
ifrq.ifr_flags &= ~IFF_UP;
if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
LogPrintf(LogERROR, "OsInterfaceDown: ioctl(SIOCSIFFLAGS): %s\n",
strerror(errno));
1995-01-31 06:29:58 +00:00
close(s);
return (-1);
1995-01-31 06:29:58 +00:00
}
zeroaddr.s_addr = 0;
SetIpDevice(zeroaddr, zeroaddr, zeroaddr, SET_DOWN);
1995-01-31 06:29:58 +00:00
close(s);
return (0);
1995-01-31 06:29:58 +00:00
}
/*
* Open tunnel device and returns its descriptor
*/
#define MAX_TUN 256
/* MAX_TUN is set at an arbitrarily large value *
* as the loop aborts when it reaches the first *
* 'Device not configured' (ENXIO), or the third *
* 'No such file or directory' (ENOENT) error. */
1995-01-31 06:29:58 +00:00
int
OpenTunnel(int *ptun)
1995-01-31 06:29:58 +00:00
{
int s;
char ifname[IFNAMSIZ];
static char devname[14]; /* sufficient room for "/dev/tun65535" */
unsigned unit, enoentcount = 0;
int err;
1995-01-31 06:29:58 +00:00
err = ENOENT;
for (unit = 0; unit <= MAX_TUN; unit++) {
snprintf(devname, sizeof devname, "/dev/tun%d", unit);
tun_out = ID0open(devname, O_RDWR);
if (tun_out >= 0)
break;
if (errno == ENXIO) {
unit = MAX_TUN;
err = errno;
} else if (errno == ENOENT) {
enoentcount++;
if (enoentcount > 2)
unit = MAX_TUN;
} else
err = errno;
1995-01-31 06:29:58 +00:00
}
if (unit > MAX_TUN) {
if (VarTerm)
fprintf(VarTerm, "No tunnel device is available (%s).\n", strerror(err));
return -1;
1995-01-31 06:29:58 +00:00
}
*ptun = unit;
1995-01-31 06:29:58 +00:00
LogSetTun(unit);
1995-01-31 06:29:58 +00:00
/*
* At first, name the interface.
*/
strncpy(ifname, devname + 5, IFNAMSIZ - 1);
1995-01-31 06:29:58 +00:00
memset(&ifra, '\0', sizeof ifra);
memset(&ifrq, '\0', sizeof ifrq);
1995-01-31 06:29:58 +00:00
strncpy(ifrq.ifr_name, ifname, IFNAMSIZ - 1);
strncpy(ifra.ifra_name, ifname, IFNAMSIZ - 1);
1995-01-31 06:29:58 +00:00
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0) {
LogPrintf(LogERROR, "OpenTunnel: socket(): %s\n", strerror(errno));
return (-1);
1995-01-31 06:29:58 +00:00
}
/*
* Now, bring up the interface.
1995-01-31 06:29:58 +00:00
*/
if (ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) {
LogPrintf(LogERROR, "OpenTunnel: ioctl(SIOCGIFFLAGS): %s\n",
strerror(errno));
1995-01-31 06:29:58 +00:00
close(s);
return (-1);
1995-01-31 06:29:58 +00:00
}
ifrq.ifr_flags |= IFF_UP;
if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
LogPrintf(LogERROR, "OpenTunnel: ioctl(SIOCSIFFLAGS): %s\n",
strerror(errno));
1995-01-31 06:29:58 +00:00
close(s);
return (-1);
1995-01-31 06:29:58 +00:00
}
tun_in = tun_out;
IfDevName = devname + 5;
if (GetIfIndex(IfDevName) < 0) {
LogPrintf(LogERROR, "OpenTunnel: Can't find ifindex.\n");
1995-01-31 06:29:58 +00:00
close(s);
return (-1);
1995-01-31 06:29:58 +00:00
}
if (VarTerm)
fprintf(VarTerm, "Using interface: %s\n", IfDevName);
LogPrintf(LogPHASE, "Using interface: %s\n", IfDevName);
1995-01-31 06:29:58 +00:00
close(s);
return (0);
1995-01-31 06:29:58 +00:00
}