/*
* ipcp.c
*
* Written by Toshiharu OHNO <tony-o@iij.ad.jp>
* Copyright (c) 1993, Internet Initiative Japan, Inc. All rights reserved.
* See ``COPYRIGHT.iij''
*
* Rewritten by Archie Cobbs <archie@freebsd.org>
* Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved.
* See ``COPYRIGHT.whistle''
*/
#include "ppp.h"
#include "ipcp.h"
#include "fsm.h"
#include "ip.h"
#include "iface.h"
#include "custom.h"
#include "msg.h"
#include "ngfunc.h"
#include <netgraph.h>
#include <sys/mbuf.h>
#include <net/slcompress.h>
#include <netgraph/ng_vjc.h>
/*
* DEFINITIONS
*/
#define IPCP_KNOWN_CODES ( (1 << CODE_CONFIGREQ) \
| (1 << CODE_CONFIGACK) \
| (1 << CODE_CONFIGNAK) \
| (1 << CODE_CONFIGREJ) \
| (1 << CODE_TERMREQ) \
| (1 << CODE_TERMACK) \
| (1 << CODE_CODEREJ) )
#define TY_IPADDRS 1
#define TY_COMPPROTO 2
#define TY_IPADDR 3
#define TY_PRIMARYDNS 129
#define TY_PRIMARYNBNS 130
#define TY_SECONDARYDNS 131
#define TY_SECONDARYNBNS 132
#define IPCP_REJECTED(p,x) ((p)->peer_reject & (1<<(x)))
#define IPCP_PEER_REJ(p,x) do{(p)->peer_reject |= (1<<(x));}while(0)
#define IPCP_VJCOMP_MIN_MAXCHAN (NG_VJC_MIN_CHANNELS - 1)
#define IPCP_VJCOMP_MAX_MAXCHAN (NG_VJC_MAX_CHANNELS - 1)
#define IPCP_VJCOMP_DEFAULT_MAXCHAN IPCP_VJCOMP_MAX_MAXCHAN
/* Set menu options */
enum {
SET_RANGES,
SET_ENABLE,
SET_DNS,
SET_NBNS,
SET_DISABLE,
SET_ACCEPT,
SET_DENY,
SET_YES,
SET_NO,
};
/*
* INTERNAL FUNCTIONS
*/
static void IpcpConfigure(Fsm fp);
static void IpcpUnConfigure(Fsm fp);
static u_char *IpcpBuildConfigReq(Fsm fp, u_char *cp);
static void IpcpDecodeConfig(Fsm fp, FsmOption list, int num, int mode);
static void IpcpLayerStart(Fsm fp);
static void IpcpLayerFinish(Fsm fp);
static void IpcpLayerUp(Fsm fp);
static void IpcpLayerDown(Fsm fp);
static void IpcpFailure(Fsm fp, enum fsmfail reason);
static int IpcpSetCommand(int ac, char *av[], void *arg);
/*
* GLOBAL VARIABLES
*/
const struct cmdtab IpcpSetCmds[] = {
{ "ranges self/width peer/width", "Allowed IP address ranges",
IpcpSetCommand, NULL, (void *) SET_RANGES },
{ "enable [opt ...]", "Enable option",
IpcpSetCommand, NULL, (void *) SET_ENABLE},
{ "dns primary [secondary]", "Set peer DNS servers",
IpcpSetCommand, NULL, (void *) SET_DNS},
{ "nbns primary [secondary]", "Set peer NBNS servers",
IpcpSetCommand, NULL, (void *) SET_NBNS},
{ "disable [opt ...]", "Disable option",
IpcpSetCommand, NULL, (void *) SET_DISABLE},
{ "accept [opt ...]", "Accept option",
IpcpSetCommand, NULL, (void *) SET_ACCEPT},
{ "deny [opt ...]", "Deny option",
IpcpSetCommand, NULL, (void *) SET_DENY},
{ "yes [opt ...]", "Enable and accept option",
IpcpSetCommand, NULL, (void *) SET_YES},
{ "no [opt ...]", "Disable and deny option",
IpcpSetCommand, NULL, (void *) SET_NO},
{ NULL },
};
/*
* INTERNAL VARIABLES
*/
static const struct fsmoptinfo gIpcpConfOpts[] = {
{ "IPADDRS", TY_IPADDRS, 8, 8, FALSE },
{ "COMPPROTO", TY_COMPPROTO, 4, 4, TRUE },
{ "IPADDR", TY_IPADDR, 4, 4, TRUE },
{ "PRIDNS", TY_PRIMARYDNS, 4, 4, TRUE },
{ "PRINBNS", TY_PRIMARYNBNS, 4, 4, TRUE },
{ "SECDNS", TY_SECONDARYDNS, 4, 4, TRUE },
{ "SECNBNS", TY_SECONDARYNBNS, 4, 4, TRUE },
{ NULL }
};
static const struct confinfo gConfList[] = {
{ 1, IPCP_CONF_VJCOMP, "vjcomp" },
{ 0, IPCP_CONF_REQPRIDNS, "req-pri-dns" },
{ 0, IPCP_CONF_REQSECDNS, "req-sec-dns" },
{ 0, IPCP_CONF_REQPRINBNS, "req-pri-nbns" },
{ 0, IPCP_CONF_REQSECNBNS, "req-sec-nbns" },
{ 0, IPCP_CONF_PRETENDIP, "pretend-ip" },
{ 0, IPCP_CONF_RADIUSIP, "radius-ip" },
{ 0, 0, NULL },
};
static const struct fsmtype gIpcpFsmType = {
"IPCP",
PROTO_IPCP,
IPCP_KNOWN_CODES,
LG_IPCP, LG_IPCP,
FALSE,
NULL,
IpcpLayerUp,
IpcpLayerDown,
IpcpLayerStart,
IpcpLayerFinish,
IpcpBuildConfigReq,
IpcpDecodeConfig,
IpcpConfigure,
IpcpUnConfigure,
NULL,
NULL,
NULL,
NULL,
IpcpFailure,
NULL,
NULL,
NULL,
};
/*
* IpcpStat()
*/
int
IpcpStat(int ac, char *av[], void *arg)
{
char path[NG_PATHLEN + 1];
IpcpState const ipcp = &bund->ipcp;
Fsm fp = &ipcp->fsm;
union {
u_char buf[sizeof(struct ng_mesg) + sizeof(struct slcompress)];
struct ng_mesg reply;
} u;
struct slcompress *const sls = (struct slcompress *)(void *)u.reply.data;
printf("%s [%s]\n", Pref(fp), FsmStateName(fp->state));
printf("Allowed IP address ranges:\n");
printf("\tSelf: %s/%d\n",
inet_ntoa(ipcp->conf.self_allow.ipaddr), ipcp->conf.self_allow.width);
printf("\tPeer: %s/%d\n",
inet_ntoa(ipcp->conf.peer_allow.ipaddr), ipcp->conf.peer_allow.width);
printf("Current addressing:\n");
printf("\tSelf: %s\n", inet_ntoa(ipcp->want_addr));
printf("\tPeer: %s\n", inet_ntoa(ipcp->peer_addr));
printf("Compression:\n");
printf("\tSelf: ");
if (ipcp->want_comp.proto != 0)
printf("%s, %d compression channels, CID %scompressible\n",
ProtoName(ntohs(ipcp->want_comp.proto)),
ipcp->want_comp.maxchan + 1, ipcp->want_comp.compcid ? "" : "not ");
else
printf("None\n");
printf("\tPeer: ");
if (ipcp->peer_comp.proto != 0)
printf("%s, %d compression channels, CID %scompressible\n",
ProtoName(ntohs(ipcp->peer_comp.proto)),
ipcp->peer_comp.maxchan + 1, ipcp->peer_comp.compcid ? "" : "not ");
else
printf("None\n");
printf("Server info we give to peer:\n");
printf("DNS servers : %15s", inet_ntoa(ipcp->conf.peer_dns[0]));
printf(" %15s\n", inet_ntoa(ipcp->conf.peer_dns[1]));
printf("NBNS servers: %15s", inet_ntoa(ipcp->conf.peer_nbns[0]));
printf(" %15s\n", inet_ntoa(ipcp->conf.peer_nbns[1]));
printf("Server info peer gave to us:\n");
printf("DNS servers : %15s", inet_ntoa(ipcp->want_dns[0]));
printf(" %15s\n", inet_ntoa(ipcp->want_dns[1]));
printf("NBNS servers: %15s", inet_ntoa(ipcp->want_nbns[0]));
printf(" %15s\n", inet_ntoa(ipcp->want_nbns[1]));
printf("IPCP Options:\n");
OptStat(&ipcp->conf.options, gConfList);
/* Get VJC state */
snprintf(path, sizeof(path), "%s.%s", MPD_HOOK_PPP, NG_PPP_HOOK_VJC_IP);
if (NgSendMsg(bund->csock, path,
NGM_VJC_COOKIE, NGM_VJC_GET_STATE, NULL, 0) < 0) {
return(0);
}
if (NgRecvMsg(bund->csock, &u.reply, sizeof(u), NULL) < 0) {
Log(LG_ERR, ("[%s] node \"%s\" reply: %s",
bund->name, path, strerror(errno)));
return(0);
}
printf("VJ Compression:\n");
printf("\tOut comp : %d\n", sls->sls_compressed);
printf("\tOut total: %d\n", sls->sls_packets);
printf("\tMissed : %d\n", sls->sls_misses);
printf("\tSearched : %d\n", sls->sls_searches);
printf("\tIn comp : %d\n", sls->sls_compressedin);
printf("\tIn uncomp: %d\n", sls->sls_uncompressedin);
printf("\tIn error : %d\n", sls->sls_errorin);
printf("\tIn tossed: %d\n", sls->sls_tossed);
return(0);
}
/*
* IpcpInit()
*/
void
IpcpInit(void)
{
IpcpState const ipcp = &bund->ipcp;
/* Init state machine */
memset(ipcp, 0, sizeof(*ipcp));
FsmInit(&ipcp->fsm, &gIpcpFsmType);
/* Come up with a default IP address for my side of the link */
memset(&ipcp->conf.self_allow, 0, sizeof(ipcp->conf.self_allow));
IfaceGetAnyIpAddress(&ipcp->conf.self_allow.ipaddr);
/* Default we want VJ comp */
Enable(&ipcp->conf.options, IPCP_CONF_VJCOMP);
Accept(&ipcp->conf.options, IPCP_CONF_VJCOMP);
}
/*
* IpcpConfigure()
*/
static void
IpcpConfigure(Fsm fp)
{
IpcpState const ipcp = &bund->ipcp;
/* FSM stuff */
ipcp->peer_reject = 0;
/* Get allowed IP addresses from config and/or from current bundle */
ipcp->self_allow = ipcp->conf.self_allow;
if (bund->peer_allow.ipaddr.s_addr != 0 || bund->peer_allow.width != 0)
ipcp->peer_allow = bund->peer_allow;
else
ipcp->peer_allow = ipcp->conf.peer_allow;
/* Dynamically get IP address? */
#ifdef IA_CUSTOM
if (ipcp->conf.peer_allow.ipaddr.s_addr == 0) {
ipcp->conf.peer_allow.ipaddr = CustomGetPeerIp();
ipcp->conf.peer_allow.width = 32;
if (ipcp->conf.peer_allow.ipaddr.s_addr == 0)
Log(LG_IPCP, ("[%s] %s",
bund->name, "no IP address available for peer!"));
else
ipcp->ipDynamic = TRUE;
}
#endif
/* Initially request addresses as specified by config */
ipcp->want_addr = ipcp->self_allow.ipaddr;
ipcp->peer_addr = ipcp->peer_allow.ipaddr;
/* Van Jacobson compression */
ipcp->peer_comp.proto = 0;
ipcp->peer_comp.maxchan = IPCP_VJCOMP_DEFAULT_MAXCHAN;
ipcp->peer_comp.compcid = 0;
ipcp->want_comp.proto =
Enabled(&ipcp->conf.options, IPCP_CONF_VJCOMP) ? htons(PROTO_VJCOMP) : 0;
ipcp->want_comp.maxchan = IPCP_VJCOMP_MAX_MAXCHAN;
/* DNS and NBNS servers */
memset(&ipcp->want_dns, 0, sizeof(ipcp->want_dns));
memset(&ipcp->want_nbns, 0, sizeof(ipcp->want_nbns));
/* If any of our links are unable to give receive error indications, we must
tell the peer not to compress the slot-id in VJCOMP packets (cf. RFC1144).
To be on the safe side, we always say this. */
ipcp->want_comp.compcid = 0;
}
/*
* IpcpUnConfigure()
*/
static void
IpcpUnConfigure(Fsm fp)
{
#ifdef IA_CUSTOM
IpcpState const ipcp = &bund->ipcp;
if (ipcp->ipDynamic) {
CustomReleasePeerIp(ipcp->conf.peer_allow.ipaddr);
ipcp->conf.peer_allow.ipaddr.s_addr = 0;
ipcp->ipDynamic = FALSE;
}
#endif
}
/*
* IpcpBuildConfigReq()
*/
static u_char *
IpcpBuildConfigReq(Fsm fp, u_char *cp)
{
IpcpState const ipcp = &bund->ipcp;
/* Put in my desired IP address */
if (!IPCP_REJECTED(ipcp, TY_IPADDR) || ipcp->want_addr.s_addr == 0)
cp = FsmConfValue(cp, TY_IPADDR, 4, &ipcp->want_addr.s_addr);
/* Put in my requested compression protocol */
if (ipcp->want_comp.proto != 0 && !IPCP_REJECTED(ipcp, TY_COMPPROTO))
cp = FsmConfValue(cp, TY_COMPPROTO, 4, &ipcp->want_comp);
/* Request peer's DNS and NBNS servers */
{
const int sopts[2][2] = { { IPCP_CONF_REQPRIDNS, IPCP_CONF_REQSECDNS },
{ IPCP_CONF_REQPRINBNS, IPCP_CONF_REQSECNBNS }};
const int nopts[2][2] = { { TY_PRIMARYDNS, TY_SECONDARYDNS },
{ TY_PRIMARYNBNS, TY_SECONDARYNBNS } };
struct in_addr *vals[2] = { ipcp->want_dns, ipcp->want_nbns };
int sopt, pri;
for (sopt = 0; sopt < 2; sopt++) {
for (pri = 0; pri < 2; pri++) {
const int opt = nopts[sopt][pri];
/* Add option if we desire it and it hasn't been rejected */
if (Enabled(&ipcp->conf.options, sopts[sopt][pri])
&& !IPCP_REJECTED(ipcp, opt)) {
cp = FsmConfValue(cp, opt, 4, &vals[sopt][pri]);
}
}
}
}
/* Done */
return(cp);
}
/*
* IpcpLayerStart()
*
* Tell the lower layer (the bundle) that we need it
*/
static void
IpcpLayerStart(Fsm fp)
{
BundOpen(/*PROTO_IPCP*/);
}
/*
* IpcpLayerFinish()
*
* Tell the lower layer (the bundle) that we no longer need it
*/
static void
IpcpLayerFinish(Fsm fp)
{
BundClose(/*PROTO_IPCP*/);
}
/*
* IpcpLayerUp()
*
* Called when IPCP has reached the OPEN state
*/
static void
IpcpLayerUp(Fsm fp)
{
IpcpState const ipcp = &bund->ipcp;
char ipbuf[20];
char path[NG_PATHLEN + 1];
struct ngm_vjc_config vjc;
/* Determine actual address we'll use for ourselves */
if (!IpAddrInRange(&ipcp->self_allow, ipcp->want_addr)) {
Log(fp->log, (" Note: ignoring negotiated %s IP %s,",
"self", inet_ntoa(ipcp->want_addr)));
Log(fp->log, (" using %s instead.",
inet_ntoa(ipcp->self_allow.ipaddr)));
ipcp->want_addr = ipcp->self_allow.ipaddr;
}
/* Determine actual address we'll use for peer */
if (!IpAddrInRange(&ipcp->peer_allow, ipcp->peer_addr)
&& ipcp->peer_allow.ipaddr.s_addr != 0) {
Log(fp->log, (" Note: ignoring negotiated %s IP %s,",
"peer", inet_ntoa(ipcp->peer_addr)));
Log(fp->log, (" using %s instead.",
inet_ntoa(ipcp->peer_allow.ipaddr)));
ipcp->peer_addr = ipcp->peer_allow.ipaddr;
}
/* Report */
snprintf(ipbuf, sizeof(ipbuf), "%s", inet_ntoa(ipcp->peer_addr));
Log(fp->log, (" %s -> %s", inet_ntoa(ipcp->want_addr), ipbuf));
/* Bring up IP interface */
IfaceUp(ipcp->want_addr, ipcp->peer_addr);
/* Configure VJ compression node */
memset(&vjc, 0, sizeof(vjc));
vjc.enableComp = ntohs(ipcp->peer_comp.proto) == PROTO_VJCOMP;
vjc.enableDecomp = ntohs(ipcp->want_comp.proto) == PROTO_VJCOMP;
vjc.maxChannel = ipcp->peer_comp.maxchan;
vjc.compressCID = ipcp->peer_comp.compcid;
snprintf(path, sizeof(path), "%s.%s", MPD_HOOK_PPP, NG_PPP_HOOK_VJC_IP);
if (NgSendMsg(bund->csock, path,
NGM_VJC_COOKIE, NGM_VJC_SET_CONFIG, &vjc, sizeof(vjc)) < 0) {
Log(LG_ERR, ("[%s] can't config %s node: %s",
bund->name, NG_VJC_NODE_TYPE, strerror(errno)));
}
/* Tell upper layer (ip interface) that we are available */
IfaceUp(ipcp->want_addr, ipcp->peer_addr);
/* Enable IP packets in the PPP node */
#if NGM_PPP_COOKIE < 940897794
bund->pppConfig.enableIP = 1;
bund->pppConfig.enableVJCompression = vjc.enableComp;
bund->pppConfig.enableVJDecompression = vjc.enableDecomp;
#else
bund->pppConfig.bund.enableIP = 1;
bund->pppConfig.bund.enableVJCompression = vjc.enableComp;
bund->pppConfig.bund.enableVJDecompression = vjc.enableDecomp;
#endif
NgFuncSetConfig();
}
/*
* IpcpLayerDown()
*
* Called when IPCP leaves the OPEN state
*/
static void
IpcpLayerDown(Fsm fp)
{
struct ngm_vjc_config vjc;
char path[NG_PATHLEN + 1];
/* Turn off IP packets */
#if NGM_PPP_COOKIE < 940897794
bund->pppConfig.enableIP = 0;
bund->pppConfig.enableVJCompression = 0;
bund->pppConfig.enableVJDecompression = 0;
#else
bund->pppConfig.bund.enableIP = 0;
bund->pppConfig.bund.enableVJCompression = 0;
bund->pppConfig.bund.enableVJDecompression = 0;
#endif
NgFuncSetConfig();
/* Turn off VJ compression node */
memset(&vjc, 0, sizeof(vjc));
snprintf(path, sizeof(path), "%s.%s", MPD_HOOK_PPP, NG_PPP_HOOK_VJC_IP);
if (NgSendMsg(bund->csock, path,
NGM_VJC_COOKIE, NGM_VJC_SET_CONFIG, &vjc, sizeof(vjc)) < 0) {
Log(LG_ERR, ("[%s] can't config %s node: %s",
bund->name, NG_VJC_NODE_TYPE, strerror(errno)));
}
/* Notify interface */
IfaceDown();
}
/*
* IpcpUp()
*/
void
IpcpUp(void)
{
FsmUp(&bund->ipcp.fsm);
}
/*
* IpcpClose()
*/
void
IpcpClose(void)
{
FsmClose(&bund->ipcp.fsm);
}
/*
* IpcpDown()
*/
void
IpcpDown(void)
{
FsmDown(&bund->ipcp.fsm);
}
/*
* IpcpOpen()
*/
void
IpcpOpen(void)
{
FsmOpen(&bund->ipcp.fsm);
}
/*
* IpcpFailure()
*/
static void
IpcpFailure(Fsm fp, enum fsmfail reason)
{
char buf[100];
snlcatf(buf, sizeof(buf), STR_IPCP_FAILED, FsmFailureStr(reason));
SetStatus(ADLG_WAN_NEGOTIATION_FAILURE, STR_COPY, buf);
RecordLinkUpDownReason(NULL, 0, STR_PROTO_ERR, "%s", buf);
RecordLinkUpDownReason(NULL, 1, STR_REDIAL, NULL);
}
/*
* IpcpDecodeConfig()
*/
static void
IpcpDecodeConfig(Fsm fp, FsmOption list, int num, int mode)
{
IpcpState const ipcp = &bund->ipcp;
struct in_addr *wantip, *peerip;
int k;
/* Decode each config option */
for (k = 0; k < num; k++) {
FsmOption const opt = &list[k];
FsmOptInfo const oi = FsmFindOptInfo(gIpcpConfOpts, opt->type);
if (!oi) {
Log(LG_IPCP, (" UNKNOWN[%d] len=%d", opt->type, opt->len));
if (mode == MODE_REQ)
FsmRej(fp, opt);
continue;
}
if (!oi->supported) {
Log(LG_IPCP, (" %s", oi->name));
if (mode == MODE_REQ) {
Log(LG_IPCP, (" Not supported"));
FsmRej(fp, opt);
}
continue;
}
if (opt->len < oi->minLen + 2 || opt->len > oi->maxLen + 2) {
Log(LG_IPCP, (" %s", oi->name));
if (mode == MODE_REQ) {
Log(LG_IPCP, (" bogus len=%d", opt->len));
FsmRej(fp, opt);
}
continue;
}
switch (opt->type) {
case TY_IPADDR:
{
struct in_addr ip;
memcpy(&ip, opt->data, 4);
Log(LG_IPCP, (" %s %s", oi->name, inet_ntoa(ip)));
switch (mode) {
case MODE_REQ:
if (!IpAddrInRange(&ipcp->peer_allow, ip) || !ip.s_addr) {
if (ipcp->peer_addr.s_addr == 0)
Log(LG_IPCP, (" %s", "no IP address available for peer!"));
if (Enabled(&ipcp->conf.options, IPCP_CONF_PRETENDIP)) {
Log(LG_IPCP, (" pretending that %s is OK, will ignore",
inet_ntoa(ip)));
ipcp->peer_addr = ip;
FsmAck(fp, opt);
break;
}
memcpy(opt->data, &ipcp->peer_addr, 4);
Log(LG_IPCP, (" NAKing with %s", inet_ntoa(ipcp->peer_addr)));
FsmNak(fp, opt);
break;
}
Log(LG_IPCP, (" %s is OK", inet_ntoa(ip)));
ipcp->peer_addr = ip;
FsmAck(fp, opt);
break;
case MODE_NAK:
{
int bogus = 0;
#ifdef IA_CUSTOM
if (gIpcpExcludeRange.ipaddr.s_addr != 0
&& IpAddrInRange(&gIpcpExcludeRange, ip)) {
Log(LG_IPCP, (" %s is on my LAN network!", inet_ntoa(ip)));
bogus = 1;
}
#endif
if (IpAddrInRange(&ipcp->self_allow, ip) && !bogus) {
Log(LG_IPCP, (" %s is OK", inet_ntoa(ip)));
ipcp->want_addr = ip;
} else if (Enabled(&ipcp->conf.options, IPCP_CONF_PRETENDIP)) {
Log(LG_IPCP, (" pretending that %s is OK, will ignore",
inet_ntoa(ip)));
ipcp->want_addr = ip;
} else
Log(LG_IPCP, (" %s is unacceptable", inet_ntoa(ip)));
}
break;
case MODE_REJ:
IPCP_PEER_REJ(ipcp, opt->type);
if (ipcp->want_addr.s_addr == 0)
Log(LG_IPCP, (" Problem: I need an IP address!"));
break;
}
}
break;
case TY_COMPPROTO:
{
struct ipcpvjcomp vj;
memcpy(&vj, opt->data, sizeof(vj));
Log(LG_IPCP, (" %s %s, %d comp. channels, %s comp-cid",
oi->name, ProtoName(ntohs(vj.proto)),
vj.maxchan + 1, vj.compcid ? "allow" : "no"));
switch (mode) {
case MODE_REQ:
if (!Acceptable(&ipcp->conf.options, IPCP_CONF_VJCOMP)) {
FsmRej(fp, opt);
break;
}
if (ntohs(vj.proto) == PROTO_VJCOMP
&& vj.maxchan <= IPCP_VJCOMP_MAX_MAXCHAN
&& vj.maxchan >= IPCP_VJCOMP_MIN_MAXCHAN) {
ipcp->peer_comp = vj;
FsmAck(fp, opt);
break;
}
vj.proto = htons(PROTO_VJCOMP);
vj.maxchan = IPCP_VJCOMP_MAX_MAXCHAN;
vj.compcid = 0;
memcpy(opt->data, &vj, sizeof(vj));
FsmNak(fp, opt);
break;
case MODE_NAK:
if (ntohs(vj.proto) != PROTO_VJCOMP) {
Log(LG_IPCP, (" Can't accept proto 0x%04x",
(u_short) ntohs(vj.proto)));
break;
}
if (vj.maxchan != ipcp->want_comp.maxchan) {
if (vj.maxchan <= IPCP_VJCOMP_MAX_MAXCHAN
&& vj.maxchan >= IPCP_VJCOMP_MIN_MAXCHAN) {
Log(LG_IPCP, (" Adjusting # compression channels"));
ipcp->want_comp.maxchan = vj.maxchan;
} else {
Log(LG_IPCP, (" Can't handle %d maxchan", vj.maxchan));
}
}
if (vj.compcid) {
Log(LG_IPCP, (" Can't accept comp-cid"));
break;
}
break;
case MODE_REJ:
IPCP_PEER_REJ(ipcp, opt->type);
ipcp->want_comp.proto = 0;
break;
}
}
break;
case TY_PRIMARYDNS:
peerip = &ipcp->conf.peer_dns[0];
wantip = &ipcp->want_dns[0];
goto doDnsNbns;
case TY_PRIMARYNBNS:
peerip = &ipcp->conf.peer_nbns[0];
wantip = &ipcp->want_nbns[0];
goto doDnsNbns;
case TY_SECONDARYDNS:
peerip = &ipcp->conf.peer_dns[1];
wantip = &ipcp->want_dns[1];
goto doDnsNbns;
case TY_SECONDARYNBNS:
peerip = &ipcp->conf.peer_nbns[1];
wantip = &ipcp->want_nbns[1];
doDnsNbns:
{
struct in_addr hisip;
memcpy(&hisip, opt->data, 4);
Log(LG_IPCP, (" %s %s", oi->name, inet_ntoa(hisip)));
switch (mode) {
case MODE_REQ:
if (hisip.s_addr == 0) { /* he's asking for one */
if (peerip->s_addr == 0) { /* we don't got one */
FsmRej(fp, opt);
break;
}
Log(LG_IPCP, (" NAKing with %s", inet_ntoa(*peerip)));
memcpy(opt->data, peerip, sizeof(*peerip));
FsmNak(fp, opt); /* we got one for him */
break;
}
FsmAck(fp, opt); /* he knows what he wants */
break;
case MODE_NAK: /* we asked for his server, he's telling us */
*wantip = hisip;
break;
case MODE_REJ: /* we asked for his server, he's ignorant */
IPCP_PEER_REJ(ipcp, opt->type);
break;
}
}
break;
default:
assert(0);
}
}
}
/*
* IpcpInput()
*
* Deal with an incoming IPCP packet
*/
void
IpcpInput(Mbuf bp, int linkNum)
{
FsmInput(&bund->ipcp.fsm, bp, linkNum);
}
/*
* IpcpSetCommand()
*/
static int
IpcpSetCommand(int ac, char *av[], void *arg)
{
IpcpState const ipcp = &bund->ipcp;
struct in_addr *ips;
if (ac == 0)
return(-1);
switch ((intptr_t)arg) {
case SET_RANGES:
{
struct in_range self_new_allow;
struct in_range peer_new_allow;
/* Parse args */
if (ac != 2
|| !ParseAddr(*av++, &self_new_allow)
|| !ParseAddr(*av++, &peer_new_allow))
return(-1);
ipcp->conf.self_allow = self_new_allow;
ipcp->conf.peer_allow = peer_new_allow;
#ifndef IA_CUSTOM
/* Can't accept peer having zero address */
if (ipcp->conf.peer_allow.ipaddr.s_addr == 0) {
Log(LG_ERR, ("[%s] IPCP: peer address cannot be zero", bund->name));
return(0);
}
#endif
}
break;
case SET_DNS:
ips = ipcp->conf.peer_dns;
goto getPrimSec;
break;
case SET_NBNS:
ips = ipcp->conf.peer_nbns;
getPrimSec:
if (!inet_aton(av[0], &ips[0])) {
Log(LG_ERR, ("[%s] %s: invalid IP address", bund->name, av[0]));
return(0);
}
ips[1].s_addr = 0;
if (ac > 1 && !inet_aton(av[1], &ips[1])) {
Log(LG_ERR, ("[%s] %s: invalid IP address", bund->name, av[1]));
return(0);
}
break;
case SET_ACCEPT:
AcceptCommand(ac, av, &ipcp->conf.options, gConfList);
break;
case SET_DENY:
DenyCommand(ac, av, &ipcp->conf.options, gConfList);
break;
case SET_ENABLE:
EnableCommand(ac, av, &ipcp->conf.options, gConfList);
break;
case SET_DISABLE:
DisableCommand(ac, av, &ipcp->conf.options, gConfList);
break;
case SET_YES:
YesCommand(ac, av, &ipcp->conf.options, gConfList);
break;
case SET_NO:
NoCommand(ac, av, &ipcp->conf.options, gConfList);
break;
default:
assert(0);
}
return(0);
}
syntax highlighted by Code2HTML, v. 0.9.1