📄 ipcp.c
字号:
//==========================================================================
//
// src/ipcp.c
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Portions created by Nick Garnett are
// Copyright (C) 2003 eCosCentric Ltd.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//####BSDCOPYRIGHTBEGIN####
//
// -------------------------------------------
//
// Portions of this software may have been derived from OpenBSD,
// FreeBSD or other sources, and are covered by the appropriate
// copyright disclaimers included herein.
//
// -------------------------------------------
//
//####BSDCOPYRIGHTEND####
//==========================================================================
/*
* 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[] = "$FreeBSD: src/usr.sbin/pppd/ipcp.c,v 1.12 1999/08/28 01:19:03 peter Exp $";
#endif
/*
* TODO:
*/
#include <stdio.h>
#include <string.h>
#include <cyg/ppp/syslog.h>
#include <netdb.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "cyg/ppp/pppd.h"
#include "cyg/ppp/fsm.h"
#include "cyg/ppp/ipcp.h"
#define option_error(msg) db_printf("Option error: %s\n", msg )
/* 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 */
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;
/* 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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -