2007-07-10 00:51:58 +04:00
|
|
|
/* $NetBSD: if_spppsubr.c,v 1.106 2007/07/09 21:11:00 ad Exp $ */
|
1999-04-04 10:57:03 +04:00
|
|
|
|
1999-03-25 06:38:00 +03:00
|
|
|
/*
|
|
|
|
* Synchronous PPP/Cisco link level subroutines.
|
|
|
|
* Keepalive protocol implemented in both Cisco and PPP modes.
|
|
|
|
*
|
1999-04-04 10:07:56 +04:00
|
|
|
* Copyright (C) 1994-1996 Cronyx Engineering Ltd.
|
|
|
|
* Author: Serge Vakulenko, <vak@cronyx.ru>
|
|
|
|
*
|
|
|
|
* Heavily revamped to conform to RFC 1661.
|
|
|
|
* Copyright (C) 1997, Joerg Wunsch.
|
1999-03-25 06:38:00 +03:00
|
|
|
*
|
2000-05-02 16:43:16 +04:00
|
|
|
* RFC2472 IPv6CP support.
|
|
|
|
* Copyright (C) 2000, Jun-ichiro itojun Hagino <itojun@iijlab.net>.
|
|
|
|
*
|
2002-09-27 10:20:30 +04:00
|
|
|
* 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.
|
1999-03-25 06:38:00 +03:00
|
|
|
*
|
2005-02-27 01:45:09 +03:00
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT ``AS IS'' AND ANY
|
|
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
2002-09-27 10:20:30 +04:00
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT 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)
|
2005-02-27 01:45:09 +03:00
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
2002-09-27 10:20:30 +04:00
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
1999-03-25 06:38:00 +03:00
|
|
|
*
|
1999-04-04 10:07:56 +04:00
|
|
|
* From: Version 2.4, Thu Apr 30 17:17:21 MSD 1997
|
|
|
|
*
|
|
|
|
* From: if_spppsubr.c,v 1.39 1998/04/04 13:26:03 phk Exp
|
|
|
|
*
|
1999-04-04 10:57:03 +04:00
|
|
|
* From: Id: if_spppsubr.c,v 1.23 1999/02/23 14:47:50 hm Exp
|
1999-03-25 06:38:00 +03:00
|
|
|
*/
|
|
|
|
|
2001-11-13 02:49:33 +03:00
|
|
|
#include <sys/cdefs.h>
|
2007-07-10 00:51:58 +04:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: if_spppsubr.c,v 1.106 2007/07/09 21:11:00 ad Exp $");
|
2001-11-13 02:49:33 +03:00
|
|
|
|
1999-03-25 06:38:00 +03:00
|
|
|
#include "opt_inet.h"
|
|
|
|
#include "opt_ipx.h"
|
1999-04-04 10:07:56 +04:00
|
|
|
#include "opt_iso.h"
|
2004-09-18 20:04:41 +04:00
|
|
|
#include "opt_pfil_hooks.h"
|
1999-03-25 06:38:00 +03:00
|
|
|
|
|
|
|
#include <sys/param.h>
|
2002-01-04 15:21:24 +03:00
|
|
|
#include <sys/proc.h>
|
1999-03-25 06:38:00 +03:00
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/kernel.h>
|
1999-04-04 10:07:56 +04:00
|
|
|
#include <sys/sockio.h>
|
1999-03-25 06:38:00 +03:00
|
|
|
#include <sys/socket.h>
|
1999-04-04 10:07:56 +04:00
|
|
|
#include <sys/syslog.h>
|
|
|
|
#include <sys/malloc.h>
|
1999-03-25 06:38:00 +03:00
|
|
|
#include <sys/mbuf.h>
|
2002-01-04 15:21:24 +03:00
|
|
|
#include <sys/callout.h>
|
1999-04-04 10:07:56 +04:00
|
|
|
#include <sys/md5.h>
|
2003-01-28 18:36:38 +03:00
|
|
|
#include <sys/inttypes.h>
|
2006-05-15 01:19:33 +04:00
|
|
|
#include <sys/kauth.h>
|
1999-04-04 10:07:56 +04:00
|
|
|
|
1999-03-25 06:38:00 +03:00
|
|
|
#include <net/if.h>
|
|
|
|
#include <net/netisr.h>
|
|
|
|
#include <net/if_types.h>
|
1999-04-04 10:07:56 +04:00
|
|
|
#include <net/route.h>
|
2000-07-02 21:38:09 +04:00
|
|
|
#include <net/ppp_defs.h>
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
#include <machine/stdarg.h>
|
1999-03-25 06:38:00 +03:00
|
|
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/in_systm.h>
|
|
|
|
#include <netinet/in_var.h>
|
2000-10-02 07:53:47 +04:00
|
|
|
#ifdef INET
|
1999-03-25 06:38:00 +03:00
|
|
|
#include <netinet/ip.h>
|
|
|
|
#include <netinet/tcp.h>
|
2000-10-02 07:53:47 +04:00
|
|
|
#endif
|
1999-04-04 10:07:56 +04:00
|
|
|
#include <net/ethertypes.h>
|
1999-03-25 06:38:00 +03:00
|
|
|
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
#ifdef INET6
|
|
|
|
#include <netinet6/scope6_var.h>
|
|
|
|
#endif
|
|
|
|
|
1999-03-25 06:38:00 +03:00
|
|
|
#ifdef IPX
|
|
|
|
#include <netipx/ipx.h>
|
|
|
|
#include <netipx/ipx_if.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef ISO
|
|
|
|
#include <netiso/argo_debug.h>
|
|
|
|
#include <netiso/iso.h>
|
|
|
|
#include <netiso/iso_var.h>
|
|
|
|
#include <netiso/iso_snpac.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <net/if_sppp.h>
|
2002-01-04 15:21:24 +03:00
|
|
|
#include <net/if_spppvar.h>
|
1999-03-25 06:38:00 +03:00
|
|
|
|
2003-09-04 00:48:46 +04:00
|
|
|
#define LCP_KEEPALIVE_INTERVAL 10 /* seconds between checks */
|
|
|
|
#define LOOPALIVECNT 3 /* loopback detection tries */
|
|
|
|
#define DEFAULT_MAXALIVECNT 3 /* max. missed alive packets */
|
|
|
|
#define DEFAULT_NORECV_TIME 15 /* before we get worried */
|
2002-01-07 13:49:02 +03:00
|
|
|
#define DEFAULT_MAX_AUTH_FAILURES 5 /* max. auth. failures */
|
1999-03-25 06:38:00 +03:00
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
/*
|
|
|
|
* Interface flags that can be set in an ifconfig command.
|
|
|
|
*
|
|
|
|
* Setting link0 will make the link passive, i.e. it will be marked
|
|
|
|
* as being administrative openable, but won't be opened to begin
|
|
|
|
* with. Incoming calls will be answered, or subsequent calls with
|
|
|
|
* -link1 will cause the administrative open of the LCP layer.
|
|
|
|
*
|
|
|
|
* Setting link1 will cause the link to auto-dial only as packets
|
|
|
|
* arrive to be sent.
|
|
|
|
*
|
|
|
|
* Setting IFF_DEBUG will syslog the option negotiation and state
|
|
|
|
* transitions at level kern.debug. Note: all logs consistently look
|
|
|
|
* like
|
|
|
|
*
|
|
|
|
* <if-name><unit>: <proto-name> <additional info...>
|
|
|
|
*
|
|
|
|
* with <if-name><unit> being something like "bppp0", and <proto-name>
|
|
|
|
* being one of "lcp", "ipcp", "cisco", "chap", "pap", etc.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define IFF_PASSIVE IFF_LINK0 /* wait passively for connection */
|
|
|
|
#define IFF_AUTO IFF_LINK1 /* auto-dial on output */
|
|
|
|
|
|
|
|
#define CONF_REQ 1 /* PPP configure request */
|
|
|
|
#define CONF_ACK 2 /* PPP configure acknowledge */
|
|
|
|
#define CONF_NAK 3 /* PPP configure negative ack */
|
|
|
|
#define CONF_REJ 4 /* PPP configure reject */
|
|
|
|
#define TERM_REQ 5 /* PPP terminate request */
|
|
|
|
#define TERM_ACK 6 /* PPP terminate acknowledge */
|
|
|
|
#define CODE_REJ 7 /* PPP code reject */
|
|
|
|
#define PROTO_REJ 8 /* PPP protocol reject */
|
|
|
|
#define ECHO_REQ 9 /* PPP echo request */
|
|
|
|
#define ECHO_REPLY 10 /* PPP echo reply */
|
|
|
|
#define DISC_REQ 11 /* PPP discard request */
|
|
|
|
|
|
|
|
#define LCP_OPT_MRU 1 /* maximum receive unit */
|
|
|
|
#define LCP_OPT_ASYNC_MAP 2 /* async control character map */
|
|
|
|
#define LCP_OPT_AUTH_PROTO 3 /* authentication protocol */
|
|
|
|
#define LCP_OPT_QUAL_PROTO 4 /* quality protocol */
|
|
|
|
#define LCP_OPT_MAGIC 5 /* magic number */
|
|
|
|
#define LCP_OPT_RESERVED 6 /* reserved */
|
|
|
|
#define LCP_OPT_PROTO_COMP 7 /* protocol field compression */
|
|
|
|
#define LCP_OPT_ADDR_COMP 8 /* address/control field compression */
|
|
|
|
|
|
|
|
#define IPCP_OPT_ADDRESSES 1 /* both IP addresses; deprecated */
|
2000-10-10 15:43:51 +04:00
|
|
|
#define IPCP_OPT_COMPRESSION 2 /* IP compression protocol */
|
1999-04-04 10:07:56 +04:00
|
|
|
#define IPCP_OPT_ADDRESS 3 /* local IP address */
|
2001-12-08 22:46:39 +03:00
|
|
|
#define IPCP_OPT_PRIMDNS 129 /* primary remote dns address */
|
|
|
|
#define IPCP_OPT_SECDNS 131 /* secondary remote dns address */
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2000-05-02 16:43:16 +04:00
|
|
|
#define IPV6CP_OPT_IFID 1 /* interface identifier */
|
|
|
|
#define IPV6CP_OPT_COMPRESSION 2 /* IPv6 compression protocol */
|
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
#define PAP_REQ 1 /* PAP name/password request */
|
|
|
|
#define PAP_ACK 2 /* PAP acknowledge */
|
|
|
|
#define PAP_NAK 3 /* PAP fail */
|
|
|
|
|
|
|
|
#define CHAP_CHALLENGE 1 /* CHAP challenge request */
|
|
|
|
#define CHAP_RESPONSE 2 /* CHAP challenge response */
|
|
|
|
#define CHAP_SUCCESS 3 /* CHAP response ok */
|
|
|
|
#define CHAP_FAILURE 4 /* CHAP response failed */
|
|
|
|
|
|
|
|
#define CHAP_MD5 5 /* hash algorithm - MD5 */
|
|
|
|
|
|
|
|
#define CISCO_MULTICAST 0x8f /* Cisco multicast address */
|
|
|
|
#define CISCO_UNICAST 0x0f /* Cisco unicast address */
|
|
|
|
#define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */
|
|
|
|
#define CISCO_ADDR_REQ 0 /* Cisco address request */
|
|
|
|
#define CISCO_ADDR_REPLY 1 /* Cisco address reply */
|
|
|
|
#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */
|
|
|
|
|
|
|
|
/* states are named and numbered according to RFC 1661 */
|
|
|
|
#define STATE_INITIAL 0
|
|
|
|
#define STATE_STARTING 1
|
|
|
|
#define STATE_CLOSED 2
|
|
|
|
#define STATE_STOPPED 3
|
|
|
|
#define STATE_CLOSING 4
|
|
|
|
#define STATE_STOPPING 5
|
|
|
|
#define STATE_REQ_SENT 6
|
|
|
|
#define STATE_ACK_RCVD 7
|
|
|
|
#define STATE_ACK_SENT 8
|
|
|
|
#define STATE_OPENED 9
|
1999-03-25 06:38:00 +03:00
|
|
|
|
|
|
|
struct ppp_header {
|
2003-09-06 03:02:40 +04:00
|
|
|
u_int8_t address;
|
|
|
|
u_int8_t control;
|
|
|
|
u_int16_t protocol;
|
1999-11-19 23:41:19 +03:00
|
|
|
} __attribute__((__packed__));
|
1999-03-25 06:38:00 +03:00
|
|
|
#define PPP_HEADER_LEN sizeof (struct ppp_header)
|
|
|
|
|
|
|
|
struct lcp_header {
|
2003-09-06 03:02:40 +04:00
|
|
|
u_int8_t type;
|
|
|
|
u_int8_t ident;
|
|
|
|
u_int16_t len;
|
1999-11-19 23:41:19 +03:00
|
|
|
} __attribute__((__packed__));
|
1999-03-25 06:38:00 +03:00
|
|
|
#define LCP_HEADER_LEN sizeof (struct lcp_header)
|
|
|
|
|
|
|
|
struct cisco_packet {
|
2001-12-05 00:32:15 +03:00
|
|
|
u_int32_t type;
|
|
|
|
u_int32_t par1;
|
|
|
|
u_int32_t par2;
|
2003-09-06 03:02:40 +04:00
|
|
|
u_int16_t rel;
|
|
|
|
u_int16_t time0;
|
|
|
|
u_int16_t time1;
|
1999-11-19 23:41:19 +03:00
|
|
|
} __attribute__((__packed__));
|
1999-03-25 06:38:00 +03:00
|
|
|
#define CISCO_PACKET_LEN 18
|
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
/*
|
|
|
|
* We follow the spelling and capitalization of RFC 1661 here, to make
|
|
|
|
* it easier comparing with the standard. Please refer to this RFC in
|
|
|
|
* case you can't make sense out of these abbreviation; it will also
|
|
|
|
* explain the semantics related to the various events and actions.
|
|
|
|
*/
|
|
|
|
struct cp {
|
|
|
|
u_short proto; /* PPP control protocol number */
|
|
|
|
u_char protoidx; /* index into state table in struct sppp */
|
|
|
|
u_char flags;
|
|
|
|
#define CP_LCP 0x01 /* this is the LCP */
|
|
|
|
#define CP_AUTH 0x02 /* this is an authentication protocol */
|
|
|
|
#define CP_NCP 0x04 /* this is a NCP */
|
|
|
|
#define CP_QUAL 0x08 /* this is a quality reporting protocol */
|
|
|
|
const char *name; /* name of this control protocol */
|
|
|
|
/* event handlers */
|
|
|
|
void (*Up)(struct sppp *sp);
|
|
|
|
void (*Down)(struct sppp *sp);
|
|
|
|
void (*Open)(struct sppp *sp);
|
|
|
|
void (*Close)(struct sppp *sp);
|
|
|
|
void (*TO)(void *sp);
|
|
|
|
int (*RCR)(struct sppp *sp, struct lcp_header *h, int len);
|
|
|
|
void (*RCN_rej)(struct sppp *sp, struct lcp_header *h, int len);
|
|
|
|
void (*RCN_nak)(struct sppp *sp, struct lcp_header *h, int len);
|
|
|
|
/* actions */
|
|
|
|
void (*tlu)(struct sppp *sp);
|
|
|
|
void (*tld)(struct sppp *sp);
|
|
|
|
void (*tls)(struct sppp *sp);
|
|
|
|
void (*tlf)(struct sppp *sp);
|
|
|
|
void (*scr)(struct sppp *sp);
|
|
|
|
};
|
|
|
|
|
1999-03-25 06:38:00 +03:00
|
|
|
static struct sppp *spppq;
|
2007-07-10 00:51:58 +04:00
|
|
|
static callout_t keepalive_ch;
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2000-10-02 07:53:47 +04:00
|
|
|
#ifdef INET
|
1999-03-25 06:38:00 +03:00
|
|
|
/*
|
|
|
|
* The following disgusting hack gets around the problem that IP TOS
|
|
|
|
* can't be set yet. We want to put "interactive" traffic on a high
|
|
|
|
* priority queue. To decide if traffic is interactive, we check that
|
|
|
|
* a) it is TCP and b) one of its ports is telnet, rlogin or ftp control.
|
1999-04-04 10:07:56 +04:00
|
|
|
*
|
|
|
|
* XXX is this really still necessary? - joerg -
|
1999-03-25 06:38:00 +03:00
|
|
|
*/
|
1999-04-04 10:07:56 +04:00
|
|
|
static u_short interactive_ports[8] = {
|
1999-03-25 06:38:00 +03:00
|
|
|
0, 513, 0, 0,
|
|
|
|
0, 21, 0, 23,
|
|
|
|
};
|
2002-09-25 11:24:06 +04:00
|
|
|
#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p))
|
2000-10-02 07:53:47 +04:00
|
|
|
#endif
|
1999-03-25 06:38:00 +03:00
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
/* almost every function needs these */
|
|
|
|
#define STDDCL \
|
|
|
|
struct ifnet *ifp = &sp->pp_if; \
|
|
|
|
int debug = ifp->if_flags & IFF_DEBUG
|
1999-03-25 06:38:00 +03:00
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
static int sppp_output(struct ifnet *ifp, struct mbuf *m,
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
const struct sockaddr *dst, struct rtentry *rt);
|
1999-03-25 06:38:00 +03:00
|
|
|
|
2001-12-05 00:32:15 +03:00
|
|
|
static void sppp_cisco_send(struct sppp *sp, int type, int32_t par1, int32_t par2);
|
1999-04-04 10:07:56 +04:00
|
|
|
static void sppp_cisco_input(struct sppp *sp, struct mbuf *m);
|
|
|
|
|
|
|
|
static void sppp_cp_input(const struct cp *cp, struct sppp *sp,
|
|
|
|
struct mbuf *m);
|
|
|
|
static void sppp_cp_send(struct sppp *sp, u_short proto, u_char type,
|
|
|
|
u_char ident, u_short len, void *data);
|
|
|
|
/* static void sppp_cp_timeout(void *arg); */
|
|
|
|
static void sppp_cp_change_state(const struct cp *cp, struct sppp *sp,
|
|
|
|
int newstate);
|
|
|
|
static void sppp_auth_send(const struct cp *cp,
|
|
|
|
struct sppp *sp, unsigned int type, unsigned int id,
|
|
|
|
...);
|
|
|
|
|
|
|
|
static void sppp_up_event(const struct cp *cp, struct sppp *sp);
|
|
|
|
static void sppp_down_event(const struct cp *cp, struct sppp *sp);
|
|
|
|
static void sppp_open_event(const struct cp *cp, struct sppp *sp);
|
|
|
|
static void sppp_close_event(const struct cp *cp, struct sppp *sp);
|
|
|
|
static void sppp_to_event(const struct cp *cp, struct sppp *sp);
|
|
|
|
|
|
|
|
static void sppp_null(struct sppp *sp);
|
|
|
|
|
|
|
|
static void sppp_lcp_init(struct sppp *sp);
|
|
|
|
static void sppp_lcp_up(struct sppp *sp);
|
|
|
|
static void sppp_lcp_down(struct sppp *sp);
|
|
|
|
static void sppp_lcp_open(struct sppp *sp);
|
|
|
|
static void sppp_lcp_close(struct sppp *sp);
|
|
|
|
static void sppp_lcp_TO(void *sp);
|
|
|
|
static int sppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len);
|
|
|
|
static void sppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len);
|
|
|
|
static void sppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len);
|
|
|
|
static void sppp_lcp_tlu(struct sppp *sp);
|
|
|
|
static void sppp_lcp_tld(struct sppp *sp);
|
|
|
|
static void sppp_lcp_tls(struct sppp *sp);
|
|
|
|
static void sppp_lcp_tlf(struct sppp *sp);
|
|
|
|
static void sppp_lcp_scr(struct sppp *sp);
|
|
|
|
static void sppp_lcp_check_and_close(struct sppp *sp);
|
|
|
|
static int sppp_ncp_check(struct sppp *sp);
|
|
|
|
|
|
|
|
static void sppp_ipcp_init(struct sppp *sp);
|
|
|
|
static void sppp_ipcp_up(struct sppp *sp);
|
|
|
|
static void sppp_ipcp_down(struct sppp *sp);
|
|
|
|
static void sppp_ipcp_open(struct sppp *sp);
|
|
|
|
static void sppp_ipcp_close(struct sppp *sp);
|
|
|
|
static void sppp_ipcp_TO(void *sp);
|
|
|
|
static int sppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len);
|
|
|
|
static void sppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len);
|
|
|
|
static void sppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len);
|
|
|
|
static void sppp_ipcp_tlu(struct sppp *sp);
|
|
|
|
static void sppp_ipcp_tld(struct sppp *sp);
|
|
|
|
static void sppp_ipcp_tls(struct sppp *sp);
|
|
|
|
static void sppp_ipcp_tlf(struct sppp *sp);
|
|
|
|
static void sppp_ipcp_scr(struct sppp *sp);
|
|
|
|
|
2000-05-02 16:43:16 +04:00
|
|
|
static void sppp_ipv6cp_init(struct sppp *sp);
|
|
|
|
static void sppp_ipv6cp_up(struct sppp *sp);
|
|
|
|
static void sppp_ipv6cp_down(struct sppp *sp);
|
|
|
|
static void sppp_ipv6cp_open(struct sppp *sp);
|
|
|
|
static void sppp_ipv6cp_close(struct sppp *sp);
|
|
|
|
static void sppp_ipv6cp_TO(void *sp);
|
|
|
|
static int sppp_ipv6cp_RCR(struct sppp *sp, struct lcp_header *h, int len);
|
|
|
|
static void sppp_ipv6cp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len);
|
|
|
|
static void sppp_ipv6cp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len);
|
|
|
|
static void sppp_ipv6cp_tlu(struct sppp *sp);
|
|
|
|
static void sppp_ipv6cp_tld(struct sppp *sp);
|
|
|
|
static void sppp_ipv6cp_tls(struct sppp *sp);
|
|
|
|
static void sppp_ipv6cp_tlf(struct sppp *sp);
|
|
|
|
static void sppp_ipv6cp_scr(struct sppp *sp);
|
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
static void sppp_pap_input(struct sppp *sp, struct mbuf *m);
|
|
|
|
static void sppp_pap_init(struct sppp *sp);
|
|
|
|
static void sppp_pap_open(struct sppp *sp);
|
|
|
|
static void sppp_pap_close(struct sppp *sp);
|
|
|
|
static void sppp_pap_TO(void *sp);
|
|
|
|
static void sppp_pap_my_TO(void *sp);
|
|
|
|
static void sppp_pap_tlu(struct sppp *sp);
|
|
|
|
static void sppp_pap_tld(struct sppp *sp);
|
|
|
|
static void sppp_pap_scr(struct sppp *sp);
|
|
|
|
|
|
|
|
static void sppp_chap_input(struct sppp *sp, struct mbuf *m);
|
|
|
|
static void sppp_chap_init(struct sppp *sp);
|
|
|
|
static void sppp_chap_open(struct sppp *sp);
|
|
|
|
static void sppp_chap_close(struct sppp *sp);
|
|
|
|
static void sppp_chap_TO(void *sp);
|
|
|
|
static void sppp_chap_tlu(struct sppp *sp);
|
|
|
|
static void sppp_chap_tld(struct sppp *sp);
|
|
|
|
static void sppp_chap_scr(struct sppp *sp);
|
|
|
|
|
|
|
|
static const char *sppp_auth_type_name(u_short proto, u_char type);
|
|
|
|
static const char *sppp_cp_type_name(u_char type);
|
2001-12-05 00:32:15 +03:00
|
|
|
static const char *sppp_dotted_quad(u_int32_t addr);
|
1999-04-04 10:07:56 +04:00
|
|
|
static const char *sppp_ipcp_opt_name(u_char opt);
|
2000-05-02 16:43:16 +04:00
|
|
|
#ifdef INET6
|
|
|
|
static const char *sppp_ipv6cp_opt_name(u_char opt);
|
|
|
|
#endif
|
1999-04-04 10:07:56 +04:00
|
|
|
static const char *sppp_lcp_opt_name(u_char opt);
|
2002-01-04 15:21:24 +03:00
|
|
|
static const char *sppp_phase_name(int phase);
|
1999-04-04 10:07:56 +04:00
|
|
|
static const char *sppp_proto_name(u_short proto);
|
|
|
|
static const char *sppp_state_name(int state);
|
|
|
|
static int sppp_params(struct sppp *sp, int cmd, void *data);
|
2004-12-06 05:59:23 +03:00
|
|
|
#ifdef INET
|
2001-12-05 00:32:15 +03:00
|
|
|
static void sppp_get_ip_addrs(struct sppp *sp, u_int32_t *src, u_int32_t *dst,
|
|
|
|
u_int32_t *srcmask);
|
2004-12-06 05:59:23 +03:00
|
|
|
static void sppp_set_ip_addrs(struct sppp *sp, u_int32_t myaddr, u_int32_t hisaddr);
|
|
|
|
static void sppp_clear_ip_addrs(struct sppp *sp);
|
|
|
|
#endif
|
1999-04-04 10:07:56 +04:00
|
|
|
static void sppp_keepalive(void *dummy);
|
|
|
|
static void sppp_phase_network(struct sppp *sp);
|
|
|
|
static void sppp_print_bytes(const u_char *p, u_short len);
|
|
|
|
static void sppp_print_string(const char *p, u_short len);
|
2000-05-02 16:43:16 +04:00
|
|
|
#ifdef INET6
|
|
|
|
static void sppp_get_ip6_addrs(struct sppp *sp, struct in6_addr *src,
|
|
|
|
struct in6_addr *dst, struct in6_addr *srcmask);
|
|
|
|
#ifdef IPV6CP_MYIFID_DYN
|
|
|
|
static void sppp_set_ip6_addr(struct sppp *sp, const struct in6_addr *src);
|
|
|
|
static void sppp_gen_ip6_addr(struct sppp *sp, const struct in6_addr *src);
|
|
|
|
#endif
|
|
|
|
static void sppp_suggest_ip6_addr(struct sppp *sp, struct in6_addr *src);
|
|
|
|
#endif
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
/* our control protocol descriptors */
|
|
|
|
static const struct cp lcp = {
|
|
|
|
PPP_LCP, IDX_LCP, CP_LCP, "lcp",
|
|
|
|
sppp_lcp_up, sppp_lcp_down, sppp_lcp_open, sppp_lcp_close,
|
|
|
|
sppp_lcp_TO, sppp_lcp_RCR, sppp_lcp_RCN_rej, sppp_lcp_RCN_nak,
|
|
|
|
sppp_lcp_tlu, sppp_lcp_tld, sppp_lcp_tls, sppp_lcp_tlf,
|
|
|
|
sppp_lcp_scr
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct cp ipcp = {
|
2001-01-16 18:28:27 +03:00
|
|
|
PPP_IPCP, IDX_IPCP,
|
|
|
|
#ifdef INET
|
|
|
|
CP_NCP, /*don't run IPCP if there's no IPv4 support*/
|
|
|
|
#else
|
|
|
|
0,
|
|
|
|
#endif
|
|
|
|
"ipcp",
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_ipcp_up, sppp_ipcp_down, sppp_ipcp_open, sppp_ipcp_close,
|
|
|
|
sppp_ipcp_TO, sppp_ipcp_RCR, sppp_ipcp_RCN_rej, sppp_ipcp_RCN_nak,
|
|
|
|
sppp_ipcp_tlu, sppp_ipcp_tld, sppp_ipcp_tls, sppp_ipcp_tlf,
|
|
|
|
sppp_ipcp_scr
|
|
|
|
};
|
|
|
|
|
2000-05-02 16:43:16 +04:00
|
|
|
static const struct cp ipv6cp = {
|
|
|
|
PPP_IPV6CP, IDX_IPV6CP,
|
|
|
|
#ifdef INET6 /*don't run IPv6CP if there's no IPv6 support*/
|
|
|
|
CP_NCP,
|
|
|
|
#else
|
|
|
|
0,
|
|
|
|
#endif
|
|
|
|
"ipv6cp",
|
|
|
|
sppp_ipv6cp_up, sppp_ipv6cp_down, sppp_ipv6cp_open, sppp_ipv6cp_close,
|
|
|
|
sppp_ipv6cp_TO, sppp_ipv6cp_RCR, sppp_ipv6cp_RCN_rej, sppp_ipv6cp_RCN_nak,
|
|
|
|
sppp_ipv6cp_tlu, sppp_ipv6cp_tld, sppp_ipv6cp_tls, sppp_ipv6cp_tlf,
|
|
|
|
sppp_ipv6cp_scr
|
|
|
|
};
|
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
static const struct cp pap = {
|
|
|
|
PPP_PAP, IDX_PAP, CP_AUTH, "pap",
|
|
|
|
sppp_null, sppp_null, sppp_pap_open, sppp_pap_close,
|
|
|
|
sppp_pap_TO, 0, 0, 0,
|
|
|
|
sppp_pap_tlu, sppp_pap_tld, sppp_null, sppp_null,
|
|
|
|
sppp_pap_scr
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct cp chap = {
|
|
|
|
PPP_CHAP, IDX_CHAP, CP_AUTH, "chap",
|
|
|
|
sppp_null, sppp_null, sppp_chap_open, sppp_chap_close,
|
|
|
|
sppp_chap_TO, 0, 0, 0,
|
|
|
|
sppp_chap_tlu, sppp_chap_tld, sppp_null, sppp_null,
|
|
|
|
sppp_chap_scr
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct cp *cps[IDX_COUNT] = {
|
|
|
|
&lcp, /* IDX_LCP */
|
|
|
|
&ipcp, /* IDX_IPCP */
|
2000-05-02 16:43:16 +04:00
|
|
|
&ipv6cp, /* IDX_IPV6CP */
|
1999-04-04 10:07:56 +04:00
|
|
|
&pap, /* IDX_PAP */
|
|
|
|
&chap, /* IDX_CHAP */
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2006-04-20 21:03:35 +04:00
|
|
|
void spppattach(int);
|
|
|
|
void
|
|
|
|
/*ARGSUSED*/
|
2006-11-16 04:32:37 +03:00
|
|
|
spppattach(int count)
|
2006-04-20 21:03:35 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2002-01-19 01:39:12 +03:00
|
|
|
/*
|
1999-04-04 10:07:56 +04:00
|
|
|
* Exported functions, comprising our interface to the lower layer.
|
|
|
|
*/
|
1999-03-25 06:38:00 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Process the received packet.
|
|
|
|
*/
|
1999-04-04 10:07:56 +04:00
|
|
|
void
|
|
|
|
sppp_input(struct ifnet *ifp, struct mbuf *m)
|
1999-03-25 06:38:00 +03:00
|
|
|
{
|
2001-04-09 23:33:01 +04:00
|
|
|
struct ppp_header *h = NULL;
|
1999-03-25 06:38:00 +03:00
|
|
|
struct ifqueue *inq = 0;
|
2001-04-09 23:33:01 +04:00
|
|
|
u_int16_t protocol;
|
1999-03-25 06:38:00 +03:00
|
|
|
int s;
|
1999-04-04 10:07:56 +04:00
|
|
|
struct sppp *sp = (struct sppp *)ifp;
|
|
|
|
int debug = ifp->if_flags & IFF_DEBUG;
|
1999-03-25 06:38:00 +03:00
|
|
|
|
2003-09-04 00:48:46 +04:00
|
|
|
if (ifp->if_flags & IFF_UP) {
|
2001-04-09 23:33:01 +04:00
|
|
|
/* Count received bytes, add hardware framing */
|
|
|
|
ifp->if_ibytes += m->m_pkthdr.len + sp->pp_framebytes;
|
2003-09-04 00:48:46 +04:00
|
|
|
/* Note time of last receive */
|
2006-06-08 02:33:33 +04:00
|
|
|
sp->pp_last_receive = time_uptime;
|
2003-09-04 00:48:46 +04:00
|
|
|
}
|
1999-03-25 06:38:00 +03:00
|
|
|
|
|
|
|
if (m->m_pkthdr.len <= PPP_HEADER_LEN) {
|
|
|
|
/* Too small packet, drop it. */
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug)
|
|
|
|
log(LOG_DEBUG,
|
2003-05-15 02:41:40 +04:00
|
|
|
"%s: input packet is too small, %d bytes\n",
|
|
|
|
ifp->if_xname, m->m_pkthdr.len);
|
1999-04-04 10:07:56 +04:00
|
|
|
drop:
|
|
|
|
++ifp->if_ierrors;
|
|
|
|
++ifp->if_iqdrops;
|
2002-09-25 11:24:06 +04:00
|
|
|
m_freem(m);
|
1999-03-25 06:38:00 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-04-09 23:33:01 +04:00
|
|
|
if (sp->pp_flags & PP_NOFRAMING) {
|
2001-12-05 00:32:15 +03:00
|
|
|
memcpy(&protocol, mtod(m, void *), 2);
|
2001-04-09 23:33:01 +04:00
|
|
|
protocol = ntohs(protocol);
|
|
|
|
m_adj(m, 2);
|
|
|
|
} else {
|
1999-03-25 06:38:00 +03:00
|
|
|
|
2001-04-09 23:33:01 +04:00
|
|
|
/* Get PPP header. */
|
2002-09-25 11:24:06 +04:00
|
|
|
h = mtod(m, struct ppp_header *);
|
|
|
|
m_adj(m, PPP_HEADER_LEN);
|
2001-04-09 23:33:01 +04:00
|
|
|
|
|
|
|
switch (h->address) {
|
|
|
|
case PPP_ALLSTATIONS:
|
|
|
|
if (h->control != PPP_UI)
|
|
|
|
goto invalid;
|
|
|
|
if (sp->pp_flags & PP_CISCO) {
|
|
|
|
if (debug)
|
|
|
|
log(LOG_DEBUG,
|
2003-05-15 02:41:40 +04:00
|
|
|
"%s: PPP packet in Cisco mode "
|
2001-04-09 23:33:01 +04:00
|
|
|
"<addr=0x%x ctrl=0x%x proto=0x%x>\n",
|
2003-05-15 02:41:40 +04:00
|
|
|
ifp->if_xname,
|
2001-04-09 23:33:01 +04:00
|
|
|
h->address, h->control, ntohs(h->protocol));
|
|
|
|
goto drop;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CISCO_MULTICAST:
|
|
|
|
case CISCO_UNICAST:
|
|
|
|
/* Don't check the control field here (RFC 1547). */
|
|
|
|
if (! (sp->pp_flags & PP_CISCO)) {
|
|
|
|
if (debug)
|
|
|
|
log(LOG_DEBUG,
|
2003-05-15 02:41:40 +04:00
|
|
|
"%s: Cisco packet in PPP mode "
|
2001-04-09 23:33:01 +04:00
|
|
|
"<addr=0x%x ctrl=0x%x proto=0x%x>\n",
|
2003-05-15 02:41:40 +04:00
|
|
|
ifp->if_xname,
|
2001-04-09 23:33:01 +04:00
|
|
|
h->address, h->control, ntohs(h->protocol));
|
|
|
|
goto drop;
|
|
|
|
}
|
2002-09-25 11:24:06 +04:00
|
|
|
switch (ntohs(h->protocol)) {
|
2001-04-09 23:33:01 +04:00
|
|
|
default:
|
|
|
|
++ifp->if_noproto;
|
|
|
|
goto invalid;
|
|
|
|
case CISCO_KEEPALIVE:
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_cisco_input((struct sppp *) ifp, m);
|
|
|
|
m_freem(m);
|
2001-04-09 23:33:01 +04:00
|
|
|
return;
|
1999-03-25 06:38:00 +03:00
|
|
|
#ifdef INET
|
2001-04-09 23:33:01 +04:00
|
|
|
case ETHERTYPE_IP:
|
2002-09-25 11:24:06 +04:00
|
|
|
schednetisr(NETISR_IP);
|
1999-03-25 06:38:00 +03:00
|
|
|
inq = &ipintrq;
|
2001-04-09 23:33:01 +04:00
|
|
|
break;
|
1999-03-25 06:38:00 +03:00
|
|
|
#endif
|
2000-04-12 14:51:15 +04:00
|
|
|
#ifdef INET6
|
2001-04-09 23:33:01 +04:00
|
|
|
case ETHERTYPE_IPV6:
|
2002-09-25 11:24:06 +04:00
|
|
|
schednetisr(NETISR_IPV6);
|
2000-04-12 14:51:15 +04:00
|
|
|
inq = &ip6intrq;
|
2001-04-09 23:33:01 +04:00
|
|
|
break;
|
2000-04-12 14:51:15 +04:00
|
|
|
#endif
|
1999-03-25 06:38:00 +03:00
|
|
|
#ifdef IPX
|
2001-04-09 23:33:01 +04:00
|
|
|
case ETHERTYPE_IPX:
|
2002-09-25 11:24:06 +04:00
|
|
|
schednetisr(NETISR_IPX);
|
1999-03-25 06:38:00 +03:00
|
|
|
inq = &ipxintrq;
|
2001-04-09 23:33:01 +04:00
|
|
|
break;
|
1999-03-25 06:38:00 +03:00
|
|
|
#endif
|
|
|
|
}
|
2001-04-09 23:33:01 +04:00
|
|
|
goto queue_pkt;
|
|
|
|
default: /* Invalid PPP packet. */
|
|
|
|
invalid:
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug)
|
|
|
|
log(LOG_DEBUG,
|
2003-05-15 02:41:40 +04:00
|
|
|
"%s: invalid input packet "
|
1999-04-04 10:07:56 +04:00
|
|
|
"<addr=0x%x ctrl=0x%x proto=0x%x>\n",
|
2003-05-15 02:41:40 +04:00
|
|
|
ifp->if_xname,
|
1999-04-04 10:07:56 +04:00
|
|
|
h->address, h->control, ntohs(h->protocol));
|
1999-03-25 06:38:00 +03:00
|
|
|
goto drop;
|
|
|
|
}
|
2002-09-25 11:24:06 +04:00
|
|
|
protocol = ntohs(h->protocol);
|
2001-04-09 23:33:01 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (protocol) {
|
|
|
|
default:
|
|
|
|
if (sp->state[IDX_LCP] == STATE_OPENED) {
|
|
|
|
u_int16_t prot = htons(protocol);
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_cp_send(sp, PPP_LCP, PROTO_REJ,
|
2001-04-09 23:33:01 +04:00
|
|
|
++sp->pp_seq[IDX_LCP], m->m_pkthdr.len + 2,
|
|
|
|
&prot);
|
|
|
|
}
|
|
|
|
if (debug)
|
|
|
|
log(LOG_DEBUG,
|
2003-05-15 02:41:40 +04:00
|
|
|
"%s: invalid input protocol "
|
|
|
|
"<proto=0x%x>\n", ifp->if_xname, ntohs(protocol));
|
2001-04-09 23:33:01 +04:00
|
|
|
++ifp->if_noproto;
|
|
|
|
goto drop;
|
|
|
|
case PPP_LCP:
|
|
|
|
sppp_cp_input(&lcp, sp, m);
|
2002-09-25 11:24:06 +04:00
|
|
|
m_freem(m);
|
2001-04-09 23:33:01 +04:00
|
|
|
return;
|
|
|
|
case PPP_PAP:
|
2002-01-04 15:21:24 +03:00
|
|
|
if (sp->pp_phase >= SPPP_PHASE_AUTHENTICATE)
|
2001-04-09 23:33:01 +04:00
|
|
|
sppp_pap_input(sp, m);
|
2002-09-25 11:24:06 +04:00
|
|
|
m_freem(m);
|
2001-04-09 23:33:01 +04:00
|
|
|
return;
|
|
|
|
case PPP_CHAP:
|
2002-01-04 15:21:24 +03:00
|
|
|
if (sp->pp_phase >= SPPP_PHASE_AUTHENTICATE)
|
2001-04-09 23:33:01 +04:00
|
|
|
sppp_chap_input(sp, m);
|
2002-09-25 11:24:06 +04:00
|
|
|
m_freem(m);
|
2001-04-09 23:33:01 +04:00
|
|
|
return;
|
1999-03-25 06:38:00 +03:00
|
|
|
#ifdef INET
|
2001-04-09 23:33:01 +04:00
|
|
|
case PPP_IPCP:
|
2002-01-04 15:21:24 +03:00
|
|
|
if (sp->pp_phase == SPPP_PHASE_NETWORK)
|
2001-04-09 23:33:01 +04:00
|
|
|
sppp_cp_input(&ipcp, sp, m);
|
2002-09-25 11:24:06 +04:00
|
|
|
m_freem(m);
|
2001-04-09 23:33:01 +04:00
|
|
|
return;
|
|
|
|
case PPP_IP:
|
|
|
|
if (sp->state[IDX_IPCP] == STATE_OPENED) {
|
2002-09-25 11:24:06 +04:00
|
|
|
schednetisr(NETISR_IP);
|
1999-03-25 06:38:00 +03:00
|
|
|
inq = &ipintrq;
|
2006-06-08 02:33:33 +04:00
|
|
|
sp->pp_last_activity = time_uptime;
|
2001-04-09 23:33:01 +04:00
|
|
|
}
|
|
|
|
break;
|
1999-03-25 06:38:00 +03:00
|
|
|
#endif
|
2000-04-12 14:51:15 +04:00
|
|
|
#ifdef INET6
|
2001-04-09 23:33:01 +04:00
|
|
|
case PPP_IPV6CP:
|
2002-01-04 15:21:24 +03:00
|
|
|
if (sp->pp_phase == SPPP_PHASE_NETWORK)
|
2001-04-09 23:33:01 +04:00
|
|
|
sppp_cp_input(&ipv6cp, sp, m);
|
2002-09-25 11:24:06 +04:00
|
|
|
m_freem(m);
|
2001-04-09 23:33:01 +04:00
|
|
|
return;
|
|
|
|
|
|
|
|
case PPP_IPV6:
|
|
|
|
if (sp->state[IDX_IPV6CP] == STATE_OPENED) {
|
2002-09-25 11:24:06 +04:00
|
|
|
schednetisr(NETISR_IPV6);
|
2000-04-12 14:51:15 +04:00
|
|
|
inq = &ip6intrq;
|
2006-06-08 02:33:33 +04:00
|
|
|
sp->pp_last_activity = time_uptime;
|
2001-04-09 23:33:01 +04:00
|
|
|
}
|
|
|
|
break;
|
2000-04-12 14:51:15 +04:00
|
|
|
#endif
|
1999-03-25 06:38:00 +03:00
|
|
|
#ifdef IPX
|
2001-04-09 23:33:01 +04:00
|
|
|
case PPP_IPX:
|
|
|
|
/* IPX IPXCP not implemented yet */
|
2002-01-04 15:21:24 +03:00
|
|
|
if (sp->pp_phase == SPPP_PHASE_NETWORK) {
|
2002-09-25 11:24:06 +04:00
|
|
|
schednetisr(NETISR_IPX);
|
1999-03-25 06:38:00 +03:00
|
|
|
inq = &ipxintrq;
|
2001-04-09 23:33:01 +04:00
|
|
|
}
|
|
|
|
break;
|
1999-03-25 06:38:00 +03:00
|
|
|
#endif
|
2001-04-09 23:33:01 +04:00
|
|
|
#ifdef ISO
|
|
|
|
case PPP_ISO:
|
|
|
|
/* OSI NLCP not implemented yet */
|
2002-01-04 15:21:24 +03:00
|
|
|
if (sp->pp_phase == SPPP_PHASE_NETWORK) {
|
2002-09-25 11:24:06 +04:00
|
|
|
schednetisr(NETISR_ISO);
|
2001-04-09 23:33:01 +04:00
|
|
|
inq = &clnlintrq;
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
|
|
|
break;
|
2001-04-09 23:33:01 +04:00
|
|
|
#endif
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
|
|
|
|
2001-04-09 23:33:01 +04:00
|
|
|
queue_pkt:
|
1999-03-25 06:38:00 +03:00
|
|
|
if (! (ifp->if_flags & IFF_UP) || ! inq)
|
|
|
|
goto drop;
|
|
|
|
|
|
|
|
/* Check queue. */
|
2001-04-14 03:29:55 +04:00
|
|
|
s = splnet();
|
2002-09-25 11:24:06 +04:00
|
|
|
if (IF_QFULL(inq)) {
|
1999-03-25 06:38:00 +03:00
|
|
|
/* Queue overflow. */
|
1999-04-04 10:07:56 +04:00
|
|
|
IF_DROP(inq);
|
|
|
|
splx(s);
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: protocol queue overflow\n",
|
|
|
|
ifp->if_xname);
|
1999-03-25 06:38:00 +03:00
|
|
|
goto drop;
|
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
IF_ENQUEUE(inq, m);
|
|
|
|
splx(s);
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Enqueue transmit packet.
|
|
|
|
*/
|
|
|
|
static int
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_output(struct ifnet *ifp, struct mbuf *m,
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
const struct sockaddr *dst, struct rtentry *rt)
|
1999-03-25 06:38:00 +03:00
|
|
|
{
|
2002-09-25 11:24:06 +04:00
|
|
|
struct sppp *sp = (struct sppp *) ifp;
|
2001-04-09 23:33:01 +04:00
|
|
|
struct ppp_header *h = NULL;
|
2000-12-14 01:07:50 +03:00
|
|
|
struct ifqueue *ifq = NULL; /* XXX */
|
2005-03-31 19:48:13 +04:00
|
|
|
int s, error = 0;
|
2001-04-09 23:33:01 +04:00
|
|
|
u_int16_t protocol;
|
2000-12-14 01:07:50 +03:00
|
|
|
ALTQ_DECL(struct altq_pktattr pktattr;)
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2001-04-14 03:29:55 +04:00
|
|
|
s = splnet();
|
1999-03-25 06:38:00 +03:00
|
|
|
|
2006-06-08 02:33:33 +04:00
|
|
|
sp->pp_last_activity = time_uptime;
|
2002-01-06 23:14:29 +03:00
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
if ((ifp->if_flags & IFF_UP) == 0 ||
|
|
|
|
(ifp->if_flags & (IFF_RUNNING | IFF_AUTO)) == 0) {
|
2002-09-25 11:24:06 +04:00
|
|
|
m_freem(m);
|
|
|
|
splx(s);
|
1999-03-25 06:38:00 +03:00
|
|
|
return (ENETDOWN);
|
|
|
|
}
|
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
if ((ifp->if_flags & (IFF_RUNNING | IFF_AUTO)) == IFF_AUTO) {
|
|
|
|
/*
|
|
|
|
* Interface is not yet running, but auto-dial. Need
|
|
|
|
* to start LCP for it.
|
|
|
|
*/
|
|
|
|
ifp->if_flags |= IFF_RUNNING;
|
|
|
|
splx(s);
|
|
|
|
lcp.Open(sp);
|
2001-04-14 03:29:55 +04:00
|
|
|
s = splnet();
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
|
2000-12-14 01:07:50 +03:00
|
|
|
/*
|
|
|
|
* If the queueing discipline needs packet classification,
|
|
|
|
* do it before prepending link headers.
|
|
|
|
*/
|
|
|
|
IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
|
1999-04-04 10:07:56 +04:00
|
|
|
|
1999-03-25 06:38:00 +03:00
|
|
|
#ifdef INET
|
2002-07-06 22:33:45 +04:00
|
|
|
if (dst->sa_family == AF_INET) {
|
|
|
|
struct ip *ip = NULL;
|
|
|
|
struct tcphdr *th = NULL;
|
|
|
|
|
|
|
|
if (m->m_len >= sizeof(struct ip)) {
|
2002-09-25 11:24:06 +04:00
|
|
|
ip = mtod(m, struct ip *);
|
2002-07-06 22:33:45 +04:00
|
|
|
if (ip->ip_p == IPPROTO_TCP &&
|
|
|
|
m->m_len >= sizeof(struct ip) + (ip->ip_hl << 2) +
|
|
|
|
sizeof(struct tcphdr)) {
|
|
|
|
th = (struct tcphdr *)
|
2007-03-04 08:59:00 +03:00
|
|
|
((char *)ip + (ip->ip_hl << 2));
|
2002-07-06 22:33:45 +04:00
|
|
|
}
|
|
|
|
} else
|
|
|
|
ip = NULL;
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* When using dynamic local IP address assignment by using
|
|
|
|
* 0.0.0.0 as a local address, the first TCP session will
|
|
|
|
* not connect because the local TCP checksum is computed
|
|
|
|
* using 0.0.0.0 which will later become our real IP address
|
|
|
|
* so the TCP checksum computed at the remote end will
|
|
|
|
* become invalid. So we
|
|
|
|
* - don't let packets with src ip addr 0 thru
|
|
|
|
* - we flag TCP packets with src ip 0 as an error
|
2005-02-27 01:45:09 +03:00
|
|
|
*/
|
2002-07-06 22:33:45 +04:00
|
|
|
if (ip && ip->ip_src.s_addr == INADDR_ANY) {
|
2002-07-12 01:21:53 +04:00
|
|
|
u_int8_t proto = ip->ip_p;
|
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
m_freem(m);
|
|
|
|
splx(s);
|
2002-07-12 01:21:53 +04:00
|
|
|
if (proto == IPPROTO_TCP)
|
2002-09-11 09:36:26 +04:00
|
|
|
return (EADDRNOTAVAIL);
|
1999-04-04 10:07:56 +04:00
|
|
|
else
|
2002-09-11 09:36:26 +04:00
|
|
|
return (0);
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
2005-02-27 01:45:09 +03:00
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
/*
|
|
|
|
* Put low delay, telnet, rlogin and ftp control packets
|
|
|
|
* in front of the queue.
|
|
|
|
*/
|
2005-02-27 01:45:09 +03:00
|
|
|
|
2002-07-06 22:33:45 +04:00
|
|
|
if (!IF_QFULL(&sp->pp_fastq) &&
|
|
|
|
((ip && (ip->ip_tos & IPTOS_LOWDELAY)) ||
|
|
|
|
(th && (INTERACTIVE(ntohs(th->th_sport)) ||
|
|
|
|
INTERACTIVE(ntohs(th->th_dport))))))
|
1999-03-25 06:38:00 +03:00
|
|
|
ifq = &sp->pp_fastq;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1999-07-30 14:35:34 +04:00
|
|
|
#ifdef INET6
|
|
|
|
if (dst->sa_family == AF_INET6) {
|
|
|
|
/* XXX do something tricky here? */
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2001-04-09 23:33:01 +04:00
|
|
|
if ((sp->pp_flags & PP_NOFRAMING) == 0) {
|
|
|
|
/*
|
|
|
|
* Prepend general data packet PPP header. For now, IP only.
|
|
|
|
*/
|
2002-09-25 11:24:06 +04:00
|
|
|
M_PREPEND(m, PPP_HEADER_LEN, M_DONTWAIT);
|
2001-04-09 23:33:01 +04:00
|
|
|
if (! m) {
|
|
|
|
if (ifp->if_flags & IFF_DEBUG)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: no memory for transmit header\n",
|
|
|
|
ifp->if_xname);
|
2001-04-09 23:33:01 +04:00
|
|
|
++ifp->if_oerrors;
|
2002-09-25 11:24:06 +04:00
|
|
|
splx(s);
|
2001-04-09 23:33:01 +04:00
|
|
|
return (ENOBUFS);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* May want to check size of packet
|
|
|
|
* (albeit due to the implementation it's always enough)
|
|
|
|
*/
|
2002-09-25 11:24:06 +04:00
|
|
|
h = mtod(m, struct ppp_header *);
|
2001-04-09 23:33:01 +04:00
|
|
|
if (sp->pp_flags & PP_CISCO) {
|
|
|
|
h->address = CISCO_UNICAST; /* unicast address */
|
|
|
|
h->control = 0;
|
|
|
|
} else {
|
|
|
|
h->address = PPP_ALLSTATIONS; /* broadcast address */
|
|
|
|
h->control = PPP_UI; /* Unnumbered Info */
|
|
|
|
}
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (dst->sa_family) {
|
|
|
|
#ifdef INET
|
|
|
|
case AF_INET: /* Internet Protocol */
|
|
|
|
if (sp->pp_flags & PP_CISCO)
|
2002-09-25 11:24:06 +04:00
|
|
|
protocol = htons(ETHERTYPE_IP);
|
1999-03-25 06:38:00 +03:00
|
|
|
else {
|
1999-04-04 10:07:56 +04:00
|
|
|
/*
|
|
|
|
* Don't choke with an ENETDOWN early. It's
|
|
|
|
* possible that we just started dialing out,
|
|
|
|
* so don't drop the packet immediately. If
|
|
|
|
* we notice that we run out of buffer space
|
|
|
|
* below, we will however remember that we are
|
|
|
|
* not ready to carry IP packets, and return
|
|
|
|
* ENETDOWN, as opposed to ENOBUFS.
|
|
|
|
*/
|
2001-04-09 23:33:01 +04:00
|
|
|
protocol = htons(PPP_IP);
|
1999-04-04 10:07:56 +04:00
|
|
|
if (sp->state[IDX_IPCP] != STATE_OPENED)
|
2005-03-31 19:48:13 +04:00
|
|
|
error = ENETDOWN;
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
#endif
|
1999-07-30 14:35:34 +04:00
|
|
|
#ifdef INET6
|
|
|
|
case AF_INET6: /* Internet Protocol version 6 */
|
|
|
|
if (sp->pp_flags & PP_CISCO)
|
2002-09-25 11:24:06 +04:00
|
|
|
protocol = htons(ETHERTYPE_IPV6);
|
1999-07-30 14:35:34 +04:00
|
|
|
else {
|
|
|
|
/*
|
|
|
|
* Don't choke with an ENETDOWN early. It's
|
|
|
|
* possible that we just started dialing out,
|
|
|
|
* so don't drop the packet immediately. If
|
|
|
|
* we notice that we run out of buffer space
|
|
|
|
* below, we will however remember that we are
|
|
|
|
* not ready to carry IP packets, and return
|
|
|
|
* ENETDOWN, as opposed to ENOBUFS.
|
|
|
|
*/
|
2001-04-09 23:33:01 +04:00
|
|
|
protocol = htons(PPP_IPV6);
|
2000-05-02 16:43:16 +04:00
|
|
|
if (sp->state[IDX_IPV6CP] != STATE_OPENED)
|
2005-03-31 19:48:13 +04:00
|
|
|
error = ENETDOWN;
|
1999-07-30 14:35:34 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
#endif
|
1999-03-25 06:38:00 +03:00
|
|
|
#ifdef IPX
|
|
|
|
case AF_IPX: /* Novell IPX Protocol */
|
2002-09-25 11:24:06 +04:00
|
|
|
protocol = htons((sp->pp_flags & PP_CISCO) ?
|
1999-03-25 06:38:00 +03:00
|
|
|
ETHERTYPE_IPX : PPP_IPX);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#ifdef ISO
|
|
|
|
case AF_ISO: /* ISO OSI Protocol */
|
|
|
|
if (sp->pp_flags & PP_CISCO)
|
|
|
|
goto nosupport;
|
2002-09-25 11:24:06 +04:00
|
|
|
protocol = htons(PPP_ISO);
|
1999-03-25 06:38:00 +03:00
|
|
|
break;
|
|
|
|
nosupport:
|
|
|
|
#endif
|
|
|
|
default:
|
2002-09-25 11:24:06 +04:00
|
|
|
m_freem(m);
|
1999-04-04 10:07:56 +04:00
|
|
|
++ifp->if_oerrors;
|
2002-09-25 11:24:06 +04:00
|
|
|
splx(s);
|
1999-03-25 06:38:00 +03:00
|
|
|
return (EAFNOSUPPORT);
|
|
|
|
}
|
|
|
|
|
2001-04-09 23:33:01 +04:00
|
|
|
if (sp->pp_flags & PP_NOFRAMING) {
|
2002-09-25 11:24:06 +04:00
|
|
|
M_PREPEND(m, 2, M_DONTWAIT);
|
2001-04-09 23:33:01 +04:00
|
|
|
if (m == NULL) {
|
|
|
|
if (ifp->if_flags & IFF_DEBUG)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: no memory for transmit header\n",
|
|
|
|
ifp->if_xname);
|
2001-04-09 23:33:01 +04:00
|
|
|
++ifp->if_oerrors;
|
2002-09-25 11:24:06 +04:00
|
|
|
splx(s);
|
2001-04-09 23:33:01 +04:00
|
|
|
return (ENOBUFS);
|
|
|
|
}
|
2002-09-25 11:24:06 +04:00
|
|
|
*mtod(m, u_int16_t *) = protocol;
|
2001-04-09 23:33:01 +04:00
|
|
|
} else {
|
|
|
|
h->protocol = protocol;
|
|
|
|
}
|
|
|
|
|
2000-12-14 01:07:50 +03:00
|
|
|
|
2005-03-31 19:48:13 +04:00
|
|
|
error = ifq_enqueue2(ifp, ifq, m ALTQ_COMMA ALTQ_DECL(&pktattr));
|
1999-03-25 06:38:00 +03:00
|
|
|
|
2005-03-31 19:48:13 +04:00
|
|
|
if (error == 0) {
|
|
|
|
/*
|
|
|
|
* Count output packets and bytes.
|
|
|
|
* The packet length includes header + additional hardware
|
|
|
|
* framing according to RFC 1333.
|
|
|
|
*/
|
|
|
|
if (!(ifp->if_flags & IFF_OACTIVE))
|
|
|
|
(*ifp->if_start)(ifp);
|
|
|
|
ifp->if_obytes += m->m_pkthdr.len + sp->pp_framebytes;
|
|
|
|
}
|
2002-09-25 11:24:06 +04:00
|
|
|
splx(s);
|
2005-03-31 19:48:13 +04:00
|
|
|
return error;
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
void
|
|
|
|
sppp_attach(struct ifnet *ifp)
|
1999-03-25 06:38:00 +03:00
|
|
|
{
|
2002-09-25 11:24:06 +04:00
|
|
|
struct sppp *sp = (struct sppp *) ifp;
|
1999-03-25 06:38:00 +03:00
|
|
|
|
|
|
|
/* Initialize keepalive handler. */
|
2000-03-23 10:01:25 +03:00
|
|
|
if (! spppq) {
|
2007-07-10 00:51:58 +04:00
|
|
|
callout_init(&keepalive_ch, 0);
|
2002-09-01 22:54:12 +04:00
|
|
|
callout_reset(&keepalive_ch, hz * LCP_KEEPALIVE_INTERVAL, sppp_keepalive, NULL);
|
2000-03-23 10:01:25 +03:00
|
|
|
}
|
1999-03-25 06:38:00 +03:00
|
|
|
|
|
|
|
/* Insert new entry into the keepalive list. */
|
|
|
|
sp->pp_next = spppq;
|
|
|
|
spppq = sp;
|
|
|
|
|
|
|
|
sp->pp_if.if_type = IFT_PPP;
|
|
|
|
sp->pp_if.if_output = sppp_output;
|
|
|
|
sp->pp_fastq.ifq_maxlen = 32;
|
1999-04-04 10:07:56 +04:00
|
|
|
sp->pp_cpq.ifq_maxlen = 20;
|
1999-03-25 06:38:00 +03:00
|
|
|
sp->pp_loopcnt = 0;
|
|
|
|
sp->pp_alivecnt = 0;
|
2002-01-06 23:14:29 +03:00
|
|
|
sp->pp_last_activity = 0;
|
2003-09-04 00:48:46 +04:00
|
|
|
sp->pp_last_receive = 0;
|
|
|
|
sp->pp_maxalive = DEFAULT_MAXALIVECNT;
|
|
|
|
sp->pp_max_noreceive = DEFAULT_NORECV_TIME;
|
2002-01-06 23:14:29 +03:00
|
|
|
sp->pp_idle_timeout = 0;
|
2001-07-18 20:43:09 +04:00
|
|
|
memset(&sp->pp_seq[0], 0, sizeof(sp->pp_seq));
|
|
|
|
memset(&sp->pp_rseq[0], 0, sizeof(sp->pp_rseq));
|
2002-01-07 13:49:02 +03:00
|
|
|
sp->pp_auth_failures = 0;
|
|
|
|
sp->pp_max_auth_fail = DEFAULT_MAX_AUTH_FAILURES;
|
2002-01-04 15:21:24 +03:00
|
|
|
sp->pp_phase = SPPP_PHASE_DEAD;
|
1999-04-04 10:07:56 +04:00
|
|
|
sp->pp_up = lcp.Up;
|
|
|
|
sp->pp_down = lcp.Down;
|
|
|
|
|
2001-01-17 03:30:49 +03:00
|
|
|
if_alloc_sadl(ifp);
|
|
|
|
|
2002-01-04 15:21:24 +03:00
|
|
|
memset(&sp->myauth, 0, sizeof sp->myauth);
|
|
|
|
memset(&sp->hisauth, 0, sizeof sp->hisauth);
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_lcp_init(sp);
|
|
|
|
sppp_ipcp_init(sp);
|
2000-05-02 16:43:16 +04:00
|
|
|
sppp_ipv6cp_init(sp);
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_pap_init(sp);
|
|
|
|
sppp_chap_init(sp);
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
void
|
|
|
|
sppp_detach(struct ifnet *ifp)
|
1999-03-25 06:38:00 +03:00
|
|
|
{
|
2002-09-25 11:24:06 +04:00
|
|
|
struct sppp **q, *p, *sp = (struct sppp *) ifp;
|
1999-04-04 10:07:56 +04:00
|
|
|
int i;
|
1999-03-25 06:38:00 +03:00
|
|
|
|
|
|
|
/* Remove the entry from the keepalive list. */
|
|
|
|
for (q = &spppq; (p = *q); q = &p->pp_next)
|
|
|
|
if (p == sp) {
|
|
|
|
*q = p->pp_next;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Stop keepalive handler. */
|
2000-03-23 10:01:25 +03:00
|
|
|
if (! spppq) {
|
|
|
|
callout_stop(&keepalive_ch);
|
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2000-03-23 10:01:25 +03:00
|
|
|
for (i = 0; i < IDX_COUNT; i++) {
|
|
|
|
callout_stop(&sp->ch[i]);
|
|
|
|
}
|
|
|
|
callout_stop(&sp->pap_my_to_ch);
|
2001-01-17 03:30:49 +03:00
|
|
|
|
2002-01-04 15:21:24 +03:00
|
|
|
/* free authentication info */
|
|
|
|
if (sp->myauth.name) free(sp->myauth.name, M_DEVBUF);
|
|
|
|
if (sp->myauth.secret) free(sp->myauth.secret, M_DEVBUF);
|
|
|
|
if (sp->hisauth.name) free(sp->hisauth.name, M_DEVBUF);
|
|
|
|
if (sp->hisauth.secret) free(sp->hisauth.secret, M_DEVBUF);
|
|
|
|
|
2003-05-23 14:06:17 +04:00
|
|
|
#if 0 /* done in if_detach() */
|
2001-01-17 03:30:49 +03:00
|
|
|
if_free_sadl(ifp);
|
2003-05-23 14:06:17 +04:00
|
|
|
#endif
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Flush the interface output queue.
|
|
|
|
*/
|
1999-04-04 10:07:56 +04:00
|
|
|
void
|
|
|
|
sppp_flush(struct ifnet *ifp)
|
1999-03-25 06:38:00 +03:00
|
|
|
{
|
2002-09-25 11:24:06 +04:00
|
|
|
struct sppp *sp = (struct sppp *) ifp;
|
1999-03-25 06:38:00 +03:00
|
|
|
|
2002-09-25 11:24:06 +04:00
|
|
|
IFQ_PURGE(&sp->pp_if.if_snd);
|
|
|
|
IF_PURGE(&sp->pp_fastq);
|
|
|
|
IF_PURGE(&sp->pp_cpq);
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if the output queue is empty.
|
|
|
|
*/
|
|
|
|
int
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_isempty(struct ifnet *ifp)
|
1999-03-25 06:38:00 +03:00
|
|
|
{
|
2002-09-25 11:24:06 +04:00
|
|
|
struct sppp *sp = (struct sppp *) ifp;
|
1999-04-04 10:07:56 +04:00
|
|
|
int empty, s;
|
1999-03-25 06:38:00 +03:00
|
|
|
|
2001-04-14 03:29:55 +04:00
|
|
|
s = splnet();
|
2002-02-10 18:17:21 +03:00
|
|
|
empty = IF_IS_EMPTY(&sp->pp_fastq) && IF_IS_EMPTY(&sp->pp_cpq) &&
|
|
|
|
IFQ_IS_EMPTY(&sp->pp_if.if_snd);
|
1999-04-04 10:07:56 +04:00
|
|
|
splx(s);
|
1999-03-25 06:38:00 +03:00
|
|
|
return (empty);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get next packet to send.
|
|
|
|
*/
|
1999-04-04 10:07:56 +04:00
|
|
|
struct mbuf *
|
|
|
|
sppp_dequeue(struct ifnet *ifp)
|
1999-03-25 06:38:00 +03:00
|
|
|
{
|
2002-09-25 11:24:06 +04:00
|
|
|
struct sppp *sp = (struct sppp *) ifp;
|
1999-03-25 06:38:00 +03:00
|
|
|
struct mbuf *m;
|
1999-04-04 10:07:56 +04:00
|
|
|
int s;
|
|
|
|
|
2001-04-14 03:29:55 +04:00
|
|
|
s = splnet();
|
1999-04-04 10:07:56 +04:00
|
|
|
/*
|
|
|
|
* Process only the control protocol queue until we have at
|
|
|
|
* least one NCP open.
|
|
|
|
*
|
|
|
|
* Do always serve all three queues in Cisco mode.
|
|
|
|
*/
|
|
|
|
IF_DEQUEUE(&sp->pp_cpq, m);
|
|
|
|
if (m == NULL &&
|
|
|
|
(sppp_ncp_check(sp) || (sp->pp_flags & PP_CISCO) != 0)) {
|
|
|
|
IF_DEQUEUE(&sp->pp_fastq, m);
|
|
|
|
if (m == NULL)
|
2003-07-10 00:12:53 +04:00
|
|
|
IFQ_DEQUEUE(&sp->pp_if.if_snd, m);
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
splx(s);
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
1999-03-25 06:38:00 +03:00
|
|
|
/*
|
1999-04-04 10:07:56 +04:00
|
|
|
* Process an ioctl request. Called on low priority level.
|
1999-03-25 06:38:00 +03:00
|
|
|
*/
|
1999-04-04 10:07:56 +04:00
|
|
|
int
|
|
|
|
sppp_ioctl(struct ifnet *ifp, u_long cmd, void *data)
|
1999-03-25 06:38:00 +03:00
|
|
|
{
|
2006-10-26 19:11:22 +04:00
|
|
|
struct lwp *l = curlwp; /* XXX */
|
2002-09-25 11:24:06 +04:00
|
|
|
struct ifreq *ifr = (struct ifreq *) data;
|
|
|
|
struct sppp *sp = (struct sppp *) ifp;
|
2002-01-19 01:39:12 +03:00
|
|
|
int s, error=0, going_up, going_down, newmode;
|
1999-03-25 06:38:00 +03:00
|
|
|
|
2001-04-14 03:29:55 +04:00
|
|
|
s = splnet();
|
1999-04-04 10:07:56 +04:00
|
|
|
switch (cmd) {
|
|
|
|
case SIOCAIFADDR:
|
|
|
|
case SIOCSIFDSTADDR:
|
2006-07-14 03:43:13 +04:00
|
|
|
case SIOCSIFADDR:
|
1999-04-04 10:07:56 +04:00
|
|
|
break;
|
1999-03-25 06:38:00 +03:00
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
case SIOCSIFFLAGS:
|
|
|
|
going_up = ifp->if_flags & IFF_UP &&
|
|
|
|
(ifp->if_flags & IFF_RUNNING) == 0;
|
|
|
|
going_down = (ifp->if_flags & IFF_UP) == 0 &&
|
|
|
|
ifp->if_flags & IFF_RUNNING;
|
|
|
|
newmode = ifp->if_flags & (IFF_AUTO | IFF_PASSIVE);
|
|
|
|
if (newmode == (IFF_AUTO | IFF_PASSIVE)) {
|
|
|
|
/* sanity */
|
|
|
|
newmode = IFF_PASSIVE;
|
|
|
|
ifp->if_flags &= ~IFF_AUTO;
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
if (going_up || going_down)
|
|
|
|
lcp.Close(sp);
|
|
|
|
if (going_up && newmode == 0) {
|
|
|
|
/* neither auto-dial nor passive */
|
|
|
|
ifp->if_flags |= IFF_RUNNING;
|
|
|
|
if (!(sp->pp_flags & PP_CISCO))
|
|
|
|
lcp.Open(sp);
|
|
|
|
} else if (going_down) {
|
|
|
|
sppp_flush(ifp);
|
|
|
|
ifp->if_flags &= ~IFF_RUNNING;
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
#ifdef SIOCSIFMTU
|
|
|
|
#ifndef ifr_mtu
|
|
|
|
#define ifr_mtu ifr_metric
|
|
|
|
#endif
|
|
|
|
case SIOCSIFMTU:
|
2007-06-23 12:45:25 +04:00
|
|
|
if (ifr->ifr_mtu < PPP_MINMRU ||
|
|
|
|
ifr->ifr_mtu > sp->lcp.their_mru) {
|
2002-12-29 00:09:14 +03:00
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
ifp->if_mtu = ifr->ifr_mtu;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#ifdef SLIOCSETMTU
|
|
|
|
case SLIOCSETMTU:
|
2007-06-23 12:45:25 +04:00
|
|
|
if (*(short *)data < PPP_MINMRU ||
|
|
|
|
*(short *)data > sp->lcp.their_mru)
|
2002-12-29 00:09:14 +03:00
|
|
|
{
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2002-09-25 11:24:06 +04:00
|
|
|
ifp->if_mtu = *(short *)data;
|
1999-04-04 10:07:56 +04:00
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#ifdef SIOCGIFMTU
|
|
|
|
case SIOCGIFMTU:
|
|
|
|
ifr->ifr_mtu = ifp->if_mtu;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#ifdef SLIOCGETMTU
|
|
|
|
case SLIOCGETMTU:
|
2002-09-25 11:24:06 +04:00
|
|
|
*(short *)data = ifp->if_mtu;
|
1999-04-04 10:07:56 +04:00
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
case SIOCADDMULTI:
|
|
|
|
case SIOCDELMULTI:
|
|
|
|
break;
|
|
|
|
|
2002-01-04 15:21:24 +03:00
|
|
|
case SPPPSETAUTHCFG:
|
|
|
|
case SPPPSETLCPCFG:
|
2002-01-06 23:14:29 +03:00
|
|
|
case SPPPSETIDLETO:
|
2002-01-07 13:49:02 +03:00
|
|
|
case SPPPSETAUTHFAILURE:
|
2002-03-02 19:23:42 +03:00
|
|
|
case SPPPSETDNSOPTS:
|
2003-09-04 00:48:46 +04:00
|
|
|
case SPPPSETKEEPALIVE:
|
2006-10-26 19:11:22 +04:00
|
|
|
error = kauth_authorize_network(l->l_cred,
|
|
|
|
KAUTH_NETWORK_INTERFACE,
|
|
|
|
KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
|
|
|
|
NULL);
|
|
|
|
if (error)
|
|
|
|
break;
|
|
|
|
error = sppp_params(sp, cmd, data);
|
|
|
|
break;
|
2002-01-04 15:21:24 +03:00
|
|
|
|
2006-10-26 19:11:22 +04:00
|
|
|
case SPPPGETAUTHCFG:
|
|
|
|
case SPPPGETLCPCFG:
|
|
|
|
case SPPPGETAUTHFAILURES:
|
|
|
|
error = kauth_authorize_network(l->l_cred,
|
|
|
|
KAUTH_NETWORK_INTERFACE,
|
|
|
|
KAUTH_REQ_NETWORK_INTERFACE_GETPRIV, ifp, (void *)cmd,
|
|
|
|
NULL);
|
|
|
|
if (error)
|
2002-01-04 15:21:24 +03:00
|
|
|
break;
|
2006-10-26 19:11:22 +04:00
|
|
|
error = sppp_params(sp, cmd, data);
|
|
|
|
break;
|
|
|
|
|
2002-01-04 15:21:24 +03:00
|
|
|
case SPPPGETSTATUS:
|
2003-12-27 02:39:23 +03:00
|
|
|
case SPPPGETSTATUSNCP:
|
2002-01-06 23:14:29 +03:00
|
|
|
case SPPPGETIDLETO:
|
2002-03-02 19:23:42 +03:00
|
|
|
case SPPPGETDNSOPTS:
|
|
|
|
case SPPPGETDNSADDRS:
|
2003-09-04 00:48:46 +04:00
|
|
|
case SPPPGETKEEPALIVE:
|
2002-01-19 01:39:12 +03:00
|
|
|
error = sppp_params(sp, cmd, data);
|
1999-04-04 10:07:56 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2002-01-19 01:39:12 +03:00
|
|
|
error = ENOTTY;
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
splx(s);
|
2002-01-19 01:39:12 +03:00
|
|
|
return (error);
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2002-01-19 01:39:12 +03:00
|
|
|
/*
|
1999-04-04 10:07:56 +04:00
|
|
|
* Cisco framing implementation.
|
|
|
|
*/
|
|
|
|
|
1999-03-25 06:38:00 +03:00
|
|
|
/*
|
1999-04-04 10:07:56 +04:00
|
|
|
* Handle incoming Cisco keepalive protocol packets.
|
1999-03-25 06:38:00 +03:00
|
|
|
*/
|
1999-04-04 10:07:56 +04:00
|
|
|
static void
|
|
|
|
sppp_cisco_input(struct sppp *sp, struct mbuf *m)
|
1999-03-25 06:38:00 +03:00
|
|
|
{
|
1999-04-04 10:07:56 +04:00
|
|
|
STDDCL;
|
|
|
|
struct cisco_packet *h;
|
2004-12-06 05:59:23 +03:00
|
|
|
#ifdef INET
|
2006-05-14 09:30:31 +04:00
|
|
|
u_int32_t me, mymask = 0; /* XXX: GCC */
|
2004-12-06 05:59:23 +03:00
|
|
|
#endif
|
1999-03-25 06:38:00 +03:00
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
if (m->m_pkthdr.len < CISCO_PACKET_LEN) {
|
|
|
|
if (debug)
|
|
|
|
log(LOG_DEBUG,
|
2003-05-15 02:41:40 +04:00
|
|
|
"%s: cisco invalid packet length: %d bytes\n",
|
|
|
|
ifp->if_xname, m->m_pkthdr.len);
|
1999-03-25 06:38:00 +03:00
|
|
|
return;
|
|
|
|
}
|
2002-09-25 11:24:06 +04:00
|
|
|
h = mtod(m, struct cisco_packet *);
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug)
|
|
|
|
log(LOG_DEBUG,
|
2003-05-15 02:41:40 +04:00
|
|
|
"%s: cisco input: %d bytes "
|
2001-12-05 00:32:15 +03:00
|
|
|
"<0x%x 0x%x 0x%x 0x%x 0x%x-0x%x>\n",
|
2003-05-15 02:41:40 +04:00
|
|
|
ifp->if_xname, m->m_pkthdr.len,
|
2004-12-22 08:11:24 +03:00
|
|
|
ntohl(h->type), h->par1, h->par2, (u_int)h->rel,
|
1999-04-04 10:07:56 +04:00
|
|
|
(u_int)h->time0, (u_int)h->time1);
|
2004-12-22 08:11:24 +03:00
|
|
|
switch (ntohl(h->type)) {
|
1999-03-25 06:38:00 +03:00
|
|
|
default:
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
addlog("%s: cisco unknown packet type: 0x%x\n",
|
2004-12-22 08:11:24 +03:00
|
|
|
ifp->if_xname, ntohl(h->type));
|
1999-03-25 06:38:00 +03:00
|
|
|
break;
|
1999-04-04 10:07:56 +04:00
|
|
|
case CISCO_ADDR_REPLY:
|
|
|
|
/* Reply on address request, ignore */
|
|
|
|
break;
|
|
|
|
case CISCO_KEEPALIVE_REQ:
|
|
|
|
sp->pp_alivecnt = 0;
|
2004-12-22 08:11:24 +03:00
|
|
|
sp->pp_rseq[IDX_LCP] = ntohl(h->par1);
|
2000-05-02 16:43:16 +04:00
|
|
|
if (sp->pp_seq[IDX_LCP] == sp->pp_rseq[IDX_LCP]) {
|
1999-04-04 10:07:56 +04:00
|
|
|
/* Local and remote sequence numbers are equal.
|
|
|
|
* Probably, the line is in loopback mode. */
|
2003-09-04 00:48:46 +04:00
|
|
|
if (sp->pp_loopcnt >= LOOPALIVECNT) {
|
2003-05-15 02:41:40 +04:00
|
|
|
printf ("%s: loopback\n",
|
|
|
|
ifp->if_xname);
|
1999-03-25 06:38:00 +03:00
|
|
|
sp->pp_loopcnt = 0;
|
|
|
|
if (ifp->if_flags & IFF_UP) {
|
2002-09-25 11:24:06 +04:00
|
|
|
if_down(ifp);
|
|
|
|
IF_PURGE(&sp->pp_cpq);
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
1999-03-25 06:38:00 +03:00
|
|
|
++sp->pp_loopcnt;
|
|
|
|
|
|
|
|
/* Generate new local sequence number */
|
2003-05-15 03:16:44 +04:00
|
|
|
sp->pp_seq[IDX_LCP] = arc4random();
|
1999-03-25 06:38:00 +03:00
|
|
|
break;
|
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
sp->pp_loopcnt = 0;
|
1999-03-25 06:38:00 +03:00
|
|
|
if (! (ifp->if_flags & IFF_UP) &&
|
|
|
|
(ifp->if_flags & IFF_RUNNING)) {
|
1999-04-04 10:07:56 +04:00
|
|
|
if_up(ifp);
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CISCO_ADDR_REQ:
|
2004-12-06 05:59:23 +03:00
|
|
|
#ifdef INET
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_get_ip_addrs(sp, &me, 0, &mymask);
|
|
|
|
if (me != 0L)
|
|
|
|
sppp_cisco_send(sp, CISCO_ADDR_REPLY, me, mymask);
|
2004-12-06 05:59:23 +03:00
|
|
|
#endif
|
1999-03-25 06:38:00 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1999-04-04 10:07:56 +04:00
|
|
|
* Send Cisco keepalive packet.
|
1999-03-25 06:38:00 +03:00
|
|
|
*/
|
|
|
|
static void
|
2001-12-05 00:32:15 +03:00
|
|
|
sppp_cisco_send(struct sppp *sp, int type, int32_t par1, int32_t par2)
|
1999-03-25 06:38:00 +03:00
|
|
|
{
|
1999-04-04 10:07:56 +04:00
|
|
|
STDDCL;
|
1999-03-25 06:38:00 +03:00
|
|
|
struct ppp_header *h;
|
1999-04-04 10:07:56 +04:00
|
|
|
struct cisco_packet *ch;
|
1999-03-25 06:38:00 +03:00
|
|
|
struct mbuf *m;
|
2006-06-08 02:33:33 +04:00
|
|
|
u_int32_t t;
|
1999-03-25 06:38:00 +03:00
|
|
|
|
2006-06-08 02:33:33 +04:00
|
|
|
t = time_uptime * 1000;
|
2002-09-25 11:24:06 +04:00
|
|
|
MGETHDR(m, M_DONTWAIT, MT_DATA);
|
1999-03-25 06:38:00 +03:00
|
|
|
if (! m)
|
|
|
|
return;
|
1999-04-04 10:07:56 +04:00
|
|
|
m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + CISCO_PACKET_LEN;
|
1999-03-25 06:38:00 +03:00
|
|
|
m->m_pkthdr.rcvif = 0;
|
|
|
|
|
2002-09-25 11:24:06 +04:00
|
|
|
h = mtod(m, struct ppp_header *);
|
1999-04-04 10:07:56 +04:00
|
|
|
h->address = CISCO_MULTICAST;
|
|
|
|
h->control = 0;
|
2002-09-25 11:24:06 +04:00
|
|
|
h->protocol = htons(CISCO_KEEPALIVE);
|
1999-03-25 06:38:00 +03:00
|
|
|
|
2002-09-25 11:24:06 +04:00
|
|
|
ch = (struct cisco_packet *)(h + 1);
|
|
|
|
ch->type = htonl(type);
|
|
|
|
ch->par1 = htonl(par1);
|
|
|
|
ch->par2 = htonl(par2);
|
1999-04-04 10:07:56 +04:00
|
|
|
ch->rel = -1;
|
1999-03-25 06:38:00 +03:00
|
|
|
|
2002-09-25 11:24:06 +04:00
|
|
|
ch->time0 = htons((u_short)(t >> 16));
|
|
|
|
ch->time1 = htons((u_short) t);
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
if (debug)
|
|
|
|
log(LOG_DEBUG,
|
2003-05-15 02:41:40 +04:00
|
|
|
"%s: cisco output: <0x%x 0x%x 0x%x 0x%x 0x%x-0x%x>\n",
|
2004-12-22 08:11:24 +03:00
|
|
|
ifp->if_xname, ntohl(ch->type), ch->par1,
|
2001-12-05 00:32:15 +03:00
|
|
|
ch->par2, (u_int)ch->rel, (u_int)ch->time0,
|
|
|
|
(u_int)ch->time1);
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2002-09-25 11:24:06 +04:00
|
|
|
if (IF_QFULL(&sp->pp_cpq)) {
|
|
|
|
IF_DROP(&sp->pp_fastq);
|
|
|
|
IF_DROP(&ifp->if_snd);
|
|
|
|
m_freem(m);
|
2002-07-12 01:37:51 +04:00
|
|
|
++ifp->if_oerrors;
|
|
|
|
return;
|
1999-03-25 06:38:00 +03:00
|
|
|
} else
|
2002-09-25 11:24:06 +04:00
|
|
|
IF_ENQUEUE(&sp->pp_cpq, m);
|
1999-03-25 06:38:00 +03:00
|
|
|
if (! (ifp->if_flags & IFF_OACTIVE))
|
2002-09-25 11:24:06 +04:00
|
|
|
(*ifp->if_start)(ifp);
|
2001-04-09 23:33:01 +04:00
|
|
|
ifp->if_obytes += m->m_pkthdr.len + sp->pp_framebytes;
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
|
|
|
|
2002-01-19 01:39:12 +03:00
|
|
|
/*
|
1999-04-04 10:07:56 +04:00
|
|
|
* PPP protocol implementation.
|
|
|
|
*/
|
|
|
|
|
1999-03-25 06:38:00 +03:00
|
|
|
/*
|
1999-04-04 10:07:56 +04:00
|
|
|
* Send PPP control protocol packet.
|
1999-03-25 06:38:00 +03:00
|
|
|
*/
|
|
|
|
static void
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_cp_send(struct sppp *sp, u_short proto, u_char type,
|
|
|
|
u_char ident, u_short len, void *data)
|
1999-03-25 06:38:00 +03:00
|
|
|
{
|
1999-04-04 10:07:56 +04:00
|
|
|
STDDCL;
|
|
|
|
struct lcp_header *lh;
|
1999-03-25 06:38:00 +03:00
|
|
|
struct mbuf *m;
|
2001-04-09 23:33:01 +04:00
|
|
|
size_t pkthdrlen;
|
|
|
|
|
|
|
|
pkthdrlen = (sp->pp_flags & PP_NOFRAMING) ? 2 : PPP_HEADER_LEN;
|
1999-03-25 06:38:00 +03:00
|
|
|
|
2001-04-09 23:33:01 +04:00
|
|
|
if (len > MHLEN - pkthdrlen - LCP_HEADER_LEN)
|
|
|
|
len = MHLEN - pkthdrlen - LCP_HEADER_LEN;
|
2002-09-25 11:24:06 +04:00
|
|
|
MGETHDR(m, M_DONTWAIT, MT_DATA);
|
1999-03-25 06:38:00 +03:00
|
|
|
if (! m)
|
|
|
|
return;
|
2001-04-09 23:33:01 +04:00
|
|
|
m->m_pkthdr.len = m->m_len = pkthdrlen + LCP_HEADER_LEN + len;
|
1999-03-25 06:38:00 +03:00
|
|
|
m->m_pkthdr.rcvif = 0;
|
|
|
|
|
2001-04-09 23:33:01 +04:00
|
|
|
if (sp->pp_flags & PP_NOFRAMING) {
|
2002-09-25 11:24:06 +04:00
|
|
|
*mtod(m, u_int16_t *) = htons(proto);
|
|
|
|
lh = (struct lcp_header *)(mtod(m, u_int8_t *) + 2);
|
2001-04-09 23:33:01 +04:00
|
|
|
} else {
|
|
|
|
struct ppp_header *h;
|
2002-09-25 11:24:06 +04:00
|
|
|
h = mtod(m, struct ppp_header *);
|
2001-04-09 23:33:01 +04:00
|
|
|
h->address = PPP_ALLSTATIONS; /* broadcast address */
|
|
|
|
h->control = PPP_UI; /* Unnumbered Info */
|
2002-09-25 11:24:06 +04:00
|
|
|
h->protocol = htons(proto); /* Link Control Protocol */
|
|
|
|
lh = (struct lcp_header *)(h + 1);
|
2001-04-09 23:33:01 +04:00
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
lh->type = type;
|
|
|
|
lh->ident = ident;
|
2002-09-25 11:24:06 +04:00
|
|
|
lh->len = htons(LCP_HEADER_LEN + len);
|
1999-04-04 10:07:56 +04:00
|
|
|
if (len)
|
2002-09-25 11:24:06 +04:00
|
|
|
bcopy (data, lh + 1, len);
|
1999-03-25 06:38:00 +03:00
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug) {
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: %s output <%s id=0x%x len=%d",
|
|
|
|
ifp->if_xname,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_proto_name(proto),
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_cp_type_name(lh->type), lh->ident, ntohs(lh->len));
|
1999-04-04 10:07:56 +04:00
|
|
|
if (len)
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_print_bytes((u_char *)(lh + 1), len);
|
1999-04-04 10:07:56 +04:00
|
|
|
addlog(">\n");
|
|
|
|
}
|
2002-09-25 11:24:06 +04:00
|
|
|
if (IF_QFULL(&sp->pp_cpq)) {
|
|
|
|
IF_DROP(&sp->pp_fastq);
|
|
|
|
IF_DROP(&ifp->if_snd);
|
|
|
|
m_freem(m);
|
1999-04-04 10:07:56 +04:00
|
|
|
++ifp->if_oerrors;
|
2002-07-12 01:37:51 +04:00
|
|
|
return;
|
1999-03-25 06:38:00 +03:00
|
|
|
} else
|
2002-09-25 11:24:06 +04:00
|
|
|
IF_ENQUEUE(&sp->pp_cpq, m);
|
1999-03-25 06:38:00 +03:00
|
|
|
if (! (ifp->if_flags & IFF_OACTIVE))
|
2002-09-25 11:24:06 +04:00
|
|
|
(*ifp->if_start)(ifp);
|
2001-04-09 23:33:01 +04:00
|
|
|
ifp->if_obytes += m->m_pkthdr.len + sp->pp_framebytes;
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1999-04-04 10:07:56 +04:00
|
|
|
* Handle incoming PPP control protocol packets.
|
1999-03-25 06:38:00 +03:00
|
|
|
*/
|
|
|
|
static void
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_cp_input(const struct cp *cp, struct sppp *sp, struct mbuf *m)
|
1999-03-25 06:38:00 +03:00
|
|
|
{
|
1999-04-04 10:07:56 +04:00
|
|
|
STDDCL;
|
1999-03-25 06:38:00 +03:00
|
|
|
struct lcp_header *h;
|
2006-08-24 00:02:23 +04:00
|
|
|
int printlen, len = m->m_pkthdr.len;
|
1999-04-04 10:07:56 +04:00
|
|
|
int rv;
|
|
|
|
u_char *p;
|
2001-12-05 00:32:15 +03:00
|
|
|
u_int32_t u32;
|
1999-03-25 06:38:00 +03:00
|
|
|
|
|
|
|
if (len < 4) {
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug)
|
|
|
|
log(LOG_DEBUG,
|
2003-05-15 02:41:40 +04:00
|
|
|
"%s: %s invalid packet length: %d bytes\n",
|
|
|
|
ifp->if_xname, cp->name, len);
|
1999-03-25 06:38:00 +03:00
|
|
|
return;
|
|
|
|
}
|
2002-09-25 11:24:06 +04:00
|
|
|
h = mtod(m, struct lcp_header *);
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug) {
|
2006-08-24 00:02:23 +04:00
|
|
|
printlen = ntohs(h->len);
|
1999-04-04 10:07:56 +04:00
|
|
|
log(LOG_DEBUG,
|
2003-05-15 02:41:40 +04:00
|
|
|
"%s: %s input(%s): <%s id=0x%x len=%d",
|
|
|
|
ifp->if_xname, cp->name,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_state_name(sp->state[cp->protoidx]),
|
2006-08-24 00:02:23 +04:00
|
|
|
sppp_cp_type_name(h->type), h->ident, printlen);
|
|
|
|
if (len < printlen)
|
|
|
|
printlen = len;
|
|
|
|
if (printlen > 4)
|
|
|
|
sppp_print_bytes((u_char *)(h + 1), printlen - 4);
|
1999-04-04 10:07:56 +04:00
|
|
|
addlog(">\n");
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
2002-09-25 11:24:06 +04:00
|
|
|
if (len > ntohs(h->len))
|
|
|
|
len = ntohs(h->len);
|
1999-04-04 10:07:56 +04:00
|
|
|
p = (u_char *)(h + 1);
|
1999-03-25 06:38:00 +03:00
|
|
|
switch (h->type) {
|
1999-04-04 10:07:56 +04:00
|
|
|
case CONF_REQ:
|
1999-03-25 06:38:00 +03:00
|
|
|
if (len < 4) {
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
addlog("%s: %s invalid conf-req length %d\n",
|
|
|
|
ifp->if_xname, cp->name,
|
1999-04-04 10:07:56 +04:00
|
|
|
len);
|
|
|
|
++ifp->if_ierrors;
|
|
|
|
break;
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
/* handle states where RCR doesn't get a SCA/SCN */
|
|
|
|
switch (sp->state[cp->protoidx]) {
|
|
|
|
case STATE_CLOSING:
|
|
|
|
case STATE_STOPPING:
|
|
|
|
return;
|
|
|
|
case STATE_CLOSED:
|
|
|
|
sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident,
|
|
|
|
0, 0);
|
|
|
|
return;
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
rv = (cp->RCR)(sp, h, len);
|
2006-08-24 00:02:23 +04:00
|
|
|
if (rv < 0) {
|
|
|
|
/* fatal error, shut down */
|
|
|
|
(cp->tld)(sp);
|
|
|
|
sppp_lcp_tlf(sp);
|
|
|
|
return;
|
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
switch (sp->state[cp->protoidx]) {
|
|
|
|
case STATE_OPENED:
|
|
|
|
(cp->tld)(sp);
|
|
|
|
(cp->scr)(sp);
|
|
|
|
/* fall through... */
|
|
|
|
case STATE_ACK_SENT:
|
|
|
|
case STATE_REQ_SENT:
|
|
|
|
sppp_cp_change_state(cp, sp, rv?
|
|
|
|
STATE_ACK_SENT: STATE_REQ_SENT);
|
1999-03-25 06:38:00 +03:00
|
|
|
break;
|
1999-04-04 10:07:56 +04:00
|
|
|
case STATE_STOPPED:
|
|
|
|
sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
|
|
|
|
(cp->scr)(sp);
|
|
|
|
sppp_cp_change_state(cp, sp, rv?
|
|
|
|
STATE_ACK_SENT: STATE_REQ_SENT);
|
1999-03-25 06:38:00 +03:00
|
|
|
break;
|
1999-04-04 10:07:56 +04:00
|
|
|
case STATE_ACK_RCVD:
|
|
|
|
if (rv) {
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_OPENED);
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: %s tlu\n",
|
|
|
|
ifp->if_xname,
|
1999-04-04 10:07:56 +04:00
|
|
|
cp->name);
|
|
|
|
(cp->tlu)(sp);
|
|
|
|
} else
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_ACK_RCVD);
|
1999-03-25 06:38:00 +03:00
|
|
|
break;
|
1999-04-04 10:07:56 +04:00
|
|
|
default:
|
2003-05-15 02:41:40 +04:00
|
|
|
printf("%s: %s illegal %s in state %s\n",
|
|
|
|
ifp->if_xname, cp->name,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_cp_type_name(h->type),
|
|
|
|
sppp_state_name(sp->state[cp->protoidx]));
|
|
|
|
++ifp->if_ierrors;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CONF_ACK:
|
|
|
|
if (h->ident != sp->confid[cp->protoidx]) {
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
addlog("%s: %s id mismatch 0x%x != 0x%x\n",
|
|
|
|
ifp->if_xname, cp->name,
|
1999-04-04 10:07:56 +04:00
|
|
|
h->ident, sp->confid[cp->protoidx]);
|
|
|
|
++ifp->if_ierrors;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
switch (sp->state[cp->protoidx]) {
|
|
|
|
case STATE_CLOSED:
|
|
|
|
case STATE_STOPPED:
|
|
|
|
sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0);
|
|
|
|
break;
|
|
|
|
case STATE_CLOSING:
|
|
|
|
case STATE_STOPPING:
|
|
|
|
break;
|
|
|
|
case STATE_REQ_SENT:
|
|
|
|
sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_ACK_RCVD);
|
|
|
|
break;
|
|
|
|
case STATE_OPENED:
|
|
|
|
(cp->tld)(sp);
|
|
|
|
/* fall through */
|
|
|
|
case STATE_ACK_RCVD:
|
|
|
|
(cp->scr)(sp);
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
|
|
|
|
break;
|
|
|
|
case STATE_ACK_SENT:
|
|
|
|
sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_OPENED);
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: %s tlu\n",
|
|
|
|
ifp->if_xname, cp->name);
|
1999-04-04 10:07:56 +04:00
|
|
|
(cp->tlu)(sp);
|
|
|
|
break;
|
|
|
|
default:
|
2003-05-15 02:41:40 +04:00
|
|
|
printf("%s: %s illegal %s in state %s\n",
|
|
|
|
ifp->if_xname, cp->name,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_cp_type_name(h->type),
|
|
|
|
sppp_state_name(sp->state[cp->protoidx]));
|
|
|
|
++ifp->if_ierrors;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CONF_NAK:
|
|
|
|
case CONF_REJ:
|
|
|
|
if (h->ident != sp->confid[cp->protoidx]) {
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
addlog("%s: %s id mismatch 0x%x != 0x%x\n",
|
|
|
|
ifp->if_xname, cp->name,
|
1999-04-04 10:07:56 +04:00
|
|
|
h->ident, sp->confid[cp->protoidx]);
|
|
|
|
++ifp->if_ierrors;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (h->type == CONF_NAK)
|
|
|
|
(cp->RCN_nak)(sp, h, len);
|
|
|
|
else /* CONF_REJ */
|
|
|
|
(cp->RCN_rej)(sp, h, len);
|
|
|
|
|
|
|
|
switch (sp->state[cp->protoidx]) {
|
|
|
|
case STATE_CLOSED:
|
|
|
|
case STATE_STOPPED:
|
|
|
|
sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0);
|
|
|
|
break;
|
|
|
|
case STATE_REQ_SENT:
|
|
|
|
case STATE_ACK_SENT:
|
|
|
|
sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
|
|
|
|
(cp->scr)(sp);
|
|
|
|
break;
|
|
|
|
case STATE_OPENED:
|
|
|
|
(cp->tld)(sp);
|
|
|
|
/* fall through */
|
|
|
|
case STATE_ACK_RCVD:
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_ACK_SENT);
|
|
|
|
(cp->scr)(sp);
|
|
|
|
break;
|
|
|
|
case STATE_CLOSING:
|
|
|
|
case STATE_STOPPING:
|
|
|
|
break;
|
|
|
|
default:
|
2003-05-15 02:41:40 +04:00
|
|
|
printf("%s: %s illegal %s in state %s\n",
|
|
|
|
ifp->if_xname, cp->name,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_cp_type_name(h->type),
|
|
|
|
sppp_state_name(sp->state[cp->protoidx]));
|
|
|
|
++ifp->if_ierrors;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TERM_REQ:
|
|
|
|
switch (sp->state[cp->protoidx]) {
|
|
|
|
case STATE_ACK_RCVD:
|
|
|
|
case STATE_ACK_SENT:
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
|
|
|
|
/* fall through */
|
|
|
|
case STATE_CLOSED:
|
|
|
|
case STATE_STOPPED:
|
|
|
|
case STATE_CLOSING:
|
|
|
|
case STATE_STOPPING:
|
|
|
|
case STATE_REQ_SENT:
|
|
|
|
sta:
|
|
|
|
/* Send Terminate-Ack packet. */
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: %s send terminate-ack\n",
|
|
|
|
ifp->if_xname, cp->name);
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0);
|
|
|
|
break;
|
|
|
|
case STATE_OPENED:
|
|
|
|
(cp->tld)(sp);
|
|
|
|
sp->rst_counter[cp->protoidx] = 0;
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_STOPPING);
|
|
|
|
goto sta;
|
|
|
|
default:
|
2003-05-15 02:41:40 +04:00
|
|
|
printf("%s: %s illegal %s in state %s\n",
|
|
|
|
ifp->if_xname, cp->name,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_cp_type_name(h->type),
|
|
|
|
sppp_state_name(sp->state[cp->protoidx]));
|
|
|
|
++ifp->if_ierrors;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TERM_ACK:
|
|
|
|
switch (sp->state[cp->protoidx]) {
|
|
|
|
case STATE_CLOSED:
|
|
|
|
case STATE_STOPPED:
|
|
|
|
case STATE_REQ_SENT:
|
|
|
|
case STATE_ACK_SENT:
|
|
|
|
break;
|
|
|
|
case STATE_CLOSING:
|
|
|
|
(cp->tlf)(sp);
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_CLOSED);
|
2001-07-17 23:12:02 +04:00
|
|
|
sppp_lcp_check_and_close(sp);
|
1999-04-04 10:07:56 +04:00
|
|
|
break;
|
|
|
|
case STATE_STOPPING:
|
|
|
|
(cp->tlf)(sp);
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_STOPPED);
|
2001-07-17 23:12:02 +04:00
|
|
|
sppp_lcp_check_and_close(sp);
|
1999-04-04 10:07:56 +04:00
|
|
|
break;
|
|
|
|
case STATE_ACK_RCVD:
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
|
|
|
|
break;
|
|
|
|
case STATE_OPENED:
|
|
|
|
(cp->tld)(sp);
|
|
|
|
(cp->scr)(sp);
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_ACK_RCVD);
|
|
|
|
break;
|
|
|
|
default:
|
2003-05-15 02:41:40 +04:00
|
|
|
printf("%s: %s illegal %s in state %s\n",
|
|
|
|
ifp->if_xname, cp->name,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_cp_type_name(h->type),
|
|
|
|
sppp_state_name(sp->state[cp->protoidx]));
|
|
|
|
++ifp->if_ierrors;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CODE_REJ:
|
|
|
|
/* XXX catastrophic rejects (RXJ-) aren't handled yet. */
|
|
|
|
log(LOG_INFO,
|
2003-05-15 02:41:40 +04:00
|
|
|
"%s: %s: ignoring RXJ (%s) for code ?, "
|
1999-04-04 10:07:56 +04:00
|
|
|
"danger will robinson\n",
|
2003-05-15 02:41:40 +04:00
|
|
|
ifp->if_xname, cp->name,
|
2000-05-02 16:43:16 +04:00
|
|
|
sppp_cp_type_name(h->type));
|
|
|
|
switch (sp->state[cp->protoidx]) {
|
|
|
|
case STATE_CLOSED:
|
|
|
|
case STATE_STOPPED:
|
|
|
|
case STATE_REQ_SENT:
|
|
|
|
case STATE_ACK_SENT:
|
|
|
|
case STATE_CLOSING:
|
|
|
|
case STATE_STOPPING:
|
|
|
|
case STATE_OPENED:
|
|
|
|
break;
|
|
|
|
case STATE_ACK_RCVD:
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
|
|
|
|
break;
|
|
|
|
default:
|
2003-05-15 02:41:40 +04:00
|
|
|
printf("%s: %s illegal %s in state %s\n",
|
|
|
|
ifp->if_xname, cp->name,
|
2000-05-02 16:43:16 +04:00
|
|
|
sppp_cp_type_name(h->type),
|
|
|
|
sppp_state_name(sp->state[cp->protoidx]));
|
|
|
|
++ifp->if_ierrors;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PROTO_REJ:
|
|
|
|
{
|
|
|
|
int catastrophic;
|
|
|
|
const struct cp *upper;
|
|
|
|
int i;
|
|
|
|
u_int16_t proto;
|
|
|
|
|
|
|
|
catastrophic = 0;
|
|
|
|
upper = NULL;
|
2001-12-05 00:32:15 +03:00
|
|
|
proto = p[0] << 8 | p[1];
|
2000-05-02 16:43:16 +04:00
|
|
|
for (i = 0; i < IDX_COUNT; i++) {
|
|
|
|
if (cps[i]->proto == proto) {
|
|
|
|
upper = cps[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (upper == NULL)
|
|
|
|
catastrophic++;
|
|
|
|
|
2002-04-29 20:29:29 +04:00
|
|
|
if (debug)
|
|
|
|
log(LOG_INFO,
|
2003-05-15 02:41:40 +04:00
|
|
|
"%s: %s: RXJ%c (%s) for proto 0x%x (%s/%s)\n",
|
|
|
|
ifp->if_xname, cp->name, catastrophic ? '-' : '+',
|
2002-04-29 20:29:29 +04:00
|
|
|
sppp_cp_type_name(h->type), proto,
|
|
|
|
upper ? upper->name : "unknown",
|
|
|
|
upper ? sppp_state_name(sp->state[upper->protoidx]) : "?");
|
2000-05-02 16:43:16 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* if we got RXJ+ against conf-req, the peer does not implement
|
|
|
|
* this particular protocol type. terminate the protocol.
|
|
|
|
*/
|
|
|
|
if (upper && !catastrophic) {
|
|
|
|
if (sp->state[upper->protoidx] == STATE_REQ_SENT) {
|
|
|
|
upper->Close(sp);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX catastrophic rejects (RXJ-) aren't handled yet. */
|
1999-04-04 10:07:56 +04:00
|
|
|
switch (sp->state[cp->protoidx]) {
|
|
|
|
case STATE_CLOSED:
|
|
|
|
case STATE_STOPPED:
|
|
|
|
case STATE_REQ_SENT:
|
|
|
|
case STATE_ACK_SENT:
|
|
|
|
case STATE_CLOSING:
|
|
|
|
case STATE_STOPPING:
|
|
|
|
case STATE_OPENED:
|
|
|
|
break;
|
|
|
|
case STATE_ACK_RCVD:
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
|
|
|
|
break;
|
|
|
|
default:
|
2003-05-15 02:41:40 +04:00
|
|
|
printf("%s: %s illegal %s in state %s\n",
|
|
|
|
ifp->if_xname, cp->name,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_cp_type_name(h->type),
|
|
|
|
sppp_state_name(sp->state[cp->protoidx]));
|
|
|
|
++ifp->if_ierrors;
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
|
|
|
break;
|
2000-05-02 16:43:16 +04:00
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
case DISC_REQ:
|
|
|
|
if (cp->proto != PPP_LCP)
|
|
|
|
goto illegal;
|
|
|
|
/* Discard the packet. */
|
1999-03-25 06:38:00 +03:00
|
|
|
break;
|
1999-04-04 10:07:56 +04:00
|
|
|
case ECHO_REQ:
|
|
|
|
if (cp->proto != PPP_LCP)
|
|
|
|
goto illegal;
|
|
|
|
if (sp->state[cp->protoidx] != STATE_OPENED) {
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
addlog("%s: lcp echo req but lcp closed\n",
|
|
|
|
ifp->if_xname);
|
1999-04-04 10:07:56 +04:00
|
|
|
++ifp->if_ierrors;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (len < 8) {
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
addlog("%s: invalid lcp echo request "
|
1999-04-04 10:07:56 +04:00
|
|
|
"packet length: %d bytes\n",
|
2003-05-15 02:41:40 +04:00
|
|
|
ifp->if_xname, len);
|
1999-04-04 10:07:56 +04:00
|
|
|
break;
|
|
|
|
}
|
2001-12-05 00:32:15 +03:00
|
|
|
memcpy(&u32, h + 1, sizeof u32);
|
|
|
|
if (ntohl(u32) == sp->lcp.magic) {
|
1999-04-04 10:07:56 +04:00
|
|
|
/* Line loopback mode detected. */
|
2003-05-15 02:41:40 +04:00
|
|
|
printf("%s: loopback\n", ifp->if_xname);
|
2002-09-25 11:24:06 +04:00
|
|
|
if_down(ifp);
|
|
|
|
IF_PURGE(&sp->pp_cpq);
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
/* Shut down the PPP link. */
|
|
|
|
/* XXX */
|
|
|
|
lcp.Down(sp);
|
|
|
|
lcp.Up(sp);
|
|
|
|
break;
|
|
|
|
}
|
2001-12-05 00:32:15 +03:00
|
|
|
u32 = htonl(sp->lcp.magic);
|
|
|
|
memcpy(h + 1, &u32, sizeof u32);
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
addlog("%s: got lcp echo req, sending echo rep\n",
|
|
|
|
ifp->if_xname);
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_cp_send(sp, PPP_LCP, ECHO_REPLY, h->ident, len - 4,
|
|
|
|
h + 1);
|
1999-03-25 06:38:00 +03:00
|
|
|
break;
|
1999-04-04 10:07:56 +04:00
|
|
|
case ECHO_REPLY:
|
|
|
|
if (cp->proto != PPP_LCP)
|
|
|
|
goto illegal;
|
|
|
|
if (h->ident != sp->lcp.echoid) {
|
|
|
|
++ifp->if_ierrors;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (len < 8) {
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
addlog("%s: lcp invalid echo reply "
|
1999-04-04 10:07:56 +04:00
|
|
|
"packet length: %d bytes\n",
|
2003-05-15 02:41:40 +04:00
|
|
|
ifp->if_xname, len);
|
1999-04-04 10:07:56 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
addlog("%s: lcp got echo rep\n",
|
|
|
|
ifp->if_xname);
|
2001-12-05 00:32:15 +03:00
|
|
|
memcpy(&u32, h + 1, sizeof u32);
|
|
|
|
if (ntohl(u32) != sp->lcp.magic)
|
1999-04-04 10:07:56 +04:00
|
|
|
sp->pp_alivecnt = 0;
|
1999-03-25 06:38:00 +03:00
|
|
|
break;
|
1999-04-04 10:07:56 +04:00
|
|
|
default:
|
|
|
|
/* Unknown packet type -- send Code-Reject packet. */
|
|
|
|
illegal:
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
addlog("%s: %s send code-rej for 0x%x\n",
|
|
|
|
ifp->if_xname, cp->name, h->type);
|
2000-05-02 16:43:16 +04:00
|
|
|
sppp_cp_send(sp, cp->proto, CODE_REJ,
|
|
|
|
++sp->pp_seq[cp->protoidx], m->m_pkthdr.len, h);
|
1999-04-04 10:07:56 +04:00
|
|
|
++ifp->if_ierrors;
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The generic part of all Up/Down/Open/Close/TO event handlers.
|
|
|
|
* Basically, the state transition handling in the automaton.
|
|
|
|
*/
|
1999-03-25 06:38:00 +03:00
|
|
|
static void
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_up_event(const struct cp *cp, struct sppp *sp)
|
1999-03-25 06:38:00 +03:00
|
|
|
{
|
1999-04-04 10:07:56 +04:00
|
|
|
STDDCL;
|
1999-03-25 06:38:00 +03:00
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: %s up(%s)\n",
|
|
|
|
ifp->if_xname, cp->name,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_state_name(sp->state[cp->protoidx]));
|
|
|
|
|
|
|
|
switch (sp->state[cp->protoidx]) {
|
|
|
|
case STATE_INITIAL:
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_CLOSED);
|
|
|
|
break;
|
|
|
|
case STATE_STARTING:
|
|
|
|
sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
|
|
|
|
(cp->scr)(sp);
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
|
|
|
|
break;
|
|
|
|
default:
|
2003-05-15 02:41:40 +04:00
|
|
|
printf("%s: %s illegal up in state %s\n",
|
|
|
|
ifp->if_xname, cp->name,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_state_name(sp->state[cp->protoidx]));
|
|
|
|
}
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_down_event(const struct cp *cp, struct sppp *sp)
|
1999-03-25 06:38:00 +03:00
|
|
|
{
|
1999-04-04 10:07:56 +04:00
|
|
|
STDDCL;
|
|
|
|
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: %s down(%s)\n",
|
|
|
|
ifp->if_xname, cp->name,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_state_name(sp->state[cp->protoidx]));
|
|
|
|
|
|
|
|
switch (sp->state[cp->protoidx]) {
|
|
|
|
case STATE_CLOSED:
|
|
|
|
case STATE_CLOSING:
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_INITIAL);
|
|
|
|
break;
|
|
|
|
case STATE_STOPPED:
|
|
|
|
(cp->tls)(sp);
|
|
|
|
/* fall through */
|
|
|
|
case STATE_STOPPING:
|
|
|
|
case STATE_REQ_SENT:
|
|
|
|
case STATE_ACK_RCVD:
|
|
|
|
case STATE_ACK_SENT:
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_STARTING);
|
|
|
|
break;
|
|
|
|
case STATE_OPENED:
|
|
|
|
(cp->tld)(sp);
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_STARTING);
|
|
|
|
break;
|
|
|
|
default:
|
2003-05-15 02:41:40 +04:00
|
|
|
printf("%s: %s illegal down in state %s\n",
|
|
|
|
ifp->if_xname, cp->name,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_state_name(sp->state[cp->protoidx]));
|
|
|
|
}
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
|
1999-03-25 06:38:00 +03:00
|
|
|
static void
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_open_event(const struct cp *cp, struct sppp *sp)
|
1999-03-25 06:38:00 +03:00
|
|
|
{
|
1999-04-04 10:07:56 +04:00
|
|
|
STDDCL;
|
1999-03-25 06:38:00 +03:00
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: %s open(%s)\n",
|
|
|
|
ifp->if_xname, cp->name,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_state_name(sp->state[cp->protoidx]));
|
|
|
|
|
|
|
|
switch (sp->state[cp->protoidx]) {
|
|
|
|
case STATE_INITIAL:
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_STARTING);
|
2006-05-21 09:09:13 +04:00
|
|
|
(cp->tls)(sp);
|
1999-04-04 10:07:56 +04:00
|
|
|
break;
|
|
|
|
case STATE_STARTING:
|
|
|
|
break;
|
|
|
|
case STATE_CLOSED:
|
|
|
|
sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
|
|
|
|
(cp->scr)(sp);
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
|
|
|
|
break;
|
|
|
|
case STATE_STOPPED:
|
|
|
|
case STATE_STOPPING:
|
|
|
|
case STATE_REQ_SENT:
|
|
|
|
case STATE_ACK_RCVD:
|
|
|
|
case STATE_ACK_SENT:
|
|
|
|
case STATE_OPENED:
|
|
|
|
break;
|
|
|
|
case STATE_CLOSING:
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_STOPPING);
|
|
|
|
break;
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_close_event(const struct cp *cp, struct sppp *sp)
|
|
|
|
{
|
|
|
|
STDDCL;
|
|
|
|
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: %s close(%s)\n",
|
|
|
|
ifp->if_xname, cp->name,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_state_name(sp->state[cp->protoidx]));
|
|
|
|
|
|
|
|
switch (sp->state[cp->protoidx]) {
|
|
|
|
case STATE_INITIAL:
|
|
|
|
case STATE_CLOSED:
|
|
|
|
case STATE_CLOSING:
|
1999-03-25 06:38:00 +03:00
|
|
|
break;
|
1999-04-04 10:07:56 +04:00
|
|
|
case STATE_STARTING:
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_INITIAL);
|
2006-05-21 09:09:13 +04:00
|
|
|
(cp->tlf)(sp);
|
1999-03-25 06:38:00 +03:00
|
|
|
break;
|
1999-04-04 10:07:56 +04:00
|
|
|
case STATE_STOPPED:
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_CLOSED);
|
1999-03-25 06:38:00 +03:00
|
|
|
break;
|
1999-04-04 10:07:56 +04:00
|
|
|
case STATE_STOPPING:
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_CLOSING);
|
|
|
|
break;
|
|
|
|
case STATE_OPENED:
|
|
|
|
(cp->tld)(sp);
|
|
|
|
/* fall through */
|
|
|
|
case STATE_REQ_SENT:
|
|
|
|
case STATE_ACK_RCVD:
|
|
|
|
case STATE_ACK_SENT:
|
|
|
|
sp->rst_counter[cp->protoidx] = sp->lcp.max_terminate;
|
2000-05-02 16:43:16 +04:00
|
|
|
sppp_cp_send(sp, cp->proto, TERM_REQ,
|
|
|
|
++sp->pp_seq[cp->protoidx], 0, 0);
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_cp_change_state(cp, sp, STATE_CLOSING);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_to_event(const struct cp *cp, struct sppp *sp)
|
|
|
|
{
|
|
|
|
STDDCL;
|
|
|
|
int s;
|
|
|
|
|
2001-04-14 03:29:55 +04:00
|
|
|
s = splnet();
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: %s TO(%s) rst_counter = %d\n",
|
|
|
|
ifp->if_xname, cp->name,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_state_name(sp->state[cp->protoidx]),
|
|
|
|
sp->rst_counter[cp->protoidx]);
|
|
|
|
|
|
|
|
if (--sp->rst_counter[cp->protoidx] < 0)
|
|
|
|
/* TO- event */
|
|
|
|
switch (sp->state[cp->protoidx]) {
|
|
|
|
case STATE_CLOSING:
|
|
|
|
(cp->tlf)(sp);
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_CLOSED);
|
2001-07-17 23:12:02 +04:00
|
|
|
sppp_lcp_check_and_close(sp);
|
1999-04-04 10:07:56 +04:00
|
|
|
break;
|
|
|
|
case STATE_STOPPING:
|
|
|
|
(cp->tlf)(sp);
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_STOPPED);
|
2001-07-17 23:12:02 +04:00
|
|
|
sppp_lcp_check_and_close(sp);
|
1999-04-04 10:07:56 +04:00
|
|
|
break;
|
|
|
|
case STATE_REQ_SENT:
|
|
|
|
case STATE_ACK_RCVD:
|
|
|
|
case STATE_ACK_SENT:
|
|
|
|
(cp->tlf)(sp);
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_STOPPED);
|
2001-07-17 23:12:02 +04:00
|
|
|
sppp_lcp_check_and_close(sp);
|
1999-03-25 06:38:00 +03:00
|
|
|
break;
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
/* TO+ event */
|
|
|
|
switch (sp->state[cp->protoidx]) {
|
|
|
|
case STATE_CLOSING:
|
|
|
|
case STATE_STOPPING:
|
2000-05-02 16:43:16 +04:00
|
|
|
sppp_cp_send(sp, cp->proto, TERM_REQ,
|
|
|
|
++sp->pp_seq[cp->protoidx], 0, 0);
|
2000-03-23 10:01:25 +03:00
|
|
|
callout_reset(&sp->ch[cp->protoidx], sp->lcp.timeout,
|
|
|
|
cp->TO, sp);
|
1999-03-25 06:38:00 +03:00
|
|
|
break;
|
1999-04-04 10:07:56 +04:00
|
|
|
case STATE_REQ_SENT:
|
|
|
|
case STATE_ACK_RCVD:
|
|
|
|
(cp->scr)(sp);
|
|
|
|
/* sppp_cp_change_state() will restart the timer */
|
|
|
|
sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
|
1999-03-25 06:38:00 +03:00
|
|
|
break;
|
1999-04-04 10:07:56 +04:00
|
|
|
case STATE_ACK_SENT:
|
|
|
|
(cp->scr)(sp);
|
2000-03-23 10:01:25 +03:00
|
|
|
callout_reset(&sp->ch[cp->protoidx], sp->lcp.timeout,
|
|
|
|
cp->TO, sp);
|
1999-03-25 06:38:00 +03:00
|
|
|
break;
|
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Change the state of a control protocol in the state automaton.
|
|
|
|
* Takes care of starting/stopping the restart timer.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
sppp_cp_change_state(const struct cp *cp, struct sppp *sp, int newstate)
|
|
|
|
{
|
|
|
|
sp->state[cp->protoidx] = newstate;
|
2000-03-23 10:01:25 +03:00
|
|
|
callout_stop(&sp->ch[cp->protoidx]);
|
1999-04-04 10:07:56 +04:00
|
|
|
switch (newstate) {
|
|
|
|
case STATE_INITIAL:
|
|
|
|
case STATE_STARTING:
|
|
|
|
case STATE_CLOSED:
|
|
|
|
case STATE_STOPPED:
|
|
|
|
case STATE_OPENED:
|
|
|
|
break;
|
|
|
|
case STATE_CLOSING:
|
|
|
|
case STATE_STOPPING:
|
|
|
|
case STATE_REQ_SENT:
|
|
|
|
case STATE_ACK_RCVD:
|
|
|
|
case STATE_ACK_SENT:
|
2000-03-23 10:01:25 +03:00
|
|
|
callout_reset(&sp->ch[cp->protoidx], sp->lcp.timeout,
|
|
|
|
cp->TO, sp);
|
1999-03-25 06:38:00 +03:00
|
|
|
break;
|
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
2002-01-19 01:39:12 +03:00
|
|
|
|
|
|
|
/*
|
1999-04-04 10:07:56 +04:00
|
|
|
*--------------------------------------------------------------------------*
|
|
|
|
* *
|
|
|
|
* The LCP implementation. *
|
|
|
|
* *
|
|
|
|
*--------------------------------------------------------------------------*
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
sppp_lcp_init(struct sppp *sp)
|
|
|
|
{
|
|
|
|
sp->lcp.opts = (1 << LCP_OPT_MAGIC);
|
|
|
|
sp->lcp.magic = 0;
|
|
|
|
sp->state[IDX_LCP] = STATE_INITIAL;
|
|
|
|
sp->fail_counter[IDX_LCP] = 0;
|
2000-05-02 16:43:16 +04:00
|
|
|
sp->pp_seq[IDX_LCP] = 0;
|
|
|
|
sp->pp_rseq[IDX_LCP] = 0;
|
1999-04-04 10:07:56 +04:00
|
|
|
sp->lcp.protos = 0;
|
2007-06-23 12:45:25 +04:00
|
|
|
if (sp->pp_if.if_mtu < PP_MTU) {
|
|
|
|
sp->lcp.mru = sp->pp_if.if_mtu;
|
|
|
|
sp->lcp.opts |= (1 << LCP_OPT_MRU);
|
|
|
|
} else
|
|
|
|
sp->lcp.mru = PP_MTU;
|
|
|
|
sp->lcp.their_mru = PP_MTU;
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize counters and timeout values. Note that we don't
|
|
|
|
* use the 3 seconds suggested in RFC 1661 since we are likely
|
|
|
|
* running on a fast link. XXX We should probably implement
|
|
|
|
* the exponential backoff option. Note that these values are
|
|
|
|
* relevant for all control protocols, not just LCP only.
|
|
|
|
*/
|
|
|
|
sp->lcp.timeout = 1 * hz;
|
|
|
|
sp->lcp.max_terminate = 2;
|
|
|
|
sp->lcp.max_configure = 10;
|
|
|
|
sp->lcp.max_failure = 10;
|
2007-07-10 00:51:58 +04:00
|
|
|
callout_init(&sp->ch[IDX_LCP], 0);
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
static void
|
|
|
|
sppp_lcp_up(struct sppp *sp)
|
1999-03-25 06:38:00 +03:00
|
|
|
{
|
1999-04-04 10:07:56 +04:00
|
|
|
STDDCL;
|
|
|
|
|
2002-01-14 10:39:14 +03:00
|
|
|
/* Initialize activity timestamp: opening a connection is an activity */
|
2006-06-08 02:33:33 +04:00
|
|
|
sp->pp_last_receive = sp->pp_last_activity = time_uptime;
|
2002-01-14 10:39:14 +03:00
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
/*
|
|
|
|
* If this interface is passive or dial-on-demand, and we are
|
|
|
|
* still in Initial state, it means we've got an incoming
|
|
|
|
* call. Activate the interface.
|
|
|
|
*/
|
|
|
|
if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) != 0) {
|
|
|
|
if (debug)
|
|
|
|
log(LOG_DEBUG,
|
2003-05-15 02:41:40 +04:00
|
|
|
"%s: Up event", ifp->if_xname);
|
1999-04-04 10:07:56 +04:00
|
|
|
ifp->if_flags |= IFF_RUNNING;
|
|
|
|
if (sp->state[IDX_LCP] == STATE_INITIAL) {
|
|
|
|
if (debug)
|
|
|
|
addlog("(incoming call)\n");
|
|
|
|
sp->pp_flags |= PP_CALLIN;
|
|
|
|
lcp.Open(sp);
|
|
|
|
} else if (debug)
|
|
|
|
addlog("\n");
|
2001-12-10 03:22:21 +03:00
|
|
|
} else if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) == 0 &&
|
|
|
|
(sp->state[IDX_LCP] == STATE_INITIAL)) {
|
|
|
|
ifp->if_flags |= IFF_RUNNING;
|
|
|
|
lcp.Open(sp);
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
sppp_up_event(&lcp, sp);
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_lcp_down(struct sppp *sp)
|
1999-03-25 06:38:00 +03:00
|
|
|
{
|
1999-04-04 10:07:56 +04:00
|
|
|
STDDCL;
|
|
|
|
|
|
|
|
sppp_down_event(&lcp, sp);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If this is neither a dial-on-demand nor a passive
|
|
|
|
* interface, simulate an ``ifconfig down'' action, so the
|
|
|
|
* administrator can force a redial by another ``ifconfig
|
|
|
|
* up''. XXX For leased line operation, should we immediately
|
|
|
|
* try to reopen the connection here?
|
|
|
|
*/
|
|
|
|
if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) == 0) {
|
2002-04-29 20:29:29 +04:00
|
|
|
if (debug)
|
|
|
|
log(LOG_INFO,
|
2003-05-15 02:41:40 +04:00
|
|
|
"%s: Down event (carrier loss), taking interface down.\n",
|
|
|
|
ifp->if_xname);
|
1999-04-04 10:07:56 +04:00
|
|
|
if_down(ifp);
|
|
|
|
} else {
|
|
|
|
if (debug)
|
|
|
|
log(LOG_DEBUG,
|
2003-05-15 02:41:40 +04:00
|
|
|
"%s: Down event (carrier loss)\n",
|
|
|
|
ifp->if_xname);
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
sp->pp_flags &= ~PP_CALLIN;
|
|
|
|
if (sp->state[IDX_LCP] != STATE_INITIAL)
|
|
|
|
lcp.Close(sp);
|
|
|
|
ifp->if_flags &= ~IFF_RUNNING;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_lcp_open(struct sppp *sp)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If we are authenticator, negotiate LCP_AUTH
|
|
|
|
*/
|
|
|
|
if (sp->hisauth.proto != 0)
|
|
|
|
sp->lcp.opts |= (1 << LCP_OPT_AUTH_PROTO);
|
|
|
|
else
|
|
|
|
sp->lcp.opts &= ~(1 << LCP_OPT_AUTH_PROTO);
|
|
|
|
sp->pp_flags &= ~PP_NEEDAUTH;
|
|
|
|
sppp_open_event(&lcp, sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_lcp_close(struct sppp *sp)
|
|
|
|
{
|
|
|
|
sppp_close_event(&lcp, sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_lcp_TO(void *cookie)
|
|
|
|
{
|
|
|
|
sppp_to_event(&lcp, (struct sppp *)cookie);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Analyze a configure request. Return true if it was agreeable, and
|
|
|
|
* caused action sca, false if it has been rejected or nak'ed, and
|
|
|
|
* caused action scn. (The return value is used to make the state
|
|
|
|
* transition decision in the state automaton.)
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
sppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len)
|
|
|
|
{
|
|
|
|
STDDCL;
|
|
|
|
u_char *buf, *r, *p;
|
|
|
|
int origlen, rlen;
|
2001-12-05 00:32:15 +03:00
|
|
|
u_int32_t nmagic;
|
1999-04-04 10:07:56 +04:00
|
|
|
u_short authproto;
|
|
|
|
|
|
|
|
len -= 4;
|
|
|
|
origlen = len;
|
|
|
|
buf = r = malloc (len, M_TEMP, M_NOWAIT);
|
|
|
|
if (! buf)
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: lcp parse opts:",
|
|
|
|
ifp->if_xname);
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
/* pass 1: check for things that need to be rejected */
|
2002-09-25 11:24:06 +04:00
|
|
|
p = (void *)(h + 1);
|
1999-04-04 10:07:56 +04:00
|
|
|
for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
|
2006-08-24 00:02:23 +04:00
|
|
|
/* Sanity check option length */
|
|
|
|
if (p[1] > len) {
|
|
|
|
/*
|
2006-11-25 00:23:07 +03:00
|
|
|
* Malicious option - drop immediately.
|
2006-08-24 00:02:23 +04:00
|
|
|
* XXX Maybe we should just RXJ it?
|
|
|
|
*/
|
|
|
|
addlog("%s: received malicious LCP option 0x%02x, "
|
|
|
|
"length 0x%02x, (len: 0x%02x) dropping.\n", ifp->if_xname,
|
|
|
|
p[0], p[1], len);
|
|
|
|
goto drop;
|
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" %s", sppp_lcp_opt_name(*p));
|
1999-04-04 10:07:56 +04:00
|
|
|
switch (*p) {
|
|
|
|
case LCP_OPT_MAGIC:
|
|
|
|
/* Magic number. */
|
|
|
|
/* fall through, both are same length */
|
|
|
|
case LCP_OPT_ASYNC_MAP:
|
|
|
|
/* Async control character map. */
|
|
|
|
if (len >= 6 || p[1] == 6)
|
|
|
|
continue;
|
|
|
|
if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" [invalid]");
|
1999-04-04 10:07:56 +04:00
|
|
|
break;
|
|
|
|
case LCP_OPT_MRU:
|
|
|
|
/* Maximum receive unit. */
|
|
|
|
if (len >= 4 && p[1] == 4)
|
|
|
|
continue;
|
|
|
|
if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" [invalid]");
|
1999-04-04 10:07:56 +04:00
|
|
|
break;
|
|
|
|
case LCP_OPT_AUTH_PROTO:
|
|
|
|
if (len < 4) {
|
|
|
|
if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" [invalid]");
|
1999-04-04 10:07:56 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
authproto = (p[2] << 8) + p[3];
|
|
|
|
if (authproto == PPP_CHAP && p[1] != 5) {
|
|
|
|
if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" [invalid chap len]");
|
1999-04-04 10:07:56 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (sp->myauth.proto == 0) {
|
|
|
|
/* we are not configured to do auth */
|
|
|
|
if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" [not configured]");
|
1999-04-04 10:07:56 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Remote want us to authenticate, remember this,
|
2002-01-04 15:21:24 +03:00
|
|
|
* so we stay in SPPP_PHASE_AUTHENTICATE after LCP got
|
1999-04-04 10:07:56 +04:00
|
|
|
* up.
|
|
|
|
*/
|
|
|
|
sp->pp_flags |= PP_NEEDAUTH;
|
|
|
|
continue;
|
|
|
|
default:
|
|
|
|
/* Others not supported. */
|
|
|
|
if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" [rej]");
|
1999-04-04 10:07:56 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* Add the option to rejected list. */
|
|
|
|
bcopy (p, r, p[1]);
|
|
|
|
r += p[1];
|
|
|
|
rlen += p[1];
|
|
|
|
}
|
|
|
|
if (rlen) {
|
|
|
|
if (debug)
|
|
|
|
addlog(" send conf-rej\n");
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_cp_send(sp, PPP_LCP, CONF_REJ, h->ident, rlen, buf);
|
2000-05-02 16:43:16 +04:00
|
|
|
goto end;
|
1999-04-04 10:07:56 +04:00
|
|
|
} else if (debug)
|
|
|
|
addlog("\n");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* pass 2: check for option values that are unacceptable and
|
|
|
|
* thus require to be nak'ed.
|
|
|
|
*/
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: lcp parse opt values: ",
|
|
|
|
ifp->if_xname);
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2002-09-25 11:24:06 +04:00
|
|
|
p = (void *)(h + 1);
|
1999-04-04 10:07:56 +04:00
|
|
|
len = origlen;
|
|
|
|
for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
|
|
|
|
if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" %s", sppp_lcp_opt_name(*p));
|
1999-04-04 10:07:56 +04:00
|
|
|
switch (*p) {
|
|
|
|
case LCP_OPT_MAGIC:
|
|
|
|
/* Magic number -- extract. */
|
2001-12-05 00:32:15 +03:00
|
|
|
nmagic = (u_int32_t)p[2] << 24 |
|
|
|
|
(u_int32_t)p[3] << 16 | p[4] << 8 | p[5];
|
1999-04-04 10:07:56 +04:00
|
|
|
if (nmagic != sp->lcp.magic) {
|
|
|
|
if (debug)
|
2001-12-05 00:32:15 +03:00
|
|
|
addlog(" 0x%x", nmagic);
|
1999-04-04 10:07:56 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Local and remote magics equal -- loopback?
|
|
|
|
*/
|
2003-09-04 00:48:46 +04:00
|
|
|
if (sp->pp_loopcnt >= LOOPALIVECNT*5) {
|
2003-05-15 02:41:40 +04:00
|
|
|
printf ("%s: loopback\n",
|
|
|
|
ifp->if_xname);
|
1999-04-04 10:07:56 +04:00
|
|
|
sp->pp_loopcnt = 0;
|
|
|
|
if (ifp->if_flags & IFF_UP) {
|
|
|
|
if_down(ifp);
|
2001-08-23 04:56:03 +04:00
|
|
|
IF_PURGE(&sp->pp_cpq);
|
1999-04-04 10:07:56 +04:00
|
|
|
/* XXX ? */
|
|
|
|
lcp.Down(sp);
|
|
|
|
lcp.Up(sp);
|
|
|
|
}
|
|
|
|
} else if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" [glitch]");
|
1999-04-04 10:07:56 +04:00
|
|
|
++sp->pp_loopcnt;
|
|
|
|
/*
|
|
|
|
* We negate our magic here, and NAK it. If
|
|
|
|
* we see it later in an NAK packet, we
|
|
|
|
* suggest a new one.
|
|
|
|
*/
|
|
|
|
nmagic = ~sp->lcp.magic;
|
|
|
|
/* Gonna NAK it. */
|
|
|
|
p[2] = nmagic >> 24;
|
|
|
|
p[3] = nmagic >> 16;
|
|
|
|
p[4] = nmagic >> 8;
|
|
|
|
p[5] = nmagic;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LCP_OPT_ASYNC_MAP:
|
2002-07-30 17:16:35 +04:00
|
|
|
/*
|
|
|
|
* Async control character map -- just ignore it.
|
|
|
|
*
|
|
|
|
* Quote from RFC 1662, chapter 6:
|
|
|
|
* To enable this functionality, synchronous PPP
|
|
|
|
* implementations MUST always respond to the
|
|
|
|
* Async-Control-Character-Map Configuration
|
|
|
|
* Option with the LCP Configure-Ack. However,
|
|
|
|
* acceptance of the Configuration Option does
|
|
|
|
* not imply that the synchronous implementation
|
|
|
|
* will do any ACCM mapping. Instead, all such
|
|
|
|
* octet mapping will be performed by the
|
|
|
|
* asynchronous-to-synchronous converter.
|
|
|
|
*/
|
2002-07-29 02:16:47 +04:00
|
|
|
continue;
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
case LCP_OPT_MRU:
|
|
|
|
/*
|
|
|
|
* Maximum receive unit. Always agreeable,
|
|
|
|
* but ignored by now.
|
|
|
|
*/
|
|
|
|
sp->lcp.their_mru = p[2] * 256 + p[3];
|
|
|
|
if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" %ld", sp->lcp.their_mru);
|
1999-04-04 10:07:56 +04:00
|
|
|
continue;
|
|
|
|
|
|
|
|
case LCP_OPT_AUTH_PROTO:
|
|
|
|
authproto = (p[2] << 8) + p[3];
|
|
|
|
if (sp->myauth.proto != authproto) {
|
|
|
|
/* not agreed, nak */
|
|
|
|
if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" [mine %s != his %s]",
|
2003-10-03 14:29:05 +04:00
|
|
|
sppp_proto_name(sp->myauth.proto),
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_proto_name(authproto));
|
|
|
|
p[2] = sp->myauth.proto >> 8;
|
|
|
|
p[3] = sp->myauth.proto;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (authproto == PPP_CHAP && p[4] != CHAP_MD5) {
|
|
|
|
if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" [chap not MD5]");
|
1999-04-04 10:07:56 +04:00
|
|
|
p[4] = CHAP_MD5;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* Add the option to nak'ed list. */
|
|
|
|
bcopy (p, r, p[1]);
|
|
|
|
r += p[1];
|
|
|
|
rlen += p[1];
|
|
|
|
}
|
|
|
|
if (rlen) {
|
|
|
|
if (++sp->fail_counter[IDX_LCP] >= sp->lcp.max_failure) {
|
|
|
|
if (debug)
|
|
|
|
addlog(" max_failure (%d) exceeded, "
|
|
|
|
"send conf-rej\n",
|
|
|
|
sp->lcp.max_failure);
|
|
|
|
sppp_cp_send(sp, PPP_LCP, CONF_REJ, h->ident, rlen, buf);
|
|
|
|
} else {
|
|
|
|
if (debug)
|
|
|
|
addlog(" send conf-nak\n");
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_cp_send(sp, PPP_LCP, CONF_NAK, h->ident, rlen, buf);
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
2000-05-02 16:43:16 +04:00
|
|
|
goto end;
|
1999-04-04 10:07:56 +04:00
|
|
|
} else {
|
|
|
|
if (debug)
|
|
|
|
addlog(" send conf-ack\n");
|
|
|
|
sp->fail_counter[IDX_LCP] = 0;
|
|
|
|
sp->pp_loopcnt = 0;
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_cp_send(sp, PPP_LCP, CONF_ACK, h->ident, origlen, h + 1);
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
|
2000-05-02 16:43:16 +04:00
|
|
|
end:
|
2002-09-25 11:24:06 +04:00
|
|
|
free(buf, M_TEMP);
|
1999-04-04 10:07:56 +04:00
|
|
|
return (rlen == 0);
|
2006-08-24 00:02:23 +04:00
|
|
|
|
|
|
|
drop:
|
|
|
|
free(buf, M_TEMP);
|
|
|
|
return -1;
|
1999-03-25 06:38:00 +03:00
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Analyze the LCP Configure-Reject option list, and adjust our
|
|
|
|
* negotiation.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
sppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
|
|
|
|
{
|
|
|
|
STDDCL;
|
|
|
|
u_char *buf, *p;
|
|
|
|
|
|
|
|
len -= 4;
|
|
|
|
buf = malloc (len, M_TEMP, M_NOWAIT);
|
|
|
|
if (!buf)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: lcp rej opts:",
|
|
|
|
ifp->if_xname);
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2002-09-25 11:24:06 +04:00
|
|
|
p = (void *)(h + 1);
|
1999-04-04 10:07:56 +04:00
|
|
|
for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
|
2006-08-24 00:02:23 +04:00
|
|
|
/* Sanity check option length */
|
|
|
|
if (p[1] > len) {
|
|
|
|
/*
|
2006-11-25 00:23:07 +03:00
|
|
|
* Malicious option - drop immediately.
|
2006-08-24 00:02:23 +04:00
|
|
|
* XXX Maybe we should just RXJ it?
|
|
|
|
*/
|
|
|
|
addlog("%s: received malicious LCP option, "
|
|
|
|
"dropping.\n", ifp->if_xname);
|
|
|
|
goto drop;
|
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" %s", sppp_lcp_opt_name(*p));
|
1999-04-04 10:07:56 +04:00
|
|
|
switch (*p) {
|
|
|
|
case LCP_OPT_MAGIC:
|
|
|
|
/* Magic number -- can't use it, use 0 */
|
|
|
|
sp->lcp.opts &= ~(1 << LCP_OPT_MAGIC);
|
|
|
|
sp->lcp.magic = 0;
|
|
|
|
break;
|
|
|
|
case LCP_OPT_MRU:
|
|
|
|
/*
|
2007-06-23 12:45:25 +04:00
|
|
|
* We try to negotiate a lower MRU if the underlying
|
|
|
|
* link's MTU is less than PP_MTU (e.g. PPPoE). If the
|
|
|
|
* peer rejects this lower rate, fallback to the
|
|
|
|
* default.
|
1999-04-04 10:07:56 +04:00
|
|
|
*/
|
2007-06-23 12:45:25 +04:00
|
|
|
if (debug) {
|
|
|
|
addlog("%s: warning: peer rejected our MRU of "
|
|
|
|
"%ld bytes. Defaulting to %d bytes\n",
|
|
|
|
ifp->if_xname, sp->lcp.mru, PP_MTU);
|
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
sp->lcp.opts &= ~(1 << LCP_OPT_MRU);
|
2007-06-23 12:45:25 +04:00
|
|
|
sp->lcp.mru = PP_MTU;
|
1999-04-04 10:07:56 +04:00
|
|
|
break;
|
|
|
|
case LCP_OPT_AUTH_PROTO:
|
|
|
|
/*
|
|
|
|
* Peer doesn't want to authenticate himself,
|
|
|
|
* deny unless this is a dialout call, and
|
2002-01-04 15:21:24 +03:00
|
|
|
* SPPP_AUTHFLAG_NOCALLOUT is set.
|
1999-04-04 10:07:56 +04:00
|
|
|
*/
|
|
|
|
if ((sp->pp_flags & PP_CALLIN) == 0 &&
|
2002-01-04 15:21:24 +03:00
|
|
|
(sp->hisauth.flags & SPPP_AUTHFLAG_NOCALLOUT) != 0) {
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" [don't insist on auth "
|
1999-04-04 10:07:56 +04:00
|
|
|
"for callout]");
|
|
|
|
sp->lcp.opts &= ~(1 << LCP_OPT_AUTH_PROTO);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (debug)
|
|
|
|
addlog("[access denied]\n");
|
|
|
|
lcp.Close(sp);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (debug)
|
|
|
|
addlog("\n");
|
2006-08-24 00:02:23 +04:00
|
|
|
drop:
|
2002-09-25 11:24:06 +04:00
|
|
|
free(buf, M_TEMP);
|
1999-04-04 10:07:56 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Analyze the LCP Configure-NAK option list, and adjust our
|
|
|
|
* negotiation.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
sppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
|
|
|
|
{
|
|
|
|
STDDCL;
|
|
|
|
u_char *buf, *p;
|
2001-12-05 00:32:15 +03:00
|
|
|
u_int32_t magic;
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
len -= 4;
|
|
|
|
buf = malloc (len, M_TEMP, M_NOWAIT);
|
|
|
|
if (!buf)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: lcp nak opts:",
|
|
|
|
ifp->if_xname);
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2002-09-25 11:24:06 +04:00
|
|
|
p = (void *)(h + 1);
|
1999-04-04 10:07:56 +04:00
|
|
|
for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
|
2006-08-24 00:02:23 +04:00
|
|
|
/* Sanity check option length */
|
|
|
|
if (p[1] > len) {
|
|
|
|
/*
|
2006-11-25 00:23:07 +03:00
|
|
|
* Malicious option - drop immediately.
|
2006-08-24 00:02:23 +04:00
|
|
|
* XXX Maybe we should just RXJ it?
|
|
|
|
*/
|
|
|
|
addlog("%s: received malicious LCP option, "
|
|
|
|
"dropping.\n", ifp->if_xname);
|
|
|
|
goto drop;
|
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" %s", sppp_lcp_opt_name(*p));
|
1999-04-04 10:07:56 +04:00
|
|
|
switch (*p) {
|
|
|
|
case LCP_OPT_MAGIC:
|
|
|
|
/* Magic number -- renegotiate */
|
|
|
|
if ((sp->lcp.opts & (1 << LCP_OPT_MAGIC)) &&
|
|
|
|
len >= 6 && p[1] == 6) {
|
2001-12-05 00:32:15 +03:00
|
|
|
magic = (u_int32_t)p[2] << 24 |
|
|
|
|
(u_int32_t)p[3] << 16 | p[4] << 8 | p[5];
|
1999-04-04 10:07:56 +04:00
|
|
|
/*
|
|
|
|
* If the remote magic is our negated one,
|
|
|
|
* this looks like a loopback problem.
|
|
|
|
* Suggest a new magic to make sure.
|
|
|
|
*/
|
|
|
|
if (magic == ~sp->lcp.magic) {
|
|
|
|
if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" magic glitch");
|
2003-05-15 03:16:44 +04:00
|
|
|
sp->lcp.magic = arc4random();
|
1999-04-04 10:07:56 +04:00
|
|
|
} else {
|
|
|
|
sp->lcp.magic = magic;
|
|
|
|
if (debug)
|
2001-12-05 00:32:15 +03:00
|
|
|
addlog(" %d", magic);
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LCP_OPT_MRU:
|
|
|
|
/*
|
|
|
|
* Peer wants to advise us to negotiate an MRU.
|
|
|
|
* Agree on it if it's reasonable, or use
|
|
|
|
* default otherwise.
|
|
|
|
*/
|
|
|
|
if (len >= 4 && p[1] == 4) {
|
|
|
|
u_int mru = p[2] * 256 + p[3];
|
|
|
|
if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" %d", mru);
|
2007-06-23 12:45:25 +04:00
|
|
|
if (mru < PPP_MINMRU || mru > sp->pp_if.if_mtu)
|
|
|
|
mru = sp->pp_if.if_mtu;
|
1999-04-04 10:07:56 +04:00
|
|
|
sp->lcp.mru = mru;
|
|
|
|
sp->lcp.opts |= (1 << LCP_OPT_MRU);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LCP_OPT_AUTH_PROTO:
|
|
|
|
/*
|
|
|
|
* Peer doesn't like our authentication method,
|
|
|
|
* deny.
|
|
|
|
*/
|
|
|
|
if (debug)
|
|
|
|
addlog("[access denied]\n");
|
|
|
|
lcp.Close(sp);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (debug)
|
|
|
|
addlog("\n");
|
2006-08-24 00:02:23 +04:00
|
|
|
drop:
|
2002-09-25 11:24:06 +04:00
|
|
|
free(buf, M_TEMP);
|
1999-04-04 10:07:56 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_lcp_tlu(struct sppp *sp)
|
|
|
|
{
|
|
|
|
STDDCL;
|
|
|
|
int i;
|
2001-12-05 00:32:15 +03:00
|
|
|
u_int32_t mask;
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
/* XXX ? */
|
|
|
|
if (! (ifp->if_flags & IFF_UP) &&
|
|
|
|
(ifp->if_flags & IFF_RUNNING)) {
|
|
|
|
/* Coming out of loopback mode. */
|
|
|
|
if_up(ifp);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < IDX_COUNT; i++)
|
|
|
|
if ((cps[i])->flags & CP_QUAL)
|
|
|
|
(cps[i])->Open(sp);
|
|
|
|
|
|
|
|
if ((sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) != 0 ||
|
|
|
|
(sp->pp_flags & PP_NEEDAUTH) != 0)
|
2002-01-04 15:21:24 +03:00
|
|
|
sp->pp_phase = SPPP_PHASE_AUTHENTICATE;
|
1999-04-04 10:07:56 +04:00
|
|
|
else
|
2002-01-04 15:21:24 +03:00
|
|
|
sp->pp_phase = SPPP_PHASE_NETWORK;
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2003-10-02 05:27:20 +04:00
|
|
|
if (debug)
|
1999-04-04 10:07:56 +04:00
|
|
|
{
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_INFO, "%s: phase %s\n", ifp->if_xname,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_phase_name(sp->pp_phase));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Open all authentication protocols. This is even required
|
|
|
|
* if we already proceeded to network phase, since it might be
|
|
|
|
* that remote wants us to authenticate, so we might have to
|
|
|
|
* send a PAP request. Undesired authentication protocols
|
|
|
|
* don't do anything when they get an Open event.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < IDX_COUNT; i++)
|
|
|
|
if ((cps[i])->flags & CP_AUTH)
|
|
|
|
(cps[i])->Open(sp);
|
|
|
|
|
2002-01-04 15:21:24 +03:00
|
|
|
if (sp->pp_phase == SPPP_PHASE_NETWORK) {
|
1999-04-04 10:07:56 +04:00
|
|
|
/* Notify all NCPs. */
|
|
|
|
for (i = 0; i < IDX_COUNT; i++)
|
|
|
|
if ((cps[i])->flags & CP_NCP)
|
|
|
|
(cps[i])->Open(sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Send Up events to all started protos. */
|
|
|
|
for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
|
2000-10-08 06:37:42 +04:00
|
|
|
if ((sp->lcp.protos & mask) && ((cps[i])->flags & CP_LCP) == 0)
|
1999-04-04 10:07:56 +04:00
|
|
|
(cps[i])->Up(sp);
|
|
|
|
|
|
|
|
/* notify low-level driver of state change */
|
|
|
|
if (sp->pp_chg)
|
|
|
|
sp->pp_chg(sp, (int)sp->pp_phase);
|
2005-02-27 01:45:09 +03:00
|
|
|
|
2002-01-04 15:21:24 +03:00
|
|
|
if (sp->pp_phase == SPPP_PHASE_NETWORK)
|
1999-04-04 10:07:56 +04:00
|
|
|
/* if no NCP is starting, close down */
|
|
|
|
sppp_lcp_check_and_close(sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_lcp_tld(struct sppp *sp)
|
|
|
|
{
|
|
|
|
STDDCL;
|
|
|
|
int i;
|
2001-12-05 00:32:15 +03:00
|
|
|
u_int32_t mask;
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2002-01-04 15:21:24 +03:00
|
|
|
sp->pp_phase = SPPP_PHASE_TERMINATE;
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2003-10-02 05:27:20 +04:00
|
|
|
if (debug)
|
1999-04-04 10:07:56 +04:00
|
|
|
{
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_INFO, "%s: phase %s\n", ifp->if_xname,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_phase_name(sp->pp_phase));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Take upper layers down. We send the Down event first and
|
|
|
|
* the Close second to prevent the upper layers from sending
|
|
|
|
* ``a flurry of terminate-request packets'', as the RFC
|
|
|
|
* describes it.
|
|
|
|
*/
|
|
|
|
for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
|
2000-10-08 06:37:42 +04:00
|
|
|
if ((sp->lcp.protos & mask) && ((cps[i])->flags & CP_LCP) == 0) {
|
1999-04-04 10:07:56 +04:00
|
|
|
(cps[i])->Down(sp);
|
|
|
|
(cps[i])->Close(sp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_lcp_tls(struct sppp *sp)
|
|
|
|
{
|
|
|
|
STDDCL;
|
|
|
|
|
2002-01-07 13:49:02 +03:00
|
|
|
if (sp->pp_max_auth_fail != 0 && sp->pp_auth_failures >= sp->pp_max_auth_fail) {
|
|
|
|
printf("%s: authentication failed %d times, not retrying again\n",
|
|
|
|
sp->pp_if.if_xname, sp->pp_auth_failures);
|
|
|
|
if_down(&sp->pp_if);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-01-04 15:21:24 +03:00
|
|
|
sp->pp_phase = SPPP_PHASE_ESTABLISH;
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2003-10-02 05:27:20 +04:00
|
|
|
if (debug)
|
1999-04-04 10:07:56 +04:00
|
|
|
{
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_INFO, "%s: phase %s\n", ifp->if_xname,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_phase_name(sp->pp_phase));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Notify lower layer if desired. */
|
|
|
|
if (sp->pp_tls)
|
|
|
|
(sp->pp_tls)(sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_lcp_tlf(struct sppp *sp)
|
|
|
|
{
|
|
|
|
STDDCL;
|
|
|
|
|
2002-01-04 15:21:24 +03:00
|
|
|
sp->pp_phase = SPPP_PHASE_DEAD;
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2003-10-02 05:27:20 +04:00
|
|
|
if (debug)
|
1999-04-04 10:07:56 +04:00
|
|
|
{
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_INFO, "%s: phase %s\n", ifp->if_xname,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_phase_name(sp->pp_phase));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Notify lower layer if desired. */
|
|
|
|
if (sp->pp_tlf)
|
|
|
|
(sp->pp_tlf)(sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_lcp_scr(struct sppp *sp)
|
|
|
|
{
|
|
|
|
char opt[6 /* magicnum */ + 4 /* mru */ + 5 /* chap */];
|
|
|
|
int i = 0;
|
|
|
|
u_short authproto;
|
|
|
|
|
|
|
|
if (sp->lcp.opts & (1 << LCP_OPT_MAGIC)) {
|
|
|
|
if (! sp->lcp.magic)
|
2003-05-15 03:16:44 +04:00
|
|
|
sp->lcp.magic = arc4random();
|
1999-04-04 10:07:56 +04:00
|
|
|
opt[i++] = LCP_OPT_MAGIC;
|
|
|
|
opt[i++] = 6;
|
|
|
|
opt[i++] = sp->lcp.magic >> 24;
|
|
|
|
opt[i++] = sp->lcp.magic >> 16;
|
|
|
|
opt[i++] = sp->lcp.magic >> 8;
|
|
|
|
opt[i++] = sp->lcp.magic;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sp->lcp.opts & (1 << LCP_OPT_MRU)) {
|
|
|
|
opt[i++] = LCP_OPT_MRU;
|
|
|
|
opt[i++] = 4;
|
|
|
|
opt[i++] = sp->lcp.mru >> 8;
|
|
|
|
opt[i++] = sp->lcp.mru;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) {
|
|
|
|
authproto = sp->hisauth.proto;
|
|
|
|
opt[i++] = LCP_OPT_AUTH_PROTO;
|
|
|
|
opt[i++] = authproto == PPP_CHAP? 5: 4;
|
|
|
|
opt[i++] = authproto >> 8;
|
|
|
|
opt[i++] = authproto;
|
|
|
|
if (authproto == PPP_CHAP)
|
|
|
|
opt[i++] = CHAP_MD5;
|
|
|
|
}
|
|
|
|
|
2000-05-02 16:43:16 +04:00
|
|
|
sp->confid[IDX_LCP] = ++sp->pp_seq[IDX_LCP];
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_cp_send(sp, PPP_LCP, CONF_REQ, sp->confid[IDX_LCP], i, &opt);
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check the open NCPs, return true if at least one NCP is open.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
sppp_ncp_check(struct sppp *sp)
|
|
|
|
{
|
|
|
|
int i, mask;
|
|
|
|
|
|
|
|
for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
|
2000-10-08 06:37:42 +04:00
|
|
|
if ((sp->lcp.protos & mask) && (cps[i])->flags & CP_NCP)
|
1999-04-04 10:07:56 +04:00
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Re-check the open NCPs and see if we should terminate the link.
|
|
|
|
* Called by the NCPs during their tlf action handling.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
sppp_lcp_check_and_close(struct sppp *sp)
|
|
|
|
{
|
|
|
|
|
2002-01-04 15:21:24 +03:00
|
|
|
if (sp->pp_phase < SPPP_PHASE_NETWORK)
|
1999-04-04 10:07:56 +04:00
|
|
|
/* don't bother, we are already going down */
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (sppp_ncp_check(sp))
|
|
|
|
return;
|
|
|
|
|
|
|
|
lcp.Close(sp);
|
|
|
|
}
|
2000-05-02 16:43:16 +04:00
|
|
|
|
|
|
|
|
2002-01-19 01:39:12 +03:00
|
|
|
/*
|
1999-04-04 10:07:56 +04:00
|
|
|
*--------------------------------------------------------------------------*
|
|
|
|
* *
|
|
|
|
* The IPCP implementation. *
|
|
|
|
* *
|
|
|
|
*--------------------------------------------------------------------------*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_ipcp_init(struct sppp *sp)
|
|
|
|
{
|
|
|
|
sp->ipcp.opts = 0;
|
|
|
|
sp->ipcp.flags = 0;
|
|
|
|
sp->state[IDX_IPCP] = STATE_INITIAL;
|
|
|
|
sp->fail_counter[IDX_IPCP] = 0;
|
2000-05-02 16:43:16 +04:00
|
|
|
sp->pp_seq[IDX_IPCP] = 0;
|
|
|
|
sp->pp_rseq[IDX_IPCP] = 0;
|
2007-07-10 00:51:58 +04:00
|
|
|
callout_init(&sp->ch[IDX_IPCP], 0);
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_ipcp_up(struct sppp *sp)
|
|
|
|
{
|
|
|
|
sppp_up_event(&ipcp, sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_ipcp_down(struct sppp *sp)
|
|
|
|
{
|
|
|
|
sppp_down_event(&ipcp, sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_ipcp_open(struct sppp *sp)
|
|
|
|
{
|
|
|
|
STDDCL;
|
2001-12-05 00:32:15 +03:00
|
|
|
u_int32_t myaddr, hisaddr;
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2001-12-08 22:46:39 +03:00
|
|
|
sp->ipcp.flags &= ~(IPCP_HISADDR_SEEN|IPCP_MYADDR_SEEN|IPCP_MYADDR_DYN|IPCP_HISADDR_DYN);
|
|
|
|
sp->ipcp.req_myaddr = 0;
|
|
|
|
sp->ipcp.req_hisaddr = 0;
|
2002-03-02 19:23:42 +03:00
|
|
|
memset(&sp->dns_addrs, 0, sizeof sp->dns_addrs);
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2004-12-06 05:59:23 +03:00
|
|
|
#ifdef INET
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_get_ip_addrs(sp, &myaddr, &hisaddr, 0);
|
2004-12-06 05:59:23 +03:00
|
|
|
#else
|
|
|
|
myaddr = hisaddr = 0;
|
|
|
|
#endif
|
1999-04-04 10:07:56 +04:00
|
|
|
/*
|
|
|
|
* If we don't have his address, this probably means our
|
|
|
|
* interface doesn't want to talk IP at all. (This could
|
|
|
|
* be the case if somebody wants to speak only IPX, for
|
|
|
|
* example.) Don't open IPCP in this case.
|
|
|
|
*/
|
2004-12-06 05:59:23 +03:00
|
|
|
if (hisaddr == 0) {
|
1999-04-04 10:07:56 +04:00
|
|
|
/* XXX this message should go away */
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: ipcp_open(): no IP interface\n",
|
|
|
|
ifp->if_xname);
|
1999-04-04 10:07:56 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-12-08 22:46:39 +03:00
|
|
|
if (myaddr == 0) {
|
1999-04-04 10:07:56 +04:00
|
|
|
/*
|
|
|
|
* I don't have an assigned address, so i need to
|
|
|
|
* negotiate my address.
|
|
|
|
*/
|
|
|
|
sp->ipcp.flags |= IPCP_MYADDR_DYN;
|
|
|
|
sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS);
|
2001-12-08 22:46:39 +03:00
|
|
|
}
|
|
|
|
if (hisaddr == 1) {
|
|
|
|
/*
|
|
|
|
* XXX - remove this hack!
|
2003-11-10 11:51:51 +03:00
|
|
|
* remote has no valid address, we need to get one assigned.
|
2001-12-08 22:46:39 +03:00
|
|
|
*/
|
|
|
|
sp->ipcp.flags |= IPCP_HISADDR_DYN;
|
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_open_event(&ipcp, sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_ipcp_close(struct sppp *sp)
|
|
|
|
{
|
2003-01-28 18:36:38 +03:00
|
|
|
STDDCL;
|
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_close_event(&ipcp, sp);
|
2004-12-06 05:59:23 +03:00
|
|
|
#ifdef INET
|
2001-12-08 22:46:39 +03:00
|
|
|
if (sp->ipcp.flags & (IPCP_MYADDR_DYN|IPCP_HISADDR_DYN))
|
1999-04-04 10:07:56 +04:00
|
|
|
/*
|
2001-12-08 22:46:39 +03:00
|
|
|
* Some address was dynamic, clear it again.
|
1999-04-04 10:07:56 +04:00
|
|
|
*/
|
2001-12-08 22:46:39 +03:00
|
|
|
sppp_clear_ip_addrs(sp);
|
2004-12-06 05:59:23 +03:00
|
|
|
#endif
|
2003-01-28 18:36:38 +03:00
|
|
|
|
|
|
|
if (sp->pp_saved_mtu > 0) {
|
|
|
|
ifp->if_mtu = sp->pp_saved_mtu;
|
|
|
|
sp->pp_saved_mtu = 0;
|
|
|
|
if (debug)
|
|
|
|
log(LOG_DEBUG,
|
2003-05-15 02:41:40 +04:00
|
|
|
"%s: resetting MTU to %" PRIu64 " bytes\n",
|
|
|
|
ifp->if_xname, ifp->if_mtu);
|
2003-01-28 18:36:38 +03:00
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_ipcp_TO(void *cookie)
|
|
|
|
{
|
|
|
|
sppp_to_event(&ipcp, (struct sppp *)cookie);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Analyze a configure request. Return true if it was agreeable, and
|
|
|
|
* caused action sca, false if it has been rejected or nak'ed, and
|
|
|
|
* caused action scn. (The return value is used to make the state
|
|
|
|
* transition decision in the state automaton.)
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
sppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len)
|
|
|
|
{
|
|
|
|
u_char *buf, *r, *p;
|
|
|
|
struct ifnet *ifp = &sp->pp_if;
|
|
|
|
int rlen, origlen, debug = ifp->if_flags & IFF_DEBUG;
|
2001-12-05 00:32:15 +03:00
|
|
|
u_int32_t hisaddr, desiredaddr;
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
len -= 4;
|
|
|
|
origlen = len;
|
|
|
|
/*
|
|
|
|
* Make sure to allocate a buf that can at least hold a
|
|
|
|
* conf-nak with an `address' option. We might need it below.
|
|
|
|
*/
|
|
|
|
buf = r = malloc ((len < 6? 6: len), M_TEMP, M_NOWAIT);
|
|
|
|
if (! buf)
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
/* pass 1: see if we can recognize them */
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: ipcp parse opts:",
|
|
|
|
ifp->if_xname);
|
2002-09-25 11:24:06 +04:00
|
|
|
p = (void *)(h + 1);
|
1999-04-04 10:07:56 +04:00
|
|
|
for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
|
2006-08-24 00:02:23 +04:00
|
|
|
/* Sanity check option length */
|
|
|
|
if (p[1] > len) {
|
|
|
|
/* XXX should we just RXJ? */
|
|
|
|
addlog("%s: malicious IPCP option received, dropping\n",
|
|
|
|
ifp->if_xname);
|
|
|
|
goto drop;
|
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" %s", sppp_ipcp_opt_name(*p));
|
1999-04-04 10:07:56 +04:00
|
|
|
switch (*p) {
|
|
|
|
#ifdef notyet
|
|
|
|
case IPCP_OPT_COMPRESSION:
|
|
|
|
if (len >= 6 && p[1] >= 6) {
|
|
|
|
/* correctly formed compress option */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" [invalid]");
|
1999-04-04 10:07:56 +04:00
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
case IPCP_OPT_ADDRESS:
|
|
|
|
if (len >= 6 && p[1] == 6) {
|
|
|
|
/* correctly formed address option */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" [invalid]");
|
1999-04-04 10:07:56 +04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Others not supported. */
|
|
|
|
if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" [rej]");
|
1999-04-04 10:07:56 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* Add the option to rejected list. */
|
|
|
|
bcopy (p, r, p[1]);
|
|
|
|
r += p[1];
|
|
|
|
rlen += p[1];
|
|
|
|
}
|
|
|
|
if (rlen) {
|
|
|
|
if (debug)
|
|
|
|
addlog(" send conf-rej\n");
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_cp_send(sp, PPP_IPCP, CONF_REJ, h->ident, rlen, buf);
|
2000-05-02 16:43:16 +04:00
|
|
|
goto end;
|
1999-04-04 10:07:56 +04:00
|
|
|
} else if (debug)
|
|
|
|
addlog("\n");
|
|
|
|
|
|
|
|
/* pass 2: parse option values */
|
2001-12-08 22:46:39 +03:00
|
|
|
if (sp->ipcp.flags & IPCP_HISADDR_SEEN)
|
|
|
|
hisaddr = sp->ipcp.req_hisaddr; /* we already aggreed on that */
|
|
|
|
else
|
2004-12-06 05:59:23 +03:00
|
|
|
#ifdef INET
|
2001-12-08 22:46:39 +03:00
|
|
|
sppp_get_ip_addrs(sp, 0, &hisaddr, 0); /* user configuration */
|
2004-12-06 05:59:23 +03:00
|
|
|
#else
|
|
|
|
hisaddr = 0;
|
|
|
|
#endif
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: ipcp parse opt values: ",
|
|
|
|
ifp->if_xname);
|
2002-09-25 11:24:06 +04:00
|
|
|
p = (void *)(h + 1);
|
1999-04-04 10:07:56 +04:00
|
|
|
len = origlen;
|
|
|
|
for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
|
|
|
|
if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" %s", sppp_ipcp_opt_name(*p));
|
1999-04-04 10:07:56 +04:00
|
|
|
switch (*p) {
|
|
|
|
#ifdef notyet
|
|
|
|
case IPCP_OPT_COMPRESSION:
|
|
|
|
continue;
|
|
|
|
#endif
|
|
|
|
case IPCP_OPT_ADDRESS:
|
|
|
|
desiredaddr = p[2] << 24 | p[3] << 16 |
|
|
|
|
p[4] << 8 | p[5];
|
2001-12-08 22:46:39 +03:00
|
|
|
if (desiredaddr == hisaddr ||
|
|
|
|
((sp->ipcp.flags & IPCP_HISADDR_DYN) && desiredaddr != 0)) {
|
1999-04-04 10:07:56 +04:00
|
|
|
/*
|
2001-12-08 22:46:39 +03:00
|
|
|
* Peer's address is same as our value,
|
|
|
|
* this is agreeable. Gonna conf-ack
|
|
|
|
* it.
|
|
|
|
*/
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug)
|
2001-12-08 22:46:39 +03:00
|
|
|
addlog(" %s [ack]",
|
|
|
|
sppp_dotted_quad(hisaddr));
|
|
|
|
/* record that we've seen it already */
|
|
|
|
sp->ipcp.flags |= IPCP_HISADDR_SEEN;
|
|
|
|
sp->ipcp.req_hisaddr = desiredaddr;
|
|
|
|
hisaddr = desiredaddr;
|
1999-04-04 10:07:56 +04:00
|
|
|
continue;
|
|
|
|
}
|
2001-12-08 22:46:39 +03:00
|
|
|
/*
|
|
|
|
* The address wasn't agreeable. This is either
|
|
|
|
* he sent us 0.0.0.0, asking to assign him an
|
|
|
|
* address, or he send us another address not
|
|
|
|
* matching our value. Either case, we gonna
|
|
|
|
* conf-nak it with our value.
|
|
|
|
*/
|
|
|
|
if (debug) {
|
|
|
|
if (desiredaddr == 0)
|
|
|
|
addlog(" [addr requested]");
|
|
|
|
else
|
|
|
|
addlog(" %s [not agreed]",
|
|
|
|
sppp_dotted_quad(desiredaddr));
|
|
|
|
}
|
|
|
|
|
|
|
|
p[2] = hisaddr >> 24;
|
|
|
|
p[3] = hisaddr >> 16;
|
|
|
|
p[4] = hisaddr >> 8;
|
|
|
|
p[5] = hisaddr;
|
|
|
|
break;
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
/* Add the option to nak'ed list. */
|
|
|
|
bcopy (p, r, p[1]);
|
|
|
|
r += p[1];
|
|
|
|
rlen += p[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we are about to conf-ack the request, but haven't seen
|
|
|
|
* his address so far, gonna conf-nak it instead, with the
|
|
|
|
* `address' option present and our idea of his address being
|
|
|
|
* filled in there, to request negotiation of both addresses.
|
|
|
|
*
|
|
|
|
* XXX This can result in an endless req - nak loop if peer
|
|
|
|
* doesn't want to send us his address. Q: What should we do
|
|
|
|
* about it? XXX A: implement the max-failure counter.
|
|
|
|
*/
|
2001-12-08 22:46:39 +03:00
|
|
|
if (rlen == 0 && !(sp->ipcp.flags & IPCP_HISADDR_SEEN)) {
|
1999-04-04 10:07:56 +04:00
|
|
|
buf[0] = IPCP_OPT_ADDRESS;
|
|
|
|
buf[1] = 6;
|
|
|
|
buf[2] = hisaddr >> 24;
|
|
|
|
buf[3] = hisaddr >> 16;
|
|
|
|
buf[4] = hisaddr >> 8;
|
|
|
|
buf[5] = hisaddr;
|
|
|
|
rlen = 6;
|
|
|
|
if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" still need hisaddr");
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (rlen) {
|
|
|
|
if (debug)
|
|
|
|
addlog(" send conf-nak\n");
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_cp_send(sp, PPP_IPCP, CONF_NAK, h->ident, rlen, buf);
|
1999-04-04 10:07:56 +04:00
|
|
|
} else {
|
|
|
|
if (debug)
|
|
|
|
addlog(" send conf-ack\n");
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_cp_send(sp, PPP_IPCP, CONF_ACK, h->ident, origlen, h + 1);
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
|
2000-05-02 16:43:16 +04:00
|
|
|
end:
|
2002-09-25 11:24:06 +04:00
|
|
|
free(buf, M_TEMP);
|
1999-04-04 10:07:56 +04:00
|
|
|
return (rlen == 0);
|
2006-08-24 00:02:23 +04:00
|
|
|
|
|
|
|
drop:
|
|
|
|
free(buf, M_TEMP);
|
|
|
|
return -1;
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Analyze the IPCP Configure-Reject option list, and adjust our
|
|
|
|
* negotiation.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
sppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
|
|
|
|
{
|
|
|
|
u_char *buf, *p;
|
|
|
|
struct ifnet *ifp = &sp->pp_if;
|
|
|
|
int debug = ifp->if_flags & IFF_DEBUG;
|
|
|
|
|
|
|
|
len -= 4;
|
|
|
|
buf = malloc (len, M_TEMP, M_NOWAIT);
|
|
|
|
if (!buf)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: ipcp rej opts:",
|
|
|
|
ifp->if_xname);
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2002-09-25 11:24:06 +04:00
|
|
|
p = (void *)(h + 1);
|
1999-04-04 10:07:56 +04:00
|
|
|
for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
|
2006-08-24 00:02:23 +04:00
|
|
|
/* Sanity check option length */
|
|
|
|
if (p[1] > len) {
|
|
|
|
/* XXX should we just RXJ? */
|
|
|
|
addlog("%s: malicious IPCP option received, dropping\n",
|
|
|
|
ifp->if_xname);
|
|
|
|
goto drop;
|
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" %s", sppp_ipcp_opt_name(*p));
|
1999-04-04 10:07:56 +04:00
|
|
|
switch (*p) {
|
|
|
|
case IPCP_OPT_ADDRESS:
|
|
|
|
/*
|
|
|
|
* Peer doesn't grok address option. This is
|
|
|
|
* bad. XXX Should we better give up here?
|
|
|
|
*/
|
|
|
|
sp->ipcp.opts &= ~(1 << IPCP_OPT_ADDRESS);
|
|
|
|
break;
|
|
|
|
#ifdef notyet
|
|
|
|
case IPCP_OPT_COMPRESS:
|
|
|
|
sp->ipcp.opts &= ~(1 << IPCP_OPT_COMPRESS);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (debug)
|
|
|
|
addlog("\n");
|
2006-08-24 00:02:23 +04:00
|
|
|
drop:
|
2002-09-25 11:24:06 +04:00
|
|
|
free(buf, M_TEMP);
|
1999-04-04 10:07:56 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Analyze the IPCP Configure-NAK option list, and adjust our
|
|
|
|
* negotiation.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
sppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
|
|
|
|
{
|
2002-03-02 19:23:42 +03:00
|
|
|
u_char *p;
|
1999-04-04 10:07:56 +04:00
|
|
|
struct ifnet *ifp = &sp->pp_if;
|
|
|
|
int debug = ifp->if_flags & IFF_DEBUG;
|
2001-12-05 00:32:15 +03:00
|
|
|
u_int32_t wantaddr;
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
len -= 4;
|
|
|
|
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: ipcp nak opts:",
|
|
|
|
ifp->if_xname);
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2002-09-25 11:24:06 +04:00
|
|
|
p = (void *)(h + 1);
|
1999-04-04 10:07:56 +04:00
|
|
|
for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
|
2006-08-24 00:02:23 +04:00
|
|
|
/* Sanity check option length */
|
|
|
|
if (p[1] > len) {
|
|
|
|
/* XXX should we just RXJ? */
|
|
|
|
addlog("%s: malicious IPCP option received, dropping\n",
|
|
|
|
ifp->if_xname);
|
|
|
|
return;
|
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" %s", sppp_ipcp_opt_name(*p));
|
1999-04-04 10:07:56 +04:00
|
|
|
switch (*p) {
|
|
|
|
case IPCP_OPT_ADDRESS:
|
|
|
|
/*
|
|
|
|
* Peer doesn't like our local IP address. See
|
|
|
|
* if we can do something for him. We'll drop
|
|
|
|
* him our address then.
|
|
|
|
*/
|
|
|
|
if (len >= 6 && p[1] == 6) {
|
|
|
|
wantaddr = p[2] << 24 | p[3] << 16 |
|
|
|
|
p[4] << 8 | p[5];
|
|
|
|
sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS);
|
|
|
|
if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" [wantaddr %s]",
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_dotted_quad(wantaddr));
|
|
|
|
/*
|
|
|
|
* When doing dynamic address assignment,
|
|
|
|
* we accept his offer. Otherwise, we
|
|
|
|
* ignore it and thus continue to negotiate
|
|
|
|
* our already existing value.
|
|
|
|
*/
|
|
|
|
if (sp->ipcp.flags & IPCP_MYADDR_DYN) {
|
|
|
|
if (debug)
|
2000-05-02 16:43:16 +04:00
|
|
|
addlog(" [agree]");
|
1999-04-04 10:07:56 +04:00
|
|
|
sp->ipcp.flags |= IPCP_MYADDR_SEEN;
|
2001-12-08 22:46:39 +03:00
|
|
|
sp->ipcp.req_myaddr = wantaddr;
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2002-03-02 19:23:42 +03:00
|
|
|
|
|
|
|
case IPCP_OPT_PRIMDNS:
|
|
|
|
if (len >= 6 && p[1] == 6) {
|
|
|
|
sp->dns_addrs[0] = p[2] << 24 | p[3] << 16 |
|
2005-02-27 01:45:09 +03:00
|
|
|
p[4] << 8 | p[5];
|
2002-03-02 19:23:42 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPCP_OPT_SECDNS:
|
|
|
|
if (len >= 6 && p[1] == 6) {
|
|
|
|
sp->dns_addrs[1] = p[2] << 24 | p[3] << 16 |
|
2005-02-27 01:45:09 +03:00
|
|
|
p[4] << 8 | p[5];
|
2002-03-02 19:23:42 +03:00
|
|
|
}
|
|
|
|
break;
|
1999-04-04 10:07:56 +04:00
|
|
|
#ifdef notyet
|
|
|
|
case IPCP_OPT_COMPRESS:
|
|
|
|
/*
|
|
|
|
* Peer wants different compression parameters.
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (debug)
|
|
|
|
addlog("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_ipcp_tlu(struct sppp *sp)
|
|
|
|
{
|
2004-12-06 05:59:23 +03:00
|
|
|
#ifdef INET
|
2001-12-08 22:46:39 +03:00
|
|
|
/* we are up. Set addresses and notify anyone interested */
|
2003-01-28 18:36:38 +03:00
|
|
|
STDDCL;
|
2001-12-08 22:46:39 +03:00
|
|
|
u_int32_t myaddr, hisaddr;
|
2003-01-28 18:36:38 +03:00
|
|
|
|
2001-12-08 22:46:39 +03:00
|
|
|
sppp_get_ip_addrs(sp, &myaddr, &hisaddr, 0);
|
|
|
|
if ((sp->ipcp.flags & IPCP_MYADDR_DYN) && (sp->ipcp.flags & IPCP_MYADDR_SEEN))
|
|
|
|
myaddr = sp->ipcp.req_myaddr;
|
|
|
|
if ((sp->ipcp.flags & IPCP_HISADDR_DYN) && (sp->ipcp.flags & IPCP_HISADDR_SEEN))
|
|
|
|
hisaddr = sp->ipcp.req_hisaddr;
|
|
|
|
sppp_set_ip_addrs(sp, myaddr, hisaddr);
|
2003-01-28 18:36:38 +03:00
|
|
|
|
|
|
|
if (ifp->if_mtu > sp->lcp.their_mru) {
|
|
|
|
sp->pp_saved_mtu = ifp->if_mtu;
|
|
|
|
ifp->if_mtu = sp->lcp.their_mru;
|
|
|
|
if (debug)
|
|
|
|
log(LOG_DEBUG,
|
2003-05-15 02:41:40 +04:00
|
|
|
"%s: setting MTU to %" PRIu64 " bytes\n",
|
|
|
|
ifp->if_xname, ifp->if_mtu);
|
2003-01-28 18:36:38 +03:00
|
|
|
}
|
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
if (sp->pp_con)
|
|
|
|
sp->pp_con(sp);
|
2004-12-06 05:59:23 +03:00
|
|
|
#endif
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2006-11-16 04:32:37 +03:00
|
|
|
sppp_ipcp_tld(struct sppp *sp)
|
1999-04-04 10:07:56 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_ipcp_tls(struct sppp *sp)
|
|
|
|
{
|
|
|
|
/* indicate to LCP that it must stay alive */
|
|
|
|
sp->lcp.protos |= (1 << IDX_IPCP);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_ipcp_tlf(struct sppp *sp)
|
|
|
|
{
|
|
|
|
/* we no longer need LCP */
|
|
|
|
sp->lcp.protos &= ~(1 << IDX_IPCP);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_ipcp_scr(struct sppp *sp)
|
|
|
|
{
|
2002-03-02 19:23:42 +03:00
|
|
|
char opt[6 /* compression */ + 6 /* address */ + 12 /* dns addresses */];
|
2004-12-06 05:59:23 +03:00
|
|
|
#ifdef INET
|
2001-12-05 00:32:15 +03:00
|
|
|
u_int32_t ouraddr;
|
2004-12-06 05:59:23 +03:00
|
|
|
#endif
|
1999-04-04 10:07:56 +04:00
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
#ifdef notyet
|
|
|
|
if (sp->ipcp.opts & (1 << IPCP_OPT_COMPRESSION)) {
|
|
|
|
opt[i++] = IPCP_OPT_COMPRESSION;
|
|
|
|
opt[i++] = 6;
|
|
|
|
opt[i++] = 0; /* VJ header compression */
|
|
|
|
opt[i++] = 0x2d; /* VJ header compression */
|
|
|
|
opt[i++] = max_slot_id;
|
|
|
|
opt[i++] = comp_slot_id;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2004-12-06 05:59:23 +03:00
|
|
|
#ifdef INET
|
1999-04-04 10:07:56 +04:00
|
|
|
if (sp->ipcp.opts & (1 << IPCP_OPT_ADDRESS)) {
|
2001-12-08 22:46:39 +03:00
|
|
|
if (sp->ipcp.flags & IPCP_MYADDR_SEEN)
|
|
|
|
ouraddr = sp->ipcp.req_myaddr; /* not sure if this can ever happen */
|
|
|
|
else
|
|
|
|
sppp_get_ip_addrs(sp, &ouraddr, 0, 0);
|
1999-04-04 10:07:56 +04:00
|
|
|
opt[i++] = IPCP_OPT_ADDRESS;
|
|
|
|
opt[i++] = 6;
|
|
|
|
opt[i++] = ouraddr >> 24;
|
|
|
|
opt[i++] = ouraddr >> 16;
|
|
|
|
opt[i++] = ouraddr >> 8;
|
|
|
|
opt[i++] = ouraddr;
|
|
|
|
}
|
2004-12-06 05:59:23 +03:00
|
|
|
#endif
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2002-03-02 19:23:42 +03:00
|
|
|
if (sp->query_dns & 1) {
|
|
|
|
opt[i++] = IPCP_OPT_PRIMDNS;
|
|
|
|
opt[i++] = 6;
|
|
|
|
opt[i++] = sp->dns_addrs[0] >> 24;
|
|
|
|
opt[i++] = sp->dns_addrs[0] >> 16;
|
|
|
|
opt[i++] = sp->dns_addrs[0] >> 8;
|
|
|
|
opt[i++] = sp->dns_addrs[0];
|
|
|
|
}
|
|
|
|
if (sp->query_dns & 2) {
|
|
|
|
opt[i++] = IPCP_OPT_SECDNS;
|
|
|
|
opt[i++] = 6;
|
|
|
|
opt[i++] = sp->dns_addrs[1] >> 24;
|
|
|
|
opt[i++] = sp->dns_addrs[1] >> 16;
|
|
|
|
opt[i++] = sp->dns_addrs[1] >> 8;
|
|
|
|
opt[i++] = sp->dns_addrs[1];
|
|
|
|
}
|
|
|
|
|
2000-05-02 16:43:16 +04:00
|
|
|
sp->confid[IDX_IPCP] = ++sp->pp_seq[IDX_IPCP];
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_cp_send(sp, PPP_IPCP, CONF_REQ, sp->confid[IDX_IPCP], i, &opt);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-01-19 01:39:12 +03:00
|
|
|
/*
|
2000-05-02 16:43:16 +04:00
|
|
|
*--------------------------------------------------------------------------*
|
|
|
|
* *
|
|
|
|
* The IPv6CP implementation. *
|
|
|
|
* *
|
|
|
|
*--------------------------------------------------------------------------*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef INET6
|
|
|
|
static void
|
|
|
|
sppp_ipv6cp_init(struct sppp *sp)
|
|
|
|
{
|
|
|
|
sp->ipv6cp.opts = 0;
|
|
|
|
sp->ipv6cp.flags = 0;
|
|
|
|
sp->state[IDX_IPV6CP] = STATE_INITIAL;
|
|
|
|
sp->fail_counter[IDX_IPV6CP] = 0;
|
|
|
|
sp->pp_seq[IDX_IPV6CP] = 0;
|
|
|
|
sp->pp_rseq[IDX_IPV6CP] = 0;
|
2007-07-10 00:51:58 +04:00
|
|
|
callout_init(&sp->ch[IDX_IPV6CP], 0);
|
2000-05-02 16:43:16 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_ipv6cp_up(struct sppp *sp)
|
|
|
|
{
|
|
|
|
sppp_up_event(&ipv6cp, sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_ipv6cp_down(struct sppp *sp)
|
|
|
|
{
|
|
|
|
sppp_down_event(&ipv6cp, sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_ipv6cp_open(struct sppp *sp)
|
|
|
|
{
|
|
|
|
STDDCL;
|
|
|
|
struct in6_addr myaddr, hisaddr;
|
|
|
|
|
|
|
|
#ifdef IPV6CP_MYIFID_DYN
|
|
|
|
sp->ipv6cp.flags &= ~(IPV6CP_MYIFID_SEEN|IPV6CP_MYIFID_DYN);
|
|
|
|
#else
|
|
|
|
sp->ipv6cp.flags &= ~IPV6CP_MYIFID_SEEN;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
sppp_get_ip6_addrs(sp, &myaddr, &hisaddr, 0);
|
|
|
|
/*
|
|
|
|
* If we don't have our address, this probably means our
|
|
|
|
* interface doesn't want to talk IPv6 at all. (This could
|
|
|
|
* be the case if somebody wants to speak only IPX, for
|
|
|
|
* example.) Don't open IPv6CP in this case.
|
|
|
|
*/
|
|
|
|
if (IN6_IS_ADDR_UNSPECIFIED(&myaddr)) {
|
|
|
|
/* XXX this message should go away */
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: ipv6cp_open(): no IPv6 interface\n",
|
|
|
|
ifp->if_xname);
|
2000-05-02 16:43:16 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sp->ipv6cp.flags |= IPV6CP_MYIFID_SEEN;
|
|
|
|
sp->ipv6cp.opts |= (1 << IPV6CP_OPT_IFID);
|
|
|
|
sppp_open_event(&ipv6cp, sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_ipv6cp_close(struct sppp *sp)
|
|
|
|
{
|
|
|
|
sppp_close_event(&ipv6cp, sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_ipv6cp_TO(void *cookie)
|
|
|
|
{
|
|
|
|
sppp_to_event(&ipv6cp, (struct sppp *)cookie);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Analyze a configure request. Return true if it was agreeable, and
|
|
|
|
* caused action sca, false if it has been rejected or nak'ed, and
|
|
|
|
* caused action scn. (The return value is used to make the state
|
|
|
|
* transition decision in the state automaton.)
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
sppp_ipv6cp_RCR(struct sppp *sp, struct lcp_header *h, int len)
|
|
|
|
{
|
|
|
|
u_char *buf, *r, *p;
|
|
|
|
struct ifnet *ifp = &sp->pp_if;
|
|
|
|
int rlen, origlen, debug = ifp->if_flags & IFF_DEBUG;
|
|
|
|
struct in6_addr myaddr, desiredaddr, suggestaddr;
|
|
|
|
int ifidcount;
|
|
|
|
int type;
|
|
|
|
int collision, nohisaddr;
|
|
|
|
|
|
|
|
len -= 4;
|
|
|
|
origlen = len;
|
|
|
|
/*
|
|
|
|
* Make sure to allocate a buf that can at least hold a
|
|
|
|
* conf-nak with an `address' option. We might need it below.
|
|
|
|
*/
|
|
|
|
buf = r = malloc ((len < 6? 6: len), M_TEMP, M_NOWAIT);
|
|
|
|
if (! buf)
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
/* pass 1: see if we can recognize them */
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: ipv6cp parse opts:",
|
|
|
|
ifp->if_xname);
|
2002-09-25 11:24:06 +04:00
|
|
|
p = (void *)(h + 1);
|
2000-05-02 16:43:16 +04:00
|
|
|
ifidcount = 0;
|
|
|
|
for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
|
2006-08-24 00:02:23 +04:00
|
|
|
/* Sanity check option length */
|
|
|
|
if (p[1] > len) {
|
|
|
|
/* XXX just RXJ? */
|
|
|
|
addlog("%s: received malicious IPCPv6 option, "
|
|
|
|
"dropping\n", ifp->if_xname);
|
|
|
|
goto drop;
|
|
|
|
}
|
2000-05-02 16:43:16 +04:00
|
|
|
if (debug)
|
|
|
|
addlog(" %s", sppp_ipv6cp_opt_name(*p));
|
|
|
|
switch (*p) {
|
|
|
|
case IPV6CP_OPT_IFID:
|
|
|
|
if (len >= 10 && p[1] == 10 && ifidcount == 0) {
|
|
|
|
/* correctly formed address option */
|
|
|
|
ifidcount++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (debug)
|
|
|
|
addlog(" [invalid]");
|
|
|
|
break;
|
|
|
|
#ifdef notyet
|
|
|
|
case IPV6CP_OPT_COMPRESSION:
|
|
|
|
if (len >= 4 && p[1] >= 4) {
|
|
|
|
/* correctly formed compress option */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (debug)
|
|
|
|
addlog(" [invalid]");
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
/* Others not supported. */
|
|
|
|
if (debug)
|
|
|
|
addlog(" [rej]");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* Add the option to rejected list. */
|
|
|
|
bcopy (p, r, p[1]);
|
|
|
|
r += p[1];
|
|
|
|
rlen += p[1];
|
|
|
|
}
|
|
|
|
if (rlen) {
|
|
|
|
if (debug)
|
|
|
|
addlog(" send conf-rej\n");
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_cp_send(sp, PPP_IPV6CP, CONF_REJ, h->ident, rlen, buf);
|
2000-05-02 16:43:16 +04:00
|
|
|
goto end;
|
|
|
|
} else if (debug)
|
|
|
|
addlog("\n");
|
|
|
|
|
|
|
|
/* pass 2: parse option values */
|
|
|
|
sppp_get_ip6_addrs(sp, &myaddr, 0, 0);
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: ipv6cp parse opt values: ",
|
|
|
|
ifp->if_xname);
|
2002-09-25 11:24:06 +04:00
|
|
|
p = (void *)(h + 1);
|
2000-05-02 16:43:16 +04:00
|
|
|
len = origlen;
|
|
|
|
type = CONF_ACK;
|
|
|
|
for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
|
|
|
|
if (debug)
|
|
|
|
addlog(" %s", sppp_ipv6cp_opt_name(*p));
|
|
|
|
switch (*p) {
|
|
|
|
#ifdef notyet
|
|
|
|
case IPV6CP_OPT_COMPRESSION:
|
|
|
|
continue;
|
|
|
|
#endif
|
|
|
|
case IPV6CP_OPT_IFID:
|
2001-07-18 20:43:09 +04:00
|
|
|
memset(&desiredaddr, 0, sizeof(desiredaddr));
|
2000-05-02 16:43:16 +04:00
|
|
|
bcopy(&p[2], &desiredaddr.s6_addr[8], 8);
|
2002-01-04 15:21:24 +03:00
|
|
|
collision = (memcmp(&desiredaddr.s6_addr[8],
|
2000-05-02 16:43:16 +04:00
|
|
|
&myaddr.s6_addr[8], 8) == 0);
|
|
|
|
nohisaddr = IN6_IS_ADDR_UNSPECIFIED(&desiredaddr);
|
|
|
|
|
|
|
|
desiredaddr.s6_addr16[0] = htons(0xfe80);
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
(void)in6_setscope(&desiredaddr, &sp->pp_if, NULL);
|
2000-05-02 16:43:16 +04:00
|
|
|
|
|
|
|
if (!collision && !nohisaddr) {
|
|
|
|
/* no collision, hisaddr known - Conf-Ack */
|
|
|
|
type = CONF_ACK;
|
|
|
|
|
|
|
|
if (debug) {
|
|
|
|
addlog(" %s [%s]",
|
|
|
|
ip6_sprintf(&desiredaddr),
|
|
|
|
sppp_cp_type_name(type));
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2001-07-18 20:43:09 +04:00
|
|
|
memset(&suggestaddr, 0, sizeof(&suggestaddr));
|
2000-05-02 16:43:16 +04:00
|
|
|
if (collision && nohisaddr) {
|
|
|
|
/* collision, hisaddr unknown - Conf-Rej */
|
|
|
|
type = CONF_REJ;
|
2001-07-18 20:43:09 +04:00
|
|
|
memset(&p[2], 0, 8);
|
2000-05-02 16:43:16 +04:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* - no collision, hisaddr unknown, or
|
|
|
|
* - collision, hisaddr known
|
|
|
|
* Conf-Nak, suggest hisaddr
|
|
|
|
*/
|
|
|
|
type = CONF_NAK;
|
|
|
|
sppp_suggest_ip6_addr(sp, &suggestaddr);
|
|
|
|
bcopy(&suggestaddr.s6_addr[8], &p[2], 8);
|
|
|
|
}
|
|
|
|
if (debug)
|
|
|
|
addlog(" %s [%s]", ip6_sprintf(&desiredaddr),
|
|
|
|
sppp_cp_type_name(type));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* Add the option to nak'ed list. */
|
|
|
|
bcopy (p, r, p[1]);
|
|
|
|
r += p[1];
|
|
|
|
rlen += p[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rlen == 0 && type == CONF_ACK) {
|
|
|
|
if (debug)
|
|
|
|
addlog(" send %s\n", sppp_cp_type_name(type));
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_cp_send(sp, PPP_IPV6CP, type, h->ident, origlen, h + 1);
|
2000-05-02 16:43:16 +04:00
|
|
|
} else {
|
2002-05-29 05:38:46 +04:00
|
|
|
#ifdef notdef
|
2000-05-02 16:43:16 +04:00
|
|
|
if (type == CONF_ACK)
|
|
|
|
panic("IPv6CP RCR: CONF_ACK with non-zero rlen");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (debug) {
|
|
|
|
addlog(" send %s suggest %s\n",
|
|
|
|
sppp_cp_type_name(type), ip6_sprintf(&suggestaddr));
|
|
|
|
}
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_cp_send(sp, PPP_IPV6CP, type, h->ident, rlen, buf);
|
2000-05-02 16:43:16 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
end:
|
2002-09-25 11:24:06 +04:00
|
|
|
free(buf, M_TEMP);
|
2000-05-02 16:43:16 +04:00
|
|
|
return (rlen == 0);
|
2006-08-24 00:02:23 +04:00
|
|
|
|
|
|
|
drop:
|
|
|
|
free(buf, M_TEMP);
|
|
|
|
return -1;
|
2000-05-02 16:43:16 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Analyze the IPv6CP Configure-Reject option list, and adjust our
|
|
|
|
* negotiation.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
sppp_ipv6cp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
|
|
|
|
{
|
|
|
|
u_char *buf, *p;
|
|
|
|
struct ifnet *ifp = &sp->pp_if;
|
|
|
|
int debug = ifp->if_flags & IFF_DEBUG;
|
|
|
|
|
|
|
|
len -= 4;
|
|
|
|
buf = malloc (len, M_TEMP, M_NOWAIT);
|
|
|
|
if (!buf)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: ipv6cp rej opts:",
|
|
|
|
ifp->if_xname);
|
2000-05-02 16:43:16 +04:00
|
|
|
|
2002-09-25 11:24:06 +04:00
|
|
|
p = (void *)(h + 1);
|
2000-05-02 16:43:16 +04:00
|
|
|
for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
|
2006-08-24 00:02:23 +04:00
|
|
|
if (p[1] > len) {
|
|
|
|
/* XXX just RXJ? */
|
|
|
|
addlog("%s: received malicious IPCPv6 option, "
|
|
|
|
"dropping\n", ifp->if_xname);
|
|
|
|
goto drop;
|
|
|
|
}
|
2000-05-02 16:43:16 +04:00
|
|
|
if (debug)
|
|
|
|
addlog(" %s", sppp_ipv6cp_opt_name(*p));
|
|
|
|
switch (*p) {
|
|
|
|
case IPV6CP_OPT_IFID:
|
|
|
|
/*
|
|
|
|
* Peer doesn't grok address option. This is
|
|
|
|
* bad. XXX Should we better give up here?
|
|
|
|
*/
|
|
|
|
sp->ipv6cp.opts &= ~(1 << IPV6CP_OPT_IFID);
|
|
|
|
break;
|
|
|
|
#ifdef notyet
|
|
|
|
case IPV6CP_OPT_COMPRESS:
|
|
|
|
sp->ipv6cp.opts &= ~(1 << IPV6CP_OPT_COMPRESS);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (debug)
|
|
|
|
addlog("\n");
|
2006-08-24 00:02:23 +04:00
|
|
|
drop:
|
2002-09-25 11:24:06 +04:00
|
|
|
free(buf, M_TEMP);
|
2000-05-02 16:43:16 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Analyze the IPv6CP Configure-NAK option list, and adjust our
|
|
|
|
* negotiation.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
sppp_ipv6cp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
|
|
|
|
{
|
|
|
|
u_char *buf, *p;
|
|
|
|
struct ifnet *ifp = &sp->pp_if;
|
|
|
|
int debug = ifp->if_flags & IFF_DEBUG;
|
|
|
|
struct in6_addr suggestaddr;
|
|
|
|
|
|
|
|
len -= 4;
|
|
|
|
buf = malloc (len, M_TEMP, M_NOWAIT);
|
|
|
|
if (!buf)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: ipv6cp nak opts:",
|
|
|
|
ifp->if_xname);
|
2000-05-02 16:43:16 +04:00
|
|
|
|
2002-09-25 11:24:06 +04:00
|
|
|
p = (void *)(h + 1);
|
2000-05-02 16:43:16 +04:00
|
|
|
for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
|
2006-08-24 00:02:23 +04:00
|
|
|
if (p[1] > len) {
|
|
|
|
/* XXX just RXJ? */
|
|
|
|
addlog("%s: received malicious IPCPv6 option, "
|
|
|
|
"dropping\n", ifp->if_xname);
|
|
|
|
goto drop;
|
|
|
|
}
|
2000-05-02 16:43:16 +04:00
|
|
|
if (debug)
|
|
|
|
addlog(" %s", sppp_ipv6cp_opt_name(*p));
|
|
|
|
switch (*p) {
|
|
|
|
case IPV6CP_OPT_IFID:
|
|
|
|
/*
|
|
|
|
* Peer doesn't like our local ifid. See
|
|
|
|
* if we can do something for him. We'll drop
|
|
|
|
* him our address then.
|
|
|
|
*/
|
|
|
|
if (len < 10 || p[1] != 10)
|
|
|
|
break;
|
2001-07-18 20:43:09 +04:00
|
|
|
memset(&suggestaddr, 0, sizeof(suggestaddr));
|
2000-05-02 16:43:16 +04:00
|
|
|
suggestaddr.s6_addr16[0] = htons(0xfe80);
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
(void)in6_setscope(&suggestaddr, &sp->pp_if, NULL);
|
2000-05-02 16:43:16 +04:00
|
|
|
bcopy(&p[2], &suggestaddr.s6_addr[8], 8);
|
|
|
|
|
|
|
|
sp->ipv6cp.opts |= (1 << IPV6CP_OPT_IFID);
|
|
|
|
if (debug)
|
|
|
|
addlog(" [suggestaddr %s]",
|
|
|
|
ip6_sprintf(&suggestaddr));
|
|
|
|
#ifdef IPV6CP_MYIFID_DYN
|
|
|
|
/*
|
|
|
|
* When doing dynamic address assignment,
|
|
|
|
* we accept his offer.
|
|
|
|
*/
|
|
|
|
if (sp->ipv6cp.flags & IPV6CP_MYIFID_DYN) {
|
|
|
|
struct in6_addr lastsuggest;
|
|
|
|
/*
|
|
|
|
* If <suggested myaddr from peer> equals to
|
|
|
|
* <hisaddr we have suggested last time>,
|
|
|
|
* we have a collision. generate new random
|
|
|
|
* ifid.
|
|
|
|
*/
|
|
|
|
sppp_suggest_ip6_addr(&lastsuggest);
|
|
|
|
if (IN6_ARE_ADDR_EQUAL(&suggestaddr,
|
|
|
|
lastsuggest)) {
|
|
|
|
if (debug)
|
|
|
|
addlog(" [random]");
|
|
|
|
sppp_gen_ip6_addr(sp, &suggestaddr);
|
|
|
|
}
|
|
|
|
sppp_set_ip6_addr(sp, &suggestaddr, 0);
|
|
|
|
if (debug)
|
|
|
|
addlog(" [agree]");
|
|
|
|
sp->ipv6cp.flags |= IPV6CP_MYIFID_SEEN;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
/*
|
|
|
|
* Since we do not do dynamic address assignment,
|
|
|
|
* we ignore it and thus continue to negotiate
|
|
|
|
* our already existing value. This can possibly
|
|
|
|
* go into infinite request-reject loop.
|
|
|
|
*
|
|
|
|
* This is not likely because we normally use
|
|
|
|
* ifid based on MAC-address.
|
|
|
|
* If you have no ethernet card on the node, too bad.
|
|
|
|
* XXX should we use fail_counter?
|
|
|
|
*/
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
#ifdef notyet
|
|
|
|
case IPV6CP_OPT_COMPRESS:
|
|
|
|
/*
|
|
|
|
* Peer wants different compression parameters.
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (debug)
|
|
|
|
addlog("\n");
|
2006-08-24 00:02:23 +04:00
|
|
|
drop:
|
2002-09-25 11:24:06 +04:00
|
|
|
free(buf, M_TEMP);
|
2000-05-02 16:43:16 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_ipv6cp_tlu(struct sppp *sp)
|
|
|
|
{
|
|
|
|
/* we are up - notify isdn daemon */
|
|
|
|
if (sp->pp_con)
|
|
|
|
sp->pp_con(sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2006-11-16 04:32:37 +03:00
|
|
|
sppp_ipv6cp_tld(struct sppp *sp)
|
2000-05-02 16:43:16 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_ipv6cp_tls(struct sppp *sp)
|
|
|
|
{
|
|
|
|
/* indicate to LCP that it must stay alive */
|
|
|
|
sp->lcp.protos |= (1 << IDX_IPV6CP);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_ipv6cp_tlf(struct sppp *sp)
|
|
|
|
{
|
|
|
|
/* we no longer need LCP */
|
|
|
|
sp->lcp.protos &= ~(1 << IDX_IPV6CP);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_ipv6cp_scr(struct sppp *sp)
|
|
|
|
{
|
|
|
|
char opt[10 /* ifid */ + 4 /* compression, minimum */];
|
|
|
|
struct in6_addr ouraddr;
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
if (sp->ipv6cp.opts & (1 << IPV6CP_OPT_IFID)) {
|
|
|
|
sppp_get_ip6_addrs(sp, &ouraddr, 0, 0);
|
|
|
|
opt[i++] = IPV6CP_OPT_IFID;
|
|
|
|
opt[i++] = 10;
|
|
|
|
bcopy(&ouraddr.s6_addr[8], &opt[i], 8);
|
|
|
|
i += 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef notyet
|
|
|
|
if (sp->ipv6cp.opts & (1 << IPV6CP_OPT_COMPRESSION)) {
|
|
|
|
opt[i++] = IPV6CP_OPT_COMPRESSION;
|
|
|
|
opt[i++] = 4;
|
|
|
|
opt[i++] = 0; /* TBD */
|
|
|
|
opt[i++] = 0; /* TBD */
|
|
|
|
/* variable length data may follow */
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
sp->confid[IDX_IPV6CP] = ++sp->pp_seq[IDX_IPV6CP];
|
|
|
|
sppp_cp_send(sp, PPP_IPV6CP, CONF_REQ, sp->confid[IDX_IPV6CP], i, &opt);
|
|
|
|
}
|
|
|
|
#else /*INET6*/
|
2006-10-13 20:53:35 +04:00
|
|
|
static void
|
2006-11-16 04:32:37 +03:00
|
|
|
sppp_ipv6cp_init(struct sppp *sp)
|
2000-05-02 16:43:16 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-10-13 20:53:35 +04:00
|
|
|
static void
|
2006-11-16 04:32:37 +03:00
|
|
|
sppp_ipv6cp_up(struct sppp *sp)
|
2000-05-02 16:43:16 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-10-13 20:53:35 +04:00
|
|
|
static void
|
2006-11-16 04:32:37 +03:00
|
|
|
sppp_ipv6cp_down(struct sppp *sp)
|
2000-05-02 16:43:16 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-10-13 20:53:35 +04:00
|
|
|
static void
|
2006-11-16 04:32:37 +03:00
|
|
|
sppp_ipv6cp_open(struct sppp *sp)
|
2000-05-02 16:43:16 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-10-13 20:53:35 +04:00
|
|
|
static void
|
2006-11-16 04:32:37 +03:00
|
|
|
sppp_ipv6cp_close(struct sppp *sp)
|
2000-05-02 16:43:16 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-10-13 20:53:35 +04:00
|
|
|
static void
|
2006-11-16 04:32:37 +03:00
|
|
|
sppp_ipv6cp_TO(void *sp)
|
2000-05-02 16:43:16 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-10-13 20:53:35 +04:00
|
|
|
static int
|
2006-11-16 04:32:37 +03:00
|
|
|
sppp_ipv6cp_RCR(struct sppp *sp, struct lcp_header *h,
|
|
|
|
int len)
|
2000-05-02 16:43:16 +04:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-10-13 20:53:35 +04:00
|
|
|
static void
|
2006-11-16 04:32:37 +03:00
|
|
|
sppp_ipv6cp_RCN_rej(struct sppp *sp, struct lcp_header *h,
|
|
|
|
int len)
|
2000-05-02 16:43:16 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-10-13 20:53:35 +04:00
|
|
|
static void
|
2006-11-16 04:32:37 +03:00
|
|
|
sppp_ipv6cp_RCN_nak(struct sppp *sp, struct lcp_header *h,
|
|
|
|
int len)
|
2000-05-02 16:43:16 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-10-13 20:53:35 +04:00
|
|
|
static void
|
2006-11-16 04:32:37 +03:00
|
|
|
sppp_ipv6cp_tlu(struct sppp *sp)
|
2000-05-02 16:43:16 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-10-13 20:53:35 +04:00
|
|
|
static void
|
2006-11-16 04:32:37 +03:00
|
|
|
sppp_ipv6cp_tld(struct sppp *sp)
|
2000-05-02 16:43:16 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-10-13 20:53:35 +04:00
|
|
|
static void
|
2006-11-16 04:32:37 +03:00
|
|
|
sppp_ipv6cp_tls(struct sppp *sp)
|
2000-05-02 16:43:16 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-10-13 20:53:35 +04:00
|
|
|
static void
|
2006-11-16 04:32:37 +03:00
|
|
|
sppp_ipv6cp_tlf(struct sppp *sp)
|
2000-05-02 16:43:16 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-10-13 20:53:35 +04:00
|
|
|
static void
|
2006-11-16 04:32:37 +03:00
|
|
|
sppp_ipv6cp_scr(struct sppp *sp)
|
2000-05-02 16:43:16 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
#endif /*INET6*/
|
|
|
|
|
|
|
|
|
2002-01-19 01:39:12 +03:00
|
|
|
/*
|
1999-04-04 10:07:56 +04:00
|
|
|
*--------------------------------------------------------------------------*
|
|
|
|
* *
|
|
|
|
* The CHAP implementation. *
|
|
|
|
* *
|
|
|
|
*--------------------------------------------------------------------------*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The authentication protocols don't employ a full-fledged state machine as
|
|
|
|
* the control protocols do, since they do have Open and Close events, but
|
|
|
|
* not Up and Down, nor are they explicitly terminated. Also, use of the
|
|
|
|
* authentication protocols may be different in both directions (this makes
|
|
|
|
* sense, think of a machine that never accepts incoming calls but only
|
|
|
|
* calls out, it doesn't require the called party to authenticate itself).
|
|
|
|
*
|
|
|
|
* Our state machine for the local authentication protocol (we are requesting
|
|
|
|
* the peer to authenticate) looks like:
|
|
|
|
*
|
|
|
|
* RCA-
|
|
|
|
* +--------------------------------------------+
|
|
|
|
* V scn,tld|
|
|
|
|
* +--------+ Close +---------+ RCA+
|
|
|
|
* | |<----------------------------------| |------+
|
|
|
|
* +--->| Closed | TO* | Opened | sca |
|
|
|
|
* | | |-----+ +-------| |<-----+
|
|
|
|
* | +--------+ irc | | +---------+
|
|
|
|
* | ^ | | ^
|
|
|
|
* | | | | |
|
|
|
|
* | | | | |
|
|
|
|
* | TO-| | | |
|
|
|
|
* | |tld TO+ V | |
|
|
|
|
* | | +------->+ | |
|
|
|
|
* | | | | | |
|
|
|
|
* | +--------+ V | |
|
|
|
|
* | | |<----+<--------------------+ |
|
|
|
|
* | | Req- | scr |
|
|
|
|
* | | Sent | |
|
|
|
|
* | | | |
|
|
|
|
* | +--------+ |
|
|
|
|
* | RCA- | | RCA+ |
|
|
|
|
* +------+ +------------------------------------------+
|
|
|
|
* scn,tld sca,irc,ict,tlu
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* with:
|
|
|
|
*
|
|
|
|
* Open: LCP reached authentication phase
|
|
|
|
* Close: LCP reached terminate phase
|
|
|
|
*
|
|
|
|
* RCA+: received reply (pap-req, chap-response), acceptable
|
|
|
|
* RCN: received reply (pap-req, chap-response), not acceptable
|
|
|
|
* TO+: timeout with restart counter >= 0
|
|
|
|
* TO-: timeout with restart counter < 0
|
|
|
|
* TO*: reschedule timeout for CHAP
|
|
|
|
*
|
|
|
|
* scr: send request packet (none for PAP, chap-challenge)
|
|
|
|
* sca: send ack packet (pap-ack, chap-success)
|
|
|
|
* scn: send nak packet (pap-nak, chap-failure)
|
|
|
|
* ict: initialize re-challenge timer (CHAP only)
|
|
|
|
*
|
|
|
|
* tlu: this-layer-up, LCP reaches network phase
|
|
|
|
* tld: this-layer-down, LCP enters terminate phase
|
|
|
|
*
|
|
|
|
* Note that in CHAP mode, after sending a new challenge, while the state
|
|
|
|
* automaton falls back into Req-Sent state, it doesn't signal a tld
|
|
|
|
* event to LCP, so LCP remains in network phase. Only after not getting
|
|
|
|
* any response (or after getting an unacceptable response), CHAP closes,
|
|
|
|
* causing LCP to enter terminate phase.
|
|
|
|
*
|
|
|
|
* With PAP, there is no initial request that can be sent. The peer is
|
|
|
|
* expected to send one based on the successful negotiation of PAP as
|
|
|
|
* the authentication protocol during the LCP option negotiation.
|
|
|
|
*
|
|
|
|
* Incoming authentication protocol requests (remote requests
|
|
|
|
* authentication, we are peer) don't employ a state machine at all,
|
|
|
|
* they are simply answered. Some peers [Ascend P50 firmware rev
|
2000-05-02 16:43:16 +04:00
|
|
|
* 4.50] react allergically when sending IPCP/IPv6CP requests while they are
|
1999-04-04 10:07:56 +04:00
|
|
|
* still in authentication phase (thereby violating the standard that
|
|
|
|
* demands that these NCP packets are to be discarded), so we keep
|
|
|
|
* track of the peer demanding us to authenticate, and only proceed to
|
|
|
|
* phase network once we've seen a positive acknowledge for the
|
|
|
|
* authentication.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle incoming CHAP packets.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
sppp_chap_input(struct sppp *sp, struct mbuf *m)
|
|
|
|
{
|
|
|
|
STDDCL;
|
|
|
|
struct lcp_header *h;
|
|
|
|
int len, x;
|
2002-01-04 15:21:24 +03:00
|
|
|
u_char *value, *name, digest[sizeof(sp->myauth.challenge)], dsize;
|
1999-04-04 10:07:56 +04:00
|
|
|
int value_len, name_len;
|
|
|
|
MD5_CTX ctx;
|
|
|
|
|
|
|
|
len = m->m_pkthdr.len;
|
|
|
|
if (len < 4) {
|
|
|
|
if (debug)
|
|
|
|
log(LOG_DEBUG,
|
2003-05-15 02:41:40 +04:00
|
|
|
"%s: chap invalid packet length: %d bytes\n",
|
|
|
|
ifp->if_xname, len);
|
1999-04-04 10:07:56 +04:00
|
|
|
return;
|
|
|
|
}
|
2002-09-25 11:24:06 +04:00
|
|
|
h = mtod(m, struct lcp_header *);
|
|
|
|
if (len > ntohs(h->len))
|
|
|
|
len = ntohs(h->len);
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
switch (h->type) {
|
|
|
|
/* challenge, failure and success are his authproto */
|
|
|
|
case CHAP_CHALLENGE:
|
2002-01-04 15:21:24 +03:00
|
|
|
if (sp->myauth.secret == NULL || sp->myauth.name == NULL) {
|
|
|
|
/* can't do anything usefull */
|
2002-01-07 13:49:02 +03:00
|
|
|
sp->pp_auth_failures++;
|
2003-05-15 02:41:40 +04:00
|
|
|
printf("%s: chap input without my name and my secret being set\n",
|
|
|
|
ifp->if_xname);
|
2002-01-04 15:21:24 +03:00
|
|
|
break;
|
|
|
|
}
|
2002-09-25 11:24:06 +04:00
|
|
|
value = 1 + (u_char *)(h + 1);
|
1999-04-04 10:07:56 +04:00
|
|
|
value_len = value[-1];
|
|
|
|
name = value + value_len;
|
|
|
|
name_len = len - value_len - 5;
|
|
|
|
if (name_len < 0) {
|
|
|
|
if (debug) {
|
|
|
|
log(LOG_DEBUG,
|
2003-05-15 02:41:40 +04:00
|
|
|
"%s: chap corrupted challenge "
|
1999-04-04 10:07:56 +04:00
|
|
|
"<%s id=0x%x len=%d",
|
2003-05-15 02:41:40 +04:00
|
|
|
ifp->if_xname,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_auth_type_name(PPP_CHAP, h->type),
|
|
|
|
h->ident, ntohs(h->len));
|
|
|
|
if (len > 4)
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_print_bytes((u_char *)(h + 1),
|
|
|
|
len - 4);
|
1999-04-04 10:07:56 +04:00
|
|
|
addlog(">\n");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2005-02-27 01:45:09 +03:00
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug) {
|
|
|
|
log(LOG_DEBUG,
|
2003-05-15 02:41:40 +04:00
|
|
|
"%s: chap input <%s id=0x%x len=%d name=",
|
|
|
|
ifp->if_xname,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_auth_type_name(PPP_CHAP, h->type), h->ident,
|
|
|
|
ntohs(h->len));
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_print_string((char *) name, name_len);
|
1999-04-04 10:07:56 +04:00
|
|
|
addlog(" value-size=%d value=", value_len);
|
|
|
|
sppp_print_bytes(value, value_len);
|
|
|
|
addlog(">\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Compute reply value. */
|
|
|
|
MD5Init(&ctx);
|
|
|
|
MD5Update(&ctx, &h->ident, 1);
|
2002-07-28 23:54:47 +04:00
|
|
|
MD5Update(&ctx, sp->myauth.secret, sp->myauth.secret_len);
|
1999-04-04 10:07:56 +04:00
|
|
|
MD5Update(&ctx, value, value_len);
|
|
|
|
MD5Final(digest, &ctx);
|
|
|
|
dsize = sizeof digest;
|
|
|
|
|
|
|
|
sppp_auth_send(&chap, sp, CHAP_RESPONSE, h->ident,
|
|
|
|
sizeof dsize, (const char *)&dsize,
|
|
|
|
sizeof digest, digest,
|
2002-07-28 23:54:47 +04:00
|
|
|
sp->myauth.name_len,
|
1999-04-04 10:07:56 +04:00
|
|
|
sp->myauth.name,
|
|
|
|
0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CHAP_SUCCESS:
|
|
|
|
if (debug) {
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: chap success",
|
|
|
|
ifp->if_xname);
|
1999-04-04 10:07:56 +04:00
|
|
|
if (len > 4) {
|
|
|
|
addlog(": ");
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_print_string((char *)(h + 1), len - 4);
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
addlog("\n");
|
|
|
|
}
|
2001-04-14 03:29:55 +04:00
|
|
|
x = splnet();
|
2002-01-07 13:49:02 +03:00
|
|
|
sp->pp_auth_failures = 0;
|
1999-04-04 10:07:56 +04:00
|
|
|
sp->pp_flags &= ~PP_NEEDAUTH;
|
|
|
|
if (sp->myauth.proto == PPP_CHAP &&
|
|
|
|
(sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) &&
|
|
|
|
(sp->lcp.protos & (1 << IDX_CHAP)) == 0) {
|
|
|
|
/*
|
|
|
|
* We are authenticator for CHAP but didn't
|
|
|
|
* complete yet. Leave it to tlu to proceed
|
|
|
|
* to network phase.
|
|
|
|
*/
|
|
|
|
splx(x);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
splx(x);
|
|
|
|
sppp_phase_network(sp);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CHAP_FAILURE:
|
2002-01-07 13:49:02 +03:00
|
|
|
x = splnet();
|
|
|
|
sp->pp_auth_failures++;
|
|
|
|
splx(x);
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug) {
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_INFO, "%s: chap failure",
|
|
|
|
ifp->if_xname);
|
1999-04-04 10:07:56 +04:00
|
|
|
if (len > 4) {
|
|
|
|
addlog(": ");
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_print_string((char *)(h + 1), len - 4);
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
addlog("\n");
|
|
|
|
} else
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_INFO, "%s: chap failure\n",
|
|
|
|
ifp->if_xname);
|
1999-04-04 10:07:56 +04:00
|
|
|
/* await LCP shutdown by authenticator */
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* response is my authproto */
|
|
|
|
case CHAP_RESPONSE:
|
2002-01-04 15:21:24 +03:00
|
|
|
if (sp->hisauth.secret == NULL) {
|
|
|
|
/* can't do anything usefull */
|
2003-05-15 02:41:40 +04:00
|
|
|
printf("%s: chap input without his secret being set\n",
|
|
|
|
ifp->if_xname);
|
2002-01-04 15:21:24 +03:00
|
|
|
break;
|
|
|
|
}
|
2002-09-25 11:24:06 +04:00
|
|
|
value = 1 + (u_char *)(h + 1);
|
1999-04-04 10:07:56 +04:00
|
|
|
value_len = value[-1];
|
|
|
|
name = value + value_len;
|
|
|
|
name_len = len - value_len - 5;
|
|
|
|
if (name_len < 0) {
|
|
|
|
if (debug) {
|
|
|
|
log(LOG_DEBUG,
|
2003-05-15 02:41:40 +04:00
|
|
|
"%s: chap corrupted response "
|
1999-04-04 10:07:56 +04:00
|
|
|
"<%s id=0x%x len=%d",
|
2003-05-15 02:41:40 +04:00
|
|
|
ifp->if_xname,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_auth_type_name(PPP_CHAP, h->type),
|
|
|
|
h->ident, ntohs(h->len));
|
|
|
|
if (len > 4)
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_print_bytes((u_char *)(h + 1),
|
|
|
|
len - 4);
|
1999-04-04 10:07:56 +04:00
|
|
|
addlog(">\n");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (h->ident != sp->confid[IDX_CHAP]) {
|
|
|
|
if (debug)
|
|
|
|
log(LOG_DEBUG,
|
2003-05-15 02:41:40 +04:00
|
|
|
"%s: chap dropping response for old ID "
|
1999-04-04 10:07:56 +04:00
|
|
|
"(got %d, expected %d)\n",
|
2003-05-15 02:41:40 +04:00
|
|
|
ifp->if_xname,
|
1999-04-04 10:07:56 +04:00
|
|
|
h->ident, sp->confid[IDX_CHAP]);
|
|
|
|
break;
|
|
|
|
}
|
2005-02-27 01:45:09 +03:00
|
|
|
if (sp->hisauth.name != NULL &&
|
2002-07-28 23:54:47 +04:00
|
|
|
(name_len != sp->hisauth.name_len
|
2002-01-04 15:21:24 +03:00
|
|
|
|| memcmp(name, sp->hisauth.name, name_len) != 0)) {
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_INFO, "%s: chap response, his name ",
|
|
|
|
ifp->if_xname);
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_print_string(name, name_len);
|
|
|
|
addlog(" != expected ");
|
|
|
|
sppp_print_string(sp->hisauth.name,
|
2002-07-28 23:54:47 +04:00
|
|
|
sp->hisauth.name_len);
|
1999-04-04 10:07:56 +04:00
|
|
|
addlog("\n");
|
2002-01-04 15:21:24 +03:00
|
|
|
goto chap_failure;
|
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug) {
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: chap input(%s) "
|
1999-04-04 10:07:56 +04:00
|
|
|
"<%s id=0x%x len=%d name=",
|
2003-05-15 02:41:40 +04:00
|
|
|
ifp->if_xname,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_state_name(sp->state[IDX_CHAP]),
|
|
|
|
sppp_auth_type_name(PPP_CHAP, h->type),
|
2002-09-25 11:24:06 +04:00
|
|
|
h->ident, ntohs(h->len));
|
|
|
|
sppp_print_string((char *)name, name_len);
|
1999-04-04 10:07:56 +04:00
|
|
|
addlog(" value-size=%d value=", value_len);
|
|
|
|
sppp_print_bytes(value, value_len);
|
|
|
|
addlog(">\n");
|
|
|
|
}
|
2002-01-04 15:21:24 +03:00
|
|
|
if (value_len != sizeof(sp->myauth.challenge)) {
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug)
|
|
|
|
log(LOG_DEBUG,
|
2003-05-15 02:41:40 +04:00
|
|
|
"%s: chap bad hash value length: "
|
2002-01-05 22:26:44 +03:00
|
|
|
"%d bytes, should be %ld\n",
|
2003-05-15 02:41:40 +04:00
|
|
|
ifp->if_xname, value_len,
|
2002-01-05 22:26:44 +03:00
|
|
|
(long) sizeof(sp->myauth.challenge));
|
2002-01-04 15:21:24 +03:00
|
|
|
goto chap_failure;
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
MD5Init(&ctx);
|
|
|
|
MD5Update(&ctx, &h->ident, 1);
|
2002-07-28 23:54:47 +04:00
|
|
|
MD5Update(&ctx, sp->hisauth.secret, sp->hisauth.secret_len);
|
2002-01-04 15:21:24 +03:00
|
|
|
MD5Update(&ctx, sp->myauth.challenge, sizeof(sp->myauth.challenge));
|
1999-04-04 10:07:56 +04:00
|
|
|
MD5Final(digest, &ctx);
|
|
|
|
|
|
|
|
#define FAILMSG "Failed..."
|
|
|
|
#define SUCCMSG "Welcome!"
|
|
|
|
|
|
|
|
if (value_len != sizeof digest ||
|
2002-01-04 15:21:24 +03:00
|
|
|
memcmp(digest, value, value_len) != 0) {
|
|
|
|
chap_failure:
|
1999-04-04 10:07:56 +04:00
|
|
|
/* action scn, tld */
|
2002-01-07 13:49:02 +03:00
|
|
|
x = splnet();
|
|
|
|
sp->pp_auth_failures++;
|
|
|
|
splx(x);
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_auth_send(&chap, sp, CHAP_FAILURE, h->ident,
|
2005-05-30 01:22:52 +04:00
|
|
|
sizeof(FAILMSG) - 1, (const u_char *)FAILMSG,
|
1999-04-04 10:07:56 +04:00
|
|
|
0);
|
|
|
|
chap.tld(sp);
|
|
|
|
break;
|
|
|
|
}
|
2002-01-07 13:49:02 +03:00
|
|
|
sp->pp_auth_failures = 0;
|
1999-04-04 10:07:56 +04:00
|
|
|
/* action sca, perhaps tlu */
|
|
|
|
if (sp->state[IDX_CHAP] == STATE_REQ_SENT ||
|
|
|
|
sp->state[IDX_CHAP] == STATE_OPENED)
|
|
|
|
sppp_auth_send(&chap, sp, CHAP_SUCCESS, h->ident,
|
2005-05-30 01:22:52 +04:00
|
|
|
sizeof(SUCCMSG) - 1, (const u_char *)SUCCMSG,
|
1999-04-04 10:07:56 +04:00
|
|
|
0);
|
|
|
|
if (sp->state[IDX_CHAP] == STATE_REQ_SENT) {
|
|
|
|
sppp_cp_change_state(&chap, sp, STATE_OPENED);
|
|
|
|
chap.tlu(sp);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* Unknown CHAP packet type -- ignore. */
|
|
|
|
if (debug) {
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: chap unknown input(%s) "
|
1999-04-04 10:07:56 +04:00
|
|
|
"<0x%x id=0x%xh len=%d",
|
2003-05-15 02:41:40 +04:00
|
|
|
ifp->if_xname,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_state_name(sp->state[IDX_CHAP]),
|
|
|
|
h->type, h->ident, ntohs(h->len));
|
|
|
|
if (len > 4)
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_print_bytes((u_char *)(h + 1), len - 4);
|
1999-04-04 10:07:56 +04:00
|
|
|
addlog(">\n");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_chap_init(struct sppp *sp)
|
|
|
|
{
|
|
|
|
/* Chap doesn't have STATE_INITIAL at all. */
|
|
|
|
sp->state[IDX_CHAP] = STATE_CLOSED;
|
|
|
|
sp->fail_counter[IDX_CHAP] = 0;
|
2000-05-02 16:43:16 +04:00
|
|
|
sp->pp_seq[IDX_CHAP] = 0;
|
|
|
|
sp->pp_rseq[IDX_CHAP] = 0;
|
2007-07-10 00:51:58 +04:00
|
|
|
callout_init(&sp->ch[IDX_CHAP], 0);
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_chap_open(struct sppp *sp)
|
|
|
|
{
|
|
|
|
if (sp->myauth.proto == PPP_CHAP &&
|
|
|
|
(sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) != 0) {
|
|
|
|
/* we are authenticator for CHAP, start it */
|
|
|
|
chap.scr(sp);
|
|
|
|
sp->rst_counter[IDX_CHAP] = sp->lcp.max_configure;
|
|
|
|
sppp_cp_change_state(&chap, sp, STATE_REQ_SENT);
|
|
|
|
}
|
|
|
|
/* nothing to be done if we are peer, await a challenge */
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_chap_close(struct sppp *sp)
|
|
|
|
{
|
|
|
|
if (sp->state[IDX_CHAP] != STATE_CLOSED)
|
|
|
|
sppp_cp_change_state(&chap, sp, STATE_CLOSED);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_chap_TO(void *cookie)
|
|
|
|
{
|
|
|
|
struct sppp *sp = (struct sppp *)cookie;
|
|
|
|
STDDCL;
|
|
|
|
int s;
|
|
|
|
|
2001-04-14 03:29:55 +04:00
|
|
|
s = splnet();
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: chap TO(%s) rst_counter = %d\n",
|
|
|
|
ifp->if_xname,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_state_name(sp->state[IDX_CHAP]),
|
|
|
|
sp->rst_counter[IDX_CHAP]);
|
|
|
|
|
|
|
|
if (--sp->rst_counter[IDX_CHAP] < 0)
|
|
|
|
/* TO- event */
|
|
|
|
switch (sp->state[IDX_CHAP]) {
|
|
|
|
case STATE_REQ_SENT:
|
|
|
|
chap.tld(sp);
|
|
|
|
sppp_cp_change_state(&chap, sp, STATE_CLOSED);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
/* TO+ (or TO*) event */
|
|
|
|
switch (sp->state[IDX_CHAP]) {
|
|
|
|
case STATE_OPENED:
|
|
|
|
/* TO* event */
|
|
|
|
sp->rst_counter[IDX_CHAP] = sp->lcp.max_configure;
|
|
|
|
/* fall through */
|
|
|
|
case STATE_REQ_SENT:
|
|
|
|
chap.scr(sp);
|
|
|
|
/* sppp_cp_change_state() will restart the timer */
|
|
|
|
sppp_cp_change_state(&chap, sp, STATE_REQ_SENT);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_chap_tlu(struct sppp *sp)
|
|
|
|
{
|
|
|
|
STDDCL;
|
|
|
|
int i, x;
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
sp->rst_counter[IDX_CHAP] = sp->lcp.max_configure;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Some broken CHAP implementations (Conware CoNet, firmware
|
|
|
|
* 4.0.?) don't want to re-authenticate their CHAP once the
|
|
|
|
* initial challenge-response exchange has taken place.
|
|
|
|
* Provide for an option to avoid rechallenges.
|
|
|
|
*/
|
2002-01-04 15:21:24 +03:00
|
|
|
if ((sp->hisauth.flags & SPPP_AUTHFLAG_NORECHALLENGE) == 0) {
|
1999-04-04 10:07:56 +04:00
|
|
|
/*
|
|
|
|
* Compute the re-challenge timeout. This will yield
|
|
|
|
* a number between 300 and 810 seconds.
|
|
|
|
*/
|
2003-05-15 03:16:44 +04:00
|
|
|
i = 300 + ((unsigned)(arc4random() & 0xff00) >> 7);
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2000-03-23 10:01:25 +03:00
|
|
|
callout_reset(&sp->ch[IDX_CHAP], i * hz, chap.TO, sp);
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (debug) {
|
|
|
|
log(LOG_DEBUG,
|
2003-05-15 02:41:40 +04:00
|
|
|
"%s: chap %s, ",
|
|
|
|
ifp->if_xname,
|
2002-01-04 15:21:24 +03:00
|
|
|
sp->pp_phase == SPPP_PHASE_NETWORK? "reconfirmed": "tlu");
|
|
|
|
if ((sp->hisauth.flags & SPPP_AUTHFLAG_NORECHALLENGE) == 0)
|
1999-04-04 10:07:56 +04:00
|
|
|
addlog("next re-challenge in %d seconds\n", i);
|
|
|
|
else
|
|
|
|
addlog("re-challenging supressed\n");
|
|
|
|
}
|
|
|
|
|
2001-04-14 03:29:55 +04:00
|
|
|
x = splnet();
|
2002-01-07 13:49:02 +03:00
|
|
|
sp->pp_auth_failures = 0;
|
1999-04-04 10:07:56 +04:00
|
|
|
/* indicate to LCP that we need to be closed down */
|
|
|
|
sp->lcp.protos |= (1 << IDX_CHAP);
|
|
|
|
|
|
|
|
if (sp->pp_flags & PP_NEEDAUTH) {
|
|
|
|
/*
|
|
|
|
* Remote is authenticator, but his auth proto didn't
|
|
|
|
* complete yet. Defer the transition to network
|
|
|
|
* phase.
|
|
|
|
*/
|
|
|
|
splx(x);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
splx(x);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we are already in phase network, we are done here. This
|
|
|
|
* is the case if this is a dummy tlu event after a re-challenge.
|
|
|
|
*/
|
2002-01-04 15:21:24 +03:00
|
|
|
if (sp->pp_phase != SPPP_PHASE_NETWORK)
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_phase_network(sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_chap_tld(struct sppp *sp)
|
|
|
|
{
|
|
|
|
STDDCL;
|
|
|
|
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: chap tld\n", ifp->if_xname);
|
2000-03-23 10:01:25 +03:00
|
|
|
callout_stop(&sp->ch[IDX_CHAP]);
|
1999-04-04 10:07:56 +04:00
|
|
|
sp->lcp.protos &= ~(1 << IDX_CHAP);
|
|
|
|
|
|
|
|
lcp.Close(sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_chap_scr(struct sppp *sp)
|
|
|
|
{
|
2003-05-15 03:16:44 +04:00
|
|
|
u_int32_t *ch;
|
1999-04-04 10:07:56 +04:00
|
|
|
u_char clen;
|
|
|
|
|
2002-01-04 15:21:24 +03:00
|
|
|
if (sp->myauth.name == NULL) {
|
|
|
|
/* can't do anything usefull */
|
2003-05-15 02:41:40 +04:00
|
|
|
printf("%s: chap starting without my name being set\n",
|
|
|
|
sp->pp_if.if_xname);
|
2002-01-04 15:21:24 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
/* Compute random challenge. */
|
2001-12-05 00:32:15 +03:00
|
|
|
ch = (u_int32_t *)sp->myauth.challenge;
|
2003-05-15 03:16:44 +04:00
|
|
|
ch[0] = arc4random();
|
|
|
|
ch[1] = arc4random();
|
|
|
|
ch[2] = arc4random();
|
|
|
|
ch[3] = arc4random();
|
2002-01-04 15:21:24 +03:00
|
|
|
clen = 16; /* 4 * sizeof(u_int32_t) */
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2000-05-02 16:43:16 +04:00
|
|
|
sp->confid[IDX_CHAP] = ++sp->pp_seq[IDX_CHAP];
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
sppp_auth_send(&chap, sp, CHAP_CHALLENGE, sp->confid[IDX_CHAP],
|
|
|
|
sizeof clen, (const char *)&clen,
|
2002-01-04 15:21:24 +03:00
|
|
|
sizeof(sp->myauth.challenge), sp->myauth.challenge,
|
2002-07-28 23:54:47 +04:00
|
|
|
sp->myauth.name_len,
|
1999-04-04 10:07:56 +04:00
|
|
|
sp->myauth.name,
|
|
|
|
0);
|
|
|
|
}
|
2002-01-19 01:39:12 +03:00
|
|
|
|
|
|
|
/*
|
1999-04-04 10:07:56 +04:00
|
|
|
*--------------------------------------------------------------------------*
|
|
|
|
* *
|
|
|
|
* The PAP implementation. *
|
|
|
|
* *
|
|
|
|
*--------------------------------------------------------------------------*
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* For PAP, we need to keep a little state also if we are the peer, not the
|
|
|
|
* authenticator. This is since we don't get a request to authenticate, but
|
|
|
|
* have to repeatedly authenticate ourself until we got a response (or the
|
|
|
|
* retry counter is expired).
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle incoming PAP packets. */
|
|
|
|
static void
|
|
|
|
sppp_pap_input(struct sppp *sp, struct mbuf *m)
|
|
|
|
{
|
|
|
|
STDDCL;
|
|
|
|
struct lcp_header *h;
|
|
|
|
int len, x;
|
2002-01-04 15:21:24 +03:00
|
|
|
u_char mlen;
|
2002-07-28 19:12:29 +04:00
|
|
|
char *name, *secret;
|
2002-07-27 23:09:07 +04:00
|
|
|
int name_len, secret_len;
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2006-08-24 00:02:23 +04:00
|
|
|
/*
|
|
|
|
* Malicious input might leave this uninitialized, so
|
|
|
|
* init to an impossible value.
|
|
|
|
*/
|
|
|
|
secret_len = -1;
|
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
len = m->m_pkthdr.len;
|
|
|
|
if (len < 5) {
|
|
|
|
if (debug)
|
|
|
|
log(LOG_DEBUG,
|
2003-05-15 02:41:40 +04:00
|
|
|
"%s: pap invalid packet length: %d bytes\n",
|
|
|
|
ifp->if_xname, len);
|
1999-04-04 10:07:56 +04:00
|
|
|
return;
|
|
|
|
}
|
2002-09-25 11:24:06 +04:00
|
|
|
h = mtod(m, struct lcp_header *);
|
|
|
|
if (len > ntohs(h->len))
|
|
|
|
len = ntohs(h->len);
|
1999-04-04 10:07:56 +04:00
|
|
|
switch (h->type) {
|
|
|
|
/* PAP request is my authproto */
|
|
|
|
case PAP_REQ:
|
2002-01-04 15:21:24 +03:00
|
|
|
if (sp->hisauth.name == NULL || sp->hisauth.secret == NULL) {
|
|
|
|
/* can't do anything usefull */
|
2003-05-15 02:41:40 +04:00
|
|
|
printf("%s: pap request without his name and his secret being set\n",
|
|
|
|
ifp->if_xname);
|
2002-01-04 15:21:24 +03:00
|
|
|
break;
|
|
|
|
}
|
2002-09-25 11:24:06 +04:00
|
|
|
name = 1 + (u_char *)(h + 1);
|
1999-04-04 10:07:56 +04:00
|
|
|
name_len = name[-1];
|
2002-07-27 23:09:07 +04:00
|
|
|
secret = name + name_len + 1;
|
1999-04-04 10:07:56 +04:00
|
|
|
if (name_len > len - 6 ||
|
2002-07-27 23:09:07 +04:00
|
|
|
(secret_len = secret[-1]) > len - 6 - name_len) {
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug) {
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: pap corrupted input "
|
1999-04-04 10:07:56 +04:00
|
|
|
"<%s id=0x%x len=%d",
|
2003-05-15 02:41:40 +04:00
|
|
|
ifp->if_xname,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_auth_type_name(PPP_PAP, h->type),
|
|
|
|
h->ident, ntohs(h->len));
|
|
|
|
if (len > 4)
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_print_bytes((u_char *)(h + 1),
|
|
|
|
len - 4);
|
1999-04-04 10:07:56 +04:00
|
|
|
addlog(">\n");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (debug) {
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: pap input(%s) "
|
1999-04-04 10:07:56 +04:00
|
|
|
"<%s id=0x%x len=%d name=",
|
2003-05-15 02:41:40 +04:00
|
|
|
ifp->if_xname,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_state_name(sp->state[IDX_PAP]),
|
|
|
|
sppp_auth_type_name(PPP_PAP, h->type),
|
|
|
|
h->ident, ntohs(h->len));
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_print_string((char *)name, name_len);
|
2002-07-27 23:09:07 +04:00
|
|
|
addlog(" secret=");
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_print_string((char *)secret, secret_len);
|
1999-04-04 10:07:56 +04:00
|
|
|
addlog(">\n");
|
|
|
|
}
|
2002-07-28 23:54:47 +04:00
|
|
|
if (name_len != sp->hisauth.name_len ||
|
|
|
|
secret_len != sp->hisauth.secret_len ||
|
2002-07-28 19:12:29 +04:00
|
|
|
memcmp(name, sp->hisauth.name, name_len) != 0 ||
|
|
|
|
memcmp(secret, sp->hisauth.secret, secret_len) != 0) {
|
1999-04-04 10:07:56 +04:00
|
|
|
/* action scn, tld */
|
2002-01-07 13:49:02 +03:00
|
|
|
sp->pp_auth_failures++;
|
1999-04-04 10:07:56 +04:00
|
|
|
mlen = sizeof(FAILMSG) - 1;
|
|
|
|
sppp_auth_send(&pap, sp, PAP_NAK, h->ident,
|
|
|
|
sizeof mlen, (const char *)&mlen,
|
2005-05-30 01:22:52 +04:00
|
|
|
sizeof(FAILMSG) - 1, (const u_char *)FAILMSG,
|
1999-04-04 10:07:56 +04:00
|
|
|
0);
|
|
|
|
pap.tld(sp);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* action sca, perhaps tlu */
|
|
|
|
if (sp->state[IDX_PAP] == STATE_REQ_SENT ||
|
|
|
|
sp->state[IDX_PAP] == STATE_OPENED) {
|
|
|
|
mlen = sizeof(SUCCMSG) - 1;
|
|
|
|
sppp_auth_send(&pap, sp, PAP_ACK, h->ident,
|
|
|
|
sizeof mlen, (const char *)&mlen,
|
2005-05-30 01:22:52 +04:00
|
|
|
sizeof(SUCCMSG) - 1, (const u_char *)SUCCMSG,
|
1999-04-04 10:07:56 +04:00
|
|
|
0);
|
|
|
|
}
|
|
|
|
if (sp->state[IDX_PAP] == STATE_REQ_SENT) {
|
|
|
|
sppp_cp_change_state(&pap, sp, STATE_OPENED);
|
|
|
|
pap.tlu(sp);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* ack and nak are his authproto */
|
|
|
|
case PAP_ACK:
|
2000-03-23 10:01:25 +03:00
|
|
|
callout_stop(&sp->pap_my_to_ch);
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug) {
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: pap success",
|
|
|
|
ifp->if_xname);
|
2006-08-24 00:02:23 +04:00
|
|
|
name = 1 + (u_char *)(h + 1);
|
|
|
|
name_len = name[-1];
|
|
|
|
if (len > 5 && name_len < len+4) {
|
1999-04-04 10:07:56 +04:00
|
|
|
addlog(": ");
|
2006-08-24 00:02:23 +04:00
|
|
|
sppp_print_string(name, name_len);
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
addlog("\n");
|
|
|
|
}
|
2001-04-14 03:29:55 +04:00
|
|
|
x = splnet();
|
2002-01-07 13:49:02 +03:00
|
|
|
sp->pp_auth_failures = 0;
|
1999-04-04 10:07:56 +04:00
|
|
|
sp->pp_flags &= ~PP_NEEDAUTH;
|
|
|
|
if (sp->myauth.proto == PPP_PAP &&
|
|
|
|
(sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) &&
|
|
|
|
(sp->lcp.protos & (1 << IDX_PAP)) == 0) {
|
|
|
|
/*
|
|
|
|
* We are authenticator for PAP but didn't
|
|
|
|
* complete yet. Leave it to tlu to proceed
|
|
|
|
* to network phase.
|
|
|
|
*/
|
|
|
|
splx(x);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
splx(x);
|
|
|
|
sppp_phase_network(sp);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PAP_NAK:
|
2000-03-23 10:01:25 +03:00
|
|
|
callout_stop(&sp->pap_my_to_ch);
|
2002-01-07 13:49:02 +03:00
|
|
|
sp->pp_auth_failures++;
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug) {
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_INFO, "%s: pap failure",
|
|
|
|
ifp->if_xname);
|
2006-08-24 00:02:23 +04:00
|
|
|
name = 1 + (u_char *)(h + 1);
|
|
|
|
name_len = name[-1];
|
|
|
|
if (len > 5 && name_len < len+4) {
|
1999-04-04 10:07:56 +04:00
|
|
|
addlog(": ");
|
2006-08-24 00:02:23 +04:00
|
|
|
sppp_print_string(name, name_len);
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
addlog("\n");
|
|
|
|
} else
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_INFO, "%s: pap failure\n",
|
|
|
|
ifp->if_xname);
|
1999-04-04 10:07:56 +04:00
|
|
|
/* await LCP shutdown by authenticator */
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* Unknown PAP packet type -- ignore. */
|
|
|
|
if (debug) {
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: pap corrupted input "
|
1999-04-04 10:07:56 +04:00
|
|
|
"<0x%x id=0x%x len=%d",
|
2003-05-15 02:41:40 +04:00
|
|
|
ifp->if_xname,
|
1999-04-04 10:07:56 +04:00
|
|
|
h->type, h->ident, ntohs(h->len));
|
|
|
|
if (len > 4)
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_print_bytes((u_char *)(h + 1), len - 4);
|
1999-04-04 10:07:56 +04:00
|
|
|
addlog(">\n");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_pap_init(struct sppp *sp)
|
|
|
|
{
|
|
|
|
/* PAP doesn't have STATE_INITIAL at all. */
|
|
|
|
sp->state[IDX_PAP] = STATE_CLOSED;
|
|
|
|
sp->fail_counter[IDX_PAP] = 0;
|
2000-05-02 16:43:16 +04:00
|
|
|
sp->pp_seq[IDX_PAP] = 0;
|
|
|
|
sp->pp_rseq[IDX_PAP] = 0;
|
2007-07-10 00:51:58 +04:00
|
|
|
callout_init(&sp->ch[IDX_PAP], 0);
|
|
|
|
callout_init(&sp->pap_my_to_ch, 0);
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_pap_open(struct sppp *sp)
|
|
|
|
{
|
|
|
|
if (sp->hisauth.proto == PPP_PAP &&
|
|
|
|
(sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) != 0) {
|
|
|
|
/* we are authenticator for PAP, start our timer */
|
|
|
|
sp->rst_counter[IDX_PAP] = sp->lcp.max_configure;
|
|
|
|
sppp_cp_change_state(&pap, sp, STATE_REQ_SENT);
|
|
|
|
}
|
|
|
|
if (sp->myauth.proto == PPP_PAP) {
|
|
|
|
/* we are peer, send a request, and start a timer */
|
|
|
|
pap.scr(sp);
|
2000-03-23 10:01:25 +03:00
|
|
|
callout_reset(&sp->pap_my_to_ch, sp->lcp.timeout,
|
|
|
|
sppp_pap_my_TO, sp);
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_pap_close(struct sppp *sp)
|
|
|
|
{
|
|
|
|
if (sp->state[IDX_PAP] != STATE_CLOSED)
|
|
|
|
sppp_cp_change_state(&pap, sp, STATE_CLOSED);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* That's the timeout routine if we are authenticator. Since the
|
|
|
|
* authenticator is basically passive in PAP, we can't do much here.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
sppp_pap_TO(void *cookie)
|
|
|
|
{
|
|
|
|
struct sppp *sp = (struct sppp *)cookie;
|
|
|
|
STDDCL;
|
|
|
|
int s;
|
|
|
|
|
2001-04-14 03:29:55 +04:00
|
|
|
s = splnet();
|
1999-04-04 10:07:56 +04:00
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: pap TO(%s) rst_counter = %d\n",
|
|
|
|
ifp->if_xname,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_state_name(sp->state[IDX_PAP]),
|
|
|
|
sp->rst_counter[IDX_PAP]);
|
|
|
|
|
|
|
|
if (--sp->rst_counter[IDX_PAP] < 0)
|
|
|
|
/* TO- event */
|
|
|
|
switch (sp->state[IDX_PAP]) {
|
|
|
|
case STATE_REQ_SENT:
|
|
|
|
pap.tld(sp);
|
|
|
|
sppp_cp_change_state(&pap, sp, STATE_CLOSED);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
/* TO+ event, not very much we could do */
|
|
|
|
switch (sp->state[IDX_PAP]) {
|
|
|
|
case STATE_REQ_SENT:
|
|
|
|
/* sppp_cp_change_state() will restart the timer */
|
|
|
|
sppp_cp_change_state(&pap, sp, STATE_REQ_SENT);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* That's the timeout handler if we are peer. Since the peer is active,
|
|
|
|
* we need to retransmit our PAP request since it is apparently lost.
|
|
|
|
* XXX We should impose a max counter.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
sppp_pap_my_TO(void *cookie)
|
|
|
|
{
|
|
|
|
struct sppp *sp = (struct sppp *)cookie;
|
|
|
|
STDDCL;
|
|
|
|
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: pap peer TO\n",
|
|
|
|
ifp->if_xname);
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
pap.scr(sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_pap_tlu(struct sppp *sp)
|
|
|
|
{
|
|
|
|
STDDCL;
|
|
|
|
int x;
|
|
|
|
|
|
|
|
sp->rst_counter[IDX_PAP] = sp->lcp.max_configure;
|
|
|
|
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: %s tlu\n",
|
|
|
|
ifp->if_xname, pap.name);
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2001-04-14 03:29:55 +04:00
|
|
|
x = splnet();
|
2002-01-07 13:49:02 +03:00
|
|
|
sp->pp_auth_failures = 0;
|
1999-04-04 10:07:56 +04:00
|
|
|
/* indicate to LCP that we need to be closed down */
|
|
|
|
sp->lcp.protos |= (1 << IDX_PAP);
|
|
|
|
|
|
|
|
if (sp->pp_flags & PP_NEEDAUTH) {
|
|
|
|
/*
|
|
|
|
* Remote is authenticator, but his auth proto didn't
|
|
|
|
* complete yet. Defer the transition to network
|
|
|
|
* phase.
|
|
|
|
*/
|
|
|
|
splx(x);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
splx(x);
|
|
|
|
sppp_phase_network(sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_pap_tld(struct sppp *sp)
|
|
|
|
{
|
|
|
|
STDDCL;
|
|
|
|
|
|
|
|
if (debug)
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: pap tld\n", ifp->if_xname);
|
2000-03-23 10:01:25 +03:00
|
|
|
callout_stop(&sp->ch[IDX_PAP]);
|
|
|
|
callout_stop(&sp->pap_my_to_ch);
|
1999-04-04 10:07:56 +04:00
|
|
|
sp->lcp.protos &= ~(1 << IDX_PAP);
|
|
|
|
|
|
|
|
lcp.Close(sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_pap_scr(struct sppp *sp)
|
|
|
|
{
|
|
|
|
u_char idlen, pwdlen;
|
|
|
|
|
2002-01-04 15:21:24 +03:00
|
|
|
if (sp->myauth.secret == NULL || sp->myauth.name == NULL) {
|
|
|
|
/* can't do anything usefull */
|
2003-05-15 02:41:40 +04:00
|
|
|
printf("%s: pap starting without my name and secret being set\n",
|
|
|
|
sp->pp_if.if_xname);
|
2002-01-04 15:21:24 +03:00
|
|
|
return;
|
|
|
|
}
|
2005-02-27 01:45:09 +03:00
|
|
|
|
2000-05-02 16:43:16 +04:00
|
|
|
sp->confid[IDX_PAP] = ++sp->pp_seq[IDX_PAP];
|
2002-07-28 23:54:47 +04:00
|
|
|
pwdlen = sp->myauth.secret_len;
|
|
|
|
idlen = sp->myauth.name_len;
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
sppp_auth_send(&pap, sp, PAP_REQ, sp->confid[IDX_PAP],
|
|
|
|
sizeof idlen, (const char *)&idlen,
|
2002-01-04 15:21:24 +03:00
|
|
|
idlen, sp->myauth.name,
|
1999-04-04 10:07:56 +04:00
|
|
|
sizeof pwdlen, (const char *)&pwdlen,
|
2002-01-04 15:21:24 +03:00
|
|
|
pwdlen, sp->myauth.secret,
|
1999-04-04 10:07:56 +04:00
|
|
|
0);
|
|
|
|
}
|
2002-01-19 01:39:12 +03:00
|
|
|
|
|
|
|
/*
|
1999-04-04 10:07:56 +04:00
|
|
|
* Random miscellaneous functions.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Send a PAP or CHAP proto packet.
|
|
|
|
*
|
|
|
|
* Varadic function, each of the elements for the ellipsis is of type
|
|
|
|
* ``size_t mlen, const u_char *msg''. Processing will stop iff
|
|
|
|
* mlen == 0.
|
|
|
|
* NOTE: never declare variadic functions with types subject to type
|
|
|
|
* promotion (i.e. u_char). This is asking for big trouble depending
|
|
|
|
* on the architecture you are on...
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_auth_send(const struct cp *cp, struct sppp *sp,
|
|
|
|
unsigned int type, unsigned int id,
|
|
|
|
...)
|
|
|
|
{
|
|
|
|
STDDCL;
|
|
|
|
struct lcp_header *lh;
|
|
|
|
struct mbuf *m;
|
|
|
|
u_char *p;
|
|
|
|
int len;
|
2001-04-09 23:33:01 +04:00
|
|
|
size_t pkthdrlen;
|
1999-04-04 10:07:56 +04:00
|
|
|
unsigned int mlen;
|
|
|
|
const char *msg;
|
|
|
|
va_list ap;
|
|
|
|
|
2002-09-25 11:24:06 +04:00
|
|
|
MGETHDR(m, M_DONTWAIT, MT_DATA);
|
1999-04-04 10:07:56 +04:00
|
|
|
if (! m)
|
|
|
|
return;
|
|
|
|
m->m_pkthdr.rcvif = 0;
|
|
|
|
|
2001-04-09 23:33:01 +04:00
|
|
|
if (sp->pp_flags & PP_NOFRAMING) {
|
2002-09-25 11:24:06 +04:00
|
|
|
*mtod(m, u_int16_t *) = htons(cp->proto);
|
2001-04-09 23:33:01 +04:00
|
|
|
pkthdrlen = 2;
|
2002-09-25 11:24:06 +04:00
|
|
|
lh = (struct lcp_header *)(mtod(m, u_int8_t *)+2);
|
2001-04-09 23:33:01 +04:00
|
|
|
} else {
|
|
|
|
struct ppp_header *h;
|
2002-09-25 11:24:06 +04:00
|
|
|
h = mtod(m, struct ppp_header *);
|
2001-04-09 23:33:01 +04:00
|
|
|
h->address = PPP_ALLSTATIONS; /* broadcast address */
|
|
|
|
h->control = PPP_UI; /* Unnumbered Info */
|
|
|
|
h->protocol = htons(cp->proto);
|
|
|
|
pkthdrlen = PPP_HEADER_LEN;
|
|
|
|
|
2002-09-25 11:24:06 +04:00
|
|
|
lh = (struct lcp_header *)(h + 1);
|
2001-04-09 23:33:01 +04:00
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
lh->type = type;
|
|
|
|
lh->ident = id;
|
2002-09-25 11:24:06 +04:00
|
|
|
p = (u_char *)(lh + 1);
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
va_start(ap, id);
|
|
|
|
len = 0;
|
|
|
|
|
|
|
|
while ((mlen = (unsigned int)va_arg(ap, size_t)) != 0) {
|
|
|
|
msg = va_arg(ap, const char *);
|
|
|
|
len += mlen;
|
2001-04-09 23:33:01 +04:00
|
|
|
if (len > MHLEN - pkthdrlen - LCP_HEADER_LEN) {
|
1999-04-04 10:07:56 +04:00
|
|
|
va_end(ap);
|
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bcopy(msg, p, mlen);
|
|
|
|
p += mlen;
|
|
|
|
}
|
|
|
|
va_end(ap);
|
|
|
|
|
2001-04-09 23:33:01 +04:00
|
|
|
m->m_pkthdr.len = m->m_len = pkthdrlen + LCP_HEADER_LEN + len;
|
2002-09-25 11:24:06 +04:00
|
|
|
lh->len = htons(LCP_HEADER_LEN + len);
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
if (debug) {
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: %s output <%s id=0x%x len=%d",
|
|
|
|
ifp->if_xname, cp->name,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_auth_type_name(cp->proto, lh->type),
|
|
|
|
lh->ident, ntohs(lh->len));
|
|
|
|
if (len)
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_print_bytes((u_char *)(lh + 1), len);
|
1999-04-04 10:07:56 +04:00
|
|
|
addlog(">\n");
|
|
|
|
}
|
2002-09-25 11:24:06 +04:00
|
|
|
if (IF_QFULL(&sp->pp_cpq)) {
|
|
|
|
IF_DROP(&sp->pp_fastq);
|
|
|
|
IF_DROP(&ifp->if_snd);
|
|
|
|
m_freem(m);
|
1999-04-04 10:07:56 +04:00
|
|
|
++ifp->if_oerrors;
|
2002-07-12 01:37:51 +04:00
|
|
|
return;
|
1999-04-04 10:07:56 +04:00
|
|
|
} else
|
2002-09-25 11:24:06 +04:00
|
|
|
IF_ENQUEUE(&sp->pp_cpq, m);
|
1999-04-04 10:07:56 +04:00
|
|
|
if (! (ifp->if_flags & IFF_OACTIVE))
|
2002-09-25 11:24:06 +04:00
|
|
|
(*ifp->if_start)(ifp);
|
1999-04-04 10:07:56 +04:00
|
|
|
ifp->if_obytes += m->m_pkthdr.len + 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Send keepalive packets, every 10 seconds.
|
|
|
|
*/
|
|
|
|
static void
|
2006-11-16 04:32:37 +03:00
|
|
|
sppp_keepalive(void *dummy)
|
1999-04-04 10:07:56 +04:00
|
|
|
{
|
|
|
|
struct sppp *sp;
|
|
|
|
int s;
|
2002-01-06 23:14:29 +03:00
|
|
|
time_t now;
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2001-04-14 03:29:55 +04:00
|
|
|
s = splnet();
|
2006-06-08 02:33:33 +04:00
|
|
|
now = time_uptime;
|
1999-04-04 10:07:56 +04:00
|
|
|
for (sp=spppq; sp; sp=sp->pp_next) {
|
|
|
|
struct ifnet *ifp = &sp->pp_if;
|
|
|
|
|
2002-01-06 23:14:29 +03:00
|
|
|
/* check idle timeout */
|
2002-01-14 10:39:14 +03:00
|
|
|
if ((sp->pp_idle_timeout != 0) && (ifp->if_flags & IFF_RUNNING)
|
|
|
|
&& (sp->pp_phase == SPPP_PHASE_NETWORK)) {
|
2002-01-06 23:14:29 +03:00
|
|
|
/* idle timeout is enabled for this interface */
|
|
|
|
if ((now-sp->pp_last_activity) >= sp->pp_idle_timeout) {
|
|
|
|
if (ifp->if_flags & IFF_DEBUG)
|
2005-04-27 11:48:02 +04:00
|
|
|
printf("%s: no activity for %lu seconds\n",
|
2002-01-06 23:14:29 +03:00
|
|
|
sp->pp_if.if_xname,
|
|
|
|
(unsigned long)(now-sp->pp_last_activity));
|
|
|
|
lcp.Close(sp);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
/* Keepalive mode disabled or channel down? */
|
|
|
|
if (! (sp->pp_flags & PP_KEEPALIVE) ||
|
|
|
|
! (ifp->if_flags & IFF_RUNNING))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* No keepalive in PPP mode if LCP not opened yet. */
|
|
|
|
if (! (sp->pp_flags & PP_CISCO) &&
|
2002-01-04 15:21:24 +03:00
|
|
|
sp->pp_phase < SPPP_PHASE_AUTHENTICATE)
|
1999-04-04 10:07:56 +04:00
|
|
|
continue;
|
|
|
|
|
2002-09-01 22:54:12 +04:00
|
|
|
/* No echo reply, but maybe user data passed through? */
|
2003-09-04 00:48:46 +04:00
|
|
|
if ((now - sp->pp_last_receive) < sp->pp_max_noreceive) {
|
2002-09-01 22:54:12 +04:00
|
|
|
sp->pp_alivecnt = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2003-09-04 00:48:46 +04:00
|
|
|
if (sp->pp_alivecnt >= sp->pp_maxalive) {
|
1999-04-04 10:07:56 +04:00
|
|
|
/* No keepalive packets got. Stop the interface. */
|
|
|
|
if_down (ifp);
|
2002-09-25 11:24:06 +04:00
|
|
|
IF_PURGE(&sp->pp_cpq);
|
1999-04-04 10:07:56 +04:00
|
|
|
if (! (sp->pp_flags & PP_CISCO)) {
|
2001-12-15 23:40:37 +03:00
|
|
|
printf("%s: LCP keepalive timed out, going to restart the connection\n",
|
|
|
|
ifp->if_xname);
|
|
|
|
sp->pp_alivecnt = 0;
|
|
|
|
|
|
|
|
/* we are down, close all open protocols */
|
|
|
|
lcp.Close(sp);
|
|
|
|
|
|
|
|
/* And now prepare LCP to reestablish the link, if configured to do so. */
|
|
|
|
sppp_cp_change_state(&lcp, sp, STATE_STOPPED);
|
|
|
|
|
2006-11-25 00:23:07 +03:00
|
|
|
/* Close connection immediately, completition of this
|
2001-12-15 23:40:37 +03:00
|
|
|
* will summon the magic needed to reestablish it. */
|
2006-05-21 09:09:13 +04:00
|
|
|
if (sp->pp_tlf)
|
|
|
|
sp->pp_tlf(sp);
|
2001-12-15 23:40:37 +03:00
|
|
|
continue;
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
}
|
2003-09-04 00:48:46 +04:00
|
|
|
if (sp->pp_alivecnt < sp->pp_maxalive)
|
1999-04-04 10:07:56 +04:00
|
|
|
++sp->pp_alivecnt;
|
|
|
|
if (sp->pp_flags & PP_CISCO)
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_cisco_send(sp, CISCO_KEEPALIVE_REQ,
|
2000-05-02 16:43:16 +04:00
|
|
|
++sp->pp_seq[IDX_LCP], sp->pp_rseq[IDX_LCP]);
|
2002-01-04 15:21:24 +03:00
|
|
|
else if (sp->pp_phase >= SPPP_PHASE_AUTHENTICATE) {
|
2002-09-25 11:24:06 +04:00
|
|
|
int32_t nmagic = htonl(sp->lcp.magic);
|
2000-05-02 16:43:16 +04:00
|
|
|
sp->lcp.echoid = ++sp->pp_seq[IDX_LCP];
|
2002-09-25 11:24:06 +04:00
|
|
|
sppp_cp_send(sp, PPP_LCP, ECHO_REQ,
|
1999-04-04 10:07:56 +04:00
|
|
|
sp->lcp.echoid, 4, &nmagic);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
splx(s);
|
2002-09-01 22:54:12 +04:00
|
|
|
callout_reset(&keepalive_ch, hz * LCP_KEEPALIVE_INTERVAL, sppp_keepalive, NULL);
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
|
2004-12-06 05:59:23 +03:00
|
|
|
#ifdef INET
|
1999-04-04 10:07:56 +04:00
|
|
|
/*
|
|
|
|
* Get both IP addresses.
|
|
|
|
*/
|
|
|
|
static void
|
2001-12-05 00:32:15 +03:00
|
|
|
sppp_get_ip_addrs(struct sppp *sp, u_int32_t *src, u_int32_t *dst, u_int32_t *srcmask)
|
1999-04-04 10:07:56 +04:00
|
|
|
{
|
|
|
|
struct ifnet *ifp = &sp->pp_if;
|
|
|
|
struct ifaddr *ifa;
|
|
|
|
struct sockaddr_in *si, *sm;
|
2001-12-05 00:32:15 +03:00
|
|
|
u_int32_t ssrc, ddst;
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
sm = NULL;
|
2001-12-05 00:32:15 +03:00
|
|
|
ssrc = ddst = 0;
|
1999-04-04 10:07:56 +04:00
|
|
|
/*
|
|
|
|
* Pick the first AF_INET address from the list,
|
|
|
|
* aliases don't make any sense on a p2p link anyway.
|
|
|
|
*/
|
2001-11-05 21:02:15 +03:00
|
|
|
si = 0;
|
2005-01-25 00:25:09 +03:00
|
|
|
IFADDR_FOREACH(ifa, ifp) {
|
1999-04-04 10:07:56 +04:00
|
|
|
if (ifa->ifa_addr->sa_family == AF_INET) {
|
|
|
|
si = (struct sockaddr_in *)ifa->ifa_addr;
|
|
|
|
sm = (struct sockaddr_in *)ifa->ifa_netmask;
|
|
|
|
if (si)
|
|
|
|
break;
|
|
|
|
}
|
2001-11-05 21:02:15 +03:00
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
if (ifa) {
|
|
|
|
if (si && si->sin_addr.s_addr) {
|
|
|
|
ssrc = si->sin_addr.s_addr;
|
|
|
|
if (srcmask)
|
|
|
|
*srcmask = ntohl(sm->sin_addr.s_addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
si = (struct sockaddr_in *)ifa->ifa_dstaddr;
|
|
|
|
if (si && si->sin_addr.s_addr)
|
|
|
|
ddst = si->sin_addr.s_addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dst) *dst = ntohl(ddst);
|
|
|
|
if (src) *src = ntohl(ssrc);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2001-12-08 22:46:39 +03:00
|
|
|
* Set IP addresses. Must be called at splnet.
|
|
|
|
* If an address is 0, leave it the way it is.
|
1999-04-04 10:07:56 +04:00
|
|
|
*/
|
|
|
|
static void
|
2001-12-08 22:46:39 +03:00
|
|
|
sppp_set_ip_addrs(struct sppp *sp, u_int32_t myaddr, u_int32_t hisaddr)
|
1999-04-04 10:07:56 +04:00
|
|
|
{
|
|
|
|
STDDCL;
|
|
|
|
struct ifaddr *ifa;
|
2003-10-28 23:21:44 +03:00
|
|
|
struct sockaddr_in *si, *dest;
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Pick the first AF_INET address from the list,
|
|
|
|
* aliases don't make any sense on a p2p link anyway.
|
|
|
|
*/
|
|
|
|
|
2005-01-25 00:25:09 +03:00
|
|
|
IFADDR_FOREACH(ifa, ifp) {
|
2003-10-28 23:21:44 +03:00
|
|
|
if (ifa->ifa_addr->sa_family == AF_INET) {
|
1999-04-04 10:07:56 +04:00
|
|
|
si = (struct sockaddr_in *)ifa->ifa_addr;
|
2001-12-08 22:46:39 +03:00
|
|
|
dest = (struct sockaddr_in *)ifa->ifa_dstaddr;
|
2003-10-28 23:21:44 +03:00
|
|
|
goto found;
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
}
|
2003-10-28 23:21:44 +03:00
|
|
|
return;
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2003-10-28 23:21:44 +03:00
|
|
|
found:
|
1999-04-04 10:07:56 +04:00
|
|
|
{
|
|
|
|
int error;
|
|
|
|
struct sockaddr_in new_sin = *si;
|
2001-12-08 22:46:39 +03:00
|
|
|
struct sockaddr_in new_dst = *dest;
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2001-12-08 22:46:39 +03:00
|
|
|
/*
|
|
|
|
* Scrub old routes now instead of calling in_ifinit with
|
|
|
|
* scrub=1, because we may change the dstaddr
|
|
|
|
* before the call to in_ifinit.
|
|
|
|
*/
|
|
|
|
in_ifscrub(ifp, ifatoia(ifa));
|
|
|
|
|
|
|
|
if (myaddr != 0)
|
|
|
|
new_sin.sin_addr.s_addr = htonl(myaddr);
|
|
|
|
if (hisaddr != 0) {
|
|
|
|
new_dst.sin_addr.s_addr = htonl(hisaddr);
|
|
|
|
if (new_dst.sin_addr.s_addr != dest->sin_addr.s_addr) {
|
|
|
|
sp->ipcp.saved_hisaddr = dest->sin_addr.s_addr;
|
|
|
|
*dest = new_dst; /* fix dstaddr in place */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
error = in_ifinit(ifp, ifatoia(ifa), &new_sin, 0);
|
2003-10-02 05:27:20 +04:00
|
|
|
if (debug && error)
|
1999-04-04 10:07:56 +04:00
|
|
|
{
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: sppp_set_ip_addrs: in_ifinit "
|
|
|
|
" failed, error=%d\n", ifp->if_xname, error);
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
2004-09-18 20:04:41 +04:00
|
|
|
#ifdef PFIL_HOOKS
|
|
|
|
if (!error)
|
|
|
|
(void)pfil_run_hooks(&if_pfil,
|
|
|
|
(struct mbuf **)SIOCAIFADDR, ifp, PFIL_IFADDR);
|
|
|
|
#endif
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
2005-02-27 01:45:09 +03:00
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2001-12-08 22:46:39 +03:00
|
|
|
/*
|
|
|
|
* Clear IP addresses. Must be called at splnet.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
sppp_clear_ip_addrs(struct sppp *sp)
|
|
|
|
{
|
|
|
|
struct ifnet *ifp = &sp->pp_if;
|
|
|
|
struct ifaddr *ifa;
|
2003-10-28 23:21:44 +03:00
|
|
|
struct sockaddr_in *si, *dest;
|
2001-12-08 22:46:39 +03:00
|
|
|
|
|
|
|
u_int32_t remote;
|
|
|
|
if (sp->ipcp.flags & IPCP_HISADDR_DYN)
|
|
|
|
remote = sp->ipcp.saved_hisaddr;
|
|
|
|
else
|
|
|
|
sppp_get_ip_addrs(sp, 0, &remote, 0);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Pick the first AF_INET address from the list,
|
|
|
|
* aliases don't make any sense on a p2p link anyway.
|
|
|
|
*/
|
|
|
|
|
2005-01-25 00:25:09 +03:00
|
|
|
IFADDR_FOREACH(ifa, ifp) {
|
2003-10-28 23:21:44 +03:00
|
|
|
if (ifa->ifa_addr->sa_family == AF_INET) {
|
2001-12-08 22:46:39 +03:00
|
|
|
si = (struct sockaddr_in *)ifa->ifa_addr;
|
|
|
|
dest = (struct sockaddr_in *)ifa->ifa_dstaddr;
|
2003-10-28 23:21:44 +03:00
|
|
|
goto found;
|
2001-12-08 22:46:39 +03:00
|
|
|
}
|
|
|
|
}
|
2003-10-28 23:21:44 +03:00
|
|
|
return;
|
2001-12-08 22:46:39 +03:00
|
|
|
|
2003-10-28 23:21:44 +03:00
|
|
|
found:
|
2001-12-08 22:46:39 +03:00
|
|
|
{
|
|
|
|
struct sockaddr_in new_sin = *si;
|
|
|
|
|
|
|
|
in_ifscrub(ifp, ifatoia(ifa));
|
|
|
|
if (sp->ipcp.flags & IPCP_MYADDR_DYN)
|
|
|
|
new_sin.sin_addr.s_addr = 0;
|
|
|
|
if (sp->ipcp.flags & IPCP_HISADDR_DYN)
|
|
|
|
/* replace peer addr in place */
|
|
|
|
dest->sin_addr.s_addr = sp->ipcp.saved_hisaddr;
|
|
|
|
in_ifinit(ifp, ifatoia(ifa), &new_sin, 0);
|
2004-09-18 20:04:41 +04:00
|
|
|
#ifdef PFIL_HOOKS
|
|
|
|
(void)pfil_run_hooks(&if_pfil,
|
|
|
|
(struct mbuf **)SIOCDIFADDR, ifp, PFIL_IFADDR);
|
|
|
|
#endif
|
2001-12-08 22:46:39 +03:00
|
|
|
}
|
2005-02-27 01:45:09 +03:00
|
|
|
}
|
2004-12-06 05:59:23 +03:00
|
|
|
#endif
|
2001-12-08 22:46:39 +03:00
|
|
|
|
2000-05-02 16:43:16 +04:00
|
|
|
#ifdef INET6
|
|
|
|
/*
|
|
|
|
* Get both IPv6 addresses.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
sppp_get_ip6_addrs(struct sppp *sp, struct in6_addr *src, struct in6_addr *dst,
|
|
|
|
struct in6_addr *srcmask)
|
|
|
|
{
|
|
|
|
struct ifnet *ifp = &sp->pp_if;
|
|
|
|
struct ifaddr *ifa;
|
|
|
|
struct sockaddr_in6 *si, *sm;
|
|
|
|
struct in6_addr ssrc, ddst;
|
|
|
|
|
|
|
|
sm = NULL;
|
2001-07-18 20:43:09 +04:00
|
|
|
memset(&ssrc, 0, sizeof(ssrc));
|
|
|
|
memset(&ddst, 0, sizeof(ddst));
|
2000-05-02 16:43:16 +04:00
|
|
|
/*
|
|
|
|
* Pick the first link-local AF_INET6 address from the list,
|
|
|
|
* aliases don't make any sense on a p2p link anyway.
|
|
|
|
*/
|
2001-11-05 21:02:15 +03:00
|
|
|
si = 0;
|
2005-01-25 00:25:09 +03:00
|
|
|
IFADDR_FOREACH(ifa, ifp)
|
2000-05-02 16:43:16 +04:00
|
|
|
if (ifa->ifa_addr->sa_family == AF_INET6) {
|
|
|
|
si = (struct sockaddr_in6 *)ifa->ifa_addr;
|
|
|
|
sm = (struct sockaddr_in6 *)ifa->ifa_netmask;
|
|
|
|
if (si && IN6_IS_ADDR_LINKLOCAL(&si->sin6_addr))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (ifa) {
|
|
|
|
if (si && !IN6_IS_ADDR_UNSPECIFIED(&si->sin6_addr)) {
|
|
|
|
bcopy(&si->sin6_addr, &ssrc, sizeof(ssrc));
|
|
|
|
if (srcmask) {
|
|
|
|
bcopy(&sm->sin6_addr, srcmask,
|
|
|
|
sizeof(*srcmask));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
si = (struct sockaddr_in6 *)ifa->ifa_dstaddr;
|
|
|
|
if (si && !IN6_IS_ADDR_UNSPECIFIED(&si->sin6_addr))
|
|
|
|
bcopy(&si->sin6_addr, &ddst, sizeof(ddst));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dst)
|
|
|
|
bcopy(&ddst, dst, sizeof(*dst));
|
|
|
|
if (src)
|
|
|
|
bcopy(&ssrc, src, sizeof(*src));
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef IPV6CP_MYIFID_DYN
|
|
|
|
/*
|
|
|
|
* Generate random ifid.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
sppp_gen_ip6_addr(struct sppp *sp, struct in6_addr *addr)
|
|
|
|
{
|
|
|
|
/* TBD */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2001-04-14 03:29:55 +04:00
|
|
|
* Set my IPv6 address. Must be called at splnet.
|
2000-05-02 16:43:16 +04:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
sppp_set_ip6_addr(struct sppp *sp, const struct in6_addr *src)
|
|
|
|
{
|
|
|
|
STDDCL;
|
|
|
|
struct ifaddr *ifa;
|
|
|
|
struct sockaddr_in6 *sin6;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Pick the first link-local AF_INET6 address from the list,
|
|
|
|
* aliases don't make any sense on a p2p link anyway.
|
|
|
|
*/
|
|
|
|
|
|
|
|
sin6 = NULL;
|
2005-01-25 00:25:09 +03:00
|
|
|
IFADDR_FOREACH(ifa, ifp)
|
2000-05-02 16:43:16 +04:00
|
|
|
{
|
|
|
|
if (ifa->ifa_addr->sa_family == AF_INET6)
|
|
|
|
{
|
|
|
|
sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
|
|
|
|
if (sin6 && IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ifa && sin6)
|
|
|
|
{
|
|
|
|
int error;
|
|
|
|
struct sockaddr_in6 new_sin6 = *sin6;
|
|
|
|
|
|
|
|
bcopy(src, &new_sin6.sin6_addr, sizeof(new_sin6.sin6_addr));
|
|
|
|
error = in6_ifinit(ifp, ifatoia6(ifa), &new_sin6, 1);
|
|
|
|
if (debug && error)
|
|
|
|
{
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_DEBUG, "%s: sppp_set_ip6_addr: in6_ifinit "
|
|
|
|
" failed, error=%d\n", ifp->if_xname, error);
|
2000-05-02 16:43:16 +04:00
|
|
|
}
|
2004-09-18 20:04:41 +04:00
|
|
|
#ifdef PFIL_HOOKS
|
|
|
|
if (!error)
|
|
|
|
(void)pfil_run_hooks(&if_pfil,
|
|
|
|
(struct mbuf **)SIOCAIFADDR_IN6, ifp, PFIL_IFADDR);
|
|
|
|
#endif
|
2000-05-02 16:43:16 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Suggest a candidate address to be used by peer.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
sppp_suggest_ip6_addr(struct sppp *sp, struct in6_addr *suggest)
|
|
|
|
{
|
|
|
|
struct in6_addr myaddr;
|
2000-05-16 09:45:27 +04:00
|
|
|
struct timeval tv;
|
2000-05-02 16:43:16 +04:00
|
|
|
|
|
|
|
sppp_get_ip6_addrs(sp, &myaddr, 0, 0);
|
|
|
|
|
|
|
|
myaddr.s6_addr[8] &= ~0x02; /* u bit to "local" */
|
2000-05-16 09:45:27 +04:00
|
|
|
microtime(&tv);
|
|
|
|
if ((tv.tv_usec & 0xff) == 0 && (tv.tv_sec & 0xff) == 0) {
|
|
|
|
myaddr.s6_addr[14] ^= 0xff;
|
|
|
|
myaddr.s6_addr[15] ^= 0xff;
|
|
|
|
} else {
|
|
|
|
myaddr.s6_addr[14] ^= (tv.tv_usec & 0xff);
|
|
|
|
myaddr.s6_addr[15] ^= (tv.tv_sec & 0xff);
|
|
|
|
}
|
2000-05-02 16:43:16 +04:00
|
|
|
if (suggest)
|
|
|
|
bcopy(&myaddr, suggest, sizeof(myaddr));
|
|
|
|
}
|
|
|
|
#endif /*INET6*/
|
|
|
|
|
2002-01-04 15:21:24 +03:00
|
|
|
/*
|
|
|
|
* Process ioctl requests specific to the PPP interface.
|
|
|
|
* Permissions have already been checked.
|
|
|
|
*/
|
1999-04-04 10:07:56 +04:00
|
|
|
static int
|
|
|
|
sppp_params(struct sppp *sp, int cmd, void *data)
|
|
|
|
{
|
2002-01-04 15:21:24 +03:00
|
|
|
switch (cmd) {
|
|
|
|
case SPPPGETAUTHCFG:
|
|
|
|
{
|
2002-01-19 01:39:12 +03:00
|
|
|
struct spppauthcfg *cfg = (struct spppauthcfg *)data;
|
|
|
|
int error;
|
|
|
|
size_t len;
|
|
|
|
|
2002-01-04 15:21:24 +03:00
|
|
|
cfg->myauthflags = sp->myauth.flags;
|
|
|
|
cfg->hisauthflags = sp->hisauth.flags;
|
|
|
|
strncpy(cfg->ifname, sp->pp_if.if_xname, IFNAMSIZ);
|
|
|
|
cfg->hisauth = 0;
|
|
|
|
if (sp->hisauth.proto)
|
2002-01-19 01:39:12 +03:00
|
|
|
cfg->hisauth = (sp->hisauth.proto == PPP_PAP) ? SPPP_AUTHPROTO_PAP : SPPP_AUTHPROTO_CHAP;
|
2002-01-04 15:21:24 +03:00
|
|
|
cfg->myauth = 0;
|
|
|
|
if (sp->myauth.proto)
|
2002-01-19 01:39:12 +03:00
|
|
|
cfg->myauth = (sp->myauth.proto == PPP_PAP) ? SPPP_AUTHPROTO_PAP : SPPP_AUTHPROTO_CHAP;
|
2002-01-04 15:21:24 +03:00
|
|
|
if (cfg->myname_length == 0) {
|
|
|
|
if (sp->myauth.name != NULL)
|
2002-07-28 23:54:47 +04:00
|
|
|
cfg->myname_length = sp->myauth.name_len + 1;
|
2002-01-04 15:21:24 +03:00
|
|
|
} else {
|
2002-01-15 15:28:08 +03:00
|
|
|
if (sp->myauth.name == NULL) {
|
|
|
|
cfg->myname_length = 0;
|
|
|
|
} else {
|
2002-07-28 23:54:47 +04:00
|
|
|
len = sp->myauth.name_len + 1;
|
2002-01-15 15:28:08 +03:00
|
|
|
if (cfg->myname_length < len)
|
2002-01-19 01:39:12 +03:00
|
|
|
return (ENAMETOOLONG);
|
|
|
|
error = copyout(sp->myauth.name, cfg->myname, len);
|
|
|
|
if (error) return error;
|
2002-01-15 15:28:08 +03:00
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
2002-01-04 15:21:24 +03:00
|
|
|
if (cfg->hisname_length == 0) {
|
2003-10-02 05:27:20 +04:00
|
|
|
if (sp->hisauth.name != NULL)
|
2002-07-28 23:54:47 +04:00
|
|
|
cfg->hisname_length = sp->hisauth.name_len + 1;
|
2002-01-04 15:21:24 +03:00
|
|
|
} else {
|
2002-01-15 15:28:08 +03:00
|
|
|
if (sp->hisauth.name == NULL) {
|
|
|
|
cfg->hisname_length = 0;
|
|
|
|
} else {
|
2002-07-28 23:54:47 +04:00
|
|
|
len = sp->hisauth.name_len + 1;
|
2002-01-15 15:28:08 +03:00
|
|
|
if (cfg->hisname_length < len)
|
2002-01-19 01:39:12 +03:00
|
|
|
return (ENAMETOOLONG);
|
|
|
|
error = copyout(sp->hisauth.name, cfg->hisname, len);
|
|
|
|
if (error) return error;
|
2002-01-15 15:28:08 +03:00
|
|
|
}
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
2002-01-04 15:21:24 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SPPPSETAUTHCFG:
|
|
|
|
{
|
2002-09-25 11:24:06 +04:00
|
|
|
struct spppauthcfg *cfg = (struct spppauthcfg *)data;
|
2002-01-19 01:39:12 +03:00
|
|
|
int error;
|
|
|
|
|
|
|
|
if (sp->myauth.name) {
|
|
|
|
free(sp->myauth.name, M_DEVBUF);
|
|
|
|
sp->myauth.name = NULL;
|
|
|
|
}
|
|
|
|
if (sp->myauth.secret) {
|
|
|
|
free(sp->myauth.secret, M_DEVBUF);
|
|
|
|
sp->myauth.secret = NULL;
|
|
|
|
}
|
|
|
|
if (sp->hisauth.name) {
|
|
|
|
free(sp->hisauth.name, M_DEVBUF);
|
|
|
|
sp->hisauth.name = NULL;
|
|
|
|
}
|
|
|
|
if (sp->hisauth.secret) {
|
|
|
|
free(sp->hisauth.secret, M_DEVBUF);
|
|
|
|
sp->hisauth.secret = NULL;
|
|
|
|
}
|
2002-01-04 15:21:24 +03:00
|
|
|
|
2002-01-15 15:28:08 +03:00
|
|
|
if (cfg->hisname != NULL && cfg->hisname_length > 0) {
|
|
|
|
if (cfg->hisname_length >= MCLBYTES)
|
2002-01-19 01:39:12 +03:00
|
|
|
return (ENAMETOOLONG);
|
2002-01-04 15:21:24 +03:00
|
|
|
sp->hisauth.name = malloc(cfg->hisname_length, M_DEVBUF, M_WAITOK);
|
2002-01-19 01:39:12 +03:00
|
|
|
error = copyin(cfg->hisname, sp->hisauth.name, cfg->hisname_length);
|
|
|
|
if (error) {
|
2002-01-15 15:28:08 +03:00
|
|
|
free(sp->hisauth.name, M_DEVBUF);
|
|
|
|
sp->hisauth.name = NULL;
|
2002-01-19 01:39:12 +03:00
|
|
|
return error;
|
2002-01-15 15:28:08 +03:00
|
|
|
}
|
2002-07-29 02:16:47 +04:00
|
|
|
sp->hisauth.name_len = cfg->hisname_length - 1;
|
|
|
|
sp->hisauth.name[sp->hisauth.name_len] = 0;
|
2002-01-04 15:21:24 +03:00
|
|
|
}
|
2002-01-15 15:28:08 +03:00
|
|
|
if (cfg->hissecret != NULL && cfg->hissecret_length > 0) {
|
|
|
|
if (cfg->hissecret_length >= MCLBYTES)
|
2002-01-19 01:39:12 +03:00
|
|
|
return (ENAMETOOLONG);
|
2002-01-04 15:21:24 +03:00
|
|
|
sp->hisauth.secret = malloc(cfg->hissecret_length, M_DEVBUF, M_WAITOK);
|
2002-01-19 01:39:12 +03:00
|
|
|
error = copyin(cfg->hissecret, sp->hisauth.secret, cfg->hissecret_length);
|
|
|
|
if (error) {
|
2002-01-15 15:28:08 +03:00
|
|
|
free(sp->hisauth.secret, M_DEVBUF);
|
|
|
|
sp->hisauth.secret = NULL;
|
2002-01-19 01:39:12 +03:00
|
|
|
return error;
|
2002-01-15 15:28:08 +03:00
|
|
|
}
|
2002-07-29 02:16:47 +04:00
|
|
|
sp->hisauth.secret_len = cfg->hissecret_length - 1;
|
|
|
|
sp->hisauth.secret[sp->hisauth.secret_len] = 0;
|
2002-01-04 15:21:24 +03:00
|
|
|
}
|
2002-01-15 15:28:08 +03:00
|
|
|
if (cfg->myname != NULL && cfg->myname_length > 0) {
|
|
|
|
if (cfg->myname_length >= MCLBYTES)
|
2002-01-19 01:39:12 +03:00
|
|
|
return (ENAMETOOLONG);
|
2002-01-04 15:21:24 +03:00
|
|
|
sp->myauth.name = malloc(cfg->myname_length, M_DEVBUF, M_WAITOK);
|
2002-01-19 01:39:12 +03:00
|
|
|
error = copyin(cfg->myname, sp->myauth.name, cfg->myname_length);
|
|
|
|
if (error) {
|
2002-01-15 15:28:08 +03:00
|
|
|
free(sp->myauth.name, M_DEVBUF);
|
|
|
|
sp->myauth.name = NULL;
|
2002-01-19 01:39:12 +03:00
|
|
|
return error;
|
2002-01-15 15:28:08 +03:00
|
|
|
}
|
2002-07-29 02:16:47 +04:00
|
|
|
sp->myauth.name_len = cfg->myname_length - 1;
|
|
|
|
sp->myauth.name[sp->myauth.name_len] = 0;
|
2002-01-04 15:21:24 +03:00
|
|
|
}
|
2002-01-15 15:28:08 +03:00
|
|
|
if (cfg->mysecret != NULL && cfg->mysecret_length > 0) {
|
|
|
|
if (cfg->mysecret_length >= MCLBYTES)
|
2002-01-19 01:39:12 +03:00
|
|
|
return (ENAMETOOLONG);
|
2002-01-04 15:21:24 +03:00
|
|
|
sp->myauth.secret = malloc(cfg->mysecret_length, M_DEVBUF, M_WAITOK);
|
2002-01-19 01:39:12 +03:00
|
|
|
error = copyin(cfg->mysecret, sp->myauth.secret, cfg->mysecret_length);
|
|
|
|
if (error) {
|
2002-01-15 15:28:08 +03:00
|
|
|
free(sp->myauth.secret, M_DEVBUF);
|
|
|
|
sp->myauth.secret = NULL;
|
2002-01-19 01:39:12 +03:00
|
|
|
return error;
|
2002-01-15 15:28:08 +03:00
|
|
|
}
|
2002-07-29 02:16:47 +04:00
|
|
|
sp->myauth.secret_len = cfg->mysecret_length - 1;
|
|
|
|
sp->myauth.secret[sp->myauth.secret_len] = 0;
|
2002-01-04 15:21:24 +03:00
|
|
|
}
|
|
|
|
sp->myauth.flags = cfg->myauthflags;
|
|
|
|
if (cfg->myauth)
|
2002-01-19 01:39:12 +03:00
|
|
|
sp->myauth.proto = (cfg->myauth == SPPP_AUTHPROTO_PAP) ? PPP_PAP : PPP_CHAP;
|
2002-01-04 15:21:24 +03:00
|
|
|
sp->hisauth.flags = cfg->hisauthflags;
|
|
|
|
if (cfg->hisauth)
|
2002-01-19 01:39:12 +03:00
|
|
|
sp->hisauth.proto = (cfg->hisauth == SPPP_AUTHPROTO_PAP) ? PPP_PAP : PPP_CHAP;
|
2002-01-07 13:49:02 +03:00
|
|
|
sp->pp_auth_failures = 0;
|
2005-02-27 01:45:09 +03:00
|
|
|
if (sp->hisauth.proto != 0)
|
2002-07-29 02:16:47 +04:00
|
|
|
sp->lcp.opts |= (1 << LCP_OPT_AUTH_PROTO);
|
|
|
|
else
|
|
|
|
sp->lcp.opts &= ~(1 << LCP_OPT_AUTH_PROTO);
|
2002-01-04 15:21:24 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SPPPGETLCPCFG:
|
|
|
|
{
|
2005-05-30 01:22:52 +04:00
|
|
|
struct sppplcpcfg *lcpp = (struct sppplcpcfg *)data;
|
|
|
|
lcpp->lcp_timeout = sp->lcp.timeout;
|
2002-01-04 15:21:24 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SPPPSETLCPCFG:
|
|
|
|
{
|
2005-05-30 01:22:52 +04:00
|
|
|
struct sppplcpcfg *lcpp = (struct sppplcpcfg *)data;
|
|
|
|
sp->lcp.timeout = lcpp->lcp_timeout;
|
2002-01-04 15:21:24 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SPPPGETSTATUS:
|
|
|
|
{
|
2002-01-19 01:39:12 +03:00
|
|
|
struct spppstatus *status = (struct spppstatus *)data;
|
2002-01-04 15:21:24 +03:00
|
|
|
status->phase = sp->pp_phase;
|
|
|
|
}
|
|
|
|
break;
|
2003-12-27 02:39:23 +03:00
|
|
|
case SPPPGETSTATUSNCP:
|
|
|
|
{
|
|
|
|
struct spppstatusncp *status = (struct spppstatusncp *)data;
|
|
|
|
status->phase = sp->pp_phase;
|
|
|
|
status->ncpup = sppp_ncp_check(sp);
|
|
|
|
}
|
|
|
|
break;
|
2002-01-06 23:14:29 +03:00
|
|
|
case SPPPGETIDLETO:
|
|
|
|
{
|
2002-01-19 01:39:12 +03:00
|
|
|
struct spppidletimeout *to = (struct spppidletimeout *)data;
|
2002-01-06 23:14:29 +03:00
|
|
|
to->idle_seconds = sp->pp_idle_timeout;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SPPPSETIDLETO:
|
|
|
|
{
|
2002-01-19 01:39:12 +03:00
|
|
|
struct spppidletimeout *to = (struct spppidletimeout *)data;
|
2002-01-06 23:14:29 +03:00
|
|
|
sp->pp_idle_timeout = to->idle_seconds;
|
|
|
|
}
|
|
|
|
break;
|
2002-01-07 13:49:02 +03:00
|
|
|
case SPPPSETAUTHFAILURE:
|
|
|
|
{
|
2002-01-19 01:39:12 +03:00
|
|
|
struct spppauthfailuresettings *afsettings = (struct spppauthfailuresettings *)data;
|
2002-01-07 13:49:02 +03:00
|
|
|
sp->pp_max_auth_fail = afsettings->max_failures;
|
|
|
|
sp->pp_auth_failures = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SPPPGETAUTHFAILURES:
|
|
|
|
{
|
2002-01-19 01:39:12 +03:00
|
|
|
struct spppauthfailurestats *stats = (struct spppauthfailurestats *)data;
|
2002-01-07 13:49:02 +03:00
|
|
|
stats->auth_failures = sp->pp_auth_failures;
|
|
|
|
stats->max_failures = sp->pp_max_auth_fail;
|
|
|
|
}
|
|
|
|
break;
|
2002-03-02 19:23:42 +03:00
|
|
|
case SPPPSETDNSOPTS:
|
|
|
|
{
|
2002-09-25 11:24:06 +04:00
|
|
|
struct spppdnssettings *req = (struct spppdnssettings *)data;
|
2002-03-02 19:23:42 +03:00
|
|
|
sp->query_dns = req->query_dns & 3;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SPPPGETDNSOPTS:
|
|
|
|
{
|
2002-09-25 11:24:06 +04:00
|
|
|
struct spppdnssettings *req = (struct spppdnssettings *)data;
|
2002-03-02 19:23:42 +03:00
|
|
|
req->query_dns = sp->query_dns;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SPPPGETDNSADDRS:
|
|
|
|
{
|
2002-09-25 11:24:06 +04:00
|
|
|
struct spppdnsaddrs *addrs = (struct spppdnsaddrs *)data;
|
2002-03-02 19:23:42 +03:00
|
|
|
memcpy(&addrs->dns, &sp->dns_addrs, sizeof addrs->dns);
|
|
|
|
}
|
|
|
|
break;
|
2003-09-04 00:48:46 +04:00
|
|
|
case SPPPGETKEEPALIVE:
|
|
|
|
{
|
|
|
|
struct spppkeepalivesettings *settings =
|
|
|
|
(struct spppkeepalivesettings*)data;
|
|
|
|
settings->maxalive = sp->pp_maxalive;
|
|
|
|
settings->max_noreceive = sp->pp_max_noreceive;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SPPPSETKEEPALIVE:
|
|
|
|
{
|
|
|
|
struct spppkeepalivesettings *settings =
|
|
|
|
(struct spppkeepalivesettings*)data;
|
|
|
|
sp->pp_maxalive = settings->maxalive;
|
|
|
|
sp->pp_max_noreceive = settings->max_noreceive;
|
|
|
|
}
|
|
|
|
break;
|
1999-04-04 10:07:56 +04:00
|
|
|
default:
|
2002-01-19 01:39:12 +03:00
|
|
|
return (EINVAL);
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
|
2002-01-19 01:39:12 +03:00
|
|
|
return (0);
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_phase_network(struct sppp *sp)
|
|
|
|
{
|
|
|
|
STDDCL;
|
|
|
|
int i;
|
2001-12-05 00:32:15 +03:00
|
|
|
u_int32_t mask;
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2002-01-04 15:21:24 +03:00
|
|
|
sp->pp_phase = SPPP_PHASE_NETWORK;
|
1999-04-04 10:07:56 +04:00
|
|
|
|
2003-10-02 05:27:20 +04:00
|
|
|
if (debug)
|
1999-04-04 10:07:56 +04:00
|
|
|
{
|
2003-05-15 02:41:40 +04:00
|
|
|
log(LOG_INFO, "%s: phase %s\n", ifp->if_xname,
|
1999-04-04 10:07:56 +04:00
|
|
|
sppp_phase_name(sp->pp_phase));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Notify NCPs now. */
|
|
|
|
for (i = 0; i < IDX_COUNT; i++)
|
|
|
|
if ((cps[i])->flags & CP_NCP)
|
|
|
|
(cps[i])->Open(sp);
|
|
|
|
|
|
|
|
/* Send Up events to all NCPs. */
|
|
|
|
for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
|
2000-10-08 06:37:42 +04:00
|
|
|
if ((sp->lcp.protos & mask) && ((cps[i])->flags & CP_NCP))
|
1999-04-04 10:07:56 +04:00
|
|
|
(cps[i])->Up(sp);
|
|
|
|
|
|
|
|
/* if no NCP is starting, all this was in vain, close down */
|
|
|
|
sppp_lcp_check_and_close(sp);
|
|
|
|
}
|
2005-02-27 01:45:09 +03:00
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
|
|
|
|
static const char *
|
|
|
|
sppp_cp_type_name(u_char type)
|
|
|
|
{
|
|
|
|
static char buf[12];
|
|
|
|
switch (type) {
|
|
|
|
case CONF_REQ: return "conf-req";
|
|
|
|
case CONF_ACK: return "conf-ack";
|
|
|
|
case CONF_NAK: return "conf-nak";
|
|
|
|
case CONF_REJ: return "conf-rej";
|
|
|
|
case TERM_REQ: return "term-req";
|
|
|
|
case TERM_ACK: return "term-ack";
|
|
|
|
case CODE_REJ: return "code-rej";
|
|
|
|
case PROTO_REJ: return "proto-rej";
|
|
|
|
case ECHO_REQ: return "echo-req";
|
|
|
|
case ECHO_REPLY: return "echo-reply";
|
|
|
|
case DISC_REQ: return "discard-req";
|
|
|
|
}
|
2004-04-21 21:45:38 +04:00
|
|
|
snprintf(buf, sizeof(buf), "0x%x", type);
|
1999-04-04 10:07:56 +04:00
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
sppp_auth_type_name(u_short proto, u_char type)
|
|
|
|
{
|
|
|
|
static char buf[12];
|
|
|
|
switch (proto) {
|
|
|
|
case PPP_CHAP:
|
|
|
|
switch (type) {
|
|
|
|
case CHAP_CHALLENGE: return "challenge";
|
|
|
|
case CHAP_RESPONSE: return "response";
|
|
|
|
case CHAP_SUCCESS: return "success";
|
|
|
|
case CHAP_FAILURE: return "failure";
|
|
|
|
}
|
|
|
|
case PPP_PAP:
|
|
|
|
switch (type) {
|
|
|
|
case PAP_REQ: return "req";
|
|
|
|
case PAP_ACK: return "ack";
|
|
|
|
case PAP_NAK: return "nak";
|
|
|
|
}
|
|
|
|
}
|
2004-04-21 21:45:38 +04:00
|
|
|
snprintf(buf, sizeof(buf), "0x%x", type);
|
1999-04-04 10:07:56 +04:00
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
sppp_lcp_opt_name(u_char opt)
|
|
|
|
{
|
|
|
|
static char buf[12];
|
|
|
|
switch (opt) {
|
|
|
|
case LCP_OPT_MRU: return "mru";
|
|
|
|
case LCP_OPT_ASYNC_MAP: return "async-map";
|
|
|
|
case LCP_OPT_AUTH_PROTO: return "auth-proto";
|
|
|
|
case LCP_OPT_QUAL_PROTO: return "qual-proto";
|
|
|
|
case LCP_OPT_MAGIC: return "magic";
|
|
|
|
case LCP_OPT_PROTO_COMP: return "proto-comp";
|
|
|
|
case LCP_OPT_ADDR_COMP: return "addr-comp";
|
|
|
|
}
|
2004-04-21 21:45:38 +04:00
|
|
|
snprintf(buf, sizeof(buf), "0x%x", opt);
|
1999-04-04 10:07:56 +04:00
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
sppp_ipcp_opt_name(u_char opt)
|
|
|
|
{
|
|
|
|
static char buf[12];
|
|
|
|
switch (opt) {
|
|
|
|
case IPCP_OPT_ADDRESSES: return "addresses";
|
|
|
|
case IPCP_OPT_COMPRESSION: return "compression";
|
|
|
|
case IPCP_OPT_ADDRESS: return "address";
|
|
|
|
}
|
2004-04-21 21:45:38 +04:00
|
|
|
snprintf(buf, sizeof(buf), "0x%x", opt);
|
1999-04-04 10:07:56 +04:00
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2000-05-02 16:43:16 +04:00
|
|
|
#ifdef INET6
|
|
|
|
static const char *
|
|
|
|
sppp_ipv6cp_opt_name(u_char opt)
|
|
|
|
{
|
|
|
|
static char buf[12];
|
|
|
|
switch (opt) {
|
|
|
|
case IPV6CP_OPT_IFID: return "ifid";
|
|
|
|
case IPV6CP_OPT_COMPRESSION: return "compression";
|
|
|
|
}
|
2004-04-21 21:45:38 +04:00
|
|
|
snprintf(buf, sizeof(buf), "0x%x", opt);
|
2000-05-02 16:43:16 +04:00
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1999-04-04 10:07:56 +04:00
|
|
|
static const char *
|
|
|
|
sppp_state_name(int state)
|
|
|
|
{
|
|
|
|
switch (state) {
|
|
|
|
case STATE_INITIAL: return "initial";
|
|
|
|
case STATE_STARTING: return "starting";
|
|
|
|
case STATE_CLOSED: return "closed";
|
|
|
|
case STATE_STOPPED: return "stopped";
|
|
|
|
case STATE_CLOSING: return "closing";
|
|
|
|
case STATE_STOPPING: return "stopping";
|
|
|
|
case STATE_REQ_SENT: return "req-sent";
|
|
|
|
case STATE_ACK_RCVD: return "ack-rcvd";
|
|
|
|
case STATE_ACK_SENT: return "ack-sent";
|
|
|
|
case STATE_OPENED: return "opened";
|
|
|
|
}
|
|
|
|
return "illegal";
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *
|
2002-01-04 15:21:24 +03:00
|
|
|
sppp_phase_name(int phase)
|
1999-04-04 10:07:56 +04:00
|
|
|
{
|
|
|
|
switch (phase) {
|
2002-01-04 15:21:24 +03:00
|
|
|
case SPPP_PHASE_DEAD: return "dead";
|
|
|
|
case SPPP_PHASE_ESTABLISH: return "establish";
|
|
|
|
case SPPP_PHASE_TERMINATE: return "terminate";
|
|
|
|
case SPPP_PHASE_AUTHENTICATE: return "authenticate";
|
|
|
|
case SPPP_PHASE_NETWORK: return "network";
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
|
|
|
return "illegal";
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
sppp_proto_name(u_short proto)
|
|
|
|
{
|
|
|
|
static char buf[12];
|
|
|
|
switch (proto) {
|
|
|
|
case PPP_LCP: return "lcp";
|
|
|
|
case PPP_IPCP: return "ipcp";
|
|
|
|
case PPP_PAP: return "pap";
|
|
|
|
case PPP_CHAP: return "chap";
|
2000-05-02 16:43:16 +04:00
|
|
|
case PPP_IPV6CP: return "ipv6cp";
|
1999-04-04 10:07:56 +04:00
|
|
|
}
|
2004-04-21 21:45:38 +04:00
|
|
|
snprintf(buf, sizeof(buf), "0x%x", (unsigned)proto);
|
1999-04-04 10:07:56 +04:00
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_print_bytes(const u_char *p, u_short len)
|
|
|
|
{
|
|
|
|
addlog(" %02x", *p++);
|
|
|
|
while (--len > 0)
|
|
|
|
addlog("-%02x", *p++);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sppp_print_string(const char *p, u_short len)
|
|
|
|
{
|
|
|
|
u_char c;
|
|
|
|
|
|
|
|
while (len-- > 0) {
|
|
|
|
c = *p++;
|
|
|
|
/*
|
|
|
|
* Print only ASCII chars directly. RFC 1994 recommends
|
|
|
|
* using only them, but we don't rely on it. */
|
|
|
|
if (c < ' ' || c > '~')
|
|
|
|
addlog("\\x%x", c);
|
|
|
|
else
|
|
|
|
addlog("%c", c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *
|
2001-12-05 00:32:15 +03:00
|
|
|
sppp_dotted_quad(u_int32_t addr)
|
1999-04-04 10:07:56 +04:00
|
|
|
{
|
|
|
|
static char s[16];
|
2004-04-21 21:45:38 +04:00
|
|
|
snprintf(s, sizeof(s), "%d.%d.%d.%d",
|
1999-04-04 10:07:56 +04:00
|
|
|
(int)((addr >> 24) & 0xff),
|
|
|
|
(int)((addr >> 16) & 0xff),
|
|
|
|
(int)((addr >> 8) & 0xff),
|
|
|
|
(int)(addr & 0xff));
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* a dummy, used to drop uninteresting events */
|
|
|
|
static void
|
2006-11-16 04:32:37 +03:00
|
|
|
sppp_null(struct sppp *unused)
|
1999-04-04 10:07:56 +04:00
|
|
|
{
|
|
|
|
/* do just nothing */
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* This file is large. Tell emacs to highlight it nevertheless.
|
|
|
|
*
|
|
|
|
* Local Variables:
|
|
|
|
* hilit-auto-highlight-maxout: 120000
|
|
|
|
* End:
|
|
|
|
*/
|