URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
Compare Revisions
- This comparison shows the changes necessary to convert path
/openrisc/trunk/rtos/rtems/c/src/libnetworking/pppd
- from Rev 30 to Rev 173
- ↔ Reverse comparison
Rev 30 → Rev 173
/ppp_tty.c
0,0 → 1,1080
/* |
* ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous |
* tty devices. |
* |
* Copyright (c) 1989 Carnegie Mellon University. |
* All rights reserved. |
* |
* 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 Carnegie Mellon University. The name of the |
* University 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. |
* |
* Drew D. Perkins |
* Carnegie Mellon University |
* 4910 Forbes Ave. |
* Pittsburgh, PA 15213 |
* (412) 268-8576 |
* ddp@andrew.cmu.edu |
* |
* Based on: |
* @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89 |
* |
* Copyright (c) 1987 Regents of the University of California. |
* All rights reserved. |
* |
* 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 University of California, Berkeley. The name of the |
* University 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. |
* |
* Serial Line interface |
* |
* Rick Adams |
* Center for Seismic Studies |
* 1300 N 17th Street, Suite 1450 |
* Arlington, Virginia 22209 |
* (703)276-7900 |
* rick@seismo.ARPA |
* seismo!rick |
* |
* Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris). |
* Converted to 4.3BSD Beta by Chris Torek. |
* Other changes made at Berkeley, based in part on code by Kirk Smith. |
* |
* Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com) |
* Added VJ tcp header compression; more unified ioctls |
* |
* Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au). |
* Cleaned up a lot of the mbuf-related code to fix bugs that |
* caused system crashes and packet corruption. Changed pppstart |
* so that it doesn't just give up with a "collision" if the whole |
* packet doesn't fit in the output ring buffer. |
* |
* Added priority queueing for interactive IP packets, following |
* the model of if_sl.c, plus hooks for bpf. |
* Paul Mackerras (paulus@cs.anu.edu.au). |
*/ |
|
/* $Id: ppp_tty.c,v 1.2 2001-09-27 12:01:57 chris Exp $ */ |
/* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */ |
/* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:58 cgd Exp */ |
|
#include "ppp.h" |
#if NPPP > 0 |
|
#define VJC |
#define PPP_COMPRESS |
|
#include <sys/param.h> |
#include <sys/systm.h> |
#include <sys/proc.h> |
#include <sys/mbuf.h> |
#include <sys/dkstat.h> |
#include <sys/socket.h> |
#include <sys/ioctl.h> |
#include <sys/file.h> |
#include <sys/tty.h> |
#include <sys/kernel.h> |
#include <sys/conf.h> |
#include <sys/vnode.h> |
|
#include <net/if.h> |
#include <net/if_types.h> |
|
#ifdef VJC |
#include <netinet/in.h> |
#include <netinet/in_systm.h> |
#include <netinet/ip.h> |
#include <net/pppcompress.h> |
#endif |
|
#ifdef PPP_FILTER |
#include <net/bpf.h> |
#endif |
#include <net/ppp_defs.h> |
#include <net/if_ppp.h> |
#include <net/if_pppvar.h> |
|
void pppasyncattach __P((void)); |
int pppopen __P((dev_t dev, struct tty *tp)); |
int pppclose __P((struct tty *tp, int flag)); |
int pppread __P((struct tty *tp, struct uio *uio, int flag)); |
int pppwrite __P((struct tty *tp, struct uio *uio, int flag)); |
int ppptioctl __P((struct tty *tp, int cmd, caddr_t data, int flag, |
struct proc *)); |
int pppinput __P((int c, struct tty *tp)); |
int pppstart __P((struct tty *tp)); |
|
static u_short pppfcs __P((u_short fcs, u_char *cp, int len)); |
static void pppasyncstart __P((struct ppp_softc *)); |
static void pppasyncctlp __P((struct ppp_softc *)); |
static void pppasyncrelinq __P((struct ppp_softc *)); |
static void ppp_timeout __P((void *)); |
static void pppgetm __P((struct ppp_softc *sc)); |
static void pppdumpb __P((u_char *b, int l)); |
static void ppplogchar __P((struct ppp_softc *, int)); |
|
/* |
* Some useful mbuf macros not in mbuf.h. |
*/ |
#define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT) |
|
#define M_DATASTART(m) \ |
(M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \ |
(m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat) |
|
#define M_DATASIZE(m) \ |
(M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \ |
(m)->m_flags & M_PKTHDR ? MHLEN: MLEN) |
|
/* |
* Does c need to be escaped? |
*/ |
#define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F))) |
|
/* |
* Procedures for using an async tty interface for PPP. |
*/ |
|
/* This is a FreeBSD-2.0 kernel. */ |
#define CCOUNT(q) ((q)->c_cc) |
#define PPP_LOWAT 100 /* Process more output when < LOWAT on queue */ |
#define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */ |
|
/* |
* Define the PPP line discipline. |
*/ |
|
static struct linesw pppdisc = { |
pppopen, pppclose, pppread, pppwrite, ppptioctl, |
pppinput, pppstart, ttymodem |
}; |
|
void |
pppasyncattach() |
{ |
linesw[PPPDISC] = pppdisc; |
} |
|
TEXT_SET(pseudo_set, pppasyncattach); |
|
/* |
* Line specific open routine for async tty devices. |
* Attach the given tty to the first available ppp unit. |
* Called from device open routine or ttioctl. |
*/ |
/* ARGSUSED */ |
int |
pppopen(dev, tp) |
dev_t dev; |
register struct tty *tp; |
{ |
struct proc *p = curproc; /* XXX */ |
register struct ppp_softc *sc; |
int error, s; |
|
if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) |
return (error); |
|
s = spltty(); |
|
if (tp->t_line == PPPDISC) { |
sc = (struct ppp_softc *) tp->t_sc; |
if (sc != NULL && sc->sc_devp == (void *) tp) { |
splx(s); |
return (0); |
} |
} |
|
if ((sc = pppalloc(p->p_pid)) == NULL) { |
splx(s); |
return ENXIO; |
} |
|
if (sc->sc_relinq) |
(*sc->sc_relinq)(sc); /* get previous owner to relinquish the unit */ |
|
sc->sc_ilen = 0; |
sc->sc_m = NULL; |
bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap)); |
sc->sc_asyncmap[0] = 0xffffffff; |
sc->sc_asyncmap[3] = 0x60000000; |
sc->sc_rasyncmap = 0; |
sc->sc_devp = (void *) tp; |
sc->sc_start = pppasyncstart; |
sc->sc_ctlp = pppasyncctlp; |
sc->sc_relinq = pppasyncrelinq; |
sc->sc_outm = NULL; |
pppgetm(sc); |
sc->sc_if.if_flags |= IFF_RUNNING; |
sc->sc_if.if_baudrate = tp->t_ospeed; |
|
tp->t_sc = (caddr_t) sc; |
ttyflush(tp, FREAD | FWRITE); |
|
splx(s); |
return (0); |
} |
|
/* |
* Line specific close routine, called from device close routine |
* and from ttioctl. |
* Detach the tty from the ppp unit. |
* Mimics part of ttyclose(). |
*/ |
int |
pppclose(tp, flag) |
struct tty *tp; |
int flag; |
{ |
register struct ppp_softc *sc; |
int s; |
|
s = spltty(); |
ttyflush(tp, FREAD|FWRITE); |
tp->t_line = 0; |
sc = (struct ppp_softc *) tp->t_sc; |
if (sc != NULL) { |
tp->t_sc = NULL; |
if (tp == (struct tty *) sc->sc_devp) { |
pppasyncrelinq(sc); |
pppdealloc(sc); |
} |
} |
splx(s); |
return 0; |
} |
|
/* |
* Relinquish the interface unit to another device. |
*/ |
static void |
pppasyncrelinq(sc) |
struct ppp_softc *sc; |
{ |
int s; |
|
s = spltty(); |
if (sc->sc_outm) { |
m_freem(sc->sc_outm); |
sc->sc_outm = NULL; |
} |
if (sc->sc_m) { |
m_freem(sc->sc_m); |
sc->sc_m = NULL; |
} |
if (sc->sc_flags & SC_TIMEOUT) { |
untimeout(ppp_timeout, (void *) sc); |
sc->sc_flags &= ~SC_TIMEOUT; |
} |
splx(s); |
} |
|
/* |
* Line specific (tty) read routine. |
*/ |
int |
pppread(tp, uio, flag) |
register struct tty *tp; |
struct uio *uio; |
int flag; |
{ |
register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc; |
struct mbuf *m, *m0; |
register int s; |
int error = 0; |
|
if (sc == NULL) |
return 0; |
/* |
* Loop waiting for input, checking that nothing disasterous |
* happens in the meantime. |
*/ |
s = spltty(); |
for (;;) { |
if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) { |
splx(s); |
return 0; |
} |
if (sc->sc_inq.ifq_head != NULL) |
break; |
if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0 |
&& (tp->t_state & TS_ISOPEN)) { |
splx(s); |
return 0; /* end of file */ |
} |
if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) { |
splx(s); |
return (EWOULDBLOCK); |
} |
error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, "ttyin", 0); |
if (error) { |
splx(s); |
return error; |
} |
} |
|
/* Pull place-holder byte out of canonical queue */ |
getc(&tp->t_canq); |
|
/* Get the packet from the input queue */ |
IF_DEQUEUE(&sc->sc_inq, m0); |
splx(s); |
|
for (m = m0; m && uio->uio_resid; m = m->m_next) |
if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0) |
break; |
m_freem(m0); |
return (error); |
} |
|
/* |
* Line specific (tty) write routine. |
*/ |
int |
pppwrite(tp, uio, flag) |
register struct tty *tp; |
struct uio *uio; |
int flag; |
{ |
register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc; |
struct mbuf *m, *m0, **mp; |
struct sockaddr dst; |
int len, error; |
|
if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) |
return 0; /* wrote 0 bytes */ |
if (tp->t_line != PPPDISC) |
return (EINVAL); |
if (sc == NULL || tp != (struct tty *) sc->sc_devp) |
return EIO; |
if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN || |
uio->uio_resid < PPP_HDRLEN) |
return (EMSGSIZE); |
for (mp = &m0; uio->uio_resid; mp = &m->m_next) { |
MGET(m, M_WAIT, MT_DATA); |
if ((*mp = m) == NULL) { |
m_freem(m0); |
return (ENOBUFS); |
} |
m->m_len = 0; |
if (uio->uio_resid >= MCLBYTES / 2) |
MCLGET(m, M_DONTWAIT); |
len = M_TRAILINGSPACE(m); |
if (len > uio->uio_resid) |
len = uio->uio_resid; |
if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) { |
m_freem(m0); |
return (error); |
} |
m->m_len = len; |
} |
dst.sa_family = AF_UNSPEC; |
bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN); |
m0->m_data += PPP_HDRLEN; |
m0->m_len -= PPP_HDRLEN; |
return (pppoutput(&sc->sc_if, m0, &dst, (struct rtentry *)0)); |
} |
|
/* |
* Line specific (tty) ioctl routine. |
* This discipline requires that tty device drivers call |
* the line specific l_ioctl routine from their ioctl routines. |
*/ |
/* ARGSUSED */ |
int |
ppptioctl(tp, cmd, data, flag, p) |
struct tty *tp; |
int cmd; |
caddr_t data; |
int flag; |
struct proc *p; |
{ |
struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc; |
int error, s; |
|
if (sc == NULL || tp != (struct tty *) sc->sc_devp) |
return -1; |
|
error = 0; |
switch (cmd) { |
case PPPIOCSASYNCMAP: |
if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) |
break; |
sc->sc_asyncmap[0] = *(u_int *)data; |
break; |
|
case PPPIOCGASYNCMAP: |
*(u_int *)data = sc->sc_asyncmap[0]; |
break; |
|
case PPPIOCSRASYNCMAP: |
if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) |
break; |
sc->sc_rasyncmap = *(u_int *)data; |
break; |
|
case PPPIOCGRASYNCMAP: |
*(u_int *)data = sc->sc_rasyncmap; |
break; |
|
case PPPIOCSXASYNCMAP: |
if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) |
break; |
s = spltty(); |
bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap)); |
sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */ |
sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */ |
sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */ |
splx(s); |
break; |
|
case PPPIOCGXASYNCMAP: |
bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap)); |
break; |
|
default: |
error = pppioctl(sc, cmd, data, flag, p); |
if (error == 0 && cmd == PPPIOCSMRU) |
pppgetm(sc); |
} |
|
return error; |
} |
|
/* |
* FCS lookup table as calculated by genfcstab. |
*/ |
static u_short fcstab[256] = { |
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, |
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, |
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, |
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, |
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, |
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, |
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, |
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, |
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, |
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, |
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, |
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, |
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, |
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, |
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, |
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, |
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, |
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, |
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, |
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, |
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, |
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, |
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, |
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, |
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, |
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, |
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, |
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, |
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, |
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, |
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, |
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 |
}; |
|
/* |
* Calculate a new FCS given the current FCS and the new data. |
*/ |
static u_short |
pppfcs(fcs, cp, len) |
register u_short fcs; |
register u_char *cp; |
register int len; |
{ |
while (len--) |
fcs = PPP_FCS(fcs, *cp++); |
return (fcs); |
} |
|
/* |
* This gets called at splsoftnet from if_ppp.c at various times |
* when there is data ready to be sent. |
*/ |
static void |
pppasyncstart(sc) |
register struct ppp_softc *sc; |
{ |
register struct tty *tp = (struct tty *) sc->sc_devp; |
register struct mbuf *m; |
register int len; |
register u_char *start, *stop, *cp; |
int n, ndone, done, idle; |
struct mbuf *m2; |
int s; |
|
idle = 0; |
while (CCOUNT(&tp->t_outq) < PPP_HIWAT) { |
/* |
* See if we have an existing packet partly sent. |
* If not, get a new packet and start sending it. |
*/ |
m = sc->sc_outm; |
if (m == NULL) { |
/* |
* Get another packet to be sent. |
*/ |
m = ppp_dequeue(sc); |
if (m == NULL) { |
idle = 1; |
break; |
} |
|
/* |
* The extra PPP_FLAG will start up a new packet, and thus |
* will flush any accumulated garbage. We do this whenever |
* the line may have been idle for some time. |
*/ |
if (CCOUNT(&tp->t_outq) == 0) { |
++sc->sc_stats.ppp_obytes; |
(void) putc(PPP_FLAG, &tp->t_outq); |
} |
|
/* Calculate the FCS for the first mbuf's worth. */ |
sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len); |
sc->sc_if.if_lastchange = time; |
} |
|
for (;;) { |
start = mtod(m, u_char *); |
len = m->m_len; |
stop = start + len; |
while (len > 0) { |
/* |
* Find out how many bytes in the string we can |
* handle without doing something special. |
*/ |
for (cp = start; cp < stop; cp++) |
if (ESCAPE_P(*cp)) |
break; |
n = cp - start; |
if (n) { |
/* NetBSD (0.9 or later), 4.3-Reno or similar. */ |
ndone = n - b_to_q(start, n, &tp->t_outq); |
len -= ndone; |
start += ndone; |
sc->sc_stats.ppp_obytes += ndone; |
|
if (ndone < n) |
break; /* packet doesn't fit */ |
} |
/* |
* If there are characters left in the mbuf, |
* the first one must be special. |
* Put it out in a different form. |
*/ |
if (len) { |
s = spltty(); |
if (putc(PPP_ESCAPE, &tp->t_outq)) |
break; |
if (putc(*start ^ PPP_TRANS, &tp->t_outq)) { |
(void) unputc(&tp->t_outq); |
splx(s); |
break; |
} |
splx(s); |
sc->sc_stats.ppp_obytes += 2; |
start++; |
len--; |
} |
} |
|
/* |
* If we didn't empty this mbuf, remember where we're up to. |
* If we emptied the last mbuf, try to add the FCS and closing |
* flag, and if we can't, leave sc_outm pointing to m, but with |
* m->m_len == 0, to remind us to output the FCS and flag later. |
*/ |
done = len == 0; |
if (done && m->m_next == NULL) { |
u_char *p, *q; |
int c; |
u_char endseq[8]; |
|
/* |
* We may have to escape the bytes in the FCS. |
*/ |
p = endseq; |
c = ~sc->sc_outfcs & 0xFF; |
if (ESCAPE_P(c)) { |
*p++ = PPP_ESCAPE; |
*p++ = c ^ PPP_TRANS; |
} else |
*p++ = c; |
c = (~sc->sc_outfcs >> 8) & 0xFF; |
if (ESCAPE_P(c)) { |
*p++ = PPP_ESCAPE; |
*p++ = c ^ PPP_TRANS; |
} else |
*p++ = c; |
*p++ = PPP_FLAG; |
|
/* |
* Try to output the FCS and flag. If the bytes |
* don't all fit, back out. |
*/ |
s = spltty(); |
for (q = endseq; q < p; ++q) |
if (putc(*q, &tp->t_outq)) { |
done = 0; |
for (; q > endseq; --q) |
unputc(&tp->t_outq); |
break; |
} |
splx(s); |
if (done) |
sc->sc_stats.ppp_obytes += q - endseq; |
} |
|
if (!done) { |
/* remember where we got to */ |
m->m_data = start; |
m->m_len = len; |
break; |
} |
|
/* Finished with this mbuf; free it and move on. */ |
MFREE(m, m2); |
m = m2; |
if (m == NULL) { |
/* Finished a packet */ |
break; |
} |
sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len); |
} |
|
/* |
* If m == NULL, we have finished a packet. |
* If m != NULL, we've either done as much work this time |
* as we need to, or else we've filled up the output queue. |
*/ |
sc->sc_outm = m; |
if (m) |
break; |
} |
|
/* Call pppstart to start output again if necessary. */ |
s = spltty(); |
pppstart(tp); |
|
/* |
* This timeout is needed for operation on a pseudo-tty, |
* because the pty code doesn't call pppstart after it has |
* drained the t_outq. |
*/ |
if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) { |
timeout(ppp_timeout, (void *) sc, 1); |
sc->sc_flags |= SC_TIMEOUT; |
} |
|
splx(s); |
} |
|
/* |
* This gets called when a received packet is placed on |
* the inq, at splsoftnet. |
*/ |
static void |
pppasyncctlp(sc) |
struct ppp_softc *sc; |
{ |
struct tty *tp; |
int s; |
|
/* Put a placeholder byte in canq for ttselect()/ttnread(). */ |
s = spltty(); |
tp = (struct tty *) sc->sc_devp; |
putc(0, &tp->t_canq); |
ttwakeup(tp); |
splx(s); |
} |
|
/* |
* Start output on async tty interface. If the transmit queue |
* has drained sufficiently, arrange for pppasyncstart to be |
* called later at splsoftnet. |
* Called at spltty or higher. |
*/ |
int |
pppstart(tp) |
register struct tty *tp; |
{ |
register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc; |
|
/* |
* If there is stuff in the output queue, send it now. |
* We are being called in lieu of ttstart and must do what it would. |
*/ |
if (tp->t_oproc != NULL) |
(*tp->t_oproc)(tp); |
|
/* |
* If the transmit queue has drained and the tty has not hung up |
* or been disconnected from the ppp unit, then tell if_ppp.c that |
* we need more output. |
*/ |
if (CCOUNT(&tp->t_outq) < PPP_LOWAT |
&& !((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) |
&& sc != NULL && tp == (struct tty *) sc->sc_devp) { |
ppp_restart(sc); |
} |
|
return 0; |
} |
|
/* |
* Timeout routine - try to start some more output. |
*/ |
static void |
ppp_timeout(x) |
void *x; |
{ |
struct ppp_softc *sc = (struct ppp_softc *) x; |
struct tty *tp = (struct tty *) sc->sc_devp; |
int s; |
|
s = spltty(); |
sc->sc_flags &= ~SC_TIMEOUT; |
pppstart(tp); |
splx(s); |
} |
|
/* |
* Allocate enough mbuf to handle current MRU. |
*/ |
static void |
pppgetm(sc) |
register struct ppp_softc *sc; |
{ |
struct mbuf *m, **mp; |
int len; |
|
mp = &sc->sc_m; |
for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){ |
if ((m = *mp) == NULL) { |
MGETHDR(m, M_DONTWAIT, MT_DATA); |
if (m == NULL) |
break; |
*mp = m; |
MCLGET(m, M_DONTWAIT); |
} |
len -= M_DATASIZE(m); |
mp = &m->m_next; |
} |
} |
|
/* |
* tty interface receiver interrupt. |
*/ |
static unsigned paritytab[8] = { |
0x96696996, 0x69969669, 0x69969669, 0x96696996, |
0x69969669, 0x96696996, 0x96696996, 0x69969669 |
}; |
|
int |
pppinput(c, tp) |
int c; |
register struct tty *tp; |
{ |
register struct ppp_softc *sc; |
struct mbuf *m; |
int ilen, s; |
|
sc = (struct ppp_softc *) tp->t_sc; |
if (sc == NULL || tp != (struct tty *) sc->sc_devp) |
return 0; |
|
++tk_nin; |
++sc->sc_stats.ppp_ibytes; |
|
if (c & TTY_FE) { |
/* framing error or overrun on this char - abort packet */ |
if (sc->sc_flags & SC_DEBUG) |
printf("ppp%d: bad char %x\n", sc->sc_if.if_unit, c); |
goto flush; |
} |
|
c &= 0xff; |
|
/* |
* Handle software flow control of output. |
*/ |
if (tp->t_iflag & IXON) { |
if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) { |
if ((tp->t_state & TS_TTSTOP) == 0) { |
tp->t_state |= TS_TTSTOP; |
(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); |
} |
return 0; |
} |
if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) { |
tp->t_state &= ~TS_TTSTOP; |
if (tp->t_oproc != NULL) |
(*tp->t_oproc)(tp); |
return 0; |
} |
} |
|
s = spltty(); |
if (c & 0x80) |
sc->sc_flags |= SC_RCV_B7_1; |
else |
sc->sc_flags |= SC_RCV_B7_0; |
if (paritytab[c >> 5] & (1 << (c & 0x1F))) |
sc->sc_flags |= SC_RCV_ODDP; |
else |
sc->sc_flags |= SC_RCV_EVNP; |
splx(s); |
|
if (sc->sc_flags & SC_LOG_RAWIN) |
ppplogchar(sc, c); |
|
if (c == PPP_FLAG) { |
ilen = sc->sc_ilen; |
sc->sc_ilen = 0; |
|
if (sc->sc_rawin_count > 0) |
ppplogchar(sc, -1); |
|
/* |
* If SC_ESCAPED is set, then we've seen the packet |
* abort sequence "}~". |
*/ |
if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED) |
|| (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) { |
s = spltty(); |
sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */ |
if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){ |
if (sc->sc_flags & SC_DEBUG) |
printf("ppp%d: bad fcs %x, pkt len %d\n", |
sc->sc_if.if_unit, sc->sc_fcs, ilen); |
sc->sc_if.if_ierrors++; |
sc->sc_stats.ppp_ierrors++; |
} else |
sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED); |
splx(s); |
return 0; |
} |
|
if (ilen < PPP_HDRLEN + PPP_FCSLEN) { |
if (ilen) { |
if (sc->sc_flags & SC_DEBUG) |
printf("ppp%d: too short (%d)\n", sc->sc_if.if_unit, ilen); |
s = spltty(); |
sc->sc_if.if_ierrors++; |
sc->sc_stats.ppp_ierrors++; |
sc->sc_flags |= SC_PKTLOST; |
splx(s); |
} |
return 0; |
} |
|
/* |
* Remove FCS trailer. Somewhat painful... |
*/ |
ilen -= 2; |
if (--sc->sc_mc->m_len == 0) { |
for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next) |
; |
sc->sc_mc = m; |
} |
sc->sc_mc->m_len--; |
|
/* excise this mbuf chain */ |
m = sc->sc_m; |
sc->sc_m = sc->sc_mc->m_next; |
sc->sc_mc->m_next = NULL; |
|
ppppktin(sc, m, sc->sc_flags & SC_PKTLOST); |
if (sc->sc_flags & SC_PKTLOST) { |
s = spltty(); |
sc->sc_flags &= ~SC_PKTLOST; |
splx(s); |
} |
|
pppgetm(sc); |
return 0; |
} |
|
if (sc->sc_flags & SC_FLUSH) { |
if (sc->sc_flags & SC_LOG_FLUSH) |
ppplogchar(sc, c); |
return 0; |
} |
|
if (c < 0x20 && (sc->sc_rasyncmap & (1 << c))) |
return 0; |
|
s = spltty(); |
if (sc->sc_flags & SC_ESCAPED) { |
sc->sc_flags &= ~SC_ESCAPED; |
c ^= PPP_TRANS; |
} else if (c == PPP_ESCAPE) { |
sc->sc_flags |= SC_ESCAPED; |
splx(s); |
return 0; |
} |
splx(s); |
|
/* |
* Initialize buffer on first octet received. |
* First octet could be address or protocol (when compressing |
* address/control). |
* Second octet is control. |
* Third octet is first or second (when compressing protocol) |
* octet of protocol. |
* Fourth octet is second octet of protocol. |
*/ |
if (sc->sc_ilen == 0) { |
/* reset the first input mbuf */ |
if (sc->sc_m == NULL) { |
pppgetm(sc); |
if (sc->sc_m == NULL) { |
if (sc->sc_flags & SC_DEBUG) |
printf("ppp%d: no input mbufs!\n", sc->sc_if.if_unit); |
goto flush; |
} |
} |
m = sc->sc_m; |
m->m_len = 0; |
m->m_data = M_DATASTART(sc->sc_m); |
sc->sc_mc = m; |
sc->sc_mp = mtod(m, char *); |
sc->sc_fcs = PPP_INITFCS; |
if (c != PPP_ALLSTATIONS) { |
if (sc->sc_flags & SC_REJ_COMP_AC) { |
if (sc->sc_flags & SC_DEBUG) |
printf("ppp%d: garbage received: 0x%x (need 0xFF)\n", |
sc->sc_if.if_unit, c); |
goto flush; |
} |
*sc->sc_mp++ = PPP_ALLSTATIONS; |
*sc->sc_mp++ = PPP_UI; |
sc->sc_ilen += 2; |
m->m_len += 2; |
} |
} |
if (sc->sc_ilen == 1 && c != PPP_UI) { |
if (sc->sc_flags & SC_DEBUG) |
printf("ppp%d: missing UI (0x3), got 0x%x\n", |
sc->sc_if.if_unit, c); |
goto flush; |
} |
if (sc->sc_ilen == 2 && (c & 1) == 1) { |
/* a compressed protocol */ |
*sc->sc_mp++ = 0; |
sc->sc_ilen++; |
sc->sc_mc->m_len++; |
} |
if (sc->sc_ilen == 3 && (c & 1) == 0) { |
if (sc->sc_flags & SC_DEBUG) |
printf("ppp%d: bad protocol %x\n", sc->sc_if.if_unit, |
(sc->sc_mp[-1] << 8) + c); |
goto flush; |
} |
|
/* packet beyond configured mru? */ |
if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) { |
if (sc->sc_flags & SC_DEBUG) |
printf("ppp%d: packet too big\n", sc->sc_if.if_unit); |
goto flush; |
} |
|
/* is this mbuf full? */ |
m = sc->sc_mc; |
if (M_TRAILINGSPACE(m) <= 0) { |
if (m->m_next == NULL) { |
pppgetm(sc); |
if (m->m_next == NULL) { |
if (sc->sc_flags & SC_DEBUG) |
printf("ppp%d: too few input mbufs!\n", sc->sc_if.if_unit); |
goto flush; |
} |
} |
sc->sc_mc = m = m->m_next; |
m->m_len = 0; |
m->m_data = M_DATASTART(m); |
sc->sc_mp = mtod(m, char *); |
} |
|
++m->m_len; |
*sc->sc_mp++ = c; |
sc->sc_fcs = PPP_FCS(sc->sc_fcs, c); |
return 0; |
|
flush: |
if (!(sc->sc_flags & SC_FLUSH)) { |
s = spltty(); |
sc->sc_if.if_ierrors++; |
sc->sc_stats.ppp_ierrors++; |
sc->sc_flags |= SC_FLUSH; |
splx(s); |
if (sc->sc_flags & SC_LOG_FLUSH) |
ppplogchar(sc, c); |
} |
return 0; |
} |
|
#define MAX_DUMP_BYTES 128 |
|
static void |
ppplogchar(sc, c) |
struct ppp_softc *sc; |
int c; |
{ |
if (c >= 0) |
sc->sc_rawin[sc->sc_rawin_count++] = c; |
if (sc->sc_rawin_count >= sizeof(sc->sc_rawin) |
|| (c < 0 && sc->sc_rawin_count > 0)) { |
printf("ppp%d input: ", sc->sc_if.if_unit); |
pppdumpb(sc->sc_rawin, sc->sc_rawin_count); |
sc->sc_rawin_count = 0; |
} |
} |
|
static void |
pppdumpb(b, l) |
u_char *b; |
int l; |
{ |
char buf[3*MAX_DUMP_BYTES+4]; |
char *bp = buf; |
static char digits[] = "0123456789abcdef"; |
|
while (l--) { |
if (bp >= buf + sizeof(buf) - 3) { |
*bp++ = '>'; |
break; |
} |
*bp++ = digits[*b >> 4]; /* convert byte to ascii hex */ |
*bp++ = digits[*b++ & 0xf]; |
*bp++ = ' '; |
} |
|
*bp = 0; |
printf("%s\n", buf); |
} |
|
#endif /* NPPP > 0 */ |
/ipcp.h
0,0 → 1,70
/* |
* ipcp.h - IP Control Protocol definitions. |
* |
* Copyright (c) 1989 Carnegie Mellon University. |
* All rights reserved. |
* |
* 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 Carnegie Mellon University. The name of the |
* University may not be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
* |
* $Id: ipcp.h,v 1.2 2001-09-27 12:01:57 chris Exp $ |
*/ |
|
/* |
* Options. |
*/ |
#define CI_ADDRS 1 /* IP Addresses */ |
#define CI_COMPRESSTYPE 2 /* Compression Type */ |
#define CI_ADDR 3 |
|
#define CI_MS_DNS1 129 /* Primary DNS value */ |
#define CI_MS_WINS1 130 /* Primary WINS value */ |
#define CI_MS_DNS2 131 /* Secondary DNS value */ |
#define CI_MS_WINS2 132 /* Secondary WINS value */ |
|
#define MAX_STATES 16 /* from slcompress.h */ |
|
#define IPCP_VJMODE_OLD 1 /* "old" mode (option # = 0x0037) */ |
#define IPCP_VJMODE_RFC1172 2 /* "old-rfc"mode (option # = 0x002d) */ |
#define IPCP_VJMODE_RFC1332 3 /* "new-rfc"mode (option # = 0x002d, */ |
/* maxslot and slot number compression) */ |
|
#define IPCP_VJ_COMP 0x002d /* current value for VJ compression option*/ |
#define IPCP_VJ_COMP_OLD 0x0037 /* "old" (i.e, broken) value for VJ */ |
/* compression option*/ |
|
typedef struct ipcp_options { |
int neg_addr : 1; /* Negotiate IP Address? */ |
int old_addrs : 1; /* Use old (IP-Addresses) option? */ |
int req_addr : 1; /* Ask peer to send IP address? */ |
int default_route : 1; /* Assign default route through interface? */ |
int proxy_arp : 1; /* Make proxy ARP entry for peer? */ |
int neg_vj : 1; /* Van Jacobson Compression? */ |
int old_vj : 1; /* use old (short) form of VJ option? */ |
int accept_local : 1; /* accept peer's value for ouraddr */ |
int accept_remote : 1; /* accept peer's value for hisaddr */ |
u_short vj_protocol; /* protocol value to use in VJ option */ |
u_char maxslotindex, cflag; /* values for RFC1332 VJ compression neg. */ |
u_int32_t ouraddr, hisaddr; /* Addresses in NETWORK BYTE ORDER */ |
u_int32_t dnsaddr[2]; /* Primary and secondary MS DNS entries */ |
u_int32_t winsaddr[2]; /* Primary and secondary MS WINS entries */ |
} ipcp_options; |
|
extern fsm ipcp_fsm[]; |
extern ipcp_options ipcp_wantoptions[]; |
extern ipcp_options ipcp_gotoptions[]; |
extern ipcp_options ipcp_allowoptions[]; |
extern ipcp_options ipcp_hisoptions[]; |
|
char *ip_ntoa __P((u_int32_t)); |
|
extern struct protent ipcp_protent; |
/STATUS
0,0 → 1,27
# |
# $Id: STATUS,v 1.2 2001-09-27 12:01:57 chris Exp $ |
# |
|
Overall, this code should still be considered in its early stages. It |
works but has some distance to go before it is fully documented and |
easily configurable. |
|
+ Compare the code to the original 2.3.5 and eliminate spurious changes. |
|
+ Update the code to 2.3.10. |
|
+ Eliminate items specific to Tomasz' system. In particular, the |
code reports status and gets configuration information in a system |
specific manner. main.c is particularly guilty of this although |
other files suffer from this also. |
|
+ Find comments in Polish and get Tomasz to translate them. :) |
|
+ Add netdemo showing configuration and initialization. |
|
+ Get feature list. |
|
+ Document dialer setup. |
|
+ Only modem driver is system specific so there is the possibility |
that shareable code exists in it. |
/upap.c
0,0 → 1,619
/* |
* upap.c - User/Password Authentication Protocol. |
* |
* Copyright (c) 1989 Carnegie Mellon University. |
* All rights reserved. |
* |
* 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 Carnegie Mellon University. The name of the |
* University 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. |
*/ |
|
#ifndef lint |
/* static char rcsid[] = "$Id: upap.c,v 1.2 2001-09-27 12:01:57 chris Exp $"; */ |
#endif |
|
/* |
* TODO: |
*/ |
|
#include <stdio.h> |
#include <string.h> |
#include <sys/types.h> |
#include <sys/time.h> |
#include <syslog.h> |
|
#include "pppd.h" |
#include "upap.h" |
#define print_string(user, ulen, printer, arg) |
|
/* |
* Protocol entry points. |
*/ |
static void upap_init __P((int)); |
static void upap_lowerup __P((int)); |
static void upap_lowerdown __P((int)); |
static void upap_input __P((int, u_char *, int)); |
static void upap_protrej __P((int)); |
static int upap_printpkt __P((u_char *, int, |
void (*) __P((void *, char *, ...)), void *)); |
|
struct protent pap_protent = { |
PPP_PAP, |
upap_init, |
upap_input, |
upap_protrej, |
upap_lowerup, |
upap_lowerdown, |
NULL, |
NULL, |
upap_printpkt, |
NULL, |
1, |
"PAP", |
NULL, |
NULL, |
NULL |
}; |
|
upap_state upap[NUM_PPP]; /* UPAP state; one for each unit */ |
|
static void upap_timeout __P((void *)); |
static void upap_reqtimeout __P((void *)); |
static void upap_rauthreq __P((upap_state *, u_char *, int, int)); |
static void upap_rauthack __P((upap_state *, u_char *, int, int)); |
static void upap_rauthnak __P((upap_state *, u_char *, int, int)); |
static void upap_sauthreq __P((upap_state *)); |
static void upap_sresp __P((upap_state *, int, int, char *, int)); |
|
|
/* |
* upap_init - Initialize a UPAP unit. |
*/ |
static void |
upap_init(unit) |
int unit; |
{ |
upap_state *u = &upap[unit]; |
|
u->us_unit = unit; |
u->us_user = NULL; |
u->us_userlen = 0; |
u->us_passwd = NULL; |
u->us_passwdlen = 0; |
u->us_clientstate = UPAPCS_INITIAL; |
u->us_serverstate = UPAPSS_INITIAL; |
u->us_id = 0; |
u->us_timeouttime = UPAP_DEFTIMEOUT; |
u->us_maxtransmits = 10; |
u->us_reqtimeout = UPAP_DEFREQTIME; |
} |
|
|
/* |
* upap_authwithpeer - Authenticate us with our peer (start client). |
* |
* Set new state and send authenticate's. |
*/ |
void |
upap_authwithpeer(unit, user, password) |
int unit; |
char *user, *password; |
{ |
upap_state *u = &upap[unit]; |
|
/* Save the username and password we're given */ |
u->us_user = user; |
u->us_userlen = strlen(user); |
u->us_passwd = password; |
u->us_passwdlen = strlen(password); |
u->us_transmits = 0; |
|
/* Lower layer up yet? */ |
if (u->us_clientstate == UPAPCS_INITIAL || |
u->us_clientstate == UPAPCS_PENDING) { |
u->us_clientstate = UPAPCS_PENDING; |
return; |
} |
|
upap_sauthreq(u); /* Start protocol */ |
} |
|
|
/* |
* upap_authpeer - Authenticate our peer (start server). |
* |
* Set new state. |
*/ |
void |
upap_authpeer(unit) |
int unit; |
{ |
upap_state *u = &upap[unit]; |
|
/* Lower layer up yet? */ |
if (u->us_serverstate == UPAPSS_INITIAL || |
u->us_serverstate == UPAPSS_PENDING) { |
u->us_serverstate = UPAPSS_PENDING; |
return; |
} |
|
u->us_serverstate = UPAPSS_LISTEN; |
if (u->us_reqtimeout > 0) |
TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout); |
} |
|
|
/* |
* upap_timeout - Retransmission timer for sending auth-reqs expired. |
*/ |
static void |
upap_timeout(arg) |
void *arg; |
{ |
upap_state *u = (upap_state *) arg; |
|
if (u->us_clientstate != UPAPCS_AUTHREQ) |
return; |
|
if (u->us_transmits >= u->us_maxtransmits) { |
/* give up in disgust */ |
syslog(LOG_ERR, "No response to PAP authenticate-requests"); |
u->us_clientstate = UPAPCS_BADAUTH; |
auth_withpeer_fail(u->us_unit, PPP_PAP); |
return; |
} |
|
upap_sauthreq(u); /* Send Authenticate-Request */ |
} |
|
|
/* |
* upap_reqtimeout - Give up waiting for the peer to send an auth-req. |
*/ |
static void |
upap_reqtimeout(arg) |
void *arg; |
{ |
upap_state *u = (upap_state *) arg; |
|
if (u->us_serverstate != UPAPSS_LISTEN) |
return; /* huh?? */ |
|
auth_peer_fail(u->us_unit, PPP_PAP); |
u->us_serverstate = UPAPSS_BADAUTH; |
} |
|
|
/* |
* upap_lowerup - The lower layer is up. |
* |
* Start authenticating if pending. |
*/ |
static void |
upap_lowerup(unit) |
int unit; |
{ |
upap_state *u = &upap[unit]; |
|
if (u->us_clientstate == UPAPCS_INITIAL) |
u->us_clientstate = UPAPCS_CLOSED; |
else if (u->us_clientstate == UPAPCS_PENDING) { |
upap_sauthreq(u); /* send an auth-request */ |
} |
|
if (u->us_serverstate == UPAPSS_INITIAL) |
u->us_serverstate = UPAPSS_CLOSED; |
else if (u->us_serverstate == UPAPSS_PENDING) { |
u->us_serverstate = UPAPSS_LISTEN; |
if (u->us_reqtimeout > 0) |
TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout); |
} |
} |
|
|
/* |
* upap_lowerdown - The lower layer is down. |
* |
* Cancel all timeouts. |
*/ |
static void |
upap_lowerdown(unit) |
int unit; |
{ |
upap_state *u = &upap[unit]; |
|
if (u->us_clientstate == UPAPCS_AUTHREQ) /* Timeout pending? */ |
UNTIMEOUT(upap_timeout, u); /* Cancel timeout */ |
if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0) |
UNTIMEOUT(upap_reqtimeout, u); |
|
u->us_clientstate = UPAPCS_INITIAL; |
u->us_serverstate = UPAPSS_INITIAL; |
} |
|
|
/* |
* upap_protrej - Peer doesn't speak this protocol. |
* |
* This shouldn't happen. In any case, pretend lower layer went down. |
*/ |
static void |
upap_protrej(unit) |
int unit; |
{ |
upap_state *u = &upap[unit]; |
|
if (u->us_clientstate == UPAPCS_AUTHREQ) { |
syslog(LOG_ERR, "PAP authentication failed due to protocol-reject"); |
auth_withpeer_fail(unit, PPP_PAP); |
} |
if (u->us_serverstate == UPAPSS_LISTEN) { |
syslog(LOG_ERR, "PAP authentication of peer failed (protocol-reject)"); |
auth_peer_fail(unit, PPP_PAP); |
} |
upap_lowerdown(unit); |
} |
|
|
/* |
* upap_input - Input UPAP packet. |
*/ |
static void |
upap_input(unit, inpacket, l) |
int unit; |
u_char *inpacket; |
int l; |
{ |
upap_state *u = &upap[unit]; |
u_char *inp; |
u_char code, id; |
int len; |
|
/* |
* Parse header (code, id and length). |
* If packet too short, drop it. |
*/ |
inp = inpacket; |
if (l < UPAP_HEADERLEN) { |
UPAPDEBUG((LOG_INFO, "pap_input: rcvd short header.")); |
return; |
} |
GETCHAR(code, inp); |
GETCHAR(id, inp); |
GETSHORT(len, inp); |
if (len < UPAP_HEADERLEN) { |
UPAPDEBUG((LOG_INFO, "pap_input: rcvd illegal length.")); |
return; |
} |
if (len > l) { |
UPAPDEBUG((LOG_INFO, "pap_input: rcvd short packet.")); |
return; |
} |
len -= UPAP_HEADERLEN; |
|
/* |
* Action depends on code. |
*/ |
switch (code) { |
case UPAP_AUTHREQ: |
upap_rauthreq(u, inp, id, len); |
break; |
|
case UPAP_AUTHACK: |
upap_rauthack(u, inp, id, len); |
break; |
|
case UPAP_AUTHNAK: |
upap_rauthnak(u, inp, id, len); |
break; |
|
default: /* XXX Need code reject */ |
break; |
} |
} |
|
|
/* |
* upap_rauth - Receive Authenticate. |
*/ |
static void |
upap_rauthreq(u, inp, id, len) |
upap_state *u; |
u_char *inp; |
int id; |
int len; |
{ |
u_char ruserlen, rpasswdlen; |
char *ruser, *rpasswd; |
int retcode; |
char *msg; |
int msglen; |
|
UPAPDEBUG((LOG_INFO, "pap_rauth: Rcvd id %d.", id)); |
|
if (u->us_serverstate < UPAPSS_LISTEN) |
return; |
|
/* |
* If we receive a duplicate authenticate-request, we are |
* supposed to return the same status as for the first request. |
*/ |
if (u->us_serverstate == UPAPSS_OPEN) { |
upap_sresp(u, UPAP_AUTHACK, id, "", 0); /* return auth-ack */ |
return; |
} |
if (u->us_serverstate == UPAPSS_BADAUTH) { |
upap_sresp(u, UPAP_AUTHNAK, id, "", 0); /* return auth-nak */ |
return; |
} |
|
/* |
* Parse user/passwd. |
*/ |
if (len < sizeof (u_char)) { |
UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.")); |
return; |
} |
GETCHAR(ruserlen, inp); |
len -= sizeof (u_char) + ruserlen + sizeof (u_char); |
if (len < 0) { |
UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.")); |
return; |
} |
ruser = (char *) inp; |
INCPTR(ruserlen, inp); |
GETCHAR(rpasswdlen, inp); |
if (len < rpasswdlen) { |
UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.")); |
return; |
} |
rpasswd = (char *) inp; |
|
/* |
* Check the username and password given. |
*/ |
retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd, |
rpasswdlen, &msg, &msglen); |
BZERO(rpasswd, rpasswdlen); |
|
upap_sresp(u, retcode, id, msg, msglen); |
|
if (retcode == UPAP_AUTHACK) { |
u->us_serverstate = UPAPSS_OPEN; |
auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen); |
} else { |
u->us_serverstate = UPAPSS_BADAUTH; |
auth_peer_fail(u->us_unit, PPP_PAP); |
} |
|
if (u->us_reqtimeout > 0) |
UNTIMEOUT(upap_reqtimeout, u); |
} |
|
|
/* |
* upap_rauthack - Receive Authenticate-Ack. |
*/ |
static void |
upap_rauthack(u, inp, id, len) |
upap_state *u; |
u_char *inp; |
int id; |
int len; |
{ |
u_char msglen; |
char *msg; |
|
UPAPDEBUG((LOG_INFO, "pap_rauthack: Rcvd id %d.", id)); |
if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */ |
return; |
|
/* |
* Parse message. |
*/ |
if (len < sizeof (u_char)) { |
UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet.")); |
return; |
} |
GETCHAR(msglen, inp); |
len -= sizeof (u_char); |
if (len < msglen) { |
UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet.")); |
return; |
} |
msg = (char *) inp; |
PRINTMSG(msg, msglen); |
|
u->us_clientstate = UPAPCS_OPEN; |
|
auth_withpeer_success(u->us_unit, PPP_PAP); |
} |
|
|
/* |
* upap_rauthnak - Receive Authenticate-Nakk. |
*/ |
static void |
upap_rauthnak(u, inp, id, len) |
upap_state *u; |
u_char *inp; |
int id; |
int len; |
{ |
u_char msglen; |
char *msg; |
|
UPAPDEBUG((LOG_INFO, "pap_rauthnak: Rcvd id %d.", id)); |
if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */ |
return; |
|
/* |
* Parse message. |
*/ |
if (len < sizeof (u_char)) { |
UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.")); |
return; |
} |
GETCHAR(msglen, inp); |
len -= sizeof (u_char); |
if (len < msglen) { |
UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.")); |
return; |
} |
msg = (char *) inp; |
PRINTMSG(msg, msglen); |
|
u->us_clientstate = UPAPCS_BADAUTH; |
|
syslog(LOG_ERR, "PAP authentication failed"); |
auth_withpeer_fail(u->us_unit, PPP_PAP); |
} |
|
|
/* |
* upap_sauthreq - Send an Authenticate-Request. |
*/ |
static void |
upap_sauthreq(u) |
upap_state *u; |
{ |
u_char *outp; |
int outlen; |
|
outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) + |
u->us_userlen + u->us_passwdlen; |
outp = outpacket_buf; |
|
MAKEHEADER(outp, PPP_PAP); |
|
PUTCHAR(UPAP_AUTHREQ, outp); |
PUTCHAR(++u->us_id, outp); |
PUTSHORT(outlen, outp); |
PUTCHAR(u->us_userlen, outp); |
BCOPY(u->us_user, outp, u->us_userlen); |
INCPTR(u->us_userlen, outp); |
PUTCHAR(u->us_passwdlen, outp); |
BCOPY(u->us_passwd, outp, u->us_passwdlen); |
|
output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN); |
|
UPAPDEBUG((LOG_INFO, "pap_sauth: Sent id %d.", u->us_id)); |
|
TIMEOUT(upap_timeout, u, u->us_timeouttime); |
++u->us_transmits; |
u->us_clientstate = UPAPCS_AUTHREQ; |
} |
|
|
/* |
* upap_sresp - Send a response (ack or nak). |
*/ |
static void |
upap_sresp(u, code, id, msg, msglen) |
upap_state *u; |
u_char code, id; |
char *msg; |
int msglen; |
{ |
u_char *outp; |
int outlen; |
|
outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen; |
outp = outpacket_buf; |
MAKEHEADER(outp, PPP_PAP); |
|
PUTCHAR(code, outp); |
PUTCHAR(id, outp); |
PUTSHORT(outlen, outp); |
PUTCHAR(msglen, outp); |
BCOPY(msg, outp, msglen); |
output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN); |
|
UPAPDEBUG((LOG_INFO, "pap_sresp: Sent code %d, id %d.", code, id)); |
} |
|
/* |
* upap_printpkt - print the contents of a PAP packet. |
*/ |
static char *upap_codenames[] = { |
"AuthReq", "AuthAck", "AuthNak" |
}; |
|
static int |
upap_printpkt(p, plen, printer, arg) |
u_char *p; |
int plen; |
void (*printer) __P((void *, char *, ...)); |
void *arg; |
{ |
int code, id, len; |
int mlen, ulen, wlen; |
char *user, *pwd, *msg; |
u_char *pstart; |
|
if (plen < UPAP_HEADERLEN) |
return 0; |
pstart = p; |
GETCHAR(code, p); |
GETCHAR(id, p); |
GETSHORT(len, p); |
if (len < UPAP_HEADERLEN || len > plen) |
return 0; |
|
if (code >= 1 && code <= sizeof(upap_codenames) / sizeof(char *)) |
printer(arg, " %s", upap_codenames[code-1]); |
else |
printer(arg, " code=0x%x", code); |
printer(arg, " id=0x%x", id); |
len -= UPAP_HEADERLEN; |
switch (code) { |
case UPAP_AUTHREQ: |
if (len < 1) |
break; |
ulen = p[0]; |
if (len < ulen + 2) |
break; |
wlen = p[ulen + 1]; |
if (len < ulen + wlen + 2) |
break; |
user = (char *) (p + 1); |
pwd = (char *) (p + ulen + 2); |
p += ulen + wlen + 2; |
len -= ulen + wlen + 2; |
printer(arg, " user="); |
print_string(user, ulen, printer, arg); |
printer(arg, " password="); |
print_string(pwd, wlen, printer, arg); |
break; |
case UPAP_AUTHACK: |
case UPAP_AUTHNAK: |
if (len < 1) |
break; |
mlen = p[0]; |
if (len < mlen + 1) |
break; |
msg = (char *) (p + 1); |
p += mlen + 1; |
len -= mlen + 1; |
printer(arg, " "); |
print_string(msg, mlen, printer, arg); |
break; |
} |
|
/* print the rest of the bytes in the packet */ |
for (; len > 0; --len) { |
GETCHAR(code, p); |
printer(arg, " %.2x", code); |
} |
|
return p - pstart; |
} |
/pppd.h
0,0 → 1,497
/* |
* pppd.h - PPP daemon global declarations. |
* |
* Copyright (c) 1989 Carnegie Mellon University. |
* All rights reserved. |
* |
* 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 Carnegie Mellon University. The name of the |
* University may not be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
* |
* $Id: pppd.h,v 1.2 2001-09-27 12:01:57 chris Exp $ |
*/ |
|
/* |
* TODO: |
*/ |
|
#ifndef __PPPD_H__ |
#define __PPPD_H__ |
|
#include <stdio.h> /* for FILE */ |
#include <sys/param.h> /* for MAXPATHLEN and BSD4_4, if defined */ |
#include <sys/types.h> /* for u_int32_t, if defined */ |
#include <sys/time.h> /* for struct timeval */ |
#include <net/ppp_defs.h> |
|
#if __STDC__ |
#include <stdarg.h> |
#define __V(x) x |
#else |
#include <varargs.h> |
#define __V(x) (va_alist) va_dcl |
#define const |
#endif |
|
/* |
* Limits. |
*/ |
|
#define NUM_PPP 1 /* One PPP interface supported (per process) */ |
#define MAXWORDLEN 1024 /* max length of word in file (incl null) */ |
#define MAXARGS 1 /* max # args to a command */ |
#define MAXNAMELEN 256 /* max length of hostname or name for auth */ |
#define MAXSECRETLEN 256 /* max length of password or secret */ |
|
/* |
* Global variables. |
*/ |
|
extern int hungup; /* Physical layer has disconnected */ |
extern int interfunit; /* Interface unit number */ |
extern char ifname[]; /* Interface name */ |
extern int ttyfd; /* Serial device file descriptor */ |
extern char hostname[]; /* Our hostname */ |
extern u_char outpacket_buf[]; /* Buffer for outgoing packets */ |
extern int phase; /* Current state of link - see values below */ |
extern int baud_rate; /* Current link speed in bits/sec */ |
extern char *progname; /* Name of this program */ |
extern int redirect_stderr;/* Connector's stderr should go to file */ |
extern char peer_authname[];/* Authenticated name of peer */ |
extern int privileged; /* We were run by real-uid root */ |
extern int need_holdoff; /* Need holdoff period after link terminates */ |
extern char **script_env; /* Environment variables for scripts */ |
extern int detached; /* Have detached from controlling tty */ |
|
/* |
* Variables set by command-line options. |
*/ |
|
extern int debug; /* Debug flag */ |
extern int kdebugflag; /* Tell kernel to print debug messages */ |
extern int default_device; /* Using /dev/tty or equivalent */ |
extern char devnam[]; /* Device name */ |
extern int crtscts; /* Use hardware flow control */ |
extern int modem; /* Use modem control lines */ |
extern int inspeed; /* Input/Output speed requested */ |
extern u_int32_t netmask; /* IP netmask to set on interface */ |
extern int lockflag; /* Create lock file to lock the serial dev */ |
extern int nodetach; /* Don't detach from controlling tty */ |
extern char *connector[]; /* Script to establish physical link */ |
extern char **disconnector; /* Script to disestablish physical link */ |
extern char **welcomer; /* Script to welcome client after connection */ |
extern int maxconnect; /* Maximum connect time (seconds) */ |
extern char user[]; /* Our name for authenticating ourselves */ |
extern char passwd[]; /* Password for PAP */ |
extern int auth_required; /* Peer is required to authenticate */ |
extern int proxyarp; /* Set up proxy ARP entry for peer */ |
extern int persist; /* Reopen link after it goes down */ |
extern int uselogin; /* Use /etc/passwd for checking PAP */ |
extern int lcp_echo_interval; /* Interval between LCP echo-requests */ |
extern int lcp_echo_fails; /* Tolerance to unanswered echo-requests */ |
extern char our_name[]; /* Our name for authentication purposes */ |
extern char remote_name[]; /* Peer's name for authentication */ |
extern int explicit_remote;/* remote_name specified with remotename opt */ |
extern int usehostname; /* Use hostname for our_name */ |
extern int disable_defaultip; /* Don't use hostname for default IP adrs */ |
extern int demand; /* Do dial-on-demand */ |
extern char *ipparam; /* Extra parameter for ip up/down scripts */ |
extern int cryptpap; /* Others' PAP passwords are encrypted */ |
extern int idle_time_limit;/* Shut down link if idle for this long */ |
extern int holdoff; /* Dead time before restarting */ |
extern int refuse_pap; /* Don't wanna auth. ourselves with PAP */ |
extern int refuse_chap; /* Don't wanna auth. ourselves with CHAP */ |
#ifdef PPP_FILTER |
extern struct bpf_program pass_filter; /* Filter for pkts to pass */ |
extern struct bpf_program active_filter; /* Filter for link-active pkts */ |
#endif |
|
|
#ifdef MSLANMAN |
extern int ms_lanman; /* Nonzero if use LanMan password instead of NT */ |
/* Has meaning only with MS-CHAP challenges */ |
#endif |
|
/* |
* Values for phase. |
*/ |
#define PHASE_DEAD 0 |
#define PHASE_INITIALIZE 1 |
#define PHASE_DORMANT 2 |
#define PHASE_ESTABLISH 3 |
#define PHASE_AUTHENTICATE 4 |
#define PHASE_CALLBACK 5 |
#define PHASE_NETWORK 6 |
#define PHASE_TERMINATE 7 |
#define PHASE_HOLDOFF 8 |
|
/* |
* The following struct gives the addresses of procedures to call |
* for a particular protocol. |
*/ |
struct protent { |
u_short protocol; /* PPP protocol number */ |
/* Initialization procedure */ |
void (*init) __P((int unit)); |
/* Process a received packet */ |
void (*input) __P((int unit, u_char *pkt, int len)); |
/* Process a received protocol-reject */ |
void (*protrej) __P((int unit)); |
/* Lower layer has come up */ |
void (*lowerup) __P((int unit)); |
/* Lower layer has gone down */ |
void (*lowerdown) __P((int unit)); |
/* Open the protocol */ |
void (*open) __P((int unit)); |
/* Close the protocol */ |
void (*close) __P((int unit, char *reason)); |
/* Print a packet in readable form */ |
int (*printpkt) __P((u_char *pkt, int len, |
void (*printer) __P((void *, char *, ...)), |
void *arg)); |
/* Process a received data packet */ |
void (*datainput) __P((int unit, u_char *pkt, int len)); |
int enabled_flag; /* 0 iff protocol is disabled */ |
char *name; /* Text name of protocol */ |
/* Check requested options, assign defaults */ |
void (*check_options) __P((void)); |
/* Configure interface for demand-dial */ |
int (*demand_conf) __P((int unit)); |
/* Say whether to bring up link for this pkt */ |
int (*active_pkt) __P((u_char *pkt, int len)); |
}; |
|
/* Table of pointers to supported protocols */ |
extern struct protent *protocols[]; |
|
/* |
* Prototypes. |
*/ |
|
/* Procedures exported from main.c. */ |
void detach __P((void)); /* Detach from controlling tty */ |
void die __P((int)); /* Cleanup and exit */ |
void quit __P((void)); /* like die(1) */ |
void novm __P((char *)); /* Say we ran out of memory, and die */ |
void my_timeout __P((void (*func)(void *), void *arg, int t)); |
/* Call func(arg) after t seconds */ |
void untimeout __P((void (*func)(void *), void *arg)); |
/* Cancel call to func(arg) */ |
int run_program __P((char *prog, char **args, int must_exist)); |
/* Run program prog with args in child */ |
void demuxprotrej __P((int, int)); |
/* Demultiplex a Protocol-Reject */ |
void format_packet __P((u_char *, int, void (*) (void *, char *, ...), |
void *)); /* Format a packet in human-readable form */ |
void log_packet __P((u_char *, int, char *, int)); |
/* Format a packet and log it with syslog */ |
void print_string __P((char *, int, void (*) (void *, char *, ...), |
void *)); /* Format a string for output */ |
int fmtmsg __P((char *, int, char *, ...)); /* sprintf++ */ |
int vfmtmsg __P((char *, int, char *, va_list)); /* vsprintf++ */ |
void script_setenv __P((char *, char *)); /* set script env var */ |
void script_unsetenv __P((char *)); /* unset script env var */ |
/* My procedures */ |
int connect_stb(); |
int disconnect_stb(); |
int pppdmain(int, char*[]); |
int chatmain(char*); |
|
/* Procedures exported from auth.c */ |
|
void link_required __P((int)); /* we are starting to use the link */ |
void link_terminated __P((int)); /* we are finished with the link */ |
void link_down __P((int)); /* the LCP layer has left the Opened state */ |
void link_established __P((int)); /* the link is up; authenticate now */ |
void np_up __P((int, int)); /* a network protocol has come up */ |
void np_down __P((int, int)); /* a network protocol has gone down */ |
void np_finished __P((int, int)); /* a network protocol no longer needs link */ |
void auth_peer_fail __P((int, int)); |
/* peer failed to authenticate itself */ |
void auth_peer_success __P((int, int, char *, int)); |
/* peer successfully authenticated itself */ |
void auth_withpeer_fail __P((int, int)); |
/* we failed to authenticate ourselves */ |
void auth_withpeer_success __P((int, int)); |
/* we successfully authenticated ourselves */ |
void auth_check_options __P((void)); |
/* check authentication options supplied */ |
void auth_reset __P((int)); /* check what secrets we have */ |
int check_passwd __P((int, char *, int, char *, int, char **, int *)); |
/* Check peer-supplied username/password */ |
int get_secret __P((int, char *, char *, char *, int *, int)); |
/* get "secret" for chap */ |
int auth_ip_addr __P((int, u_int32_t)); |
/* check if IP address is authorized */ |
int bad_ip_adrs __P((u_int32_t)); |
/* check if IP address is unreasonable */ |
void check_access __P((FILE *, char *)); |
/* check permissions on secrets file */ |
|
/* Procedures exported from demand.c */ |
void demand_conf __P((void)); /* config interface(s) for demand-dial */ |
void demand_block __P((void)); /* set all NPs to queue up packets */ |
void demand_unblock __P((void)); /* set all NPs to pass packets */ |
void demand_discard __P((void)); /* set all NPs to discard packets */ |
void demand_rexmit __P((int)); /* retransmit saved frames for an NP */ |
int loop_chars __P((unsigned char *, int)); /* process chars from loopback */ |
int loop_frame __P((unsigned char *, int)); /* process frame from loopback */ |
|
/* Procedures exported from sys-*.c */ |
void sys_init __P((void)); /* Do system-dependent initialization */ |
void sys_cleanup __P((void)); /* Restore system state before exiting */ |
void sys_check_options __P((void)); /* Check options specified */ |
void sys_close __P((void)); /* Clean up in a child before execing */ |
int ppp_available __P((void)); /* Test whether ppp kernel support exists */ |
void open_ppp_loopback __P((void)); /* Open loopback for demand-dialling */ |
void establish_ppp __P((int)); /* Turn serial port into a ppp interface */ |
void restore_loop __P((void)); /* Transfer ppp unit back to loopback */ |
void disestablish_ppp __P((int)); /* Restore port to normal operation */ |
void clean_check __P((void)); /* Check if line was 8-bit clean */ |
void set_up_tty __P((int, int)); /* Set up port's speed, parameters, etc. */ |
void restore_tty __P((int)); /* Restore port's original parameters */ |
void setdtr __P((int, int)); /* Raise or lower port's DTR line */ |
void output __P((int, u_char *, int)); /* Output a PPP packet */ |
void wait_input __P((struct timeval *)); |
/* Wait for input, with timeout */ |
void wait_loop_output __P((struct timeval *)); |
/* Wait for pkt from loopback, with timeout */ |
void wait_time __P((struct timeval *)); /* Wait for given length of time */ |
int read_packet __P((u_char *)); /* Read PPP packet */ |
int get_loop_output __P((void)); /* Read pkts from loopback */ |
void ppp_send_config __P((int, int, u_int32_t, int, int)); |
/* Configure i/f transmit parameters */ |
void ppp_set_xaccm __P((int, ext_accm)); |
/* Set extended transmit ACCM */ |
void ppp_recv_config __P((int, int, u_int32_t, int, int)); |
/* Configure i/f receive parameters */ |
int ccp_test __P((int, u_char *, int, int)); |
/* Test support for compression scheme */ |
void ccp_flags_set __P((int, int, int)); |
/* Set kernel CCP state */ |
int ccp_fatal_error __P((int)); /* Test for fatal decomp error in kernel */ |
int get_idle_time __P((int, struct ppp_idle *)); |
/* Find out how long link has been idle */ |
int sifvjcomp __P((int, int, int, int)); |
/* Configure VJ TCP header compression */ |
int sifup __P((int)); /* Configure i/f up (for IP) */ |
int sifnpmode __P((int u, int proto, enum NPmode mode)); |
/* Set mode for handling packets for proto */ |
int sifdown __P((int)); /* Configure i/f down (for IP) */ |
int sifaddr __P((int, u_int32_t, u_int32_t, u_int32_t)); |
/* Configure IP addresses for i/f */ |
int cifaddr __P((int, u_int32_t, u_int32_t)); |
/* Reset i/f IP addresses */ |
int sifdefaultroute __P((int, u_int32_t, u_int32_t)); |
/* Create default route through i/f */ |
int cifdefaultroute __P((int, u_int32_t, u_int32_t)); |
/* Delete default route through i/f */ |
int sifproxyarp __P((int, u_int32_t)); |
/* Add proxy ARP entry for peer */ |
int cifproxyarp __P((int, u_int32_t)); |
/* Delete proxy ARP entry for peer */ |
u_int32_t GetMask __P((u_int32_t)); /* Get appropriate netmask for address */ |
int lock __P((char *)); /* Create lock file for device */ |
void unlock __P((void)); /* Delete previously-created lock file */ |
int daemon __P((int, int)); /* Detach us from terminal session */ |
void logwtmp __P((const char *, const char *, const char *)); |
/* Write entry to wtmp file */ |
int get_host_seed __P((void)); /* Get host-dependent random number seed */ |
#ifdef PPP_FILTER |
int set_filters __P((struct bpf_program *pass, struct bpf_program *active)); |
/* Set filter programs in kernel */ |
#endif |
|
/* Procedures exported from options.c */ |
int parse_args __P((int argc, char **argv)); |
/* Parse options from arguments given */ |
void usage __P((void)); /* Print a usage message */ |
int options_from_file __P((char *filename, int must_exist, int check_prot, |
int privileged)); |
/* Parse options from an options file */ |
int options_from_user __P((void)); /* Parse options from user's .ppprc */ |
int options_for_tty __P((void)); /* Parse options from /etc/ppp/options.tty */ |
void scan_args __P((int argc, char **argv)); |
/* Look for tty name in command-line args */ |
int getword __P((FILE *f, char *word, int *newlinep, char *filename)); |
/* Read a word from a file */ |
void option_error __P((char *fmt, ...)); |
/* Print an error message about an option */ |
|
/* |
* This structure is used to store information about certain |
* options, such as where the option value came from (/etc/ppp/options, |
* command line, etc.) and whether it came from a privileged source. |
*/ |
|
struct option_info { |
int priv; /* was value set by sysadmin? */ |
char *source; /* where option came from */ |
}; |
|
extern struct option_info auth_req_info; |
extern struct option_info connector_info; |
extern struct option_info disconnector_info; |
extern struct option_info welcomer_info; |
extern struct option_info devnam_info; |
|
/* |
* Inline versions of get/put char/short/long. |
* Pointer is advanced; we assume that both arguments |
* are lvalues and will already be in registers. |
* cp MUST be u_char *. |
*/ |
#define GETCHAR(c, cp) { \ |
(c) = *(cp)++; \ |
} |
#define PUTCHAR(c, cp) { \ |
*(cp)++ = (u_char) (c); \ |
} |
|
|
#define GETSHORT(s, cp) { \ |
(s) = *(cp)++ << 8; \ |
(s) |= *(cp)++; \ |
} |
#define PUTSHORT(s, cp) { \ |
*(cp)++ = (u_char) ((s) >> 8); \ |
*(cp)++ = (u_char) (s); \ |
} |
|
#define GETLONG(l, cp) { \ |
(l) = *(cp)++ << 8; \ |
(l) |= *(cp)++; (l) <<= 8; \ |
(l) |= *(cp)++; (l) <<= 8; \ |
(l) |= *(cp)++; \ |
} |
#define PUTLONG(l, cp) { \ |
*(cp)++ = (u_char) ((l) >> 24); \ |
*(cp)++ = (u_char) ((l) >> 16); \ |
*(cp)++ = (u_char) ((l) >> 8); \ |
*(cp)++ = (u_char) (l); \ |
} |
|
#define INCPTR(n, cp) ((cp) += (n)) |
#define DECPTR(n, cp) ((cp) -= (n)) |
|
#undef FALSE |
#define FALSE 0 |
#undef TRUE |
#define TRUE 1 |
|
/* |
* System dependent definitions for user-level 4.3BSD UNIX implementation. |
*/ |
|
#define DEMUXPROTREJ(u, p) demuxprotrej(u, p) |
|
#define TIMEOUT(r, f, t) my_timeout((r), (f), (t)) |
#define UNTIMEOUT(r, f) untimeout((r), (f)) |
|
#define BCOPY(s, d, l) memcpy(d, s, l) |
#define BZERO(s, n) memset(s, 0, n) |
#define EXIT(u) quit() |
|
#define PRINTMSG(m, l) { m[l] = '\0'; syslog(LOG_INFO, "Remote message: %s", m); } |
|
/* |
* MAKEHEADER - Add Header fields to a packet. |
*/ |
#define MAKEHEADER(p, t) { \ |
PUTCHAR(PPP_ALLSTATIONS, p); \ |
PUTCHAR(PPP_UI, p); \ |
PUTSHORT(t, p); } |
|
/* #define DEBUGALL */ |
|
#ifdef DEBUGALL |
#define DEBUGMAIN 1 |
#define DEBUGFSM 1 |
#define DEBUGLCP 1 |
#define DEBUGIPCP 1 |
#define DEBUGUPAP 1 |
#define DEBUGCHAP 1 |
#endif |
|
#ifndef LOG_PPP /* we use LOG_LOCAL2 for syslog by default */ |
#if defined(DEBUGMAIN) || defined(DEBUGFSM) || defined(DEBUGSYS) \ |
|| defined(DEBUGLCP) || defined(DEBUGIPCP) || defined(DEBUGUPAP) \ |
|| defined(DEBUGCHAP) || defined(DEBUG) |
#define LOG_PPP LOG_LOCAL2 |
#else |
#define LOG_PPP LOG_DAEMON |
#endif |
#endif /* LOG_PPP */ |
extern rtems_id pppdaemon_tid; |
#ifdef DEBUGMAIN |
#define MAINDEBUG(x) if (debug) syslog x |
#else |
#define MAINDEBUG(x) |
#endif |
|
#ifdef DEBUGSYS |
#define SYSDEBUG(x) if (debug) syslog x |
#else |
#define SYSDEBUG(x) |
#endif |
|
#ifdef DEBUGFSM |
#define FSMDEBUG(x) if (debug) syslog x |
#else |
#define FSMDEBUG(x) |
#endif |
|
#ifdef DEBUGLCP |
#define LCPDEBUG(x) if (debug) syslog x |
#else |
#define LCPDEBUG(x) |
#endif |
|
#ifdef DEBUGIPCP |
#define IPCPDEBUG(x) if (debug) syslog x |
#else |
#define IPCPDEBUG(x) |
#endif |
|
#ifdef DEBUGUPAP |
#define UPAPDEBUG(x) if (debug) syslog x |
#else |
#define UPAPDEBUG(x) |
#endif |
|
#ifdef DEBUGCHAP |
#define CHAPDEBUG(x) if (debug) syslog x |
#else |
#define CHAPDEBUG(x) |
#endif |
|
#ifdef DEBUGIPXCP |
#define IPXCPDEBUG(x) if (debug) syslog x |
#else |
#define IPXCPDEBUG(x) |
#endif |
|
#ifndef SIGTYPE |
#if defined(sun) || defined(SYSV) || defined(POSIX_SOURCE) |
#define SIGTYPE void |
#else |
#define SIGTYPE int |
#endif /* defined(sun) || defined(SYSV) || defined(POSIX_SOURCE) */ |
#endif /* SIGTYPE */ |
|
#ifndef MIN |
#define MIN(a, b) ((a) < (b)? (a): (b)) |
#endif |
#ifndef MAX |
#define MAX(a, b) ((a) > (b)? (a): (b)) |
#endif |
|
#endif /* __PPP_H__ */ |
/chap_ms.c
0,0 → 1,335
/* |
* chap_ms.c - Microsoft MS-CHAP compatible implementation. |
* |
* Copyright (c) 1995 Eric Rosenquist, Strata Software Limited. |
* http://www.strataware.com/ |
* |
* All rights reserved. |
* |
* 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 Eric Rosenquist. The name of the author 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. |
*/ |
|
/* |
* Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997 |
* |
* Implemented LANManager type password response to MS-CHAP challenges. |
* Now pppd provides both NT style and LANMan style blocks, and the |
* prefered is set by option "ms-lanman". Default is to use NT. |
* The hash text (StdText) was taken from Win95 RASAPI32.DLL. |
* |
* You should also use DOMAIN\\USERNAME as described in README.MSCHAP80 |
*/ |
|
#ifndef lint |
/* static char rcsid[] = "$Id: chap_ms.c,v 1.2 2001-09-27 12:01:57 chris Exp $"; */ |
#endif |
|
#ifdef CHAPMS |
|
#include <stdio.h> |
#include <string.h> |
#include <ctype.h> |
#include <sys/types.h> |
#include <sys/time.h> |
#include <syslog.h> |
#include <unistd.h> |
#ifdef HAVE_CRYPT_H |
#include <crypt.h> |
#endif |
|
#include "pppd.h" |
#include "chap.h" |
#include "chap_ms.h" |
#include "md4.h" |
|
#ifndef USE_CRYPT |
#include <des.h> |
#endif |
|
typedef struct { |
u_char LANManResp[24]; |
u_char NTResp[24]; |
u_char UseNT; /* If 1, ignore the LANMan response field */ |
} MS_ChapResponse; |
/* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse), |
in case this struct gets padded. */ |
|
|
static void ChallengeResponse __P((u_char *, u_char *, u_char *)); |
static void DesEncrypt __P((u_char *, u_char *, u_char *)); |
static void MakeKey __P((u_char *, u_char *)); |
static u_char Get7Bits __P((u_char *, int)); |
static void ChapMS_NT __P((char *, int, char *, int, MS_ChapResponse *)); |
#ifdef MSLANMAN |
static void ChapMS_LANMan __P((char *, int, char *, int, MS_ChapResponse *)); |
#endif |
|
#ifdef USE_CRYPT |
static void Expand __P((u_char *, u_char *)); |
static void Collapse __P((u_char *, u_char *)); |
#endif |
|
static void |
ChallengeResponse(challenge, pwHash, response) |
u_char *challenge; /* IN 8 octets */ |
u_char *pwHash; /* IN 16 octets */ |
u_char *response; /* OUT 24 octets */ |
{ |
char ZPasswordHash[21]; |
|
BZERO(ZPasswordHash, sizeof(ZPasswordHash)); |
BCOPY(pwHash, ZPasswordHash, MD4_SIGNATURE_SIZE); |
|
#if 0 |
log_packet(ZPasswordHash, sizeof(ZPasswordHash), "ChallengeResponse - ZPasswordHash", LOG_DEBUG); |
#endif |
|
DesEncrypt(challenge, ZPasswordHash + 0, response + 0); |
DesEncrypt(challenge, ZPasswordHash + 7, response + 8); |
DesEncrypt(challenge, ZPasswordHash + 14, response + 16); |
|
#if 0 |
log_packet(response, 24, "ChallengeResponse - response", LOG_DEBUG); |
#endif |
} |
|
|
#ifdef USE_CRYPT |
static void |
DesEncrypt(clear, key, cipher) |
u_char *clear; /* IN 8 octets */ |
u_char *key; /* IN 7 octets */ |
u_char *cipher; /* OUT 8 octets */ |
{ |
u_char des_key[8]; |
u_char crypt_key[66]; |
u_char des_input[66]; |
|
MakeKey(key, des_key); |
|
Expand(des_key, crypt_key); |
setkey(crypt_key); |
|
#if 0 |
CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X", |
clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7])); |
#endif |
|
Expand(clear, des_input); |
encrypt(des_input, 0); |
Collapse(des_input, cipher); |
|
#if 0 |
CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X", |
cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7])); |
#endif |
} |
|
#else /* USE_CRYPT */ |
|
static void |
DesEncrypt(clear, key, cipher) |
u_char *clear; /* IN 8 octets */ |
u_char *key; /* IN 7 octets */ |
u_char *cipher; /* OUT 8 octets */ |
{ |
des_cblock des_key; |
des_key_schedule key_schedule; |
|
MakeKey(key, des_key); |
|
des_set_key(&des_key, key_schedule); |
|
#if 0 |
CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X", |
clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7])); |
#endif |
|
des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1); |
|
#if 0 |
CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X", |
cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7])); |
#endif |
} |
|
#endif /* USE_CRYPT */ |
|
|
static u_char Get7Bits(input, startBit) |
u_char *input; |
int startBit; |
{ |
register unsigned int word; |
|
word = (unsigned)input[startBit / 8] << 8; |
word |= (unsigned)input[startBit / 8 + 1]; |
|
word >>= 15 - (startBit % 8 + 7); |
|
return word & 0xFE; |
} |
|
#ifdef USE_CRYPT |
|
/* in == 8-byte string (expanded version of the 56-bit key) |
* out == 64-byte string where each byte is either 1 or 0 |
* Note that the low-order "bit" is always ignored by by setkey() |
*/ |
static void Expand(in, out) |
u_char *in; |
u_char *out; |
{ |
int j, c; |
int i; |
|
for(i = 0; i < 64; in++){ |
c = *in; |
for(j = 7; j >= 0; j--) |
*out++ = (c >> j) & 01; |
i += 8; |
} |
} |
|
/* The inverse of Expand |
*/ |
static void Collapse(in, out) |
u_char *in; |
u_char *out; |
{ |
int j; |
int i; |
unsigned int c; |
|
for (i = 0; i < 64; i += 8, out++) { |
c = 0; |
for (j = 7; j >= 0; j--, in++) |
c |= *in << j; |
*out = c & 0xff; |
} |
} |
#endif |
|
static void MakeKey(key, des_key) |
u_char *key; /* IN 56 bit DES key missing parity bits */ |
u_char *des_key; /* OUT 64 bit DES key with parity bits added */ |
{ |
des_key[0] = Get7Bits(key, 0); |
des_key[1] = Get7Bits(key, 7); |
des_key[2] = Get7Bits(key, 14); |
des_key[3] = Get7Bits(key, 21); |
des_key[4] = Get7Bits(key, 28); |
des_key[5] = Get7Bits(key, 35); |
des_key[6] = Get7Bits(key, 42); |
des_key[7] = Get7Bits(key, 49); |
|
#ifndef USE_CRYPT |
des_set_odd_parity((des_cblock *)des_key); |
#endif |
|
#if 0 |
CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X", |
key[0], key[1], key[2], key[3], key[4], key[5], key[6])); |
CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X", |
des_key[0], des_key[1], des_key[2], des_key[3], des_key[4], des_key[5], des_key[6], des_key[7])); |
#endif |
} |
|
static void |
ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, response) |
char *rchallenge; |
int rchallenge_len; |
char *secret; |
int secret_len; |
MS_ChapResponse *response; |
{ |
int i; |
MD4_CTX md4Context; |
u_char hash[MD4_SIGNATURE_SIZE]; |
u_char unicodePassword[MAX_NT_PASSWORD * 2]; |
|
/* Initialize the Unicode version of the secret (== password). */ |
/* This implicitly supports 8-bit ISO8859/1 characters. */ |
BZERO(unicodePassword, sizeof(unicodePassword)); |
for (i = 0; i < secret_len; i++) |
unicodePassword[i * 2] = (u_char)secret[i]; |
|
MD4Init(&md4Context); |
MD4Update(&md4Context, unicodePassword, secret_len * 2 * 8); /* Unicode is 2 bytes/char, *8 for bit count */ |
|
MD4Final(hash, &md4Context); /* Tell MD4 we're done */ |
|
ChallengeResponse(rchallenge, hash, response->NTResp); |
} |
|
#ifdef MSLANMAN |
static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */ |
|
static void |
ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, response) |
char *rchallenge; |
int rchallenge_len; |
char *secret; |
int secret_len; |
MS_ChapResponse *response; |
{ |
int i; |
u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */ |
u_char PasswordHash[MD4_SIGNATURE_SIZE]; |
|
/* LANMan password is case insensitive */ |
BZERO(UcasePassword, sizeof(UcasePassword)); |
for (i = 0; i < secret_len; i++) |
UcasePassword[i] = (u_char)toupper(secret[i]); |
DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 ); |
DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 ); |
ChallengeResponse(rchallenge, PasswordHash, response->LANManResp); |
} |
#endif |
|
void |
ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len) |
chap_state *cstate; |
char *rchallenge; |
int rchallenge_len; |
char *secret; |
int secret_len; |
{ |
MS_ChapResponse response; |
#ifdef MSLANMAN |
extern int ms_lanman; |
#endif |
|
#if 0 |
CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret)); |
#endif |
BZERO(&response, sizeof(response)); |
|
/* Calculate both always */ |
ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response); |
|
#ifdef MSLANMAN |
ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response); |
|
/* prefered method is set by option */ |
response.UseNT = !ms_lanman; |
#else |
response.UseNT = 1; |
#endif |
|
BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN); |
cstate->resp_length = MS_CHAP_RESPONSE_LEN; |
} |
|
#endif /* CHAPMS */ |
/upap.h
0,0 → 1,87
/* |
* upap.h - User/Password Authentication Protocol definitions. |
* |
* Copyright (c) 1989 Carnegie Mellon University. |
* All rights reserved. |
* |
* 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 Carnegie Mellon University. The name of the |
* University may not be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
* |
* $Id: upap.h,v 1.2 2001-09-27 12:01:57 chris Exp $ |
*/ |
|
/* |
* Packet header = Code, id, length. |
*/ |
#define UPAP_HEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short)) |
|
|
/* |
* UPAP codes. |
*/ |
#define UPAP_AUTHREQ 1 /* Authenticate-Request */ |
#define UPAP_AUTHACK 2 /* Authenticate-Ack */ |
#define UPAP_AUTHNAK 3 /* Authenticate-Nak */ |
|
|
/* |
* Each interface is described by upap structure. |
*/ |
typedef struct upap_state { |
int us_unit; /* Interface unit number */ |
char *us_user; /* User */ |
int us_userlen; /* User length */ |
char *us_passwd; /* Password */ |
int us_passwdlen; /* Password length */ |
int us_clientstate; /* Client state */ |
int us_serverstate; /* Server state */ |
u_char us_id; /* Current id */ |
int us_timeouttime; /* Timeout (seconds) for auth-req retrans. */ |
int us_transmits; /* Number of auth-reqs sent */ |
int us_maxtransmits; /* Maximum number of auth-reqs to send */ |
int us_reqtimeout; /* Time to wait for auth-req from peer */ |
} upap_state; |
|
|
/* |
* Client states. |
*/ |
#define UPAPCS_INITIAL 0 /* Connection down */ |
#define UPAPCS_CLOSED 1 /* Connection up, haven't requested auth */ |
#define UPAPCS_PENDING 2 /* Connection down, have requested auth */ |
#define UPAPCS_AUTHREQ 3 /* We've sent an Authenticate-Request */ |
#define UPAPCS_OPEN 4 /* We've received an Ack */ |
#define UPAPCS_BADAUTH 5 /* We've received a Nak */ |
|
/* |
* Server states. |
*/ |
#define UPAPSS_INITIAL 0 /* Connection down */ |
#define UPAPSS_CLOSED 1 /* Connection up, haven't requested auth */ |
#define UPAPSS_PENDING 2 /* Connection down, have requested auth */ |
#define UPAPSS_LISTEN 3 /* Listening for an Authenticate */ |
#define UPAPSS_OPEN 4 /* We've sent an Ack */ |
#define UPAPSS_BADAUTH 5 /* We've sent a Nak */ |
|
|
/* |
* Timeouts. |
*/ |
#define UPAP_DEFTIMEOUT 3 /* Timeout (seconds) for retransmitting req */ |
#define UPAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */ |
|
extern upap_state upap[]; |
|
void upap_authwithpeer __P((int, char *, char *)); |
void upap_authpeer __P((int)); |
|
extern struct protent pap_protent; |
/chap_ms.h
0,0 → 1,33
/* |
* chap.h - Challenge Handshake Authentication Protocol definitions. |
* |
* Copyright (c) 1995 Eric Rosenquist, Strata Software Limited. |
* http://www.strataware.com/ |
* |
* All rights reserved. |
* |
* 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 Eric Rosenquist. The name of the author may not be used to |
* endorse or promote products derived from this software without |
* specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
* |
* $Id: chap_ms.h,v 1.2 2001-09-27 12:01:57 chris Exp $ |
*/ |
|
#ifndef __CHAPMS_INCLUDE__ |
|
#define MD4_SIGNATURE_SIZE 16 /* 16 bytes in a MD4 message digest */ |
#define MAX_NT_PASSWORD 256 /* Maximum number of (Unicode) chars in an NT password */ |
|
void ChapMS __P((chap_state *, char *, int, char *, int)); |
|
#define __CHAPMS_INCLUDE__ |
#endif /* __CHAPMS_INCLUDE__ */ |
/magic.c
0,0 → 1,86
/* |
* magic.c - PPP Magic Number routines. |
* |
* Copyright (c) 1989 Carnegie Mellon University. |
* All rights reserved. |
* |
* 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 Carnegie Mellon University. The name of the |
* University 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. |
*/ |
|
#ifndef lint |
/* static char rcsid[] = "$Id: magic.c,v 1.2 2001-09-27 12:01:57 chris Exp $"; */ |
#endif |
|
#include <stdio.h> |
#include <unistd.h> |
#include <stdlib.h> |
#include <sys/types.h> |
#include <sys/time.h> |
|
#include "pppd.h" |
#include "magic.h" |
|
extern long mrand48 __P((void)); |
extern void srand48 __P((long)); |
|
/* |
* magic_init - Initialize the magic number generator. |
* |
* Attempts to compute a random number seed which will not repeat. |
* The current method uses the current hostid, current process ID |
* and current time, currently. |
*/ |
void |
magic_init() |
{ |
long seed; |
struct timeval t; |
|
gettimeofday(&t, NULL); |
seed = get_host_seed() ^ t.tv_sec ^ t.tv_usec ^ getpid(); |
srand48(seed); |
} |
|
/* |
* magic - Returns the next magic number. |
*/ |
u_int32_t |
magic() |
{ |
return (u_int32_t) mrand48(); |
} |
|
/* |
* Substitute procedures for those systems which don't have |
* drand48 et al. |
*/ |
/* #include <stdlib.h> */ |
double |
drand48() |
{ |
return (double)rand() / (double)0x7fffffffL; /* 2**31-1 */ |
} |
|
long |
mrand48() |
{ |
return rand(); |
} |
|
void |
srand48(seedval) |
long seedval; |
{ |
srand((int)seedval); |
} |
|
/ipxcp.c
0,0 → 1,1399
/* |
* ipxcp.c - PPP IPX Control Protocol. |
* |
* Copyright (c) 1989 Carnegie Mellon University. |
* All rights reserved. |
* |
* 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 Carnegie Mellon University. The name of the |
* University 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. |
*/ |
|
#ifdef IPX_CHANGE |
#ifndef lint |
/* static char rcsid[] = "$Id: ipxcp.c,v 1.2 2001-09-27 12:01:57 chris Exp $"; */ |
#endif |
|
/* |
* TODO: |
*/ |
|
#include <stdio.h> |
#include <string.h> |
#include <syslog.h> |
#include <sys/types.h> |
#include <sys/socket.h> |
#include <netinet/in.h> |
|
#include "pppd.h" |
#include "fsm.h" |
#include "ipxcp.h" |
#include "pathnames.h" |
|
/* global vars */ |
ipxcp_options ipxcp_wantoptions[NUM_PPP]; /* Options that we want to request */ |
ipxcp_options ipxcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */ |
ipxcp_options ipxcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */ |
ipxcp_options ipxcp_hisoptions[NUM_PPP]; /* Options that we ack'd */ |
|
#define wo (&ipxcp_wantoptions[0]) |
#define ao (&ipxcp_allowoptions[0]) |
#define go (&ipxcp_gotoptions[0]) |
#define ho (&ipxcp_hisoptions[0]) |
|
/* |
* Callbacks for fsm code. (CI = Configuration Information) |
*/ |
static void ipxcp_resetci __P((fsm *)); /* Reset our CI */ |
static int ipxcp_cilen __P((fsm *)); /* Return length of our CI */ |
static void ipxcp_addci __P((fsm *, u_char *, int *)); /* Add our CI */ |
static int ipxcp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */ |
static int ipxcp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */ |
static int ipxcp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */ |
static int ipxcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */ |
static void ipxcp_up __P((fsm *)); /* We're UP */ |
static void ipxcp_down __P((fsm *)); /* We're DOWN */ |
static void ipxcp_script __P((fsm *, char *)); /* Run an up/down script */ |
|
fsm ipxcp_fsm[NUM_PPP]; /* IPXCP fsm structure */ |
|
static fsm_callbacks ipxcp_callbacks = { /* IPXCP callback routines */ |
ipxcp_resetci, /* Reset our Configuration Information */ |
ipxcp_cilen, /* Length of our Configuration Information */ |
ipxcp_addci, /* Add our Configuration Information */ |
ipxcp_ackci, /* ACK our Configuration Information */ |
ipxcp_nakci, /* NAK our Configuration Information */ |
ipxcp_rejci, /* Reject our Configuration Information */ |
ipxcp_reqci, /* Request peer's Configuration Information */ |
ipxcp_up, /* Called when fsm reaches OPENED state */ |
ipxcp_down, /* Called when fsm leaves OPENED state */ |
NULL, /* Called when we want the lower layer up */ |
NULL, /* Called when we want the lower layer down */ |
NULL, /* Called when Protocol-Reject received */ |
NULL, /* Retransmission is necessary */ |
NULL, /* Called to handle protocol-specific codes */ |
"IPXCP" /* String name of protocol */ |
}; |
|
/* |
* Protocol entry points. |
*/ |
|
static void ipxcp_init __P((int)); |
static void ipxcp_open __P((int)); |
static void ipxcp_close __P((int, char *)); |
static void ipxcp_lowerup __P((int)); |
static void ipxcp_lowerdown __P((int)); |
static void ipxcp_input __P((int, u_char *, int)); |
static void ipxcp_protrej __P((int)); |
static int ipxcp_printpkt __P((u_char *, int, |
void (*) __P((void *, char *, ...)), void *)); |
|
struct protent ipxcp_protent = { |
PPP_IPXCP, |
ipxcp_init, |
ipxcp_input, |
ipxcp_protrej, |
ipxcp_lowerup, |
ipxcp_lowerdown, |
ipxcp_open, |
ipxcp_close, |
ipxcp_printpkt, |
NULL, |
0, |
"IPXCP", |
NULL, |
NULL, |
NULL |
}; |
|
/* |
* Lengths of configuration options. |
*/ |
|
#define CILEN_VOID 2 |
#define CILEN_COMPLETE 2 /* length of complete option */ |
#define CILEN_NETN 6 /* network number length option */ |
#define CILEN_NODEN 8 /* node number length option */ |
#define CILEN_PROTOCOL 4 /* Minimum length of routing protocol */ |
#define CILEN_NAME 3 /* Minimum length of router name */ |
#define CILEN_COMPRESS 4 /* Minimum length of compression protocol */ |
|
#define CODENAME(x) ((x) == CONFACK ? "ACK" : \ |
(x) == CONFNAK ? "NAK" : "REJ") |
|
/* Used in printing the node number */ |
#define NODE(base) base[0], base[1], base[2], base[3], base[4], base[5] |
|
/* Used to generate the proper bit mask */ |
#define BIT(num) (1 << (num)) |
|
/* |
* Convert from internal to external notation |
*/ |
|
static short int |
to_external(internal) |
short int internal; |
{ |
short int external; |
|
if (internal & IPX_NONE) |
external = IPX_NONE; |
else |
external = RIP_SAP; |
|
return external; |
} |
|
/* |
* Make a string representation of a network IP address. |
*/ |
|
char * |
ipx_ntoa(ipxaddr) |
u_int32_t ipxaddr; |
{ |
static char b[64]; |
sprintf(b, "%x", ipxaddr); |
return b; |
} |
|
|
/* |
* ipxcp_init - Initialize IPXCP. |
*/ |
static void |
ipxcp_init(unit) |
int unit; |
{ |
fsm *f = &ipxcp_fsm[unit]; |
|
f->unit = unit; |
f->protocol = PPP_IPXCP; |
f->callbacks = &ipxcp_callbacks; |
fsm_init(&ipxcp_fsm[unit]); |
|
memset (wo->name, 0, sizeof (wo->name)); |
memset (wo->our_node, 0, sizeof (wo->our_node)); |
memset (wo->his_node, 0, sizeof (wo->his_node)); |
|
wo->neg_nn = 1; |
wo->neg_complete = 1; |
wo->network = 0; |
|
ao->neg_node = 1; |
ao->neg_nn = 1; |
ao->neg_name = 1; |
ao->neg_complete = 1; |
ao->neg_router = 1; |
|
ao->accept_local = 0; |
ao->accept_remote = 0; |
ao->accept_network = 0; |
|
wo->tried_rip = 0; |
wo->tried_nlsp = 0; |
} |
|
/* |
* Copy the node number |
*/ |
|
static void |
copy_node (src, dst) |
u_char *src, *dst; |
{ |
memcpy (dst, src, sizeof (ipxcp_wantoptions[0].our_node)); |
} |
|
/* |
* Compare node numbers |
*/ |
|
static int |
compare_node (src, dst) |
u_char *src, *dst; |
{ |
return memcmp (dst, src, sizeof (ipxcp_wantoptions[0].our_node)) == 0; |
} |
|
/* |
* Is the node number zero? |
*/ |
|
static int |
zero_node (node) |
u_char *node; |
{ |
int indx; |
for (indx = 0; indx < sizeof (ipxcp_wantoptions[0].our_node); ++indx) |
if (node [indx] != 0) |
return 0; |
return 1; |
} |
|
/* |
* Increment the node number |
*/ |
|
static void |
inc_node (node) |
u_char *node; |
{ |
u_char *outp; |
u_int32_t magic_num; |
|
outp = node; |
magic_num = magic(); |
*outp++ = '\0'; |
*outp++ = '\0'; |
PUTLONG (magic_num, outp); |
} |
|
/* |
* ipxcp_open - IPXCP is allowed to come up. |
*/ |
static void |
ipxcp_open(unit) |
int unit; |
{ |
fsm_open(&ipxcp_fsm[unit]); |
} |
|
/* |
* ipxcp_close - Take IPXCP down. |
*/ |
static void |
ipxcp_close(unit, reason) |
int unit; |
char *reason; |
{ |
fsm_close(&ipxcp_fsm[unit], reason); |
} |
|
|
/* |
* ipxcp_lowerup - The lower layer is up. |
*/ |
static void |
ipxcp_lowerup(unit) |
int unit; |
{ |
fsm_lowerup(&ipxcp_fsm[unit]); |
} |
|
|
/* |
* ipxcp_lowerdown - The lower layer is down. |
*/ |
static void |
ipxcp_lowerdown(unit) |
int unit; |
{ |
fsm_lowerdown(&ipxcp_fsm[unit]); |
} |
|
|
/* |
* ipxcp_input - Input IPXCP packet. |
*/ |
static void |
ipxcp_input(unit, p, len) |
int unit; |
u_char *p; |
int len; |
{ |
fsm_input(&ipxcp_fsm[unit], p, len); |
} |
|
|
/* |
* ipxcp_protrej - A Protocol-Reject was received for IPXCP. |
* |
* Pretend the lower layer went down, so we shut up. |
*/ |
static void |
ipxcp_protrej(unit) |
int unit; |
{ |
fsm_lowerdown(&ipxcp_fsm[unit]); |
} |
|
|
/* |
* ipxcp_resetci - Reset our CI. |
*/ |
static void |
ipxcp_resetci(f) |
fsm *f; |
{ |
wo->req_node = wo->neg_node && ao->neg_node; |
wo->req_nn = wo->neg_nn && ao->neg_nn; |
|
if (wo->our_network == 0) { |
wo->neg_node = 1; |
ao->accept_network = 1; |
} |
/* |
* If our node number is zero then change it. |
*/ |
if (zero_node (wo->our_node)) { |
inc_node (wo->our_node); |
ao->accept_local = 1; |
wo->neg_node = 1; |
} |
/* |
* If his node number is zero then change it. |
*/ |
if (zero_node (wo->his_node)) { |
inc_node (wo->his_node); |
ao->accept_remote = 1; |
} |
/* |
* If no routing agent was specified then we do RIP/SAP according to the |
* RFC documents. If you have specified something then OK. Otherwise, we |
* do RIP/SAP. |
*/ |
if (ao->router == 0) { |
ao->router |= BIT(RIP_SAP); |
wo->router |= BIT(RIP_SAP); |
} |
|
/* Always specify a routing protocol unless it was REJected. */ |
wo->neg_router = 1; |
/* |
* Start with these default values |
*/ |
*go = *wo; |
} |
|
/* |
* ipxcp_cilen - Return length of our CI. |
*/ |
|
static int |
ipxcp_cilen(f) |
fsm *f; |
{ |
int len; |
|
len = go->neg_nn ? CILEN_NETN : 0; |
len += go->neg_node ? CILEN_NODEN : 0; |
len += go->neg_name ? CILEN_NAME + strlen (go->name) - 1 : 0; |
|
/* RFC says that defaults should not be included. */ |
if (go->neg_router && to_external(go->router) != RIP_SAP) |
len += CILEN_PROTOCOL; |
|
return (len); |
} |
|
|
/* |
* ipxcp_addci - Add our desired CIs to a packet. |
*/ |
static void |
ipxcp_addci(f, ucp, lenp) |
fsm *f; |
u_char *ucp; |
int *lenp; |
{ |
/* |
* Add the options to the record. |
*/ |
if (go->neg_nn) { |
PUTCHAR (IPX_NETWORK_NUMBER, ucp); |
PUTCHAR (CILEN_NETN, ucp); |
PUTLONG (go->our_network, ucp); |
} |
|
if (go->neg_node) { |
int indx; |
PUTCHAR (IPX_NODE_NUMBER, ucp); |
PUTCHAR (CILEN_NODEN, ucp); |
for (indx = 0; indx < sizeof (go->our_node); ++indx) |
PUTCHAR (go->our_node[indx], ucp); |
} |
|
if (go->neg_name) { |
int cilen = strlen (go->name); |
int indx; |
PUTCHAR (IPX_ROUTER_NAME, ucp); |
PUTCHAR (CILEN_NAME + cilen - 1, ucp); |
for (indx = 0; indx < cilen; ++indx) |
PUTCHAR (go->name [indx], ucp); |
} |
|
if (go->neg_router) { |
short external = to_external (go->router); |
if (external != RIP_SAP) { |
PUTCHAR (IPX_ROUTER_PROTOCOL, ucp); |
PUTCHAR (CILEN_PROTOCOL, ucp); |
PUTSHORT (external, ucp); |
} |
} |
} |
|
/* |
* ipxcp_ackci - Ack our CIs. |
* |
* Returns: |
* 0 - Ack was bad. |
* 1 - Ack was good. |
*/ |
static int |
ipxcp_ackci(f, p, len) |
fsm *f; |
u_char *p; |
int len; |
{ |
u_short cilen, citype, cishort; |
u_char cichar; |
u_int32_t cilong; |
|
#define ACKCIVOID(opt, neg) \ |
if (neg) { \ |
if ((len -= CILEN_VOID) < 0) \ |
break; \ |
GETCHAR(citype, p); \ |
GETCHAR(cilen, p); \ |
if (cilen != CILEN_VOID || \ |
citype != opt) \ |
break; \ |
} |
|
#define ACKCICOMPLETE(opt,neg) ACKCIVOID(opt, neg) |
|
#define ACKCICHARS(opt, neg, val, cnt) \ |
if (neg) { \ |
int indx, count = cnt; \ |
len -= (count + 2); \ |
if (len < 0) \ |
break; \ |
GETCHAR(citype, p); \ |
GETCHAR(cilen, p); \ |
if (cilen != (count + 2) || \ |
citype != opt) \ |
break; \ |
for (indx = 0; indx < count; ++indx) {\ |
GETCHAR(cichar, p); \ |
if (cichar != ((u_char *) &val)[indx]) \ |
break; \ |
}\ |
if (indx != count) \ |
break; \ |
} |
|
#define ACKCINODE(opt,neg,val) ACKCICHARS(opt,neg,val,sizeof(val)) |
#define ACKCINAME(opt,neg,val) ACKCICHARS(opt,neg,val,strlen(val)) |
|
#define ACKCINETWORK(opt, neg, val) \ |
if (neg) { \ |
if ((len -= CILEN_NETN) < 0) \ |
break; \ |
GETCHAR(citype, p); \ |
GETCHAR(cilen, p); \ |
if (cilen != CILEN_NETN || \ |
citype != opt) \ |
break; \ |
GETLONG(cilong, p); \ |
if (cilong != val) \ |
break; \ |
} |
|
#define ACKCIPROTO(opt, neg, val) \ |
if (neg) { \ |
if (len < 2) \ |
break; \ |
GETCHAR(citype, p); \ |
GETCHAR(cilen, p); \ |
if (cilen != CILEN_PROTOCOL || citype != opt) \ |
break; \ |
len -= cilen; \ |
if (len < 0) \ |
break; \ |
GETSHORT(cishort, p); \ |
if (cishort != to_external (val) || cishort == RIP_SAP) \ |
break; \ |
} |
/* |
* Process the ACK frame in the order in which the frame was assembled |
*/ |
do { |
ACKCINETWORK (IPX_NETWORK_NUMBER, go->neg_nn, go->our_network); |
ACKCINODE (IPX_NODE_NUMBER, go->neg_node, go->our_node); |
ACKCINAME (IPX_ROUTER_NAME, go->neg_name, go->name); |
ACKCIPROTO (IPX_ROUTER_PROTOCOL, go->neg_router, go->router); |
ACKCIPROTO (IPX_ROUTER_PROTOCOL, go->neg_router, go->router); |
ACKCIPROTO (IPX_ROUTER_PROTOCOL, go->neg_router, go->router); |
/* |
* This is the end of the record. |
*/ |
if (len == 0) |
return (1); |
} while (0); |
/* |
* The frame is invalid |
*/ |
IPXCPDEBUG((LOG_INFO, "ipxcp_ackci: received bad Ack!")); |
return (0); |
} |
|
/* |
* ipxcp_nakci - Peer has sent a NAK for some of our CIs. |
* This should not modify any state if the Nak is bad |
* or if IPXCP is in the OPENED state. |
* |
* Returns: |
* 0 - Nak was bad. |
* 1 - Nak was good. |
*/ |
|
static int |
ipxcp_nakci(f, p, len) |
fsm *f; |
u_char *p; |
int len; |
{ |
u_char citype, cilen, *next; |
u_short s; |
u_int32_t l; |
ipxcp_options no; /* options we've seen Naks for */ |
ipxcp_options try; /* options to request next time */ |
|
BZERO(&no, sizeof(no)); |
try = *go; |
|
while (len > CILEN_VOID) { |
GETCHAR (citype, p); |
GETCHAR (cilen, p); |
len -= cilen; |
if (len < 0) |
goto bad; |
next = &p [cilen - CILEN_VOID]; |
|
switch (citype) { |
case IPX_NETWORK_NUMBER: |
if (!go->neg_nn || no.neg_nn || (cilen != CILEN_NETN)) |
goto bad; |
no.neg_nn = 1; |
|
GETLONG(l, p); |
IPXCPDEBUG((LOG_INFO, "local IP address %d", l)); |
if (l && ao->accept_network) |
try.our_network = l; |
break; |
|
case IPX_NODE_NUMBER: |
if (!go->neg_node || no.neg_node || (cilen != CILEN_NODEN)) |
goto bad; |
no.neg_node = 1; |
|
IPXCPDEBUG((LOG_INFO, |
"local node number %02X%02X%02X%02X%02X%02X", |
NODE(p))); |
|
if (!zero_node (p) && ao->accept_local && |
! compare_node (p, ho->his_node)) |
copy_node (p, try.our_node); |
break; |
|
/* This has never been sent. Ignore the NAK frame */ |
case IPX_COMPRESSION_PROTOCOL: |
goto bad; |
|
case IPX_ROUTER_PROTOCOL: |
if (!go->neg_router || (cilen < CILEN_PROTOCOL)) |
goto bad; |
|
GETSHORT (s, p); |
if (s > 15) /* This is just bad, but ignore for now. */ |
break; |
|
s = BIT(s); |
if (no.router & s) /* duplicate NAKs are always bad */ |
goto bad; |
|
if (no.router == 0) /* Reset on first NAK only */ |
try.router = 0; |
|
no.router |= s; |
try.router |= s; |
try.neg_router = 1; |
|
IPXCPDEBUG((LOG_INFO, "Router protocol number %d", s)); |
break; |
|
/* These, according to the RFC, must never be NAKed. */ |
case IPX_ROUTER_NAME: |
case IPX_COMPLETE: |
goto bad; |
|
/* These are for options which we have not seen. */ |
default: |
break; |
} |
p = next; |
} |
|
/* If there is still anything left, this packet is bad. */ |
if (len != 0) |
goto bad; |
|
/* |
* Do not permit the peer to force a router protocol which we do not |
* support. However, default to the condition that will accept "NONE". |
*/ |
try.router &= (ao->router | BIT(IPX_NONE)); |
if (try.router == 0 && ao->router != 0) |
try.router = BIT(IPX_NONE); |
|
if (try.router != 0) |
try.neg_router = 1; |
|
/* |
* OK, the Nak is good. Now we can update state. |
*/ |
if (f->state != OPENED) |
*go = try; |
|
return 1; |
|
bad: |
IPXCPDEBUG((LOG_INFO, "ipxcp_nakci: received bad Nak!")); |
return 0; |
} |
|
/* |
* ipxcp_rejci - Reject some of our CIs. |
*/ |
static int |
ipxcp_rejci(f, p, len) |
fsm *f; |
u_char *p; |
int len; |
{ |
u_short cilen, citype, cishort; |
u_char cichar; |
u_int32_t cilong; |
ipxcp_options try; /* options to request next time */ |
|
#define REJCINETWORK(opt, neg, val) \ |
if (neg && p[0] == opt) { \ |
if ((len -= CILEN_NETN) < 0) \ |
break; \ |
GETCHAR(citype, p); \ |
GETCHAR(cilen, p); \ |
if (cilen != CILEN_NETN || \ |
citype != opt) \ |
break; \ |
GETLONG(cilong, p); \ |
if (cilong != val) \ |
break; \ |
IPXCPDEBUG((LOG_INFO,"ipxcp_rejci rejected long opt %d", opt)); \ |
neg = 0; \ |
} |
|
#define REJCICHARS(opt, neg, val, cnt) \ |
if (neg && p[0] == opt) { \ |
int indx, count = cnt; \ |
len -= (count + 2); \ |
if (len < 0) \ |
break; \ |
GETCHAR(citype, p); \ |
GETCHAR(cilen, p); \ |
if (cilen != (count + 2) || \ |
citype != opt) \ |
break; \ |
for (indx = 0; indx < count; ++indx) {\ |
GETCHAR(cichar, p); \ |
if (cichar != ((u_char *) &val)[indx]) \ |
break; \ |
}\ |
if (indx != count) \ |
break; \ |
IPXCPDEBUG((LOG_INFO,"ipxcp_rejci rejected opt %d", opt)); \ |
neg = 0; \ |
} |
|
#define REJCINODE(opt,neg,val) REJCICHARS(opt,neg,val,sizeof(val)) |
#define REJCINAME(opt,neg,val) REJCICHARS(opt,neg,val,strlen(val)) |
|
#define REJCIVOID(gpt, neg! \ |
if (neg && p[0] == opt) { \ |
if ((len -= CILEN_VOID) < 0) \ |
break; \ |
GETCHAR(citype, p); \ |
GETCHAR(cilen, p); \ |
if (cilen != CILEN_VOID || citype != opt) \ |
break; \ |
IPXCPDEBUG((LOG_INFO, "ipxcp_rejci rejected void opt %d", opt)); \ |
neg = 0; \ |
} |
|
/* a reject for RIP/SAP is invalid since we don't send it and you can't |
reject something which is not sent. (You can NAK, but you can't REJ.) */ |
#define REJCIPROTO(opt, neg, val, bit) \ |
if (neg && p[0] == opt) { \ |
if ((len -= CILEN_PROTOCOL) < 0) \ |
break; \ |
GETCHAR(citype, p); \ |
GETCHAR(cilen, p); \ |
if (cilen != CILEN_PROTOCOL) \ |
break; \ |
GETSHORT(cishort, p); \ |
if (cishort != to_external (val) || cishort == RIP_SAP) \ |
break; \ |
IPXCPDEBUG((LOG_INFO, "ipxcp_rejci short opt %d", opt)); \ |
neg = 0; \ |
} |
/* |
* Any Rejected CIs must be in exactly the same order that we sent. |
* Check packet length and CI length at each step. |
* If we find any deviations, then this packet is bad. |
*/ |
try = *go; |
|
do { |
REJCINETWORK (IPX_NETWORK_NUMBER, try.neg_nn, try.our_network); |
REJCINODE (IPX_NODE_NUMBER, try.neg_node, try.our_node); |
REJCINAME (IPX_ROUTER_NAME, try.neg_name, try.name); |
REJCIPROTO (IPX_ROUTER_PROTOCOL, try.neg_router, try.router, 0); |
/* |
* This is the end of the record. |
*/ |
if (len == 0) { |
if (f->state != OPENED) |
*go = try; |
return (1); |
} |
} while (0); |
/* |
* The frame is invalid at this point. |
*/ |
IPXCPDEBUG((LOG_INFO, "ipxcp_rejci: received bad Reject!")); |
return 0; |
} |
|
/* |
* ipxcp_reqci - Check the peer's requested CIs and send appropriate response. |
* |
* Returns: CONFACK, CONFNAK or CONFREJ and input packet modified |
* appropriately. If reject_if_disagree is non-zero, doesn't return |
* CONFNAK; returns CONFREJ if it can't return CONFACK. |
*/ |
static int |
ipxcp_reqci(f, inp, len, reject_if_disagree) |
fsm *f; |
u_char *inp; /* Requested CIs */ |
int *len; /* Length of requested CIs */ |
int reject_if_disagree; |
{ |
u_char *cip, *next; /* Pointer to current and next CIs */ |
u_short cilen, citype; /* Parsed len, type */ |
u_short cishort; /* Parsed short value */ |
u_int32_t cinetwork; /* Parsed address values */ |
int rc = CONFACK; /* Final packet return code */ |
int orc; /* Individual option return code */ |
u_char *p; /* Pointer to next char to parse */ |
u_char *ucp = inp; /* Pointer to current output char */ |
int l = *len; /* Length left */ |
|
/* |
* Reset all his options. |
*/ |
BZERO(ho, sizeof(*ho)); |
|
/* |
* Process all his options. |
*/ |
next = inp; |
while (l) { |
orc = CONFACK; /* Assume success */ |
cip = p = next; /* Remember begining of CI */ |
if (l < 2 || /* Not enough data for CI header or */ |
p[1] < 2 || /* CI length too small or */ |
p[1] > l) { /* CI length too big? */ |
IPXCPDEBUG((LOG_INFO, "ipxcp_reqci: bad CI length!")); |
orc = CONFREJ; /* Reject bad CI */ |
cilen = l; /* Reject till end of packet */ |
l = 0; /* Don't loop again */ |
goto endswitch; |
} |
GETCHAR(citype, p); /* Parse CI type */ |
GETCHAR(cilen, p); /* Parse CI length */ |
l -= cilen; /* Adjust remaining length */ |
next += cilen; /* Step to next CI */ |
|
switch (citype) { /* Check CI type */ |
/* |
* The network number must match. Choose the larger of the two. |
*/ |
case IPX_NETWORK_NUMBER: |
IPXCPDEBUG((LOG_INFO, "ipxcp: received Network Number request")); |
|
/* if we wont negotiate the network number or the length is wrong |
then reject the option */ |
if ( !ao->neg_nn || cilen != CILEN_NETN ) { |
orc = CONFREJ; |
break; |
} |
GETLONG(cinetwork, p); |
IPXCPDEBUG((LOG_INFO,"Remote proposed IPX network number is %8Lx",tl)); |
|
/* If the network numbers match then acknowledge them. */ |
if (cinetwork != 0) { |
ho->his_network = cinetwork; |
ho->neg_nn = 1; |
if (wo->our_network == cinetwork) |
break; |
/* |
* If the network number is not given or we don't accept their change or |
* the network number is too small then NAK it. |
*/ |
if (! ao->accept_network || cinetwork < wo->our_network) { |
DECPTR (sizeof (u_int32_t), p); |
PUTLONG (wo->our_network, p); |
orc = CONFNAK; |
} |
break; |
} |
/* |
* The peer sent '0' for the network. Give it ours if we have one. |
*/ |
if (go->our_network != 0) { |
DECPTR (sizeof (u_int32_t), p); |
PUTLONG (wo->our_network, p); |
orc = CONFNAK; |
/* |
* We don't have one. Reject the value. |
*/ |
} else |
orc = CONFREJ; |
|
break; |
/* |
* The node number is required |
*/ |
case IPX_NODE_NUMBER: |
IPXCPDEBUG((LOG_INFO, "ipxcp: received Node Number request")); |
|
/* if we wont negotiate the node number or the length is wrong |
then reject the option */ |
if ( cilen != CILEN_NODEN ) { |
orc = CONFREJ; |
break; |
} |
|
copy_node (p, ho->his_node); |
ho->neg_node = 1; |
/* |
* If the remote does not have a number and we do then NAK it with the value |
* which we have for it. (We never have a default value of zero.) |
*/ |
if (zero_node (ho->his_node)) { |
orc = CONFNAK; |
copy_node (wo->his_node, p); |
INCPTR (sizeof (wo->his_node), p); |
break; |
} |
/* |
* If you have given me the expected network node number then I'll accept |
* it now. |
*/ |
if (compare_node (wo->his_node, ho->his_node)) { |
orc = CONFACK; |
ho->neg_node = 1; |
INCPTR (sizeof (wo->his_node), p); |
break; |
} |
/* |
* If his node number is the same as ours then ask him to try the next |
* value. |
*/ |
if (compare_node (ho->his_node, go->our_node)) { |
inc_node (ho->his_node); |
orc = CONFNAK; |
copy_node (ho->his_node, p); |
INCPTR (sizeof (wo->his_node), p); |
break; |
} |
/* |
* If we don't accept a new value then NAK it. |
*/ |
if (! ao->accept_remote) { |
copy_node (wo->his_node, p); |
INCPTR (sizeof (wo->his_node), p); |
orc = CONFNAK; |
break; |
} |
orc = CONFACK; |
ho->neg_node = 1; |
INCPTR (sizeof (wo->his_node), p); |
break; |
/* |
* Compression is not desired at this time. It is always rejected. |
*/ |
case IPX_COMPRESSION_PROTOCOL: |
IPXCPDEBUG((LOG_INFO, "ipxcp: received Compression Protocol request ")); |
orc = CONFREJ; |
break; |
/* |
* The routing protocol is a bitmask of various types. Any combination |
* of the values RIP_SAP and NLSP are permissible. 'IPX_NONE' for no |
* routing protocol must be specified only once. |
*/ |
case IPX_ROUTER_PROTOCOL: |
if ( !ao->neg_router || cilen < CILEN_PROTOCOL ) { |
orc = CONFREJ; |
break; |
} |
|
GETSHORT (cishort, p); |
IPXCPDEBUG((LOG_INFO, |
"Remote router protocol number 0x%04x", |
cishort)); |
|
if (wo->neg_router == 0) { |
wo->neg_router = 1; |
wo->router = BIT(IPX_NONE); |
} |
|
if ((cishort == IPX_NONE && ho->router != 0) || |
(ho->router & BIT(IPX_NONE))) { |
orc = CONFREJ; |
break; |
} |
|
cishort = BIT(cishort); |
if (ho->router & cishort) { |
orc = CONFREJ; |
break; |
} |
|
ho->router |= cishort; |
ho->neg_router = 1; |
|
/* Finally do not allow a router protocol which we do not |
support. */ |
|
if ((cishort & (ao->router | BIT(IPX_NONE))) == 0) { |
int protocol; |
|
if (cishort == BIT(NLSP) && |
(ao->router & BIT(RIP_SAP)) && |
!wo->tried_rip) { |
protocol = RIP_SAP; |
wo->tried_rip = 1; |
} else |
protocol = IPX_NONE; |
|
DECPTR (sizeof (u_int16_t), p); |
PUTSHORT (protocol, p); |
orc = CONFNAK; |
} |
break; |
/* |
* The router name is advisorary. Just accept it if it is not too large. |
*/ |
case IPX_ROUTER_NAME: |
IPXCPDEBUG((LOG_INFO, "ipxcp: received Router Name request")); |
if (cilen >= CILEN_NAME) { |
int name_size = cilen - CILEN_NAME; |
if (name_size > sizeof (ho->name)) |
name_size = sizeof (ho->name) - 1; |
memset (ho->name, 0, sizeof (ho->name)); |
memcpy (ho->name, p, name_size); |
ho->name [name_size] = '\0'; |
ho->neg_name = 1; |
orc = CONFACK; |
break; |
} |
orc = CONFREJ; |
break; |
/* |
* This is advisorary. |
*/ |
case IPX_COMPLETE: |
IPXCPDEBUG((LOG_INFO, "ipxcp: received Complete request")); |
if (cilen != CILEN_COMPLETE) |
orc = CONFREJ; |
else { |
ho->neg_complete = 1; |
orc = CONFACK; |
} |
break; |
/* |
* All other entries are not known at this time. |
*/ |
default: |
IPXCPDEBUG((LOG_INFO, "ipxcp: received Complete request")); |
orc = CONFREJ; |
break; |
} |
|
endswitch: |
IPXCPDEBUG((LOG_INFO, " (%s)\n", CODENAME(orc))); |
|
if (orc == CONFACK && /* Good CI */ |
rc != CONFACK) /* but prior CI wasnt? */ |
continue; /* Don't send this one */ |
|
if (orc == CONFNAK) { /* Nak this CI? */ |
if (reject_if_disagree) /* Getting fed up with sending NAKs? */ |
orc = CONFREJ; /* Get tough if so */ |
if (rc == CONFREJ) /* Rejecting prior CI? */ |
continue; /* Don't send this one */ |
if (rc == CONFACK) { /* Ack'd all prior CIs? */ |
rc = CONFNAK; /* Not anymore... */ |
ucp = inp; /* Backup */ |
} |
} |
|
if (orc == CONFREJ && /* Reject this CI */ |
rc != CONFREJ) { /* but no prior ones? */ |
rc = CONFREJ; |
ucp = inp; /* Backup */ |
} |
|
/* Need to move CI? */ |
if (ucp != cip) |
BCOPY(cip, ucp, cilen); /* Move it */ |
|
/* Update output pointer */ |
INCPTR(cilen, ucp); |
} |
|
/* |
* If we aren't rejecting this packet, and we want to negotiate |
* their address, and they didn't send their address, then we |
* send a NAK with a IPX_NODE_NUMBER option appended. We assume the |
* input buffer is long enough that we can append the extra |
* option safely. |
*/ |
|
if (rc != CONFREJ && !ho->neg_node && |
wo->req_nn && !reject_if_disagree) { |
if (rc == CONFACK) { |
rc = CONFNAK; |
wo->req_nn = 0; /* don't ask again */ |
ucp = inp; /* reset pointer */ |
} |
|
if (zero_node (wo->his_node)) |
inc_node (wo->his_node); |
|
PUTCHAR (IPX_NODE_NUMBER, ucp); |
PUTCHAR (CILEN_NODEN, ucp); |
copy_node (wo->his_node, ucp); |
INCPTR (sizeof (wo->his_node), ucp); |
} |
|
*len = ucp - inp; /* Compute output length */ |
IPXCPDEBUG((LOG_INFO, "ipxcp: returning Configure-%s", CODENAME(rc))); |
return (rc); /* Return final code */ |
} |
|
/* |
* ipxcp_up - IPXCP has come UP. |
* |
* Configure the IP network interface appropriately and bring it up. |
*/ |
|
static void |
ipxcp_up(f) |
fsm *f; |
{ |
int unit = f->unit; |
|
IPXCPDEBUG((LOG_INFO, "ipxcp: up")); |
|
/* The default router protocol is RIP/SAP. */ |
if (ho->router == 0) |
ho->router = BIT(RIP_SAP); |
|
if (go->router == 0) |
go->router = BIT(RIP_SAP); |
|
/* Fetch the network number */ |
if (!ho->neg_nn) |
ho->his_network = wo->his_network; |
|
if (!ho->neg_node) |
copy_node (wo->his_node, ho->his_node); |
|
if (!wo->neg_node && !go->neg_node) |
copy_node (wo->our_node, go->our_node); |
|
if (zero_node (go->our_node)) { |
static char errmsg[] = "Could not determine local IPX node address"; |
IPXCPDEBUG((LOG_ERR, errmsg)); |
ipxcp_close(f->unit, errmsg); |
return; |
} |
|
go->network = go->our_network; |
if (ho->his_network != 0 && ho->his_network > go->network) |
go->network = ho->his_network; |
|
if (go->network == 0) { |
static char errmsg[] = "Can not determine network number"; |
IPXCPDEBUG((LOG_ERR, errmsg)); |
ipxcp_close (unit, errmsg); |
return; |
} |
|
/* bring the interface up */ |
if (!sifup(unit)) { |
IPXCPDEBUG((LOG_WARNING, "sifup failed")); |
ipxcp_close(unit, "Interface configuration failed"); |
return; |
} |
|
/* set the network number for IPX */ |
if (!sipxfaddr(unit, go->network, go->our_node)) { |
IPXCPDEBUG((LOG_WARNING, "sipxfaddr failed")); |
ipxcp_close(unit, "Interface configuration failed"); |
return; |
} |
|
/* |
* Execute the ipx-up script, like this: |
* /etc/ppp/ipx-up interface tty speed local-IPX remote-IPX |
*/ |
|
ipxcp_script (f, _PATH_IPXUP); |
} |
|
/* |
* ipxcp_down - IPXCP has gone DOWN. |
* |
* Take the IP network interface down, clear its addresses |
* and delete routes through it. |
*/ |
|
static void |
ipxcp_down(f) |
fsm *f; |
{ |
IPXCPDEBUG((LOG_INFO, "ipxcp: down")); |
|
cipxfaddr (f->unit); |
sifdown(f->unit); |
ipxcp_script (f, _PATH_IPXDOWN); |
} |
|
|
/* |
* ipxcp_script - Execute a script with arguments |
* interface-name tty-name speed local-IPX remote-IPX networks. |
*/ |
static void |
ipxcp_script(f, script) |
fsm *f; |
char *script; |
{ |
char strspeed[32], strlocal[32], strremote[32]; |
char strnetwork[32], strpid[32]; |
char *argv[14], strproto_lcl[32], strproto_rmt[32]; |
|
sprintf (strpid, "%d", getpid()); |
sprintf (strspeed, "%d", baud_rate); |
|
strproto_lcl[0] = '\0'; |
if (go->neg_router && ((go->router & BIT(IPX_NONE)) == 0)) { |
if (go->router & BIT(RIP_SAP)) |
strcpy (strproto_lcl, "RIP "); |
if (go->router & BIT(NLSP)) |
strcat (strproto_lcl, "NLSP "); |
} |
|
if (strproto_lcl[0] == '\0') |
strcpy (strproto_lcl, "NONE "); |
|
strproto_lcl[strlen (strproto_lcl)-1] = '\0'; |
|
strproto_rmt[0] = '\0'; |
if (ho->neg_router && ((ho->router & BIT(IPX_NONE)) == 0)) { |
if (ho->router & BIT(RIP_SAP)) |
strcpy (strproto_rmt, "RIP "); |
if (ho->router & BIT(NLSP)) |
strcat (strproto_rmt, "NLSP "); |
} |
|
if (strproto_rmt[0] == '\0') |
strcpy (strproto_rmt, "NONE "); |
|
strproto_rmt[strlen (strproto_rmt)-1] = '\0'; |
|
strcpy (strnetwork, ipx_ntoa (go->network)); |
|
sprintf (strlocal, |
"%02X%02X%02X%02X%02X%02X", |
NODE(go->our_node)); |
|
sprintf (strremote, |
"%02X%02X%02X%02X%02X%02X", |
NODE(ho->his_node)); |
|
argv[0] = script; |
argv[1] = ifname; |
argv[2] = devnam; |
argv[3] = strspeed; |
argv[4] = strnetwork; |
argv[5] = strlocal; |
argv[6] = strremote; |
argv[7] = strproto_lcl; |
argv[8] = strproto_rmt; |
argv[9] = go->name; |
argv[10] = ho->name; |
argv[11] = ipparam; |
argv[12] = strpid; |
argv[13] = NULL; |
run_program(script, argv, 0); |
} |
|
/* |
* ipxcp_printpkt - print the contents of an IPXCP packet. |
*/ |
static char *ipxcp_codenames[] = { |
"ConfReq", "ConfAck", "ConfNak", "ConfRej", |
"TermReq", "TermAck", "CodeRej" |
}; |
|
static int |
ipxcp_printpkt(p, plen, printer, arg) |
u_char *p; |
int plen; |
void (*printer) __P((void *, char *, ...)); |
void *arg; |
{ |
int code, id, len, olen; |
u_char *pstart, *optend; |
u_short cishort; |
u_int32_t cilong; |
|
if (plen < HEADERLEN) |
return 0; |
pstart = p; |
GETCHAR(code, p); |
GETCHAR(id, p); |
GETSHORT(len, p); |
if (len < HEADERLEN || len > plen) |
return 0; |
|
if (code >= 1 && code <= sizeof(ipxcp_codenames) / sizeof(char *)) |
printer(arg, " %s", ipxcp_codenames[code-1]); |
else |
printer(arg, " code=0x%x", code); |
printer(arg, " id=0x%x", id); |
len -= HEADERLEN; |
switch (code) { |
case CONFREQ: |
case CONFACK: |
case CONFNAK: |
case CONFREJ: |
/* print option list */ |
while (len >= 2) { |
GETCHAR(code, p); |
GETCHAR(olen, p); |
p -= 2; |
if (olen < CILEN_VOID || olen > len) { |
break; |
} |
printer(arg, " <"); |
len -= olen; |
optend = p + olen; |
switch (code) { |
case IPX_NETWORK_NUMBER: |
if (olen == CILEN_NETN) { |
p += 2; |
GETLONG(cilong, p); |
printer (arg, "network %s", ipx_ntoa (cilong)); |
} |
break; |
case IPX_NODE_NUMBER: |
if (olen == CILEN_NODEN) { |
p += 2; |
printer (arg, "node "); |
while (p < optend) { |
GETCHAR(code, p); |
printer(arg, "%.2x", (int) (unsigned int) (unsigned char) code); |
} |
} |
break; |
case IPX_COMPRESSION_PROTOCOL: |
if (olen == CILEN_COMPRESS) { |
p += 2; |
GETSHORT (cishort, p); |
printer (arg, "compression %d", (int) cishort); |
} |
break; |
case IPX_ROUTER_PROTOCOL: |
if (olen == CILEN_PROTOCOL) { |
p += 2; |
GETSHORT (cishort, p); |
printer (arg, "router proto %d", (int) cishort); |
} |
break; |
case IPX_ROUTER_NAME: |
if (olen >= CILEN_NAME) { |
p += 2; |
printer (arg, "router name \""); |
while (p < optend) { |
GETCHAR(code, p); |
if (code >= 0x20 && code <= 0x7E) |
printer (arg, "%c", (int) (unsigned int) (unsigned char) code); |
else |
printer (arg, " \\%.2x", (int) (unsigned int) (unsigned char) code); |
} |
printer (arg, "\""); |
} |
break; |
case IPX_COMPLETE: |
if (olen == CILEN_COMPLETE) { |
p += 2; |
printer (arg, "complete"); |
} |
break; |
default: |
break; |
} |
|
while (p < optend) { |
GETCHAR(code, p); |
printer(arg, " %.2x", (int) (unsigned int) (unsigned char) code); |
} |
printer(arg, ">"); |
} |
break; |
|
case TERMACK: |
case TERMREQ: |
if (len > 0 && *p >= ' ' && *p < 0x7f) { |
printer(arg, " "); |
print_string(p, len, printer, arg); |
p += len; |
len = 0; |
} |
break; |
} |
|
/* print the rest of the bytes in the packet */ |
for (; len > 0; --len) { |
GETCHAR(code, p); |
printer(arg, " %.2x", (int) (unsigned int) (unsigned char) code); |
} |
|
return p - pstart; |
} |
#endif /* ifdef IPX_CHANGE */ |
/md4.c
0,0 → 1,298
/* |
** ******************************************************************** |
** md4.c -- Implementation of MD4 Message Digest Algorithm ** |
** Updated: 2/16/90 by Ronald L. Rivest ** |
** (C) 1990 RSA Data Security, Inc. ** |
** ******************************************************************** |
*/ |
|
/* |
** To use MD4: |
** -- Include md4.h in your program |
** -- Declare an MDstruct MD to hold the state of the digest |
** computation. |
** -- Initialize MD using MDbegin(&MD) |
** -- For each full block (64 bytes) X you wish to process, call |
** MD4Update(&MD,X,512) |
** (512 is the number of bits in a full block.) |
** -- For the last block (less than 64 bytes) you wish to process, |
** MD4Update(&MD,X,n) |
** where n is the number of bits in the partial block. A partial |
** block terminates the computation, so every MD computation |
** should terminate by processing a partial block, even if it |
** has n = 0. |
** -- The message digest is available in MD.buffer[0] ... |
** MD.buffer[3]. (Least-significant byte of each word |
** should be output first.) |
** -- You can print out the digest using MDprint(&MD) |
*/ |
|
/* Implementation notes: |
** This implementation assumes that ints are 32-bit quantities. |
*/ |
|
#define TRUE 1 |
#define FALSE 0 |
|
/* Compile-time includes |
*/ |
#include <stdio.h> |
#include "md4.h" |
#include "pppd.h" |
|
/* Compile-time declarations of MD4 "magic constants". |
*/ |
#define I0 0x67452301 /* Initial values for MD buffer */ |
#define I1 0xefcdab89 |
#define I2 0x98badcfe |
#define I3 0x10325476 |
#define C2 013240474631 /* round 2 constant = sqrt(2) in octal */ |
#define C3 015666365641 /* round 3 constant = sqrt(3) in octal */ |
/* C2 and C3 are from Knuth, The Art of Programming, Volume 2 |
** (Seminumerical Algorithms), Second Edition (1981), Addison-Wesley. |
** Table 2, page 660. |
*/ |
|
#define fs1 3 /* round 1 shift amounts */ |
#define fs2 7 |
#define fs3 11 |
#define fs4 19 |
#define gs1 3 /* round 2 shift amounts */ |
#define gs2 5 |
#define gs3 9 |
#define gs4 13 |
#define hs1 3 /* round 3 shift amounts */ |
#define hs2 9 |
#define hs3 11 |
#define hs4 15 |
|
/* Compile-time macro declarations for MD4. |
** Note: The "rot" operator uses the variable "tmp". |
** It assumes tmp is declared as unsigned int, so that the >> |
** operator will shift in zeros rather than extending the sign bit. |
*/ |
#define f(X,Y,Z) ((X&Y) | ((~X)&Z)) |
#define g(X,Y,Z) ((X&Y) | (X&Z) | (Y&Z)) |
#define h(X,Y,Z) (X^Y^Z) |
#define rot(X,S) (tmp=X,(tmp<<S) | (tmp>>(32-S))) |
#define ff(A,B,C,D,i,s) A = rot((A + f(B,C,D) + X[i]),s) |
#define gg(A,B,C,D,i,s) A = rot((A + g(B,C,D) + X[i] + C2),s) |
#define hh(A,B,C,D,i,s) A = rot((A + h(B,C,D) + X[i] + C3),s) |
|
/* MD4print(MDp) |
** Print message digest buffer MDp as 32 hexadecimal digits. |
** Order is from low-order byte of buffer[0] to high-order byte of |
** buffer[3]. |
** Each byte is printed with high-order hexadecimal digit first. |
** This is a user-callable routine. |
*/ |
void |
MD4Print(MDp) |
MD4_CTX *MDp; |
{ |
int i,j; |
for (i=0;i<4;i++) |
for (j=0;j<32;j=j+8) |
printf("%02x",(MDp->buffer[i]>>j) & 0xFF); |
} |
|
/* MD4Init(MDp) |
** Initialize message digest buffer MDp. |
** This is a user-callable routine. |
*/ |
void |
MD4Init(MDp) |
MD4_CTX *MDp; |
{ |
int i; |
MDp->buffer[0] = I0; |
MDp->buffer[1] = I1; |
MDp->buffer[2] = I2; |
MDp->buffer[3] = I3; |
for (i=0;i<8;i++) MDp->count[i] = 0; |
MDp->done = 0; |
} |
|
/* MDblock(MDp,X) |
** Update message digest buffer MDp->buffer using 16-word data block X. |
** Assumes all 16 words of X are full of data. |
** Does not update MDp->count. |
** This routine is not user-callable. |
*/ |
static void |
MDblock(MDp,Xb) |
MD4_CTX *MDp; |
unsigned char *Xb; |
{ |
register unsigned int tmp, A, B, C, D; |
unsigned int X[16]; |
int i; |
|
for (i = 0; i < 16; ++i) { |
X[i] = Xb[0] + (Xb[1] << 8) + (Xb[2] << 16) + (Xb[3] << 24); |
Xb += 4; |
} |
|
A = MDp->buffer[0]; |
B = MDp->buffer[1]; |
C = MDp->buffer[2]; |
D = MDp->buffer[3]; |
/* Update the message digest buffer */ |
ff(A , B , C , D , 0 , fs1); /* Round 1 */ |
ff(D , A , B , C , 1 , fs2); |
ff(C , D , A , B , 2 , fs3); |
ff(B , C , D , A , 3 , fs4); |
ff(A , B , C , D , 4 , fs1); |
ff(D , A , B , C , 5 , fs2); |
ff(C , D , A , B , 6 , fs3); |
ff(B , C , D , A , 7 , fs4); |
ff(A , B , C , D , 8 , fs1); |
ff(D , A , B , C , 9 , fs2); |
ff(C , D , A , B , 10 , fs3); |
ff(B , C , D , A , 11 , fs4); |
ff(A , B , C , D , 12 , fs1); |
ff(D , A , B , C , 13 , fs2); |
ff(C , D , A , B , 14 , fs3); |
ff(B , C , D , A , 15 , fs4); |
gg(A , B , C , D , 0 , gs1); /* Round 2 */ |
gg(D , A , B , C , 4 , gs2); |
gg(C , D , A , B , 8 , gs3); |
gg(B , C , D , A , 12 , gs4); |
gg(A , B , C , D , 1 , gs1); |
gg(D , A , B , C , 5 , gs2); |
gg(C , D , A , B , 9 , gs3); |
gg(B , C , D , A , 13 , gs4); |
gg(A , B , C , D , 2 , gs1); |
gg(D , A , B , C , 6 , gs2); |
gg(C , D , A , B , 10 , gs3); |
gg(B , C , D , A , 14 , gs4); |
gg(A , B , C , D , 3 , gs1); |
gg(D , A , B , C , 7 , gs2); |
gg(C , D , A , B , 11 , gs3); |
gg(B , C , D , A , 15 , gs4); |
hh(A , B , C , D , 0 , hs1); /* Round 3 */ |
hh(D , A , B , C , 8 , hs2); |
hh(C , D , A , B , 4 , hs3); |
hh(B , C , D , A , 12 , hs4); |
hh(A , B , C , D , 2 , hs1); |
hh(D , A , B , C , 10 , hs2); |
hh(C , D , A , B , 6 , hs3); |
hh(B , C , D , A , 14 , hs4); |
hh(A , B , C , D , 1 , hs1); |
hh(D , A , B , C , 9 , hs2); |
hh(C , D , A , B , 5 , hs3); |
hh(B , C , D , A , 13 , hs4); |
hh(A , B , C , D , 3 , hs1); |
hh(D , A , B , C , 11 , hs2); |
hh(C , D , A , B , 7 , hs3); |
hh(B , C , D , A , 15 , hs4); |
MDp->buffer[0] += A; |
MDp->buffer[1] += B; |
MDp->buffer[2] += C; |
MDp->buffer[3] += D; |
} |
|
/* MD4Update(MDp,X,count) |
** Input: X -- a pointer to an array of unsigned characters. |
** count -- the number of bits of X to use. |
** (if not a multiple of 8, uses high bits of last byte.) |
** Update MDp using the number of bits of X given by count. |
** This is the basic input routine for an MD4 user. |
** The routine completes the MD computation when count < 512, so |
** every MD computation should end with one call to MD4Update with a |
** count less than 512. A call with count 0 will be ignored if the |
** MD has already been terminated (done != 0), so an extra call with |
** count 0 can be given as a "courtesy close" to force termination |
** if desired. |
*/ |
void |
MD4Update(MDp,X,count) |
MD4_CTX *MDp; |
unsigned char *X; |
unsigned int count; |
{ |
unsigned int i, tmp, bit, byte, mask; |
unsigned char XX[64]; |
unsigned char *p; |
|
/* return with no error if this is a courtesy close with count |
** zero and MDp->done is true. |
*/ |
if (count == 0 && MDp->done) return; |
/* check to see if MD is already done and report error */ |
if (MDp->done) |
{ printf("\nError: MD4Update MD already done."); return; } |
|
/* Add count to MDp->count */ |
tmp = count; |
p = MDp->count; |
while (tmp) |
{ tmp += *p; |
*p++ = tmp; |
tmp = tmp >> 8; |
} |
|
/* Process data */ |
if (count == 512) |
{ /* Full block of data to handle */ |
MDblock(MDp,X); |
} |
else if (count > 512) /* Check for count too large */ |
{ |
printf("\nError: MD4Update called with illegal count value %d.", |
count); |
return; |
} |
else /* partial block -- must be last block so finish up */ |
{ |
/* Find out how many bytes and residual bits there are */ |
byte = count >> 3; |
bit = count & 7; |
/* Copy X into XX since we need to modify it */ |
for (i=0;i<=byte;i++) XX[i] = X[i]; |
for (i=byte+1;i<64;i++) XX[i] = 0; |
/* Add padding '1' bit and low-order zeros in last byte */ |
mask = 1 << (7 - bit); |
XX[byte] = (XX[byte] | mask) & ~( mask - 1); |
/* If room for bit count, finish up with this block */ |
if (byte <= 55) |
{ |
for (i=0;i<8;i++) XX[56+i] = MDp->count[i]; |
MDblock(MDp,XX); |
} |
else /* need to do two blocks to finish up */ |
{ |
MDblock(MDp,XX); |
for (i=0;i<56;i++) XX[i] = 0; |
for (i=0;i<8;i++) XX[56+i] = MDp->count[i]; |
MDblock(MDp,XX); |
} |
/* Set flag saying we're done with MD computation */ |
MDp->done = 1; |
} |
} |
|
/* |
** Finish up MD4 computation and return message digest. |
*/ |
void |
MD4Final(buf, MD) |
unsigned char *buf; |
MD4_CTX *MD; |
{ |
int i, j; |
unsigned int w; |
|
MD4Update(MD, NULL, 0); |
for (i = 0; i < 4; ++i) { |
w = MD->buffer[i]; |
for (j = 0; j < 4; ++j) { |
*buf++ = w; |
w >>= 8; |
} |
} |
} |
|
/* |
** End of md4.c |
****************************(cut)***********************************/ |
/md5.c
0,0 → 1,306
|
|
/* |
*********************************************************************** |
** md5.c -- the source code for MD5 routines ** |
** RSA Data Security, Inc. MD5 Message-Digest Algorithm ** |
** Created: 2/17/90 RLR ** |
** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. ** |
*********************************************************************** |
*/ |
|
/* |
*********************************************************************** |
** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** |
** ** |
** License to copy and use this software is granted provided that ** |
** it is identified as the "RSA Data Security, Inc. MD5 Message- ** |
** Digest Algorithm" in all material mentioning or referencing this ** |
** software or this function. ** |
** ** |
** License is also granted to make and use derivative works ** |
** provided that such works are identified as "derived from the RSA ** |
** Data Security, Inc. MD5 Message-Digest Algorithm" in all ** |
** material mentioning or referencing the derived work. ** |
** ** |
** RSA Data Security, Inc. makes no representations concerning ** |
** either the merchantability of this software or the suitability ** |
** of this software for any particular purpose. It is provided "as ** |
** is" without express or implied warranty of any kind. ** |
** ** |
** These notices must be retained in any copies of any part of this ** |
** documentation and/or software. ** |
*********************************************************************** |
*/ |
|
#include "md5.h" |
|
/* |
*********************************************************************** |
** Message-digest routines: ** |
** To form the message digest for a message M ** |
** (1) Initialize a context buffer mdContext using MD5Init ** |
** (2) Call MD5Update on mdContext and M ** |
** (3) Call MD5Final on mdContext ** |
** The message digest is now in mdContext->digest[0...15] ** |
*********************************************************************** |
*/ |
|
/* forward declaration */ |
static void Transform (); |
|
static unsigned char PADDING[64] = { |
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
}; |
|
/* F, G, H and I are basic MD5 functions */ |
#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) |
#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) |
#define H(x, y, z) ((x) ^ (y) ^ (z)) |
#define I(x, y, z) ((y) ^ ((x) | (~z))) |
|
/* ROTATE_LEFT rotates x left n bits */ |
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) |
|
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */ |
/* Rotation is separate from addition to prevent recomputation */ |
#define FF(a, b, c, d, x, s, ac) \ |
{(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ |
(a) = ROTATE_LEFT ((a), (s)); \ |
(a) += (b); \ |
} |
#define GG(a, b, c, d, x, s, ac) \ |
{(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ |
(a) = ROTATE_LEFT ((a), (s)); \ |
(a) += (b); \ |
} |
#define HH(a, b, c, d, x, s, ac) \ |
{(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ |
(a) = ROTATE_LEFT ((a), (s)); \ |
(a) += (b); \ |
} |
#define II(a, b, c, d, x, s, ac) \ |
{(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ |
(a) = ROTATE_LEFT ((a), (s)); \ |
(a) += (b); \ |
} |
|
#ifdef __STDC__ |
#define UL(x) x##U |
#else |
#define UL(x) x |
#endif |
|
/* The routine MD5Init initializes the message-digest context |
mdContext. All fields are set to zero. |
*/ |
void MD5Init (mdContext) |
MD5_CTX *mdContext; |
{ |
mdContext->i[0] = mdContext->i[1] = (UINT4)0; |
|
/* Load magic initialization constants. |
*/ |
mdContext->buf[0] = (UINT4)0x67452301; |
mdContext->buf[1] = (UINT4)0xefcdab89; |
mdContext->buf[2] = (UINT4)0x98badcfe; |
mdContext->buf[3] = (UINT4)0x10325476; |
} |
|
/* The routine MD5Update updates the message-digest context to |
account for the presence of each of the characters inBuf[0..inLen-1] |
in the message whose digest is being computed. |
*/ |
void MD5Update (mdContext, inBuf, inLen) |
MD5_CTX *mdContext; |
unsigned char *inBuf; |
unsigned int inLen; |
{ |
UINT4 in[16]; |
int mdi; |
unsigned int i, ii; |
|
/* compute number of bytes mod 64 */ |
mdi = (int)((mdContext->i[0] >> 3) & 0x3F); |
|
/* update number of bits */ |
if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0]) |
mdContext->i[1]++; |
mdContext->i[0] += ((UINT4)inLen << 3); |
mdContext->i[1] += ((UINT4)inLen >> 29); |
|
while (inLen--) { |
/* add new character to buffer, increment mdi */ |
mdContext->in[mdi++] = *inBuf++; |
|
/* transform if necessary */ |
if (mdi == 0x40) { |
for (i = 0, ii = 0; i < 16; i++, ii += 4) |
in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | |
(((UINT4)mdContext->in[ii+2]) << 16) | |
(((UINT4)mdContext->in[ii+1]) << 8) | |
((UINT4)mdContext->in[ii]); |
Transform (mdContext->buf, in); |
mdi = 0; |
} |
} |
} |
|
/* The routine MD5Final terminates the message-digest computation and |
ends with the desired message digest in mdContext->digest[0...15]. |
*/ |
void MD5Final (hash, mdContext) |
unsigned char hash[]; |
MD5_CTX *mdContext; |
{ |
UINT4 in[16]; |
int mdi; |
unsigned int i, ii; |
unsigned int padLen; |
|
/* save number of bits */ |
in[14] = mdContext->i[0]; |
in[15] = mdContext->i[1]; |
|
/* compute number of bytes mod 64 */ |
mdi = (int)((mdContext->i[0] >> 3) & 0x3F); |
|
/* pad out to 56 mod 64 */ |
padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi); |
MD5Update (mdContext, PADDING, padLen); |
|
/* append length in bits and transform */ |
for (i = 0, ii = 0; i < 14; i++, ii += 4) |
in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | |
(((UINT4)mdContext->in[ii+2]) << 16) | |
(((UINT4)mdContext->in[ii+1]) << 8) | |
((UINT4)mdContext->in[ii]); |
Transform (mdContext->buf, in); |
|
/* store buffer in digest */ |
for (i = 0, ii = 0; i < 4; i++, ii += 4) { |
mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF); |
mdContext->digest[ii+1] = |
(unsigned char)((mdContext->buf[i] >> 8) & 0xFF); |
mdContext->digest[ii+2] = |
(unsigned char)((mdContext->buf[i] >> 16) & 0xFF); |
mdContext->digest[ii+3] = |
(unsigned char)((mdContext->buf[i] >> 24) & 0xFF); |
} |
memcpy(hash, mdContext->digest, 16); |
} |
|
/* Basic MD5 step. Transforms buf based on in. |
*/ |
static void Transform (buf, in) |
UINT4 *buf; |
UINT4 *in; |
{ |
UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; |
|
/* Round 1 */ |
#define S11 7 |
#define S12 12 |
#define S13 17 |
#define S14 22 |
FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */ |
FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */ |
FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */ |
FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */ |
FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */ |
FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */ |
FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */ |
FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */ |
FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */ |
FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */ |
FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */ |
FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */ |
FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */ |
FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */ |
FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */ |
FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */ |
|
/* Round 2 */ |
#define S21 5 |
#define S22 9 |
#define S23 14 |
#define S24 20 |
GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */ |
GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */ |
GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */ |
GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */ |
GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */ |
GG ( d, a, b, c, in[10], S22, UL( 38016083)); /* 22 */ |
GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */ |
GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */ |
GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */ |
GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */ |
GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */ |
GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */ |
GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */ |
GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */ |
GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */ |
GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */ |
|
/* Round 3 */ |
#define S31 4 |
#define S32 11 |
#define S33 16 |
#define S34 23 |
HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */ |
HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */ |
HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */ |
HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */ |
HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */ |
HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */ |
HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */ |
HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */ |
HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */ |
HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */ |
HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */ |
HH ( b, c, d, a, in[ 6], S34, UL( 76029189)); /* 44 */ |
HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */ |
HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */ |
HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */ |
HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */ |
|
/* Round 4 */ |
#define S41 6 |
#define S42 10 |
#define S43 15 |
#define S44 21 |
II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */ |
II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */ |
II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */ |
II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */ |
II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */ |
II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */ |
II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */ |
II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */ |
II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */ |
II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */ |
II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */ |
II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */ |
II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */ |
II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */ |
II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */ |
II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */ |
|
buf[0] += a; |
buf[1] += b; |
buf[2] += c; |
buf[3] += d; |
} |
|
/* |
*********************************************************************** |
** End of md5.c ** |
******************************** (cut) ******************************** |
*/ |
/magic.h
0,0 → 1,23
/* |
* magic.h - PPP Magic Number definitions. |
* |
* Copyright (c) 1989 Carnegie Mellon University. |
* All rights reserved. |
* |
* 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 Carnegie Mellon University. The name of the |
* University may not be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
* |
* $Id: magic.h,v 1.2 2001-09-27 12:01:57 chris Exp $ |
*/ |
|
void magic_init __P((void)); /* Initialize the magic number generator */ |
u_int32_t magic __P((void)); /* Returns the next magic number */ |
/ipxcp.h
0,0 → 1,71
/* |
* ipxcp.h - IPX Control Protocol definitions. |
* |
* Copyright (c) 1989 Carnegie Mellon University. |
* All rights reserved. |
* |
* 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 Carnegie Mellon University. The name of the |
* University may not be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
* |
* $Id: ipxcp.h,v 1.2 2001-09-27 12:01:57 chris Exp $ |
*/ |
|
/* |
* Options. |
*/ |
#define IPX_NETWORK_NUMBER 1 /* IPX Network Number */ |
#define IPX_NODE_NUMBER 2 |
#define IPX_COMPRESSION_PROTOCOL 3 |
#define IPX_ROUTER_PROTOCOL 4 |
#define IPX_ROUTER_NAME 5 |
#define IPX_COMPLETE 6 |
|
/* Values for the router protocol */ |
#define IPX_NONE 0 |
#define RIP_SAP 2 |
#define NLSP 4 |
|
typedef struct ipxcp_options { |
int neg_node : 1; /* Negotiate IPX node number? */ |
int req_node : 1; /* Ask peer to send IPX node number? */ |
|
int neg_nn : 1; /* Negotiate IPX network number? */ |
int req_nn : 1; /* Ask peer to send IPX network number */ |
|
int neg_name : 1; /* Negotiate IPX router name */ |
int neg_complete : 1; /* Negotiate completion */ |
int neg_router : 1; /* Negotiate IPX router number */ |
|
int accept_local : 1; /* accept peer's value for ournode */ |
int accept_remote : 1; /* accept peer's value for hisnode */ |
int accept_network : 1; /* accept network number */ |
|
int tried_nlsp : 1; /* I have suggested NLSP already */ |
int tried_rip : 1; /* I have suggested RIP/SAP already */ |
|
u_int32_t his_network; /* base network number */ |
u_int32_t our_network; /* our value for network number */ |
u_int32_t network; /* the final network number */ |
|
u_char his_node[6]; /* peer's node number */ |
u_char our_node[6]; /* our node number */ |
u_char name [48]; /* name of the router */ |
int router; /* routing protocol */ |
} ipxcp_options; |
|
extern fsm ipxcp_fsm[]; |
extern ipxcp_options ipxcp_wantoptions[]; |
extern ipxcp_options ipxcp_gotoptions[]; |
extern ipxcp_options ipxcp_allowoptions[]; |
extern ipxcp_options ipxcp_hisoptions[]; |
|
extern struct protent ipxcp_protent; |
/demand.c
0,0 → 1,348
/* |
* demand.c - Support routines for demand-dialling. |
* |
* Copyright (c) 1993 The Australian National University. |
* All rights reserved. |
* |
* 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 Australian National University. The name of the University |
* 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. |
*/ |
|
#ifndef lint |
/* static char rcsid[] = "$Id: demand.c,v 1.2 2001-09-27 12:01:57 chris Exp $"; */ |
#endif |
|
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <errno.h> |
#include <fcntl.h> |
#include <syslog.h> |
#include <netdb.h> |
#include <sys/param.h> |
#include <sys/types.h> |
#include <sys/wait.h> |
#include <sys/time.h> |
#include <sys/resource.h> |
#include <sys/stat.h> |
#include <sys/socket.h> |
#ifdef PPP_FILTER |
#include <net/if.h> |
#include <net/bpf.h> |
#include <pcap.h> |
#endif |
|
#include "pppd.h" |
#include "fsm.h" |
#include "ipcp.h" |
#include "lcp.h" |
|
char *frame; |
int framelen; |
int framemax; |
int escape_flag; |
int flush_flag; |
int fcs; |
|
struct packet { |
int length; |
struct packet *next; |
unsigned char data[1]; |
}; |
|
struct packet *pend_q; |
struct packet *pend_qtail; |
|
static int active_packet __P((unsigned char *, int)); |
|
/* |
* demand_conf - configure the interface for doing dial-on-demand. |
*/ |
void |
demand_conf() |
{ |
int i; |
struct protent *protp; |
|
/* framemax = lcp_allowoptions[0].mru; |
if (framemax < PPP_MRU) */ |
framemax = PPP_MRU; |
framemax += PPP_HDRLEN + PPP_FCSLEN; |
frame = malloc(framemax); |
if (frame == NULL) |
novm("demand frame"); |
framelen = 0; |
pend_q = NULL; |
escape_flag = 0; |
flush_flag = 0; |
fcs = PPP_INITFCS; |
|
ppp_send_config(0, PPP_MRU, (u_int32_t) 0, 0, 0); |
ppp_recv_config(0, PPP_MRU, (u_int32_t) 0, 0, 0); |
|
#ifdef PPP_FILTER |
set_filters(&pass_filter, &active_filter); |
#endif |
|
/* |
* Call the demand_conf procedure for each protocol that's got one. |
*/ |
for (i = 0; (protp = protocols[i]) != NULL; ++i) |
if (protp->enabled_flag && protp->demand_conf != NULL) |
if (!((*protp->demand_conf)(0))) |
die(1); |
} |
|
|
/* |
* demand_block - set each network protocol to block further packets. |
*/ |
void |
demand_block() |
{ |
int i; |
struct protent *protp; |
|
for (i = 0; (protp = protocols[i]) != NULL; ++i) |
if (protp->enabled_flag && protp->demand_conf != NULL) |
sifnpmode(0, protp->protocol & ~0x8000, NPMODE_QUEUE); |
get_loop_output(); |
} |
|
/* |
* demand_discard - set each network protocol to discard packets |
* with an error. |
*/ |
void |
demand_discard() |
{ |
struct packet *pkt, *nextpkt; |
int i; |
struct protent *protp; |
|
for (i = 0; (protp = protocols[i]) != NULL; ++i) |
if (protp->enabled_flag && protp->demand_conf != NULL) |
sifnpmode(0, protp->protocol & ~0x8000, NPMODE_ERROR); |
get_loop_output(); |
|
/* discard all saved packets */ |
for (pkt = pend_q; pkt != NULL; pkt = nextpkt) { |
nextpkt = pkt->next; |
free(pkt); |
} |
pend_q = NULL; |
framelen = 0; |
flush_flag = 0; |
escape_flag = 0; |
fcs = PPP_INITFCS; |
} |
|
/* |
* demand_unblock - set each enabled network protocol to pass packets. |
*/ |
void |
demand_unblock() |
{ |
int i; |
struct protent *protp; |
|
for (i = 0; (protp = protocols[i]) != NULL; ++i) |
if (protp->enabled_flag && protp->demand_conf != NULL) |
sifnpmode(0, protp->protocol & ~0x8000, NPMODE_PASS); |
} |
|
/* |
* FCS lookup table as calculated by genfcstab. |
*/ |
static u_short fcstab[256] = { |
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, |
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, |
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, |
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, |
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, |
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, |
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, |
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, |
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, |
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, |
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, |
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, |
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, |
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, |
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, |
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, |
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, |
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, |
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, |
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, |
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, |
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, |
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, |
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, |
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, |
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, |
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, |
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, |
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, |
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, |
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, |
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 |
}; |
|
/* |
* loop_chars - process characters received from the loopback. |
* Calls loop_frame when a complete frame has been accumulated. |
* Return value is 1 if we need to bring up the link, 0 otherwise. |
*/ |
int |
loop_chars(p, n) |
unsigned char *p; |
int n; |
{ |
int c, rv; |
|
rv = 0; |
for (; n > 0; --n) { |
c = *p++; |
if (c == PPP_FLAG) { |
if (!escape_flag && !flush_flag |
&& framelen > 2 && fcs == PPP_GOODFCS) { |
framelen -= 2; |
if (loop_frame(frame, framelen)) |
rv = 1; |
} |
framelen = 0; |
flush_flag = 0; |
escape_flag = 0; |
fcs = PPP_INITFCS; |
continue; |
} |
if (flush_flag) |
continue; |
if (escape_flag) { |
c ^= PPP_TRANS; |
escape_flag = 0; |
} else if (c == PPP_ESCAPE) { |
escape_flag = 1; |
continue; |
} |
if (framelen >= framemax) { |
flush_flag = 1; |
continue; |
} |
frame[framelen++] = c; |
fcs = PPP_FCS(fcs, c); |
} |
return rv; |
} |
|
/* |
* loop_frame - given a frame obtained from the loopback, |
* decide whether to bring up the link or not, and, if we want |
* to transmit this frame later, put it on the pending queue. |
* Return value is 1 if we need to bring up the link, 0 otherwise. |
* We assume that the kernel driver has already applied the |
* pass_filter, so we won't get packets it rejected. |
* We apply the active_filter to see if we want this packet to |
* bring up the link. |
*/ |
int |
loop_frame(frame, len) |
unsigned char *frame; |
int len; |
{ |
struct packet *pkt; |
|
/* log_packet(frame, len, "from loop: ", LOG_DEBUG); */ |
if (len < PPP_HDRLEN) |
return 0; |
if ((PPP_PROTOCOL(frame) & 0x8000) != 0) |
return 0; /* shouldn't get any of these anyway */ |
if (!active_packet(frame, len)) |
return 0; |
|
pkt = (struct packet *) malloc(sizeof(struct packet) + len); |
if (pkt != NULL) { |
pkt->length = len; |
pkt->next = NULL; |
memcpy(pkt->data, frame, len); |
if (pend_q == NULL) |
pend_q = pkt; |
else |
pend_qtail->next = pkt; |
pend_qtail = pkt; |
} |
return 1; |
} |
|
/* |
* demand_rexmit - Resend all those frames which we got via the |
* loopback, now that the real serial link is up. |
*/ |
void |
demand_rexmit(proto) |
int proto; |
{ |
struct packet *pkt, *prev, *nextpkt; |
|
prev = NULL; |
pkt = pend_q; |
pend_q = NULL; |
for (; pkt != NULL; pkt = nextpkt) { |
nextpkt = pkt->next; |
if (PPP_PROTOCOL(pkt->data) == proto) { |
output(0, pkt->data, pkt->length); |
free(pkt); |
} else { |
if (prev == NULL) |
pend_q = pkt; |
else |
prev->next = pkt; |
prev = pkt; |
} |
} |
pend_qtail = prev; |
if (prev != NULL) |
prev->next = NULL; |
} |
|
/* |
* Scan a packet to decide whether it is an "active" packet, |
* that is, whether it is worth bringing up the link for. |
*/ |
static int |
active_packet(p, len) |
unsigned char *p; |
int len; |
{ |
int proto, i; |
struct protent *protp; |
|
if (len < PPP_HDRLEN) |
return 0; |
proto = PPP_PROTOCOL(p); |
#ifdef PPP_FILTER |
if (active_filter.bf_len != 0 |
&& bpf_filter(active_filter.bf_insns, frame, len, len) == 0) |
return 0; |
#endif |
for (i = 0; (protp = protocols[i]) != NULL; ++i) { |
if (protp->protocol < 0xC000 && (protp->protocol & ~0x8000) == proto) { |
if (!protp->enabled_flag) |
return 0; |
if (protp->active_pkt == NULL) |
return 1; |
return (*protp->active_pkt)(p, len); |
} |
} |
return 0; /* not a supported protocol !!?? */ |
} |
/md4.h
0,0 → 1,64
|
/* |
** ******************************************************************** |
** md4.h -- Header file for implementation of ** |
** MD4 Message Digest Algorithm ** |
** Updated: 2/13/90 by Ronald L. Rivest ** |
** (C) 1990 RSA Data Security, Inc. ** |
** ******************************************************************** |
*/ |
|
#ifndef __P |
# if defined(__STDC__) || defined(__GNUC__) |
# define __P(x) x |
# else |
# define __P(x) () |
# endif |
#endif |
|
|
/* MDstruct is the data structure for a message digest computation. |
*/ |
typedef struct { |
unsigned int buffer[4]; /* Holds 4-word result of MD computation */ |
unsigned char count[8]; /* Number of bits processed so far */ |
unsigned int done; /* Nonzero means MD computation finished */ |
} MD4_CTX; |
|
/* MD4Init(MD4_CTX *) |
** Initialize the MD4_CTX prepatory to doing a message digest |
** computation. |
*/ |
extern void MD4Init __P((MD4_CTX *MD)); |
|
/* MD4Update(MD,X,count) |
** Input: X -- a pointer to an array of unsigned characters. |
** count -- the number of bits of X to use (an unsigned int). |
** Updates MD using the first "count" bits of X. |
** The array pointed to by X is not modified. |
** If count is not a multiple of 8, MD4Update uses high bits of |
** last byte. |
** This is the basic input routine for a user. |
** The routine terminates the MD computation when count < 512, so |
** every MD computation should end with one call to MD4Update with a |
** count less than 512. Zero is OK for a count. |
*/ |
extern void MD4Update __P((MD4_CTX *MD, unsigned char *X, unsigned int count)); |
|
/* MD4Print(MD) |
** Prints message digest buffer MD as 32 hexadecimal digits. |
** Order is from low-order byte of buffer[0] to high-order byte |
** of buffer[3]. |
** Each byte is printed with high-order hexadecimal digit first. |
*/ |
extern void MD4Print __P((MD4_CTX *)); |
|
/* MD4Final(buf, MD) |
** Returns message digest from MD and terminates the message |
** digest computation. |
*/ |
extern void MD4Final __P((unsigned char *, MD4_CTX *)); |
|
/* |
** End of md4.h |
****************************(cut)***********************************/ |
/md5.h
0,0 → 1,58
/* |
*********************************************************************** |
** md5.h -- header file for implementation of MD5 ** |
** RSA Data Security, Inc. MD5 Message-Digest Algorithm ** |
** Created: 2/17/90 RLR ** |
** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version ** |
** Revised (for MD5): RLR 4/27/91 ** |
** -- G modified to have y&~z instead of y&z ** |
** -- FF, GG, HH modified to add in last register done ** |
** -- Access pattern: round 2 works mod 5, round 3 works mod 3 ** |
** -- distinct additive constant for each step ** |
** -- round 4 added, working mod 7 ** |
*********************************************************************** |
*/ |
|
/* |
*********************************************************************** |
** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** |
** ** |
** License to copy and use this software is granted provided that ** |
** it is identified as the "RSA Data Security, Inc. MD5 Message- ** |
** Digest Algorithm" in all material mentioning or referencing this ** |
** software or this function. ** |
** ** |
** License is also granted to make and use derivative works ** |
** provided that such works are identified as "derived from the RSA ** |
** Data Security, Inc. MD5 Message-Digest Algorithm" in all ** |
** material mentioning or referencing the derived work. ** |
** ** |
** RSA Data Security, Inc. makes no representations concerning ** |
** either the merchantability of this software or the suitability ** |
** of this software for any particular purpose. It is provided "as ** |
** is" without express or implied warranty of any kind. ** |
** ** |
** These notices must be retained in any copies of any part of this ** |
** documentation and/or software. ** |
*********************************************************************** |
*/ |
|
#ifndef __MD5_INCLUDE__ |
|
/* typedef a 32-bit type */ |
typedef unsigned int UINT4; |
|
/* Data structure for MD5 (Message-Digest) computation */ |
typedef struct { |
UINT4 i[2]; /* number of _bits_ handled mod 2^64 */ |
UINT4 buf[4]; /* scratch buffer */ |
unsigned char in[64]; /* input buffer */ |
unsigned char digest[16]; /* actual digest after MD5Final call */ |
} MD5_CTX; |
|
void MD5Init (); |
void MD5Update (); |
void MD5Final (); |
|
#define __MD5_INCLUDE__ |
#endif /* __MD5_INCLUDE__ */ |
/modem_example/ppp.c
0,0 → 1,1504
/* |
* if_ppp.c - Point-to-Point Protocol (PPP) Asynchronous driver. |
* |
* Copyright (c) 1989 Carnegie Mellon University. |
* All rights reserved. |
* |
* 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 Carnegie Mellon University. The name of the |
* University 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. |
* |
* Drew D. Perkins |
* Carnegie Mellon University |
* 4910 Forbes Ave. |
* Pittsburgh, PA 15213 |
* (412) 268-8576 |
* ddp@andrew.cmu.edu |
* |
* Based on: |
* @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89 |
* |
* Copyright (c) 1987 Regents of the University of California. |
* All rights reserved. |
* |
* 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 University of California, Berkeley. The name of the |
* University 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. |
* |
* Serial Line interface |
* |
* Rick Adams |
* Center for Seismic Studies |
* 1300 N 17th Street, Suite 1450 |
* Arlington, Virginia 22209 |
* (703)276-7900 |
* rick@seismo.ARPA |
* seismo!rick |
* |
* Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris). |
* Converted to 4.3BSD Beta by Chris Torek. |
* Other changes made at Berkeley, based in part on code by Kirk Smith. |
* |
* Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com) |
* Added VJ tcp header compression; more unified ioctls |
* |
* Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au). |
* Cleaned up a lot of the mbuf-related code to fix bugs that |
* caused system crashes and packet corruption. Changed pppstart |
* so that it doesn't just give up with a collision if the whole |
* packet doesn't fit in the output ring buffer. |
* |
* Added priority queueing for interactive IP packets, following |
* the model of if_sl.c, plus hooks for bpf. |
* Paul Mackerras (paulus@cs.anu.edu.au). |
*/ |
|
/* $Id: ppp.c,v 1.2 2001-09-27 12:01:57 chris Exp $ */ |
/* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */ |
/* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:58 cgd Exp */ |
|
#include "ppp.h" |
#if NPPP > 0 |
/* na razie wylaczmy kompresje*/ |
|
#include <sys/param.h> |
#include <sys/systm.h> |
#include <sys/proc.h> |
#include <sys/mbuf.h> |
#include <sys/socket.h> |
#include <sys/ioctl.h> |
#include <sys/kernel.h> |
#include <sys/time.h> |
#include <sys/malloc.h> |
|
#include <rtems/rtems_bsdnet.h> |
#include <net/if.h> |
#include <sys/errno.h> |
#include <net/if_types.h> |
#include <net/netisr.h> |
#include <net/route.h> |
#ifdef PPP_FILTER |
#include <net/bpf.h> |
#endif |
|
#ifdef INET |
#include <netinet/in.h> |
#include <netinet/in_systm.h> |
#include <netinet/in_var.h> |
#include <netinet/ip.h> |
#endif |
|
#include <bpfilter.h> |
#if NBPFILTER > 0 |
#include <net/bpf.h> |
#endif |
|
#ifdef VJC |
#include <net/pppcompress.h> |
#endif |
|
#include <net/ppp_defs.h> |
#include <net/if_ppp.h> |
#include <net/if_pppvar.h> |
#include <machine/cpu.h> |
|
#define splsoftnet splnet |
|
#ifndef NETISR_PPP |
/* This definition should be moved to net/netisr.h */ |
#define NETISR_PPP 26 /* PPP software interrupt */ |
#endif |
|
#ifdef PPP_COMPRESS |
#define PACKETPTR struct mbuf * |
#include <net/ppp-comp.h> |
#endif |
extern struct ifqueue ipintrq; |
static int pppsioctl __P((struct ifnet *, int, caddr_t)); |
static void ppp_requeue __P((struct ppp_softc *)); |
static void ppp_ccp __P((struct ppp_softc *, struct mbuf *m, int rcvd)); |
static void ppp_ccp_closed __P((struct ppp_softc *)); |
static void ppp_inproc __P((struct ppp_softc *, struct mbuf *)); |
static void pppdumpm __P((struct mbuf *m0)); |
|
/* |
* Some useful mbuf macros not in mbuf.h. |
*/ |
#define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT) |
|
#define M_DATASTART(m) \ |
(M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \ |
(m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat) |
|
#define M_DATASIZE(m) \ |
(M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \ |
(m)->m_flags & M_PKTHDR ? MHLEN: MLEN) |
|
/* |
* We steal two bits in the mbuf m_flags, to mark high-priority packets |
* for output, and received packets following lost/corrupted packets. |
*/ |
#define M_HIGHPRI 0x2000 /* output packet for sc_fastq */ |
#define M_ERRMARK 0x4000 /* steal a bit in mbuf m_flags */ |
|
|
#ifdef PPP_COMPRESS |
/* |
* List of compressors we know about. |
* We leave some space so maybe we can modload compressors. |
*/ |
|
extern struct compressor ppp_bsd_compress; |
extern struct compressor ppp_deflate, ppp_deflate_draft; |
|
|
struct compressor *ppp_compressors[8] = { |
#if DO_BSD_COMPRESS |
&ppp_bsd_compress, |
#endif |
#if DO_DEFLATE |
&ppp_deflate, |
&ppp_deflate_draft, |
#endif |
NULL |
}; |
#endif /* PPP_COMPRESS */ |
static struct timeval ppp_time; |
|
TEXT_SET(pseudo_set, pppattach); |
|
/* |
* Called from boot code to establish ppp interfaces. |
*/ |
int rtems_ppp_driver_attach (struct rtems_bsdnet_ifconfig *config) |
{ |
register struct ppp_softc *sc; |
register int i = 0; |
extern void (*netisrs[])__P((void)); |
|
for (sc = ppp_softc; i < NPPP; sc++) { |
sc->sc_if.if_name = "ppp"; |
sc->sc_if.if_unit = i++; |
sc->sc_if.if_mtu = PPP_MTU; |
sc->sc_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; |
sc->sc_if.if_type = IFT_PPP; |
sc->sc_if.if_hdrlen = PPP_HDRLEN; |
sc->sc_if.if_ioctl = pppsioctl; |
sc->sc_if.if_output = pppoutput; |
sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN; |
sc->sc_inq.ifq_maxlen = IFQ_MAXLEN; |
sc->sc_fastq.ifq_maxlen = IFQ_MAXLEN; |
sc->sc_rawq.ifq_maxlen = IFQ_MAXLEN; |
if_attach(&sc->sc_if); |
#if NBPFILTER > 0 |
bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_PPP, PPP_HDRLEN); |
#endif |
} |
/* wpisane na twardo do rtems_glue.c |
netisrs[NETISR_PPP] = pppintr; */ |
return 1; |
} |
|
/* |
* Allocate a ppp interface unit and initialize it. |
*/ |
struct ppp_softc * |
pppalloc(pid) |
pid_t pid; |
{ |
int nppp, i; |
struct ppp_softc *sc; |
for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++) |
if (sc->sc_xfer == pid) { |
sc->sc_xfer = 0; |
return sc; |
} |
for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++) |
if (sc->sc_devp == NULL) |
break; |
if (nppp >= NPPP) |
return NULL; |
|
sc->sc_flags = 0; |
sc->sc_mru = PPP_MRU; |
sc->sc_relinq = NULL; |
bzero((char *)&sc->sc_stats, sizeof(sc->sc_stats)); |
#ifdef VJC |
sc->sc_comp=malloc(sizeof(struct vjcompress),M_DEVBUF, M_NOWAIT); |
if (sc->sc_comp) |
vj_compress_init(sc->sc_comp, -1); |
#endif |
#ifdef PPP_COMPRESS |
sc->sc_xc_state = NULL; |
sc->sc_rc_state = NULL; |
#endif /* PPP_COMPRESS */ |
for (i = 0; i < NUM_NP; ++i) |
sc->sc_npmode[i] = NPMODE_ERROR; |
sc->sc_npqueue = NULL; |
sc->sc_npqtail = &sc->sc_npqueue; |
microtime(&ppp_time); |
sc->sc_last_sent = sc->sc_last_recv = ppp_time.tv_sec; |
|
return sc; |
} |
|
/* |
* Deallocate a ppp unit. Must be called at splsoftnet or higher. |
*/ |
void |
pppdealloc(sc) |
struct ppp_softc *sc; |
{ |
struct mbuf *m; |
|
if_down(&sc->sc_if); |
sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING); |
sc->sc_devp = NULL; |
sc->sc_xfer = 0; |
for (;;) { |
IF_DEQUEUE(&sc->sc_rawq, m); |
if (m == NULL) |
break; |
m_freem(m); |
} |
for (;;) { |
IF_DEQUEUE(&sc->sc_inq, m); |
if (m == NULL) |
break; |
m_freem(m); |
} |
for (;;) { |
IF_DEQUEUE(&sc->sc_fastq, m); |
if (m == NULL) |
break; |
m_freem(m); |
} |
while ((m = sc->sc_npqueue) != NULL) { |
sc->sc_npqueue = m->m_nextpkt; |
m_freem(m); |
} |
if (sc->sc_togo != NULL) { |
m_freem(sc->sc_togo); |
sc->sc_togo = NULL; |
} |
#ifdef PPP_COMPRESS |
ppp_ccp_closed(sc); |
sc->sc_xc_state = NULL; |
sc->sc_rc_state = NULL; |
#endif /* PPP_COMPRESS */ |
#ifdef PPP_FILTER |
if (sc->sc_pass_filt.bf_insns != 0) { |
free(sc->sc_pass_filt.bf_insns, M_DEVBUF); |
sc->sc_pass_filt.bf_insns = 0; |
sc->sc_pass_filt.bf_len = 0; |
} |
if (sc->sc_active_filt.bf_insns != 0) { |
free(sc->sc_active_filt.bf_insns, M_DEVBUF); |
sc->sc_active_filt.bf_insns = 0; |
sc->sc_active_filt.bf_len = 0; |
} |
#endif /* PPP_FILTER */ |
#ifdef VJC |
if (sc->sc_comp != 0) { |
free(sc->sc_comp, M_DEVBUF); |
sc->sc_comp = 0; |
} |
#endif |
} |
|
/* |
* Ioctl routine for generic ppp devices. |
*/ |
int |
pppioctl(sc, cmd, data, flag, p) |
struct ppp_softc *sc; |
int cmd; |
caddr_t data; |
int flag; |
struct proc *p; |
{ |
int s, error, flags, mru, nb, npx; |
struct ppp_option_data *odp; |
struct compressor **cp; |
struct npioctl *npi; |
time_t t; |
#ifdef PPP_FILTER |
struct bpf_program *bp, *nbp; |
struct bpf_insn *newcode, *oldcode; |
int newcodelen; |
#endif /* PPP_FILTER */ |
#ifdef PPP_COMPRESS |
u_char ccp_option[CCP_MAX_OPTION_LENGTH]; |
#endif |
|
switch (cmd) { |
case FIONREAD: |
*(int *)data = sc->sc_inq.ifq_len; |
break; |
|
case PPPIOCGUNIT: |
*(int *)data = sc->sc_if.if_unit; |
break; |
|
case PPPIOCGFLAGS: |
*(u_int *)data = sc->sc_flags; |
break; |
|
case PPPIOCSFLAGS: |
flags = *(int *)data & SC_MASK; |
s = splsoftnet(); |
#ifdef PPP_COMPRESS |
if (sc->sc_flags & SC_CCP_OPEN && !(flags & SC_CCP_OPEN)) |
ppp_ccp_closed(sc); |
#endif |
splimp(); |
sc->sc_flags = (sc->sc_flags & ~SC_MASK) | flags; |
splx(s); |
break; |
|
case PPPIOCSMRU: |
mru = *(int *)data; |
if (mru >= PPP_MRU && mru <= PPP_MAXMRU) |
sc->sc_mru = mru; |
break; |
|
case PPPIOCGMRU: |
*(int *)data = sc->sc_mru; |
break; |
|
#ifdef VJC |
case PPPIOCSMAXCID: |
if (sc->sc_comp) { |
s = splsoftnet(); |
vj_compress_init(sc->sc_comp, *(int *)data); |
splx(s); |
} |
break; |
#endif |
|
case PPPIOCXFERUNIT: |
sc->sc_xfer = 0; /* Always root p->p_pid;*/ |
break; |
|
#ifdef PPP_COMPRESS |
case PPPIOCSCOMPRESS: |
odp = (struct ppp_option_data *) data; |
nb = odp->length; |
if (nb > sizeof(ccp_option)) |
nb = sizeof(ccp_option); |
if ((error = copyin(odp->ptr, ccp_option, nb)) != 0) |
return (error); |
if (ccp_option[1] < 2) /* preliminary check on the length byte */ |
return (EINVAL); |
for (cp = ppp_compressors; *cp != NULL; ++cp) |
if ((*cp)->compress_proto == ccp_option[0]) { |
/* |
* Found a handler for the protocol - try to allocate |
* a compressor or decompressor. |
*/ |
error = 0; |
if (odp->transmit) { |
s = splsoftnet(); |
if (sc->sc_xc_state != NULL) |
(*sc->sc_xcomp->comp_free)(sc->sc_xc_state); |
sc->sc_xcomp = *cp; |
sc->sc_xc_state = (*cp)->comp_alloc(ccp_option, nb); |
if (sc->sc_xc_state == NULL) { |
if (sc->sc_flags & SC_DEBUG) |
printf("ppp%d: comp_alloc failed\n", |
sc->sc_if.if_unit); |
error = ENOBUFS; |
} |
splimp(); |
sc->sc_flags &= ~SC_COMP_RUN; |
splx(s); |
} else { |
s = splsoftnet(); |
if (sc->sc_rc_state != NULL) |
(*sc->sc_rcomp->decomp_free)(sc->sc_rc_state); |
sc->sc_rcomp = *cp; |
sc->sc_rc_state = (*cp)->decomp_alloc(ccp_option, nb); |
if (sc->sc_rc_state == NULL) { |
if (sc->sc_flags & SC_DEBUG) |
printf("ppp%d: decomp_alloc failed\n", |
sc->sc_if.if_unit); |
error = ENOBUFS; |
} |
splimp(); |
sc->sc_flags &= ~SC_DECOMP_RUN; |
splx(s); |
} |
return (error); |
} |
if (sc->sc_flags & SC_DEBUG) |
printf("ppp%d: no compressor for [%x %x %x], %x\n", |
sc->sc_if.if_unit, ccp_option[0], ccp_option[1], |
ccp_option[2], nb); |
return (EINVAL); /* no handler found */ |
#endif /* PPP_COMPRESS */ |
|
case PPPIOCGNPMODE: |
case PPPIOCSNPMODE: |
npi = (struct npioctl *) data; |
switch (npi->protocol) { |
case PPP_IP: |
npx = NP_IP; |
break; |
default: |
return EINVAL; |
} |
if (cmd == PPPIOCGNPMODE) { |
npi->mode = sc->sc_npmode[npx]; |
} else { |
if (npi->mode != sc->sc_npmode[npx]) { |
s = splsoftnet(); |
sc->sc_npmode[npx] = npi->mode; |
if (npi->mode != NPMODE_QUEUE) { |
ppp_requeue(sc); |
(*sc->sc_start)(sc); |
} |
splx(s); |
} |
} |
break; |
|
case PPPIOCGIDLE: |
s = splsoftnet(); |
microtime(&ppp_time); |
t = ppp_time.tv_sec; |
((struct ppp_idle *)data)->xmit_idle = t - sc->sc_last_sent; |
((struct ppp_idle *)data)->recv_idle = t - sc->sc_last_recv; |
splx(s); |
break; |
|
#ifdef PPP_FILTER |
case PPPIOCSPASS: |
case PPPIOCSACTIVE: |
nbp = (struct bpf_program *) data; |
if ((unsigned) nbp->bf_len > BPF_MAXINSNS) |
return EINVAL; |
newcodelen = nbp->bf_len * sizeof(struct bpf_insn); |
if (newcodelen != 0) { |
newcode=(struct bpf_insn *) malloc (newcodelen, M_DEVBUF, M_WAITOK); |
if (newcode == 0) { |
return EINVAL; /* or sumpin */ |
} |
if ((error = copyin((caddr_t)nbp->bf_insns, (caddr_t)newcode, |
newcodelen)) != 0) { |
free(newcode, M_DEVBUF); |
return error; |
} |
if (!bpf_validate(newcode, nbp->bf_len)) { |
free(newcode, M_DEVBUF); |
return EINVAL; |
} |
} else |
newcode = 0; |
bp = (cmd == PPPIOCSPASS)? &sc->sc_pass_filt: &sc->sc_active_filt; |
oldcode = bp->bf_insns; |
s = splimp(); |
bp->bf_len = nbp->bf_len; |
bp->bf_insns = newcode; |
splx(s); |
if (oldcode != 0) |
free(oldcode, M_DEVBUF); |
break; |
#endif |
|
default: |
return (-1); |
} |
return (0); |
} |
|
/* |
* Process an ioctl request to the ppp network interface. |
*/ |
static int |
pppsioctl(ifp, cmd, data) |
register struct ifnet *ifp; |
int cmd; |
caddr_t data; |
{ |
/* struct proc *p = curproc; *//* XXX */ |
register struct ppp_softc *sc = &ppp_softc[ifp->if_unit]; |
register struct ifaddr *ifa = (struct ifaddr *)data; |
register struct ifreq *ifr = (struct ifreq *)data; |
struct ppp_stats *psp; |
#ifdef PPP_COMPRESS |
struct ppp_comp_stats *pcp; |
#endif |
int s = splimp(), error = 0; |
|
switch (cmd) { |
case SIOCSIFFLAGS: |
if ((ifp->if_flags & IFF_RUNNING) == 0) |
ifp->if_flags &= ~IFF_UP; |
break; |
|
case SIOCSIFADDR: |
if (ifa->ifa_addr->sa_family != AF_INET) |
error = EAFNOSUPPORT; |
break; |
|
case SIOCSIFDSTADDR: |
if (ifa->ifa_addr->sa_family != AF_INET) |
error = EAFNOSUPPORT; |
break; |
|
case SIOCSIFMTU: |
sc->sc_if.if_mtu = ifr->ifr_mtu; |
break; |
|
case SIOCGIFMTU: |
ifr->ifr_mtu = sc->sc_if.if_mtu; |
break; |
|
case SIOCADDMULTI: |
case SIOCDELMULTI: |
if (ifr == 0) { |
error = EAFNOSUPPORT; |
break; |
} |
switch(ifr->ifr_addr.sa_family) { |
#ifdef INET |
case AF_INET: |
break; |
#endif |
default: |
error = EAFNOSUPPORT; |
break; |
} |
break; |
case SIO_RTEMS_SHOW_STATS: |
printf (" MRU:%-8lu", sc->sc_mru); |
printf (" Bytes received:%-8lu", sc->sc_stats.ppp_ibytes); |
printf (" Packets received:%-8lu", sc->sc_stats.ppp_ipackets); |
printf (" Receive errors:%-8lu\n", sc->sc_stats.ppp_ierrors); |
printf (" Bytes sent:%-8lu", sc->sc_stats.ppp_obytes); |
printf (" Packets sent:%-8lu", sc->sc_stats.ppp_opackets); |
printf (" Transmit errors:%-8lu\n", sc->sc_stats.ppp_oerrors); |
|
break; |
|
|
case SIOCGPPPSTATS: |
psp = &((struct ifpppstatsreq *) data)->stats; |
bzero(psp, sizeof(*psp)); |
psp->p = sc->sc_stats; |
#if defined(VJC) && !defined(SL_NO_STATS) |
if (sc->sc_comp) { |
psp->vj.vjs_packets = sc->sc_comp->sls_packets; |
psp->vj.vjs_compressed = sc->sc_comp->sls_compressed; |
psp->vj.vjs_searches = sc->sc_comp->sls_searches; |
psp->vj.vjs_misses = sc->sc_comp->sls_misses; |
psp->vj.vjs_uncompressedin = sc->sc_comp->sls_uncompressedin; |
psp->vj.vjs_compressedin = sc->sc_comp->sls_compressedin; |
psp->vj.vjs_errorin = sc->sc_comp->sls_errorin; |
psp->vj.vjs_tossed = sc->sc_comp->sls_tossed; |
} |
#endif /* VJC */ |
break; |
|
#ifdef PPP_COMPRESS |
case SIOCGPPPCSTATS: |
pcp = &((struct ifpppcstatsreq *) data)->stats; |
bzero(pcp, sizeof(*pcp)); |
if (sc->sc_xc_state != NULL) |
(*sc->sc_xcomp->comp_stat)(sc->sc_xc_state, &pcp->c); |
if (sc->sc_rc_state != NULL) |
(*sc->sc_rcomp->decomp_stat)(sc->sc_rc_state, &pcp->d); |
break; |
#endif /* PPP_COMPRESS */ |
|
default: |
error = EINVAL; |
} |
splx(s); |
return (error); |
} |
|
/* |
* Queue a packet. Start transmission if not active. |
* Packet is placed in Information field of PPP frame. |
*/ |
int |
pppoutput(ifp, m0, dst, rtp) |
struct ifnet *ifp; |
struct mbuf *m0; |
struct sockaddr *dst; |
struct rtentry *rtp; |
{ |
register struct ppp_softc *sc = &ppp_softc[ifp->if_unit]; |
int protocol, address, control; |
u_char *cp; |
int s, error; |
struct ip *ip; |
struct ifqueue *ifq; |
enum NPmode mode; |
int len; |
struct mbuf *m; |
if (sc->sc_devp == NULL || (ifp->if_flags & IFF_RUNNING) == 0 |
|| ((ifp->if_flags & IFF_UP) == 0 && dst->sa_family != AF_UNSPEC)) { |
error = ENETDOWN; /* sort of */ |
goto bad; |
} |
|
/* |
* Compute PPP header. |
*/ |
m0->m_flags &= ~M_HIGHPRI; |
switch (dst->sa_family) { |
#ifdef INET |
case AF_INET: |
address = PPP_ALLSTATIONS; |
control = PPP_UI; |
protocol = PPP_IP; |
mode = sc->sc_npmode[NP_IP]; |
|
/* |
* If this packet has the "low delay" bit set in the IP header, |
* put it on the fastq instead. |
*/ |
ip = mtod(m0, struct ip *); |
if (ip->ip_tos & IPTOS_LOWDELAY) |
m0->m_flags |= M_HIGHPRI; |
break; |
#endif |
case AF_UNSPEC: |
address = PPP_ADDRESS(dst->sa_data); |
control = PPP_CONTROL(dst->sa_data); |
protocol = PPP_PROTOCOL(dst->sa_data); |
mode = NPMODE_PASS; |
break; |
default: |
printf("ppp%d: af%d not supported\n", ifp->if_unit, dst->sa_family); |
error = EAFNOSUPPORT; |
goto bad; |
} |
|
/* |
* Drop this packet, or return an error, if necessary. |
*/ |
if (mode == NPMODE_ERROR) { |
error = ENETDOWN; |
goto bad; |
} |
if (mode == NPMODE_DROP) { |
error = 0; |
goto bad; |
} |
|
/* |
* Add PPP header. If no space in first mbuf, allocate another. |
* (This assumes M_LEADINGSPACE is always 0 for a cluster mbuf.) |
*/ |
if (M_LEADINGSPACE(m0) < PPP_HDRLEN) { |
m0 = m_prepend(m0, PPP_HDRLEN, M_DONTWAIT); |
if (m0 == 0) { |
error = ENOBUFS; |
goto bad; |
} |
m0->m_len = 0; |
} else |
m0->m_data -= PPP_HDRLEN; |
|
cp = mtod(m0, u_char *); |
*cp++ = address; |
*cp++ = control; |
*cp++ = protocol >> 8; |
*cp++ = protocol & 0xff; |
m0->m_len += PPP_HDRLEN; |
|
len = 0; |
for (m = m0; m != 0; m = m->m_next) |
len += m->m_len; |
|
if (sc->sc_flags & SC_LOG_OUTPKT) { |
printf("ppp%d output: ", ifp->if_unit); |
pppdumpm(m0); |
} |
|
if ((protocol & 0x8000) == 0) { |
#ifdef PPP_FILTER |
/* |
* Apply the pass and active filters to the packet, |
* but only if it is a data packet. |
*/ |
*mtod(m0, u_char *) = 1; /* indicates outbound */ |
if (sc->sc_pass_filt.bf_insns != 0 |
&& bpf_filter(sc->sc_pass_filt.bf_insns, (u_char *) m0, |
len, 0) == 0) { |
error = 0; /* drop this packet */ |
goto bad; |
} |
|
/* |
* Update the time we sent the most recent packet. |
*/ |
if (sc->sc_active_filt.bf_insns == 0 |
|| bpf_filter(sc->sc_active_filt.bf_insns, (u_char *) m0, len, 0)) |
{ |
microtime(&ppp_time); |
sc->sc_last_sent = ppp_time.tv_sec; |
} |
|
*mtod(m0, u_char *) = address; |
#else |
/* |
* Update the time we sent the most recent data packet. |
*/ |
microtime(&ppp_time); |
sc->sc_last_sent = ppp_time.tv_sec; |
#endif /* PPP_FILTER */ |
} |
|
#if NBPFILTER > 0 |
/* |
* See if bpf wants to look at the packet. |
*/ |
if (sc->sc_bpf) |
bpf_mtap(sc->sc_bpf, m0); |
#endif |
|
/* |
* Put the packet on the appropriate queue. |
*/ |
if (mode == NPMODE_QUEUE) { |
/* XXX we should limit the number of packets on this queue */ |
*sc->sc_npqtail = m0; |
m0->m_nextpkt = NULL; |
sc->sc_npqtail = &m0->m_nextpkt; |
} else { |
ifq = (m0->m_flags & M_HIGHPRI)? &sc->sc_fastq: &ifp->if_snd; |
if (IF_QFULL(ifq) && dst->sa_family != AF_UNSPEC) { |
IF_DROP(ifq); |
splx(s); |
sc->sc_if.if_oerrors++; |
sc->sc_stats.ppp_oerrors++; |
error = ENOBUFS; |
goto bad; |
} |
IF_ENQUEUE(ifq, m0); |
(*sc->sc_start)(sc); |
} |
microtime(&ppp_time); |
ifp->if_lastchange = ppp_time; |
ifp->if_opackets++; |
ifp->if_obytes += len; |
|
return (0); |
|
bad: |
m_freem(m0); |
return (error); |
} |
|
/* |
* After a change in the NPmode for some NP, move packets from the |
* npqueue to the send queue or the fast queue as appropriate. |
* Should be called at splsoftnet. |
*/ |
static void |
ppp_requeue(sc) |
struct ppp_softc *sc; |
{ |
struct mbuf *m, **mpp; |
struct ifqueue *ifq; |
enum NPmode mode; |
|
for (mpp = &sc->sc_npqueue; (m = *mpp) != NULL; ) { |
switch (PPP_PROTOCOL(mtod(m, u_char *))) { |
case PPP_IP: |
mode = sc->sc_npmode[NP_IP]; |
break; |
default: |
mode = NPMODE_PASS; |
} |
|
switch (mode) { |
case NPMODE_PASS: |
/* |
* This packet can now go on one of the queues to be sent. |
*/ |
*mpp = m->m_nextpkt; |
m->m_nextpkt = NULL; |
ifq = (m->m_flags & M_HIGHPRI)? &sc->sc_fastq: &sc->sc_if.if_snd; |
if (IF_QFULL(ifq)) { |
IF_DROP(ifq); |
sc->sc_if.if_oerrors++; |
sc->sc_stats.ppp_oerrors++; |
} else |
IF_ENQUEUE(ifq, m); |
break; |
|
case NPMODE_DROP: |
case NPMODE_ERROR: |
*mpp = m->m_nextpkt; |
m_freem(m); |
break; |
|
case NPMODE_QUEUE: |
mpp = &m->m_nextpkt; |
break; |
} |
} |
sc->sc_npqtail = mpp; |
} |
|
/* |
* Transmitter has finished outputting some stuff; |
* remember to call sc->sc_start later at splsoftnet. |
*/ |
void |
ppp_restart(sc) |
struct ppp_softc *sc; |
{ |
|
sc->sc_flags &= ~SC_TBUSY; |
/* schednetisr(NETISR_PPP); |
*/} |
|
/* |
* Get a packet to send. This procedure is intended to be called at |
* splsoftnet, since it may involve time-consuming operations such as |
* applying VJ compression, packet compression, address/control and/or |
* protocol field compression to the packet. |
*/ |
struct mbuf * |
ppp_dequeue(sc) |
struct ppp_softc *sc; |
{ |
struct mbuf *m, *mp; |
u_char *cp; |
int address, control, protocol; |
|
/* |
* Grab a packet to send: first try the fast queue, then the |
* normal queue. |
*/ |
IF_DEQUEUE(&sc->sc_fastq, m); |
if (m == NULL) |
IF_DEQUEUE(&sc->sc_if.if_snd, m); |
if (m == NULL) |
return NULL; |
|
++sc->sc_stats.ppp_opackets; |
|
/* |
* Extract the ppp header of the new packet. |
* The ppp header will be in one mbuf. |
*/ |
cp = mtod(m, u_char *); |
address = PPP_ADDRESS(cp); |
control = PPP_CONTROL(cp); |
protocol = PPP_PROTOCOL(cp); |
|
switch (protocol) { |
case PPP_IP: |
#ifdef VJC |
/* |
* If the packet is a TCP/IP packet, see if we can compress it. |
*/ |
if ((sc->sc_flags & SC_COMP_TCP) && sc->sc_comp != NULL) { |
struct ip *ip; |
int type; |
|
mp = m; |
ip = (struct ip *) (cp + PPP_HDRLEN); |
if (mp->m_len <= PPP_HDRLEN) { |
mp = mp->m_next; |
if (mp == NULL) |
break; |
ip = mtod(mp, struct ip *); |
} |
/* this code assumes the IP/TCP header is in one non-shared mbuf */ |
if (ip->ip_p == IPPROTO_TCP) { |
type = vj_compress_tcp(mp, ip, sc->sc_comp, |
!(sc->sc_flags & SC_NO_TCP_CCID)); |
switch (type) { |
case TYPE_UNCOMPRESSED_TCP: |
protocol = PPP_VJC_UNCOMP; |
break; |
case TYPE_COMPRESSED_TCP: |
protocol = PPP_VJC_COMP; |
cp = mtod(m, u_char *); |
cp[0] = address; /* header has moved */ |
cp[1] = control; |
cp[2] = 0; |
break; |
} |
cp[3] = protocol; /* update protocol in PPP header */ |
} |
} |
#endif /* VJC */ |
break; |
|
#ifdef PPP_COMPRESS |
case PPP_CCP: |
ppp_ccp(sc, m, 0); |
break; |
#endif /* PPP_COMPRESS */ |
} |
|
#ifdef PPP_COMPRESS |
if (protocol != PPP_LCP && protocol != PPP_CCP |
&& sc->sc_xc_state && (sc->sc_flags & SC_COMP_RUN)) { |
struct mbuf *mcomp = NULL; |
int slen, clen; |
|
slen = 0; |
for (mp = m; mp != NULL; mp = mp->m_next) |
slen += mp->m_len; |
clen = (*sc->sc_xcomp->compress) |
(sc->sc_xc_state, &mcomp, m, slen, sc->sc_if.if_mtu + PPP_HDRLEN); |
if (mcomp != NULL) { |
if (sc->sc_flags & SC_CCP_UP) { |
/* Send the compressed packet instead of the original. */ |
m_freem(m); |
m = mcomp; |
cp = mtod(m, u_char *); |
protocol = cp[3]; |
} else { |
/* Can't transmit compressed packets until CCP is up. */ |
m_freem(mcomp); |
} |
} |
} |
#endif /* PPP_COMPRESS */ |
|
/* |
* Compress the address/control and protocol, if possible. |
*/ |
if (sc->sc_flags & SC_COMP_AC && address == PPP_ALLSTATIONS && |
control == PPP_UI && protocol != PPP_ALLSTATIONS && |
protocol != PPP_LCP) { |
/* can compress address/control */ |
m->m_data += 2; |
m->m_len -= 2; |
} |
if (sc->sc_flags & SC_COMP_PROT && protocol < 0xFF) { |
/* can compress protocol */ |
if (mtod(m, u_char *) == cp) { |
cp[2] = cp[1]; /* move address/control up */ |
cp[1] = cp[0]; |
} |
++m->m_data; |
--m->m_len; |
} |
|
return m; |
} |
|
/* |
* Software interrupt routine, called at splsoftnet. |
*/ |
void |
pppintr() |
{ |
struct ppp_softc *sc; |
int i, s, s2; |
struct mbuf *m; |
|
sc = ppp_softc; |
for (i = 0; i < NPPP; ++i, ++sc) { |
if (!(sc->sc_flags & SC_TBUSY) |
&& (sc->sc_if.if_snd.ifq_head || sc->sc_fastq.ifq_head)) { |
s2 = splimp(); |
sc->sc_flags |= SC_TBUSY; |
splx(s2); |
(*sc->sc_start)(sc); |
} |
for (;;) { |
IF_DEQUEUE(&sc->sc_rawq, m); |
if (m == NULL) |
break; |
ppp_inproc(sc, m); |
} |
} |
} |
|
#ifdef PPP_COMPRESS |
/* |
* Handle a CCP packet. `rcvd' is 1 if the packet was received, |
* 0 if it is about to be transmitted. |
*/ |
static void |
ppp_ccp(sc, m, rcvd) |
struct ppp_softc *sc; |
struct mbuf *m; |
int rcvd; |
{ |
u_char *dp, *ep; |
struct mbuf *mp; |
int slen, s; |
|
/* |
* Get a pointer to the data after the PPP header. |
*/ |
if (m->m_len <= PPP_HDRLEN) { |
mp = m->m_next; |
if (mp == NULL) |
return; |
dp = (mp != NULL)? mtod(mp, u_char *): NULL; |
} else { |
mp = m; |
dp = mtod(mp, u_char *) + PPP_HDRLEN; |
} |
|
ep = mtod(mp, u_char *) + mp->m_len; |
if (dp + CCP_HDRLEN > ep) |
return; |
slen = CCP_LENGTH(dp); |
if (dp + slen > ep) { |
if (sc->sc_flags & SC_DEBUG) |
printf("if_ppp/ccp: not enough data in mbuf (%p+%x > %p+%x)\n", |
dp, slen, mtod(mp, u_char *), mp->m_len); |
return; |
} |
|
switch (CCP_CODE(dp)) { |
case CCP_CONFREQ: |
case CCP_TERMREQ: |
case CCP_TERMACK: |
/* CCP must be going down - disable compression */ |
if (sc->sc_flags & SC_CCP_UP) { |
s = splimp(); |
sc->sc_flags &= ~(SC_CCP_UP | SC_COMP_RUN | SC_DECOMP_RUN); |
splx(s); |
} |
break; |
|
case CCP_CONFACK: |
if (sc->sc_flags & SC_CCP_OPEN && !(sc->sc_flags & SC_CCP_UP) |
&& slen >= CCP_HDRLEN + CCP_OPT_MINLEN |
&& slen >= CCP_OPT_LENGTH(dp + CCP_HDRLEN) + CCP_HDRLEN) { |
if (!rcvd) { |
/* we're agreeing to send compressed packets. */ |
if (sc->sc_xc_state != NULL |
&& (*sc->sc_xcomp->comp_init) |
(sc->sc_xc_state, dp + CCP_HDRLEN, slen - CCP_HDRLEN, |
sc->sc_if.if_unit, 0, sc->sc_flags & SC_DEBUG)) { |
s = splimp(); |
sc->sc_flags |= SC_COMP_RUN; |
splx(s); |
} |
} else { |
/* peer is agreeing to send compressed packets. */ |
if (sc->sc_rc_state != NULL |
&& (*sc->sc_rcomp->decomp_init) |
(sc->sc_rc_state, dp + CCP_HDRLEN, slen - CCP_HDRLEN, |
sc->sc_if.if_unit, 0, sc->sc_mru, |
sc->sc_flags & SC_DEBUG)) { |
s = splimp(); |
sc->sc_flags |= SC_DECOMP_RUN; |
sc->sc_flags &= ~(SC_DC_ERROR | SC_DC_FERROR); |
splx(s); |
} |
} |
} |
break; |
|
case CCP_RESETACK: |
if (sc->sc_flags & SC_CCP_UP) { |
if (!rcvd) { |
if (sc->sc_xc_state && (sc->sc_flags & SC_COMP_RUN)) |
(*sc->sc_xcomp->comp_reset)(sc->sc_xc_state); |
} else { |
if (sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)) { |
(*sc->sc_rcomp->decomp_reset)(sc->sc_rc_state); |
s = splimp(); |
sc->sc_flags &= ~SC_DC_ERROR; |
splx(s); |
} |
} |
} |
break; |
} |
} |
|
/* |
* CCP is down; free (de)compressor state if necessary. |
*/ |
static void |
ppp_ccp_closed(sc) |
struct ppp_softc *sc; |
{ |
if (sc->sc_xc_state) { |
(*sc->sc_xcomp->comp_free)(sc->sc_xc_state); |
sc->sc_xc_state = NULL; |
} |
if (sc->sc_rc_state) { |
(*sc->sc_rcomp->decomp_free)(sc->sc_rc_state); |
sc->sc_rc_state = NULL; |
} |
} |
#endif /* PPP_COMPRESS */ |
|
/* |
* PPP packet input routine. |
* The caller has checked and removed the FCS and has inserted |
* the address/control bytes and the protocol high byte if they |
* were omitted. |
*/ |
void |
ppppktin(sc, m, lost) |
struct ppp_softc *sc; |
struct mbuf *m; |
int lost; |
{ |
|
if (lost) |
m->m_flags |= M_ERRMARK; |
IF_ENQUEUE(&sc->sc_rawq, m); |
pppintr(); |
} |
|
/* |
* Process a received PPP packet, doing decompression as necessary. |
* Should be called at splsoftnet. |
*/ |
#define COMPTYPE(proto) ((proto) == PPP_VJC_COMP? TYPE_COMPRESSED_TCP: \ |
TYPE_UNCOMPRESSED_TCP) |
|
static void |
ppp_inproc(sc, m) |
struct ppp_softc *sc; |
struct mbuf *m; |
{ |
struct ifnet *ifp = &sc->sc_if; |
struct ifqueue *inq; |
int s, ilen, xlen, proto, rv; |
u_char *cp, adrs, ctrl; |
struct mbuf *mp, *dmp = NULL; |
u_char *iphdr; |
u_int hlen; |
|
sc->sc_stats.ppp_ipackets++; |
|
if (sc->sc_flags & SC_LOG_INPKT) { |
ilen = 0; |
for (mp = m; mp != NULL; mp = mp->m_next) |
ilen += mp->m_len; |
printf("ppp%d: got %d bytes\n", ifp->if_unit, ilen); |
pppdumpm(m); |
} |
|
cp = mtod(m, u_char *); |
adrs = PPP_ADDRESS(cp); |
ctrl = PPP_CONTROL(cp); |
proto = PPP_PROTOCOL(cp); |
|
if (m->m_flags & M_ERRMARK) { |
m->m_flags &= ~M_ERRMARK; |
s = splimp(); |
sc->sc_flags |= SC_VJ_RESET; |
splx(s); |
} |
|
#ifdef PPP_COMPRESS |
/* |
* Decompress this packet if necessary, update the receiver's |
* dictionary, or take appropriate action on a CCP packet. |
*/ |
if (proto == PPP_COMP && sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN) |
&& !(sc->sc_flags & SC_DC_ERROR) && !(sc->sc_flags & SC_DC_FERROR)) { |
/* decompress this packet */ |
rv = (*sc->sc_rcomp->decompress)(sc->sc_rc_state, m, &dmp); |
if (rv == DECOMP_OK) { |
m_freem(m); |
if (dmp == NULL) { |
/* no error, but no decompressed packet produced */ |
return; |
} |
m = dmp; |
cp = mtod(m, u_char *); |
proto = PPP_PROTOCOL(cp); |
|
} else { |
/* |
* An error has occurred in decompression. |
* Pass the compressed packet up to pppd, which may take |
* CCP down or issue a Reset-Req. |
*/ |
if (sc->sc_flags & SC_DEBUG) |
printf("ppp%d: decompress failed %d\n", ifp->if_unit, rv); |
s = splimp(); |
sc->sc_flags |= SC_VJ_RESET; |
if (rv == DECOMP_ERROR) |
sc->sc_flags |= SC_DC_ERROR; |
else |
sc->sc_flags |= SC_DC_FERROR; |
splx(s); |
} |
|
} else { |
if (sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)) { |
(*sc->sc_rcomp->incomp)(sc->sc_rc_state, m); |
} |
if (proto == PPP_CCP) { |
ppp_ccp(sc, m, 1); |
} |
} |
#endif |
|
ilen = 0; |
for (mp = m; mp != NULL; mp = mp->m_next) |
ilen += mp->m_len; |
|
#ifdef VJC |
if (sc->sc_flags & SC_VJ_RESET) { |
/* |
* If we've missed a packet, we must toss subsequent compressed |
* packets which don't have an explicit connection ID. |
*/ |
if (sc->sc_comp) |
vj_uncompress_tcp(NULL, 0, TYPE_ERROR, sc->sc_comp); |
s = splimp(); |
sc->sc_flags &= ~SC_VJ_RESET; |
splx(s); |
} |
|
/* |
* See if we have a VJ-compressed packet to uncompress. |
*/ |
if (proto == PPP_VJC_COMP) { |
if ((sc->sc_flags & SC_REJ_COMP_TCP) || sc->sc_comp == 0) |
goto bad; |
|
xlen = vj_uncompress_tcp_core(cp + PPP_HDRLEN, m->m_len - PPP_HDRLEN, |
ilen - PPP_HDRLEN, TYPE_COMPRESSED_TCP, |
sc->sc_comp, &iphdr, &hlen); |
|
if (xlen <= 0) { |
if (sc->sc_flags & SC_DEBUG) |
printf("ppp%d: VJ uncompress failed on type comp\n", |
ifp->if_unit); |
goto bad; |
} |
|
/* Copy the PPP and IP headers into a new mbuf. */ |
MGETHDR(mp, M_DONTWAIT, MT_DATA); |
if (mp == NULL) |
goto bad; |
mp->m_len = 0; |
mp->m_next = NULL; |
if (hlen + PPP_HDRLEN > MHLEN) { |
MCLGET(mp, M_DONTWAIT); |
if (M_TRAILINGSPACE(mp) < hlen + PPP_HDRLEN) { |
m_freem(mp); |
goto bad; /* lose if big headers and no clusters */ |
} |
} |
cp = mtod(mp, u_char *); |
cp[0] = adrs; |
cp[1] = ctrl; |
cp[2] = 0; |
cp[3] = PPP_IP; |
proto = PPP_IP; |
bcopy(iphdr, cp + PPP_HDRLEN, hlen); |
mp->m_len = hlen + PPP_HDRLEN; |
|
/* |
* Trim the PPP and VJ headers off the old mbuf |
* and stick the new and old mbufs together. |
*/ |
m->m_data += PPP_HDRLEN + xlen; |
m->m_len -= PPP_HDRLEN + xlen; |
if (m->m_len <= M_TRAILINGSPACE(mp)) { |
bcopy(mtod(m, u_char *), mtod(mp, u_char *) + mp->m_len, m->m_len); |
mp->m_len += m->m_len; |
MFREE(m, mp->m_next); |
} else |
mp->m_next = m; |
m = mp; |
ilen += hlen - xlen; |
|
} else if (proto == PPP_VJC_UNCOMP) { |
if ((sc->sc_flags & SC_REJ_COMP_TCP) || sc->sc_comp == 0) |
goto bad; |
|
xlen = vj_uncompress_tcp_core(cp + PPP_HDRLEN, m->m_len - PPP_HDRLEN, |
ilen - PPP_HDRLEN, TYPE_UNCOMPRESSED_TCP, |
sc->sc_comp, &iphdr, &hlen); |
|
if (xlen < 0) { |
if (sc->sc_flags & SC_DEBUG) |
printf("ppp%d: VJ uncompress failed on type uncomp\n", |
ifp->if_unit); |
goto bad; |
} |
|
proto = PPP_IP; |
cp[3] = PPP_IP; |
} |
#endif /* VJC */ |
|
/* |
* If the packet will fit in a header mbuf, don't waste a |
* whole cluster on it. |
*/ |
if (ilen <= MHLEN && M_IS_CLUSTER(m)) { |
MGETHDR(mp, M_DONTWAIT, MT_DATA); |
if (mp != NULL) { |
m_copydata(m, 0, ilen, mtod(mp, caddr_t)); |
m_freem(m); |
m = mp; |
m->m_len = ilen; |
} |
} |
m->m_pkthdr.len = ilen; |
m->m_pkthdr.rcvif = ifp; |
|
if ((proto & 0x8000) == 0) { |
#ifdef PPP_FILTER |
/* |
* See whether we want to pass this packet, and |
* if it counts as link activity. |
*/ |
adrs = *mtod(m, u_char *); /* save address field */ |
*mtod(m, u_char *) = 0; /* indicate inbound */ |
if (sc->sc_pass_filt.bf_insns != 0 |
&& bpf_filter(sc->sc_pass_filt.bf_insns, (u_char *) m, |
ilen, 0) == 0) { |
/* drop this packet */ |
m_freem(m); |
return; |
} |
if (sc->sc_active_filt.bf_insns == 0 |
|| bpf_filter(sc->sc_active_filt.bf_insns, (u_char *) m, ilen, 0)) |
{ |
microtime(&ppp_time); |
|
sc->sc_last_recv = ppp_time.tv_sec; |
} |
|
*mtod(m, u_char *) = adrs; |
#else |
/* |
* Record the time that we received this packet. |
*/ |
microtime(&ppp_time); |
sc->sc_last_recv = ppp_time.tv_sec; |
#endif /* PPP_FILTER */ |
} |
|
#if NBPFILTER > 0 |
/* See if bpf wants to look at the packet. */ |
if (sc->sc_bpf) |
bpf_mtap(sc->sc_bpf, m); |
#endif |
|
rv = 0; |
switch (proto) { |
#ifdef INET |
case PPP_IP: |
/* |
* IP packet - take off the ppp header and pass it up to IP. |
*/ |
if ((ifp->if_flags & IFF_UP) == 0 |
|| sc->sc_npmode[NP_IP] != NPMODE_PASS) { |
/* interface is down - drop the packet. */ |
m_freem(m); |
return; |
} |
m->m_pkthdr.len -= PPP_HDRLEN; |
m->m_data += PPP_HDRLEN; |
m->m_len -= PPP_HDRLEN; |
schednetisr(NETISR_IP); |
inq = &ipintrq; |
break; |
#endif |
|
default: |
/* |
* Some other protocol - place on input queue for read(). |
*/ |
inq = &sc->sc_inq; |
rv = 1; |
break; |
} |
|
/* |
* Put the packet on the appropriate input queue. |
*/ |
s = splimp(); |
if (IF_QFULL(inq)) { |
IF_DROP(inq); |
splx(s); |
if (sc->sc_flags & SC_DEBUG) |
printf("ppp%d: input queue full\n", ifp->if_unit); |
ifp->if_iqdrops++; |
goto bad; |
} |
IF_ENQUEUE(inq, m); |
splx(s); |
ifp->if_ipackets++; |
ifp->if_ibytes += ilen; |
microtime(&ppp_time); |
ifp->if_lastchange = ppp_time; |
|
if (rv) |
(*sc->sc_ctlp)(sc); |
|
return; |
|
bad: |
m_freem(m); |
sc->sc_if.if_ierrors++; |
sc->sc_stats.ppp_ierrors++; |
} |
|
#define MAX_DUMP_BYTES 128 |
|
static void |
pppdumpm(m0) |
struct mbuf *m0; |
{ |
char buf[3*MAX_DUMP_BYTES+4]; |
char *bp = buf; |
struct mbuf *m; |
static char digits[] = "0123456789abcdef"; |
|
for (m = m0; m; m = m->m_next) { |
int l = m->m_len; |
u_char *rptr = (u_char *)m->m_data; |
|
while (l--) { |
if (bp > buf + sizeof(buf) - 4) |
goto done; |
*bp++ = digits[*rptr >> 4]; /* convert byte to ascii hex */ |
*bp++ = digits[*rptr++ & 0xf]; |
} |
|
if (m->m_next) { |
if (bp > buf + sizeof(buf) - 3) |
goto done; |
*bp++ = '|'; |
} else |
*bp++ = ' '; |
} |
done: |
if (m) |
*bp++ = '>'; |
*bp = 0; |
printf("%s\n", buf); |
} |
|
#endif /* NPPP > 0 */ |
/modem_example/modem.c
0,0 → 1,1438
/* |
* Modem device driver for RTEMS |
* Author: Tomasz Domin (dot@comarch.pl) |
* Copyright (C) 1998 by ComArch SA |
* Driver will use termios for character output and ppp specific out procecedures for network protocols |
*/ |
|
#include <bsp.h> |
#include <rtems.h> |
#include <rtems/libio.h> |
#include <sys/ttycom.h> |
#include <unistd.h> |
#include <sys/errno.h> |
#include <rtems/rtems/event.h> |
#include <rtems/rtems/tasks.h> |
#include <mpc823.h> |
#include <sys/param.h> |
#include <sys/systm.h> |
#include <sys/proc.h> |
#include <sys/mbuf.h> |
#include <sys/socket.h> |
#include <sys/ioctl.h> |
#include <sys/file.h> |
|
#include <sys/kernel.h> |
#include <sys/conf.h> |
#include <net/if.h> |
#include <net/ppp_defs.h> |
#include <sys/fcntl.h> |
#include "ppp.h" |
#include <net/if_pppvar.h> |
#include <net/if_ppp.h> |
/* RTEMS specific */ |
rtems_id modem_task_id; |
#include "16550.h" |
#include <mpc823.h> |
#define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F))) |
#define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT) |
|
#define M_DATASTART(m) \ |
(M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \ |
(m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat) |
|
#define M_DATASIZE(m) \ |
(M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \ |
(m)->m_flags & M_PKTHDR ? MHLEN: MLEN) |
|
|
struct rtems_termios_tty *modem_tty; |
/* |
* RTEMS event used by interrupt handler to signal daemons. |
* This must *not* be the same event used by the KA9Q task synchronization. |
*/ |
#define INTERRUPT_EVENT RTEMS_EVENT_1 |
#define START_TRANSMIT_EVENT RTEMS_EVENT_2 |
#define PPP_LOWAT 100 /* Process more output when < LOWAT on queue */ |
#define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */ |
|
/* |
* RTEMS event used to start transmit daemon. |
* This must not be the same as INTERRUPT_EVENT. |
*/ |
|
/*static struct modem_tty *tp=&modem_tp;*/ |
static rtems_id modem_rx_task,modem_tx_task; |
|
|
|
/* internal FIFO buffers for input and output characters */ |
#define MODEM_BUFFER_LENGTH 4096 |
#define RTS_STOP_SIZE MODEM_BUFFER_LENGTH-128 |
#define RTS_START_SIZE 16 |
|
int xmt_start,xmt_len; |
int rcv_start,rcv_len; |
|
static unsigned char xmt_buf[MODEM_BUFFER_LENGTH]; |
static unsigned char rcv_buf[MODEM_BUFFER_LENGTH]; |
|
static volatile char _tx_stop = 0 ,_modem_cd=0; |
struct ModemData |
{ |
int t_line; |
struct ppp_softc *t_sc; |
rtems_id pppsem; |
int offhook; |
} ModemData; |
|
int pppstart(struct tty *ignore); |
static u_short fcstab[256] = { |
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, |
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, |
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, |
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, |
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, |
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, |
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, |
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, |
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, |
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, |
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, |
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, |
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, |
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, |
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, |
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, |
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, |
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, |
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, |
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, |
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, |
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, |
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, |
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, |
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, |
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, |
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, |
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, |
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, |
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, |
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, |
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 |
}; |
|
|
static u_short |
pppfcs(fcs, cp, len) |
register u_short fcs; |
register u_char *cp; |
register int len; |
{ |
while (len--) |
fcs = PPP_FCS(fcs, *cp++); |
return (fcs); |
} |
|
static void |
ppp_timeout(x) |
void *x; |
{ |
struct ppp_softc *sc = ModemData.t_sc; |
struct tty *tp = (struct tty *) sc->sc_devp; |
int s; |
|
sc->sc_flags &= ~SC_TIMEOUT; |
pppstart(tp); |
} |
|
static void |
pppasyncrelinq(sc) |
struct ppp_softc *sc; |
{ |
int s; |
|
if (sc->sc_outm) { |
m_freem(sc->sc_outm); |
sc->sc_outm = NULL; |
} |
if (sc->sc_m) { |
m_freem(sc->sc_m); |
sc->sc_m = NULL; |
} |
if (sc->sc_flags & SC_TIMEOUT) { |
untimeout(ppp_timeout, (void *) sc); |
sc->sc_flags &= ~SC_TIMEOUT; |
} |
} |
|
/* Put data in input queue */ |
int |
pppstart(struct tty *ignore) |
{ |
register struct ppp_softc *sc = ModemData.t_sc; |
|
/* |
* If there is stuff in the output queue, send it now. |
* We are being called in lieu of ttstart and must do what it would. |
*/ |
rtems_event_send(modem_tx_task,START_TRANSMIT_EVENT); |
sc->sc_if.if_flags |= IFF_OACTIVE; |
|
/* |
* If the transmit queue has drained and the tty has not hung up |
* or been disconnected from the ppp unit, then tell if_ppp.c that |
* we need more output. |
*/ |
/* if (CCOUNT(&tp->t_outq) < PPP_LOWAT |
&& !((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) |
&& sc != NULL && tp == (struct tty *) sc->sc_devp) { |
ppp_restart(sc); |
} |
*/ |
return 0; |
} |
int putc(unsigned char c) |
{ |
int level; |
|
if (xmt_len<MODEM_BUFFER_LENGTH-1) |
{ |
_CPU_ISR_Disable(level); |
xmt_buf[(xmt_start+xmt_len)%MODEM_BUFFER_LENGTH]=c; |
xmt_len++; |
_CPU_ISR_Enable(level); |
return 0; |
} |
return 1; |
} |
|
void unputc(void) |
{ |
int level; |
|
if (xmt_len==0) |
return; |
_CPU_ISR_Disable(level); |
xmt_len--; |
_CPU_ISR_Enable(level); |
} |
|
static void |
pppasyncstart(sc) |
register struct ppp_softc *sc; |
{ |
/* Call pppstart to start output again if necessary. */ |
pppstart(sc->sc_devp); |
|
/* |
* This timeout is needed for operation on a pseudo-tty, |
* because the pty code doesn't call pppstart after it has |
* drained the t_outq. |
*/ |
/* if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) { |
timeout(ppp_timeout, (void *) sc, 1); |
sc->sc_flags |= SC_TIMEOUT; |
} |
*/ |
|
} |
|
|
void modem_sendpacket() |
{ |
struct mbuf *l = NULL; |
rtems_unsigned16 status; |
int curr; |
register struct mbuf *m; |
register int len; |
register u_char *start, *stop, *cp; |
int n, ndone, done, idle; |
struct mbuf *m2; |
int s; |
register struct ppp_softc *sc=ModemData.t_sc; |
|
|
while (xmt_len < PPP_HIWAT) { |
/* |
* See if we have an existing packet partly sent. |
* If not, get a new packet and start sending it. |
*/ |
m = sc->sc_outm; |
if (m == NULL) { |
/* |
* Get another packet to be sent. |
|
*/ |
m = ppp_dequeue(sc); |
if (m == NULL) |
{ |
break; |
} |
|
/* |
* The extra PPP_FLAG will start up a new packet, and thus |
* will flush any accumulated garbage. We do this whenever |
* the line may have been idle for some time. |
*/ |
if (xmt_len == 0) { |
++sc->sc_stats.ppp_obytes; |
putc(PPP_FLAG); |
} |
|
/* Calculate the FCS for the first mbuf's worth. */ |
sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len); |
microtime(&sc->sc_if.if_lastchange); |
} |
|
for (;;) { |
start = mtod(m, u_char *); |
len = m->m_len; |
stop = start + len; |
while (len > 0) { |
/* |
* Find out how many bytes in the string we can |
* handle without doing something special. |
*/ |
for (cp = start; cp < stop; cp++) |
if (ESCAPE_P(*cp)) |
break; |
n = cp - start; |
if (n) { |
register int i; |
/* NetBSD (0.9 or later), 4.3-Reno or similar. */ |
for(i=0;i<n;i++) |
if (putc(start[i])) |
break; |
ndone = i; |
len -= ndone; |
start += ndone; |
sc->sc_stats.ppp_obytes += ndone; |
|
if (ndone < n) |
break; /* packet doesn't fit */ |
} |
/* |
* If there are characters left in the mbuf, |
* the first one must be special. |
* Put it out in a different form. |
*/ |
if (len) { |
if (putc(PPP_ESCAPE)) |
break; |
if (putc(*start ^ PPP_TRANS)) { |
unputc(); |
break; |
} |
sc->sc_stats.ppp_obytes += 2; |
start++; |
len--; |
} |
} |
|
/* |
* If we didn't empty this mbuf, remember where we're up to. |
* If we emptied the last mbuf, try to add the FCS and closing |
* flag, and if we can't, leave sc_outm pointing to m, but with |
* m->m_len == 0, to remind us to output the FCS and flag later. |
*/ |
done = len == 0; |
if (done && m->m_next == NULL) { |
u_char *p, *q; |
int c; |
u_char endseq[8]; |
|
/* |
* We may have to escape the bytes in the FCS. |
*/ |
p = endseq; |
c = ~sc->sc_outfcs & 0xFF; |
if (ESCAPE_P(c)) { |
*p++ = PPP_ESCAPE; |
*p++ = c ^ PPP_TRANS; |
} else |
*p++ = c; |
c = (~sc->sc_outfcs >> 8) & 0xFF; |
if (ESCAPE_P(c)) { |
*p++ = PPP_ESCAPE; |
*p++ = c ^ PPP_TRANS; |
} else |
*p++ = c; |
*p++ = PPP_FLAG; |
|
/* |
* Try to output the FCS and flag. If the bytes |
* don't all fit, back out. |
*/ |
for (q = endseq; q < p; ++q) |
if (putc(*q)) { |
done = 0; |
for (; q > endseq; --q) |
unputc(); |
break; |
} |
if (done) |
sc->sc_stats.ppp_obytes += q - endseq; |
} |
|
if (!done) { |
/* remember where we got to */ |
m->m_data = start; |
m->m_len = len; |
break; |
} |
|
/* Finished with this mbuf; free it and move on. */ |
MFREE(m, m2); |
m = m2; |
if (m == NULL) { |
/* Finished a packet */ |
break; |
} |
sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len); |
} |
|
/* |
* If m == NULL, we have finished a packet. |
* If m != NULL, we've either done as much work this time |
* as we need to, or else we've filled up the output queue. |
*/ |
sc->sc_outm = m; |
if (m) |
break; |
} |
|
} |
|
static void |
pppasyncctlp(sc) |
struct ppp_softc *sc; |
{ |
rtems_semaphore_release(ModemData.pppsem); |
} |
|
|
static unsigned paritytab[8] = { |
0x96696996, 0x69969669, 0x69969669, 0x96696996, |
0x69969669, 0x96696996, 0x96696996, 0x69969669 |
}; |
#define MAX_DUMP_BYTES 128 |
|
static void |
pppdumpb(b, l) |
u_char *b; |
int l; |
{ |
char buf[3*MAX_DUMP_BYTES+4]; |
char *bp = buf; |
static char digits[] = "0123456789abcdef"; |
|
while (l--) { |
if (bp >= buf + sizeof(buf) - 3) { |
*bp++ = '>'; |
break; |
} |
*bp++ = digits[*b >> 4]; /* convert byte to ascii hex */ |
*bp++ = digits[*b++ & 0xf]; |
*bp++ = ' '; |
} |
|
*bp = 0; |
|
} |
|
static void |
ppplogchar(sc, c) |
struct ppp_softc *sc; |
int c; |
{ |
if (c >= 0) |
sc->sc_rawin[sc->sc_rawin_count++] = c; |
if (sc->sc_rawin_count >= sizeof(sc->sc_rawin) |
|| (c < 0 && sc->sc_rawin_count > 0)) { |
/* printf("ppp%d input: ", sc->sc_if.if_unit); |
*/ pppdumpb(sc->sc_rawin, sc->sc_rawin_count); |
sc->sc_rawin_count = 0; |
} |
} |
static void |
pppgetm(sc) |
register struct ppp_softc *sc; |
{ |
struct mbuf *m, **mp; |
int len; |
mp = &sc->sc_m; |
for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){ |
if ((m = *mp) == NULL) { |
MGETHDR(m, M_DONTWAIT, MT_DATA); |
if (m == NULL) |
break; |
*mp = m; |
MCLGET(m, M_DONTWAIT); |
} |
len -= M_DATASIZE(m); |
mp = &m->m_next; |
} |
} |
|
|
int |
pppinput(c) |
int c; |
|
{ |
register struct ppp_softc *sc=ModemData.t_sc; |
struct mbuf *m; |
int ilen, s; |
|
if (sc == NULL ) |
return 0; |
|
++sc->sc_stats.ppp_ibytes; |
/* |
if (c & TTY_FE) {*/ |
/* framing error or overrun on this char - abort packet */ |
/* if (sc->sc_flags & SC_DEBUG) |
printf("ppp%d: bad char %x\n", sc->sc_if.if_unit, c); |
goto flush; |
}*/ |
|
c &= 0xff; |
|
/* |
* Handle software flow control of output. |
*/ |
/* if (tp->t_iflag & IXON) { |
if (c == tp->t_cc[VSTOP] ) { |
if ((tp->t_state & TS_TTSTOP) == 0) { |
tp->t_state |= TS_TTSTOP; |
sccppp_stop_transmission(tp); |
} |
return 0; |
} |
if (c == tp->t_cc[VSTART] ) { |
tp->t_state &= ~TS_TTSTOP; |
sccppp_start_transmission(tp); |
return 0; |
} |
} |
*/ |
|
if (c & 0x80) |
sc->sc_flags |= SC_RCV_B7_1; |
else |
sc->sc_flags |= SC_RCV_B7_0; |
if (paritytab[c >> 5] & (1 << (c & 0x1F))) |
sc->sc_flags |= SC_RCV_ODDP; |
else |
sc->sc_flags |= SC_RCV_EVNP; |
|
|
/* if (sc->sc_flags & SC_LOG_RAWIN)*/ |
// ppplogchar(sc, c); |
|
if (c == PPP_FLAG) { |
ilen = sc->sc_ilen; |
sc->sc_ilen = 0; |
|
if (sc->sc_rawin_count > 0) |
ppplogchar(sc, -1); |
|
/* |
* If SC_ESCAPED is set, then we've seen the packet |
* abort sequence |
*/ |
if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED) |
|| (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) { |
sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */ |
if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){ |
if (sc->sc_flags & SC_DEBUG) |
printf("ppp%d: bad fcs %x, pkt len %d\n", |
sc->sc_if.if_unit, sc->sc_fcs, ilen); |
sc->sc_if.if_ierrors++; |
sc->sc_stats.ppp_ierrors++; |
} else |
sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED); |
return 0; |
} |
|
if (ilen < PPP_HDRLEN + PPP_FCSLEN) { |
if (ilen) { |
if (sc->sc_flags & SC_DEBUG) |
/* printf("ppp%d: too short (%d)\n", sc->sc_if.if_unit, ilen); |
*/ sc->sc_if.if_ierrors++; |
sc->sc_stats.ppp_ierrors++; |
sc->sc_flags |= SC_PKTLOST; |
splx(s); |
} |
return 0; |
} |
|
/* |
* Remove FCS trailer. Somewhat painful... |
*/ |
ilen -= 2; |
if (--sc->sc_mc->m_len == 0) { |
for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next) |
; |
sc->sc_mc = m; |
} |
sc->sc_mc->m_len--; |
|
/* excise this mbuf chain */ |
m = sc->sc_m; |
sc->sc_m = sc->sc_mc->m_next; |
sc->sc_mc->m_next = NULL; |
ppppktin(sc, m, sc->sc_flags & SC_PKTLOST); |
if (sc->sc_flags & SC_PKTLOST) { |
sc->sc_flags &= ~SC_PKTLOST; |
} |
|
pppgetm(sc); |
return 0; |
} |
|
if (sc->sc_flags & SC_FLUSH) { |
if (sc->sc_flags & SC_LOG_FLUSH) |
ppplogchar(sc, c); |
return 0; |
} |
|
if (c < 0x20 && (sc->sc_rasyncmap & (1 << c))) |
return 0; |
|
if (sc->sc_flags & SC_ESCAPED) { |
sc->sc_flags &= ~SC_ESCAPED; |
c ^= PPP_TRANS; |
} else if (c == PPP_ESCAPE) { |
sc->sc_flags |= SC_ESCAPED; |
return 0; |
} |
|
/* |
* Initialize buffer on first octet received. |
* First octet could be address or protocol (when compressing |
* address/control). |
* Second octet is control. |
* Third octet is first or second (when compressing protocol) |
* octet of protocol. |
* Fourth octet is second octet of protocol. |
*/ |
if (sc->sc_ilen == 0) { |
/* reset the first input mbuf */ |
if (sc->sc_m == NULL) { |
pppgetm(sc); |
if (sc->sc_m == NULL) { |
if (sc->sc_flags & SC_DEBUG) |
/* printf("ppp%d: no input mbufs!\n", sc->sc_if.if_unit); |
*/ goto flush; |
} |
} |
m = sc->sc_m; |
m->m_len = 0; |
m->m_data = M_DATASTART(sc->sc_m); |
sc->sc_mc = m; |
sc->sc_mp = mtod(m, char *); |
sc->sc_fcs = PPP_INITFCS; |
if (c != PPP_ALLSTATIONS) { |
if (sc->sc_flags & SC_REJ_COMP_AC) { |
if (sc->sc_flags & SC_DEBUG) |
/* printf("ppp%d: garbage received: 0x%x (need 0xFF)\n", |
sc->sc_if.if_unit, c);*/ |
goto flush; |
} |
*sc->sc_mp++ = PPP_ALLSTATIONS; |
*sc->sc_mp++ = PPP_UI; |
sc->sc_ilen += 2; |
m->m_len += 2; |
} |
} |
if (sc->sc_ilen == 1 && c != PPP_UI) { |
if (sc->sc_flags & SC_DEBUG) |
/* printf("ppp%d: missing UI (0x3), got 0x%x\n", |
sc->sc_if.if_unit, c); |
*/ goto flush; |
} |
if (sc->sc_ilen == 2 && (c & 1) == 1) { |
/* a compressed protocol */ |
*sc->sc_mp++ = 0; |
sc->sc_ilen++; |
sc->sc_mc->m_len++; |
} |
if (sc->sc_ilen == 3 && (c & 1) == 0) { |
if (sc->sc_flags & SC_DEBUG) |
/* printf("ppp%d: bad protocol %x\n", sc->sc_if.if_unit, |
(sc->sc_mp[-1] << 8) + c); |
*/ goto flush; |
} |
|
/* packet beyond configured mru? */ |
if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) { |
if (sc->sc_flags & SC_DEBUG) |
/* printf("ppp%d: packet too big\n", sc->sc_if.if_unit); |
*/ goto flush; |
} |
|
/* is this mbuf full? */ |
m = sc->sc_mc; |
if (M_TRAILINGSPACE(m) <= 0) { |
if (m->m_next == NULL) { |
pppgetm(sc); |
if (m->m_next == NULL) { |
if (sc->sc_flags & SC_DEBUG) |
/* printf("ppp%d: too few input mbufs!\n", sc->sc_if.if_unit); |
*/ goto flush; |
} |
} |
sc->sc_mc = m = m->m_next; |
m->m_len = 0; |
m->m_data = M_DATASTART(m); |
sc->sc_mp = mtod(m, char *); |
} |
|
++m->m_len; |
*sc->sc_mp++ = c; |
sc->sc_fcs = PPP_FCS(sc->sc_fcs, c); |
return 0; |
|
flush: |
if (!(sc->sc_flags & SC_FLUSH)) { |
sc->sc_if.if_ierrors++; |
sc->sc_stats.ppp_ierrors++; |
sc->sc_flags |= SC_FLUSH; |
if (sc->sc_flags & SC_LOG_FLUSH) |
ppplogchar(sc, c); |
} |
return 0; |
} |
|
|
void |
modem_txDaemon (void *arg) |
{ |
rtems_event_set events; |
register int level,i,maxonce; |
while (1) |
{ |
if (xmt_len==0) //jezeli nic nie ma to czekajmy na event |
rtems_event_receive(START_TRANSMIT_EVENT|INTERRUPT_EVENT,RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT,&events); |
/* wait for transmit buffer to become empty */ |
|
while(_tx_stop) //tu czekamy na start transmisji |
rtems_event_receive(INTERRUPT_EVENT|START_TRANSMIT_EVENT,RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT,&events); |
|
_CPU_ISR_Disable(level); |
if (*LSR & THRE) //jezeli nie ma transmisji to wyslijmy pierwsze bajty, jezeli jest, same pojda |
{ |
maxonce=(xmt_len>14)?14:xmt_len; |
if (maxonce>0) |
{ |
for (i=0;i<maxonce;i++) |
{ |
*THR=xmt_buf[xmt_start]; |
xmt_start=(xmt_start+1)%MODEM_BUFFER_LENGTH; |
} |
xmt_len-=maxonce; |
} |
} |
_CPU_ISR_Enable(level); |
if ((ModemData.t_line==PPPDISC)) |
{ |
rtems_bsdnet_semaphore_obtain(); |
modem_sendpacket(); |
rtems_bsdnet_semaphore_release(); |
} |
|
} |
} |
|
static void modem_rxDaemon (void *arg) |
{ |
rtems_event_set events; |
unsigned char bufor_posr[MODEM_BUFFER_LENGTH]; |
register unsigned char ch; |
int level,i,j; |
while(1) |
{ |
/* wait for interrupt */ |
i=0; |
_CPU_ISR_Disable(level); |
while(rcv_len>0) |
{ |
bufor_posr[i++]=rcv_buf[rcv_start]; |
rcv_start=(rcv_start+1)%MODEM_BUFFER_LENGTH; |
rcv_len--; |
} |
_CPU_ISR_Enable(level); |
if (ModemData.t_line==PPPDISC) |
{ |
rtems_bsdnet_semaphore_obtain(); |
for(j=0;j<i;j++) |
pppinput(bufor_posr[j]); |
rtems_bsdnet_semaphore_release(); |
} |
else |
if (i!=0)rtems_termios_enqueue_raw_characters(modem_tty,bufor_posr,i); |
rtems_event_receive(INTERRUPT_EVENT,RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT,&events); |
} |
} |
#define CLK_FREQ 1843200 |
void set_modem_speed(int speed) |
{ |
*LCR = (char)(DLAB); |
*DLL = (char)((int)(CLK_FREQ/speed/16.0+0.5) & 0xFF); |
*DLM = (char)(((int)(CLK_FREQ/speed/16.0+0.5) & 0xFF00) >> 8); |
*LCR = (char)(WL_8 ); /* 8 bitowe slowo */ |
} |
|
|
static void |
modem_init (int speed) /* port is the SMC number (i.e. 1 or 2) */ |
{ |
set_modem_speed(speed); |
/* Line control setup */ |
|
*LCR = (char)(WL_8 ); /* 8 bitowe slowo */ |
/* bylo NSB - bylo 2 jest 1*/ |
|
/* Interrupt setup */ |
*IER = (char) 0x0f; /* enable transmit, receive, modem stat int */ |
|
/* FIFO setup */ |
*FCR = (char)(FIFO_E | 0xc0); |
|
/* Modem control setup */ |
*MCR = (char) RTS|DTR|OUT2; |
|
/* init tx_stop with CTS */ |
_tx_stop = ( (*MDSR & CTS) ? 0 : 1); |
} |
|
void set_modem_dtr(int how) |
{ |
unsigned char znak; |
znak=*MCR; |
*MCR=(how)?(znak|DTR):(znak&(~DTR)); |
} |
void modem_status() |
{ |
unsigned char status; |
status=*MDSR; |
|
/* printf("Modem Status %x ",status); |
*/ if (status&CTS) |
{ |
_tx_stop=0; |
rtems_event_send (modem_tx_task, START_TRANSMIT_EVENT|INTERRUPT_EVENT); |
} |
else |
{ |
_tx_stop=1; |
} |
if (status&DCD) |
_modem_cd=1; |
else |
_modem_cd=0; |
} |
|
static rtems_isr |
modemInterruptHandler (rtems_vector_number v) |
{ |
register char a,i,ch; |
register int maxonce; |
static errcount = 0; |
for(;;) |
{ |
a=*IIR & (NIP | IID_MASK); /* read interrupt id register */ |
switch (a) { |
case 0x04: case 0x0c: |
/* |
* Buffer received? |
*/ |
while( (*LSR & DR) != 0) |
{ |
ch=*RBR; |
rcv_buf[(rcv_start+rcv_len)%MODEM_BUFFER_LENGTH]=ch; |
rcv_len++; |
} |
rtems_event_send (modem_rx_task, INTERRUPT_EVENT); |
break; |
case 0x02: |
/* |
* Buffer transmitted ? |
*/ |
if (*LSR & THRE) //jezeli nie ma transmisji (a nie powinno byc) to wyslijmy bajty |
{ |
maxonce=(xmt_len>14)?14:xmt_len; |
if (maxonce>0) |
{ |
for (i=0;i<maxonce;i++) |
{ |
*THR=xmt_buf[xmt_start]; |
xmt_start=(xmt_start+1)%MODEM_BUFFER_LENGTH; |
} |
xmt_len-=maxonce; |
} |
} |
rtems_event_send (modem_tx_task, INTERRUPT_EVENT); |
break; |
case 0x00: |
modem_status(); |
break; |
case 0x01: |
return; |
case 0x06: |
ch=*RBR; |
errcount++; |
break; |
|
default: |
break; |
} |
} |
} |
|
|
void modem_flush(int mode) |
{ |
if (mode&FWRITE) |
{ |
} |
if (mode&FREAD) |
{ |
} |
|
} |
|
|
|
int modemWriteTermios(int minor, const char *buf, int len) |
{ |
int level; |
int i,maxonce; |
if (len<=0) |
return 0; |
|
if (ModemData.t_line!=PPPDISC) |
{ |
_CPU_ISR_Disable(level); |
for(i=0;i<len;i++) |
{ |
if (xmt_len>=MODEM_BUFFER_LENGTH) |
break; |
xmt_buf[(xmt_start+xmt_len)%MODEM_BUFFER_LENGTH]=buf[i]; |
xmt_len++; |
} |
_CPU_ISR_Enable(level); |
} |
rtems_event_send(modem_tx_task,START_TRANSMIT_EVENT); |
return i; |
} |
|
|
/* |
* Initialize and register the device |
*/ |
rtems_device_driver modem_initialize( |
rtems_device_major_number major, |
rtems_device_minor_number minor, |
void *arg |
) |
{ |
rtems_status_code status; |
rtems_isr_entry old_handler; |
rtems_status_code sc; |
rtems_termios_initialize (); |
sc = rtems_semaphore_create ( |
rtems_build_name ('M', 'D', 'M', 'P'), |
0, |
RTEMS_COUNTING_SEMAPHORE, |
RTEMS_NO_PRIORITY_CEILING, |
&ModemData.pppsem); |
if (sc != RTEMS_SUCCESSFUL) |
rtems_fatal_error_occurred (sc); |
modem_init(9600); |
|
sc = rtems_interrupt_catch (modemInterruptHandler, |
PPC_IRQ_IRQ4, |
&old_handler); |
|
/* |
* Register the devices |
*/ |
modem_tx_task=0; |
modem_rx_task=0; |
status = rtems_io_register_name ("/dev/modem", major, 0); |
if (status != RTEMS_SUCCESSFUL) |
rtems_fatal_error_occurred (status); |
return RTEMS_SUCCESSFUL; |
} |
|
rtems_device_driver modem_first_open( |
rtems_device_major_number major, |
rtems_device_minor_number minor, |
void * arg |
) |
{ |
modem_tty=(struct rtems_termios_tty *)(((rtems_libio_open_close_args_t *)arg)->iop->data1); |
return RTEMS_SUCCESSFUL; |
} |
rtems_device_driver modem_last_close( |
rtems_device_major_number major, |
rtems_device_minor_number minor, |
void * arg |
) |
{ |
m823.siu.simask &=(~M823_SIMASK_IRM4); /* block the interrupts */ |
return RTEMS_SUCCESSFUL; |
} |
|
static int |
modemSetAttr(int minor, const struct termios *t) |
{ |
int baud; |
|
switch (t->c_cflag & CBAUD) |
{ |
case B50: |
baud = 50; |
break; |
case B75: |
baud = 75; |
break; |
case B110: |
baud = 110; |
break; |
case B134: |
baud = 134; |
break; |
case B150: |
baud = 150; |
break; |
case B200: |
baud = 200; |
break; |
case B300: |
baud = 300; |
break; |
case B600: |
baud = 600; |
break; |
case B1200: |
baud = 1200; |
break; |
case B1800: |
baud = 1800; |
break; |
case B2400: |
baud = 2400; |
break; |
case B4800: |
baud = 4800; |
break; |
case B9600: |
baud = 9600; |
break; |
case B19200: |
baud = 19200; |
break; |
case B38400: |
baud = 38400; |
break; |
case B57600: |
baud = 57600; |
break; |
case B115200: |
baud = 115200; |
break; |
default: |
baud = 0; |
rtems_fatal_error_occurred (RTEMS_INTERNAL_ERROR); |
return 0; |
} |
set_modem_speed(baud); |
return RTEMS_SUCCESSFUL; |
} |
|
|
/* |
* Open the device |
*/ |
|
|
|
rtems_device_driver modem_open( |
rtems_device_major_number major, |
rtems_device_minor_number minor, |
void * arg |
) |
{ |
int error, s; |
rtems_status_code status; |
register struct ppp_softc *sc; |
static rtems_termios_callbacks cb = |
{ |
modem_first_open, /* firstOpen */ |
modem_last_close, /* lastClose */ |
NULL, /* poll read */ |
modemWriteTermios, /* write */ |
modemSetAttr, /* setAttributes */ |
NULL, /* stopRemoteTx */ |
NULL, /* startRemoteTx */ |
0 /* outputUsesInterrupts */ |
}; |
|
if (ModemData.t_line == PPPDISC) |
{ |
sc = ModemData.t_sc; |
if (sc != NULL && sc->sc_devp == (void *) &ModemData) |
{ |
return (0); |
} |
} |
|
if ((ModemData.t_sc= sc = pppalloc(1)) == NULL) |
return 2; |
|
if (sc->sc_relinq) |
(*sc->sc_relinq)(sc); /* get previous owner to relinquish the unit */ |
|
sc->sc_ilen = 0; |
sc->sc_m = NULL; |
bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap)); |
sc->sc_asyncmap[0] = 0xffffffff; |
sc->sc_asyncmap[3] = 0x60000000; |
sc->sc_rasyncmap = 0; |
sc->sc_devp = &ModemData; |
sc->sc_start = pppasyncstart; |
sc->sc_ctlp = pppasyncctlp; |
sc->sc_relinq = pppasyncrelinq; |
sc->sc_outm = NULL; |
pppgetm(sc); |
sc->sc_if.if_flags |= IFF_RUNNING; |
sc->sc_if.if_baudrate = 38400; |
|
status = rtems_termios_open (major, minor, arg, &cb); |
if(status != RTEMS_SUCCESSFUL) |
{ |
/* printf("Error openning console device\n"); |
*/ return status; |
} |
|
|
/* init rx and tx task for device */ |
xmt_start=xmt_len=0; |
rcv_start=rcv_len=0; |
|
if (modem_rx_task==0 && modem_tx_task==0) |
{ |
rtems_status_code sc; |
sc = rtems_task_create (rtems_build_name ('M', 'D', 't', 'x'), |
101, |
16*1024, |
RTEMS_PREEMPT|RTEMS_TIMESLICE|RTEMS_NO_ASR|RTEMS_INTERRUPT_LEVEL(0), |
RTEMS_NO_FLOATING_POINT|RTEMS_LOCAL, |
&modem_tx_task); |
if (sc != RTEMS_SUCCESSFUL) { |
|
} |
|
sc = rtems_task_start (modem_tx_task, (void *)modem_txDaemon, 0); |
if (sc != RTEMS_SUCCESSFUL) { |
|
} |
|
sc = rtems_task_create (rtems_build_name ('M', 'D', 'r', 'x'), |
101, |
16*1024, |
RTEMS_PREEMPT|RTEMS_TIMESLICE|RTEMS_NO_ASR|RTEMS_INTERRUPT_LEVEL(0), |
RTEMS_NO_FLOATING_POINT|RTEMS_LOCAL, |
&modem_rx_task); |
if (sc != RTEMS_SUCCESSFUL) { |
|
} |
|
sc = rtems_task_start (modem_rx_task, (void *)modem_rxDaemon, 0); |
if (sc != RTEMS_SUCCESSFUL) { |
|
} |
|
} |
/* Enable modem interrupts */ |
m823.siu.simask |= M823_SIMASK_IRM4; |
|
return RTEMS_SUCCESSFUL; |
} |
|
/* |
* Close the device |
*/ |
rtems_device_driver modem_close( |
rtems_device_major_number major, |
rtems_device_minor_number minor, |
void * arg |
) |
{ |
register struct ppp_softc *sc; |
modem_flush( FREAD|FWRITE); |
|
ModemData.t_line = 0; |
sc = ModemData.t_sc; |
if (sc != NULL) { |
ModemData.t_sc = NULL; |
if (&ModemData == (struct tty *) sc->sc_devp) { |
rtems_bsdnet_semaphore_obtain(); |
pppasyncrelinq(sc); |
pppdealloc(sc); |
rtems_bsdnet_semaphore_release(); |
} |
} |
return RTEMS_SUCCESSFUL; |
} |
|
/* for now works only as serial device */ |
|
|
rtems_device_driver modem_read( |
rtems_device_major_number major, |
rtems_device_minor_number minor, |
void * arg |
) |
{ |
rtems_libio_rw_args_t *rw_args= (rtems_libio_rw_args_t *)arg; |
char *buffer; |
int count=0,maximum; |
rtems_status_code sc; |
|
buffer = rw_args->buffer; |
maximum = rw_args->count; |
if (ModemData.t_line==PPPDISC) |
{ |
|
struct mbuf *m, *m0; |
register int s; |
int error = 0; |
rtems_status_code status; |
rtems_interval ticks; |
register struct ppp_softc *sc = (struct ppp_softc *)ModemData.t_sc; |
ticks=1000000/rtems_bsdnet_microseconds_per_tick; |
|
if (sc == NULL) |
return 0; |
/* |
* Loop waiting for input, checking that nothing disasterous |
* happens in the meantime. |
*/ |
for (;;) { |
if (sc->sc_inq.ifq_head != NULL) |
{ |
/* printf("Read : Dane sa w buforze\n"); |
*/ break; |
} |
/* printf("Read : Czekam na dane\n"); |
*/ |
status=rtems_semaphore_obtain(ModemData.pppsem,RTEMS_WAIT,ticks); |
if (_modem_cd==0) |
{ |
rw_args->bytes_moved =0; |
return RTEMS_SUCCESSFUL; |
} |
|
if (status==RTEMS_TIMEOUT) |
return status; |
} |
rtems_bsdnet_semaphore_obtain(); |
IF_DEQUEUE(&sc->sc_inq, m0); |
rtems_bsdnet_semaphore_release(); |
|
for (m = m0; m && (count+m->m_next->m_len<maximum); m = m->m_next) /* check if packet will fit in buffer */ |
{ |
memcpy(buffer,mtod(m, u_char *),m->m_len); |
count+=m->m_len; |
buffer+=m->m_len; |
} |
m_freem(m0); |
rw_args->bytes_moved = count; |
|
} |
else |
sc = rtems_termios_read (arg); |
|
count=rw_args->bytes_moved; |
return (count >= 0) ? RTEMS_SUCCESSFUL : RTEMS_UNSATISFIED; |
} |
|
/* |
* Write to the device |
*/ |
rtems_device_driver modem_write( |
rtems_device_major_number major, |
rtems_device_minor_number minor, |
void * arg |
) |
{ |
int count,len; |
rtems_libio_rw_args_t *rw_args; |
char *out_buffer; |
int n,maximum; |
rw_args = (rtems_libio_rw_args_t *) arg; |
|
out_buffer = rw_args->buffer; |
maximum = rw_args->count; |
|
if (ModemData.t_line==PPPDISC) |
{ |
register struct ppp_softc *sc = (struct ppp_softc *)ModemData.t_sc; |
struct sockaddr dst; |
struct mbuf *m, *m0, **mp; |
rtems_bsdnet_semaphore_obtain(); |
for (mp = &m0; maximum; mp = &m->m_next) |
{ |
MGET(m, M_WAIT, MT_DATA); |
if ((*mp = m) == NULL) |
{ |
rtems_bsdnet_semaphore_release(); |
m_freem(m0); |
return (ENOBUFS); |
} |
m->m_len = 0; |
if (maximum>= MCLBYTES / 2) |
MCLGET(m, M_DONTWAIT); |
len = M_TRAILINGSPACE(m); |
if (len > maximum) |
{ |
memcpy(mtod(m, u_char *),out_buffer,maximum); |
m->m_len=maximum; |
maximum=0; |
} |
else |
{ |
memcpy(mtod(m, u_char *),out_buffer,len); |
maximum-=len; |
m->m_len=len; |
out_buffer+=len; |
} |
} |
|
dst.sa_family = AF_UNSPEC; |
bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN); |
m0->m_data += PPP_HDRLEN; |
m0->m_len -= PPP_HDRLEN; |
|
/* printf("Wysylam %d bajtow \n",m0->m_len); |
*/ n=pppoutput(&sc->sc_if, m0, &dst, (struct rtentry *)0); |
rtems_bsdnet_semaphore_release(); |
return n; |
} |
else |
return rtems_termios_write (arg); |
} |
|
|
|
/* |
* Handle ioctl request. |
* Should set hardware line speed, bits/char, etc. |
*/ |
rtems_device_driver modem_control( |
rtems_device_major_number major, |
rtems_device_minor_number minor, |
void * arg |
) |
{ |
rtems_libio_ioctl_args_t *args=(rtems_libio_ioctl_args_t *)arg; |
struct ppp_softc *sc=ModemData.t_sc; |
int cmd; |
caddr_t data; |
int error=RTEMS_SUCCESSFUL; |
|
data=args->buffer; |
cmd=args->command; |
|
switch (cmd) { |
case RTEMS_IO_GET_ATTRIBUTES: |
case RTEMS_IO_SET_ATTRIBUTES: |
case RTEMS_IO_TCDRAIN: |
return rtems_termios_ioctl (arg); |
break; |
case PPPIOCSASYNCMAP: |
sc->sc_asyncmap[0] = *(u_int *)data; |
break; |
|
case PPPIOCGASYNCMAP: |
*(u_int *)data = sc->sc_asyncmap[0]; |
break; |
|
case PPPIOCSRASYNCMAP: |
sc->sc_rasyncmap = *(u_int *)data; |
break; |
|
case TIOCSETD: |
ModemData.t_line=*(int*)data; |
break; |
case TIOCGETD: |
*(int*)data=ModemData.t_line; |
break; |
case TIOCMBIS: |
if ((*(int*)data)&TIOCM_DTR) |
set_modem_dtr(1); |
break; |
case TIOCMBIC: |
if ((*(int*)data)&TIOCM_DTR) |
set_modem_dtr(0); |
break; |
case PPPIOCGRASYNCMAP: |
*(u_int *)data = sc->sc_rasyncmap; |
break; |
|
case PPPIOCSXASYNCMAP: |
bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap)); |
sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */ |
sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */ |
sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */ |
break; |
|
case PPPIOCGXASYNCMAP: |
bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap)); |
break; |
|
default: |
rtems_bsdnet_semaphore_obtain(); |
error = pppioctl(sc, cmd, data, 0, NULL); |
if (error == 0 && cmd == PPPIOCSMRU) |
pppgetm(sc); |
rtems_bsdnet_semaphore_release(); |
|
} |
return error; |
|
} |
|
|
|
void |
wait_input(timo) |
struct timeval *timo; |
{ |
int n; |
rtems_event_set events; |
rtems_interval ticks; |
rtems_status_code err; |
int czekaj=1; |
register struct ppp_softc *sc = (struct ppp_softc *)ModemData.t_sc; |
ticks = 1+(timo->tv_sec*1000000+timo->tv_usec)/rtems_bsdnet_microseconds_per_tick; |
while (czekaj) |
{ |
|
if (sc->sc_inq.ifq_head != NULL) |
break; |
/* printf("Wait : Czekam na dane przez %d ticks\n",ticks); |
*/ err=rtems_semaphore_obtain(ModemData.pppsem,RTEMS_WAIT,ticks); |
if (err==RTEMS_TIMEOUT) |
{ |
/* printf("TIMEOUT :Brak danych\n"); |
*/ break; |
} |
} |
|
} |
/modem_example/ppp.h
0,0 → 1,7
#ifndef __PPP_H__ |
#define __PPP_H__ |
#define NPPP 1 |
#define NBPFILER 0 |
#define VJC |
/*#define PPP_COMPRESS*/ |
#endif |
/modem_example/16550.h
0,0 → 1,110
/* |
*------------------------------------------------------------------- |
* |
* 16550 -- header file for National Semiconducor's 16550 UART |
* |
* This file has been created by John S. Gwynne for the efi68k |
* project. |
* |
* The license and distribution terms for this file may in |
* the file LICENSE in this distribution or at |
* http://www.OARcorp.com/rtems/license.html. |
* |
*------------------------------------------------------------------ |
* |
* $Id: 16550.h,v 1.2 2001-09-27 12:01:57 chris Exp $ |
*/ |
|
#ifndef _16550_H_ |
#define _16550_H_ |
|
/* base address is the physical location of register 0 */ |
#define UART_BASE_ADDRESS 0xF0000000 |
|
/* definitions of register addresses and associate bits */ |
|
#define RBR (volatile unsigned char * const)(0+UART_BASE_ADDRESS) |
/* Receiver Buffer Register (w/DLAB=0)*/ |
/* 8-bit data */ |
|
#define THR (volatile unsigned char * const)(0+UART_BASE_ADDRESS) |
/* Transmitter Holding Register (w/DLAB=0) */ |
/* 8-bit data */ |
|
#define DLL (volatile unsigned char * const)(0+UART_BASE_ADDRESS) |
/* Divisor Latch (LS) (w/DLAB=1) */ |
/* LSB of Divisor */ |
|
#define DLM (volatile unsigned char * const)(1+UART_BASE_ADDRESS) |
/* Divisor Latch (MS) (w/DLAB=1) */ |
/* MSB of Divisor */ |
|
#define IER (volatile unsigned char * const)(1+UART_BASE_ADDRESS) |
/* Interrupt Enable Register (w/DLAB=0) */ |
#define ERBFI 0x01 /* Enable Recv Data Available Interrupt */ |
#define ETBEI 0x02 /* Enable Trans Holding Reg Empty Inter */ |
#define ELSI 0x04 /* Enable Recv Line Status Interrupt */ |
#define EDSSI 0x08 /* Enable Modem Status Interrupt */ |
|
#define IIR (volatile unsigned char * const)(2+UART_BASE_ADDRESS) |
/* Interrupt Ident Register (read only) */ |
#define NIP 0x01 /* No Interrupt Pending */ |
#define IID_MASK 0x0e /* Interrupt ID mask */ |
#define FE_MASK 0xc0 /* FIFO's Enabled */ |
|
#define FCR (volatile unsigned char * const)(2+UART_BASE_ADDRESS) |
/* FIFO Control Register (write only) */ |
#define FIFO_E 0x01 /* FIFO Enable */ |
#define RFR 0x02 /* RCVR FIFO Reset */ |
#define XFR 0x04 /* XMIT FIFO Reset */ |
#define DMAMS 0x08 /* DMA Mode Select */ |
#define RCVRTG_MASK 0xC0 /* RCVR Triger MSBit/LSBit */ |
|
#define LCR (volatile unsigned char * const)(3+UART_BASE_ADDRESS) |
/* Line Control Register */ |
#define WLS_MASK 0x03 /* Word Legth Select Mask */ |
#define WL_5 0x00 /* 5 bits */ |
#define WL_6 0x01 /* 6 bits */ |
#define WL_7 0x02 /* 7 bits */ |
#define WL_8 0x03 /* 8 bits */ |
#define NSB 0x04 /* Number of Stop Bits (set is 2/1.5) */ |
#define PEN 0x08 /* Parity Enable */ |
#define EPS 0x10 /* Even Parity Select */ |
#define STP 0x20 /* Stick Parity */ |
#define SETBK 0x40 /* Set Break */ |
#define DLAB 0x80 /* Divisor Latch Access Bit */ |
|
#define MCR (volatile unsigned char * const)(4+UART_BASE_ADDRESS) |
/* Modem Control Register */ |
#define DTR 0x01 /* Data Terminal Ready */ |
#define RTS 0x02 /* Request to Send */ |
#define OUT1 0x04 /* Out 1 */ |
#define OUT2 0x08 /* Out 2 */ |
#define LOOP 0x10 /* Loop */ |
|
#define LSR (volatile unsigned char * const)(5+UART_BASE_ADDRESS) |
/* Line Status Register */ |
#define DR 0x01 /* Data Ready */ |
#define OE 0x02 /* Overrun error */ |
#define PE 0x04 /* Parity error */ |
#define FE 0x08 /* Framing error */ |
#define BI 0x10 /* Break Interrupt */ |
#define THRE 0x20 /* Transmitter Holding Register */ |
#define TEMT 0x40 /* Transmitter Empty */ |
#define RCVFIE 0x80 /* Recv FIFO Error */ |
|
#define MDSR (volatile unsigned char * const)(6+UART_BASE_ADDRESS) |
/* Modem Status Register */ |
#define DCTS 0x01 /* Delta Clear to Send */ |
#define DDSR 0x02 /* Delta Data Set Ready */ |
#define TERI 0x04 /* Trailing Edge Ring Indicator */ |
#define DDCD 0x08 /* Delta Data Carrier Detect */ |
#define CTS 0x10 /* Clear to Send */ |
#define DSR 0x20 /* Data Set Ready */ |
#define RI 0x40 /* Ring Indicator */ |
#define DCD 0x80 /* Data Carrier Detect */ |
|
#define SCR (volatile unsigned char * const)(7+UART_BASE_ADDRESS) |
/* Scratch Register */ |
/* 8-bit register */ |
#endif |
/modem_example/modem.h
0,0 → 1,45
#ifndef _MODEM_H_ |
#define _MODEM_H_ |
|
void modem_reserve_resources( |
rtems_configuration_table * configuration |
); |
|
rtems_device_driver modem_initialize( |
rtems_device_major_number, |
rtems_device_minor_number, |
void * |
); |
|
rtems_device_driver modem_open( |
rtems_device_major_number, |
rtems_device_minor_number, |
void * |
); |
|
rtems_device_driver modem_close( |
rtems_device_major_number, |
rtems_device_minor_number, |
void * |
); |
|
rtems_device_driver modem_read( |
rtems_device_major_number, |
rtems_device_minor_number, |
void * |
); |
|
rtems_device_driver modem_write( |
rtems_device_major_number, |
rtems_device_minor_number, |
void * |
); |
|
rtems_device_driver modem_control( |
rtems_device_major_number, |
rtems_device_minor_number, |
void * |
); |
|
|
#endif |
/modem_example/pppcompress.c
0,0 → 1,593
/*- |
* Copyright (c) 1989 The Regents of the University of California. |
* 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. |
* 3. All advertising materials mentioning features or use of this software |
* must display the following acknowledgement: |
* This product includes software developed by the University of |
* California, Berkeley and its contributors. |
* 4. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. |
* |
* @(#)slcompress.c 7.7 (Berkeley) 5/7/91 |
*/ |
|
/* |
* Routines to compress and uncompess tcp packets (for transmission |
* over low speed serial lines. |
* |
* Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: |
* - Initial distribution. |
* |
* $Id: pppcompress.c,v 1.2 2001-09-27 12:01:58 chris Exp $ |
*/ |
|
#include <sys/types.h> |
#include <sys/param.h> |
#include <sys/systm.h> |
#include <sys/mbuf.h> |
#include <sys/socket.h> |
#include <sys/socketvar.h> |
|
#include <netinet/in.h> |
#include <netinet/in_systm.h> |
#include <netinet/ip.h> |
#include <netinet/tcp.h> |
|
#include <net/pppcompress.h> |
|
#ifndef SL_NO_STATS |
#define INCR(counter) ++comp->counter; |
#else |
#define INCR(counter) |
#endif |
|
#define BCMP(p1, p2, n) bcmp((char *)(p1), (char *)(p2), (int)(n)) |
#define BCOPY(p1, p2, n) bcopy((char *)(p1), (char *)(p2), (int)(n)) |
#ifndef KERNEL |
#define ovbcopy bcopy |
#endif |
|
void |
vj_compress_init(comp, max_state) |
struct vjcompress *comp; |
int max_state; |
{ |
register u_int i; |
register struct cstate *tstate = comp->tstate; |
|
if ((unsigned) max_state > MAX_STATES - 1) |
max_state = MAX_STATES - 1; |
bzero((char *)comp, sizeof(*comp)); |
for (i = max_state; i > 0; --i) { |
tstate[i].cs_id = i; |
tstate[i].cs_next = &tstate[i - 1]; |
} |
tstate[0].cs_next = &tstate[max_state]; |
tstate[0].cs_id = 0; |
comp->last_cs = &tstate[0]; |
comp->last_recv = 255; |
comp->last_xmit = 255; |
comp->flags = SLF_TOSS; |
} |
|
|
/* ENCODE encodes a number that is known to be non-zero. ENCODEZ |
* checks for zero (since zero has to be encoded in the long, 3 byte |
* form). |
*/ |
#define ENCODE(n) { \ |
if ((u_short)(n) >= 256) { \ |
*cp++ = 0; \ |
cp[1] = (n); \ |
cp[0] = (n) >> 8; \ |
cp += 2; \ |
} else { \ |
*cp++ = (n); \ |
} \ |
} |
#define ENCODEZ(n) { \ |
if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \ |
*cp++ = 0; \ |
cp[1] = (n); \ |
cp[0] = (n) >> 8; \ |
cp += 2; \ |
} else { \ |
*cp++ = (n); \ |
} \ |
} |
|
#define DECODEL(f) { \ |
if (*cp == 0) {\ |
(f) = htonl(ntohl(f) + ((cp[1] << 8) | cp[2])); \ |
cp += 3; \ |
} else { \ |
(f) = htonl(ntohl(f) + (u_long)*cp++); \ |
} \ |
} |
|
#define DECODES(f) { \ |
if (*cp == 0) {\ |
(f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \ |
cp += 3; \ |
} else { \ |
(f) = htons(ntohs(f) + (u_long)*cp++); \ |
} \ |
} |
|
#define DECODEU(f) { \ |
if (*cp == 0) {\ |
(f) = htons((cp[1] << 8) | cp[2]); \ |
cp += 3; \ |
} else { \ |
(f) = htons((u_long)*cp++); \ |
} \ |
} |
|
u_int |
vj_compress_tcp(m, ip, comp, compress_cid) |
struct mbuf *m; |
register struct ip *ip; |
struct vjcompress *comp; |
int compress_cid; |
{ |
register struct cstate *cs = comp->last_cs->cs_next; |
register u_int hlen = ip->ip_hl; |
register struct tcphdr *oth; |
register struct tcphdr *th; |
register u_int deltaS, deltaA; |
register u_int changes = 0; |
u_char new_seq[16]; |
register u_char *cp = new_seq; |
|
/* |
* Bail if this is an IP fragment or if the TCP packet isn't |
* `compressible' (i.e., ACK isn't set or some other control bit is |
* set). (We assume that the caller has already made sure the |
* packet is IP proto TCP). |
*/ |
if ((ip->ip_off & htons(0x3fff)) || m->m_len < 40) |
return (TYPE_IP); |
|
th = (struct tcphdr *)&((int *)ip)[hlen]; |
if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK) |
return (TYPE_IP); |
/* |
* Packet is compressible -- we're going to send either a |
* COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need |
* to locate (or create) the connection state. Special case the |
* most recently used connection since it's most likely to be used |
* again & we don't have to do any reordering if it's used. |
*/ |
INCR(sls_packets) |
if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr || |
ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr || |
*(int *)th != ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl]) { |
/* |
* Wasn't the first -- search for it. |
* |
* States are kept in a circularly linked list with |
* last_cs pointing to the end of the list. The |
* list is kept in lru order by moving a state to the |
* head of the list whenever it is referenced. Since |
* the list is short and, empirically, the connection |
* we want is almost always near the front, we locate |
* states via linear search. If we don't find a state |
* for the datagram, the oldest state is (re-)used. |
*/ |
register struct cstate *lcs; |
register struct cstate *lastcs = comp->last_cs; |
|
do { |
lcs = cs; cs = cs->cs_next; |
INCR(sls_searches) |
if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr |
&& ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr |
&& *(int *)th == ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl]) |
goto found; |
} while (cs != lastcs); |
|
/* |
* Didn't find it -- re-use oldest cstate. Send an |
* uncompressed packet that tells the other side what |
* connection number we're using for this conversation. |
* Note that since the state list is circular, the oldest |
* state points to the newest and we only need to set |
* last_cs to update the lru linkage. |
*/ |
INCR(sls_misses) |
comp->last_cs = lcs; |
hlen += th->th_off; |
hlen <<= 2; |
goto uncompressed; |
|
found: |
/* |
* Found it -- move to the front on the connection list. |
*/ |
if (cs == lastcs) |
comp->last_cs = lcs; |
else { |
lcs->cs_next = cs->cs_next; |
cs->cs_next = lastcs->cs_next; |
lastcs->cs_next = cs; |
} |
} |
|
/* |
* Make sure that only what we expect to change changed. The first |
* line of the `if' checks the IP protocol version, header length & |
* type of service. The 2nd line checks the "Don't fragment" bit. |
* The 3rd line checks the time-to-live and protocol (the protocol |
* check is unnecessary but costless). The 4th line checks the TCP |
* header length. The 5th line checks IP options, if any. The 6th |
* line checks TCP options, if any. If any of these things are |
* different between the previous & current datagram, we send the |
* current datagram `uncompressed'. |
*/ |
oth = (struct tcphdr *)&((int *)&cs->cs_ip)[hlen]; |
deltaS = hlen; |
hlen += th->th_off; |
hlen <<= 2; |
|
if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0] || |
((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3] || |
((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4] || |
th->th_off != oth->th_off || |
(deltaS > 5 && |
BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) || |
(th->th_off > 5 && |
BCMP(th + 1, oth + 1, (th->th_off - 5) << 2))) |
goto uncompressed; |
|
/* |
* Figure out which of the changing fields changed. The |
* receiver expects changes in the order: urgent, window, |
* ack, seq (the order minimizes the number of temporaries |
* needed in this section of code). |
*/ |
if (th->th_flags & TH_URG) { |
deltaS = ntohs(th->th_urp); |
ENCODEZ(deltaS); |
changes |= NEW_U; |
} else if (th->th_urp != oth->th_urp) |
/* argh! URG not set but urp changed -- a sensible |
* implementation should never do this but RFC793 |
* doesn't prohibit the change so we have to deal |
* with it. */ |
goto uncompressed; |
|
if (deltaS = (u_short)(ntohs(th->th_win) - ntohs(oth->th_win))) { |
ENCODE(deltaS); |
changes |= NEW_W; |
} |
|
if (deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack)) { |
if (deltaA > 0xffff) |
goto uncompressed; |
ENCODE(deltaA); |
changes |= NEW_A; |
} |
|
if (deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq)) { |
if (deltaS > 0xffff) |
goto uncompressed; |
ENCODE(deltaS); |
changes |= NEW_S; |
} |
|
switch(changes) { |
|
case 0: |
/* |
* Nothing changed. If this packet contains data and the |
* last one didn't, this is probably a data packet following |
* an ack (normal on an interactive connection) and we send |
* it compressed. Otherwise it's probably a retransmit, |
* retransmitted ack or window probe. Send it uncompressed |
* in case the other side missed the compressed version. |
*/ |
if (ip->ip_len != cs->cs_ip.ip_len && |
ntohs(cs->cs_ip.ip_len) == hlen) |
break; |
|
/* (fall through) */ |
|
case SPECIAL_I: |
case SPECIAL_D: |
/* |
* actual changes match one of our special case encodings -- |
* send packet uncompressed. |
*/ |
goto uncompressed; |
|
case NEW_S|NEW_A: |
if (deltaS == deltaA && |
deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { |
/* special case for echoed terminal traffic */ |
changes = SPECIAL_I; |
cp = new_seq; |
} |
break; |
|
case NEW_S: |
if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { |
/* special case for data xfer */ |
changes = SPECIAL_D; |
cp = new_seq; |
} |
break; |
} |
|
deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id); |
if (deltaS != 1) { |
ENCODEZ(deltaS); |
changes |= NEW_I; |
} |
if (th->th_flags & TH_PUSH) |
changes |= TCP_PUSH_BIT; |
/* |
* Grab the cksum before we overwrite it below. Then update our |
* state with this packet's header. |
*/ |
deltaA = ntohs(th->th_sum); |
BCOPY(ip, &cs->cs_ip, hlen); |
|
/* |
* We want to use the original packet as our compressed packet. |
* (cp - new_seq) is the number of bytes we need for compressed |
* sequence numbers. In addition we need one byte for the change |
* mask, one for the connection id and two for the tcp checksum. |
* So, (cp - new_seq) + 4 bytes of header are needed. hlen is how |
* many bytes of the original packet to toss so subtract the two to |
* get the new packet size. |
*/ |
deltaS = cp - new_seq; |
cp = (u_char *)ip; |
if (compress_cid == 0 || comp->last_xmit != cs->cs_id) { |
comp->last_xmit = cs->cs_id; |
hlen -= deltaS + 4; |
cp += hlen; |
*cp++ = changes | NEW_C; |
*cp++ = cs->cs_id; |
} else { |
hlen -= deltaS + 3; |
cp += hlen; |
*cp++ = changes; |
} |
m->m_len -= hlen; |
m->m_data += hlen; |
*cp++ = deltaA >> 8; |
*cp++ = deltaA; |
BCOPY(new_seq, cp, deltaS); |
INCR(sls_compressed) |
return (TYPE_COMPRESSED_TCP); |
|
/* |
* Update connection state cs & send uncompressed packet ('uncompressed' |
* means a regular ip/tcp packet but with the 'conversation id' we hope |
* to use on future compressed packets in the protocol field). |
*/ |
uncompressed: |
BCOPY(ip, &cs->cs_ip, hlen); |
ip->ip_p = cs->cs_id; |
comp->last_xmit = cs->cs_id; |
return (TYPE_UNCOMPRESSED_TCP); |
} |
|
|
int |
vj_uncompress_tcp(bufp, len, type, comp) |
u_char **bufp; |
int len; |
u_int type; |
struct vjcompress *comp; |
{ |
u_char *hdr, *cp; |
int hlen, vjlen; |
|
cp = bufp? *bufp: NULL; |
vjlen = vj_uncompress_tcp_core(cp, len, len, type, comp, &hdr, &hlen); |
if (vjlen < 0) |
return (0); /* error */ |
if (vjlen == 0) |
return (len); /* was uncompressed already */ |
|
cp += vjlen; |
len -= vjlen; |
|
/* |
* At this point, cp points to the first byte of data in the |
* packet. If we're not aligned on a 4-byte boundary, copy the |
* data down so the ip & tcp headers will be aligned. Then back up |
* cp by the tcp/ip header length to make room for the reconstructed |
* header (we assume the packet we were handed has enough space to |
* prepend 128 bytes of header). |
*/ |
if ((int)cp & 3) { |
if (len > 0) |
(void) ovbcopy(cp, (caddr_t)((int)cp &~ 3), len); |
cp = (u_char *)((int)cp &~ 3); |
} |
cp -= hlen; |
len += hlen; |
BCOPY(hdr, cp, hlen); |
|
*bufp = cp; |
return (len); |
} |
|
/* |
* Uncompress a packet of total length total_len. The first buflen |
* bytes are at buf; this must include the entire (compressed or |
* uncompressed) TCP/IP header. This procedure returns the length |
* of the VJ header, with a pointer to the uncompressed IP header |
* in *hdrp and its length in *hlenp. |
*/ |
int |
vj_uncompress_tcp_core(buf, buflen, total_len, type, comp, hdrp, hlenp) |
u_char *buf; |
int buflen, total_len; |
u_int type; |
struct vjcompress *comp; |
u_char **hdrp; |
u_int *hlenp; |
{ |
register u_char *cp; |
register u_int hlen, changes; |
register struct tcphdr *th; |
register struct cstate *cs; |
register struct ip *ip; |
register u_short *bp; |
register u_int vjlen; |
|
switch (type) { |
|
case TYPE_UNCOMPRESSED_TCP: |
ip = (struct ip *) buf; |
if (ip->ip_p >= MAX_STATES) |
goto bad; |
cs = &comp->rstate[comp->last_recv = ip->ip_p]; |
comp->flags &=~ SLF_TOSS; |
ip->ip_p = IPPROTO_TCP; |
/* |
* Calculate the size of the TCP/IP header and make sure that |
* we don't overflow the space we have available for it. |
*/ |
hlen = ip->ip_hl << 2; |
if (hlen + sizeof(struct tcphdr) > buflen) |
goto bad; |
hlen += ((struct tcphdr *)&((char *)ip)[hlen])->th_off << 2; |
if (hlen > MAX_HDR || hlen > buflen) |
goto bad; |
BCOPY(ip, &cs->cs_ip, hlen); |
cs->cs_hlen = hlen; |
INCR(sls_uncompressedin) |
*hdrp = (u_char *) &cs->cs_ip; |
*hlenp = hlen; |
return (0); |
|
default: |
goto bad; |
|
case TYPE_COMPRESSED_TCP: |
break; |
} |
/* We've got a compressed packet. */ |
INCR(sls_compressedin) |
cp = buf; |
changes = *cp++; |
if (changes & NEW_C) { |
/* Make sure the state index is in range, then grab the state. |
* If we have a good state index, clear the 'discard' flag. */ |
if (*cp >= MAX_STATES) |
goto bad; |
|
comp->flags &=~ SLF_TOSS; |
comp->last_recv = *cp++; |
} else { |
/* this packet has an implicit state index. If we've |
* had a line error since the last time we got an |
* explicit state index, we have to toss the packet. */ |
if (comp->flags & SLF_TOSS) { |
INCR(sls_tossed) |
return (-1); |
} |
} |
cs = &comp->rstate[comp->last_recv]; |
hlen = cs->cs_ip.ip_hl << 2; |
th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen]; |
th->th_sum = htons((*cp << 8) | cp[1]); |
cp += 2; |
if (changes & TCP_PUSH_BIT) |
th->th_flags |= TH_PUSH; |
else |
th->th_flags &=~ TH_PUSH; |
|
switch (changes & SPECIALS_MASK) { |
case SPECIAL_I: |
{ |
register u_int i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen; |
th->th_ack = htonl(ntohl(th->th_ack) + i); |
th->th_seq = htonl(ntohl(th->th_seq) + i); |
} |
break; |
|
case SPECIAL_D: |
th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len) |
- cs->cs_hlen); |
break; |
|
default: |
if (changes & NEW_U) { |
th->th_flags |= TH_URG; |
DECODEU(th->th_urp) |
} else |
th->th_flags &=~ TH_URG; |
if (changes & NEW_W) |
DECODES(th->th_win) |
if (changes & NEW_A) |
DECODEL(th->th_ack) |
if (changes & NEW_S) |
DECODEL(th->th_seq) |
break; |
} |
if (changes & NEW_I) { |
DECODES(cs->cs_ip.ip_id) |
} else |
cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1); |
|
/* |
* At this point, cp points to the first byte of data in the |
* packet. Fill in the IP total length and update the IP |
* header checksum. |
*/ |
vjlen = cp - buf; |
buflen -= vjlen; |
if (buflen < 0) |
/* we must have dropped some characters (crc should detect |
* this but the old slip framing won't) */ |
goto bad; |
|
total_len += cs->cs_hlen - vjlen; |
cs->cs_ip.ip_len = htons(total_len); |
|
/* recompute the ip header checksum */ |
bp = (u_short *) &cs->cs_ip; |
cs->cs_ip.ip_sum = 0; |
for (changes = 0; hlen > 0; hlen -= 2) |
changes += *bp++; |
changes = (changes & 0xffff) + (changes >> 16); |
changes = (changes & 0xffff) + (changes >> 16); |
cs->cs_ip.ip_sum = ~ changes; |
|
*hdrp = (u_char *) &cs->cs_ip; |
*hlenp = cs->cs_hlen; |
return vjlen; |
|
bad: |
comp->flags |= SLF_TOSS; |
INCR(sls_errorin) |
return (-1); |
} |
/modem_example/README
0,0 → 1,7
# |
# $Id: README,v 1.2 2001-09-27 12:01:57 chris Exp $ |
# |
|
This is a modem driver which should work with limited modifications |
on any 16550. |
|
/auth.c
0,0 → 1,843
/* |
* auth.c - PPP authentication and phase control. |
* |
* Copyright (c) 1993 The Australian National University. |
* All rights reserved. |
* |
* 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 Australian National University. The name of the University |
* 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. |
* |
* Copyright (c) 1989 Carnegie Mellon University. |
* All rights reserved. |
* |
* 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 Carnegie Mellon University. The name of the |
* University 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. |
*/ |
|
#ifndef lint |
/* static char rcsid[] = "$Id: auth.c,v 1.2 2001-09-27 12:01:57 chris Exp $"; */ |
#endif |
|
#include <stdio.h> |
#include <stddef.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <syslog.h> |
#include <pwd.h> |
#include <string.h> |
#include <sys/types.h> |
#include <sys/stat.h> |
#include <sys/socket.h> |
|
#include <fcntl.h> |
#if defined(_PATH_LASTLOG) && defined(_linux_) |
#include <lastlog.h> |
#endif |
|
#include <netdb.h> |
#include <netinet/in.h> |
#include <arpa/inet.h> |
/* #include <stbconfig.h> */ |
|
#include "pppd.h" |
#include "fsm.h" |
#include "lcp.h" |
#include "ipcp.h" |
#include "upap.h" |
#include "chap.h" |
#ifdef CBCP_SUPPORT |
#include "cbcp.h" |
#endif |
#include "pathnames.h" |
|
/* Used for storing a sequence of words. Usually malloced. */ |
struct wordlist { |
struct wordlist *next; |
char word[1]; |
}; |
|
/* Bits in scan_authfile return value */ |
#define NONWILD_SERVER 1 |
#define NONWILD_CLIENT 2 |
|
#define ISWILD(word) (word[0] == '*' && word[1] == 0) |
|
#define FALSE 0 |
#define TRUE 1 |
|
/* The name by which the peer authenticated itself to us. */ |
char peer_authname[MAXNAMELEN]; |
|
/* Records which authentication operations haven't completed yet. */ |
static int auth_pending[NUM_PPP]; |
|
/* Set if we have successfully called plogin() */ |
static int logged_in; |
|
/* Set if we have run the /etc/ppp/auth-up script. */ |
static int did_authup; |
|
/* List of addresses which the peer may use. */ |
static struct wordlist *addresses[NUM_PPP]; |
|
/* Number of network protocols which we have opened. */ |
static int num_np_open; |
|
/* Number of network protocols which have come up. */ |
static int num_np_up; |
|
/* Set if we got the contents of passwd[] from the pap-secrets file. */ |
static int passwd_from_file; |
|
/* Bits in auth_pending[] */ |
#define PAP_WITHPEER 1 |
#define PAP_PEER 2 |
#define CHAP_WITHPEER 4 |
#define CHAP_PEER 8 |
|
extern char *crypt __P((const char *, const char *)); |
|
/* Prototypes for procedures local to this file. */ |
|
static void network_phase __P((int)); |
static void check_idle __P((void *)); |
static void connect_time_expired __P((void *)); |
static int plogin __P((char *, char *, char **, int *)); |
static void plogout __P((void)); |
static int null_login __P((int)); |
static int get_pap_passwd __P((char *)); |
static int have_pap_secret __P((void)); |
static int have_chap_secret __P((char *, char *, u_int32_t)); |
static int ip_addr_check __P((u_int32_t, struct wordlist *)); |
static int scan_authfile __P((FILE *, char *, char *, u_int32_t, char *, |
struct wordlist **, char *)); |
static void free_wordlist __P((struct wordlist *)); |
static void auth_script __P((char *)); |
static void set_allowed_addrs __P((int, struct wordlist *)); |
|
/* |
* An Open on LCP has requested a change from Dead to Establish phase. |
* Do what's necessary to bring the physical layer up. |
*/ |
void |
link_required(unit) |
int unit; |
{ |
} |
|
/* |
* LCP has terminated the link; go to the Dead phase and take the |
* physical layer down. |
*/ |
void |
link_terminated(unit) |
int unit; |
{ |
if (phase == PHASE_DEAD) |
return; |
if (logged_in) |
plogout(); |
phase = PHASE_DEAD; |
syslog(LOG_NOTICE, "Connection terminated."); |
} |
|
/* |
* LCP has gone down; it will either die or try to re-establish. |
*/ |
void |
link_down(unit) |
int unit; |
{ |
int i; |
struct protent *protp; |
|
did_authup = 0; |
for (i = 0; (protp = protocols[i]) != NULL; ++i) { |
if (!protp->enabled_flag) |
continue; |
if (protp->protocol != PPP_LCP && protp->lowerdown != NULL) |
(*protp->lowerdown)(unit); |
if (protp->protocol < 0xC000 && protp->close != NULL) |
(*protp->close)(unit, "LCP down"); |
} |
num_np_open = 0; |
num_np_up = 0; |
if (phase != PHASE_DEAD) |
phase = PHASE_TERMINATE; |
} |
|
/* |
* The link is established. |
* Proceed to the Dead, Authenticate or Network phase as appropriate. |
*/ |
void |
link_established(unit) |
int unit; |
{ |
int auth; |
lcp_options *wo = &lcp_wantoptions[unit]; |
lcp_options *go = &lcp_gotoptions[unit]; |
lcp_options *ho = &lcp_hisoptions[unit]; |
int i; |
struct protent *protp; |
|
/* |
* Tell higher-level protocols that LCP is up. |
*/ |
for (i = 0; (protp = protocols[i]) != NULL; ++i) |
if (protp->protocol != PPP_LCP && protp->enabled_flag |
&& protp->lowerup != NULL) |
(*protp->lowerup)(unit); |
|
if (auth_required && !(go->neg_chap || go->neg_upap)) { |
/* |
* We wanted the peer to authenticate itself, and it refused: |
* treat it as though it authenticated with PAP using a username |
* of "" and a password of "". If that's not OK, boot it out. |
*/ |
if (!wo->neg_upap || !null_login(unit)) { |
lcp_close(unit, "peer refused to authenticate"); |
return; |
} |
} |
|
phase = PHASE_AUTHENTICATE; |
auth = 0; |
if (go->neg_chap) { |
ChapAuthPeer(unit, our_name, go->chap_mdtype); |
auth |= CHAP_PEER; |
} else if (go->neg_upap) { |
upap_authpeer(unit); |
auth |= PAP_PEER; |
} |
if (ho->neg_chap) { |
ChapAuthWithPeer(unit, user, ho->chap_mdtype); |
auth |= CHAP_WITHPEER; |
} else if (ho->neg_upap) { |
if (passwd[0] == 0) { |
passwd_from_file = 1; |
get_pap_passwd(passwd); |
} |
upap_authwithpeer(unit, user, passwd); |
auth |= PAP_WITHPEER; |
} |
auth_pending[unit] = auth; |
|
if (!auth) |
network_phase(unit); |
} |
|
/* |
* Proceed to the network phase. |
*/ |
static void |
network_phase(unit) |
int unit; |
{ |
int i; |
struct protent *protp; |
lcp_options *go = &lcp_gotoptions[unit]; |
|
/* |
* If the peer had to authenticate, run the auth-up script now. |
*/ |
if ((go->neg_chap || go->neg_upap) && !did_authup) { |
auth_script(_PATH_AUTHUP); |
did_authup = 1; |
} |
|
#ifdef CBCP_SUPPORT |
/* |
* If we negotiated callback, do it now. |
*/ |
if (go->neg_cbcp) { |
phase = PHASE_CALLBACK; |
(*cbcp_protent.open)(unit); |
return; |
} |
#endif |
|
phase = PHASE_NETWORK; |
|
for (i = 0; (protp = protocols[i]) != NULL; ++i) |
if (protp->protocol < 0xC000 && protp->enabled_flag |
&& protp->open != NULL) { |
(*protp->open)(unit); |
if (protp->protocol != PPP_CCP) |
++num_np_open; |
} |
|
if (num_np_open == 0) |
/* nothing to do */ |
lcp_close(0, "No network protocols running"); |
} |
|
/* |
* The peer has failed to authenticate himself using `protocol'. |
*/ |
void |
auth_peer_fail(unit, protocol) |
int unit, protocol; |
{ |
/* |
* Authentication failure: take the link down |
*/ |
lcp_close(unit, "Authentication failed"); |
} |
|
/* |
* The peer has been successfully authenticated using `protocol'. |
*/ |
void |
auth_peer_success(unit, protocol, name, namelen) |
int unit, protocol; |
char *name; |
int namelen; |
{ |
int bit; |
|
switch (protocol) { |
case PPP_CHAP: |
bit = CHAP_PEER; |
break; |
case PPP_PAP: |
bit = PAP_PEER; |
break; |
default: |
syslog(LOG_WARNING, "auth_peer_success: unknown protocol %x", |
protocol); |
return; |
} |
|
/* |
* Save the authenticated name of the peer for later. |
*/ |
if (namelen > sizeof(peer_authname) - 1) |
namelen = sizeof(peer_authname) - 1; |
BCOPY(name, peer_authname, namelen); |
peer_authname[namelen] = 0; |
/* |
* If there is no more authentication still to be done, |
* proceed to the network (or callback) phase. |
*/ |
if ((auth_pending[unit] &= ~bit) == 0) |
network_phase(unit); |
} |
|
/* |
* We have failed to authenticate ourselves to the peer using `protocol'. |
*/ |
void |
auth_withpeer_fail(unit, protocol) |
int unit, protocol; |
{ |
if (passwd_from_file) |
BZERO(passwd, MAXSECRETLEN); |
/* |
* We've failed to authenticate ourselves to our peer. |
* He'll probably take the link down, and there's not much |
* we can do except wait for that. |
*/ |
} |
|
/* |
* We have successfully authenticated ourselves with the peer using `protocol'. |
*/ |
void |
auth_withpeer_success(unit, protocol) |
int unit, protocol; |
{ |
int bit; |
|
switch (protocol) { |
case PPP_CHAP: |
bit = CHAP_WITHPEER; |
break; |
case PPP_PAP: |
if (passwd_from_file) |
BZERO(passwd, MAXSECRETLEN); |
bit = PAP_WITHPEER; |
break; |
default: |
|
bit = 0; |
} |
|
/* |
* If there is no more authentication still being done, |
* proceed to the network (or callback) phase. |
*/ |
if ((auth_pending[unit] &= ~bit) == 0) |
network_phase(unit); |
} |
|
|
/* |
* np_up - a network protocol has come up. |
*/ |
void |
np_up(unit, proto) |
int unit, proto; |
{ |
if (num_np_up == 0) { |
/* |
* At this point we consider that the link has come up successfully. |
*/ |
need_holdoff = 0; |
|
if (idle_time_limit > 0) |
TIMEOUT(check_idle, NULL, idle_time_limit); |
|
/* |
* Set a timeout to close the connection once the maximum |
* connect time has expired. |
*/ |
if (maxconnect > 0) |
TIMEOUT(connect_time_expired, 0, maxconnect); |
|
/* |
* Detach now, if the updetach option was given. |
*/ |
if (nodetach == -1) |
detach(); |
} |
++num_np_up; |
} |
|
/* |
* np_down - a network protocol has gone down. |
*/ |
void |
np_down(unit, proto) |
int unit, proto; |
{ |
if (--num_np_up == 0 && idle_time_limit > 0) { |
UNTIMEOUT(check_idle, NULL); |
} |
} |
|
/* |
* np_finished - a network protocol has finished using the link. |
*/ |
void |
np_finished(unit, proto) |
int unit, proto; |
{ |
if (--num_np_open <= 0) { |
/* no further use for the link: shut up shop. */ |
lcp_close(0, "No network protocols running"); |
} |
} |
|
/* |
* check_idle - check whether the link has been idle for long |
* enough that we can shut it down. |
*/ |
static void |
check_idle(arg) |
void *arg; |
{ |
struct ppp_idle idle; |
time_t itime; |
|
if (!get_idle_time(0, &idle)) |
return; |
itime = MIN(idle.xmit_idle, idle.recv_idle); |
if (itime >= idle_time_limit) { |
/* link is idle: shut it down. */ |
syslog(LOG_INFO, "Terminating connection due to lack of activity."); |
lcp_close(0, "Link inactive"); |
} else { |
TIMEOUT(check_idle, NULL, idle_time_limit - itime); |
} |
} |
|
/* |
* connect_time_expired - log a message and close the connection. |
*/ |
static void |
connect_time_expired(arg) |
void *arg; |
{ |
syslog(LOG_INFO, "Connect time expired"); |
lcp_close(0, "Connect time expired"); /* Close connection */ |
} |
|
/* |
* auth_check_options - called to check authentication options. |
*/ |
void |
auth_check_options() |
{ |
lcp_options *wo = &lcp_wantoptions[0]; |
int can_auth; |
ipcp_options *ipwo = &ipcp_wantoptions[0]; |
u_int32_t remote; |
|
/* Default our_name to hostname, and user to our_name */ |
if (our_name[0] == 0 || usehostname) |
strcpy(our_name, hostname); |
if (user[0] == 0) |
strcpy(user, our_name); |
|
/* If authentication is required, ask peer for CHAP or PAP. */ |
if (auth_required && !wo->neg_chap && !wo->neg_upap) { |
wo->neg_chap = 1; |
wo->neg_upap = 1; |
} |
|
/* |
* Check whether we have appropriate secrets to use |
* to authenticate the peer. |
*/ |
can_auth = wo->neg_upap && (uselogin || have_pap_secret()); |
if (!can_auth && wo->neg_chap) { |
remote = ipwo->accept_remote? 0: ipwo->hisaddr; |
can_auth = have_chap_secret(remote_name, our_name, remote); |
} |
|
if (auth_required && !can_auth) { |
option_error("peer authentication required but no suitable secret(s) found\n"); |
if (remote_name[0] == 0) |
option_error("for authenticating any peer to us (%s)\n", our_name); |
else |
option_error("for authenticating peer %s to us (%s)\n", |
remote_name, our_name); |
exit(1); |
} |
|
/* |
* Check whether the user tried to override certain values |
* set by root. |
*/ |
if (!auth_required && auth_req_info.priv > 0) { |
if (!default_device && devnam_info.priv == 0) { |
option_error("can't override device name when noauth option used"); |
exit(1); |
} |
if ((connector != NULL && connector_info.priv == 0) |
|| (disconnector != NULL && disconnector_info.priv == 0) |
|| (welcomer != NULL && welcomer_info.priv == 0)) { |
option_error("can't override connect, disconnect or welcome"); |
option_error("option values when noauth option used"); |
exit(1); |
} |
} |
} |
|
/* |
* auth_reset - called when LCP is starting negotiations to recheck |
* authentication options, i.e. whether we have appropriate secrets |
* to use for authenticating ourselves and/or the peer. |
*/ |
void |
auth_reset(unit) |
int unit; |
{ |
lcp_options *go = &lcp_gotoptions[unit]; |
lcp_options *ao = &lcp_allowoptions[0]; |
ipcp_options *ipwo = &ipcp_wantoptions[0]; |
u_int32_t remote; |
|
ao->neg_upap = !refuse_pap /*&& (passwd[0] != 0 || get_pap_passwd(NULL))*/; |
ao->neg_chap = !refuse_chap |
&& have_chap_secret(user, remote_name, (u_int32_t)0); |
|
if (go->neg_upap && !uselogin && !have_pap_secret()) |
go->neg_upap = 0; |
if (go->neg_chap) { |
remote = ipwo->accept_remote? 0: ipwo->hisaddr; |
if (!have_chap_secret(remote_name, our_name, remote)) |
go->neg_chap = 0; |
} |
} |
|
|
/* |
* check_passwd - Check the user name and passwd against the PAP secrets |
* file. If requested, also check against the system password database, |
* and login the user if OK. |
* |
* returns: |
* UPAP_AUTHNAK: Authentication failed. |
* UPAP_AUTHACK: Authentication succeeded. |
* In either case, msg points to an appropriate message. |
*/ |
int |
check_passwd(unit, auser, userlen, apasswd, passwdlen, msg, msglen) |
int unit; |
char *auser; |
int userlen; |
char *apasswd; |
int passwdlen; |
char **msg; |
int *msglen; |
{ |
|
|
return UPAP_AUTHNAK; |
} |
|
|
/* |
* plogin - Check the user name and password against the system |
* password database, and login the user if OK. |
* |
* returns: |
* UPAP_AUTHNAK: Login failed. |
* UPAP_AUTHACK: Login succeeded. |
* In either case, msg points to an appropriate message. |
*/ |
|
static int |
plogin(user, passwd, msg, msglen) |
char *user; |
char *passwd; |
char **msg; |
int *msglen; |
{ |
syslog(LOG_INFO, "user %s logged in", user); |
logged_in = TRUE; |
|
return (UPAP_AUTHACK); |
} |
|
/* |
* plogout - Logout the user. |
*/ |
static void |
plogout() |
{ |
|
logged_in = FALSE; |
} |
|
|
/* |
* null_login - Check if a username of "" and a password of "" are |
* acceptable, and iff so, set the list of acceptable IP addresses |
* and return 1. |
*/ |
static int |
null_login(unit) |
int unit; |
{ |
return 1; |
} |
|
|
/* |
* get_pap_passwd - get a password for authenticating ourselves with |
* our peer using PAP. Returns 1 on success, 0 if no suitable password |
* could be found. |
*/ |
|
static int |
get_pap_passwd(passwd) |
char *passwd; |
{ |
#if 0 |
/* XXX PPPConfiguration */ |
GlobalSystemStatus *stat; |
stat=LockSTBSystemParam(); |
strncpy(passwd, stat->PPP_Password, MAXSECRETLEN); |
UnlockSTBSystemParam(); |
#endif |
return 1; |
} |
|
|
/* |
* have_pap_secret - check whether we have a PAP file with any |
* secrets that we could possibly use for authenticating the peer. |
*/ |
static int |
have_pap_secret() |
{ |
return 1; |
} |
|
|
/* |
* have_chap_secret - check whether we have a CHAP file with a |
* secret that we could possibly use for authenticating `client' |
* on `server'. Either can be the null string, meaning we don't |
* know the identity yet. |
*/ |
static int |
have_chap_secret(client, server, remote) |
char *client; |
char *server; |
u_int32_t remote; |
{ |
|
return 1; |
} |
|
|
/* |
* get_secret - open the CHAP secret file and return the secret |
* for authenticating the given client on the given server. |
* (We could be either client or server). |
*/ |
int |
get_secret(unit, client, server, secret, secret_len, save_addrs) |
int unit; |
char *client; |
char *server; |
char *secret; |
int *secret_len; |
int save_addrs; |
{ |
#if 0 |
/* XXX PPPConfiguration */ |
int len; |
GlobalSystemStatus *stat; |
stat=LockSTBSystemParam(); |
len=strlen(stat->PPP_Password); |
strcpy( secret,stat->PPP_Password); |
UnlockSTBSystemParam(); |
|
*secret_len = len; |
#endif |
return 1; |
} |
|
/* |
* set_allowed_addrs() - set the list of allowed addresses. |
*/ |
static void |
set_allowed_addrs(unit, addrs) |
int unit; |
struct wordlist *addrs; |
{ |
|
} |
|
/* |
* auth_ip_addr - check whether the peer is authorized to use |
* a given IP address. Returns 1 if authorized, 0 otherwise. |
*/ |
int |
auth_ip_addr(unit, addr) |
int unit; |
u_int32_t addr; |
{ |
return ip_addr_check(addr, addresses[unit]); |
} |
|
static int |
ip_addr_check(addr, addrs) |
u_int32_t addr; |
struct wordlist *addrs; |
{ |
#if 0 |
u_int32_t a, mask, ah; |
int accept; |
char *ptr_word, *ptr_mask; |
struct hostent *hp; |
struct netent *np; |
#endif |
|
/* don't allow loopback or multicast address */ |
if (bad_ip_adrs(addr)) |
return 0; |
|
if (addrs == NULL) |
return !auth_required; /* no addresses authorized */ |
|
return 1; |
} |
|
/* |
* bad_ip_adrs - return 1 if the IP address is one we don't want |
* to use, such as an address in the loopback net or a multicast address. |
* addr is in network byte order. |
*/ |
int |
bad_ip_adrs(addr) |
u_int32_t addr; |
{ |
addr = ntohl(addr); |
return (addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET |
|| IN_MULTICAST(addr) || IN_BADCLASS(addr); |
} |
|
/* |
* check_access - complain if a secret file has too-liberal permissions. |
*/ |
void |
check_access(f, filename) |
FILE *f; |
char *filename; |
{ |
|
} |
|
|
/* |
* scan_authfile - Scan an authorization file for a secret suitable |
* for authenticating `client' on `server'. The return value is -1 |
* if no secret is found, otherwise >= 0. The return value has |
* NONWILD_CLIENT set if the secret didn't have "*" for the client, and |
* NONWILD_SERVER set if the secret didn't have "*" for the server. |
* Any following words on the line (i.e. address authorization |
* info) are placed in a wordlist and returned in *addrs. |
*/ |
static int |
scan_authfile(f, client, server, ipaddr, secret, addrs, filename) |
FILE *f; |
char *client; |
char *server; |
u_int32_t ipaddr; |
char *secret; |
struct wordlist **addrs; |
char *filename; |
{ |
|
return -1; |
} |
|
/* |
* free_wordlist - release memory allocated for a wordlist. |
*/ |
static void |
free_wordlist(wp) |
struct wordlist *wp; |
{ |
struct wordlist *next; |
|
while (wp != NULL) { |
next = wp->next; |
free(wp); |
wp = next; |
} |
} |
|
/* |
* auth_script - execute a script with arguments |
* interface-name peer-name real-user tty speed |
*/ |
static void |
auth_script(script) |
char *script; |
{ |
} |
/ccp.c
0,0 → 1,1117
/* |
* ccp.c - PPP Compression Control Protocol. |
* |
* Copyright (c) 1994 The Australian National University. |
* All rights reserved. |
* |
* Permission to use, copy, modify, and distribute this software and its |
* documentation is hereby granted, provided that the above copyright |
* notice appears in all copies. This software is provided without any |
* warranty, express or implied. The Australian National University |
* makes no representations about the suitability of this software for |
* any purpose. |
* |
* IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY |
* PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF |
* THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY |
* OF SUCH DAMAGE. |
* |
* THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, |
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY |
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
* ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO |
* OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, |
* OR MODIFICATIONS. |
*/ |
|
#ifndef lint |
/* static char rcsid[] = "$Id: ccp.c,v 1.2 2001-09-27 12:01:57 chris Exp $"; */ |
#endif |
|
#include <string.h> |
#include <syslog.h> |
#include <sys/ioctl.h> |
#include <sys/types.h> |
|
#include "pppd.h" |
#include "fsm.h" |
#include "ccp.h" |
#include <net/ppp-comp.h> |
|
/* |
* Protocol entry points from main code. |
*/ |
static void ccp_init __P((int unit)); |
static void ccp_open __P((int unit)); |
static void ccp_close __P((int unit, char *)); |
static void ccp_lowerup __P((int unit)); |
static void ccp_lowerdown __P((int)); |
static void ccp_input __P((int unit, u_char *pkt, int len)); |
static void ccp_protrej __P((int unit)); |
static int ccp_printpkt __P((u_char *pkt, int len, |
void (*printer) __P((void *, char *, ...)), |
void *arg)); |
static void ccp_datainput __P((int unit, u_char *pkt, int len)); |
|
struct protent ccp_protent = { |
PPP_CCP, |
ccp_init, |
ccp_input, |
ccp_protrej, |
ccp_lowerup, |
ccp_lowerdown, |
ccp_open, |
ccp_close, |
ccp_printpkt, |
ccp_datainput, |
1, |
"CCP", |
NULL, |
NULL, |
NULL |
}; |
|
fsm ccp_fsm[NUM_PPP]; |
ccp_options ccp_wantoptions[NUM_PPP]; /* what to request the peer to use */ |
ccp_options ccp_gotoptions[NUM_PPP]; /* what the peer agreed to do */ |
ccp_options ccp_allowoptions[NUM_PPP]; /* what we'll agree to do */ |
ccp_options ccp_hisoptions[NUM_PPP]; /* what we agreed to do */ |
|
/* |
* Callbacks for fsm code. |
*/ |
static void ccp_resetci __P((fsm *)); |
static int ccp_cilen __P((fsm *)); |
static void ccp_addci __P((fsm *, u_char *, int *)); |
static int ccp_ackci __P((fsm *, u_char *, int)); |
static int ccp_nakci __P((fsm *, u_char *, int)); |
static int ccp_rejci __P((fsm *, u_char *, int)); |
static int ccp_reqci __P((fsm *, u_char *, int *, int)); |
static void ccp_up __P((fsm *)); |
static void ccp_down __P((fsm *)); |
static int ccp_extcode __P((fsm *, int, int, u_char *, int)); |
static void ccp_rack_timeout __P((void *)); |
static char *method_name __P((ccp_options *, ccp_options *)); |
|
static fsm_callbacks ccp_callbacks = { |
ccp_resetci, |
ccp_cilen, |
ccp_addci, |
ccp_ackci, |
ccp_nakci, |
ccp_rejci, |
ccp_reqci, |
ccp_up, |
ccp_down, |
NULL, |
NULL, |
NULL, |
NULL, |
ccp_extcode, |
"CCP" |
}; |
|
/* |
* Do we want / did we get any compression? |
*/ |
#define ANY_COMPRESS(opt) ((opt).deflate || (opt).bsd_compress \ |
|| (opt).predictor_1 || (opt).predictor_2) |
|
/* |
* Local state (mainly for handling reset-reqs and reset-acks). |
*/ |
static int ccp_localstate[NUM_PPP]; |
#define RACK_PENDING 1 /* waiting for reset-ack */ |
#define RREQ_REPEAT 2 /* send another reset-req if no reset-ack */ |
|
#define RACKTIMEOUT 1 /* second */ |
|
static int all_rejected[NUM_PPP]; /* we rejected all peer's options */ |
|
/* |
* ccp_init - initialize CCP. |
*/ |
static void |
ccp_init(unit) |
int unit; |
{ |
fsm *f = &ccp_fsm[unit]; |
|
f->unit = unit; |
f->protocol = PPP_CCP; |
f->callbacks = &ccp_callbacks; |
fsm_init(f); |
|
memset(&ccp_wantoptions[unit], 0, sizeof(ccp_options)); |
memset(&ccp_gotoptions[unit], 0, sizeof(ccp_options)); |
memset(&ccp_allowoptions[unit], 0, sizeof(ccp_options)); |
memset(&ccp_hisoptions[unit], 0, sizeof(ccp_options)); |
|
ccp_wantoptions[0].deflate = 1; |
ccp_wantoptions[0].deflate_size = DEFLATE_MAX_SIZE; |
ccp_wantoptions[0].deflate_correct = 1; |
ccp_wantoptions[0].deflate_draft = 1; |
ccp_allowoptions[0].deflate = 1; |
ccp_allowoptions[0].deflate_size = DEFLATE_MAX_SIZE; |
ccp_allowoptions[0].deflate_correct = 1; |
ccp_allowoptions[0].deflate_draft = 1; |
|
ccp_wantoptions[0].bsd_compress = 1; |
ccp_wantoptions[0].bsd_bits = BSD_MAX_BITS; |
ccp_allowoptions[0].bsd_compress = 1; |
ccp_allowoptions[0].bsd_bits = BSD_MAX_BITS; |
|
ccp_allowoptions[0].predictor_1 = 1; |
} |
|
/* |
* ccp_open - CCP is allowed to come up. |
*/ |
static void |
ccp_open(unit) |
int unit; |
{ |
fsm *f = &ccp_fsm[unit]; |
|
if (f->state != OPENED) |
ccp_flags_set(unit, 1, 0); |
|
/* |
* Find out which compressors the kernel supports before |
* deciding whether to open in silent mode. |
*/ |
ccp_resetci(f); |
if (!ANY_COMPRESS(ccp_gotoptions[unit])) |
f->flags |= OPT_SILENT; |
|
fsm_open(f); |
} |
|
/* |
* ccp_close - Terminate CCP. |
*/ |
static void |
ccp_close(unit, reason) |
int unit; |
char *reason; |
{ |
ccp_flags_set(unit, 0, 0); |
fsm_close(&ccp_fsm[unit], reason); |
} |
|
/* |
* ccp_lowerup - we may now transmit CCP packets. |
*/ |
static void |
ccp_lowerup(unit) |
int unit; |
{ |
fsm_lowerup(&ccp_fsm[unit]); |
} |
|
/* |
* ccp_lowerdown - we may not transmit CCP packets. |
*/ |
static void |
ccp_lowerdown(unit) |
int unit; |
{ |
fsm_lowerdown(&ccp_fsm[unit]); |
} |
|
/* |
* ccp_input - process a received CCP packet. |
*/ |
static void |
ccp_input(unit, p, len) |
int unit; |
u_char *p; |
int len; |
{ |
fsm *f = &ccp_fsm[unit]; |
int oldstate; |
|
/* |
* Check for a terminate-request so we can print a message. |
*/ |
oldstate = f->state; |
fsm_input(f, p, len); |
if (oldstate == OPENED && p[0] == TERMREQ && f->state != OPENED); |
syslog(LOG_NOTICE, "Compression disabled by peer."); |
|
/* |
* If we get a terminate-ack and we're not asking for compression, |
* close CCP. |
*/ |
if (oldstate == REQSENT && p[0] == TERMACK |
&& !ANY_COMPRESS(ccp_gotoptions[unit])) |
ccp_close(unit, "No compression negotiated"); |
} |
|
/* |
* Handle a CCP-specific code. |
*/ |
static int |
ccp_extcode(f, code, id, p, len) |
fsm *f; |
int code, id; |
u_char *p; |
int len; |
{ |
switch (code) { |
case CCP_RESETREQ: |
if (f->state != OPENED) |
break; |
/* send a reset-ack, which the transmitter will see and |
reset its compression state. */ |
fsm_sdata(f, CCP_RESETACK, id, NULL, 0); |
break; |
|
case CCP_RESETACK: |
if (ccp_localstate[f->unit] & RACK_PENDING && id == f->reqid) { |
ccp_localstate[f->unit] &= ~(RACK_PENDING | RREQ_REPEAT); |
UNTIMEOUT(ccp_rack_timeout, f); |
} |
break; |
|
default: |
return 0; |
} |
|
return 1; |
} |
|
/* |
* ccp_protrej - peer doesn't talk CCP. |
*/ |
static void |
ccp_protrej(unit) |
int unit; |
{ |
ccp_flags_set(unit, 0, 0); |
fsm_lowerdown(&ccp_fsm[unit]); |
} |
|
/* |
* ccp_resetci - initialize at start of negotiation. |
*/ |
static void |
ccp_resetci(f) |
fsm *f; |
{ |
ccp_options *go = &ccp_gotoptions[f->unit]; |
u_char opt_buf[16]; |
|
*go = ccp_wantoptions[f->unit]; |
all_rejected[f->unit] = 0; |
|
/* |
* Check whether the kernel knows about the various |
* compression methods we might request. |
*/ |
if (go->bsd_compress) { |
opt_buf[0] = CI_BSD_COMPRESS; |
opt_buf[1] = CILEN_BSD_COMPRESS; |
opt_buf[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, BSD_MIN_BITS); |
if (ccp_test(f->unit, opt_buf, CILEN_BSD_COMPRESS, 0) <= 0) |
go->bsd_compress = 0; |
} |
if (go->deflate) { |
if (go->deflate_correct) { |
opt_buf[0] = CI_DEFLATE; |
opt_buf[1] = CILEN_DEFLATE; |
opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_SIZE); |
opt_buf[3] = DEFLATE_CHK_SEQUENCE; |
if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE, 0) <= 0) |
go->deflate_correct = 0; |
} |
if (go->deflate_draft) { |
opt_buf[0] = CI_DEFLATE_DRAFT; |
opt_buf[1] = CILEN_DEFLATE; |
opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_SIZE); |
opt_buf[3] = DEFLATE_CHK_SEQUENCE; |
if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE, 0) <= 0) |
go->deflate_draft = 0; |
} |
if (!go->deflate_correct && !go->deflate_draft) |
go->deflate = 0; |
} |
if (go->predictor_1) { |
opt_buf[0] = CI_PREDICTOR_1; |
opt_buf[1] = CILEN_PREDICTOR_1; |
if (ccp_test(f->unit, opt_buf, CILEN_PREDICTOR_1, 0) <= 0) |
go->predictor_1 = 0; |
} |
if (go->predictor_2) { |
opt_buf[0] = CI_PREDICTOR_2; |
opt_buf[1] = CILEN_PREDICTOR_2; |
if (ccp_test(f->unit, opt_buf, CILEN_PREDICTOR_2, 0) <= 0) |
go->predictor_2 = 0; |
} |
} |
|
/* |
* ccp_cilen - Return total length of our configuration info. |
*/ |
static int |
ccp_cilen(f) |
fsm *f; |
{ |
ccp_options *go = &ccp_gotoptions[f->unit]; |
|
return (go->bsd_compress? CILEN_BSD_COMPRESS: 0) |
+ (go->deflate? CILEN_DEFLATE: 0) |
+ (go->predictor_1? CILEN_PREDICTOR_1: 0) |
+ (go->predictor_2? CILEN_PREDICTOR_2: 0); |
} |
|
/* |
* ccp_addci - put our requests in a packet. |
*/ |
static void |
ccp_addci(f, p, lenp) |
fsm *f; |
u_char *p; |
int *lenp; |
{ |
int res; |
ccp_options *go = &ccp_gotoptions[f->unit]; |
u_char *p0 = p; |
|
/* |
* Add the compression types that we can receive, in decreasing |
* preference order. Get the kernel to allocate the first one |
* in case it gets Acked. |
*/ |
if (go->deflate) { |
p[0] = go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT; |
p[1] = CILEN_DEFLATE; |
p[2] = DEFLATE_MAKE_OPT(go->deflate_size); |
p[3] = DEFLATE_CHK_SEQUENCE; |
for (;;) { |
res = ccp_test(f->unit, p, CILEN_DEFLATE, 0); |
if (res > 0) { |
p += CILEN_DEFLATE; |
break; |
} |
if (res < 0 || go->deflate_size <= DEFLATE_MIN_SIZE) { |
go->deflate = 0; |
break; |
} |
--go->deflate_size; |
p[2] = DEFLATE_MAKE_OPT(go->deflate_size); |
} |
if (p != p0 && go->deflate_correct && go->deflate_draft) { |
p[0] = CI_DEFLATE_DRAFT; |
p[1] = CILEN_DEFLATE; |
p[2] = p[2 - CILEN_DEFLATE]; |
p[3] = DEFLATE_CHK_SEQUENCE; |
p += CILEN_DEFLATE; |
} |
} |
if (go->bsd_compress) { |
p[0] = CI_BSD_COMPRESS; |
p[1] = CILEN_BSD_COMPRESS; |
p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits); |
if (p != p0) { |
p += CILEN_BSD_COMPRESS; /* not the first option */ |
} else { |
for (;;) { |
res = ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 0); |
if (res > 0) { |
p += CILEN_BSD_COMPRESS; |
break; |
} |
if (res < 0 || go->bsd_bits <= BSD_MIN_BITS) { |
go->bsd_compress = 0; |
break; |
} |
--go->bsd_bits; |
p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits); |
} |
} |
} |
/* XXX Should Predictor 2 be preferable to Predictor 1? */ |
if (go->predictor_1) { |
p[0] = CI_PREDICTOR_1; |
p[1] = CILEN_PREDICTOR_1; |
if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_1, 0) <= 0) { |
go->predictor_1 = 0; |
} else { |
p += CILEN_PREDICTOR_1; |
} |
} |
if (go->predictor_2) { |
p[0] = CI_PREDICTOR_2; |
p[1] = CILEN_PREDICTOR_2; |
if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_2, 0) <= 0) { |
go->predictor_2 = 0; |
} else { |
p += CILEN_PREDICTOR_2; |
} |
} |
|
go->method = (p > p0)? p0[0]: -1; |
|
*lenp = p - p0; |
} |
|
/* |
* ccp_ackci - process a received configure-ack, and return |
* 1 iff the packet was OK. |
*/ |
static int |
ccp_ackci(f, p, len) |
fsm *f; |
u_char *p; |
int len; |
{ |
ccp_options *go = &ccp_gotoptions[f->unit]; |
u_char *p0 = p; |
|
if (go->deflate) { |
if (len < CILEN_DEFLATE |
|| p[0] != (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT) |
|| p[1] != CILEN_DEFLATE |
|| p[2] != DEFLATE_MAKE_OPT(go->deflate_size) |
|| p[3] != DEFLATE_CHK_SEQUENCE) |
return 0; |
p += CILEN_DEFLATE; |
len -= CILEN_DEFLATE; |
/* XXX Cope with first/fast ack */ |
if (len == 0) |
return 1; |
if (go->deflate_correct && go->deflate_draft) { |
if (len < CILEN_DEFLATE |
|| p[0] != CI_DEFLATE_DRAFT |
|| p[1] != CILEN_DEFLATE |
|| p[2] != DEFLATE_MAKE_OPT(go->deflate_size) |
|| p[3] != DEFLATE_CHK_SEQUENCE) |
return 0; |
p += CILEN_DEFLATE; |
len -= CILEN_DEFLATE; |
} |
} |
if (go->bsd_compress) { |
if (len < CILEN_BSD_COMPRESS |
|| p[0] != CI_BSD_COMPRESS || p[1] != CILEN_BSD_COMPRESS |
|| p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits)) |
return 0; |
p += CILEN_BSD_COMPRESS; |
len -= CILEN_BSD_COMPRESS; |
/* XXX Cope with first/fast ack */ |
if (p == p0 && len == 0) |
return 1; |
} |
if (go->predictor_1) { |
if (len < CILEN_PREDICTOR_1 |
|| p[0] != CI_PREDICTOR_1 || p[1] != CILEN_PREDICTOR_1) |
return 0; |
p += CILEN_PREDICTOR_1; |
len -= CILEN_PREDICTOR_1; |
/* XXX Cope with first/fast ack */ |
if (p == p0 && len == 0) |
return 1; |
} |
if (go->predictor_2) { |
if (len < CILEN_PREDICTOR_2 |
|| p[0] != CI_PREDICTOR_2 || p[1] != CILEN_PREDICTOR_2) |
return 0; |
p += CILEN_PREDICTOR_2; |
len -= CILEN_PREDICTOR_2; |
/* XXX Cope with first/fast ack */ |
if (p == p0 && len == 0) |
return 1; |
} |
|
if (len != 0) |
return 0; |
return 1; |
} |
|
/* |
* ccp_nakci - process received configure-nak. |
* Returns 1 iff the nak was OK. |
*/ |
static int |
ccp_nakci(f, p, len) |
fsm *f; |
u_char *p; |
int len; |
{ |
ccp_options *go = &ccp_gotoptions[f->unit]; |
ccp_options no; /* options we've seen already */ |
ccp_options try; /* options to ask for next time */ |
|
memset(&no, 0, sizeof(no)); |
try = *go; |
|
if (go->deflate && len >= CILEN_DEFLATE |
&& p[0] == (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT) |
&& p[1] == CILEN_DEFLATE) { |
no.deflate = 1; |
/* |
* Peer wants us to use a different code size or something. |
* Stop asking for Deflate if we don't understand his suggestion. |
*/ |
if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL |
|| DEFLATE_SIZE(p[2]) < DEFLATE_MIN_SIZE |
|| p[3] != DEFLATE_CHK_SEQUENCE) |
try.deflate = 0; |
else if (DEFLATE_SIZE(p[2]) < go->deflate_size) |
try.deflate_size = DEFLATE_SIZE(p[2]); |
p += CILEN_DEFLATE; |
len -= CILEN_DEFLATE; |
if (go->deflate_correct && go->deflate_draft |
&& len >= CILEN_DEFLATE && p[0] == CI_DEFLATE_DRAFT |
&& p[1] == CILEN_DEFLATE) { |
p += CILEN_DEFLATE; |
len -= CILEN_DEFLATE; |
} |
} |
|
if (go->bsd_compress && len >= CILEN_BSD_COMPRESS |
&& p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) { |
no.bsd_compress = 1; |
/* |
* Peer wants us to use a different number of bits |
* or a different version. |
*/ |
if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION) |
try.bsd_compress = 0; |
else if (BSD_NBITS(p[2]) < go->bsd_bits) |
try.bsd_bits = BSD_NBITS(p[2]); |
p += CILEN_BSD_COMPRESS; |
len -= CILEN_BSD_COMPRESS; |
} |
|
/* |
* Predictor-1 and 2 have no options, so they can't be Naked. |
* |
* XXX What should we do with any remaining options? |
*/ |
|
if (len != 0) |
return 0; |
|
if (f->state != OPENED) |
*go = try; |
return 1; |
} |
|
/* |
* ccp_rejci - reject some of our suggested compression methods. |
*/ |
static int |
ccp_rejci(f, p, len) |
fsm *f; |
u_char *p; |
int len; |
{ |
ccp_options *go = &ccp_gotoptions[f->unit]; |
ccp_options try; /* options to request next time */ |
|
try = *go; |
|
/* |
* Cope with empty configure-rejects by ceasing to send |
* configure-requests. |
*/ |
if (len == 0 && all_rejected[f->unit]) |
return -1; |
|
if (go->deflate && len >= CILEN_DEFLATE |
&& p[0] == (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT) |
&& p[1] == CILEN_DEFLATE) { |
if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size) |
|| p[3] != DEFLATE_CHK_SEQUENCE) |
return 0; /* Rej is bad */ |
if (go->deflate_correct) |
try.deflate_correct = 0; |
else |
try.deflate_draft = 0; |
p += CILEN_DEFLATE; |
len -= CILEN_DEFLATE; |
if (go->deflate_correct && go->deflate_draft |
&& len >= CILEN_DEFLATE && p[0] == CI_DEFLATE_DRAFT |
&& p[1] == CILEN_DEFLATE) { |
if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size) |
|| p[3] != DEFLATE_CHK_SEQUENCE) |
return 0; /* Rej is bad */ |
try.deflate_draft = 0; |
p += CILEN_DEFLATE; |
len -= CILEN_DEFLATE; |
} |
if (!try.deflate_correct && !try.deflate_draft) |
try.deflate = 0; |
} |
if (go->bsd_compress && len >= CILEN_BSD_COMPRESS |
&& p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) { |
if (p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits)) |
return 0; |
try.bsd_compress = 0; |
p += CILEN_BSD_COMPRESS; |
len -= CILEN_BSD_COMPRESS; |
} |
if (go->predictor_1 && len >= CILEN_PREDICTOR_1 |
&& p[0] == CI_PREDICTOR_1 && p[1] == CILEN_PREDICTOR_1) { |
try.predictor_1 = 0; |
p += CILEN_PREDICTOR_1; |
len -= CILEN_PREDICTOR_1; |
} |
if (go->predictor_2 && len >= CILEN_PREDICTOR_2 |
&& p[0] == CI_PREDICTOR_2 && p[1] == CILEN_PREDICTOR_2) { |
try.predictor_2 = 0; |
p += CILEN_PREDICTOR_2; |
len -= CILEN_PREDICTOR_2; |
} |
|
if (len != 0) |
return 0; |
|
if (f->state != OPENED) |
*go = try; |
|
return 1; |
} |
|
/* |
* ccp_reqci - processed a received configure-request. |
* Returns CONFACK, CONFNAK or CONFREJ and the packet modified |
* appropriately. |
*/ |
static int |
ccp_reqci(f, p, lenp, dont_nak) |
fsm *f; |
u_char *p; |
int *lenp; |
int dont_nak; |
{ |
int ret, newret, res; |
u_char *p0, *retp; |
int len, clen, type, nb; |
ccp_options *ho = &ccp_hisoptions[f->unit]; |
ccp_options *ao = &ccp_allowoptions[f->unit]; |
|
ret = CONFACK; |
retp = p0 = p; |
len = *lenp; |
|
memset(ho, 0, sizeof(ccp_options)); |
ho->method = (len > 0)? p[0]: -1; |
|
while (len > 0) { |
newret = CONFACK; |
if (len < 2 || p[1] < 2 || p[1] > len) { |
/* length is bad */ |
clen = len; |
newret = CONFREJ; |
|
} else { |
type = p[0]; |
clen = p[1]; |
|
switch (type) { |
case CI_DEFLATE: |
case CI_DEFLATE_DRAFT: |
if (!ao->deflate || clen != CILEN_DEFLATE |
|| (!ao->deflate_correct && type == CI_DEFLATE) |
|| (!ao->deflate_draft && type == CI_DEFLATE_DRAFT)) { |
newret = CONFREJ; |
break; |
} |
|
ho->deflate = 1; |
ho->deflate_size = nb = DEFLATE_SIZE(p[2]); |
if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL |
|| p[3] != DEFLATE_CHK_SEQUENCE |
|| nb > ao->deflate_size || nb < DEFLATE_MIN_SIZE) { |
newret = CONFNAK; |
if (!dont_nak) { |
p[2] = DEFLATE_MAKE_OPT(ao->deflate_size); |
p[3] = DEFLATE_CHK_SEQUENCE; |
/* fall through to test this #bits below */ |
} else |
break; |
} |
|
/* |
* Check whether we can do Deflate with the window |
* size they want. If the window is too big, reduce |
* it until the kernel can cope and nak with that. |
* We only check this for the first option. |
*/ |
if (p == p0) { |
for (;;) { |
res = ccp_test(f->unit, p, CILEN_DEFLATE, 1); |
if (res > 0) |
break; /* it's OK now */ |
if (res < 0 || nb == DEFLATE_MIN_SIZE || dont_nak) { |
newret = CONFREJ; |
p[2] = DEFLATE_MAKE_OPT(ho->deflate_size); |
break; |
} |
newret = CONFNAK; |
--nb; |
p[2] = DEFLATE_MAKE_OPT(nb); |
} |
} |
break; |
|
case CI_BSD_COMPRESS: |
if (!ao->bsd_compress || clen != CILEN_BSD_COMPRESS) { |
newret = CONFREJ; |
break; |
} |
|
ho->bsd_compress = 1; |
ho->bsd_bits = nb = BSD_NBITS(p[2]); |
if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION |
|| nb > ao->bsd_bits || nb < BSD_MIN_BITS) { |
newret = CONFNAK; |
if (!dont_nak) { |
p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, ao->bsd_bits); |
/* fall through to test this #bits below */ |
} else |
break; |
} |
|
/* |
* Check whether we can do BSD-Compress with the code |
* size they want. If the code size is too big, reduce |
* it until the kernel can cope and nak with that. |
* We only check this for the first option. |
*/ |
if (p == p0) { |
for (;;) { |
res = ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 1); |
if (res > 0) |
break; |
if (res < 0 || nb == BSD_MIN_BITS || dont_nak) { |
newret = CONFREJ; |
p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, |
ho->bsd_bits); |
break; |
} |
newret = CONFNAK; |
--nb; |
p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb); |
} |
} |
break; |
|
case CI_PREDICTOR_1: |
if (!ao->predictor_1 || clen != CILEN_PREDICTOR_1) { |
newret = CONFREJ; |
break; |
} |
|
ho->predictor_1 = 1; |
if (p == p0 |
&& ccp_test(f->unit, p, CILEN_PREDICTOR_1, 1) <= 0) { |
newret = CONFREJ; |
} |
break; |
|
case CI_PREDICTOR_2: |
if (!ao->predictor_2 || clen != CILEN_PREDICTOR_2) { |
newret = CONFREJ; |
break; |
} |
|
ho->predictor_2 = 1; |
if (p == p0 |
&& ccp_test(f->unit, p, CILEN_PREDICTOR_2, 1) <= 0) { |
newret = CONFREJ; |
} |
break; |
|
default: |
newret = CONFREJ; |
} |
} |
|
if (newret == CONFNAK && dont_nak) |
newret = CONFREJ; |
if (!(newret == CONFACK || (newret == CONFNAK && ret == CONFREJ))) { |
/* we're returning this option */ |
if (newret == CONFREJ && ret == CONFNAK) |
retp = p0; |
ret = newret; |
if (p != retp) |
BCOPY(p, retp, clen); |
retp += clen; |
} |
|
p += clen; |
len -= clen; |
} |
|
if (ret != CONFACK) { |
if (ret == CONFREJ && *lenp == retp - p0) |
all_rejected[f->unit] = 1; |
else |
*lenp = retp - p0; |
} |
return ret; |
} |
|
/* |
* Make a string name for a compression method (or 2). |
*/ |
static char * |
method_name(opt, opt2) |
ccp_options *opt, *opt2; |
{ |
static char result[64]; |
|
if (!ANY_COMPRESS(*opt)) |
return "(none)"; |
switch (opt->method) { |
case CI_DEFLATE: |
case CI_DEFLATE_DRAFT: |
if (opt2 != NULL && opt2->deflate_size != opt->deflate_size) |
sprintf(result, "Deflate%s (%d/%d)", |
(opt->method == CI_DEFLATE_DRAFT? "(old#)": ""), |
opt->deflate_size, opt2->deflate_size); |
else |
sprintf(result, "Deflate%s (%d)", |
(opt->method == CI_DEFLATE_DRAFT? "(old#)": ""), |
opt->deflate_size); |
break; |
case CI_BSD_COMPRESS: |
if (opt2 != NULL && opt2->bsd_bits != opt->bsd_bits) |
sprintf(result, "BSD-Compress (%d/%d)", opt->bsd_bits, |
opt2->bsd_bits); |
else |
sprintf(result, "BSD-Compress (%d)", opt->bsd_bits); |
break; |
case CI_PREDICTOR_1: |
return "Predictor 1"; |
case CI_PREDICTOR_2: |
return "Predictor 2"; |
default: |
sprintf(result, "Method %d", opt->method); |
} |
return result; |
} |
|
/* |
* CCP has come up - inform the kernel driver and log a message. |
*/ |
static void |
ccp_up(f) |
fsm *f; |
{ |
ccp_options *go = &ccp_gotoptions[f->unit]; |
ccp_options *ho = &ccp_hisoptions[f->unit]; |
char method1[64]; |
|
ccp_flags_set(f->unit, 1, 1); |
if (ANY_COMPRESS(*go)) { |
if (ANY_COMPRESS(*ho)) { |
if (go->method == ho->method) { |
syslog(LOG_NOTICE, "%s compression enabled", |
method_name(go, ho)) |
; |
} else { |
strcpy(method1, method_name(go, NULL)); |
syslog(LOG_NOTICE, "%s / %s compression enabled", |
method1, method_name(ho, NULL)) |
; |
} |
} else |
syslog(LOG_NOTICE, "%s receive compression enabled", |
method_name(go, NULL)) |
; |
} else if (ANY_COMPRESS(*ho)) |
syslog(LOG_NOTICE, "%s transmit compression enabled", |
method_name(ho, NULL)) |
; |
} |
|
/* |
* CCP has gone down - inform the kernel driver. |
*/ |
static void |
ccp_down(f) |
fsm *f; |
{ |
if (ccp_localstate[f->unit] & RACK_PENDING) |
UNTIMEOUT(ccp_rack_timeout, f); |
ccp_localstate[f->unit] = 0; |
ccp_flags_set(f->unit, 1, 0); |
} |
|
/* |
* Print the contents of a CCP packet. |
*/ |
static char *ccp_codenames[] = { |
"ConfReq", "ConfAck", "ConfNak", "ConfRej", |
"TermReq", "TermAck", "CodeRej", |
NULL, NULL, NULL, NULL, NULL, NULL, |
"ResetReq", "ResetAck", |
}; |
|
static int |
ccp_printpkt(p, plen, printer, arg) |
u_char *p; |
int plen; |
void (*printer) __P((void *, char *, ...)); |
void *arg; |
{ |
u_char *p0, *optend; |
int code, id, len; |
int optlen; |
|
p0 = p; |
if (plen < HEADERLEN) |
return 0; |
code = p[0]; |
id = p[1]; |
len = (p[2] << 8) + p[3]; |
if (len < HEADERLEN || len > plen) |
return 0; |
|
if (code >= 1 && code <= sizeof(ccp_codenames) / sizeof(char *) |
&& ccp_codenames[code-1] != NULL) |
printer(arg, " %s", ccp_codenames[code-1]); |
else |
printer(arg, " code=0x%x", code); |
printer(arg, " id=0x%x", id); |
len -= HEADERLEN; |
p += HEADERLEN; |
|
switch (code) { |
case CONFREQ: |
case CONFACK: |
case CONFNAK: |
case CONFREJ: |
/* print list of possible compression methods */ |
while (len >= 2) { |
code = p[0]; |
optlen = p[1]; |
if (optlen < 2 || optlen > len) |
break; |
printer(arg, " <"); |
len -= optlen; |
optend = p + optlen; |
switch (code) { |
case CI_DEFLATE: |
case CI_DEFLATE_DRAFT: |
if (optlen >= CILEN_DEFLATE) { |
printer(arg, "deflate%s %d", |
(code == CI_DEFLATE_DRAFT? "(old#)": ""), |
DEFLATE_SIZE(p[2])); |
if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL) |
printer(arg, " method %d", DEFLATE_METHOD(p[2])); |
if (p[3] != DEFLATE_CHK_SEQUENCE) |
printer(arg, " check %d", p[3]); |
p += CILEN_DEFLATE; |
} |
break; |
case CI_BSD_COMPRESS: |
if (optlen >= CILEN_BSD_COMPRESS) { |
printer(arg, "bsd v%d %d", BSD_VERSION(p[2]), |
BSD_NBITS(p[2])); |
p += CILEN_BSD_COMPRESS; |
} |
break; |
case CI_PREDICTOR_1: |
if (optlen >= CILEN_PREDICTOR_1) { |
printer(arg, "predictor 1"); |
p += CILEN_PREDICTOR_1; |
} |
break; |
case CI_PREDICTOR_2: |
if (optlen >= CILEN_PREDICTOR_2) { |
printer(arg, "predictor 2"); |
p += CILEN_PREDICTOR_2; |
} |
break; |
} |
/* while (p < optend) |
printer(arg, " %.2x", *p++); |
printer(arg, ">"); |
*/ } |
break; |
|
case TERMACK: |
case TERMREQ: |
/* if (len > 0 && *p >= ' ' && *p < 0x7f) { |
print_string(p, len, printer, arg); |
p += len; |
len = 0; |
} |
*/ break; |
} |
|
/* dump out the rest of the packet in hex */ |
/* while (--len >= 0) |
printer(arg, " %.2x", *p++); |
*/ |
return p - p0; |
} |
|
/* |
* We have received a packet that the decompressor failed to |
* decompress. Here we would expect to issue a reset-request, but |
* Motorola has a patent on resetting the compressor as a result of |
* detecting an error in the decompressed data after decompression. |
* (See US patent 5,130,993; international patent publication number |
* WO 91/10289; Australian patent 73296/91.) |
* |
* So we ask the kernel whether the error was detected after |
* decompression; if it was, we take CCP down, thus disabling |
* compression :-(, otherwise we issue the reset-request. |
*/ |
static void |
ccp_datainput(unit, pkt, len) |
int unit; |
u_char *pkt; |
int len; |
{ |
fsm *f; |
|
f = &ccp_fsm[unit]; |
if (f->state == OPENED) { |
if (ccp_fatal_error(unit)) { |
/* |
* Disable compression by taking CCP down. |
*/ |
syslog(LOG_ERR, "Lost compression sync: disabling compression"); |
ccp_close(unit, "Lost compression sync"); |
} else { |
/* |
* Send a reset-request to reset the peer's compressor. |
* We don't do that if we are still waiting for an |
* acknowledgement to a previous reset-request. |
*/ |
if (!(ccp_localstate[f->unit] & RACK_PENDING)) { |
fsm_sdata(f, CCP_RESETREQ, f->reqid = ++f->id, NULL, 0); |
TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT); |
ccp_localstate[f->unit] |= RACK_PENDING; |
} else |
ccp_localstate[f->unit] |= RREQ_REPEAT; |
} |
} |
} |
|
/* |
* Timeout waiting for reset-ack. |
*/ |
static void |
ccp_rack_timeout(arg) |
void *arg; |
{ |
fsm *f = arg; |
|
if (f->state == OPENED && ccp_localstate[f->unit] & RREQ_REPEAT) { |
fsm_sdata(f, CCP_RESETREQ, f->reqid, NULL, 0); |
TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT); |
ccp_localstate[f->unit] &= ~RREQ_REPEAT; |
} else |
ccp_localstate[f->unit] &= ~RACK_PENDING; |
} |
|
/cbcp.c
0,0 → 1,431
/* |
* cbcp - Call Back Configuration Protocol. |
* |
* Copyright (c) 1995 Pedro Roque Marques |
* All rights reserved. |
* |
* 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 Pedro Roque Marques. The name of the author 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. |
*/ |
|
#ifndef lint |
/* static char rcsid[] = "$Id: cbcp.c,v 1.2 2001-09-27 12:01:57 chris Exp $"; */ |
#endif |
|
#include <stdio.h> |
#include <string.h> |
#include <sys/types.h> |
#include <sys/time.h> |
#include <syslog.h> |
|
#include "pppd.h" |
#include "cbcp.h" |
#include "fsm.h" |
#include "lcp.h" |
#include "ipcp.h" |
|
/* |
* Protocol entry points. |
*/ |
static void cbcp_init __P((int unit)); |
static void cbcp_open __P((int unit)); |
static void cbcp_lowerup __P((int unit)); |
static void cbcp_input __P((int unit, u_char *pkt, int len)); |
static void cbcp_protrej __P((int unit)); |
static int cbcp_printpkt __P((u_char *pkt, int len, |
void (*printer) __P((void *, char *, ...)), |
void *arg)); |
|
struct protent cbcp_protent = { |
PPP_CBCP, |
cbcp_init, |
cbcp_input, |
cbcp_protrej, |
cbcp_lowerup, |
NULL, |
cbcp_open, |
NULL, |
cbcp_printpkt, |
NULL, |
0, |
"CBCP", |
NULL, |
NULL, |
NULL |
}; |
|
cbcp_state cbcp[NUM_PPP]; |
|
/* internal prototypes */ |
|
static void cbcp_recvreq __P((cbcp_state *us, char *pckt, int len)); |
static void cbcp_resp __P((cbcp_state *us)); |
static void cbcp_up __P((cbcp_state *us)); |
static void cbcp_recvack __P((cbcp_state *us, char *pckt, int len)); |
static void cbcp_send __P((cbcp_state *us, u_char code, u_char *buf, int len)); |
|
/* init state */ |
static void |
cbcp_init(iface) |
int iface; |
{ |
cbcp_state *us; |
|
us = &cbcp[iface]; |
memset(us, 0, sizeof(cbcp_state)); |
us->us_unit = iface; |
us->us_type |= (1 << CB_CONF_NO); |
} |
|
/* lower layer is up */ |
static void |
cbcp_lowerup(iface) |
int iface; |
{ |
cbcp_state *us = &cbcp[iface]; |
|
|
syslog(LOG_DEBUG, "cbcp_lowerup"); |
syslog(LOG_DEBUG, "want: %d", us->us_type); |
|
if (us->us_type == CB_CONF_USER) |
syslog(LOG_DEBUG, "phone no: %s", us->us_number); |
} |
|
static void |
cbcp_open(unit) |
int unit; |
{ |
syslog(LOG_DEBUG, "cbcp_open"); |
} |
|
/* process an incomming packet */ |
static void |
cbcp_input(unit, inpacket, pktlen) |
int unit; |
u_char *inpacket; |
int pktlen; |
{ |
u_char *inp; |
u_char code, id; |
u_short len; |
|
cbcp_state *us = &cbcp[unit]; |
|
inp = inpacket; |
|
if (pktlen < CBCP_MINLEN) { |
syslog(LOG_ERR, "CBCP packet is too small"); |
return; |
} |
|
GETCHAR(code, inp); |
GETCHAR(id, inp); |
GETSHORT(len, inp); |
|
#if 0 |
if (len > pktlen) { |
syslog(LOG_ERR, "CBCP packet: invalid length"); |
return; |
} |
#endif |
|
len -= CBCP_MINLEN; |
|
switch(code) { |
case CBCP_REQ: |
us->us_id = id; |
cbcp_recvreq(us, inp, len); |
break; |
|
case CBCP_RESP: |
syslog(LOG_DEBUG, "CBCP_RESP received"); |
break; |
|
case CBCP_ACK: |
if (id != us->us_id) |
syslog(LOG_DEBUG, "id doesn't match: expected %d recv %d", |
us->us_id, id); |
|
cbcp_recvack(us, inp, len); |
break; |
|
default: |
break; |
} |
} |
|
/* protocol was rejected by foe */ |
void cbcp_protrej(int iface) |
{ |
} |
|
char *cbcp_codenames[] = { |
"Request", "Response", "Ack" |
}; |
|
char *cbcp_optionnames[] = { |
"NoCallback", |
"UserDefined", |
"AdminDefined", |
"List" |
}; |
|
/* pretty print a packet */ |
static int |
cbcp_printpkt(p, plen, printer, arg) |
u_char *p; |
int plen; |
void (*printer) __P((void *, char *, ...)); |
void *arg; |
{ |
int code, opt, id, len, olen, delay; |
u_char *pstart; |
|
if (plen < HEADERLEN) |
return 0; |
pstart = p; |
GETCHAR(code, p); |
GETCHAR(id, p); |
GETSHORT(len, p); |
if (len < HEADERLEN || len > plen) |
return 0; |
|
if (code >= 1 && code <= sizeof(cbcp_codenames) / sizeof(char *)) |
printer(arg, " %s", cbcp_codenames[code-1]); |
else |
printer(arg, " code=0x%x", code); |
|
printer(arg, " id=0x%x", id); |
len -= HEADERLEN; |
|
switch (code) { |
case CBCP_REQ: |
case CBCP_RESP: |
case CBCP_ACK: |
while(len >= 2) { |
GETCHAR(opt, p); |
GETCHAR(olen, p); |
|
if (olen < 2 || olen > len) { |
break; |
} |
|
printer(arg, " <"); |
len -= olen; |
|
if (opt >= 1 && opt <= sizeof(cbcp_optionnames) / sizeof(char *)) |
printer(arg, " %s", cbcp_optionnames[opt-1]); |
else |
printer(arg, " option=0x%x", opt); |
|
if (olen > 2) { |
GETCHAR(delay, p); |
printer(arg, " delay = %d", delay); |
} |
|
if (olen > 3) { |
int addrt; |
char str[256]; |
|
GETCHAR(addrt, p); |
memcpy(str, p, olen - 4); |
str[olen - 4] = 0; |
printer(arg, " number = %s", str); |
} |
printer(arg, ">"); |
break; |
} |
|
default: |
break; |
} |
|
for (; len > 0; --len) { |
GETCHAR(code, p); |
printer(arg, " %.2x", code); |
} |
|
return p - pstart; |
} |
|
/* received CBCP request */ |
static void |
cbcp_recvreq(us, pckt, pcktlen) |
cbcp_state *us; |
char *pckt; |
int pcktlen; |
{ |
u_char type, opt_len, delay, addr_type; |
char address[256]; |
int len = pcktlen; |
|
address[0] = 0; |
|
while (len) { |
syslog(LOG_DEBUG, "length: %d", len); |
|
GETCHAR(type, pckt); |
GETCHAR(opt_len, pckt); |
|
if (opt_len > 2) |
GETCHAR(delay, pckt); |
|
us->us_allowed |= (1 << type); |
|
switch(type) { |
case CB_CONF_NO: |
syslog(LOG_DEBUG, "no callback allowed"); |
break; |
|
case CB_CONF_USER: |
syslog(LOG_DEBUG, "user callback allowed"); |
if (opt_len > 4) { |
GETCHAR(addr_type, pckt); |
memcpy(address, pckt, opt_len - 4); |
address[opt_len - 4] = 0; |
if (address[0]) |
syslog(LOG_DEBUG, "address: %s", address); |
} |
break; |
|
case CB_CONF_ADMIN: |
syslog(LOG_DEBUG, "user admin defined allowed"); |
break; |
|
case CB_CONF_LIST: |
break; |
} |
len -= opt_len; |
} |
|
cbcp_resp(us); |
} |
|
static void |
cbcp_resp(us) |
cbcp_state *us; |
{ |
u_char cb_type; |
u_char buf[256]; |
u_char *bufp = buf; |
int len = 0; |
|
cb_type = us->us_allowed & us->us_type; |
syslog(LOG_DEBUG, "cbcp_resp cb_type=%d", cb_type); |
|
#if 0 |
if (!cb_type) |
lcp_down(us->us_unit); |
#endif |
|
if (cb_type & ( 1 << CB_CONF_USER ) ) { |
syslog(LOG_DEBUG, "cbcp_resp CONF_USER"); |
PUTCHAR(CB_CONF_USER, bufp); |
len = 3 + 1 + strlen(us->us_number) + 1; |
PUTCHAR(len , bufp); |
PUTCHAR(5, bufp); /* delay */ |
PUTCHAR(1, bufp); |
BCOPY(us->us_number, bufp, strlen(us->us_number) + 1); |
cbcp_send(us, CBCP_RESP, buf, len); |
return; |
} |
|
if (cb_type & ( 1 << CB_CONF_ADMIN ) ) { |
syslog(LOG_DEBUG, "cbcp_resp CONF_ADMIN"); |
PUTCHAR(CB_CONF_ADMIN, bufp); |
len = 3 + 1; |
PUTCHAR(len , bufp); |
PUTCHAR(5, bufp); /* delay */ |
PUTCHAR(0, bufp); |
cbcp_send(us, CBCP_RESP, buf, len); |
return; |
} |
|
if (cb_type & ( 1 << CB_CONF_NO ) ) { |
syslog(LOG_DEBUG, "cbcp_resp CONF_NO"); |
PUTCHAR(CB_CONF_NO, bufp); |
len = 3; |
PUTCHAR(len , bufp); |
PUTCHAR(0, bufp); |
cbcp_send(us, CBCP_RESP, buf, len); |
(*ipcp_protent.open)(us->us_unit); |
return; |
} |
} |
|
static void |
cbcp_send(us, code, buf, len) |
cbcp_state *us; |
u_char code; |
u_char *buf; |
int len; |
{ |
u_char *outp; |
int outlen; |
|
outp = outpacket_buf; |
|
outlen = 4 + len; |
|
MAKEHEADER(outp, PPP_CBCP); |
|
PUTCHAR(code, outp); |
PUTCHAR(us->us_id, outp); |
PUTSHORT(outlen, outp); |
|
if (len) |
BCOPY(buf, outp, len); |
|
output(us->us_unit, outpacket_buf, outlen + PPP_HDRLEN); |
} |
|
static void |
cbcp_recvack(us, pckt, len) |
cbcp_state *us; |
char *pckt; |
int len; |
{ |
u_char type, delay, addr_type; |
int opt_len; |
char address[256]; |
|
if (len) { |
GETCHAR(type, pckt); |
GETCHAR(opt_len, pckt); |
|
if (opt_len > 2) |
GETCHAR(delay, pckt); |
|
if (opt_len > 4) { |
GETCHAR(addr_type, pckt); |
memcpy(address, pckt, opt_len - 4); |
address[opt_len - 4] = 0; |
if (address[0]) |
syslog(LOG_DEBUG, "peer will call: %s", address); |
} |
} |
|
cbcp_up(us); |
} |
|
extern int persist; |
|
/* ok peer will do callback */ |
static void |
cbcp_up(us) |
cbcp_state *us; |
{ |
persist = 0; |
lcp_close(0, "Call me back, please"); |
} |
/ccp.h
0,0 → 1,48
/* |
* ccp.h - Definitions for PPP Compression Control Protocol. |
* |
* Copyright (c) 1994 The Australian National University. |
* All rights reserved. |
* |
* Permission to use, copy, modify, and distribute this software and its |
* documentation is hereby granted, provided that the above copyright |
* notice appears in all copies. This software is provided without any |
* warranty, express or implied. The Australian National University |
* makes no representations about the suitability of this software for |
* any purpose. |
* |
* IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY |
* PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF |
* THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY |
* OF SUCH DAMAGE. |
* |
* THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, |
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY |
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
* ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO |
* OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, |
* OR MODIFICATIONS. |
* |
* $Id: ccp.h,v 1.2 2001-09-27 12:01:57 chris Exp $ |
*/ |
|
typedef struct ccp_options { |
u_int bsd_compress: 1; /* do BSD Compress? */ |
u_int deflate: 1; /* do Deflate? */ |
u_int predictor_1: 1; /* do Predictor-1? */ |
u_int predictor_2: 1; /* do Predictor-2? */ |
u_int deflate_correct: 1; /* use correct code for deflate? */ |
u_int deflate_draft: 1; /* use draft RFC code for deflate? */ |
u_short bsd_bits; /* # bits/code for BSD Compress */ |
u_short deflate_size; /* lg(window size) for Deflate */ |
short method; /* code for chosen compression method */ |
} ccp_options; |
|
extern fsm ccp_fsm[]; |
extern ccp_options ccp_wantoptions[]; |
extern ccp_options ccp_gotoptions[]; |
extern ccp_options ccp_allowoptions[]; |
extern ccp_options ccp_hisoptions[]; |
|
extern struct protent ccp_protent; |
/chap.c
0,0 → 1,872
/* |
* chap.c - Challenge Handshake Authentication Protocol. |
* |
* Copyright (c) 1993 The Australian National University. |
* All rights reserved. |
* |
* 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 Australian National University. The name of the University |
* 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. |
* |
* Copyright (c) 1991 Gregory M. Christy. |
* All rights reserved. |
* |
* 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 Gregory M. Christy. The name of the author 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. |
*/ |
|
#ifndef lint |
/* static char rcsid[] = "$Id: chap.c,v 1.2 2001-09-27 12:01:57 chris Exp $"; */ |
#endif |
|
/* |
* TODO: |
*/ |
|
#include <stdio.h> |
#include <string.h> |
#include <sys/types.h> |
#include <sys/time.h> |
#include <syslog.h> |
|
#include "pppd.h" |
#include "chap.h" |
#include "md5.h" |
#ifdef CHAPMS |
#include "chap_ms.h" |
#endif |
|
/* |
* Protocol entry points. |
*/ |
static void ChapInit __P((int)); |
static void ChapLowerUp __P((int)); |
static void ChapLowerDown __P((int)); |
static void ChapInput __P((int, u_char *, int)); |
static void ChapProtocolReject __P((int)); |
static int ChapPrintPkt __P((u_char *, int, |
void (*) __P((void *, char *, ...)), void *)); |
|
struct protent chap_protent = { |
PPP_CHAP, |
ChapInit, |
ChapInput, |
ChapProtocolReject, |
ChapLowerUp, |
ChapLowerDown, |
NULL, |
NULL, |
ChapPrintPkt, |
NULL, |
1, |
"CHAP", |
NULL, |
NULL, |
NULL |
}; |
|
chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */ |
|
static void ChapChallengeTimeout __P((void *)); |
static void ChapResponseTimeout __P((void *)); |
static void ChapReceiveChallenge __P((chap_state *, u_char *, int, int)); |
static void ChapRechallenge __P((void *)); |
static void ChapReceiveResponse __P((chap_state *, u_char *, int, int)); |
static void ChapReceiveSuccess __P((chap_state *, u_char *, int, int)); |
static void ChapReceiveFailure __P((chap_state *, u_char *, int, int)); |
static void ChapSendStatus __P((chap_state *, int)); |
static void ChapSendChallenge __P((chap_state *)); |
static void ChapSendResponse __P((chap_state *)); |
static void ChapGenChallenge __P((chap_state *)); |
/* #include <stdlib.h> */ |
|
extern double drand48 __P((void)); |
/*{ |
return (((double)rand())/RAND_MAX); |
} |
*/ |
extern void srand48 __P((long)); |
|
/* |
* ChapInit - Initialize a CHAP unit. |
*/ |
static void |
ChapInit(unit) |
int unit; |
{ |
chap_state *cstate = &chap[unit]; |
|
BZERO(cstate, sizeof(*cstate)); |
cstate->unit = unit; |
cstate->clientstate = CHAPCS_INITIAL; |
cstate->serverstate = CHAPSS_INITIAL; |
cstate->timeouttime = CHAP_DEFTIMEOUT; |
cstate->max_transmits = CHAP_DEFTRANSMITS; |
/* random number generator is initialized in magic_init */ |
} |
|
|
/* |
* ChapAuthWithPeer - Authenticate us with our peer (start client). |
* |
*/ |
void |
ChapAuthWithPeer(unit, our_name, digest) |
int unit; |
char *our_name; |
int digest; |
{ |
chap_state *cstate = &chap[unit]; |
|
cstate->resp_name = our_name; |
cstate->resp_type = digest; |
|
if (cstate->clientstate == CHAPCS_INITIAL || |
cstate->clientstate == CHAPCS_PENDING) { |
/* lower layer isn't up - wait until later */ |
cstate->clientstate = CHAPCS_PENDING; |
return; |
} |
|
/* |
* We get here as a result of LCP coming up. |
* So even if CHAP was open before, we will |
* have to re-authenticate ourselves. |
*/ |
cstate->clientstate = CHAPCS_LISTEN; |
} |
|
|
/* |
* ChapAuthPeer - Authenticate our peer (start server). |
*/ |
void |
ChapAuthPeer(unit, our_name, digest) |
int unit; |
char *our_name; |
int digest; |
{ |
chap_state *cstate = &chap[unit]; |
|
cstate->chal_name = our_name; |
cstate->chal_type = digest; |
|
if (cstate->serverstate == CHAPSS_INITIAL || |
cstate->serverstate == CHAPSS_PENDING) { |
/* lower layer isn't up - wait until later */ |
cstate->serverstate = CHAPSS_PENDING; |
return; |
} |
|
ChapGenChallenge(cstate); |
ChapSendChallenge(cstate); /* crank it up dude! */ |
cstate->serverstate = CHAPSS_INITIAL_CHAL; |
} |
|
|
/* |
* ChapChallengeTimeout - Timeout expired on sending challenge. |
*/ |
static void |
ChapChallengeTimeout(arg) |
void *arg; |
{ |
chap_state *cstate = (chap_state *) arg; |
|
/* if we aren't sending challenges, don't worry. then again we */ |
/* probably shouldn't be here either */ |
if (cstate->serverstate != CHAPSS_INITIAL_CHAL && |
cstate->serverstate != CHAPSS_RECHALLENGE) |
return; |
|
if (cstate->chal_transmits >= cstate->max_transmits) { |
/* give up on peer */ |
syslog(LOG_ERR, "Peer failed to respond to CHAP challenge"); |
cstate->serverstate = CHAPSS_BADAUTH; |
auth_peer_fail(cstate->unit, PPP_CHAP); |
return; |
} |
|
ChapSendChallenge(cstate); /* Re-send challenge */ |
} |
|
|
/* |
* ChapResponseTimeout - Timeout expired on sending response. |
*/ |
static void |
ChapResponseTimeout(arg) |
void *arg; |
{ |
chap_state *cstate = (chap_state *) arg; |
|
/* if we aren't sending a response, don't worry. */ |
if (cstate->clientstate != CHAPCS_RESPONSE) |
return; |
|
ChapSendResponse(cstate); /* re-send response */ |
} |
|
|
/* |
* ChapRechallenge - Time to challenge the peer again. |
*/ |
static void |
ChapRechallenge(arg) |
void *arg; |
{ |
chap_state *cstate = (chap_state *) arg; |
|
/* if we aren't sending a response, don't worry. */ |
if (cstate->serverstate != CHAPSS_OPEN) |
return; |
|
ChapGenChallenge(cstate); |
ChapSendChallenge(cstate); |
cstate->serverstate = CHAPSS_RECHALLENGE; |
} |
|
|
/* |
* ChapLowerUp - The lower layer is up. |
* |
* Start up if we have pending requests. |
*/ |
static void |
ChapLowerUp(unit) |
int unit; |
{ |
chap_state *cstate = &chap[unit]; |
|
if (cstate->clientstate == CHAPCS_INITIAL) |
cstate->clientstate = CHAPCS_CLOSED; |
else if (cstate->clientstate == CHAPCS_PENDING) |
cstate->clientstate = CHAPCS_LISTEN; |
|
if (cstate->serverstate == CHAPSS_INITIAL) |
cstate->serverstate = CHAPSS_CLOSED; |
else if (cstate->serverstate == CHAPSS_PENDING) { |
ChapGenChallenge(cstate); |
ChapSendChallenge(cstate); |
cstate->serverstate = CHAPSS_INITIAL_CHAL; |
} |
} |
|
|
/* |
* ChapLowerDown - The lower layer is down. |
* |
* Cancel all timeouts. |
*/ |
static void |
ChapLowerDown(unit) |
int unit; |
{ |
chap_state *cstate = &chap[unit]; |
|
/* Timeout(s) pending? Cancel if so. */ |
if (cstate->serverstate == CHAPSS_INITIAL_CHAL || |
cstate->serverstate == CHAPSS_RECHALLENGE) |
UNTIMEOUT(ChapChallengeTimeout, cstate); |
else if (cstate->serverstate == CHAPSS_OPEN |
&& cstate->chal_interval != 0) |
UNTIMEOUT(ChapRechallenge, cstate); |
if (cstate->clientstate == CHAPCS_RESPONSE) |
UNTIMEOUT(ChapResponseTimeout, cstate); |
|
cstate->clientstate = CHAPCS_INITIAL; |
cstate->serverstate = CHAPSS_INITIAL; |
} |
|
|
/* |
* ChapProtocolReject - Peer doesn't grok CHAP. |
*/ |
static void |
ChapProtocolReject(unit) |
int unit; |
{ |
chap_state *cstate = &chap[unit]; |
|
if (cstate->serverstate != CHAPSS_INITIAL && |
cstate->serverstate != CHAPSS_CLOSED) |
auth_peer_fail(unit, PPP_CHAP); |
if (cstate->clientstate != CHAPCS_INITIAL && |
cstate->clientstate != CHAPCS_CLOSED) |
auth_withpeer_fail(unit, PPP_CHAP); |
ChapLowerDown(unit); /* shutdown chap */ |
} |
|
|
/* |
* ChapInput - Input CHAP packet. |
*/ |
static void |
ChapInput(unit, inpacket, packet_len) |
int unit; |
u_char *inpacket; |
int packet_len; |
{ |
chap_state *cstate = &chap[unit]; |
u_char *inp; |
u_char code, id; |
int len; |
|
/* |
* Parse header (code, id and length). |
* If packet too short, drop it. |
*/ |
inp = inpacket; |
if (packet_len < CHAP_HEADERLEN) { |
CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header.")); |
return; |
} |
GETCHAR(code, inp); |
GETCHAR(id, inp); |
GETSHORT(len, inp); |
if (len < CHAP_HEADERLEN) { |
CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length.")); |
return; |
} |
if (len > packet_len) { |
CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet.")); |
return; |
} |
len -= CHAP_HEADERLEN; |
|
/* |
* Action depends on code (as in fact it usually does :-). |
*/ |
switch (code) { |
case CHAP_CHALLENGE: |
ChapReceiveChallenge(cstate, inp, id, len); |
break; |
|
case CHAP_RESPONSE: |
ChapReceiveResponse(cstate, inp, id, len); |
break; |
|
case CHAP_FAILURE: |
ChapReceiveFailure(cstate, inp, id, len); |
break; |
|
case CHAP_SUCCESS: |
ChapReceiveSuccess(cstate, inp, id, len); |
break; |
|
default: /* Need code reject? */ |
syslog(LOG_WARNING, "Unknown CHAP code (%d) received.", code); |
break; |
} |
} |
|
|
/* |
* ChapReceiveChallenge - Receive Challenge and send Response. |
*/ |
static void |
ChapReceiveChallenge(cstate, inp, id, len) |
chap_state *cstate; |
u_char *inp; |
int id; |
int len; |
{ |
int rchallenge_len; |
u_char *rchallenge; |
int secret_len; |
char secret[MAXSECRETLEN]; |
char rhostname[256]; |
MD5_CTX mdContext; |
u_char hash[MD5_SIGNATURE_SIZE]; |
|
CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.", id)); |
if (cstate->clientstate == CHAPCS_CLOSED || |
cstate->clientstate == CHAPCS_PENDING) { |
CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: in state %d", |
cstate->clientstate)); |
return; |
} |
|
if (len < 2) { |
CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.")); |
return; |
} |
|
GETCHAR(rchallenge_len, inp); |
len -= sizeof (u_char) + rchallenge_len; /* now name field length */ |
if (len < 0) { |
CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.")); |
return; |
} |
rchallenge = inp; |
INCPTR(rchallenge_len, inp); |
|
if (len >= sizeof(rhostname)) |
len = sizeof(rhostname) - 1; |
BCOPY(inp, rhostname, len); |
rhostname[len] = '\000'; |
|
CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field '%s'", |
rhostname)); |
|
/* Microsoft doesn't send their name back in the PPP packet */ |
if (remote_name[0] != 0 && (explicit_remote || rhostname[0] == 0)) { |
strncpy(rhostname, remote_name, sizeof(rhostname)); |
rhostname[sizeof(rhostname) - 1] = 0; |
CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: using '%s' as remote name", |
rhostname)); |
} |
|
/* get secret for authenticating ourselves with the specified host */ |
if (!get_secret(cstate->unit, cstate->resp_name, rhostname, |
secret, &secret_len, 0)) { |
secret_len = 0; /* assume null secret if can't find one */ |
syslog(LOG_WARNING, "No CHAP secret found for authenticating us to %s", |
rhostname); |
} |
|
/* cancel response send timeout if necessary */ |
if (cstate->clientstate == CHAPCS_RESPONSE) |
UNTIMEOUT(ChapResponseTimeout, cstate); |
|
cstate->resp_id = id; |
cstate->resp_transmits = 0; |
|
/* generate MD based on negotiated type */ |
switch (cstate->resp_type) { |
|
case CHAP_DIGEST_MD5: |
MD5Init(&mdContext); |
MD5Update(&mdContext, &cstate->resp_id, 1); |
MD5Update(&mdContext, secret, secret_len); |
MD5Update(&mdContext, rchallenge, rchallenge_len); |
MD5Final(hash, &mdContext); |
BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE); |
cstate->resp_length = MD5_SIGNATURE_SIZE; |
break; |
|
#ifdef CHAPMS |
case CHAP_MICROSOFT: |
ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len); |
break; |
#endif |
|
default: |
CHAPDEBUG((LOG_INFO, "unknown digest type %d", cstate->resp_type)); |
return; |
} |
|
BZERO(secret, sizeof(secret)); |
ChapSendResponse(cstate); |
} |
|
|
/* |
* ChapReceiveResponse - Receive and process response. |
*/ |
static void |
ChapReceiveResponse(cstate, inp, id, len) |
chap_state *cstate; |
u_char *inp; |
int id; |
int len; |
{ |
u_char *remmd, remmd_len; |
int secret_len, old_state; |
int code; |
char rhostname[256]; |
MD5_CTX mdContext; |
char secret[MAXSECRETLEN]; |
u_char hash[MD5_SIGNATURE_SIZE]; |
|
CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.", id)); |
|
if (cstate->serverstate == CHAPSS_CLOSED || |
cstate->serverstate == CHAPSS_PENDING) { |
CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: in state %d", |
cstate->serverstate)); |
return; |
} |
|
if (id != cstate->chal_id) |
return; /* doesn't match ID of last challenge */ |
|
/* |
* If we have received a duplicate or bogus Response, |
* we have to send the same answer (Success/Failure) |
* as we did for the first Response we saw. |
*/ |
if (cstate->serverstate == CHAPSS_OPEN) { |
ChapSendStatus(cstate, CHAP_SUCCESS); |
return; |
} |
if (cstate->serverstate == CHAPSS_BADAUTH) { |
ChapSendStatus(cstate, CHAP_FAILURE); |
return; |
} |
|
if (len < 2) { |
CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.")); |
return; |
} |
GETCHAR(remmd_len, inp); /* get length of MD */ |
remmd = inp; /* get pointer to MD */ |
INCPTR(remmd_len, inp); |
|
len -= sizeof (u_char) + remmd_len; |
if (len < 0) { |
CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.")); |
return; |
} |
|
UNTIMEOUT(ChapChallengeTimeout, cstate); |
|
if (len >= sizeof(rhostname)) |
len = sizeof(rhostname) - 1; |
BCOPY(inp, rhostname, len); |
rhostname[len] = '\000'; |
|
CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s", |
rhostname)); |
|
/* |
* Get secret for authenticating them with us, |
* do the hash ourselves, and compare the result. |
*/ |
code = CHAP_FAILURE; |
if (!get_secret(cstate->unit, rhostname, cstate->chal_name, |
secret, &secret_len, 1)) { |
syslog(LOG_WARNING, "No CHAP secret found for authenticating %s", |
rhostname); |
} else { |
|
/* generate MD based on negotiated type */ |
switch (cstate->chal_type) { |
|
case CHAP_DIGEST_MD5: /* only MD5 is defined for now */ |
if (remmd_len != MD5_SIGNATURE_SIZE) |
break; /* it's not even the right length */ |
MD5Init(&mdContext); |
MD5Update(&mdContext, &cstate->chal_id, 1); |
MD5Update(&mdContext, secret, secret_len); |
MD5Update(&mdContext, cstate->challenge, cstate->chal_len); |
MD5Final(hash, &mdContext); |
|
/* compare local and remote MDs and send the appropriate status */ |
if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0) |
code = CHAP_SUCCESS; /* they are the same! */ |
break; |
|
default: |
CHAPDEBUG((LOG_INFO, "unknown digest type %d", cstate->chal_type)); |
} |
} |
|
BZERO(secret, sizeof(secret)); |
ChapSendStatus(cstate, code); |
|
if (code == CHAP_SUCCESS) { |
old_state = cstate->serverstate; |
cstate->serverstate = CHAPSS_OPEN; |
if (old_state == CHAPSS_INITIAL_CHAL) { |
auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len); |
} |
if (cstate->chal_interval != 0) |
TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval); |
syslog(LOG_NOTICE, "CHAP peer authentication succeeded for %s", |
rhostname); |
|
} else { |
syslog(LOG_ERR, "CHAP peer authentication failed for remote host %s", |
rhostname); |
cstate->serverstate = CHAPSS_BADAUTH; |
auth_peer_fail(cstate->unit, PPP_CHAP); |
} |
} |
|
/* |
* ChapReceiveSuccess - Receive Success |
*/ |
static void |
ChapReceiveSuccess(cstate, inp, id, len) |
chap_state *cstate; |
u_char *inp; |
int id; /* was u_char id */ |
int len; |
{ |
|
CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.", id)); |
|
if (cstate->clientstate == CHAPCS_OPEN) |
/* presumably an answer to a duplicate response */ |
return; |
|
if (cstate->clientstate != CHAPCS_RESPONSE) { |
/* don't know what this is */ |
CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: in state %d\n", |
cstate->clientstate)); |
return; |
} |
|
UNTIMEOUT(ChapResponseTimeout, cstate); |
|
/* |
* Print message. |
*/ |
if (len > 0) |
PRINTMSG(inp, len); |
|
cstate->clientstate = CHAPCS_OPEN; |
|
auth_withpeer_success(cstate->unit, PPP_CHAP); |
} |
|
|
/* |
* ChapReceiveFailure - Receive failure. |
*/ |
static void |
ChapReceiveFailure(cstate, inp, id, len) |
chap_state *cstate; |
u_char *inp; |
int id; /* was u_char id; */ |
int len; |
{ |
CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.", id)); |
|
if (cstate->clientstate != CHAPCS_RESPONSE) { |
/* don't know what this is */ |
CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: in state %d\n", |
cstate->clientstate)); |
return; |
} |
|
UNTIMEOUT(ChapResponseTimeout, cstate); |
|
/* |
* Print message. |
*/ |
if (len > 0) |
PRINTMSG(inp, len); |
|
syslog(LOG_ERR, "CHAP authentication failed"); |
auth_withpeer_fail(cstate->unit, PPP_CHAP); |
} |
|
|
/* |
* ChapSendChallenge - Send an Authenticate challenge. |
*/ |
static void |
ChapSendChallenge(cstate) |
chap_state *cstate; |
{ |
u_char *outp; |
int chal_len, name_len; |
int outlen; |
|
chal_len = cstate->chal_len; |
name_len = strlen(cstate->chal_name); |
outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len; |
outp = outpacket_buf; |
|
MAKEHEADER(outp, PPP_CHAP); /* paste in a CHAP header */ |
|
PUTCHAR(CHAP_CHALLENGE, outp); |
PUTCHAR(cstate->chal_id, outp); |
PUTSHORT(outlen, outp); |
|
PUTCHAR(chal_len, outp); /* put length of challenge */ |
BCOPY(cstate->challenge, outp, chal_len); |
INCPTR(chal_len, outp); |
|
BCOPY(cstate->chal_name, outp, name_len); /* append hostname */ |
|
output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN); |
|
CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.", cstate->chal_id)); |
|
TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime); |
++cstate->chal_transmits; |
} |
|
|
/* |
* ChapSendStatus - Send a status response (ack or nak). |
*/ |
static void |
ChapSendStatus(cstate, code) |
chap_state *cstate; |
int code; |
{ |
u_char *outp; |
int outlen, msglen; |
char msg[256]; |
|
if (code == CHAP_SUCCESS) |
sprintf(msg, "Welcome to %s.", hostname); |
else |
sprintf(msg, "I don't like you. Go 'way."); |
msglen = strlen(msg); |
|
outlen = CHAP_HEADERLEN + msglen; |
outp = outpacket_buf; |
|
MAKEHEADER(outp, PPP_CHAP); /* paste in a header */ |
|
PUTCHAR(code, outp); |
PUTCHAR(cstate->chal_id, outp); |
PUTSHORT(outlen, outp); |
BCOPY(msg, outp, msglen); |
output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN); |
|
CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.", code, |
cstate->chal_id)); |
} |
|
/* |
* ChapGenChallenge is used to generate a pseudo-random challenge string of |
* a pseudo-random length between min_len and max_len. The challenge |
* string and its length are stored in *cstate, and various other fields of |
* *cstate are initialized. |
*/ |
|
static void |
ChapGenChallenge(cstate) |
chap_state *cstate; |
{ |
int chal_len; |
u_char *ptr = cstate->challenge; |
unsigned int i; |
|
/* pick a random challenge length between MIN_CHALLENGE_LENGTH and |
MAX_CHALLENGE_LENGTH */ |
chal_len = (unsigned) ((drand48() * |
(MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) + |
MIN_CHALLENGE_LENGTH); |
cstate->chal_len = chal_len; |
cstate->chal_id = ++cstate->id; |
cstate->chal_transmits = 0; |
|
/* generate a random string */ |
for (i = 0; i < chal_len; i++ ) |
*ptr++ = (char) (drand48() * 0xff); |
} |
|
/* |
* ChapSendResponse - send a response packet with values as specified |
* in *cstate. |
*/ |
/* ARGSUSED */ |
static void |
ChapSendResponse(cstate) |
chap_state *cstate; |
{ |
u_char *outp; |
int outlen, md_len, name_len; |
|
md_len = cstate->resp_length; |
name_len = strlen(cstate->resp_name); |
outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len; |
outp = outpacket_buf; |
|
MAKEHEADER(outp, PPP_CHAP); |
|
PUTCHAR(CHAP_RESPONSE, outp); /* we are a response */ |
PUTCHAR(cstate->resp_id, outp); /* copy id from challenge packet */ |
PUTSHORT(outlen, outp); /* packet length */ |
|
PUTCHAR(md_len, outp); /* length of MD */ |
BCOPY(cstate->response, outp, md_len); /* copy MD to buffer */ |
INCPTR(md_len, outp); |
|
BCOPY(cstate->resp_name, outp, name_len); /* append our name */ |
|
/* send the packet */ |
output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN); |
|
cstate->clientstate = CHAPCS_RESPONSE; |
TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime); |
++cstate->resp_transmits; |
} |
|
/* |
* ChapPrintPkt - print the contents of a CHAP packet. |
*/ |
static char *ChapCodenames[] = { |
"Challenge", "Response", "Success", "Failure" |
}; |
|
static int |
ChapPrintPkt(p, plen, printer, arg) |
u_char *p; |
int plen; |
void (*printer) __P((void *, char *, ...)); |
void *arg; |
{ |
int code, id, len; |
int clen, nlen; |
u_char x; |
if (plen < CHAP_HEADERLEN) |
return 0; |
GETCHAR(code, p); |
GETCHAR(id, p); |
GETSHORT(len, p); |
if (len < CHAP_HEADERLEN || len > plen) |
return 0; |
|
if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *)) |
printer(arg, " %s", ChapCodenames[code-1]); |
else |
printer(arg, " code=0x%x", code); |
printer(arg, " id=0x%x", id); |
len -= CHAP_HEADERLEN; |
switch (code) { |
case CHAP_CHALLENGE: |
case CHAP_RESPONSE: |
if (len < 1) |
break; |
clen = p[0]; |
if (len < clen + 1) |
break; |
++p; |
nlen = len - clen - 1; |
printer(arg, " <"); |
for (; clen > 0; --clen) { |
GETCHAR(x, p); |
printer(arg, "%.2x", x); |
} |
printer(arg, ">, name = "); |
print_string((char *)p, nlen, printer, arg); |
break; |
case CHAP_FAILURE: |
case CHAP_SUCCESS: |
printer(arg, " "); |
print_string((char *)p, len, printer, arg); |
break; |
default: |
for (clen = len; clen > 0; --clen) { |
GETCHAR(x, p); |
printer(arg, " %.2x", x); |
} |
} |
return len + CHAP_HEADERLEN; |
} |
/cbcp.h
0,0 → 1,26
#ifndef CBCP_H |
#define CBCP_H |
|
typedef struct cbcp_state { |
int us_unit; /* Interface unit number */ |
u_char us_id; /* Current id */ |
u_char us_allowed; |
int us_type; |
char *us_number; /* Telefone Number */ |
} cbcp_state; |
|
extern cbcp_state cbcp[]; |
|
extern struct protent cbcp_protent; |
|
#define CBCP_MINLEN 4 |
|
#define CBCP_REQ 1 |
#define CBCP_RESP 2 |
#define CBCP_ACK 3 |
|
#define CB_CONF_NO 1 |
#define CB_CONF_USER 2 |
#define CB_CONF_ADMIN 3 |
#define CB_CONF_LIST 4 |
#endif |
/README
0,0 → 1,58
# |
# $Id: README,v 1.2 2001-09-27 12:01:57 chris Exp $ |
# |
|
This directory contains a port of ppp-2.3.5. The official site for |
the original source for this PPP implementation is: |
|
ftp://cs.anu.edu.au/pub/software/ppp |
|
NOTE: As of 11/30/1999, the current version of this source is 2.3.10. |
|
The port was performed by Tomasz Domin <dot@comarch.pl> of ComArch SA |
and has only been tested on the mpc823. The modem driver should |
work with minor modifications on other systems. |
================================================================= |
Some comments: |
|
+ "SetStatusInfo is a function which displays given message on |
bottom side of the screen." |
|
The issue of how to deal with SetStatusInfo in a generic, portable |
fashion is still open. |
|
+ "Dialer returns positive integer when an error occurs, and negative one |
which is parsed from modem aswer, when connection is done (for example |
-28000 if connection speed is 28000 baud ...)" |
|
+ PPP_User/PPP_Password |
"When this field is set, it is sent to the server when there is need |
to login .... |
When it is blank - it is using other method of authentification ... or |
none ... |
PPP_Password is also used in CHAT and PAP - because there is no |
configuration files in RTEMS ..." |
|
This falls into the general question of how to generally configure this. |
|
+ ConnectionStatus |
|
This is the method of synchronization between pppd task and others. |
ConnectionStatus field is set by pppd - when connection occurs it`s state |
is set to Connected. WantConnection is set by client application (and |
the appriopriate event is sent then) so pppd knows what user wants to do ... |
|
+ Around line 270 of main.c, there is code to change the default |
nameserver... why? |
|
Becouse in my application user can change it anytime ... - without need of |
rebooting the system |
When PPP connection is configured there is needed additional info about |
nameservers - PPP layer cant discover them itself |
|
|
|
|
|
|
|
/lcp.c
0,0 → 1,1858
/* |
* lcp.c - PPP Link Control Protocol. |
* |
* Copyright (c) 1989 Carnegie Mellon University. |
* All rights reserved. |
* |
* 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 Carnegie Mellon University. The name of the |
* University 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. |
*/ |
|
#ifndef lint |
/* static char rcsid[] = "$Id: lcp.c,v 1.2 2001-09-27 12:01:57 chris Exp $"; */ |
#endif |
|
/* |
* TODO: |
*/ |
|
#include <stdio.h> |
#include <string.h> |
#include <syslog.h> |
#include <assert.h> |
#include <sys/ioctl.h> |
#include <sys/types.h> |
#include <sys/socket.h> |
#include <sys/time.h> |
#include <netinet/in.h> |
|
#include "pppd.h" |
#include "fsm.h" |
#include "lcp.h" |
#include "chap.h" |
#include "magic.h" |
|
/* global vars */ |
fsm lcp_fsm[NUM_PPP]; /* LCP fsm structure (global)*/ |
lcp_options lcp_wantoptions[NUM_PPP]; /* Options that we want to request */ |
lcp_options lcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */ |
lcp_options lcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */ |
lcp_options lcp_hisoptions[NUM_PPP]; /* Options that we ack'd */ |
u_int32_t xmit_accm[NUM_PPP][8]; /* extended transmit ACCM */ |
|
static u_int32_t lcp_echos_pending = 0; /* Number of outstanding echo msgs */ |
static u_int32_t lcp_echo_number = 0; /* ID number of next echo frame */ |
static u_int32_t lcp_echo_timer_running = 0; /* TRUE if a timer is running */ |
|
static u_char nak_buffer[PPP_MRU]; /* where we construct a nak packet */ |
|
/* |
* Callbacks for fsm code. (CI = Configuration Information) |
*/ |
static void lcp_resetci __P((fsm *)); /* Reset our CI */ |
static int lcp_cilen __P((fsm *)); /* Return length of our CI */ |
static void lcp_addci __P((fsm *, u_char *, int *)); /* Add our CI to pkt */ |
static int lcp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */ |
static int lcp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */ |
static int lcp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */ |
static int lcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv peer CI */ |
static void lcp_up __P((fsm *)); /* We're UP */ |
static void lcp_down __P((fsm *)); /* We're DOWN */ |
static void lcp_starting __P((fsm *)); /* We need lower layer up */ |
static void lcp_finished __P((fsm *)); /* We need lower layer down */ |
static int lcp_extcode __P((fsm *, int, int, u_char *, int)); |
static void lcp_rprotrej __P((fsm *, u_char *, int)); |
|
/* |
* routines to send LCP echos to peer |
*/ |
|
static void lcp_echo_lowerup __P((int)); |
static void lcp_echo_lowerdown __P((int)); |
static void LcpEchoTimeout __P((void *)); |
static void lcp_received_echo_reply __P((fsm *, int, u_char *, int)); |
static void LcpSendEchoRequest __P((fsm *)); |
static void LcpLinkFailure __P((fsm *)); |
static void LcpEchoCheck __P((fsm *)); |
|
static fsm_callbacks lcp_callbacks = { /* LCP callback routines */ |
lcp_resetci, /* Reset our Configuration Information */ |
lcp_cilen, /* Length of our Configuration Information */ |
lcp_addci, /* Add our Configuration Information */ |
lcp_ackci, /* ACK our Configuration Information */ |
lcp_nakci, /* NAK our Configuration Information */ |
lcp_rejci, /* Reject our Configuration Information */ |
lcp_reqci, /* Request peer's Configuration Information */ |
lcp_up, /* Called when fsm reaches OPENED state */ |
lcp_down, /* Called when fsm leaves OPENED state */ |
lcp_starting, /* Called when we want the lower layer up */ |
lcp_finished, /* Called when we want the lower layer down */ |
NULL, /* Called when Protocol-Reject received */ |
NULL, /* Retransmission is necessary */ |
lcp_extcode, /* Called to handle LCP-specific codes */ |
"LCP" /* String name of protocol */ |
}; |
|
/* |
* Protocol entry points. |
* Some of these are called directly. |
*/ |
|
static void lcp_init __P((int)); |
static void lcp_input __P((int, u_char *, int)); |
static void lcp_protrej __P((int)); |
static int lcp_printpkt __P((u_char *, int, |
void (*) __P((void *, char *, ...)), void *)); |
|
struct protent lcp_protent = { |
PPP_LCP, |
lcp_init, |
lcp_input, |
lcp_protrej, |
lcp_lowerup, |
lcp_lowerdown, |
lcp_open, |
lcp_close, |
lcp_printpkt, |
NULL, |
1, |
"LCP", |
NULL, |
NULL, |
NULL |
}; |
|
int lcp_loopbackfail = DEFLOOPBACKFAIL; |
|
/* |
* Length of each type of configuration option (in octets) |
*/ |
#define CILEN_VOID 2 |
#define CILEN_CHAR 3 |
#define CILEN_SHORT 4 /* CILEN_VOID + sizeof(short) */ |
#define CILEN_CHAP 5 /* CILEN_VOID + sizeof(short) + 1 */ |
#define CILEN_LONG 6 /* CILEN_VOID + sizeof(long) */ |
#define CILEN_LQR 8 /* CILEN_VOID + sizeof(short) + sizeof(long) */ |
#define CILEN_CBCP 3 |
|
#define CODENAME(x) ((x) == CONFACK ? "ACK" : \ |
(x) == CONFNAK ? "NAK" : "REJ") |
|
|
/* |
* lcp_init - Initialize LCP. |
*/ |
static void |
lcp_init(unit) |
int unit; |
{ |
fsm *f = &lcp_fsm[unit]; |
lcp_options *wo = &lcp_wantoptions[unit]; |
lcp_options *ao = &lcp_allowoptions[unit]; |
|
f->unit = unit; |
f->protocol = PPP_LCP; |
f->callbacks = &lcp_callbacks; |
|
fsm_init(f); |
|
wo->passive = 0; |
wo->silent = 0; |
wo->restart = 0; /* Set to 1 in kernels or multi-line |
implementations */ |
wo->neg_mru = 1; |
wo->mru = DEFMRU; |
wo->neg_asyncmap = 0; |
wo->asyncmap = 0; |
wo->neg_chap = 0; /* Set to 1 on server */ |
wo->neg_upap = 0; /* Set to 1 on server */ |
wo->chap_mdtype = CHAP_DIGEST_MD5; |
wo->neg_magicnumber = 1; |
wo->neg_pcompression = 1; |
wo->neg_accompression = 1; |
wo->neg_lqr = 0; /* no LQR implementation yet */ |
wo->neg_cbcp = 0; |
|
ao->neg_mru = 1; |
ao->mru = MAXMRU; |
ao->neg_asyncmap = 1; |
ao->asyncmap = 0; |
ao->neg_chap = 1; |
ao->chap_mdtype = CHAP_DIGEST_MD5; |
ao->neg_upap = 1; |
ao->neg_magicnumber = 1; |
ao->neg_pcompression = 1; |
ao->neg_accompression = 1; |
ao->neg_lqr = 0; /* no LQR implementation yet */ |
#ifdef CBCP_SUPPORT |
ao->neg_cbcp = 1; |
#else |
ao->neg_cbcp = 0; |
#endif |
|
memset(xmit_accm[unit], 0, sizeof(xmit_accm[0])); |
xmit_accm[unit][3] = 0x60000000; |
} |
|
|
/* |
* lcp_open - LCP is allowed to come up. |
*/ |
void |
lcp_open(unit) |
int unit; |
{ |
fsm *f = &lcp_fsm[unit]; |
lcp_options *wo = &lcp_wantoptions[unit]; |
|
f->flags = 0; |
if (wo->passive) |
f->flags |= OPT_PASSIVE; |
if (wo->silent) |
f->flags |= OPT_SILENT; |
fsm_open(f); |
} |
|
|
/* |
* lcp_close - Take LCP down. |
*/ |
void |
lcp_close(unit, reason) |
int unit; |
char *reason; |
{ |
fsm *f = &lcp_fsm[unit]; |
|
if (phase != PHASE_DEAD) |
phase = PHASE_TERMINATE; |
if (f->state == STOPPED && f->flags & (OPT_PASSIVE|OPT_SILENT)) { |
/* |
* This action is not strictly according to the FSM in RFC1548, |
* but it does mean that the program terminates if you do a |
* lcp_close() in passive/silent mode when a connection hasn't |
* been established. |
*/ |
f->state = CLOSED; |
lcp_finished(f); |
|
} else |
fsm_close(&lcp_fsm[unit], reason); |
} |
|
|
/* |
* lcp_lowerup - The lower layer is up. |
*/ |
void |
lcp_lowerup(unit) |
int unit; |
{ |
lcp_options *wo = &lcp_wantoptions[unit]; |
|
/* |
* Don't use A/C or protocol compression on transmission, |
* but accept A/C and protocol compressed packets |
* if we are going to ask for A/C and protocol compression. |
*/ |
ppp_set_xaccm(unit, xmit_accm[unit]); |
ppp_send_config(unit, PPP_MRU, 0xffffffff, 0, 0); |
ppp_recv_config(unit, PPP_MRU, 0xffffffff, |
wo->neg_pcompression, wo->neg_accompression); |
peer_mru[unit] = PPP_MRU; |
lcp_allowoptions[unit].asyncmap = xmit_accm[unit][0]; |
|
fsm_lowerup(&lcp_fsm[unit]); |
} |
|
|
/* |
* lcp_lowerdown - The lower layer is down. |
*/ |
void |
lcp_lowerdown(unit) |
int unit; |
{ |
fsm_lowerdown(&lcp_fsm[unit]); |
} |
|
|
/* |
* lcp_input - Input LCP packet. |
*/ |
static void |
lcp_input(unit, p, len) |
int unit; |
u_char *p; |
int len; |
{ |
fsm *f = &lcp_fsm[unit]; |
|
fsm_input(f, p, len); |
} |
|
|
/* |
* lcp_extcode - Handle a LCP-specific code. |
*/ |
static int |
lcp_extcode(f, code, id, inp, len) |
fsm *f; |
int code, id; |
u_char *inp; |
int len; |
{ |
u_char *magp; |
|
switch( code ){ |
case PROTREJ: |
lcp_rprotrej(f, inp, len); |
break; |
|
case ECHOREQ: |
if (f->state != OPENED) |
break; |
LCPDEBUG((LOG_INFO, "lcp: Echo-Request, Rcvd id %d", id)); |
magp = inp; |
PUTLONG(lcp_gotoptions[f->unit].magicnumber, magp); |
fsm_sdata(f, ECHOREP, id, inp, len); |
break; |
|
case ECHOREP: |
lcp_received_echo_reply(f, id, inp, len); |
break; |
|
case DISCREQ: |
break; |
|
default: |
return 0; |
} |
return 1; |
} |
|
|
/* |
* lcp_rprotrej - Receive an Protocol-Reject. |
* |
* Figure out which protocol is rejected and inform it. |
*/ |
static void |
lcp_rprotrej(f, inp, len) |
fsm *f; |
u_char *inp; |
int len; |
{ |
int i; |
struct protent *protp; |
u_short prot; |
|
LCPDEBUG((LOG_INFO, "lcp_rprotrej.")); |
|
if (len < sizeof (u_short)) { |
LCPDEBUG((LOG_INFO, |
"lcp_rprotrej: Rcvd short Protocol-Reject packet!")); |
return; |
} |
|
GETSHORT(prot, inp); |
|
LCPDEBUG((LOG_INFO, |
"lcp_rprotrej: Rcvd Protocol-Reject packet for %x!", |
prot)); |
|
/* |
* Protocol-Reject packets received in any state other than the LCP |
* OPENED state SHOULD be silently discarded. |
*/ |
if( f->state != OPENED ){ |
LCPDEBUG((LOG_INFO, "Protocol-Reject discarded: LCP in state %d", |
f->state)); |
return; |
} |
|
/* |
* Upcall the proper Protocol-Reject routine. |
*/ |
for (i = 0; (protp = protocols[i]) != NULL; ++i) |
if (protp->protocol == prot && protp->enabled_flag) { |
(*protp->protrej)(f->unit); |
return; |
} |
|
syslog(LOG_WARNING, "Protocol-Reject for unsupported protocol 0x%x", |
prot); |
} |
|
|
/* |
* lcp_protrej - A Protocol-Reject was received. |
*/ |
/*ARGSUSED*/ |
static void |
lcp_protrej(unit) |
int unit; |
{ |
/* |
* Can't reject LCP! |
*/ |
LCPDEBUG((LOG_WARNING, |
"lcp_protrej: Received Protocol-Reject for LCP!")); |
fsm_protreject(&lcp_fsm[unit]); |
} |
|
|
/* |
* lcp_sprotrej - Send a Protocol-Reject for some protocol. |
*/ |
void |
lcp_sprotrej(unit, p, len) |
int unit; |
u_char *p; |
int len; |
{ |
/* |
* Send back the protocol and the information field of the |
* rejected packet. We only get here if LCP is in the OPENED state. |
*/ |
p += 2; |
len -= 2; |
|
fsm_sdata(&lcp_fsm[unit], PROTREJ, ++lcp_fsm[unit].id, |
p, len); |
} |
|
|
/* |
* lcp_resetci - Reset our CI. |
*/ |
static void |
lcp_resetci(f) |
fsm *f; |
{ |
lcp_wantoptions[f->unit].magicnumber = magic(); |
lcp_wantoptions[f->unit].numloops = 0; |
lcp_gotoptions[f->unit] = lcp_wantoptions[f->unit]; |
peer_mru[f->unit] = PPP_MRU; |
auth_reset(f->unit); |
} |
|
|
/* |
* lcp_cilen - Return length of our CI. |
*/ |
static int |
lcp_cilen(f) |
fsm *f; |
{ |
lcp_options *go = &lcp_gotoptions[f->unit]; |
|
#define LENCIVOID(neg) ((neg) ? CILEN_VOID : 0) |
#define LENCICHAP(neg) ((neg) ? CILEN_CHAP : 0) |
#define LENCISHORT(neg) ((neg) ? CILEN_SHORT : 0) |
#define LENCILONG(neg) ((neg) ? CILEN_LONG : 0) |
#define LENCILQR(neg) ((neg) ? CILEN_LQR: 0) |
#define LENCICBCP(neg) ((neg) ? CILEN_CBCP: 0) |
/* |
* NB: we only ask for one of CHAP and UPAP, even if we will |
* accept either. |
*/ |
return (LENCISHORT(go->neg_mru && go->mru != DEFMRU) + |
LENCILONG(go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) + |
LENCICHAP(go->neg_chap) + |
LENCISHORT(!go->neg_chap && go->neg_upap) + |
LENCILQR(go->neg_lqr) + |
LENCICBCP(go->neg_cbcp) + |
LENCILONG(go->neg_magicnumber) + |
LENCIVOID(go->neg_pcompression) + |
LENCIVOID(go->neg_accompression)); |
} |
|
|
/* |
* lcp_addci - Add our desired CIs to a packet. |
*/ |
static void |
lcp_addci(f, ucp, lenp) |
fsm *f; |
u_char *ucp; |
int *lenp; |
{ |
lcp_options *go = &lcp_gotoptions[f->unit]; |
u_char *start_ucp = ucp; |
|
#define ADDCIVOID(opt, neg) \ |
if (neg) { \ |
PUTCHAR(opt, ucp); \ |
PUTCHAR(CILEN_VOID, ucp); \ |
} |
#define ADDCISHORT(opt, neg, val) \ |
if (neg) { \ |
PUTCHAR(opt, ucp); \ |
PUTCHAR(CILEN_SHORT, ucp); \ |
PUTSHORT(val, ucp); \ |
} |
#define ADDCICHAP(opt, neg, val, digest) \ |
if (neg) { \ |
PUTCHAR(opt, ucp); \ |
PUTCHAR(CILEN_CHAP, ucp); \ |
PUTSHORT(val, ucp); \ |
PUTCHAR(digest, ucp); \ |
} |
#define ADDCILONG(opt, neg, val) \ |
if (neg) { \ |
PUTCHAR(opt, ucp); \ |
PUTCHAR(CILEN_LONG, ucp); \ |
PUTLONG(val, ucp); \ |
} |
#define ADDCILQR(opt, neg, val) \ |
if (neg) { \ |
PUTCHAR(opt, ucp); \ |
PUTCHAR(CILEN_LQR, ucp); \ |
PUTSHORT(PPP_LQR, ucp); \ |
PUTLONG(val, ucp); \ |
} |
#define ADDCICHAR(opt, neg, val) \ |
if (neg) { \ |
PUTCHAR(opt, ucp); \ |
PUTCHAR(CILEN_CHAR, ucp); \ |
PUTCHAR(val, ucp); \ |
} |
|
ADDCISHORT(CI_MRU, go->neg_mru && go->mru != DEFMRU, go->mru); |
ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF, |
go->asyncmap); |
ADDCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype); |
ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP); |
ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period); |
ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT); |
ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber); |
ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression); |
ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression); |
|
if (ucp - start_ucp != *lenp) { |
/* this should never happen, because peer_mtu should be 1500 */ |
syslog(LOG_ERR, "Bug in lcp_addci: wrong length") |
; |
} |
} |
|
|
/* |
* lcp_ackci - Ack our CIs. |
* This should not modify any state if the Ack is bad. |
* |
* Returns: |
* 0 - Ack was bad. |
* 1 - Ack was good. |
*/ |
static int |
lcp_ackci(f, p, len) |
fsm *f; |
u_char *p; |
int len; |
{ |
lcp_options *go = &lcp_gotoptions[f->unit]; |
u_char cilen, citype, cichar; |
u_short cishort; |
u_int32_t cilong; |
|
/* |
* CIs must be in exactly the same order that we sent. |
* Check packet length and CI length at each step. |
* If we find any deviations, then this packet is bad. |
*/ |
#define ACKCIVOID(opt, neg) \ |
if (neg) { \ |
if ((len -= CILEN_VOID) < 0) \ |
goto bad; \ |
GETCHAR(citype, p); \ |
GETCHAR(cilen, p); \ |
if (cilen != CILEN_VOID || \ |
citype != opt) \ |
goto bad; \ |
} |
#define ACKCISHORT(opt, neg, val) \ |
if (neg) { \ |
if ((len -= CILEN_SHORT) < 0) \ |
goto bad; \ |
GETCHAR(citype, p); \ |
GETCHAR(cilen, p); \ |
if (cilen != CILEN_SHORT || \ |
citype != opt) \ |
goto bad; \ |
GETSHORT(cishort, p); \ |
if (cishort != val) \ |
goto bad; \ |
} |
#define ACKCICHAR(opt, neg, val) \ |
if (neg) { \ |
if ((len -= CILEN_CHAR) < 0) \ |
goto bad; \ |
GETCHAR(citype, p); \ |
GETCHAR(cilen, p); \ |
if (cilen != CILEN_CHAR || \ |
citype != opt) \ |
goto bad; \ |
GETCHAR(cichar, p); \ |
if (cichar != val) \ |
goto bad; \ |
} |
#define ACKCICHAP(opt, neg, val, digest) \ |
if (neg) { \ |
if ((len -= CILEN_CHAP) < 0) \ |
goto bad; \ |
GETCHAR(citype, p); \ |
GETCHAR(cilen, p); \ |
if (cilen != CILEN_CHAP || \ |
citype != opt) \ |
goto bad; \ |
GETSHORT(cishort, p); \ |
if (cishort != val) \ |
goto bad; \ |
GETCHAR(cichar, p); \ |
if (cichar != digest) \ |
goto bad; \ |
} |
#define ACKCILONG(opt, neg, val) \ |
if (neg) { \ |
if ((len -= CILEN_LONG) < 0) \ |
goto bad; \ |
GETCHAR(citype, p); \ |
GETCHAR(cilen, p); \ |
if (cilen != CILEN_LONG || \ |
citype != opt) \ |
goto bad; \ |
GETLONG(cilong, p); \ |
if (cilong != val) \ |
goto bad; \ |
} |
#define ACKCILQR(opt, neg, val) \ |
if (neg) { \ |
if ((len -= CILEN_LQR) < 0) \ |
goto bad; \ |
GETCHAR(citype, p); \ |
GETCHAR(cilen, p); \ |
if (cilen != CILEN_LQR || \ |
citype != opt) \ |
goto bad; \ |
GETSHORT(cishort, p); \ |
if (cishort != PPP_LQR) \ |
goto bad; \ |
GETLONG(cilong, p); \ |
if (cilong != val) \ |
goto bad; \ |
} |
|
ACKCISHORT(CI_MRU, go->neg_mru && go->mru != DEFMRU, go->mru); |
ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF, |
go->asyncmap); |
ACKCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype); |
ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP); |
ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period); |
ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT); |
ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber); |
ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression); |
ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression); |
|
/* |
* If there are any remaining CIs, then this packet is bad. |
*/ |
if (len != 0) |
goto bad; |
return (1); |
bad: |
LCPDEBUG((LOG_WARNING, "lcp_acki: received bad Ack!")); |
return (0); |
} |
|
|
/* |
* lcp_nakci - Peer has sent a NAK for some of our CIs. |
* This should not modify any state if the Nak is bad |
* or if LCP is in the OPENED state. |
* |
* Returns: |
* 0 - Nak was bad. |
* 1 - Nak was good. |
*/ |
static int |
lcp_nakci(f, p, len) |
fsm *f; |
u_char *p; |
int len; |
{ |
lcp_options *go = &lcp_gotoptions[f->unit]; |
lcp_options *wo = &lcp_wantoptions[f->unit]; |
u_char citype, cichar, *next; |
u_short cishort; |
u_int32_t cilong; |
lcp_options no; /* options we've seen Naks for */ |
lcp_options try; /* options to request next time */ |
int looped_back = 0; |
int cilen; |
|
BZERO(&no, sizeof(no)); |
try = *go; |
|
/* |
* Any Nak'd CIs must be in exactly the same order that we sent. |
* Check packet length and CI length at each step. |
* If we find any deviations, then this packet is bad. |
*/ |
#define NAKCIVOID(opt, neg, code) \ |
if (go->neg && \ |
len >= CILEN_VOID && \ |
p[1] == CILEN_VOID && \ |
p[0] == opt) { \ |
len -= CILEN_VOID; \ |
INCPTR(CILEN_VOID, p); \ |
no.neg = 1; \ |
code \ |
} |
#define NAKCICHAP(opt, neg, code) \ |
if (go->neg && \ |
len >= CILEN_CHAP && \ |
p[1] == CILEN_CHAP && \ |
p[0] == opt) { \ |
len -= CILEN_CHAP; \ |
INCPTR(2, p); \ |
GETSHORT(cishort, p); \ |
GETCHAR(cichar, p); \ |
no.neg = 1; \ |
code \ |
} |
#define NAKCICHAR(opt, neg, code) \ |
if (go->neg && \ |
len >= CILEN_CHAR && \ |
p[1] == CILEN_CHAR && \ |
p[0] == opt) { \ |
len -= CILEN_CHAR; \ |
INCPTR(2, p); \ |
GETCHAR(cichar, p); \ |
no.neg = 1; \ |
code \ |
} |
#define NAKCISHORT(opt, neg, code) \ |
if (go->neg && \ |
len >= CILEN_SHORT && \ |
p[1] == CILEN_SHORT && \ |
p[0] == opt) { \ |
len -= CILEN_SHORT; \ |
INCPTR(2, p); \ |
GETSHORT(cishort, p); \ |
no.neg = 1; \ |
code \ |
} |
#define NAKCILONG(opt, neg, code) \ |
if (go->neg && \ |
len >= CILEN_LONG && \ |
p[1] == CILEN_LONG && \ |
p[0] == opt) { \ |
len -= CILEN_LONG; \ |
INCPTR(2, p); \ |
GETLONG(cilong, p); \ |
no.neg = 1; \ |
code \ |
} |
#define NAKCILQR(opt, neg, code) \ |
if (go->neg && \ |
len >= CILEN_LQR && \ |
p[1] == CILEN_LQR && \ |
p[0] == opt) { \ |
len -= CILEN_LQR; \ |
INCPTR(2, p); \ |
GETSHORT(cishort, p); \ |
GETLONG(cilong, p); \ |
no.neg = 1; \ |
code \ |
} |
|
/* |
* We don't care if they want to send us smaller packets than |
* we want. Therefore, accept any MRU less than what we asked for, |
* but then ignore the new value when setting the MRU in the kernel. |
* If they send us a bigger MRU than what we asked, accept it, up to |
* the limit of the default MRU we'd get if we didn't negotiate. |
*/ |
if (go->neg_mru && go->mru != DEFMRU) { |
NAKCISHORT(CI_MRU, neg_mru, |
if (cishort <= wo->mru || cishort <= DEFMRU) |
try.mru = cishort; |
); |
} |
|
/* |
* Add any characters they want to our (receive-side) asyncmap. |
*/ |
if (go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) { |
NAKCILONG(CI_ASYNCMAP, neg_asyncmap, |
try.asyncmap = go->asyncmap | cilong; |
); |
} |
|
/* |
* If they've nak'd our authentication-protocol, check whether |
* they are proposing a different protocol, or a different |
* hash algorithm for CHAP. |
*/ |
if ((go->neg_chap || go->neg_upap) |
&& len >= CILEN_SHORT |
&& p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT && p[1] <= len) { |
cilen = p[1]; |
len -= cilen; |
no.neg_chap = go->neg_chap; |
no.neg_upap = go->neg_upap; |
INCPTR(2, p); |
GETSHORT(cishort, p); |
if (cishort == PPP_PAP && cilen == CILEN_SHORT) { |
/* |
* If we were asking for CHAP, they obviously don't want to do it. |
* If we weren't asking for CHAP, then we were asking for PAP, |
* in which case this Nak is bad. |
*/ |
if (!go->neg_chap) |
goto bad; |
try.neg_chap = 0; |
|
} else if (cishort == PPP_CHAP && cilen == CILEN_CHAP) { |
GETCHAR(cichar, p); |
if (go->neg_chap) { |
/* |
* We were asking for CHAP/MD5; they must want a different |
* algorithm. If they can't do MD5, we'll have to stop |
* asking for CHAP. |
*/ |
if (cichar != go->chap_mdtype) |
try.neg_chap = 0; |
} else { |
/* |
* Stop asking for PAP if we were asking for it. |
*/ |
try.neg_upap = 0; |
} |
|
} else { |
/* |
* We don't recognize what they're suggesting. |
* Stop asking for what we were asking for. |
*/ |
if (go->neg_chap) |
try.neg_chap = 0; |
else |
try.neg_upap = 0; |
p += cilen - CILEN_SHORT; |
} |
} |
|
/* |
* If they can't cope with our link quality protocol, we'll have |
* to stop asking for LQR. We haven't got any other protocol. |
* If they Nak the reporting period, take their value XXX ? |
*/ |
NAKCILQR(CI_QUALITY, neg_lqr, |
if (cishort != PPP_LQR) |
try.neg_lqr = 0; |
else |
try.lqr_period = cilong; |
); |
|
/* |
* Only implementing CBCP...not the rest of the callback options |
*/ |
NAKCICHAR(CI_CALLBACK, neg_cbcp, |
try.neg_cbcp = 0; |
); |
|
/* |
* Check for a looped-back line. |
*/ |
NAKCILONG(CI_MAGICNUMBER, neg_magicnumber, |
try.magicnumber = magic(); |
looped_back = 1; |
); |
|
/* |
* Peer shouldn't send Nak for protocol compression or |
* address/control compression requests; they should send |
* a Reject instead. If they send a Nak, treat it as a Reject. |
*/ |
NAKCIVOID(CI_PCOMPRESSION, neg_pcompression, |
try.neg_pcompression = 0; |
); |
NAKCIVOID(CI_ACCOMPRESSION, neg_accompression, |
try.neg_accompression = 0; |
); |
|
/* |
* There may be remaining CIs, if the peer is requesting negotiation |
* on an option that we didn't include in our request packet. |
* If we see an option that we requested, or one we've already seen |
* in this packet, then this packet is bad. |
* If we wanted to respond by starting to negotiate on the requested |
* option(s), we could, but we don't, because except for the |
* authentication type and quality protocol, if we are not negotiating |
* an option, it is because we were told not to. |
* For the authentication type, the Nak from the peer means |
* `let me authenticate myself with you' which is a bit pointless. |
* For the quality protocol, the Nak means `ask me to send you quality |
* reports', but if we didn't ask for them, we don't want them. |
* An option we don't recognize represents the peer asking to |
* negotiate some option we don't support, so ignore it. |
*/ |
while (len > CILEN_VOID) { |
GETCHAR(citype, p); |
GETCHAR(cilen, p); |
if (cilen < CILEN_VOID || (len -= cilen) < 0) |
goto bad; |
next = p + cilen - 2; |
|
switch (citype) { |
case CI_MRU: |
if ((go->neg_mru && go->mru != DEFMRU) |
|| no.neg_mru || cilen != CILEN_SHORT) |
goto bad; |
GETSHORT(cishort, p); |
if (cishort < DEFMRU) |
try.mru = cishort; |
break; |
case CI_ASYNCMAP: |
if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) |
|| no.neg_asyncmap || cilen != CILEN_LONG) |
goto bad; |
break; |
case CI_AUTHTYPE: |
if (go->neg_chap || no.neg_chap || go->neg_upap || no.neg_upap) |
goto bad; |
break; |
case CI_MAGICNUMBER: |
if (go->neg_magicnumber || no.neg_magicnumber || |
cilen != CILEN_LONG) |
goto bad; |
break; |
case CI_PCOMPRESSION: |
if (go->neg_pcompression || no.neg_pcompression |
|| cilen != CILEN_VOID) |
goto bad; |
break; |
case CI_ACCOMPRESSION: |
if (go->neg_accompression || no.neg_accompression |
|| cilen != CILEN_VOID) |
goto bad; |
break; |
case CI_QUALITY: |
if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR) |
goto bad; |
break; |
} |
p = next; |
} |
|
/* If there is still anything left, this packet is bad. */ |
if (len != 0) |
goto bad; |
|
/* |
* OK, the Nak is good. Now we can update state. |
*/ |
if (f->state != OPENED) { |
if (looped_back) { |
if (++try.numloops >= lcp_loopbackfail) { |
syslog(LOG_NOTICE, "Serial line is looped back."); |
lcp_close(f->unit, "Loopback detected"); |
} |
} else |
try.numloops = 0; |
*go = try; |
} |
|
return 1; |
|
bad: |
LCPDEBUG((LOG_WARNING, "lcp_nakci: received bad Nak!")); |
return 0; |
} |
|
|
/* |
* lcp_rejci - Peer has Rejected some of our CIs. |
* This should not modify any state if the Reject is bad |
* or if LCP is in the OPENED state. |
* |
* Returns: |
* 0 - Reject was bad. |
* 1 - Reject was good. |
*/ |
static int |
lcp_rejci(f, p, len) |
fsm *f; |
u_char *p; |
int len; |
{ |
lcp_options *go = &lcp_gotoptions[f->unit]; |
u_char cichar; |
u_short cishort; |
u_int32_t cilong; |
lcp_options try; /* options to request next time */ |
|
try = *go; |
|
/* |
* Any Rejected CIs must be in exactly the same order that we sent. |
* Check packet length and CI length at each step. |
* If we find any deviations, then this packet is bad. |
*/ |
#define REJCIVOID(opt, neg) \ |
if (go->neg && \ |
len >= CILEN_VOID && \ |
p[1] == CILEN_VOID && \ |
p[0] == opt) { \ |
len -= CILEN_VOID; \ |
INCPTR(CILEN_VOID, p); \ |
try.neg = 0; \ |
LCPDEBUG((LOG_INFO, "lcp_rejci rejected void opt %d", opt)); \ |
} |
#define REJCISHORT(opt, neg, val) \ |
if (go->neg && \ |
len >= CILEN_SHORT && \ |
p[1] == CILEN_SHORT && \ |
p[0] == opt) { \ |
len -= CILEN_SHORT; \ |
INCPTR(2, p); \ |
GETSHORT(cishort, p); \ |
/* Check rejected value. */ \ |
if (cishort != val) \ |
goto bad; \ |
try.neg = 0; \ |
LCPDEBUG((LOG_INFO,"lcp_rejci rejected short opt %d", opt)); \ |
} |
#define REJCICHAP(opt, neg, val, digest) \ |
if (go->neg && \ |
len >= CILEN_CHAP && \ |
p[1] == CILEN_CHAP && \ |
p[0] == opt) { \ |
len -= CILEN_CHAP; \ |
INCPTR(2, p); \ |
GETSHORT(cishort, p); \ |
GETCHAR(cichar, p); \ |
/* Check rejected value. */ \ |
if (cishort != val || cichar != digest) \ |
goto bad; \ |
try.neg = 0; \ |
try.neg_upap = 0; \ |
LCPDEBUG((LOG_INFO,"lcp_rejci rejected chap opt %d", opt)); \ |
} |
#define REJCILONG(opt, neg, val) \ |
if (go->neg && \ |
len >= CILEN_LONG && \ |
p[1] == CILEN_LONG && \ |
p[0] == opt) { \ |
len -= CILEN_LONG; \ |
INCPTR(2, p); \ |
GETLONG(cilong, p); \ |
/* Check rejected value. */ \ |
if (cilong != val) \ |
goto bad; \ |
try.neg = 0; \ |
LCPDEBUG((LOG_INFO,"lcp_rejci rejected long opt %d", opt)); \ |
} |
#define REJCILQR(opt, neg, val) \ |
if (go->neg && \ |
len >= CILEN_LQR && \ |
p[1] == CILEN_LQR && \ |
p[0] == opt) { \ |
len -= CILEN_LQR; \ |
INCPTR(2, p); \ |
GETSHORT(cishort, p); \ |
GETLONG(cilong, p); \ |
/* Check rejected value. */ \ |
if (cishort != PPP_LQR || cilong != val) \ |
goto bad; \ |
try.neg = 0; \ |
LCPDEBUG((LOG_INFO,"lcp_rejci rejected LQR opt %d", opt)); \ |
} |
#define REJCICBCP(opt, neg, val) \ |
if (go->neg && \ |
len >= CILEN_CBCP && \ |
p[1] == CILEN_CBCP && \ |
p[0] == opt) { \ |
len -= CILEN_CBCP; \ |
INCPTR(2, p); \ |
GETCHAR(cichar, p); \ |
/* Check rejected value. */ \ |
if (cichar != val) \ |
goto bad; \ |
try.neg = 0; \ |
LCPDEBUG((LOG_INFO,"lcp_rejci rejected Callback opt %d", opt)); \ |
} |
|
REJCISHORT(CI_MRU, neg_mru, go->mru); |
REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap); |
REJCICHAP(CI_AUTHTYPE, neg_chap, PPP_CHAP, go->chap_mdtype); |
if (!go->neg_chap) { |
REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP); |
} |
REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period); |
REJCICBCP(CI_CALLBACK, neg_cbcp, CBCP_OPT); |
REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber); |
REJCIVOID(CI_PCOMPRESSION, neg_pcompression); |
REJCIVOID(CI_ACCOMPRESSION, neg_accompression); |
|
/* |
* If there are any remaining CIs, then this packet is bad. |
*/ |
if (len != 0) |
goto bad; |
/* |
* Now we can update state. |
*/ |
if (f->state != OPENED) |
*go = try; |
return 1; |
|
bad: |
LCPDEBUG((LOG_WARNING, "lcp_rejci: received bad Reject!")); |
return 0; |
} |
|
|
/* |
* lcp_reqci - Check the peer's requested CIs and send appropriate response. |
* |
* Returns: CONFACK, CONFNAK or CONFREJ and input packet modified |
* appropriately. If reject_if_disagree is non-zero, doesn't return |
* CONFNAK; returns CONFREJ if it can't return CONFACK. |
*/ |
static int |
lcp_reqci(f, inp, lenp, reject_if_disagree) |
fsm *f; |
u_char *inp; /* Requested CIs */ |
int *lenp; /* Length of requested CIs */ |
int reject_if_disagree; |
{ |
lcp_options *go = &lcp_gotoptions[f->unit]; |
lcp_options *ho = &lcp_hisoptions[f->unit]; |
lcp_options *ao = &lcp_allowoptions[f->unit]; |
u_char *cip, *next; /* Pointer to current and next CIs */ |
int cilen, citype, cichar; /* Parsed len, type, char value */ |
u_short cishort; /* Parsed short value */ |
u_int32_t cilong; /* Parse long value */ |
int rc = CONFACK; /* Final packet return code */ |
int orc; /* Individual option return code */ |
u_char *p; /* Pointer to next char to parse */ |
u_char *rejp; /* Pointer to next char in reject frame */ |
u_char *nakp; /* Pointer to next char in Nak frame */ |
int l = *lenp; /* Length left */ |
|
/* |
* Reset all his options. |
*/ |
BZERO(ho, sizeof(*ho)); |
|
/* |
* Process all his options. |
*/ |
next = inp; |
nakp = nak_buffer; |
rejp = inp; |
while (l) { |
orc = CONFACK; /* Assume success */ |
cip = p = next; /* Remember begining of CI */ |
if (l < 2 || /* Not enough data for CI header or */ |
p[1] < 2 || /* CI length too small or */ |
p[1] > l) { /* CI length too big? */ |
LCPDEBUG((LOG_WARNING, "lcp_reqci: bad CI length!")); |
orc = CONFREJ; /* Reject bad CI */ |
cilen = l; /* Reject till end of packet */ |
l = 0; /* Don't loop again */ |
citype = 0; |
goto endswitch; |
} |
GETCHAR(citype, p); /* Parse CI type */ |
GETCHAR(cilen, p); /* Parse CI length */ |
l -= cilen; /* Adjust remaining length */ |
next += cilen; /* Step to next CI */ |
|
switch (citype) { /* Check CI type */ |
case CI_MRU: |
LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd MRU")); |
if (!ao->neg_mru || /* Allow option? */ |
cilen != CILEN_SHORT) { /* Check CI length */ |
orc = CONFREJ; /* Reject CI */ |
break; |
} |
GETSHORT(cishort, p); /* Parse MRU */ |
LCPDEBUG((LOG_INFO, "(%d)", cishort)); |
|
/* |
* He must be able to receive at least our minimum. |
* No need to check a maximum. If he sends a large number, |
* we'll just ignore it. |
*/ |
if (cishort < MINMRU) { |
orc = CONFNAK; /* Nak CI */ |
PUTCHAR(CI_MRU, nakp); |
PUTCHAR(CILEN_SHORT, nakp); |
PUTSHORT(MINMRU, nakp); /* Give him a hint */ |
break; |
} |
ho->neg_mru = 1; /* Remember he sent MRU */ |
ho->mru = cishort; /* And remember value */ |
break; |
|
case CI_ASYNCMAP: |
LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd ASYNCMAP")); |
if (!ao->neg_asyncmap || |
cilen != CILEN_LONG) { |
orc = CONFREJ; |
break; |
} |
GETLONG(cilong, p); |
LCPDEBUG((LOG_INFO, "(%x)", (unsigned int) cilong)); |
|
/* |
* Asyncmap must have set at least the bits |
* which are set in lcp_allowoptions[unit].asyncmap. |
*/ |
if ((ao->asyncmap & ~cilong) != 0) { |
orc = CONFNAK; |
PUTCHAR(CI_ASYNCMAP, nakp); |
PUTCHAR(CILEN_LONG, nakp); |
PUTLONG(ao->asyncmap | cilong, nakp); |
break; |
} |
ho->neg_asyncmap = 1; |
ho->asyncmap = cilong; |
break; |
|
case CI_AUTHTYPE: |
LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd AUTHTYPE")); |
if (cilen < CILEN_SHORT || |
!(ao->neg_upap || ao->neg_chap)) { |
/* |
* Reject the option if we're not willing to authenticate. |
*/ |
orc = CONFREJ; |
break; |
} |
GETSHORT(cishort, p); |
LCPDEBUG((LOG_INFO, "(%x)", cishort)); |
|
/* |
* Authtype must be UPAP or CHAP. |
* |
* Note: if both ao->neg_upap and ao->neg_chap are set, |
* and the peer sends a Configure-Request with two |
* authenticate-protocol requests, one for CHAP and one |
* for UPAP, then we will reject the second request. |
* Whether we end up doing CHAP or UPAP depends then on |
* the ordering of the CIs in the peer's Configure-Request. |
*/ |
|
if (cishort == PPP_PAP) { |
if (ho->neg_chap || /* we've already accepted CHAP */ |
cilen != CILEN_SHORT) { |
LCPDEBUG((LOG_WARNING, |
"lcp_reqci: rcvd AUTHTYPE PAP, rejecting...")); |
orc = CONFREJ; |
break; |
} |
if (!ao->neg_upap) { /* we don't want to do PAP */ |
orc = CONFNAK; /* NAK it and suggest CHAP */ |
PUTCHAR(CI_AUTHTYPE, nakp); |
PUTCHAR(CILEN_CHAP, nakp); |
PUTSHORT(PPP_CHAP, nakp); |
PUTCHAR(ao->chap_mdtype, nakp); |
break; |
} |
ho->neg_upap = 1; |
break; |
} |
if (cishort == PPP_CHAP) { |
if (ho->neg_upap || /* we've already accepted PAP */ |
cilen != CILEN_CHAP) { |
LCPDEBUG((LOG_INFO, |
"lcp_reqci: rcvd AUTHTYPE CHAP, rejecting...")); |
orc = CONFREJ; |
break; |
} |
if (!ao->neg_chap) { /* we don't want to do CHAP */ |
orc = CONFNAK; /* NAK it and suggest PAP */ |
PUTCHAR(CI_AUTHTYPE, nakp); |
PUTCHAR(CILEN_SHORT, nakp); |
PUTSHORT(PPP_PAP, nakp); |
break; |
} |
GETCHAR(cichar, p); /* get digest type*/ |
if (cichar != CHAP_DIGEST_MD5 |
#ifdef CHAPMS |
&& cichar != CHAP_MICROSOFT |
#endif |
) { |
orc = CONFNAK; |
PUTCHAR(CI_AUTHTYPE, nakp); |
PUTCHAR(CILEN_CHAP, nakp); |
PUTSHORT(PPP_CHAP, nakp); |
PUTCHAR(ao->chap_mdtype, nakp); |
break; |
} |
ho->chap_mdtype = cichar; /* save md type */ |
ho->neg_chap = 1; |
break; |
} |
|
/* |
* We don't recognize the protocol they're asking for. |
* Nak it with something we're willing to do. |
* (At this point we know ao->neg_upap || ao->neg_chap.) |
*/ |
orc = CONFNAK; |
PUTCHAR(CI_AUTHTYPE, nakp); |
if (ao->neg_chap) { |
PUTCHAR(CILEN_CHAP, nakp); |
PUTSHORT(PPP_CHAP, nakp); |
PUTCHAR(ao->chap_mdtype, nakp); |
} else { |
PUTCHAR(CILEN_SHORT, nakp); |
PUTSHORT(PPP_PAP, nakp); |
} |
break; |
|
case CI_QUALITY: |
LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd QUALITY")); |
if (!ao->neg_lqr || |
cilen != CILEN_LQR) { |
orc = CONFREJ; |
break; |
} |
|
GETSHORT(cishort, p); |
GETLONG(cilong, p); |
LCPDEBUG((LOG_INFO, "(%x %x)", cishort, (unsigned int) cilong)); |
|
/* |
* Check the protocol and the reporting period. |
* XXX When should we Nak this, and what with? |
*/ |
if (cishort != PPP_LQR) { |
orc = CONFNAK; |
PUTCHAR(CI_QUALITY, nakp); |
PUTCHAR(CILEN_LQR, nakp); |
PUTSHORT(PPP_LQR, nakp); |
PUTLONG(ao->lqr_period, nakp); |
break; |
} |
break; |
|
case CI_MAGICNUMBER: |
LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd MAGICNUMBER")); |
if (!(ao->neg_magicnumber || go->neg_magicnumber) || |
cilen != CILEN_LONG) { |
orc = CONFREJ; |
break; |
} |
GETLONG(cilong, p); |
LCPDEBUG((LOG_INFO, "(%x)", (unsigned int) cilong)); |
|
/* |
* He must have a different magic number. |
*/ |
if (go->neg_magicnumber && |
cilong == go->magicnumber) { |
cilong = magic(); /* Don't put magic() inside macro! */ |
orc = CONFNAK; |
PUTCHAR(CI_MAGICNUMBER, nakp); |
PUTCHAR(CILEN_LONG, nakp); |
PUTLONG(cilong, nakp); |
break; |
} |
ho->neg_magicnumber = 1; |
ho->magicnumber = cilong; |
break; |
|
|
case CI_PCOMPRESSION: |
LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd PCOMPRESSION")); |
if (!ao->neg_pcompression || |
cilen != CILEN_VOID) { |
orc = CONFREJ; |
break; |
} |
ho->neg_pcompression = 1; |
break; |
|
case CI_ACCOMPRESSION: |
LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd ACCOMPRESSION")); |
if (!ao->neg_accompression || |
cilen != CILEN_VOID) { |
orc = CONFREJ; |
break; |
} |
ho->neg_accompression = 1; |
break; |
|
default: |
LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd unknown option %d", |
citype)); |
orc = CONFREJ; |
break; |
} |
|
endswitch: |
LCPDEBUG((LOG_INFO, " (%s)", CODENAME(orc))); |
if (orc == CONFACK && /* Good CI */ |
rc != CONFACK) /* but prior CI wasnt? */ |
continue; /* Don't send this one */ |
|
if (orc == CONFNAK) { /* Nak this CI? */ |
if (reject_if_disagree /* Getting fed up with sending NAKs? */ |
&& citype != CI_MAGICNUMBER) { |
orc = CONFREJ; /* Get tough if so */ |
} else { |
if (rc == CONFREJ) /* Rejecting prior CI? */ |
continue; /* Don't send this one */ |
rc = CONFNAK; |
} |
} |
if (orc == CONFREJ) { /* Reject this CI */ |
rc = CONFREJ; |
if (cip != rejp) /* Need to move rejected CI? */ |
BCOPY(cip, rejp, cilen); /* Move it */ |
INCPTR(cilen, rejp); /* Update output pointer */ |
} |
} |
|
/* |
* If we wanted to send additional NAKs (for unsent CIs), the |
* code would go here. The extra NAKs would go at *nakp. |
* At present there are no cases where we want to ask the |
* peer to negotiate an option. |
*/ |
|
switch (rc) { |
case CONFACK: |
*lenp = next - inp; |
break; |
case CONFNAK: |
/* |
* Copy the Nak'd options from the nak_buffer to the caller's buffer. |
*/ |
*lenp = nakp - nak_buffer; |
BCOPY(nak_buffer, inp, *lenp); |
break; |
case CONFREJ: |
*lenp = rejp - inp; |
break; |
} |
|
LCPDEBUG((LOG_INFO, "lcp_reqci: returning CONF%s.", CODENAME(rc))); |
return (rc); /* Return final code */ |
} |
|
|
/* |
* lcp_up - LCP has come UP. |
*/ |
static void |
lcp_up(f) |
fsm *f; |
{ |
lcp_options *wo = &lcp_wantoptions[f->unit]; |
lcp_options *ho = &lcp_hisoptions[f->unit]; |
lcp_options *go = &lcp_gotoptions[f->unit]; |
lcp_options *ao = &lcp_allowoptions[f->unit]; |
|
if (!go->neg_magicnumber) |
go->magicnumber = 0; |
if (!ho->neg_magicnumber) |
ho->magicnumber = 0; |
|
/* |
* Set our MTU to the smaller of the MTU we wanted and |
* the MRU our peer wanted. If we negotiated an MRU, |
* set our MRU to the larger of value we wanted and |
* the value we got in the negotiation. |
*/ |
ppp_send_config(f->unit, MIN(ao->mru, (ho->neg_mru? ho->mru: PPP_MRU)), |
(ho->neg_asyncmap? ho->asyncmap: 0xffffffff), |
ho->neg_pcompression, ho->neg_accompression); |
ppp_recv_config(f->unit, (go->neg_mru? MAX(wo->mru, go->mru): PPP_MRU), |
(go->neg_asyncmap? go->asyncmap: 0xffffffff), |
go->neg_pcompression, go->neg_accompression); |
|
if (ho->neg_mru) |
peer_mru[f->unit] = ho->mru; |
|
lcp_echo_lowerup(f->unit); /* Enable echo messages */ |
|
link_established(f->unit); |
} |
|
|
/* |
* lcp_down - LCP has gone DOWN. |
* |
* Alert other protocols. |
*/ |
static void |
lcp_down(f) |
fsm *f; |
{ |
lcp_options *go = &lcp_gotoptions[f->unit]; |
|
lcp_echo_lowerdown(f->unit); |
|
link_down(f->unit); |
|
ppp_send_config(f->unit, PPP_MRU, 0xffffffff, 0, 0); |
ppp_recv_config(f->unit, PPP_MRU, |
(go->neg_asyncmap? go->asyncmap: 0xffffffff), |
go->neg_pcompression, go->neg_accompression); |
peer_mru[f->unit] = PPP_MRU; |
} |
|
|
/* |
* lcp_starting - LCP needs the lower layer up. |
*/ |
static void |
lcp_starting(f) |
fsm *f; |
{ |
link_required(f->unit); |
} |
|
|
/* |
* lcp_finished - LCP has finished with the lower layer. |
*/ |
static void |
lcp_finished(f) |
fsm *f; |
{ |
link_terminated(f->unit); |
} |
|
|
/* |
* lcp_printpkt - print the contents of an LCP packet. |
*/ |
static char *lcp_codenames[] = { |
"ConfReq", "ConfAck", "ConfNak", "ConfRej", |
"TermReq", "TermAck", "CodeRej", "ProtRej", |
"EchoReq", "EchoRep", "DiscReq" |
}; |
|
static int |
lcp_printpkt(p, plen, printer, arg) |
u_char *p; |
int plen; |
void (*printer) __P((void *, char *, ...)); |
void *arg; |
{ |
int code, id, len, olen; |
u_char *pstart, *optend; |
u_short cishort; |
u_int32_t cilong; |
|
if (plen < HEADERLEN) |
return 0; |
pstart = p; |
GETCHAR(code, p); |
GETCHAR(id, p); |
GETSHORT(len, p); |
if (len < HEADERLEN || len > plen) |
return 0; |
|
if (code >= 1 && code <= sizeof(lcp_codenames) / sizeof(char *)) |
printer(arg, " %s", lcp_codenames[code-1]); |
else |
printer(arg, " code=0x%x", code); |
printer(arg, " id=0x%x", id); |
len -= HEADERLEN; |
switch (code) { |
case CONFREQ: |
case CONFACK: |
case CONFNAK: |
case CONFREJ: |
|
while (len >= 2) { |
GETCHAR(code, p); |
GETCHAR(olen, p); |
p -= 2; |
if (olen < 2 || olen > len) { |
break; |
} |
printer(arg, " <"); |
len -= olen; |
optend = p + olen; |
switch (code) { |
case CI_MRU: |
if (olen == CILEN_SHORT) { |
p += 2; |
GETSHORT(cishort, p); |
printer(arg, "mru %d", cishort); |
} |
break; |
case CI_ASYNCMAP: |
if (olen == CILEN_LONG) { |
p += 2; |
GETLONG(cilong, p); |
printer(arg, "asyncmap 0x%x", cilong); |
} |
break; |
case CI_AUTHTYPE: |
if (olen >= CILEN_SHORT) { |
p += 2; |
printer(arg, "auth "); |
GETSHORT(cishort, p); |
switch (cishort) { |
case PPP_PAP: |
printer(arg, "pap"); |
break; |
case PPP_CHAP: |
printer(arg, "chap"); |
break; |
default: |
printer(arg, "0x%x", cishort); |
} |
} |
break; |
case CI_QUALITY: |
if (olen >= CILEN_SHORT) { |
p += 2; |
printer(arg, "quality "); |
GETSHORT(cishort, p); |
switch (cishort) { |
case PPP_LQR: |
printer(arg, "lqr"); |
break; |
default: |
printer(arg, "0x%x", cishort); |
} |
} |
break; |
case CI_CALLBACK: |
if (olen >= CILEN_CHAR) { |
p += 2; |
printer(arg, "callback "); |
GETSHORT(cishort, p); |
switch (cishort) { |
case CBCP_OPT: |
printer(arg, "CBCP"); |
break; |
default: |
printer(arg, "0x%x", cishort); |
} |
} |
break; |
case CI_MAGICNUMBER: |
if (olen == CILEN_LONG) { |
p += 2; |
GETLONG(cilong, p); |
printer(arg, "magic 0x%x", cilong); |
} |
break; |
case CI_PCOMPRESSION: |
if (olen == CILEN_VOID) { |
p += 2; |
printer(arg, "pcomp"); |
} |
break; |
case CI_ACCOMPRESSION: |
if (olen == CILEN_VOID) { |
p += 2; |
printer(arg, "accomp"); |
} |
break; |
} |
while (p < optend) { |
GETCHAR(code, p); |
printer(arg, " %.2x", code); |
} |
printer(arg, ">"); |
} |
break; |
|
case TERMACK: |
case TERMREQ: |
if (len > 0 && *p >= ' ' && *p < 0x7f) { |
printer(arg, " "); |
print_string(p, len, printer, arg); |
p += len; |
len = 0; |
} |
break; |
|
case ECHOREQ: |
case ECHOREP: |
case DISCREQ: |
if (len >= 4) { |
GETLONG(cilong, p); |
printer(arg, " magic=0x%x", cilong); |
p += 4; |
len -= 4; |
} |
break; |
} |
|
|
for (; len > 0; --len) { |
GETCHAR(code, p); |
printer(arg, " %.2x", code); |
} |
|
return p - pstart; |
} |
|
/* |
* Time to shut down the link because there is nothing out there. |
*/ |
|
static |
void LcpLinkFailure (f) |
fsm *f; |
{ |
if (f->state == OPENED) { |
syslog(LOG_INFO, "No response to %d echo-requests", lcp_echos_pending); |
syslog(LOG_NOTICE, "Serial link appears to be disconnected."); |
lcp_close(f->unit, "Peer not responding"); |
} |
} |
|
/* |
* Timer expired for the LCP echo requests from this process. |
*/ |
|
static void |
LcpEchoCheck (f) |
fsm *f; |
{ |
LcpSendEchoRequest (f); |
|
/* |
* Start the timer for the next interval. |
*/ |
assert (lcp_echo_timer_running==0); |
TIMEOUT (LcpEchoTimeout, f, lcp_echo_interval); |
lcp_echo_timer_running = 1; |
} |
|
/* |
* LcpEchoTimeout - Timer expired on the LCP echo |
*/ |
|
static void |
LcpEchoTimeout (arg) |
void *arg; |
{ |
if (lcp_echo_timer_running != 0) { |
lcp_echo_timer_running = 0; |
LcpEchoCheck ((fsm *) arg); |
} |
} |
|
/* |
* LcpEchoReply - LCP has received a reply to the echo |
*/ |
|
static void |
lcp_received_echo_reply (f, id, inp, len) |
fsm *f; |
int id; u_char *inp; int len; |
{ |
u_int32_t magic; |
|
/* Check the magic number - don't count replies from ourselves. */ |
if (len < 4) { |
syslog(LOG_DEBUG, "lcp: received short Echo-Reply, length %d", len); |
return; |
} |
GETLONG(magic, inp); |
if (lcp_gotoptions[f->unit].neg_magicnumber |
&& magic == lcp_gotoptions[f->unit].magicnumber) { |
syslog(LOG_WARNING, "appear to have received our own echo-reply!"); |
return; |
} |
|
/* Reset the number of outstanding echo frames */ |
lcp_echos_pending = 0; |
} |
|
/* |
* LcpSendEchoRequest - Send an echo request frame to the peer |
*/ |
|
static void |
LcpSendEchoRequest (f) |
fsm *f; |
{ |
u_int32_t lcp_magic; |
u_char pkt[4], *pktp; |
|
/* |
* Detect the failure of the peer at this point. |
*/ |
if (lcp_echo_fails != 0) { |
if (lcp_echos_pending >= lcp_echo_fails) { |
LcpLinkFailure(f); |
lcp_echos_pending = 0; |
} |
} |
|
/* |
* Make and send the echo request frame. |
*/ |
if (f->state == OPENED) { |
lcp_magic = lcp_gotoptions[f->unit].magicnumber; |
pktp = pkt; |
PUTLONG(lcp_magic, pktp); |
fsm_sdata(f, ECHOREQ, lcp_echo_number++ & 0xFF, pkt, pktp - pkt); |
++lcp_echos_pending; |
} |
} |
|
/* |
* lcp_echo_lowerup - Start the timer for the LCP frame |
*/ |
|
static void |
lcp_echo_lowerup (unit) |
int unit; |
{ |
fsm *f = &lcp_fsm[unit]; |
|
/* Clear the parameters for generating echo frames */ |
lcp_echos_pending = 0; |
lcp_echo_number = 0; |
lcp_echo_timer_running = 0; |
|
/* If a timeout interval is specified then start the timer */ |
if (lcp_echo_interval != 0) |
LcpEchoCheck (f); |
} |
|
/* |
* lcp_echo_lowerdown - Stop the timer for the LCP frame |
*/ |
|
static void |
lcp_echo_lowerdown (unit) |
int unit; |
{ |
fsm *f = &lcp_fsm[unit]; |
|
if (lcp_echo_timer_running != 0) { |
UNTIMEOUT (LcpEchoTimeout, f); |
lcp_echo_timer_running = 0; |
} |
} |
/chat.c
0,0 → 1,1004
/* |
* Chat -- a program for automatic session establishment (i.e. dial |
* the phone and log in). |
* |
* Standard termination codes: |
* 0 - successful completion of the script |
* 1 - invalid argument, expect string too large, etc. |
* 2 - error on an I/O operation or fatal error condition. |
* 3 - timeout waiting for a simple string. |
* 4 - the first string declared as "ABORT" |
* 5 - the second string declared as "ABORT" |
* 6 - ... and so on for successive ABORT strings. |
* |
* This software is in the public domain. |
* |
* ----------------- |
* added -T and -U option and \T and \U substitution to pass a phone |
* number into chat script. Two are needed for some ISDN TA applications. |
* Keith Dart <kdart@cisco.com> |
* |
* |
* Added SAY keyword to send output to stderr. |
* This allows to turn ECHO OFF and to output specific, user selected, |
* text to give progress messages. This best works when stderr |
* exists (i.e.: pppd in nodetach mode). |
* |
* Added HANGUP directives to allow for us to be called |
* back. When HANGUP is set to NO, chat will not hangup at HUP signal. |
* We rely on timeouts in that case. |
* |
* Added CLR_ABORT to clear previously set ABORT string. This has been |
* dictated by the HANGUP above as "NO CARRIER" (for example) must be |
* an ABORT condition until we know the other host is going to close |
* the connection for call back. As soon as we have completed the |
* first stage of the call back sequence, "NO CARRIER" is a valid, non |
* fatal string. As soon as we got called back (probably get "CONNECT"), |
* we should re-arm the ABORT "NO CARRIER". Hence the CLR_ABORT command. |
* Note that CLR_ABORT packs the abort_strings[] array so that we do not |
* have unused entries not being reclaimed. |
* |
* In the same vein as above, added CLR_REPORT keyword. |
* |
* Allow for comments. Line starting with '#' are comments and are |
* ignored. If a '#' is to be expected as the first character, the |
* expect string must be quoted. |
* |
* |
* Francis Demierre <Francis@SwissMail.Com> |
* Thu May 15 17:15:40 MET DST 1997 |
* |
* |
* Added -r "report file" switch & REPORT keyword. |
* Robert Geer <bgeer@xmission.com> |
* |
* Added -s "use stderr" and -S "don't use syslog" switches. |
* June 18, 1997 |
* Karl O. Pinc <kop@meme.com> |
* |
* |
* Added -e "echo" switch & ECHO keyword |
* Dick Streefland <dicks@tasking.nl> |
* |
* |
* Considerable updates and modifications by |
* Al Longyear <longyear@pobox.com> |
* Paul Mackerras <paulus@cs.anu.edu.au> |
* |
* |
* The original author is: |
* |
* Karl Fox <karl@MorningStar.Com> |
* Morning Star Technologies, Inc. |
* 1760 Zollinger Road |
* Columbus, OH 43221 |
* (614)451-1883 |
* |
* |
*/ |
|
#ifndef lint |
/* static char rcsid[] = ""; */ |
#endif |
|
#include <stdio.h> |
#include <ctype.h> |
#include <time.h> |
#include <fcntl.h> |
#include <signal.h> |
#include <errno.h> |
#include <string.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <sys/types.h> |
#include <sys/stat.h> |
#include <syslog.h> |
|
#undef TERMIOS |
#define TERMIOS |
|
|
#include <termios.h> |
|
#define STR_LEN 1024 |
char temp2[STR_LEN]; |
|
#ifndef SIGTYPE |
#define SIGTYPE void |
#endif |
|
#undef __P |
#undef __V |
|
#ifdef __STDC__ |
#include <stdarg.h> |
#define __V(x) x |
#define __P(x) x |
#else |
#include <varargs.h> |
#define __V(x) (va_alist) va_dcl |
#define __P(x) () |
#define const |
#endif |
|
#ifndef O_NONBLOCK |
#define O_NONBLOCK O_NDELAY |
#endif |
|
|
/*************** Micro getopt() *********************************************/ |
#define OPTION(c,v) (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \ |
(--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\ |
&&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0)) |
#define OPTARG(c,v) (_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \ |
(_O=4,(char*)0):(char*)0) |
#define OPTONLYARG(c,v) (_O&2&&**v?(_O=1,--c,*v++):(char*)0) |
#define ARG(c,v) (c?(--c,*v++):(char*)0) |
|
#if 0 |
static int _O = 0; /* Internal state */ |
#endif |
/*************** Micro getopt() *********************************************/ |
|
char *program_name; |
|
#define MAX_ABORTS 5 |
#define MAX_REPORTS 5 |
#define DEFAULT_CHAT_TIMEOUT 45 |
#define fcntl(a, b,c ) 0 |
#define MAX_TIMEOUTS 10 |
|
int echo = 0; |
int verbose = 0; |
int to_log = 1; |
int to_stderr = 0; |
int Verbose = 0; |
int quiet = 0; |
int report = 0; |
int exit_code = 0; |
static int speed=0; |
char *report_file = (char *) 0; |
char *chat_file = (char *) 0; |
char *phone_num = (char *) 0; |
char *phone_num2 = (char *) 0; |
int chat_timeout = DEFAULT_CHAT_TIMEOUT; |
static int timeout = DEFAULT_CHAT_TIMEOUT; |
int have_tty_parameters = 0; |
|
#ifdef TERMIOS |
#define term_parms struct termios |
#define get_term_param(param) tcgetattr(modem_fd, param) |
#define set_term_param(param) tcsetattr(modem_fd, TCSANOW, param) |
struct termios saved_tty_parameters; |
#endif |
|
char *abort_string[MAX_ABORTS]={"BUSY","NO DIALTONE","NO CARRIER","NO ASWER","RINGING\r\n\r\nRINGING"}; |
char *fail_reason = (char *)0, |
fail_buffer[50]; |
int n_aborts = MAX_ABORTS, abort_next = 0, timeout_next = 0, echo_next = 0; |
int clear_abort_next = 0; |
|
char *report_string[MAX_REPORTS] ; |
char report_buffer[50] ; |
int n_reports = 0, report_next = 0, report_gathering = 0 ; |
int clear_report_next = 0; |
|
int say_next = 0, hup_next = 0; |
|
void *dup_mem __P((void *b, size_t c)); |
void *copy_of __P((char *s)); |
/* |
SIGTYPE sigalrm __P((int signo)); |
SIGTYPE sigint __P((int signo)); |
SIGTYPE sigterm __P((int signo)); |
SIGTYPE sighup __P((int signo)); |
*/ |
void unalarm __P((void)); |
void init __P((void)); |
void set_tty_parameters __P((void)); |
void echo_stderr __P((int)); |
void break_sequence __P((void)); |
void terminate __P((int status)); |
void do_file __P((char *chat_file)); |
int get_string __P((register char *string)); |
int put_string __P((register char *s)); |
int write_char __P((int c)); |
int put_char __P((int c)); |
int get_char __P((void)); |
void chat_send __P((register char *s)); |
char *character __P((int c)); |
void chat_expect __P((register char *s)); |
char *clean __P((register char *s, int sending)); |
void break_sequence __P((void)); |
void terminate __P((int status)); |
void pack_array __P((char **array, int end)); |
char *expect_strtok __P((char *, char *)); |
int vfmtmsg __P((char *, int, const char *, va_list)); /* vsprintf++ */ |
|
#if 0 |
int usleep( long usec ); /* returns 0 if ok, else -1 */ |
#endif |
|
extern int input_fd,output_fd; |
|
int main __P((int, char *[])); |
|
void *dup_mem(b, c) |
void *b; |
size_t c; |
{ |
void *ans = malloc (c); |
if (!ans) |
return NULL; |
|
memcpy (ans, b, c); |
return ans; |
} |
|
void *copy_of (s) |
char *s; |
{ |
return dup_mem (s, strlen (s) + 1); |
} |
|
/* |
* chat [ -v ] [-T number] [-U number] [ -t timeout ] [ -f chat-file ] \ |
* [ -r report-file ] \ |
* [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]] |
* |
* Perform a UUCP-dialer-like chat script on stdin and stdout. |
*/ |
char *getnextcommand(char **string) |
{ |
char *buf=*string,*res; |
res=strchr(buf,'@'); |
if (res==NULL) |
return NULL; |
*res='\0'; |
*string=res+1; |
return buf; |
} |
|
|
extern int modem_fd; |
int |
chatmain(argv) |
char *argv; |
{ |
char *arg; |
int i; |
char *t; |
exit_code=0; |
speed=0; |
/* |
* Default the report file to the stderr location |
*/ |
/* if (report_fp == NULL) |
report_fp = stderr; |
*/ |
init(); |
while ( (arg = getnextcommand(&argv)) != NULL) { |
chat_expect(arg); |
if (exit_code>0) break; |
t=temp2; |
|
while(*t) |
{ |
if (strncmp("CARRIER",t,7)==0) |
{/* parse speed information */ |
i=0; |
while(!isdigit(t[i])) |
i++; |
t=&t[i]; |
i=0; |
while(isdigit(t[i])) |
i++; |
t[i]=0; |
sscanf(t,"%d",&speed); |
break; |
} |
t++; |
} |
if ((arg = getnextcommand(&argv)) != NULL) |
chat_send(arg); |
if (exit_code>0) break; |
} |
|
if (exit_code) return exit_code; |
return -speed; |
} |
|
|
|
/* |
* Print an error message and terminate. |
*/ |
|
void init() |
{ |
set_tty_parameters(); |
speed=0; |
} |
|
void set_tty_parameters() |
{ |
term_parms t; |
|
if (get_term_param (&t) < 0) |
syslog(LOG_NOTICE,"Can't get terminal parameters:") |
; |
|
saved_tty_parameters = t; |
have_tty_parameters = 1; |
t.c_iflag |= IGNBRK | ISTRIP | IGNPAR; |
t.c_oflag = 0; |
t.c_lflag = 0; |
t.c_cc[VERASE] = |
t.c_cc[VKILL] = 0; |
t.c_cc[VMIN] = 0; |
t.c_cc[VTIME] = 1; |
if (set_term_param (&t) < 0) |
syslog(LOG_NOTICE,"Can't set terminal parameters:") |
; |
} |
|
void break_sequence() |
{ |
|
/* tcsendbreak (0, 0);*/ |
} |
|
/*void terminate(status) |
int status; |
{ |
echo_stderr(-1); |
|
if (have_tty_parameters) { |
if (set_term_param (&saved_tty_parameters) < 0) |
fatal(2, "Can't restore terminal parameters: %m"); |
} |
} |
*/ |
/* |
* 'Clean up' this string. |
*/ |
char *clean(s, sending) |
register char *s; |
int sending; /* set to 1 when sending (putting) this string. */ |
{ |
char temp[STR_LEN], cur_chr; |
register char *s1, *phchar; |
int add_return = sending; |
#define isoctal(chr) (((chr) >= '0') && ((chr) <= '7')) |
|
s1 = temp; |
while (*s) { |
cur_chr = *s++; |
if (cur_chr == '^') { |
cur_chr = *s++; |
if (cur_chr == '\0') { |
*s1++ = '^'; |
break; |
} |
cur_chr &= 0x1F; |
if (cur_chr != 0) { |
*s1++ = cur_chr; |
} |
continue; |
} |
|
if (cur_chr != '\\') { |
*s1++ = cur_chr; |
continue; |
} |
|
cur_chr = *s++; |
if (cur_chr == '\0') { |
if (sending) { |
*s1++ = '\\'; |
*s1++ = '\\'; |
} |
break; |
} |
|
switch (cur_chr) { |
case 'b': |
*s1++ = '\b'; |
break; |
|
case 'c': |
if (sending && *s == '\0') |
add_return = 0; |
else |
*s1++ = cur_chr; |
break; |
|
case '\\': |
case 'K': |
case 'p': |
case 'd': |
if (sending) |
*s1++ = '\\'; |
|
*s1++ = cur_chr; |
break; |
|
case 'T': |
if (sending && phone_num) { |
for ( phchar = phone_num; *phchar != '\0'; phchar++) |
*s1++ = *phchar; |
} |
else { |
*s1++ = '\\'; |
*s1++ = 'T'; |
} |
break; |
|
case 'U': |
if (sending && phone_num2) { |
for ( phchar = phone_num2; *phchar != '\0'; phchar++) |
*s1++ = *phchar; |
} |
else { |
*s1++ = '\\'; |
*s1++ = 'U'; |
} |
break; |
|
case 'q': |
quiet = 1; |
break; |
|
case 'r': |
*s1++ = '\r'; |
break; |
|
case 'n': |
*s1++ = '\n'; |
break; |
|
case 's': |
*s1++ = ' '; |
break; |
|
case 't': |
*s1++ = '\t'; |
break; |
|
case 'N': |
if (sending) { |
*s1++ = '\\'; |
*s1++ = '\0'; |
} |
else |
*s1++ = 'N'; |
break; |
|
default: |
if (isoctal (cur_chr)) { |
cur_chr &= 0x07; |
if (isoctal (*s)) { |
cur_chr <<= 3; |
cur_chr |= *s++ - '0'; |
if (isoctal (*s)) { |
cur_chr <<= 3; |
cur_chr |= *s++ - '0'; |
} |
} |
|
if (cur_chr != 0 || sending) { |
if (sending && (cur_chr == '\\' || cur_chr == 0)) |
*s1++ = '\\'; |
*s1++ = cur_chr; |
} |
break; |
} |
|
if (sending) |
*s1++ = '\\'; |
*s1++ = cur_chr; |
break; |
} |
} |
|
if (add_return) |
*s1++ = '\r'; |
|
*s1++ = '\0'; /* guarantee closure */ |
*s1++ = '\0'; /* terminate the string */ |
return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */ |
} |
|
/* |
* A modified version of 'strtok'. This version skips \ sequences. |
*/ |
|
char *expect_strtok (s, term) |
char *s, *term; |
{ |
static char *str = ""; |
int escape_flag = 0; |
char *result; |
|
/* |
* If a string was specified then do initial processing. |
*/ |
if (s) |
str = s; |
|
/* |
* If this is the escape flag then reset it and ignore the character. |
*/ |
if (*str) |
result = str; |
else |
result = (char *) 0; |
|
while (*str) { |
if (escape_flag) { |
escape_flag = 0; |
++str; |
continue; |
} |
|
if (*str == '\\') { |
++str; |
escape_flag = 1; |
continue; |
} |
|
/* |
* If this is not in the termination string, continue. |
*/ |
if (strchr (term, *str) == (char *) 0) { |
++str; |
continue; |
} |
|
/* |
* This is the terminator. Mark the end of the string and stop. |
*/ |
*str++ = '\0'; |
break; |
} |
return (result); |
} |
|
/* |
* Process the expect string |
*/ |
|
void chat_expect (s) |
char *s; |
{ |
char *expect; |
char *reply; |
|
if (strcmp(s, "HANGUP") == 0) { |
++hup_next; |
return ; |
} |
|
if (strcmp(s, "ABORT") == 0) { |
++abort_next; |
return ; |
} |
|
if (strcmp(s, "CLR_ABORT") == 0) { |
++clear_abort_next; |
return ; |
} |
|
if (strcmp(s, "REPORT") == 0) { |
++report_next; |
return ; |
} |
|
if (strcmp(s, "CLR_REPORT") == 0) { |
++clear_report_next; |
return ; |
} |
|
if (strcmp(s, "TIMEOUT") == 0) { |
++timeout_next; |
return ; |
} |
|
if (strcmp(s, "ECHO") == 0) { |
++echo_next; |
return ; |
} |
|
if (strcmp(s, "SAY") == 0) { |
++say_next; |
return ; |
} |
|
/* |
* Fetch the expect and reply string. |
*/ |
for (;;) { |
expect = expect_strtok (s, "-"); |
s = (char *)0 ; |
|
if (expect == (char *) 0) |
return ; |
|
reply = expect_strtok (s, "-"); |
|
/* |
* Handle the expect string. If successful then exit. |
*/ |
if (get_string (expect)) |
return; |
|
/* |
* If there is a sub-reply string then send it. Otherwise any condition |
* is terminal. |
*/ |
if (reply == (char *) 0 || exit_code != 3) |
break; |
|
chat_send (reply); |
} |
|
/* |
* The expectation did not occur. This is terminal. |
*/ |
return ; |
} |
|
/* |
* process the reply string |
*/ |
void chat_send (s) |
register char *s; |
{ |
if (say_next) { |
say_next = 0; |
s = clean(s,0); |
write(modem_fd, s, strlen(s)); |
free(s); |
return; |
} |
|
if (hup_next) { |
hup_next = 0; |
} |
|
if (echo_next) { |
echo_next = 0; |
echo = (strcmp(s, "ON") == 0); |
return; |
} |
|
if (abort_next) { |
/* char *s1; */ |
|
|
; |
|
|
return; |
} |
|
|
/* if (report_next) { |
char *s1; |
|
report_next = 0; |
if (n_reports >= MAX_REPORTS) |
{ |
exit_code=2; |
return; |
} |
|
s1 = clean(s, 0); |
|
if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) |
{ |
exit_code=1; |
return; |
} |
|
report_string[n_reports++] = s1; |
|
return; |
} |
*/ |
/* if (clear_report_next) { |
char *s1; |
int i; |
int old_max; |
int pack = 0; |
|
clear_report_next = 0; |
|
s1 = clean(s, 0); |
|
if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) |
{ |
exit_code=1; |
return; |
} |
|
old_max = n_reports; |
for (i=0; i < n_reports; i++) { |
if ( strcmp(s1,report_string[i]) == 0 ) { |
free(report_string[i]); |
report_string[i] = NULL; |
pack++; |
n_reports--; |
} |
} |
free(s1); |
if (pack) |
pack_array(report_string,old_max); |
|
return; |
} |
*/ |
|
if (timeout_next) { |
timeout=atoi(s); |
timeout_next = 0; |
chat_timeout = atoi(s); |
|
if (chat_timeout <= 0) |
chat_timeout = DEFAULT_CHAT_TIMEOUT; |
|
|
return; |
} |
if (strcmp(s, "EOT") == 0) |
s = "^D\\c"; |
else if (strcmp(s, "BREAK") == 0) |
s = "\\K\\c"; |
|
if (!put_string(s)) |
{ |
exit_code=1; |
return; |
} |
} |
|
int get_char() |
{ |
int status; |
char c; |
int tries=MAX_TIMEOUTS; |
|
while(tries) |
{ |
status = read(modem_fd, &c, 1); |
switch (status) { |
case 1: |
return ((int)c & 0x7F); |
default: |
tries--; |
} |
} |
return -1; |
} |
|
int put_char(c) |
int c; |
{ |
int status; |
char ch = c; |
|
/* inter-character typing delay (?) */ |
|
status = write(modem_fd, &ch, 1); |
|
switch (status) { |
case 1: |
return (0); |
|
default: |
|
|
} |
return 0; |
} |
|
int write_char (c) |
int c; |
{ |
if (put_char(c) < 0) { |
return (0); |
} |
return (1); |
} |
|
int put_string (s) |
register char *s; |
{ |
|
|
quiet = 0; |
s = clean(s, 1); |
while (*s) { |
register char c = *s++; |
|
if (c != '\\') { |
if (!write_char (c)) |
return 0; |
continue; |
} |
|
c = *s++; |
switch (c) { |
case 'd': |
sleep(1); |
break; |
|
case 'K': |
break_sequence(); |
break; |
|
case 'p': |
usleep(10000); /* 1/100th of a second (arg is microseconds) */ |
break; |
|
default: |
if (!write_char (c)) |
return 0; |
break; |
} |
} |
|
/* alarm(0);*/ |
return (1); |
} |
|
/* |
* Echo a character to stderr. |
* When called with -1, a '\n' character is generated when |
* the cursor is not at the beginning of a line. |
*/ |
void echo_stderr(n) |
int n; |
{ |
/* static int need_lf; |
char *s; |
|
switch (n) { |
case '\r': |
break; |
case -1: |
if (need_lf == 0) |
break; |
|
case '\n': |
write(2, "\n", 1); |
need_lf = 0; |
break; |
default: |
s = character(n); |
write(2, s, strlen(s)); |
need_lf = 1; |
break; |
}*/ |
} |
|
/* |
* 'Wait for' this string to appear on this file descriptor. |
*/ |
|
int get_string(string) |
register char *string; |
{ |
int c, len, minlen; |
register char *s = temp2, *end = s + STR_LEN; |
char *logged = temp2; |
struct termios tios; |
|
tcgetattr(modem_fd, &tios); |
tios.c_cc[VMIN] = 0; |
tios.c_cc[VTIME] = timeout*10/MAX_TIMEOUTS; |
tcsetattr(modem_fd, TCSANOW, &tios); |
|
string = clean(string, 0); |
len = strlen(string); |
minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1; |
|
if (len > STR_LEN) { |
exit_code = 1; |
return 0; |
} |
|
if (len == 0) { |
return (1); |
} |
|
|
while ( (c = get_char()) >= 0) { |
int n, abort_len; |
|
*s++ = c; |
*s=0; |
|
if (s - temp2 >= len && |
c == string[len - 1] && |
strncmp(s - len, string, len) == 0) { |
return (1); |
} |
|
for (n = 0; n < n_aborts; ++n) { |
if (s - temp2 >= (abort_len = strlen(abort_string[n])) && |
strncmp(s - abort_len, abort_string[n], abort_len) == 0) { |
|
exit_code = n + 4; |
strcpy(fail_reason = fail_buffer, abort_string[n]); |
return (0); |
} |
} |
|
if (s >= end) { |
if (logged < s - minlen) { |
logged = s; |
} |
s -= minlen; |
memmove(temp2, s, minlen); |
logged = temp2 + (logged - s); |
s = temp2 + minlen; |
} |
} |
exit_code = 3; |
return (0); |
} |
|
/* |
* Gross kludge to handle Solaris versions >= 2.6 having usleep. |
*/ |
|
/* |
usleep -- support routine for 4.2BSD system call emulations |
last edit: 29-Oct-1984 D A Gwyn |
*/ |
|
|
#if 0 |
int |
usleep( usec ) /* returns 0 if ok, else -1 */ |
long usec; /* delay in microseconds */ |
{ |
rtems_status_code status; |
rtems_interval ticks_per_second; |
rtems_interval ticks; |
status = rtems_clock_get( |
RTEMS_CLOCK_GET_TICKS_PER_SECOND, |
&ticks_per_second); |
ticks = (usec * (ticks_per_second/1000))/1000; |
status = rtems_task_wake_after( ticks ); |
return 0; |
} |
#endif |
|
void pack_array (array, end) |
char **array; /* The address of the array of string pointers */ |
int end; /* The index of the next free entry before CLR_ */ |
{ |
int i, j; |
|
for (i = 0; i < end; i++) { |
if (array[i] == NULL) { |
for (j = i+1; j < end; ++j) |
if (array[j] != NULL) |
array[i++] = array[j]; |
for (; i < end; ++i) |
array[i] = NULL; |
break; |
} |
} |
} |
|
/* |
* vfmtmsg - format a message into a buffer. Like vsprintf except we |
* also specify the length of the output buffer, and we handle the |
* %m (error message) format. |
* Doesn't do floating-point formats. |
* Returns the number of chars put into buf. |
*/ |
#define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0) |
/chap.h
0,0 → 1,124
/* |
* chap.h - Challenge Handshake Authentication Protocol definitions. |
* |
* Copyright (c) 1993 The Australian National University. |
* All rights reserved. |
* |
* 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 Australian National University. The name of the University |
* 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. |
* |
* Copyright (c) 1991 Gregory M. Christy |
* All rights reserved. |
* |
* 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 author. |
* |
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
* |
* $Id: chap.h,v 1.2 2001-09-27 12:01:57 chris Exp $ |
*/ |
|
#ifndef __CHAP_INCLUDE__ |
|
/* Code + ID + length */ |
#define CHAP_HEADERLEN 4 |
|
/* |
* CHAP codes. |
*/ |
|
#define CHAP_DIGEST_MD5 5 /* use MD5 algorithm */ |
#define MD5_SIGNATURE_SIZE 16 /* 16 bytes in a MD5 message digest */ |
#define CHAP_MICROSOFT 0x80 /* use Microsoft-compatible alg. */ |
#define MS_CHAP_RESPONSE_LEN 49 /* Response length for MS-CHAP */ |
|
#define CHAP_CHALLENGE 1 |
#define CHAP_RESPONSE 2 |
#define CHAP_SUCCESS 3 |
#define CHAP_FAILURE 4 |
|
/* |
* Challenge lengths (for challenges we send) and other limits. |
*/ |
#define MIN_CHALLENGE_LENGTH 32 |
#define MAX_CHALLENGE_LENGTH 64 |
#define MAX_RESPONSE_LENGTH 64 /* sufficient for MD5 or MS-CHAP */ |
|
/* |
* Each interface is described by a chap structure. |
*/ |
|
typedef struct chap_state { |
int unit; /* Interface unit number */ |
int clientstate; /* Client state */ |
int serverstate; /* Server state */ |
u_char challenge[MAX_CHALLENGE_LENGTH]; /* last challenge string sent */ |
u_char chal_len; /* challenge length */ |
u_char chal_id; /* ID of last challenge */ |
u_char chal_type; /* hash algorithm for challenges */ |
u_char id; /* Current id */ |
char *chal_name; /* Our name to use with challenge */ |
int chal_interval; /* Time until we challenge peer again */ |
int timeouttime; /* Timeout time in seconds */ |
int max_transmits; /* Maximum # of challenge transmissions */ |
int chal_transmits; /* Number of transmissions of challenge */ |
int resp_transmits; /* Number of transmissions of response */ |
u_char response[MAX_RESPONSE_LENGTH]; /* Response to send */ |
u_char resp_length; /* length of response */ |
u_char resp_id; /* ID for response messages */ |
u_char resp_type; /* hash algorithm for responses */ |
char *resp_name; /* Our name to send with response */ |
} chap_state; |
|
|
/* |
* Client (peer) states. |
*/ |
#define CHAPCS_INITIAL 0 /* Lower layer down, not opened */ |
#define CHAPCS_CLOSED 1 /* Lower layer up, not opened */ |
#define CHAPCS_PENDING 2 /* Auth us to peer when lower up */ |
#define CHAPCS_LISTEN 3 /* Listening for a challenge */ |
#define CHAPCS_RESPONSE 4 /* Sent response, waiting for status */ |
#define CHAPCS_OPEN 5 /* We've received Success */ |
|
/* |
* Server (authenticator) states. |
*/ |
#define CHAPSS_INITIAL 0 /* Lower layer down, not opened */ |
#define CHAPSS_CLOSED 1 /* Lower layer up, not opened */ |
#define CHAPSS_PENDING 2 /* Auth peer when lower up */ |
#define CHAPSS_INITIAL_CHAL 3 /* We've sent the first challenge */ |
#define CHAPSS_OPEN 4 /* We've sent a Success msg */ |
#define CHAPSS_RECHALLENGE 5 /* We've sent another challenge */ |
#define CHAPSS_BADAUTH 6 /* We've sent a Failure msg */ |
|
/* |
* Timeouts. |
*/ |
#define CHAP_DEFTIMEOUT 3 /* Timeout time in seconds */ |
#define CHAP_DEFTRANSMITS 10 /* max # times to send challenge */ |
|
extern chap_state chap[]; |
|
void ChapAuthWithPeer __P((int, char *, int)); |
void ChapAuthPeer __P((int, char *, int)); |
|
extern struct protent chap_protent; |
|
#define __CHAP_INCLUDE__ |
#endif /* __CHAP_INCLUDE__ */ |
/lcp.h
0,0 → 1,88
/* |
* lcp.h - Link Control Protocol definitions. |
* |
* Copyright (c) 1989 Carnegie Mellon University. |
* All rights reserved. |
* |
* 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 Carnegie Mellon University. The name of the |
* University may not be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
* |
* $Id: lcp.h,v 1.2 2001-09-27 12:01:57 chris Exp $ |
*/ |
|
/* |
* Options. |
*/ |
#define CI_MRU 1 /* Maximum Receive Unit */ |
#define CI_ASYNCMAP 2 /* Async Control Character Map */ |
#define CI_AUTHTYPE 3 /* Authentication Type */ |
#define CI_QUALITY 4 /* Quality Protocol */ |
#define CI_MAGICNUMBER 5 /* Magic Number */ |
#define CI_PCOMPRESSION 7 /* Protocol Field Compression */ |
#define CI_ACCOMPRESSION 8 /* Address/Control Field Compression */ |
#define CI_CALLBACK 13 /* callback */ |
|
/* |
* LCP-specific packet types. |
*/ |
#define PROTREJ 8 /* Protocol Reject */ |
#define ECHOREQ 9 /* Echo Request */ |
#define ECHOREP 10 /* Echo Reply */ |
#define DISCREQ 11 /* Discard Request */ |
#define CBCP_OPT 6 /* Use callback control protocol */ |
|
/* |
* The state of options is described by an lcp_options structure. |
*/ |
typedef struct lcp_options { |
int passive : 1; /* Don't die if we don't get a response */ |
int silent : 1; /* Wait for the other end to start first */ |
int restart : 1; /* Restart vs. exit after close */ |
int neg_mru : 1; /* Negotiate the MRU? */ |
int neg_asyncmap : 1; /* Negotiate the async map? */ |
int neg_upap : 1; /* Ask for UPAP authentication? */ |
int neg_chap : 1; /* Ask for CHAP authentication? */ |
int neg_magicnumber : 1; /* Ask for magic number? */ |
int neg_pcompression : 1; /* HDLC Protocol Field Compression? */ |
int neg_accompression : 1; /* HDLC Address/Control Field Compression? */ |
int neg_lqr : 1; /* Negotiate use of Link Quality Reports */ |
int neg_cbcp : 1; /* Negotiate use of CBCP */ |
u_short mru; /* Value of MRU */ |
u_char chap_mdtype; /* which MD type (hashing algorithm) */ |
u_int32_t asyncmap; /* Value of async map */ |
u_int32_t magicnumber; |
int numloops; /* Number of loops during magic number neg. */ |
u_int32_t lqr_period; /* Reporting period for LQR 1/100ths second */ |
} lcp_options; |
|
extern fsm lcp_fsm[]; |
extern lcp_options lcp_wantoptions[]; |
extern lcp_options lcp_gotoptions[]; |
extern lcp_options lcp_allowoptions[]; |
extern lcp_options lcp_hisoptions[]; |
extern u_int32_t xmit_accm[][8]; |
|
#define DEFMRU 1500 /* Try for this */ |
#define MINMRU 128 /* No MRUs below this */ |
#define MAXMRU 16384 /* Normally limit MRU to this */ |
|
void lcp_open __P((int)); |
void lcp_close __P((int, char *)); |
void lcp_lowerup __P((int)); |
void lcp_lowerdown __P((int)); |
void lcp_sprotrej __P((int, u_char *, int)); /* send protocol reject */ |
|
extern struct protent lcp_protent; |
|
/* Default number of times we receive our magic number from the peer |
before deciding the link is looped-back. */ |
#define DEFLOOPBACKFAIL 10 |
/main.c
0,0 → 1,1284
/* |
* main.c - Point-to-Point Protocol main module |
* |
* Copyright (c) 1989 Carnegie Mellon University. |
* All rights reserved. |
* |
* 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 Carnegie Mellon University. The name of the |
* University 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. |
*/ |
|
/*#ifndef lint |
/* static char rcsid[] = "$Id: main.c,v 1.2 2001-09-27 12:01:57 chris Exp $"; */ |
#endif |
*/ |
#include <stdio.h> |
#include <ctype.h> |
/* #include <stdlib.h> */ |
#include <string.h> |
#include <unistd.h> |
#include <signal.h> |
#include <errno.h> |
#include <fcntl.h> |
#include <syslog.h> |
#include <netdb.h> |
#include <pwd.h> |
#include <sys/param.h> |
#include <sys/types.h> |
#include <sys/wait.h> |
#include <sys/time.h> |
#include <sys/resource.h> |
#include <sys/stat.h> |
#include <sys/socket.h> |
#include <rtems/rtems/tasks.h> |
#include <sys/types.h> |
#include <netinet/in.h> |
|
/* #include <stbconfig.h> */ |
#include "pppd.h" |
#include "magic.h" |
#include "fsm.h" |
#include "lcp.h" |
#include "ipcp.h" |
#include "upap.h" |
#include "chap.h" |
#include "ccp.h" |
#include "pathnames.h" |
#include "patchlevel.h" |
|
#ifdef CBCP_SUPPORT |
#include "cbcp.h" |
#endif |
|
#if defined(SUNOS4) |
extern char *strerror(); |
#endif |
|
#ifdef IPX_CHANGE |
#include "ipxcp.h" |
#endif /* IPX_CHANGE */ |
#ifdef AT_CHANGE |
#include "atcp.h" |
#endif |
|
void SetStatusInfo(int state, char * text, int res); |
|
/* interface vars */ |
char ifname[32]; /* Interface name */ |
int interfunit; /* Interface unit number */ |
|
char *progname; /* Name of this program */ |
char hostname[MAXNAMELEN] = "infotel"; /* Our hostname */ |
static char default_devnam[MAXPATHLEN]; /* name of default device */ |
/*static pid_t pid; */ /* Our pid */ |
static uid_t uid; /* Our real user-id */ |
static int conn_running; /* we have a [dis]connector running */ |
|
int ttyfd = -1; /* Serial port file descriptor */ |
mode_t tty_mode = -1; /* Original access permissions to tty */ |
int baud_rate; /* Actual bits/second for serial device */ |
int hungup; /* terminal has been hung up */ |
int privileged; /* we're running as real uid root */ |
int need_holdoff; /* need holdoff period before restarting */ |
int detached; /* have detached from terminal */ |
|
int phase; /* where the link is at */ |
int kill_link; |
int open_ccp_flag; |
|
char **script_env; /* Env. variable values for scripts */ |
int s_env_nalloc; /* # words avail at script_env */ |
|
u_char outpacket_buf[PPP_MRU + PPP_HDRLEN]; /* buffer for outgoing packet */ |
u_char inpacket_buf[PPP_MRU + PPP_HDRLEN]; /* buffer for incoming packet */ |
|
|
|
char *no_ppp_msg = "lack of PPP\n"; |
|
/* Prototypes for procedures local to this file. */ |
static void cleanup(void); |
static void create_pidfile __P((void)); |
static void close_tty __P((void)); |
static void get_input __P((void)); |
static void calltimeout __P((void)); |
static struct timeval *timeleft __P((struct timeval *)); |
static void holdoff_end __P((void *)); |
static int device_script __P((char *[], int, int)); |
static void reap_kids __P((void)); |
static void pr_log __P((void *, char *,...)); |
|
extern char *ttyname __P((int)); |
extern char *getlogin __P((void)); |
int main __P((int, char *[])); |
|
|
|
|
|
/* |
* PPP Data Link Layer "protocol" table. |
* One entry per supported protocol. |
* The last entry must be NULL. |
*/ |
struct protent *protocols[] = |
{ |
&lcp_protent, |
&pap_protent, |
&chap_protent, |
#ifdef CBCP_SUPPORT |
&cbcp_protent, |
#endif |
&ipcp_protent, |
&ccp_protent, |
#ifdef IPX_CHANGE |
&ipxcp_protent, |
#endif |
#ifdef AT_CHANGE |
&atcp_protent, |
#endif |
NULL |
}; |
|
extern int connect_stb(); |
|
|
extern int disconnect_stb(); |
|
|
extern struct in_addr rtems_bsdnet_nameserver[]; |
extern int rtems_bsdnet_nameserver_count; |
extern int __res_init(void); |
|
int pppdmain(argc, argv) |
int argc; |
char *argv[]; |
{ |
int i; |
struct timeval timo; |
struct protent *protp; |
struct stat statbuf; |
char t[100]; |
|
|
phase = PHASE_INITIALIZE; |
|
strcpy(default_devnam, "/dev/modem"); |
strcpy(devnam, "/dev/modem"); |
|
script_env = NULL; |
|
/* if (gethostname(hostname, MAXNAMELEN) < 0 ) { |
die(1); |
} |
*/ |
hostname[MAXNAMELEN - 1] = 0; |
|
uid = 0; |
privileged = uid == 0; |
|
/* |
* Initialize to the standard option set, then parse, in order, |
* the system options file, the user's options file, |
* the tty's options file, and the command line arguments. |
*/ |
for (i = 0; (protp = protocols[i]) != NULL; ++i) |
(*protp->init) (0); |
|
|
|
if (!ppp_available()) { |
exit(1); |
} |
/* |
* Check that the options given are valid and consistent. |
*/ |
sys_check_options(); |
auth_check_options(); |
for (i = 0; (protp = protocols[i]) != NULL; ++i) |
if (protp->check_options != NULL) |
(*protp->check_options) (); |
|
/* |
* If the user has specified the default device name explicitly, |
* pretend they hadn't. |
*/ |
if (!default_device && strcmp(devnam, default_devnam) == 0) |
default_device = 1; |
if (default_device) |
nodetach = 1; |
|
/* |
* Initialize system-dependent stuff and magic number package. |
*/ |
sys_init(); |
magic_init(); |
|
/* |
* Detach ourselves from the terminal, if required, |
* and identify who is running us. |
*/ |
|
/* |
syslog(LOG_NOTICE, "pppd %s.%d%s started by %s, uid %d", |
VERSION, PATCHLEVEL, IMPLEMENTATION, p, uid); |
*/ |
|
|
for (;;) { |
|
/* !!! here should be done some kind of synchronization - I did it following way ... */ |
/* GlobalSystemStatus is set of different things shared between different tasks ... */ |
#if 0 |
/* XXX PPPConfiguration */ |
GlobalSystemStatus * volatile stat; |
stat=LockSTBSystemParam(); |
stat->ConnectionStatus = NotConnected; |
UnlockSTBSystemParam(); |
#endif |
|
|
while (1) { |
rtems_event_set events; |
int status; |
|
#if 0 |
/* XXX PPPConfiguration */ |
stat=LockSTBSystemParam(); |
status=stat->WantConnection; |
UnlockSTBSystemParam(); |
|
if (status == Connect) break; |
#endif |
rtems_event_receive(RTEMS_EVENT_1, RTEMS_WAIT | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &events); |
} |
#if 0 |
/* XXX PPPConfiguration */ |
stat=LockSTBSystemParam(); |
/* stat->WantConnection=DontConnect; */ |
stat->ConnectionStatus = Connecting; |
|
/* Here you can change default nameserver ... */ |
rtems_bsdnet_nameserver[0].s_addr=inet_addr(stat->DNS); |
rtems_bsdnet_nameserver_count=1; |
UnlockSTBSystemParam(); |
#endif |
/* initialize DNS services here */ |
SetStatusInfo(0, "Connecting...",0); |
|
__res_init(); |
/* |
* Open the serial device and set it up to be the ppp interface. |
* First we open it in non-blocking mode so we can set the |
* various termios flags appropriately. If we aren't dialling |
* out and we want to use the modem lines, we reopen it later |
* in order to wait for the carrier detect signal from the modem. |
*/ |
while ((ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0)) < 0) { |
if (errno != EINTR) |
syslog(LOG_ERR, "Failed to open %s: %m", devnam); |
|
if (!persist || errno != EINTR) |
goto fail; |
} |
|
hungup = 0; |
kill_link = 0; |
|
/* |
* Do the equivalent of `mesg n' to stop broadcast messages. |
*/ |
tty_mode = statbuf.st_mode; |
|
/* run connection script */ |
/* |
* Set line speed, flow control, etc. |
* On most systems we set CLOCAL for now so that we can talk |
* to the modem before carrier comes up. But this has the |
* side effect that we might miss it if CD drops before we |
* get to clear CLOCAL below. On systems where we can talk |
* successfully to the modem with CLOCAL clear and CD down, |
* we can clear CLOCAL at this point. |
*/ |
set_up_tty(ttyfd, 1); |
|
/* drop dtr to hang up in case modem is off hook */ |
setdtr(ttyfd, FALSE); |
sleep(1); |
setdtr(ttyfd, TRUE); |
{ |
/* Make a call ... */ |
#if 0 |
/* XXX PPPConfiguration */ |
char t[100]; |
stat=LockSTBSystemParam(); |
|
UnlockSTBSystemParam(); |
#endif |
SetStatusInfo(0, t,0); |
} |
|
|
if ((i=connect_script(ttyfd)) >0) { |
/* here go error messages ... */ |
static char *error_msgs[]={ "Bad script", "IO Error" |
"Timeout", "Busy", "No dialtone", "No carrier", |
"No answer", "No answer from server" }; |
setdtr(ttyfd, FALSE); |
sprintf(t,"Communication error: %s",error_msgs[i-1]); |
syslog(LOG_ERR, "Connect script failed"); |
SetStatusInfo(0, t,1); |
goto fail; |
} |
|
else |
if (i<0) |
{ |
char t[100]; |
|
SetStatusInfo(0, t,0); |
} |
else |
|
syslog(LOG_INFO, "Serial connection established."); |
|
sleep(1); /* give it time to set up its terminal */ |
|
/* set line speed, flow control, etc.; clear CLOCAL if modem option */ |
set_up_tty(ttyfd, 0); |
|
/* reopen tty if necessary to wait for carrier */ |
|
/* run welcome script, if any */ |
/* if (welcomer && welcomer[0]) { |
if (device_script(welcomer, 21, ttyfd) < 0) |
syslog(LOG_WARNING, "Welcome script failed"); |
} |
*/ |
/* set up the serial device as a ppp interface */ |
establish_ppp(ttyfd); |
|
/* syslog(LOG_INFO, "Using interface ppp%d", interfunit); */ |
(void) sprintf(ifname, "ppp%d", interfunit); |
|
/* |
* Start opening the connection and wait for |
* incoming events (reply, timeout, etc.). |
*/ |
/* syslog(LOG_NOTICE, "Connect: %s <--> %s", ifname, devnam); */ |
|
rtems_bsdnet_semaphore_obtain(); |
|
lcp_lowerup(0); |
lcp_open(0); /* Start protocol */ |
|
rtems_bsdnet_semaphore_release(); |
|
|
for (phase = PHASE_ESTABLISH; phase != PHASE_DEAD;) { |
wait_input(timeleft(&timo)); |
calltimeout(); |
get_input(); |
#if 0 |
/* XXX PPPConfiguration */ |
stat=LockSTBSystemParam(); |
if (stat->WantConnection==DontConnect) { |
stat->ConnectionStatus = NotConnected; |
|
lcp_close(0, ""); |
kill_link = 0; |
} |
UnlockSTBSystemParam(); |
#endif |
if (open_ccp_flag) { |
if (phase == PHASE_NETWORK) { |
ccp_fsm[0].flags = OPT_RESTART; /* clears OPT_SILENT */ |
(*ccp_protent.open) (0); |
} |
open_ccp_flag = 0; |
} |
} |
/* |
* If we may want to bring the link up again, transfer |
* the ppp unit back to the loopback. Set the |
* real serial device back to its normal mode of operation. |
*/ |
clean_check(); |
disestablish_ppp(ttyfd); |
|
|
/* |
* Run disconnector script, if requested. |
* XXX we may not be able to do this if the line has hung up! |
*/ |
/* if (disconnector && !hungup) { |
set_up_tty(ttyfd, 1); |
if (device_script(disconnector, ttyfd, ttyfd) < 0) { |
syslog(LOG_WARNING, "disconnect script failed"); |
} else { |
syslog(LOG_INFO, "Serial link disconnected."); |
} |
} |
*/ |
fail: |
#if 0 |
/* XXX PPPConfiguration */ |
stat=LockSTBSystemParam(); |
stat->ConnectionStatus = NotConnected; |
stat->WantConnection=DontConnect; |
UnlockSTBSystemParam(); |
#endif |
if (ttyfd >= 0) |
close_tty(); |
|
|
|
} |
|
return 0; |
} |
|
/* |
* detach - detach us from the controlling terminal. |
*/ |
void detach() |
{ |
} |
|
/* |
* holdoff_end - called via a timeout when the holdoff period ends. |
*/ |
|
static void holdoff_end(arg) |
void *arg; |
{ |
phase = PHASE_DORMANT; |
} |
|
/* |
* get_input - called when incoming data is available. |
*/ |
static void get_input() |
{ |
int len, i; |
u_char *p; |
u_short protocol; |
struct protent *protp; |
|
p = inpacket_buf; /* point to beginning of packet buffer */ |
|
len = read_packet(inpacket_buf); |
if (len < 0) |
return; |
|
if (len == 0) { |
#if 0 |
/* XXX PPPConfiguration */ |
GlobalSystemStatus * volatile stat; |
#endif |
/* syslog(LOG_NOTICE, "Modem hangup"); */ |
hungup = 1; |
#if 0 |
/* XXX PPPConfiguration */ |
stat=LockSTBSystemParam(); |
stat->ConnectionStatus = NotConnected; |
UnlockSTBSystemParam(); |
#endif |
|
lcp_lowerdown(0); /* serial link is no longer available */ |
link_terminated(0); |
return; |
} |
/* if ((debug)) |
log_packet(p, len, "rcvd ", LOG_DEBUG); |
*/ |
|
if (len < PPP_HDRLEN) { |
/* |
if (debug) |
MAINDEBUG((LOG_INFO, "io(): Received short packet.")); |
*/ |
return; |
} |
/* We need to modify internal network structures here */ |
rtems_bsdnet_semaphore_obtain(); |
|
p += 2; /* Skip address and control */ |
GETSHORT(protocol, p); |
len -= PPP_HDRLEN; |
|
/* |
* Toss all non-LCP packets unless LCP is OPEN. |
*/ |
if (protocol != PPP_LCP && lcp_fsm[0].state != OPENED) { |
MAINDEBUG((LOG_INFO, |
"get_input: Received non-LCP packet when LCP not open.")); |
rtems_bsdnet_semaphore_release(); |
return; |
} |
/* |
* Until we get past the authentication phase, toss all packets |
* except LCP, LQR and authentication packets. |
*/ |
if (phase <= PHASE_AUTHENTICATE |
&& !(protocol == PPP_LCP || protocol == PPP_LQR |
|| protocol == PPP_PAP || protocol == PPP_CHAP)) { |
|
rtems_bsdnet_semaphore_release(); |
return; |
} |
/* |
* Upcall the proper protocol input routine. |
*/ |
for (i = 0; (protp = protocols[i]) != NULL; ++i) { |
if (protp->protocol == protocol && protp->enabled_flag) { |
(*protp->input) (0, p, len); |
rtems_bsdnet_semaphore_release(); |
return; |
} |
if (protocol == (protp->protocol & ~0x8000) && protp->enabled_flag |
&& protp->datainput != NULL) { |
(*protp->datainput) (0, p, len); |
rtems_bsdnet_semaphore_release(); |
return; |
} |
} |
|
lcp_sprotrej(0, p - PPP_HDRLEN, len + PPP_HDRLEN); |
rtems_bsdnet_semaphore_release(); |
} |
|
|
/* |
* quit - Clean up state and exit (with an error indication). |
*/ |
void quit() |
{ |
die(1); |
} |
|
/* |
* die - like quit, except we can specify an exit status. |
*/ |
void die(status) |
int status; |
{ |
cleanup(); |
} |
|
/* |
* cleanup - restore anything which needs to be restored before we exit |
*/ |
/* ARGSUSED */ |
static void cleanup() |
{ |
sys_cleanup(); |
|
if (ttyfd >= 0) |
close_tty(); |
|
} |
|
/* |
* close_tty - restore the terminal device and close it. |
*/ |
static void close_tty() |
{ |
disestablish_ppp(ttyfd); |
|
/* drop dtr to hang up */ |
setdtr(ttyfd, FALSE); |
/* |
* This sleep is in case the serial port has CLOCAL set by default, |
* and consequently will reassert DTR when we close the device. |
*/ |
sleep(1); |
|
restore_tty(ttyfd); |
close(ttyfd); |
ttyfd = -1; |
} |
|
|
struct callout { |
struct timeval c_time; |
void *c_arg; |
void (*c_func) __P((void *)); |
struct callout *c_next; |
}; |
|
static struct callout *callout = NULL; |
static struct timeval timenow; |
|
/* |
* timeout - Schedule a timeout. |
* |
* Note that this timeout takes the number of seconds, NOT hz (as in |
* the kernel). |
*/ |
void my_timeout(func, arg, time) |
void (*func) __P((void *)); |
void *arg; |
int time; |
{ |
struct callout *newp, *p, **pp; |
|
MAINDEBUG((LOG_DEBUG, "Timeout %lx:%lx in %d seconds.", |
(long) func, (long) arg, time)); |
/* |
* Allocate timeout. |
*/ |
if ((newp = (struct callout *) malloc(sizeof(struct callout))) == NULL) { |
/* syslog(LOG_ERR, "Out of memory in timeout()!"); */ |
die(1); |
} |
newp->c_arg = arg; |
newp->c_func = func; |
gettimeofday(&timenow, NULL); |
newp->c_time.tv_sec = timenow.tv_sec + time; |
newp->c_time.tv_usec = timenow.tv_usec; |
/* |
* Find correct place and link it in. |
*/ |
for (pp = &callout; (p = *pp); pp = &p->c_next) |
if (newp->c_time.tv_sec < p->c_time.tv_sec |
|| (newp->c_time.tv_sec == p->c_time.tv_sec |
&& newp->c_time.tv_usec < p->c_time.tv_sec)) |
break; |
newp->c_next = p; |
*pp = newp; |
} |
|
/* |
* untimeout - Unschedule a timeout. |
*/ |
|
void untimeout(func, arg) |
void (*func) __P((void *)); |
void *arg; |
{ |
struct callout **copp, *freep; |
|
MAINDEBUG((LOG_DEBUG, "Untimeout %lx:%lx.", (long) func, (long) arg)); |
|
for (copp = &callout; (freep = *copp); copp = &freep->c_next) |
if (freep->c_func == func && freep->c_arg == arg) { |
*copp = freep->c_next; |
(void) free((char *) freep); |
break; |
} |
} |
|
|
/* |
* calltimeout - Call any timeout routines which are now due. |
*/ |
static void calltimeout() |
{ |
struct callout *p; |
|
while (callout != NULL) { |
p = callout; |
|
if (gettimeofday(&timenow, NULL) < 0) { |
die(1); |
} |
if (!(p->c_time.tv_sec < timenow.tv_sec |
|| (p->c_time.tv_sec == timenow.tv_sec |
&& p->c_time.tv_usec <= timenow.tv_usec))) |
break; /* no, it's not time yet */ |
|
callout = p->c_next; |
(*p->c_func) (p->c_arg); |
|
free((char *) p); |
} |
} |
|
|
/* |
* timeleft - return the length of time until the next timeout is due. |
*/ |
static struct timeval * |
timeleft(tvp) |
struct timeval *tvp; |
{ |
if (callout == NULL) |
return NULL; |
|
gettimeofday(&timenow, NULL); |
tvp->tv_sec = callout->c_time.tv_sec - timenow.tv_sec; |
tvp->tv_usec = callout->c_time.tv_usec - timenow.tv_usec; |
if (tvp->tv_usec < 0) { |
tvp->tv_usec += 1000000; |
tvp->tv_sec -= 1; |
} |
if (tvp->tv_sec < 0) |
tvp->tv_sec = tvp->tv_usec = 0; |
|
return tvp; |
} |
|
|
/* |
* term - Catch SIGTERM signal and SIGINT signal (^C/del). |
* |
* Indicates that we should initiate a graceful disconnect and exit. |
*/ |
static void term(sig) |
int sig; |
{ |
/* persist = 0; *//* don't try to restart */ |
kill_link = 1; |
} |
|
static int input_fd, output_fd; |
#include <rtems/rtems/tasks.h> |
|
|
|
extern int modem_fd; |
int connect_script(int fd) |
{ |
int status; |
char program[256]; |
#if 0 |
/* XXX PPPConfiguration */ |
GlobalSystemStatus * volatile stat; |
#endif |
/* Connect scripts are almost the same as in Linux Chat ... */ |
static char *scripts[] = |
{ |
"TIMEOUT@5@@\rAT@OK-+++\\c-OK@ATH0@TIMEOUT@90@OK@ATDT%s@CONNECT@", |
"TIMEOUT@5@@\rAT@OK-+++\\c-OK@ATH0@TIMEOUT@90@OK@ATDT%s@CONNECT@@ppp@@Username:@%s@Password:@%s@" |
}; |
modem_fd = fd; |
#if 0 |
/* XXX PPPConfiguration */ |
stat=LockSTBSystemParam(); |
if (strcmp("",stat->PPP_User)) |
{ |
stat->provider=Poland_TPSA; |
} |
else |
stat->provider=DumbLogin; |
switch (stat->provider) { |
case Poland_TPSA: |
sprintf(program, scripts[1], stat->Phone_Number, stat->PPP_User, stat->PPP_Password); |
break; |
default: |
sprintf(program, scripts[0], stat->Phone_Number); |
|
} |
UnlockSTBSystemParam(); |
#endif |
conn_running = 0; |
|
return chatmain(program); |
} |
|
|
/* |
* run-program - execute a program with given arguments, |
* but don't wait for it. |
* If the program can't be executed, logs an error unless |
* must_exist is 0 and the program file doesn't exist. |
*/ |
int run_program(prog, args, must_exist) |
char *prog; |
char **args; |
int must_exist; |
{ |
|
return 0; |
} |
|
|
/* |
* reap_kids - get status from any dead child processes, |
* and log a message for abnormal terminations. |
*/ |
static void reap_kids() |
{ |
} |
|
|
/* |
* log_packet - format a packet and log it. |
*/ |
|
char line[256]; |
char *linep; |
|
/*#define log_packet(p, len, prefix, level) */ |
void log_packet(p, len, prefix, level) |
u_char *p; |
int len; |
char *prefix; |
int level; |
{ |
strcpy(line, prefix); |
linep = line + strlen(line); |
/* format_packet(p, len, pr_log, NULL); */ |
/* if (linep != line) |
syslog(level, "%s", line); |
*/ |
} |
|
/* |
* format_packet - make a readable representation of a packet, |
* calling `printer(arg, format, ...)' to output it. |
*/ |
/*#define format_packet(p, len, printer, arg) */ |
|
void format_packet(p, len, printer, arg) |
u_char *p; |
int len; |
void (*printer) __P((void *, char *,...)); |
void *arg; |
{ |
/* |
int i, n; |
u_short proto; |
struct protent *protp; |
|
if (len >= PPP_HDRLEN && p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) { |
p += 2; |
GETSHORT(proto, p); |
len -= PPP_HDRLEN; |
for (i = 0; (protp = protocols[i]) != NULL; ++i) |
if (proto == protp->protocol) |
break; |
if (protp != NULL) { |
printer(arg, "[%s", protp->name); |
n = (*protp->printpkt) (p, len, printer, arg); |
printer(arg, "]"); |
p += n; |
len -= n; |
} else { |
printer(arg, "[proto=0x%x]", proto); |
} |
} |
*/ |
/* for (; len > 0; --len) { |
GETCHAR(x, p); |
printer(arg, " %.2x", x); |
} |
*/ |
} |
|
|
|
static void |
pr_log __V((void *arg, char *fmt,...)) |
{ |
int n; |
va_list pvar; |
char buf[256]; |
|
#if __STDC__ |
va_start(pvar, fmt); |
#else |
void *arg; |
char *fmt; |
va_start(pvar); |
arg = va_arg(pvar, void *); |
fmt = va_arg(pvar, char *); |
#endif |
|
n = vfmtmsg(buf, sizeof(buf), fmt, pvar); |
va_end(pvar); |
|
if (linep + n + 1 > line + sizeof(line)) { |
/* syslog(LOG_DEBUG, "%s", line); */ |
linep = line; |
} |
strcpy(linep, buf); |
linep += n; |
} |
|
/* |
* print_string - print a readable representation of a string using |
* printer. |
*/ |
/*#define print_string(p, len, printer, arg) */ |
|
void print_string(p, len, printer, arg) |
char *p; |
int len; |
void (*printer) __P((void *, char *,...)); |
void *arg; |
{ |
int c; |
|
printer(arg, "\""); |
for (; len > 0; --len) { |
c = *p++; |
if (' ' <= c && c <= '~') { |
if (c == '\\' || c == '"') |
printer(arg, "\\"); |
printer(arg, "%c", c); |
} else { |
switch (c) { |
case '\n': |
printer(arg, "\\n"); |
break; |
case '\r': |
printer(arg, "\\r"); |
break; |
case '\t': |
printer(arg, "\\t"); |
break; |
default: |
printer(arg, "\\%.3o", c); |
} |
} |
} |
printer(arg, "\""); |
} |
|
|
/* |
* novm - log an error message saying we ran out of memory, and die. |
*/ |
void novm(msg) |
char *msg; |
{ |
/* syslog(LOG_ERR, "Virtual memory exhausted allocating %s\n", msg); |
*/ die(1); |
} |
|
/* |
* fmtmsg - format a message into a buffer. Like sprintf except we |
* also specify the length of the output buffer, and we handle |
* %r (recursive format), %m (error message) and %I (IP address) formats. |
* Doesn't do floating-point formats. |
* Returns the number of chars put into buf. |
*/ |
int |
fmtmsg __V((char *buf, int buflen, char *fmt,...)) |
{ |
va_list args; |
int n; |
|
#if __STDC__ |
va_start(args, fmt); |
#else |
char *buf; |
int buflen; |
char *fmt; |
va_start(args); |
buf = va_arg(args, char *); |
buflen = va_arg(args, int); |
fmt = va_arg(args, char *); |
#endif |
n = vfmtmsg(buf, buflen, fmt, args); |
va_end(args); |
return n; |
} |
|
/* |
* vfmtmsg - like fmtmsg, takes a va_list instead of a list of args. |
*/ |
#define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0) |
/*#define vfmtmsg(buf, buflen, fmt, args) */ |
|
int vfmtmsg(buf, buflen, fmt, args) |
char *buf; |
int buflen; |
char *fmt; |
va_list args; |
{ |
/* int c, i, n; |
int width, prec, fillch; |
int base, len, neg, quoted; |
unsigned long val = 0; |
char *str, *f, *buf0; |
unsigned char *p; |
char num[32]; |
time_t t; |
static char hexchars[] = "0123456789abcdef"; |
|
buf0 = buf; |
--buflen; |
while (buflen > 0) { |
for (f = fmt; *f != '%' && *f != 0; ++f) |
; |
if (f > fmt) { |
len = f - fmt; |
if (len > buflen) |
len = buflen; |
memcpy(buf, fmt, len); |
buf += len; |
buflen -= len; |
fmt = f; |
} |
if (*fmt == 0) |
break; |
c = *++fmt; |
width = prec = 0; |
fillch = ' '; |
if (c == '0') { |
fillch = '0'; |
c = *++fmt; |
} |
if (c == '*') { |
width = va_arg(args, int); |
c = *++fmt; |
} else { |
while (isdigit(c)) { |
width = width * 10 + c - '0'; |
c = *++fmt; |
} |
} |
if (c == '.') { |
c = *++fmt; |
if (c == '*') { |
prec = va_arg(args, int); |
c = *++fmt; |
} else { |
while (isdigit(c)) { |
prec = prec * 10 + c - '0'; |
c = *++fmt; |
} |
} |
} |
str = 0; |
base = 0; |
neg = 0; |
++fmt; |
switch (c) { |
case 'd': |
i = va_arg(args, int); |
if (i < 0) { |
neg = 1; |
val = -i; |
} else |
val = i; |
base = 10; |
break; |
case 'o': |
val = va_arg(args, unsigned int); |
base = 8; |
break; |
case 'x': |
val = va_arg(args, unsigned int); |
base = 16; |
break; |
case 'p': |
val = (unsigned long) va_arg(args, void *); |
base = 16; |
neg = 2; |
break; |
case 's': |
str = va_arg(args, char *); |
break; |
case 'c': |
num[0] = va_arg(args, int); |
num[1] = 0; |
str = num; |
break; |
case 'm': |
str = strerror(errno); |
break; |
case 'I': |
str = ip_ntoa(va_arg(args, u_int32_t)); |
break; |
case 'r': |
f = va_arg(args, char *); |
#ifndef __powerpc__ |
n = vfmtmsg(buf, buflen + 1, f, va_arg(args, va_list)); |
#else |
|
n = vfmtmsg(buf, buflen + 1, f, va_arg(args, void *)); |
#endif |
buf += n; |
buflen -= n; |
continue; |
case 't': |
break; |
case 'v': |
case 'q': |
quoted = c == 'q'; |
p = va_arg(args, unsigned char *); |
if (fillch == '0' && prec > 0) { |
n = prec; |
} else { |
n = strlen((char *)p); |
if (prec > 0 && prec < n) |
n = prec; |
} |
while (n > 0 && buflen > 0) { |
c = *p++; |
--n; |
if (!quoted && c >= 0x80) { |
OUTCHAR('M'); |
OUTCHAR('-'); |
c -= 0x80; |
} |
if (quoted && (c == '"' || c == '\\')) |
OUTCHAR('\\'); |
if (c < 0x20 || (0x7f <= c && c < 0xa0)) { |
if (quoted) { |
OUTCHAR('\\'); |
switch (c) { |
case '\t': OUTCHAR('t'); break; |
case '\n': OUTCHAR('n'); break; |
case '\b': OUTCHAR('b'); break; |
case '\f': OUTCHAR('f'); break; |
default: |
OUTCHAR('x'); |
OUTCHAR(hexchars[c >> 4]); |
OUTCHAR(hexchars[c & 0xf]); |
} |
} else { |
if (c == '\t') |
OUTCHAR(c); |
else { |
OUTCHAR('^'); |
OUTCHAR(c ^ 0x40); |
} |
} |
} else |
OUTCHAR(c); |
} |
continue; |
default: |
*buf++ = '%'; |
if (c != '%') |
--fmt; |
--buflen; |
continue; |
} |
if (base != 0) { |
str = num + sizeof(num); |
*--str = 0; |
while (str > num + neg) { |
*--str = hexchars[val % base]; |
val = val / base; |
if (--prec <= 0 && val == 0) |
break; |
} |
switch (neg) { |
case 1: |
*--str = '-'; |
break; |
case 2: |
*--str = 'x'; |
*--str = '0'; |
break; |
} |
len = num + sizeof(num) - 1 - str; |
} else { |
len = strlen(str); |
if (prec > 0 && len > prec) |
len = prec; |
} |
if (width > 0) { |
if (width > buflen) |
width = buflen; |
if ((n = width - len) > 0) { |
buflen -= n; |
for (; n > 0; --n) |
*buf++ = fillch; |
} |
} |
if (len > buflen) |
len = buflen; |
memcpy(buf, str, len); |
buf += len; |
buflen -= len; |
} |
*buf = 0; |
return buf - buf0; |
*/ |
return 0; |
} |
|
|
/* |
* script_setenv - set an environment variable value to be used |
* for scripts that we run (e.g. ip-up, auth-up, etc.) |
*/ |
#define script_setenv(var, value) |
/* |
void |
script_setenv(var, value) |
char *var, *value; |
{ |
int vl = strlen(var); |
int i; |
char *p, *newstring; |
|
newstring = (char *) malloc(vl + strlen(value) + 2); |
if (newstring == 0) |
return; |
strcpy(newstring, var); |
newstring[vl] = '='; |
strcpy(newstring+vl+1, value); |
|
if (script_env != 0) { |
for (i = 0; (p = script_env[i]) != 0; ++i) { |
if (strncmp(p, var, vl) == 0 && p[vl] == '=') { |
free(p); |
script_env[i] = newstring; |
return; |
} |
} |
} else { |
i = 0; |
script_env = (char **) malloc(16 * sizeof(char *)); |
if (script_env == 0) |
return; |
s_env_nalloc = 16; |
} |
|
if (i + 1 >= s_env_nalloc) { |
int new_n = i + 17; |
char **newenv = (char **) realloc((void *)script_env, |
new_n * sizeof(char *)); |
if (newenv == 0) |
return; |
script_env = newenv; |
s_env_nalloc = new_n; |
} |
|
script_env[i] = newstring; |
script_env[i+1] = 0; |
} |
|
*//* |
* script_unsetenv - remove a variable from the environment |
* for scripts. |
*/ |
#define script_unsetenv(var) |
/* |
void |
script_unsetenv(var) |
char *var; |
{ |
int vl = strlen(var); |
int i; |
char *p; |
|
if (script_env == 0) |
return; |
for (i = 0; (p = script_env[i]) != 0; ++i) { |
if (strncmp(p, var, vl) == 0 && p[vl] == '=') { |
free(p); |
while ((script_env[i] = script_env[i+1]) != 0) |
++i; |
break; |
} |
} |
} |
*/ |
/pathnames.h
0,0 → 1,30
/* |
* define path names |
* |
* $Id: pathnames.h,v 1.2 2001-09-27 12:01:57 chris Exp $ |
*/ |
|
#ifdef HAVE_PATHS_H |
#include <paths.h> |
|
#else |
#define _PATH_VARRUN "/etc/ppp/" |
#define _PATH_DEVNULL "/dev/null" |
#endif |
|
#define _PATH_UPAPFILE "/etc/ppp/pap-secrets" |
#define _PATH_CHAPFILE "/etc/ppp/chap-secrets" |
#define _PATH_SYSOPTIONS "/etc/ppp/options" |
#define _PATH_IPUP "/etc/ppp/ip-up" |
#define _PATH_IPDOWN "/etc/ppp/ip-down" |
#define _PATH_AUTHUP "/etc/ppp/auth-up" |
#define _PATH_AUTHDOWN "/etc/ppp/auth-down" |
#define _PATH_TTYOPT "/etc/ppp/options." |
#define _PATH_CONNERRS "/etc/ppp/connect-errors" |
#define _PATH_USEROPT ".ppprc" |
#define _PATH_PEERFILES "/etc/ppp/peers/" |
|
#ifdef IPX_CHANGE |
#define _PATH_IPXUP "/etc/ppp/ipx-up" |
#define _PATH_IPXDOWN "/etc/ppp/ipx-down" |
#endif /* IPX_CHANGE */ |
/fsm.c
0,0 → 1,798
/* |
* fsm.c - {Link, IP} Control Protocol Finite State Machine. |
* |
* Copyright (c) 1989 Carnegie Mellon University. |
* All rights reserved. |
* |
* 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 Carnegie Mellon University. The name of the |
* University 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. |
*/ |
|
#ifndef lint |
/* static char rcsid[] = "$Id: fsm.c,v 1.2 2001-09-27 12:01:57 chris Exp $"; */ |
#endif |
#define log_packet(p, len, prefix, level) |
/* |
* TODO: |
* Randomize fsm id on link/init. |
* Deal with variable outgoing MTU. |
*/ |
|
#include <stdio.h> |
#include <string.h> |
#include <sys/types.h> |
#include <syslog.h> |
|
#include "pppd.h" |
#include "fsm.h" |
|
static void fsm_timeout __P((void *)); |
static void fsm_rconfreq __P((fsm *, int, u_char *, int)); |
static void fsm_rconfack __P((fsm *, int, u_char *, int)); |
static void fsm_rconfnakrej __P((fsm *, int, int, u_char *, int)); |
static void fsm_rtermreq __P((fsm *, int, u_char *, int)); |
static void fsm_rtermack __P((fsm *)); |
static void fsm_rcoderej __P((fsm *, u_char *, int)); |
static void fsm_sconfreq __P((fsm *, int)); |
|
#define PROTO_NAME(f) ((f)->callbacks->proto_name) |
|
int peer_mru[NUM_PPP]; |
|
|
/* |
* fsm_init - Initialize fsm. |
* |
* Initialize fsm state. |
*/ |
void |
fsm_init(f) |
fsm *f; |
{ |
f->state = INITIAL; |
f->flags = 0; |
f->id = 0; /* XXX Start with random id? */ |
f->timeouttime = DEFTIMEOUT; |
f->maxconfreqtransmits = DEFMAXCONFREQS; |
f->maxtermtransmits = DEFMAXTERMREQS; |
f->maxnakloops = DEFMAXNAKLOOPS; |
f->term_reason_len = 0; |
} |
|
|
/* |
* fsm_lowerup - The lower layer is up. |
*/ |
void |
fsm_lowerup(f) |
fsm *f; |
{ |
switch( f->state ){ |
case INITIAL: |
f->state = CLOSED; |
break; |
|
case STARTING: |
if( f->flags & OPT_SILENT ) |
f->state = STOPPED; |
else { |
/* Send an initial configure-request */ |
fsm_sconfreq(f, 0); |
f->state = REQSENT; |
} |
break; |
|
default: |
FSMDEBUG((LOG_INFO, "%s: Up event in state %d!", |
PROTO_NAME(f), f->state)); |
} |
} |
|
|
/* |
* fsm_lowerdown - The lower layer is down. |
* |
* Cancel all timeouts and inform upper layers. |
*/ |
void |
fsm_lowerdown(f) |
fsm *f; |
{ |
switch( f->state ){ |
case CLOSED: |
f->state = INITIAL; |
break; |
|
case STOPPED: |
f->state = STARTING; |
if( f->callbacks->starting ) |
(*f->callbacks->starting)(f); |
break; |
|
case CLOSING: |
f->state = INITIAL; |
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ |
break; |
|
case STOPPING: |
case REQSENT: |
case ACKRCVD: |
case ACKSENT: |
f->state = STARTING; |
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ |
break; |
|
case OPENED: |
if( f->callbacks->down ) |
(*f->callbacks->down)(f); |
f->state = STARTING; |
break; |
|
default: |
FSMDEBUG((LOG_INFO, "%s: Down event in state %d!", |
PROTO_NAME(f), f->state)); |
} |
} |
|
|
/* |
* fsm_open - Link is allowed to come up. |
*/ |
void |
fsm_open(f) |
fsm *f; |
{ |
switch( f->state ){ |
case INITIAL: |
f->state = STARTING; |
if( f->callbacks->starting ) |
(*f->callbacks->starting)(f); |
break; |
|
case CLOSED: |
if( f->flags & OPT_SILENT ) |
f->state = STOPPED; |
else { |
/* Send an initial configure-request */ |
fsm_sconfreq(f, 0); |
f->state = REQSENT; |
} |
break; |
|
case CLOSING: |
f->state = STOPPING; |
/* fall through */ |
case STOPPED: |
case OPENED: |
if( f->flags & OPT_RESTART ){ |
fsm_lowerdown(f); |
fsm_lowerup(f); |
} |
break; |
} |
} |
|
|
/* |
* fsm_close - Start closing connection. |
* |
* Cancel timeouts and either initiate close or possibly go directly to |
* the CLOSED state. |
*/ |
void |
fsm_close(f, reason) |
fsm *f; |
char *reason; |
{ |
f->term_reason = reason; |
f->term_reason_len = (reason == NULL? 0: strlen(reason)); |
switch( f->state ){ |
case STARTING: |
f->state = INITIAL; |
break; |
case STOPPED: |
f->state = CLOSED; |
break; |
case STOPPING: |
f->state = CLOSING; |
break; |
|
case REQSENT: |
case ACKRCVD: |
case ACKSENT: |
case OPENED: |
if( f->state != OPENED ) |
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ |
else if( f->callbacks->down ) |
(*f->callbacks->down)(f); /* Inform upper layers we're down */ |
|
/* Init restart counter, send Terminate-Request */ |
f->retransmits = f->maxtermtransmits; |
fsm_sdata(f, TERMREQ, f->reqid = ++f->id, |
(u_char *) f->term_reason, f->term_reason_len); |
TIMEOUT(fsm_timeout, f, f->timeouttime); |
--f->retransmits; |
|
f->state = CLOSING; |
break; |
} |
} |
|
|
/* |
* fsm_timeout - Timeout expired. |
*/ |
static void |
fsm_timeout(arg) |
void *arg; |
{ |
fsm *f = (fsm *) arg; |
|
switch (f->state) { |
case CLOSING: |
case STOPPING: |
if( f->retransmits <= 0 ){ |
/* |
* We've waited for an ack long enough. Peer probably heard us. |
*/ |
f->state = (f->state == CLOSING)? CLOSED: STOPPED; |
if( f->callbacks->finished ) |
(*f->callbacks->finished)(f); |
} else { |
/* Send Terminate-Request */ |
fsm_sdata(f, TERMREQ, f->reqid = ++f->id, |
(u_char *) f->term_reason, f->term_reason_len); |
TIMEOUT(fsm_timeout, f, f->timeouttime); |
--f->retransmits; |
} |
break; |
|
case REQSENT: |
case ACKRCVD: |
case ACKSENT: |
if (f->retransmits <= 0) { |
syslog(LOG_WARNING, "%s: timeout sending Config-Requests", |
PROTO_NAME(f)); |
f->state = STOPPED; |
if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) |
(*f->callbacks->finished)(f); |
|
} else { |
/* Retransmit the configure-request */ |
if (f->callbacks->retransmit) |
(*f->callbacks->retransmit)(f); |
fsm_sconfreq(f, 1); /* Re-send Configure-Request */ |
if( f->state == ACKRCVD ) |
f->state = REQSENT; |
} |
break; |
|
default: |
FSMDEBUG((LOG_INFO, "%s: Timeout event in state %d!", |
PROTO_NAME(f), f->state)); |
} |
} |
|
|
/* |
* fsm_input - Input packet. |
*/ |
void |
fsm_input(f, inpacket, l) |
fsm *f; |
u_char *inpacket; |
int l; |
{ |
u_char *inp; |
u_char code, id; |
int len; |
|
/* |
* Parse header (code, id and length). |
* If packet too short, drop it. |
*/ |
inp = inpacket; |
if (l < HEADERLEN) { |
FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.", |
f->protocol)); |
return; |
} |
GETCHAR(code, inp); |
GETCHAR(id, inp); |
GETSHORT(len, inp); |
if (len < HEADERLEN) { |
FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.", |
f->protocol)); |
return; |
} |
if (len > l) { |
FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.", |
f->protocol)); |
return; |
} |
len -= HEADERLEN; /* subtract header length */ |
|
if( f->state == INITIAL || f->state == STARTING ){ |
FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d.", |
f->protocol, f->state)); |
return; |
} |
|
/* |
* Action depends on code. |
*/ |
switch (code) { |
case CONFREQ: |
fsm_rconfreq(f, id, inp, len); |
break; |
|
case CONFACK: |
fsm_rconfack(f, id, inp, len); |
break; |
|
case CONFNAK: |
case CONFREJ: |
fsm_rconfnakrej(f, code, id, inp, len); |
break; |
|
case TERMREQ: |
fsm_rtermreq(f, id, inp, len); |
break; |
|
case TERMACK: |
fsm_rtermack(f); |
break; |
|
case CODEREJ: |
fsm_rcoderej(f, inp, len); |
break; |
|
default: |
if( !f->callbacks->extcode |
|| !(*f->callbacks->extcode)(f, code, id, inp, len) ) |
fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN); |
break; |
} |
} |
|
|
/* |
* fsm_rconfreq - Receive Configure-Request. |
*/ |
static void |
fsm_rconfreq(f, id, inp, len) |
fsm *f; |
u_char id; |
u_char *inp; |
int len; |
{ |
int code, reject_if_disagree; |
|
FSMDEBUG((LOG_INFO, "fsm_rconfreq(%s): Rcvd id %d.", PROTO_NAME(f), id)); |
switch( f->state ){ |
case CLOSED: |
/* Go away, we're closed */ |
fsm_sdata(f, TERMACK, id, NULL, 0); |
return; |
case CLOSING: |
case STOPPING: |
return; |
|
case OPENED: |
/* Go down and restart negotiation */ |
if( f->callbacks->down ) |
(*f->callbacks->down)(f); /* Inform upper layers */ |
fsm_sconfreq(f, 0); /* Send initial Configure-Request */ |
break; |
|
case STOPPED: |
/* Negotiation started by our peer */ |
fsm_sconfreq(f, 0); /* Send initial Configure-Request */ |
f->state = REQSENT; |
break; |
} |
|
/* |
* Pass the requested configuration options |
* to protocol-specific code for checking. |
*/ |
if (f->callbacks->reqci){ /* Check CI */ |
reject_if_disagree = (f->nakloops >= f->maxnakloops); |
code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree); |
} else if (len) |
code = CONFREJ; /* Reject all CI */ |
else |
code = CONFACK; |
|
/* send the Ack, Nak or Rej to the peer */ |
fsm_sdata(f, code, id, inp, len); |
|
if (code == CONFACK) { |
if (f->state == ACKRCVD) { |
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ |
f->state = OPENED; |
if (f->callbacks->up) |
(*f->callbacks->up)(f); /* Inform upper layers */ |
} else |
f->state = ACKSENT; |
f->nakloops = 0; |
|
} else { |
/* we sent CONFACK or CONFREJ */ |
if (f->state != ACKRCVD) |
f->state = REQSENT; |
if( code == CONFNAK ) |
++f->nakloops; |
} |
} |
|
|
/* |
* fsm_rconfack - Receive Configure-Ack. |
*/ |
static void |
fsm_rconfack(f, id, inp, len) |
fsm *f; |
int id; |
u_char *inp; |
int len; |
{ |
FSMDEBUG((LOG_INFO, "fsm_rconfack(%s): Rcvd id %d.", |
PROTO_NAME(f), id)); |
|
if (id != f->reqid || f->seen_ack) /* Expected id? */ |
return; /* Nope, toss... */ |
if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): |
(len == 0)) ){ |
/* Ack is bad - ignore it */ |
log_packet(inp, len, "Received bad configure-ack: ", LOG_ERR); |
FSMDEBUG((LOG_INFO, "%s: received bad Ack (length %d)", |
PROTO_NAME(f), len)); |
return; |
} |
f->seen_ack = 1; |
|
switch (f->state) { |
case CLOSED: |
case STOPPED: |
fsm_sdata(f, TERMACK, id, NULL, 0); |
break; |
|
case REQSENT: |
f->state = ACKRCVD; |
f->retransmits = f->maxconfreqtransmits; |
break; |
|
case ACKRCVD: |
/* Huh? an extra valid Ack? oh well... */ |
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ |
fsm_sconfreq(f, 0); |
f->state = REQSENT; |
break; |
|
case ACKSENT: |
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ |
f->state = OPENED; |
f->retransmits = f->maxconfreqtransmits; |
if (f->callbacks->up) |
(*f->callbacks->up)(f); /* Inform upper layers */ |
break; |
|
case OPENED: |
/* Go down and restart negotiation */ |
if (f->callbacks->down) |
(*f->callbacks->down)(f); /* Inform upper layers */ |
fsm_sconfreq(f, 0); /* Send initial Configure-Request */ |
f->state = REQSENT; |
break; |
} |
} |
|
|
/* |
* fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject. |
*/ |
static void |
fsm_rconfnakrej(f, code, id, inp, len) |
fsm *f; |
int code, id; |
u_char *inp; |
int len; |
{ |
int (*proc) __P((fsm *, u_char *, int)); |
int ret; |
|
FSMDEBUG((LOG_INFO, "fsm_rconfnakrej(%s): Rcvd id %d.", |
PROTO_NAME(f), id)); |
|
if (id != f->reqid || f->seen_ack) /* Expected id? */ |
return; /* Nope, toss... */ |
proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci; |
if (!proc || !(ret = proc(f, inp, len))) { |
/* Nak/reject is bad - ignore it */ |
log_packet(inp, len, "Received bad configure-nak/rej: ", LOG_ERR); |
FSMDEBUG((LOG_INFO, "%s: received bad %s (length %d)", |
PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len)); |
return; |
} |
f->seen_ack = 1; |
|
switch (f->state) { |
case CLOSED: |
case STOPPED: |
fsm_sdata(f, TERMACK, id, NULL, 0); |
break; |
|
case REQSENT: |
case ACKSENT: |
/* They didn't agree to what we wanted - try another request */ |
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ |
if (ret < 0) |
f->state = STOPPED; /* kludge for stopping CCP */ |
else |
fsm_sconfreq(f, 0); /* Send Configure-Request */ |
break; |
|
case ACKRCVD: |
/* Got a Nak/reject when we had already had an Ack?? oh well... */ |
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ |
fsm_sconfreq(f, 0); |
f->state = REQSENT; |
break; |
|
case OPENED: |
/* Go down and restart negotiation */ |
if (f->callbacks->down) |
(*f->callbacks->down)(f); /* Inform upper layers */ |
fsm_sconfreq(f, 0); /* Send initial Configure-Request */ |
f->state = REQSENT; |
break; |
} |
} |
|
|
/* |
* fsm_rtermreq - Receive Terminate-Req. |
*/ |
static void |
fsm_rtermreq(f, id, p, len) |
fsm *f; |
int id; |
u_char *p; |
int len; |
{ |
char str[80]; |
|
FSMDEBUG((LOG_INFO, "fsm_rtermreq(%s): Rcvd id %d.", |
PROTO_NAME(f), id)); |
|
switch (f->state) { |
case ACKRCVD: |
case ACKSENT: |
f->state = REQSENT; /* Start over but keep trying */ |
break; |
|
case OPENED: |
if (len > 0) { |
fmtmsg(str, sizeof(str), "%0.*v", len, p); |
syslog(LOG_INFO, "%s terminated by peer (%s)", PROTO_NAME(f), str); |
} else |
syslog(LOG_INFO, "%s terminated by peer", PROTO_NAME(f)); |
if (f->callbacks->down) |
(*f->callbacks->down)(f); /* Inform upper layers */ |
f->retransmits = 0; |
f->state = STOPPING; |
TIMEOUT(fsm_timeout, f, f->timeouttime); |
break; |
} |
|
fsm_sdata(f, TERMACK, id, NULL, 0); |
} |
|
|
/* |
* fsm_rtermack - Receive Terminate-Ack. |
*/ |
static void |
fsm_rtermack(f) |
fsm *f; |
{ |
FSMDEBUG((LOG_INFO, "fsm_rtermack(%s).", PROTO_NAME(f))); |
|
switch (f->state) { |
case CLOSING: |
UNTIMEOUT(fsm_timeout, f); |
f->state = CLOSED; |
if( f->callbacks->finished ) |
(*f->callbacks->finished)(f); |
break; |
case STOPPING: |
UNTIMEOUT(fsm_timeout, f); |
f->state = STOPPED; |
if( f->callbacks->finished ) |
(*f->callbacks->finished)(f); |
break; |
|
case ACKRCVD: |
f->state = REQSENT; |
break; |
|
case OPENED: |
if (f->callbacks->down) |
(*f->callbacks->down)(f); /* Inform upper layers */ |
fsm_sconfreq(f, 0); |
break; |
} |
} |
|
|
/* |
* fsm_rcoderej - Receive an Code-Reject. |
*/ |
static void |
fsm_rcoderej(f, inp, len) |
fsm *f; |
u_char *inp; |
int len; |
{ |
u_char code, id; |
|
FSMDEBUG((LOG_INFO, "fsm_rcoderej(%s).", PROTO_NAME(f))); |
|
if (len < HEADERLEN) { |
FSMDEBUG((LOG_INFO, "fsm_rcoderej: Rcvd short Code-Reject packet!")); |
return; |
} |
GETCHAR(code, inp); |
GETCHAR(id, inp); |
syslog(LOG_WARNING, "%s: Rcvd Code-Reject for code %d, id %d", |
PROTO_NAME(f), code, id); |
|
if( f->state == ACKRCVD ) |
f->state = REQSENT; |
} |
|
|
/* |
* fsm_protreject - Peer doesn't speak this protocol. |
* |
* Treat this as a catastrophic error (RXJ-). |
*/ |
void |
fsm_protreject(f) |
fsm *f; |
{ |
switch( f->state ){ |
case CLOSING: |
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ |
/* fall through */ |
case CLOSED: |
f->state = CLOSED; |
if( f->callbacks->finished ) |
(*f->callbacks->finished)(f); |
break; |
|
case STOPPING: |
case REQSENT: |
case ACKRCVD: |
case ACKSENT: |
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ |
/* fall through */ |
case STOPPED: |
f->state = STOPPED; |
if( f->callbacks->finished ) |
(*f->callbacks->finished)(f); |
break; |
|
case OPENED: |
if( f->callbacks->down ) |
(*f->callbacks->down)(f); |
|
/* Init restart counter, send Terminate-Request */ |
f->retransmits = f->maxtermtransmits; |
fsm_sdata(f, TERMREQ, f->reqid = ++f->id, |
(u_char *) f->term_reason, f->term_reason_len); |
TIMEOUT(fsm_timeout, f, f->timeouttime); |
--f->retransmits; |
|
f->state = STOPPING; |
break; |
|
default: |
FSMDEBUG((LOG_INFO, "%s: Protocol-reject event in state %d!", |
PROTO_NAME(f), f->state)); |
} |
} |
|
|
/* |
* fsm_sconfreq - Send a Configure-Request. |
*/ |
static void |
fsm_sconfreq(f, retransmit) |
fsm *f; |
int retransmit; |
{ |
u_char *outp; |
int cilen; |
|
if( f->state != REQSENT && f->state != ACKRCVD && f->state != ACKSENT ){ |
/* Not currently negotiating - reset options */ |
if( f->callbacks->resetci ) |
(*f->callbacks->resetci)(f); |
f->nakloops = 0; |
} |
|
if( !retransmit ){ |
/* New request - reset retransmission counter, use new ID */ |
f->retransmits = f->maxconfreqtransmits; |
f->reqid = ++f->id; |
} |
|
f->seen_ack = 0; |
|
/* |
* Make up the request packet |
*/ |
outp = outpacket_buf + PPP_HDRLEN + HEADERLEN; |
if( f->callbacks->cilen && f->callbacks->addci ){ |
cilen = (*f->callbacks->cilen)(f); |
if( cilen > peer_mru[f->unit] - HEADERLEN ) |
cilen = peer_mru[f->unit] - HEADERLEN; |
if (f->callbacks->addci) |
(*f->callbacks->addci)(f, outp, &cilen); |
} else |
cilen = 0; |
|
/* send the request to our peer */ |
fsm_sdata(f, CONFREQ, f->reqid, outp, cilen); |
|
/* start the retransmit timer */ |
--f->retransmits; |
TIMEOUT(fsm_timeout, f, f->timeouttime); |
|
FSMDEBUG((LOG_INFO, "%s: sending Configure-Request, id %d", |
PROTO_NAME(f), f->reqid)); |
} |
|
|
/* |
* fsm_sdata - Send some data. |
* |
* Used for all packets sent to our peer by this module. |
*/ |
void |
fsm_sdata(f, code, id, data, datalen) |
fsm *f; |
u_char code, id; |
u_char *data; |
int datalen; |
{ |
u_char *outp; |
int outlen; |
|
/* Adjust length to be smaller than MTU */ |
outp = outpacket_buf; |
if (datalen > peer_mru[f->unit] - HEADERLEN) |
datalen = peer_mru[f->unit] - HEADERLEN; |
if (datalen && data != outp + PPP_HDRLEN + HEADERLEN) |
BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen); |
outlen = datalen + HEADERLEN; |
MAKEHEADER(outp, f->protocol); |
PUTCHAR(code, outp); |
PUTCHAR(id, outp); |
PUTSHORT(outlen, outp); |
output(f->unit, outpacket_buf, outlen + PPP_HDRLEN); |
|
FSMDEBUG((LOG_INFO, "fsm_sdata(%s): Sent code %d, id %d.", |
PROTO_NAME(f), code, id)); |
} |
/rtems-ppp.c
0,0 → 1,1522
/* |
* sys-bsd.c - System-dependent procedures for setting up |
* PPP interfaces on bsd-4.4-ish systems (including 386BSD, NetBSD, RTEMS, etc.) |
* |
* Copyright (c) 1989 Carnegie Mellon University. |
* Copyright (c) 1995 The Australian National University. |
* All rights reserved. |
* |
* 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 Carnegie Mellon University and The Australian National University. |
* The names of the Universities 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. |
*/ |
|
#ifndef lint |
/* static char rcsid[] = "$Id: rtems-ppp.c,v 1.2 2001-09-27 12:01:57 chris Exp $"; */ |
/* $NetBSD: sys-bsd.c,v 1.1.1.3 1997/09/26 18:53:04 christos Exp $ */ |
#endif |
|
/* |
* TODO: |
*/ |
|
#include <stdio.h> |
#include <syslog.h> |
#include <string.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <errno.h> |
#include <fcntl.h> |
#include <termios.h> |
#include <signal.h> |
#include <sys/ioctl.h> |
#include <sys/types.h> |
#include <sys/socket.h> |
#include <sys/time.h> |
#include <sys/stat.h> |
#include <sys/param.h> |
#ifdef NetBSD1_2 |
#include <util.h> |
#endif |
#ifdef PPP_FILTER |
#include <net/bpf.h> |
#endif |
|
#include <net/if.h> |
#include <net/ppp_defs.h> |
#include <net/if_ppp.h> |
#include <net/route.h> |
#include <net/if_dl.h> |
#include <netinet/in.h> |
|
#if RTM_VERSION >= 3 |
#include <sys/param.h> |
#if defined(NetBSD) && (NetBSD >= 199703) |
#include <netinet/if_inarp.h> |
#else /* NetBSD 1.2D or later */ |
#include <netinet/if_ether.h> |
#endif |
#endif |
|
#include "pppd.h" |
#include "fsm.h" |
#include "ipcp.h" |
|
static int initdisc = -1; /* Initial TTY discipline for ppp_fd */ |
static int initfdflags = -1; /* Initial file descriptor flags for ppp_fd */ |
static int ppp_fd = -1; /* fd which is set to PPP discipline */ |
static int rtm_seq; |
|
static int restore_term; /* 1 => we've munged the terminal */ |
static struct termios inittermios; /* Initial TTY termios */ |
static struct winsize wsinfo; /* Initial window size info */ |
|
#if 0 |
static char *lock_file; /* name of lock file created */ |
#endif |
|
static int loop_slave = -1; |
static int loop_master; |
#if 0 |
static char loop_name[20]; |
#endif |
|
static unsigned char inbuf[512]; /* buffer for chars read from loopback */ |
|
static int sockfd; /* socket for doing interface ioctls */ |
|
static int if_is_up; /* the interface is currently up */ |
static u_int32_t ifaddrs[2]; /* local and remote addresses we set */ |
static u_int32_t default_route_gateway; /* gateway addr for default route */ |
static u_int32_t proxy_arp_addr; /* remote addr for proxy arp */ |
|
/* Prototypes for procedures local to this file. */ |
static int dodefaultroute __P((u_int32_t, int)); |
static int get_ether_addr __P((u_int32_t, struct sockaddr_dl *)); |
|
|
/* |
* sys_init - System-dependent initialization. |
*/ |
void |
sys_init() |
{ |
/* Get an internet socket for doing socket ioctl's on. */ |
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { |
syslog(LOG_ERR, "Couldn't create IP socket: %m"); |
die(1); |
} |
} |
|
/* |
* sys_cleanup - restore any system state we modified before exiting: |
* mark the interface down, delete default route and/or proxy arp entry. |
* This should call die() because it's called from die(). |
*/ |
void |
sys_cleanup() |
{ |
struct ifreq ifr; |
|
if (if_is_up) { |
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) >= 0 |
&& ((ifr.ifr_flags & IFF_UP) != 0)) { |
ifr.ifr_flags &= ~IFF_UP; |
ioctl(sockfd, SIOCSIFFLAGS, &ifr); |
} |
} |
if (ifaddrs[0] != 0) |
cifaddr(0, ifaddrs[0], ifaddrs[1]); |
if (default_route_gateway) |
cifdefaultroute(0, 0, default_route_gateway); |
if (proxy_arp_addr) |
cifproxyarp(0, proxy_arp_addr); |
} |
|
/* |
* sys_close - Clean up in a child process before execing. |
*/ |
void |
sys_close() |
{ |
close(sockfd); |
if (loop_slave >= 0) { |
close(loop_slave); |
close(loop_master); |
} |
} |
|
/* |
* sys_check_options - check the options that the user specified |
*/ |
void |
sys_check_options() |
{ |
} |
|
/* |
* ppp_available - check whether the system has any ppp interfaces |
* (in fact we check whether we can do an ioctl on ppp0). |
*/ |
int |
ppp_available() |
{ |
int s, ok; |
struct ifreq ifr; |
extern char *no_ppp_msg; |
|
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) |
return 1; /* can't tell */ |
|
strncpy(ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name)); |
ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0; |
close(s); |
|
no_ppp_msg = "\ |
This system lacks kernel support for PPP. To include PPP support\n\ |
in the kernel, please follow the steps detailed in the README.bsd\n\ |
file in the ppp-2.2 distribution.\n"; |
return ok; |
} |
|
/* |
* establish_ppp - Turn the serial port into a ppp interface. |
*/ |
void |
establish_ppp(fd) |
int fd; |
{ |
int pppdisc = PPPDISC; |
int x; |
|
if (demand) { |
/* |
* Demand mode - prime the old ppp device to relinquish the unit. |
*/ |
if (ioctl(ppp_fd, PPPIOCXFERUNIT, 0) < 0) { |
syslog(LOG_ERR, "ioctl(transfer ppp unit): %m"); |
die(1); |
} |
} |
|
/* |
* Save the old line discipline of fd, and set it to PPP. |
*/ |
if (ioctl(fd, TIOCGETD, &initdisc) < 0) { |
syslog(LOG_ERR, "ioctl(TIOCGETD): %m"); |
die(1); |
} |
if (ioctl(fd, TIOCSETD, &pppdisc) < 0) { |
syslog(LOG_ERR, "ioctl(TIOCSETD): %m"); |
die(1); |
} |
|
if (!demand) { |
/* |
* Find out which interface we were given. |
*/ |
if (ioctl(fd, PPPIOCGUNIT, &interfunit) < 0) { |
syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m"); |
die(1); |
} |
} else { |
/* |
* Check that we got the same unit again. |
*/ |
|
if (ioctl(fd, PPPIOCGUNIT, &x) < 0) { |
syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m"); |
die(1); |
} |
if (x != interfunit) { |
syslog(LOG_ERR, "transfer_ppp failed: wanted unit %d, got %d", |
interfunit, x); |
die(1); |
} |
x = TTYDISC; |
ioctl(loop_slave, TIOCSETD, &x); |
} |
|
ppp_fd = fd; |
|
/* |
* Enable debug in the driver if requested. |
*/ |
if (kdebugflag) { |
if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { |
syslog(LOG_WARNING, "ioctl (PPPIOCGFLAGS): %m"); |
} else { |
x |= (kdebugflag & 0xFF) * SC_DEBUG; |
if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) |
syslog(LOG_WARNING, "ioctl(PPPIOCSFLAGS): %m") |
; |
} |
} |
|
/* |
* Set device for non-blocking reads. |
*/ |
#define fcntl(a) |
|
|
/* if ((initfdflags = fcntl(fd, F_GETFL)) == -1 |
|| fcntl(fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) { |
*/ |
/* syslog(LOG_WARNING, "Couldn't set device to non-blocking mode: %m"); |
*/ /*}*/ |
} |
|
/* |
* restore_loop - reattach the ppp unit to the loopback. |
*/ |
void |
restore_loop() |
{ |
int x; |
|
/* |
* Transfer the ppp interface back to the loopback. |
*/ |
if (ioctl(ppp_fd, PPPIOCXFERUNIT, 0) < 0) { |
syslog(LOG_ERR, "ioctl(transfer ppp unit): %m"); |
die(1); |
} |
x = PPPDISC; |
if (ioctl(loop_slave, TIOCSETD, &x) < 0) { |
syslog(LOG_ERR, "ioctl(TIOCSETD): %m"); |
die(1); |
} |
|
/* |
* Check that we got the same unit again. |
*/ |
if (ioctl(loop_slave, PPPIOCGUNIT, &x) < 0) { |
syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m"); |
die(1); |
} |
if (x != interfunit) { |
syslog(LOG_ERR, "transfer_ppp failed: wanted unit %d, got %d", |
interfunit, x); |
die(1); |
} |
ppp_fd = loop_slave; |
} |
|
|
/* |
* disestablish_ppp - Restore the serial port to normal operation. |
* This shouldn't call die() because it's called from die(). |
*/ |
void |
disestablish_ppp(fd) |
int fd; |
{ |
/* Reset non-blocking mode on fd. */ |
/* if (initfdflags != -1 && fcntl(fd, F_SETFL, initfdflags) < 0)*/ |
/* syslog(LOG_WARNING, "Couldn't restore device fd flags: %m"); |
*/ initfdflags = -1; |
|
/* Restore old line discipline. */ |
if (initdisc >= 0 && ioctl(fd, TIOCSETD, &initdisc) < 0) |
/* syslog(LOG_ERR, "ioctl(TIOCSETD): %m"); |
*/ initdisc = -1; |
|
if (fd == ppp_fd) |
ppp_fd = -1; |
} |
|
/* |
* Check whether the link seems not to be 8-bit clean. |
*/ |
void |
clean_check() |
{ |
int x; |
char *s; |
|
if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) == 0) { |
s = NULL; |
switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) { |
case SC_RCV_B7_0: |
s = "bit 7 set to 1"; |
break; |
case SC_RCV_B7_1: |
s = "bit 7 set to 0"; |
break; |
case SC_RCV_EVNP: |
s = "odd parity"; |
break; |
case SC_RCV_ODDP: |
s = "even parity"; |
break; |
} |
/* if (s != NULL) { |
syslog(LOG_WARNING, "Serial link is not 8-bit clean:"); |
syslog(LOG_WARNING, "All received characters had %s", s); |
} |
*/ } |
} |
|
/* |
* set_up_tty: Set up the serial port on `fd' for 8 bits, no parity, |
* at the requested speed, etc. If `local' is true, set CLOCAL |
* regardless of whether the modem option was specified. |
* |
* For *BSD, we assume that speed_t values numerically equal bits/second. |
*/ |
void |
set_up_tty(fd, local) |
int fd, local; |
{ |
struct termios tios; |
|
if (tcgetattr(fd, &tios) < 0) { |
syslog(LOG_ERR, "tcgetattr: %m"); |
die(1); |
} |
|
if (!restore_term) { |
inittermios = tios; |
ioctl(fd, TIOCGWINSZ, &wsinfo); |
} |
|
tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL); |
if (crtscts > 0 && !local) |
tios.c_cflag |= CRTSCTS; |
else if (crtscts < 0) |
tios.c_cflag &= ~CRTSCTS; |
|
tios.c_cflag |= CS8 | CREAD | HUPCL; |
if (local || !modem) |
tios.c_cflag |= CLOCAL; |
tios.c_iflag = IGNBRK | IGNPAR; |
tios.c_oflag = 0; |
tios.c_lflag = 0; |
tios.c_cc[VMIN] = 1; |
tios.c_cc[VTIME] = 0; |
|
if (crtscts == -2) { |
tios.c_iflag |= IXON | IXOFF; |
tios.c_cc[VSTOP] = 0x13; |
tios.c_cc[VSTART] = 0x11; |
} |
|
if (inspeed) { |
cfsetospeed(&tios, inspeed); |
cfsetispeed(&tios, inspeed); |
} else { |
inspeed = cfgetospeed(&tios); |
/* |
* We can't proceed if the serial port speed is 0, |
* since that implies that the serial port is disabled. |
*/ |
if (inspeed == 0) { |
syslog(LOG_ERR, "Baud rate for %s is 0; need explicit baud rate", |
devnam); |
die(1); |
} |
} |
/* baud_rate = 9600;*/ |
/* na razie wpisujemy na twardo*/ |
|
if (tcsetattr(fd, TCSANOW, &tios) < 0) { |
syslog(LOG_ERR, "tcsetattr: %m"); |
die(1); |
} |
|
restore_term = 1; |
} |
|
/* |
* restore_tty - restore the terminal to the saved settings. |
*/ |
void |
restore_tty(fd) |
int fd; |
{ |
/* if (restore_term) { |
if (!default_device) { |
*/ /* |
* Turn off echoing, because otherwise we can get into |
* a loop with the tty and the modem echoing to each other. |
* We presume we are the sole user of this tty device, so |
* when we close it, it will revert to its defaults anyway. |
*/ |
/* inittermios.c_lflag &= ~(ECHO | ECHONL); |
} |
if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0) |
if (errno != ENXIO) |
syslog(LOG_WARNING, "tcsetattr: %m"); |
ioctl(fd, TIOCSWINSZ, &wsinfo); |
restore_term = 0; |
} |
*/} |
|
/* |
* - control the DTR line on the serial port. |
* This is called from die(), so it shouldn't call die(). |
*/ |
void |
setdtr(fd, on) |
int fd, on; |
{ |
int modembits = TIOCM_DTR; |
|
ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits); |
} |
|
|
/* |
* open_ppp_loopback - open the device we use for getting |
* packets in demand mode, and connect it to a ppp interface. |
* Here we use a pty. |
*/ |
void |
open_ppp_loopback() |
{ |
|
} |
|
|
/* |
* output - Output PPP packet. |
*/ |
void |
output(unit, p, len) |
int unit; |
u_char *p; |
int len; |
{ |
if (debug); |
syslog(LOG_DEBUG, "sent %d bytes ", len ); |
|
if (write(ttyfd, p, len) < 0) { |
/* if (errno != EIO) |
syslog(LOG_ERR, "write: %m"); |
*/ } |
} |
|
extern int rtems_bsdnet_microseconds_per_tick; |
#include <rtems.h> |
#include <rtems/rtems_bsdnet.h> |
/* |
* wait_input - wait until there is data available on ttyfd, |
* for the length of time specified by *timo (indefinite |
* if timo is NULL). |
*/ |
|
/* |
* wait_loop_output - wait until there is data available on the |
* loopback, for the length of time specified by *timo (indefinite |
* if timo is NULL). |
*/ |
void |
wait_loop_output(timo) |
struct timeval *timo; |
{ |
/* |
fd_set ready; |
int n; |
*/ |
|
/* FD_ZERO(&ready); |
FD_SET(loop_master, &ready); |
n = select(loop_master + 1, &ready, NULL, &ready, timo); |
if (n < 0 && errno != EINTR) { |
*/ |
/* syslog(LOG_ERR, "select: %m");*/ |
/* die(1); |
} |
*/ |
} |
|
|
/* |
* wait_time - wait for a given length of time or until a |
* signal is received. |
*/ |
void |
wait_time(timo) |
struct timeval *timo; |
{ |
rtems_status_code status; |
rtems_interval ticks; |
|
ticks = |
(timo->tv_sec*1000000+timo->tv_usec)/rtems_bsdnet_microseconds_per_tick; |
status = rtems_task_wake_after( ticks ); |
} |
|
|
/* |
* read_packet - get a PPP packet from the serial device. |
*/ |
int |
read_packet(buf) |
u_char *buf; |
{ |
int len; |
|
if ((len = read(ttyfd, buf, PPP_MTU + PPP_HDRLEN)) < 0) { |
if (errno == EWOULDBLOCK || errno == EINTR || errno == ETIMEDOUT) |
return -1; |
syslog(LOG_ERR, "read: %m"); |
} |
return len; |
} |
|
|
/* |
* get_loop_output - read characters from the loopback, form them |
* into frames, and detect when we want to bring the real link up. |
* Return value is 1 if we need to bring up the link, 0 otherwise. |
*/ |
int |
get_loop_output() |
{ |
int rv = 0; |
int n; |
|
while ((n = read(loop_master, inbuf, sizeof(inbuf))) >= 0) { |
if (loop_chars(inbuf, n)) |
rv = 1; |
} |
|
if (n == 0) { |
syslog(LOG_ERR, "eof on loopback"); |
die(1); |
} else if (errno != EWOULDBLOCK){ |
syslog(LOG_ERR, "read from loopback: %m"); |
die(1); |
} |
|
return rv; |
} |
|
|
/* |
* ppp_send_config - configure the transmit characteristics of |
* the ppp interface. |
*/ |
void |
ppp_send_config(unit, mtu, asyncmap, pcomp, accomp) |
int unit, mtu; |
u_int32_t asyncmap; |
int pcomp, accomp; |
{ |
u_int x; |
struct ifreq ifr; |
|
strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); |
ifr.ifr_mtu = mtu; |
if (ioctl(sockfd, SIOCSIFMTU, (caddr_t) &ifr) < 0) { |
syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m"); |
quit(); |
} |
|
if (ioctl(ppp_fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) { |
syslog(LOG_ERR, "ioctl(PPPIOCSASYNCMAP): %m"); |
quit(); |
} |
|
if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { |
syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m"); |
quit(); |
} |
x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT; |
x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC; |
if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) { |
syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m"); |
quit(); |
} |
} |
|
|
/* |
* ppp_set_xaccm - set the extended transmit ACCM for the interface. |
*/ |
void |
ppp_set_xaccm(unit, accm) |
int unit; |
ext_accm accm; |
{ |
if (ioctl(ppp_fd, PPPIOCSXASYNCMAP, accm) < 0 && errno != ENOTTY) |
/*syslog(LOG_WARNING, "ioctl(set extended ACCM): %m")*/; |
} |
|
|
/* |
* ppp_recv_config - configure the receive-side characteristics of |
* the ppp interface. |
*/ |
void |
ppp_recv_config(unit, mru, asyncmap, pcomp, accomp) |
int unit, mru; |
u_int32_t asyncmap; |
int pcomp, accomp; |
{ |
/* |
int x; |
*/ |
|
/* if (ioctl(ppp_fd, PPPIOCSMRU, (caddr_t) &mru) < 0) { |
syslog(LOG_ERR, "ioctl(PPPIOCSMRU): %m"); |
quit(); |
} |
*/ |
/* if (ioctl(ppp_fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) { |
syslog(LOG_ERR, "ioctl(PPPIOCSRASYNCMAP): %m"); |
quit(); |
} |
*/ |
/* if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { |
syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m"); |
quit(); |
} |
*/ |
/* x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC; |
if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) { |
syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m"); |
quit(); |
} |
*/ |
} |
|
/* |
* ccp_test - ask kernel whether a given compression method |
* is acceptable for use. Returns 1 if the method and parameters |
* are OK, 0 if the method is known but the parameters are not OK |
* (e.g. code size should be reduced), or -1 if the method is unknown. |
*/ |
int |
ccp_test(unit, opt_ptr, opt_len, for_transmit) |
int unit, opt_len, for_transmit; |
u_char *opt_ptr; |
{ |
struct ppp_option_data data; |
|
data.ptr = opt_ptr; |
data.length = opt_len; |
data.transmit = for_transmit; |
if (ioctl(ttyfd, PPPIOCSCOMPRESS, (caddr_t) &data) >= 0) |
return 1; |
return (errno == ENOBUFS)? 0: -1; |
} |
|
/* |
* ccp_flags_set - inform kernel about the current state of CCP. |
*/ |
void |
ccp_flags_set(unit, isopen, isup) |
int unit, isopen, isup; |
{ |
int x; |
|
if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { |
/* syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m"); |
*/ return; |
} |
x = isopen? x | SC_CCP_OPEN: x &~ SC_CCP_OPEN; |
x = isup? x | SC_CCP_UP: x &~ SC_CCP_UP; |
if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) |
/* syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m")*/; |
} |
|
/* |
* ccp_fatal_error - returns 1 if decompression was disabled as a |
* result of an error detected after decompression of a packet, |
* 0 otherwise. This is necessary because of patent nonsense. |
*/ |
int |
ccp_fatal_error(unit) |
int unit; |
{ |
int x; |
|
if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { |
/* syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %m");*/ |
return 0; |
} |
return x & SC_DC_FERROR; |
} |
|
/* |
* get_idle_time - return how long the link has been idle. |
*/ |
int |
get_idle_time(u, ip) |
int u; |
struct ppp_idle *ip; |
{ |
return ioctl(ppp_fd, PPPIOCGIDLE, ip) >= 0; |
} |
|
|
#ifdef PPP_FILTER |
/* |
* set_filters - transfer the pass and active filters to the kernel. |
*/ |
int |
set_filters(pass, active) |
struct bpf_program *pass, *active; |
{ |
int ret = 1; |
|
if (pass->bf_len > 0) { |
if (ioctl(ppp_fd, PPPIOCSPASS, pass) < 0) { |
syslog(LOG_ERR, "Couldn't set pass-filter in kernel: %m"); |
ret = 0; |
} |
} |
if (active->bf_len > 0) { |
if (ioctl(ppp_fd, PPPIOCSACTIVE, active) < 0) { |
syslog(LOG_ERR, "Couldn't set active-filter in kernel: %m"); |
ret = 0; |
} |
} |
return ret; |
} |
#endif |
|
/* |
* sifvjcomp - config tcp header compression |
*/ |
int |
sifvjcomp(u, vjcomp, cidcomp, maxcid) |
int u, vjcomp, cidcomp, maxcid; |
{ |
u_int x; |
|
if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { |
syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m"); |
return 0; |
} |
x = vjcomp ? x | SC_COMP_TCP: x &~ SC_COMP_TCP; |
x = cidcomp? x & ~SC_NO_TCP_CCID: x | SC_NO_TCP_CCID; |
if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) { |
syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m"); |
return 0; |
} |
if (vjcomp && ioctl(ppp_fd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) { |
syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m"); |
return 0; |
} |
return 1; |
} |
|
/* |
* sifup - Config the interface up and enable IP packets to pass. |
*/ |
int |
sifup(u) |
int u; |
{ |
struct ifreq ifr; |
|
strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); |
if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { |
syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m"); |
return 0; |
} |
ifr.ifr_flags |= IFF_UP; |
if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { |
syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m"); |
return 0; |
} |
if_is_up = 1; |
return 1; |
} |
|
/* |
* sifnpmode - Set the mode for handling packets for a given NP. |
*/ |
int |
sifnpmode(u, proto, mode) |
int u; |
int proto; |
enum NPmode mode; |
{ |
struct npioctl npi; |
|
npi.protocol = proto; |
npi.mode = mode; |
if (ioctl(ppp_fd, PPPIOCSNPMODE, &npi) < 0) { |
/* syslog(LOG_ERR, "ioctl(set NP %d mode to %d): %m", proto, mode);*/ |
return 0; |
} |
return 1; |
} |
|
/* |
* sifdown - Config the interface down and disable IP. |
*/ |
int |
sifdown(u) |
int u; |
{ |
struct ifreq ifr; |
int rv; |
struct npioctl npi; |
|
rv = 1; |
npi.protocol = PPP_IP; |
npi.mode = NPMODE_ERROR; |
ioctl(ppp_fd, PPPIOCSNPMODE, (caddr_t) &npi); |
/* ignore errors, because ppp_fd might have been closed by now. */ |
|
strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); |
if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { |
/* syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");*/ |
rv = 0; |
} else { |
ifr.ifr_flags &= ~IFF_UP; |
if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { |
/* syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");*/ |
rv = 0; |
} else |
if_is_up = 0; |
} |
return rv; |
} |
|
/* |
* SET_SA_FAMILY - set the sa_family field of a struct sockaddr, |
* if it exists. |
*/ |
#define SET_SA_FAMILY(addr, family) \ |
BZERO((char *) &(addr), sizeof(addr)); \ |
addr.sa_family = (family); \ |
addr.sa_len = sizeof(addr); |
|
/* |
* sifaddr - Config the interface IP addresses and netmask. |
*/ |
int |
sifaddr(u, o, h, m) |
int u; |
u_int32_t o, h, m; |
{ |
struct ifaliasreq ifra; |
struct ifreq ifr; |
/* struct sockaddr_in address; |
struct sockaddr_in netmask; |
struct sockaddr_in broadcast; |
|
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
memset (&address, '\0', sizeof address); |
address.sin_len = sizeof address; |
address.sin_family = AF_INET; |
address.sin_addr.s_addr = o; |
memcpy (&ifr.ifr_addr, &address, sizeof address); |
if (ioctl(sockfd, SIOCDIFADDR, (caddr_t) &ifr) < 0) { |
if (errno != EADDRNOTAVAIL) |
syslog(LOG_WARNING, "Couldn't remove interface address: %m"); |
} |
|
if (ioctl (sockfd, SIOCSIFADDR, &ifr) < 0) |
syslog(LOG_ERR, "Can't set address: "); |
|
|
memset (&netmask, '\0', sizeof netmask); |
netmask.sin_len = sizeof netmask; |
netmask.sin_family = AF_INET; |
netmask.sin_addr.s_addr = m ; |
memcpy (&ifr.ifr_addr, &netmask, sizeof netmask); |
|
if (ioctl (sockfd, SIOCSIFNETMASK, &ifr) < 0) |
syslog(LOG_ERR,"Can't set netmask: "); |
memset (&broadcast, '\0', sizeof broadcast); |
broadcast.sin_len = sizeof broadcast; |
broadcast.sin_family = AF_INET; |
broadcast.sin_addr.s_addr = h; |
memcpy (&ifr.ifr_broadaddr, &broadcast, sizeof broadcast); |
if (ioctl (sockfd, SIOCSIFBRDADDR, &ifr) < 0) |
syslog(LOG_ERR,"Can't set broadcast address: "); |
|
*/ |
strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name)); |
SET_SA_FAMILY(ifra.ifra_addr, AF_INET); |
((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o; |
SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET); |
((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h; |
if (m != 0) { |
SET_SA_FAMILY(ifra.ifra_mask, AF_INET); |
((struct sockaddr_in *) &ifra.ifra_mask)->sin_addr.s_addr = m; |
} else |
BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask)); |
BZERO(&ifr, sizeof(ifr)); |
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
|
if (ioctl(sockfd, SIOCDIFADDR, (caddr_t) &ifr) < 0) { |
/* if (errno != EADDRNOTAVAIL) |
syslog(LOG_WARNING, "Couldn't remove interface address: %m"); |
*/ |
} |
|
|
|
if (ioctl(sockfd, SIOCAIFADDR, (caddr_t) &ifra) < 0) { |
if (errno != EEXIST) { |
syslog(LOG_ERR, "Couldn't set interface address: %m"); |
return 0; |
} |
/* syslog(LOG_WARNING, |
"Couldn't set interface address: Address %s already exists", |
ip_ntoa(o)); |
*/ } |
ifaddrs[0] = o; |
ifaddrs[1] = h; |
return 1; |
} |
|
/* |
* cifaddr - Clear the interface IP addresses, and delete routes |
* through the interface if possible. |
*/ |
int |
cifaddr(u, o, h) |
int u; |
u_int32_t o, h; |
{ |
struct ifaliasreq ifra; |
|
ifaddrs[0] = 0; |
strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name)); |
SET_SA_FAMILY(ifra.ifra_addr, AF_INET); |
((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o; |
SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET); |
((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h; |
BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask)); |
if (ioctl(sockfd, SIOCDIFADDR, (caddr_t) &ifra) < 0) { |
/* if (errno != EADDRNOTAVAIL) |
syslog(LOG_WARNING, "Couldn't delete interface address: %m"); |
*/ return 0; |
} |
return 1; |
} |
|
/* |
* sifdefaultroute - assign a default route through the address given. |
*/ |
int |
sifdefaultroute(u, l, g) |
int u; |
u_int32_t l, g; |
{ |
return dodefaultroute(g, 's'); |
} |
|
/* |
* cifdefaultroute - delete a default route through the address given. |
*/ |
int |
cifdefaultroute(u, l, g) |
int u; |
u_int32_t l, g; |
{ |
return dodefaultroute(g, 'c'); |
} |
|
/* |
* dodefaultroute - talk to a routing socket to add/delete a default route. |
*/ |
static int |
dodefaultroute(g, cmd) |
u_int32_t g; |
int cmd; |
{ |
/* int routes;*/ |
|
struct sockaddr_in address; |
struct sockaddr_in netmask; |
/* struct sockaddr_in broadcast; */ |
struct sockaddr_in gateway; |
|
/* struct { |
struct rt_msghdr hdr; |
struct sockaddr_in dst; |
struct sockaddr_in gway; |
struct sockaddr_in mask; |
} rtmsg; |
*/ |
/* if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) { |
syslog(LOG_ERR, "Couldn't %s default route: socket: %m", |
cmd=='s'? "add": "delete"); |
return 0; |
} |
*/ |
memset((void *) &address, 0, sizeof(address)); |
address.sin_len = sizeof address; |
address.sin_family = AF_INET; |
address.sin_addr.s_addr = INADDR_ANY; |
|
memset((void *) &netmask, 0, sizeof(netmask)); |
netmask.sin_len = sizeof netmask; |
netmask.sin_addr.s_addr = INADDR_ANY; |
netmask.sin_family = AF_INET; |
|
|
if (cmd=='s') |
{ |
memset((void *) &gateway, 0, sizeof(gateway)); |
gateway.sin_len = sizeof gateway; |
gateway.sin_family = AF_INET; |
gateway.sin_addr.s_addr = htons(g) ; |
|
|
if (rtems_bsdnet_rtrequest (RTM_ADD, |
(struct sockaddr *)&address, |
(struct sockaddr *)&gateway, |
(struct sockaddr *)&netmask, |
(RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL) < 0) |
/*syslog(LOG_WARNING,"Can't set default route: ")*/ |
; |
} |
else |
{ |
memset((void *) &gateway, 0, sizeof(gateway)); |
gateway.sin_len = sizeof gateway; |
gateway.sin_family = AF_INET; |
gateway.sin_addr.s_addr = INADDR_ANY; |
|
if (rtems_bsdnet_rtrequest (RTM_DELETE, |
(struct sockaddr *)&address, |
(struct sockaddr *)&gateway, |
(struct sockaddr *)&netmask, |
(RTF_UP | RTF_STATIC), NULL) < 0) |
/*syslog(LOG_WARNING,"Can't set default route: ")*/ |
; |
} |
|
/* |
rtmsg.hdr.rtm_type = cmd == 's'? RTM_ADD: RTM_DELETE; |
rtmsg.hdr.rtm_flags = RTF_UP | RTF_GATEWAY; |
rtmsg.hdr.rtm_version = RTM_VERSION; |
rtmsg.hdr.rtm_seq = ++rtm_seq; |
rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; |
rtmsg.dst.sin_len = sizeof(rtmsg.dst); |
rtmsg.dst.sin_family = AF_INET; |
rtmsg.gway.sin_len = sizeof(rtmsg.gway); |
rtmsg.gway.sin_family = AF_INET; |
rtmsg.gway.sin_addr.s_addr = g; |
rtmsg.mask.sin_len = sizeof(rtmsg.dst); |
rtmsg.mask.sin_family = AF_INET; |
|
rtmsg.hdr.rtm_msglen = sizeof(rtmsg); |
|
|
if (write(routes, &rtmsg, sizeof(rtmsg)) < 0) { |
syslog(LOG_ERR, "Couldn't %s default route: %m", |
cmd=='s'? "add": "delete"); |
close(routes); |
return 0; |
} |
|
close(routes);*/ |
default_route_gateway = (cmd == 's')? g: 0; |
return 1; |
} |
|
#if RTM_VERSION >= 3 |
|
/* |
* sifproxyarp - Make a proxy ARP entry for the peer. |
*/ |
static struct { |
struct rt_msghdr hdr; |
struct sockaddr_inarp dst; |
struct sockaddr_dl hwa; |
char extra[128]; |
} arpmsg; |
|
static int arpmsg_valid; |
|
int |
sifproxyarp(unit, hisaddr) |
int unit; |
u_int32_t hisaddr; |
{ |
int routes; |
return 0; |
|
|
/* |
* Get the hardware address of an interface on the same subnet |
* as our local address. |
*/ |
memset(&arpmsg, 0, sizeof(arpmsg)); |
if (!get_ether_addr(hisaddr, &arpmsg.hwa)) { |
/* syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP"); |
*/ return 0; |
} |
|
if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) { |
/* syslog(LOG_ERR, "Couldn't add proxy arp entry: socket: %m"); |
*/ return 0; |
} |
|
arpmsg.hdr.rtm_type = RTM_ADD; |
arpmsg.hdr.rtm_flags = RTF_ANNOUNCE | RTF_HOST | RTF_STATIC; |
arpmsg.hdr.rtm_version = RTM_VERSION; |
arpmsg.hdr.rtm_seq = ++rtm_seq; |
arpmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY; |
arpmsg.hdr.rtm_inits = RTV_EXPIRE; |
arpmsg.dst.sin_len = sizeof(struct sockaddr_inarp); |
arpmsg.dst.sin_family = AF_INET; |
arpmsg.dst.sin_addr.s_addr = hisaddr; |
arpmsg.dst.sin_other = SIN_PROXY; |
|
arpmsg.hdr.rtm_msglen = (char *) &arpmsg.hwa - (char *) &arpmsg |
+ arpmsg.hwa.sdl_len; |
if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) { |
/* syslog(LOG_ERR, "Couldn't add proxy arp entry: %m"); |
*/ close(routes); |
return 0; |
} |
|
close(routes); |
arpmsg_valid = 1; |
proxy_arp_addr = hisaddr; |
return 1; |
} |
|
/* |
* cifproxyarp - Delete the proxy ARP entry for the peer. |
*/ |
int |
cifproxyarp(unit, hisaddr) |
int unit; |
u_int32_t hisaddr; |
{ |
int routes; |
|
if (!arpmsg_valid) |
return 0; |
arpmsg_valid = 0; |
|
arpmsg.hdr.rtm_type = RTM_DELETE; |
arpmsg.hdr.rtm_seq = ++rtm_seq; |
|
if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) { |
syslog(LOG_ERR, "Couldn't delete proxy arp entry: socket: %m"); |
return 0; |
} |
|
if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) { |
syslog(LOG_ERR, "Couldn't delete proxy arp entry: %m"); |
close(routes); |
return 0; |
} |
|
close(routes); |
proxy_arp_addr = 0; |
return 1; |
} |
|
#else /* RTM_VERSION */ |
|
/* |
* sifproxyarp - Make a proxy ARP entry for the peer. |
*/ |
int |
sifproxyarp(unit, hisaddr) |
int unit; |
u_int32_t hisaddr; |
{ |
struct arpreq arpreq; |
struct { |
struct sockaddr_dl sdl; |
char space[128]; |
} dls; |
|
BZERO(&arpreq, sizeof(arpreq)); |
|
/* |
* Get the hardware address of an interface on the same subnet |
* as our local address. |
*/ |
if (!get_ether_addr(hisaddr, &dls.sdl)) { |
syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP"); |
return 0; |
} |
|
arpreq.arp_ha.sa_len = sizeof(struct sockaddr); |
arpreq.arp_ha.sa_family = AF_UNSPEC; |
BCOPY(LLADDR(&dls.sdl), arpreq.arp_ha.sa_data, dls.sdl.sdl_alen); |
SET_SA_FAMILY(arpreq.arp_pa, AF_INET); |
((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr; |
arpreq.arp_flags = ATF_PERM | ATF_PUBL; |
if (ioctl(sockfd, SIOCSARP, (caddr_t)&arpreq) < 0) { |
syslog(LOG_ERR, "Couldn't add proxy arp entry: %m"); |
return 0; |
} |
|
proxy_arp_addr = hisaddr; |
return 1; |
} |
|
/* |
* cifproxyarp - Delete the proxy ARP entry for the peer. |
*/ |
int |
cifproxyarp(unit, hisaddr) |
int unit; |
u_int32_t hisaddr; |
{ |
struct arpreq arpreq; |
|
BZERO(&arpreq, sizeof(arpreq)); |
SET_SA_FAMILY(arpreq.arp_pa, AF_INET); |
((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr; |
if (ioctl(sockfd, SIOCDARP, (caddr_t)&arpreq) < 0) { |
syslog(LOG_WARNING, "Couldn't delete proxy arp entry: %m"); |
return 0; |
} |
proxy_arp_addr = 0; |
return 1; |
} |
#endif /* RTM_VERSION */ |
|
|
/* |
* get_ether_addr - get the hardware address of an interface on the |
* the same subnet as ipaddr. |
*/ |
#define MAX_IFS 32 |
|
static int |
get_ether_addr(ipaddr, hwaddr) |
u_int32_t ipaddr; |
struct sockaddr_dl *hwaddr; |
{ |
struct ifreq *ifr, *ifend, *ifp; |
u_int32_t ina, mask; |
struct sockaddr_dl *dla; |
struct ifreq ifreq; |
struct ifconf ifc; |
struct ifreq ifs[MAX_IFS]; |
|
ifc.ifc_len = sizeof(ifs); |
ifc.ifc_req = ifs; |
if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) { |
syslog(LOG_ERR, "ioctl(SIOCGIFCONF): %m"); |
return 0; |
} |
|
/* |
* Scan through looking for an interface with an Internet |
* address on the same subnet as `ipaddr'. |
*/ |
ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); |
for (ifr = ifc.ifc_req; ifr < ifend; ifr = (struct ifreq *) |
((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len)) { |
if (ifr->ifr_addr.sa_family == AF_INET) { |
ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr; |
strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); |
/* |
* Check that the interface is up, and not point-to-point |
* or loopback. |
*/ |
if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0) |
continue; |
if ((ifreq.ifr_flags & |
(IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP)) |
!= (IFF_UP|IFF_BROADCAST)) |
continue; |
/* |
* Get its netmask and check that it's on the right subnet. |
*/ |
if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0) |
continue; |
mask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr; |
if ((ipaddr & mask) != (ina & mask)) |
continue; |
|
break; |
} |
} |
|
if (ifr >= ifend) |
return 0; |
syslog(LOG_INFO, "found interface %s for proxy arp", ifr->ifr_name); |
|
/* |
* Now scan through again looking for a link-level address |
* for this interface. |
*/ |
ifp = ifr; |
for (ifr = ifc.ifc_req; ifr < ifend; ) { |
if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0 |
&& ifr->ifr_addr.sa_family == AF_LINK) { |
/* |
* Found the link-level address - copy it out |
*/ |
dla = (struct sockaddr_dl *) &ifr->ifr_addr; |
BCOPY(dla, hwaddr, dla->sdl_len); |
return 1; |
} |
ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len); |
} |
|
return 0; |
} |
|
/* |
* Return user specified netmask, modified by any mask we might determine |
* for address `addr' (in network byte order). |
* Here we scan through the system's list of interfaces, looking for |
* any non-point-to-point interfaces which might appear to be on the same |
* network as `addr'. If we find any, we OR in their netmask to the |
* user-specified netmask. |
*/ |
u_int32_t |
GetMask(addr) |
u_int32_t addr; |
{ |
u_int32_t mask, nmask, ina; |
struct ifreq *ifr, *ifend, ifreq; |
struct ifconf ifc; |
struct ifreq ifs[MAX_IFS]; |
|
addr = ntohl(addr); |
if (IN_CLASSA(addr)) /* determine network mask for address class */ |
nmask = IN_CLASSA_NET; |
else if (IN_CLASSB(addr)) |
nmask = IN_CLASSB_NET; |
else |
nmask = IN_CLASSC_NET; |
/* class D nets are disallowed by bad_ip_adrs */ |
mask = netmask | htonl(nmask); |
|
/* |
* Scan through the system's network interfaces. |
*/ |
ifc.ifc_len = sizeof(ifs); |
ifc.ifc_req = ifs; |
if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) { |
syslog(LOG_WARNING, "ioctl(SIOCGIFCONF): %m"); |
return mask; |
} |
ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); |
for (ifr = ifc.ifc_req; ifr < ifend; ifr = (struct ifreq *) |
((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len)) { |
/* |
* Check the interface's internet address. |
*/ |
if (ifr->ifr_addr.sa_family != AF_INET) |
continue; |
ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr; |
if ((ntohl(ina) & nmask) != (addr & nmask)) |
continue; |
/* |
* Check that the interface is up, and not point-to-point or loopback. |
*/ |
strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); |
if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0) |
continue; |
if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK)) |
!= IFF_UP) |
continue; |
/* |
* Get its netmask and OR it into our mask. |
*/ |
if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0) |
continue; |
mask |= ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr; |
} |
|
return mask; |
} |
|
/* |
* Use the hostid as part of the random number seed. |
*/ |
int |
get_host_seed() |
{ |
return 33; |
/* return gethostid();*/ |
} |
|
/* |
* lock - create a lock file for the named lock device |
*/ |
#define LOCK_PREFIX "/var/spool/lock/LCK.." |
|
int |
lock(dev) |
char *dev; |
{ |
/* char hdb_lock_buffer[12]; |
int fd, pid, n; |
char *p; |
|
if ((p = strrchr(dev, '/')) != NULL) |
dev = p + 1; |
lock_file = malloc(strlen(LOCK_PREFIX) + strlen(dev) + 1); |
if (lock_file == NULL) |
novm("lock file name"); |
strcat(strcpy(lock_file, LOCK_PREFIX), dev); |
|
while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) { |
if (errno == EEXIST |
&& (fd = open(lock_file, O_RDONLY, 0)) >= 0) { |
|
n = read(fd, hdb_lock_buffer, 11); |
if (n <= 0) { |
syslog(LOG_ERR, "Can't read pid from lock file %s", lock_file); |
close(fd); |
} else { |
hdb_lock_buffer[n] = 0; |
pid = atoi(hdb_lock_buffer); |
if (kill(pid, 0) == -1 && errno == ESRCH) { |
|
if (unlink(lock_file) == 0) { |
close(fd); |
syslog(LOG_NOTICE, "Removed stale lock on %s (pid %d)", |
dev, pid); |
continue; |
} else |
syslog(LOG_WARNING, "Couldn't remove stale lock on %s", |
dev); |
} else |
syslog(LOG_NOTICE, "Device %s is locked by pid %d", |
dev, pid); |
} |
close(fd); |
} else |
syslog(LOG_ERR, "Can't create lock file %s: %m", lock_file); |
free(lock_file); |
lock_file = NULL; |
return -1; |
} |
|
sprintf(hdb_lock_buffer, "%10d\n", getpid()); |
write(fd, hdb_lock_buffer, 11); |
|
close(fd); |
*/ return 0; |
} |
|
/* |
* unlock - remove our lockfile |
*/ |
void |
unlock() |
{ |
/* if (lock_file) { |
unlink(lock_file); |
free(lock_file); |
lock_file = NULL; |
} |
*/} |
/Makefile.am
0,0 → 1,44
## |
## $Id: Makefile.am,v 1.2 2001-09-27 12:01:57 chris Exp $ |
## |
|
AUTOMAKE_OPTIONS = foreign 1.4 |
|
LIBNAME = lib.a |
LIB = $(ARCH)/$(LIBNAME) |
|
# What to do about main.c? |
C_FILES = auth.c cbcp.c ccp.c chap.c chap_ms.c chat.c demand.c fsm.c ipcp.c \ |
ipxcp.c lcp.c magic.c options.c upap.c md4.c md5.c rtems-ppp.c |
C_O_FILES = $(C_FILES:%.c=$(ARCH)/%.o) |
|
OBJS = $(C_O_FILES) |
|
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg |
include $(top_srcdir)/../../../automake/lib.am |
|
# |
# Add local stuff here using += |
# |
|
# DEFINES += -D_COMPILING_BSD_KERNEL_ -DKERNEL -DINET -DNFS -DDIAGNOSTIC \ |
# -DBOOTP_COMPAT |
|
$(LIB): $(OBJS) |
$(make-library) |
|
EXTRA_FILES = modem_example/16550.h modem_example/README \ |
modem_example/modem.c modem_example/modem.h modem_example/ppp.c \ |
modem_example/ppp.h modem_example/pppcompress.c |
|
all-local: $(ARCH) $(OBJS) $(LIB) |
|
.PRECIOUS: $(LIB) |
|
EXTRA_DIST = README STATUS auth.c cbcp.c cbcp.h ccp.c ccp.h chap.c chap.h \ |
chap_ms.c chap_ms.h chat.c demand.c fsm.c fsm.h ipcp.c ipcp.h ipxcp.c \ |
ipxcp.h lcp.c lcp.h magic.c magic.h main.c md4.c md4.h md5.c md5.h \ |
options.c patchlevel.h pathnames.h ppp_tty.c pppd.h rtems-ppp.c upap.c \ |
upap.h $(EXTRA_FILES) |
|
include $(top_srcdir)/../../../automake/local.am |
/fsm.h
0,0 → 1,144
/* |
* fsm.h - {Link, IP} Control Protocol Finite State Machine definitions. |
* |
* Copyright (c) 1989 Carnegie Mellon University. |
* All rights reserved. |
* |
* 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 Carnegie Mellon University. The name of the |
* University may not be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
* |
* $Id: fsm.h,v 1.2 2001-09-27 12:01:57 chris Exp $ |
*/ |
|
/* |
* Packet header = Code, id, length. |
*/ |
#define HEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short)) |
|
|
/* |
* CP (LCP, IPCP, etc.) codes. |
*/ |
#define CONFREQ 1 /* Configuration Request */ |
#define CONFACK 2 /* Configuration Ack */ |
#define CONFNAK 3 /* Configuration Nak */ |
#define CONFREJ 4 /* Configuration Reject */ |
#define TERMREQ 5 /* Termination Request */ |
#define TERMACK 6 /* Termination Ack */ |
#define CODEREJ 7 /* Code Reject */ |
|
|
/* |
* Each FSM is described by an fsm structure and fsm callbacks. |
*/ |
typedef struct fsm { |
int unit; /* Interface unit number */ |
int protocol; /* Data Link Layer Protocol field value */ |
int state; /* State */ |
int flags; /* Contains option bits */ |
u_char id; /* Current id */ |
u_char reqid; /* Current request id */ |
u_char seen_ack; /* Have received valid Ack/Nak/Rej to Req */ |
int timeouttime; /* Timeout time in milliseconds */ |
int maxconfreqtransmits; /* Maximum Configure-Request transmissions */ |
int retransmits; /* Number of retransmissions left */ |
int maxtermtransmits; /* Maximum Terminate-Request transmissions */ |
int nakloops; /* Number of nak loops since last ack */ |
int maxnakloops; /* Maximum number of nak loops tolerated */ |
struct fsm_callbacks *callbacks; /* Callback routines */ |
char *term_reason; /* Reason for closing protocol */ |
int term_reason_len; /* Length of term_reason */ |
} fsm; |
|
|
typedef struct fsm_callbacks { |
void (*resetci) /* Reset our Configuration Information */ |
__P((fsm *)); |
int (*cilen) /* Length of our Configuration Information */ |
__P((fsm *)); |
void (*addci) /* Add our Configuration Information */ |
__P((fsm *, u_char *, int *)); |
int (*ackci) /* ACK our Configuration Information */ |
__P((fsm *, u_char *, int)); |
int (*nakci) /* NAK our Configuration Information */ |
__P((fsm *, u_char *, int)); |
int (*rejci) /* Reject our Configuration Information */ |
__P((fsm *, u_char *, int)); |
int (*reqci) /* Request peer's Configuration Information */ |
__P((fsm *, u_char *, int *, int)); |
void (*up) /* Called when fsm reaches OPENED state */ |
__P((fsm *)); |
void (*down) /* Called when fsm leaves OPENED state */ |
__P((fsm *)); |
void (*starting) /* Called when we want the lower layer */ |
__P((fsm *)); |
void (*finished) /* Called when we don't want the lower layer */ |
__P((fsm *)); |
void (*protreject) /* Called when Protocol-Reject received */ |
__P((int)); |
void (*retransmit) /* Retransmission is necessary */ |
__P((fsm *)); |
int (*extcode) /* Called when unknown code received */ |
__P((fsm *, int, int, u_char *, int)); |
char *proto_name; /* String name for protocol (for messages) */ |
} fsm_callbacks; |
|
|
/* |
* Link states. |
*/ |
#define INITIAL 0 /* Down, hasn't been opened */ |
#define STARTING 1 /* Down, been opened */ |
#define CLOSED 2 /* Up, hasn't been opened */ |
#define STOPPED 3 /* Open, waiting for down event */ |
#define CLOSING 4 /* Terminating the connection, not open */ |
#define STOPPING 5 /* Terminating, but open */ |
#define REQSENT 6 /* We've sent a Config Request */ |
#define ACKRCVD 7 /* We've received a Config Ack */ |
#define ACKSENT 8 /* We've sent a Config Ack */ |
#define OPENED 9 /* Connection available */ |
|
|
/* |
* Flags - indicate options controlling FSM operation |
*/ |
#define OPT_PASSIVE 1 /* Don't die if we don't get a response */ |
#define OPT_RESTART 2 /* Treat 2nd OPEN as DOWN, UP */ |
#define OPT_SILENT 4 /* Wait for peer to speak first */ |
|
|
/* |
* Timeouts. |
*/ |
#define DEFTIMEOUT 3 /* Timeout time in seconds */ |
#define DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */ |
#define DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */ |
#define DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */ |
|
|
/* |
* Prototypes |
*/ |
void fsm_init __P((fsm *)); |
void fsm_lowerup __P((fsm *)); |
void fsm_lowerdown __P((fsm *)); |
void fsm_open __P((fsm *)); |
void fsm_close __P((fsm *, char *)); |
void fsm_input __P((fsm *, u_char *, int)); |
void fsm_protreject __P((fsm *)); |
void fsm_sdata __P((fsm *, int, int, u_char *, int)); |
|
|
/* |
* Variables |
*/ |
extern int peer_mru[]; /* currently negotiated peer MRU (per unit) */ |
/options.c
0,0 → 1,393
/* |
* options.c - handles option processing for PPP. |
* |
* Copyright (c) 1989 Carnegie Mellon University. |
* All rights reserved. |
* |
* 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 Carnegie Mellon University. The name of the |
* University 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. |
*/ |
|
#ifndef lint |
/* static char rcsid[] = "$Id: options.c,v 1.2 2001-09-27 12:01:57 chris Exp $"; */ |
#endif |
|
#include <ctype.h> |
#include <stdio.h> |
#include <errno.h> |
#include <unistd.h> |
#include <limits.h> |
/* #include <stdlib.h> */ |
#include <termios.h> |
#include <syslog.h> |
#include <string.h> |
#include <netdb.h> |
#include <pwd.h> |
#include <sys/types.h> |
#include <sys/stat.h> |
#include <netinet/in.h> |
#include <arpa/inet.h> |
#ifdef PPP_FILTER |
#include <pcap.h> |
#include <pcap-int.h> /* XXX: To get struct pcap */ |
#endif |
|
#include "pppd.h" |
#include "pathnames.h" |
#include "patchlevel.h" |
#include "fsm.h" |
#include "lcp.h" |
#include "ipcp.h" |
#include "upap.h" |
#include "chap.h" |
#include "ccp.h" |
#ifdef CBCP_SUPPORT |
#include "cbcp.h" |
#endif |
|
#ifdef IPX_CHANGE |
#include "ipxcp.h" |
#endif /* IPX_CHANGE */ |
|
#include <net/ppp-comp.h> |
|
#define FALSE 0 |
#define TRUE 1 |
|
|
#ifndef GIDSET_TYPE |
#define GIDSET_TYPE gid_t |
#endif |
#if 0 |
static int privileged_option; /* set iff the current option came from root */ |
static char *option_source; /* string saying where the option came from */ |
#endif |
|
/* |
* Option variables and default values. |
*/ |
#ifdef PPP_FILTER |
int dflag = 0; /* Tell libpcap we want debugging */ |
#endif |
int debug = 1; /* Debug flag */ |
int kdebugflag = 1; /* Tell kernel to print debug messages */ |
int default_device = 1; /* Using /dev/tty or equivalent */ |
char devnam[MAXPATHLEN] = "/dev/sccppp"; /* Device name */ |
int crtscts = 0; /* Use hardware flow control */ |
int modem = 0; /* Use modem control lines */ |
int inspeed = B115200; /* Input/Output speed requested */ |
u_int32_t netmask = 0; /* IP netmask to set on interface */ |
int lockflag = 0; /* Create lock file to lock the serial dev */ |
int nodetach = 0; /* Don't detach from controlling tty */ |
char *connector[]={"TIMEOUT","3","ABORT","\nBUSY\r","ABORT","\nNO DIALTONE\r","ABORT","\nNO CARRIER\r","ABORT","\nNO ANSWER\r","ABORT","\nRINGING\r\n\r\nRINGING\r", |
"","\rAT","OK-+++\\c-OK","ATH0","TIMEOUT","30","OK","ATDT13","CONNECT",""}; |
/*char *connector[]={"TIMEOUT","3","ABORT","\nBUSY\r","ABORT","\nNO DIALTONE\r","ABORT","\nNO CARRIER\r","ABORT","\nNO ANSWER\r","ABORT","\nRINGING\r\n\r\nRINGING\r", |
"","\rAT","OK-+++\\c-OK","ATH0","TIMEOUT","30","OK","ATDT0202122","CONNECT","","ppp","","Username:","ppp","Password:","ppp"}; |
*/ |
char **disconnector; /* Script to disestablish physical link */ |
char **welcomer; /* Script to run after phys link estab. */ |
int maxconnect = 0; /* Maximum connect time */ |
char user[MAXNAMELEN]="stb"; /* Username for PAP */ |
char passwd[MAXSECRETLEN]="stb"; /* Password for PAP */ |
int auth_required = 0; /* Peer is required to authenticate */ |
int defaultroute = 1; /* assign default route through interface */ |
int proxyarp = 0; /* Set up proxy ARP entry for peer */ |
int persist = 1; /* Reopen link after it goes down */ |
int uselogin = 0; /* Use /etc/passwd for checking PAP */ |
int lcp_echo_interval = 0; /* Interval between LCP echo-requests */ |
int lcp_echo_fails = 0; /* Tolerance to unanswered echo-requests */ |
char our_name[MAXNAMELEN]="infotel"; /* Our name for authentication purposes */ |
char remote_name[MAXNAMELEN]; /* Peer's name for authentication */ |
int explicit_remote = 0; /* User specified explicit remote name */ |
int usehostname = 0; /* Use hostname for our_name */ |
int disable_defaultip = 1; /* Don't use hostname for default IP adrs */ |
int demand = 0; /* do dial-on-demand */ |
char *ipparam = NULL; /* Extra parameter for ip up/down scripts */ |
int cryptpap; /* Passwords in pap-secrets are encrypted */ |
int idle_time_limit = 0; /* Disconnect if idle for this many seconds */ |
int holdoff = 30; /* # seconds to pause before reconnecting */ |
int refuse_pap = 0; /* Set to say we won't do PAP */ |
int refuse_chap = 1; /* Set to say we won't do CHAP */ |
|
#ifdef MSLANMAN |
int ms_lanman = 0; /* Nonzero if use LanMan password instead of NT */ |
/* Has meaning only with MS-CHAP challenges */ |
#endif |
|
struct option_info auth_req_info; |
struct option_info connector_info; |
struct option_info disconnector_info; |
struct option_info welcomer_info; |
struct option_info devnam_info; |
#ifdef PPP_FILTER |
struct bpf_program pass_filter;/* Filter program for packets to pass */ |
struct bpf_program active_filter; /* Filter program for link-active pkts */ |
pcap_t pc; /* Fake struct pcap so we can compile expr */ |
#endif |
|
/* |
* Prototypes |
*/ |
#if 0 |
static int setdevname __P((char *, int)); |
static int setipaddr __P((char *)); |
static int setspeed __P((char *)); |
static int setdebug __P((char **)); |
static int setkdebug __P((char **)); |
static int setpassive __P((char **)); |
static int setsilent __P((char **)); |
static int noopt __P((char **)); |
static int setnovj __P((char **)); |
static int setnovjccomp __P((char **)); |
static int setvjslots __P((char **)); |
static int reqpap __P((char **)); |
static int nopap __P((char **)); |
#ifdef OLD_OPTIONS |
static int setupapfile __P((char **)); |
#endif |
static int nochap __P((char **)); |
static int reqchap __P((char **)); |
static int noaccomp __P((char **)); |
static int noasyncmap __P((char **)); |
static int noip __P((char **)); |
static int nomagicnumber __P((char **)); |
static int setasyncmap __P((char **)); |
static int setescape __P((char **)); |
static int setmru __P((char **)); |
static int setmtu __P((char **)); |
#ifdef CBCP_SUPPORT |
static int setcbcp __P((char **)); |
#endif |
static int nomru __P((char **)); |
static int nopcomp __P((char **)); |
static int setconnector __P((char **)); |
static int setdisconnector __P((char **)); |
static int setwelcomer __P((char **)); |
static int setmaxconnect __P((char **)); |
static int setdomain __P((char **)); |
static int setnetmask __P((char **)); |
static int setcrtscts __P((char **)); |
static int setnocrtscts __P((char **)); |
static int setxonxoff __P((char **)); |
static int setnodetach __P((char **)); |
static int setupdetach __P((char **)); |
static int setmodem __P((char **)); |
static int setlocal __P((char **)); |
static int setlock __P((char **)); |
static int setname __P((char **)); |
static int setuser __P((char **)); |
static int setremote __P((char **)); |
static int setauth __P((char **)); |
static int setnoauth __P((char **)); |
static int readfile __P((char **)); |
static int callfile __P((char **)); |
static int setdefaultroute __P((char **)); |
static int setnodefaultroute __P((char **)); |
static int setproxyarp __P((char **)); |
static int setnoproxyarp __P((char **)); |
static int setpersist __P((char **)); |
static int setnopersist __P((char **)); |
static int setdologin __P((char **)); |
static int setusehostname __P((char **)); |
static int setnoipdflt __P((char **)); |
static int setlcptimeout __P((char **)); |
static int setlcpterm __P((char **)); |
static int setlcpconf __P((char **)); |
static int setlcpfails __P((char **)); |
static int setipcptimeout __P((char **)); |
static int setipcpterm __P((char **)); |
static int setipcpconf __P((char **)); |
static int setipcpfails __P((char **)); |
static int setpaptimeout __P((char **)); |
static int setpapreqs __P((char **)); |
static int setpapreqtime __P((char **)); |
static int setchaptimeout __P((char **)); |
static int setchapchal __P((char **)); |
static int setchapintv __P((char **)); |
static int setipcpaccl __P((char **)); |
static int setipcpaccr __P((char **)); |
static int setlcpechointv __P((char **)); |
static int setlcpechofails __P((char **)); |
static int noccp __P((char **)); |
static int setbsdcomp __P((char **)); |
static int setnobsdcomp __P((char **)); |
static int setdeflate __P((char **)); |
static int setnodeflate __P((char **)); |
static int setnodeflatedraft __P((char **)); |
static int setdemand __P((char **)); |
static int setpred1comp __P((char **)); |
static int setnopred1comp __P((char **)); |
static int setipparam __P((char **)); |
static int setpapcrypt __P((char **)); |
static int setidle __P((char **)); |
static int setholdoff __P((char **)); |
static int setdnsaddr __P((char **)); |
static int resetipxproto __P((char **)); |
static int setwinsaddr __P((char **)); |
static int showversion __P((char **)); |
static int showhelp __P((char **)); |
|
#ifdef PPP_FILTER |
static int setpdebug __P((char **)); |
static int setpassfilter __P((char **)); |
static int setactivefilter __P((char **)); |
#endif |
|
#ifdef IPX_CHANGE |
static int setipxproto __P((char **)); |
static int setipxanet __P((char **)); |
static int setipxalcl __P((char **)); |
static int setipxarmt __P((char **)); |
static int setipxnetwork __P((char **)); |
static int setipxnode __P((char **)); |
static int setipxrouter __P((char **)); |
static int setipxname __P((char **)); |
static int setipxcptimeout __P((char **)); |
static int setipxcpterm __P((char **)); |
static int setipxcpconf __P((char **)); |
static int setipxcpfails __P((char **)); |
#endif /* IPX_CHANGE */ |
|
#ifdef MSLANMAN |
static int setmslanman __P((char **)); |
#endif |
|
static int number_option __P((char *, u_int32_t *, int)); |
static int int_option __P((char *, int *)); |
static int readable __P((int fd)); |
#endif |
|
/* |
* Valid arguments. |
*/ |
|
/* |
* parse_args - parse a string of arguments from the command line. |
*/ |
int |
parse_args(argc, argv) |
int argc; |
char **argv; |
{ |
|
|
return 0; |
} |
|
/* |
* scan_args - scan the command line arguments to get the tty name, |
* if specified. |
*/ |
|
/* |
* usage - print out a message telling how to use the program. |
*/ |
void |
usage() |
{ |
} |
|
/* |
* showhelp - print out usage message and exit. |
*/ |
static int |
showhelp(argv) |
char **argv; |
{ |
return 0; |
} |
|
/* |
* showversion - print out the version number and exit. |
*/ |
static int |
showversion(argv) |
char **argv; |
{ |
return 0; |
} |
|
void |
option_error __V((char *fmt, ...)) |
{ |
} |
/* |
* readable - check if a file is readable by the real user. |
*/ |
/*static int |
readable(fd) |
int fd; |
{ |
uid_t uid; |
int ngroups, i; |
struct stat sbuf; |
GIDSET_TYPE groups[NGROUPS_MAX]; |
|
uid = getuid(); |
if (uid == 0) |
return 1; |
if (fstat(fd, &sbuf) != 0) |
return 0; |
if (sbuf.st_uid == uid) |
return sbuf.st_mode & S_IRUSR; |
if (sbuf.st_gid == getgid()) |
return sbuf.st_mode & S_IRGRP; |
ngroups = getgroups(NGROUPS_MAX, groups); |
for (i = 0; i < ngroups; ++i) |
if (sbuf.st_gid == groups[i]) |
return sbuf.st_mode & S_IRGRP; |
return sbuf.st_mode & S_IROTH; |
} |
*/ |
/* |
* Read a word from a file. |
* Words are delimited by white-space or by quotes (" or '). |
* Quotes, white-space and \ may be escaped with \. |
* \<newline> is ignored. |
*/ |
|
/* |
* The following procedures parse options. |
*/ |
|
/* |
* readfile - take commands from a file. |
*/ |
|
/* |
* callfile - take commands from /etc/ppp/peers/<name>. |
* Name may not contain /../, start with / or ../, or end in /.. |
*/ |
/* |
* setdebug - Set debug (command line argument). |
*/ |
|
|
/* |
* noopt - Disable all options. |
*/ |
static int |
noopt(argv) |
char **argv; |
{ |
BZERO((char *) &lcp_wantoptions[0], sizeof (struct lcp_options)); |
BZERO((char *) &lcp_allowoptions[0], sizeof (struct lcp_options)); |
BZERO((char *) &ipcp_wantoptions[0], sizeof (struct ipcp_options)); |
BZERO((char *) &ipcp_allowoptions[0], sizeof (struct ipcp_options)); |
|
#ifdef IPX_CHANGE |
BZERO((char *) &ipxcp_wantoptions[0], sizeof (struct ipxcp_options)); |
BZERO((char *) &ipxcp_allowoptions[0], sizeof (struct ipxcp_options)); |
#endif /* IPX_CHANGE */ |
|
return (1); |
} |
/ipcp.c
0,0 → 1,1506
/* |
* ipcp.c - PPP IP Control Protocol. |
* |
* Copyright (c) 1989 Carnegie Mellon University. |
* All rights reserved. |
* |
* 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 Carnegie Mellon University. The name of the |
* University 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. |
*/ |
|
#ifndef lint |
/* static char rcsid[] = "$Id: ipcp.c,v 1.2 2001-09-27 12:01:57 chris Exp $"; */ |
#endif |
|
/* |
* TODO: |
*/ |
|
#include <stdio.h> |
#include <string.h> |
#include <syslog.h> |
#include <netdb.h> |
#include <sys/param.h> |
#include <sys/types.h> |
#include <sys/socket.h> |
#include <netinet/in.h> |
/* #include <stbconfig.h> */ |
|
#include "pppd.h" |
#include "fsm.h" |
#include "ipcp.h" |
#include "pathnames.h" |
|
/* global vars */ |
ipcp_options ipcp_wantoptions[NUM_PPP]; /* Options that we want to request */ |
ipcp_options ipcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */ |
ipcp_options ipcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */ |
ipcp_options ipcp_hisoptions[NUM_PPP]; /* Options that we ack'd */ |
|
/* local vars */ |
static int cis_received[NUM_PPP]; /* # Conf-Reqs received */ |
static int default_route_set[NUM_PPP]; /* Have set up a default route */ |
static int proxy_arp_set[NUM_PPP]; /* Have created proxy arp entry */ |
|
/* |
* Callbacks for fsm code. (CI = Configuration Information) |
*/ |
static void ipcp_resetci __P((fsm *)); /* Reset our CI */ |
static int ipcp_cilen __P((fsm *)); /* Return length of our CI */ |
static void ipcp_addci __P((fsm *, u_char *, int *)); /* Add our CI */ |
static int ipcp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */ |
static int ipcp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */ |
static int ipcp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */ |
static int ipcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */ |
static void ipcp_up __P((fsm *)); /* We're UP */ |
static void ipcp_down __P((fsm *)); /* We're DOWN */ |
#if 0 |
static void ipcp_script __P((fsm *, char *)); /* Run an up/down script */ |
#endif |
static void ipcp_finished __P((fsm *)); /* Don't need lower layer */ |
|
fsm ipcp_fsm[NUM_PPP]; /* IPCP fsm structure */ |
|
static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */ |
ipcp_resetci, /* Reset our Configuration Information */ |
ipcp_cilen, /* Length of our Configuration Information */ |
ipcp_addci, /* Add our Configuration Information */ |
ipcp_ackci, /* ACK our Configuration Information */ |
ipcp_nakci, /* NAK our Configuration Information */ |
ipcp_rejci, /* Reject our Configuration Information */ |
ipcp_reqci, /* Request peer's Configuration Information */ |
ipcp_up, /* Called when fsm reaches OPENED state */ |
ipcp_down, /* Called when fsm leaves OPENED state */ |
NULL, /* Called when we want the lower layer up */ |
ipcp_finished, /* Called when we want the lower layer down */ |
NULL, /* Called when Protocol-Reject received */ |
NULL, /* Retransmission is necessary */ |
NULL, /* Called to handle protocol-specific codes */ |
"IPCP" /* String name of protocol */ |
}; |
|
/* |
* Protocol entry points from main code. |
*/ |
static void ipcp_init __P((int)); |
static void ipcp_open __P((int)); |
static void ipcp_close __P((int, char *)); |
static void ipcp_lowerup __P((int)); |
static void ipcp_lowerdown __P((int)); |
static void ipcp_input __P((int, u_char *, int)); |
static void ipcp_protrej __P((int)); |
static int ipcp_printpkt __P((u_char *, int, |
void (*) __P((void *, char *, ...)), void *)); |
static void ip_check_options __P((void)); |
static int ip_demand_conf __P((int)); |
static int ip_active_pkt __P((u_char *, int)); |
|
struct protent ipcp_protent = { |
PPP_IPCP, |
ipcp_init, |
ipcp_input, |
ipcp_protrej, |
ipcp_lowerup, |
ipcp_lowerdown, |
ipcp_open, |
ipcp_close, |
ipcp_printpkt, |
NULL, |
1, |
"IPCP", |
ip_check_options, |
ip_demand_conf, |
ip_active_pkt |
}; |
|
static void ipcp_clear_addrs __P((int)); |
|
/* |
* Lengths of configuration options. |
*/ |
#define CILEN_VOID 2 |
#define CILEN_COMPRESS 4 /* min length for compression protocol opt. */ |
#define CILEN_VJ 6 /* length for RFC1332 Van-Jacobson opt. */ |
#define CILEN_ADDR 6 /* new-style single address option */ |
#define CILEN_ADDRS 10 /* old-style dual address option */ |
|
|
#define CODENAME(x) ((x) == CONFACK ? "ACK" : \ |
(x) == CONFNAK ? "NAK" : "REJ") |
|
|
/* |
* Make a string representation of a network IP address. |
*/ |
char * |
ip_ntoa(ipaddr) |
u_int32_t ipaddr; |
{ |
static char b[64]; |
|
ipaddr = ntohl(ipaddr); |
|
sprintf(b, "%d.%d.%d.%d", |
(u_char)(ipaddr >> 24), |
(u_char)(ipaddr >> 16), |
(u_char)(ipaddr >> 8), |
(u_char)(ipaddr)); |
return b; |
} |
|
|
/* |
* ipcp_init - Initialize IPCP. |
*/ |
static void |
ipcp_init(unit) |
int unit; |
{ |
fsm *f = &ipcp_fsm[unit]; |
ipcp_options *wo = &ipcp_wantoptions[unit]; |
ipcp_options *ao = &ipcp_allowoptions[unit]; |
|
f->unit = unit; |
f->protocol = PPP_IPCP; |
f->callbacks = &ipcp_callbacks; |
fsm_init(&ipcp_fsm[unit]); |
|
memset(wo, 0, sizeof(*wo)); |
memset(ao, 0, sizeof(*ao)); |
|
wo->neg_addr = 1; |
wo->neg_vj = 1; |
wo->vj_protocol = IPCP_VJ_COMP; |
wo->maxslotindex = MAX_STATES - 1; /* really max index */ |
wo->cflag = 1; |
ipcp_wantoptions[0].default_route = 1; |
/* max slots and slot-id compression are currently hardwired in */ |
/* ppp_if.c to 16 and 1, this needs to be changed (among other */ |
/* things) gmc */ |
|
ao->neg_addr = 1; |
ao->neg_vj = 1; |
ao->maxslotindex = MAX_STATES - 1; |
ao->cflag = 1; |
|
/* |
* XXX These control whether the user may use the proxyarp |
* and defaultroute options. |
*/ |
ao->proxy_arp = 1; |
ao->default_route = 1; |
} |
|
|
/* |
* ipcp_open - IPCP is allowed to come up. |
*/ |
static void |
ipcp_open(unit) |
int unit; |
{ |
fsm_open(&ipcp_fsm[unit]); |
} |
|
|
/* |
* ipcp_close - Take IPCP down. |
*/ |
static void |
ipcp_close(unit, reason) |
int unit; |
char *reason; |
{ |
fsm_close(&ipcp_fsm[unit], reason); |
} |
|
|
/* |
* ipcp_lowerup - The lower layer is up. |
*/ |
static void |
ipcp_lowerup(unit) |
int unit; |
{ |
fsm_lowerup(&ipcp_fsm[unit]); |
} |
|
|
/* |
* ipcp_lowerdown - The lower layer is down. |
*/ |
static void |
ipcp_lowerdown(unit) |
int unit; |
{ |
fsm_lowerdown(&ipcp_fsm[unit]); |
} |
|
|
/* |
* ipcp_input - Input IPCP packet. |
*/ |
static void |
ipcp_input(unit, p, len) |
int unit; |
u_char *p; |
int len; |
{ |
fsm_input(&ipcp_fsm[unit], p, len); |
} |
|
|
/* |
* ipcp_protrej - A Protocol-Reject was received for IPCP. |
* |
* Pretend the lower layer went down, so we shut up. |
*/ |
static void |
ipcp_protrej(unit) |
int unit; |
{ |
fsm_lowerdown(&ipcp_fsm[unit]); |
} |
|
|
/* |
* ipcp_resetci - Reset our CI. |
*/ |
static void |
ipcp_resetci(f) |
fsm *f; |
{ |
ipcp_options *wo = &ipcp_wantoptions[f->unit]; |
|
wo->req_addr = wo->neg_addr && ipcp_allowoptions[f->unit].neg_addr; |
if (wo->ouraddr == 0) |
wo->accept_local = 1; |
if (wo->hisaddr == 0) |
wo->accept_remote = 1; |
ipcp_gotoptions[f->unit] = *wo; |
cis_received[f->unit] = 0; |
} |
|
|
/* |
* ipcp_cilen - Return length of our CI. |
*/ |
static int |
ipcp_cilen(f) |
fsm *f; |
{ |
ipcp_options *go = &ipcp_gotoptions[f->unit]; |
ipcp_options *wo = &ipcp_wantoptions[f->unit]; |
ipcp_options *ho = &ipcp_hisoptions[f->unit]; |
|
#define LENCIVJ(neg, old) (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0) |
#define LENCIADDR(neg, old) (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0) |
|
/* |
* First see if we want to change our options to the old |
* forms because we have received old forms from the peer. |
*/ |
if (wo->neg_addr && !go->neg_addr && !go->old_addrs) { |
/* use the old style of address negotiation */ |
go->neg_addr = 1; |
go->old_addrs = 1; |
} |
if (wo->neg_vj && !go->neg_vj && !go->old_vj) { |
/* try an older style of VJ negotiation */ |
if (cis_received[f->unit] == 0) { |
/* keep trying the new style until we see some CI from the peer */ |
go->neg_vj = 1; |
} else { |
/* use the old style only if the peer did */ |
if (ho->neg_vj && ho->old_vj) { |
go->neg_vj = 1; |
go->old_vj = 1; |
go->vj_protocol = ho->vj_protocol; |
} |
} |
} |
|
return (LENCIADDR(go->neg_addr, go->old_addrs) + |
LENCIVJ(go->neg_vj, go->old_vj)); |
} |
|
|
/* |
* ipcp_addci - Add our desired CIs to a packet. |
*/ |
static void |
ipcp_addci(f, ucp, lenp) |
fsm *f; |
u_char *ucp; |
int *lenp; |
{ |
ipcp_options *go = &ipcp_gotoptions[f->unit]; |
int len = *lenp; |
|
#define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \ |
if (neg) { \ |
int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \ |
if (len >= vjlen) { \ |
PUTCHAR(opt, ucp); \ |
PUTCHAR(vjlen, ucp); \ |
PUTSHORT(val, ucp); \ |
if (!old) { \ |
PUTCHAR(maxslotindex, ucp); \ |
PUTCHAR(cflag, ucp); \ |
} \ |
len -= vjlen; \ |
} else \ |
neg = 0; \ |
} |
|
#define ADDCIADDR(opt, neg, old, val1, val2) \ |
if (neg) { \ |
int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \ |
if (len >= addrlen) { \ |
u_int32_t l; \ |
PUTCHAR(opt, ucp); \ |
PUTCHAR(addrlen, ucp); \ |
l = ntohl(val1); \ |
PUTLONG(l, ucp); \ |
if (old) { \ |
l = ntohl(val2); \ |
PUTLONG(l, ucp); \ |
} \ |
len -= addrlen; \ |
} else \ |
neg = 0; \ |
} |
|
ADDCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr, |
go->old_addrs, go->ouraddr, go->hisaddr); |
|
ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj, |
go->maxslotindex, go->cflag); |
|
*lenp -= len; |
} |
|
|
/* |
* ipcp_ackci - Ack our CIs. |
* |
* Returns: |
* 0 - Ack was bad. |
* 1 - Ack was good. |
*/ |
static int |
ipcp_ackci(f, p, len) |
fsm *f; |
u_char *p; |
int len; |
{ |
ipcp_options *go = &ipcp_gotoptions[f->unit]; |
u_short cilen, citype, cishort; |
u_int32_t cilong; |
u_char cimaxslotindex, cicflag; |
|
/* |
* CIs must be in exactly the same order that we sent... |
* Check packet length and CI length at each step. |
* If we find any deviations, then this packet is bad. |
*/ |
|
#define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \ |
if (neg) { \ |
int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \ |
if ((len -= vjlen) < 0) \ |
goto bad; \ |
GETCHAR(citype, p); \ |
GETCHAR(cilen, p); \ |
if (cilen != vjlen || \ |
citype != opt) \ |
goto bad; \ |
GETSHORT(cishort, p); \ |
if (cishort != val) \ |
goto bad; \ |
if (!old) { \ |
GETCHAR(cimaxslotindex, p); \ |
if (cimaxslotindex != maxslotindex) \ |
goto bad; \ |
GETCHAR(cicflag, p); \ |
if (cicflag != cflag) \ |
goto bad; \ |
} \ |
} |
|
#define ACKCIADDR(opt, neg, old, val1, val2) \ |
if (neg) { \ |
int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \ |
u_int32_t l; \ |
if ((len -= addrlen) < 0) \ |
goto bad; \ |
GETCHAR(citype, p); \ |
GETCHAR(cilen, p); \ |
if (cilen != addrlen || \ |
citype != opt) \ |
goto bad; \ |
GETLONG(l, p); \ |
cilong = htonl(l); \ |
if (val1 != cilong) \ |
goto bad; \ |
if (old) { \ |
GETLONG(l, p); \ |
cilong = htonl(l); \ |
if (val2 != cilong) \ |
goto bad; \ |
} \ |
} |
|
ACKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr, |
go->old_addrs, go->ouraddr, go->hisaddr); |
|
ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj, |
go->maxslotindex, go->cflag); |
|
/* |
* If there are any remaining CIs, then this packet is bad. |
*/ |
if (len != 0) |
goto bad; |
return (1); |
|
bad: |
IPCPDEBUG((LOG_INFO, "ipcp_ackci: received bad Ack!")); |
return (0); |
} |
|
/* |
* ipcp_nakci - Peer has sent a NAK for some of our CIs. |
* This should not modify any state if the Nak is bad |
* or if IPCP is in the OPENED state. |
* |
* Returns: |
* 0 - Nak was bad. |
* 1 - Nak was good. |
*/ |
static int |
ipcp_nakci(f, p, len) |
fsm *f; |
u_char *p; |
int len; |
{ |
ipcp_options *go = &ipcp_gotoptions[f->unit]; |
u_char cimaxslotindex, cicflag; |
u_char citype, cilen, *next; |
u_short cishort; |
u_int32_t ciaddr1, ciaddr2, l; |
ipcp_options no; /* options we've seen Naks for */ |
ipcp_options try; /* options to request next time */ |
|
BZERO(&no, sizeof(no)); |
try = *go; |
|
/* |
* Any Nak'd CIs must be in exactly the same order that we sent. |
* Check packet length and CI length at each step. |
* If we find any deviations, then this packet is bad. |
*/ |
#define NAKCIADDR(opt, neg, old, code) \ |
if (go->neg && \ |
len >= (cilen = (old? CILEN_ADDRS: CILEN_ADDR)) && \ |
p[1] == cilen && \ |
p[0] == opt) { \ |
len -= cilen; \ |
INCPTR(2, p); \ |
GETLONG(l, p); \ |
ciaddr1 = htonl(l); \ |
if (old) { \ |
GETLONG(l, p); \ |
ciaddr2 = htonl(l); \ |
no.old_addrs = 1; \ |
} else \ |
ciaddr2 = 0; \ |
no.neg = 1; \ |
code \ |
} |
|
#define NAKCIVJ(opt, neg, code) \ |
if (go->neg && \ |
((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \ |
len >= cilen && \ |
p[0] == opt) { \ |
len -= cilen; \ |
INCPTR(2, p); \ |
GETSHORT(cishort, p); \ |
no.neg = 1; \ |
code \ |
} |
|
/* |
* Accept the peer's idea of {our,his} address, if different |
* from our idea, only if the accept_{local,remote} flag is set. |
*/ |
NAKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go->old_addrs, |
if (go->accept_local && ciaddr1) { /* Do we know our address? */ |
try.ouraddr = ciaddr1; |
IPCPDEBUG((LOG_INFO, "local IP address %s", |
ip_ntoa(ciaddr1))); |
} |
if (go->accept_remote && ciaddr2) { /* Does he know his? */ |
try.hisaddr = ciaddr2; |
IPCPDEBUG((LOG_INFO, "remote IP address %s", |
ip_ntoa(ciaddr2))); |
} |
); |
|
/* |
* Accept the peer's value of maxslotindex provided that it |
* is less than what we asked for. Turn off slot-ID compression |
* if the peer wants. Send old-style compress-type option if |
* the peer wants. |
*/ |
NAKCIVJ(CI_COMPRESSTYPE, neg_vj, |
if (cilen == CILEN_VJ) { |
GETCHAR(cimaxslotindex, p); |
GETCHAR(cicflag, p); |
if (cishort == IPCP_VJ_COMP) { |
try.old_vj = 0; |
if (cimaxslotindex < go->maxslotindex) |
try.maxslotindex = cimaxslotindex; |
if (!cicflag) |
try.cflag = 0; |
} else { |
try.neg_vj = 0; |
} |
} else { |
if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) { |
try.old_vj = 1; |
try.vj_protocol = cishort; |
} else { |
try.neg_vj = 0; |
} |
} |
); |
|
/* |
* There may be remaining CIs, if the peer is requesting negotiation |
* on an option that we didn't include in our request packet. |
* If they want to negotiate about IP addresses, we comply. |
* If they want us to ask for compression, we refuse. |
*/ |
while (len > CILEN_VOID) { |
GETCHAR(citype, p); |
GETCHAR(cilen, p); |
if( (len -= cilen) < 0 ) |
goto bad; |
next = p + cilen - 2; |
|
switch (citype) { |
case CI_COMPRESSTYPE: |
if (go->neg_vj || no.neg_vj || |
(cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) |
goto bad; |
no.neg_vj = 1; |
break; |
case CI_ADDRS: |
if ((go->neg_addr && go->old_addrs) || no.old_addrs |
|| cilen != CILEN_ADDRS) |
goto bad; |
try.neg_addr = 1; |
try.old_addrs = 1; |
GETLONG(l, p); |
ciaddr1 = htonl(l); |
if (ciaddr1 && go->accept_local) |
try.ouraddr = ciaddr1; |
GETLONG(l, p); |
ciaddr2 = htonl(l); |
if (ciaddr2 && go->accept_remote) |
try.hisaddr = ciaddr2; |
no.old_addrs = 1; |
break; |
case CI_ADDR: |
if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR) |
goto bad; |
try.old_addrs = 0; |
GETLONG(l, p); |
ciaddr1 = htonl(l); |
if (ciaddr1 && go->accept_local) |
try.ouraddr = ciaddr1; |
if (try.ouraddr != 0) |
try.neg_addr = 1; |
no.neg_addr = 1; |
break; |
} |
p = next; |
} |
|
/* If there is still anything left, this packet is bad. */ |
if (len != 0) |
goto bad; |
|
/* |
* OK, the Nak is good. Now we can update state. |
*/ |
if (f->state != OPENED) |
*go = try; |
|
return 1; |
|
bad: |
IPCPDEBUG((LOG_INFO, "ipcp_nakci: received bad Nak!")); |
return 0; |
} |
|
|
/* |
* ipcp_rejci - Reject some of our CIs. |
*/ |
static int |
ipcp_rejci(f, p, len) |
fsm *f; |
u_char *p; |
int len; |
{ |
ipcp_options *go = &ipcp_gotoptions[f->unit]; |
u_char cimaxslotindex, ciflag, cilen; |
u_short cishort; |
u_int32_t cilong; |
ipcp_options try; /* options to request next time */ |
|
try = *go; |
/* |
* Any Rejected CIs must be in exactly the same order that we sent. |
* Check packet length and CI length at each step. |
* If we find any deviations, then this packet is bad. |
*/ |
#define REJCIADDR(opt, neg, old, val1, val2) \ |
if (go->neg && \ |
len >= (cilen = old? CILEN_ADDRS: CILEN_ADDR) && \ |
p[1] == cilen && \ |
p[0] == opt) { \ |
u_int32_t l; \ |
len -= cilen; \ |
INCPTR(2, p); \ |
GETLONG(l, p); \ |
cilong = htonl(l); \ |
/* Check rejected value. */ \ |
if (cilong != val1) \ |
goto bad; \ |
if (old) { \ |
GETLONG(l, p); \ |
cilong = htonl(l); \ |
/* Check rejected value. */ \ |
if (cilong != val2) \ |
goto bad; \ |
} \ |
try.neg = 0; \ |
} |
|
#define REJCIVJ(opt, neg, val, old, maxslot, cflag) \ |
if (go->neg && \ |
p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \ |
len >= p[1] && \ |
p[0] == opt) { \ |
len -= p[1]; \ |
INCPTR(2, p); \ |
GETSHORT(cishort, p); \ |
/* Check rejected value. */ \ |
if (cishort != val) \ |
goto bad; \ |
if (!old) { \ |
GETCHAR(cimaxslotindex, p); \ |
if (cimaxslotindex != maxslot) \ |
goto bad; \ |
GETCHAR(ciflag, p); \ |
if (ciflag != cflag) \ |
goto bad; \ |
} \ |
try.neg = 0; \ |
} |
|
REJCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, |
go->old_addrs, go->ouraddr, go->hisaddr); |
|
REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj, |
go->maxslotindex, go->cflag); |
|
/* |
* If there are any remaining CIs, then this packet is bad. |
*/ |
if (len != 0) |
goto bad; |
/* |
* Now we can update state. |
*/ |
if (f->state != OPENED) |
*go = try; |
return 1; |
|
bad: |
IPCPDEBUG((LOG_INFO, "ipcp_rejci: received bad Reject!")); |
return 0; |
} |
|
|
/* |
* ipcp_reqci - Check the peer's requested CIs and send appropriate response. |
* |
* Returns: CONFACK, CONFNAK or CONFREJ and input packet modified |
* appropriately. If reject_if_disagree is non-zero, doesn't return |
* CONFNAK; returns CONFREJ if it can't return CONFACK. |
*/ |
static int |
ipcp_reqci(f, inp, len, reject_if_disagree) |
fsm *f; |
u_char *inp; /* Requested CIs */ |
int *len; /* Length of requested CIs */ |
int reject_if_disagree; |
{ |
ipcp_options *wo = &ipcp_wantoptions[f->unit]; |
ipcp_options *ho = &ipcp_hisoptions[f->unit]; |
ipcp_options *ao = &ipcp_allowoptions[f->unit]; |
ipcp_options *go = &ipcp_gotoptions[f->unit]; |
u_char *cip, *next; /* Pointer to current and next CIs */ |
u_short cilen, citype; /* Parsed len, type */ |
u_short cishort; /* Parsed short value */ |
u_int32_t tl, ciaddr1, ciaddr2;/* Parsed address values */ |
int rc = CONFACK; /* Final packet return code */ |
int orc; /* Individual option return code */ |
u_char *p; /* Pointer to next char to parse */ |
u_char *ucp = inp; /* Pointer to current output char */ |
int l = *len; /* Length left */ |
u_char maxslotindex, cflag; |
int d; |
|
cis_received[f->unit] = 1; |
|
/* |
* Reset all his options. |
*/ |
BZERO(ho, sizeof(*ho)); |
|
/* |
* Process all his options. |
*/ |
next = inp; |
while (l) { |
orc = CONFACK; /* Assume success */ |
cip = p = next; /* Remember begining of CI */ |
if (l < 2 || /* Not enough data for CI header or */ |
p[1] < 2 || /* CI length too small or */ |
p[1] > l) { /* CI length too big? */ |
IPCPDEBUG((LOG_INFO, "ipcp_reqci: bad CI length!")); |
orc = CONFREJ; /* Reject bad CI */ |
cilen = l; /* Reject till end of packet */ |
l = 0; /* Don't loop again */ |
goto endswitch; |
} |
GETCHAR(citype, p); /* Parse CI type */ |
GETCHAR(cilen, p); /* Parse CI length */ |
l -= cilen; /* Adjust remaining length */ |
next += cilen; /* Step to next CI */ |
|
switch (citype) { /* Check CI type */ |
case CI_ADDRS: |
IPCPDEBUG((LOG_INFO, "ipcp: received ADDRS ")); |
if (!ao->neg_addr || |
cilen != CILEN_ADDRS) { /* Check CI length */ |
orc = CONFREJ; /* Reject CI */ |
break; |
} |
|
/* |
* If he has no address, or if we both have his address but |
* disagree about it, then NAK it with our idea. |
* In particular, if we don't know his address, but he does, |
* then accept it. |
*/ |
GETLONG(tl, p); /* Parse source address (his) */ |
ciaddr1 = htonl(tl); |
IPCPDEBUG((LOG_INFO, "(%s:", ip_ntoa(ciaddr1))); |
if (ciaddr1 != wo->hisaddr |
&& (ciaddr1 == 0 || !wo->accept_remote)) { |
orc = CONFNAK; |
if (!reject_if_disagree) { |
DECPTR(sizeof(u_int32_t), p); |
tl = ntohl(wo->hisaddr); |
PUTLONG(tl, p); |
} |
} else if (ciaddr1 == 0 && wo->hisaddr == 0) { |
/* |
* If neither we nor he knows his address, reject the option. |
*/ |
orc = CONFREJ; |
wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */ |
break; |
} |
|
/* |
* If he doesn't know our address, or if we both have our address |
* but disagree about it, then NAK it with our idea. |
*/ |
GETLONG(tl, p); /* Parse desination address (ours) */ |
ciaddr2 = htonl(tl); |
IPCPDEBUG((LOG_INFO, "%s)", ip_ntoa(ciaddr2))); |
if (ciaddr2 != wo->ouraddr) { |
if (ciaddr2 == 0 || !wo->accept_local) { |
orc = CONFNAK; |
if (!reject_if_disagree) { |
DECPTR(sizeof(u_int32_t), p); |
tl = ntohl(wo->ouraddr); |
PUTLONG(tl, p); |
} |
} else { |
go->ouraddr = ciaddr2; /* accept peer's idea */ |
} |
} |
|
ho->neg_addr = 1; |
ho->old_addrs = 1; |
ho->hisaddr = ciaddr1; |
ho->ouraddr = ciaddr2; |
break; |
|
case CI_ADDR: |
IPCPDEBUG((LOG_INFO, "ipcp: received ADDR ")); |
|
if (!ao->neg_addr || |
cilen != CILEN_ADDR) { /* Check CI length */ |
orc = CONFREJ; /* Reject CI */ |
break; |
} |
|
/* |
* If he has no address, or if we both have his address but |
* disagree about it, then NAK it with our idea. |
* In particular, if we don't know his address, but he does, |
* then accept it. |
*/ |
GETLONG(tl, p); /* Parse source address (his) */ |
ciaddr1 = htonl(tl); |
IPCPDEBUG((LOG_INFO, "(%s)", ip_ntoa(ciaddr1))); |
if (ciaddr1 != wo->hisaddr |
&& (ciaddr1 == 0 || !wo->accept_remote)) { |
orc = CONFNAK; |
if (!reject_if_disagree) { |
DECPTR(sizeof(u_int32_t), p); |
tl = ntohl(wo->hisaddr); |
PUTLONG(tl, p); |
} |
} else if (ciaddr1 == 0 && wo->hisaddr == 0) { |
/* |
* Don't ACK an address of 0.0.0.0 - reject it instead. |
*/ |
orc = CONFREJ; |
wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */ |
break; |
} |
|
ho->neg_addr = 1; |
ho->hisaddr = ciaddr1; |
break; |
|
case CI_MS_DNS1: |
case CI_MS_DNS2: |
/* Microsoft primary or secondary DNS request */ |
d = citype == CI_MS_DNS2; |
IPCPDEBUG((LOG_INFO, "ipcp: received DNS%d Request ", d+1)); |
|
/* If we do not have a DNS address then we cannot send it */ |
if (ao->dnsaddr[d] == 0 || |
cilen != CILEN_ADDR) { /* Check CI length */ |
orc = CONFREJ; /* Reject CI */ |
break; |
} |
GETLONG(tl, p); |
if (htonl(tl) != ao->dnsaddr[d]) { |
DECPTR(sizeof(u_int32_t), p); |
tl = ntohl(ao->dnsaddr[d]); |
PUTLONG(tl, p); |
orc = CONFNAK; |
} |
break; |
|
case CI_MS_WINS1: |
case CI_MS_WINS2: |
/* Microsoft primary or secondary WINS request */ |
d = citype == CI_MS_WINS2; |
IPCPDEBUG((LOG_INFO, "ipcp: received WINS%d Request ", d+1)); |
|
/* If we do not have a DNS address then we cannot send it */ |
if (ao->winsaddr[d] == 0 || |
cilen != CILEN_ADDR) { /* Check CI length */ |
orc = CONFREJ; /* Reject CI */ |
break; |
} |
GETLONG(tl, p); |
if (htonl(tl) != ao->winsaddr[d]) { |
DECPTR(sizeof(u_int32_t), p); |
tl = ntohl(ao->winsaddr[d]); |
PUTLONG(tl, p); |
orc = CONFNAK; |
} |
break; |
|
case CI_COMPRESSTYPE: |
IPCPDEBUG((LOG_INFO, "ipcp: received COMPRESSTYPE ")); |
if (!ao->neg_vj || |
(cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) { |
orc = CONFREJ; |
break; |
} |
GETSHORT(cishort, p); |
IPCPDEBUG((LOG_INFO, "(%d)", cishort)); |
|
if (!(cishort == IPCP_VJ_COMP || |
(cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) { |
orc = CONFREJ; |
break; |
} |
|
ho->neg_vj = 1; |
ho->vj_protocol = cishort; |
if (cilen == CILEN_VJ) { |
GETCHAR(maxslotindex, p); |
if (maxslotindex > ao->maxslotindex) { |
orc = CONFNAK; |
if (!reject_if_disagree){ |
DECPTR(1, p); |
PUTCHAR(ao->maxslotindex, p); |
} |
} |
GETCHAR(cflag, p); |
if (cflag && !ao->cflag) { |
orc = CONFNAK; |
if (!reject_if_disagree){ |
DECPTR(1, p); |
PUTCHAR(wo->cflag, p); |
} |
} |
ho->maxslotindex = maxslotindex; |
ho->cflag = cflag; |
} else { |
ho->old_vj = 1; |
ho->maxslotindex = MAX_STATES - 1; |
ho->cflag = 1; |
} |
break; |
|
default: |
orc = CONFREJ; |
break; |
} |
|
endswitch: |
IPCPDEBUG((LOG_INFO, " (%s)\n", CODENAME(orc))); |
|
if (orc == CONFACK && /* Good CI */ |
rc != CONFACK) /* but prior CI wasnt? */ |
continue; /* Don't send this one */ |
|
if (orc == CONFNAK) { /* Nak this CI? */ |
if (reject_if_disagree) /* Getting fed up with sending NAKs? */ |
orc = CONFREJ; /* Get tough if so */ |
else { |
if (rc == CONFREJ) /* Rejecting prior CI? */ |
continue; /* Don't send this one */ |
if (rc == CONFACK) { /* Ack'd all prior CIs? */ |
rc = CONFNAK; /* Not anymore... */ |
ucp = inp; /* Backup */ |
} |
} |
} |
|
if (orc == CONFREJ && /* Reject this CI */ |
rc != CONFREJ) { /* but no prior ones? */ |
rc = CONFREJ; |
ucp = inp; /* Backup */ |
} |
|
/* Need to move CI? */ |
if (ucp != cip) |
BCOPY(cip, ucp, cilen); /* Move it */ |
|
/* Update output pointer */ |
INCPTR(cilen, ucp); |
} |
|
/* |
* If we aren't rejecting this packet, and we want to negotiate |
* their address, and they didn't send their address, then we |
* send a NAK with a CI_ADDR option appended. We assume the |
* input buffer is long enough that we can append the extra |
* option safely. |
*/ |
if (rc != CONFREJ && !ho->neg_addr && |
wo->req_addr && !reject_if_disagree) { |
if (rc == CONFACK) { |
rc = CONFNAK; |
ucp = inp; /* reset pointer */ |
wo->req_addr = 0; /* don't ask again */ |
} |
PUTCHAR(CI_ADDR, ucp); |
PUTCHAR(CILEN_ADDR, ucp); |
tl = ntohl(wo->hisaddr); |
PUTLONG(tl, ucp); |
} |
|
*len = ucp - inp; /* Compute output length */ |
IPCPDEBUG((LOG_INFO, "ipcp: returning Configure-%s", CODENAME(rc))); |
return (rc); /* Return final code */ |
} |
|
|
/* |
* ip_check_options - check that any IP-related options are OK, |
* and assign appropriate defaults. |
*/ |
static void |
ip_check_options() |
{ |
struct hostent *hp; |
u_int32_t local; |
ipcp_options *wo = &ipcp_wantoptions[0]; |
|
/* |
* Default our local IP address based on our hostname. |
* If local IP address already given, don't bother. |
*/ |
if (wo->ouraddr == 0 && !disable_defaultip) { |
/* |
* Look up our hostname (possibly with domain name appended) |
* and take the first IP address as our local IP address. |
* If there isn't an IP address for our hostname, too bad. |
*/ |
wo->accept_local = 1; /* don't insist on this default value */ |
if ((hp = gethostbyname(hostname)) != NULL) { |
local = *(u_int32_t *)hp->h_addr; |
if (local != 0 && !bad_ip_adrs(local)) |
wo->ouraddr = local; |
} |
} |
|
} |
|
|
/* |
* ip_demand_conf - configure the interface as though |
* IPCP were up, for use with dial-on-demand. |
*/ |
static int |
ip_demand_conf(u) |
int u; |
{ |
ipcp_options *wo = &ipcp_wantoptions[u]; |
|
if (!sifaddr(u, wo->ouraddr, wo->hisaddr, GetMask(wo->ouraddr))) |
return 0; |
if (!sifup(u)) |
return 0; |
if (!sifnpmode(u, PPP_IP, NPMODE_QUEUE)) |
return 0; |
if (wo->default_route) |
if (sifdefaultroute(u, wo->ouraddr, wo->hisaddr)) |
default_route_set[u] = 1; |
if (wo->proxy_arp) |
if (sifproxyarp(u, wo->hisaddr)) |
proxy_arp_set[u] = 1; |
|
syslog(LOG_NOTICE, "local IP address %s", ip_ntoa(wo->ouraddr)); |
syslog(LOG_NOTICE, "remote IP address %s", ip_ntoa(wo->hisaddr)); |
|
return 1; |
} |
|
|
/* |
* ipcp_up - IPCP has come UP. |
* |
* Configure the IP network interface appropriately and bring it up. |
*/ |
#define script_setenv(a,b) |
|
|
static void |
ipcp_up(f) |
fsm *f; |
{ |
u_int32_t mask; |
ipcp_options *ho = &ipcp_hisoptions[f->unit]; |
ipcp_options *go = &ipcp_gotoptions[f->unit]; |
ipcp_options *wo = &ipcp_wantoptions[f->unit]; |
|
np_up(f->unit, PPP_IP); |
IPCPDEBUG((LOG_INFO, "ipcp: up")); |
|
/* |
* We must have a non-zero IP address for both ends of the link. |
*/ |
if (!ho->neg_addr) |
ho->hisaddr = wo->hisaddr; |
|
if (ho->hisaddr == 0) { |
syslog(LOG_ERR, "Could not determine remote IP address"); |
ipcp_close(f->unit, "Could not determine remote IP address"); |
return; |
} |
if (go->ouraddr == 0) { |
syslog(LOG_ERR, "Could not determine local IP address"); |
ipcp_close(f->unit, "Could not determine local IP address"); |
return; |
} |
/* script_setenv("IPLOCAL", ip_ntoa(go->ouraddr)); |
script_setenv("IPREMOTE", ip_ntoa(ho->hisaddr)); |
*/ |
/* |
* Check that the peer is allowed to use the IP address it wants. |
*/ |
if (!auth_ip_addr(f->unit, ho->hisaddr)) { |
syslog(LOG_ERR, "Peer is not authorized to use remote address %s", |
ip_ntoa(ho->hisaddr)); |
ipcp_close(f->unit, "Unauthorized remote IP address"); |
return; |
} |
|
/* set tcp compression */ |
sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex); |
|
/* |
* If we are doing dial-on-demand, the interface is already |
* configured, so we put out any saved-up packets, then set the |
* interface to pass IP packets. |
*/ |
{ |
/* |
* Set IP addresses and (if specified) netmask. |
*/ |
mask = GetMask(go->ouraddr); |
|
#if !(defined(SVR4) && (defined(SNI) || defined(__USLC__))) |
if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) { |
IPCPDEBUG((LOG_WARNING, "sifaddr failed")); |
ipcp_close(f->unit, "Interface configuration failed"); |
return; |
} |
#endif |
|
/* bring the interface up for IP */ |
if (!sifup(f->unit)) { |
IPCPDEBUG((LOG_WARNING, "sifup failed")); |
ipcp_close(f->unit, "Interface configuration failed"); |
return; |
} |
|
#if (defined(SVR4) && (defined(SNI) || defined(__USLC__))) |
if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) { |
IPCPDEBUG((LOG_WARNING, "sifaddr failed")); |
ipcp_close(f->unit, "Interface configuration failed"); |
return; |
} |
#endif |
sifnpmode(f->unit, PPP_IP, NPMODE_PASS); |
|
/* assign a default route through the interface if required */ |
if (ipcp_wantoptions[f->unit].default_route) |
if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr)) |
default_route_set[f->unit] = 1; |
|
/* Make a proxy ARP entry if requested. */ |
if (ipcp_wantoptions[f->unit].proxy_arp) |
if (sifproxyarp(f->unit, ho->hisaddr)) |
proxy_arp_set[f->unit] = 1; |
|
syslog(LOG_NOTICE, "local IP address %s", ip_ntoa(go->ouraddr)); |
syslog(LOG_NOTICE, "remote IP address %s", ip_ntoa(ho->hisaddr)); |
} |
|
/* |
* Execute the ip-up script, like this: |
* /etc/ppp/ip-up interface tty speed local-IP remote-IP |
*/ |
{ |
#if 0 |
/* XXX PPPConfiguration */ |
GlobalSystemStatus *stat; |
stat=LockSTBSystemParam(); |
stat->ConnectionStatus=Connected; |
UnlockSTBSystemParam(); |
#endif |
} |
} |
|
|
/* |
* ipcp_down - IPCP has gone DOWN. |
* |
* Take the IP network interface down, clear its addresses |
* and delete routes through it. |
*/ |
static void |
ipcp_down(f) |
fsm *f; |
{ |
IPCPDEBUG((LOG_INFO, "ipcp: down")); |
np_down(f->unit, PPP_IP); |
sifvjcomp(f->unit, 0, 0, 0); |
|
/* |
* If we are doing dial-on-demand, set the interface |
* to queue up outgoing packets (for now). |
*/ |
sifdown(f->unit); |
ipcp_clear_addrs(f->unit); |
|
/* Execute the ip-down script */ |
{ |
#if 0 |
/* XXX PPPConfiguration */ |
GlobalSystemStatus *stat; |
stat=LockSTBSystemParam(); |
stat->ConnectionStatus=NotConnected; |
UnlockSTBSystemParam(); |
#endif |
} |
} |
|
|
/* |
* ipcp_clear_addrs() - clear the interface addresses, routes, |
* proxy arp entries, etc. |
*/ |
static void |
ipcp_clear_addrs(unit) |
int unit; |
{ |
u_int32_t ouraddr, hisaddr; |
|
ouraddr = ipcp_gotoptions[unit].ouraddr; |
hisaddr = ipcp_hisoptions[unit].hisaddr; |
if (proxy_arp_set[unit]) { |
cifproxyarp(unit, hisaddr); |
proxy_arp_set[unit] = 0; |
} |
if (default_route_set[unit]) { |
cifdefaultroute(unit, ouraddr, hisaddr); |
default_route_set[unit] = 0; |
} |
cifaddr(unit, ouraddr, hisaddr); |
} |
|
|
/* |
* ipcp_finished - possibly shut down the lower layers. |
*/ |
static void |
ipcp_finished(f) |
fsm *f; |
{ |
np_finished(f->unit, PPP_IP); |
} |
|
|
#if 0 |
/* |
* ipcp_script - Execute a script with arguments |
* interface-name tty-name speed local-IP remote-IP. |
*/ |
static void |
ipcp_script(f, script) |
fsm *f; |
char *script; |
{ |
char strspeed[32], strlocal[32], strremote[32]; |
char *argv[8]; |
|
sprintf(strspeed, "%d", baud_rate); |
strcpy(strlocal, ip_ntoa(ipcp_gotoptions[f->unit].ouraddr)); |
strcpy(strremote, ip_ntoa(ipcp_hisoptions[f->unit].hisaddr)); |
|
argv[0] = script; |
argv[1] = ifname; |
argv[2] = devnam; |
argv[3] = strspeed; |
argv[4] = strlocal; |
argv[5] = strremote; |
argv[6] = ipparam; |
argv[7] = NULL; |
run_program(script, argv, 0); |
} |
#endif |
|
/* |
* ipcp_printpkt - print the contents of an IPCP packet. |
*/ |
static char *ipcp_codenames[] = { |
"ConfReq", "ConfAck", "ConfNak", "ConfRej", |
"TermReq", "TermAck", "CodeRej" |
}; |
|
static int |
ipcp_printpkt(p, plen, printer, arg) |
u_char *p; |
int plen; |
void (*printer) __P((void *, char *, ...)); |
void *arg; |
{ |
int code, id, len, olen; |
u_char *pstart, *optend; |
u_short cishort; |
u_int32_t cilong; |
|
if (plen < HEADERLEN) |
return 0; |
pstart = p; |
GETCHAR(code, p); |
GETCHAR(id, p); |
GETSHORT(len, p); |
if (len < HEADERLEN || len > plen) |
return 0; |
|
if (code >= 1 && code <= sizeof(ipcp_codenames) / sizeof(char *)) |
printer(arg, " %s", ipcp_codenames[code-1]); |
else |
printer(arg, " code=0x%x", code); |
printer(arg, " id=0x%x", id); |
len -= HEADERLEN; |
switch (code) { |
case CONFREQ: |
case CONFACK: |
case CONFNAK: |
case CONFREJ: |
|
while (len >= 2) { |
GETCHAR(code, p); |
GETCHAR(olen, p); |
p -= 2; |
if (olen < 2 || olen > len) { |
break; |
} |
printer(arg, " <"); |
len -= olen; |
optend = p + olen; |
switch (code) { |
case CI_ADDRS: |
if (olen == CILEN_ADDRS) { |
p += 2; |
GETLONG(cilong, p); |
printer(arg, "addrs %I", htonl(cilong)); |
GETLONG(cilong, p); |
printer(arg, " %I", htonl(cilong)); |
} |
break; |
case CI_COMPRESSTYPE: |
if (olen >= CILEN_COMPRESS) { |
p += 2; |
GETSHORT(cishort, p); |
printer(arg, "compress "); |
switch (cishort) { |
case IPCP_VJ_COMP: |
printer(arg, "VJ"); |
break; |
case IPCP_VJ_COMP_OLD: |
printer(arg, "old-VJ"); |
break; |
default: |
printer(arg, "0x%x", cishort); |
} |
} |
break; |
case CI_ADDR: |
if (olen == CILEN_ADDR) { |
p += 2; |
GETLONG(cilong, p); |
printer(arg, "addr %I", htonl(cilong)); |
} |
break; |
case CI_MS_DNS1: |
case CI_MS_DNS2: |
p += 2; |
GETLONG(cilong, p); |
printer(arg, "ms-dns %I", htonl(cilong)); |
break; |
case CI_MS_WINS1: |
case CI_MS_WINS2: |
p += 2; |
GETLONG(cilong, p); |
printer(arg, "ms-wins %I", htonl(cilong)); |
break; |
} |
while (p < optend) { |
GETCHAR(code, p); |
printer(arg, " %.2x", code); |
} |
printer(arg, ">"); |
} |
break; |
|
case TERMACK: |
case TERMREQ: |
if (len > 0 && *p >= ' ' && *p < 0x7f) { |
printer(arg, " "); |
print_string(p, len, printer, arg); |
p += len; |
len = 0; |
} |
break; |
} |
|
for (; len > 0; --len) { |
GETCHAR(code, p); |
printer(arg, " %.2x", code); |
} |
|
return p - pstart; |
} |
|
/* |
* ip_active_pkt - see if this IP packet is worth bringing the link up for. |
* We don't bring the link up for IP fragments or for TCP FIN packets |
* with no data. |
*/ |
#define IP_HDRLEN 20 /* bytes */ |
#define IP_OFFMASK 0x1fff |
#define IPPROTO_TCP 6 |
#define TCP_HDRLEN 20 |
#define TH_FIN 0x01 |
|
/* |
* We use these macros because the IP header may be at an odd address, |
* and some compilers might use word loads to get th_off or ip_hl. |
*/ |
|
#define net_short(x) (((x)[0] << 8) + (x)[1]) |
#define get_iphl(x) (((unsigned char *)(x))[0] & 0xF) |
#define get_ipoff(x) net_short((unsigned char *)(x) + 6) |
#define get_ipproto(x) (((unsigned char *)(x))[9]) |
#define get_tcpoff(x) (((unsigned char *)(x))[12] >> 4) |
#define get_tcpflags(x) (((unsigned char *)(x))[13]) |
|
static int |
ip_active_pkt(pkt, len) |
u_char *pkt; |
int len; |
{ |
u_char *tcp; |
int hlen; |
|
len -= PPP_HDRLEN; |
pkt += PPP_HDRLEN; |
if (len < IP_HDRLEN) |
return 0; |
if ((get_ipoff(pkt) & IP_OFFMASK) != 0) |
return 0; |
if (get_ipproto(pkt) != IPPROTO_TCP) |
return 1; |
hlen = get_iphl(pkt) * 4; |
if (len < hlen + TCP_HDRLEN) |
return 0; |
tcp = pkt + hlen; |
if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == hlen + get_tcpoff(tcp) * 4) |
return 0; |
return 1; |
} |
/patchlevel.h
0,0 → 1,6
/* $Id: patchlevel.h,v 1.2 2001-09-27 12:01:57 chris Exp $ */ |
#define PATCHLEVEL 5 |
|
#define VERSION "2.3" |
#define IMPLEMENTATION "" |
#define DATE "4 May 1998" |