📄 ipcp.c
字号:
/*
* 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.
*/
/*
* TODO:
*/
#include <stdio.h>
#include <string.h>
#include "syslog.h"
#include "ppp.h"
#include "fsm.h"
#include "ipcp.h"
#define BCOPY(p0, p1, n) memmove (p1, p0, n)
/* 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 */
/*
* 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 */
static char *ip_ntoa __P((u_int32_t));
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 */
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 */
"IPCP" /* String name of protocol */
};
/*
* 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.
*/
static 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.
*/
void
ipcp_init(unit)
int unit;
{
fsm *f = &ipcp_fsm[unit];
ipcp_options *wo = &ipcp_wantoptions[unit];
ipcp_options *ao = &ipcp_allowoptions[unit];
struct ppp_cfg *pcp = &pppcfgtab[unit];
f->unit = unit;
f->protocol = PPP_IPCP;
f->callbacks = &ipcp_callbacks;
fsm_init(&ipcp_fsm[unit]);
wo->neg_addr = ((pcp->ipcp_options & NEGADDR) ? 1 : 0);
wo->old_addrs = 0;
wo->ouraddr = pcp->local_ip;
wo->hisaddr = pcp->peer_ip;
wo->neg_vj = ((pcp->ipcp_options & NEGIPCOMP) ? 1 : 0);
wo->old_vj = 0;
wo->vj_protocol = IPCP_VJ_COMP;
wo->maxslotindex = MAX_STATES - 1; /* really max index */
wo->cflag = 1;
wo->proxy_arp = 0;
wo->default_route = 0;
/* 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 = ((pcp->ipcp_options & NEGADDR) ? 1 : 0);
ao->neg_vj = ((pcp->ipcp_options & NEGIPCOMP) ? 1 : 0);
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.
*/
void
ipcp_open(unit)
int unit;
{
fsm_open(&ipcp_fsm[unit]);
}
/*
* ipcp_close - Take IPCP down.
*/
void
ipcp_close(unit)
int unit;
{
fsm_close(&ipcp_fsm[unit]);
}
/*
* ipcp_lowerup - The lower layer is up.
*/
void
ipcp_lowerup(unit)
int unit;
{
fsm_lowerup(&ipcp_fsm[unit]);
}
/*
* ipcp_lowerdown - The lower layer is down.
*/
void
ipcp_lowerdown(unit)
int unit;
{
fsm_lowerdown(&ipcp_fsm[unit]);
}
/*
* ipcp_input - Input IPCP packet.
*/
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.
*/
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];
#define LENCIVJ(neg, old) (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0)
#define LENCIADDR(neg, old) (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0)
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 *wo = &ipcp_wantoptions[f->unit];
ipcp_options *go = &ipcp_gotoptions[f->unit];
ipcp_options *ho = &ipcp_hisoptions[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; \
}
/*
* 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;
}
}
}
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -