709 lines
18 KiB
C
709 lines
18 KiB
C
/* $Header: /usr/cvsroot/target/src/wrn/wm/demo/lib/pppbsd.c,v 1.3 2003/01/15 14:04:33 josh Exp $ */
|
|
|
|
/*
|
|
* Copyright (C) 1999-2005 Wind River Systems, Inc.
|
|
* All rights reserved. Provided under license only.
|
|
* Distribution or other use of this software is only
|
|
* permitted pursuant to the terms of a license agreement
|
|
* from Wind River Systems (and is otherwise prohibited).
|
|
* Refer to that license agreement for terms of use.
|
|
*/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
* Copyright 1993-1997 Epilogue Technology Corporation.
|
|
* Copyright 1998 Integrated Systems, Inc.
|
|
* All rights reserved.
|
|
****************************************************************************/
|
|
|
|
/*
|
|
* $Log: pppbsd.c,v $
|
|
* Revision 1.3 2003/01/15 14:04:33 josh
|
|
* directory structure shifting
|
|
*
|
|
* Revision 1.2 2001/11/08 15:56:25 tneale
|
|
* Updated for newest file layout
|
|
*
|
|
* Revision 1.1.1.1 2001/11/05 17:48:42 tneale
|
|
* Tornado shuffle
|
|
*
|
|
* Revision 2.10 2001/01/19 22:23:49 paul
|
|
* Update copyright.
|
|
*
|
|
* Revision 2.9 2000/10/16 19:21:54 paul
|
|
* Restore sockets and mempool code.
|
|
*
|
|
* Revision 2.8 2000/03/17 00:12:43 meister
|
|
* Update copyright message
|
|
*
|
|
* Revision 2.7 2000/03/13 21:22:08 paul
|
|
* Removed some code that we are no longer working on.
|
|
*
|
|
* Revision 2.6 1999/11/05 22:29:06 paul
|
|
* Updated driver structs to reflect conditional backwards-compatibility
|
|
* fields and new fields.
|
|
*
|
|
* Revision 2.5 1999/03/01 22:05:26 wes
|
|
* Add Yet Another Way to connect attache ppp to a unix ppp: attach
|
|
* ourselves to the master side of a pty; run pppd attached to the slave
|
|
* side.
|
|
* configured via INSTALL_SNARK_BSD_PPP_OVER_PTY
|
|
*
|
|
* Revision 2.4 1998/02/25 15:21:49 sra
|
|
* Finish moving types.h, bug.h, and bugdef.h to common/h/.
|
|
*
|
|
* Revision 2.3 1998/02/25 04:57:35 sra
|
|
* Update copyrights.
|
|
*
|
|
* Revision 2.2 1997/11/18 18:05:19 sra
|
|
* Make PPP work on Purify/SunOS testbed.
|
|
*
|
|
* Revision 2.1 1997/10/28 00:51:55 sra
|
|
* Convert PPP code to use BUG() macro.
|
|
* Bang on CHAP and PAP code some more.
|
|
* Create test driver for PPP under Snark/BSD.
|
|
*
|
|
*
|
|
*/
|
|
|
|
/* [clearcase]
|
|
modification history
|
|
-------------------
|
|
01a,19apr05,job update copyright notices
|
|
*/
|
|
|
|
|
|
/*
|
|
* Point-to-Point Protocol (PPP) interface for snark under BSD-derived systems.
|
|
*
|
|
* This code has only been tested under FreeBSD 2.x. It should work on
|
|
* any BSD-derived system with minor modifications.
|
|
*
|
|
* We depend on the PPP media layer code to handle the FCS, address, and
|
|
* control fields in the framing (PPPC_FCS must be enabled). So all we
|
|
* have to worry about is the byte stuffing and the framing "flag" byte.
|
|
*/
|
|
|
|
#include <wrn/wm/attache/config.h>
|
|
#include <wrn/wm/common/types.h>
|
|
#include <wrn/wm/attache/mib.h>
|
|
#include <wrn/wm/attache/timer.h>
|
|
#include <wrn/wm/attache/packet.h>
|
|
#include <wrn/wm/attache/net.h>
|
|
#include <wrn/wm/attache/route.h>
|
|
#include <wrn/wm/attache/ip.h>
|
|
#include <wrn/wm/attache/ppp.h>
|
|
#include <wrn/wm/attache/glue.h>
|
|
|
|
#include <stdio.h>
|
|
#include <termios.h>
|
|
#include <sys/types.h>
|
|
#include <sys/time.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <sys/file.h>
|
|
#include <unistd.h>
|
|
|
|
#if INSTALL_SNARK_BSD_PPP_OVER_TCP
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#endif
|
|
|
|
#if INSTALL_SNARK_BSD_PPP_OVER_PTY
|
|
#include <util.h>
|
|
#include <termios.h>
|
|
#endif
|
|
|
|
#include <wrn/wm/demo/snarklib.h>
|
|
|
|
#include <wrn/wm/demo/bsdif.h>
|
|
#include <wrn/wm/demo/pppbsd.h>
|
|
|
|
#define PF_PPP_BOP 0x1000
|
|
|
|
#ifndef BSDPPP_COMPORT_NAME
|
|
#if INSTALL_SNARK_BSD_PPP_OVER_PTY
|
|
#define BSDPPP_COMPORT_NAME "pty"
|
|
#elif INSTALL_SNARK_BSD_PPP_OVER_TCP
|
|
#define BSDPPP_COMPORT_NAME "tcp"
|
|
#else
|
|
#define BSDPPP_COMPORT_NAME "cuaa"
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
* PPP control structure, hangs off net->specific->private.
|
|
*/
|
|
|
|
#ifndef SNARKBSD_PPP_IBUFLEN
|
|
#define SNARKBSD_PPP_IBUFLEN 6000
|
|
#endif
|
|
|
|
#ifndef SNARKBSD_PPP_OBUFLEN
|
|
#define SNARKBSD_PPP_OBUFLEN 6000
|
|
#endif
|
|
|
|
struct ppp_driver_ctl {
|
|
struct net *net;
|
|
bits32_t snd_asynch_mask;
|
|
packet *ipkt, *opkt_head, **opkt_tail;
|
|
int ilen, olen;
|
|
unsigned char *ibp, *obp;
|
|
unsigned char ibuf[SNARKBSD_PPP_IBUFLEN], obuf[SNARKBSD_PPP_OBUFLEN];
|
|
unsigned iescaped : 1;
|
|
unsigned idiscard : 1;
|
|
unsigned oescaped : 1;
|
|
};
|
|
|
|
/*
|
|
* PPP framing and byte stuffing magic
|
|
*/
|
|
#define PPP_FLAG 0x7e
|
|
#define PPP_ESCAPE 0x7d
|
|
#define PPP_XOR 0x20
|
|
|
|
#define PPP_MASKED(_c_, _m_) ((_c_) < 32 && ((_m_) & (1 << (_c_))))
|
|
|
|
#ifndef PPP_DRIVER_RCV_ASYNCH_MASK
|
|
#define PPP_DRIVER_RCV_ASYNCH_MASK 0
|
|
#endif
|
|
|
|
static void hexdump (char *flag, unsigned char *cp, int len)
|
|
{
|
|
int i;
|
|
|
|
fprintf(stderr, "%s:", flag);
|
|
for (i=0; i<len; i++) {
|
|
fprintf(stderr, " %02x", cp[i]);
|
|
}
|
|
fprintf(stderr, "\n");
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Decode a buffer of data into zero or more Attache packet buffers.
|
|
* Most of the hair is just checking for weird boundary conditions.
|
|
*/
|
|
|
|
#define DOCHAR(x) \
|
|
do { \
|
|
if (pdc->idiscard) { \
|
|
continue; \
|
|
} else if (p->pkt_data < p->pkt_buffer + p->pkt_buflen) { \
|
|
*p->pkt_data++ = (x); \
|
|
} else { \
|
|
pdc->idiscard = 1; \
|
|
continue; \
|
|
} \
|
|
} while (0)
|
|
|
|
static packet *ppp_driver_decode
|
|
(struct net *net, unsigned char *buf, int len, int *used)
|
|
{
|
|
struct bsdif *bif = net->specific;
|
|
struct ppp_driver_ctl *pdc = bif->private;
|
|
unsigned char *bob = buf, *eob = buf + len;
|
|
packet *p;
|
|
|
|
while (buf < eob) {
|
|
if (pdc->ipkt == 0 && (pdc->ipkt = pkt_alloc(net->driver->maxlen)) == 0)
|
|
break; /* Oops, no packet buffers */
|
|
p = pdc->ipkt;
|
|
|
|
if (PPP_MASKED(*buf, PPP_DRIVER_RCV_ASYNCH_MASK)) {
|
|
++buf; /* Noise byte, just ignore it */
|
|
continue;
|
|
}
|
|
|
|
if (pdc->iescaped) { /* Was escaped? */
|
|
pdc->iescaped = 0; /* ain't no more */
|
|
if (*buf == PPP_FLAG) /* End of frame in escape sequence? */
|
|
pdc->idiscard = 1; /* yeah, abort this packet */
|
|
DOCHAR(*buf++ ^ PPP_XOR); /* Save unescaped byte */
|
|
} else { /* Not escaped */
|
|
switch (*buf++) {
|
|
case PPP_FLAG:
|
|
if (!pdc->idiscard && p->pkt_data > p->pkt_buffer) {
|
|
pdc->ipkt = 0;
|
|
p->pkt_datalen = p->pkt_data - p->pkt_buffer;
|
|
p->pkt_data = p->pkt_buffer;
|
|
if (used)
|
|
*used = buf - bob;
|
|
return p; /* Happy packet */
|
|
}
|
|
pdc->idiscard = 0; /* Bogus packet now history */
|
|
p->pkt_data = p->pkt_buffer;
|
|
continue;
|
|
case PPP_ESCAPE:
|
|
pdc->iescaped = 1; /* An escaping byte! */
|
|
continue;
|
|
default:
|
|
DOCHAR(*(buf-1)); /* A normal boring byte */
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
if (used)
|
|
*used = buf - bob;
|
|
return 0; /* Yes, we have no packet today */
|
|
}
|
|
|
|
#undef DOCHAR
|
|
|
|
|
|
|
|
/*
|
|
* Encode zero or more Attache packet buffers into a data buffer.
|
|
* Packets will have been queued for us by ppp_driver_send().
|
|
*/
|
|
|
|
#define DOCHAR(x) \
|
|
do { *buf++ = (x); if (buf == eob) return (buf - bob); } while (0)
|
|
|
|
static int ppp_driver_encode(struct net *net, unsigned char *buf, int len)
|
|
{
|
|
struct bsdif *bif = net->specific;
|
|
struct ppp_driver_ctl *pdc = bif->private;
|
|
unsigned char *bob = buf, *eob = buf + len;
|
|
packet *p;
|
|
|
|
if (buf >= eob)
|
|
return 0;
|
|
|
|
while ((p = pdc->opkt_head) != 0) {
|
|
|
|
/*
|
|
* Send framing sequence before a new packet, to flush line noise.
|
|
*/
|
|
if ((p->pkt_flags & PF_PPP_BOP) != 0) {
|
|
p->pkt_flags &= ~PF_PPP_BOP;
|
|
DOCHAR(PPP_FLAG);
|
|
}
|
|
|
|
/*
|
|
* Process data in this packet.
|
|
*/
|
|
while (p->pkt_datalen > 0) {
|
|
if (pdc->oescaped) {
|
|
pdc->oescaped = 0; /* Was escaped, ain't no more */
|
|
DOCHAR((*p->pkt_data++) ^ PPP_XOR);
|
|
} else {
|
|
switch (*p->pkt_data) {
|
|
default:
|
|
if (!PPP_MASKED(*p->pkt_data, pdc->snd_asynch_mask)) {
|
|
DOCHAR(*p->pkt_data++);
|
|
break; /* Ordinary char, just send it */
|
|
}
|
|
case PPP_FLAG: /* I need an escape */
|
|
case PPP_ESCAPE:
|
|
pdc->oescaped = 1;
|
|
DOCHAR(PPP_ESCAPE);
|
|
continue; /* Doesn't count as sent yet */
|
|
}
|
|
}
|
|
p->pkt_datalen--; /* One less octet to feed */
|
|
}
|
|
|
|
/*
|
|
* No more data in current packet, so send framing sequence
|
|
* and proceed with next packet in the output queue.
|
|
*/
|
|
DOCHAR(PPP_FLAG);
|
|
if ((pdc->opkt_head = p->pkt_link) == 0)
|
|
pdc->opkt_tail = &pdc->opkt_head;
|
|
pkt_free(p);
|
|
}
|
|
|
|
return buf - bob;
|
|
}
|
|
|
|
#undef DOCHAR
|
|
|
|
|
|
|
|
/*
|
|
* Process whatever incoming PPP data we can without blocking,
|
|
* passing zero or more Attache packets to ppp_rcv().
|
|
*/
|
|
|
|
static void ppp_driver_input(struct net *net)
|
|
{
|
|
struct bsdif *bif = net->specific;
|
|
struct ppp_driver_ctl *pdc = bif->private;
|
|
packet *p;
|
|
int n;
|
|
|
|
if (pdc->ilen <= 0) {
|
|
do {
|
|
n = read(bif->fd, (char *) pdc->ibuf, sizeof(pdc->ibuf));
|
|
} while (n < 0 && errno == EINTR);
|
|
if (n == 0 || (n < 0 && errno != EWOULDBLOCK)) {
|
|
bif->flags &= ~BSDIF_READ;
|
|
return;
|
|
}
|
|
pdc->ilen = n;
|
|
pdc->ibp = pdc->ibuf;
|
|
}
|
|
|
|
while (pdc->ilen > 0) {
|
|
if ((p = ppp_driver_decode(net, pdc->ibp, pdc->ilen, &n)) != 0) {
|
|
p->pkt_n = net;
|
|
hexdump("RX", p->pkt_data, p->pkt_datalen);
|
|
ppp_rcv(p);
|
|
}
|
|
if (n == 0) /* out of packet buffers, try again later */
|
|
break;
|
|
pdc->ibp += n; /* count what we consumed */
|
|
pdc->ilen -= n;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Process whatever outgoing Attache packets we can without blocking.
|
|
* Generates zero or more writes of encoded PPP data.
|
|
*/
|
|
|
|
static void ppp_driver_output(struct net *net)
|
|
{
|
|
struct bsdif *bif = net->specific;
|
|
struct ppp_driver_ctl *pdc = bif->private;
|
|
int n;
|
|
|
|
for (;;) {
|
|
if (pdc->olen == 0) {
|
|
if ((n = ppp_driver_encode(net, pdc->obuf, sizeof(pdc->obuf))) == 0)
|
|
break;
|
|
pdc->olen = n;
|
|
pdc->obp = pdc->obuf;
|
|
}
|
|
do {
|
|
n = write(bif->fd, pdc->obp, pdc->olen);
|
|
} while (n < 0 && errno == EINTR);
|
|
if (n <= 0)
|
|
break;
|
|
pdc->obp += n;
|
|
pdc->olen -= n;
|
|
}
|
|
if (n == 0 || (n < 0 && errno != EWOULDBLOCK))
|
|
bif->flags &= ~BSDIF_WRITE;
|
|
}
|
|
|
|
/*
|
|
* Handle events detected by generic NetBSD I/O loop.
|
|
* The flags tell us what kind of event happened, we call the
|
|
* non-blocking I/O routines to do the real work.
|
|
*/
|
|
|
|
static void ppp_driver_handler(int fd, void *net, unsigned flags)
|
|
{
|
|
if ((flags & BSDIF_WRITE) != 0)
|
|
ppp_driver_output(net);
|
|
if ((flags & BSDIF_READ) != 0)
|
|
ppp_driver_input(net);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Attache device driver routines.
|
|
*/
|
|
|
|
static void ppp_driver_send(packet *p)
|
|
{
|
|
struct net *net = p->pkt_n;
|
|
struct bsdif *bif = net->specific;
|
|
struct ppp_driver_ctl *pdc = bif->private;
|
|
|
|
hexdump("TX", p->pkt_data, p->pkt_datalen);
|
|
|
|
p->pkt_flags |= PF_PPP_BOP; /* Flag that this is a new packet */
|
|
|
|
p->pkt_link = 0; /* Stuff this packet into the */
|
|
*pdc->opkt_tail = p; /* output queue */
|
|
pdc->opkt_tail = &p->pkt_link;
|
|
|
|
bif->flags |= BSDIF_WRITE; /* Now interested in output events */
|
|
ppp_driver_output(net); /* Send what we can right away */
|
|
}
|
|
|
|
static void ppp_driver_close(struct net *net)
|
|
{
|
|
struct bsdif *bif = net->specific;
|
|
|
|
net->flags |= NF_DRIVER_DOWN;
|
|
bif->flags &= ~(BSDIF_READ | BSDIF_WRITE);
|
|
|
|
if (bif->fd >= 0) {
|
|
(void) close(bif->fd); /* Clean up our file if we had one */
|
|
bif->fd = -1;
|
|
}
|
|
if (bif->private) {
|
|
GLUE_FREE(bif->private); /* Release our memory if we had any */
|
|
bif->private = 0;
|
|
}
|
|
}
|
|
|
|
static void ppp_driver_init(struct net *net)
|
|
{
|
|
struct bsdif *bif = net->specific;
|
|
struct ppp_driver_ctl *pdc;
|
|
char name[64];
|
|
|
|
net->flags |= NF_DRIVER_DOWN;
|
|
|
|
if (!net->speed)
|
|
net->speed = 115200;
|
|
|
|
if ((bif->private = pdc = GLUE_ALLOC(sizeof(*pdc))) == 0) {
|
|
fprintf(stderr, "couldn't allocate ppp control structure\n");
|
|
return;
|
|
}
|
|
MEMSET(pdc, 0, sizeof(*pdc));
|
|
pdc->opkt_tail = &pdc->opkt_head;
|
|
pdc->net = net;
|
|
|
|
#if INSTALL_SNARK_BSD_PPP_OVER_PTY
|
|
{
|
|
int pty, tty;
|
|
int subpid;
|
|
char *pppd_path;
|
|
struct termios t;
|
|
int nsleep = 10;
|
|
|
|
sprintf(name, "SNARKBSDPPP_PTY%d", net->instance);
|
|
pppd_path = getenv(name);
|
|
|
|
if (!pppd_path)
|
|
return;
|
|
|
|
if (openpty(&pty, &tty, name, NULL, NULL) < 0) {
|
|
perror("can't open pty");
|
|
return;
|
|
}
|
|
|
|
tcgetattr(tty, &t);
|
|
cfmakeraw(&t);
|
|
tcsetattr(tty, TCSAFLUSH, &t);
|
|
|
|
fflush(NULL);
|
|
subpid = fork();
|
|
if (subpid < 0) {
|
|
perror("fork");
|
|
return; /* !!! cleanup? */
|
|
}
|
|
|
|
if (subpid == 0) {
|
|
|
|
/* in the child; start pppd... */
|
|
|
|
dup2(tty, 0);
|
|
dup2(tty, 1);
|
|
close(pty);
|
|
close(tty);
|
|
fprintf(stderr, "execing %s in pid %d on %s in %d seconds...\n", pppd_path, getpid(), name, nsleep);
|
|
sleep(nsleep);
|
|
fprintf(stderr, "execing now\n");
|
|
execlp(pppd_path, "pppd", name,
|
|
"file", "snark.ppprc", NULL);
|
|
_exit(1);
|
|
}
|
|
|
|
/* now in the parent.. */
|
|
close(tty);
|
|
bif->fd = pty;
|
|
sleep(nsleep+1);
|
|
}
|
|
#elif !INSTALL_SNARK_BSD_PPP_OVER_TCP
|
|
|
|
/*
|
|
* Normal /dev/ttyxxx-based PPP. This code was written for FreeBSD 2.2.1,
|
|
* it should be pretty easy to make it work on other Unix-like systems.
|
|
*/
|
|
{
|
|
struct termios termios;
|
|
|
|
sprintf(name, "/dev/%s", net->s_name + 3);
|
|
if ((bif->fd = open(name, O_RDWR, 0660)) < 0) { /* |O_NONBLOCK */
|
|
perror("couldn't open ppp device");
|
|
goto lose;
|
|
}
|
|
if (tcgetattr(bif->fd, &termios) < 0) {
|
|
perror("couldn't get ppp line state");
|
|
goto lose;
|
|
}
|
|
if (cfmakeraw(&termios), cfsetspeed(&termios, net->speed) < 0) {
|
|
perror("couldn't fiddle ppp state");
|
|
goto lose;
|
|
}
|
|
if (tcsetattr(bif->fd, TCSANOW, &termios) < 0) {
|
|
perror("couldn't set ppp line flags and speed");
|
|
goto lose;
|
|
}
|
|
}
|
|
#elif 0
|
|
/*
|
|
* PPP over TCP. This version does an active connect. In theory,
|
|
* it should work nicely with IIJ-PPP in -direct mode running under
|
|
* Juergen Nickelsen's "socket" program, but in practice the connection
|
|
* keeps getting closed before LCP ever really gets going. Sigh.
|
|
*/
|
|
{
|
|
struct sockaddr_in sin;
|
|
char host[20];
|
|
unsigned short port;
|
|
|
|
sprintf(name, "SNARKBSDPPP_%s", net->s_name + 3);
|
|
if (sscanf(getenv(name), "%16[0-9.]:%hu", host, &port) != 2) {
|
|
fprintf(stderr, "couldn't line information for PPP/TCP link\n");
|
|
goto lose;
|
|
}
|
|
MEMSET(&sin, 0, sizeof(sin));
|
|
sin.sin_family = AF_INET;
|
|
sin.sin_port = htons(port);
|
|
sin.sin_addr.s_addr = inet_addr(host);
|
|
if ((bif->fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
|
perror("couldn't get socket for PPP/TCP link");
|
|
goto lose;
|
|
}
|
|
if (connect(bif->fd, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
|
|
perror("couldn't connect PPP/TCP link");
|
|
goto lose;
|
|
}
|
|
}
|
|
#else
|
|
/*
|
|
* PPP over TCP. This version does a passive listen, which, in theory,
|
|
* should allow IIJ-PPP to connect to it directly.
|
|
*/
|
|
{
|
|
struct sockaddr_in sin;
|
|
unsigned short port;
|
|
int s, n;
|
|
|
|
sprintf(name, "SNARKBSDPPP_%s", net->s_name + 3);
|
|
if (sscanf(getenv(name), "%hu", &port) != 1) {
|
|
fprintf(stderr, "couldn't parse line information for PPP/TCP link %s: %s\n",
|
|
name, getenv(name));
|
|
goto lose;
|
|
}
|
|
MEMSET(&sin, 0, sizeof(sin));
|
|
sin.sin_family = AF_INET;
|
|
sin.sin_port = htons(port);
|
|
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
|
perror("couldn't get socket for PPP/TCP listener");
|
|
goto lose;
|
|
}
|
|
if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
|
|
perror("couldn't bind socket for PPP/TCP listener");
|
|
goto lose;
|
|
}
|
|
if (listen(s, 1) < 0) {
|
|
perror("couldn't listen for for PPP/TCP connection");
|
|
goto lose;
|
|
}
|
|
fprintf(stderr, "[Listening for PPP/TCP connection on port %u]\n", port);
|
|
n = sizeof(sin);
|
|
if ((bif->fd = accept(s, (struct sockaddr *) &sin, &n)) < 0) {
|
|
perror("couldn't accept PPP/TCP connection");
|
|
goto lose;
|
|
}
|
|
close(s);
|
|
fprintf(stderr, "[Got PPP/TCP connection from %s:%u]\n",
|
|
inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
|
|
}
|
|
#endif
|
|
|
|
if (fcntl(bif->fd, F_SETFL, FNDELAY) < 0) {
|
|
perror("unable to set ppp line non-blocking");
|
|
goto lose;
|
|
}
|
|
|
|
bif->handler = ppp_driver_handler;
|
|
bif->flags |= BSDIF_READ;
|
|
net->flags &= ~NF_DRIVER_DOWN;
|
|
return; /* success */
|
|
|
|
lose:
|
|
ppp_driver_close(net); /* failure */
|
|
}
|
|
|
|
static int ppp_driver_device_ctl(struct net *net, int code, ptr_t cookie)
|
|
{
|
|
struct bsdif *bif = net->specific;
|
|
struct ppp_driver_ctl *pdc = bif->private;
|
|
|
|
switch (code) {
|
|
case DEVICE_CTL_SET_PPP_ASYNC_CTL_MAP:
|
|
BUG_ASSERT(cookie && bif && pdc);
|
|
pdc->snd_asynch_mask = *(bits32_t *)cookie;
|
|
return DEVICE_CTL_GOOD;
|
|
case DEVICE_CTL_GET_PPP_RCV_ASYNC_CTL_MAP:
|
|
BUG_ASSERT(cookie);
|
|
*(bits32_t *)cookie = PPP_DRIVER_RCV_ASYNCH_MASK;
|
|
return DEVICE_CTL_GOOD;
|
|
default:
|
|
return DEVICE_CTL_UNKNOWN_CODE;
|
|
}
|
|
}
|
|
|
|
static struct driver ppp_driver = {
|
|
ppp_driver_init, /* Init routine */
|
|
ppp_driver_send, /* Raw send routine */
|
|
ppp_ip_send, /* IP packet send routine */
|
|
0, /* ARP routine */
|
|
ppp_driver_device_ctl, /* Device control routine */
|
|
ppp_driver_close, /* Close routine */
|
|
"ppp", /* Driver name prefix */
|
|
"Point-to-Point Protocol", /* Driver name */
|
|
4, /* Header length (adr, ctl, prot) */
|
|
2, /* Trailer length (FCS) */
|
|
1506, /* Max packet size */
|
|
IF_PPP, /* MIB interface type */
|
|
0, /* ARP hardware type */
|
|
ppp_control, /* Media control routine */
|
|
0, /* IPv6 send */
|
|
0 /* IPv4 send */
|
|
};
|
|
|
|
void ppp_driver_find
|
|
(void (*config)(char *, struct driver *, int, bits16_t, unsigned, bits32_t))
|
|
{
|
|
char name[64];
|
|
int speed, instance;
|
|
|
|
for (instance = 0; ; instance++) {
|
|
#if INSTALL_SNARK_BSD_PPP_OVER_PTY
|
|
sprintf(name, "SNARKBSDPPP_PTY%d", instance);
|
|
if (!getenv(name))
|
|
return;
|
|
speed = 115200;
|
|
#elif INSTALL_SNARK_BSD_PPP_OVER_TCP
|
|
sprintf(name, "SNARKBSDPPP_%s%d", BSDPPP_COMPORT_NAME, instance);
|
|
if (!getenv(name))
|
|
return;
|
|
speed = 115200;
|
|
#else
|
|
struct termios termios;
|
|
int fd;
|
|
sprintf(name, "/dev/%s%d", BSDPPP_COMPORT_NAME, instance);
|
|
if ((fd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
|
|
if (errno == ENOENT)
|
|
return;
|
|
continue;
|
|
}
|
|
speed = (tcgetattr(fd, &termios) < 0 ? 0 : cfgetispeed(&termios));
|
|
(void) close(fd);
|
|
if (speed == 0)
|
|
continue;
|
|
#endif
|
|
sprintf(name, "%s%d", BSDPPP_COMPORT_NAME, instance);
|
|
config(name, &ppp_driver, instance, 0,
|
|
ppp_driver.maxlen - ppp_driver.lnh - ppp_driver.lnt, speed);
|
|
}
|
|
}
|