FreeBSD Bugzilla – Attachment 5963 Details for
Bug 13841
ISDN i4b does not hang up
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
file.shar
file.shar (text/plain), 367.97 KB, created by
ob
on 1999-09-20 00:30:02 UTC
(
hide
)
Description:
file.shar
Filename:
MIME Type:
Creator:
ob
Created:
1999-09-20 00:30:02 UTC
Size:
367.97 KB
patch
obsolete
># This is a shell archive. Save it in a file, remove anything before ># this line, and then unpack it by entering "sh file". Note, it may ># create directories; files and directories will be owned by you and ># have default permissions. ># ># This archive contains: ># ># . ># ./usr ># ./usr/include ># ./usr/include/net ># ./usr/include/net/if_sppp.h ># ./usr/include/net/if_sppp.h.orig ># ./usr/include/net/if_sppp.h.patch ># ./usr/src ># ./usr/src/sys ># ./usr/src/sys/net ># ./usr/src/sys/net/if_sppp.h ># ./usr/src/sys/net/if_sppp.h.orig ># ./usr/src/sys/net/if_sppp.h.patch ># ./usr/src/sys/net/if_spppsubr.c ># ./usr/src/sys/net/if_spppsubr.c.patch ># ./usr/src/sys/net/if_spppsubr.c.orig ># ./usr/src/sys/i4b ># ./usr/src/sys/i4b/driver ># ./usr/src/sys/i4b/driver/i4b_isppp.c ># ./usr/src/sys/i4b/driver/i4b_isppp.c.patch ># ./usr/src/sys/i4b/driver/i4b_isppp.c.orig ># ./usr/src/sys/i4b/layer4 ># ./usr/src/sys/i4b/layer4/i4b_l4.c ># ./usr/src/sys/i4b/layer4/i4b_l4.c.patch ># ./usr/src/sys/i4b/layer4/i4b_l4.c.orig ># ./usr/src/sbin ># ./usr/src/sbin/spppcontrol ># ./usr/src/sbin/spppcontrol/Makefile ># ./usr/src/sbin/spppcontrol/spppcontrol.1 ># ./usr/src/sbin/spppcontrol/spppcontrol.c ># ./usr/src/sbin/spppcontrol/spppcontrol.c.patch ># ./usr/src/sbin/spppcontrol/spppcontrol.c.orig ># >echo c - . >mkdir -p . > /dev/null 2>&1 >echo c - ./usr >mkdir -p ./usr > /dev/null 2>&1 >echo c - ./usr/include >mkdir -p ./usr/include > /dev/null 2>&1 >echo c - ./usr/include/net >mkdir -p ./usr/include/net > /dev/null 2>&1 >echo x - ./usr/include/net/if_sppp.h >sed 's/^X//' >./usr/include/net/if_sppp.h << 'END-of-./usr/include/net/if_sppp.h' >X/* >X * Defines for synchronous PPP/Cisco link level subroutines. >X * >X * Copyright (C) 1994 Cronyx Ltd. >X * Author: Serge Vakulenko, <vak@cronyx.ru> >X * >X * Heavily revamped to conform to RFC 1661. >X * Copyright (C) 1997, Joerg Wunsch. >X * >X * This software is distributed with NO WARRANTIES, not even the implied >X * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. >X * >X * Authors grant any other persons or organizations permission to use >X * or modify this software as long as this message is kept with the software, >X * all derivative works or modified versions. >X * >X * From: Version 2.0, Fri Oct 6 20:39:21 MSK 1995 >X * >X * $Id: if_sppp.h,v 1.13 1998/12/27 21:30:44 phk Exp $ >X */ >X >X#ifndef _NET_IF_SPPP_H_ >X#define _NET_IF_SPPP_H_ 1 >X >X#define IDX_LCP 0 /* idx into state table */ >X >Xstruct slcp { >X u_long opts; /* LCP options to send (bitfield) */ >X u_long magic; /* local magic number */ >X u_long mru; /* our max receive unit */ >X u_long their_mru; /* their max receive unit */ >X u_long protos; /* bitmask of protos that are started */ >X u_char echoid; /* id of last keepalive echo request */ >X /* restart max values, see RFC 1661 */ >X int timeout; >X int max_terminate; >X int max_configure; >X int max_failure; >X}; >X >X#define IDX_IPCP 1 /* idx into state table */ >X >Xstruct sipcp { >X u_long opts; /* IPCP options to send (bitfield) */ >X u_int flags; >X#define IPCP_HISADDR_SEEN 1 /* have seen his address already */ >X#define IPCP_MYADDR_DYN 2 /* my address is dynamically assigned */ >X#define IPCP_MYADDR_SEEN 4 /* have seen his address already */ >X}; >X >X#define AUTHNAMELEN 32 >X#define AUTHKEYLEN 16 >X >Xstruct sauth { >X u_short proto; /* authentication protocol to use */ >X u_short flags; >X#define AUTHFLAG_NOCALLOUT 1 /* do not require authentication on */ >X /* callouts */ >X#define AUTHFLAG_NORECHALLENGE 2 /* do not re-challenge CHAP */ >X u_char name[AUTHNAMELEN]; /* system identification name */ >X u_char secret[AUTHKEYLEN]; /* secret password */ >X u_char challenge[AUTHKEYLEN]; /* random challenge */ >X}; >X >X#define IDX_PAP 2 >X#define IDX_CHAP 3 >X >X#define IDX_COUNT (IDX_CHAP + 1) /* bump this when adding cp's! */ >X >X/* >X * Don't change the order of this. Ordering the phases this way allows >X * for a comparision of ``pp_phase >= PHASE_AUTHENTICATE'' in order to >X * know whether LCP is up. >X */ >Xenum ppp_phase { >X PHASE_DEAD, PHASE_ESTABLISH, PHASE_TERMINATE, >X PHASE_AUTHENTICATE, PHASE_NETWORK >X}; >X >Xstruct sppp { >X /* NB: pp_if _must_ be first */ >X struct ifnet pp_if; /* network interface data */ >X struct ifqueue pp_fastq; /* fast output queue */ >X struct ifqueue pp_cpq; /* PPP control protocol queue */ >X struct sppp *pp_next; /* next interface in keepalive list */ >X u_int pp_flags; /* use Cisco protocol instead of PPP */ >X u_short pp_alivecnt; /* keepalive packets counter */ >X u_short pp_loopcnt; /* loopback detection counter */ >X u_long pp_seq; /* local sequence number */ >X u_long pp_rseq; /* remote sequence number */ >X time_t pp_last_sent; >X time_t pp_last_recv; >X enum ppp_phase pp_phase; /* phase we're currently in */ >X int state[IDX_COUNT]; /* state machine */ >X u_char confid[IDX_COUNT]; /* id of last configuration request */ >X int rst_counter[IDX_COUNT]; /* restart counter */ >X int fail_counter[IDX_COUNT]; /* negotiation failure counter */ >X struct callout_handle ch[IDX_COUNT]; /* per-proto and if callouts */ >X struct callout_handle pap_my_to_ch; /* PAP needs one more... */ >X struct slcp lcp; /* LCP params */ >X struct sipcp ipcp; /* IPCP params */ >X struct sauth myauth; /* auth params, i'm peer */ >X struct sauth hisauth; /* auth params, i'm authenticator */ >X /* >X * These functions are filled in by sppp_attach(), and are >X * expected to be used by the lower layer (hardware) drivers >X * in order to communicate the (un)availability of the >X * communication link. Lower layer drivers that are always >X * ready to communicate (like hardware HDLC) can shortcut >X * pp_up from pp_tls, and pp_down from pp_tlf. >X */ >X void (*pp_up)(struct sppp *sp); >X void (*pp_down)(struct sppp *sp); >X /* >X * These functions need to be filled in by the lower layer >X * (hardware) drivers if they request notification from the >X * PPP layer whether the link is actually required. They >X * correspond to the tls and tlf actions. >X */ >X void (*pp_tls)(struct sppp *sp); >X void (*pp_tlf)(struct sppp *sp); >X /* >X * These (optional) functions may be filled by the hardware >X * driver if any notification of established connections >X * (currently: IPCP up) is desired (pp_con) or any internal >X * state change of the interface state machine should be >X * signaled for monitoring purposes (pp_chg). >X */ >X void (*pp_con)(struct sppp *sp); >X void (*pp_chg)(struct sppp *sp, int new_state); >X /* These two fields are for use by the lower layer */ >X void *pp_lowerp; >X int pp_loweri; >X}; >X >X#define PP_KEEPALIVE 0x01 /* use keepalive protocol */ >X#define PP_CISCO 0x02 /* use Cisco protocol instead of PPP */ >X /* 0x04 was PP_TIMO */ >X#define PP_CALLIN 0x08 /* we are being called */ >X#define PP_NEEDAUTH 0x10 /* remote requested authentication */ >X >X >X#define PP_MTU 1500 /* default/minimal MRU */ >X#define PP_MAX_MRU 2048 /* maximal MRU we want to negotiate */ >X >X/* >X * Definitions to pass struct sppp data down into the kernel using the >X * SIOC[SG]IFGENERIC ioctl interface. >X * >X * In order to use this, create a struct spppreq, fill in the cmd >X * field with SPPPIOGDEFS, and put the address of this structure into >X * the ifr_data portion of a struct ifreq. Pass this struct to a >X * SIOCGIFGENERIC ioctl. Then replace the cmd field by SPPPIOCDEFS, >X * modify the defs field as desired, and pass the struct ifreq now >X * to a SIOCSIFGENERIC ioctl. >X */ >X >X#define SPPPIOGDEFS ((caddr_t)(('S' << 24) + (1 << 16) + sizeof(struct sppp))) >X#define SPPPIOSDEFS ((caddr_t)(('S' << 24) + (2 << 16) + sizeof(struct sppp))) >X >Xstruct spppreq { >X int cmd; >X struct sppp defs; >X}; >X >X#ifdef KERNEL >Xvoid sppp_attach (struct ifnet *ifp); >Xvoid sppp_detach (struct ifnet *ifp); >Xvoid sppp_input (struct ifnet *ifp, struct mbuf *m); >Xint sppp_ioctl (struct ifnet *ifp, u_long cmd, void *data); >Xstruct mbuf *sppp_dequeue (struct ifnet *ifp); >Xstruct mbuf *sppp_pick(struct ifnet *ifp); >Xint sppp_isempty (struct ifnet *ifp); >Xvoid sppp_flush (struct ifnet *ifp); >X#endif >X >X#endif /* _NET_IF_SPPP_H_ */ >END-of-./usr/include/net/if_sppp.h >echo x - ./usr/include/net/if_sppp.h.orig >sed 's/^X//' >./usr/include/net/if_sppp.h.orig << 'END-of-./usr/include/net/if_sppp.h.orig' >X/* >X * Defines for synchronous PPP/Cisco link level subroutines. >X * >X * Copyright (C) 1994 Cronyx Ltd. >X * Author: Serge Vakulenko, <vak@cronyx.ru> >X * >X * Heavily revamped to conform to RFC 1661. >X * Copyright (C) 1997, Joerg Wunsch. >X * >X * This software is distributed with NO WARRANTIES, not even the implied >X * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. >X * >X * Authors grant any other persons or organizations permission to use >X * or modify this software as long as this message is kept with the software, >X * all derivative works or modified versions. >X * >X * From: Version 2.0, Fri Oct 6 20:39:21 MSK 1995 >X * >X * $Id: if_sppp.h,v 1.13 1998/12/27 21:30:44 phk Exp $ >X */ >X >X#ifndef _NET_IF_SPPP_H_ >X#define _NET_IF_SPPP_H_ 1 >X >X#define IDX_LCP 0 /* idx into state table */ >X >Xstruct slcp { >X u_long opts; /* LCP options to send (bitfield) */ >X u_long magic; /* local magic number */ >X u_long mru; /* our max receive unit */ >X u_long their_mru; /* their max receive unit */ >X u_long protos; /* bitmask of protos that are started */ >X u_char echoid; /* id of last keepalive echo request */ >X /* restart max values, see RFC 1661 */ >X int timeout; >X int max_terminate; >X int max_configure; >X int max_failure; >X}; >X >X#define IDX_IPCP 1 /* idx into state table */ >X >Xstruct sipcp { >X u_long opts; /* IPCP options to send (bitfield) */ >X u_int flags; >X#define IPCP_HISADDR_SEEN 1 /* have seen his address already */ >X#define IPCP_MYADDR_DYN 2 /* my address is dynamically assigned */ >X#define IPCP_MYADDR_SEEN 4 /* have seen his address already */ >X}; >X >X#define AUTHNAMELEN 32 >X#define AUTHKEYLEN 16 >X >Xstruct sauth { >X u_short proto; /* authentication protocol to use */ >X u_short flags; >X#define AUTHFLAG_NOCALLOUT 1 /* do not require authentication on */ >X /* callouts */ >X#define AUTHFLAG_NORECHALLENGE 2 /* do not re-challenge CHAP */ >X u_char name[AUTHNAMELEN]; /* system identification name */ >X u_char secret[AUTHKEYLEN]; /* secret password */ >X u_char challenge[AUTHKEYLEN]; /* random challenge */ >X}; >X >X#define IDX_PAP 2 >X#define IDX_CHAP 3 >X >X#define IDX_COUNT (IDX_CHAP + 1) /* bump this when adding cp's! */ >X >X/* >X * Don't change the order of this. Ordering the phases this way allows >X * for a comparision of ``pp_phase >= PHASE_AUTHENTICATE'' in order to >X * know whether LCP is up. >X */ >Xenum ppp_phase { >X PHASE_DEAD, PHASE_ESTABLISH, PHASE_TERMINATE, >X PHASE_AUTHENTICATE, PHASE_NETWORK >X}; >X >Xstruct sppp { >X /* NB: pp_if _must_ be first */ >X struct ifnet pp_if; /* network interface data */ >X struct ifqueue pp_fastq; /* fast output queue */ >X struct ifqueue pp_cpq; /* PPP control protocol queue */ >X struct sppp *pp_next; /* next interface in keepalive list */ >X u_int pp_flags; /* use Cisco protocol instead of PPP */ >X u_short pp_alivecnt; /* keepalive packets counter */ >X u_short pp_loopcnt; /* loopback detection counter */ >X u_long pp_seq; /* local sequence number */ >X u_long pp_rseq; /* remote sequence number */ >X enum ppp_phase pp_phase; /* phase we're currently in */ >X int state[IDX_COUNT]; /* state machine */ >X u_char confid[IDX_COUNT]; /* id of last configuration request */ >X int rst_counter[IDX_COUNT]; /* restart counter */ >X int fail_counter[IDX_COUNT]; /* negotiation failure counter */ >X struct callout_handle ch[IDX_COUNT]; /* per-proto and if callouts */ >X struct callout_handle pap_my_to_ch; /* PAP needs one more... */ >X struct slcp lcp; /* LCP params */ >X struct sipcp ipcp; /* IPCP params */ >X struct sauth myauth; /* auth params, i'm peer */ >X struct sauth hisauth; /* auth params, i'm authenticator */ >X /* >X * These functions are filled in by sppp_attach(), and are >X * expected to be used by the lower layer (hardware) drivers >X * in order to communicate the (un)availability of the >X * communication link. Lower layer drivers that are always >X * ready to communicate (like hardware HDLC) can shortcut >X * pp_up from pp_tls, and pp_down from pp_tlf. >X */ >X void (*pp_up)(struct sppp *sp); >X void (*pp_down)(struct sppp *sp); >X /* >X * These functions need to be filled in by the lower layer >X * (hardware) drivers if they request notification from the >X * PPP layer whether the link is actually required. They >X * correspond to the tls and tlf actions. >X */ >X void (*pp_tls)(struct sppp *sp); >X void (*pp_tlf)(struct sppp *sp); >X /* >X * These (optional) functions may be filled by the hardware >X * driver if any notification of established connections >X * (currently: IPCP up) is desired (pp_con) or any internal >X * state change of the interface state machine should be >X * signaled for monitoring purposes (pp_chg). >X */ >X void (*pp_con)(struct sppp *sp); >X void (*pp_chg)(struct sppp *sp, int new_state); >X /* These two fields are for use by the lower layer */ >X void *pp_lowerp; >X int pp_loweri; >X}; >X >X#define PP_KEEPALIVE 0x01 /* use keepalive protocol */ >X#define PP_CISCO 0x02 /* use Cisco protocol instead of PPP */ >X /* 0x04 was PP_TIMO */ >X#define PP_CALLIN 0x08 /* we are being called */ >X#define PP_NEEDAUTH 0x10 /* remote requested authentication */ >X >X >X#define PP_MTU 1500 /* default/minimal MRU */ >X#define PP_MAX_MRU 2048 /* maximal MRU we want to negotiate */ >X >X/* >X * Definitions to pass struct sppp data down into the kernel using the >X * SIOC[SG]IFGENERIC ioctl interface. >X * >X * In order to use this, create a struct spppreq, fill in the cmd >X * field with SPPPIOGDEFS, and put the address of this structure into >X * the ifr_data portion of a struct ifreq. Pass this struct to a >X * SIOCGIFGENERIC ioctl. Then replace the cmd field by SPPPIOCDEFS, >X * modify the defs field as desired, and pass the struct ifreq now >X * to a SIOCSIFGENERIC ioctl. >X */ >X >X#define SPPPIOGDEFS ((caddr_t)(('S' << 24) + (1 << 16) + sizeof(struct sppp))) >X#define SPPPIOSDEFS ((caddr_t)(('S' << 24) + (2 << 16) + sizeof(struct sppp))) >X >Xstruct spppreq { >X int cmd; >X struct sppp defs; >X}; >X >X#ifdef KERNEL >Xvoid sppp_attach (struct ifnet *ifp); >Xvoid sppp_detach (struct ifnet *ifp); >Xvoid sppp_input (struct ifnet *ifp, struct mbuf *m); >Xint sppp_ioctl (struct ifnet *ifp, u_long cmd, void *data); >Xstruct mbuf *sppp_dequeue (struct ifnet *ifp); >Xstruct mbuf *sppp_pick(struct ifnet *ifp); >Xint sppp_isempty (struct ifnet *ifp); >Xvoid sppp_flush (struct ifnet *ifp); >X#endif >X >X#endif /* _NET_IF_SPPP_H_ */ >END-of-./usr/include/net/if_sppp.h.orig >echo x - ./usr/include/net/if_sppp.h.patch >sed 's/^X//' >./usr/include/net/if_sppp.h.patch << 'END-of-./usr/include/net/if_sppp.h.patch' >X*** if_sppp.h Tue Dec 1 21:20:19 1998 >X--- if_sppp.h.new Tue Mar 16 15:54:06 1999 >X*************** >X*** 90,95 **** >X--- 90,97 ---- >X u_short pp_loopcnt; /* loopback detection counter */ >X u_long pp_seq; /* local sequence number */ >X u_long pp_rseq; /* remote sequence number */ >X+ time_t pp_last_sent; >X+ time_t pp_last_recv; >X enum ppp_phase pp_phase; /* phase we're currently in */ >X int state[IDX_COUNT]; /* state machine */ >X u_char confid[IDX_COUNT]; /* id of last configuration request */ >END-of-./usr/include/net/if_sppp.h.patch >echo c - ./usr/src >mkdir -p ./usr/src > /dev/null 2>&1 >echo c - ./usr/src/sys >mkdir -p ./usr/src/sys > /dev/null 2>&1 >echo c - ./usr/src/sys/net >mkdir -p ./usr/src/sys/net > /dev/null 2>&1 >echo x - ./usr/src/sys/net/if_sppp.h >sed 's/^X//' >./usr/src/sys/net/if_sppp.h << 'END-of-./usr/src/sys/net/if_sppp.h' >X/* >X * Defines for synchronous PPP/Cisco link level subroutines. >X * >X * Copyright (C) 1994 Cronyx Ltd. >X * Author: Serge Vakulenko, <vak@cronyx.ru> >X * >X * Heavily revamped to conform to RFC 1661. >X * Copyright (C) 1997, Joerg Wunsch. >X * >X * This software is distributed with NO WARRANTIES, not even the implied >X * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. >X * >X * Authors grant any other persons or organizations permission to use >X * or modify this software as long as this message is kept with the software, >X * all derivative works or modified versions. >X * >X * From: Version 2.0, Fri Oct 6 20:39:21 MSK 1995 >X * >X * $Id: if_sppp.h,v 1.13 1998/12/27 21:30:44 phk Exp $ >X */ >X >X#ifndef _NET_IF_SPPP_H_ >X#define _NET_IF_SPPP_H_ 1 >X >X#define IDX_LCP 0 /* idx into state table */ >X >Xstruct slcp { >X u_long opts; /* LCP options to send (bitfield) */ >X u_long magic; /* local magic number */ >X u_long mru; /* our max receive unit */ >X u_long their_mru; /* their max receive unit */ >X u_long protos; /* bitmask of protos that are started */ >X u_char echoid; /* id of last keepalive echo request */ >X /* restart max values, see RFC 1661 */ >X int timeout; >X int max_terminate; >X int max_configure; >X int max_failure; >X}; >X >X#define IDX_IPCP 1 /* idx into state table */ >X >Xstruct sipcp { >X u_long opts; /* IPCP options to send (bitfield) */ >X u_int flags; >X#define IPCP_HISADDR_SEEN 1 /* have seen his address already */ >X#define IPCP_MYADDR_DYN 2 /* my address is dynamically assigned */ >X#define IPCP_MYADDR_SEEN 4 /* have seen his address already */ >X}; >X >X#define AUTHNAMELEN 32 >X#define AUTHKEYLEN 16 >X >Xstruct sauth { >X u_short proto; /* authentication protocol to use */ >X u_short flags; >X#define AUTHFLAG_NOCALLOUT 1 /* do not require authentication on */ >X /* callouts */ >X#define AUTHFLAG_NORECHALLENGE 2 /* do not re-challenge CHAP */ >X u_char name[AUTHNAMELEN]; /* system identification name */ >X u_char secret[AUTHKEYLEN]; /* secret password */ >X u_char challenge[AUTHKEYLEN]; /* random challenge */ >X}; >X >X#define IDX_PAP 2 >X#define IDX_CHAP 3 >X >X#define IDX_COUNT (IDX_CHAP + 1) /* bump this when adding cp's! */ >X >X/* >X * Don't change the order of this. Ordering the phases this way allows >X * for a comparision of ``pp_phase >= PHASE_AUTHENTICATE'' in order to >X * know whether LCP is up. >X */ >Xenum ppp_phase { >X PHASE_DEAD, PHASE_ESTABLISH, PHASE_TERMINATE, >X PHASE_AUTHENTICATE, PHASE_NETWORK >X}; >X >Xstruct sppp { >X /* NB: pp_if _must_ be first */ >X struct ifnet pp_if; /* network interface data */ >X struct ifqueue pp_fastq; /* fast output queue */ >X struct ifqueue pp_cpq; /* PPP control protocol queue */ >X struct sppp *pp_next; /* next interface in keepalive list */ >X u_int pp_flags; /* use Cisco protocol instead of PPP */ >X u_short pp_alivecnt; /* keepalive packets counter */ >X u_short pp_loopcnt; /* loopback detection counter */ >X u_long pp_seq; /* local sequence number */ >X u_long pp_rseq; /* remote sequence number */ >X time_t pp_last_sent; >X time_t pp_last_recv; >X enum ppp_phase pp_phase; /* phase we're currently in */ >X int state[IDX_COUNT]; /* state machine */ >X u_char confid[IDX_COUNT]; /* id of last configuration request */ >X int rst_counter[IDX_COUNT]; /* restart counter */ >X int fail_counter[IDX_COUNT]; /* negotiation failure counter */ >X struct callout_handle ch[IDX_COUNT]; /* per-proto and if callouts */ >X struct callout_handle pap_my_to_ch; /* PAP needs one more... */ >X struct slcp lcp; /* LCP params */ >X struct sipcp ipcp; /* IPCP params */ >X struct sauth myauth; /* auth params, i'm peer */ >X struct sauth hisauth; /* auth params, i'm authenticator */ >X /* >X * These functions are filled in by sppp_attach(), and are >X * expected to be used by the lower layer (hardware) drivers >X * in order to communicate the (un)availability of the >X * communication link. Lower layer drivers that are always >X * ready to communicate (like hardware HDLC) can shortcut >X * pp_up from pp_tls, and pp_down from pp_tlf. >X */ >X void (*pp_up)(struct sppp *sp); >X void (*pp_down)(struct sppp *sp); >X /* >X * These functions need to be filled in by the lower layer >X * (hardware) drivers if they request notification from the >X * PPP layer whether the link is actually required. They >X * correspond to the tls and tlf actions. >X */ >X void (*pp_tls)(struct sppp *sp); >X void (*pp_tlf)(struct sppp *sp); >X /* >X * These (optional) functions may be filled by the hardware >X * driver if any notification of established connections >X * (currently: IPCP up) is desired (pp_con) or any internal >X * state change of the interface state machine should be >X * signaled for monitoring purposes (pp_chg). >X */ >X void (*pp_con)(struct sppp *sp); >X void (*pp_chg)(struct sppp *sp, int new_state); >X /* These two fields are for use by the lower layer */ >X void *pp_lowerp; >X int pp_loweri; >X}; >X >X#define PP_KEEPALIVE 0x01 /* use keepalive protocol */ >X#define PP_CISCO 0x02 /* use Cisco protocol instead of PPP */ >X /* 0x04 was PP_TIMO */ >X#define PP_CALLIN 0x08 /* we are being called */ >X#define PP_NEEDAUTH 0x10 /* remote requested authentication */ >X >X >X#define PP_MTU 1500 /* default/minimal MRU */ >X#define PP_MAX_MRU 2048 /* maximal MRU we want to negotiate */ >X >X/* >X * Definitions to pass struct sppp data down into the kernel using the >X * SIOC[SG]IFGENERIC ioctl interface. >X * >X * In order to use this, create a struct spppreq, fill in the cmd >X * field with SPPPIOGDEFS, and put the address of this structure into >X * the ifr_data portion of a struct ifreq. Pass this struct to a >X * SIOCGIFGENERIC ioctl. Then replace the cmd field by SPPPIOCDEFS, >X * modify the defs field as desired, and pass the struct ifreq now >X * to a SIOCSIFGENERIC ioctl. >X */ >X >X#define SPPPIOGDEFS ((caddr_t)(('S' << 24) + (1 << 16) + sizeof(struct sppp))) >X#define SPPPIOSDEFS ((caddr_t)(('S' << 24) + (2 << 16) + sizeof(struct sppp))) >X >Xstruct spppreq { >X int cmd; >X struct sppp defs; >X}; >X >X#ifdef KERNEL >Xvoid sppp_attach (struct ifnet *ifp); >Xvoid sppp_detach (struct ifnet *ifp); >Xvoid sppp_input (struct ifnet *ifp, struct mbuf *m); >Xint sppp_ioctl (struct ifnet *ifp, u_long cmd, void *data); >Xstruct mbuf *sppp_dequeue (struct ifnet *ifp); >Xstruct mbuf *sppp_pick(struct ifnet *ifp); >Xint sppp_isempty (struct ifnet *ifp); >Xvoid sppp_flush (struct ifnet *ifp); >X#endif >X >X#endif /* _NET_IF_SPPP_H_ */ >END-of-./usr/src/sys/net/if_sppp.h >echo x - ./usr/src/sys/net/if_sppp.h.orig >sed 's/^X//' >./usr/src/sys/net/if_sppp.h.orig << 'END-of-./usr/src/sys/net/if_sppp.h.orig' >X/* >X * Defines for synchronous PPP/Cisco link level subroutines. >X * >X * Copyright (C) 1994 Cronyx Ltd. >X * Author: Serge Vakulenko, <vak@cronyx.ru> >X * >X * Heavily revamped to conform to RFC 1661. >X * Copyright (C) 1997, Joerg Wunsch. >X * >X * This software is distributed with NO WARRANTIES, not even the implied >X * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. >X * >X * Authors grant any other persons or organizations permission to use >X * or modify this software as long as this message is kept with the software, >X * all derivative works or modified versions. >X * >X * From: Version 2.0, Fri Oct 6 20:39:21 MSK 1995 >X * >X * $Id: if_sppp.h,v 1.13 1998/12/27 21:30:44 phk Exp $ >X */ >X >X#ifndef _NET_IF_SPPP_H_ >X#define _NET_IF_SPPP_H_ 1 >X >X#define IDX_LCP 0 /* idx into state table */ >X >Xstruct slcp { >X u_long opts; /* LCP options to send (bitfield) */ >X u_long magic; /* local magic number */ >X u_long mru; /* our max receive unit */ >X u_long their_mru; /* their max receive unit */ >X u_long protos; /* bitmask of protos that are started */ >X u_char echoid; /* id of last keepalive echo request */ >X /* restart max values, see RFC 1661 */ >X int timeout; >X int max_terminate; >X int max_configure; >X int max_failure; >X}; >X >X#define IDX_IPCP 1 /* idx into state table */ >X >Xstruct sipcp { >X u_long opts; /* IPCP options to send (bitfield) */ >X u_int flags; >X#define IPCP_HISADDR_SEEN 1 /* have seen his address already */ >X#define IPCP_MYADDR_DYN 2 /* my address is dynamically assigned */ >X#define IPCP_MYADDR_SEEN 4 /* have seen his address already */ >X}; >X >X#define AUTHNAMELEN 32 >X#define AUTHKEYLEN 16 >X >Xstruct sauth { >X u_short proto; /* authentication protocol to use */ >X u_short flags; >X#define AUTHFLAG_NOCALLOUT 1 /* do not require authentication on */ >X /* callouts */ >X#define AUTHFLAG_NORECHALLENGE 2 /* do not re-challenge CHAP */ >X u_char name[AUTHNAMELEN]; /* system identification name */ >X u_char secret[AUTHKEYLEN]; /* secret password */ >X u_char challenge[AUTHKEYLEN]; /* random challenge */ >X}; >X >X#define IDX_PAP 2 >X#define IDX_CHAP 3 >X >X#define IDX_COUNT (IDX_CHAP + 1) /* bump this when adding cp's! */ >X >X/* >X * Don't change the order of this. Ordering the phases this way allows >X * for a comparision of ``pp_phase >= PHASE_AUTHENTICATE'' in order to >X * know whether LCP is up. >X */ >Xenum ppp_phase { >X PHASE_DEAD, PHASE_ESTABLISH, PHASE_TERMINATE, >X PHASE_AUTHENTICATE, PHASE_NETWORK >X}; >X >Xstruct sppp { >X /* NB: pp_if _must_ be first */ >X struct ifnet pp_if; /* network interface data */ >X struct ifqueue pp_fastq; /* fast output queue */ >X struct ifqueue pp_cpq; /* PPP control protocol queue */ >X struct sppp *pp_next; /* next interface in keepalive list */ >X u_int pp_flags; /* use Cisco protocol instead of PPP */ >X u_short pp_alivecnt; /* keepalive packets counter */ >X u_short pp_loopcnt; /* loopback detection counter */ >X u_long pp_seq; /* local sequence number */ >X u_long pp_rseq; /* remote sequence number */ >X enum ppp_phase pp_phase; /* phase we're currently in */ >X int state[IDX_COUNT]; /* state machine */ >X u_char confid[IDX_COUNT]; /* id of last configuration request */ >X int rst_counter[IDX_COUNT]; /* restart counter */ >X int fail_counter[IDX_COUNT]; /* negotiation failure counter */ >X struct callout_handle ch[IDX_COUNT]; /* per-proto and if callouts */ >X struct callout_handle pap_my_to_ch; /* PAP needs one more... */ >X struct slcp lcp; /* LCP params */ >X struct sipcp ipcp; /* IPCP params */ >X struct sauth myauth; /* auth params, i'm peer */ >X struct sauth hisauth; /* auth params, i'm authenticator */ >X /* >X * These functions are filled in by sppp_attach(), and are >X * expected to be used by the lower layer (hardware) drivers >X * in order to communicate the (un)availability of the >X * communication link. Lower layer drivers that are always >X * ready to communicate (like hardware HDLC) can shortcut >X * pp_up from pp_tls, and pp_down from pp_tlf. >X */ >X void (*pp_up)(struct sppp *sp); >X void (*pp_down)(struct sppp *sp); >X /* >X * These functions need to be filled in by the lower layer >X * (hardware) drivers if they request notification from the >X * PPP layer whether the link is actually required. They >X * correspond to the tls and tlf actions. >X */ >X void (*pp_tls)(struct sppp *sp); >X void (*pp_tlf)(struct sppp *sp); >X /* >X * These (optional) functions may be filled by the hardware >X * driver if any notification of established connections >X * (currently: IPCP up) is desired (pp_con) or any internal >X * state change of the interface state machine should be >X * signaled for monitoring purposes (pp_chg). >X */ >X void (*pp_con)(struct sppp *sp); >X void (*pp_chg)(struct sppp *sp, int new_state); >X /* These two fields are for use by the lower layer */ >X void *pp_lowerp; >X int pp_loweri; >X}; >X >X#define PP_KEEPALIVE 0x01 /* use keepalive protocol */ >X#define PP_CISCO 0x02 /* use Cisco protocol instead of PPP */ >X /* 0x04 was PP_TIMO */ >X#define PP_CALLIN 0x08 /* we are being called */ >X#define PP_NEEDAUTH 0x10 /* remote requested authentication */ >X >X >X#define PP_MTU 1500 /* default/minimal MRU */ >X#define PP_MAX_MRU 2048 /* maximal MRU we want to negotiate */ >X >X/* >X * Definitions to pass struct sppp data down into the kernel using the >X * SIOC[SG]IFGENERIC ioctl interface. >X * >X * In order to use this, create a struct spppreq, fill in the cmd >X * field with SPPPIOGDEFS, and put the address of this structure into >X * the ifr_data portion of a struct ifreq. Pass this struct to a >X * SIOCGIFGENERIC ioctl. Then replace the cmd field by SPPPIOCDEFS, >X * modify the defs field as desired, and pass the struct ifreq now >X * to a SIOCSIFGENERIC ioctl. >X */ >X >X#define SPPPIOGDEFS ((caddr_t)(('S' << 24) + (1 << 16) + sizeof(struct sppp))) >X#define SPPPIOSDEFS ((caddr_t)(('S' << 24) + (2 << 16) + sizeof(struct sppp))) >X >Xstruct spppreq { >X int cmd; >X struct sppp defs; >X}; >X >X#ifdef KERNEL >Xvoid sppp_attach (struct ifnet *ifp); >Xvoid sppp_detach (struct ifnet *ifp); >Xvoid sppp_input (struct ifnet *ifp, struct mbuf *m); >Xint sppp_ioctl (struct ifnet *ifp, u_long cmd, void *data); >Xstruct mbuf *sppp_dequeue (struct ifnet *ifp); >Xstruct mbuf *sppp_pick(struct ifnet *ifp); >Xint sppp_isempty (struct ifnet *ifp); >Xvoid sppp_flush (struct ifnet *ifp); >X#endif >X >X#endif /* _NET_IF_SPPP_H_ */ >END-of-./usr/src/sys/net/if_sppp.h.orig >echo x - ./usr/src/sys/net/if_sppp.h.patch >sed 's/^X//' >./usr/src/sys/net/if_sppp.h.patch << 'END-of-./usr/src/sys/net/if_sppp.h.patch' >X*** if_sppp.h Tue Dec 1 21:20:19 1998 >X--- if_sppp.h.new Tue Mar 16 15:54:06 1999 >X*************** >X*** 90,95 **** >X--- 90,97 ---- >X u_short pp_loopcnt; /* loopback detection counter */ >X u_long pp_seq; /* local sequence number */ >X u_long pp_rseq; /* remote sequence number */ >X+ time_t pp_last_sent; >X+ time_t pp_last_recv; >X enum ppp_phase pp_phase; /* phase we're currently in */ >X int state[IDX_COUNT]; /* state machine */ >X u_char confid[IDX_COUNT]; /* id of last configuration request */ >END-of-./usr/src/sys/net/if_sppp.h.patch >echo x - ./usr/src/sys/net/if_spppsubr.c >sed 's/^X//' >./usr/src/sys/net/if_spppsubr.c << 'END-of-./usr/src/sys/net/if_spppsubr.c' >X/* >X * Synchronous PPP/Cisco link level subroutines. >X * Keepalive protocol implemented in both Cisco and PPP modes. >X * >X * Copyright (C) 1994-1996 Cronyx Engineering Ltd. >X * Author: Serge Vakulenko, <vak@cronyx.ru> >X * >X * Heavily revamped to conform to RFC 1661. >X * Copyright (C) 1997, Joerg Wunsch. >X * >X * This software is distributed with NO WARRANTIES, not even the implied >X * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. >X * >X * Authors grant any other persons or organisations permission to use >X * or modify this software as long as this message is kept with the software, >X * all derivative works or modified versions. >X * >X * From: Version 2.4, Thu Apr 30 17:17:21 MSD 1997 >X * >X * $Id: if_spppsubr.c,v 1.52 1998/12/27 21:30:44 phk Exp $ >X */ >X >X#include <sys/param.h> >X >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X#include "opt_inet.h" >X#include "opt_ipx.h" >X#endif >X >X#ifdef NetBSD1_3 >X# if NetBSD1_3 > 6 >X# include "opt_inet.h" >X# include "opt_iso.h" >X# endif >X#endif >X >X#include <sys/systm.h> >X#include <sys/kernel.h> >X#include <sys/sockio.h> >X#include <sys/socket.h> >X#include <sys/syslog.h> >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X#include <machine/random.h> >X#endif >X#include <sys/malloc.h> >X#include <sys/mbuf.h> >X >X#if defined (__OpenBSD__) >X#include <sys/md5k.h> >X#else >X#include <sys/md5.h> >X#endif >X >X#include <net/if.h> >X#include <net/netisr.h> >X#include <net/if_types.h> >X#include <net/route.h> >X >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X#include <machine/random.h> >X#endif >X#if defined (__NetBSD__) || defined (__OpenBSD__) >X#include <machine/cpu.h> /* XXX for softnet */ >X#endif >X >X#include <machine/stdarg.h> >X >X#ifdef INET >X#include <netinet/in.h> >X#include <netinet/in_systm.h> >X#include <netinet/in_var.h> >X#include <netinet/ip.h> >X#include <netinet/tcp.h> >X# if defined (__FreeBSD__) || defined (__OpenBSD__) >X# include <netinet/if_ether.h> >X# else >X# include <net/ethertypes.h> >X# endif >X#else >X# error Huh? sppp without INET? >X#endif >X >X#ifdef IPX >X#include <netipx/ipx.h> >X#include <netipx/ipx_if.h> >X#endif >X >X#ifdef NS >X#include <netns/ns.h> >X#include <netns/ns_if.h> >X#endif >X >X#ifdef ISO >X#include <netiso/argo_debug.h> >X#include <netiso/iso.h> >X#include <netiso/iso_var.h> >X#include <netiso/iso_snpac.h> >X#endif >X >X#include <net/if_sppp.h> >X >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X# define UNTIMEOUT(fun, arg, handle) untimeout(fun, arg, handle) >X# define TIMEOUT(fun, arg1, arg2, handle) handle = timeout(fun, arg1, arg2) >X# define IOCTL_CMD_T u_long >X#else >X# define UNTIMEOUT(fun, arg, handle) untimeout(fun, arg) >X# define TIMEOUT(fun, arg1, arg2, handle) timeout(fun, arg1, arg2) >X# define IOCTL_CMD_T int >X#endif >X >X#define MAXALIVECNT 3 /* max. alive packets */ >X >X/* >X * Interface flags that can be set in an ifconfig command. >X * >X * Setting link0 will make the link passive, i.e. it will be marked >X * as being administrative openable, but won't be opened to begin >X * with. Incoming calls will be answered, or subsequent calls with >X * -link1 will cause the administrative open of the LCP layer. >X * >X * Setting link1 will cause the link to auto-dial only as packets >X * arrive to be sent. >X * >X * Setting IFF_DEBUG will syslog the option negotiation and state >X * transitions at level kern.debug. Note: all logs consistently look >X * like >X * >X * <if-name><unit>: <proto-name> <additional info...> >X * >X * with <if-name><unit> being something like "bppp0", and <proto-name> >X * being one of "lcp", "ipcp", "cisco", "chap", "pap", etc. >X */ >X >X#define IFF_PASSIVE IFF_LINK0 /* wait passively for connection */ >X#define IFF_AUTO IFF_LINK1 /* auto-dial on output */ >X >X#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ >X#define PPP_UI 0x03 /* Unnumbered Information */ >X#define PPP_IP 0x0021 /* Internet Protocol */ >X#define PPP_ISO 0x0023 /* ISO OSI Protocol */ >X#define PPP_XNS 0x0025 /* Xerox NS Protocol */ >X#define PPP_IPX 0x002b /* Novell IPX Protocol */ >X#define PPP_LCP 0xc021 /* Link Control Protocol */ >X#define PPP_PAP 0xc023 /* Password Authentication Protocol */ >X#define PPP_CHAP 0xc223 /* Challenge-Handshake Auth Protocol */ >X#define PPP_IPCP 0x8021 /* Internet Protocol Control Protocol */ >X >X#define CONF_REQ 1 /* PPP configure request */ >X#define CONF_ACK 2 /* PPP configure acknowledge */ >X#define CONF_NAK 3 /* PPP configure negative ack */ >X#define CONF_REJ 4 /* PPP configure reject */ >X#define TERM_REQ 5 /* PPP terminate request */ >X#define TERM_ACK 6 /* PPP terminate acknowledge */ >X#define CODE_REJ 7 /* PPP code reject */ >X#define PROTO_REJ 8 /* PPP protocol reject */ >X#define ECHO_REQ 9 /* PPP echo request */ >X#define ECHO_REPLY 10 /* PPP echo reply */ >X#define DISC_REQ 11 /* PPP discard request */ >X >X#define LCP_OPT_MRU 1 /* maximum receive unit */ >X#define LCP_OPT_ASYNC_MAP 2 /* async control character map */ >X#define LCP_OPT_AUTH_PROTO 3 /* authentication protocol */ >X#define LCP_OPT_QUAL_PROTO 4 /* quality protocol */ >X#define LCP_OPT_MAGIC 5 /* magic number */ >X#define LCP_OPT_RESERVED 6 /* reserved */ >X#define LCP_OPT_PROTO_COMP 7 /* protocol field compression */ >X#define LCP_OPT_ADDR_COMP 8 /* address/control field compression */ >X >X#define IPCP_OPT_ADDRESSES 1 /* both IP addresses; deprecated */ >X#define IPCP_OPT_COMPRESSION 2 /* IP compression protocol (VJ) */ >X#define IPCP_OPT_ADDRESS 3 /* local IP address */ >X >X#define PAP_REQ 1 /* PAP name/password request */ >X#define PAP_ACK 2 /* PAP acknowledge */ >X#define PAP_NAK 3 /* PAP fail */ >X >X#define CHAP_CHALLENGE 1 /* CHAP challenge request */ >X#define CHAP_RESPONSE 2 /* CHAP challenge response */ >X#define CHAP_SUCCESS 3 /* CHAP response ok */ >X#define CHAP_FAILURE 4 /* CHAP response failed */ >X >X#define CHAP_MD5 5 /* hash algorithm - MD5 */ >X >X#define CISCO_MULTICAST 0x8f /* Cisco multicast address */ >X#define CISCO_UNICAST 0x0f /* Cisco unicast address */ >X#define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */ >X#define CISCO_ADDR_REQ 0 /* Cisco address request */ >X#define CISCO_ADDR_REPLY 1 /* Cisco address reply */ >X#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ >X >X/* states are named and numbered according to RFC 1661 */ >X#define STATE_INITIAL 0 >X#define STATE_STARTING 1 >X#define STATE_CLOSED 2 >X#define STATE_STOPPED 3 >X#define STATE_CLOSING 4 >X#define STATE_STOPPING 5 >X#define STATE_REQ_SENT 6 >X#define STATE_ACK_RCVD 7 >X#define STATE_ACK_SENT 8 >X#define STATE_OPENED 9 >X >Xstruct ppp_header { >X u_char address; >X u_char control; >X u_short protocol; >X}; >X#define PPP_HEADER_LEN sizeof (struct ppp_header) >X >Xstruct lcp_header { >X u_char type; >X u_char ident; >X u_short len; >X}; >X#define LCP_HEADER_LEN sizeof (struct lcp_header) >X >Xstruct cisco_packet { >X u_long type; >X u_long par1; >X u_long par2; >X u_short rel; >X u_short time0; >X u_short time1; >X}; >X#define CISCO_PACKET_LEN 18 >X >X/* >X * We follow the spelling and capitalization of RFC 1661 here, to make >X * it easier comparing with the standard. Please refer to this RFC in >X * case you can't make sense out of these abbreviation; it will also >X * explain the semantics related to the various events and actions. >X */ >Xstruct cp { >X u_short proto; /* PPP control protocol number */ >X u_char protoidx; /* index into state table in struct sppp */ >X u_char flags; >X#define CP_LCP 0x01 /* this is the LCP */ >X#define CP_AUTH 0x02 /* this is an authentication protocol */ >X#define CP_NCP 0x04 /* this is a NCP */ >X#define CP_QUAL 0x08 /* this is a quality reporting protocol */ >X const char *name; /* name of this control protocol */ >X /* event handlers */ >X void (*Up)(struct sppp *sp); >X void (*Down)(struct sppp *sp); >X void (*Open)(struct sppp *sp); >X void (*Close)(struct sppp *sp); >X void (*TO)(void *sp); >X int (*RCR)(struct sppp *sp, struct lcp_header *h, int len); >X void (*RCN_rej)(struct sppp *sp, struct lcp_header *h, int len); >X void (*RCN_nak)(struct sppp *sp, struct lcp_header *h, int len); >X /* actions */ >X void (*tlu)(struct sppp *sp); >X void (*tld)(struct sppp *sp); >X void (*tls)(struct sppp *sp); >X void (*tlf)(struct sppp *sp); >X void (*scr)(struct sppp *sp); >X}; >X >Xstatic struct sppp *spppq; >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >Xstatic struct callout_handle keepalive_ch; >X#endif >X >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X#define SPP_FMT "%s%d: " >X#define SPP_ARGS(ifp) (ifp)->if_name, (ifp)->if_unit >X#else >X#define SPP_FMT "%s: " >X#define SPP_ARGS(ifp) (ifp)->if_xname >X#endif >X >X/* >X * The following disgusting hack gets around the problem that IP TOS >X * can't be set yet. We want to put "interactive" traffic on a high >X * priority queue. To decide if traffic is interactive, we check that >X * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control. >X * >X * XXX is this really still necessary? - joerg - >X */ >Xstatic u_short interactive_ports[8] = { >X 0, 513, 0, 0, >X 0, 21, 0, 23, >X}; >X#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p)) >X >X/* almost every function needs these */ >X#define STDDCL \ >X struct ifnet *ifp = &sp->pp_if; \ >X int debug = ifp->if_flags & IFF_DEBUG >X >Xstatic int sppp_output(struct ifnet *ifp, struct mbuf *m, >X struct sockaddr *dst, struct rtentry *rt); >X >Xstatic void sppp_cisco_send(struct sppp *sp, int type, long par1, long par2); >Xstatic void sppp_cisco_input(struct sppp *sp, struct mbuf *m); >X >Xstatic void sppp_cp_input(const struct cp *cp, struct sppp *sp, >X struct mbuf *m); >Xstatic void sppp_cp_send(struct sppp *sp, u_short proto, u_char type, >X u_char ident, u_short len, void *data); >X/* static void sppp_cp_timeout(void *arg); */ >Xstatic void sppp_cp_change_state(const struct cp *cp, struct sppp *sp, >X int newstate); >Xstatic void sppp_auth_send(const struct cp *cp, >X struct sppp *sp, unsigned int type, unsigned int id, >X ...); >X >Xstatic void sppp_up_event(const struct cp *cp, struct sppp *sp); >Xstatic void sppp_down_event(const struct cp *cp, struct sppp *sp); >Xstatic void sppp_open_event(const struct cp *cp, struct sppp *sp); >Xstatic void sppp_close_event(const struct cp *cp, struct sppp *sp); >Xstatic void sppp_to_event(const struct cp *cp, struct sppp *sp); >X >Xstatic void sppp_null(struct sppp *sp); >X >Xstatic void sppp_lcp_init(struct sppp *sp); >Xstatic void sppp_lcp_up(struct sppp *sp); >Xstatic void sppp_lcp_down(struct sppp *sp); >Xstatic void sppp_lcp_open(struct sppp *sp); >Xstatic void sppp_lcp_close(struct sppp *sp); >Xstatic void sppp_lcp_TO(void *sp); >Xstatic int sppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len); >Xstatic void sppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len); >Xstatic void sppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len); >Xstatic void sppp_lcp_tlu(struct sppp *sp); >Xstatic void sppp_lcp_tld(struct sppp *sp); >Xstatic void sppp_lcp_tls(struct sppp *sp); >Xstatic void sppp_lcp_tlf(struct sppp *sp); >Xstatic void sppp_lcp_scr(struct sppp *sp); >Xstatic void sppp_lcp_check_and_close(struct sppp *sp); >Xstatic int sppp_ncp_check(struct sppp *sp); >X >Xstatic void sppp_ipcp_init(struct sppp *sp); >Xstatic void sppp_ipcp_up(struct sppp *sp); >Xstatic void sppp_ipcp_down(struct sppp *sp); >Xstatic void sppp_ipcp_open(struct sppp *sp); >Xstatic void sppp_ipcp_close(struct sppp *sp); >Xstatic void sppp_ipcp_TO(void *sp); >Xstatic int sppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len); >Xstatic void sppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len); >Xstatic void sppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len); >Xstatic void sppp_ipcp_tlu(struct sppp *sp); >Xstatic void sppp_ipcp_tld(struct sppp *sp); >Xstatic void sppp_ipcp_tls(struct sppp *sp); >Xstatic void sppp_ipcp_tlf(struct sppp *sp); >Xstatic void sppp_ipcp_scr(struct sppp *sp); >X >Xstatic void sppp_pap_input(struct sppp *sp, struct mbuf *m); >Xstatic void sppp_pap_init(struct sppp *sp); >Xstatic void sppp_pap_open(struct sppp *sp); >Xstatic void sppp_pap_close(struct sppp *sp); >Xstatic void sppp_pap_TO(void *sp); >Xstatic void sppp_pap_my_TO(void *sp); >Xstatic void sppp_pap_tlu(struct sppp *sp); >Xstatic void sppp_pap_tld(struct sppp *sp); >Xstatic void sppp_pap_scr(struct sppp *sp); >X >Xstatic void sppp_chap_input(struct sppp *sp, struct mbuf *m); >Xstatic void sppp_chap_init(struct sppp *sp); >Xstatic void sppp_chap_open(struct sppp *sp); >Xstatic void sppp_chap_close(struct sppp *sp); >Xstatic void sppp_chap_TO(void *sp); >Xstatic void sppp_chap_tlu(struct sppp *sp); >Xstatic void sppp_chap_tld(struct sppp *sp); >Xstatic void sppp_chap_scr(struct sppp *sp); >X >Xstatic const char *sppp_auth_type_name(u_short proto, u_char type); >Xstatic const char *sppp_cp_type_name(u_char type); >Xstatic const char *sppp_dotted_quad(u_long addr); >Xstatic const char *sppp_ipcp_opt_name(u_char opt); >Xstatic const char *sppp_lcp_opt_name(u_char opt); >Xstatic const char *sppp_phase_name(enum ppp_phase phase); >Xstatic const char *sppp_proto_name(u_short proto); >Xstatic const char *sppp_state_name(int state); >Xstatic int sppp_params(struct sppp *sp, u_long cmd, void *data); >Xstatic int sppp_strnlen(u_char *p, int max); >Xstatic void sppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst, >X u_long *srcmask); >Xstatic void sppp_keepalive(void *dummy); >Xstatic void sppp_phase_network(struct sppp *sp); >Xstatic void sppp_print_bytes(const u_char *p, u_short len); >Xstatic void sppp_print_string(const char *p, u_short len); >Xstatic void sppp_qflush(struct ifqueue *ifq); >Xstatic void sppp_set_ip_addr(struct sppp *sp, u_long src); >X >X/* our control protocol descriptors */ >Xstatic const struct cp lcp = { >X PPP_LCP, IDX_LCP, CP_LCP, "lcp", >X sppp_lcp_up, sppp_lcp_down, sppp_lcp_open, sppp_lcp_close, >X sppp_lcp_TO, sppp_lcp_RCR, sppp_lcp_RCN_rej, sppp_lcp_RCN_nak, >X sppp_lcp_tlu, sppp_lcp_tld, sppp_lcp_tls, sppp_lcp_tlf, >X sppp_lcp_scr >X}; >X >Xstatic const struct cp ipcp = { >X PPP_IPCP, IDX_IPCP, CP_NCP, "ipcp", >X sppp_ipcp_up, sppp_ipcp_down, sppp_ipcp_open, sppp_ipcp_close, >X sppp_ipcp_TO, sppp_ipcp_RCR, sppp_ipcp_RCN_rej, sppp_ipcp_RCN_nak, >X sppp_ipcp_tlu, sppp_ipcp_tld, sppp_ipcp_tls, sppp_ipcp_tlf, >X sppp_ipcp_scr >X}; >X >Xstatic const struct cp pap = { >X PPP_PAP, IDX_PAP, CP_AUTH, "pap", >X sppp_null, sppp_null, sppp_pap_open, sppp_pap_close, >X sppp_pap_TO, 0, 0, 0, >X sppp_pap_tlu, sppp_pap_tld, sppp_null, sppp_null, >X sppp_pap_scr >X}; >X >Xstatic const struct cp chap = { >X PPP_CHAP, IDX_CHAP, CP_AUTH, "chap", >X sppp_null, sppp_null, sppp_chap_open, sppp_chap_close, >X sppp_chap_TO, 0, 0, 0, >X sppp_chap_tlu, sppp_chap_tld, sppp_null, sppp_null, >X sppp_chap_scr >X}; >X >Xstatic const struct cp *cps[IDX_COUNT] = { >X &lcp, /* IDX_LCP */ >X &ipcp, /* IDX_IPCP */ >X &pap, /* IDX_PAP */ >X &chap, /* IDX_CHAP */ >X}; >X >X >X/* >X * Exported functions, comprising our interface to the lower layer. >X */ >X >X/* >X * Process the received packet. >X */ >Xvoid >Xsppp_input(struct ifnet *ifp, struct mbuf *m) >X{ >X struct ppp_header *h; >X struct ifqueue *inq = 0; >X int s; >X struct sppp *sp = (struct sppp *)ifp; >X int debug = ifp->if_flags & IFF_DEBUG; >X >X if (ifp->if_flags & IFF_UP) >X /* Count received bytes, add FCS and one flag */ >X ifp->if_ibytes += m->m_pkthdr.len + 3; >X >X if (m->m_pkthdr.len <= PPP_HEADER_LEN) { >X /* Too small packet, drop it. */ >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "input packet is too small, %d bytes\n", >X SPP_ARGS(ifp), m->m_pkthdr.len); >X drop: >X ++ifp->if_ierrors; >X ++ifp->if_iqdrops; >X m_freem (m); >X return; >X } >X >X /* Get PPP header. */ >X h = mtod (m, struct ppp_header*); >X m_adj (m, PPP_HEADER_LEN); >X >X switch (h->address) { >X case PPP_ALLSTATIONS: >X if (h->control != PPP_UI) >X goto invalid; >X if (sp->pp_flags & PP_CISCO) { >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "PPP packet in Cisco mode " >X "<addr=0x%x ctrl=0x%x proto=0x%x>\n", >X SPP_ARGS(ifp), >X h->address, h->control, ntohs(h->protocol)); >X goto drop; >X } >X switch (ntohs (h->protocol)) { >X default: >X if (sp->state[IDX_LCP] == STATE_OPENED) >X sppp_cp_send (sp, PPP_LCP, PROTO_REJ, >X ++sp->pp_seq, m->m_pkthdr.len + 2, >X &h->protocol); >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "invalid input protocol " >X "<addr=0x%x ctrl=0x%x proto=0x%x>\n", >X SPP_ARGS(ifp), >X h->address, h->control, ntohs(h->protocol)); >X ++ifp->if_noproto; >X goto drop; >X case PPP_LCP: >X sppp_cp_input(&lcp, sp, m); >X m_freem (m); >X return; >X case PPP_PAP: >X if (sp->pp_phase >= PHASE_AUTHENTICATE) >X sppp_pap_input(sp, m); >X m_freem (m); >X return; >X case PPP_CHAP: >X if (sp->pp_phase >= PHASE_AUTHENTICATE) >X sppp_chap_input(sp, m); >X m_freem (m); >X return; >X#ifdef INET >X case PPP_IPCP: >X if (sp->pp_phase == PHASE_NETWORK) >X sppp_cp_input(&ipcp, sp, m); >X m_freem (m); >X return; >X case PPP_IP: >X if (sp->state[IDX_IPCP] == STATE_OPENED) { >X schednetisr (NETISR_IP); >X inq = &ipintrq; >X } >X break; >X#endif >X#ifdef IPX >X case PPP_IPX: >X /* IPX IPXCP not implemented yet */ >X if (sp->pp_phase == PHASE_NETWORK) { >X schednetisr (NETISR_IPX); >X inq = &ipxintrq; >X } >X break; >X#endif >X#ifdef NS >X case PPP_XNS: >X /* XNS IDPCP not implemented yet */ >X if (sp->pp_phase == PHASE_NETWORK) { >X schednetisr (NETISR_NS); >X inq = &nsintrq; >X } >X break; >X#endif >X#ifdef ISO >X case PPP_ISO: >X /* OSI NLCP not implemented yet */ >X if (sp->pp_phase == PHASE_NETWORK) { >X schednetisr (NETISR_ISO); >X inq = &clnlintrq; >X } >X break; >X#endif >X } >X break; >X case CISCO_MULTICAST: >X case CISCO_UNICAST: >X /* Don't check the control field here (RFC 1547). */ >X if (! (sp->pp_flags & PP_CISCO)) { >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "Cisco packet in PPP mode " >X "<addr=0x%x ctrl=0x%x proto=0x%x>\n", >X SPP_ARGS(ifp), >X h->address, h->control, ntohs(h->protocol)); >X goto drop; >X } >X switch (ntohs (h->protocol)) { >X default: >X ++ifp->if_noproto; >X goto invalid; >X case CISCO_KEEPALIVE: >X sppp_cisco_input ((struct sppp*) ifp, m); >X m_freem (m); >X return; >X#ifdef INET >X case ETHERTYPE_IP: >X schednetisr (NETISR_IP); >X inq = &ipintrq; >X break; >X#endif >X#ifdef IPX >X case ETHERTYPE_IPX: >X schednetisr (NETISR_IPX); >X inq = &ipxintrq; >X break; >X#endif >X#ifdef NS >X case ETHERTYPE_NS: >X schednetisr (NETISR_NS); >X inq = &nsintrq; >X break; >X#endif >X } >X break; >X default: /* Invalid PPP packet. */ >X invalid: >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "invalid input packet " >X "<addr=0x%x ctrl=0x%x proto=0x%x>\n", >X SPP_ARGS(ifp), >X h->address, h->control, ntohs(h->protocol)); >X goto drop; >X } >X >X if (! (ifp->if_flags & IFF_UP) || ! inq) >X goto drop; >X >X /* Check queue. */ >X s = splimp(); >X if (IF_QFULL (inq)) { >X /* Queue overflow. */ >X IF_DROP(inq); >X splx(s); >X if (debug) >X log(LOG_DEBUG, SPP_FMT "protocol queue overflow\n", >X SPP_ARGS(ifp)); >X goto drop; >X } >X IF_ENQUEUE(inq, m); >X sp->pp_last_recv = time_second; >X splx(s); >X} >X >X/* >X * Enqueue transmit packet. >X */ >Xstatic int >Xsppp_output(struct ifnet *ifp, struct mbuf *m, >X struct sockaddr *dst, struct rtentry *rt) >X{ >X struct sppp *sp = (struct sppp*) ifp; >X struct ppp_header *h; >X struct ifqueue *ifq; >X int s, rv = 0; >X int debug = ifp->if_flags & IFF_DEBUG; >X >X s = splimp(); >X >X if ((ifp->if_flags & IFF_UP) == 0 || >X (ifp->if_flags & (IFF_RUNNING | IFF_AUTO)) == 0) { >X m_freem (m); >X splx (s); >X return (ENETDOWN); >X } >X >X if ((ifp->if_flags & (IFF_RUNNING | IFF_AUTO)) == IFF_AUTO) { >X /* >X * Interface is not yet running, but auto-dial. Need >X * to start LCP for it. >X */ >X ifp->if_flags |= IFF_RUNNING; >X splx(s); >X lcp.Open(sp); >X s = splimp(); >X } >X >X ifq = &ifp->if_snd; >X#ifdef INET >X if (dst->sa_family == AF_INET) { >X /* XXX Check mbuf length here? */ >X struct ip *ip = mtod (m, struct ip*); >X struct tcphdr *tcp = (struct tcphdr*) ((long*)ip + ip->ip_hl); >X >X /* >X * When using dynamic local IP address assignment by using >X * 0.0.0.0 as a local address, the first TCP session will >X * not connect because the local TCP checksum is computed >X * using 0.0.0.0 which will later become our real IP address >X * so the TCP checksum computed at the remote end will >X * become invalid. So we >X * - don't let packets with src ip addr 0 thru >X * - we flag TCP packets with src ip 0 as an error >X */ >X >X if(ip->ip_src.s_addr == INADDR_ANY) /* -hm */ >X { >X m_freem(m); >X splx(s); >X if(ip->ip_p == IPPROTO_TCP) >X return(EADDRNOTAVAIL); >X else >X return(0); >X } >X >X /* >X * Put low delay, telnet, rlogin and ftp control packets >X * in front of the queue. >X */ >X if (IF_QFULL (&sp->pp_fastq)) >X ; >X else if (ip->ip_tos & IPTOS_LOWDELAY) >X ifq = &sp->pp_fastq; >X else if (m->m_len < sizeof *ip + sizeof *tcp) >X ; >X else if (ip->ip_p != IPPROTO_TCP) >X ; >X else if (INTERACTIVE (ntohs (tcp->th_sport))) >X ifq = &sp->pp_fastq; >X else if (INTERACTIVE (ntohs (tcp->th_dport))) >X ifq = &sp->pp_fastq; >X } >X#endif >X >X /* >X * Prepend general data packet PPP header. For now, IP only. >X */ >X M_PREPEND (m, PPP_HEADER_LEN, M_DONTWAIT); >X if (! m) { >X if (debug) >X log(LOG_DEBUG, SPP_FMT "no memory for transmit header\n", >X SPP_ARGS(ifp)); >X ++ifp->if_oerrors; >X splx (s); >X return (ENOBUFS); >X } >X /* >X * May want to check size of packet >X * (albeit due to the implementation it's always enough) >X */ >X h = mtod (m, struct ppp_header*); >X if (sp->pp_flags & PP_CISCO) { >X h->address = CISCO_UNICAST; /* unicast address */ >X h->control = 0; >X } else { >X h->address = PPP_ALLSTATIONS; /* broadcast address */ >X h->control = PPP_UI; /* Unnumbered Info */ >X } >X >X switch (dst->sa_family) { >X#ifdef INET >X case AF_INET: /* Internet Protocol */ >X if (sp->pp_flags & PP_CISCO) >X h->protocol = htons (ETHERTYPE_IP); >X else { >X /* >X * Don't choke with an ENETDOWN early. It's >X * possible that we just started dialing out, >X * so don't drop the packet immediately. If >X * we notice that we run out of buffer space >X * below, we will however remember that we are >X * not ready to carry IP packets, and return >X * ENETDOWN, as opposed to ENOBUFS. >X */ >X h->protocol = htons(PPP_IP); >X if (sp->state[IDX_IPCP] != STATE_OPENED) >X rv = ENETDOWN; >X } >X break; >X#endif >X#ifdef NS >X case AF_NS: /* Xerox NS Protocol */ >X h->protocol = htons ((sp->pp_flags & PP_CISCO) ? >X ETHERTYPE_NS : PPP_XNS); >X break; >X#endif >X#ifdef IPX >X case AF_IPX: /* Novell IPX Protocol */ >X h->protocol = htons ((sp->pp_flags & PP_CISCO) ? >X ETHERTYPE_IPX : PPP_IPX); >X break; >X#endif >X#ifdef ISO >X case AF_ISO: /* ISO OSI Protocol */ >X if (sp->pp_flags & PP_CISCO) >X goto nosupport; >X h->protocol = htons (PPP_ISO); >X break; >Xnosupport: >X#endif >X default: >X m_freem (m); >X ++ifp->if_oerrors; >X splx (s); >X return (EAFNOSUPPORT); >X } >X >X /* >X * Queue message on interface, and start output if interface >X * not yet active. >X */ >X if (IF_QFULL (ifq)) { >X IF_DROP (&ifp->if_snd); >X m_freem (m); >X ++ifp->if_oerrors; >X splx (s); >X return (rv? rv: ENOBUFS); >X } >X IF_ENQUEUE (ifq, m); >X if (! (ifp->if_flags & IFF_OACTIVE)) >X (*ifp->if_start) (ifp); >X >X /* >X * Count output packets and bytes. >X * The packet length includes header, FCS and 1 flag, >X * according to RFC 1333. >X */ >X ifp->if_obytes += m->m_pkthdr.len + 3; >X sp->pp_last_sent = time_second; >X splx (s); >X return (0); >X} >X >Xvoid >Xsppp_attach(struct ifnet *ifp) >X{ >X struct sppp *sp = (struct sppp*) ifp; >X >X /* Initialize keepalive handler. */ >X if (! spppq) >X TIMEOUT(sppp_keepalive, 0, hz * 10, keepalive_ch); >X >X /* Insert new entry into the keepalive list. */ >X sp->pp_next = spppq; >X spppq = sp; >X >X sp->pp_if.if_mtu = PP_MTU; >X sp->pp_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; >X sp->pp_if.if_type = IFT_PPP; >X sp->pp_if.if_output = sppp_output; >X#if 0 >X sp->pp_flags = PP_KEEPALIVE; >X#endif >X sp->pp_fastq.ifq_maxlen = 32; >X sp->pp_cpq.ifq_maxlen = 20; >X sp->pp_loopcnt = 0; >X sp->pp_alivecnt = 0; >X sp->pp_seq = 0; >X sp->pp_rseq = 0; >X sp->pp_phase = PHASE_DEAD; >X sp->pp_up = lcp.Up; >X sp->pp_down = lcp.Down; >X >X sp->pp_last_recv = sp->pp_last_sent = time_second; >X sppp_lcp_init(sp); >X sppp_ipcp_init(sp); >X sppp_pap_init(sp); >X sppp_chap_init(sp); >X} >X >Xvoid >Xsppp_detach(struct ifnet *ifp) >X{ >X struct sppp **q, *p, *sp = (struct sppp*) ifp; >X int i; >X >X /* Remove the entry from the keepalive list. */ >X for (q = &spppq; (p = *q); q = &p->pp_next) >X if (p == sp) { >X *q = p->pp_next; >X break; >X } >X >X /* Stop keepalive handler. */ >X if (! spppq) >X UNTIMEOUT(sppp_keepalive, 0, keepalive_ch); >X >X for (i = 0; i < IDX_COUNT; i++) >X UNTIMEOUT((cps[i])->TO, (void *)sp, sp->ch[i]); >X UNTIMEOUT(sppp_pap_my_TO, (void *)sp, sp->pap_my_to_ch); >X} >X >X/* >X * Flush the interface output queue. >X */ >Xvoid >Xsppp_flush(struct ifnet *ifp) >X{ >X struct sppp *sp = (struct sppp*) ifp; >X >X sppp_qflush (&sp->pp_if.if_snd); >X sppp_qflush (&sp->pp_fastq); >X sppp_qflush (&sp->pp_cpq); >X} >X >X/* >X * Check if the output queue is empty. >X */ >Xint >Xsppp_isempty(struct ifnet *ifp) >X{ >X struct sppp *sp = (struct sppp*) ifp; >X int empty, s; >X >X s = splimp(); >X empty = !sp->pp_fastq.ifq_head && !sp->pp_cpq.ifq_head && >X !sp->pp_if.if_snd.ifq_head; >X splx(s); >X return (empty); >X} >X >X/* >X * Get next packet to send. >X */ >Xstruct mbuf * >Xsppp_dequeue(struct ifnet *ifp) >X{ >X struct sppp *sp = (struct sppp*) ifp; >X struct mbuf *m; >X int s; >X >X s = splimp(); >X /* >X * Process only the control protocol queue until we have at >X * least one NCP open. >X * >X * Do always serve all three queues in Cisco mode. >X */ >X IF_DEQUEUE(&sp->pp_cpq, m); >X if (m == NULL && >X (sppp_ncp_check(sp) || (sp->pp_flags & PP_CISCO) != 0)) { >X IF_DEQUEUE(&sp->pp_fastq, m); >X if (m == NULL) >X IF_DEQUEUE (&sp->pp_if.if_snd, m); >X } >X splx(s); >X return m; >X} >X >X/* >X * Pick the next packet, do not remove it from the queue. >X */ >Xstruct mbuf * >Xsppp_pick(struct ifnet *ifp) >X{ >X struct sppp *sp = (struct sppp*)ifp; >X struct mbuf *m; >X int s; >X >X s= splimp (); >X >X m = sp->pp_cpq.ifq_head; >X if (m == NULL && >X (sp->pp_phase == PHASE_NETWORK || >X (sp->pp_flags & PP_CISCO) != 0)) >X if ((m = sp->pp_fastq.ifq_head) == NULL) >X m = sp->pp_if.if_snd.ifq_head; >X splx (s); >X return (m); >X} >X >X/* >X * Process an ioctl request. Called on low priority level. >X */ >Xint >Xsppp_ioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, void *data) >X{ >X struct ifreq *ifr = (struct ifreq*) data; >X struct sppp *sp = (struct sppp*) ifp; >X int s, rv, going_up, going_down, newmode; >X >X s = splimp(); >X rv = 0; >X switch (cmd) { >X case SIOCAIFADDR: >X case SIOCSIFDSTADDR: >X break; >X >X case SIOCSIFADDR: >X if_up(ifp); >X /* fall through... */ >X >X case SIOCSIFFLAGS: >X going_up = ifp->if_flags & IFF_UP && >X (ifp->if_flags & IFF_RUNNING) == 0; >X going_down = (ifp->if_flags & IFF_UP) == 0 && >X ifp->if_flags & IFF_RUNNING; >X newmode = ifp->if_flags & (IFF_AUTO | IFF_PASSIVE); >X if (newmode == (IFF_AUTO | IFF_PASSIVE)) { >X /* sanity */ >X newmode = IFF_PASSIVE; >X ifp->if_flags &= ~IFF_AUTO; >X } >X >X if (going_up || going_down) >X lcp.Close(sp); >X if (going_up && newmode == 0) { >X /* neither auto-dial nor passive */ >X ifp->if_flags |= IFF_RUNNING; >X if (!(sp->pp_flags & PP_CISCO)) >X lcp.Open(sp); >X } else if (going_down) { >X sppp_flush(ifp); >X ifp->if_flags &= ~IFF_RUNNING; >X } >X >X break; >X >X#ifdef SIOCSIFMTU >X#ifndef ifr_mtu >X#define ifr_mtu ifr_metric >X#endif >X case SIOCSIFMTU: >X if (ifr->ifr_mtu < 128 || ifr->ifr_mtu > sp->lcp.their_mru) >X return (EINVAL); >X ifp->if_mtu = ifr->ifr_mtu; >X break; >X#endif >X#ifdef SLIOCSETMTU >X case SLIOCSETMTU: >X if (*(short*)data < 128 || *(short*)data > sp->lcp.their_mru) >X return (EINVAL); >X ifp->if_mtu = *(short*)data; >X break; >X#endif >X#ifdef SIOCGIFMTU >X case SIOCGIFMTU: >X ifr->ifr_mtu = ifp->if_mtu; >X break; >X#endif >X#ifdef SLIOCGETMTU >X case SLIOCGETMTU: >X *(short*)data = ifp->if_mtu; >X break; >X#endif >X case SIOCADDMULTI: >X case SIOCDELMULTI: >X break; >X >X case SIOCGIFGENERIC: >X case SIOCSIFGENERIC: >X rv = sppp_params(sp, cmd, data); >X break; >X >X default: >X rv = ENOTTY; >X } >X splx(s); >X return rv; >X} >X >X >X/* >X * Cisco framing implementation. >X */ >X >X/* >X * Handle incoming Cisco keepalive protocol packets. >X */ >Xstatic void >Xsppp_cisco_input(struct sppp *sp, struct mbuf *m) >X{ >X STDDCL; >X struct cisco_packet *h; >X u_long me, mymask; >X >X if (m->m_pkthdr.len < CISCO_PACKET_LEN) { >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "cisco invalid packet length: %d bytes\n", >X SPP_ARGS(ifp), m->m_pkthdr.len); >X return; >X } >X h = mtod (m, struct cisco_packet*); >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "cisco input: %d bytes " >X "<0x%lx 0x%lx 0x%lx 0x%x 0x%x-0x%x>\n", >X SPP_ARGS(ifp), m->m_pkthdr.len, >X (u_long)ntohl (h->type), (u_long)h->par1, (u_long)h->par2, (u_int)h->rel, >X (u_int)h->time0, (u_int)h->time1); >X switch (ntohl (h->type)) { >X default: >X if (debug) >X addlog(SPP_FMT "cisco unknown packet type: 0x%lx\n", >X SPP_ARGS(ifp), (u_long)ntohl (h->type)); >X break; >X case CISCO_ADDR_REPLY: >X /* Reply on address request, ignore */ >X break; >X case CISCO_KEEPALIVE_REQ: >X sp->pp_alivecnt = 0; >X sp->pp_rseq = ntohl (h->par1); >X if (sp->pp_seq == sp->pp_rseq) { >X /* Local and remote sequence numbers are equal. >X * Probably, the line is in loopback mode. */ >X if (sp->pp_loopcnt >= MAXALIVECNT) { >X printf (SPP_FMT "loopback\n", >X SPP_ARGS(ifp)); >X sp->pp_loopcnt = 0; >X if (ifp->if_flags & IFF_UP) { >X if_down (ifp); >X sppp_qflush (&sp->pp_cpq); >X } >X } >X ++sp->pp_loopcnt; >X >X /* Generate new local sequence number */ >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X sp->pp_seq = random(); >X#else >X sp->pp_seq ^= time.tv_sec ^ time.tv_usec; >X#endif >X break; >X } >X sp->pp_loopcnt = 0; >X if (! (ifp->if_flags & IFF_UP) && >X (ifp->if_flags & IFF_RUNNING)) { >X if_up(ifp); >X printf (SPP_FMT "up\n", SPP_ARGS(ifp)); >X } >X break; >X case CISCO_ADDR_REQ: >X sppp_get_ip_addrs(sp, &me, 0, &mymask); >X if (me != 0L) >X sppp_cisco_send(sp, CISCO_ADDR_REPLY, me, mymask); >X break; >X } >X} >X >X/* >X * Send Cisco keepalive packet. >X */ >Xstatic void >Xsppp_cisco_send(struct sppp *sp, int type, long par1, long par2) >X{ >X STDDCL; >X struct ppp_header *h; >X struct cisco_packet *ch; >X struct mbuf *m; >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X struct timeval tv; >X#else >X u_long t = (time.tv_sec - boottime.tv_sec) * 1000; >X#endif >X >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X getmicrouptime(&tv); >X#endif >X >X MGETHDR (m, M_DONTWAIT, MT_DATA); >X if (! m) >X return; >X m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + CISCO_PACKET_LEN; >X m->m_pkthdr.rcvif = 0; >X >X h = mtod (m, struct ppp_header*); >X h->address = CISCO_MULTICAST; >X h->control = 0; >X h->protocol = htons (CISCO_KEEPALIVE); >X >X ch = (struct cisco_packet*) (h + 1); >X ch->type = htonl (type); >X ch->par1 = htonl (par1); >X ch->par2 = htonl (par2); >X ch->rel = -1; >X >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X ch->time0 = htons ((u_short) (tv.tv_sec >> 16)); >X ch->time1 = htons ((u_short) tv.tv_sec); >X#else >X ch->time0 = htons ((u_short) (t >> 16)); >X ch->time1 = htons ((u_short) t); >X#endif >X >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "cisco output: <0x%lx 0x%lx 0x%lx 0x%x 0x%x-0x%x>\n", >X SPP_ARGS(ifp), (u_long)ntohl (ch->type), (u_long)ch->par1, >X (u_long)ch->par2, (u_int)ch->rel, (u_int)ch->time0, (u_int)ch->time1); >X >X if (IF_QFULL (&sp->pp_cpq)) { >X IF_DROP (&sp->pp_fastq); >X IF_DROP (&ifp->if_snd); >X m_freem (m); >X } else >X IF_ENQUEUE (&sp->pp_cpq, m); >X if (! (ifp->if_flags & IFF_OACTIVE)) >X (*ifp->if_start) (ifp); >X ifp->if_obytes += m->m_pkthdr.len + 3; >X} >X >X/* >X * PPP protocol implementation. >X */ >X >X/* >X * Send PPP control protocol packet. >X */ >Xstatic void >Xsppp_cp_send(struct sppp *sp, u_short proto, u_char type, >X u_char ident, u_short len, void *data) >X{ >X STDDCL; >X struct ppp_header *h; >X struct lcp_header *lh; >X struct mbuf *m; >X >X if (len > MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN) >X len = MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN; >X MGETHDR (m, M_DONTWAIT, MT_DATA); >X if (! m) >X return; >X m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + LCP_HEADER_LEN + len; >X m->m_pkthdr.rcvif = 0; >X >X h = mtod (m, struct ppp_header*); >X h->address = PPP_ALLSTATIONS; /* broadcast address */ >X h->control = PPP_UI; /* Unnumbered Info */ >X h->protocol = htons (proto); /* Link Control Protocol */ >X >X lh = (struct lcp_header*) (h + 1); >X lh->type = type; >X lh->ident = ident; >X lh->len = htons (LCP_HEADER_LEN + len); >X if (len) >X bcopy (data, lh+1, len); >X >X if (debug) { >X log(LOG_DEBUG, SPP_FMT "%s output <%s id=0x%x len=%d", >X SPP_ARGS(ifp), >X sppp_proto_name(proto), >X sppp_cp_type_name (lh->type), lh->ident, >X ntohs (lh->len)); >X if (len) >X sppp_print_bytes ((u_char*) (lh+1), len); >X addlog(">\n"); >X } >X if (IF_QFULL (&sp->pp_cpq)) { >X IF_DROP (&sp->pp_fastq); >X IF_DROP (&ifp->if_snd); >X m_freem (m); >X ++ifp->if_oerrors; >X } else >X IF_ENQUEUE (&sp->pp_cpq, m); >X if (! (ifp->if_flags & IFF_OACTIVE)) >X (*ifp->if_start) (ifp); >X ifp->if_obytes += m->m_pkthdr.len + 3; >X} >X >X/* >X * Handle incoming PPP control protocol packets. >X */ >Xstatic void >Xsppp_cp_input(const struct cp *cp, struct sppp *sp, struct mbuf *m) >X{ >X STDDCL; >X struct lcp_header *h; >X int len = m->m_pkthdr.len; >X int rv; >X u_char *p; >X >X if (len < 4) { >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "%s invalid packet length: %d bytes\n", >X SPP_ARGS(ifp), cp->name, len); >X return; >X } >X h = mtod (m, struct lcp_header*); >X if (debug) { >X log(LOG_DEBUG, >X SPP_FMT "%s input(%s): <%s id=0x%x len=%d", >X SPP_ARGS(ifp), cp->name, >X sppp_state_name(sp->state[cp->protoidx]), >X sppp_cp_type_name (h->type), h->ident, ntohs (h->len)); >X if (len > 4) >X sppp_print_bytes ((u_char*) (h+1), len-4); >X addlog(">\n"); >X } >X if (len > ntohs (h->len)) >X len = ntohs (h->len); >X p = (u_char *)(h + 1); >X switch (h->type) { >X case CONF_REQ: >X if (len < 4) { >X if (debug) >X addlog(SPP_FMT "%s invalid conf-req length %d\n", >X SPP_ARGS(ifp), cp->name, >X len); >X ++ifp->if_ierrors; >X break; >X } >X /* handle states where RCR doesn't get a SCA/SCN */ >X switch (sp->state[cp->protoidx]) { >X case STATE_CLOSING: >X case STATE_STOPPING: >X return; >X case STATE_CLOSED: >X sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, >X 0, 0); >X return; >X } >X rv = (cp->RCR)(sp, h, len); >X switch (sp->state[cp->protoidx]) { >X case STATE_OPENED: >X (cp->tld)(sp); >X (cp->scr)(sp); >X /* fall through... */ >X case STATE_ACK_SENT: >X case STATE_REQ_SENT: >X sppp_cp_change_state(cp, sp, rv? >X STATE_ACK_SENT: STATE_REQ_SENT); >X break; >X case STATE_STOPPED: >X sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; >X (cp->scr)(sp); >X sppp_cp_change_state(cp, sp, rv? >X STATE_ACK_SENT: STATE_REQ_SENT); >X break; >X case STATE_ACK_RCVD: >X if (rv) { >X sppp_cp_change_state(cp, sp, STATE_OPENED); >X if (debug) >X log(LOG_DEBUG, SPP_FMT "%s tlu\n", >X SPP_ARGS(ifp), >X cp->name); >X (cp->tlu)(sp); >X } else >X sppp_cp_change_state(cp, sp, STATE_ACK_RCVD); >X break; >X default: >X printf(SPP_FMT "%s illegal %s in state %s\n", >X SPP_ARGS(ifp), cp->name, >X sppp_cp_type_name(h->type), >X sppp_state_name(sp->state[cp->protoidx])); >X ++ifp->if_ierrors; >X } >X break; >X case CONF_ACK: >X if (h->ident != sp->confid[cp->protoidx]) { >X if (debug) >X addlog(SPP_FMT "%s id mismatch 0x%x != 0x%x\n", >X SPP_ARGS(ifp), cp->name, >X h->ident, sp->confid[cp->protoidx]); >X ++ifp->if_ierrors; >X break; >X } >X switch (sp->state[cp->protoidx]) { >X case STATE_CLOSED: >X case STATE_STOPPED: >X sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0); >X break; >X case STATE_CLOSING: >X case STATE_STOPPING: >X break; >X case STATE_REQ_SENT: >X sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; >X sppp_cp_change_state(cp, sp, STATE_ACK_RCVD); >X break; >X case STATE_OPENED: >X (cp->tld)(sp); >X /* fall through */ >X case STATE_ACK_RCVD: >X (cp->scr)(sp); >X sppp_cp_change_state(cp, sp, STATE_REQ_SENT); >X break; >X case STATE_ACK_SENT: >X sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; >X sppp_cp_change_state(cp, sp, STATE_OPENED); >X if (debug) >X log(LOG_DEBUG, SPP_FMT "%s tlu\n", >X SPP_ARGS(ifp), cp->name); >X (cp->tlu)(sp); >X break; >X default: >X printf(SPP_FMT "%s illegal %s in state %s\n", >X SPP_ARGS(ifp), cp->name, >X sppp_cp_type_name(h->type), >X sppp_state_name(sp->state[cp->protoidx])); >X ++ifp->if_ierrors; >X } >X break; >X case CONF_NAK: >X case CONF_REJ: >X if (h->ident != sp->confid[cp->protoidx]) { >X if (debug) >X addlog(SPP_FMT "%s id mismatch 0x%x != 0x%x\n", >X SPP_ARGS(ifp), cp->name, >X h->ident, sp->confid[cp->protoidx]); >X ++ifp->if_ierrors; >X break; >X } >X if (h->type == CONF_NAK) >X (cp->RCN_nak)(sp, h, len); >X else /* CONF_REJ */ >X (cp->RCN_rej)(sp, h, len); >X >X switch (sp->state[cp->protoidx]) { >X case STATE_CLOSED: >X case STATE_STOPPED: >X sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0); >X break; >X case STATE_REQ_SENT: >X case STATE_ACK_SENT: >X sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; >X (cp->scr)(sp); >X break; >X case STATE_OPENED: >X (cp->tld)(sp); >X /* fall through */ >X case STATE_ACK_RCVD: >X sppp_cp_change_state(cp, sp, STATE_ACK_SENT); >X (cp->scr)(sp); >X break; >X case STATE_CLOSING: >X case STATE_STOPPING: >X break; >X default: >X printf(SPP_FMT "%s illegal %s in state %s\n", >X SPP_ARGS(ifp), cp->name, >X sppp_cp_type_name(h->type), >X sppp_state_name(sp->state[cp->protoidx])); >X ++ifp->if_ierrors; >X } >X break; >X >X case TERM_REQ: >X switch (sp->state[cp->protoidx]) { >X case STATE_ACK_RCVD: >X case STATE_ACK_SENT: >X sppp_cp_change_state(cp, sp, STATE_REQ_SENT); >X /* fall through */ >X case STATE_CLOSED: >X case STATE_STOPPED: >X case STATE_CLOSING: >X case STATE_STOPPING: >X case STATE_REQ_SENT: >X sta: >X /* Send Terminate-Ack packet. */ >X if (debug) >X log(LOG_DEBUG, SPP_FMT "%s send terminate-ack\n", >X SPP_ARGS(ifp), cp->name); >X sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0); >X break; >X case STATE_OPENED: >X (cp->tld)(sp); >X sp->rst_counter[cp->protoidx] = 0; >X sppp_cp_change_state(cp, sp, STATE_STOPPING); >X goto sta; >X break; >X default: >X printf(SPP_FMT "%s illegal %s in state %s\n", >X SPP_ARGS(ifp), cp->name, >X sppp_cp_type_name(h->type), >X sppp_state_name(sp->state[cp->protoidx])); >X ++ifp->if_ierrors; >X } >X break; >X case TERM_ACK: >X switch (sp->state[cp->protoidx]) { >X case STATE_CLOSED: >X case STATE_STOPPED: >X case STATE_REQ_SENT: >X case STATE_ACK_SENT: >X break; >X case STATE_CLOSING: >X sppp_cp_change_state(cp, sp, STATE_CLOSED); >X (cp->tlf)(sp); >X break; >X case STATE_STOPPING: >X sppp_cp_change_state(cp, sp, STATE_STOPPED); >X (cp->tlf)(sp); >X break; >X case STATE_ACK_RCVD: >X sppp_cp_change_state(cp, sp, STATE_REQ_SENT); >X break; >X case STATE_OPENED: >X (cp->tld)(sp); >X (cp->scr)(sp); >X sppp_cp_change_state(cp, sp, STATE_ACK_RCVD); >X break; >X default: >X printf(SPP_FMT "%s illegal %s in state %s\n", >X SPP_ARGS(ifp), cp->name, >X sppp_cp_type_name(h->type), >X sppp_state_name(sp->state[cp->protoidx])); >X ++ifp->if_ierrors; >X } >X break; >X case CODE_REJ: >X case PROTO_REJ: >X /* XXX catastrophic rejects (RXJ-) aren't handled yet. */ >X log(LOG_INFO, >X SPP_FMT "%s: ignoring RXJ (%s) for proto 0x%x, " >X "danger will robinson\n", >X SPP_ARGS(ifp), cp->name, >X sppp_cp_type_name(h->type), ntohs(*((u_short *)p))); >X switch (sp->state[cp->protoidx]) { >X case STATE_CLOSED: >X case STATE_STOPPED: >X case STATE_REQ_SENT: >X case STATE_ACK_SENT: >X case STATE_CLOSING: >X case STATE_STOPPING: >X case STATE_OPENED: >X break; >X case STATE_ACK_RCVD: >X sppp_cp_change_state(cp, sp, STATE_REQ_SENT); >X break; >X default: >X printf(SPP_FMT "%s illegal %s in state %s\n", >X SPP_ARGS(ifp), cp->name, >X sppp_cp_type_name(h->type), >X sppp_state_name(sp->state[cp->protoidx])); >X ++ifp->if_ierrors; >X } >X break; >X case DISC_REQ: >X if (cp->proto != PPP_LCP) >X goto illegal; >X /* Discard the packet. */ >X break; >X case ECHO_REQ: >X if (cp->proto != PPP_LCP) >X goto illegal; >X if (sp->state[cp->protoidx] != STATE_OPENED) { >X if (debug) >X addlog(SPP_FMT "lcp echo req but lcp closed\n", >X SPP_ARGS(ifp)); >X ++ifp->if_ierrors; >X break; >X } >X if (len < 8) { >X if (debug) >X addlog(SPP_FMT "invalid lcp echo request " >X "packet length: %d bytes\n", >X SPP_ARGS(ifp), len); >X break; >X } >X if (ntohl (*(long*)(h+1)) == sp->lcp.magic) { >X /* Line loopback mode detected. */ >X printf(SPP_FMT "loopback\n", SPP_ARGS(ifp)); >X if_down (ifp); >X sppp_qflush (&sp->pp_cpq); >X >X /* Shut down the PPP link. */ >X /* XXX */ >X lcp.Down(sp); >X lcp.Up(sp); >X break; >X } >X *(long*)(h+1) = htonl (sp->lcp.magic); >X if (debug) >X addlog(SPP_FMT "got lcp echo req, sending echo rep\n", >X SPP_ARGS(ifp)); >X sppp_cp_send (sp, PPP_LCP, ECHO_REPLY, h->ident, len-4, h+1); >X break; >X case ECHO_REPLY: >X if (cp->proto != PPP_LCP) >X goto illegal; >X if (h->ident != sp->lcp.echoid) { >X ++ifp->if_ierrors; >X break; >X } >X if (len < 8) { >X if (debug) >X addlog(SPP_FMT "lcp invalid echo reply " >X "packet length: %d bytes\n", >X SPP_ARGS(ifp), len); >X break; >X } >X if (debug) >X addlog(SPP_FMT "lcp got echo rep\n", >X SPP_ARGS(ifp)); >X if (ntohl (*(long*)(h+1)) != sp->lcp.magic) >X sp->pp_alivecnt = 0; >X break; >X default: >X /* Unknown packet type -- send Code-Reject packet. */ >X illegal: >X if (debug) >X addlog(SPP_FMT "%s send code-rej for 0x%x\n", >X SPP_ARGS(ifp), cp->name, h->type); >X sppp_cp_send(sp, cp->proto, CODE_REJ, ++sp->pp_seq, >X m->m_pkthdr.len, h); >X ++ifp->if_ierrors; >X } >X} >X >X >X/* >X * The generic part of all Up/Down/Open/Close/TO event handlers. >X * Basically, the state transition handling in the automaton. >X */ >Xstatic void >Xsppp_up_event(const struct cp *cp, struct sppp *sp) >X{ >X STDDCL; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "%s up(%s)\n", >X SPP_ARGS(ifp), cp->name, >X sppp_state_name(sp->state[cp->protoidx])); >X >X switch (sp->state[cp->protoidx]) { >X case STATE_INITIAL: >X sppp_cp_change_state(cp, sp, STATE_CLOSED); >X break; >X case STATE_STARTING: >X sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; >X (cp->scr)(sp); >X sppp_cp_change_state(cp, sp, STATE_REQ_SENT); >X break; >X default: >X printf(SPP_FMT "%s illegal up in state %s\n", >X SPP_ARGS(ifp), cp->name, >X sppp_state_name(sp->state[cp->protoidx])); >X } >X} >X >Xstatic void >Xsppp_down_event(const struct cp *cp, struct sppp *sp) >X{ >X STDDCL; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "%s down(%s)\n", >X SPP_ARGS(ifp), cp->name, >X sppp_state_name(sp->state[cp->protoidx])); >X >X switch (sp->state[cp->protoidx]) { >X case STATE_CLOSED: >X case STATE_CLOSING: >X sppp_cp_change_state(cp, sp, STATE_INITIAL); >X break; >X case STATE_STOPPED: >X sppp_cp_change_state(cp, sp, STATE_STARTING); >X (cp->tls)(sp); >X break; >X case STATE_STOPPING: >X case STATE_REQ_SENT: >X case STATE_ACK_RCVD: >X case STATE_ACK_SENT: >X sppp_cp_change_state(cp, sp, STATE_STARTING); >X break; >X case STATE_OPENED: >X (cp->tld)(sp); >X sppp_cp_change_state(cp, sp, STATE_STARTING); >X break; >X default: >X printf(SPP_FMT "%s illegal down in state %s\n", >X SPP_ARGS(ifp), cp->name, >X sppp_state_name(sp->state[cp->protoidx])); >X } >X} >X >X >Xstatic void >Xsppp_open_event(const struct cp *cp, struct sppp *sp) >X{ >X STDDCL; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "%s open(%s)\n", >X SPP_ARGS(ifp), cp->name, >X sppp_state_name(sp->state[cp->protoidx])); >X >X switch (sp->state[cp->protoidx]) { >X case STATE_INITIAL: >X sppp_cp_change_state(cp, sp, STATE_STARTING); >X (cp->tls)(sp); >X break; >X case STATE_STARTING: >X break; >X case STATE_CLOSED: >X sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; >X (cp->scr)(sp); >X sppp_cp_change_state(cp, sp, STATE_REQ_SENT); >X break; >X case STATE_STOPPED: >X case STATE_STOPPING: >X case STATE_REQ_SENT: >X case STATE_ACK_RCVD: >X case STATE_ACK_SENT: >X case STATE_OPENED: >X break; >X case STATE_CLOSING: >X sppp_cp_change_state(cp, sp, STATE_STOPPING); >X break; >X } >X} >X >X >Xstatic void >Xsppp_close_event(const struct cp *cp, struct sppp *sp) >X{ >X STDDCL; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "%s close(%s)\n", >X SPP_ARGS(ifp), cp->name, >X sppp_state_name(sp->state[cp->protoidx])); >X >X switch (sp->state[cp->protoidx]) { >X case STATE_INITIAL: >X case STATE_CLOSED: >X case STATE_CLOSING: >X break; >X case STATE_STARTING: >X sppp_cp_change_state(cp, sp, STATE_INITIAL); >X (cp->tlf)(sp); >X break; >X case STATE_STOPPED: >X sppp_cp_change_state(cp, sp, STATE_CLOSED); >X break; >X case STATE_STOPPING: >X sppp_cp_change_state(cp, sp, STATE_CLOSING); >X break; >X case STATE_OPENED: >X (cp->tld)(sp); >X /* fall through */ >X case STATE_REQ_SENT: >X case STATE_ACK_RCVD: >X case STATE_ACK_SENT: >X sp->rst_counter[cp->protoidx] = sp->lcp.max_terminate; >X sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq, 0, 0); >X sppp_cp_change_state(cp, sp, STATE_CLOSING); >X break; >X } >X} >X >Xstatic void >Xsppp_to_event(const struct cp *cp, struct sppp *sp) >X{ >X STDDCL; >X int s; >X >X s = splimp(); >X if (debug) >X log(LOG_DEBUG, SPP_FMT "%s TO(%s) rst_counter = %d\n", >X SPP_ARGS(ifp), cp->name, >X sppp_state_name(sp->state[cp->protoidx]), >X sp->rst_counter[cp->protoidx]); >X >X if (--sp->rst_counter[cp->protoidx] < 0) >X /* TO- event */ >X switch (sp->state[cp->protoidx]) { >X case STATE_CLOSING: >X sppp_cp_change_state(cp, sp, STATE_CLOSED); >X (cp->tlf)(sp); >X break; >X case STATE_STOPPING: >X sppp_cp_change_state(cp, sp, STATE_STOPPED); >X (cp->tlf)(sp); >X break; >X case STATE_REQ_SENT: >X case STATE_ACK_RCVD: >X case STATE_ACK_SENT: >X sppp_cp_change_state(cp, sp, STATE_STOPPED); >X (cp->tlf)(sp); >X break; >X } >X else >X /* TO+ event */ >X switch (sp->state[cp->protoidx]) { >X case STATE_CLOSING: >X case STATE_STOPPING: >X sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq, >X 0, 0); >X TIMEOUT(cp->TO, (void *)sp, sp->lcp.timeout, >X sp->ch[cp->protoidx]); >X break; >X case STATE_REQ_SENT: >X case STATE_ACK_RCVD: >X (cp->scr)(sp); >X /* sppp_cp_change_state() will restart the timer */ >X sppp_cp_change_state(cp, sp, STATE_REQ_SENT); >X break; >X case STATE_ACK_SENT: >X (cp->scr)(sp); >X TIMEOUT(cp->TO, (void *)sp, sp->lcp.timeout, >X sp->ch[cp->protoidx]); >X break; >X } >X >X splx(s); >X} >X >X/* >X * Change the state of a control protocol in the state automaton. >X * Takes care of starting/stopping the restart timer. >X */ >Xvoid >Xsppp_cp_change_state(const struct cp *cp, struct sppp *sp, int newstate) >X{ >X sp->state[cp->protoidx] = newstate; >X >X UNTIMEOUT(cp->TO, (void *)sp, sp->ch[cp->protoidx]); >X switch (newstate) { >X case STATE_INITIAL: >X case STATE_STARTING: >X case STATE_CLOSED: >X case STATE_STOPPED: >X case STATE_OPENED: >X break; >X case STATE_CLOSING: >X case STATE_STOPPING: >X case STATE_REQ_SENT: >X case STATE_ACK_RCVD: >X case STATE_ACK_SENT: >X TIMEOUT(cp->TO, (void *)sp, sp->lcp.timeout, >X sp->ch[cp->protoidx]); >X break; >X } >X} >X/* >X *--------------------------------------------------------------------------* >X * * >X * The LCP implementation. * >X * * >X *--------------------------------------------------------------------------* >X */ >Xstatic void >Xsppp_lcp_init(struct sppp *sp) >X{ >X sp->lcp.opts = (1 << LCP_OPT_MAGIC); >X sp->lcp.magic = 0; >X sp->state[IDX_LCP] = STATE_INITIAL; >X sp->fail_counter[IDX_LCP] = 0; >X sp->lcp.protos = 0; >X sp->lcp.mru = sp->lcp.their_mru = PP_MTU; >X >X /* >X * Initialize counters and timeout values. Note that we don't >X * use the 3 seconds suggested in RFC 1661 since we are likely >X * running on a fast link. XXX We should probably implement >X * the exponential backoff option. Note that these values are >X * relevant for all control protocols, not just LCP only. >X */ >X sp->lcp.timeout = 1 * hz; >X sp->lcp.max_terminate = 2; >X sp->lcp.max_configure = 10; >X sp->lcp.max_failure = 10; >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X callout_handle_init(&sp->ch[IDX_LCP]); >X#endif >X} >X >Xstatic void >Xsppp_lcp_up(struct sppp *sp) >X{ >X STDDCL; >X >X /* >X * If this interface is passive or dial-on-demand, and we are >X * still in Initial state, it means we've got an incoming >X * call. Activate the interface. >X */ >X if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) != 0) { >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "Up event", SPP_ARGS(ifp)); >X ifp->if_flags |= IFF_RUNNING; >X if (sp->state[IDX_LCP] == STATE_INITIAL) { >X if (debug) >X addlog("(incoming call)\n"); >X sp->pp_flags |= PP_CALLIN; >X lcp.Open(sp); >X } else if (debug) >X addlog("\n"); >X } >X >X sppp_up_event(&lcp, sp); >X} >X >Xstatic void >Xsppp_lcp_down(struct sppp *sp) >X{ >X STDDCL; >X >X sppp_down_event(&lcp, sp); >X >X /* >X * If this is neither a dial-on-demand nor a passive >X * interface, simulate an ``ifconfig down'' action, so the >X * administrator can force a redial by another ``ifconfig >X * up''. XXX For leased line operation, should we immediately >X * try to reopen the connection here? >X */ >X if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) == 0) { >X log(LOG_INFO, >X SPP_FMT "Down event, taking interface down.\n", >X SPP_ARGS(ifp)); >X if_down(ifp); >X } else { >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "Down event (carrier loss)\n", >X SPP_ARGS(ifp)); >X } >X sp->pp_flags &= ~PP_CALLIN; >X if (sp->state[IDX_LCP] != STATE_INITIAL) >X lcp.Close(sp); >X ifp->if_flags &= ~IFF_RUNNING; >X} >X >Xstatic void >Xsppp_lcp_open(struct sppp *sp) >X{ >X /* >X * If we are authenticator, negotiate LCP_AUTH >X */ >X if (sp->hisauth.proto != 0) >X sp->lcp.opts |= (1 << LCP_OPT_AUTH_PROTO); >X else >X sp->lcp.opts &= ~(1 << LCP_OPT_AUTH_PROTO); >X sp->pp_flags &= ~PP_NEEDAUTH; >X sppp_open_event(&lcp, sp); >X} >X >Xstatic void >Xsppp_lcp_close(struct sppp *sp) >X{ >X sppp_close_event(&lcp, sp); >X} >X >Xstatic void >Xsppp_lcp_TO(void *cookie) >X{ >X sppp_to_event(&lcp, (struct sppp *)cookie); >X} >X >X/* >X * Analyze a configure request. Return true if it was agreeable, and >X * caused action sca, false if it has been rejected or nak'ed, and >X * caused action scn. (The return value is used to make the state >X * transition decision in the state automaton.) >X */ >Xstatic int >Xsppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len) >X{ >X STDDCL; >X u_char *buf, *r, *p; >X int origlen, rlen; >X u_long nmagic; >X u_short authproto; >X >X len -= 4; >X origlen = len; >X buf = r = malloc (len, M_TEMP, M_NOWAIT); >X if (! buf) >X return (0); >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "lcp parse opts: ", >X SPP_ARGS(ifp)); >X >X /* pass 1: check for things that need to be rejected */ >X p = (void*) (h+1); >X for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { >X if (debug) >X addlog(" %s ", sppp_lcp_opt_name(*p)); >X switch (*p) { >X case LCP_OPT_MAGIC: >X /* Magic number. */ >X /* fall through, both are same length */ >X case LCP_OPT_ASYNC_MAP: >X /* Async control character map. */ >X if (len >= 6 || p[1] == 6) >X continue; >X if (debug) >X addlog("[invalid] "); >X break; >X case LCP_OPT_MRU: >X /* Maximum receive unit. */ >X if (len >= 4 && p[1] == 4) >X continue; >X if (debug) >X addlog("[invalid] "); >X break; >X case LCP_OPT_AUTH_PROTO: >X if (len < 4) { >X if (debug) >X addlog("[invalid] "); >X break; >X } >X authproto = (p[2] << 8) + p[3]; >X if (authproto == PPP_CHAP && p[1] != 5) { >X if (debug) >X addlog("[invalid chap len] "); >X break; >X } >X if (sp->myauth.proto == 0) { >X /* we are not configured to do auth */ >X if (debug) >X addlog("[not configured] "); >X break; >X } >X /* >X * Remote want us to authenticate, remember this, >X * so we stay in PHASE_AUTHENTICATE after LCP got >X * up. >X */ >X sp->pp_flags |= PP_NEEDAUTH; >X continue; >X default: >X /* Others not supported. */ >X if (debug) >X addlog("[rej] "); >X break; >X } >X /* Add the option to rejected list. */ >X bcopy (p, r, p[1]); >X r += p[1]; >X rlen += p[1]; >X } >X if (rlen) { >X if (debug) >X addlog(" send conf-rej\n"); >X sppp_cp_send (sp, PPP_LCP, CONF_REJ, h->ident, rlen, buf); >X return 0; >X } else if (debug) >X addlog("\n"); >X >X /* >X * pass 2: check for option values that are unacceptable and >X * thus require to be nak'ed. >X */ >X if (debug) >X log(LOG_DEBUG, SPP_FMT "lcp parse opt values: ", >X SPP_ARGS(ifp)); >X >X p = (void*) (h+1); >X len = origlen; >X for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { >X if (debug) >X addlog(" %s ", sppp_lcp_opt_name(*p)); >X switch (*p) { >X case LCP_OPT_MAGIC: >X /* Magic number -- extract. */ >X nmagic = (u_long)p[2] << 24 | >X (u_long)p[3] << 16 | p[4] << 8 | p[5]; >X if (nmagic != sp->lcp.magic) { >X if (debug) >X addlog("0x%lx ", nmagic); >X continue; >X } >X /* >X * Local and remote magics equal -- loopback? >X */ >X if (sp->pp_loopcnt >= MAXALIVECNT*5) { >X printf (SPP_FMT "loopback\n", >X SPP_ARGS(ifp)); >X sp->pp_loopcnt = 0; >X if (ifp->if_flags & IFF_UP) { >X if_down(ifp); >X sppp_qflush(&sp->pp_cpq); >X /* XXX ? */ >X lcp.Down(sp); >X lcp.Up(sp); >X } >X } else if (debug) >X addlog("[glitch] "); >X ++sp->pp_loopcnt; >X /* >X * We negate our magic here, and NAK it. If >X * we see it later in an NAK packet, we >X * suggest a new one. >X */ >X nmagic = ~sp->lcp.magic; >X /* Gonna NAK it. */ >X p[2] = nmagic >> 24; >X p[3] = nmagic >> 16; >X p[4] = nmagic >> 8; >X p[5] = nmagic; >X break; >X >X case LCP_OPT_ASYNC_MAP: >X /* Async control character map -- check to be zero. */ >X if (! p[2] && ! p[3] && ! p[4] && ! p[5]) { >X if (debug) >X addlog("[empty] "); >X continue; >X } >X if (debug) >X addlog("[non-empty] "); >X /* suggest a zero one */ >X p[2] = p[3] = p[4] = p[5] = 0; >X break; >X >X case LCP_OPT_MRU: >X /* >X * Maximum receive unit. Always agreeable, >X * but ignored by now. >X */ >X sp->lcp.their_mru = p[2] * 256 + p[3]; >X if (debug) >X addlog("%lu ", sp->lcp.their_mru); >X continue; >X >X case LCP_OPT_AUTH_PROTO: >X authproto = (p[2] << 8) + p[3]; >X if (sp->myauth.proto != authproto) { >X /* not agreed, nak */ >X if (debug) >X addlog("[mine %s != his %s] ", >X sppp_proto_name(sp->hisauth.proto), >X sppp_proto_name(authproto)); >X p[2] = sp->myauth.proto >> 8; >X p[3] = sp->myauth.proto; >X break; >X } >X if (authproto == PPP_CHAP && p[4] != CHAP_MD5) { >X if (debug) >X addlog("[chap not MD5] "); >X p[4] = CHAP_MD5; >X break; >X } >X continue; >X } >X /* Add the option to nak'ed list. */ >X bcopy (p, r, p[1]); >X r += p[1]; >X rlen += p[1]; >X } >X if (rlen) { >X if (++sp->fail_counter[IDX_LCP] >= sp->lcp.max_failure) { >X if (debug) >X addlog(" max_failure (%d) exceeded, " >X "send conf-rej\n", >X sp->lcp.max_failure); >X sppp_cp_send(sp, PPP_LCP, CONF_REJ, h->ident, rlen, buf); >X } else { >X if (debug) >X addlog(" send conf-nak\n"); >X sppp_cp_send (sp, PPP_LCP, CONF_NAK, h->ident, rlen, buf); >X } >X return 0; >X } else { >X if (debug) >X addlog(" send conf-ack\n"); >X sp->fail_counter[IDX_LCP] = 0; >X sp->pp_loopcnt = 0; >X sppp_cp_send (sp, PPP_LCP, CONF_ACK, >X h->ident, origlen, h+1); >X } >X >X free (buf, M_TEMP); >X return (rlen == 0); >X} >X >X/* >X * Analyze the LCP Configure-Reject option list, and adjust our >X * negotiation. >X */ >Xstatic void >Xsppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len) >X{ >X STDDCL; >X u_char *buf, *p; >X >X len -= 4; >X buf = malloc (len, M_TEMP, M_NOWAIT); >X if (!buf) >X return; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "lcp rej opts: ", >X SPP_ARGS(ifp)); >X >X p = (void*) (h+1); >X for (; len > 1 && p[1]; len -= p[1], p += p[1]) { >X if (debug) >X addlog(" %s ", sppp_lcp_opt_name(*p)); >X switch (*p) { >X case LCP_OPT_MAGIC: >X /* Magic number -- can't use it, use 0 */ >X sp->lcp.opts &= ~(1 << LCP_OPT_MAGIC); >X sp->lcp.magic = 0; >X break; >X case LCP_OPT_MRU: >X /* >X * Should not be rejected anyway, since we only >X * negotiate a MRU if explicitly requested by >X * peer. >X */ >X sp->lcp.opts &= ~(1 << LCP_OPT_MRU); >X break; >X case LCP_OPT_AUTH_PROTO: >X /* >X * Peer doesn't want to authenticate himself, >X * deny unless this is a dialout call, and >X * AUTHFLAG_NOCALLOUT is set. >X */ >X if ((sp->pp_flags & PP_CALLIN) == 0 && >X (sp->hisauth.flags & AUTHFLAG_NOCALLOUT) != 0) { >X if (debug) >X addlog("[don't insist on auth " >X "for callout]"); >X sp->lcp.opts &= ~(1 << LCP_OPT_AUTH_PROTO); >X break; >X } >X if (debug) >X addlog("[access denied]\n"); >X lcp.Close(sp); >X break; >X } >X } >X if (debug) >X addlog("\n"); >X free (buf, M_TEMP); >X return; >X} >X >X/* >X * Analyze the LCP Configure-NAK option list, and adjust our >X * negotiation. >X */ >Xstatic void >Xsppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len) >X{ >X STDDCL; >X u_char *buf, *p; >X u_long magic; >X >X len -= 4; >X buf = malloc (len, M_TEMP, M_NOWAIT); >X if (!buf) >X return; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "lcp nak opts: ", >X SPP_ARGS(ifp)); >X >X p = (void*) (h+1); >X for (; len > 1 && p[1]; len -= p[1], p += p[1]) { >X if (debug) >X addlog(" %s ", sppp_lcp_opt_name(*p)); >X switch (*p) { >X case LCP_OPT_MAGIC: >X /* Magic number -- renegotiate */ >X if ((sp->lcp.opts & (1 << LCP_OPT_MAGIC)) && >X len >= 6 && p[1] == 6) { >X magic = (u_long)p[2] << 24 | >X (u_long)p[3] << 16 | p[4] << 8 | p[5]; >X /* >X * If the remote magic is our negated one, >X * this looks like a loopback problem. >X * Suggest a new magic to make sure. >X */ >X if (magic == ~sp->lcp.magic) { >X if (debug) >X addlog("magic glitch "); >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X sp->lcp.magic = random(); >X#else >X sp->lcp.magic = time.tv_sec + time.tv_usec; >X#endif >X } else { >X sp->lcp.magic = magic; >X if (debug) >X addlog("%lu ", magic); >X } >X } >X break; >X case LCP_OPT_MRU: >X /* >X * Peer wants to advise us to negotiate an MRU. >X * Agree on it if it's reasonable, or use >X * default otherwise. >X */ >X if (len >= 4 && p[1] == 4) { >X u_int mru = p[2] * 256 + p[3]; >X if (debug) >X addlog("%d ", mru); >X if (mru < PP_MTU || mru > PP_MAX_MRU) >X mru = PP_MTU; >X sp->lcp.mru = mru; >X sp->lcp.opts |= (1 << LCP_OPT_MRU); >X } >X break; >X case LCP_OPT_AUTH_PROTO: >X /* >X * Peer doesn't like our authentication method, >X * deny. >X */ >X if (debug) >X addlog("[access denied]\n"); >X lcp.Close(sp); >X break; >X } >X } >X if (debug) >X addlog("\n"); >X free (buf, M_TEMP); >X return; >X} >X >Xstatic void >Xsppp_lcp_tlu(struct sppp *sp) >X{ >X STDDCL; >X int i; >X u_long mask; >X >X /* XXX ? */ >X if (! (ifp->if_flags & IFF_UP) && >X (ifp->if_flags & IFF_RUNNING)) { >X /* Coming out of loopback mode. */ >X if_up(ifp); >X printf (SPP_FMT "up\n", SPP_ARGS(ifp)); >X } >X >X for (i = 0; i < IDX_COUNT; i++) >X if ((cps[i])->flags & CP_QUAL) >X (cps[i])->Open(sp); >X >X if ((sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) != 0 || >X (sp->pp_flags & PP_NEEDAUTH) != 0) >X sp->pp_phase = PHASE_AUTHENTICATE; >X else >X sp->pp_phase = PHASE_NETWORK; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "phase %s\n", SPP_ARGS(ifp), >X sppp_phase_name(sp->pp_phase)); >X >X /* >X * Open all authentication protocols. This is even required >X * if we already proceeded to network phase, since it might be >X * that remote wants us to authenticate, so we might have to >X * send a PAP request. Undesired authentication protocols >X * don't do anything when they get an Open event. >X */ >X for (i = 0; i < IDX_COUNT; i++) >X if ((cps[i])->flags & CP_AUTH) >X (cps[i])->Open(sp); >X >X if (sp->pp_phase == PHASE_NETWORK) { >X /* Notify all NCPs. */ >X for (i = 0; i < IDX_COUNT; i++) >X if ((cps[i])->flags & CP_NCP) >X (cps[i])->Open(sp); >X } >X >X /* Send Up events to all started protos. */ >X for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1) >X if (sp->lcp.protos & mask && ((cps[i])->flags & CP_LCP) == 0) >X (cps[i])->Up(sp); >X >X /* notify low-level driver of state change */ >X if (sp->pp_chg) >X sp->pp_chg(sp, (int)sp->pp_phase); >X >X if (sp->pp_phase == PHASE_NETWORK) >X /* if no NCP is starting, close down */ >X sppp_lcp_check_and_close(sp); >X} >X >Xstatic void >Xsppp_lcp_tld(struct sppp *sp) >X{ >X STDDCL; >X int i; >X u_long mask; >X >X sp->pp_phase = PHASE_TERMINATE; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "phase %s\n", SPP_ARGS(ifp), >X sppp_phase_name(sp->pp_phase)); >X >X /* >X * Take upper layers down. We send the Down event first and >X * the Close second to prevent the upper layers from sending >X * ``a flurry of terminate-request packets'', as the RFC >X * describes it. >X */ >X for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1) >X if (sp->lcp.protos & mask && ((cps[i])->flags & CP_LCP) == 0) { >X (cps[i])->Down(sp); >X (cps[i])->Close(sp); >X } >X} >X >Xstatic void >Xsppp_lcp_tls(struct sppp *sp) >X{ >X STDDCL; >X >X sp->pp_phase = PHASE_ESTABLISH; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "phase %s\n", SPP_ARGS(ifp), >X sppp_phase_name(sp->pp_phase)); >X >X /* Notify lower layer if desired. */ >X if (sp->pp_tls) >X (sp->pp_tls)(sp); >X else >X (sp->pp_up)(sp); >X} >X >Xstatic void >Xsppp_lcp_tlf(struct sppp *sp) >X{ >X STDDCL; >X >X sp->pp_phase = PHASE_DEAD; >X if (debug) >X log(LOG_DEBUG, SPP_FMT "phase %s\n", SPP_ARGS(ifp), >X sppp_phase_name(sp->pp_phase)); >X >X /* Notify lower layer if desired. */ >X if (sp->pp_tlf) >X (sp->pp_tlf)(sp); >X else >X (sp->pp_down)(sp); >X} >X >Xstatic void >Xsppp_lcp_scr(struct sppp *sp) >X{ >X char opt[6 /* magicnum */ + 4 /* mru */ + 5 /* chap */]; >X int i = 0; >X u_short authproto; >X >X if (sp->lcp.opts & (1 << LCP_OPT_MAGIC)) { >X if (! sp->lcp.magic) >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X sp->lcp.magic = random(); >X#else >X sp->lcp.magic = time.tv_sec + time.tv_usec; >X#endif >X opt[i++] = LCP_OPT_MAGIC; >X opt[i++] = 6; >X opt[i++] = sp->lcp.magic >> 24; >X opt[i++] = sp->lcp.magic >> 16; >X opt[i++] = sp->lcp.magic >> 8; >X opt[i++] = sp->lcp.magic; >X } >X >X if (sp->lcp.opts & (1 << LCP_OPT_MRU)) { >X opt[i++] = LCP_OPT_MRU; >X opt[i++] = 4; >X opt[i++] = sp->lcp.mru >> 8; >X opt[i++] = sp->lcp.mru; >X } >X >X if (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) { >X authproto = sp->hisauth.proto; >X opt[i++] = LCP_OPT_AUTH_PROTO; >X opt[i++] = authproto == PPP_CHAP? 5: 4; >X opt[i++] = authproto >> 8; >X opt[i++] = authproto; >X if (authproto == PPP_CHAP) >X opt[i++] = CHAP_MD5; >X } >X >X sp->confid[IDX_LCP] = ++sp->pp_seq; >X sppp_cp_send (sp, PPP_LCP, CONF_REQ, sp->confid[IDX_LCP], i, &opt); >X} >X >X/* >X * Check the open NCPs, return true if at least one NCP is open. >X */ >Xstatic int >Xsppp_ncp_check(struct sppp *sp) >X{ >X int i, mask; >X >X for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1) >X if (sp->lcp.protos & mask && (cps[i])->flags & CP_NCP) >X return 1; >X return 0; >X} >X >X/* >X * Re-check the open NCPs and see if we should terminate the link. >X * Called by the NCPs during their tlf action handling. >X */ >Xstatic void >Xsppp_lcp_check_and_close(struct sppp *sp) >X{ >X >X if (sp->pp_phase < PHASE_NETWORK) >X /* don't bother, we are already going down */ >X return; >X >X if (sppp_ncp_check(sp)) >X return; >X >X lcp.Close(sp); >X} >X/* >X *--------------------------------------------------------------------------* >X * * >X * The IPCP implementation. * >X * * >X *--------------------------------------------------------------------------* >X */ >X >Xstatic void >Xsppp_ipcp_init(struct sppp *sp) >X{ >X sp->ipcp.opts = 0; >X sp->ipcp.flags = 0; >X sp->state[IDX_IPCP] = STATE_INITIAL; >X sp->fail_counter[IDX_IPCP] = 0; >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X callout_handle_init(&sp->ch[IDX_IPCP]); >X#endif >X} >X >Xstatic void >Xsppp_ipcp_up(struct sppp *sp) >X{ >X sppp_up_event(&ipcp, sp); >X} >X >Xstatic void >Xsppp_ipcp_down(struct sppp *sp) >X{ >X sppp_down_event(&ipcp, sp); >X} >X >Xstatic void >Xsppp_ipcp_open(struct sppp *sp) >X{ >X STDDCL; >X u_long myaddr, hisaddr; >X >X sp->ipcp.flags &= ~(IPCP_HISADDR_SEEN|IPCP_MYADDR_SEEN|IPCP_MYADDR_DYN); >X >X sppp_get_ip_addrs(sp, &myaddr, &hisaddr, 0); >X /* >X * If we don't have his address, this probably means our >X * interface doesn't want to talk IP at all. (This could >X * be the case if somebody wants to speak only IPX, for >X * example.) Don't open IPCP in this case. >X */ >X if (hisaddr == 0L) { >X /* XXX this message should go away */ >X if (debug) >X log(LOG_DEBUG, SPP_FMT "ipcp_open(): no IP interface\n", >X SPP_ARGS(ifp)); >X return; >X } >X >X if (myaddr == 0L) { >X /* >X * I don't have an assigned address, so i need to >X * negotiate my address. >X */ >X sp->ipcp.flags |= IPCP_MYADDR_DYN; >X sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS); >X } else >X sp->ipcp.flags |= IPCP_MYADDR_SEEN; >X sppp_open_event(&ipcp, sp); >X} >X >Xstatic void >Xsppp_ipcp_close(struct sppp *sp) >X{ >X sppp_close_event(&ipcp, sp); >X if (sp->ipcp.flags & IPCP_MYADDR_DYN) >X /* >X * My address was dynamic, clear it again. >X */ >X sppp_set_ip_addr(sp, 0L); >X} >X >Xstatic void >Xsppp_ipcp_TO(void *cookie) >X{ >X sppp_to_event(&ipcp, (struct sppp *)cookie); >X} >X >X/* >X * Analyze a configure request. Return true if it was agreeable, and >X * caused action sca, false if it has been rejected or nak'ed, and >X * caused action scn. (The return value is used to make the state >X * transition decision in the state automaton.) >X */ >Xstatic int >Xsppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len) >X{ >X u_char *buf, *r, *p; >X struct ifnet *ifp = &sp->pp_if; >X int rlen, origlen, debug = ifp->if_flags & IFF_DEBUG; >X u_long hisaddr, desiredaddr; >X int gotmyaddr = 0; >X >X len -= 4; >X origlen = len; >X /* >X * Make sure to allocate a buf that can at least hold a >X * conf-nak with an `address' option. We might need it below. >X */ >X buf = r = malloc ((len < 6? 6: len), M_TEMP, M_NOWAIT); >X if (! buf) >X return (0); >X >X /* pass 1: see if we can recognize them */ >X if (debug) >X log(LOG_DEBUG, SPP_FMT "ipcp parse opts: ", >X SPP_ARGS(ifp)); >X p = (void*) (h+1); >X for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { >X if (debug) >X addlog(" %s ", sppp_ipcp_opt_name(*p)); >X switch (*p) { >X#ifdef notyet >X case IPCP_OPT_COMPRESSION: >X if (len >= 6 && p[1] >= 6) { >X /* correctly formed compress option */ >X continue; >X } >X if (debug) >X addlog("[invalid] "); >X break; >X#endif >X case IPCP_OPT_ADDRESS: >X if (len >= 6 && p[1] == 6) { >X /* correctly formed address option */ >X continue; >X } >X if (debug) >X addlog("[invalid] "); >X break; >X default: >X /* Others not supported. */ >X if (debug) >X addlog("[rej] "); >X break; >X } >X /* Add the option to rejected list. */ >X bcopy (p, r, p[1]); >X r += p[1]; >X rlen += p[1]; >X } >X if (rlen) { >X if (debug) >X addlog(" send conf-rej\n"); >X sppp_cp_send (sp, PPP_IPCP, CONF_REJ, h->ident, rlen, buf); >X return 0; >X } else if (debug) >X addlog("\n"); >X >X /* pass 2: parse option values */ >X sppp_get_ip_addrs(sp, 0, &hisaddr, 0); >X if (debug) >X log(LOG_DEBUG, SPP_FMT "ipcp parse opt values: ", >X SPP_ARGS(ifp)); >X p = (void*) (h+1); >X len = origlen; >X for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { >X if (debug) >X addlog(" %s ", sppp_ipcp_opt_name(*p)); >X switch (*p) { >X#ifdef notyet >X case IPCP_OPT_COMPRESSION: >X continue; >X#endif >X case IPCP_OPT_ADDRESS: >X /* This is the address he wants in his end */ >X desiredaddr = p[2] << 24 | p[3] << 16 | >X p[4] << 8 | p[5]; >X if (desiredaddr == hisaddr || >X (hisaddr == 1 && desiredaddr != 0)) { >X /* >X * Peer's address is same as our value, >X * or we have set it to 0.0.0.1 to >X * indicate that we do not really care, >X * this is agreeable. Gonna conf-ack >X * it. >X */ >X if (debug) >X addlog("%s [ack] ", >X sppp_dotted_quad(hisaddr)); >X /* record that we've seen it already */ >X sp->ipcp.flags |= IPCP_HISADDR_SEEN; >X continue; >X } >X /* >X * The address wasn't agreeable. This is either >X * he sent us 0.0.0.0, asking to assign him an >X * address, or he send us another address not >X * matching our value. Either case, we gonna >X * conf-nak it with our value. >X * XXX: we should "rej" if hisaddr == 0 >X */ >X if (debug) { >X if (desiredaddr == 0) >X addlog("[addr requested] "); >X else >X addlog("%s [not agreed] ", >X sppp_dotted_quad(desiredaddr)); >X >X p[2] = hisaddr >> 24; >X p[3] = hisaddr >> 16; >X p[4] = hisaddr >> 8; >X p[5] = hisaddr; >X } >X break; >X } >X /* Add the option to nak'ed list. */ >X bcopy (p, r, p[1]); >X r += p[1]; >X rlen += p[1]; >X } >X >X /* >X * If we are about to conf-ack the request, but haven't seen >X * his address so far, gonna conf-nak it instead, with the >X * `address' option present and our idea of his address being >X * filled in there, to request negotiation of both addresses. >X * >X * XXX This can result in an endless req - nak loop if peer >X * doesn't want to send us his address. Q: What should we do >X * about it? XXX A: implement the max-failure counter. >X */ >X if (rlen == 0 && !(sp->ipcp.flags & IPCP_HISADDR_SEEN) && !gotmyaddr) { >X buf[0] = IPCP_OPT_ADDRESS; >X buf[1] = 6; >X buf[2] = hisaddr >> 24; >X buf[3] = hisaddr >> 16; >X buf[4] = hisaddr >> 8; >X buf[5] = hisaddr; >X rlen = 6; >X if (debug) >X addlog("still need hisaddr "); >X } >X >X if (rlen) { >X if (debug) >X addlog(" send conf-nak\n"); >X sppp_cp_send (sp, PPP_IPCP, CONF_NAK, h->ident, rlen, buf); >X } else { >X if (debug) >X addlog(" send conf-ack\n"); >X sppp_cp_send (sp, PPP_IPCP, CONF_ACK, >X h->ident, origlen, h+1); >X } >X >X free (buf, M_TEMP); >X return (rlen == 0); >X} >X >X/* >X * Analyze the IPCP Configure-Reject option list, and adjust our >X * negotiation. >X */ >Xstatic void >Xsppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len) >X{ >X u_char *buf, *p; >X struct ifnet *ifp = &sp->pp_if; >X int debug = ifp->if_flags & IFF_DEBUG; >X >X len -= 4; >X buf = malloc (len, M_TEMP, M_NOWAIT); >X if (!buf) >X return; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "ipcp rej opts: ", >X SPP_ARGS(ifp)); >X >X p = (void*) (h+1); >X for (; len > 1 && p[1]; len -= p[1], p += p[1]) { >X if (debug) >X addlog(" %s ", sppp_ipcp_opt_name(*p)); >X switch (*p) { >X case IPCP_OPT_ADDRESS: >X /* >X * Peer doesn't grok address option. This is >X * bad. XXX Should we better give up here? >X * XXX We could try old "addresses" option... >X */ >X sp->ipcp.opts &= ~(1 << IPCP_OPT_ADDRESS); >X break; >X#ifdef notyet >X case IPCP_OPT_COMPRESS: >X sp->ipcp.opts &= ~(1 << IPCP_OPT_COMPRESS); >X break; >X#endif >X } >X } >X if (debug) >X addlog("\n"); >X free (buf, M_TEMP); >X return; >X} >X >X/* >X * Analyze the IPCP Configure-NAK option list, and adjust our >X * negotiation. >X */ >Xstatic void >Xsppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len) >X{ >X u_char *buf, *p; >X struct ifnet *ifp = &sp->pp_if; >X int debug = ifp->if_flags & IFF_DEBUG; >X u_long wantaddr; >X >X len -= 4; >X buf = malloc (len, M_TEMP, M_NOWAIT); >X if (!buf) >X return; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "ipcp nak opts: ", >X SPP_ARGS(ifp)); >X >X p = (void*) (h+1); >X for (; len > 1 && p[1]; len -= p[1], p += p[1]) { >X if (debug) >X addlog(" %s ", sppp_ipcp_opt_name(*p)); >X switch (*p) { >X case IPCP_OPT_ADDRESS: >X /* >X * Peer doesn't like our local IP address. See >X * if we can do something for him. We'll drop >X * him our address then. >X */ >X if (len >= 6 && p[1] == 6) { >X wantaddr = p[2] << 24 | p[3] << 16 | >X p[4] << 8 | p[5]; >X sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS); >X if (debug) >X addlog("[wantaddr %s] ", >X sppp_dotted_quad(wantaddr)); >X /* >X * When doing dynamic address assignment, >X * we accept his offer. Otherwise, we >X * ignore it and thus continue to negotiate >X * our already existing value. >X * XXX: Bogus, if he said no once, he'll >X * just say no again, might as well die. >X */ >X if (sp->ipcp.flags & IPCP_MYADDR_DYN) { >X sppp_set_ip_addr(sp, wantaddr); >X if (debug) >X addlog("[agree] "); >X sp->ipcp.flags |= IPCP_MYADDR_SEEN; >X } >X } >X break; >X#ifdef notyet >X case IPCP_OPT_COMPRESS: >X /* >X * Peer wants different compression parameters. >X */ >X break; >X#endif >X } >X } >X if (debug) >X addlog("\n"); >X free (buf, M_TEMP); >X return; >X} >X >Xstatic void >Xsppp_ipcp_tlu(struct sppp *sp) >X{ >X /* we are up - notify isdn daemon */ >X if (sp->pp_con) >X sp->pp_con(sp); >X} >X >Xstatic void >Xsppp_ipcp_tld(struct sppp *sp) >X{ >X} >X >Xstatic void >Xsppp_ipcp_tls(struct sppp *sp) >X{ >X /* indicate to LCP that it must stay alive */ >X sp->lcp.protos |= (1 << IDX_IPCP); >X} >X >Xstatic void >Xsppp_ipcp_tlf(struct sppp *sp) >X{ >X /* we no longer need LCP */ >X sp->lcp.protos &= ~(1 << IDX_IPCP); >X sppp_lcp_check_and_close(sp); >X} >X >Xstatic void >Xsppp_ipcp_scr(struct sppp *sp) >X{ >X char opt[6 /* compression */ + 6 /* address */]; >X u_long ouraddr; >X int i = 0; >X >X#ifdef notyet >X if (sp->ipcp.opts & (1 << IPCP_OPT_COMPRESSION)) { >X opt[i++] = IPCP_OPT_COMPRESSION; >X opt[i++] = 6; >X opt[i++] = 0; /* VJ header compression */ >X opt[i++] = 0x2d; /* VJ header compression */ >X opt[i++] = max_slot_id; >X opt[i++] = comp_slot_id; >X } >X#endif >X >X if (sp->ipcp.opts & (1 << IPCP_OPT_ADDRESS)) { >X sppp_get_ip_addrs(sp, &ouraddr, 0, 0); >X opt[i++] = IPCP_OPT_ADDRESS; >X opt[i++] = 6; >X opt[i++] = ouraddr >> 24; >X opt[i++] = ouraddr >> 16; >X opt[i++] = ouraddr >> 8; >X opt[i++] = ouraddr; >X } >X >X sp->confid[IDX_IPCP] = ++sp->pp_seq; >X sppp_cp_send(sp, PPP_IPCP, CONF_REQ, sp->confid[IDX_IPCP], i, &opt); >X} >X >X >X/* >X *--------------------------------------------------------------------------* >X * * >X * The CHAP implementation. * >X * * >X *--------------------------------------------------------------------------* >X */ >X >X/* >X * The authentication protocols don't employ a full-fledged state machine as >X * the control protocols do, since they do have Open and Close events, but >X * not Up and Down, nor are they explicitly terminated. Also, use of the >X * authentication protocols may be different in both directions (this makes >X * sense, think of a machine that never accepts incoming calls but only >X * calls out, it doesn't require the called party to authenticate itself). >X * >X * Our state machine for the local authentication protocol (we are requesting >X * the peer to authenticate) looks like: >X * >X * RCA- >X * +--------------------------------------------+ >X * V scn,tld| >X * +--------+ Close +---------+ RCA+ >X * | |<----------------------------------| |------+ >X * +--->| Closed | TO* | Opened | sca | >X * | | |-----+ +-------| |<-----+ >X * | +--------+ irc | | +---------+ >X * | ^ | | ^ >X * | | | | | >X * | | | | | >X * | TO-| | | | >X * | |tld TO+ V | | >X * | | +------->+ | | >X * | | | | | | >X * | +--------+ V | | >X * | | |<----+<--------------------+ | >X * | | Req- | scr | >X * | | Sent | | >X * | | | | >X * | +--------+ | >X * | RCA- | | RCA+ | >X * +------+ +------------------------------------------+ >X * scn,tld sca,irc,ict,tlu >X * >X * >X * with: >X * >X * Open: LCP reached authentication phase >X * Close: LCP reached terminate phase >X * >X * RCA+: received reply (pap-req, chap-response), acceptable >X * RCN: received reply (pap-req, chap-response), not acceptable >X * TO+: timeout with restart counter >= 0 >X * TO-: timeout with restart counter < 0 >X * TO*: reschedule timeout for CHAP >X * >X * scr: send request packet (none for PAP, chap-challenge) >X * sca: send ack packet (pap-ack, chap-success) >X * scn: send nak packet (pap-nak, chap-failure) >X * ict: initialize re-challenge timer (CHAP only) >X * >X * tlu: this-layer-up, LCP reaches network phase >X * tld: this-layer-down, LCP enters terminate phase >X * >X * Note that in CHAP mode, after sending a new challenge, while the state >X * automaton falls back into Req-Sent state, it doesn't signal a tld >X * event to LCP, so LCP remains in network phase. Only after not getting >X * any response (or after getting an unacceptable response), CHAP closes, >X * causing LCP to enter terminate phase. >X * >X * With PAP, there is no initial request that can be sent. The peer is >X * expected to send one based on the successful negotiation of PAP as >X * the authentication protocol during the LCP option negotiation. >X * >X * Incoming authentication protocol requests (remote requests >X * authentication, we are peer) don't employ a state machine at all, >X * they are simply answered. Some peers [Ascend P50 firmware rev >X * 4.50] react allergically when sending IPCP requests while they are >X * still in authentication phase (thereby violating the standard that >X * demands that these NCP packets are to be discarded), so we keep >X * track of the peer demanding us to authenticate, and only proceed to >X * phase network once we've seen a positive acknowledge for the >X * authentication. >X */ >X >X/* >X * Handle incoming CHAP packets. >X */ >Xvoid >Xsppp_chap_input(struct sppp *sp, struct mbuf *m) >X{ >X STDDCL; >X struct lcp_header *h; >X int len, x; >X u_char *value, *name, digest[AUTHKEYLEN], dsize; >X int value_len, name_len; >X MD5_CTX ctx; >X >X len = m->m_pkthdr.len; >X if (len < 4) { >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "chap invalid packet length: %d bytes\n", >X SPP_ARGS(ifp), len); >X return; >X } >X h = mtod (m, struct lcp_header*); >X if (len > ntohs (h->len)) >X len = ntohs (h->len); >X >X switch (h->type) { >X /* challenge, failure and success are his authproto */ >X case CHAP_CHALLENGE: >X value = 1 + (u_char*)(h+1); >X value_len = value[-1]; >X name = value + value_len; >X name_len = len - value_len - 5; >X if (name_len < 0) { >X if (debug) { >X log(LOG_DEBUG, >X SPP_FMT "chap corrupted challenge " >X "<%s id=0x%x len=%d", >X SPP_ARGS(ifp), >X sppp_auth_type_name(PPP_CHAP, h->type), >X h->ident, ntohs(h->len)); >X if (len > 4) >X sppp_print_bytes((u_char*) (h+1), len-4); >X addlog(">\n"); >X } >X break; >X } >X >X if (debug) { >X log(LOG_DEBUG, >X SPP_FMT "chap input <%s id=0x%x len=%d name=", >X SPP_ARGS(ifp), >X sppp_auth_type_name(PPP_CHAP, h->type), h->ident, >X ntohs(h->len)); >X sppp_print_string((char*) name, name_len); >X addlog(" value-size=%d value=", value_len); >X sppp_print_bytes(value, value_len); >X addlog(">\n"); >X } >X >X /* Compute reply value. */ >X MD5Init(&ctx); >X MD5Update(&ctx, &h->ident, 1); >X MD5Update(&ctx, sp->myauth.secret, >X sppp_strnlen(sp->myauth.secret, AUTHKEYLEN)); >X MD5Update(&ctx, value, value_len); >X MD5Final(digest, &ctx); >X dsize = sizeof digest; >X >X sppp_auth_send(&chap, sp, CHAP_RESPONSE, h->ident, >X sizeof dsize, (const char *)&dsize, >X sizeof digest, digest, >X (size_t)sppp_strnlen(sp->myauth.name, AUTHNAMELEN), >X sp->myauth.name, >X 0); >X break; >X >X case CHAP_SUCCESS: >X if (debug) { >X log(LOG_DEBUG, SPP_FMT "chap success", >X SPP_ARGS(ifp)); >X if (len > 4) { >X addlog(": "); >X sppp_print_string((char*)(h + 1), len - 4); >X } >X addlog("\n"); >X } >X x = splimp(); >X sp->pp_flags &= ~PP_NEEDAUTH; >X if (sp->myauth.proto == PPP_CHAP && >X (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) && >X (sp->lcp.protos & (1 << IDX_CHAP)) == 0) { >X /* >X * We are authenticator for CHAP but didn't >X * complete yet. Leave it to tlu to proceed >X * to network phase. >X */ >X splx(x); >X break; >X } >X splx(x); >X sppp_phase_network(sp); >X break; >X >X case CHAP_FAILURE: >X if (debug) { >X log(LOG_INFO, SPP_FMT "chap failure", >X SPP_ARGS(ifp)); >X if (len > 4) { >X addlog(": "); >X sppp_print_string((char*)(h + 1), len - 4); >X } >X addlog("\n"); >X } else >X log(LOG_INFO, SPP_FMT "chap failure\n", >X SPP_ARGS(ifp)); >X /* await LCP shutdown by authenticator */ >X break; >X >X /* response is my authproto */ >X case CHAP_RESPONSE: >X value = 1 + (u_char*)(h+1); >X value_len = value[-1]; >X name = value + value_len; >X name_len = len - value_len - 5; >X if (name_len < 0) { >X if (debug) { >X log(LOG_DEBUG, >X SPP_FMT "chap corrupted response " >X "<%s id=0x%x len=%d", >X SPP_ARGS(ifp), >X sppp_auth_type_name(PPP_CHAP, h->type), >X h->ident, ntohs(h->len)); >X if (len > 4) >X sppp_print_bytes((u_char*)(h+1), len-4); >X addlog(">\n"); >X } >X break; >X } >X if (h->ident != sp->confid[IDX_CHAP]) { >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "chap dropping response for old ID " >X "(got %d, expected %d)\n", >X SPP_ARGS(ifp), >X h->ident, sp->confid[IDX_CHAP]); >X break; >X } >X if (name_len != sppp_strnlen(sp->hisauth.name, AUTHNAMELEN) >X || bcmp(name, sp->hisauth.name, name_len) != 0) { >X log(LOG_INFO, SPP_FMT "chap response, his name ", >X SPP_ARGS(ifp)); >X sppp_print_string(name, name_len); >X addlog(" != expected "); >X sppp_print_string(sp->hisauth.name, >X sppp_strnlen(sp->hisauth.name, AUTHNAMELEN)); >X addlog("\n"); >X } >X if (debug) { >X log(LOG_DEBUG, SPP_FMT "chap input(%s) " >X "<%s id=0x%x len=%d name=", >X SPP_ARGS(ifp), >X sppp_state_name(sp->state[IDX_CHAP]), >X sppp_auth_type_name(PPP_CHAP, h->type), >X h->ident, ntohs (h->len)); >X sppp_print_string((char*)name, name_len); >X addlog(" value-size=%d value=", value_len); >X sppp_print_bytes(value, value_len); >X addlog(">\n"); >X } >X if (value_len != AUTHKEYLEN) { >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "chap bad hash value length: " >X "%d bytes, should be %d\n", >X SPP_ARGS(ifp), value_len, >X AUTHKEYLEN); >X break; >X } >X >X MD5Init(&ctx); >X MD5Update(&ctx, &h->ident, 1); >X MD5Update(&ctx, sp->hisauth.secret, >X sppp_strnlen(sp->hisauth.secret, AUTHKEYLEN)); >X MD5Update(&ctx, sp->myauth.challenge, AUTHKEYLEN); >X MD5Final(digest, &ctx); >X >X#define FAILMSG "Failed..." >X#define SUCCMSG "Welcome!" >X >X if (value_len != sizeof digest || >X bcmp(digest, value, value_len) != 0) { >X /* action scn, tld */ >X sppp_auth_send(&chap, sp, CHAP_FAILURE, h->ident, >X sizeof(FAILMSG) - 1, (u_char *)FAILMSG, >X 0); >X chap.tld(sp); >X break; >X } >X /* action sca, perhaps tlu */ >X if (sp->state[IDX_CHAP] == STATE_REQ_SENT || >X sp->state[IDX_CHAP] == STATE_OPENED) >X sppp_auth_send(&chap, sp, CHAP_SUCCESS, h->ident, >X sizeof(SUCCMSG) - 1, (u_char *)SUCCMSG, >X 0); >X if (sp->state[IDX_CHAP] == STATE_REQ_SENT) { >X sppp_cp_change_state(&chap, sp, STATE_OPENED); >X chap.tlu(sp); >X } >X break; >X >X default: >X /* Unknown CHAP packet type -- ignore. */ >X if (debug) { >X log(LOG_DEBUG, SPP_FMT "chap unknown input(%s) " >X "<0x%x id=0x%xh len=%d", >X SPP_ARGS(ifp), >X sppp_state_name(sp->state[IDX_CHAP]), >X h->type, h->ident, ntohs(h->len)); >X if (len > 4) >X sppp_print_bytes((u_char*)(h+1), len-4); >X addlog(">\n"); >X } >X break; >X >X } >X} >X >Xstatic void >Xsppp_chap_init(struct sppp *sp) >X{ >X /* Chap doesn't have STATE_INITIAL at all. */ >X sp->state[IDX_CHAP] = STATE_CLOSED; >X sp->fail_counter[IDX_CHAP] = 0; >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X callout_handle_init(&sp->ch[IDX_CHAP]); >X#endif >X} >X >Xstatic void >Xsppp_chap_open(struct sppp *sp) >X{ >X if (sp->myauth.proto == PPP_CHAP && >X (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) != 0) { >X /* we are authenticator for CHAP, start it */ >X chap.scr(sp); >X sp->rst_counter[IDX_CHAP] = sp->lcp.max_configure; >X sppp_cp_change_state(&chap, sp, STATE_REQ_SENT); >X } >X /* nothing to be done if we are peer, await a challenge */ >X} >X >Xstatic void >Xsppp_chap_close(struct sppp *sp) >X{ >X if (sp->state[IDX_CHAP] != STATE_CLOSED) >X sppp_cp_change_state(&chap, sp, STATE_CLOSED); >X} >X >Xstatic void >Xsppp_chap_TO(void *cookie) >X{ >X struct sppp *sp = (struct sppp *)cookie; >X STDDCL; >X int s; >X >X s = splimp(); >X if (debug) >X log(LOG_DEBUG, SPP_FMT "chap TO(%s) rst_counter = %d\n", >X SPP_ARGS(ifp), >X sppp_state_name(sp->state[IDX_CHAP]), >X sp->rst_counter[IDX_CHAP]); >X >X if (--sp->rst_counter[IDX_CHAP] < 0) >X /* TO- event */ >X switch (sp->state[IDX_CHAP]) { >X case STATE_REQ_SENT: >X chap.tld(sp); >X sppp_cp_change_state(&chap, sp, STATE_CLOSED); >X break; >X } >X else >X /* TO+ (or TO*) event */ >X switch (sp->state[IDX_CHAP]) { >X case STATE_OPENED: >X /* TO* event */ >X sp->rst_counter[IDX_CHAP] = sp->lcp.max_configure; >X /* fall through */ >X case STATE_REQ_SENT: >X chap.scr(sp); >X /* sppp_cp_change_state() will restart the timer */ >X sppp_cp_change_state(&chap, sp, STATE_REQ_SENT); >X break; >X } >X >X splx(s); >X} >X >Xstatic void >Xsppp_chap_tlu(struct sppp *sp) >X{ >X STDDCL; >X int i, x; >X >X i = 0; >X sp->rst_counter[IDX_CHAP] = sp->lcp.max_configure; >X >X /* >X * Some broken CHAP implementations (Conware CoNet, firmware >X * 4.0.?) don't want to re-authenticate their CHAP once the >X * initial challenge-response exchange has taken place. >X * Provide for an option to avoid rechallenges. >X */ >X if ((sp->hisauth.flags & AUTHFLAG_NORECHALLENGE) == 0) { >X /* >X * Compute the re-challenge timeout. This will yield >X * a number between 300 and 810 seconds. >X */ >X i = 300 + ((unsigned)(random() & 0xff00) >> 7); >X TIMEOUT(chap.TO, (void *)sp, i * hz, sp->ch[IDX_CHAP]); >X } >X >X if (debug) { >X log(LOG_DEBUG, >X SPP_FMT "chap %s, ", >X SPP_ARGS(ifp), >X sp->pp_phase == PHASE_NETWORK? "reconfirmed": "tlu"); >X if ((sp->hisauth.flags & AUTHFLAG_NORECHALLENGE) == 0) >X addlog("next re-challenge in %d seconds\n", i); >X else >X addlog("re-challenging supressed\n"); >X } >X >X x = splimp(); >X /* indicate to LCP that we need to be closed down */ >X sp->lcp.protos |= (1 << IDX_CHAP); >X >X if (sp->pp_flags & PP_NEEDAUTH) { >X /* >X * Remote is authenticator, but his auth proto didn't >X * complete yet. Defer the transition to network >X * phase. >X */ >X splx(x); >X return; >X } >X splx(x); >X >X /* >X * If we are already in phase network, we are done here. This >X * is the case if this is a dummy tlu event after a re-challenge. >X */ >X if (sp->pp_phase != PHASE_NETWORK) >X sppp_phase_network(sp); >X} >X >Xstatic void >Xsppp_chap_tld(struct sppp *sp) >X{ >X STDDCL; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "chap tld\n", SPP_ARGS(ifp)); >X UNTIMEOUT(chap.TO, (void *)sp, sp->ch[IDX_CHAP]); >X sp->lcp.protos &= ~(1 << IDX_CHAP); >X >X lcp.Close(sp); >X} >X >Xstatic void >Xsppp_chap_scr(struct sppp *sp) >X{ >X u_long *ch, seed; >X u_char clen; >X >X /* Compute random challenge. */ >X ch = (u_long *)sp->myauth.challenge; >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X read_random(&seed, sizeof seed); >X#else >X { >X struct timeval tv; >X microtime(&tv); >X seed = tv.tv_sec ^ tv.tv_usec; >X } >X#endif >X ch[0] = seed ^ random(); >X ch[1] = seed ^ random(); >X ch[2] = seed ^ random(); >X ch[3] = seed ^ random(); >X clen = AUTHKEYLEN; >X >X sp->confid[IDX_CHAP] = ++sp->pp_seq; >X >X sppp_auth_send(&chap, sp, CHAP_CHALLENGE, sp->confid[IDX_CHAP], >X sizeof clen, (const char *)&clen, >X (size_t)AUTHKEYLEN, sp->myauth.challenge, >X (size_t)sppp_strnlen(sp->myauth.name, AUTHNAMELEN), >X sp->myauth.name, >X 0); >X} >X/* >X *--------------------------------------------------------------------------* >X * * >X * The PAP implementation. * >X * * >X *--------------------------------------------------------------------------* >X */ >X/* >X * For PAP, we need to keep a little state also if we are the peer, not the >X * authenticator. This is since we don't get a request to authenticate, but >X * have to repeatedly authenticate ourself until we got a response (or the >X * retry counter is expired). >X */ >X >X/* >X * Handle incoming PAP packets. */ >Xstatic void >Xsppp_pap_input(struct sppp *sp, struct mbuf *m) >X{ >X STDDCL; >X struct lcp_header *h; >X int len, x; >X u_char *name, *passwd, mlen; >X int name_len, passwd_len; >X >X len = m->m_pkthdr.len; >X if (len < 5) { >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "pap invalid packet length: %d bytes\n", >X SPP_ARGS(ifp), len); >X return; >X } >X h = mtod (m, struct lcp_header*); >X if (len > ntohs (h->len)) >X len = ntohs (h->len); >X switch (h->type) { >X /* PAP request is my authproto */ >X case PAP_REQ: >X name = 1 + (u_char*)(h+1); >X name_len = name[-1]; >X passwd = name + name_len + 1; >X if (name_len > len - 6 || >X (passwd_len = passwd[-1]) > len - 6 - name_len) { >X if (debug) { >X log(LOG_DEBUG, SPP_FMT "pap corrupted input " >X "<%s id=0x%x len=%d", >X SPP_ARGS(ifp), >X sppp_auth_type_name(PPP_PAP, h->type), >X h->ident, ntohs(h->len)); >X if (len > 4) >X sppp_print_bytes((u_char*)(h+1), len-4); >X addlog(">\n"); >X } >X break; >X } >X if (debug) { >X log(LOG_DEBUG, SPP_FMT "pap input(%s) " >X "<%s id=0x%x len=%d name=", >X SPP_ARGS(ifp), >X sppp_state_name(sp->state[IDX_PAP]), >X sppp_auth_type_name(PPP_PAP, h->type), >X h->ident, ntohs(h->len)); >X sppp_print_string((char*)name, name_len); >X addlog(" passwd="); >X sppp_print_string((char*)passwd, passwd_len); >X addlog(">\n"); >X } >X if (name_len > AUTHNAMELEN || >X passwd_len > AUTHKEYLEN || >X bcmp(name, sp->hisauth.name, name_len) != 0 || >X bcmp(passwd, sp->hisauth.secret, passwd_len) != 0) { >X /* action scn, tld */ >X mlen = sizeof(FAILMSG) - 1; >X sppp_auth_send(&pap, sp, PAP_NAK, h->ident, >X sizeof mlen, (const char *)&mlen, >X sizeof(FAILMSG) - 1, (u_char *)FAILMSG, >X 0); >X pap.tld(sp); >X break; >X } >X /* action sca, perhaps tlu */ >X if (sp->state[IDX_PAP] == STATE_REQ_SENT || >X sp->state[IDX_PAP] == STATE_OPENED) { >X mlen = sizeof(SUCCMSG) - 1; >X sppp_auth_send(&pap, sp, PAP_ACK, h->ident, >X sizeof mlen, (const char *)&mlen, >X sizeof(SUCCMSG) - 1, (u_char *)SUCCMSG, >X 0); >X } >X if (sp->state[IDX_PAP] == STATE_REQ_SENT) { >X sppp_cp_change_state(&pap, sp, STATE_OPENED); >X pap.tlu(sp); >X } >X break; >X >X /* ack and nak are his authproto */ >X case PAP_ACK: >X UNTIMEOUT(sppp_pap_my_TO, (void *)sp, sp->pap_my_to_ch); >X if (debug) { >X log(LOG_DEBUG, SPP_FMT "pap success", >X SPP_ARGS(ifp)); >X name_len = *((char *)h); >X if (len > 5 && name_len) { >X addlog(": "); >X sppp_print_string((char*)(h+1), name_len); >X } >X addlog("\n"); >X } >X x = splimp(); >X sp->pp_flags &= ~PP_NEEDAUTH; >X if (sp->myauth.proto == PPP_PAP && >X (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) && >X (sp->lcp.protos & (1 << IDX_PAP)) == 0) { >X /* >X * We are authenticator for PAP but didn't >X * complete yet. Leave it to tlu to proceed >X * to network phase. >X */ >X splx(x); >X break; >X } >X splx(x); >X sppp_phase_network(sp); >X break; >X >X case PAP_NAK: >X UNTIMEOUT(sppp_pap_my_TO, (void *)sp, sp->pap_my_to_ch); >X if (debug) { >X log(LOG_INFO, SPP_FMT "pap failure", >X SPP_ARGS(ifp)); >X name_len = *((char *)h); >X if (len > 5 && name_len) { >X addlog(": "); >X sppp_print_string((char*)(h+1), name_len); >X } >X addlog("\n"); >X } else >X log(LOG_INFO, SPP_FMT "pap failure\n", >X SPP_ARGS(ifp)); >X /* await LCP shutdown by authenticator */ >X break; >X >X default: >X /* Unknown PAP packet type -- ignore. */ >X if (debug) { >X log(LOG_DEBUG, SPP_FMT "pap corrupted input " >X "<0x%x id=0x%x len=%d", >X SPP_ARGS(ifp), >X h->type, h->ident, ntohs(h->len)); >X if (len > 4) >X sppp_print_bytes((u_char*)(h+1), len-4); >X addlog(">\n"); >X } >X break; >X >X } >X} >X >Xstatic void >Xsppp_pap_init(struct sppp *sp) >X{ >X /* PAP doesn't have STATE_INITIAL at all. */ >X sp->state[IDX_PAP] = STATE_CLOSED; >X sp->fail_counter[IDX_PAP] = 0; >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X callout_handle_init(&sp->ch[IDX_PAP]); >X callout_handle_init(&sp->pap_my_to_ch); >X#endif >X} >X >Xstatic void >Xsppp_pap_open(struct sppp *sp) >X{ >X if (sp->hisauth.proto == PPP_PAP && >X (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) != 0) { >X /* we are authenticator for PAP, start our timer */ >X sp->rst_counter[IDX_PAP] = sp->lcp.max_configure; >X sppp_cp_change_state(&pap, sp, STATE_REQ_SENT); >X } >X if (sp->myauth.proto == PPP_PAP) { >X /* we are peer, send a request, and start a timer */ >X pap.scr(sp); >X TIMEOUT(sppp_pap_my_TO, (void *)sp, sp->lcp.timeout, >X sp->pap_my_to_ch); >X } >X} >X >Xstatic void >Xsppp_pap_close(struct sppp *sp) >X{ >X if (sp->state[IDX_PAP] != STATE_CLOSED) >X sppp_cp_change_state(&pap, sp, STATE_CLOSED); >X} >X >X/* >X * That's the timeout routine if we are authenticator. Since the >X * authenticator is basically passive in PAP, we can't do much here. >X */ >Xstatic void >Xsppp_pap_TO(void *cookie) >X{ >X struct sppp *sp = (struct sppp *)cookie; >X STDDCL; >X int s; >X >X s = splimp(); >X if (debug) >X log(LOG_DEBUG, SPP_FMT "pap TO(%s) rst_counter = %d\n", >X SPP_ARGS(ifp), >X sppp_state_name(sp->state[IDX_PAP]), >X sp->rst_counter[IDX_PAP]); >X >X if (--sp->rst_counter[IDX_PAP] < 0) >X /* TO- event */ >X switch (sp->state[IDX_PAP]) { >X case STATE_REQ_SENT: >X pap.tld(sp); >X sppp_cp_change_state(&pap, sp, STATE_CLOSED); >X break; >X } >X else >X /* TO+ event, not very much we could do */ >X switch (sp->state[IDX_PAP]) { >X case STATE_REQ_SENT: >X /* sppp_cp_change_state() will restart the timer */ >X sppp_cp_change_state(&pap, sp, STATE_REQ_SENT); >X break; >X } >X >X splx(s); >X} >X >X/* >X * That's the timeout handler if we are peer. Since the peer is active, >X * we need to retransmit our PAP request since it is apparently lost. >X * XXX We should impose a max counter. >X */ >Xstatic void >Xsppp_pap_my_TO(void *cookie) >X{ >X struct sppp *sp = (struct sppp *)cookie; >X STDDCL; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "pap peer TO\n", >X SPP_ARGS(ifp)); >X >X pap.scr(sp); >X} >X >Xstatic void >Xsppp_pap_tlu(struct sppp *sp) >X{ >X STDDCL; >X int x; >X >X sp->rst_counter[IDX_PAP] = sp->lcp.max_configure; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "%s tlu\n", >X SPP_ARGS(ifp), pap.name); >X >X x = splimp(); >X /* indicate to LCP that we need to be closed down */ >X sp->lcp.protos |= (1 << IDX_PAP); >X >X if (sp->pp_flags & PP_NEEDAUTH) { >X /* >X * Remote is authenticator, but his auth proto didn't >X * complete yet. Defer the transition to network >X * phase. >X */ >X splx(x); >X return; >X } >X splx(x); >X sppp_phase_network(sp); >X} >X >Xstatic void >Xsppp_pap_tld(struct sppp *sp) >X{ >X STDDCL; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "pap tld\n", SPP_ARGS(ifp)); >X UNTIMEOUT(pap.TO, (void *)sp, sp->ch[IDX_PAP]); >X UNTIMEOUT(sppp_pap_my_TO, (void *)sp, sp->pap_my_to_ch); >X sp->lcp.protos &= ~(1 << IDX_PAP); >X >X lcp.Close(sp); >X} >X >Xstatic void >Xsppp_pap_scr(struct sppp *sp) >X{ >X u_char idlen, pwdlen; >X >X sp->confid[IDX_PAP] = ++sp->pp_seq; >X pwdlen = sppp_strnlen(sp->myauth.secret, AUTHKEYLEN); >X idlen = sppp_strnlen(sp->myauth.name, AUTHNAMELEN); >X >X sppp_auth_send(&pap, sp, PAP_REQ, sp->confid[IDX_PAP], >X sizeof idlen, (const char *)&idlen, >X (size_t)idlen, sp->myauth.name, >X sizeof pwdlen, (const char *)&pwdlen, >X (size_t)pwdlen, sp->myauth.secret, >X 0); >X} >X/* >X * Random miscellaneous functions. >X */ >X >X/* >X * Send a PAP or CHAP proto packet. >X * >X * Varadic function, each of the elements for the ellipsis is of type >X * ``size_t mlen, const u_char *msg''. Processing will stop iff >X * mlen == 0. >X * NOTE: never declare variadic functions with types subject to type >X * promotion (i.e. u_char). This is asking for big trouble depending >X * on the architecture you are on... >X */ >X >Xstatic void >Xsppp_auth_send(const struct cp *cp, struct sppp *sp, >X unsigned int type, unsigned int id, >X ...) >X{ >X STDDCL; >X struct ppp_header *h; >X struct lcp_header *lh; >X struct mbuf *m; >X u_char *p; >X int len; >X unsigned int mlen; >X const char *msg; >X va_list ap; >X >X MGETHDR (m, M_DONTWAIT, MT_DATA); >X if (! m) >X return; >X m->m_pkthdr.rcvif = 0; >X >X h = mtod (m, struct ppp_header*); >X h->address = PPP_ALLSTATIONS; /* broadcast address */ >X h->control = PPP_UI; /* Unnumbered Info */ >X h->protocol = htons(cp->proto); >X >X lh = (struct lcp_header*)(h + 1); >X lh->type = type; >X lh->ident = id; >X p = (u_char*) (lh+1); >X >X va_start(ap, id); >X len = 0; >X >X while ((mlen = (unsigned int)va_arg(ap, size_t)) != 0) { >X msg = va_arg(ap, const char *); >X len += mlen; >X if (len > MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN) { >X va_end(ap); >X m_freem(m); >X return; >X } >X >X bcopy(msg, p, mlen); >X p += mlen; >X } >X va_end(ap); >X >X m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + LCP_HEADER_LEN + len; >X lh->len = htons (LCP_HEADER_LEN + len); >X >X if (debug) { >X log(LOG_DEBUG, SPP_FMT "%s output <%s id=0x%x len=%d", >X SPP_ARGS(ifp), cp->name, >X sppp_auth_type_name(cp->proto, lh->type), >X lh->ident, ntohs(lh->len)); >X if (len) >X sppp_print_bytes((u_char*) (lh+1), len); >X addlog(">\n"); >X } >X if (IF_QFULL (&sp->pp_cpq)) { >X IF_DROP (&sp->pp_fastq); >X IF_DROP (&ifp->if_snd); >X m_freem (m); >X ++ifp->if_oerrors; >X } else >X IF_ENQUEUE (&sp->pp_cpq, m); >X if (! (ifp->if_flags & IFF_OACTIVE)) >X (*ifp->if_start) (ifp); >X ifp->if_obytes += m->m_pkthdr.len + 3; >X} >X >X/* >X * Flush interface queue. >X */ >Xstatic void >Xsppp_qflush(struct ifqueue *ifq) >X{ >X struct mbuf *m, *n; >X >X n = ifq->ifq_head; >X while ((m = n)) { >X n = m->m_act; >X m_freem (m); >X } >X ifq->ifq_head = 0; >X ifq->ifq_tail = 0; >X ifq->ifq_len = 0; >X} >X >X/* >X * Send keepalive packets, every 10 seconds. >X */ >Xstatic void >Xsppp_keepalive(void *dummy) >X{ >X struct sppp *sp; >X int s; >X >X s = splimp(); >X for (sp=spppq; sp; sp=sp->pp_next) { >X struct ifnet *ifp = &sp->pp_if; >X >X /* Keepalive mode disabled or channel down? */ >X if (! (sp->pp_flags & PP_KEEPALIVE) || >X ! (ifp->if_flags & IFF_RUNNING)) >X continue; >X >X /* No keepalive in PPP mode if LCP not opened yet. */ >X if (! (sp->pp_flags & PP_CISCO) && >X sp->pp_phase < PHASE_AUTHENTICATE) >X continue; >X >X if (sp->pp_alivecnt == MAXALIVECNT) { >X /* No keepalive packets got. Stop the interface. */ >X printf (SPP_FMT "down\n", SPP_ARGS(ifp)); >X if_down (ifp); >X sppp_qflush (&sp->pp_cpq); >X if (! (sp->pp_flags & PP_CISCO)) { >X /* XXX */ >X /* Shut down the PPP link. */ >X lcp.Down(sp); >X /* Initiate negotiation. XXX */ >X lcp.Up(sp); >X } >X } >X if (sp->pp_alivecnt <= MAXALIVECNT) >X ++sp->pp_alivecnt; >X if (sp->pp_flags & PP_CISCO) >X sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq, >X sp->pp_rseq); >X else if (sp->pp_phase >= PHASE_AUTHENTICATE) { >X long nmagic = htonl (sp->lcp.magic); >X sp->lcp.echoid = ++sp->pp_seq; >X sppp_cp_send (sp, PPP_LCP, ECHO_REQ, >X sp->lcp.echoid, 4, &nmagic); >X } >X } >X splx(s); >X TIMEOUT(sppp_keepalive, 0, hz * 10, keepalive_ch); >X} >X >X/* >X * Get both IP addresses. >X */ >Xstatic void >Xsppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst, u_long *srcmask) >X{ >X struct ifnet *ifp = &sp->pp_if; >X struct ifaddr *ifa; >X struct sockaddr_in *si, *sm; >X u_long ssrc, ddst; >X >X sm = NULL; >X ssrc = ddst = 0L; >X /* >X * Pick the first AF_INET address from the list, >X * aliases don't make any sense on a p2p link anyway. >X */ >X si = 0; >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) >X#elif defined(__NetBSD__) || defined (__OpenBSD__) >X for (ifa = ifp->if_addrlist.tqh_first; >X ifa; >X ifa = ifa->ifa_list.tqe_next) >X#else >X for (ifa = ifp->if_addrlist; >X ifa; >X ifa = ifa->ifa_next) >X#endif >X if (ifa->ifa_addr->sa_family == AF_INET) { >X si = (struct sockaddr_in *)ifa->ifa_addr; >X sm = (struct sockaddr_in *)ifa->ifa_netmask; >X if (si) >X break; >X } >X if (ifa) { >X if (si && si->sin_addr.s_addr) { >X ssrc = si->sin_addr.s_addr; >X if (srcmask) >X *srcmask = ntohl(sm->sin_addr.s_addr); >X } >X >X si = (struct sockaddr_in *)ifa->ifa_dstaddr; >X if (si && si->sin_addr.s_addr) >X ddst = si->sin_addr.s_addr; >X } >X >X if (dst) *dst = ntohl(ddst); >X if (src) *src = ntohl(ssrc); >X} >X >X/* >X * Set my IP address. Must be called at splimp. >X */ >Xstatic void >Xsppp_set_ip_addr(struct sppp *sp, u_long src) >X{ >X STDDCL; >X struct ifaddr *ifa; >X struct sockaddr_in *si; >X >X /* >X * Pick the first AF_INET address from the list, >X * aliases don't make any sense on a p2p link anyway. >X */ >X si = 0; >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) >X#elif defined(__NetBSD__) || defined (__OpenBSD__) >X for (ifa = ifp->if_addrlist.tqh_first; >X ifa; >X ifa = ifa->ifa_list.tqe_next) >X#else >X for (ifa = ifp->if_addrlist; >X ifa; >X ifa = ifa->ifa_next) >X#endif >X { >X if (ifa->ifa_addr->sa_family == AF_INET) >X { >X si = (struct sockaddr_in *)ifa->ifa_addr; >X if (si) >X break; >X } >X } >X >X if (ifa && si) >X { >X int error; >X#if __NetBSD_Version__ >= 103080000 >X struct sockaddr_in new_sin = *si; >X >X new_sin.sin_addr.s_addr = htonl(src); >X error = in_ifinit(ifp, ifatoia(ifa), &new_sin, 1); >X if(debug && error) >X { >X log(LOG_DEBUG, SPP_FMT "sppp_set_ip_addr: in_ifinit " >X " failed, error=%d\n", SPP_ARGS(ifp), error); >X } >X#else >X /* delete old route */ >X error = rtinit(ifa, (int)RTM_DELETE, RTF_HOST); >X if(debug && error) >X { >X log(LOG_DEBUG, SPP_FMT "sppp_set_ip_addr: rtinit DEL failed, error=%d\n", >X SPP_ARGS(ifp), error); >X } >X >X /* set new address */ >X si->sin_addr.s_addr = htonl(src); >X >X /* add new route */ >X error = rtinit(ifa, (int)RTM_ADD, RTF_HOST); >X if (debug && error) >X { >X log(LOG_DEBUG, SPP_FMT "sppp_set_ip_addr: rtinit ADD failed, error=%d", >X SPP_ARGS(ifp), error); >X } >X#endif >X } >X} >X >Xstatic int >Xsppp_params(struct sppp *sp, u_long cmd, void *data) >X{ >X u_long subcmd; >X struct ifreq *ifr = (struct ifreq *)data; >X struct spppreq spr; >X >X /* >X * ifr->ifr_data is supposed to point to a struct spppreq. >X * Check the cmd word first before attempting to fetch all the >X * data. >X */ >X if ((subcmd = fuword(ifr->ifr_data)) == -1) >X return EFAULT; >X >X if (copyin((caddr_t)ifr->ifr_data, &spr, sizeof spr) != 0) >X return EFAULT; >X >X switch (subcmd) { >X case SPPPIOGDEFS: >X if (cmd != SIOCGIFGENERIC) >X return EINVAL; >X /* >X * We copy over the entire current state, but clean >X * out some of the stuff we don't wanna pass up. >X * Remember, SIOCGIFGENERIC is unprotected, and can be >X * called by any user. No need to ever get PAP or >X * CHAP secrets back to userland anyway. >X */ >X bcopy(sp, &spr.defs, sizeof(struct sppp)); >X bzero(spr.defs.myauth.secret, AUTHKEYLEN); >X bzero(spr.defs.myauth.challenge, AUTHKEYLEN); >X bzero(spr.defs.hisauth.secret, AUTHKEYLEN); >X bzero(spr.defs.hisauth.challenge, AUTHKEYLEN); >X return copyout(&spr, (caddr_t)ifr->ifr_data, sizeof spr); >X >X case SPPPIOSDEFS: >X if (cmd != SIOCSIFGENERIC) >X return EINVAL; >X /* >X * We have a very specific idea of which fields we allow >X * being passed back from userland, so to not clobber our >X * current state. For one, we only allow setting >X * anything if LCP is in dead phase. Once the LCP >X * negotiations started, the authentication settings must >X * not be changed again. (The administrator can force an >X * ifconfig down in order to get LCP back into dead >X * phase.) >X * >X * Also, we only allow for authentication parameters to be >X * specified. >X * >X * XXX Should allow to set or clear pp_flags. >X * >X * Finally, if the respective authentication protocol to >X * be used is set differently than 0, but the secret is >X * passed as all zeros, we don't trash the existing secret. >X * This allows an administrator to change the system name >X * only without clobbering the secret (which he didn't get >X * back in a previous SPPPIOGDEFS call). However, the >X * secrets are cleared if the authentication protocol is >X * reset to 0. >X */ >X if (sp->pp_phase != PHASE_DEAD) >X return EBUSY; >X >X if ((spr.defs.myauth.proto != 0 && spr.defs.myauth.proto != PPP_PAP && >X spr.defs.myauth.proto != PPP_CHAP) || >X (spr.defs.hisauth.proto != 0 && spr.defs.hisauth.proto != PPP_PAP && >X spr.defs.hisauth.proto != PPP_CHAP)) >X return EINVAL; >X >X if (spr.defs.myauth.proto == 0) >X /* resetting myauth */ >X bzero(&sp->myauth, sizeof sp->myauth); >X else { >X /* setting/changing myauth */ >X sp->myauth.proto = spr.defs.myauth.proto; >X bcopy(spr.defs.myauth.name, sp->myauth.name, AUTHNAMELEN); >X if (spr.defs.myauth.secret[0] != '\0') >X bcopy(spr.defs.myauth.secret, sp->myauth.secret, >X AUTHKEYLEN); >X } >X if (spr.defs.hisauth.proto == 0) >X /* resetting hisauth */ >X bzero(&sp->hisauth, sizeof sp->hisauth); >X else { >X /* setting/changing hisauth */ >X sp->hisauth.proto = spr.defs.hisauth.proto; >X sp->hisauth.flags = spr.defs.hisauth.flags; >X bcopy(spr.defs.hisauth.name, sp->hisauth.name, AUTHNAMELEN); >X if (spr.defs.hisauth.secret[0] != '\0') >X bcopy(spr.defs.hisauth.secret, sp->hisauth.secret, >X AUTHKEYLEN); >X } >X break; >X >X default: >X return EINVAL; >X } >X >X return 0; >X} >X >Xstatic void >Xsppp_phase_network(struct sppp *sp) >X{ >X STDDCL; >X int i; >X u_long mask; >X >X sp->pp_phase = PHASE_NETWORK; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "phase %s\n", SPP_ARGS(ifp), >X sppp_phase_name(sp->pp_phase)); >X >X /* Notify NCPs now. */ >X for (i = 0; i < IDX_COUNT; i++) >X if ((cps[i])->flags & CP_NCP) >X (cps[i])->Open(sp); >X >X /* Send Up events to all NCPs. */ >X for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1) >X if (sp->lcp.protos & mask && ((cps[i])->flags & CP_NCP)) >X (cps[i])->Up(sp); >X >X /* if no NCP is starting, all this was in vain, close down */ >X sppp_lcp_check_and_close(sp); >X} >X >X >Xstatic const char * >Xsppp_cp_type_name(u_char type) >X{ >X static char buf[12]; >X switch (type) { >X case CONF_REQ: return "conf-req"; >X case CONF_ACK: return "conf-ack"; >X case CONF_NAK: return "conf-nak"; >X case CONF_REJ: return "conf-rej"; >X case TERM_REQ: return "term-req"; >X case TERM_ACK: return "term-ack"; >X case CODE_REJ: return "code-rej"; >X case PROTO_REJ: return "proto-rej"; >X case ECHO_REQ: return "echo-req"; >X case ECHO_REPLY: return "echo-reply"; >X case DISC_REQ: return "discard-req"; >X } >X snprintf (buf, sizeof(buf), "0x%x", type); >X return buf; >X} >X >Xstatic const char * >Xsppp_auth_type_name(u_short proto, u_char type) >X{ >X static char buf[12]; >X switch (proto) { >X case PPP_CHAP: >X switch (type) { >X case CHAP_CHALLENGE: return "challenge"; >X case CHAP_RESPONSE: return "response"; >X case CHAP_SUCCESS: return "success"; >X case CHAP_FAILURE: return "failure"; >X } >X case PPP_PAP: >X switch (type) { >X case PAP_REQ: return "req"; >X case PAP_ACK: return "ack"; >X case PAP_NAK: return "nak"; >X } >X } >X snprintf (buf, sizeof(buf), "0x%x", type); >X return buf; >X} >X >Xstatic const char * >Xsppp_lcp_opt_name(u_char opt) >X{ >X static char buf[12]; >X switch (opt) { >X case LCP_OPT_MRU: return "mru"; >X case LCP_OPT_ASYNC_MAP: return "async-map"; >X case LCP_OPT_AUTH_PROTO: return "auth-proto"; >X case LCP_OPT_QUAL_PROTO: return "qual-proto"; >X case LCP_OPT_MAGIC: return "magic"; >X case LCP_OPT_PROTO_COMP: return "proto-comp"; >X case LCP_OPT_ADDR_COMP: return "addr-comp"; >X } >X snprintf (buf, sizeof(buf), "0x%x", opt); >X return buf; >X} >X >Xstatic const char * >Xsppp_ipcp_opt_name(u_char opt) >X{ >X static char buf[12]; >X switch (opt) { >X case IPCP_OPT_ADDRESSES: return "addresses"; >X case IPCP_OPT_COMPRESSION: return "compression"; >X case IPCP_OPT_ADDRESS: return "address"; >X } >X snprintf (buf, sizeof(buf), "0x%x", opt); >X return buf; >X} >X >Xstatic const char * >Xsppp_state_name(int state) >X{ >X switch (state) { >X case STATE_INITIAL: return "initial"; >X case STATE_STARTING: return "starting"; >X case STATE_CLOSED: return "closed"; >X case STATE_STOPPED: return "stopped"; >X case STATE_CLOSING: return "closing"; >X case STATE_STOPPING: return "stopping"; >X case STATE_REQ_SENT: return "req-sent"; >X case STATE_ACK_RCVD: return "ack-rcvd"; >X case STATE_ACK_SENT: return "ack-sent"; >X case STATE_OPENED: return "opened"; >X } >X return "illegal"; >X} >X >Xstatic const char * >Xsppp_phase_name(enum ppp_phase phase) >X{ >X switch (phase) { >X case PHASE_DEAD: return "dead"; >X case PHASE_ESTABLISH: return "establish"; >X case PHASE_TERMINATE: return "terminate"; >X case PHASE_AUTHENTICATE: return "authenticate"; >X case PHASE_NETWORK: return "network"; >X } >X return "illegal"; >X} >X >Xstatic const char * >Xsppp_proto_name(u_short proto) >X{ >X static char buf[12]; >X switch (proto) { >X case PPP_LCP: return "lcp"; >X case PPP_IPCP: return "ipcp"; >X case PPP_PAP: return "pap"; >X case PPP_CHAP: return "chap"; >X } >X snprintf(buf, sizeof(buf), "0x%x", (unsigned)proto); >X return buf; >X} >X >Xstatic void >Xsppp_print_bytes(const u_char *p, u_short len) >X{ >X addlog(" %02x", *p++); >X while (--len > 0) >X addlog("-%02x", *p++); >X} >X >Xstatic void >Xsppp_print_string(const char *p, u_short len) >X{ >X u_char c; >X >X while (len-- > 0) { >X c = *p++; >X /* >X * Print only ASCII chars directly. RFC 1994 recommends >X * using only them, but we don't rely on it. */ >X if (c < ' ' || c > '~') >X addlog("\\x%x", c); >X else >X addlog("%c", c); >X } >X} >X >Xstatic const char * >Xsppp_dotted_quad(u_long addr) >X{ >X static char s[16]; >X sprintf(s, "%d.%d.%d.%d", >X (int)((addr >> 24) & 0xff), >X (int)((addr >> 16) & 0xff), >X (int)((addr >> 8) & 0xff), >X (int)(addr & 0xff)); >X return s; >X} >X >Xstatic int >Xsppp_strnlen(u_char *p, int max) >X{ >X int len; >X >X for (len = 0; len < max && *p; ++p) >X ++len; >X return len; >X} >X >X/* a dummy, used to drop uninteresting events */ >Xstatic void >Xsppp_null(struct sppp *unused) >X{ >X /* do just nothing */ >X} >END-of-./usr/src/sys/net/if_spppsubr.c >echo x - ./usr/src/sys/net/if_spppsubr.c.patch >sed 's/^X//' >./usr/src/sys/net/if_spppsubr.c.patch << 'END-of-./usr/src/sys/net/if_spppsubr.c.patch' >X*** if_spppsubr.c Tue Dec 1 21:20:21 1998 >X--- if_spppsubr.c.new Tue Mar 16 15:54:10 1999 >X*************** >X*** 603,608 **** >X--- 603,609 ---- >X goto drop; >X } >X IF_ENQUEUE(inq, m); >X+ sp->pp_last_recv = time_second; >X splx(s); >X } >X >X*************** >X*** 777,782 **** >X--- 778,784 ---- >X * according to RFC 1333. >X */ >X ifp->if_obytes += m->m_pkthdr.len + 3; >X+ sp->pp_last_sent = time_second; >X splx (s); >X return (0); >X } >X*************** >X*** 809,814 **** >X--- 811,817 ---- >X sp->pp_up = lcp.Up; >X sp->pp_down = lcp.Down; >X >X+ sp->pp_last_recv = sp->pp_last_sent = time_second; >X sppp_lcp_init(sp); >X sppp_ipcp_init(sp); >X sppp_pap_init(sp); >END-of-./usr/src/sys/net/if_spppsubr.c.patch >echo x - ./usr/src/sys/net/if_spppsubr.c.orig >sed 's/^X//' >./usr/src/sys/net/if_spppsubr.c.orig << 'END-of-./usr/src/sys/net/if_spppsubr.c.orig' >X/* >X * Synchronous PPP/Cisco link level subroutines. >X * Keepalive protocol implemented in both Cisco and PPP modes. >X * >X * Copyright (C) 1994-1996 Cronyx Engineering Ltd. >X * Author: Serge Vakulenko, <vak@cronyx.ru> >X * >X * Heavily revamped to conform to RFC 1661. >X * Copyright (C) 1997, Joerg Wunsch. >X * >X * This software is distributed with NO WARRANTIES, not even the implied >X * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. >X * >X * Authors grant any other persons or organisations permission to use >X * or modify this software as long as this message is kept with the software, >X * all derivative works or modified versions. >X * >X * From: Version 2.4, Thu Apr 30 17:17:21 MSD 1997 >X * >X * $Id: if_spppsubr.c,v 1.52 1998/12/27 21:30:44 phk Exp $ >X */ >X >X#include <sys/param.h> >X >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X#include "opt_inet.h" >X#include "opt_ipx.h" >X#endif >X >X#ifdef NetBSD1_3 >X# if NetBSD1_3 > 6 >X# include "opt_inet.h" >X# include "opt_iso.h" >X# endif >X#endif >X >X#include <sys/systm.h> >X#include <sys/kernel.h> >X#include <sys/sockio.h> >X#include <sys/socket.h> >X#include <sys/syslog.h> >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X#include <machine/random.h> >X#endif >X#include <sys/malloc.h> >X#include <sys/mbuf.h> >X >X#if defined (__OpenBSD__) >X#include <sys/md5k.h> >X#else >X#include <sys/md5.h> >X#endif >X >X#include <net/if.h> >X#include <net/netisr.h> >X#include <net/if_types.h> >X#include <net/route.h> >X >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X#include <machine/random.h> >X#endif >X#if defined (__NetBSD__) || defined (__OpenBSD__) >X#include <machine/cpu.h> /* XXX for softnet */ >X#endif >X >X#include <machine/stdarg.h> >X >X#ifdef INET >X#include <netinet/in.h> >X#include <netinet/in_systm.h> >X#include <netinet/in_var.h> >X#include <netinet/ip.h> >X#include <netinet/tcp.h> >X# if defined (__FreeBSD__) || defined (__OpenBSD__) >X# include <netinet/if_ether.h> >X# else >X# include <net/ethertypes.h> >X# endif >X#else >X# error Huh? sppp without INET? >X#endif >X >X#ifdef IPX >X#include <netipx/ipx.h> >X#include <netipx/ipx_if.h> >X#endif >X >X#ifdef NS >X#include <netns/ns.h> >X#include <netns/ns_if.h> >X#endif >X >X#ifdef ISO >X#include <netiso/argo_debug.h> >X#include <netiso/iso.h> >X#include <netiso/iso_var.h> >X#include <netiso/iso_snpac.h> >X#endif >X >X#include <net/if_sppp.h> >X >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X# define UNTIMEOUT(fun, arg, handle) untimeout(fun, arg, handle) >X# define TIMEOUT(fun, arg1, arg2, handle) handle = timeout(fun, arg1, arg2) >X# define IOCTL_CMD_T u_long >X#else >X# define UNTIMEOUT(fun, arg, handle) untimeout(fun, arg) >X# define TIMEOUT(fun, arg1, arg2, handle) timeout(fun, arg1, arg2) >X# define IOCTL_CMD_T int >X#endif >X >X#define MAXALIVECNT 3 /* max. alive packets */ >X >X/* >X * Interface flags that can be set in an ifconfig command. >X * >X * Setting link0 will make the link passive, i.e. it will be marked >X * as being administrative openable, but won't be opened to begin >X * with. Incoming calls will be answered, or subsequent calls with >X * -link1 will cause the administrative open of the LCP layer. >X * >X * Setting link1 will cause the link to auto-dial only as packets >X * arrive to be sent. >X * >X * Setting IFF_DEBUG will syslog the option negotiation and state >X * transitions at level kern.debug. Note: all logs consistently look >X * like >X * >X * <if-name><unit>: <proto-name> <additional info...> >X * >X * with <if-name><unit> being something like "bppp0", and <proto-name> >X * being one of "lcp", "ipcp", "cisco", "chap", "pap", etc. >X */ >X >X#define IFF_PASSIVE IFF_LINK0 /* wait passively for connection */ >X#define IFF_AUTO IFF_LINK1 /* auto-dial on output */ >X >X#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ >X#define PPP_UI 0x03 /* Unnumbered Information */ >X#define PPP_IP 0x0021 /* Internet Protocol */ >X#define PPP_ISO 0x0023 /* ISO OSI Protocol */ >X#define PPP_XNS 0x0025 /* Xerox NS Protocol */ >X#define PPP_IPX 0x002b /* Novell IPX Protocol */ >X#define PPP_LCP 0xc021 /* Link Control Protocol */ >X#define PPP_PAP 0xc023 /* Password Authentication Protocol */ >X#define PPP_CHAP 0xc223 /* Challenge-Handshake Auth Protocol */ >X#define PPP_IPCP 0x8021 /* Internet Protocol Control Protocol */ >X >X#define CONF_REQ 1 /* PPP configure request */ >X#define CONF_ACK 2 /* PPP configure acknowledge */ >X#define CONF_NAK 3 /* PPP configure negative ack */ >X#define CONF_REJ 4 /* PPP configure reject */ >X#define TERM_REQ 5 /* PPP terminate request */ >X#define TERM_ACK 6 /* PPP terminate acknowledge */ >X#define CODE_REJ 7 /* PPP code reject */ >X#define PROTO_REJ 8 /* PPP protocol reject */ >X#define ECHO_REQ 9 /* PPP echo request */ >X#define ECHO_REPLY 10 /* PPP echo reply */ >X#define DISC_REQ 11 /* PPP discard request */ >X >X#define LCP_OPT_MRU 1 /* maximum receive unit */ >X#define LCP_OPT_ASYNC_MAP 2 /* async control character map */ >X#define LCP_OPT_AUTH_PROTO 3 /* authentication protocol */ >X#define LCP_OPT_QUAL_PROTO 4 /* quality protocol */ >X#define LCP_OPT_MAGIC 5 /* magic number */ >X#define LCP_OPT_RESERVED 6 /* reserved */ >X#define LCP_OPT_PROTO_COMP 7 /* protocol field compression */ >X#define LCP_OPT_ADDR_COMP 8 /* address/control field compression */ >X >X#define IPCP_OPT_ADDRESSES 1 /* both IP addresses; deprecated */ >X#define IPCP_OPT_COMPRESSION 2 /* IP compression protocol (VJ) */ >X#define IPCP_OPT_ADDRESS 3 /* local IP address */ >X >X#define PAP_REQ 1 /* PAP name/password request */ >X#define PAP_ACK 2 /* PAP acknowledge */ >X#define PAP_NAK 3 /* PAP fail */ >X >X#define CHAP_CHALLENGE 1 /* CHAP challenge request */ >X#define CHAP_RESPONSE 2 /* CHAP challenge response */ >X#define CHAP_SUCCESS 3 /* CHAP response ok */ >X#define CHAP_FAILURE 4 /* CHAP response failed */ >X >X#define CHAP_MD5 5 /* hash algorithm - MD5 */ >X >X#define CISCO_MULTICAST 0x8f /* Cisco multicast address */ >X#define CISCO_UNICAST 0x0f /* Cisco unicast address */ >X#define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */ >X#define CISCO_ADDR_REQ 0 /* Cisco address request */ >X#define CISCO_ADDR_REPLY 1 /* Cisco address reply */ >X#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ >X >X/* states are named and numbered according to RFC 1661 */ >X#define STATE_INITIAL 0 >X#define STATE_STARTING 1 >X#define STATE_CLOSED 2 >X#define STATE_STOPPED 3 >X#define STATE_CLOSING 4 >X#define STATE_STOPPING 5 >X#define STATE_REQ_SENT 6 >X#define STATE_ACK_RCVD 7 >X#define STATE_ACK_SENT 8 >X#define STATE_OPENED 9 >X >Xstruct ppp_header { >X u_char address; >X u_char control; >X u_short protocol; >X}; >X#define PPP_HEADER_LEN sizeof (struct ppp_header) >X >Xstruct lcp_header { >X u_char type; >X u_char ident; >X u_short len; >X}; >X#define LCP_HEADER_LEN sizeof (struct lcp_header) >X >Xstruct cisco_packet { >X u_long type; >X u_long par1; >X u_long par2; >X u_short rel; >X u_short time0; >X u_short time1; >X}; >X#define CISCO_PACKET_LEN 18 >X >X/* >X * We follow the spelling and capitalization of RFC 1661 here, to make >X * it easier comparing with the standard. Please refer to this RFC in >X * case you can't make sense out of these abbreviation; it will also >X * explain the semantics related to the various events and actions. >X */ >Xstruct cp { >X u_short proto; /* PPP control protocol number */ >X u_char protoidx; /* index into state table in struct sppp */ >X u_char flags; >X#define CP_LCP 0x01 /* this is the LCP */ >X#define CP_AUTH 0x02 /* this is an authentication protocol */ >X#define CP_NCP 0x04 /* this is a NCP */ >X#define CP_QUAL 0x08 /* this is a quality reporting protocol */ >X const char *name; /* name of this control protocol */ >X /* event handlers */ >X void (*Up)(struct sppp *sp); >X void (*Down)(struct sppp *sp); >X void (*Open)(struct sppp *sp); >X void (*Close)(struct sppp *sp); >X void (*TO)(void *sp); >X int (*RCR)(struct sppp *sp, struct lcp_header *h, int len); >X void (*RCN_rej)(struct sppp *sp, struct lcp_header *h, int len); >X void (*RCN_nak)(struct sppp *sp, struct lcp_header *h, int len); >X /* actions */ >X void (*tlu)(struct sppp *sp); >X void (*tld)(struct sppp *sp); >X void (*tls)(struct sppp *sp); >X void (*tlf)(struct sppp *sp); >X void (*scr)(struct sppp *sp); >X}; >X >Xstatic struct sppp *spppq; >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >Xstatic struct callout_handle keepalive_ch; >X#endif >X >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X#define SPP_FMT "%s%d: " >X#define SPP_ARGS(ifp) (ifp)->if_name, (ifp)->if_unit >X#else >X#define SPP_FMT "%s: " >X#define SPP_ARGS(ifp) (ifp)->if_xname >X#endif >X >X/* >X * The following disgusting hack gets around the problem that IP TOS >X * can't be set yet. We want to put "interactive" traffic on a high >X * priority queue. To decide if traffic is interactive, we check that >X * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control. >X * >X * XXX is this really still necessary? - joerg - >X */ >Xstatic u_short interactive_ports[8] = { >X 0, 513, 0, 0, >X 0, 21, 0, 23, >X}; >X#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p)) >X >X/* almost every function needs these */ >X#define STDDCL \ >X struct ifnet *ifp = &sp->pp_if; \ >X int debug = ifp->if_flags & IFF_DEBUG >X >Xstatic int sppp_output(struct ifnet *ifp, struct mbuf *m, >X struct sockaddr *dst, struct rtentry *rt); >X >Xstatic void sppp_cisco_send(struct sppp *sp, int type, long par1, long par2); >Xstatic void sppp_cisco_input(struct sppp *sp, struct mbuf *m); >X >Xstatic void sppp_cp_input(const struct cp *cp, struct sppp *sp, >X struct mbuf *m); >Xstatic void sppp_cp_send(struct sppp *sp, u_short proto, u_char type, >X u_char ident, u_short len, void *data); >X/* static void sppp_cp_timeout(void *arg); */ >Xstatic void sppp_cp_change_state(const struct cp *cp, struct sppp *sp, >X int newstate); >Xstatic void sppp_auth_send(const struct cp *cp, >X struct sppp *sp, unsigned int type, unsigned int id, >X ...); >X >Xstatic void sppp_up_event(const struct cp *cp, struct sppp *sp); >Xstatic void sppp_down_event(const struct cp *cp, struct sppp *sp); >Xstatic void sppp_open_event(const struct cp *cp, struct sppp *sp); >Xstatic void sppp_close_event(const struct cp *cp, struct sppp *sp); >Xstatic void sppp_to_event(const struct cp *cp, struct sppp *sp); >X >Xstatic void sppp_null(struct sppp *sp); >X >Xstatic void sppp_lcp_init(struct sppp *sp); >Xstatic void sppp_lcp_up(struct sppp *sp); >Xstatic void sppp_lcp_down(struct sppp *sp); >Xstatic void sppp_lcp_open(struct sppp *sp); >Xstatic void sppp_lcp_close(struct sppp *sp); >Xstatic void sppp_lcp_TO(void *sp); >Xstatic int sppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len); >Xstatic void sppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len); >Xstatic void sppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len); >Xstatic void sppp_lcp_tlu(struct sppp *sp); >Xstatic void sppp_lcp_tld(struct sppp *sp); >Xstatic void sppp_lcp_tls(struct sppp *sp); >Xstatic void sppp_lcp_tlf(struct sppp *sp); >Xstatic void sppp_lcp_scr(struct sppp *sp); >Xstatic void sppp_lcp_check_and_close(struct sppp *sp); >Xstatic int sppp_ncp_check(struct sppp *sp); >X >Xstatic void sppp_ipcp_init(struct sppp *sp); >Xstatic void sppp_ipcp_up(struct sppp *sp); >Xstatic void sppp_ipcp_down(struct sppp *sp); >Xstatic void sppp_ipcp_open(struct sppp *sp); >Xstatic void sppp_ipcp_close(struct sppp *sp); >Xstatic void sppp_ipcp_TO(void *sp); >Xstatic int sppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len); >Xstatic void sppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len); >Xstatic void sppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len); >Xstatic void sppp_ipcp_tlu(struct sppp *sp); >Xstatic void sppp_ipcp_tld(struct sppp *sp); >Xstatic void sppp_ipcp_tls(struct sppp *sp); >Xstatic void sppp_ipcp_tlf(struct sppp *sp); >Xstatic void sppp_ipcp_scr(struct sppp *sp); >X >Xstatic void sppp_pap_input(struct sppp *sp, struct mbuf *m); >Xstatic void sppp_pap_init(struct sppp *sp); >Xstatic void sppp_pap_open(struct sppp *sp); >Xstatic void sppp_pap_close(struct sppp *sp); >Xstatic void sppp_pap_TO(void *sp); >Xstatic void sppp_pap_my_TO(void *sp); >Xstatic void sppp_pap_tlu(struct sppp *sp); >Xstatic void sppp_pap_tld(struct sppp *sp); >Xstatic void sppp_pap_scr(struct sppp *sp); >X >Xstatic void sppp_chap_input(struct sppp *sp, struct mbuf *m); >Xstatic void sppp_chap_init(struct sppp *sp); >Xstatic void sppp_chap_open(struct sppp *sp); >Xstatic void sppp_chap_close(struct sppp *sp); >Xstatic void sppp_chap_TO(void *sp); >Xstatic void sppp_chap_tlu(struct sppp *sp); >Xstatic void sppp_chap_tld(struct sppp *sp); >Xstatic void sppp_chap_scr(struct sppp *sp); >X >Xstatic const char *sppp_auth_type_name(u_short proto, u_char type); >Xstatic const char *sppp_cp_type_name(u_char type); >Xstatic const char *sppp_dotted_quad(u_long addr); >Xstatic const char *sppp_ipcp_opt_name(u_char opt); >Xstatic const char *sppp_lcp_opt_name(u_char opt); >Xstatic const char *sppp_phase_name(enum ppp_phase phase); >Xstatic const char *sppp_proto_name(u_short proto); >Xstatic const char *sppp_state_name(int state); >Xstatic int sppp_params(struct sppp *sp, u_long cmd, void *data); >Xstatic int sppp_strnlen(u_char *p, int max); >Xstatic void sppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst, >X u_long *srcmask); >Xstatic void sppp_keepalive(void *dummy); >Xstatic void sppp_phase_network(struct sppp *sp); >Xstatic void sppp_print_bytes(const u_char *p, u_short len); >Xstatic void sppp_print_string(const char *p, u_short len); >Xstatic void sppp_qflush(struct ifqueue *ifq); >Xstatic void sppp_set_ip_addr(struct sppp *sp, u_long src); >X >X/* our control protocol descriptors */ >Xstatic const struct cp lcp = { >X PPP_LCP, IDX_LCP, CP_LCP, "lcp", >X sppp_lcp_up, sppp_lcp_down, sppp_lcp_open, sppp_lcp_close, >X sppp_lcp_TO, sppp_lcp_RCR, sppp_lcp_RCN_rej, sppp_lcp_RCN_nak, >X sppp_lcp_tlu, sppp_lcp_tld, sppp_lcp_tls, sppp_lcp_tlf, >X sppp_lcp_scr >X}; >X >Xstatic const struct cp ipcp = { >X PPP_IPCP, IDX_IPCP, CP_NCP, "ipcp", >X sppp_ipcp_up, sppp_ipcp_down, sppp_ipcp_open, sppp_ipcp_close, >X sppp_ipcp_TO, sppp_ipcp_RCR, sppp_ipcp_RCN_rej, sppp_ipcp_RCN_nak, >X sppp_ipcp_tlu, sppp_ipcp_tld, sppp_ipcp_tls, sppp_ipcp_tlf, >X sppp_ipcp_scr >X}; >X >Xstatic const struct cp pap = { >X PPP_PAP, IDX_PAP, CP_AUTH, "pap", >X sppp_null, sppp_null, sppp_pap_open, sppp_pap_close, >X sppp_pap_TO, 0, 0, 0, >X sppp_pap_tlu, sppp_pap_tld, sppp_null, sppp_null, >X sppp_pap_scr >X}; >X >Xstatic const struct cp chap = { >X PPP_CHAP, IDX_CHAP, CP_AUTH, "chap", >X sppp_null, sppp_null, sppp_chap_open, sppp_chap_close, >X sppp_chap_TO, 0, 0, 0, >X sppp_chap_tlu, sppp_chap_tld, sppp_null, sppp_null, >X sppp_chap_scr >X}; >X >Xstatic const struct cp *cps[IDX_COUNT] = { >X &lcp, /* IDX_LCP */ >X &ipcp, /* IDX_IPCP */ >X &pap, /* IDX_PAP */ >X &chap, /* IDX_CHAP */ >X}; >X >X >X/* >X * Exported functions, comprising our interface to the lower layer. >X */ >X >X/* >X * Process the received packet. >X */ >Xvoid >Xsppp_input(struct ifnet *ifp, struct mbuf *m) >X{ >X struct ppp_header *h; >X struct ifqueue *inq = 0; >X int s; >X struct sppp *sp = (struct sppp *)ifp; >X int debug = ifp->if_flags & IFF_DEBUG; >X >X if (ifp->if_flags & IFF_UP) >X /* Count received bytes, add FCS and one flag */ >X ifp->if_ibytes += m->m_pkthdr.len + 3; >X >X if (m->m_pkthdr.len <= PPP_HEADER_LEN) { >X /* Too small packet, drop it. */ >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "input packet is too small, %d bytes\n", >X SPP_ARGS(ifp), m->m_pkthdr.len); >X drop: >X ++ifp->if_ierrors; >X ++ifp->if_iqdrops; >X m_freem (m); >X return; >X } >X >X /* Get PPP header. */ >X h = mtod (m, struct ppp_header*); >X m_adj (m, PPP_HEADER_LEN); >X >X switch (h->address) { >X case PPP_ALLSTATIONS: >X if (h->control != PPP_UI) >X goto invalid; >X if (sp->pp_flags & PP_CISCO) { >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "PPP packet in Cisco mode " >X "<addr=0x%x ctrl=0x%x proto=0x%x>\n", >X SPP_ARGS(ifp), >X h->address, h->control, ntohs(h->protocol)); >X goto drop; >X } >X switch (ntohs (h->protocol)) { >X default: >X if (sp->state[IDX_LCP] == STATE_OPENED) >X sppp_cp_send (sp, PPP_LCP, PROTO_REJ, >X ++sp->pp_seq, m->m_pkthdr.len + 2, >X &h->protocol); >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "invalid input protocol " >X "<addr=0x%x ctrl=0x%x proto=0x%x>\n", >X SPP_ARGS(ifp), >X h->address, h->control, ntohs(h->protocol)); >X ++ifp->if_noproto; >X goto drop; >X case PPP_LCP: >X sppp_cp_input(&lcp, sp, m); >X m_freem (m); >X return; >X case PPP_PAP: >X if (sp->pp_phase >= PHASE_AUTHENTICATE) >X sppp_pap_input(sp, m); >X m_freem (m); >X return; >X case PPP_CHAP: >X if (sp->pp_phase >= PHASE_AUTHENTICATE) >X sppp_chap_input(sp, m); >X m_freem (m); >X return; >X#ifdef INET >X case PPP_IPCP: >X if (sp->pp_phase == PHASE_NETWORK) >X sppp_cp_input(&ipcp, sp, m); >X m_freem (m); >X return; >X case PPP_IP: >X if (sp->state[IDX_IPCP] == STATE_OPENED) { >X schednetisr (NETISR_IP); >X inq = &ipintrq; >X } >X break; >X#endif >X#ifdef IPX >X case PPP_IPX: >X /* IPX IPXCP not implemented yet */ >X if (sp->pp_phase == PHASE_NETWORK) { >X schednetisr (NETISR_IPX); >X inq = &ipxintrq; >X } >X break; >X#endif >X#ifdef NS >X case PPP_XNS: >X /* XNS IDPCP not implemented yet */ >X if (sp->pp_phase == PHASE_NETWORK) { >X schednetisr (NETISR_NS); >X inq = &nsintrq; >X } >X break; >X#endif >X#ifdef ISO >X case PPP_ISO: >X /* OSI NLCP not implemented yet */ >X if (sp->pp_phase == PHASE_NETWORK) { >X schednetisr (NETISR_ISO); >X inq = &clnlintrq; >X } >X break; >X#endif >X } >X break; >X case CISCO_MULTICAST: >X case CISCO_UNICAST: >X /* Don't check the control field here (RFC 1547). */ >X if (! (sp->pp_flags & PP_CISCO)) { >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "Cisco packet in PPP mode " >X "<addr=0x%x ctrl=0x%x proto=0x%x>\n", >X SPP_ARGS(ifp), >X h->address, h->control, ntohs(h->protocol)); >X goto drop; >X } >X switch (ntohs (h->protocol)) { >X default: >X ++ifp->if_noproto; >X goto invalid; >X case CISCO_KEEPALIVE: >X sppp_cisco_input ((struct sppp*) ifp, m); >X m_freem (m); >X return; >X#ifdef INET >X case ETHERTYPE_IP: >X schednetisr (NETISR_IP); >X inq = &ipintrq; >X break; >X#endif >X#ifdef IPX >X case ETHERTYPE_IPX: >X schednetisr (NETISR_IPX); >X inq = &ipxintrq; >X break; >X#endif >X#ifdef NS >X case ETHERTYPE_NS: >X schednetisr (NETISR_NS); >X inq = &nsintrq; >X break; >X#endif >X } >X break; >X default: /* Invalid PPP packet. */ >X invalid: >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "invalid input packet " >X "<addr=0x%x ctrl=0x%x proto=0x%x>\n", >X SPP_ARGS(ifp), >X h->address, h->control, ntohs(h->protocol)); >X goto drop; >X } >X >X if (! (ifp->if_flags & IFF_UP) || ! inq) >X goto drop; >X >X /* Check queue. */ >X s = splimp(); >X if (IF_QFULL (inq)) { >X /* Queue overflow. */ >X IF_DROP(inq); >X splx(s); >X if (debug) >X log(LOG_DEBUG, SPP_FMT "protocol queue overflow\n", >X SPP_ARGS(ifp)); >X goto drop; >X } >X IF_ENQUEUE(inq, m); >X splx(s); >X} >X >X/* >X * Enqueue transmit packet. >X */ >Xstatic int >Xsppp_output(struct ifnet *ifp, struct mbuf *m, >X struct sockaddr *dst, struct rtentry *rt) >X{ >X struct sppp *sp = (struct sppp*) ifp; >X struct ppp_header *h; >X struct ifqueue *ifq; >X int s, rv = 0; >X int debug = ifp->if_flags & IFF_DEBUG; >X >X s = splimp(); >X >X if ((ifp->if_flags & IFF_UP) == 0 || >X (ifp->if_flags & (IFF_RUNNING | IFF_AUTO)) == 0) { >X m_freem (m); >X splx (s); >X return (ENETDOWN); >X } >X >X if ((ifp->if_flags & (IFF_RUNNING | IFF_AUTO)) == IFF_AUTO) { >X /* >X * Interface is not yet running, but auto-dial. Need >X * to start LCP for it. >X */ >X ifp->if_flags |= IFF_RUNNING; >X splx(s); >X lcp.Open(sp); >X s = splimp(); >X } >X >X ifq = &ifp->if_snd; >X#ifdef INET >X if (dst->sa_family == AF_INET) { >X /* XXX Check mbuf length here? */ >X struct ip *ip = mtod (m, struct ip*); >X struct tcphdr *tcp = (struct tcphdr*) ((long*)ip + ip->ip_hl); >X >X /* >X * When using dynamic local IP address assignment by using >X * 0.0.0.0 as a local address, the first TCP session will >X * not connect because the local TCP checksum is computed >X * using 0.0.0.0 which will later become our real IP address >X * so the TCP checksum computed at the remote end will >X * become invalid. So we >X * - don't let packets with src ip addr 0 thru >X * - we flag TCP packets with src ip 0 as an error >X */ >X >X if(ip->ip_src.s_addr == INADDR_ANY) /* -hm */ >X { >X m_freem(m); >X splx(s); >X if(ip->ip_p == IPPROTO_TCP) >X return(EADDRNOTAVAIL); >X else >X return(0); >X } >X >X /* >X * Put low delay, telnet, rlogin and ftp control packets >X * in front of the queue. >X */ >X if (IF_QFULL (&sp->pp_fastq)) >X ; >X else if (ip->ip_tos & IPTOS_LOWDELAY) >X ifq = &sp->pp_fastq; >X else if (m->m_len < sizeof *ip + sizeof *tcp) >X ; >X else if (ip->ip_p != IPPROTO_TCP) >X ; >X else if (INTERACTIVE (ntohs (tcp->th_sport))) >X ifq = &sp->pp_fastq; >X else if (INTERACTIVE (ntohs (tcp->th_dport))) >X ifq = &sp->pp_fastq; >X } >X#endif >X >X /* >X * Prepend general data packet PPP header. For now, IP only. >X */ >X M_PREPEND (m, PPP_HEADER_LEN, M_DONTWAIT); >X if (! m) { >X if (debug) >X log(LOG_DEBUG, SPP_FMT "no memory for transmit header\n", >X SPP_ARGS(ifp)); >X ++ifp->if_oerrors; >X splx (s); >X return (ENOBUFS); >X } >X /* >X * May want to check size of packet >X * (albeit due to the implementation it's always enough) >X */ >X h = mtod (m, struct ppp_header*); >X if (sp->pp_flags & PP_CISCO) { >X h->address = CISCO_UNICAST; /* unicast address */ >X h->control = 0; >X } else { >X h->address = PPP_ALLSTATIONS; /* broadcast address */ >X h->control = PPP_UI; /* Unnumbered Info */ >X } >X >X switch (dst->sa_family) { >X#ifdef INET >X case AF_INET: /* Internet Protocol */ >X if (sp->pp_flags & PP_CISCO) >X h->protocol = htons (ETHERTYPE_IP); >X else { >X /* >X * Don't choke with an ENETDOWN early. It's >X * possible that we just started dialing out, >X * so don't drop the packet immediately. If >X * we notice that we run out of buffer space >X * below, we will however remember that we are >X * not ready to carry IP packets, and return >X * ENETDOWN, as opposed to ENOBUFS. >X */ >X h->protocol = htons(PPP_IP); >X if (sp->state[IDX_IPCP] != STATE_OPENED) >X rv = ENETDOWN; >X } >X break; >X#endif >X#ifdef NS >X case AF_NS: /* Xerox NS Protocol */ >X h->protocol = htons ((sp->pp_flags & PP_CISCO) ? >X ETHERTYPE_NS : PPP_XNS); >X break; >X#endif >X#ifdef IPX >X case AF_IPX: /* Novell IPX Protocol */ >X h->protocol = htons ((sp->pp_flags & PP_CISCO) ? >X ETHERTYPE_IPX : PPP_IPX); >X break; >X#endif >X#ifdef ISO >X case AF_ISO: /* ISO OSI Protocol */ >X if (sp->pp_flags & PP_CISCO) >X goto nosupport; >X h->protocol = htons (PPP_ISO); >X break; >Xnosupport: >X#endif >X default: >X m_freem (m); >X ++ifp->if_oerrors; >X splx (s); >X return (EAFNOSUPPORT); >X } >X >X /* >X * Queue message on interface, and start output if interface >X * not yet active. >X */ >X if (IF_QFULL (ifq)) { >X IF_DROP (&ifp->if_snd); >X m_freem (m); >X ++ifp->if_oerrors; >X splx (s); >X return (rv? rv: ENOBUFS); >X } >X IF_ENQUEUE (ifq, m); >X if (! (ifp->if_flags & IFF_OACTIVE)) >X (*ifp->if_start) (ifp); >X >X /* >X * Count output packets and bytes. >X * The packet length includes header, FCS and 1 flag, >X * according to RFC 1333. >X */ >X ifp->if_obytes += m->m_pkthdr.len + 3; >X splx (s); >X return (0); >X} >X >Xvoid >Xsppp_attach(struct ifnet *ifp) >X{ >X struct sppp *sp = (struct sppp*) ifp; >X >X /* Initialize keepalive handler. */ >X if (! spppq) >X TIMEOUT(sppp_keepalive, 0, hz * 10, keepalive_ch); >X >X /* Insert new entry into the keepalive list. */ >X sp->pp_next = spppq; >X spppq = sp; >X >X sp->pp_if.if_mtu = PP_MTU; >X sp->pp_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; >X sp->pp_if.if_type = IFT_PPP; >X sp->pp_if.if_output = sppp_output; >X#if 0 >X sp->pp_flags = PP_KEEPALIVE; >X#endif >X sp->pp_fastq.ifq_maxlen = 32; >X sp->pp_cpq.ifq_maxlen = 20; >X sp->pp_loopcnt = 0; >X sp->pp_alivecnt = 0; >X sp->pp_seq = 0; >X sp->pp_rseq = 0; >X sp->pp_phase = PHASE_DEAD; >X sp->pp_up = lcp.Up; >X sp->pp_down = lcp.Down; >X >X sppp_lcp_init(sp); >X sppp_ipcp_init(sp); >X sppp_pap_init(sp); >X sppp_chap_init(sp); >X} >X >Xvoid >Xsppp_detach(struct ifnet *ifp) >X{ >X struct sppp **q, *p, *sp = (struct sppp*) ifp; >X int i; >X >X /* Remove the entry from the keepalive list. */ >X for (q = &spppq; (p = *q); q = &p->pp_next) >X if (p == sp) { >X *q = p->pp_next; >X break; >X } >X >X /* Stop keepalive handler. */ >X if (! spppq) >X UNTIMEOUT(sppp_keepalive, 0, keepalive_ch); >X >X for (i = 0; i < IDX_COUNT; i++) >X UNTIMEOUT((cps[i])->TO, (void *)sp, sp->ch[i]); >X UNTIMEOUT(sppp_pap_my_TO, (void *)sp, sp->pap_my_to_ch); >X} >X >X/* >X * Flush the interface output queue. >X */ >Xvoid >Xsppp_flush(struct ifnet *ifp) >X{ >X struct sppp *sp = (struct sppp*) ifp; >X >X sppp_qflush (&sp->pp_if.if_snd); >X sppp_qflush (&sp->pp_fastq); >X sppp_qflush (&sp->pp_cpq); >X} >X >X/* >X * Check if the output queue is empty. >X */ >Xint >Xsppp_isempty(struct ifnet *ifp) >X{ >X struct sppp *sp = (struct sppp*) ifp; >X int empty, s; >X >X s = splimp(); >X empty = !sp->pp_fastq.ifq_head && !sp->pp_cpq.ifq_head && >X !sp->pp_if.if_snd.ifq_head; >X splx(s); >X return (empty); >X} >X >X/* >X * Get next packet to send. >X */ >Xstruct mbuf * >Xsppp_dequeue(struct ifnet *ifp) >X{ >X struct sppp *sp = (struct sppp*) ifp; >X struct mbuf *m; >X int s; >X >X s = splimp(); >X /* >X * Process only the control protocol queue until we have at >X * least one NCP open. >X * >X * Do always serve all three queues in Cisco mode. >X */ >X IF_DEQUEUE(&sp->pp_cpq, m); >X if (m == NULL && >X (sppp_ncp_check(sp) || (sp->pp_flags & PP_CISCO) != 0)) { >X IF_DEQUEUE(&sp->pp_fastq, m); >X if (m == NULL) >X IF_DEQUEUE (&sp->pp_if.if_snd, m); >X } >X splx(s); >X return m; >X} >X >X/* >X * Pick the next packet, do not remove it from the queue. >X */ >Xstruct mbuf * >Xsppp_pick(struct ifnet *ifp) >X{ >X struct sppp *sp = (struct sppp*)ifp; >X struct mbuf *m; >X int s; >X >X s= splimp (); >X >X m = sp->pp_cpq.ifq_head; >X if (m == NULL && >X (sp->pp_phase == PHASE_NETWORK || >X (sp->pp_flags & PP_CISCO) != 0)) >X if ((m = sp->pp_fastq.ifq_head) == NULL) >X m = sp->pp_if.if_snd.ifq_head; >X splx (s); >X return (m); >X} >X >X/* >X * Process an ioctl request. Called on low priority level. >X */ >Xint >Xsppp_ioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, void *data) >X{ >X struct ifreq *ifr = (struct ifreq*) data; >X struct sppp *sp = (struct sppp*) ifp; >X int s, rv, going_up, going_down, newmode; >X >X s = splimp(); >X rv = 0; >X switch (cmd) { >X case SIOCAIFADDR: >X case SIOCSIFDSTADDR: >X break; >X >X case SIOCSIFADDR: >X if_up(ifp); >X /* fall through... */ >X >X case SIOCSIFFLAGS: >X going_up = ifp->if_flags & IFF_UP && >X (ifp->if_flags & IFF_RUNNING) == 0; >X going_down = (ifp->if_flags & IFF_UP) == 0 && >X ifp->if_flags & IFF_RUNNING; >X newmode = ifp->if_flags & (IFF_AUTO | IFF_PASSIVE); >X if (newmode == (IFF_AUTO | IFF_PASSIVE)) { >X /* sanity */ >X newmode = IFF_PASSIVE; >X ifp->if_flags &= ~IFF_AUTO; >X } >X >X if (going_up || going_down) >X lcp.Close(sp); >X if (going_up && newmode == 0) { >X /* neither auto-dial nor passive */ >X ifp->if_flags |= IFF_RUNNING; >X if (!(sp->pp_flags & PP_CISCO)) >X lcp.Open(sp); >X } else if (going_down) { >X sppp_flush(ifp); >X ifp->if_flags &= ~IFF_RUNNING; >X } >X >X break; >X >X#ifdef SIOCSIFMTU >X#ifndef ifr_mtu >X#define ifr_mtu ifr_metric >X#endif >X case SIOCSIFMTU: >X if (ifr->ifr_mtu < 128 || ifr->ifr_mtu > sp->lcp.their_mru) >X return (EINVAL); >X ifp->if_mtu = ifr->ifr_mtu; >X break; >X#endif >X#ifdef SLIOCSETMTU >X case SLIOCSETMTU: >X if (*(short*)data < 128 || *(short*)data > sp->lcp.their_mru) >X return (EINVAL); >X ifp->if_mtu = *(short*)data; >X break; >X#endif >X#ifdef SIOCGIFMTU >X case SIOCGIFMTU: >X ifr->ifr_mtu = ifp->if_mtu; >X break; >X#endif >X#ifdef SLIOCGETMTU >X case SLIOCGETMTU: >X *(short*)data = ifp->if_mtu; >X break; >X#endif >X case SIOCADDMULTI: >X case SIOCDELMULTI: >X break; >X >X case SIOCGIFGENERIC: >X case SIOCSIFGENERIC: >X rv = sppp_params(sp, cmd, data); >X break; >X >X default: >X rv = ENOTTY; >X } >X splx(s); >X return rv; >X} >X >X >X/* >X * Cisco framing implementation. >X */ >X >X/* >X * Handle incoming Cisco keepalive protocol packets. >X */ >Xstatic void >Xsppp_cisco_input(struct sppp *sp, struct mbuf *m) >X{ >X STDDCL; >X struct cisco_packet *h; >X u_long me, mymask; >X >X if (m->m_pkthdr.len < CISCO_PACKET_LEN) { >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "cisco invalid packet length: %d bytes\n", >X SPP_ARGS(ifp), m->m_pkthdr.len); >X return; >X } >X h = mtod (m, struct cisco_packet*); >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "cisco input: %d bytes " >X "<0x%lx 0x%lx 0x%lx 0x%x 0x%x-0x%x>\n", >X SPP_ARGS(ifp), m->m_pkthdr.len, >X (u_long)ntohl (h->type), (u_long)h->par1, (u_long)h->par2, (u_int)h->rel, >X (u_int)h->time0, (u_int)h->time1); >X switch (ntohl (h->type)) { >X default: >X if (debug) >X addlog(SPP_FMT "cisco unknown packet type: 0x%lx\n", >X SPP_ARGS(ifp), (u_long)ntohl (h->type)); >X break; >X case CISCO_ADDR_REPLY: >X /* Reply on address request, ignore */ >X break; >X case CISCO_KEEPALIVE_REQ: >X sp->pp_alivecnt = 0; >X sp->pp_rseq = ntohl (h->par1); >X if (sp->pp_seq == sp->pp_rseq) { >X /* Local and remote sequence numbers are equal. >X * Probably, the line is in loopback mode. */ >X if (sp->pp_loopcnt >= MAXALIVECNT) { >X printf (SPP_FMT "loopback\n", >X SPP_ARGS(ifp)); >X sp->pp_loopcnt = 0; >X if (ifp->if_flags & IFF_UP) { >X if_down (ifp); >X sppp_qflush (&sp->pp_cpq); >X } >X } >X ++sp->pp_loopcnt; >X >X /* Generate new local sequence number */ >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X sp->pp_seq = random(); >X#else >X sp->pp_seq ^= time.tv_sec ^ time.tv_usec; >X#endif >X break; >X } >X sp->pp_loopcnt = 0; >X if (! (ifp->if_flags & IFF_UP) && >X (ifp->if_flags & IFF_RUNNING)) { >X if_up(ifp); >X printf (SPP_FMT "up\n", SPP_ARGS(ifp)); >X } >X break; >X case CISCO_ADDR_REQ: >X sppp_get_ip_addrs(sp, &me, 0, &mymask); >X if (me != 0L) >X sppp_cisco_send(sp, CISCO_ADDR_REPLY, me, mymask); >X break; >X } >X} >X >X/* >X * Send Cisco keepalive packet. >X */ >Xstatic void >Xsppp_cisco_send(struct sppp *sp, int type, long par1, long par2) >X{ >X STDDCL; >X struct ppp_header *h; >X struct cisco_packet *ch; >X struct mbuf *m; >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X struct timeval tv; >X#else >X u_long t = (time.tv_sec - boottime.tv_sec) * 1000; >X#endif >X >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X getmicrouptime(&tv); >X#endif >X >X MGETHDR (m, M_DONTWAIT, MT_DATA); >X if (! m) >X return; >X m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + CISCO_PACKET_LEN; >X m->m_pkthdr.rcvif = 0; >X >X h = mtod (m, struct ppp_header*); >X h->address = CISCO_MULTICAST; >X h->control = 0; >X h->protocol = htons (CISCO_KEEPALIVE); >X >X ch = (struct cisco_packet*) (h + 1); >X ch->type = htonl (type); >X ch->par1 = htonl (par1); >X ch->par2 = htonl (par2); >X ch->rel = -1; >X >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X ch->time0 = htons ((u_short) (tv.tv_sec >> 16)); >X ch->time1 = htons ((u_short) tv.tv_sec); >X#else >X ch->time0 = htons ((u_short) (t >> 16)); >X ch->time1 = htons ((u_short) t); >X#endif >X >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "cisco output: <0x%lx 0x%lx 0x%lx 0x%x 0x%x-0x%x>\n", >X SPP_ARGS(ifp), (u_long)ntohl (ch->type), (u_long)ch->par1, >X (u_long)ch->par2, (u_int)ch->rel, (u_int)ch->time0, (u_int)ch->time1); >X >X if (IF_QFULL (&sp->pp_cpq)) { >X IF_DROP (&sp->pp_fastq); >X IF_DROP (&ifp->if_snd); >X m_freem (m); >X } else >X IF_ENQUEUE (&sp->pp_cpq, m); >X if (! (ifp->if_flags & IFF_OACTIVE)) >X (*ifp->if_start) (ifp); >X ifp->if_obytes += m->m_pkthdr.len + 3; >X} >X >X/* >X * PPP protocol implementation. >X */ >X >X/* >X * Send PPP control protocol packet. >X */ >Xstatic void >Xsppp_cp_send(struct sppp *sp, u_short proto, u_char type, >X u_char ident, u_short len, void *data) >X{ >X STDDCL; >X struct ppp_header *h; >X struct lcp_header *lh; >X struct mbuf *m; >X >X if (len > MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN) >X len = MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN; >X MGETHDR (m, M_DONTWAIT, MT_DATA); >X if (! m) >X return; >X m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + LCP_HEADER_LEN + len; >X m->m_pkthdr.rcvif = 0; >X >X h = mtod (m, struct ppp_header*); >X h->address = PPP_ALLSTATIONS; /* broadcast address */ >X h->control = PPP_UI; /* Unnumbered Info */ >X h->protocol = htons (proto); /* Link Control Protocol */ >X >X lh = (struct lcp_header*) (h + 1); >X lh->type = type; >X lh->ident = ident; >X lh->len = htons (LCP_HEADER_LEN + len); >X if (len) >X bcopy (data, lh+1, len); >X >X if (debug) { >X log(LOG_DEBUG, SPP_FMT "%s output <%s id=0x%x len=%d", >X SPP_ARGS(ifp), >X sppp_proto_name(proto), >X sppp_cp_type_name (lh->type), lh->ident, >X ntohs (lh->len)); >X if (len) >X sppp_print_bytes ((u_char*) (lh+1), len); >X addlog(">\n"); >X } >X if (IF_QFULL (&sp->pp_cpq)) { >X IF_DROP (&sp->pp_fastq); >X IF_DROP (&ifp->if_snd); >X m_freem (m); >X ++ifp->if_oerrors; >X } else >X IF_ENQUEUE (&sp->pp_cpq, m); >X if (! (ifp->if_flags & IFF_OACTIVE)) >X (*ifp->if_start) (ifp); >X ifp->if_obytes += m->m_pkthdr.len + 3; >X} >X >X/* >X * Handle incoming PPP control protocol packets. >X */ >Xstatic void >Xsppp_cp_input(const struct cp *cp, struct sppp *sp, struct mbuf *m) >X{ >X STDDCL; >X struct lcp_header *h; >X int len = m->m_pkthdr.len; >X int rv; >X u_char *p; >X >X if (len < 4) { >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "%s invalid packet length: %d bytes\n", >X SPP_ARGS(ifp), cp->name, len); >X return; >X } >X h = mtod (m, struct lcp_header*); >X if (debug) { >X log(LOG_DEBUG, >X SPP_FMT "%s input(%s): <%s id=0x%x len=%d", >X SPP_ARGS(ifp), cp->name, >X sppp_state_name(sp->state[cp->protoidx]), >X sppp_cp_type_name (h->type), h->ident, ntohs (h->len)); >X if (len > 4) >X sppp_print_bytes ((u_char*) (h+1), len-4); >X addlog(">\n"); >X } >X if (len > ntohs (h->len)) >X len = ntohs (h->len); >X p = (u_char *)(h + 1); >X switch (h->type) { >X case CONF_REQ: >X if (len < 4) { >X if (debug) >X addlog(SPP_FMT "%s invalid conf-req length %d\n", >X SPP_ARGS(ifp), cp->name, >X len); >X ++ifp->if_ierrors; >X break; >X } >X /* handle states where RCR doesn't get a SCA/SCN */ >X switch (sp->state[cp->protoidx]) { >X case STATE_CLOSING: >X case STATE_STOPPING: >X return; >X case STATE_CLOSED: >X sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, >X 0, 0); >X return; >X } >X rv = (cp->RCR)(sp, h, len); >X switch (sp->state[cp->protoidx]) { >X case STATE_OPENED: >X (cp->tld)(sp); >X (cp->scr)(sp); >X /* fall through... */ >X case STATE_ACK_SENT: >X case STATE_REQ_SENT: >X sppp_cp_change_state(cp, sp, rv? >X STATE_ACK_SENT: STATE_REQ_SENT); >X break; >X case STATE_STOPPED: >X sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; >X (cp->scr)(sp); >X sppp_cp_change_state(cp, sp, rv? >X STATE_ACK_SENT: STATE_REQ_SENT); >X break; >X case STATE_ACK_RCVD: >X if (rv) { >X sppp_cp_change_state(cp, sp, STATE_OPENED); >X if (debug) >X log(LOG_DEBUG, SPP_FMT "%s tlu\n", >X SPP_ARGS(ifp), >X cp->name); >X (cp->tlu)(sp); >X } else >X sppp_cp_change_state(cp, sp, STATE_ACK_RCVD); >X break; >X default: >X printf(SPP_FMT "%s illegal %s in state %s\n", >X SPP_ARGS(ifp), cp->name, >X sppp_cp_type_name(h->type), >X sppp_state_name(sp->state[cp->protoidx])); >X ++ifp->if_ierrors; >X } >X break; >X case CONF_ACK: >X if (h->ident != sp->confid[cp->protoidx]) { >X if (debug) >X addlog(SPP_FMT "%s id mismatch 0x%x != 0x%x\n", >X SPP_ARGS(ifp), cp->name, >X h->ident, sp->confid[cp->protoidx]); >X ++ifp->if_ierrors; >X break; >X } >X switch (sp->state[cp->protoidx]) { >X case STATE_CLOSED: >X case STATE_STOPPED: >X sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0); >X break; >X case STATE_CLOSING: >X case STATE_STOPPING: >X break; >X case STATE_REQ_SENT: >X sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; >X sppp_cp_change_state(cp, sp, STATE_ACK_RCVD); >X break; >X case STATE_OPENED: >X (cp->tld)(sp); >X /* fall through */ >X case STATE_ACK_RCVD: >X (cp->scr)(sp); >X sppp_cp_change_state(cp, sp, STATE_REQ_SENT); >X break; >X case STATE_ACK_SENT: >X sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; >X sppp_cp_change_state(cp, sp, STATE_OPENED); >X if (debug) >X log(LOG_DEBUG, SPP_FMT "%s tlu\n", >X SPP_ARGS(ifp), cp->name); >X (cp->tlu)(sp); >X break; >X default: >X printf(SPP_FMT "%s illegal %s in state %s\n", >X SPP_ARGS(ifp), cp->name, >X sppp_cp_type_name(h->type), >X sppp_state_name(sp->state[cp->protoidx])); >X ++ifp->if_ierrors; >X } >X break; >X case CONF_NAK: >X case CONF_REJ: >X if (h->ident != sp->confid[cp->protoidx]) { >X if (debug) >X addlog(SPP_FMT "%s id mismatch 0x%x != 0x%x\n", >X SPP_ARGS(ifp), cp->name, >X h->ident, sp->confid[cp->protoidx]); >X ++ifp->if_ierrors; >X break; >X } >X if (h->type == CONF_NAK) >X (cp->RCN_nak)(sp, h, len); >X else /* CONF_REJ */ >X (cp->RCN_rej)(sp, h, len); >X >X switch (sp->state[cp->protoidx]) { >X case STATE_CLOSED: >X case STATE_STOPPED: >X sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0); >X break; >X case STATE_REQ_SENT: >X case STATE_ACK_SENT: >X sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; >X (cp->scr)(sp); >X break; >X case STATE_OPENED: >X (cp->tld)(sp); >X /* fall through */ >X case STATE_ACK_RCVD: >X sppp_cp_change_state(cp, sp, STATE_ACK_SENT); >X (cp->scr)(sp); >X break; >X case STATE_CLOSING: >X case STATE_STOPPING: >X break; >X default: >X printf(SPP_FMT "%s illegal %s in state %s\n", >X SPP_ARGS(ifp), cp->name, >X sppp_cp_type_name(h->type), >X sppp_state_name(sp->state[cp->protoidx])); >X ++ifp->if_ierrors; >X } >X break; >X >X case TERM_REQ: >X switch (sp->state[cp->protoidx]) { >X case STATE_ACK_RCVD: >X case STATE_ACK_SENT: >X sppp_cp_change_state(cp, sp, STATE_REQ_SENT); >X /* fall through */ >X case STATE_CLOSED: >X case STATE_STOPPED: >X case STATE_CLOSING: >X case STATE_STOPPING: >X case STATE_REQ_SENT: >X sta: >X /* Send Terminate-Ack packet. */ >X if (debug) >X log(LOG_DEBUG, SPP_FMT "%s send terminate-ack\n", >X SPP_ARGS(ifp), cp->name); >X sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0); >X break; >X case STATE_OPENED: >X (cp->tld)(sp); >X sp->rst_counter[cp->protoidx] = 0; >X sppp_cp_change_state(cp, sp, STATE_STOPPING); >X goto sta; >X break; >X default: >X printf(SPP_FMT "%s illegal %s in state %s\n", >X SPP_ARGS(ifp), cp->name, >X sppp_cp_type_name(h->type), >X sppp_state_name(sp->state[cp->protoidx])); >X ++ifp->if_ierrors; >X } >X break; >X case TERM_ACK: >X switch (sp->state[cp->protoidx]) { >X case STATE_CLOSED: >X case STATE_STOPPED: >X case STATE_REQ_SENT: >X case STATE_ACK_SENT: >X break; >X case STATE_CLOSING: >X sppp_cp_change_state(cp, sp, STATE_CLOSED); >X (cp->tlf)(sp); >X break; >X case STATE_STOPPING: >X sppp_cp_change_state(cp, sp, STATE_STOPPED); >X (cp->tlf)(sp); >X break; >X case STATE_ACK_RCVD: >X sppp_cp_change_state(cp, sp, STATE_REQ_SENT); >X break; >X case STATE_OPENED: >X (cp->tld)(sp); >X (cp->scr)(sp); >X sppp_cp_change_state(cp, sp, STATE_ACK_RCVD); >X break; >X default: >X printf(SPP_FMT "%s illegal %s in state %s\n", >X SPP_ARGS(ifp), cp->name, >X sppp_cp_type_name(h->type), >X sppp_state_name(sp->state[cp->protoidx])); >X ++ifp->if_ierrors; >X } >X break; >X case CODE_REJ: >X case PROTO_REJ: >X /* XXX catastrophic rejects (RXJ-) aren't handled yet. */ >X log(LOG_INFO, >X SPP_FMT "%s: ignoring RXJ (%s) for proto 0x%x, " >X "danger will robinson\n", >X SPP_ARGS(ifp), cp->name, >X sppp_cp_type_name(h->type), ntohs(*((u_short *)p))); >X switch (sp->state[cp->protoidx]) { >X case STATE_CLOSED: >X case STATE_STOPPED: >X case STATE_REQ_SENT: >X case STATE_ACK_SENT: >X case STATE_CLOSING: >X case STATE_STOPPING: >X case STATE_OPENED: >X break; >X case STATE_ACK_RCVD: >X sppp_cp_change_state(cp, sp, STATE_REQ_SENT); >X break; >X default: >X printf(SPP_FMT "%s illegal %s in state %s\n", >X SPP_ARGS(ifp), cp->name, >X sppp_cp_type_name(h->type), >X sppp_state_name(sp->state[cp->protoidx])); >X ++ifp->if_ierrors; >X } >X break; >X case DISC_REQ: >X if (cp->proto != PPP_LCP) >X goto illegal; >X /* Discard the packet. */ >X break; >X case ECHO_REQ: >X if (cp->proto != PPP_LCP) >X goto illegal; >X if (sp->state[cp->protoidx] != STATE_OPENED) { >X if (debug) >X addlog(SPP_FMT "lcp echo req but lcp closed\n", >X SPP_ARGS(ifp)); >X ++ifp->if_ierrors; >X break; >X } >X if (len < 8) { >X if (debug) >X addlog(SPP_FMT "invalid lcp echo request " >X "packet length: %d bytes\n", >X SPP_ARGS(ifp), len); >X break; >X } >X if (ntohl (*(long*)(h+1)) == sp->lcp.magic) { >X /* Line loopback mode detected. */ >X printf(SPP_FMT "loopback\n", SPP_ARGS(ifp)); >X if_down (ifp); >X sppp_qflush (&sp->pp_cpq); >X >X /* Shut down the PPP link. */ >X /* XXX */ >X lcp.Down(sp); >X lcp.Up(sp); >X break; >X } >X *(long*)(h+1) = htonl (sp->lcp.magic); >X if (debug) >X addlog(SPP_FMT "got lcp echo req, sending echo rep\n", >X SPP_ARGS(ifp)); >X sppp_cp_send (sp, PPP_LCP, ECHO_REPLY, h->ident, len-4, h+1); >X break; >X case ECHO_REPLY: >X if (cp->proto != PPP_LCP) >X goto illegal; >X if (h->ident != sp->lcp.echoid) { >X ++ifp->if_ierrors; >X break; >X } >X if (len < 8) { >X if (debug) >X addlog(SPP_FMT "lcp invalid echo reply " >X "packet length: %d bytes\n", >X SPP_ARGS(ifp), len); >X break; >X } >X if (debug) >X addlog(SPP_FMT "lcp got echo rep\n", >X SPP_ARGS(ifp)); >X if (ntohl (*(long*)(h+1)) != sp->lcp.magic) >X sp->pp_alivecnt = 0; >X break; >X default: >X /* Unknown packet type -- send Code-Reject packet. */ >X illegal: >X if (debug) >X addlog(SPP_FMT "%s send code-rej for 0x%x\n", >X SPP_ARGS(ifp), cp->name, h->type); >X sppp_cp_send(sp, cp->proto, CODE_REJ, ++sp->pp_seq, >X m->m_pkthdr.len, h); >X ++ifp->if_ierrors; >X } >X} >X >X >X/* >X * The generic part of all Up/Down/Open/Close/TO event handlers. >X * Basically, the state transition handling in the automaton. >X */ >Xstatic void >Xsppp_up_event(const struct cp *cp, struct sppp *sp) >X{ >X STDDCL; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "%s up(%s)\n", >X SPP_ARGS(ifp), cp->name, >X sppp_state_name(sp->state[cp->protoidx])); >X >X switch (sp->state[cp->protoidx]) { >X case STATE_INITIAL: >X sppp_cp_change_state(cp, sp, STATE_CLOSED); >X break; >X case STATE_STARTING: >X sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; >X (cp->scr)(sp); >X sppp_cp_change_state(cp, sp, STATE_REQ_SENT); >X break; >X default: >X printf(SPP_FMT "%s illegal up in state %s\n", >X SPP_ARGS(ifp), cp->name, >X sppp_state_name(sp->state[cp->protoidx])); >X } >X} >X >Xstatic void >Xsppp_down_event(const struct cp *cp, struct sppp *sp) >X{ >X STDDCL; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "%s down(%s)\n", >X SPP_ARGS(ifp), cp->name, >X sppp_state_name(sp->state[cp->protoidx])); >X >X switch (sp->state[cp->protoidx]) { >X case STATE_CLOSED: >X case STATE_CLOSING: >X sppp_cp_change_state(cp, sp, STATE_INITIAL); >X break; >X case STATE_STOPPED: >X sppp_cp_change_state(cp, sp, STATE_STARTING); >X (cp->tls)(sp); >X break; >X case STATE_STOPPING: >X case STATE_REQ_SENT: >X case STATE_ACK_RCVD: >X case STATE_ACK_SENT: >X sppp_cp_change_state(cp, sp, STATE_STARTING); >X break; >X case STATE_OPENED: >X (cp->tld)(sp); >X sppp_cp_change_state(cp, sp, STATE_STARTING); >X break; >X default: >X printf(SPP_FMT "%s illegal down in state %s\n", >X SPP_ARGS(ifp), cp->name, >X sppp_state_name(sp->state[cp->protoidx])); >X } >X} >X >X >Xstatic void >Xsppp_open_event(const struct cp *cp, struct sppp *sp) >X{ >X STDDCL; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "%s open(%s)\n", >X SPP_ARGS(ifp), cp->name, >X sppp_state_name(sp->state[cp->protoidx])); >X >X switch (sp->state[cp->protoidx]) { >X case STATE_INITIAL: >X sppp_cp_change_state(cp, sp, STATE_STARTING); >X (cp->tls)(sp); >X break; >X case STATE_STARTING: >X break; >X case STATE_CLOSED: >X sp->rst_counter[cp->protoidx] = sp->lcp.max_configure; >X (cp->scr)(sp); >X sppp_cp_change_state(cp, sp, STATE_REQ_SENT); >X break; >X case STATE_STOPPED: >X case STATE_STOPPING: >X case STATE_REQ_SENT: >X case STATE_ACK_RCVD: >X case STATE_ACK_SENT: >X case STATE_OPENED: >X break; >X case STATE_CLOSING: >X sppp_cp_change_state(cp, sp, STATE_STOPPING); >X break; >X } >X} >X >X >Xstatic void >Xsppp_close_event(const struct cp *cp, struct sppp *sp) >X{ >X STDDCL; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "%s close(%s)\n", >X SPP_ARGS(ifp), cp->name, >X sppp_state_name(sp->state[cp->protoidx])); >X >X switch (sp->state[cp->protoidx]) { >X case STATE_INITIAL: >X case STATE_CLOSED: >X case STATE_CLOSING: >X break; >X case STATE_STARTING: >X sppp_cp_change_state(cp, sp, STATE_INITIAL); >X (cp->tlf)(sp); >X break; >X case STATE_STOPPED: >X sppp_cp_change_state(cp, sp, STATE_CLOSED); >X break; >X case STATE_STOPPING: >X sppp_cp_change_state(cp, sp, STATE_CLOSING); >X break; >X case STATE_OPENED: >X (cp->tld)(sp); >X /* fall through */ >X case STATE_REQ_SENT: >X case STATE_ACK_RCVD: >X case STATE_ACK_SENT: >X sp->rst_counter[cp->protoidx] = sp->lcp.max_terminate; >X sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq, 0, 0); >X sppp_cp_change_state(cp, sp, STATE_CLOSING); >X break; >X } >X} >X >Xstatic void >Xsppp_to_event(const struct cp *cp, struct sppp *sp) >X{ >X STDDCL; >X int s; >X >X s = splimp(); >X if (debug) >X log(LOG_DEBUG, SPP_FMT "%s TO(%s) rst_counter = %d\n", >X SPP_ARGS(ifp), cp->name, >X sppp_state_name(sp->state[cp->protoidx]), >X sp->rst_counter[cp->protoidx]); >X >X if (--sp->rst_counter[cp->protoidx] < 0) >X /* TO- event */ >X switch (sp->state[cp->protoidx]) { >X case STATE_CLOSING: >X sppp_cp_change_state(cp, sp, STATE_CLOSED); >X (cp->tlf)(sp); >X break; >X case STATE_STOPPING: >X sppp_cp_change_state(cp, sp, STATE_STOPPED); >X (cp->tlf)(sp); >X break; >X case STATE_REQ_SENT: >X case STATE_ACK_RCVD: >X case STATE_ACK_SENT: >X sppp_cp_change_state(cp, sp, STATE_STOPPED); >X (cp->tlf)(sp); >X break; >X } >X else >X /* TO+ event */ >X switch (sp->state[cp->protoidx]) { >X case STATE_CLOSING: >X case STATE_STOPPING: >X sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq, >X 0, 0); >X TIMEOUT(cp->TO, (void *)sp, sp->lcp.timeout, >X sp->ch[cp->protoidx]); >X break; >X case STATE_REQ_SENT: >X case STATE_ACK_RCVD: >X (cp->scr)(sp); >X /* sppp_cp_change_state() will restart the timer */ >X sppp_cp_change_state(cp, sp, STATE_REQ_SENT); >X break; >X case STATE_ACK_SENT: >X (cp->scr)(sp); >X TIMEOUT(cp->TO, (void *)sp, sp->lcp.timeout, >X sp->ch[cp->protoidx]); >X break; >X } >X >X splx(s); >X} >X >X/* >X * Change the state of a control protocol in the state automaton. >X * Takes care of starting/stopping the restart timer. >X */ >Xvoid >Xsppp_cp_change_state(const struct cp *cp, struct sppp *sp, int newstate) >X{ >X sp->state[cp->protoidx] = newstate; >X >X UNTIMEOUT(cp->TO, (void *)sp, sp->ch[cp->protoidx]); >X switch (newstate) { >X case STATE_INITIAL: >X case STATE_STARTING: >X case STATE_CLOSED: >X case STATE_STOPPED: >X case STATE_OPENED: >X break; >X case STATE_CLOSING: >X case STATE_STOPPING: >X case STATE_REQ_SENT: >X case STATE_ACK_RCVD: >X case STATE_ACK_SENT: >X TIMEOUT(cp->TO, (void *)sp, sp->lcp.timeout, >X sp->ch[cp->protoidx]); >X break; >X } >X} >X/* >X *--------------------------------------------------------------------------* >X * * >X * The LCP implementation. * >X * * >X *--------------------------------------------------------------------------* >X */ >Xstatic void >Xsppp_lcp_init(struct sppp *sp) >X{ >X sp->lcp.opts = (1 << LCP_OPT_MAGIC); >X sp->lcp.magic = 0; >X sp->state[IDX_LCP] = STATE_INITIAL; >X sp->fail_counter[IDX_LCP] = 0; >X sp->lcp.protos = 0; >X sp->lcp.mru = sp->lcp.their_mru = PP_MTU; >X >X /* >X * Initialize counters and timeout values. Note that we don't >X * use the 3 seconds suggested in RFC 1661 since we are likely >X * running on a fast link. XXX We should probably implement >X * the exponential backoff option. Note that these values are >X * relevant for all control protocols, not just LCP only. >X */ >X sp->lcp.timeout = 1 * hz; >X sp->lcp.max_terminate = 2; >X sp->lcp.max_configure = 10; >X sp->lcp.max_failure = 10; >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X callout_handle_init(&sp->ch[IDX_LCP]); >X#endif >X} >X >Xstatic void >Xsppp_lcp_up(struct sppp *sp) >X{ >X STDDCL; >X >X /* >X * If this interface is passive or dial-on-demand, and we are >X * still in Initial state, it means we've got an incoming >X * call. Activate the interface. >X */ >X if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) != 0) { >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "Up event", SPP_ARGS(ifp)); >X ifp->if_flags |= IFF_RUNNING; >X if (sp->state[IDX_LCP] == STATE_INITIAL) { >X if (debug) >X addlog("(incoming call)\n"); >X sp->pp_flags |= PP_CALLIN; >X lcp.Open(sp); >X } else if (debug) >X addlog("\n"); >X } >X >X sppp_up_event(&lcp, sp); >X} >X >Xstatic void >Xsppp_lcp_down(struct sppp *sp) >X{ >X STDDCL; >X >X sppp_down_event(&lcp, sp); >X >X /* >X * If this is neither a dial-on-demand nor a passive >X * interface, simulate an ``ifconfig down'' action, so the >X * administrator can force a redial by another ``ifconfig >X * up''. XXX For leased line operation, should we immediately >X * try to reopen the connection here? >X */ >X if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) == 0) { >X log(LOG_INFO, >X SPP_FMT "Down event, taking interface down.\n", >X SPP_ARGS(ifp)); >X if_down(ifp); >X } else { >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "Down event (carrier loss)\n", >X SPP_ARGS(ifp)); >X } >X sp->pp_flags &= ~PP_CALLIN; >X if (sp->state[IDX_LCP] != STATE_INITIAL) >X lcp.Close(sp); >X ifp->if_flags &= ~IFF_RUNNING; >X} >X >Xstatic void >Xsppp_lcp_open(struct sppp *sp) >X{ >X /* >X * If we are authenticator, negotiate LCP_AUTH >X */ >X if (sp->hisauth.proto != 0) >X sp->lcp.opts |= (1 << LCP_OPT_AUTH_PROTO); >X else >X sp->lcp.opts &= ~(1 << LCP_OPT_AUTH_PROTO); >X sp->pp_flags &= ~PP_NEEDAUTH; >X sppp_open_event(&lcp, sp); >X} >X >Xstatic void >Xsppp_lcp_close(struct sppp *sp) >X{ >X sppp_close_event(&lcp, sp); >X} >X >Xstatic void >Xsppp_lcp_TO(void *cookie) >X{ >X sppp_to_event(&lcp, (struct sppp *)cookie); >X} >X >X/* >X * Analyze a configure request. Return true if it was agreeable, and >X * caused action sca, false if it has been rejected or nak'ed, and >X * caused action scn. (The return value is used to make the state >X * transition decision in the state automaton.) >X */ >Xstatic int >Xsppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len) >X{ >X STDDCL; >X u_char *buf, *r, *p; >X int origlen, rlen; >X u_long nmagic; >X u_short authproto; >X >X len -= 4; >X origlen = len; >X buf = r = malloc (len, M_TEMP, M_NOWAIT); >X if (! buf) >X return (0); >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "lcp parse opts: ", >X SPP_ARGS(ifp)); >X >X /* pass 1: check for things that need to be rejected */ >X p = (void*) (h+1); >X for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { >X if (debug) >X addlog(" %s ", sppp_lcp_opt_name(*p)); >X switch (*p) { >X case LCP_OPT_MAGIC: >X /* Magic number. */ >X /* fall through, both are same length */ >X case LCP_OPT_ASYNC_MAP: >X /* Async control character map. */ >X if (len >= 6 || p[1] == 6) >X continue; >X if (debug) >X addlog("[invalid] "); >X break; >X case LCP_OPT_MRU: >X /* Maximum receive unit. */ >X if (len >= 4 && p[1] == 4) >X continue; >X if (debug) >X addlog("[invalid] "); >X break; >X case LCP_OPT_AUTH_PROTO: >X if (len < 4) { >X if (debug) >X addlog("[invalid] "); >X break; >X } >X authproto = (p[2] << 8) + p[3]; >X if (authproto == PPP_CHAP && p[1] != 5) { >X if (debug) >X addlog("[invalid chap len] "); >X break; >X } >X if (sp->myauth.proto == 0) { >X /* we are not configured to do auth */ >X if (debug) >X addlog("[not configured] "); >X break; >X } >X /* >X * Remote want us to authenticate, remember this, >X * so we stay in PHASE_AUTHENTICATE after LCP got >X * up. >X */ >X sp->pp_flags |= PP_NEEDAUTH; >X continue; >X default: >X /* Others not supported. */ >X if (debug) >X addlog("[rej] "); >X break; >X } >X /* Add the option to rejected list. */ >X bcopy (p, r, p[1]); >X r += p[1]; >X rlen += p[1]; >X } >X if (rlen) { >X if (debug) >X addlog(" send conf-rej\n"); >X sppp_cp_send (sp, PPP_LCP, CONF_REJ, h->ident, rlen, buf); >X return 0; >X } else if (debug) >X addlog("\n"); >X >X /* >X * pass 2: check for option values that are unacceptable and >X * thus require to be nak'ed. >X */ >X if (debug) >X log(LOG_DEBUG, SPP_FMT "lcp parse opt values: ", >X SPP_ARGS(ifp)); >X >X p = (void*) (h+1); >X len = origlen; >X for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { >X if (debug) >X addlog(" %s ", sppp_lcp_opt_name(*p)); >X switch (*p) { >X case LCP_OPT_MAGIC: >X /* Magic number -- extract. */ >X nmagic = (u_long)p[2] << 24 | >X (u_long)p[3] << 16 | p[4] << 8 | p[5]; >X if (nmagic != sp->lcp.magic) { >X if (debug) >X addlog("0x%lx ", nmagic); >X continue; >X } >X /* >X * Local and remote magics equal -- loopback? >X */ >X if (sp->pp_loopcnt >= MAXALIVECNT*5) { >X printf (SPP_FMT "loopback\n", >X SPP_ARGS(ifp)); >X sp->pp_loopcnt = 0; >X if (ifp->if_flags & IFF_UP) { >X if_down(ifp); >X sppp_qflush(&sp->pp_cpq); >X /* XXX ? */ >X lcp.Down(sp); >X lcp.Up(sp); >X } >X } else if (debug) >X addlog("[glitch] "); >X ++sp->pp_loopcnt; >X /* >X * We negate our magic here, and NAK it. If >X * we see it later in an NAK packet, we >X * suggest a new one. >X */ >X nmagic = ~sp->lcp.magic; >X /* Gonna NAK it. */ >X p[2] = nmagic >> 24; >X p[3] = nmagic >> 16; >X p[4] = nmagic >> 8; >X p[5] = nmagic; >X break; >X >X case LCP_OPT_ASYNC_MAP: >X /* Async control character map -- check to be zero. */ >X if (! p[2] && ! p[3] && ! p[4] && ! p[5]) { >X if (debug) >X addlog("[empty] "); >X continue; >X } >X if (debug) >X addlog("[non-empty] "); >X /* suggest a zero one */ >X p[2] = p[3] = p[4] = p[5] = 0; >X break; >X >X case LCP_OPT_MRU: >X /* >X * Maximum receive unit. Always agreeable, >X * but ignored by now. >X */ >X sp->lcp.their_mru = p[2] * 256 + p[3]; >X if (debug) >X addlog("%lu ", sp->lcp.their_mru); >X continue; >X >X case LCP_OPT_AUTH_PROTO: >X authproto = (p[2] << 8) + p[3]; >X if (sp->myauth.proto != authproto) { >X /* not agreed, nak */ >X if (debug) >X addlog("[mine %s != his %s] ", >X sppp_proto_name(sp->hisauth.proto), >X sppp_proto_name(authproto)); >X p[2] = sp->myauth.proto >> 8; >X p[3] = sp->myauth.proto; >X break; >X } >X if (authproto == PPP_CHAP && p[4] != CHAP_MD5) { >X if (debug) >X addlog("[chap not MD5] "); >X p[4] = CHAP_MD5; >X break; >X } >X continue; >X } >X /* Add the option to nak'ed list. */ >X bcopy (p, r, p[1]); >X r += p[1]; >X rlen += p[1]; >X } >X if (rlen) { >X if (++sp->fail_counter[IDX_LCP] >= sp->lcp.max_failure) { >X if (debug) >X addlog(" max_failure (%d) exceeded, " >X "send conf-rej\n", >X sp->lcp.max_failure); >X sppp_cp_send(sp, PPP_LCP, CONF_REJ, h->ident, rlen, buf); >X } else { >X if (debug) >X addlog(" send conf-nak\n"); >X sppp_cp_send (sp, PPP_LCP, CONF_NAK, h->ident, rlen, buf); >X } >X return 0; >X } else { >X if (debug) >X addlog(" send conf-ack\n"); >X sp->fail_counter[IDX_LCP] = 0; >X sp->pp_loopcnt = 0; >X sppp_cp_send (sp, PPP_LCP, CONF_ACK, >X h->ident, origlen, h+1); >X } >X >X free (buf, M_TEMP); >X return (rlen == 0); >X} >X >X/* >X * Analyze the LCP Configure-Reject option list, and adjust our >X * negotiation. >X */ >Xstatic void >Xsppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len) >X{ >X STDDCL; >X u_char *buf, *p; >X >X len -= 4; >X buf = malloc (len, M_TEMP, M_NOWAIT); >X if (!buf) >X return; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "lcp rej opts: ", >X SPP_ARGS(ifp)); >X >X p = (void*) (h+1); >X for (; len > 1 && p[1]; len -= p[1], p += p[1]) { >X if (debug) >X addlog(" %s ", sppp_lcp_opt_name(*p)); >X switch (*p) { >X case LCP_OPT_MAGIC: >X /* Magic number -- can't use it, use 0 */ >X sp->lcp.opts &= ~(1 << LCP_OPT_MAGIC); >X sp->lcp.magic = 0; >X break; >X case LCP_OPT_MRU: >X /* >X * Should not be rejected anyway, since we only >X * negotiate a MRU if explicitly requested by >X * peer. >X */ >X sp->lcp.opts &= ~(1 << LCP_OPT_MRU); >X break; >X case LCP_OPT_AUTH_PROTO: >X /* >X * Peer doesn't want to authenticate himself, >X * deny unless this is a dialout call, and >X * AUTHFLAG_NOCALLOUT is set. >X */ >X if ((sp->pp_flags & PP_CALLIN) == 0 && >X (sp->hisauth.flags & AUTHFLAG_NOCALLOUT) != 0) { >X if (debug) >X addlog("[don't insist on auth " >X "for callout]"); >X sp->lcp.opts &= ~(1 << LCP_OPT_AUTH_PROTO); >X break; >X } >X if (debug) >X addlog("[access denied]\n"); >X lcp.Close(sp); >X break; >X } >X } >X if (debug) >X addlog("\n"); >X free (buf, M_TEMP); >X return; >X} >X >X/* >X * Analyze the LCP Configure-NAK option list, and adjust our >X * negotiation. >X */ >Xstatic void >Xsppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len) >X{ >X STDDCL; >X u_char *buf, *p; >X u_long magic; >X >X len -= 4; >X buf = malloc (len, M_TEMP, M_NOWAIT); >X if (!buf) >X return; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "lcp nak opts: ", >X SPP_ARGS(ifp)); >X >X p = (void*) (h+1); >X for (; len > 1 && p[1]; len -= p[1], p += p[1]) { >X if (debug) >X addlog(" %s ", sppp_lcp_opt_name(*p)); >X switch (*p) { >X case LCP_OPT_MAGIC: >X /* Magic number -- renegotiate */ >X if ((sp->lcp.opts & (1 << LCP_OPT_MAGIC)) && >X len >= 6 && p[1] == 6) { >X magic = (u_long)p[2] << 24 | >X (u_long)p[3] << 16 | p[4] << 8 | p[5]; >X /* >X * If the remote magic is our negated one, >X * this looks like a loopback problem. >X * Suggest a new magic to make sure. >X */ >X if (magic == ~sp->lcp.magic) { >X if (debug) >X addlog("magic glitch "); >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X sp->lcp.magic = random(); >X#else >X sp->lcp.magic = time.tv_sec + time.tv_usec; >X#endif >X } else { >X sp->lcp.magic = magic; >X if (debug) >X addlog("%lu ", magic); >X } >X } >X break; >X case LCP_OPT_MRU: >X /* >X * Peer wants to advise us to negotiate an MRU. >X * Agree on it if it's reasonable, or use >X * default otherwise. >X */ >X if (len >= 4 && p[1] == 4) { >X u_int mru = p[2] * 256 + p[3]; >X if (debug) >X addlog("%d ", mru); >X if (mru < PP_MTU || mru > PP_MAX_MRU) >X mru = PP_MTU; >X sp->lcp.mru = mru; >X sp->lcp.opts |= (1 << LCP_OPT_MRU); >X } >X break; >X case LCP_OPT_AUTH_PROTO: >X /* >X * Peer doesn't like our authentication method, >X * deny. >X */ >X if (debug) >X addlog("[access denied]\n"); >X lcp.Close(sp); >X break; >X } >X } >X if (debug) >X addlog("\n"); >X free (buf, M_TEMP); >X return; >X} >X >Xstatic void >Xsppp_lcp_tlu(struct sppp *sp) >X{ >X STDDCL; >X int i; >X u_long mask; >X >X /* XXX ? */ >X if (! (ifp->if_flags & IFF_UP) && >X (ifp->if_flags & IFF_RUNNING)) { >X /* Coming out of loopback mode. */ >X if_up(ifp); >X printf (SPP_FMT "up\n", SPP_ARGS(ifp)); >X } >X >X for (i = 0; i < IDX_COUNT; i++) >X if ((cps[i])->flags & CP_QUAL) >X (cps[i])->Open(sp); >X >X if ((sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) != 0 || >X (sp->pp_flags & PP_NEEDAUTH) != 0) >X sp->pp_phase = PHASE_AUTHENTICATE; >X else >X sp->pp_phase = PHASE_NETWORK; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "phase %s\n", SPP_ARGS(ifp), >X sppp_phase_name(sp->pp_phase)); >X >X /* >X * Open all authentication protocols. This is even required >X * if we already proceeded to network phase, since it might be >X * that remote wants us to authenticate, so we might have to >X * send a PAP request. Undesired authentication protocols >X * don't do anything when they get an Open event. >X */ >X for (i = 0; i < IDX_COUNT; i++) >X if ((cps[i])->flags & CP_AUTH) >X (cps[i])->Open(sp); >X >X if (sp->pp_phase == PHASE_NETWORK) { >X /* Notify all NCPs. */ >X for (i = 0; i < IDX_COUNT; i++) >X if ((cps[i])->flags & CP_NCP) >X (cps[i])->Open(sp); >X } >X >X /* Send Up events to all started protos. */ >X for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1) >X if (sp->lcp.protos & mask && ((cps[i])->flags & CP_LCP) == 0) >X (cps[i])->Up(sp); >X >X /* notify low-level driver of state change */ >X if (sp->pp_chg) >X sp->pp_chg(sp, (int)sp->pp_phase); >X >X if (sp->pp_phase == PHASE_NETWORK) >X /* if no NCP is starting, close down */ >X sppp_lcp_check_and_close(sp); >X} >X >Xstatic void >Xsppp_lcp_tld(struct sppp *sp) >X{ >X STDDCL; >X int i; >X u_long mask; >X >X sp->pp_phase = PHASE_TERMINATE; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "phase %s\n", SPP_ARGS(ifp), >X sppp_phase_name(sp->pp_phase)); >X >X /* >X * Take upper layers down. We send the Down event first and >X * the Close second to prevent the upper layers from sending >X * ``a flurry of terminate-request packets'', as the RFC >X * describes it. >X */ >X for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1) >X if (sp->lcp.protos & mask && ((cps[i])->flags & CP_LCP) == 0) { >X (cps[i])->Down(sp); >X (cps[i])->Close(sp); >X } >X} >X >Xstatic void >Xsppp_lcp_tls(struct sppp *sp) >X{ >X STDDCL; >X >X sp->pp_phase = PHASE_ESTABLISH; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "phase %s\n", SPP_ARGS(ifp), >X sppp_phase_name(sp->pp_phase)); >X >X /* Notify lower layer if desired. */ >X if (sp->pp_tls) >X (sp->pp_tls)(sp); >X else >X (sp->pp_up)(sp); >X} >X >Xstatic void >Xsppp_lcp_tlf(struct sppp *sp) >X{ >X STDDCL; >X >X sp->pp_phase = PHASE_DEAD; >X if (debug) >X log(LOG_DEBUG, SPP_FMT "phase %s\n", SPP_ARGS(ifp), >X sppp_phase_name(sp->pp_phase)); >X >X /* Notify lower layer if desired. */ >X if (sp->pp_tlf) >X (sp->pp_tlf)(sp); >X else >X (sp->pp_down)(sp); >X} >X >Xstatic void >Xsppp_lcp_scr(struct sppp *sp) >X{ >X char opt[6 /* magicnum */ + 4 /* mru */ + 5 /* chap */]; >X int i = 0; >X u_short authproto; >X >X if (sp->lcp.opts & (1 << LCP_OPT_MAGIC)) { >X if (! sp->lcp.magic) >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X sp->lcp.magic = random(); >X#else >X sp->lcp.magic = time.tv_sec + time.tv_usec; >X#endif >X opt[i++] = LCP_OPT_MAGIC; >X opt[i++] = 6; >X opt[i++] = sp->lcp.magic >> 24; >X opt[i++] = sp->lcp.magic >> 16; >X opt[i++] = sp->lcp.magic >> 8; >X opt[i++] = sp->lcp.magic; >X } >X >X if (sp->lcp.opts & (1 << LCP_OPT_MRU)) { >X opt[i++] = LCP_OPT_MRU; >X opt[i++] = 4; >X opt[i++] = sp->lcp.mru >> 8; >X opt[i++] = sp->lcp.mru; >X } >X >X if (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) { >X authproto = sp->hisauth.proto; >X opt[i++] = LCP_OPT_AUTH_PROTO; >X opt[i++] = authproto == PPP_CHAP? 5: 4; >X opt[i++] = authproto >> 8; >X opt[i++] = authproto; >X if (authproto == PPP_CHAP) >X opt[i++] = CHAP_MD5; >X } >X >X sp->confid[IDX_LCP] = ++sp->pp_seq; >X sppp_cp_send (sp, PPP_LCP, CONF_REQ, sp->confid[IDX_LCP], i, &opt); >X} >X >X/* >X * Check the open NCPs, return true if at least one NCP is open. >X */ >Xstatic int >Xsppp_ncp_check(struct sppp *sp) >X{ >X int i, mask; >X >X for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1) >X if (sp->lcp.protos & mask && (cps[i])->flags & CP_NCP) >X return 1; >X return 0; >X} >X >X/* >X * Re-check the open NCPs and see if we should terminate the link. >X * Called by the NCPs during their tlf action handling. >X */ >Xstatic void >Xsppp_lcp_check_and_close(struct sppp *sp) >X{ >X >X if (sp->pp_phase < PHASE_NETWORK) >X /* don't bother, we are already going down */ >X return; >X >X if (sppp_ncp_check(sp)) >X return; >X >X lcp.Close(sp); >X} >X/* >X *--------------------------------------------------------------------------* >X * * >X * The IPCP implementation. * >X * * >X *--------------------------------------------------------------------------* >X */ >X >Xstatic void >Xsppp_ipcp_init(struct sppp *sp) >X{ >X sp->ipcp.opts = 0; >X sp->ipcp.flags = 0; >X sp->state[IDX_IPCP] = STATE_INITIAL; >X sp->fail_counter[IDX_IPCP] = 0; >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X callout_handle_init(&sp->ch[IDX_IPCP]); >X#endif >X} >X >Xstatic void >Xsppp_ipcp_up(struct sppp *sp) >X{ >X sppp_up_event(&ipcp, sp); >X} >X >Xstatic void >Xsppp_ipcp_down(struct sppp *sp) >X{ >X sppp_down_event(&ipcp, sp); >X} >X >Xstatic void >Xsppp_ipcp_open(struct sppp *sp) >X{ >X STDDCL; >X u_long myaddr, hisaddr; >X >X sp->ipcp.flags &= ~(IPCP_HISADDR_SEEN|IPCP_MYADDR_SEEN|IPCP_MYADDR_DYN); >X >X sppp_get_ip_addrs(sp, &myaddr, &hisaddr, 0); >X /* >X * If we don't have his address, this probably means our >X * interface doesn't want to talk IP at all. (This could >X * be the case if somebody wants to speak only IPX, for >X * example.) Don't open IPCP in this case. >X */ >X if (hisaddr == 0L) { >X /* XXX this message should go away */ >X if (debug) >X log(LOG_DEBUG, SPP_FMT "ipcp_open(): no IP interface\n", >X SPP_ARGS(ifp)); >X return; >X } >X >X if (myaddr == 0L) { >X /* >X * I don't have an assigned address, so i need to >X * negotiate my address. >X */ >X sp->ipcp.flags |= IPCP_MYADDR_DYN; >X sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS); >X } else >X sp->ipcp.flags |= IPCP_MYADDR_SEEN; >X sppp_open_event(&ipcp, sp); >X} >X >Xstatic void >Xsppp_ipcp_close(struct sppp *sp) >X{ >X sppp_close_event(&ipcp, sp); >X if (sp->ipcp.flags & IPCP_MYADDR_DYN) >X /* >X * My address was dynamic, clear it again. >X */ >X sppp_set_ip_addr(sp, 0L); >X} >X >Xstatic void >Xsppp_ipcp_TO(void *cookie) >X{ >X sppp_to_event(&ipcp, (struct sppp *)cookie); >X} >X >X/* >X * Analyze a configure request. Return true if it was agreeable, and >X * caused action sca, false if it has been rejected or nak'ed, and >X * caused action scn. (The return value is used to make the state >X * transition decision in the state automaton.) >X */ >Xstatic int >Xsppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len) >X{ >X u_char *buf, *r, *p; >X struct ifnet *ifp = &sp->pp_if; >X int rlen, origlen, debug = ifp->if_flags & IFF_DEBUG; >X u_long hisaddr, desiredaddr; >X int gotmyaddr = 0; >X >X len -= 4; >X origlen = len; >X /* >X * Make sure to allocate a buf that can at least hold a >X * conf-nak with an `address' option. We might need it below. >X */ >X buf = r = malloc ((len < 6? 6: len), M_TEMP, M_NOWAIT); >X if (! buf) >X return (0); >X >X /* pass 1: see if we can recognize them */ >X if (debug) >X log(LOG_DEBUG, SPP_FMT "ipcp parse opts: ", >X SPP_ARGS(ifp)); >X p = (void*) (h+1); >X for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { >X if (debug) >X addlog(" %s ", sppp_ipcp_opt_name(*p)); >X switch (*p) { >X#ifdef notyet >X case IPCP_OPT_COMPRESSION: >X if (len >= 6 && p[1] >= 6) { >X /* correctly formed compress option */ >X continue; >X } >X if (debug) >X addlog("[invalid] "); >X break; >X#endif >X case IPCP_OPT_ADDRESS: >X if (len >= 6 && p[1] == 6) { >X /* correctly formed address option */ >X continue; >X } >X if (debug) >X addlog("[invalid] "); >X break; >X default: >X /* Others not supported. */ >X if (debug) >X addlog("[rej] "); >X break; >X } >X /* Add the option to rejected list. */ >X bcopy (p, r, p[1]); >X r += p[1]; >X rlen += p[1]; >X } >X if (rlen) { >X if (debug) >X addlog(" send conf-rej\n"); >X sppp_cp_send (sp, PPP_IPCP, CONF_REJ, h->ident, rlen, buf); >X return 0; >X } else if (debug) >X addlog("\n"); >X >X /* pass 2: parse option values */ >X sppp_get_ip_addrs(sp, 0, &hisaddr, 0); >X if (debug) >X log(LOG_DEBUG, SPP_FMT "ipcp parse opt values: ", >X SPP_ARGS(ifp)); >X p = (void*) (h+1); >X len = origlen; >X for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { >X if (debug) >X addlog(" %s ", sppp_ipcp_opt_name(*p)); >X switch (*p) { >X#ifdef notyet >X case IPCP_OPT_COMPRESSION: >X continue; >X#endif >X case IPCP_OPT_ADDRESS: >X /* This is the address he wants in his end */ >X desiredaddr = p[2] << 24 | p[3] << 16 | >X p[4] << 8 | p[5]; >X if (desiredaddr == hisaddr || >X (hisaddr == 1 && desiredaddr != 0)) { >X /* >X * Peer's address is same as our value, >X * or we have set it to 0.0.0.1 to >X * indicate that we do not really care, >X * this is agreeable. Gonna conf-ack >X * it. >X */ >X if (debug) >X addlog("%s [ack] ", >X sppp_dotted_quad(hisaddr)); >X /* record that we've seen it already */ >X sp->ipcp.flags |= IPCP_HISADDR_SEEN; >X continue; >X } >X /* >X * The address wasn't agreeable. This is either >X * he sent us 0.0.0.0, asking to assign him an >X * address, or he send us another address not >X * matching our value. Either case, we gonna >X * conf-nak it with our value. >X * XXX: we should "rej" if hisaddr == 0 >X */ >X if (debug) { >X if (desiredaddr == 0) >X addlog("[addr requested] "); >X else >X addlog("%s [not agreed] ", >X sppp_dotted_quad(desiredaddr)); >X >X p[2] = hisaddr >> 24; >X p[3] = hisaddr >> 16; >X p[4] = hisaddr >> 8; >X p[5] = hisaddr; >X } >X break; >X } >X /* Add the option to nak'ed list. */ >X bcopy (p, r, p[1]); >X r += p[1]; >X rlen += p[1]; >X } >X >X /* >X * If we are about to conf-ack the request, but haven't seen >X * his address so far, gonna conf-nak it instead, with the >X * `address' option present and our idea of his address being >X * filled in there, to request negotiation of both addresses. >X * >X * XXX This can result in an endless req - nak loop if peer >X * doesn't want to send us his address. Q: What should we do >X * about it? XXX A: implement the max-failure counter. >X */ >X if (rlen == 0 && !(sp->ipcp.flags & IPCP_HISADDR_SEEN) && !gotmyaddr) { >X buf[0] = IPCP_OPT_ADDRESS; >X buf[1] = 6; >X buf[2] = hisaddr >> 24; >X buf[3] = hisaddr >> 16; >X buf[4] = hisaddr >> 8; >X buf[5] = hisaddr; >X rlen = 6; >X if (debug) >X addlog("still need hisaddr "); >X } >X >X if (rlen) { >X if (debug) >X addlog(" send conf-nak\n"); >X sppp_cp_send (sp, PPP_IPCP, CONF_NAK, h->ident, rlen, buf); >X } else { >X if (debug) >X addlog(" send conf-ack\n"); >X sppp_cp_send (sp, PPP_IPCP, CONF_ACK, >X h->ident, origlen, h+1); >X } >X >X free (buf, M_TEMP); >X return (rlen == 0); >X} >X >X/* >X * Analyze the IPCP Configure-Reject option list, and adjust our >X * negotiation. >X */ >Xstatic void >Xsppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len) >X{ >X u_char *buf, *p; >X struct ifnet *ifp = &sp->pp_if; >X int debug = ifp->if_flags & IFF_DEBUG; >X >X len -= 4; >X buf = malloc (len, M_TEMP, M_NOWAIT); >X if (!buf) >X return; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "ipcp rej opts: ", >X SPP_ARGS(ifp)); >X >X p = (void*) (h+1); >X for (; len > 1 && p[1]; len -= p[1], p += p[1]) { >X if (debug) >X addlog(" %s ", sppp_ipcp_opt_name(*p)); >X switch (*p) { >X case IPCP_OPT_ADDRESS: >X /* >X * Peer doesn't grok address option. This is >X * bad. XXX Should we better give up here? >X * XXX We could try old "addresses" option... >X */ >X sp->ipcp.opts &= ~(1 << IPCP_OPT_ADDRESS); >X break; >X#ifdef notyet >X case IPCP_OPT_COMPRESS: >X sp->ipcp.opts &= ~(1 << IPCP_OPT_COMPRESS); >X break; >X#endif >X } >X } >X if (debug) >X addlog("\n"); >X free (buf, M_TEMP); >X return; >X} >X >X/* >X * Analyze the IPCP Configure-NAK option list, and adjust our >X * negotiation. >X */ >Xstatic void >Xsppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len) >X{ >X u_char *buf, *p; >X struct ifnet *ifp = &sp->pp_if; >X int debug = ifp->if_flags & IFF_DEBUG; >X u_long wantaddr; >X >X len -= 4; >X buf = malloc (len, M_TEMP, M_NOWAIT); >X if (!buf) >X return; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "ipcp nak opts: ", >X SPP_ARGS(ifp)); >X >X p = (void*) (h+1); >X for (; len > 1 && p[1]; len -= p[1], p += p[1]) { >X if (debug) >X addlog(" %s ", sppp_ipcp_opt_name(*p)); >X switch (*p) { >X case IPCP_OPT_ADDRESS: >X /* >X * Peer doesn't like our local IP address. See >X * if we can do something for him. We'll drop >X * him our address then. >X */ >X if (len >= 6 && p[1] == 6) { >X wantaddr = p[2] << 24 | p[3] << 16 | >X p[4] << 8 | p[5]; >X sp->ipcp.opts |= (1 << IPCP_OPT_ADDRESS); >X if (debug) >X addlog("[wantaddr %s] ", >X sppp_dotted_quad(wantaddr)); >X /* >X * When doing dynamic address assignment, >X * we accept his offer. Otherwise, we >X * ignore it and thus continue to negotiate >X * our already existing value. >X * XXX: Bogus, if he said no once, he'll >X * just say no again, might as well die. >X */ >X if (sp->ipcp.flags & IPCP_MYADDR_DYN) { >X sppp_set_ip_addr(sp, wantaddr); >X if (debug) >X addlog("[agree] "); >X sp->ipcp.flags |= IPCP_MYADDR_SEEN; >X } >X } >X break; >X#ifdef notyet >X case IPCP_OPT_COMPRESS: >X /* >X * Peer wants different compression parameters. >X */ >X break; >X#endif >X } >X } >X if (debug) >X addlog("\n"); >X free (buf, M_TEMP); >X return; >X} >X >Xstatic void >Xsppp_ipcp_tlu(struct sppp *sp) >X{ >X /* we are up - notify isdn daemon */ >X if (sp->pp_con) >X sp->pp_con(sp); >X} >X >Xstatic void >Xsppp_ipcp_tld(struct sppp *sp) >X{ >X} >X >Xstatic void >Xsppp_ipcp_tls(struct sppp *sp) >X{ >X /* indicate to LCP that it must stay alive */ >X sp->lcp.protos |= (1 << IDX_IPCP); >X} >X >Xstatic void >Xsppp_ipcp_tlf(struct sppp *sp) >X{ >X /* we no longer need LCP */ >X sp->lcp.protos &= ~(1 << IDX_IPCP); >X sppp_lcp_check_and_close(sp); >X} >X >Xstatic void >Xsppp_ipcp_scr(struct sppp *sp) >X{ >X char opt[6 /* compression */ + 6 /* address */]; >X u_long ouraddr; >X int i = 0; >X >X#ifdef notyet >X if (sp->ipcp.opts & (1 << IPCP_OPT_COMPRESSION)) { >X opt[i++] = IPCP_OPT_COMPRESSION; >X opt[i++] = 6; >X opt[i++] = 0; /* VJ header compression */ >X opt[i++] = 0x2d; /* VJ header compression */ >X opt[i++] = max_slot_id; >X opt[i++] = comp_slot_id; >X } >X#endif >X >X if (sp->ipcp.opts & (1 << IPCP_OPT_ADDRESS)) { >X sppp_get_ip_addrs(sp, &ouraddr, 0, 0); >X opt[i++] = IPCP_OPT_ADDRESS; >X opt[i++] = 6; >X opt[i++] = ouraddr >> 24; >X opt[i++] = ouraddr >> 16; >X opt[i++] = ouraddr >> 8; >X opt[i++] = ouraddr; >X } >X >X sp->confid[IDX_IPCP] = ++sp->pp_seq; >X sppp_cp_send(sp, PPP_IPCP, CONF_REQ, sp->confid[IDX_IPCP], i, &opt); >X} >X >X >X/* >X *--------------------------------------------------------------------------* >X * * >X * The CHAP implementation. * >X * * >X *--------------------------------------------------------------------------* >X */ >X >X/* >X * The authentication protocols don't employ a full-fledged state machine as >X * the control protocols do, since they do have Open and Close events, but >X * not Up and Down, nor are they explicitly terminated. Also, use of the >X * authentication protocols may be different in both directions (this makes >X * sense, think of a machine that never accepts incoming calls but only >X * calls out, it doesn't require the called party to authenticate itself). >X * >X * Our state machine for the local authentication protocol (we are requesting >X * the peer to authenticate) looks like: >X * >X * RCA- >X * +--------------------------------------------+ >X * V scn,tld| >X * +--------+ Close +---------+ RCA+ >X * | |<----------------------------------| |------+ >X * +--->| Closed | TO* | Opened | sca | >X * | | |-----+ +-------| |<-----+ >X * | +--------+ irc | | +---------+ >X * | ^ | | ^ >X * | | | | | >X * | | | | | >X * | TO-| | | | >X * | |tld TO+ V | | >X * | | +------->+ | | >X * | | | | | | >X * | +--------+ V | | >X * | | |<----+<--------------------+ | >X * | | Req- | scr | >X * | | Sent | | >X * | | | | >X * | +--------+ | >X * | RCA- | | RCA+ | >X * +------+ +------------------------------------------+ >X * scn,tld sca,irc,ict,tlu >X * >X * >X * with: >X * >X * Open: LCP reached authentication phase >X * Close: LCP reached terminate phase >X * >X * RCA+: received reply (pap-req, chap-response), acceptable >X * RCN: received reply (pap-req, chap-response), not acceptable >X * TO+: timeout with restart counter >= 0 >X * TO-: timeout with restart counter < 0 >X * TO*: reschedule timeout for CHAP >X * >X * scr: send request packet (none for PAP, chap-challenge) >X * sca: send ack packet (pap-ack, chap-success) >X * scn: send nak packet (pap-nak, chap-failure) >X * ict: initialize re-challenge timer (CHAP only) >X * >X * tlu: this-layer-up, LCP reaches network phase >X * tld: this-layer-down, LCP enters terminate phase >X * >X * Note that in CHAP mode, after sending a new challenge, while the state >X * automaton falls back into Req-Sent state, it doesn't signal a tld >X * event to LCP, so LCP remains in network phase. Only after not getting >X * any response (or after getting an unacceptable response), CHAP closes, >X * causing LCP to enter terminate phase. >X * >X * With PAP, there is no initial request that can be sent. The peer is >X * expected to send one based on the successful negotiation of PAP as >X * the authentication protocol during the LCP option negotiation. >X * >X * Incoming authentication protocol requests (remote requests >X * authentication, we are peer) don't employ a state machine at all, >X * they are simply answered. Some peers [Ascend P50 firmware rev >X * 4.50] react allergically when sending IPCP requests while they are >X * still in authentication phase (thereby violating the standard that >X * demands that these NCP packets are to be discarded), so we keep >X * track of the peer demanding us to authenticate, and only proceed to >X * phase network once we've seen a positive acknowledge for the >X * authentication. >X */ >X >X/* >X * Handle incoming CHAP packets. >X */ >Xvoid >Xsppp_chap_input(struct sppp *sp, struct mbuf *m) >X{ >X STDDCL; >X struct lcp_header *h; >X int len, x; >X u_char *value, *name, digest[AUTHKEYLEN], dsize; >X int value_len, name_len; >X MD5_CTX ctx; >X >X len = m->m_pkthdr.len; >X if (len < 4) { >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "chap invalid packet length: %d bytes\n", >X SPP_ARGS(ifp), len); >X return; >X } >X h = mtod (m, struct lcp_header*); >X if (len > ntohs (h->len)) >X len = ntohs (h->len); >X >X switch (h->type) { >X /* challenge, failure and success are his authproto */ >X case CHAP_CHALLENGE: >X value = 1 + (u_char*)(h+1); >X value_len = value[-1]; >X name = value + value_len; >X name_len = len - value_len - 5; >X if (name_len < 0) { >X if (debug) { >X log(LOG_DEBUG, >X SPP_FMT "chap corrupted challenge " >X "<%s id=0x%x len=%d", >X SPP_ARGS(ifp), >X sppp_auth_type_name(PPP_CHAP, h->type), >X h->ident, ntohs(h->len)); >X if (len > 4) >X sppp_print_bytes((u_char*) (h+1), len-4); >X addlog(">\n"); >X } >X break; >X } >X >X if (debug) { >X log(LOG_DEBUG, >X SPP_FMT "chap input <%s id=0x%x len=%d name=", >X SPP_ARGS(ifp), >X sppp_auth_type_name(PPP_CHAP, h->type), h->ident, >X ntohs(h->len)); >X sppp_print_string((char*) name, name_len); >X addlog(" value-size=%d value=", value_len); >X sppp_print_bytes(value, value_len); >X addlog(">\n"); >X } >X >X /* Compute reply value. */ >X MD5Init(&ctx); >X MD5Update(&ctx, &h->ident, 1); >X MD5Update(&ctx, sp->myauth.secret, >X sppp_strnlen(sp->myauth.secret, AUTHKEYLEN)); >X MD5Update(&ctx, value, value_len); >X MD5Final(digest, &ctx); >X dsize = sizeof digest; >X >X sppp_auth_send(&chap, sp, CHAP_RESPONSE, h->ident, >X sizeof dsize, (const char *)&dsize, >X sizeof digest, digest, >X (size_t)sppp_strnlen(sp->myauth.name, AUTHNAMELEN), >X sp->myauth.name, >X 0); >X break; >X >X case CHAP_SUCCESS: >X if (debug) { >X log(LOG_DEBUG, SPP_FMT "chap success", >X SPP_ARGS(ifp)); >X if (len > 4) { >X addlog(": "); >X sppp_print_string((char*)(h + 1), len - 4); >X } >X addlog("\n"); >X } >X x = splimp(); >X sp->pp_flags &= ~PP_NEEDAUTH; >X if (sp->myauth.proto == PPP_CHAP && >X (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) && >X (sp->lcp.protos & (1 << IDX_CHAP)) == 0) { >X /* >X * We are authenticator for CHAP but didn't >X * complete yet. Leave it to tlu to proceed >X * to network phase. >X */ >X splx(x); >X break; >X } >X splx(x); >X sppp_phase_network(sp); >X break; >X >X case CHAP_FAILURE: >X if (debug) { >X log(LOG_INFO, SPP_FMT "chap failure", >X SPP_ARGS(ifp)); >X if (len > 4) { >X addlog(": "); >X sppp_print_string((char*)(h + 1), len - 4); >X } >X addlog("\n"); >X } else >X log(LOG_INFO, SPP_FMT "chap failure\n", >X SPP_ARGS(ifp)); >X /* await LCP shutdown by authenticator */ >X break; >X >X /* response is my authproto */ >X case CHAP_RESPONSE: >X value = 1 + (u_char*)(h+1); >X value_len = value[-1]; >X name = value + value_len; >X name_len = len - value_len - 5; >X if (name_len < 0) { >X if (debug) { >X log(LOG_DEBUG, >X SPP_FMT "chap corrupted response " >X "<%s id=0x%x len=%d", >X SPP_ARGS(ifp), >X sppp_auth_type_name(PPP_CHAP, h->type), >X h->ident, ntohs(h->len)); >X if (len > 4) >X sppp_print_bytes((u_char*)(h+1), len-4); >X addlog(">\n"); >X } >X break; >X } >X if (h->ident != sp->confid[IDX_CHAP]) { >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "chap dropping response for old ID " >X "(got %d, expected %d)\n", >X SPP_ARGS(ifp), >X h->ident, sp->confid[IDX_CHAP]); >X break; >X } >X if (name_len != sppp_strnlen(sp->hisauth.name, AUTHNAMELEN) >X || bcmp(name, sp->hisauth.name, name_len) != 0) { >X log(LOG_INFO, SPP_FMT "chap response, his name ", >X SPP_ARGS(ifp)); >X sppp_print_string(name, name_len); >X addlog(" != expected "); >X sppp_print_string(sp->hisauth.name, >X sppp_strnlen(sp->hisauth.name, AUTHNAMELEN)); >X addlog("\n"); >X } >X if (debug) { >X log(LOG_DEBUG, SPP_FMT "chap input(%s) " >X "<%s id=0x%x len=%d name=", >X SPP_ARGS(ifp), >X sppp_state_name(sp->state[IDX_CHAP]), >X sppp_auth_type_name(PPP_CHAP, h->type), >X h->ident, ntohs (h->len)); >X sppp_print_string((char*)name, name_len); >X addlog(" value-size=%d value=", value_len); >X sppp_print_bytes(value, value_len); >X addlog(">\n"); >X } >X if (value_len != AUTHKEYLEN) { >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "chap bad hash value length: " >X "%d bytes, should be %d\n", >X SPP_ARGS(ifp), value_len, >X AUTHKEYLEN); >X break; >X } >X >X MD5Init(&ctx); >X MD5Update(&ctx, &h->ident, 1); >X MD5Update(&ctx, sp->hisauth.secret, >X sppp_strnlen(sp->hisauth.secret, AUTHKEYLEN)); >X MD5Update(&ctx, sp->myauth.challenge, AUTHKEYLEN); >X MD5Final(digest, &ctx); >X >X#define FAILMSG "Failed..." >X#define SUCCMSG "Welcome!" >X >X if (value_len != sizeof digest || >X bcmp(digest, value, value_len) != 0) { >X /* action scn, tld */ >X sppp_auth_send(&chap, sp, CHAP_FAILURE, h->ident, >X sizeof(FAILMSG) - 1, (u_char *)FAILMSG, >X 0); >X chap.tld(sp); >X break; >X } >X /* action sca, perhaps tlu */ >X if (sp->state[IDX_CHAP] == STATE_REQ_SENT || >X sp->state[IDX_CHAP] == STATE_OPENED) >X sppp_auth_send(&chap, sp, CHAP_SUCCESS, h->ident, >X sizeof(SUCCMSG) - 1, (u_char *)SUCCMSG, >X 0); >X if (sp->state[IDX_CHAP] == STATE_REQ_SENT) { >X sppp_cp_change_state(&chap, sp, STATE_OPENED); >X chap.tlu(sp); >X } >X break; >X >X default: >X /* Unknown CHAP packet type -- ignore. */ >X if (debug) { >X log(LOG_DEBUG, SPP_FMT "chap unknown input(%s) " >X "<0x%x id=0x%xh len=%d", >X SPP_ARGS(ifp), >X sppp_state_name(sp->state[IDX_CHAP]), >X h->type, h->ident, ntohs(h->len)); >X if (len > 4) >X sppp_print_bytes((u_char*)(h+1), len-4); >X addlog(">\n"); >X } >X break; >X >X } >X} >X >Xstatic void >Xsppp_chap_init(struct sppp *sp) >X{ >X /* Chap doesn't have STATE_INITIAL at all. */ >X sp->state[IDX_CHAP] = STATE_CLOSED; >X sp->fail_counter[IDX_CHAP] = 0; >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X callout_handle_init(&sp->ch[IDX_CHAP]); >X#endif >X} >X >Xstatic void >Xsppp_chap_open(struct sppp *sp) >X{ >X if (sp->myauth.proto == PPP_CHAP && >X (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) != 0) { >X /* we are authenticator for CHAP, start it */ >X chap.scr(sp); >X sp->rst_counter[IDX_CHAP] = sp->lcp.max_configure; >X sppp_cp_change_state(&chap, sp, STATE_REQ_SENT); >X } >X /* nothing to be done if we are peer, await a challenge */ >X} >X >Xstatic void >Xsppp_chap_close(struct sppp *sp) >X{ >X if (sp->state[IDX_CHAP] != STATE_CLOSED) >X sppp_cp_change_state(&chap, sp, STATE_CLOSED); >X} >X >Xstatic void >Xsppp_chap_TO(void *cookie) >X{ >X struct sppp *sp = (struct sppp *)cookie; >X STDDCL; >X int s; >X >X s = splimp(); >X if (debug) >X log(LOG_DEBUG, SPP_FMT "chap TO(%s) rst_counter = %d\n", >X SPP_ARGS(ifp), >X sppp_state_name(sp->state[IDX_CHAP]), >X sp->rst_counter[IDX_CHAP]); >X >X if (--sp->rst_counter[IDX_CHAP] < 0) >X /* TO- event */ >X switch (sp->state[IDX_CHAP]) { >X case STATE_REQ_SENT: >X chap.tld(sp); >X sppp_cp_change_state(&chap, sp, STATE_CLOSED); >X break; >X } >X else >X /* TO+ (or TO*) event */ >X switch (sp->state[IDX_CHAP]) { >X case STATE_OPENED: >X /* TO* event */ >X sp->rst_counter[IDX_CHAP] = sp->lcp.max_configure; >X /* fall through */ >X case STATE_REQ_SENT: >X chap.scr(sp); >X /* sppp_cp_change_state() will restart the timer */ >X sppp_cp_change_state(&chap, sp, STATE_REQ_SENT); >X break; >X } >X >X splx(s); >X} >X >Xstatic void >Xsppp_chap_tlu(struct sppp *sp) >X{ >X STDDCL; >X int i, x; >X >X i = 0; >X sp->rst_counter[IDX_CHAP] = sp->lcp.max_configure; >X >X /* >X * Some broken CHAP implementations (Conware CoNet, firmware >X * 4.0.?) don't want to re-authenticate their CHAP once the >X * initial challenge-response exchange has taken place. >X * Provide for an option to avoid rechallenges. >X */ >X if ((sp->hisauth.flags & AUTHFLAG_NORECHALLENGE) == 0) { >X /* >X * Compute the re-challenge timeout. This will yield >X * a number between 300 and 810 seconds. >X */ >X i = 300 + ((unsigned)(random() & 0xff00) >> 7); >X TIMEOUT(chap.TO, (void *)sp, i * hz, sp->ch[IDX_CHAP]); >X } >X >X if (debug) { >X log(LOG_DEBUG, >X SPP_FMT "chap %s, ", >X SPP_ARGS(ifp), >X sp->pp_phase == PHASE_NETWORK? "reconfirmed": "tlu"); >X if ((sp->hisauth.flags & AUTHFLAG_NORECHALLENGE) == 0) >X addlog("next re-challenge in %d seconds\n", i); >X else >X addlog("re-challenging supressed\n"); >X } >X >X x = splimp(); >X /* indicate to LCP that we need to be closed down */ >X sp->lcp.protos |= (1 << IDX_CHAP); >X >X if (sp->pp_flags & PP_NEEDAUTH) { >X /* >X * Remote is authenticator, but his auth proto didn't >X * complete yet. Defer the transition to network >X * phase. >X */ >X splx(x); >X return; >X } >X splx(x); >X >X /* >X * If we are already in phase network, we are done here. This >X * is the case if this is a dummy tlu event after a re-challenge. >X */ >X if (sp->pp_phase != PHASE_NETWORK) >X sppp_phase_network(sp); >X} >X >Xstatic void >Xsppp_chap_tld(struct sppp *sp) >X{ >X STDDCL; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "chap tld\n", SPP_ARGS(ifp)); >X UNTIMEOUT(chap.TO, (void *)sp, sp->ch[IDX_CHAP]); >X sp->lcp.protos &= ~(1 << IDX_CHAP); >X >X lcp.Close(sp); >X} >X >Xstatic void >Xsppp_chap_scr(struct sppp *sp) >X{ >X u_long *ch, seed; >X u_char clen; >X >X /* Compute random challenge. */ >X ch = (u_long *)sp->myauth.challenge; >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X read_random(&seed, sizeof seed); >X#else >X { >X struct timeval tv; >X microtime(&tv); >X seed = tv.tv_sec ^ tv.tv_usec; >X } >X#endif >X ch[0] = seed ^ random(); >X ch[1] = seed ^ random(); >X ch[2] = seed ^ random(); >X ch[3] = seed ^ random(); >X clen = AUTHKEYLEN; >X >X sp->confid[IDX_CHAP] = ++sp->pp_seq; >X >X sppp_auth_send(&chap, sp, CHAP_CHALLENGE, sp->confid[IDX_CHAP], >X sizeof clen, (const char *)&clen, >X (size_t)AUTHKEYLEN, sp->myauth.challenge, >X (size_t)sppp_strnlen(sp->myauth.name, AUTHNAMELEN), >X sp->myauth.name, >X 0); >X} >X/* >X *--------------------------------------------------------------------------* >X * * >X * The PAP implementation. * >X * * >X *--------------------------------------------------------------------------* >X */ >X/* >X * For PAP, we need to keep a little state also if we are the peer, not the >X * authenticator. This is since we don't get a request to authenticate, but >X * have to repeatedly authenticate ourself until we got a response (or the >X * retry counter is expired). >X */ >X >X/* >X * Handle incoming PAP packets. */ >Xstatic void >Xsppp_pap_input(struct sppp *sp, struct mbuf *m) >X{ >X STDDCL; >X struct lcp_header *h; >X int len, x; >X u_char *name, *passwd, mlen; >X int name_len, passwd_len; >X >X len = m->m_pkthdr.len; >X if (len < 5) { >X if (debug) >X log(LOG_DEBUG, >X SPP_FMT "pap invalid packet length: %d bytes\n", >X SPP_ARGS(ifp), len); >X return; >X } >X h = mtod (m, struct lcp_header*); >X if (len > ntohs (h->len)) >X len = ntohs (h->len); >X switch (h->type) { >X /* PAP request is my authproto */ >X case PAP_REQ: >X name = 1 + (u_char*)(h+1); >X name_len = name[-1]; >X passwd = name + name_len + 1; >X if (name_len > len - 6 || >X (passwd_len = passwd[-1]) > len - 6 - name_len) { >X if (debug) { >X log(LOG_DEBUG, SPP_FMT "pap corrupted input " >X "<%s id=0x%x len=%d", >X SPP_ARGS(ifp), >X sppp_auth_type_name(PPP_PAP, h->type), >X h->ident, ntohs(h->len)); >X if (len > 4) >X sppp_print_bytes((u_char*)(h+1), len-4); >X addlog(">\n"); >X } >X break; >X } >X if (debug) { >X log(LOG_DEBUG, SPP_FMT "pap input(%s) " >X "<%s id=0x%x len=%d name=", >X SPP_ARGS(ifp), >X sppp_state_name(sp->state[IDX_PAP]), >X sppp_auth_type_name(PPP_PAP, h->type), >X h->ident, ntohs(h->len)); >X sppp_print_string((char*)name, name_len); >X addlog(" passwd="); >X sppp_print_string((char*)passwd, passwd_len); >X addlog(">\n"); >X } >X if (name_len > AUTHNAMELEN || >X passwd_len > AUTHKEYLEN || >X bcmp(name, sp->hisauth.name, name_len) != 0 || >X bcmp(passwd, sp->hisauth.secret, passwd_len) != 0) { >X /* action scn, tld */ >X mlen = sizeof(FAILMSG) - 1; >X sppp_auth_send(&pap, sp, PAP_NAK, h->ident, >X sizeof mlen, (const char *)&mlen, >X sizeof(FAILMSG) - 1, (u_char *)FAILMSG, >X 0); >X pap.tld(sp); >X break; >X } >X /* action sca, perhaps tlu */ >X if (sp->state[IDX_PAP] == STATE_REQ_SENT || >X sp->state[IDX_PAP] == STATE_OPENED) { >X mlen = sizeof(SUCCMSG) - 1; >X sppp_auth_send(&pap, sp, PAP_ACK, h->ident, >X sizeof mlen, (const char *)&mlen, >X sizeof(SUCCMSG) - 1, (u_char *)SUCCMSG, >X 0); >X } >X if (sp->state[IDX_PAP] == STATE_REQ_SENT) { >X sppp_cp_change_state(&pap, sp, STATE_OPENED); >X pap.tlu(sp); >X } >X break; >X >X /* ack and nak are his authproto */ >X case PAP_ACK: >X UNTIMEOUT(sppp_pap_my_TO, (void *)sp, sp->pap_my_to_ch); >X if (debug) { >X log(LOG_DEBUG, SPP_FMT "pap success", >X SPP_ARGS(ifp)); >X name_len = *((char *)h); >X if (len > 5 && name_len) { >X addlog(": "); >X sppp_print_string((char*)(h+1), name_len); >X } >X addlog("\n"); >X } >X x = splimp(); >X sp->pp_flags &= ~PP_NEEDAUTH; >X if (sp->myauth.proto == PPP_PAP && >X (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) && >X (sp->lcp.protos & (1 << IDX_PAP)) == 0) { >X /* >X * We are authenticator for PAP but didn't >X * complete yet. Leave it to tlu to proceed >X * to network phase. >X */ >X splx(x); >X break; >X } >X splx(x); >X sppp_phase_network(sp); >X break; >X >X case PAP_NAK: >X UNTIMEOUT(sppp_pap_my_TO, (void *)sp, sp->pap_my_to_ch); >X if (debug) { >X log(LOG_INFO, SPP_FMT "pap failure", >X SPP_ARGS(ifp)); >X name_len = *((char *)h); >X if (len > 5 && name_len) { >X addlog(": "); >X sppp_print_string((char*)(h+1), name_len); >X } >X addlog("\n"); >X } else >X log(LOG_INFO, SPP_FMT "pap failure\n", >X SPP_ARGS(ifp)); >X /* await LCP shutdown by authenticator */ >X break; >X >X default: >X /* Unknown PAP packet type -- ignore. */ >X if (debug) { >X log(LOG_DEBUG, SPP_FMT "pap corrupted input " >X "<0x%x id=0x%x len=%d", >X SPP_ARGS(ifp), >X h->type, h->ident, ntohs(h->len)); >X if (len > 4) >X sppp_print_bytes((u_char*)(h+1), len-4); >X addlog(">\n"); >X } >X break; >X >X } >X} >X >Xstatic void >Xsppp_pap_init(struct sppp *sp) >X{ >X /* PAP doesn't have STATE_INITIAL at all. */ >X sp->state[IDX_PAP] = STATE_CLOSED; >X sp->fail_counter[IDX_PAP] = 0; >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X callout_handle_init(&sp->ch[IDX_PAP]); >X callout_handle_init(&sp->pap_my_to_ch); >X#endif >X} >X >Xstatic void >Xsppp_pap_open(struct sppp *sp) >X{ >X if (sp->hisauth.proto == PPP_PAP && >X (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) != 0) { >X /* we are authenticator for PAP, start our timer */ >X sp->rst_counter[IDX_PAP] = sp->lcp.max_configure; >X sppp_cp_change_state(&pap, sp, STATE_REQ_SENT); >X } >X if (sp->myauth.proto == PPP_PAP) { >X /* we are peer, send a request, and start a timer */ >X pap.scr(sp); >X TIMEOUT(sppp_pap_my_TO, (void *)sp, sp->lcp.timeout, >X sp->pap_my_to_ch); >X } >X} >X >Xstatic void >Xsppp_pap_close(struct sppp *sp) >X{ >X if (sp->state[IDX_PAP] != STATE_CLOSED) >X sppp_cp_change_state(&pap, sp, STATE_CLOSED); >X} >X >X/* >X * That's the timeout routine if we are authenticator. Since the >X * authenticator is basically passive in PAP, we can't do much here. >X */ >Xstatic void >Xsppp_pap_TO(void *cookie) >X{ >X struct sppp *sp = (struct sppp *)cookie; >X STDDCL; >X int s; >X >X s = splimp(); >X if (debug) >X log(LOG_DEBUG, SPP_FMT "pap TO(%s) rst_counter = %d\n", >X SPP_ARGS(ifp), >X sppp_state_name(sp->state[IDX_PAP]), >X sp->rst_counter[IDX_PAP]); >X >X if (--sp->rst_counter[IDX_PAP] < 0) >X /* TO- event */ >X switch (sp->state[IDX_PAP]) { >X case STATE_REQ_SENT: >X pap.tld(sp); >X sppp_cp_change_state(&pap, sp, STATE_CLOSED); >X break; >X } >X else >X /* TO+ event, not very much we could do */ >X switch (sp->state[IDX_PAP]) { >X case STATE_REQ_SENT: >X /* sppp_cp_change_state() will restart the timer */ >X sppp_cp_change_state(&pap, sp, STATE_REQ_SENT); >X break; >X } >X >X splx(s); >X} >X >X/* >X * That's the timeout handler if we are peer. Since the peer is active, >X * we need to retransmit our PAP request since it is apparently lost. >X * XXX We should impose a max counter. >X */ >Xstatic void >Xsppp_pap_my_TO(void *cookie) >X{ >X struct sppp *sp = (struct sppp *)cookie; >X STDDCL; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "pap peer TO\n", >X SPP_ARGS(ifp)); >X >X pap.scr(sp); >X} >X >Xstatic void >Xsppp_pap_tlu(struct sppp *sp) >X{ >X STDDCL; >X int x; >X >X sp->rst_counter[IDX_PAP] = sp->lcp.max_configure; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "%s tlu\n", >X SPP_ARGS(ifp), pap.name); >X >X x = splimp(); >X /* indicate to LCP that we need to be closed down */ >X sp->lcp.protos |= (1 << IDX_PAP); >X >X if (sp->pp_flags & PP_NEEDAUTH) { >X /* >X * Remote is authenticator, but his auth proto didn't >X * complete yet. Defer the transition to network >X * phase. >X */ >X splx(x); >X return; >X } >X splx(x); >X sppp_phase_network(sp); >X} >X >Xstatic void >Xsppp_pap_tld(struct sppp *sp) >X{ >X STDDCL; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "pap tld\n", SPP_ARGS(ifp)); >X UNTIMEOUT(pap.TO, (void *)sp, sp->ch[IDX_PAP]); >X UNTIMEOUT(sppp_pap_my_TO, (void *)sp, sp->pap_my_to_ch); >X sp->lcp.protos &= ~(1 << IDX_PAP); >X >X lcp.Close(sp); >X} >X >Xstatic void >Xsppp_pap_scr(struct sppp *sp) >X{ >X u_char idlen, pwdlen; >X >X sp->confid[IDX_PAP] = ++sp->pp_seq; >X pwdlen = sppp_strnlen(sp->myauth.secret, AUTHKEYLEN); >X idlen = sppp_strnlen(sp->myauth.name, AUTHNAMELEN); >X >X sppp_auth_send(&pap, sp, PAP_REQ, sp->confid[IDX_PAP], >X sizeof idlen, (const char *)&idlen, >X (size_t)idlen, sp->myauth.name, >X sizeof pwdlen, (const char *)&pwdlen, >X (size_t)pwdlen, sp->myauth.secret, >X 0); >X} >X/* >X * Random miscellaneous functions. >X */ >X >X/* >X * Send a PAP or CHAP proto packet. >X * >X * Varadic function, each of the elements for the ellipsis is of type >X * ``size_t mlen, const u_char *msg''. Processing will stop iff >X * mlen == 0. >X * NOTE: never declare variadic functions with types subject to type >X * promotion (i.e. u_char). This is asking for big trouble depending >X * on the architecture you are on... >X */ >X >Xstatic void >Xsppp_auth_send(const struct cp *cp, struct sppp *sp, >X unsigned int type, unsigned int id, >X ...) >X{ >X STDDCL; >X struct ppp_header *h; >X struct lcp_header *lh; >X struct mbuf *m; >X u_char *p; >X int len; >X unsigned int mlen; >X const char *msg; >X va_list ap; >X >X MGETHDR (m, M_DONTWAIT, MT_DATA); >X if (! m) >X return; >X m->m_pkthdr.rcvif = 0; >X >X h = mtod (m, struct ppp_header*); >X h->address = PPP_ALLSTATIONS; /* broadcast address */ >X h->control = PPP_UI; /* Unnumbered Info */ >X h->protocol = htons(cp->proto); >X >X lh = (struct lcp_header*)(h + 1); >X lh->type = type; >X lh->ident = id; >X p = (u_char*) (lh+1); >X >X va_start(ap, id); >X len = 0; >X >X while ((mlen = (unsigned int)va_arg(ap, size_t)) != 0) { >X msg = va_arg(ap, const char *); >X len += mlen; >X if (len > MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN) { >X va_end(ap); >X m_freem(m); >X return; >X } >X >X bcopy(msg, p, mlen); >X p += mlen; >X } >X va_end(ap); >X >X m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + LCP_HEADER_LEN + len; >X lh->len = htons (LCP_HEADER_LEN + len); >X >X if (debug) { >X log(LOG_DEBUG, SPP_FMT "%s output <%s id=0x%x len=%d", >X SPP_ARGS(ifp), cp->name, >X sppp_auth_type_name(cp->proto, lh->type), >X lh->ident, ntohs(lh->len)); >X if (len) >X sppp_print_bytes((u_char*) (lh+1), len); >X addlog(">\n"); >X } >X if (IF_QFULL (&sp->pp_cpq)) { >X IF_DROP (&sp->pp_fastq); >X IF_DROP (&ifp->if_snd); >X m_freem (m); >X ++ifp->if_oerrors; >X } else >X IF_ENQUEUE (&sp->pp_cpq, m); >X if (! (ifp->if_flags & IFF_OACTIVE)) >X (*ifp->if_start) (ifp); >X ifp->if_obytes += m->m_pkthdr.len + 3; >X} >X >X/* >X * Flush interface queue. >X */ >Xstatic void >Xsppp_qflush(struct ifqueue *ifq) >X{ >X struct mbuf *m, *n; >X >X n = ifq->ifq_head; >X while ((m = n)) { >X n = m->m_act; >X m_freem (m); >X } >X ifq->ifq_head = 0; >X ifq->ifq_tail = 0; >X ifq->ifq_len = 0; >X} >X >X/* >X * Send keepalive packets, every 10 seconds. >X */ >Xstatic void >Xsppp_keepalive(void *dummy) >X{ >X struct sppp *sp; >X int s; >X >X s = splimp(); >X for (sp=spppq; sp; sp=sp->pp_next) { >X struct ifnet *ifp = &sp->pp_if; >X >X /* Keepalive mode disabled or channel down? */ >X if (! (sp->pp_flags & PP_KEEPALIVE) || >X ! (ifp->if_flags & IFF_RUNNING)) >X continue; >X >X /* No keepalive in PPP mode if LCP not opened yet. */ >X if (! (sp->pp_flags & PP_CISCO) && >X sp->pp_phase < PHASE_AUTHENTICATE) >X continue; >X >X if (sp->pp_alivecnt == MAXALIVECNT) { >X /* No keepalive packets got. Stop the interface. */ >X printf (SPP_FMT "down\n", SPP_ARGS(ifp)); >X if_down (ifp); >X sppp_qflush (&sp->pp_cpq); >X if (! (sp->pp_flags & PP_CISCO)) { >X /* XXX */ >X /* Shut down the PPP link. */ >X lcp.Down(sp); >X /* Initiate negotiation. XXX */ >X lcp.Up(sp); >X } >X } >X if (sp->pp_alivecnt <= MAXALIVECNT) >X ++sp->pp_alivecnt; >X if (sp->pp_flags & PP_CISCO) >X sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq, >X sp->pp_rseq); >X else if (sp->pp_phase >= PHASE_AUTHENTICATE) { >X long nmagic = htonl (sp->lcp.magic); >X sp->lcp.echoid = ++sp->pp_seq; >X sppp_cp_send (sp, PPP_LCP, ECHO_REQ, >X sp->lcp.echoid, 4, &nmagic); >X } >X } >X splx(s); >X TIMEOUT(sppp_keepalive, 0, hz * 10, keepalive_ch); >X} >X >X/* >X * Get both IP addresses. >X */ >Xstatic void >Xsppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst, u_long *srcmask) >X{ >X struct ifnet *ifp = &sp->pp_if; >X struct ifaddr *ifa; >X struct sockaddr_in *si, *sm; >X u_long ssrc, ddst; >X >X sm = NULL; >X ssrc = ddst = 0L; >X /* >X * Pick the first AF_INET address from the list, >X * aliases don't make any sense on a p2p link anyway. >X */ >X si = 0; >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) >X#elif defined(__NetBSD__) || defined (__OpenBSD__) >X for (ifa = ifp->if_addrlist.tqh_first; >X ifa; >X ifa = ifa->ifa_list.tqe_next) >X#else >X for (ifa = ifp->if_addrlist; >X ifa; >X ifa = ifa->ifa_next) >X#endif >X if (ifa->ifa_addr->sa_family == AF_INET) { >X si = (struct sockaddr_in *)ifa->ifa_addr; >X sm = (struct sockaddr_in *)ifa->ifa_netmask; >X if (si) >X break; >X } >X if (ifa) { >X if (si && si->sin_addr.s_addr) { >X ssrc = si->sin_addr.s_addr; >X if (srcmask) >X *srcmask = ntohl(sm->sin_addr.s_addr); >X } >X >X si = (struct sockaddr_in *)ifa->ifa_dstaddr; >X if (si && si->sin_addr.s_addr) >X ddst = si->sin_addr.s_addr; >X } >X >X if (dst) *dst = ntohl(ddst); >X if (src) *src = ntohl(ssrc); >X} >X >X/* >X * Set my IP address. Must be called at splimp. >X */ >Xstatic void >Xsppp_set_ip_addr(struct sppp *sp, u_long src) >X{ >X STDDCL; >X struct ifaddr *ifa; >X struct sockaddr_in *si; >X >X /* >X * Pick the first AF_INET address from the list, >X * aliases don't make any sense on a p2p link anyway. >X */ >X si = 0; >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) >X#elif defined(__NetBSD__) || defined (__OpenBSD__) >X for (ifa = ifp->if_addrlist.tqh_first; >X ifa; >X ifa = ifa->ifa_list.tqe_next) >X#else >X for (ifa = ifp->if_addrlist; >X ifa; >X ifa = ifa->ifa_next) >X#endif >X { >X if (ifa->ifa_addr->sa_family == AF_INET) >X { >X si = (struct sockaddr_in *)ifa->ifa_addr; >X if (si) >X break; >X } >X } >X >X if (ifa && si) >X { >X int error; >X#if __NetBSD_Version__ >= 103080000 >X struct sockaddr_in new_sin = *si; >X >X new_sin.sin_addr.s_addr = htonl(src); >X error = in_ifinit(ifp, ifatoia(ifa), &new_sin, 1); >X if(debug && error) >X { >X log(LOG_DEBUG, SPP_FMT "sppp_set_ip_addr: in_ifinit " >X " failed, error=%d\n", SPP_ARGS(ifp), error); >X } >X#else >X /* delete old route */ >X error = rtinit(ifa, (int)RTM_DELETE, RTF_HOST); >X if(debug && error) >X { >X log(LOG_DEBUG, SPP_FMT "sppp_set_ip_addr: rtinit DEL failed, error=%d\n", >X SPP_ARGS(ifp), error); >X } >X >X /* set new address */ >X si->sin_addr.s_addr = htonl(src); >X >X /* add new route */ >X error = rtinit(ifa, (int)RTM_ADD, RTF_HOST); >X if (debug && error) >X { >X log(LOG_DEBUG, SPP_FMT "sppp_set_ip_addr: rtinit ADD failed, error=%d", >X SPP_ARGS(ifp), error); >X } >X#endif >X } >X} >X >Xstatic int >Xsppp_params(struct sppp *sp, u_long cmd, void *data) >X{ >X u_long subcmd; >X struct ifreq *ifr = (struct ifreq *)data; >X struct spppreq spr; >X >X /* >X * ifr->ifr_data is supposed to point to a struct spppreq. >X * Check the cmd word first before attempting to fetch all the >X * data. >X */ >X if ((subcmd = fuword(ifr->ifr_data)) == -1) >X return EFAULT; >X >X if (copyin((caddr_t)ifr->ifr_data, &spr, sizeof spr) != 0) >X return EFAULT; >X >X switch (subcmd) { >X case SPPPIOGDEFS: >X if (cmd != SIOCGIFGENERIC) >X return EINVAL; >X /* >X * We copy over the entire current state, but clean >X * out some of the stuff we don't wanna pass up. >X * Remember, SIOCGIFGENERIC is unprotected, and can be >X * called by any user. No need to ever get PAP or >X * CHAP secrets back to userland anyway. >X */ >X bcopy(sp, &spr.defs, sizeof(struct sppp)); >X bzero(spr.defs.myauth.secret, AUTHKEYLEN); >X bzero(spr.defs.myauth.challenge, AUTHKEYLEN); >X bzero(spr.defs.hisauth.secret, AUTHKEYLEN); >X bzero(spr.defs.hisauth.challenge, AUTHKEYLEN); >X return copyout(&spr, (caddr_t)ifr->ifr_data, sizeof spr); >X >X case SPPPIOSDEFS: >X if (cmd != SIOCSIFGENERIC) >X return EINVAL; >X /* >X * We have a very specific idea of which fields we allow >X * being passed back from userland, so to not clobber our >X * current state. For one, we only allow setting >X * anything if LCP is in dead phase. Once the LCP >X * negotiations started, the authentication settings must >X * not be changed again. (The administrator can force an >X * ifconfig down in order to get LCP back into dead >X * phase.) >X * >X * Also, we only allow for authentication parameters to be >X * specified. >X * >X * XXX Should allow to set or clear pp_flags. >X * >X * Finally, if the respective authentication protocol to >X * be used is set differently than 0, but the secret is >X * passed as all zeros, we don't trash the existing secret. >X * This allows an administrator to change the system name >X * only without clobbering the secret (which he didn't get >X * back in a previous SPPPIOGDEFS call). However, the >X * secrets are cleared if the authentication protocol is >X * reset to 0. >X */ >X if (sp->pp_phase != PHASE_DEAD) >X return EBUSY; >X >X if ((spr.defs.myauth.proto != 0 && spr.defs.myauth.proto != PPP_PAP && >X spr.defs.myauth.proto != PPP_CHAP) || >X (spr.defs.hisauth.proto != 0 && spr.defs.hisauth.proto != PPP_PAP && >X spr.defs.hisauth.proto != PPP_CHAP)) >X return EINVAL; >X >X if (spr.defs.myauth.proto == 0) >X /* resetting myauth */ >X bzero(&sp->myauth, sizeof sp->myauth); >X else { >X /* setting/changing myauth */ >X sp->myauth.proto = spr.defs.myauth.proto; >X bcopy(spr.defs.myauth.name, sp->myauth.name, AUTHNAMELEN); >X if (spr.defs.myauth.secret[0] != '\0') >X bcopy(spr.defs.myauth.secret, sp->myauth.secret, >X AUTHKEYLEN); >X } >X if (spr.defs.hisauth.proto == 0) >X /* resetting hisauth */ >X bzero(&sp->hisauth, sizeof sp->hisauth); >X else { >X /* setting/changing hisauth */ >X sp->hisauth.proto = spr.defs.hisauth.proto; >X sp->hisauth.flags = spr.defs.hisauth.flags; >X bcopy(spr.defs.hisauth.name, sp->hisauth.name, AUTHNAMELEN); >X if (spr.defs.hisauth.secret[0] != '\0') >X bcopy(spr.defs.hisauth.secret, sp->hisauth.secret, >X AUTHKEYLEN); >X } >X break; >X >X default: >X return EINVAL; >X } >X >X return 0; >X} >X >Xstatic void >Xsppp_phase_network(struct sppp *sp) >X{ >X STDDCL; >X int i; >X u_long mask; >X >X sp->pp_phase = PHASE_NETWORK; >X >X if (debug) >X log(LOG_DEBUG, SPP_FMT "phase %s\n", SPP_ARGS(ifp), >X sppp_phase_name(sp->pp_phase)); >X >X /* Notify NCPs now. */ >X for (i = 0; i < IDX_COUNT; i++) >X if ((cps[i])->flags & CP_NCP) >X (cps[i])->Open(sp); >X >X /* Send Up events to all NCPs. */ >X for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1) >X if (sp->lcp.protos & mask && ((cps[i])->flags & CP_NCP)) >X (cps[i])->Up(sp); >X >X /* if no NCP is starting, all this was in vain, close down */ >X sppp_lcp_check_and_close(sp); >X} >X >X >Xstatic const char * >Xsppp_cp_type_name(u_char type) >X{ >X static char buf[12]; >X switch (type) { >X case CONF_REQ: return "conf-req"; >X case CONF_ACK: return "conf-ack"; >X case CONF_NAK: return "conf-nak"; >X case CONF_REJ: return "conf-rej"; >X case TERM_REQ: return "term-req"; >X case TERM_ACK: return "term-ack"; >X case CODE_REJ: return "code-rej"; >X case PROTO_REJ: return "proto-rej"; >X case ECHO_REQ: return "echo-req"; >X case ECHO_REPLY: return "echo-reply"; >X case DISC_REQ: return "discard-req"; >X } >X snprintf (buf, sizeof(buf), "0x%x", type); >X return buf; >X} >X >Xstatic const char * >Xsppp_auth_type_name(u_short proto, u_char type) >X{ >X static char buf[12]; >X switch (proto) { >X case PPP_CHAP: >X switch (type) { >X case CHAP_CHALLENGE: return "challenge"; >X case CHAP_RESPONSE: return "response"; >X case CHAP_SUCCESS: return "success"; >X case CHAP_FAILURE: return "failure"; >X } >X case PPP_PAP: >X switch (type) { >X case PAP_REQ: return "req"; >X case PAP_ACK: return "ack"; >X case PAP_NAK: return "nak"; >X } >X } >X snprintf (buf, sizeof(buf), "0x%x", type); >X return buf; >X} >X >Xstatic const char * >Xsppp_lcp_opt_name(u_char opt) >X{ >X static char buf[12]; >X switch (opt) { >X case LCP_OPT_MRU: return "mru"; >X case LCP_OPT_ASYNC_MAP: return "async-map"; >X case LCP_OPT_AUTH_PROTO: return "auth-proto"; >X case LCP_OPT_QUAL_PROTO: return "qual-proto"; >X case LCP_OPT_MAGIC: return "magic"; >X case LCP_OPT_PROTO_COMP: return "proto-comp"; >X case LCP_OPT_ADDR_COMP: return "addr-comp"; >X } >X snprintf (buf, sizeof(buf), "0x%x", opt); >X return buf; >X} >X >Xstatic const char * >Xsppp_ipcp_opt_name(u_char opt) >X{ >X static char buf[12]; >X switch (opt) { >X case IPCP_OPT_ADDRESSES: return "addresses"; >X case IPCP_OPT_COMPRESSION: return "compression"; >X case IPCP_OPT_ADDRESS: return "address"; >X } >X snprintf (buf, sizeof(buf), "0x%x", opt); >X return buf; >X} >X >Xstatic const char * >Xsppp_state_name(int state) >X{ >X switch (state) { >X case STATE_INITIAL: return "initial"; >X case STATE_STARTING: return "starting"; >X case STATE_CLOSED: return "closed"; >X case STATE_STOPPED: return "stopped"; >X case STATE_CLOSING: return "closing"; >X case STATE_STOPPING: return "stopping"; >X case STATE_REQ_SENT: return "req-sent"; >X case STATE_ACK_RCVD: return "ack-rcvd"; >X case STATE_ACK_SENT: return "ack-sent"; >X case STATE_OPENED: return "opened"; >X } >X return "illegal"; >X} >X >Xstatic const char * >Xsppp_phase_name(enum ppp_phase phase) >X{ >X switch (phase) { >X case PHASE_DEAD: return "dead"; >X case PHASE_ESTABLISH: return "establish"; >X case PHASE_TERMINATE: return "terminate"; >X case PHASE_AUTHENTICATE: return "authenticate"; >X case PHASE_NETWORK: return "network"; >X } >X return "illegal"; >X} >X >Xstatic const char * >Xsppp_proto_name(u_short proto) >X{ >X static char buf[12]; >X switch (proto) { >X case PPP_LCP: return "lcp"; >X case PPP_IPCP: return "ipcp"; >X case PPP_PAP: return "pap"; >X case PPP_CHAP: return "chap"; >X } >X snprintf(buf, sizeof(buf), "0x%x", (unsigned)proto); >X return buf; >X} >X >Xstatic void >Xsppp_print_bytes(const u_char *p, u_short len) >X{ >X addlog(" %02x", *p++); >X while (--len > 0) >X addlog("-%02x", *p++); >X} >X >Xstatic void >Xsppp_print_string(const char *p, u_short len) >X{ >X u_char c; >X >X while (len-- > 0) { >X c = *p++; >X /* >X * Print only ASCII chars directly. RFC 1994 recommends >X * using only them, but we don't rely on it. */ >X if (c < ' ' || c > '~') >X addlog("\\x%x", c); >X else >X addlog("%c", c); >X } >X} >X >Xstatic const char * >Xsppp_dotted_quad(u_long addr) >X{ >X static char s[16]; >X sprintf(s, "%d.%d.%d.%d", >X (int)((addr >> 24) & 0xff), >X (int)((addr >> 16) & 0xff), >X (int)((addr >> 8) & 0xff), >X (int)(addr & 0xff)); >X return s; >X} >X >Xstatic int >Xsppp_strnlen(u_char *p, int max) >X{ >X int len; >X >X for (len = 0; len < max && *p; ++p) >X ++len; >X return len; >X} >X >X/* a dummy, used to drop uninteresting events */ >Xstatic void >Xsppp_null(struct sppp *unused) >X{ >X /* do just nothing */ >X} >END-of-./usr/src/sys/net/if_spppsubr.c.orig >echo c - ./usr/src/sys/i4b >mkdir -p ./usr/src/sys/i4b > /dev/null 2>&1 >echo c - ./usr/src/sys/i4b/driver >mkdir -p ./usr/src/sys/i4b/driver > /dev/null 2>&1 >echo x - ./usr/src/sys/i4b/driver/i4b_isppp.c >sed 's/^X//' >./usr/src/sys/i4b/driver/i4b_isppp.c << 'END-of-./usr/src/sys/i4b/driver/i4b_isppp.c' >X/* >X * Copyright (c) 1997 Joerg Wunsch. All rights reserved. >X * >X * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. >X * >X * Redistribution and use in source and binary forms, with or without >X * modification, are permitted provided that the following conditions >X * are met: >X * >X * 1. Redistributions of source code must retain the above copyright >X * notice, this list of conditions and the following disclaimer. >X * 2. Redistributions in binary form must reproduce the above copyright >X * notice, this list of conditions and the following disclaimer in the >X * documentation and/or other materials provided with the distribution. >X * >X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND >X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE >X * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE >X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL >X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS >X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) >X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT >X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY >X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF >X * SUCH DAMAGE. >X * >X *--------------------------------------------------------------------------- >X * >X * i4b_isppp.c - isdn4bsd kernel SyncPPP driver >X * -------------------------------------------- >X * >X * Uses Serge Vakulenko's sppp backend (originally contributed with >X * the "cx" driver for Cronyx's HDLC-in-hardware device). This driver >X * is only the glue between sppp and i4b. >X * >X * $Id: i4b_isppp.c,v 1.1 1998/12/27 21:46:42 phk Exp $ >X * >X * last edit-date: [Fri Dec 18 11:47:58 1998] >X * >X *---------------------------------------------------------------------------*/ >X >X#include "i4bisppp.h" >X#ifdef __FreeBSD__ >X#include "sppp.h" >X#endif >X >X#if NI4BISPPP == 0 >X# error "You need to define `pseudo-device sppp <N>' with options ISPPP" >X#endif >X >X#include <sys/param.h> >X#include <sys/systm.h> >X#include <sys/mbuf.h> >X#include <sys/socket.h> >X#include <sys/errno.h> >X#include <sys/ioccom.h> >X#include <sys/sockio.h> >X#include <sys/kernel.h> >X#include <sys/protosw.h> >X >X#include <net/if.h> >X#include <net/if_types.h> >X#include <net/netisr.h> >X#include <net/route.h> >X#ifdef __FreeBSD__ >X#include <net/if_sppp.h> >X#else >X#include <i4b/sppp/if_sppp.h> >X#endif >X >X#include <netinet/in.h> >X#include <netinet/in_systm.h> >X#include <netinet/in_var.h> >X#include <netinet/ip.h> >X >X#include "bpfilter.h" >X#if NBPFILTER > 0 >X#include <sys/time.h> >X#include <net/bpf.h> >X#endif >X >X#ifdef __FreeBSD__ >X#include <machine/i4b_ioctl.h> >X#include <machine/i4b_cause.h> >X#else >X#include <i4b/i4b_ioctl.h> >X#include <i4b/i4b_cause.h> >X#endif >X >X#include <i4b/include/i4b_global.h> >X#include <i4b/include/i4b_mbuf.h> >X#include <i4b/include/i4b_l3l4.h> >X >X#include <i4b/layer4/i4b_l4.h> >X >X#ifdef __FreeBSD__ >X#define ISPPP_FMT "isp%d: " >X#define ISPPP_ARG(sc) ((sc)->sc_if.if_unit) >X#define PDEVSTATIC static >X#define IFP2UNIT(ifp) (ifp)->if_unit >X >X# if __FreeBSD_version >= 300001 >X# define CALLOUT_INIT(chan) callout_handle_init(chan) >X# define TIMEOUT(fun, arg, chan, tick) chan = timeout(fun, arg, tick) >X# define UNTIMEOUT(fun, arg, chan) untimeout(fun, arg, chan) >X# define IOCTL_CMD_T u_long >X# else >X# define CALLOUT_INIT(chan) do {} while(0) >X# define TIMEOUT(fun, arg, chan, tick) timeout(fun, arg, tick) >X# define UNTIMEOUT(fun, arg, chan) untimeout(fun, arg) >X# define IOCTL_CMD_T int >X# endif >X >X#elif defined __NetBSD__ || defined __OpenBSD__ >X#define ISPPP_FMT "%s: " >X#define ISPPP_ARG(sc) ((sc)->sc_if.if_xname) >X#define PDEVSTATIC /* not static */ >X#define IOCTL_CMD_T u_long >X#define IFP2UNIT(ifp) ((struct i4bisppp_softc *)ifp->if_softc)->sc_unit >X#else >X# error "What system are you using?" >X#endif >X >X#ifdef __FreeBSD__ >XPDEVSTATIC void i4bispppattach(void *); >XPSEUDO_SET(i4bispppattach, i4b_isppp); >X#else >XPDEVSTATIC void i4bispppattach __P((void)); >X#endif >X >X#define I4BISPPPACCT 1 /* enable accounting messages */ >X#define I4BISPPPACCTINTVL 2 /* accounting msg interval in secs */ >X#define I4BISPPPDISCDEBUG 1 >X >X#define PPP_HDRLEN 4 /* 4 octetts PPP header length */ >X >Xstruct i4bisppp_softc { >X /* >X * struct sppp starts with a struct ifnet, but we gotta allocate >X * more space for it. NB: do not relocate this union, it must >X * be first in isppp_softc. The tls and tlf hooks below want to >X * convert a ``struct sppp *'' into a ``struct isppp_softc *''. >X */ >X union { >X struct ifnet scu_if; >X struct sppp scu_sp; >X } sc_if_un; >X#define sc_if sc_if_un.scu_if >X >X int sc_state; /* state of the interface */ >X >X#ifndef __FreeBSD__ >X int sc_unit; /* unit number for Net/OpenBSD */ >X#endif >X >X call_desc_t *sc_cdp; /* ptr to call descriptor */ >X >X#ifdef I4BISPPPACCT >X int sc_iinb; /* isdn driver # of inbytes */ >X int sc_ioutb; /* isdn driver # of outbytes */ >X int sc_inb; /* # of bytes rx'd */ >X int sc_outb; /* # of bytes tx'd */ >X int sc_linb; /* last # of bytes rx'd */ >X int sc_loutb; /* last # of bytes tx'd */ >X int sc_fn; /* flag, first null acct */ >X#endif >X >X#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 >X struct callout_handle sc_ch; >X#endif >X >X} i4bisppp_softc[NI4BISPPP]; >X >Xstatic void i4bisppp_init_linktab(int unit); >Xstatic int i4bisppp_ioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, caddr_t data); >X >X#if 0 >Xstatic void i4bisppp_send(struct ifnet *ifp); >X#endif >X >Xstatic void i4bisppp_start(struct ifnet *ifp); >X >X#if 0 /* never used ??? */ >Xstatic void i4bisppp_timeout(void *cookie); >X#endif >X >Xstatic void i4bisppp_tls(struct sppp *sp); >Xstatic void i4bisppp_tlf(struct sppp *sp); >Xstatic void i4bisppp_state_changed(struct sppp *sp, int new_state); >Xstatic void i4bisppp_negotiation_complete(struct sppp *sp); >Xstatic void i4bisppp_watchdog(struct ifnet *ifp); >Xtime_t i4bisppp_idletime(int unit); >X >X/* initialized by L4 */ >X >Xstatic drvr_link_t i4bisppp_drvr_linktab[NI4BISPPP]; >Xstatic isdn_link_t *isdn_linktab[NI4BISPPP]; >X >Xenum i4bisppp_states { >X ST_IDLE, /* initialized, ready, idle */ >X ST_DIALING, /* dialling out to remote */ >X ST_CONNECTED, /* connected to remote */ >X}; >X >X/*===========================================================================* >X * DEVICE DRIVER ROUTINES >X *===========================================================================*/ >X >X/*---------------------------------------------------------------------------* >X * interface attach routine at kernel boot time >X *---------------------------------------------------------------------------*/ >XPDEVSTATIC void >X#ifdef __FreeBSD__ >Xi4bispppattach(void *dummy) >X#else >Xi4bispppattach(void) >X#endif >X{ >X struct i4bisppp_softc *sc = i4bisppp_softc; >X int i; >X >X#ifndef HACK_NO_PSEUDO_ATTACH_MSG >X printf("i4bisppp: %d ISDN SyncPPP device(s) attached\n", >X NI4BISPPP); >X#endif >X >X for(i = 0; i < NI4BISPPP; sc++, i++) { >X i4bisppp_init_linktab(i); >X >X sc->sc_if.if_softc = sc; >X >X#ifdef __FreeBSD__ >X sc->sc_if.if_name = "isp"; >X#if defined(__FreeBSD_version) && __FreeBSD_version < 300001 >X sc->sc_if.if_next = NULL; >X#endif >X sc->sc_if.if_unit = i; >X#else >X sprintf(sc->sc_if.if_xname, "isp%d", i); >X sc->sc_unit = i; >X#endif >X >X sc->sc_if.if_mtu = PP_MTU; >X sc->sc_if.if_flags = IFF_SIMPLEX | IFF_POINTOPOINT; >X sc->sc_if.if_type = IFT_ISDNBASIC; >X sc->sc_state = ST_IDLE; >X >X sc->sc_if.if_ioctl = i4bisppp_ioctl; >X >X /* actually initialized by sppp_attach() */ >X /* sc->sc_if.if_output = sppp_output; */ >X >X sc->sc_if.if_start = i4bisppp_start; >X >X sc->sc_if.if_hdrlen = 0; >X sc->sc_if.if_addrlen = 0; >X sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN; >X >X sc->sc_if.if_ipackets = 0; >X sc->sc_if.if_ierrors = 0; >X sc->sc_if.if_opackets = 0; >X sc->sc_if.if_oerrors = 0; >X sc->sc_if.if_collisions = 0; >X sc->sc_if.if_ibytes = 0; >X sc->sc_if.if_obytes = 0; >X sc->sc_if.if_imcasts = 0; >X sc->sc_if.if_omcasts = 0; >X sc->sc_if.if_iqdrops = 0; >X sc->sc_if.if_noproto = 0; >X >X#if I4BISPPPACCT >X sc->sc_if.if_timer = 0; >X sc->sc_if.if_watchdog = i4bisppp_watchdog; >X sc->sc_iinb = 0; >X sc->sc_ioutb = 0; >X sc->sc_inb = 0; >X sc->sc_outb = 0; >X sc->sc_linb = 0; >X sc->sc_loutb = 0; >X sc->sc_fn = 1; >X#endif >X >X sc->sc_if_un.scu_sp.pp_tls = i4bisppp_tls; >X sc->sc_if_un.scu_sp.pp_tlf = i4bisppp_tlf; >X sc->sc_if_un.scu_sp.pp_con = i4bisppp_negotiation_complete; >X sc->sc_if_un.scu_sp.pp_chg = i4bisppp_state_changed; >X >X sppp_attach(&sc->sc_if); >X if_attach(&sc->sc_if); >X >X#if NBPFILTER > 0 >X#ifdef __FreeBSD__ >X bpfattach(&sc->sc_if, DLT_PPP, PPP_HDRLEN); >X CALLOUT_INIT(&sc->sc_ch); >X#endif /* __FreeBSD__ */ >X#ifdef __NetBSD__ >X bpfattach(&sc->sc_if.if_bpf, &sc->sc_if, DLT_PPP, sizeof(u_int)); >X#endif >X#endif >X } >X} >X >X/*---------------------------------------------------------------------------* >X * process ioctl >X *---------------------------------------------------------------------------*/ >Xstatic int >Xi4bisppp_ioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, caddr_t data) >X{ >X struct i4bisppp_softc *sc = ifp->if_softc; >X#if 0 >X struct sppp *sp = (struct sppp *)sc; >X struct ifaddr *ifa = (struct ifaddr *) data; >X struct ifreq *ifr = (struct ifreq *) data; >X#endif >X >X int error; >X >X error = sppp_ioctl(&sc->sc_if, cmd, data); >X if (error) >X return error; >X >X switch(cmd) { >X case SIOCSIFFLAGS: >X#if 0 /* never used ??? */ >X x = splimp(); >X if ((ifp->if_flags & IFF_UP) == 0) >X UNTIMEOUT(i4bisppp_timeout, (void *)sp, sc->sc_ch); >X splx(x); >X#endif >X break; >X } >X >X return 0; >X} >X >X/*---------------------------------------------------------------------------* >X * start output to ISDN B-channel >X *---------------------------------------------------------------------------*/ >Xstatic void >Xi4bisppp_start(struct ifnet *ifp) >X{ >X struct i4bisppp_softc *sc = ifp->if_softc; >X struct mbuf *m; >X int s; >X int unit = IFP2UNIT(ifp); >X >X if (sppp_isempty(ifp)) >X return; >X >X if(sc->sc_state != ST_CONNECTED) >X return; >X >X s = splimp(); >X /*ifp->if_flags |= IFF_OACTIVE; - need to clear this somewhere */ >X splx(s); >X >X while ((m = sppp_dequeue(&sc->sc_if)) != NULL) >X { >X >X#if NBPFILTER > 0 >X#ifdef __FreeBSD__ >X if (ifp->if_bpf) >X bpf_mtap(ifp, m); >X#endif /* __FreeBSD__ */ >X >X#ifdef __NetBSD__ >X if (ifp->if_bpf) >X bpf_mtap(ifp->if_bpf, m); >X#endif >X#endif /* NBPFILTER > 0 */ >X >X microtime(&ifp->if_lastchange); >X >X IF_ENQUEUE(isdn_linktab[unit]->tx_queue, m); >X >X sc->sc_if.if_obytes += m->m_pkthdr.len; >X sc->sc_outb += m->m_pkthdr.len; >X sc->sc_if.if_opackets++; >X } >X isdn_linktab[unit]->bch_tx_start(isdn_linktab[unit]->unit, >X isdn_linktab[unit]->channel); >X} >X >X#ifdef I4BISPPPACCT >X/*---------------------------------------------------------------------------* >X * watchdog routine >X *---------------------------------------------------------------------------*/ >Xstatic void >Xi4bisppp_watchdog(struct ifnet *ifp) >X{ >X struct i4bisppp_softc *sc = ifp->if_softc; >X int unit = IFP2UNIT(ifp); >X bchan_statistics_t bs; >X >X (*isdn_linktab[unit]->bch_stat) >X (isdn_linktab[unit]->unit, isdn_linktab[unit]->channel, &bs); >X >X sc->sc_ioutb += bs.outbytes; >X sc->sc_iinb += bs.inbytes; >X >X if((sc->sc_iinb != sc->sc_linb) || (sc->sc_ioutb != sc->sc_loutb) || sc->sc_fn) >X { >X int ri = (sc->sc_iinb - sc->sc_linb)/I4BISPPPACCTINTVL; >X int ro = (sc->sc_ioutb - sc->sc_loutb)/I4BISPPPACCTINTVL; >X >X if((sc->sc_iinb == sc->sc_linb) && (sc->sc_ioutb == sc->sc_loutb)) >X sc->sc_fn = 0; >X else >X sc->sc_fn = 1; >X >X sc->sc_linb = sc->sc_iinb; >X sc->sc_loutb = sc->sc_ioutb; >X >X i4b_l4_accounting(BDRV_ISPPP, unit, ACCT_DURING, >X sc->sc_ioutb, sc->sc_iinb, ro, ri, sc->sc_outb, sc->sc_inb); >X } >X sc->sc_if.if_timer = I4BISPPPACCTINTVL; >X >X#if 0 /* old stuff, keep it around */ >X printf(ISPPP_FMT "transmit timeout\n", ISPPP_ARG(sc)); >X i4bisppp_start(ifp); >X#endif >X} >X#endif /* I4BISPPPACCT */ >X >X/* >X *===========================================================================* >X * SyncPPP layer interface routines >X *===========================================================================* >X */ >X >X#if 0 /* never used ??? */ >X/*---------------------------------------------------------------------------* >X * just an alias for i4bisppp_tls, but of type timeout_t >X *---------------------------------------------------------------------------*/ >Xstatic void >Xi4bisppp_timeout(void *cookie) >X{ >X i4bisppp_tls((struct sppp *)cookie); >X} >X#endif >X >X/*---------------------------------------------------------------------------* >X * PPP this-layer-started action >X *---------------------------------------------------------------------------* >X */ >Xstatic void >Xi4bisppp_tls(struct sppp *sp) >X{ >X struct i4bisppp_softc *sc = (struct i4bisppp_softc *)sp; >X struct ifnet *ifp = (struct ifnet *)sp; >X >X if(sc->sc_state == ST_CONNECTED) >X return; >X >X i4b_l4_dialout(BDRV_ISPPP, IFP2UNIT(ifp)); >X} >X >X/*---------------------------------------------------------------------------* >X * PPP this-layer-finished action >X *---------------------------------------------------------------------------* >X */ >Xstatic void >Xi4bisppp_tlf(struct sppp *sp) >X{ >X struct i4bisppp_softc *sc = (struct i4bisppp_softc *)sp; >X/* call_desc_t *cd = sc->sc_cdp; */ >X struct ifnet *ifp = (struct ifnet *)sp; >X >X if(sc->sc_state != ST_CONNECTED) >X return; >X >X#if 0 /* never used ??? */ >X UNTIMEOUT(i4bisppp_timeout, (void *)sp, sc->sc_ch); >X#endif >X >X i4b_l4_drvrdisc(BDRV_ISPPP, IFP2UNIT(ifp)); >X} >X/*---------------------------------------------------------------------------* >X * PPP interface phase change >X *---------------------------------------------------------------------------* >X */ >Xstatic void >Xi4bisppp_state_changed(struct sppp *sp, int new_state) >X{ >X struct i4bisppp_softc *sc = (struct i4bisppp_softc *)sp; >X >X i4b_l4_ifstate_changed(sc->sc_cdp, new_state); >X} >X >X/*---------------------------------------------------------------------------* >X * PPP control protocol negotiation complete (run ip-up script now) >X *---------------------------------------------------------------------------* >X */ >Xstatic void >Xi4bisppp_negotiation_complete(struct sppp *sp) >X{ >X struct i4bisppp_softc *sc = (struct i4bisppp_softc *)sp; >X >X i4b_l4_negcomplete(sc->sc_cdp); >X} >X >X/*===========================================================================* >X * ISDN INTERFACE ROUTINES >X *===========================================================================*/ >X >X/*---------------------------------------------------------------------------* >X * this routine is called from L4 handler at connect time >X *---------------------------------------------------------------------------*/ >Xstatic void >Xi4bisppp_connect(int unit, void *cdp) >X{ >X struct i4bisppp_softc *sc = &i4bisppp_softc[unit]; >X struct sppp *sp = &sc->sc_if_un.scu_sp; >X int s = splimp(); >X >X sc->sc_cdp = (call_desc_t *)cdp; >X sc->sc_state = ST_CONNECTED; >X >X#if I4BISPPPACCT >X sc->sc_iinb = 0; >X sc->sc_ioutb = 0; >X sc->sc_inb = 0; >X sc->sc_outb = 0; >X sc->sc_linb = 0; >X sc->sc_loutb = 0; >X sc->sc_if.if_timer = I4BISPPPACCTINTVL; >X#endif >X >X#if 0 /* never used ??? */ >X UNTIMEOUT(i4bisppp_timeout, (void *)sp, sc->sc_ch); >X#endif >X >X sp->pp_up(sp); /* tell PPP we are ready */ >X sp->pp_last_sent = sp->pp_last_recv = SECOND; >X splx(s); >X} >X >X/*---------------------------------------------------------------------------* >X * this routine is called from L4 handler at disconnect time >X *---------------------------------------------------------------------------*/ >Xstatic void >Xi4bisppp_disconnect(int unit, void *cdp) >X{ >X call_desc_t *cd = (call_desc_t *)cdp; >X struct i4bisppp_softc *sc = &i4bisppp_softc[unit]; >X struct sppp *sp = &sc->sc_if_un.scu_sp; >X >X int s = splimp(); >X >X /* new stuff to check that the active channel is being closed */ >X if (cd != sc->sc_cdp) >X { >X#ifdef I4BISPPPDISCDEBUG >X printf("i4bisppp_disconnect: isppp%d channel%d not active\n", >X cd->driver_unit, cd->channelid); >X#endif >X splx(s); >X return; >X } >X >X#if I4BISPPPACCT >X sc->sc_if.if_timer = 0; >X#endif >X >X i4b_l4_accounting(BDRV_ISPPP, unit, ACCT_FINAL, >X sc->sc_ioutb, sc->sc_iinb, 0, 0, sc->sc_outb, sc->sc_inb); >X >X if (sc->sc_state == ST_CONNECTED) >X { >X#if 0 /* never used ??? */ >X UNTIMEOUT(i4bisppp_timeout, (void *)sp, sc->sc_ch); >X#endif >X sc->sc_cdp = (call_desc_t *)0; >X /* do thhis here because pp_down calls i4bisppp_tlf */ >X sc->sc_state = ST_IDLE; >X sp->pp_down(sp); /* tell PPP we have hung up */ >X } >X >X splx(s); >X} >X >X/*---------------------------------------------------------------------------* >X * this routine is used to give a feedback from userland demon >X * in case of dial problems >X *---------------------------------------------------------------------------*/ >Xstatic void >Xi4bisppp_dialresponse(int unit, int status) >X{ >X/* struct i4bisppp_softc *sc = &i4bisppp_softc[unit]; */ >X} >X >X/*---------------------------------------------------------------------------* >X * interface up/down >X *---------------------------------------------------------------------------*/ >Xstatic void >Xi4bisppp_updown(int unit, int updown) >X{ >X /* could probably do something useful here */ >X} >X >X/*---------------------------------------------------------------------------* >X * this routine is called from the HSCX interrupt handler >X * when a new frame (mbuf) has been received and was put on >X * the rx queue. >X *---------------------------------------------------------------------------*/ >Xstatic void >Xi4bisppp_rx_data_rdy(int unit) >X{ >X struct i4bisppp_softc *sc = &i4bisppp_softc[unit]; >X struct mbuf *m; >X int s; >X >X if((m = *isdn_linktab[unit]->rx_mbuf) == NULL) >X return; >X >X m->m_pkthdr.rcvif = &sc->sc_if; >X m->m_pkthdr.len = m->m_len; >X >X microtime(&sc->sc_if.if_lastchange); >X >X sc->sc_if.if_ipackets++; >X sc->sc_if.if_ibytes += m->m_pkthdr.len; >X >X#if I4BISPPPACCT >X sc->sc_inb += m->m_pkthdr.len; >X#endif >X >X#ifdef I4BISPPPDEBUG >X printf("i4bisppp_rx_data_ready: received packet!\n"); >X#endif >X >X#if NBPFILTER > 0 >X >X#ifdef __FreeBSD__ >X if(sc->sc_if.if_bpf) >X bpf_mtap(&sc->sc_if, m); >X#endif /* __FreeBSD__ */ >X >X#ifdef __NetBSD__ >X if(sc->sc_if.if_bpf) >X bpf_mtap(sc->sc_if.if_bpf, m); >X#endif >X >X#endif /* NBPFILTER > 0 */ >X >X s = splimp(); >X >X sppp_input(&sc->sc_if, m); >X >X splx(s); >X} >X >X/*---------------------------------------------------------------------------* >X * this routine is called from the HSCX interrupt handler >X * when the last frame has been sent out and there is no >X * further frame (mbuf) in the tx queue. >X *---------------------------------------------------------------------------*/ >Xstatic void >Xi4bisppp_tx_queue_empty(int unit) >X{ >X i4bisppp_start(&i4bisppp_softc[unit].sc_if); >X} >X/*---------------------------------------------------------------------------* >X * THIS should be used instead of last_active_time to implement >X * an activity timeout mechanism. >X *---------------------------------------------------------------------------*/ >Xtime_t >Xi4bisppp_idletime(int unit) >X{ >X struct sppp *sp; >X time_t now_time, sent_time, recv_time; >X sp = (struct sppp *) &i4bisppp_softc[unit]; >X >X now_time = SECOND; >X sent_time = now_time - sp->pp_last_sent; >X recv_time = now_time - sp->pp_last_recv; >X return (sent_time<recv_time)? sent_time : recv_time; >X} >X/*---------------------------------------------------------------------------* >X * this routine is called from the HSCX interrupt handler >X * each time a packet is received or transmitted. It should >X * be used to implement an activity timeout mechanism. >X *---------------------------------------------------------------------------*/ >Xstatic void >Xi4bisppp_activity(int unit, int rxtx) >X{ >X i4bisppp_softc[unit].sc_cdp->last_active_time = SECOND; >X} >X >X/*---------------------------------------------------------------------------* >X * return this drivers linktab address >X *---------------------------------------------------------------------------*/ >Xdrvr_link_t * >Xi4bisppp_ret_linktab(int unit) >X{ >X return(&i4bisppp_drvr_linktab[unit]); >X} >X >X/*---------------------------------------------------------------------------* >X * setup the isdn_linktab for this driver >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4bisppp_set_linktab(int unit, isdn_link_t *ilt) >X{ >X isdn_linktab[unit] = ilt; >X} >X >X/*---------------------------------------------------------------------------* >X * initialize this drivers linktab >X *---------------------------------------------------------------------------*/ >Xstatic void >Xi4bisppp_init_linktab(int unit) >X{ >X i4bisppp_drvr_linktab[unit].unit = unit; >X i4bisppp_drvr_linktab[unit].bch_rx_data_ready = i4bisppp_rx_data_rdy; >X i4bisppp_drvr_linktab[unit].bch_tx_queue_empty = i4bisppp_tx_queue_empty; >X i4bisppp_drvr_linktab[unit].bch_activity = i4bisppp_activity; >X i4bisppp_drvr_linktab[unit].line_connected = i4bisppp_connect; >X i4bisppp_drvr_linktab[unit].line_disconnected = i4bisppp_disconnect; >X i4bisppp_drvr_linktab[unit].dial_response = i4bisppp_dialresponse; >X i4bisppp_drvr_linktab[unit].updown_ind = i4bisppp_updown; >X} >X >X/*===========================================================================*/ >END-of-./usr/src/sys/i4b/driver/i4b_isppp.c >echo x - ./usr/src/sys/i4b/driver/i4b_isppp.c.patch >sed 's/^X//' >./usr/src/sys/i4b/driver/i4b_isppp.c.patch << 'END-of-./usr/src/sys/i4b/driver/i4b_isppp.c.patch' >X*** i4b_isppp.c Fri Dec 18 15:20:44 1998 >X--- i4b_isppp.c.new Wed Mar 17 13:16:02 1999 >X*************** >X*** 190,195 **** >X--- 190,196 ---- >X static void i4bisppp_state_changed(struct sppp *sp, int new_state); >X static void i4bisppp_negotiation_complete(struct sppp *sp); >X static void i4bisppp_watchdog(struct ifnet *ifp); >X+ time_t i4bisppp_idletime(int unit); >X >X /* initialized by L4 */ >X >X*************** >X*** 532,538 **** >X #endif >X >X sp->pp_up(sp); /* tell PPP we are ready */ >X! >X splx(s); >X } >X >X--- 533,539 ---- >X #endif >X >X sp->pp_up(sp); /* tell PPP we are ready */ >X! sp->pp_last_sent = sp->pp_last_recv = SECOND; >X splx(s); >X } >X >X*************** >X*** 661,667 **** >X { >X i4bisppp_start(&i4bisppp_softc[unit].sc_if); >X } >X! >X /*---------------------------------------------------------------------------* >X * this routine is called from the HSCX interrupt handler >X * each time a packet is received or transmitted. It should >X--- 662,683 ---- >X { >X i4bisppp_start(&i4bisppp_softc[unit].sc_if); >X } >X! /*---------------------------------------------------------------------------* >X! * THIS should be used instead of last_active_time to implement >X! * an activity timeout mechanism. >X! *---------------------------------------------------------------------------*/ >X! time_t >X! i4bisppp_idletime(int unit) >X! { >X! struct sppp *sp; >X! time_t now_time, sent_time, recv_time; >X! sp = (struct sppp *) &i4bisppp_softc[unit]; >X! >X! now_time = SECOND; >X! sent_time = now_time - sp->pp_last_sent; >X! recv_time = now_time - sp->pp_last_recv; >X! return (sent_time<recv_time)? sent_time : recv_time; >X! } >X /*---------------------------------------------------------------------------* >X * this routine is called from the HSCX interrupt handler >X * each time a packet is received or transmitted. It should >END-of-./usr/src/sys/i4b/driver/i4b_isppp.c.patch >echo x - ./usr/src/sys/i4b/driver/i4b_isppp.c.orig >sed 's/^X//' >./usr/src/sys/i4b/driver/i4b_isppp.c.orig << 'END-of-./usr/src/sys/i4b/driver/i4b_isppp.c.orig' >X/* >X * Copyright (c) 1997 Joerg Wunsch. All rights reserved. >X * >X * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. >X * >X * Redistribution and use in source and binary forms, with or without >X * modification, are permitted provided that the following conditions >X * are met: >X * >X * 1. Redistributions of source code must retain the above copyright >X * notice, this list of conditions and the following disclaimer. >X * 2. Redistributions in binary form must reproduce the above copyright >X * notice, this list of conditions and the following disclaimer in the >X * documentation and/or other materials provided with the distribution. >X * >X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND >X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE >X * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE >X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL >X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS >X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) >X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT >X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY >X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF >X * SUCH DAMAGE. >X * >X *--------------------------------------------------------------------------- >X * >X * i4b_isppp.c - isdn4bsd kernel SyncPPP driver >X * -------------------------------------------- >X * >X * Uses Serge Vakulenko's sppp backend (originally contributed with >X * the "cx" driver for Cronyx's HDLC-in-hardware device). This driver >X * is only the glue between sppp and i4b. >X * >X * $Id: i4b_isppp.c,v 1.1 1998/12/27 21:46:42 phk Exp $ >X * >X * last edit-date: [Fri Dec 18 11:47:58 1998] >X * >X *---------------------------------------------------------------------------*/ >X >X#include "i4bisppp.h" >X#ifdef __FreeBSD__ >X#include "sppp.h" >X#endif >X >X#if NI4BISPPP == 0 >X# error "You need to define `pseudo-device sppp <N>' with options ISPPP" >X#endif >X >X#include <sys/param.h> >X#include <sys/systm.h> >X#include <sys/mbuf.h> >X#include <sys/socket.h> >X#include <sys/errno.h> >X#include <sys/ioccom.h> >X#include <sys/sockio.h> >X#include <sys/kernel.h> >X#include <sys/protosw.h> >X >X#include <net/if.h> >X#include <net/if_types.h> >X#include <net/netisr.h> >X#include <net/route.h> >X#ifdef __FreeBSD__ >X#include <net/if_sppp.h> >X#else >X#include <i4b/sppp/if_sppp.h> >X#endif >X >X#include <netinet/in.h> >X#include <netinet/in_systm.h> >X#include <netinet/in_var.h> >X#include <netinet/ip.h> >X >X#include "bpfilter.h" >X#if NBPFILTER > 0 >X#include <sys/time.h> >X#include <net/bpf.h> >X#endif >X >X#ifdef __FreeBSD__ >X#include <machine/i4b_ioctl.h> >X#include <machine/i4b_cause.h> >X#else >X#include <i4b/i4b_ioctl.h> >X#include <i4b/i4b_cause.h> >X#endif >X >X#include <i4b/include/i4b_global.h> >X#include <i4b/include/i4b_mbuf.h> >X#include <i4b/include/i4b_l3l4.h> >X >X#include <i4b/layer4/i4b_l4.h> >X >X#ifdef __FreeBSD__ >X#define ISPPP_FMT "isp%d: " >X#define ISPPP_ARG(sc) ((sc)->sc_if.if_unit) >X#define PDEVSTATIC static >X#define IFP2UNIT(ifp) (ifp)->if_unit >X >X# if __FreeBSD_version >= 300001 >X# define CALLOUT_INIT(chan) callout_handle_init(chan) >X# define TIMEOUT(fun, arg, chan, tick) chan = timeout(fun, arg, tick) >X# define UNTIMEOUT(fun, arg, chan) untimeout(fun, arg, chan) >X# define IOCTL_CMD_T u_long >X# else >X# define CALLOUT_INIT(chan) do {} while(0) >X# define TIMEOUT(fun, arg, chan, tick) timeout(fun, arg, tick) >X# define UNTIMEOUT(fun, arg, chan) untimeout(fun, arg) >X# define IOCTL_CMD_T int >X# endif >X >X#elif defined __NetBSD__ || defined __OpenBSD__ >X#define ISPPP_FMT "%s: " >X#define ISPPP_ARG(sc) ((sc)->sc_if.if_xname) >X#define PDEVSTATIC /* not static */ >X#define IOCTL_CMD_T u_long >X#define IFP2UNIT(ifp) ((struct i4bisppp_softc *)ifp->if_softc)->sc_unit >X#else >X# error "What system are you using?" >X#endif >X >X#ifdef __FreeBSD__ >XPDEVSTATIC void i4bispppattach(void *); >XPSEUDO_SET(i4bispppattach, i4b_isppp); >X#else >XPDEVSTATIC void i4bispppattach __P((void)); >X#endif >X >X#define I4BISPPPACCT 1 /* enable accounting messages */ >X#define I4BISPPPACCTINTVL 2 /* accounting msg interval in secs */ >X#define I4BISPPPDISCDEBUG 1 >X >X#define PPP_HDRLEN 4 /* 4 octetts PPP header length */ >X >Xstruct i4bisppp_softc { >X /* >X * struct sppp starts with a struct ifnet, but we gotta allocate >X * more space for it. NB: do not relocate this union, it must >X * be first in isppp_softc. The tls and tlf hooks below want to >X * convert a ``struct sppp *'' into a ``struct isppp_softc *''. >X */ >X union { >X struct ifnet scu_if; >X struct sppp scu_sp; >X } sc_if_un; >X#define sc_if sc_if_un.scu_if >X >X int sc_state; /* state of the interface */ >X >X#ifndef __FreeBSD__ >X int sc_unit; /* unit number for Net/OpenBSD */ >X#endif >X >X call_desc_t *sc_cdp; /* ptr to call descriptor */ >X >X#ifdef I4BISPPPACCT >X int sc_iinb; /* isdn driver # of inbytes */ >X int sc_ioutb; /* isdn driver # of outbytes */ >X int sc_inb; /* # of bytes rx'd */ >X int sc_outb; /* # of bytes tx'd */ >X int sc_linb; /* last # of bytes rx'd */ >X int sc_loutb; /* last # of bytes tx'd */ >X int sc_fn; /* flag, first null acct */ >X#endif >X >X#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 >X struct callout_handle sc_ch; >X#endif >X >X} i4bisppp_softc[NI4BISPPP]; >X >Xstatic void i4bisppp_init_linktab(int unit); >Xstatic int i4bisppp_ioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, caddr_t data); >X >X#if 0 >Xstatic void i4bisppp_send(struct ifnet *ifp); >X#endif >X >Xstatic void i4bisppp_start(struct ifnet *ifp); >X >X#if 0 /* never used ??? */ >Xstatic void i4bisppp_timeout(void *cookie); >X#endif >X >Xstatic void i4bisppp_tls(struct sppp *sp); >Xstatic void i4bisppp_tlf(struct sppp *sp); >Xstatic void i4bisppp_state_changed(struct sppp *sp, int new_state); >Xstatic void i4bisppp_negotiation_complete(struct sppp *sp); >Xstatic void i4bisppp_watchdog(struct ifnet *ifp); >X >X/* initialized by L4 */ >X >Xstatic drvr_link_t i4bisppp_drvr_linktab[NI4BISPPP]; >Xstatic isdn_link_t *isdn_linktab[NI4BISPPP]; >X >Xenum i4bisppp_states { >X ST_IDLE, /* initialized, ready, idle */ >X ST_DIALING, /* dialling out to remote */ >X ST_CONNECTED, /* connected to remote */ >X}; >X >X/*===========================================================================* >X * DEVICE DRIVER ROUTINES >X *===========================================================================*/ >X >X/*---------------------------------------------------------------------------* >X * interface attach routine at kernel boot time >X *---------------------------------------------------------------------------*/ >XPDEVSTATIC void >X#ifdef __FreeBSD__ >Xi4bispppattach(void *dummy) >X#else >Xi4bispppattach(void) >X#endif >X{ >X struct i4bisppp_softc *sc = i4bisppp_softc; >X int i; >X >X#ifndef HACK_NO_PSEUDO_ATTACH_MSG >X printf("i4bisppp: %d ISDN SyncPPP device(s) attached\n", >X NI4BISPPP); >X#endif >X >X for(i = 0; i < NI4BISPPP; sc++, i++) { >X i4bisppp_init_linktab(i); >X >X sc->sc_if.if_softc = sc; >X >X#ifdef __FreeBSD__ >X sc->sc_if.if_name = "isp"; >X#if defined(__FreeBSD_version) && __FreeBSD_version < 300001 >X sc->sc_if.if_next = NULL; >X#endif >X sc->sc_if.if_unit = i; >X#else >X sprintf(sc->sc_if.if_xname, "isp%d", i); >X sc->sc_unit = i; >X#endif >X >X sc->sc_if.if_mtu = PP_MTU; >X sc->sc_if.if_flags = IFF_SIMPLEX | IFF_POINTOPOINT; >X sc->sc_if.if_type = IFT_ISDNBASIC; >X sc->sc_state = ST_IDLE; >X >X sc->sc_if.if_ioctl = i4bisppp_ioctl; >X >X /* actually initialized by sppp_attach() */ >X /* sc->sc_if.if_output = sppp_output; */ >X >X sc->sc_if.if_start = i4bisppp_start; >X >X sc->sc_if.if_hdrlen = 0; >X sc->sc_if.if_addrlen = 0; >X sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN; >X >X sc->sc_if.if_ipackets = 0; >X sc->sc_if.if_ierrors = 0; >X sc->sc_if.if_opackets = 0; >X sc->sc_if.if_oerrors = 0; >X sc->sc_if.if_collisions = 0; >X sc->sc_if.if_ibytes = 0; >X sc->sc_if.if_obytes = 0; >X sc->sc_if.if_imcasts = 0; >X sc->sc_if.if_omcasts = 0; >X sc->sc_if.if_iqdrops = 0; >X sc->sc_if.if_noproto = 0; >X >X#if I4BISPPPACCT >X sc->sc_if.if_timer = 0; >X sc->sc_if.if_watchdog = i4bisppp_watchdog; >X sc->sc_iinb = 0; >X sc->sc_ioutb = 0; >X sc->sc_inb = 0; >X sc->sc_outb = 0; >X sc->sc_linb = 0; >X sc->sc_loutb = 0; >X sc->sc_fn = 1; >X#endif >X >X sc->sc_if_un.scu_sp.pp_tls = i4bisppp_tls; >X sc->sc_if_un.scu_sp.pp_tlf = i4bisppp_tlf; >X sc->sc_if_un.scu_sp.pp_con = i4bisppp_negotiation_complete; >X sc->sc_if_un.scu_sp.pp_chg = i4bisppp_state_changed; >X >X sppp_attach(&sc->sc_if); >X if_attach(&sc->sc_if); >X >X#if NBPFILTER > 0 >X#ifdef __FreeBSD__ >X bpfattach(&sc->sc_if, DLT_PPP, PPP_HDRLEN); >X CALLOUT_INIT(&sc->sc_ch); >X#endif /* __FreeBSD__ */ >X#ifdef __NetBSD__ >X bpfattach(&sc->sc_if.if_bpf, &sc->sc_if, DLT_PPP, sizeof(u_int)); >X#endif >X#endif >X } >X} >X >X/*---------------------------------------------------------------------------* >X * process ioctl >X *---------------------------------------------------------------------------*/ >Xstatic int >Xi4bisppp_ioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, caddr_t data) >X{ >X struct i4bisppp_softc *sc = ifp->if_softc; >X#if 0 >X struct sppp *sp = (struct sppp *)sc; >X struct ifaddr *ifa = (struct ifaddr *) data; >X struct ifreq *ifr = (struct ifreq *) data; >X#endif >X >X int error; >X >X error = sppp_ioctl(&sc->sc_if, cmd, data); >X if (error) >X return error; >X >X switch(cmd) { >X case SIOCSIFFLAGS: >X#if 0 /* never used ??? */ >X x = splimp(); >X if ((ifp->if_flags & IFF_UP) == 0) >X UNTIMEOUT(i4bisppp_timeout, (void *)sp, sc->sc_ch); >X splx(x); >X#endif >X break; >X } >X >X return 0; >X} >X >X/*---------------------------------------------------------------------------* >X * start output to ISDN B-channel >X *---------------------------------------------------------------------------*/ >Xstatic void >Xi4bisppp_start(struct ifnet *ifp) >X{ >X struct i4bisppp_softc *sc = ifp->if_softc; >X struct mbuf *m; >X int s; >X int unit = IFP2UNIT(ifp); >X >X if (sppp_isempty(ifp)) >X return; >X >X if(sc->sc_state != ST_CONNECTED) >X return; >X >X s = splimp(); >X /*ifp->if_flags |= IFF_OACTIVE; - need to clear this somewhere */ >X splx(s); >X >X while ((m = sppp_dequeue(&sc->sc_if)) != NULL) >X { >X >X#if NBPFILTER > 0 >X#ifdef __FreeBSD__ >X if (ifp->if_bpf) >X bpf_mtap(ifp, m); >X#endif /* __FreeBSD__ */ >X >X#ifdef __NetBSD__ >X if (ifp->if_bpf) >X bpf_mtap(ifp->if_bpf, m); >X#endif >X#endif /* NBPFILTER > 0 */ >X >X microtime(&ifp->if_lastchange); >X >X IF_ENQUEUE(isdn_linktab[unit]->tx_queue, m); >X >X sc->sc_if.if_obytes += m->m_pkthdr.len; >X sc->sc_outb += m->m_pkthdr.len; >X sc->sc_if.if_opackets++; >X } >X isdn_linktab[unit]->bch_tx_start(isdn_linktab[unit]->unit, >X isdn_linktab[unit]->channel); >X} >X >X#ifdef I4BISPPPACCT >X/*---------------------------------------------------------------------------* >X * watchdog routine >X *---------------------------------------------------------------------------*/ >Xstatic void >Xi4bisppp_watchdog(struct ifnet *ifp) >X{ >X struct i4bisppp_softc *sc = ifp->if_softc; >X int unit = IFP2UNIT(ifp); >X bchan_statistics_t bs; >X >X (*isdn_linktab[unit]->bch_stat) >X (isdn_linktab[unit]->unit, isdn_linktab[unit]->channel, &bs); >X >X sc->sc_ioutb += bs.outbytes; >X sc->sc_iinb += bs.inbytes; >X >X if((sc->sc_iinb != sc->sc_linb) || (sc->sc_ioutb != sc->sc_loutb) || sc->sc_fn) >X { >X int ri = (sc->sc_iinb - sc->sc_linb)/I4BISPPPACCTINTVL; >X int ro = (sc->sc_ioutb - sc->sc_loutb)/I4BISPPPACCTINTVL; >X >X if((sc->sc_iinb == sc->sc_linb) && (sc->sc_ioutb == sc->sc_loutb)) >X sc->sc_fn = 0; >X else >X sc->sc_fn = 1; >X >X sc->sc_linb = sc->sc_iinb; >X sc->sc_loutb = sc->sc_ioutb; >X >X i4b_l4_accounting(BDRV_ISPPP, unit, ACCT_DURING, >X sc->sc_ioutb, sc->sc_iinb, ro, ri, sc->sc_outb, sc->sc_inb); >X } >X sc->sc_if.if_timer = I4BISPPPACCTINTVL; >X >X#if 0 /* old stuff, keep it around */ >X printf(ISPPP_FMT "transmit timeout\n", ISPPP_ARG(sc)); >X i4bisppp_start(ifp); >X#endif >X} >X#endif /* I4BISPPPACCT */ >X >X/* >X *===========================================================================* >X * SyncPPP layer interface routines >X *===========================================================================* >X */ >X >X#if 0 /* never used ??? */ >X/*---------------------------------------------------------------------------* >X * just an alias for i4bisppp_tls, but of type timeout_t >X *---------------------------------------------------------------------------*/ >Xstatic void >Xi4bisppp_timeout(void *cookie) >X{ >X i4bisppp_tls((struct sppp *)cookie); >X} >X#endif >X >X/*---------------------------------------------------------------------------* >X * PPP this-layer-started action >X *---------------------------------------------------------------------------* >X */ >Xstatic void >Xi4bisppp_tls(struct sppp *sp) >X{ >X struct i4bisppp_softc *sc = (struct i4bisppp_softc *)sp; >X struct ifnet *ifp = (struct ifnet *)sp; >X >X if(sc->sc_state == ST_CONNECTED) >X return; >X >X i4b_l4_dialout(BDRV_ISPPP, IFP2UNIT(ifp)); >X} >X >X/*---------------------------------------------------------------------------* >X * PPP this-layer-finished action >X *---------------------------------------------------------------------------* >X */ >Xstatic void >Xi4bisppp_tlf(struct sppp *sp) >X{ >X struct i4bisppp_softc *sc = (struct i4bisppp_softc *)sp; >X/* call_desc_t *cd = sc->sc_cdp; */ >X struct ifnet *ifp = (struct ifnet *)sp; >X >X if(sc->sc_state != ST_CONNECTED) >X return; >X >X#if 0 /* never used ??? */ >X UNTIMEOUT(i4bisppp_timeout, (void *)sp, sc->sc_ch); >X#endif >X >X i4b_l4_drvrdisc(BDRV_ISPPP, IFP2UNIT(ifp)); >X} >X/*---------------------------------------------------------------------------* >X * PPP interface phase change >X *---------------------------------------------------------------------------* >X */ >Xstatic void >Xi4bisppp_state_changed(struct sppp *sp, int new_state) >X{ >X struct i4bisppp_softc *sc = (struct i4bisppp_softc *)sp; >X >X i4b_l4_ifstate_changed(sc->sc_cdp, new_state); >X} >X >X/*---------------------------------------------------------------------------* >X * PPP control protocol negotiation complete (run ip-up script now) >X *---------------------------------------------------------------------------* >X */ >Xstatic void >Xi4bisppp_negotiation_complete(struct sppp *sp) >X{ >X struct i4bisppp_softc *sc = (struct i4bisppp_softc *)sp; >X >X i4b_l4_negcomplete(sc->sc_cdp); >X} >X >X/*===========================================================================* >X * ISDN INTERFACE ROUTINES >X *===========================================================================*/ >X >X/*---------------------------------------------------------------------------* >X * this routine is called from L4 handler at connect time >X *---------------------------------------------------------------------------*/ >Xstatic void >Xi4bisppp_connect(int unit, void *cdp) >X{ >X struct i4bisppp_softc *sc = &i4bisppp_softc[unit]; >X struct sppp *sp = &sc->sc_if_un.scu_sp; >X int s = splimp(); >X >X sc->sc_cdp = (call_desc_t *)cdp; >X sc->sc_state = ST_CONNECTED; >X >X#if I4BISPPPACCT >X sc->sc_iinb = 0; >X sc->sc_ioutb = 0; >X sc->sc_inb = 0; >X sc->sc_outb = 0; >X sc->sc_linb = 0; >X sc->sc_loutb = 0; >X sc->sc_if.if_timer = I4BISPPPACCTINTVL; >X#endif >X >X#if 0 /* never used ??? */ >X UNTIMEOUT(i4bisppp_timeout, (void *)sp, sc->sc_ch); >X#endif >X >X sp->pp_up(sp); /* tell PPP we are ready */ >X >X splx(s); >X} >X >X/*---------------------------------------------------------------------------* >X * this routine is called from L4 handler at disconnect time >X *---------------------------------------------------------------------------*/ >Xstatic void >Xi4bisppp_disconnect(int unit, void *cdp) >X{ >X call_desc_t *cd = (call_desc_t *)cdp; >X struct i4bisppp_softc *sc = &i4bisppp_softc[unit]; >X struct sppp *sp = &sc->sc_if_un.scu_sp; >X >X int s = splimp(); >X >X /* new stuff to check that the active channel is being closed */ >X if (cd != sc->sc_cdp) >X { >X#ifdef I4BISPPPDISCDEBUG >X printf("i4bisppp_disconnect: isppp%d channel%d not active\n", >X cd->driver_unit, cd->channelid); >X#endif >X splx(s); >X return; >X } >X >X#if I4BISPPPACCT >X sc->sc_if.if_timer = 0; >X#endif >X >X i4b_l4_accounting(BDRV_ISPPP, unit, ACCT_FINAL, >X sc->sc_ioutb, sc->sc_iinb, 0, 0, sc->sc_outb, sc->sc_inb); >X >X if (sc->sc_state == ST_CONNECTED) >X { >X#if 0 /* never used ??? */ >X UNTIMEOUT(i4bisppp_timeout, (void *)sp, sc->sc_ch); >X#endif >X sc->sc_cdp = (call_desc_t *)0; >X /* do thhis here because pp_down calls i4bisppp_tlf */ >X sc->sc_state = ST_IDLE; >X sp->pp_down(sp); /* tell PPP we have hung up */ >X } >X >X splx(s); >X} >X >X/*---------------------------------------------------------------------------* >X * this routine is used to give a feedback from userland demon >X * in case of dial problems >X *---------------------------------------------------------------------------*/ >Xstatic void >Xi4bisppp_dialresponse(int unit, int status) >X{ >X/* struct i4bisppp_softc *sc = &i4bisppp_softc[unit]; */ >X} >X >X/*---------------------------------------------------------------------------* >X * interface up/down >X *---------------------------------------------------------------------------*/ >Xstatic void >Xi4bisppp_updown(int unit, int updown) >X{ >X /* could probably do something useful here */ >X} >X >X/*---------------------------------------------------------------------------* >X * this routine is called from the HSCX interrupt handler >X * when a new frame (mbuf) has been received and was put on >X * the rx queue. >X *---------------------------------------------------------------------------*/ >Xstatic void >Xi4bisppp_rx_data_rdy(int unit) >X{ >X struct i4bisppp_softc *sc = &i4bisppp_softc[unit]; >X struct mbuf *m; >X int s; >X >X if((m = *isdn_linktab[unit]->rx_mbuf) == NULL) >X return; >X >X m->m_pkthdr.rcvif = &sc->sc_if; >X m->m_pkthdr.len = m->m_len; >X >X microtime(&sc->sc_if.if_lastchange); >X >X sc->sc_if.if_ipackets++; >X sc->sc_if.if_ibytes += m->m_pkthdr.len; >X >X#if I4BISPPPACCT >X sc->sc_inb += m->m_pkthdr.len; >X#endif >X >X#ifdef I4BISPPPDEBUG >X printf("i4bisppp_rx_data_ready: received packet!\n"); >X#endif >X >X#if NBPFILTER > 0 >X >X#ifdef __FreeBSD__ >X if(sc->sc_if.if_bpf) >X bpf_mtap(&sc->sc_if, m); >X#endif /* __FreeBSD__ */ >X >X#ifdef __NetBSD__ >X if(sc->sc_if.if_bpf) >X bpf_mtap(sc->sc_if.if_bpf, m); >X#endif >X >X#endif /* NBPFILTER > 0 */ >X >X s = splimp(); >X >X sppp_input(&sc->sc_if, m); >X >X splx(s); >X} >X >X/*---------------------------------------------------------------------------* >X * this routine is called from the HSCX interrupt handler >X * when the last frame has been sent out and there is no >X * further frame (mbuf) in the tx queue. >X *---------------------------------------------------------------------------*/ >Xstatic void >Xi4bisppp_tx_queue_empty(int unit) >X{ >X i4bisppp_start(&i4bisppp_softc[unit].sc_if); >X} >X >X/*---------------------------------------------------------------------------* >X * this routine is called from the HSCX interrupt handler >X * each time a packet is received or transmitted. It should >X * be used to implement an activity timeout mechanism. >X *---------------------------------------------------------------------------*/ >Xstatic void >Xi4bisppp_activity(int unit, int rxtx) >X{ >X i4bisppp_softc[unit].sc_cdp->last_active_time = SECOND; >X} >X >X/*---------------------------------------------------------------------------* >X * return this drivers linktab address >X *---------------------------------------------------------------------------*/ >Xdrvr_link_t * >Xi4bisppp_ret_linktab(int unit) >X{ >X return(&i4bisppp_drvr_linktab[unit]); >X} >X >X/*---------------------------------------------------------------------------* >X * setup the isdn_linktab for this driver >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4bisppp_set_linktab(int unit, isdn_link_t *ilt) >X{ >X isdn_linktab[unit] = ilt; >X} >X >X/*---------------------------------------------------------------------------* >X * initialize this drivers linktab >X *---------------------------------------------------------------------------*/ >Xstatic void >Xi4bisppp_init_linktab(int unit) >X{ >X i4bisppp_drvr_linktab[unit].unit = unit; >X i4bisppp_drvr_linktab[unit].bch_rx_data_ready = i4bisppp_rx_data_rdy; >X i4bisppp_drvr_linktab[unit].bch_tx_queue_empty = i4bisppp_tx_queue_empty; >X i4bisppp_drvr_linktab[unit].bch_activity = i4bisppp_activity; >X i4bisppp_drvr_linktab[unit].line_connected = i4bisppp_connect; >X i4bisppp_drvr_linktab[unit].line_disconnected = i4bisppp_disconnect; >X i4bisppp_drvr_linktab[unit].dial_response = i4bisppp_dialresponse; >X i4bisppp_drvr_linktab[unit].updown_ind = i4bisppp_updown; >X} >X >X/*===========================================================================*/ >END-of-./usr/src/sys/i4b/driver/i4b_isppp.c.orig >echo c - ./usr/src/sys/i4b/layer4 >mkdir -p ./usr/src/sys/i4b/layer4 > /dev/null 2>&1 >echo x - ./usr/src/sys/i4b/layer4/i4b_l4.c >sed 's/^X//' >./usr/src/sys/i4b/layer4/i4b_l4.c << 'END-of-./usr/src/sys/i4b/layer4/i4b_l4.c' >X/* >X * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. >X * >X * Redistribution and use in source and binary forms, with or without >X * modification, are permitted provided that the following conditions >X * are met: >X * 1. Redistributions of source code must retain the above copyright >X * notice, this list of conditions and the following disclaimer. >X * 2. Redistributions in binary form must reproduce the above copyright >X * notice, this list of conditions and the following disclaimer in the >X * documentation and/or other materials provided with the distribution. >X * >X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND >X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE >X * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE >X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL >X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS >X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) >X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT >X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY >X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF >X * SUCH DAMAGE. >X * >X *--------------------------------------------------------------------------- >X * >X * i4b_l4.c - kernel interface to userland >X * ----------------------------------------- >X * >X * $Id: i4b_l4.c,v 1.1 1998/12/27 21:46:52 phk Exp $ >X * >X * last edit-date: [Sat Dec 5 18:35:16 1998] >X * >X *---------------------------------------------------------------------------*/ >X >X#include "i4b.h" >X#include "i4bipr.h" >X#include "i4bisppp.h" >X#include "i4brbch.h" >X#include "i4btel.h" >X >X#if NI4B > 0 >X >X#include <sys/param.h> >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X#include <sys/ioccom.h> >X#else >X#include <sys/ioctl.h> >X#endif >X#include <sys/kernel.h> >X#include <sys/systm.h> >X#include <sys/conf.h> >X#include <sys/mbuf.h> >X#include <sys/proc.h> >X#include <sys/fcntl.h> >X#include <sys/socket.h> >X#include <net/if.h> >X >X#ifdef __FreeBSD__ >X#include <machine/i4b_debug.h> >X#include <machine/i4b_ioctl.h> >X#include <machine/i4b_cause.h> >X#else >X#include <i4b/i4b_debug.h> >X#include <i4b/i4b_ioctl.h> >X#include <i4b/i4b_cause.h> >X#endif >X >X#include <i4b/include/i4b_global.h> >X#include <i4b/include/i4b_l3l4.h> >X#include <i4b/include/i4b_mbuf.h> >X#include <i4b/layer3/i4b_l3.h> >X#include <i4b/layer4/i4b_l4.h> >X >Xunsigned int i4b_l4_debug = L4_DEBUG_DEFAULT; >X >Xstruct ctrl_type_desc ctrl_types[CTRL_NUMTYPES] = { { NULL, NULL} }; >X >Xstatic int i4b_link_bchandrvr(call_desc_t *cd); >Xstatic void i4b_unlink_bchandrvr(call_desc_t *cd); >Xstatic void i4b_l4_setup_timeout(call_desc_t *cd); >Xstatic time_t i4b_get_idletime(call_desc_t *cd); >X >X/*---------------------------------------------------------------------------* >X * send MSG_PDEACT_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_pdeact(int controller, int numactive) >X{ >X struct mbuf *m; >X int i; >X call_desc_t *cd; >X >X for(i=0; i < N_CALL_DESC; i++) >X { >X if((call_desc[i].cdid != CDID_UNUSED) && >X (ctrl_desc[call_desc[i].controller].ctrl_type == CTRL_PASSIVE) && >X (ctrl_desc[call_desc[i].controller].unit == controller)) >X { >X cd = &call_desc[i]; >X >X if(cd->timeout_active) >X { >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X untimeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, cd->idle_timeout_handle); >X#else >X untimeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd); >X#endif >X } >X >X if(cd->dlt != NULL) >X { >X (*cd->dlt->line_disconnected)(cd->driver_unit, (void *)cd); >X i4b_unlink_bchandrvr(cd); >X } >X >X if((cd->channelid == CHAN_B1) || (cd->channelid == CHAN_B2)) >X { >X ctrl_desc[cd->controller].bch_state[cd->channelid] = BCH_ST_FREE; >X } >X >X cd->cdid = CDID_UNUSED; >X } >X } >X >X if((m = i4b_Dgetmbuf(sizeof(msg_pdeact_ind_t))) != NULL) >X { >X msg_pdeact_ind_t *md = (msg_pdeact_ind_t *)m->m_data; >X >X md->header.type = MSG_PDEACT_IND; >X md->header.cdid = -1; >X >X md->controller = controller; >X md->numactive = numactive; >X >X i4bputqueue_hipri(m); /* URGENT !!! */ >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_L12STAT_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_l12stat(int controller, int layer, int state) >X{ >X struct mbuf *m; >X >X if((m = i4b_Dgetmbuf(sizeof(msg_l12stat_ind_t))) != NULL) >X { >X msg_l12stat_ind_t *md = (msg_l12stat_ind_t *)m->m_data; >X >X md->header.type = MSG_L12STAT_IND; >X md->header.cdid = -1; >X >X md->controller = controller; >X md->layer = layer; >X md->state = state; >X >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_TEIASG_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_teiasg(int controller, int tei) >X{ >X struct mbuf *m; >X >X if((m = i4b_Dgetmbuf(sizeof(msg_teiasg_ind_t))) != NULL) >X { >X msg_teiasg_ind_t *md = (msg_teiasg_ind_t *)m->m_data; >X >X md->header.type = MSG_TEIASG_IND; >X md->header.cdid = -1; >X >X md->controller = controller; >X md->tei = ctrl_desc[controller].tei; >X >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_DIALOUT_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_dialout(int driver, int driver_unit) >X{ >X struct mbuf *m; >X >X if((m = i4b_Dgetmbuf(sizeof(msg_dialout_ind_t))) != NULL) >X { >X msg_dialout_ind_t *md = (msg_dialout_ind_t *)m->m_data; >X >X md->header.type = MSG_DIALOUT_IND; >X md->header.cdid = -1; >X >X md->driver = driver; >X md->driver_unit = driver_unit; >X >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_NEGOTIATION_COMPL message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_negcomplete(call_desc_t *cd) >X{ >X struct mbuf *m; >X >X if((m = i4b_Dgetmbuf(sizeof(msg_negcomplete_ind_t))) != NULL) >X { >X msg_negcomplete_ind_t *md = (msg_negcomplete_ind_t *)m->m_data; >X >X md->header.type = MSG_NEGCOMP_IND; >X md->header.cdid = cd->cdid; >X >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_IFSTATE_CHANGED_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_ifstate_changed(call_desc_t *cd, int new_state) >X{ >X struct mbuf *m; >X >X if((m = i4b_Dgetmbuf(sizeof(msg_ifstatechg_ind_t))) != NULL) >X { >X msg_ifstatechg_ind_t *md = (msg_ifstatechg_ind_t *)m->m_data; >X >X md->header.type = MSG_IFSTATE_CHANGED_IND; >X md->header.cdid = cd->cdid; >X md->state = new_state; >X >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_DRVRDISC_REQ message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_drvrdisc(int driver, int driver_unit) >X{ >X struct mbuf *m; >X >X if((m = i4b_Dgetmbuf(sizeof(msg_drvrdisc_req_t))) != NULL) >X { >X msg_drvrdisc_req_t *md = (msg_drvrdisc_req_t *)m->m_data; >X >X md->header.type = MSG_DRVRDISC_REQ; >X md->header.cdid = -1; >X >X md->driver = driver; >X md->driver_unit = driver_unit; >X >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_ACCT_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_accounting(int driver, int driver_unit, int accttype, int ioutbytes, >X int iinbytes, int ro, int ri, int outbytes, int inbytes) >X{ >X struct mbuf *m; >X >X if((m = i4b_Dgetmbuf(sizeof(msg_accounting_ind_t))) != NULL) >X { >X msg_accounting_ind_t *md = (msg_accounting_ind_t *)m->m_data; >X >X md->header.type = MSG_ACCT_IND; >X md->header.cdid = -1; >X >X md->driver = driver; >X md->driver_unit = driver_unit; >X >X md->accttype = accttype; >X md->ioutbytes = ioutbytes; >X md->iinbytes = iinbytes; >X md->outbps = ro; >X md->inbps = ri; >X md->outbytes = outbytes; >X md->inbytes = inbytes; >X >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_CONNECT_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_connect_ind(call_desc_t *cd) >X{ >X struct mbuf *m; >X >X if((m = i4b_Dgetmbuf(sizeof(msg_connect_ind_t))) != NULL) >X { >X msg_connect_ind_t *mp = (msg_connect_ind_t *)m->m_data; >X >X mp->header.type = MSG_CONNECT_IND; >X mp->header.cdid = cd->cdid; >X >X mp->controller = cd->controller; >X mp->channel = cd->channelid; >X mp->bprot = cd->bprot; >X >X cd->dir = DIR_INCOMING; >X >X if(strlen(cd->dst_telno) > 0) >X strcpy(mp->dst_telno, cd->dst_telno); >X else >X strcpy(mp->dst_telno, TELNO_EMPTY); >X >X if(strlen(cd->src_telno) > 0) >X strcpy(mp->src_telno, cd->src_telno); >X else >X strcpy(mp->src_telno, TELNO_EMPTY); >X >X strcpy(mp->display, cd->display); >X >X mp->scr_ind = cd->scr_ind; >X >X T400_start(cd); >X >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_CONNECT_ACTIVE_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_connect_active_ind(call_desc_t *cd) >X{ >X int s; >X struct mbuf *m; >X >X s = SPLI4B(); >X >X cd->last_active_time = cd->connect_time = SECOND; >X >X DBGL4(L4_TIMO, "i4b_l4_connect_active_ind", ("last_active/connect_time=%ld\n", (long)cd->connect_time)); >X >X i4b_link_bchandrvr(cd); >X >X (*cd->dlt->line_connected)(cd->driver_unit, (void *)cd); >X >X i4b_l4_setup_timeout(cd); >X >X splx(s); >X >X if((m = i4b_Dgetmbuf(sizeof(msg_connect_active_ind_t))) != NULL) >X { >X msg_connect_active_ind_t *mp = (msg_connect_active_ind_t *)m->m_data; >X >X mp->header.type = MSG_CONNECT_ACTIVE_IND; >X mp->header.cdid = cd->cdid; >X mp->controller = cd->controller; >X mp->channel = cd->channelid; >X if(cd->datetime[0] != '\0') >X strcpy(mp->datetime, cd->datetime); >X else >X mp->datetime[0] = '\0'; >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_DISCONNECT_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_disconnect_ind(call_desc_t *cd) >X{ >X struct mbuf *m; >X >X if(cd->timeout_active) >X#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 >X untimeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, cd->idle_timeout_handle); >X#else >X untimeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd); >X#endif >X >X if(cd->dlt != NULL) >X { >X (*cd->dlt->line_disconnected)(cd->driver_unit, (void *)cd); >X i4b_unlink_bchandrvr(cd); >X } >X >X if((cd->channelid == CHAN_B1) || (cd->channelid == CHAN_B2)) >X { >X ctrl_desc[cd->controller].bch_state[cd->channelid] = BCH_ST_FREE; >X } >X else >X { >X /* no error, might be hunting call for callback */ >X DBGL4(L4_MSG, "i4b_l4_disconnect_ind", ("channel free not B1/B2 but %d!\n", cd->channelid)); >X } >X >X if((m = i4b_Dgetmbuf(sizeof(msg_disconnect_ind_t))) != NULL) >X { >X msg_disconnect_ind_t *mp = (msg_disconnect_ind_t *)m->m_data; >X >X mp->header.type = MSG_DISCONNECT_IND; >X mp->header.cdid = cd->cdid; >X mp->cause = cd->cause_in; >X >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_IDLE_TIMEOUT_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_idle_timeout_ind(call_desc_t *cd) >X{ >X struct mbuf *m; >X >X if((m = i4b_Dgetmbuf(sizeof(msg_idle_timeout_ind_t))) != NULL) >X { >X msg_idle_timeout_ind_t *mp = (msg_idle_timeout_ind_t *)m->m_data; >X >X mp->header.type = MSG_IDLE_TIMEOUT_IND; >X mp->header.cdid = cd->cdid; >X >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_CHARGING_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_charging_ind(call_desc_t *cd) >X{ >X struct mbuf *m; >X >X if((m = i4b_Dgetmbuf(sizeof(msg_charging_ind_t))) != NULL) >X { >X msg_charging_ind_t *mp = (msg_charging_ind_t *)m->m_data; >X >X mp->header.type = MSG_CHARGING_IND; >X mp->header.cdid = cd->cdid; >X mp->units_type = cd->units_type; >X >X/*XXX*/ if(mp->units_type == CHARGE_CALC) >X mp->units = cd->cunits; >X else >X mp->units = cd->units; >X >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_STATUS_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_status_ind(call_desc_t *cd) >X{ >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_ALERT_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_alert_ind(call_desc_t *cd) >X{ >X struct mbuf *m; >X >X if((m = i4b_Dgetmbuf(sizeof(msg_alert_ind_t))) != NULL) >X { >X msg_alert_ind_t *mp = (msg_alert_ind_t *)m->m_data; >X >X mp->header.type = MSG_ALERT_IND; >X mp->header.cdid = cd->cdid; >X >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_INFO_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_info_ind(call_desc_t *cd) >X{ >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_INFO_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_proceeding_ind(call_desc_t *cd) >X{ >X struct mbuf *m; >X >X if((m = i4b_Dgetmbuf(sizeof(msg_proceeding_ind_t))) != NULL) >X { >X msg_proceeding_ind_t *mp = (msg_proceeding_ind_t *)m->m_data; >X >X mp->header.type = MSG_PROCEEDING_IND; >X mp->header.cdid = cd->cdid; >X mp->controller = cd->controller; >X mp->channel = cd->channelid; >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * link a driver(unit) to a B-channel(controller,unit,channel) >X *---------------------------------------------------------------------------*/ >Xstatic int >Xi4b_link_bchandrvr(call_desc_t *cd) >X{ >X int t = ctrl_desc[cd->controller].ctrl_type; >X >X if(t < 0 || t >= CTRL_NUMTYPES || ctrl_types[t].get_linktab == NULL) >X { >X cd->ilt = NULL; >X } >X else >X { >X cd->ilt = ctrl_types[t].get_linktab( >X ctrl_desc[cd->controller].unit, >X cd->channelid); >X } >X >X switch(cd->driver) >X { >X#if NI4BRBCH > 0 >X case BDRV_RBCH: >X cd->dlt = rbch_ret_linktab(cd->driver_unit); >X break; >X#endif >X >X#if NI4BTEL > 0 >X case BDRV_TEL: >X cd->dlt = tel_ret_linktab(cd->driver_unit); >X break; >X#endif >X >X#if NI4BIPR > 0 >X case BDRV_IPR: >X cd->dlt = ipr_ret_linktab(cd->driver_unit); >X break; >X#endif >X >X#if NI4BISPPP > 0 >X case BDRV_ISPPP: >X cd->dlt = i4bisppp_ret_linktab(cd->driver_unit); >X break; >X#endif >X >X default: >X cd->dlt = NULL; >X break; >X } >X >X if(cd->dlt == NULL || cd->ilt == NULL) >X return(-1); >X >X if(t >= 0 && t < CTRL_NUMTYPES && ctrl_types[t].set_linktab != NULL) >X { >X ctrl_types[t].set_linktab( >X ctrl_desc[cd->controller].unit, >X cd->channelid, >X cd->dlt); >X } >X >X switch(cd->driver) >X { >X#if NI4BRBCH > 0 >X case BDRV_RBCH: >X rbch_set_linktab(cd->driver_unit, cd->ilt); >X break; >X#endif >X >X#if NI4BTEL > 0 >X case BDRV_TEL: >X tel_set_linktab(cd->driver_unit, cd->ilt); >X break; >X#endif >X >X#if NI4BIPR > 0 >X case BDRV_IPR: >X ipr_set_linktab(cd->driver_unit, cd->ilt); >X break; >X#endif >X >X#if NI4BISPPP > 0 >X case BDRV_ISPPP: >X i4bisppp_set_linktab(cd->driver_unit, cd->ilt); >X break; >X#endif >X default: >X return(0); >X break; >X } >X >X /* activate B channel */ >X >X (*cd->ilt->bch_config)(ctrl_desc[cd->controller].unit, >X cd->channelid, cd->bprot, 1); >X >X return(0); >X} >X >X/*---------------------------------------------------------------------------* >X * unlink a driver(unit) from a B-channel(controller,unit,channel) >X *---------------------------------------------------------------------------*/ >Xstatic void >Xi4b_unlink_bchandrvr(call_desc_t *cd) >X{ >X int t = ctrl_desc[cd->controller].ctrl_type; >X >X if(t < 0 || t >= CTRL_NUMTYPES || ctrl_types[t].get_linktab == NULL) >X { >X cd->ilt = NULL; >X return; >X } >X else >X { >X cd->ilt = ctrl_types[t].get_linktab( >X ctrl_desc[cd->controller].unit, >X cd->channelid); >X } >X >X /* deactivate B channel */ >X >X (*cd->ilt->bch_config)(ctrl_desc[cd->controller].unit, >X cd->channelid, cd->bprot, 0); >X} >X >X/*--------------------------------------------------------------------------- >X >X How shorthold mode works for OUTGOING connections >X ================================================= >X >X |<---- unchecked-window ------->|<-checkwindow->|<-safetywindow>| >X >Xidletime_state: IST_NONCHK IST_CHECK IST_SAFE >X >X | | | | >X time>>+-------------------------------+---------------+---------------+-... >X | | | | >X | |<--idle_time-->|<--earlyhup--->| >X |<-----------------------unitlen------------------------------->| >X >X >X unitlen - specifies the time a charging unit lasts >X idle_time - specifies the thime the line must be idle at the >X end of the unit to be elected for hangup >X earlyhup - is the beginning of a timing safety zone before the >X next charging unit starts >X >X The algorithm works as follows: lets assume the unitlen is 100 >X secons, idle_time is 40 seconds and earlyhup is 10 seconds. >X The line then must be idle 50 seconds after the begin of the >X current unit and it must then be quiet for 40 seconds. if it >X has been quiet for this 40 seconds, the line is closed 10 >X seconds before the next charging unit starts. In case there was >X any traffic within the idle_time, the line is not closed. >X It does not matter whether there was any traffic between second >X 0 and second 50 or not. >X >X >X How shorthold mode works for INCOMING connections >X ================================================= >X >X it is just possible to specify a maximum idle time for incoming >X connections, after this time of no activity on the line the line >X is closed. >X >X---------------------------------------------------------------------------*/ >X >X/*---------------------------------------------------------------------------* >X * B channel idle check timeout setup >X *---------------------------------------------------------------------------*/ >Xstatic void >Xi4b_l4_setup_timeout(call_desc_t *cd) >X{ >X cd->timeout_active = 0; >X cd->idletime_state = IST_IDLE; >X >X if((cd->dir == DIR_INCOMING) && (cd->max_idle_time > 0)) >X { >X /* incoming call: simple max idletime check */ >X >X#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 >X cd->idle_timeout_handle = >X#endif >X timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz/2); >X cd->timeout_active = 1; >X DBGL4(L4_TIMO, "i4b_l4_setup_timeout", ("%ld: incoming-call, setup max_idle_time to %ld\n", (long)SECOND, (long)cd->max_idle_time)); >X } >X else if((cd->dir == DIR_OUTGOING) && (cd->idle_time > 0)) >X { >X /* outgoing call */ >X >X if((cd->idle_time > 0) && (cd->unitlen_time == 0)) >X { >X /* outgoing call: simple max idletime check */ >X >X#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 >X cd->idle_timeout_handle = >X#endif >X timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz/2); >X cd->timeout_active = 1; >X DBGL4(L4_TIMO, "i4b_l4_setup_timeout", ("%ld: outgoing-call, setup idle_time to %ld\n", (long)SECOND, (long)cd->idle_time)); >X } >X else if((cd->unitlen_time > 0) && (cd->unitlen_time > (cd->idle_time + cd->earlyhup_time))) >X { >X /* outgoing call: full shorthold mode check */ >X >X#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 >X cd->idle_timeout_handle = >X#endif >X timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz*(cd->unitlen_time - (cd->idle_time + cd->earlyhup_time))); >X cd->timeout_active = 1; >X cd->idletime_state = IST_NONCHK; >X DBGL4(L4_TIMO, "i4b_l4_setup_timeout", ("%ld: outgoing-call, start %ld sec nocheck window\n", >X (long)SECOND, (long)(cd->unitlen_time - (cd->idle_time + cd->earlyhup_time)))); >X >X if(cd->aocd_flag == 0) >X { >X cd->units_type = CHARGE_CALC; >X cd->cunits++; >X i4b_l4_charging_ind(cd); >X } >X } >X else >X { >X /* parms somehow got wrong .. */ >X >X DBGL4(L4_ERR, "i4b_l4_setup_timeout", ("%ld: ERROR: idletime[%ld]+earlyhup[%ld] > unitlength[%ld]!\n", >X (long)SECOND, (long)cd->idle_time, (long)cd->earlyhup_time, (long)cd->unitlen_time)); >X } >X } >X else >X { >X DBGL4(L4_TIMO, "i4b_l4_setup_timeout", ("no idle_timeout configured\n")); >X } >X} >X >Xstatic time_t >Xi4b_get_idletime(call_desc_t *cd) >X{ >X time_t t; >X switch (cd->driver) { >X#if NI4BISPPP > 0 >X case BDRV_ISPPP: >X return i4bisppp_idletime(cd->driver_unit); >X break; >X#endif >X default: >X return SECOND - cd->last_active_time; >X break; >X } >X} >X/*---------------------------------------------------------------------------* >X * B channel idle check timeout function >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_idle_check(call_desc_t *cd) >X{ >X int s; >X >X if(cd->cdid == CDID_UNUSED) >X return; >X >X s = SPLI4B(); >X >X /* failsafe */ >X >X if(cd->timeout_active == 0) >X { >X DBGL4(L4_ERR, "i4b_idle_check", ("ERROR: timeout_active == 0 !!!\n")); >X } >X else >X { >X cd->timeout_active = 0; >X } >X >X /* incoming connections, simple idletime check */ >X >X if(cd->dir == DIR_INCOMING) >X { >X if(i4b_get_idletime(cd) >= cd->max_idle_time) >X { >X DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: incoming-call, line idle timeout, disconnecting!\n", (long)SECOND)); >X (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(cd->cdid, >X (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL); >X i4b_l4_idle_timeout_ind(cd); >X } >X else >X { >X DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: incoming-call, activity, last_active=%ld, max_idle=%ld\n", (long)SECOND, (long)cd->last_active_time, (long)cd->max_idle_time)); >X#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 >X cd->idle_timeout_handle = >X#endif >X timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz/2); >X cd->timeout_active = 1; >X } >X } >X >X /* outgoing connections */ >X >X else if(cd->dir == DIR_OUTGOING) >X { >X >X /* simple idletime calculation */ >X >X if((cd->idle_time > 0) && (cd->unitlen_time == 0)) >X { >X if(i4b_get_idletime(cd) >= cd->idle_time) >X { >X DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: outgoing-call-st, idle timeout, disconnecting!\n", (long)SECOND)); >X (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(cd->cdid, >X (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL); >X i4b_l4_idle_timeout_ind(cd); >X } >X else >X { >X DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: outgoing-call-st, activity, last_active=%ld, max_idle=%ld\n", >X (long)SECOND, (long)cd->last_active_time, (long)cd->idle_time)); >X#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 >X cd->idle_timeout_handle = >X#endif >X timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz/2); >X cd->timeout_active = 1; >X } >X } >X >X /* full shorthold mode calculation */ >X >X else if((cd->unitlen_time > 0) && (cd->unitlen_time > (cd->idle_time + cd->earlyhup_time))) >X { >X switch(cd->idletime_state) >X { >X case IST_NONCHK: /* end of non-check time */ >X#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 >X cd->idle_timeout_handle = >X#endif >X timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz*(cd->idle_time)); >X cd->idletimechk_start = SECOND; >X cd->idletime_state = IST_CHECK; >X cd->timeout_active = 1; >X DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: outgoing-call, idletime check window reached!\n", (long)SECOND)); >X break; >X >X case IST_CHECK: /* end of idletime chk */ >X if((cd->last_active_time > cd->idletimechk_start) && >X (cd->last_active_time <= SECOND)) >X { /* activity detected */ >X#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 >X cd->idle_timeout_handle = >X#endif >X timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz*(cd->earlyhup_time)); >X cd->timeout_active = 1; >X cd->idletime_state = IST_SAFE; >X DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: outgoing-call, activity at %ld, wait earlyhup-end\n", (long)SECOND, (long)cd->last_active_time)); >X } >X else >X { /* no activity, hangup */ >X DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: outgoing-call, idle timeout, last activity at %ld\n", (long)SECOND, (long)cd->last_active_time)); >X (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(cd->cdid, >X (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL); >X i4b_l4_idle_timeout_ind(cd); >X cd->idletime_state = IST_IDLE; >X } >X break; >X >X case IST_SAFE: /* end of earlyhup time */ >X#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 >X cd->idle_timeout_handle = >X#endif >X timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz*(cd->unitlen_time - (cd->idle_time+cd->earlyhup_time))); >X cd->timeout_active = 1; >X cd->idletime_state = IST_NONCHK; >X >X if(cd->aocd_flag == 0) >X { >X cd->units_type = CHARGE_CALC; >X cd->cunits++; >X i4b_l4_charging_ind(cd); >X } >X >X DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: outgoing-call, earlyhup end, wait for idletime start\n", (long)SECOND)); >X break; >X >X default: >X DBGL4(L4_ERR, "i4b_idle_check", ("outgoing-call: invalid idletime_state value!\n")); >X cd->idletime_state = IST_IDLE; >X break; >X } >X } >X } >X splx(s); >X} >X >X#endif /* NI4B > 0 */ >END-of-./usr/src/sys/i4b/layer4/i4b_l4.c >echo x - ./usr/src/sys/i4b/layer4/i4b_l4.c.patch >sed 's/^X//' >./usr/src/sys/i4b/layer4/i4b_l4.c.patch << 'END-of-./usr/src/sys/i4b/layer4/i4b_l4.c.patch' >X*** i4b_l4.c Sat Dec 5 19:05:49 1998 >X--- i4b_l4.c.new Wed Mar 17 13:19:36 1999 >X*************** >X*** 79,84 **** >X--- 79,85 ---- >X static int i4b_link_bchandrvr(call_desc_t *cd); >X static void i4b_unlink_bchandrvr(call_desc_t *cd); >X static void i4b_l4_setup_timeout(call_desc_t *cd); >X+ static time_t i4b_get_idletime(call_desc_t *cd); >X >X /*---------------------------------------------------------------------------* >X * send MSG_PDEACT_IND message to userland >X*************** >X*** 753,758 **** >X--- 754,774 ---- >X } >X } >X >X+ static time_t >X+ i4b_get_idletime(call_desc_t *cd) >X+ { >X+ time_t t; >X+ switch (cd->driver) { >X+ #if NI4BISPPP > 0 >X+ case BDRV_ISPPP: >X+ return i4bisppp_idletime(cd->driver_unit); >X+ break; >X+ #endif >X+ default: >X+ return SECOND - cd->last_active_time; >X+ break; >X+ } >X+ } >X /*---------------------------------------------------------------------------* >X * B channel idle check timeout function >X *---------------------------------------------------------------------------*/ >X*************** >X*** 781,787 **** >X >X if(cd->dir == DIR_INCOMING) >X { >X! if((cd->last_active_time + cd->max_idle_time) <= SECOND) >X { >X DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: incoming-call, line idle timeout, disconnecting!\n", (long)SECOND)); >X (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(cd->cdid, >X--- 797,803 ---- >X >X if(cd->dir == DIR_INCOMING) >X { >X! if(i4b_get_idletime(cd) >= cd->max_idle_time) >X { >X DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: incoming-call, line idle timeout, disconnecting!\n", (long)SECOND)); >X (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(cd->cdid, >X*************** >X*** 808,814 **** >X >X if((cd->idle_time > 0) && (cd->unitlen_time == 0)) >X { >X! if((cd->last_active_time + cd->idle_time) <= SECOND) >X { >X DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: outgoing-call-st, idle timeout, disconnecting!\n", (long)SECOND)); >X (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(cd->cdid, >X--- 824,830 ---- >X >X if((cd->idle_time > 0) && (cd->unitlen_time == 0)) >X { >X! if(i4b_get_idletime(cd) >= cd->idle_time) >X { >X DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: outgoing-call-st, idle timeout, disconnecting!\n", (long)SECOND)); >X (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(cd->cdid, >END-of-./usr/src/sys/i4b/layer4/i4b_l4.c.patch >echo x - ./usr/src/sys/i4b/layer4/i4b_l4.c.orig >sed 's/^X//' >./usr/src/sys/i4b/layer4/i4b_l4.c.orig << 'END-of-./usr/src/sys/i4b/layer4/i4b_l4.c.orig' >X/* >X * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. >X * >X * Redistribution and use in source and binary forms, with or without >X * modification, are permitted provided that the following conditions >X * are met: >X * 1. Redistributions of source code must retain the above copyright >X * notice, this list of conditions and the following disclaimer. >X * 2. Redistributions in binary form must reproduce the above copyright >X * notice, this list of conditions and the following disclaimer in the >X * documentation and/or other materials provided with the distribution. >X * >X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND >X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE >X * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE >X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL >X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS >X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) >X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT >X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY >X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF >X * SUCH DAMAGE. >X * >X *--------------------------------------------------------------------------- >X * >X * i4b_l4.c - kernel interface to userland >X * ----------------------------------------- >X * >X * $Id: i4b_l4.c,v 1.1 1998/12/27 21:46:52 phk Exp $ >X * >X * last edit-date: [Sat Dec 5 18:35:16 1998] >X * >X *---------------------------------------------------------------------------*/ >X >X#include "i4b.h" >X#include "i4bipr.h" >X#include "i4bisppp.h" >X#include "i4brbch.h" >X#include "i4btel.h" >X >X#if NI4B > 0 >X >X#include <sys/param.h> >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X#include <sys/ioccom.h> >X#else >X#include <sys/ioctl.h> >X#endif >X#include <sys/kernel.h> >X#include <sys/systm.h> >X#include <sys/conf.h> >X#include <sys/mbuf.h> >X#include <sys/proc.h> >X#include <sys/fcntl.h> >X#include <sys/socket.h> >X#include <net/if.h> >X >X#ifdef __FreeBSD__ >X#include <machine/i4b_debug.h> >X#include <machine/i4b_ioctl.h> >X#include <machine/i4b_cause.h> >X#else >X#include <i4b/i4b_debug.h> >X#include <i4b/i4b_ioctl.h> >X#include <i4b/i4b_cause.h> >X#endif >X >X#include <i4b/include/i4b_global.h> >X#include <i4b/include/i4b_l3l4.h> >X#include <i4b/include/i4b_mbuf.h> >X#include <i4b/layer3/i4b_l3.h> >X#include <i4b/layer4/i4b_l4.h> >X >Xunsigned int i4b_l4_debug = L4_DEBUG_DEFAULT; >X >Xstruct ctrl_type_desc ctrl_types[CTRL_NUMTYPES] = { { NULL, NULL} }; >X >Xstatic int i4b_link_bchandrvr(call_desc_t *cd); >Xstatic void i4b_unlink_bchandrvr(call_desc_t *cd); >Xstatic void i4b_l4_setup_timeout(call_desc_t *cd); >X >X/*---------------------------------------------------------------------------* >X * send MSG_PDEACT_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_pdeact(int controller, int numactive) >X{ >X struct mbuf *m; >X int i; >X call_desc_t *cd; >X >X for(i=0; i < N_CALL_DESC; i++) >X { >X if((call_desc[i].cdid != CDID_UNUSED) && >X (ctrl_desc[call_desc[i].controller].ctrl_type == CTRL_PASSIVE) && >X (ctrl_desc[call_desc[i].controller].unit == controller)) >X { >X cd = &call_desc[i]; >X >X if(cd->timeout_active) >X { >X#if defined(__FreeBSD__) && __FreeBSD__ >= 3 >X untimeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, cd->idle_timeout_handle); >X#else >X untimeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd); >X#endif >X } >X >X if(cd->dlt != NULL) >X { >X (*cd->dlt->line_disconnected)(cd->driver_unit, (void *)cd); >X i4b_unlink_bchandrvr(cd); >X } >X >X if((cd->channelid == CHAN_B1) || (cd->channelid == CHAN_B2)) >X { >X ctrl_desc[cd->controller].bch_state[cd->channelid] = BCH_ST_FREE; >X } >X >X cd->cdid = CDID_UNUSED; >X } >X } >X >X if((m = i4b_Dgetmbuf(sizeof(msg_pdeact_ind_t))) != NULL) >X { >X msg_pdeact_ind_t *md = (msg_pdeact_ind_t *)m->m_data; >X >X md->header.type = MSG_PDEACT_IND; >X md->header.cdid = -1; >X >X md->controller = controller; >X md->numactive = numactive; >X >X i4bputqueue_hipri(m); /* URGENT !!! */ >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_L12STAT_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_l12stat(int controller, int layer, int state) >X{ >X struct mbuf *m; >X >X if((m = i4b_Dgetmbuf(sizeof(msg_l12stat_ind_t))) != NULL) >X { >X msg_l12stat_ind_t *md = (msg_l12stat_ind_t *)m->m_data; >X >X md->header.type = MSG_L12STAT_IND; >X md->header.cdid = -1; >X >X md->controller = controller; >X md->layer = layer; >X md->state = state; >X >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_TEIASG_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_teiasg(int controller, int tei) >X{ >X struct mbuf *m; >X >X if((m = i4b_Dgetmbuf(sizeof(msg_teiasg_ind_t))) != NULL) >X { >X msg_teiasg_ind_t *md = (msg_teiasg_ind_t *)m->m_data; >X >X md->header.type = MSG_TEIASG_IND; >X md->header.cdid = -1; >X >X md->controller = controller; >X md->tei = ctrl_desc[controller].tei; >X >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_DIALOUT_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_dialout(int driver, int driver_unit) >X{ >X struct mbuf *m; >X >X if((m = i4b_Dgetmbuf(sizeof(msg_dialout_ind_t))) != NULL) >X { >X msg_dialout_ind_t *md = (msg_dialout_ind_t *)m->m_data; >X >X md->header.type = MSG_DIALOUT_IND; >X md->header.cdid = -1; >X >X md->driver = driver; >X md->driver_unit = driver_unit; >X >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_NEGOTIATION_COMPL message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_negcomplete(call_desc_t *cd) >X{ >X struct mbuf *m; >X >X if((m = i4b_Dgetmbuf(sizeof(msg_negcomplete_ind_t))) != NULL) >X { >X msg_negcomplete_ind_t *md = (msg_negcomplete_ind_t *)m->m_data; >X >X md->header.type = MSG_NEGCOMP_IND; >X md->header.cdid = cd->cdid; >X >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_IFSTATE_CHANGED_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_ifstate_changed(call_desc_t *cd, int new_state) >X{ >X struct mbuf *m; >X >X if((m = i4b_Dgetmbuf(sizeof(msg_ifstatechg_ind_t))) != NULL) >X { >X msg_ifstatechg_ind_t *md = (msg_ifstatechg_ind_t *)m->m_data; >X >X md->header.type = MSG_IFSTATE_CHANGED_IND; >X md->header.cdid = cd->cdid; >X md->state = new_state; >X >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_DRVRDISC_REQ message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_drvrdisc(int driver, int driver_unit) >X{ >X struct mbuf *m; >X >X if((m = i4b_Dgetmbuf(sizeof(msg_drvrdisc_req_t))) != NULL) >X { >X msg_drvrdisc_req_t *md = (msg_drvrdisc_req_t *)m->m_data; >X >X md->header.type = MSG_DRVRDISC_REQ; >X md->header.cdid = -1; >X >X md->driver = driver; >X md->driver_unit = driver_unit; >X >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_ACCT_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_accounting(int driver, int driver_unit, int accttype, int ioutbytes, >X int iinbytes, int ro, int ri, int outbytes, int inbytes) >X{ >X struct mbuf *m; >X >X if((m = i4b_Dgetmbuf(sizeof(msg_accounting_ind_t))) != NULL) >X { >X msg_accounting_ind_t *md = (msg_accounting_ind_t *)m->m_data; >X >X md->header.type = MSG_ACCT_IND; >X md->header.cdid = -1; >X >X md->driver = driver; >X md->driver_unit = driver_unit; >X >X md->accttype = accttype; >X md->ioutbytes = ioutbytes; >X md->iinbytes = iinbytes; >X md->outbps = ro; >X md->inbps = ri; >X md->outbytes = outbytes; >X md->inbytes = inbytes; >X >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_CONNECT_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_connect_ind(call_desc_t *cd) >X{ >X struct mbuf *m; >X >X if((m = i4b_Dgetmbuf(sizeof(msg_connect_ind_t))) != NULL) >X { >X msg_connect_ind_t *mp = (msg_connect_ind_t *)m->m_data; >X >X mp->header.type = MSG_CONNECT_IND; >X mp->header.cdid = cd->cdid; >X >X mp->controller = cd->controller; >X mp->channel = cd->channelid; >X mp->bprot = cd->bprot; >X >X cd->dir = DIR_INCOMING; >X >X if(strlen(cd->dst_telno) > 0) >X strcpy(mp->dst_telno, cd->dst_telno); >X else >X strcpy(mp->dst_telno, TELNO_EMPTY); >X >X if(strlen(cd->src_telno) > 0) >X strcpy(mp->src_telno, cd->src_telno); >X else >X strcpy(mp->src_telno, TELNO_EMPTY); >X >X strcpy(mp->display, cd->display); >X >X mp->scr_ind = cd->scr_ind; >X >X T400_start(cd); >X >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_CONNECT_ACTIVE_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_connect_active_ind(call_desc_t *cd) >X{ >X int s; >X struct mbuf *m; >X >X s = SPLI4B(); >X >X cd->last_active_time = cd->connect_time = SECOND; >X >X DBGL4(L4_TIMO, "i4b_l4_connect_active_ind", ("last_active/connect_time=%ld\n", (long)cd->connect_time)); >X >X i4b_link_bchandrvr(cd); >X >X (*cd->dlt->line_connected)(cd->driver_unit, (void *)cd); >X >X i4b_l4_setup_timeout(cd); >X >X splx(s); >X >X if((m = i4b_Dgetmbuf(sizeof(msg_connect_active_ind_t))) != NULL) >X { >X msg_connect_active_ind_t *mp = (msg_connect_active_ind_t *)m->m_data; >X >X mp->header.type = MSG_CONNECT_ACTIVE_IND; >X mp->header.cdid = cd->cdid; >X mp->controller = cd->controller; >X mp->channel = cd->channelid; >X if(cd->datetime[0] != '\0') >X strcpy(mp->datetime, cd->datetime); >X else >X mp->datetime[0] = '\0'; >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_DISCONNECT_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_disconnect_ind(call_desc_t *cd) >X{ >X struct mbuf *m; >X >X if(cd->timeout_active) >X#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 >X untimeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, cd->idle_timeout_handle); >X#else >X untimeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd); >X#endif >X >X if(cd->dlt != NULL) >X { >X (*cd->dlt->line_disconnected)(cd->driver_unit, (void *)cd); >X i4b_unlink_bchandrvr(cd); >X } >X >X if((cd->channelid == CHAN_B1) || (cd->channelid == CHAN_B2)) >X { >X ctrl_desc[cd->controller].bch_state[cd->channelid] = BCH_ST_FREE; >X } >X else >X { >X /* no error, might be hunting call for callback */ >X DBGL4(L4_MSG, "i4b_l4_disconnect_ind", ("channel free not B1/B2 but %d!\n", cd->channelid)); >X } >X >X if((m = i4b_Dgetmbuf(sizeof(msg_disconnect_ind_t))) != NULL) >X { >X msg_disconnect_ind_t *mp = (msg_disconnect_ind_t *)m->m_data; >X >X mp->header.type = MSG_DISCONNECT_IND; >X mp->header.cdid = cd->cdid; >X mp->cause = cd->cause_in; >X >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_IDLE_TIMEOUT_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_idle_timeout_ind(call_desc_t *cd) >X{ >X struct mbuf *m; >X >X if((m = i4b_Dgetmbuf(sizeof(msg_idle_timeout_ind_t))) != NULL) >X { >X msg_idle_timeout_ind_t *mp = (msg_idle_timeout_ind_t *)m->m_data; >X >X mp->header.type = MSG_IDLE_TIMEOUT_IND; >X mp->header.cdid = cd->cdid; >X >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_CHARGING_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_charging_ind(call_desc_t *cd) >X{ >X struct mbuf *m; >X >X if((m = i4b_Dgetmbuf(sizeof(msg_charging_ind_t))) != NULL) >X { >X msg_charging_ind_t *mp = (msg_charging_ind_t *)m->m_data; >X >X mp->header.type = MSG_CHARGING_IND; >X mp->header.cdid = cd->cdid; >X mp->units_type = cd->units_type; >X >X/*XXX*/ if(mp->units_type == CHARGE_CALC) >X mp->units = cd->cunits; >X else >X mp->units = cd->units; >X >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_STATUS_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_status_ind(call_desc_t *cd) >X{ >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_ALERT_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_alert_ind(call_desc_t *cd) >X{ >X struct mbuf *m; >X >X if((m = i4b_Dgetmbuf(sizeof(msg_alert_ind_t))) != NULL) >X { >X msg_alert_ind_t *mp = (msg_alert_ind_t *)m->m_data; >X >X mp->header.type = MSG_ALERT_IND; >X mp->header.cdid = cd->cdid; >X >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_INFO_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_info_ind(call_desc_t *cd) >X{ >X} >X >X/*---------------------------------------------------------------------------* >X * send MSG_INFO_IND message to userland >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_l4_proceeding_ind(call_desc_t *cd) >X{ >X struct mbuf *m; >X >X if((m = i4b_Dgetmbuf(sizeof(msg_proceeding_ind_t))) != NULL) >X { >X msg_proceeding_ind_t *mp = (msg_proceeding_ind_t *)m->m_data; >X >X mp->header.type = MSG_PROCEEDING_IND; >X mp->header.cdid = cd->cdid; >X mp->controller = cd->controller; >X mp->channel = cd->channelid; >X i4bputqueue(m); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * link a driver(unit) to a B-channel(controller,unit,channel) >X *---------------------------------------------------------------------------*/ >Xstatic int >Xi4b_link_bchandrvr(call_desc_t *cd) >X{ >X int t = ctrl_desc[cd->controller].ctrl_type; >X >X if(t < 0 || t >= CTRL_NUMTYPES || ctrl_types[t].get_linktab == NULL) >X { >X cd->ilt = NULL; >X } >X else >X { >X cd->ilt = ctrl_types[t].get_linktab( >X ctrl_desc[cd->controller].unit, >X cd->channelid); >X } >X >X switch(cd->driver) >X { >X#if NI4BRBCH > 0 >X case BDRV_RBCH: >X cd->dlt = rbch_ret_linktab(cd->driver_unit); >X break; >X#endif >X >X#if NI4BTEL > 0 >X case BDRV_TEL: >X cd->dlt = tel_ret_linktab(cd->driver_unit); >X break; >X#endif >X >X#if NI4BIPR > 0 >X case BDRV_IPR: >X cd->dlt = ipr_ret_linktab(cd->driver_unit); >X break; >X#endif >X >X#if NI4BISPPP > 0 >X case BDRV_ISPPP: >X cd->dlt = i4bisppp_ret_linktab(cd->driver_unit); >X break; >X#endif >X >X default: >X cd->dlt = NULL; >X break; >X } >X >X if(cd->dlt == NULL || cd->ilt == NULL) >X return(-1); >X >X if(t >= 0 && t < CTRL_NUMTYPES && ctrl_types[t].set_linktab != NULL) >X { >X ctrl_types[t].set_linktab( >X ctrl_desc[cd->controller].unit, >X cd->channelid, >X cd->dlt); >X } >X >X switch(cd->driver) >X { >X#if NI4BRBCH > 0 >X case BDRV_RBCH: >X rbch_set_linktab(cd->driver_unit, cd->ilt); >X break; >X#endif >X >X#if NI4BTEL > 0 >X case BDRV_TEL: >X tel_set_linktab(cd->driver_unit, cd->ilt); >X break; >X#endif >X >X#if NI4BIPR > 0 >X case BDRV_IPR: >X ipr_set_linktab(cd->driver_unit, cd->ilt); >X break; >X#endif >X >X#if NI4BISPPP > 0 >X case BDRV_ISPPP: >X i4bisppp_set_linktab(cd->driver_unit, cd->ilt); >X break; >X#endif >X default: >X return(0); >X break; >X } >X >X /* activate B channel */ >X >X (*cd->ilt->bch_config)(ctrl_desc[cd->controller].unit, >X cd->channelid, cd->bprot, 1); >X >X return(0); >X} >X >X/*---------------------------------------------------------------------------* >X * unlink a driver(unit) from a B-channel(controller,unit,channel) >X *---------------------------------------------------------------------------*/ >Xstatic void >Xi4b_unlink_bchandrvr(call_desc_t *cd) >X{ >X int t = ctrl_desc[cd->controller].ctrl_type; >X >X if(t < 0 || t >= CTRL_NUMTYPES || ctrl_types[t].get_linktab == NULL) >X { >X cd->ilt = NULL; >X return; >X } >X else >X { >X cd->ilt = ctrl_types[t].get_linktab( >X ctrl_desc[cd->controller].unit, >X cd->channelid); >X } >X >X /* deactivate B channel */ >X >X (*cd->ilt->bch_config)(ctrl_desc[cd->controller].unit, >X cd->channelid, cd->bprot, 0); >X} >X >X/*--------------------------------------------------------------------------- >X >X How shorthold mode works for OUTGOING connections >X ================================================= >X >X |<---- unchecked-window ------->|<-checkwindow->|<-safetywindow>| >X >Xidletime_state: IST_NONCHK IST_CHECK IST_SAFE >X >X | | | | >X time>>+-------------------------------+---------------+---------------+-... >X | | | | >X | |<--idle_time-->|<--earlyhup--->| >X |<-----------------------unitlen------------------------------->| >X >X >X unitlen - specifies the time a charging unit lasts >X idle_time - specifies the thime the line must be idle at the >X end of the unit to be elected for hangup >X earlyhup - is the beginning of a timing safety zone before the >X next charging unit starts >X >X The algorithm works as follows: lets assume the unitlen is 100 >X secons, idle_time is 40 seconds and earlyhup is 10 seconds. >X The line then must be idle 50 seconds after the begin of the >X current unit and it must then be quiet for 40 seconds. if it >X has been quiet for this 40 seconds, the line is closed 10 >X seconds before the next charging unit starts. In case there was >X any traffic within the idle_time, the line is not closed. >X It does not matter whether there was any traffic between second >X 0 and second 50 or not. >X >X >X How shorthold mode works for INCOMING connections >X ================================================= >X >X it is just possible to specify a maximum idle time for incoming >X connections, after this time of no activity on the line the line >X is closed. >X >X---------------------------------------------------------------------------*/ >X >X/*---------------------------------------------------------------------------* >X * B channel idle check timeout setup >X *---------------------------------------------------------------------------*/ >Xstatic void >Xi4b_l4_setup_timeout(call_desc_t *cd) >X{ >X cd->timeout_active = 0; >X cd->idletime_state = IST_IDLE; >X >X if((cd->dir == DIR_INCOMING) && (cd->max_idle_time > 0)) >X { >X /* incoming call: simple max idletime check */ >X >X#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 >X cd->idle_timeout_handle = >X#endif >X timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz/2); >X cd->timeout_active = 1; >X DBGL4(L4_TIMO, "i4b_l4_setup_timeout", ("%ld: incoming-call, setup max_idle_time to %ld\n", (long)SECOND, (long)cd->max_idle_time)); >X } >X else if((cd->dir == DIR_OUTGOING) && (cd->idle_time > 0)) >X { >X /* outgoing call */ >X >X if((cd->idle_time > 0) && (cd->unitlen_time == 0)) >X { >X /* outgoing call: simple max idletime check */ >X >X#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 >X cd->idle_timeout_handle = >X#endif >X timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz/2); >X cd->timeout_active = 1; >X DBGL4(L4_TIMO, "i4b_l4_setup_timeout", ("%ld: outgoing-call, setup idle_time to %ld\n", (long)SECOND, (long)cd->idle_time)); >X } >X else if((cd->unitlen_time > 0) && (cd->unitlen_time > (cd->idle_time + cd->earlyhup_time))) >X { >X /* outgoing call: full shorthold mode check */ >X >X#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 >X cd->idle_timeout_handle = >X#endif >X timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz*(cd->unitlen_time - (cd->idle_time + cd->earlyhup_time))); >X cd->timeout_active = 1; >X cd->idletime_state = IST_NONCHK; >X DBGL4(L4_TIMO, "i4b_l4_setup_timeout", ("%ld: outgoing-call, start %ld sec nocheck window\n", >X (long)SECOND, (long)(cd->unitlen_time - (cd->idle_time + cd->earlyhup_time)))); >X >X if(cd->aocd_flag == 0) >X { >X cd->units_type = CHARGE_CALC; >X cd->cunits++; >X i4b_l4_charging_ind(cd); >X } >X } >X else >X { >X /* parms somehow got wrong .. */ >X >X DBGL4(L4_ERR, "i4b_l4_setup_timeout", ("%ld: ERROR: idletime[%ld]+earlyhup[%ld] > unitlength[%ld]!\n", >X (long)SECOND, (long)cd->idle_time, (long)cd->earlyhup_time, (long)cd->unitlen_time)); >X } >X } >X else >X { >X DBGL4(L4_TIMO, "i4b_l4_setup_timeout", ("no idle_timeout configured\n")); >X } >X} >X >X/*---------------------------------------------------------------------------* >X * B channel idle check timeout function >X *---------------------------------------------------------------------------*/ >Xvoid >Xi4b_idle_check(call_desc_t *cd) >X{ >X int s; >X >X if(cd->cdid == CDID_UNUSED) >X return; >X >X s = SPLI4B(); >X >X /* failsafe */ >X >X if(cd->timeout_active == 0) >X { >X DBGL4(L4_ERR, "i4b_idle_check", ("ERROR: timeout_active == 0 !!!\n")); >X } >X else >X { >X cd->timeout_active = 0; >X } >X >X /* incoming connections, simple idletime check */ >X >X if(cd->dir == DIR_INCOMING) >X { >X if((cd->last_active_time + cd->max_idle_time) <= SECOND) >X { >X DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: incoming-call, line idle timeout, disconnecting!\n", (long)SECOND)); >X (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(cd->cdid, >X (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL); >X i4b_l4_idle_timeout_ind(cd); >X } >X else >X { >X DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: incoming-call, activity, last_active=%ld, max_idle=%ld\n", (long)SECOND, (long)cd->last_active_time, (long)cd->max_idle_time)); >X#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 >X cd->idle_timeout_handle = >X#endif >X timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz/2); >X cd->timeout_active = 1; >X } >X } >X >X /* outgoing connections */ >X >X else if(cd->dir == DIR_OUTGOING) >X { >X >X /* simple idletime calculation */ >X >X if((cd->idle_time > 0) && (cd->unitlen_time == 0)) >X { >X if((cd->last_active_time + cd->idle_time) <= SECOND) >X { >X DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: outgoing-call-st, idle timeout, disconnecting!\n", (long)SECOND)); >X (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(cd->cdid, >X (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL); >X i4b_l4_idle_timeout_ind(cd); >X } >X else >X { >X DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: outgoing-call-st, activity, last_active=%ld, max_idle=%ld\n", >X (long)SECOND, (long)cd->last_active_time, (long)cd->idle_time)); >X#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 >X cd->idle_timeout_handle = >X#endif >X timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz/2); >X cd->timeout_active = 1; >X } >X } >X >X /* full shorthold mode calculation */ >X >X else if((cd->unitlen_time > 0) && (cd->unitlen_time > (cd->idle_time + cd->earlyhup_time))) >X { >X switch(cd->idletime_state) >X { >X case IST_NONCHK: /* end of non-check time */ >X#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 >X cd->idle_timeout_handle = >X#endif >X timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz*(cd->idle_time)); >X cd->idletimechk_start = SECOND; >X cd->idletime_state = IST_CHECK; >X cd->timeout_active = 1; >X DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: outgoing-call, idletime check window reached!\n", (long)SECOND)); >X break; >X >X case IST_CHECK: /* end of idletime chk */ >X if((cd->last_active_time > cd->idletimechk_start) && >X (cd->last_active_time <= SECOND)) >X { /* activity detected */ >X#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 >X cd->idle_timeout_handle = >X#endif >X timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz*(cd->earlyhup_time)); >X cd->timeout_active = 1; >X cd->idletime_state = IST_SAFE; >X DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: outgoing-call, activity at %ld, wait earlyhup-end\n", (long)SECOND, (long)cd->last_active_time)); >X } >X else >X { /* no activity, hangup */ >X DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: outgoing-call, idle timeout, last activity at %ld\n", (long)SECOND, (long)cd->last_active_time)); >X (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(cd->cdid, >X (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL); >X i4b_l4_idle_timeout_ind(cd); >X cd->idletime_state = IST_IDLE; >X } >X break; >X >X case IST_SAFE: /* end of earlyhup time */ >X#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 >X cd->idle_timeout_handle = >X#endif >X timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz*(cd->unitlen_time - (cd->idle_time+cd->earlyhup_time))); >X cd->timeout_active = 1; >X cd->idletime_state = IST_NONCHK; >X >X if(cd->aocd_flag == 0) >X { >X cd->units_type = CHARGE_CALC; >X cd->cunits++; >X i4b_l4_charging_ind(cd); >X } >X >X DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: outgoing-call, earlyhup end, wait for idletime start\n", (long)SECOND)); >X break; >X >X default: >X DBGL4(L4_ERR, "i4b_idle_check", ("outgoing-call: invalid idletime_state value!\n")); >X cd->idletime_state = IST_IDLE; >X break; >X } >X } >X } >X splx(s); >X} >X >X#endif /* NI4B > 0 */ >END-of-./usr/src/sys/i4b/layer4/i4b_l4.c.orig >echo c - ./usr/src/sbin >mkdir -p ./usr/src/sbin > /dev/null 2>&1 >echo c - ./usr/src/sbin/spppcontrol >mkdir -p ./usr/src/sbin/spppcontrol > /dev/null 2>&1 >echo x - ./usr/src/sbin/spppcontrol/Makefile >sed 's/^X//' >./usr/src/sbin/spppcontrol/Makefile << 'END-of-./usr/src/sbin/spppcontrol/Makefile' >XPROG= spppcontrol >X >X.include <bsd.prog.mk> >END-of-./usr/src/sbin/spppcontrol/Makefile >echo x - ./usr/src/sbin/spppcontrol/spppcontrol.1 >sed 's/^X//' >./usr/src/sbin/spppcontrol/spppcontrol.1 << 'END-of-./usr/src/sbin/spppcontrol/spppcontrol.1' >X.\" Copyright (C) 1997 by Joerg Wunsch, Dresden >X.\" All rights reserved. >X.\" >X.\" Redistribution and use in source and binary forms, with or without >X.\" modification, are permitted provided that the following conditions >X.\" are met: >X.\" 1. Redistributions of source code must retain the above copyright >X.\" notice, this list of conditions and the following disclaimer. >X.\" 2. Redistributions in binary form must reproduce the above copyright >X.\" notice, this list of conditions and the following disclaimer in the >X.\" documentation and/or other materials provided with the distribution. >X.\" >X.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS >X.\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED >X.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE >X.\" DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, >X.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES >X.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR >X.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) >X.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, >X.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING >X.\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE >X.\" POSSIBILITY OF SUCH DAMAGE. >X.\" >X.\" $Id: spppcontrol.1,v 1.3 1998/08/03 06:24:59 charnier Exp $ >X.\" >X.Dd October 11, 1997 >X.Os >X.Dt SPPPCONTROL 8 >X.Sh NAME >X.Nm spppcontrol >X.Nd display or set parameters for an sppp interface >X.Sh SYNOPSIS >X.Nm spppcontrol >X.Op Fl v >X.Ar ifname >X.Op Ar parameter Ns Op \&= Ns Ar value >X.Op Ar ... >X.Sh DESCRIPTION >XThe >X.Xr sppp 4 >Xdriver might require a number of additional arguments or optional >Xparameters besides the settings that can be adjusted with >X.Xr ifconfig 8 . >XThese are things like authentication protocol parameters, but also >Xother tunable configuration variables. The >X.Nm >Xutility can be used to display the current settings, or adjust these >Xparameters as required. >X.Pp >XFor whatever intent >X.Nm >Xis being called, at least the parameter >X.Ar ifname >Xneeds to be specified, naming the interface for which the settings >Xare to be performed or displayed. Use >X.Xr ifconfig 8 , >Xor >X.Xr netstat 1 >Xto see which interfaces are available. >X.Pp >XIf no other parameter is given, >X.Nm >Xwill just list the current settings for >X.Ar ifname >Xand exit. The reported settings include the current PPP phase the >Xinterface is in, which can be one of the names >X.Em dead , >X.Em establish , >X.Em authenticate , >X.Em network , >Xor >X.Em terminate . >XIf an authentication protocol is configured for the interface, the >Xname of the protocol to be used, as well as the system name to be used >Xor expected will be displayed, plus any possible options to the >Xauthentication protocol if applicable. Note that the authentication >Xsecrets (sometimes also called >X.Em keys ) >Xare not being returned by the underlying system call, and are thus not >Xdisplayed. >X.Pp >XIf any additional parameter is supplied, superuser privileges are >Xrequired, and the command works in >X.Ql set >Xmode. This is normally done quietly, unless the option >X.Fl v >Xis also enabled, which will cause a final printout of the settings as >Xdescribed above once all other actions have been taken. Use of this >Xmode will be rejected if the interface is currently in any other phase >Xthan >X.Em dead . >XNote that you can force an interface into >X.Em dead >Xphase by calling >X.Xr ifconfig 8 >Xwith the parameter >X.Ql down . >X.Pp >XThe currently supported parameters include: >X.Bl -tag -offset indent -width indent >X.It Ar authproto Ns \&= Ns Em protoname >XSet both, his and my authentication protocol to >X.Em protoname . >XThe protocol name can be one of >X.Ql chap , >X.Ql pap , >Xor >X.Ql none . >XIn the latter case, the use of an authentication protocol will be >Xturned off for the named interface. This has the side-effect of >Xclearing the other authentication-related parameters for this >Xinterface as well (i.e. system name and authentication secret will >Xbe forgotten). >X.It Ar myauthproto Ns \&= Ns Em protoname >XSame as above, but only for my end of the link. I.e. this is the >Xprotocol when remote is authenticator, and I am the peer required to >Xauthenticate. >X.It Ar hisauthproto Ns \&= Ns Em protoname >XSame as above, but only for his end of the link. >X.It Ar myauthname Ns \&= Ns Em name >XSet my system name for the authentication protocol. >X.It Ar hisauthname Ns \&= Ns Em name >XSet his system name for the authentication protocol. For CHAP, this >Xwill only be used as a hint, causing a warning message if remote did >Xsupply a different name. For PAP, it's the name remote must use to >Xauthenticate himself (in connection with his secret). >X.It Ar myauthsecret Ns \&= Ns Em secret >XSet my secret (key, password) for use in the authentication phase. >XFor CHAP, this will be used to compute the response hash value, based >Xon remote's challenge. For PAP, it will be transmitted as plain text >Xtogether with the system name. Don't forget to quote the secrets from >Xthe shell if they contain shell metacharacters (or white space). >X.It Ar myauthkey Ns \&= Ns Em secret >XSame as above. >X.It Ar hisauthsecret Ns \&= Ns Em secret >XSame as above, to be used if we are authenticator and the remote peer >Xneeds to authenticate. >X.It Ar hisauthkey Ns \&= Ns Em secret >XSame as above. >X.It Ar callin >XRequire remote to authenticate himself only when he's calling in, but >Xnot when we are caller. This is required for some peers that do not >Ximplement the authentication protocols symmetrically (like Ascend >Xrouters, for example). >X.It Ar always >XThe opposite of >X.Ar callin . >XRequire remote to always authenticate, regardless of which side is >Xplacing the call. This is the default, and will not be explicitly >Xdisplayed in >X.Ql list >Xmode. >X.It Ar norechallenge >XOnly meaningful with CHAP. Do not re-challenge peer once the initial >XCHAP handshake was successful. Used to work around broken peer >Ximplementations that can't grok being re-challenged once the >Xconnection is up. >X.It Ar rechallenge >XWith CHAP, send re-challenges at random intervals while the connection >Xis in network phase. (The intervals are currently in the range of 300 >Xthrough approximately 800 seconds.) This is the default, and will not >Xbe explicitly displayed in >X.Ql list >Xmode. >X.El >X.Sh EXAMPLES >X.Bd -literal >X# spppcontrol bppp0 >Xbppp0: phase=dead >X myauthproto=chap myauthname="uriah" >X hisauthproto=chap hisauthname="ifb-gw" norechallenge >X.Ed >X.Pp >XDisplay the settings for bppp0. The interface is currently in >X.Em dead >Xphase, i.e. the LCP layer is down, and no traffic is possible. Both >Xends of the connection use the CHAP protocol, my end tells remote the >Xsystem name >X.Ql uriah , >Xand remote is expected to authenticate by the name >X.Ql ifb-gw . >XOnce the initial CHAP handshake was successful, no further CHAP >Xchallenges will be transmitted. There are supposedly some known CHAP >Xsecrets for both ends of the link which are not being shown. >X.Pp >X.Bd -literal >X# spppcontrol bppp0 \e >X authproto=chap \e >X myauthname=uriah myauthsecret='some secret' \e >X hisauthname=ifb-gw hisauthsecret='another' \e >X norechallenge >X.Ed >X.Pp >XA possible call to >X.Nm >Xthat could have been used to bring the interface into the state shown >Xby the previous example. >X.Sh SEE ALSO >X.Xr netstat 1 , >X.Xr sppp 4 , >X.Xr ifconfig 8 >X.Rs >X.%A B. Lloyd, W. Simpson >X.%T "PPP Authentication Protocols" >X.%O RFC 1334 >X.Re >X.Rs >X.%A W. Simpson, Editor >X.%T "The Point-to-Point Protocol (PPP)" >X.%O RFC 1661 >X.Re >X.Rs >X.%A W. Simpson >X.%T "PPP Challenge Handshake Authentication Protocol (CHAP)" >X.%O RFC 1994 >X.Re >X.Sh HISTORY >XThe >X.Nm >Xutility appeared in >X.Fx 3.0 . >X.Sh AUTHORS >XThe program was written by >X.ie t J\(:org Wunsch, >X.el Joerg Wunsch, >XDresden. >END-of-./usr/src/sbin/spppcontrol/spppcontrol.1 >echo x - ./usr/src/sbin/spppcontrol/spppcontrol.c >sed 's/^X//' >./usr/src/sbin/spppcontrol/spppcontrol.c << 'END-of-./usr/src/sbin/spppcontrol/spppcontrol.c' >X/* >X * Copyright (c) 1997 Joerg Wunsch >X * >X * All rights reserved. >X * >X * Redistribution and use in source and binary forms, with or without >X * modification, are permitted provided that the following conditions >X * are met: >X * 1. Redistributions of source code must retain the above copyright >X * notice, this list of conditions and the following disclaimer. >X * 2. Redistributions in binary form must reproduce the above copyright >X * notice, this list of conditions and the following disclaimer in the >X * documentation and/or other materials provided with the distribution. >X * >X * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR >X * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES >X * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. >X * IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, >X * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT >X * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, >X * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY >X * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >X * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF >X * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >X */ >X >X#ifndef lint >Xstatic const char rcsid[] = >X "$Id: spppcontrol.c,v 1.4 1998/08/03 06:24:59 charnier Exp $"; >X#endif /* not lint */ >X >X#include <sys/param.h> >X#include <sys/callout.h> >X#include <sys/ioctl.h> >X#include <sys/socket.h> >X >X#include <net/if.h> >X#include <net/if_var.h> >X#include <net/if_sppp.h> >X >X#include <err.h> >X#include <stdio.h> >X#include <string.h> >X#include <sysexits.h> >X#include <unistd.h> >X >Xstatic void usage(void); >Xvoid print_vals(const char *ifname, struct spppreq *sp); >Xconst char *phase_name(enum ppp_phase phase); >Xconst char *proto_name(u_short proto); >Xconst char *authflags(u_short flags); >X >X#define PPP_PAP 0xc023 >X#define PPP_CHAP 0xc223 >X >Xint >Xmain(int argc, char **argv) >X{ >X int s, c; >X int errs = 0, verbose = 0; >X size_t off; >X const char *ifname, *cp; >X struct ifreq ifr; >X struct spppreq spr; >X >X while ((c = getopt(argc, argv, "v")) != -1) >X switch (c) { >X case 'v': >X verbose++; >X break; >X >X default: >X errs++; >X break; >X } >X argv += optind; >X argc -= optind; >X >X if (errs || argc < 1) >X usage(); >X >X ifname = argv[0]; >X strncpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name); >X >X /* use a random AF to create the socket */ >X if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) >X err(EX_UNAVAILABLE, "ifconfig: socket"); >X >X argc--; >X argv++; >X >X spr.cmd = (int)SPPPIOGDEFS; >X ifr.ifr_data = (caddr_t)&spr; >X >X if (ioctl(s, SIOCGIFGENERIC, &ifr) == -1) >X err(EX_OSERR, "SIOCGIFGENERIC(SPPPIOGDEFS)"); >X >X if (argc == 0) { >X /* list only mode */ >X print_vals(ifname, &spr); >X return 0; >X } >X >X#define startswith(s) strncmp(argv[0], s, (off = strlen(s))) == 0 >X >X while (argc > 0) { >X if (startswith("authproto=")) { >X cp = argv[0] + off; >X if (strcmp(cp, "pap") == 0) >X spr.defs.myauth.proto = >X spr.defs.hisauth.proto = PPP_PAP; >X else if (strcmp(cp, "chap") == 0) >X spr.defs.myauth.proto = >X spr.defs.hisauth.proto = PPP_CHAP; >X else if (strcmp(cp, "none") == 0) >X spr.defs.myauth.proto = >X spr.defs.hisauth.proto = 0; >X else >X errx(EX_DATAERR, "bad auth proto: %s", cp); >X } else if (startswith("myauthproto=")) { >X cp = argv[0] + off; >X if (strcmp(cp, "pap") == 0) >X spr.defs.myauth.proto = PPP_PAP; >X else if (strcmp(cp, "chap") == 0) >X spr.defs.myauth.proto = PPP_CHAP; >X else if (strcmp(cp, "none") == 0) >X spr.defs.myauth.proto = 0; >X else >X errx(EX_DATAERR, "bad auth proto: %s", cp); >X } else if (startswith("myauthname=")) >X strncpy(spr.defs.myauth.name, argv[0] + off, >X AUTHNAMELEN); >X else if (startswith("myauthsecret=") || >X startswith("myauthkey=")) >X strncpy(spr.defs.myauth.secret, argv[0] + off, >X AUTHKEYLEN); >X else if (startswith("hisauthproto=")) { >X cp = argv[0] + off; >X if (strcmp(cp, "pap") == 0) >X spr.defs.hisauth.proto = PPP_PAP; >X else if (strcmp(cp, "chap") == 0) >X spr.defs.hisauth.proto = PPP_CHAP; >X else if (strcmp(cp, "none") == 0) >X spr.defs.hisauth.proto = 0; >X else >X errx(EX_DATAERR, "bad auth proto: %s", cp); >X } else if (startswith("hisauthname=")) >X strncpy(spr.defs.hisauth.name, argv[0] + off, >X AUTHNAMELEN); >X else if (startswith("hisauthsecret=") || >X startswith("hisauthkey=")) >X strncpy(spr.defs.hisauth.secret, argv[0] + off, >X AUTHKEYLEN); >X else if (strcmp(argv[0], "callin") == 0) >X spr.defs.hisauth.flags |= AUTHFLAG_NOCALLOUT; >X else if (strcmp(argv[0], "always") == 0) >X spr.defs.hisauth.flags &= ~AUTHFLAG_NOCALLOUT; >X else if (strcmp(argv[0], "norechallenge") == 0) >X spr.defs.hisauth.flags |= AUTHFLAG_NORECHALLENGE; >X else if (strcmp(argv[0], "rechallenge") == 0) >X spr.defs.hisauth.flags &= ~AUTHFLAG_NORECHALLENGE; >X else >X errx(EX_DATAERR, "bad parameter: \"%s\"", argv[0]); >X >X argv++; >X argc--; >X } >X >X spr.cmd = (int)SPPPIOSDEFS; >X >X if (ioctl(s, SIOCSIFGENERIC, &ifr) == -1) >X err(EX_OSERR, "SIOCSIFGENERIC(SPPPIOSDEFS)"); >X >X if (verbose) >X print_vals(ifname, &spr); >X >X return 0; >X} >X >Xstatic void >Xusage(void) >X{ >X fprintf(stderr, "%s\n%s\n", >X "usage: spppcontrol [-v] ifname [{my|his}auth{proto|name|secret}=...]", >X " spppcontrol [-v] ifname callin|always"); >X exit(EX_USAGE); >X} >X >Xvoid >Xprint_vals(const char *ifname, struct spppreq *sp) >X{ >X time_t send, recv; >X printf("%s:\tphase=%s\n", ifname, phase_name(sp->defs.pp_phase)); >X if (sp->defs.myauth.proto) { >X printf("\tmyauthproto=%s myauthname=\"%.*s\"\n", >X proto_name(sp->defs.myauth.proto), >X AUTHNAMELEN, sp->defs.myauth.name); >X } >X if (sp->defs.hisauth.proto) { >X printf("\thisauthproto=%s hisauthname=\"%.*s\"%s\n", >X proto_name(sp->defs.hisauth.proto), >X AUTHNAMELEN, sp->defs.hisauth.name, >X authflags(sp->defs.hisauth.flags)); >X } >X send = time(NULL) - sp->defs.pp_last_sent; >X recv = time(NULL) - sp->defs.pp_last_recv; >X printf("\tidle_time=%ld\n", (send<recv)? send : recv); >X} >X >Xconst char * >Xphase_name(enum ppp_phase phase) >X{ >X switch (phase) { >X case PHASE_DEAD: return "dead"; >X case PHASE_ESTABLISH: return "establish"; >X case PHASE_TERMINATE: return "terminate"; >X case PHASE_AUTHENTICATE: return "authenticate"; >X case PHASE_NETWORK: return "network"; >X } >X return "illegal"; >X} >X >Xconst char * >Xproto_name(u_short proto) >X{ >X static char buf[12]; >X switch (proto) { >X case PPP_PAP: return "pap"; >X case PPP_CHAP: return "chap"; >X } >X sprintf(buf, "0x%x", (unsigned)proto); >X return buf; >X} >X >Xconst char * >Xauthflags(u_short flags) >X{ >X static char buf[10]; >X buf[0] = '\0'; >X if (flags & AUTHFLAG_NOCALLOUT) >X strcat(buf, " callin"); >X if (flags & AUTHFLAG_NORECHALLENGE) >X strcat(buf, " norechallenge"); >X return buf; >X} >END-of-./usr/src/sbin/spppcontrol/spppcontrol.c >echo x - ./usr/src/sbin/spppcontrol/spppcontrol.c.patch >sed 's/^X//' >./usr/src/sbin/spppcontrol/spppcontrol.c.patch << 'END-of-./usr/src/sbin/spppcontrol/spppcontrol.c.patch' >X*** spppcontrol.c Mon Mar 15 15:04:04 1999 >X--- spppcontrol.c.new Mon Mar 15 15:03:43 1999 >X*************** >X*** 209,212 **** >X--- 209,213 ---- >X print_vals(const char *ifname, struct spppreq *sp) >X { >X+ time_t send, recv; >X printf("%s:\tphase=%s\n", ifname, phase_name(sp->defs.pp_phase)); >X if (sp->defs.myauth.proto) { >X*************** >X*** 221,224 **** >X--- 222,228 ---- >X authflags(sp->defs.hisauth.flags)); >X } >X+ send = time(NULL) - sp->defs.pp_last_sent; >X+ recv = time(NULL) - sp->defs.pp_last_recv; >X+ printf("\tidle_time=%ld\n", (send<recv)? send : recv); >X } >X >END-of-./usr/src/sbin/spppcontrol/spppcontrol.c.patch >echo x - ./usr/src/sbin/spppcontrol/spppcontrol.c.orig >sed 's/^X//' >./usr/src/sbin/spppcontrol/spppcontrol.c.orig << 'END-of-./usr/src/sbin/spppcontrol/spppcontrol.c.orig' >X/* >X * Copyright (c) 1997 Joerg Wunsch >X * >X * All rights reserved. >X * >X * Redistribution and use in source and binary forms, with or without >X * modification, are permitted provided that the following conditions >X * are met: >X * 1. Redistributions of source code must retain the above copyright >X * notice, this list of conditions and the following disclaimer. >X * 2. Redistributions in binary form must reproduce the above copyright >X * notice, this list of conditions and the following disclaimer in the >X * documentation and/or other materials provided with the distribution. >X * >X * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR >X * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES >X * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. >X * IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, >X * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT >X * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, >X * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY >X * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >X * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF >X * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >X */ >X >X#ifndef lint >Xstatic const char rcsid[] = >X "$Id: spppcontrol.c,v 1.4 1998/08/03 06:24:59 charnier Exp $"; >X#endif /* not lint */ >X >X#include <sys/param.h> >X#include <sys/callout.h> >X#include <sys/ioctl.h> >X#include <sys/socket.h> >X >X#include <net/if.h> >X#include <net/if_var.h> >X#include <net/if_sppp.h> >X >X#include <err.h> >X#include <stdio.h> >X#include <string.h> >X#include <sysexits.h> >X#include <unistd.h> >X >Xstatic void usage(void); >Xvoid print_vals(const char *ifname, struct spppreq *sp); >Xconst char *phase_name(enum ppp_phase phase); >Xconst char *proto_name(u_short proto); >Xconst char *authflags(u_short flags); >X >X#define PPP_PAP 0xc023 >X#define PPP_CHAP 0xc223 >X >Xint >Xmain(int argc, char **argv) >X{ >X int s, c; >X int errs = 0, verbose = 0; >X size_t off; >X const char *ifname, *cp; >X struct ifreq ifr; >X struct spppreq spr; >X >X while ((c = getopt(argc, argv, "v")) != -1) >X switch (c) { >X case 'v': >X verbose++; >X break; >X >X default: >X errs++; >X break; >X } >X argv += optind; >X argc -= optind; >X >X if (errs || argc < 1) >X usage(); >X >X ifname = argv[0]; >X strncpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name); >X >X /* use a random AF to create the socket */ >X if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) >X err(EX_UNAVAILABLE, "ifconfig: socket"); >X >X argc--; >X argv++; >X >X spr.cmd = (int)SPPPIOGDEFS; >X ifr.ifr_data = (caddr_t)&spr; >X >X if (ioctl(s, SIOCGIFGENERIC, &ifr) == -1) >X err(EX_OSERR, "SIOCGIFGENERIC(SPPPIOGDEFS)"); >X >X if (argc == 0) { >X /* list only mode */ >X print_vals(ifname, &spr); >X return 0; >X } >X >X#define startswith(s) strncmp(argv[0], s, (off = strlen(s))) == 0 >X >X while (argc > 0) { >X if (startswith("authproto=")) { >X cp = argv[0] + off; >X if (strcmp(cp, "pap") == 0) >X spr.defs.myauth.proto = >X spr.defs.hisauth.proto = PPP_PAP; >X else if (strcmp(cp, "chap") == 0) >X spr.defs.myauth.proto = >X spr.defs.hisauth.proto = PPP_CHAP; >X else if (strcmp(cp, "none") == 0) >X spr.defs.myauth.proto = >X spr.defs.hisauth.proto = 0; >X else >X errx(EX_DATAERR, "bad auth proto: %s", cp); >X } else if (startswith("myauthproto=")) { >X cp = argv[0] + off; >X if (strcmp(cp, "pap") == 0) >X spr.defs.myauth.proto = PPP_PAP; >X else if (strcmp(cp, "chap") == 0) >X spr.defs.myauth.proto = PPP_CHAP; >X else if (strcmp(cp, "none") == 0) >X spr.defs.myauth.proto = 0; >X else >X errx(EX_DATAERR, "bad auth proto: %s", cp); >X } else if (startswith("myauthname=")) >X strncpy(spr.defs.myauth.name, argv[0] + off, >X AUTHNAMELEN); >X else if (startswith("myauthsecret=") || >X startswith("myauthkey=")) >X strncpy(spr.defs.myauth.secret, argv[0] + off, >X AUTHKEYLEN); >X else if (startswith("hisauthproto=")) { >X cp = argv[0] + off; >X if (strcmp(cp, "pap") == 0) >X spr.defs.hisauth.proto = PPP_PAP; >X else if (strcmp(cp, "chap") == 0) >X spr.defs.hisauth.proto = PPP_CHAP; >X else if (strcmp(cp, "none") == 0) >X spr.defs.hisauth.proto = 0; >X else >X errx(EX_DATAERR, "bad auth proto: %s", cp); >X } else if (startswith("hisauthname=")) >X strncpy(spr.defs.hisauth.name, argv[0] + off, >X AUTHNAMELEN); >X else if (startswith("hisauthsecret=") || >X startswith("hisauthkey=")) >X strncpy(spr.defs.hisauth.secret, argv[0] + off, >X AUTHKEYLEN); >X else if (strcmp(argv[0], "callin") == 0) >X spr.defs.hisauth.flags |= AUTHFLAG_NOCALLOUT; >X else if (strcmp(argv[0], "always") == 0) >X spr.defs.hisauth.flags &= ~AUTHFLAG_NOCALLOUT; >X else if (strcmp(argv[0], "norechallenge") == 0) >X spr.defs.hisauth.flags |= AUTHFLAG_NORECHALLENGE; >X else if (strcmp(argv[0], "rechallenge") == 0) >X spr.defs.hisauth.flags &= ~AUTHFLAG_NORECHALLENGE; >X else >X errx(EX_DATAERR, "bad parameter: \"%s\"", argv[0]); >X >X argv++; >X argc--; >X } >X >X spr.cmd = (int)SPPPIOSDEFS; >X >X if (ioctl(s, SIOCSIFGENERIC, &ifr) == -1) >X err(EX_OSERR, "SIOCSIFGENERIC(SPPPIOSDEFS)"); >X >X if (verbose) >X print_vals(ifname, &spr); >X >X return 0; >X} >X >Xstatic void >Xusage(void) >X{ >X fprintf(stderr, "%s\n%s\n", >X "usage: spppcontrol [-v] ifname [{my|his}auth{proto|name|secret}=...]", >X " spppcontrol [-v] ifname callin|always"); >X exit(EX_USAGE); >X} >X >Xvoid >Xprint_vals(const char *ifname, struct spppreq *sp) >X{ >X printf("%s:\tphase=%s\n", ifname, phase_name(sp->defs.pp_phase)); >X if (sp->defs.myauth.proto) { >X printf("\tmyauthproto=%s myauthname=\"%.*s\"\n", >X proto_name(sp->defs.myauth.proto), >X AUTHNAMELEN, sp->defs.myauth.name); >X } >X if (sp->defs.hisauth.proto) { >X printf("\thisauthproto=%s hisauthname=\"%.*s\"%s\n", >X proto_name(sp->defs.hisauth.proto), >X AUTHNAMELEN, sp->defs.hisauth.name, >X authflags(sp->defs.hisauth.flags)); >X } >X} >X >Xconst char * >Xphase_name(enum ppp_phase phase) >X{ >X switch (phase) { >X case PHASE_DEAD: return "dead"; >X case PHASE_ESTABLISH: return "establish"; >X case PHASE_TERMINATE: return "terminate"; >X case PHASE_AUTHENTICATE: return "authenticate"; >X case PHASE_NETWORK: return "network"; >X } >X return "illegal"; >X} >X >Xconst char * >Xproto_name(u_short proto) >X{ >X static char buf[12]; >X switch (proto) { >X case PPP_PAP: return "pap"; >X case PPP_CHAP: return "chap"; >X } >X sprintf(buf, "0x%x", (unsigned)proto); >X return buf; >X} >X >Xconst char * >Xauthflags(u_short flags) >X{ >X static char buf[10]; >X buf[0] = '\0'; >X if (flags & AUTHFLAG_NOCALLOUT) >X strcat(buf, " callin"); >X if (flags & AUTHFLAG_NORECHALLENGE) >X strcat(buf, " norechallenge"); >X return buf; >X} >END-of-./usr/src/sbin/spppcontrol/spppcontrol.c.orig >exit
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 13841
: 5963