From: Paul Mackerras Date: Mon, 18 Dec 1995 03:38:17 +0000 (+0000) Subject: Updates from Al's ppp-2.2.0d release X-Git-Tag: RELEASE_2_3_6~572 X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=commitdiff_plain;h=0f61ac5460e89dd768f1fb56fbdd8fa6f8af79f1;hp=2874cacceefc32c0371e0670af1604a99554161a Updates from Al's ppp-2.2.0d release --- diff --git a/chat/Makefile.linux b/chat/Makefile.linux index 1531410..7f9cbb3 100644 --- a/chat/Makefile.linux +++ b/chat/Makefile.linux @@ -1,4 +1,4 @@ -# $Id: Makefile.linux,v 1.4 1995/12/11 02:55:14 paulus Exp $ +# $Id: Makefile.linux,v 1.5 1995/12/18 03:32:43 paulus Exp $ CDEF1= -DTERMIOS # Use the termios structure CDEF2= -DPIDSTRING # I like ascii pid values @@ -7,12 +7,12 @@ CDEF4= -UNO_SLEEP # Use the usleep function CDEF5= -DFNDELAY=O_NDELAY # Old name value CDEFS= $(CDEF1) $(CDEF2) $(CDEF3) $(CDEF4) $(CDEF5) -CFLAGS= -O2 -N $(CDEFS) +CFLAGS= -O2 $(CDEFS) all: chat chat: chat.o - $(CC) -o chat chat.o + $(CC) -O2 -o chat chat.o chat.o: chat.c $(CC) -c $(CFLAGS) -o chat.o chat.c diff --git a/chat/chat.8 b/chat/chat.8 index c70eb70..c227e79 100644 --- a/chat/chat.8 +++ b/chat/chat.8 @@ -1,6 +1,6 @@ .\" -*- nroff -*- .\" manual page [] for chat 1.8 -.\" $Id: chat.8,v 1.2 1995/06/12 11:24:14 paulus Exp $ +.\" $Id: chat.8,v 1.3 1995/12/18 03:32:45 paulus Exp $ .\" SH section heading .\" SS subsection heading .\" LP paragraph @@ -48,6 +48,16 @@ Request that the \fIchat\fR script be executed in a verbose mode. The \fIchat\fR program will then log all text received from the modem and the output strings which it sends to the SYSLOG. .TP +.B -V +Request that the \fIchat\fR script be executed in a stderr verbose +mode. The \fIchat\fR program will then log all text received from the +modem and the output strings which it sends to the stderr device. This +device is usually the local console at the station running the chat or +pppd program. This option will not work properly if the stderr is +redirected to the /dev/null locaiton as is the case should pppd be run +in the 'detached' mode. In that case, use the '-v' option to record +the session on the SYSLOG device. +.TP .B script If the script is not specified in a file with the \fI-f\fR option then the script is included as parameters to the \fIchat\fR program. diff --git a/chat/chat.c b/chat/chat.c index f7aaabf..7b805ad 100644 --- a/chat/chat.c +++ b/chat/chat.c @@ -31,7 +31,7 @@ * */ -static char rcsid[] = "$Id: chat.c,v 1.9 1995/06/12 11:24:15 paulus Exp $"; +static char rcsid[] = "$Id: chat.c,v 1.10 1995/12/18 03:32:46 paulus Exp $"; #include #include @@ -93,6 +93,7 @@ char *program_name; #define DEFAULT_CHAT_TIMEOUT 45 int verbose = 0; +int Verbose = 0; int quiet = 0; int report = 0; int exit_code = 0; @@ -199,6 +200,10 @@ char **argv; ++verbose; break; + case 'V': + ++Verbose; + break; + case 'f': if (arg = OPTARG(argc, argv)) { @@ -580,7 +585,7 @@ int status; fprintf (report_fp, "Closing \"%s\".\n", report_file); } fclose (report_fp); - report_fp = (FILE*) NULL; + report_fp = (FILE *) NULL; } #if defined(get_term_param) @@ -752,12 +757,71 @@ int sending; return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */ } +/* + * A modified version of 'strtok'. This version skips \ sequences. + */ + +char *expect_strtok (s, term) +char *s, *term; + { + static char *str = ""; + static int escape_flag = 0; + char *result; +/* + * If a string was specified then do initial processing. + */ + if (s) + { + str = s; + escape_flag = 0; + } + + result = (char *) 0; + while (*str) + { +/* + * Look for the terminator sequence. + * If the escape flag is set then this character is not the terminator. + * We assume that term does not contain the backslash character. + */ + if (escape_flag || strchr (term, *str) == (char *) 0) + { + if (result == (char *) 0) + { + result = str; + } + + if (escape_flag || *str == '\\') + { + escape_flag = !escape_flag; + } + + ++str; + continue; + } +/* + * This is the terminator. If we have a string then this is the end of the + * scan operation. + */ + *str++ = '\0'; + if (result) + { + break; + } + } + return (result); + } + /* * Process the expect string */ -void chat_expect(s) -register char *s; + +void chat_expect (s) +char *s; { + char *expect; + char *reply; + if (strcmp(s, "ABORT") == 0) { ++abort_next; @@ -775,82 +839,57 @@ register char *s; ++timeout_next; return; } - - while (*s) +/* + * Fetch the expect and reply string. + */ + for (;;) { - register char *hyphen; + expect = expect_strtok (s, "-"); + s = (char *) 0; - for (hyphen = s; *hyphen; ++hyphen) + if (expect == (char *) 0) { - if (*hyphen == '-') - { - if (hyphen == s || hyphen[-1] != '\\') - { - break; - } - } + return; } - - if (*hyphen == '-') - { - *hyphen = '\0'; - if (get_string(s)) - { - return; - } - else - { - s = hyphen + 1; - - for (hyphen = s; *hyphen; ++hyphen) - { - if (*hyphen == '-') - { - if (hyphen == s || hyphen[-1] != '\\') - { - break; - } - } - } - - if (*hyphen == '-') - { - *hyphen = '\0'; - - chat_send(s); - s = hyphen + 1; - } - else - { - chat_send(s); - return; - } - } + reply = expect_strtok (s, "-"); +/* + * Handle the expect string. If successful then exit. + */ + if (get_string (expect)) + { + return; } - else +/* + * If there is a sub-reply string then send it. Otherwise any condition + * is terminal. + */ + if (reply == (char *) 0 || exit_code != 3) { - if (get_string(s)) - { - return; - } - else - { - if (fail_reason) - { - syslog(LOG_INFO, "Failed (%s)", fail_reason); - } - else - { - syslog(LOG_INFO, "Failed"); - } - - terminate(exit_code); - } + break; } + + chat_send (reply); + } +/* + * The expectation did not occur. This is terminal. + */ + if (fail_reason) + { + syslog(LOG_INFO, "Failed (%s)", fail_reason); + } + else + { + syslog(LOG_INFO, "Failed"); } + terminate(exit_code); } +/* + * Translate the input character to the appropriate string for printing + * the data. + */ + char *character(c) int c; { @@ -1219,6 +1258,11 @@ register char *string; } } + if (Verbose) { + if (c == '\n') fputc( '\n', stderr ); + else if (c != '\r') fprintf( stderr, "%s", character(c) ); + } + *s++ = c; if (s - temp >= len && diff --git a/include/linux/if_ppp.h b/include/linux/if_ppp.h index ebf3ea3..5f21d94 100644 --- a/include/linux/if_ppp.h +++ b/include/linux/if_ppp.h @@ -1,4 +1,4 @@ -/* $Id: if_ppp.h,v 1.3 1995/06/12 11:36:50 paulus Exp $ */ +/* $Id: if_ppp.h,v 1.4 1995/12/18 03:38:01 paulus Exp $ */ /* * if_ppp.h - Point-to-Point Protocol definitions. @@ -21,13 +21,13 @@ */ /* - * ==PPPVERSION 2.1.3== + * ==FILEVERSION 6== * * NOTE TO MAINTAINERS: - * If you modify this file at all, increment the last number above. - * ppp.c is shipped with a PPP distribution as well as with the kernel; - * if everyone increases the PPPVERSION number above, then scripts - * can do the right thing when deciding whether to install a new ppp.c + * If you modify this file at all, increment the number above. + * if_ppp.h is shipped with a PPP distribution as well as with the kernel; + * if everyone increases the FILEVERSION number above, then scripts + * can do the right thing when deciding whether to install a new if_ppp.h * file. Don't change the format of that line otherwise, so the * installation script can recognize it. */ @@ -35,6 +35,12 @@ #ifndef _IF_PPP_H_ #define _IF_PPP_H_ +#if defined(__linux__) +#include +#include +#include +#endif + /* * Packet sizes */ @@ -44,6 +50,8 @@ #define PPP_VERSION "2.2.0" #define PPP_MAGIC 0x5002 /* Magic value for the ppp structure */ #define PROTO_IPX 0x002b /* protocol numbers */ +#define PROTO_DNA_RT 0x0027 /* DNA Routing */ + /* * Bit definitions for flags. @@ -96,11 +104,18 @@ struct ppp_option_data { }; struct ifpppstatsreq { - char ifr__name[IFNAMSIZ]; /* Name of the device */ - struct ppp_stats *stats_ptr; /* Pointer to stats buffer */ - struct ppp_stats stats; /* statistic information */ + struct ifreq b; + struct ppp_stats stats; /* statistic information */ }; +struct ifpppcstatsreq { + struct ifreq b; + struct ppp_comp_stats stats; +}; + +#define ifr__name b.ifr_ifrn.ifrn_name +#define stats_ptr b.ifr_ifru.ifru_data + /* * Ioctl definitions. */ @@ -121,13 +136,13 @@ struct ifpppstatsreq { #define PPPIOCSCOMPRESS _IOW('t', 77, struct ppp_option_data) #define PPPIOCGNPMODE _IOWR('t', 76, struct npioctl) /* get NP mode */ #define PPPIOCSNPMODE _IOW('t', 75, struct npioctl) /* set NP mode */ - #define PPPIOCGDEBUG _IOR('t', 65, int) /* Read debug level */ #define PPPIOCSDEBUG _IOW('t', 64, int) /* Set debug level */ -#define PPPIOCGTIME _IOR('t', 63, struct ppp_ddinfo) /* Read time info */ +#define PPPIOCGIDLE _IOR('t', 63, struct ppp_idle) /* get idle time */ #define SIOCGPPPSTATS (SIOCDEVPRIVATE + 0) -#define SIOCGPPPVER (SIOCDEVPRIVATE + 1) +#define SIOCGPPPVER (SIOCDEVPRIVATE + 1) /* NEVER change this!! */ +#define SIOCGPPPCSTATS (SIOCDEVPRIVATE + 2) #if !defined(ifr_mtu) #define ifr_mtu ifr_ifru.ifru_metric diff --git a/include/linux/if_pppvar.h b/include/linux/if_pppvar.h index 89be343..8d3dfc3 100644 --- a/include/linux/if_pppvar.h +++ b/include/linux/if_pppvar.h @@ -1,4 +1,4 @@ -/* $Id: if_pppvar.h,v 1.2 1995/06/12 11:36:51 paulus Exp $ */ +/* $Id: if_pppvar.h,v 1.3 1995/12/18 03:38:02 paulus Exp $ */ /* * if_pppvar.h - private structures and declarations for PPP. * @@ -42,13 +42,13 @@ */ /* - * ==PPPVERSION 2.1.3== + * ==FILEVERSION 4== * * NOTE TO MAINTAINERS: - * If you modify this file at all, increment the last number above. - * ppp.c is shipped with a PPP distribution as well as with the kernel; - * if everyone increases the PPPVERSION number above, then scripts - * can do the right thing when deciding whether to install a new ppp.c + * If you modify this file at all, increment the number above. + * if_pppvar.h is shipped with a PPP distribution as well as with the kernel; + * if everyone increases the FILEVERSION number above, then scripts + * can do the right thing when deciding whether to install a new if_pppvar.h * file. Don't change the format of that line otherwise, so the * installation script can recognize it. */ @@ -65,19 +65,21 @@ * Buffers for the PPP process have the following structure */ -#define RBUFSIZE 2048 /* MUST be a power of 2 and be <= 4095 */ +#define RBUFSIZE 2048 /* MUST be a power of 2 and be <= 4095 */ + struct ppp_buffer { int size; /* Size of the buffer area */ int count; /* Count of characters in bufr */ int head; /* index to head of list */ int tail; /* index to tail of list */ - int locked; /* Buffer is being sent */ + unsigned long locked; /* Buffer is being sent */ int type; /* Type of the buffer */ /* =0, device read buffer */ /* =1, device write buffer */ /* =2, daemon write buffer */ /* =3, daemon read buffer */ unsigned short fcs; /* Frame Check Sequence (CRC) */ + unsigned char filler[4]; /* Extra space if needed */ }; /* Given a pointer to the ppp_buffer then return base address of buffer */ @@ -100,7 +102,7 @@ struct ppp { ext_accm xmit_async_map; /* 1 bit means that given control character is quoted on output*/ - unsigned long recv_async_map; /* 1 bit means that given control + __u32 recv_async_map; /* 1 bit means that given control character is ignored on input*/ int mtu; /* maximum xmit frame size */ int mru; /* maximum receive frame size */ @@ -122,7 +124,7 @@ struct ppp { struct ppp_buffer *s1buf; /* Pointer to daemon buffer */ struct ppp_buffer *s2buf; /* Pointer to device buffer */ - unsigned long last_xmit; /* time of last transmission */ + __u32 last_xmit; /* time of last transmission */ /* These are pointers to the malloc()ed frame buffers. These buffers are used while processing a packet. If a packet @@ -140,8 +142,8 @@ struct ppp { struct wait_queue *read_wait; /* queue for writing processes */ /* Statistic information */ - struct pppstat stats; /* statistic information */ - struct ppp_ddinfo ddinfo; /* demand dial information */ + struct pppstat stats; /* statistic information */ + struct ppp_idle ddinfo; /* demand dial information */ /* PPP compression protocol information */ u_int sc_bytessent; /* count of octets sent */ diff --git a/include/linux/ppp-comp.h b/include/linux/ppp-comp.h new file mode 100644 index 0000000..b72da19 --- /dev/null +++ b/include/linux/ppp-comp.h @@ -0,0 +1,192 @@ +/* + * ppp-comp.h - Definitions for doing PPP packet compression. + * + * Copyright (c) 1994 The Australian National University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, provided that the above copyright + * notice appears in all copies. This software is provided without any + * warranty, express or implied. The Australian National University + * makes no representations about the suitability of this software for + * any purpose. + * + * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY + * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, + * OR MODIFICATIONS. + * + * $Id: ppp-comp.h,v 1.1 1995/12/18 03:38:10 paulus Exp $ + */ + +/* + * ==FILEVERSION 4== + * + * NOTE TO MAINTAINERS: + * If you modify this file at all, increment the number above. + * ppp-comp.h is shipped with a PPP distribution as well as with the kernel; + * if everyone increases the FILEVERSION number above, then scripts + * can do the right thing when deciding whether to install a new ppp-comp.h + * file. Don't change the format of that line otherwise, so the + * installation script can recognize it. + */ + +#ifndef _NET_PPP_COMP_H +#define _NET_PPP_COMP_H + +/* + * The following symbols control whether we include code for + * various compression methods. + */ + +#ifndef DO_BSD_COMPRESS +#define DO_BSD_COMPRESS 1 /* by default, include BSD-Compress */ +#endif + +#define DO_PREDICTOR_1 0 +#define DO_PREDICTOR_2 0 +#define DO_DEFLATE 0 + +/* + * Structure giving methods for compression/decompression. + */ + +#ifdef PACKETPTR +struct compressor { + int compress_proto; /* CCP compression protocol number */ + + /* Allocate space for a compressor (transmit side) */ + void *(*comp_alloc) (unsigned char *options, int opt_len); + + /* Free space used by a compressor */ + void (*comp_free) (void *state); + + /* Initialize a compressor */ + int (*comp_init) (void *state, unsigned char *options, + int opt_len, int unit, int opthdr, int debug); + + /* Reset a compressor */ + void (*comp_reset) (void *state); + + /* Compress a packet */ + int (*compress) (void *state, unsigned char *rptr, + unsigned char *obuf, int isize, int osize); + + /* Return compression statistics */ + void (*comp_stat) (void *state, struct compstat *stats); + + /* Allocate space for a decompressor (receive side) */ + void *(*decomp_alloc) (unsigned char *options, int opt_len); + + /* Free space used by a decompressor */ + void (*decomp_free) (void *state); + + /* Initialize a decompressor */ + int (*decomp_init) (void *state, unsigned char *options, + int opt_len, int unit, int opthdr, int mru, + int debug); + + /* Reset a decompressor */ + void (*decomp_reset) (void *state); + + /* Decompress a packet. */ + int (*decompress) (void *state, unsigned char *ibuf, int isize, + unsigned char *obuf, int osize); + + /* Update state for an incompressible packet received */ + void (*incomp) (void *state, unsigned char *ibuf, int icnt); + + /* Return decompression statistics */ + void (*decomp_stat) (void *state, struct compstat *stats); +}; +#endif /* PACKETPTR */ + +/* + * Return values for decompress routine. + * We need to make these distinctions so that we can disable certain + * useful functionality, namely sending a CCP reset-request as a result + * of an error detected after decompression. This is to avoid infringing + * a patent held by Motorola. + * Don't you just lurve software patents. + */ + +#define DECOMP_OK 0 /* everything went OK */ +#define DECOMP_ERROR 1 /* error detected before decomp. */ +#define DECOMP_FATALERROR 2 /* error detected after decomp. */ + +/* + * CCP codes. + */ + +#define CCP_CONFREQ 1 +#define CCP_CONFACK 2 +#define CCP_TERMREQ 5 +#define CCP_TERMACK 6 +#define CCP_RESETREQ 14 +#define CCP_RESETACK 15 + +/* + * Max # bytes for a CCP option + */ + +#define CCP_MAX_OPTION_LENGTH 32 + +/* + * Parts of a CCP packet. + */ + +#define CCP_CODE(dp) ((dp)[0]) +#define CCP_ID(dp) ((dp)[1]) +#define CCP_LENGTH(dp) (((dp)[2] << 8) + (dp)[3]) +#define CCP_HDRLEN 4 + +#define CCP_OPT_CODE(dp) ((dp)[0]) +#define CCP_OPT_LENGTH(dp) ((dp)[1]) +#define CCP_OPT_MINLEN 2 + +/* + * Definitions for BSD-Compress. + */ + +#define CI_BSD_COMPRESS 21 /* config. option for BSD-Compress */ +#define CILEN_BSD_COMPRESS 3 /* length of config. option */ + +/* Macros for handling the 3rd byte of the BSD-Compress config option. */ +#define BSD_NBITS(x) ((x) & 0x1F) /* number of bits requested */ +#define BSD_VERSION(x) ((x) >> 5) /* version of option format */ +#define BSD_CURRENT_VERSION 1 /* current version number */ +#define BSD_MAKE_OPT(v, n) (((v) << 5) | (n)) + +#define BSD_MIN_BITS 9 /* smallest code size supported */ +#define BSD_MAX_BITS 15 /* largest code size supported */ + +/* + * Definitions for other, as yet unsupported, compression methods. + */ + +#define CI_PREDICTOR_1 1 /* config option for Predictor-1 */ +#define CILEN_PREDICTOR_1 2 /* length of its config option */ +#define CI_PREDICTOR_2 2 /* config option for Predictor-2 */ +#define CILEN_PREDICTOR_2 2 /* length of its config option */ + +#define CI_DEFLATE 24 /* config option for Deflate */ +#define CILEN_DEFLATE 4 /* length of its config option */ + +#define DEFLATE_MIN_SIZE 8 +#define DEFLATE_MAX_SIZE 15 +#define DEFLATE_METHOD_VAL 8 +#define DEFLATE_SIZE(x) (((x) >> 4) + DEFLATE_MIN_SIZE) +#define DEFLATE_METHOD(x) ((x) & 0x0F) +#define DEFLATE_MAKE_OPT(w) ((((w) - DEFLATE_MIN_SIZE) << 4) \ + + DEFLATE_METHOD_VAL) +#define DEFLATE_CHK_SEQUENCE 0 + +#endif /* _NET_PPP_COMP_H */ diff --git a/include/linux/ppp_defs.h b/include/linux/ppp_defs.h new file mode 100644 index 0000000..8913ae7 --- /dev/null +++ b/include/linux/ppp_defs.h @@ -0,0 +1,177 @@ +/* $Id: ppp_defs.h,v 1.1 1995/12/18 03:38:15 paulus Exp $ */ + +/* + * ppp_defs.h - PPP definitions. + * + * Copyright (c) 1994 The Australian National University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, provided that the above copyright + * notice appears in all copies. This software is provided without any + * warranty, express or implied. The Australian National University + * makes no representations about the suitability of this software for + * any purpose. + * + * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY + * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, + * OR MODIFICATIONS. + */ + +/* + * ==FILEVERSION 6== + * + * NOTE TO MAINTAINERS: + * If you modify this file at all, increment the number above. + * ppp_defs.h is shipped with a PPP distribution as well as with the kernel; + * if everyone increases the FILEVERSION number above, then scripts + * can do the right thing when deciding whether to install a new ppp_defs.h + * file. Don't change the format of that line otherwise, so the + * installation script can recognize it. + */ + +#ifndef _PPP_DEFS_H_ +#define _PPP_DEFS_H_ + +/* + * The basic PPP frame. + */ +#define PPP_HDRLEN 4 /* octets for standard ppp header */ +#define PPP_FCSLEN 2 /* octets for FCS */ +#define PPP_MRU 1500 /* default MRU = max length of info field */ + +#define PPP_ADDRESS(p) (((u_char *)(p))[0]) +#define PPP_CONTROL(p) (((u_char *)(p))[1]) +#define PPP_PROTOCOL(p) ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3]) + +/* + * Significant octet values. + */ +#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ +#define PPP_UI 0x03 /* Unnumbered Information */ +#define PPP_FLAG 0x7e /* Flag Sequence */ +#define PPP_ESCAPE 0x7d /* Asynchronous Control Escape */ +#define PPP_TRANS 0x20 /* Asynchronous transparency modifier */ + +/* + * Protocol field values. + */ +#define PPP_IP 0x21 /* Internet Protocol */ +#define PPP_IPX 0x2b /* IPX protocol */ +#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */ +#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */ +#define PPP_COMP 0xfd /* compressed packet */ +#define PPP_IPCP 0x8021 /* IP Control Protocol */ +#define PPP_IPXCP 0x802b /* IPX Control Protocol */ +#define PPP_CCP 0x80fd /* Compression Control Protocol */ +#define PPP_LCP 0xc021 /* Link Control Protocol */ +#define PPP_PAP 0xc023 /* Password Authentication Protocol */ +#define PPP_LQR 0xc025 /* Link Quality Report protocol */ +#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */ + +/* + * A 32-bit unsigned integral type. + */ +#ifndef __BIT_TYPES_DEFINED__ +#ifdef UINT32_T +typedef UINT32_T u_int32_t; +#else +typedef unsigned int u_int32_t; +#endif +#endif + +/* + * Extended asyncmap - allows any character to be escaped. + */ +typedef u_int32_t ext_accm[8]; + +/* + * What to do with network protocol (NP) packets. + */ +enum NPmode { + NPMODE_PASS, /* pass the packet through */ + NPMODE_DROP, /* silently drop the packet */ + NPMODE_ERROR, /* return an error */ + NPMODE_QUEUE /* save it up for later. */ +}; + +/* + * Statistics for LQRP and pppstats + */ +struct pppstat { + u_int ppp_discards; /* # frames discarded */ + + u_int ppp_ibytes; /* bytes received */ + u_int ppp_ioctects; /* bytes received not in error */ + u_int ppp_ipackets; /* packets received */ + u_int ppp_ierrors; /* receive errors */ + u_int ppp_ilqrs; /* # LQR frames received */ + + u_int ppp_obytes; /* raw bytes sent */ + u_int ppp_ooctects; /* frame bytes sent */ + u_int ppp_opackets; /* packets sent */ + u_int ppp_oerrors; /* transmit errors */ + u_int ppp_olqrs; /* # LQR frames sent */ +}; + +struct vjstat { + u_int vjs_packets; /* outbound packets */ + u_int vjs_compressed; /* outbound compressed packets */ + u_int vjs_searches; /* searches for connection state */ + u_int vjs_misses; /* times couldn't find conn. state */ + u_int vjs_uncompressedin; /* inbound uncompressed packets */ + u_int vjs_compressedin; /* inbound compressed packets */ + u_int vjs_errorin; /* inbound unknown type packets */ + u_int vjs_tossed; /* inbound packets tossed because of error */ +}; + +struct compstat { + u_int unc_bytes; /* total uncompressed bytes */ + u_int unc_packets; /* total uncompressed packets */ + u_int comp_bytes; /* compressed bytes */ + u_int comp_packets; /* compressed packets */ + u_int inc_bytes; /* incompressible bytes */ + u_int inc_packets; /* incompressible packets */ + /* the compression ratio is defined as in_count / bytes_out */ + u_int in_count; /* Bytes received */ + u_int bytes_out; /* Bytes transmitted */ + double ratio; /* not computed in kernel. */ +}; + +struct ppp_stats { + struct pppstat p; /* basic PPP statistics */ + struct vjstat vj; /* VJ header compression statistics */ +}; + +struct ppp_comp_stats { + struct compstat c; /* packet compression statistics */ + struct compstat d; /* packet decompression statistics */ +}; + +/* + * The following structure records the time in seconds since + * the last NP packet was sent or received. + */ +struct ppp_idle { + time_t xmit_idle; /* time since last NP packet sent */ + time_t recv_idle; /* time since last NP packet received */ +}; + +#ifndef __P +#ifdef __STDC__ +#define __P(x) x +#else +#define __P(x) () +#endif +#endif + +#endif /* _PPP_DEFS_H_ */ diff --git a/linux/Changes b/linux/Changes new file mode 100644 index 0000000..7eafaab --- /dev/null +++ b/linux/Changes @@ -0,0 +1,130 @@ + This archive represents the file called 'ppp-2.2.0d.tar.gz' for + Linux only. + +The changes from 2.2.0c to 2.2.0d are: + +1. Change chat to recognize the ABORT strings if you specify a sub-string. + +2. Change the ppp.c file to prevent the symbol table compilation problems. + +3. Augment the IP list in the authentication to include a netmask option + and to permit a reject as well as the default accept entries. + +4. Flushed the tty input buffer prior to starting the connect program. + This prevents old modem responses from a previous session to be fed to + the current one. + +5. Integrated Paul Mackerras' fix for a bug in the CCP which causes + the bsd compression to constantly re-negotiate a smaller and smaller + code size. + +6. Added options to set the Predictor-1 compressor if so desired. Predictor-1 + is used by Morningstar's PPP package. + +7. Add support for Microsoft DNS parameters by Christoper Lameter. + +8. Support for the IPX protocol. It originated, and substantially resembles + since it started with, the work by G.Cambell@irl.cri.nz. Many thanks to + him for starting and getting the initial code to work. The IPX support + requires at least the 1.3.43 kernel. + +The changes from 2.2.0b to 2.2.0c are: + +1. Correct the reference in the ppp.c file for the definition of the + symbol table. This is used if you not using modules. + +There is still a compile/link problem with the a.out format. The problem +is not with ppp, but in the module.h header file. If you are using a.out +and have problems linking with an unresolved 'mod_use_count_' then use +the following patch on the /usr/include/linux/module.h header file. + +ELF does not have this problem. Only a.out will complain. + +--- module.h.orig Thu Oct 19 05:32:32 1995 ++++ module.h Thu Oct 19 05:33:44 1995 +@@ -90,12 +90,12 @@ + * define the count variable, and usage macros. + */ + +-extern long mod_use_count_; + #if defined(CONFIG_MODVERSIONS) && defined(MODULE) && !defined(__GENKSYMS__) + int Using_Versions; /* gcc will handle this global (used as a flag) correctly */ + #endif + + #ifdef MODULE ++extern long mod_use_count_; + #define MOD_INC_USE_COUNT mod_use_count_++ + #define MOD_DEC_USE_COUNT mod_use_count_-- + #define MOD_IN_USE (mod_use_count_ != 0) + + +The changes from 2.2.0a to 2.2.0b are: + +1. Correct a problem with the 1.3.33+ kernels in that they would cause + a SIGSEGV should you run the pppd program with the 'defaultroute' + option. + +2. Corrections in the ppp.c driver for non-module builds regarding the + symbol version informaiton. + +3. Removed bad definitions of the MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT + from ppp.c. + +4. Corrected the cleanup logic for the device. The test for ppp_alive + was the wrong sense. + +5. Corrected the references in chat scripts for "/usr/lib/ppp" to be + "/usr/sbin". + +The changes from 2.2.0 and 2.2.0a are: + +1. The code files have been moved to the /usr/sbin directory. This should + have been done in the 2.2.0 package but something happened and an old + Makefile was shipped in its place. + +2. The BSD compressor module, bsd_comp, will ONLY compile as a loadable + module. This was performed for a few technical reasons and one legal + reason. (The legal reason is in the README file here.) + +3. The test for the presence of ppp support has been moved to after the + decode of the options. It means that the test will no longer use /dev/tty + which may not be appropriate at that time. + +4. The pppstats program has been changed to work with the driver since the + driver will no longer attempt to do a floating point operation. This + previously would cause a kernel panic. + + ADDITIONAL INFORMATION + +1. This distribution requires either a kernel from the 1.2 series +which is at or later than 1.2.11 or a kernel from the 1.3 series which +is at or later 1.3.34. In short, you should use the latest version +from either release. The difficulties in supporting earlier versions +as they were being developed were too great. This means that the code +may or may not work. If it does not then when you ask the answer will +be the same; UPGRADE to the latest revision of the 1.2 or 1.3 kernels!! + +2. Please, please, read the README file in this directory __and__ the +README.linux file. Pay attention to the fact that you _must_ do the +command: + +make kernel + +This does not mean that you need to build the kernel, although you +will need to do this also, but you must do the command from the ppp +directory to make any appropriate patches. + +3. Do not be concerned should the 'make kernel' say that a file is +current and not need to be replaced. It only means that the kernel +already has the proper files. To be honest, it is the reason that +there is a 'make kernel' -- to cover this condition. I had too many +people put older drivers into the kernel because they followed the +wrong set of instructions. Now, for all versions, there is only one +set of instructions -- "do make kernel". + +[Ed.: After I wrote this, I received email from someone who had problems +which could not be addressed by the standard 'make kernel'. It will not +be able to make the proper changes if you have not applied the sequence +against an original then there is a version specific instruction in the +README.linux file.] + diff --git a/linux/bsd_comp.c b/linux/bsd_comp.c new file mode 100644 index 0000000..508db4f --- /dev/null +++ b/linux/bsd_comp.c @@ -0,0 +1,1201 @@ +/* Because this code is derived from the 4.3BSD compress source: + * + * Copyright (c) 1985, 1986 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * James A. Woods, derived from original work by Spencer Thomas + * and Joseph Orost. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This version is for use with contigious buffers on Linux-derived systems. + * + * ==FILEVERSION 5== + * + * NOTE TO MAINTAINERS: + * If you modify this file at all, increment the number above. + * bsd_comp.c is shipped with a PPP distribution as well as with + * the kernel; if everyone increases the FILEVERSION number above, + * then scripts can do the right thing when deciding whether to + * install a new bsd_comp.c file. Don't change the format of that + * line otherwise, so the installation script can recognize it. + * + * $Id: bsd_comp.c,v 1.2 1995/12/18 03:37:05 paulus Exp $ + */ + +#ifndef MODULE +#error This file must be compiled as a module. +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* to get the struct task_struct */ +#include /* used in new tty drivers */ +#include /* used in new tty drivers */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#ifdef NEW_SKBUFF +#include +#endif + +#include +#include +#include + +#undef PACKETPTR +#define PACKETPTR 1 +#include +#undef PACKETPTR + +/* + * PPP "BSD compress" compression + * The differences between this compression and the classic BSD LZW + * source are obvious from the requirement that the classic code worked + * with files while this handles arbitrarily long streams that + * are broken into packets. They are: + * + * When the code size expands, a block of junk is not emitted by + * the compressor and not expected by the decompressor. + * + * New codes are not necessarily assigned every time an old + * code is output by the compressor. This is because a packet + * end forces a code to be emitted, but does not imply that a + * new sequence has been seen. + * + * The compression ratio is checked at the first end of a packet + * after the appropriate gap. Besides simplifying and speeding + * things up, this makes it more likely that the transmitter + * and receiver will agree when the dictionary is cleared when + * compression is not going well. + */ + +/* + * Macros to extract protocol version and number of bits + * from the third byte of the BSD Compress CCP configuration option. + */ + +#define BSD_VERSION(x) ((x) >> 5) +#define BSD_NBITS(x) ((x) & 0x1F) + +#define BSD_CURRENT_VERSION 1 + +/* + * A dictionary for doing BSD compress. + */ + +struct bsd_dict { + union { /* hash value */ + unsigned long fcode; + struct { +#ifndef BIG_ENDIAN_BITFIELD /* Little endian order */ + unsigned short prefix; /* preceding code */ + unsigned char suffix; /* last character of new code */ + unsigned char pad; +#else /* Big endian order */ + unsigned char pad; + unsigned char suffix; /* last character of new code */ + unsigned short prefix; /* preceding code */ +#endif + } hs; + } f; + unsigned short codem1; /* output of hash table -1 */ + unsigned short cptr; /* map code to hash table entry */ +}; + +struct bsd_db { + int totlen; /* length of this structure */ + unsigned int hsize; /* size of the hash table */ + unsigned char hshift; /* used in hash function */ + unsigned char n_bits; /* current bits/code */ + unsigned char maxbits; /* maximum bits/code */ + unsigned char debug; /* non-zero if debug desired */ + unsigned char unit; /* ppp unit number */ + unsigned short seqno; /* sequence # of next packet */ + unsigned int mru; /* size of receive (decompress) bufr */ + unsigned int maxmaxcode; /* largest valid code */ + unsigned int max_ent; /* largest code in use */ + unsigned int in_count; /* uncompressed bytes, aged */ + unsigned int bytes_out; /* compressed bytes, aged */ + unsigned int ratio; /* recent compression ratio */ + unsigned int checkpoint; /* when to next check the ratio */ + unsigned int clear_count; /* times dictionary cleared */ + unsigned int incomp_count; /* incompressible packets */ + unsigned int incomp_bytes; /* incompressible bytes */ + unsigned int uncomp_count; /* uncompressed packets */ + unsigned int uncomp_bytes; /* uncompressed bytes */ + unsigned int comp_count; /* compressed packets */ + unsigned int comp_bytes; /* compressed bytes */ + unsigned short *lens; /* array of lengths of codes */ + struct bsd_dict *dict; /* dictionary */ +}; + +#define BSD_OVHD 2 /* BSD compress overhead/packet */ +#define MIN_BSD_BITS 9 +#define BSD_INIT_BITS MIN_BSD_BITS +#define MAX_BSD_BITS 15 + +static void bsd_free (void *state); +static void *bsd_alloc(unsigned char *options, int opt_len, int decomp); +static void *bsd_comp_alloc (unsigned char *options, int opt_len); +static void *bsd_decomp_alloc (unsigned char *options, int opt_len); + +static int bsd_init (void *db, unsigned char *options, + int opt_len, int unit, int debug, int decomp); +static int bsd_comp_init (void *state, unsigned char *options, + int opt_len, int unit, int opthdr, int debug); +static int bsd_decomp_init (void *state, unsigned char *options, + int opt_len, int unit, int opthdr, int mru, + int debug); + +static void bsd_reset (void *state); +static void bsd_comp_stats (void *state, struct compstat *stats); + +static int bsd_compress (void *state, unsigned char *rptr, + unsigned char *obuf, int isize, int osize); +static void bsd_incomp (void *state, unsigned char *ibuf, int icnt); + +static int bsd_decompress (void *state, unsigned char *ibuf, int isize, + unsigned char *obuf, int osize); + +/* These are in ppp.c */ +extern int ppp_register_compressor (struct compressor *cp); +extern void ppp_unregister_compressor (struct compressor *cp); + +/* + * the next two codes should not be changed lightly, as they must not + * lie within the contiguous general code space. + */ +#define CLEAR 256 /* table clear output code */ +#define FIRST 257 /* first free entry */ +#define LAST 255 + +#define MAXCODE(b) ((1 << (b)) - 1) +#define BADCODEM1 MAXCODE(MAX_BSD_BITS); + +#define BSD_HASH(prefix,suffix,hshift) ((((unsigned long)(suffix))<<(hshift)) \ + ^ (unsigned long)(prefix)) +#define BSD_KEY(prefix,suffix) ((((unsigned long)(suffix)) << 16) \ + + (unsigned long)(prefix)) + +#define CHECK_GAP 10000 /* Ratio check interval */ + +#define RATIO_SCALE_LOG 8 +#define RATIO_SCALE (1<>RATIO_SCALE_LOG) + +/* + * clear the dictionary + */ + +static void +bsd_clear(struct bsd_db *db) +{ + db->clear_count++; + db->max_ent = FIRST-1; + db->n_bits = BSD_INIT_BITS; + db->bytes_out = 0; + db->in_count = 0; + db->incomp_count = 0; + db->ratio = 0; + db->checkpoint = CHECK_GAP; +} + +/* + * If the dictionary is full, then see if it is time to reset it. + * + * Compute the compression ratio using fixed-point arithmetic + * with 8 fractional bits. + * + * Since we have an infinite stream instead of a single file, + * watch only the local compression ratio. + * + * Since both peers must reset the dictionary at the same time even in + * the absence of CLEAR codes (while packets are incompressible), they + * must compute the same ratio. + */ + +static int bsd_check (struct bsd_db *db) /* 1=output CLEAR */ + { + unsigned int new_ratio; + + if (db->in_count >= db->checkpoint) + { + /* age the ratio by limiting the size of the counts */ + if (db->in_count >= RATIO_MAX || db->bytes_out >= RATIO_MAX) + { + db->in_count -= (db->in_count >> 2); + db->bytes_out -= (db->bytes_out >> 2); + } + + db->checkpoint = db->in_count + CHECK_GAP; + + if (db->max_ent >= db->maxmaxcode) + { + /* Reset the dictionary only if the ratio is worse, + * or if it looks as if it has been poisoned + * by incompressible data. + * + * This does not overflow, because + * db->in_count <= RATIO_MAX. + */ + + new_ratio = db->in_count << RATIO_SCALE_LOG; + if (db->bytes_out != 0) + { + new_ratio /= db->bytes_out; + } + + if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE) + { + bsd_clear (db); + return 1; + } + db->ratio = new_ratio; + } + } + return 0; + } + +/* + * Return statistics. + */ + +static void bsd_comp_stats (void *state, struct compstat *stats) + { + struct bsd_db *db = (struct bsd_db *) state; + + stats->unc_bytes = db->uncomp_bytes; + stats->unc_packets = db->uncomp_count; + stats->comp_bytes = db->comp_bytes; + stats->comp_packets = db->comp_count; + stats->inc_bytes = db->incomp_bytes; + stats->inc_packets = db->incomp_count; + stats->in_count = db->in_count; + stats->bytes_out = db->bytes_out; + } + +/* + * Reset state, as on a CCP ResetReq. + */ + +static void bsd_reset (void *state) + { + struct bsd_db *db = (struct bsd_db *) state; + + bsd_clear(db); + + db->seqno = 0; + db->clear_count = 0; + } + +/* + * Release the compression structure + */ + +static void bsd_free (void *state) + { + struct bsd_db *db = (struct bsd_db *) state; + + if (db) + { +/* + * Release the dictionary + */ + if (db->dict) + { + vfree (db->dict); + db->dict = NULL; + } +/* + * Release the string buffer + */ + if (db->lens) + { + vfree (db->lens); + db->lens = NULL; + } +/* + * Finally release the structure itself. + */ + kfree (db); + MOD_DEC_USE_COUNT; + } + } + +/* + * Allocate space for a (de) compressor. + */ + +static void *bsd_alloc (unsigned char *options, int opt_len, int decomp) + { + int bits; + unsigned int hsize, hshift, maxmaxcode; + struct bsd_db *db; + + if (opt_len != 3 || options[0] != CI_BSD_COMPRESS || options[1] != 3 + || BSD_VERSION(options[2]) != BSD_CURRENT_VERSION) + { + return NULL; + } + + bits = BSD_NBITS(options[2]); + + switch (bits) + { + case 9: /* needs 82152 for both directions */ + case 10: /* needs 84144 */ + case 11: /* needs 88240 */ + case 12: /* needs 96432 */ + hsize = 5003; + hshift = 4; + break; + case 13: /* needs 176784 */ + hsize = 9001; + hshift = 5; + break; + case 14: /* needs 353744 */ + hsize = 18013; + hshift = 6; + break; + case 15: /* needs 691440 */ + hsize = 35023; + hshift = 7; + break; + case 16: /* needs 1366160--far too much, */ + /* hsize = 69001; */ /* and 69001 is too big for cptr */ + /* hshift = 8; */ /* in struct bsd_db */ + /* break; */ + default: + return NULL; + } +/* + * Allocate the main control structure for this instance. + */ + maxmaxcode = MAXCODE(bits); + db = (struct bsd_db *) kmalloc (sizeof (struct bsd_db), + GFP_KERNEL); + if (!db) + { + return NULL; + } + + memset (db, 0, sizeof(struct bsd_db)); +/* + * Allocate space for the dictionary. This may be more than one page in + * length. + */ + db->dict = (struct bsd_dict *) vmalloc (hsize * + sizeof (struct bsd_dict)); + if (!db->dict) + { + bsd_free (db); + return NULL; + } + + MOD_INC_USE_COUNT; +/* + * If this is the compression buffer then there is no length data. + */ + if (!decomp) + { + db->lens = NULL; + } +/* + * For decompression, the length information is needed as well. + */ + else + { + db->lens = (unsigned short *) vmalloc ((maxmaxcode + 1) * + sizeof (db->lens[0])); + if (!db->lens) + { + bsd_free (db); + return (NULL); + } + } +/* + * Initialize the data information for the compression code + */ + db->totlen = sizeof (struct bsd_db) + + (sizeof (struct bsd_dict) * hsize); + + db->hsize = hsize; + db->hshift = hshift; + db->maxmaxcode = maxmaxcode; + db->maxbits = bits; + + return (void *) db; + } + +static void *bsd_comp_alloc (unsigned char *options, int opt_len) + { + return bsd_alloc (options, opt_len, 0); + } + +static void *bsd_decomp_alloc (unsigned char *options, int opt_len) + { + return bsd_alloc (options, opt_len, 1); + } + +/* + * Initialize the database. + */ + +static int bsd_init (void *state, unsigned char *options, + int opt_len, int unit, int debug, int decomp) + { + struct bsd_db *db = state; + int indx; + + if ((opt_len != 3) || (options[0] != CI_BSD_COMPRESS) || (options[1] != 3) + || (BSD_VERSION(options[2]) != BSD_CURRENT_VERSION) + || (BSD_NBITS(options[2]) != db->maxbits) + || (decomp && db->lens == NULL)) + { + return 0; + } + + if (decomp) + { + indx = LAST; + do + { + db->lens[indx] = 1; + } + while (indx-- > 0); + } + + indx = db->hsize; + while (indx-- != 0) + { + db->dict[indx].codem1 = BADCODEM1; + db->dict[indx].cptr = 0; + } + + db->unit = unit; + db->mru = 0; +#ifndef DEBUG + if (debug) +#endif + db->debug = 1; + + bsd_reset(db); + + return 1; + } + +static int bsd_comp_init (void *state, unsigned char *options, + int opt_len, int unit, int opthdr, int debug) + { + return bsd_init (state, options, opt_len, unit, debug, 0); + } + +static int bsd_decomp_init (void *state, unsigned char *options, + int opt_len, int unit, int opthdr, int mru, + int debug) + { + return bsd_init (state, options, opt_len, unit, debug, 1); + } + +/* + * Obtain pointers to the various structures in the compression tables + */ + +#define dict_ptrx(p,idx) &(p->dict[idx]) +#define lens_ptrx(p,idx) &(p->lens[idx]) + +#ifdef DEBUG +static unsigned short *lens_ptr(struct bsd_db *db, int idx) + { + if ((unsigned int) idx > (unsigned int) db->maxmaxcode) + { + printk ("<9>ppp: lens_ptr(%d) > max\n", idx); + idx = 0; + } + return lens_ptrx (db, idx); + } + +static struct bsd_dict *dict_ptr(struct bsd_db *db, int idx) + { + if ((unsigned int) idx >= (unsigned int) db->hsize) + { + printk ("<9>ppp: dict_ptr(%d) > max\n", idx); + idx = 0; + } + return dict_ptrx (db, idx); + } + +#else +#define lens_ptr(db,idx) lens_ptrx(db,idx) +#define dict_ptr(db,idx) dict_ptrx(db,idx) +#endif + +/* + * compress a packet + * + * The result of this function is the size of the compressed + * packet. A zero is returned if the packet was not compressed + * for some reason, such as the size being larger than uncompressed. + * + * One change from the BSD compress command is that when the + * code size expands, we do not output a bunch of padding. + */ + +static int bsd_compress (void *state, unsigned char *rptr, unsigned char *obuf, + int isize, int osize) + { + struct bsd_db *db; + int hshift; + unsigned int max_ent; + unsigned int n_bits; + unsigned int bitno; + unsigned long accm; + int ent; + unsigned long fcode; + struct bsd_dict *dictp; + unsigned char c; + int hval; + int disp; + int ilen; + int mxcode; + unsigned char *wptr; + int olen; + +#define PUTBYTE(v) \ + { \ + ++olen; \ + if (wptr) \ + { \ + *wptr++ = (unsigned char) (v); \ + if (olen >= osize) \ + { \ + wptr = NULL; \ + } \ + } \ + } + +#define OUTPUT(ent) \ + { \ + bitno -= n_bits; \ + accm |= ((ent) << bitno); \ + do \ + { \ + PUTBYTE(accm >> 24); \ + accm <<= 8; \ + bitno += 8; \ + } \ + while (bitno <= 24); \ + } + + /* + * If the protocol is not in the range we're interested in, + * just return without compressing the packet. If it is, + * the protocol becomes the first byte to compress. + */ + + ent = PPP_PROTOCOL(rptr); + if (ent < 0x21 || ent > 0xf9) + { + return 0; + } + + db = (struct bsd_db *) state; + hshift = db->hshift; + max_ent = db->max_ent; + n_bits = db->n_bits; + bitno = 32; + accm = 0; + mxcode = MAXCODE (n_bits); + + /* Initialize the output pointers */ + wptr = obuf; + olen = PPP_HDRLEN + BSD_OVHD; + + if (osize > isize) + { + osize = isize; + } + + /* This is the PPP header information */ + if (wptr) + { + *wptr++ = PPP_ADDRESS(rptr); + *wptr++ = PPP_CONTROL(rptr); + *wptr++ = 0; + *wptr++ = PPP_COMP; + *wptr++ = db->seqno >> 8; + *wptr++ = db->seqno; + } + + /* Skip the input header */ + rptr += PPP_HDRLEN; + isize -= PPP_HDRLEN; + ilen = ++isize; /* This is off by one, but that is what is in draft! */ + + while (--ilen > 0) + { + c = *rptr++; + fcode = BSD_KEY (ent, c); + hval = BSD_HASH (ent, c, hshift); + dictp = dict_ptr (db, hval); + + /* Validate and then check the entry. */ + if (dictp->codem1 >= max_ent) + { + goto nomatch; + } + + if (dictp->f.fcode == fcode) + { + ent = dictp->codem1 + 1; + continue; /* found (prefix,suffix) */ + } + + /* continue probing until a match or invalid entry */ + disp = (hval == 0) ? 1 : hval; + + do + { + hval += disp; + if (hval >= db->hsize) + { + hval -= db->hsize; + } + dictp = dict_ptr (db, hval); + if (dictp->codem1 >= max_ent) + { + goto nomatch; + } + } + while (dictp->f.fcode != fcode); + + ent = dictp->codem1 + 1; /* finally found (prefix,suffix) */ + continue; + +nomatch: + OUTPUT(ent); /* output the prefix */ + + /* code -> hashtable */ + if (max_ent < db->maxmaxcode) + { + struct bsd_dict *dictp2; + struct bsd_dict *dictp3; + int indx; + + /* expand code size if needed */ + if (max_ent >= mxcode) + { + db->n_bits = ++n_bits; + mxcode = MAXCODE (n_bits); + } + + /* Invalidate old hash table entry using + * this code, and then take it over. + */ + + dictp2 = dict_ptr (db, max_ent + 1); + indx = dictp2->cptr; + dictp3 = dict_ptr (db, indx); + + if (dictp3->codem1 == max_ent) + { + dictp3->codem1 = BADCODEM1; + } + + dictp2->cptr = hval; + dictp->codem1 = max_ent; + dictp->f.fcode = fcode; + db->max_ent = ++max_ent; + + if (db->lens) + { + unsigned short *len1 = lens_ptr (db, max_ent); + unsigned short *len2 = lens_ptr (db, ent); + *len1 = *len2 + 1; + } + } + ent = c; + } + + OUTPUT(ent); /* output the last code */ + + db->bytes_out += olen; /* Do not count bytes from here */ + db->uncomp_bytes += isize; + db->in_count += isize; + ++db->uncomp_count; + ++db->seqno; + + if (bitno < 32) + { + ++db->bytes_out; /* must be set before calling bsd_check */ + } + + /* + * Generate the clear command if needed + */ + + if (bsd_check(db)) + { + OUTPUT (CLEAR); + } + + /* + * Pad dribble bits of last code with ones. + * Do not emit a completely useless byte of ones. + */ + + if (bitno != 32) + { + PUTBYTE((accm | (0xff << (bitno-8))) >> 24); + } + + /* + * Increase code size if we would have without the packet + * boundary because the decompressor will do so. + */ + + if (max_ent >= mxcode && max_ent < db->maxmaxcode) + { + db->n_bits++; + } + + /* If output length is too large then this is an incomplete frame. */ + if (wptr == NULL) + { + ++db->incomp_count; + db->incomp_bytes += isize; + olen = 0; + } + else /* Count the number of compressed frames */ + { + ++db->comp_count; + db->comp_bytes += olen; + } + + /* Return the resulting output length */ + return olen; +#undef OUTPUT +#undef PUTBYTE + } + +/* + * Update the "BSD Compress" dictionary on the receiver for + * incompressible data by pretending to compress the incoming data. + */ + +static void bsd_incomp (void *state, unsigned char *ibuf, int icnt) + { + (void) bsd_compress (state, ibuf, (char *) 0, icnt, 0); + } + +/* + * Decompress "BSD Compress". + * + * Because of patent problems, we return DECOMP_ERROR for errors + * found by inspecting the input data and for system problems, but + * DECOMP_FATALERROR for any errors which could possibly be said to + * be being detected "after" decompression. For DECOMP_ERROR, + * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be + * infringing a patent of Motorola's if we do, so we take CCP down + * instead. + * + * Given that the frame has the correct sequence number and a good FCS, + * errors such as invalid codes in the input most likely indicate a + * bug, so we return DECOMP_FATALERROR for them in order to turn off + * compression, even though they are detected by inspecting the input. + */ + +static int bsd_decompress (void *state, unsigned char *ibuf, int isize, + unsigned char *obuf, int osize) + { + struct bsd_db *db; + unsigned int max_ent; + unsigned long accm; + unsigned int bitno; /* 1st valid bit in accm */ + unsigned int n_bits; + unsigned int tgtbitno; /* bitno when we have a code */ + struct bsd_dict *dictp; + int explen; + int seq; + unsigned int incode; + unsigned int oldcode; + unsigned int finchar; + unsigned char *p; + unsigned char *wptr; + int adrs; + int ctrl; + int ilen; + int codelen; + int extra; + + db = (struct bsd_db *) state; + max_ent = db->max_ent; + accm = 0; + bitno = 32; /* 1st valid bit in accm */ + n_bits = db->n_bits; + tgtbitno = 32 - n_bits; /* bitno when we have a code */ + + /* + * Save the address/control from the PPP header + * and then get the sequence number. + */ + + adrs = PPP_ADDRESS (ibuf); + ctrl = PPP_CONTROL (ibuf); + + seq = (ibuf[4] << 8) + ibuf[5]; + + ibuf += (PPP_HDRLEN + 2); + ilen = isize - (PPP_HDRLEN + 2); + + /* + * Check the sequence number and give up if it differs from + * the value we're expecting. + */ + + if (seq != db->seqno) + { + if (db->debug) + { + printk("bsd_decomp%d: bad sequence # %d, expected %d\n", + db->unit, seq, db->seqno - 1); + } + return DECOMP_ERROR; + } + + ++db->seqno; + db->bytes_out += ilen; + + /* + * Fill in the ppp header, but not the last byte of the protocol + * (that comes from the decompressed data). + */ + + wptr = obuf; + *wptr++ = adrs; + *wptr++ = ctrl; + *wptr++ = 0; + + oldcode = CLEAR; + explen = 3; + + /* + * Keep the checkpoint correctly so that incompressible packets + * clear the dictionary at the proper times. + */ + + for (;;) + { + if (ilen-- <= 0) + { + db->in_count += (explen - 3); /* don't count the header */ + break; + } + + /* + * Accumulate bytes until we have a complete code. + * Then get the next code, relying on the 32-bit, + * unsigned accm to mask the result. + */ + + bitno -= 8; + accm |= *ibuf++ << bitno; + if (tgtbitno < bitno) + { + continue; + } + + incode = accm >> tgtbitno; + accm <<= n_bits; + bitno += n_bits; + + /* + * The dictionary must only be cleared at the end of a packet. + */ + + if (incode == CLEAR) + { + if (ilen > 0) + { + if (db->debug) + { + printk("bsd_decomp%d: bad CLEAR\n", db->unit); + } + return DECOMP_FATALERROR; /* probably a bug */ + } + + bsd_clear(db); + break; + } + + if ((incode > max_ent + 2) || (incode > db->maxmaxcode) + || (incode > max_ent && oldcode == CLEAR)) + { + if (db->debug) + { + printk("bsd_decomp%d: bad code 0x%x oldcode=0x%x ", + db->unit, incode, oldcode); + printk("max_ent=0x%x explen=%d seqno=%d\n", + max_ent, explen, db->seqno); + } + return DECOMP_FATALERROR; /* probably a bug */ + } + + /* Special case for KwKwK string. */ + if (incode > max_ent) + { + finchar = oldcode; + extra = 1; + } + else + { + finchar = incode; + extra = 0; + } + + codelen = *(lens_ptr (db, finchar)); + explen += codelen + extra; + if (explen > osize) + { + if (db->debug) + { + printk("bsd_decomp%d: ran out of mru\n", db->unit); +#ifdef DEBUG + printk(" len=%d, finchar=0x%x, codelen=%d, explen=%d\n", + ilen, finchar, codelen, explen); +#endif + } + return DECOMP_FATALERROR; + } + + /* + * Decode this code and install it in the decompressed buffer. + */ + + wptr += codelen; + p = wptr; + while (finchar > LAST) + { + struct bsd_dict *dictp2 = dict_ptr (db, finchar); + + dictp = dict_ptr (db, dictp2->cptr); +#ifdef DEBUG + if (--codelen <= 0 || dictp->codem1 != finchar-1) + { + if (codelen <= 0) + { + printk("bsd_decomp%d: fell off end of chain ", db->unit); + printk("0x%x at 0x%x by 0x%x, max_ent=0x%x\n", + incode, finchar, dictp2->cptr, max_ent); + } + else + { + if (dictp->codem1 != finchar-1) + { + printk("bsd_decomp%d: bad code chain 0x%x " + "finchar=0x%x ", + db->unit, incode, finchar); + + printk("oldcode=0x%x cptr=0x%x codem1=0x%x\n", + oldcode, dictp2->cptr, dictp->codem1); + } + } + return DECOMP_FATALERROR; + } +#endif + *--p = dictp->f.hs.suffix; + finchar = dictp->f.hs.prefix; + } + *--p = finchar; + +#ifdef DEBUG + if (--codelen != 0) + { + printk("bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n", + db->unit, codelen, incode, max_ent); + } +#endif + + if (extra) /* the KwKwK case again */ + { + *wptr++ = finchar; + } + + /* + * If not first code in a packet, and + * if not out of code space, then allocate a new code. + * + * Keep the hash table correct so it can be used + * with uncompressed packets. + */ + + if (oldcode != CLEAR && max_ent < db->maxmaxcode) + { + struct bsd_dict *dictp2, *dictp3; + unsigned short *lens1, *lens2; + unsigned long fcode; + int hval, disp, indx; + + fcode = BSD_KEY(oldcode,finchar); + hval = BSD_HASH(oldcode,finchar,db->hshift); + dictp = dict_ptr (db, hval); + + /* look for a free hash table entry */ + if (dictp->codem1 < max_ent) + { + disp = (hval == 0) ? 1 : hval; + do + { + hval += disp; + if (hval >= db->hsize) + { + hval -= db->hsize; + } + dictp = dict_ptr (db, hval); + } + while (dictp->codem1 < max_ent); + } + + /* + * Invalidate previous hash table entry + * assigned this code, and then take it over + */ + + dictp2 = dict_ptr (db, max_ent + 1); + indx = dictp2->cptr; + dictp3 = dict_ptr (db, indx); + + if (dictp3->codem1 == max_ent) + { + dictp3->codem1 = BADCODEM1; + } + + dictp2->cptr = hval; + dictp->codem1 = max_ent; + dictp->f.fcode = fcode; + db->max_ent = ++max_ent; + + /* Update the length of this string. */ + lens1 = lens_ptr (db, max_ent); + lens2 = lens_ptr (db, oldcode); + *lens1 = *lens2 + 1; + + /* Expand code size if needed. */ + if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) + { + db->n_bits = ++n_bits; + tgtbitno = 32-n_bits; + } + } + oldcode = incode; + } + + ++db->comp_count; + ++db->uncomp_count; + db->comp_bytes += isize - BSD_OVHD - PPP_HDRLEN; + db->uncomp_bytes += explen; + + if (bsd_check(db)) + { + if (db->debug) + { + printk("bsd_decomp%d: peer should have cleared dictionary on %d\n", + db->unit, db->seqno - 1); + } + } + return explen; + } + +/************************************************************* + * Table of addresses for the BSD compression module + *************************************************************/ + +static struct compressor ppp_bsd_compress = { + CI_BSD_COMPRESS, /* compress_proto */ + bsd_comp_alloc, /* comp_alloc */ + bsd_free, /* comp_free */ + bsd_comp_init, /* comp_init */ + bsd_reset, /* comp_reset */ + bsd_compress, /* compress */ + bsd_comp_stats, /* comp_stat */ + bsd_decomp_alloc, /* decomp_alloc */ + bsd_free, /* decomp_free */ + bsd_decomp_init, /* decomp_init */ + bsd_reset, /* decomp_reset */ + bsd_decompress, /* decompress */ + bsd_incomp, /* incomp */ + bsd_comp_stats /* decomp_stat */ +}; + +/************************************************************* + * Module support routines + *************************************************************/ + +int +init_module(void) +{ + int answer = ppp_register_compressor (&ppp_bsd_compress); + if (answer == 0) + printk (KERN_INFO "PPP BSD Compression module registered\n"); + return answer; +} + +void +cleanup_module(void) +{ + ppp_unregister_compressor (&ppp_bsd_compress); +} diff --git a/linux/if.h b/linux/if.h new file mode 100644 index 0000000..222d93f --- /dev/null +++ b/linux/if.h @@ -0,0 +1,151 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Global definitions for the INET interface module. + * + * Version: @(#)if.h 1.0.2 04/18/93 + * + * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1982-1988 + * Ross Biro, + * Fred N. van Kempen, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _LINUX_IF_H +#define _LINUX_IF_H + +#include /* for "caddr_t" et al */ +#include /* for "struct sockaddr" et al */ + +/* Standard interface flags. */ +#define IFF_UP 0x1 /* interface is up */ +#define IFF_BROADCAST 0x2 /* broadcast address valid */ +#define IFF_DEBUG 0x4 /* turn on debugging */ +#define IFF_LOOPBACK 0x8 /* is a loopback net */ +#define IFF_POINTOPOINT 0x10 /* interface is has p-p link */ +#define IFF_NOTRAILERS 0x20 /* avoid use of trailers */ +#define IFF_RUNNING 0x40 /* resources allocated */ +#define IFF_NOARP 0x80 /* no ARP protocol */ +#define IFF_PROMISC 0x100 /* receive all packets */ +/* Not supported */ +#define IFF_ALLMULTI 0x200 /* receive all multicast packets*/ + +#define IFF_MASTER 0x400 /* master of a load balancer */ +#define IFF_SLAVE 0x800 /* slave of a load balancer */ + +#define IFF_MULTICAST 0x1000 /* Supports multicast */ + +/* + * The ifaddr structure contains information about one address + * of an interface. They are maintained by the different address + * families, are allocated and attached when an address is set, + * and are linked together so all addresses for an interface can + * be located. + */ + +struct ifaddr +{ + struct sockaddr ifa_addr; /* address of interface */ + union { + struct sockaddr ifu_broadaddr; + struct sockaddr ifu_dstaddr; + } ifa_ifu; + struct iface *ifa_ifp; /* back-pointer to interface */ + struct ifaddr *ifa_next; /* next address for interface */ +}; + +#define ifa_broadaddr ifa_ifu.ifu_broadaddr /* broadcast address */ +#define ifa_dstaddr ifa_ifu.ifu_dstaddr /* other end of link */ + +/* + * Device mapping structure. I'd just gone off and designed a + * beautiful scheme using only loadable modules with arguments + * for driver options and along come the PCMCIA people 8) + * + * Ah well. The get() side of this is good for WDSETUP, and it'll + * be handy for debugging things. The set side is fine for now and + * being very small might be worth keeping for clean configuration. + */ + +struct ifmap +{ + unsigned long mem_start; + unsigned long mem_end; + unsigned short base_addr; + unsigned char irq; + unsigned char dma; + unsigned char port; + /* 3 bytes spare */ +}; + +/* + * Interface request structure used for socket + * ioctl's. All interface ioctl's must have parameter + * definitions which begin with ifr_name. The + * remainder may be interface specific. + */ + +struct ifreq +{ +#define IFHWADDRLEN 6 +#define IFNAMSIZ 16 + union + { + char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + char ifrn_hwaddr[IFHWADDRLEN]; /* Obsolete */ + } ifr_ifrn; + + union { + struct sockaddr ifru_addr; + struct sockaddr ifru_dstaddr; + struct sockaddr ifru_broadaddr; + struct sockaddr ifru_netmask; + struct sockaddr ifru_hwaddr; + short ifru_flags; + int ifru_metric; + int ifru_mtu; + struct ifmap ifru_map; + char ifru_slave[IFNAMSIZ]; /* Just fits the size */ + caddr_t ifru_data; + } ifr_ifru; +}; + +#define ifr_name ifr_ifrn.ifrn_name /* interface name */ +#define old_ifr_hwaddr ifr_ifrn.ifrn_hwaddr /* interface hardware */ +#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */ +#define ifr_addr ifr_ifru.ifru_addr /* address */ +#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */ +#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ +#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */ +#define ifr_flags ifr_ifru.ifru_flags /* flags */ +#define ifr_metric ifr_ifru.ifru_metric /* metric */ +#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */ +#define ifr_map ifr_ifru.ifru_map /* device map */ +#define ifr_slave ifr_ifru.ifru_slave /* slave device */ +#define ifr_data ifr_ifru.ifru_data /* for use by interface */ + +/* + * Structure used in SIOCGIFCONF request. + * Used to retrieve interface configuration + * for machine (useful for programs which + * must know all networks accessible). + */ + +struct ifconf +{ + int ifc_len; /* size of buffer */ + union + { + caddr_t ifcu_buf; + struct ifreq *ifcu_req; + } ifc_ifcu; +}; +#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ +#define ifc_req ifc_ifcu.ifcu_req /* array of structures */ + +#endif /* _LINUX_IF_H */ diff --git a/linux/if_arp.h b/linux/if_arp.h new file mode 100644 index 0000000..34e4c78 --- /dev/null +++ b/linux/if_arp.h @@ -0,0 +1,102 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Global definitions for the ARP (RFC 826) protocol. + * + * Version: @(#)if_arp.h 1.0.1 04/16/93 + * + * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988 + * Portions taken from the KA9Q/NOS (v2.00m PA0GRI) source. + * Ross Biro, + * Fred N. van Kempen, + * Florian La Roche. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _LINUX_IF_ARP_H +#define _LINUX_IF_ARP_H + +/* ARP protocol HARDWARE identifiers. */ +#define ARPHRD_NETROM 0 /* from KA9Q: NET/ROM pseudo */ +#define ARPHRD_ETHER 1 /* Ethernet 10Mbps */ +#define ARPHRD_EETHER 2 /* Experimental Ethernet */ +#define ARPHRD_AX25 3 /* AX.25 Level 2 */ +#define ARPHRD_PRONET 4 /* PROnet token ring */ +#define ARPHRD_CHAOS 5 /* Chaosnet */ +#define ARPHRD_IEEE802 6 /* IEEE 802.2 Ethernet/TR/TB */ +#define ARPHRD_ARCNET 7 /* ARCnet */ +#define ARPHRD_APPLETLK 8 /* APPLEtalk */ +/* Dummy types for non ARP hardware */ +#define ARPHRD_SLIP 256 +#define ARPHRD_CSLIP 257 +#define ARPHRD_SLIP6 258 +#define ARPHRD_CSLIP6 259 +#define ARPHRD_RSRVD 260 /* Notional KISS type */ +#define ARPHRD_ADAPT 264 +#define ARPHRD_PPP 512 +#define ARPHRD_TUNNEL 768 /* IPIP tunnel */ +#define ARPHRD_TUNNEL6 769 /* IPIP6 tunnel */ +#define ARPHRD_FRAD 770 /* Frame Relay */ +#define ARPHRD_SKIP 771 /* SKIP vif */ + +/* ARP protocol opcodes. */ +#define ARPOP_REQUEST 1 /* ARP request */ +#define ARPOP_REPLY 2 /* ARP reply */ +#define ARPOP_RREQUEST 3 /* RARP request */ +#define ARPOP_RREPLY 4 /* RARP reply */ + + +/* ARP ioctl request. */ +struct arpreq { + struct sockaddr arp_pa; /* protocol address */ + struct sockaddr arp_ha; /* hardware address */ + int arp_flags; /* flags */ + struct sockaddr arp_netmask; /* netmask (only for proxy arps) */ + char arp_dev[16]; +}; + +struct arpreq_old { + struct sockaddr arp_pa; /* protocol address */ + struct sockaddr arp_ha; /* hardware address */ + int arp_flags; /* flags */ + struct sockaddr arp_netmask; /* netmask (only for proxy arps) */ +}; + +/* ARP Flag values. */ +#define ATF_COM 0x02 /* completed entry (ha valid) */ +#define ATF_PERM 0x04 /* permanent entry */ +#define ATF_PUBL 0x08 /* publish entry */ +#define ATF_USETRAILERS 0x10 /* has requested trailers */ +#define ATF_NETMASK 0x20 /* want to use a netmask (only + for proxy entries) */ + +/* + * This structure defines an ethernet arp header. + */ + +struct arphdr +{ + unsigned short ar_hrd; /* format of hardware address */ + unsigned short ar_pro; /* format of protocol address */ + unsigned char ar_hln; /* length of hardware address */ + unsigned char ar_pln; /* length of protocol address */ + unsigned short ar_op; /* ARP opcode (command) */ + +#if 0 + /* + * Ethernet looks like this : This bit is variable sized however... + */ + unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ + unsigned char ar_sip[4]; /* sender IP address */ + unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ + unsigned char ar_tip[4]; /* target IP address */ +#endif + +}; + +#endif /* _LINUX_IF_ARP_H */ diff --git a/linux/if_ppp.h b/linux/if_ppp.h index ebf3ea3..5f21d94 100644 --- a/linux/if_ppp.h +++ b/linux/if_ppp.h @@ -1,4 +1,4 @@ -/* $Id: if_ppp.h,v 1.3 1995/06/12 11:36:50 paulus Exp $ */ +/* $Id: if_ppp.h,v 1.4 1995/12/18 03:38:01 paulus Exp $ */ /* * if_ppp.h - Point-to-Point Protocol definitions. @@ -21,13 +21,13 @@ */ /* - * ==PPPVERSION 2.1.3== + * ==FILEVERSION 6== * * NOTE TO MAINTAINERS: - * If you modify this file at all, increment the last number above. - * ppp.c is shipped with a PPP distribution as well as with the kernel; - * if everyone increases the PPPVERSION number above, then scripts - * can do the right thing when deciding whether to install a new ppp.c + * If you modify this file at all, increment the number above. + * if_ppp.h is shipped with a PPP distribution as well as with the kernel; + * if everyone increases the FILEVERSION number above, then scripts + * can do the right thing when deciding whether to install a new if_ppp.h * file. Don't change the format of that line otherwise, so the * installation script can recognize it. */ @@ -35,6 +35,12 @@ #ifndef _IF_PPP_H_ #define _IF_PPP_H_ +#if defined(__linux__) +#include +#include +#include +#endif + /* * Packet sizes */ @@ -44,6 +50,8 @@ #define PPP_VERSION "2.2.0" #define PPP_MAGIC 0x5002 /* Magic value for the ppp structure */ #define PROTO_IPX 0x002b /* protocol numbers */ +#define PROTO_DNA_RT 0x0027 /* DNA Routing */ + /* * Bit definitions for flags. @@ -96,11 +104,18 @@ struct ppp_option_data { }; struct ifpppstatsreq { - char ifr__name[IFNAMSIZ]; /* Name of the device */ - struct ppp_stats *stats_ptr; /* Pointer to stats buffer */ - struct ppp_stats stats; /* statistic information */ + struct ifreq b; + struct ppp_stats stats; /* statistic information */ }; +struct ifpppcstatsreq { + struct ifreq b; + struct ppp_comp_stats stats; +}; + +#define ifr__name b.ifr_ifrn.ifrn_name +#define stats_ptr b.ifr_ifru.ifru_data + /* * Ioctl definitions. */ @@ -121,13 +136,13 @@ struct ifpppstatsreq { #define PPPIOCSCOMPRESS _IOW('t', 77, struct ppp_option_data) #define PPPIOCGNPMODE _IOWR('t', 76, struct npioctl) /* get NP mode */ #define PPPIOCSNPMODE _IOW('t', 75, struct npioctl) /* set NP mode */ - #define PPPIOCGDEBUG _IOR('t', 65, int) /* Read debug level */ #define PPPIOCSDEBUG _IOW('t', 64, int) /* Set debug level */ -#define PPPIOCGTIME _IOR('t', 63, struct ppp_ddinfo) /* Read time info */ +#define PPPIOCGIDLE _IOR('t', 63, struct ppp_idle) /* get idle time */ #define SIOCGPPPSTATS (SIOCDEVPRIVATE + 0) -#define SIOCGPPPVER (SIOCDEVPRIVATE + 1) +#define SIOCGPPPVER (SIOCDEVPRIVATE + 1) /* NEVER change this!! */ +#define SIOCGPPPCSTATS (SIOCDEVPRIVATE + 2) #if !defined(ifr_mtu) #define ifr_mtu ifr_ifru.ifru_metric diff --git a/linux/if_pppvar.h b/linux/if_pppvar.h index 89be343..8d3dfc3 100644 --- a/linux/if_pppvar.h +++ b/linux/if_pppvar.h @@ -1,4 +1,4 @@ -/* $Id: if_pppvar.h,v 1.2 1995/06/12 11:36:51 paulus Exp $ */ +/* $Id: if_pppvar.h,v 1.3 1995/12/18 03:38:02 paulus Exp $ */ /* * if_pppvar.h - private structures and declarations for PPP. * @@ -42,13 +42,13 @@ */ /* - * ==PPPVERSION 2.1.3== + * ==FILEVERSION 4== * * NOTE TO MAINTAINERS: - * If you modify this file at all, increment the last number above. - * ppp.c is shipped with a PPP distribution as well as with the kernel; - * if everyone increases the PPPVERSION number above, then scripts - * can do the right thing when deciding whether to install a new ppp.c + * If you modify this file at all, increment the number above. + * if_pppvar.h is shipped with a PPP distribution as well as with the kernel; + * if everyone increases the FILEVERSION number above, then scripts + * can do the right thing when deciding whether to install a new if_pppvar.h * file. Don't change the format of that line otherwise, so the * installation script can recognize it. */ @@ -65,19 +65,21 @@ * Buffers for the PPP process have the following structure */ -#define RBUFSIZE 2048 /* MUST be a power of 2 and be <= 4095 */ +#define RBUFSIZE 2048 /* MUST be a power of 2 and be <= 4095 */ + struct ppp_buffer { int size; /* Size of the buffer area */ int count; /* Count of characters in bufr */ int head; /* index to head of list */ int tail; /* index to tail of list */ - int locked; /* Buffer is being sent */ + unsigned long locked; /* Buffer is being sent */ int type; /* Type of the buffer */ /* =0, device read buffer */ /* =1, device write buffer */ /* =2, daemon write buffer */ /* =3, daemon read buffer */ unsigned short fcs; /* Frame Check Sequence (CRC) */ + unsigned char filler[4]; /* Extra space if needed */ }; /* Given a pointer to the ppp_buffer then return base address of buffer */ @@ -100,7 +102,7 @@ struct ppp { ext_accm xmit_async_map; /* 1 bit means that given control character is quoted on output*/ - unsigned long recv_async_map; /* 1 bit means that given control + __u32 recv_async_map; /* 1 bit means that given control character is ignored on input*/ int mtu; /* maximum xmit frame size */ int mru; /* maximum receive frame size */ @@ -122,7 +124,7 @@ struct ppp { struct ppp_buffer *s1buf; /* Pointer to daemon buffer */ struct ppp_buffer *s2buf; /* Pointer to device buffer */ - unsigned long last_xmit; /* time of last transmission */ + __u32 last_xmit; /* time of last transmission */ /* These are pointers to the malloc()ed frame buffers. These buffers are used while processing a packet. If a packet @@ -140,8 +142,8 @@ struct ppp { struct wait_queue *read_wait; /* queue for writing processes */ /* Statistic information */ - struct pppstat stats; /* statistic information */ - struct ppp_ddinfo ddinfo; /* demand dial information */ + struct pppstat stats; /* statistic information */ + struct ppp_idle ddinfo; /* demand dial information */ /* PPP compression protocol information */ u_int sc_bytessent; /* count of octets sent */ diff --git a/linux/kinstall.sh b/linux/kinstall.sh new file mode 100755 index 0000000..06ea13b --- /dev/null +++ b/linux/kinstall.sh @@ -0,0 +1,270 @@ +#!/bin/sh +# +# kinstall.sh -- install updated kernel PPP driver in Linux kernel source +# Michael Callahan callahan@maths.ox.ac.uk 17 May 1995 +# +# This script is complicated because we want to avoid installing a driver +# in a kernel if it won't work in that kernel. This means two things: +# 1) we check the version of the kernel and refuse to install if the +# kernel is too old; +# 2) we check that the files already in the kernel aren't more recent +# than the one we're about to install. +# If either 1) or 2) occurs then we exit with an error message and don't +# touch anything. +# +# In addition, we have to edit the Makefile in the drivers/net +# directory to add support for the ppp-comp compression option. +# +# Finally, we have to check that certain include file stubs in +# /usr/include/net exist, or else pppd won't compile. Phew! + +LINUXSRC=/usr/src/linux + +if [ $# -gt 1 ]; then + echo usage: $0 [linux-source-directory] + exit 1 +fi + +if [ $# -eq 1 ]; then + LINUXSRC=$1 +fi + +# +# Make sure we can find the kernel source + +LINUXMK=$LINUXSRC/Makefile + +if [ ! -r $LINUXMK -o ! -d $LINUXSRC/drivers ]; then + echo There appears to be no kernel source distribution in $LINUXSRC. + echo Give the top-level kernel source directory as the argument to + echo this script. + echo usage: $0 [linux-source-directory] + exit 1 +fi + +# +# Check that the kernel source Makefile includes the +# VERSION, PATCHLEVEL, SUBLEVEL version-numbering scheme +# introduced in 1.0.1 +if [ `egrep '^VERSION|^PATCHLEVEL|^SUBLEVEL' $LINUXMK | wc -l` -ne 3 ]; then + echo You appear to have a very old kernel. You must upgrade. + echo It is recommended that you upgrade to the most recent 1.2.X kernel. + exit 1 +fi + +# +# Set the VERSION, PATCHLEVEL, SUBLEVEL variables +VERSION=`egrep '^VERSION' $LINUXMK | sed 's/[^0-9]//g'` +PATCHLEVEL=`egrep '^PATCHLEVEL' $LINUXMK | sed 's/[^0-9]//g'` +SUBLEVEL=`egrep '^SUBLEVEL' $LINUXMK | sed 's/[^0-9]//g'` + +KERNEL=$VERSION.$PATCHLEVEL.$SUBLEVEL + +# +# Pass judgement on the kernel version +if [ $VERSION -eq 1 ]; then + if [ $PATCHLEVEL -eq 0 -o $PATCHLEVEL -eq 1 -a $SUBLEVEL -lt 14 ]; then + echo You appear to be running $KERNEL. There is no support for + echo kernels predating 1.1.14. It is recommended that you upgrade + echo to the most recent 1.2.X kernel. + exit 1 + fi + if [ $PATCHLEVEL -eq 1 ]; then + echo You appear to be running $KERNEL. It is recommended that you + echo upgrade to the most recent 1.2.X kernel. + echo However, installation will proceed. + fi +fi + +echo +echo Installing into kernel version $KERNEL in $LINUXSRC +echo + +# +# convenience function to exit if the last command failed + +function bombiffailed () { + STATUS=$? + if [ $STATUS -ne 0 ]; then + echo "=== kinstall.sh exiting with failure status $STATUS" + exit $STATUS + fi +} + +# +# convenience function to compare two files marked with ==FILEVERSION +# version numbers; returns success if $1 is newer than $2 + +function newer () { + if [ -r $1 ] && f1rev=`fgrep "==FILEVERSION " $1 | sed 's/[^0-9]//g'`; then + if [ -r $2 ] && f2rev=`fgrep "==FILEVERSION " $2 | sed 's/[^0-9]//g'`; then + if [ "$f1rev" != "" ]; then + # return true if f2rev is empty or f1rev => f2rev + [ "$f2rev" = "" ] || [ $f1rev -ge $f2rev ] + else + # f1rev is empty, so false + false + fi + else + true # no FILEVERSION in $2, so $1 is newer + fi + else + false # no FILEVERSION in $1, so not newer + fi +} + +# +# Change the USE_SKB_PROTOCOL for correct operation on 1.3.x +function update_ppp () { + mv $LINUXSRC/drivers/net/ppp.c $LINUXSRC/drivers/net/ppp.c.in + if [ "$VERSION.$PATCHLEVEL" = "1.3" ]; then + sed 's/#define USE_SKB_PROTOCOL 0/#define USE_SKB_PROTOCOL 1/' <$LINUXSRC/drivers/net/ppp.c.in >$LINUXSRC/drivers/net/ppp.c + else + sed 's/#define USE_SKB_PROTOCOL 1/#define USE_SKB_PROTOCOL 0/' <$LINUXSRC/drivers/net/ppp.c.in >$LINUXSRC/drivers/net/ppp.c + fi + rm $LINUXSRC/drivers/net/ppp.c.in +} + +# +# Install the files. + +function installfile () { + BASE=`basename $1` + if newer $1 $BASE; then + echo $1 is newer than $BASE, skipping + return 0 + fi + BACKUP=`echo $1 | sed 's/.c$/.old.c/;s/.h$/.old.h/'` + if [ -f $1 -a $BACKUP != $1 ]; then + echo Saving old $1 as `basename $BACKUP` + mv $1 $BACKUP + bombiffailed + fi + echo Installing new $1 + cp $BASE $1 + bombiffailed + touch $1 + bombiffailed + if [ "$2" = "yes" ]; then + update_ppp + fi +} + +if [ -f $LINUXSRC/drivers/net/ppp.h ]; then + echo Moving old $LINUXSRC/drivers/net/ppp.h file out of the way + mv $LINUXSRC/drivers/net/ppp.h $LINUXSRC/drivers/net/ppp.old.h + bombiffailed +fi + +for FILE in $LINUXSRC/drivers/net/bsd_comp.c \ + $LINUXSRC/include/linux/if_ppp.h \ + $LINUXSRC/include/linux/if_pppvar.h \ + $LINUXSRC/include/linux/ppp-comp.h \ + $LINUXSRC/include/linux/ppp_defs.h + do + installfile $FILE no +done + +installfile $LINUXSRC/drivers/net/ppp.c yes + +for FILE in if.h if_arp.h route.h + do + if [ ! -f $LINUXSRC/include/linux/$FILE ]; then + echo Installing new $1 + cp $FILE $LINUXSRC/include/linux/$FILE + bombiffailed + touch $LINUXSRC/include/linux/$FILE + bombiffailed + fi +done + +echo -n 'Adding BSD compression module to drivers makefile...' +NETMK=$LINUXSRC/drivers/net/Makefile +fgrep bsd_comp.o $NETMK >/dev/null +if [ ! "$?" = "0" ]; then + echo -n '.' + rm -f $NETMK.orig $NETMK.rej + if [ "$VERSION.$PATCHLEVEL" = "1.2" ]; then + (cd $LINUXSRC; patch -p1 -f -F30 -s) $NETMK.temp + bombiffailed + echo -n '.' + mv $NETMK $NETMK.orig + bombiffailed + echo -n '.' + mv $NETMK.temp $NETMK + bombiffailed + fi +# + if [ -e $NETMK.orig ]; then + mv $NETMK.orig $NETMK.old + fi +else + echo -n '(already there--skipping)' +fi +echo + +# +# install header stub files in /usr/include/net + +for FILE in if_ppp.h \ + if_pppvar.h \ + ppp-comp.h \ + if.h \ + if_arp.h \ + route.h \ + ppp_defs.h + do + if [ ! -f /usr/include/net/$FILE ]; then + echo Installing stub include file in /usr/include/net/$FILE + echo "#include " > /usr/include/net/$FILE + bombiffailed + chown 0:0 /usr/include/net/$FILE + bombiffailed + chmod 444 /usr/include/net/$FILE + bombiffailed + touch /usr/include/net/$FILE + bombiffailed + fi +done + +for FILE in ip.h \ + tcp.h + do + if [ ! -f /usr/include/netinet/$FILE ]; then + echo Installing stub include file in /usr/include/netinet/$FILE + if [ ! -f $LINUXSRC/include/linux/$FILE ]; then + echo "#include \"$LINUXSRC/net/inet/$FILE\"" >/usr/include/netinet/$FILE + else + echo "#include " > /usr/include/netinet/$FILE + fi + chown 0:0 /usr/include/netinet/$FILE + bombiffailed + chmod 444 /usr/include/netinet/$FILE + bombiffailed + touch /usr/include/netinet/$FILE + bombiffailed + fi +done + +echo "Kernel driver files installation done." +exit 0 diff --git a/linux/patch-1.2 b/linux/patch-1.2 new file mode 100644 index 0000000..4796a6a --- /dev/null +++ b/linux/patch-1.2 @@ -0,0 +1,23 @@ +This file is used by the 'make kernel' function. It will apply the patch +to the drivers/net/Makefile to install the bsd_comp.c file into the list +of files needed to build the kernel. + +This file is for the 1.2 kernel. + +--- linux/drivers/net/Makefile.orig Sun Oct 8 17:07:23 1995 ++++ linux/drivers/net/Makefile Sun Oct 8 17:10:25 1995 +@@ -85,12 +85,14 @@ + NETDRV_OBJS := $(NETDRV_OBJS) ppp.o + CONFIG_SLHC = CONFIG_SLHC + else + MODULES := $(MODULES) ppp.o + endif + ++MODULES := $(MODULES) bsd_comp.o ++ + ifdef CONFIG_SLIP + NETDRV_OBJS := $(NETDRV_OBJS) slip.o + CONFIG_SLHC = CONFIG_SLHC + else + MODULES := $(MODULES) slip.o + endif diff --git a/linux/patch-1.3 b/linux/patch-1.3 new file mode 100644 index 0000000..74d7437 --- /dev/null +++ b/linux/patch-1.3 @@ -0,0 +1,23 @@ +This file is used by the 'make kernel' function. It will apply the patch +to the drivers/net/Makefile to install the bsd_comp.c file into the list +of files needed to build the kernel. + +This file is for the 1.3 kernel. + +--- linux-1.3.32.ORIG/drivers/net/Makefile Fri Sep 8 23:37:24 1995 ++++ linux-1.3.32/drivers/net/Makefile Sun Sep 24 19:41:35 1995 +@@ -137,10 +137,14 @@ + CONFIG_SLHC_MODULE = y + M_OBJS += ppp.o + endif + endif + ++ifneq ($(CONFIG_PPP),n) ++ M_OBJS += bsd_comp.o ++endif ++ + ifeq ($(CONFIG_SLIP),y) + L_OBJS += slip.o + CONFIG_SLHC_BUILTIN = y + else + ifeq ($(CONFIG_SLIP),m) diff --git a/linux/ppp-comp.h b/linux/ppp-comp.h new file mode 100644 index 0000000..b72da19 --- /dev/null +++ b/linux/ppp-comp.h @@ -0,0 +1,192 @@ +/* + * ppp-comp.h - Definitions for doing PPP packet compression. + * + * Copyright (c) 1994 The Australian National University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, provided that the above copyright + * notice appears in all copies. This software is provided without any + * warranty, express or implied. The Australian National University + * makes no representations about the suitability of this software for + * any purpose. + * + * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY + * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, + * OR MODIFICATIONS. + * + * $Id: ppp-comp.h,v 1.1 1995/12/18 03:38:10 paulus Exp $ + */ + +/* + * ==FILEVERSION 4== + * + * NOTE TO MAINTAINERS: + * If you modify this file at all, increment the number above. + * ppp-comp.h is shipped with a PPP distribution as well as with the kernel; + * if everyone increases the FILEVERSION number above, then scripts + * can do the right thing when deciding whether to install a new ppp-comp.h + * file. Don't change the format of that line otherwise, so the + * installation script can recognize it. + */ + +#ifndef _NET_PPP_COMP_H +#define _NET_PPP_COMP_H + +/* + * The following symbols control whether we include code for + * various compression methods. + */ + +#ifndef DO_BSD_COMPRESS +#define DO_BSD_COMPRESS 1 /* by default, include BSD-Compress */ +#endif + +#define DO_PREDICTOR_1 0 +#define DO_PREDICTOR_2 0 +#define DO_DEFLATE 0 + +/* + * Structure giving methods for compression/decompression. + */ + +#ifdef PACKETPTR +struct compressor { + int compress_proto; /* CCP compression protocol number */ + + /* Allocate space for a compressor (transmit side) */ + void *(*comp_alloc) (unsigned char *options, int opt_len); + + /* Free space used by a compressor */ + void (*comp_free) (void *state); + + /* Initialize a compressor */ + int (*comp_init) (void *state, unsigned char *options, + int opt_len, int unit, int opthdr, int debug); + + /* Reset a compressor */ + void (*comp_reset) (void *state); + + /* Compress a packet */ + int (*compress) (void *state, unsigned char *rptr, + unsigned char *obuf, int isize, int osize); + + /* Return compression statistics */ + void (*comp_stat) (void *state, struct compstat *stats); + + /* Allocate space for a decompressor (receive side) */ + void *(*decomp_alloc) (unsigned char *options, int opt_len); + + /* Free space used by a decompressor */ + void (*decomp_free) (void *state); + + /* Initialize a decompressor */ + int (*decomp_init) (void *state, unsigned char *options, + int opt_len, int unit, int opthdr, int mru, + int debug); + + /* Reset a decompressor */ + void (*decomp_reset) (void *state); + + /* Decompress a packet. */ + int (*decompress) (void *state, unsigned char *ibuf, int isize, + unsigned char *obuf, int osize); + + /* Update state for an incompressible packet received */ + void (*incomp) (void *state, unsigned char *ibuf, int icnt); + + /* Return decompression statistics */ + void (*decomp_stat) (void *state, struct compstat *stats); +}; +#endif /* PACKETPTR */ + +/* + * Return values for decompress routine. + * We need to make these distinctions so that we can disable certain + * useful functionality, namely sending a CCP reset-request as a result + * of an error detected after decompression. This is to avoid infringing + * a patent held by Motorola. + * Don't you just lurve software patents. + */ + +#define DECOMP_OK 0 /* everything went OK */ +#define DECOMP_ERROR 1 /* error detected before decomp. */ +#define DECOMP_FATALERROR 2 /* error detected after decomp. */ + +/* + * CCP codes. + */ + +#define CCP_CONFREQ 1 +#define CCP_CONFACK 2 +#define CCP_TERMREQ 5 +#define CCP_TERMACK 6 +#define CCP_RESETREQ 14 +#define CCP_RESETACK 15 + +/* + * Max # bytes for a CCP option + */ + +#define CCP_MAX_OPTION_LENGTH 32 + +/* + * Parts of a CCP packet. + */ + +#define CCP_CODE(dp) ((dp)[0]) +#define CCP_ID(dp) ((dp)[1]) +#define CCP_LENGTH(dp) (((dp)[2] << 8) + (dp)[3]) +#define CCP_HDRLEN 4 + +#define CCP_OPT_CODE(dp) ((dp)[0]) +#define CCP_OPT_LENGTH(dp) ((dp)[1]) +#define CCP_OPT_MINLEN 2 + +/* + * Definitions for BSD-Compress. + */ + +#define CI_BSD_COMPRESS 21 /* config. option for BSD-Compress */ +#define CILEN_BSD_COMPRESS 3 /* length of config. option */ + +/* Macros for handling the 3rd byte of the BSD-Compress config option. */ +#define BSD_NBITS(x) ((x) & 0x1F) /* number of bits requested */ +#define BSD_VERSION(x) ((x) >> 5) /* version of option format */ +#define BSD_CURRENT_VERSION 1 /* current version number */ +#define BSD_MAKE_OPT(v, n) (((v) << 5) | (n)) + +#define BSD_MIN_BITS 9 /* smallest code size supported */ +#define BSD_MAX_BITS 15 /* largest code size supported */ + +/* + * Definitions for other, as yet unsupported, compression methods. + */ + +#define CI_PREDICTOR_1 1 /* config option for Predictor-1 */ +#define CILEN_PREDICTOR_1 2 /* length of its config option */ +#define CI_PREDICTOR_2 2 /* config option for Predictor-2 */ +#define CILEN_PREDICTOR_2 2 /* length of its config option */ + +#define CI_DEFLATE 24 /* config option for Deflate */ +#define CILEN_DEFLATE 4 /* length of its config option */ + +#define DEFLATE_MIN_SIZE 8 +#define DEFLATE_MAX_SIZE 15 +#define DEFLATE_METHOD_VAL 8 +#define DEFLATE_SIZE(x) (((x) >> 4) + DEFLATE_MIN_SIZE) +#define DEFLATE_METHOD(x) ((x) & 0x0F) +#define DEFLATE_MAKE_OPT(w) ((((w) - DEFLATE_MIN_SIZE) << 4) \ + + DEFLATE_METHOD_VAL) +#define DEFLATE_CHK_SEQUENCE 0 + +#endif /* _NET_PPP_COMP_H */ diff --git a/linux/ppp.c b/linux/ppp.c index cd7e605..71b6b4c 100644 --- a/linux/ppp.c +++ b/linux/ppp.c @@ -1,16 +1,20 @@ -/* - * PPP for Linux +/* PPP for Linux + * + * Michael Callahan + * Al Longyear * - * ==PPPVERSION 2.1.3== + * Dynamic PPP devices by Jim Freeman . + * ppp_tty_receive ``noisy-raise-bug'' fixed by Ove Ewerlid + * + * ==FILEVERSION 8== * * NOTE TO MAINTAINERS: - * If you modify this file at all, increment the last number above. + * If you modify this file at all, increment the number above. * ppp.c is shipped with a PPP distribution as well as with the kernel; - * if everyone increases the PPPVERSION number above, then scripts + * if everyone increases the FILEVERSION number above, then scripts * can do the right thing when deciding whether to install a new ppp.c * file. Don't change the format of that line otherwise, so the * installation script can recognize it. - * */ /* @@ -29,26 +33,44 @@ OPTIMIZE_FLAG_TIME - Number of jiffies to force sending of leading flag character. This is normally set to ((HZ * 3) / 2). - This is 1.5 seconds. If not defined then the leading + This is 1.5 seconds. If zero then the leading flag is always sent. CHECK_CHARACTERS - Enable the checking on all received characters for 8 data bits, no parity. This adds a small amount of processing for each received character. - - PPP_COMPRESS - Enable the PPP compression protocol. This protocol - is under contention with Motorolla's patent, so use - with caution. NEW_SKBUFF - Use NET3.020 sk_buff's + + IPX_CHANGE - Force the use of IPX support into the driver. + THIS IS **VERY** ALPHA LEVEL CODE!!!! */ /* #define NEW_SKBUFF 1 */ #define OPTIMIZE_FLAG_TIME ((HZ * 3)/2) + #define CHECK_CHARACTERS 1 #define PPP_COMPRESS 1 +#define USE_SKB_PROTOCOL 1 /* Set by the installation program! */ -/* $Id: ppp.c,v 1.5 1995/06/12 11:36:53 paulus Exp $ +#ifdef NEW_SKBUFF +#undef USE_SKB_PROTOCOL +#define USE_SKB_PROTOCOL 2 +#endif + +#ifndef PPP_MAX_DEV +#define PPP_MAX_DEV 256 +#endif + +#undef IPX_CHANGE + +#if defined(IPX_CHANGE) || defined(NEW_SKBUFF) +#define PPP_REQUESTED_HDR_LEN PPP_HARD_HDR_LEN +#else +#define PPP_REQUESTED_HDR_LEN 0 +#endif + +/* $Id: ppp.c,v 1.6 1995/12/18 03:38:12 paulus Exp $ * Added dynamic allocation of channels to eliminate * compiled-in limits on the number of channels. * @@ -56,6 +78,18 @@ * released under the GNU General Public License Version 2. */ +#if USE_SKB_PROTOCOL == 0 +#include /* still needed for 1.2 */ +#endif +#include + +#ifndef MOD_INC_USE_COUNT /* for those 1.2 kernels still out there */ +#undef MOD_DEC_USE_COUNT +#define MOD_DEC_USE_COUNT do {} while (0) +#define MOD_INC_USE_COUNT do {} while (0) +#endif + +#include #include #include #include @@ -74,8 +108,6 @@ #include #include #include -#include -#include #include #include #include @@ -85,37 +117,26 @@ #ifdef NEW_SKBUFF #include #else -#define skb_data(skb) ((unsigned char *) (skb)->data) -typedef struct sk_buff sk_buff; +typedef struct sk_buff sk_buff; +#define skb_data(skb) ((unsigned char *) (skb)->data) #endif -#include -#include +#include +#include #include #include "slhc.h" -#include +#include #include -#include -#include - -#ifdef MODULE -#include -#include -#define STATIC static -#else -#define MOD_INC_USE_COUNT while(0) { } -#define MOD_DEC_USE_COUNT while(0) { } -#endif /* def MODULE */ +#include +#include -#ifdef PPP_COMPRESS #undef PACKETPTR #define PACKETPTR 1 -#include +#include #undef PACKETPTR #define bsd_decompress (*ppp->sc_rcomp->decompress) #define bsd_compress (*ppp->sc_xcomp->compress) -#endif #ifndef PPP_IPX #define PPP_IPX 0x2b /* IPX protocol over PPP */ @@ -125,46 +146,53 @@ typedef struct sk_buff sk_buff; #define PPP_LQR 0xc025 /* Link Quality Reporting Protocol */ #endif +static int ppp_register_compressor (struct compressor *cp); +static void ppp_unregister_compressor (struct compressor *cp); + /* * Local functions */ +static struct compressor *find_compressor (int type); static void ppp_init_ctrl_blk (register struct ppp *); static void ppp_kick_tty (struct ppp *, struct ppp_buffer *bfr); static int ppp_doframe (struct ppp *); static struct ppp *ppp_alloc (void); -static void ppp_print_buffer (const u_char *, u_char *, int); +static void ppp_print_buffer (const u_char *, const u_char *, int); extern inline void ppp_stuff_char (struct ppp *ppp, register struct ppp_buffer *buf, register u_char chr); extern inline int lock_buffer (register struct ppp_buffer *buf); -static void ppp_proto_ccp (struct ppp *ppp, u_char *dp, int len, int rcvd); static int rcv_proto_ip (struct ppp *, u_short, u_char *, int); static int rcv_proto_ipx (struct ppp *, u_short, u_char *, int); static int rcv_proto_vjc_comp (struct ppp *, u_short, u_char *, int); static int rcv_proto_vjc_uncomp (struct ppp *, u_short, u_char *, int); static int rcv_proto_unknown (struct ppp *, u_short, u_char *, int); -static int rcv_proto_ccp (struct ppp *, u_short, u_char *, int); static int rcv_proto_lqr (struct ppp *, u_short, u_char *, int); static void ppp_doframe_lower (struct ppp *, u_char *, int); static int ppp_doframe (struct ppp *); -/* - * List of compressors we know about. - * We leave some space so maybe we can modload compressors. - */ +extern int ppp_bsd_compressor_init(void); +static void ppp_proto_ccp (struct ppp *ppp, u_char *dp, int len, int rcvd); +static int rcv_proto_ccp (struct ppp *, u_short, u_char *, int); + +#define ins_char(pbuf,c) (buf_base(pbuf) [(pbuf)->count++] = (u_char)(c)) -#ifdef PPP_COMPRESS -extern struct compressor ppp_bsd_compress; +#ifndef OPTIMIZE_FLAG_TIME +#define OPTIMIZE_FLAG_TIME 0 +#endif -struct compressor *ppp_compressors[8] = { - &ppp_bsd_compress, - NULL -}; -#endif /* PPP_COMPRESS */ +#ifndef PPP_MAX_DEV +#define PPP_MAX_DEV 256 +#endif -#define ins_char(pbuf,c) (buf_base(pbuf) [(pbuf)->count++] = (u_char)(c)) +/* + * Parameters which may be changed via insmod. + */ + +static int flag_time = OPTIMIZE_FLAG_TIME; +static int max_dev = PPP_MAX_DEV; /* * The "main" procedure to the ppp device @@ -182,6 +210,29 @@ static int ppp_dev_close (struct device *); static int ppp_dev_xmit (sk_buff *, struct device *); static struct enet_statistics *ppp_dev_stats (struct device *); +#if USE_SKB_PROTOCOL == 0 /* The 1.2.x kernel is here */ +#define dev_alloc_skb(count) alloc_skb(count, GFP_ATOMIC) +#define skb_put(skb,count) skb_data(skb) +#define get_long_user(addr) get_user_long((void *) addr) +#define get_int_user(addr) ((int) get_user_long((void *) addr)) +#define put_byte_user(val,addr) put_fs_byte(val,((u_char *) (addr))) +#define put_long_user(val,addr) put_fs_long((val),((void *) (addr))) + +static unsigned short ppp_dev_type (sk_buff *, struct device *); +static int ppp_dev_header (unsigned char *buff, struct device *dev, + unsigned short type, void *daddr, void *saddr, + unsigned len, struct sk_buff *skb); + +#else /* The 1.3.x kernel is here */ +#define get_long_user(addr) get_user(((int *) addr)) +#define get_int_user(addr) ((int) get_user(((int *) addr))) +#define put_byte_user(val,addr) put_user((val),((u_char *) (addr))) +#define put_long_user(val,addr) put_user((val),((int *) (addr))) + +static int ppp_dev_header (sk_buff *, struct device *, unsigned short, + void *, void *, unsigned); +#endif + #ifdef NEW_SKBUFF static int ppp_dev_input (struct protocol *self, struct protocol *lower, sk_buff *skb, void *saddr, void *daddr); @@ -189,11 +240,8 @@ static int ppp_dev_output (struct protocol *self, sk_buff *skb, int type, int subid, void *saddr, void *daddr, void *opt); static int ppp_dev_getkey(int protocol, int subid, unsigned char *key); #else -static int ppp_dev_header (u_char *, struct device *, unsigned short, - void *, void *, unsigned, sk_buff *); static int ppp_dev_rebuild (void *, struct device *, unsigned long, sk_buff *); -static unsigned short ppp_dev_type (sk_buff *, struct device *); #endif /* @@ -202,7 +250,7 @@ static unsigned short ppp_dev_type (sk_buff *, struct device *); static int ppp_tty_read (struct tty_struct *, struct file *, u_char *, unsigned int); -static int ppp_tty_write (struct tty_struct *, struct file *, u_char *, +static int ppp_tty_write (struct tty_struct *, struct file *, const u_char *, unsigned int); static int ppp_tty_ioctl (struct tty_struct *, struct file *, unsigned int, unsigned long); @@ -211,13 +259,12 @@ static int ppp_tty_select (struct tty_struct *tty, struct inode *inode, static int ppp_tty_open (struct tty_struct *); static void ppp_tty_close (struct tty_struct *); static int ppp_tty_room (struct tty_struct *tty); -static void ppp_tty_receive (struct tty_struct *tty, u_char * cp, +static void ppp_tty_receive (struct tty_struct *tty, const u_char * cp, char *fp, int count); static void ppp_tty_wakeup (struct tty_struct *tty); -#define PRINTK(p) printk p ; -#define CHECK_PPP(a) if (!ppp->inuse) { PRINTK ((ppp_warning, __LINE__)) return a;} -#define CHECK_PPP_VOID() if (!ppp->inuse) { PRINTK ((ppp_warning, __LINE__)) return;} +#define CHECK_PPP(a) if (!ppp->inuse) { printk (ppp_warning, __LINE__); return a;} +#define CHECK_PPP_VOID() if (!ppp->inuse) { printk (ppp_warning, __LINE__); return;} #define in_xmap(ppp,c) (ppp->xmit_async_map[(c) >> 5] & (1 << ((c) & 0x1f))) #define in_rmap(ppp,c) ((((unsigned int) (u_char) (c)) < 0x20) && \ @@ -238,7 +285,6 @@ struct ppp_hdr { #define PPP_HARD_HDR_LEN (sizeof (struct ppp_hdr)) -#if 1 typedef struct ppp_ctrl { struct ppp_ctrl *next; /* Next structure in the list */ char name [8]; /* Name of the device */ @@ -252,14 +298,6 @@ static ppp_ctrl_t *ppp_list = NULL; #define ctl2dev(ctl) (struct device *) &ctl->dev #undef PPP_NRUNIT -#else - -#define PPP_NRUNIT 4 -static struct ppp ppp_ctrl[PPP_NRUNIT]; -#undef dev2ppp -#define dev2ppp(dev) ((struct ppp *) &ppp_ctrl[dev->base_addr]) -#endif - /* Buffer types */ #define BUFFER_TYPE_DEV_RD 0 /* ppp read buffer */ #define BUFFER_TYPE_TTY_WR 1 /* tty write buffer */ @@ -287,21 +325,26 @@ typedef struct ppp_proto_struct { pfn_proto func; } ppp_proto_type; +static ppp_proto_type proto_list[] = { { PPP_IP, rcv_proto_ip }, { PPP_IPX, rcv_proto_ipx }, { PPP_VJC_COMP, rcv_proto_vjc_comp }, { PPP_VJC_UNCOMP, rcv_proto_vjc_uncomp }, - { PPP_LQR, rcv_proto_lqr }, -#ifdef PPP_COMPRESS + { PPP_LQR, rcv_proto_lqr }, { PPP_CCP, rcv_proto_ccp }, -#endif { 0, rcv_proto_unknown } /* !!! MUST BE LAST !!! */ }; -/* FCS table from RFC1331 */ +/* + * Values for FCS calculations. + */ -static unsigned short fcstab[256] = +#define PPP_INITFCS 0xffff /* Initial FCS value */ +#define PPP_GOODFCS 0xf0b8 /* Good final FCS value */ +#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ ppp_crc16_table[((fcs) ^ (c)) & 0xff]) + +unsigned short ppp_crc16_table[256] = { 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, @@ -369,35 +412,22 @@ ppp_first_time (void) static struct tty_ldisc ppp_ldisc; int status; -#ifdef PPP_NRUNIT -#define PPP_UNITS3(x) #x -#define PPP_UNITS2(x) PPP_UNITS3(x) -#define PPP_UNITS1(x) PPP_UNITS2(x) -#define PPP_UNITS "(" PPP_UNITS1(PPP_NRUNIT) " devices)" -#else -#define PPP_UNITS "(dynamic channel allocation)" -#endif printk (KERN_INFO - "PPP: version %s " PPP_UNITS + "PPP: version %s (dynamic channel allocation)" #ifdef NEW_SKBUFF " NEW_SKBUFF" #endif "\n", szVersion); -#undef PPP_UNITS -#undef PPP_UNITS1 -#undef PPP_UNITS2 -#undef PPP_UNITS3 +#ifndef MODULE /* slhc module logic has its own copyright announcment */ printk (KERN_INFO "TCP compression code copyright 1989 Regents of the " "University of California\n"); +#endif -#ifndef PPP_NRUNIT printk (KERN_INFO "PPP Dynamic channel allocation code copyright 1995 " "Caldera, Inc.\n"); -#endif - /* * Register the protocol for the device */ @@ -411,7 +441,7 @@ ppp_first_time (void) proto_ppp.bh_input = ppp_dev_input; proto_ppp.control_event = default_protocol_control; proto_ppp.get_binding = ppp_dev_getkey; - proto_ppp.header_space = 0; /* PPP_HARD_HDR_LEN; */ + proto_ppp.header_space = PPP_REQUESTED_HDR_LEN; protocol_register(&proto_ppp); #endif @@ -454,9 +484,11 @@ ppp_init_dev (struct device *dev) dev->default_protocol = &proto_ppp; /* Our protocol layer is PPP */ #else dev->hard_header = ppp_dev_header; +#if USE_SKB_PROTOCOL == 0 dev->type_trans = ppp_dev_type; +#endif dev->rebuild_header = ppp_dev_rebuild; - dev->hard_header_len = 0; /* PPP_HARD_HDR_LEN; */ + dev->hard_header_len = PPP_REQUESTED_HDR_LEN; #endif /* device INFO */ @@ -478,7 +510,7 @@ ppp_init_dev (struct device *dev) dev->pa_addr = 0; dev->pa_brdaddr = 0; dev->pa_mask = 0; - dev->pa_alen = sizeof (unsigned long); + dev->pa_alen = 4; /* sizeof (unsigned long) */ return 0; } @@ -510,28 +542,28 @@ ppp_init_ctrl_blk (register struct ppp *ppp) ppp->slcomp = NULL; ppp->read_wait = NULL; ppp->write_wait = NULL; - -#ifdef OPTIMIZE_FLAG_TIME /* ensure flag will always be sent first time */ - ppp->last_xmit = jiffies - OPTIMIZE_FLAG_TIME; -#else - ppp->last_xmit = 0; -#endif + ppp->last_xmit = jiffies - flag_time; /* clear statistics */ memset (&ppp->stats, '\0', sizeof (struct pppstat)); /* Reset the demand dial information */ - ppp->ddinfo.ip_sjiffies = - ppp->ddinfo.ip_rjiffies = - ppp->ddinfo.nip_sjiffies = - ppp->ddinfo.nip_rjiffies = jiffies; + ppp->ddinfo.xmit_idle= /* time since last NP packet sent */ + ppp->ddinfo.recv_idle=jiffies; /* time since last NP packet received */ -#ifdef PPP_COMPRESS + /* PPP compression data */ ppp->sc_xc_state = ppp->sc_rc_state = NULL; -#endif /* PPP_COMPRESS */ } +static struct symbol_table ppp_syms = { +#include + X(ppp_register_compressor), + X(ppp_unregister_compressor), + X(ppp_crc16_table), +#include +}; + /* called at boot/load time for each ppp device defined in the kernel */ #ifndef MODULE @@ -544,20 +576,11 @@ ppp_init (struct device *dev) if (first_time) { first_time = 0; answer = ppp_first_time(); + if (answer == 0) + (void) register_symtab (&ppp_syms); } -/* - * Un-register the devices defined at the start of the system. They will - * be added when they are needed again. The first device just gets us into - * this code to register the handlers. - */ -#if 1 - unregister_netdev (dev); -#else - ppp_init_dev (dev); - ppp_init_ctrl_blk (dev2ppp (dev)); - dev2ppp (dev) -> inuse = 0; - dev2ppp (dev) -> dev = dev; -#endif + if (answer == 0) + answer = -ENODEV; return answer; } #endif @@ -715,7 +738,7 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru) ppp->s2buf = NULL; ppp->xbuf = NULL; - ppp->tty->flags &= ~TTY_DO_WRITE_WAKEUP; + ppp->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); ppp->flags &= ~SC_XMIT_BUSY; sti (); @@ -733,21 +756,19 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru) * CCP is down; free (de)compressor state if necessary. */ -#ifdef PPP_COMPRESS static void ppp_ccp_closed (struct ppp *ppp) { - if (ppp->sc_xc_state) { - (*ppp->sc_xcomp->comp_free) (ppp->sc_xc_state); - ppp->sc_xc_state = NULL; - } + if (ppp->sc_xc_state) { + (*ppp->sc_xcomp->comp_free) (ppp->sc_xc_state); + ppp->sc_xc_state = NULL; + } - if (ppp->sc_rc_state) { - (*ppp->sc_rcomp->decomp_free) (ppp->sc_rc_state); - ppp->sc_rc_state = NULL; - } + if (ppp->sc_rc_state) { + (*ppp->sc_rcomp->decomp_free) (ppp->sc_rc_state); + ppp->sc_rc_state = NULL; + } } -#endif /* PPP_COMPRESS */ /* * Called to release all of the information in the current PPP structure. @@ -765,11 +786,7 @@ ppp_release (struct ppp *ppp) tty = ppp2tty (ppp); dev = ppp2dev (ppp); -#ifdef PPP_COMPRESS ppp_ccp_closed (ppp); - ppp->sc_xc_state = - ppp->sc_rc_state = NULL; -#endif /* PPP_COMPRESS */ if (tty != NULL && tty->disc_data == ppp) tty->disc_data = NULL; /* Break the tty->ppp link */ @@ -814,17 +831,19 @@ ppp_tty_close (struct tty_struct *tty) { struct ppp *ppp = tty2ppp (tty); - if (ppp == NULL || ppp->magic != PPP_MAGIC) { - if (ppp->flags & SC_DEBUG) - printk (KERN_WARNING - "ppp: trying to close unopened tty!\n"); - } else { - CHECK_PPP_VOID(); - if (ppp->flags & SC_DEBUG) - printk (KERN_INFO "ppp: channel %s closing.\n", - ppp2dev(ppp) -> name); - ppp_release (ppp); - MOD_DEC_USE_COUNT; + if (ppp != NULL) { + if (ppp->magic != PPP_MAGIC) { + if (ppp->flags & SC_DEBUG) + printk (KERN_WARNING + "ppp: trying to close unopened tty!\n"); + } else { + CHECK_PPP_VOID(); + if (ppp->flags & SC_DEBUG) + printk (KERN_INFO "ppp: channel %s closing.\n", + ppp2dev(ppp) -> name); + ppp_release (ppp); + MOD_DEC_USE_COUNT; + } } } @@ -852,7 +871,7 @@ ppp_tty_open (struct tty_struct *tty) /* * Allocate the structure from the system */ - ppp = ppp_alloc (); + ppp = ppp_alloc(); if (ppp == NULL) { if (ppp->flags & SC_DEBUG) printk (KERN_ERR @@ -874,7 +893,7 @@ ppp_tty_open (struct tty_struct *tty) if (tty->driver.flush_buffer) tty->driver.flush_buffer (tty); /* - * Allocate space for the default VJ header compression slots (16) + * Allocate space for the default VJ header compression slots */ ppp->slcomp = slhc_init (16, 16); if (ppp->slcomp == NULL) { @@ -964,7 +983,7 @@ ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty, */ xbuf = ppp->xbuf; if (xbuf != NULL) { - tty->flags &= ~TTY_DO_WRITE_WAKEUP; + tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); xbuf->locked = 0; ppp->xbuf = NULL; /* @@ -972,9 +991,9 @@ ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty, * transmission block. */ if (ppp2dev (ppp) -> flags & IFF_UP) { - ppp2dev (ppp)->tbusy = 0; + if (xbuf->type == BUFFER_TYPE_DEV_WR) + ppp2dev (ppp)->tbusy = 0; mark_bh (NET_BH); - dev_tint (ppp2dev (ppp)); } /* * Wake up the transmission queue for all completion events. @@ -983,18 +1002,21 @@ ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty, /* * Look at the priorities. Choose a daemon write over the device driver. */ + cli(); xbuf = ppp->s1buf; ppp->s1buf = NULL; if (xbuf == NULL) { xbuf = ppp->s2buf; ppp->s2buf = NULL; } + sti(); /* * If there is a pending buffer then transmit it now. */ if (xbuf != NULL) { ppp->flags &= ~SC_XMIT_BUSY; ppp_kick_tty (ppp, xbuf); + return; } } } @@ -1019,12 +1041,11 @@ ppp_tty_wakeup (struct tty_struct *tty) struct ppp_buffer *xbuf; struct ppp *ppp = tty2ppp (tty); - if (!ppp || ppp->magic != PPP_MAGIC) { - if (ppp->flags & SC_DEBUG) - printk (KERN_DEBUG "PPP: write_wakeup called but " - "couldn't find PPP struct.\n"); + if (!ppp) + return; + + if (ppp->magic != PPP_MAGIC) return; - } /* * Ensure that there is a transmission pending. Clear the re-entry flag if * there is no pending buffer. Otherwise, send the buffer. @@ -1106,16 +1127,25 @@ ppp_tty_room (struct tty_struct *tty) */ static void -ppp_tty_receive (struct tty_struct *tty, u_char * data, char *flags, int count) +ppp_tty_receive (struct tty_struct *tty, const u_char * data, + char *flags, int count) { register struct ppp *ppp = tty2ppp (tty); - register struct ppp_buffer *buf = ppp->rbuf; + register struct ppp_buffer *buf = NULL; u_char chr; +/* + * Fetch the pointer to the buffer. Be careful about race conditions. + */ + if (ppp != NULL) + buf = ppp->rbuf; + + if (buf == NULL) + return; /* * Verify the table pointer and ensure that the line is * still in PPP discipline. */ - if (!ppp || ppp->magic != PPP_MAGIC) { + if (ppp->magic != PPP_MAGIC) { if (ppp->flags & SC_DEBUG) printk (KERN_DEBUG "PPP: handler called but couldn't find " @@ -1173,7 +1203,7 @@ ppp_tty_receive (struct tty_struct *tty, u_char * data, char *flags, int count) * first FLAG are also tossed by this procedure. */ case PPP_FLAG: /* PPP_FLAG: end of frame */ - ppp->stats.ppp_ibytes = ppp->bytes_rcvd; + ppp->stats.ppp_ibytes += ppp->rbuf->count; if (ppp->escape) ppp->toss |= 0x80; /* @@ -1235,7 +1265,7 @@ ppp_tty_receive (struct tty_struct *tty, u_char * data, char *flags, int count) static int ppp_rcv_rx (struct ppp *ppp, unsigned short proto, u_char * data, int count) { - sk_buff *skb = alloc_skb (count, GFP_ATOMIC); + sk_buff *skb = dev_alloc_skb (count); /* * Generate a skb buffer for the new frame. */ @@ -1249,17 +1279,19 @@ ppp_rcv_rx (struct ppp *ppp, unsigned short proto, u_char * data, int count) /* * Move the received data from the input buffer to the skb buffer. */ - skb->len = count; /* Store the length */ skb->dev = ppp2dev (ppp); /* We are the device */ -#ifdef NEW_SKBUF +#if USE_SKB_PROTOCOL == 0 + skb->len = count; +#else skb->protocol = proto; + skb->mac.raw = skb_data(skb); #endif - memcpy ((u_char *) skb_data(skb), data, count); /* move data */ + memcpy (skb_put(skb,count), data, count); /* move data */ /* * Tag the frame and kick it to the proper receive routine */ skb->free = 1; - ppp->ddinfo.ip_rjiffies = jiffies; + ppp->ddinfo.recv_idle = jiffies; netif_rx (skb); return 1; } @@ -1271,10 +1303,8 @@ ppp_rcv_rx (struct ppp *ppp, unsigned short proto, u_char * data, int count) static int rcv_proto_ip (struct ppp *ppp, unsigned short proto, u_char * data, int count) { - if (ppp2dev (ppp)->flags & IFF_UP) { - if (count > 0) - return ppp_rcv_rx (ppp, htons (ETH_P_IP), data, count); - } + if ((ppp2dev (ppp)->flags & IFF_UP) && (count > 0)) + return ppp_rcv_rx (ppp, htons (ETH_P_IP), data, count); return 0; } @@ -1285,11 +1315,9 @@ rcv_proto_ip (struct ppp *ppp, unsigned short proto, u_char * data, int count) static int rcv_proto_ipx (struct ppp *ppp, unsigned short proto, u_char * data, int count) { -#ifdef NEW_SKBUF - if (ppp2dev (ppp)->flags & IFF_UP) { - if (count > 0) - return ppp_rcv_rx (ppp, htons (ETH_P_IPX), data, count); - } else +#if defined(NEW_SKBUFF) || defined(IPX_CHANGE) + if (((ppp2dev (ppp)->flags & IFF_UP) != 0) && (count > 0)) + return ppp_rcv_rx (ppp, htons (ETH_P_IPX), data, count); #endif return 0; } @@ -1390,10 +1418,9 @@ rcv_proto_unknown (struct ppp *ppp, unsigned short proto, if (ppp->flags & SC_DEBUG) printk (KERN_INFO - "ppp: successfully queued %d bytes\n", - len + 2); + "ppp: successfully queued %d bytes, flags = %x\n", + len + 2, ppp->flags); - ppp->ddinfo.nip_rjiffies = jiffies; return 1; /* * The buffer is full. Unlock the header @@ -1422,91 +1449,90 @@ failure: * immediate or the compressors will become confused on the peer. */ -#ifdef PPP_COMPRESS static void ppp_proto_ccp (struct ppp *ppp, u_char *dp, int len, int rcvd) { - int slen = CCP_LENGTH(dp); + int slen = CCP_LENGTH(dp); + u_char *opt = dp + CCP_HDRLEN; + int opt_len = slen - CCP_HDRLEN; + + if (slen > len) + return; - if (slen <= len) { - switch (CCP_CODE(dp)) { - case CCP_CONFREQ: - case CCP_TERMREQ: - case CCP_TERMACK: + switch (CCP_CODE(dp)) { + case CCP_CONFREQ: + case CCP_TERMREQ: + case CCP_TERMACK: /* * CCP must be going down - disable compression */ - if (ppp->flags & SC_CCP_UP) { - ppp->flags &= ~(SC_CCP_UP | - SC_COMP_RUN | - SC_DECOMP_RUN); - } - break; + if (ppp->flags & SC_CCP_UP) { + ppp->flags &= ~(SC_CCP_UP | + SC_COMP_RUN | + SC_DECOMP_RUN); + } + break; - case CCP_CONFACK: - if (ppp->flags & SC_CCP_OPEN == 0) - break; - if (ppp->flags & SC_CCP_UP) - break; - if (slen < CCP_HDRLEN + CCP_OPT_MINLEN) - break; - if (slen < CCP_OPT_LENGTH (dp + CCP_HDRLEN) + - CCP_HDRLEN) - break; + case CCP_CONFACK: + if ((ppp->flags & SC_CCP_OPEN) == 0) + break; + if (ppp->flags & SC_CCP_UP) + break; + if (slen < (CCP_HDRLEN + CCP_OPT_MINLEN)) + break; + if (slen < (CCP_OPT_LENGTH (opt) + CCP_HDRLEN)) + break; /* * we're agreeing to send compressed packets. */ - if (!rcvd) { - if (ppp->sc_xc_state == NULL) - break; - - if ((*ppp->sc_xcomp->comp_init) - (ppp->sc_xc_state, - dp + CCP_HDRLEN, - slen - CCP_HDRLEN, - ppp2dev (ppp)->base_addr, - ppp->flags & SC_DEBUG)) - ppp->flags |= SC_COMP_RUN; + if (!rcvd) { + if (ppp->sc_xc_state == NULL) break; - } + + if ((*ppp->sc_xcomp->comp_init) + (ppp->sc_xc_state, + opt, + opt_len, + ppp2dev (ppp)->base_addr, + 0, + ppp->flags)) + ppp->flags |= SC_COMP_RUN; + break; + } /* * peer is agreeing to send compressed packets. */ - if (ppp->sc_rc_state == NULL) - break; - - if ((*ppp->sc_rcomp->decomp_init) - (ppp->sc_rc_state, - dp + CCP_HDRLEN, - slen - CCP_HDRLEN, - ppp2dev (ppp)->base_addr, - ppp->mru, - ppp->flags & SC_DEBUG)) { - ppp->flags |= SC_DECOMP_RUN; - ppp->flags &= ~(SC_DC_ERROR | SC_DC_FERROR); - } + if (ppp->sc_rc_state == NULL) break; + + if ((*ppp->sc_rcomp->decomp_init) + (ppp->sc_rc_state, + opt, + opt_len, + ppp2dev (ppp)->base_addr, + 0, + ppp->mru, + ppp->flags)) { + ppp->flags |= SC_DECOMP_RUN; + ppp->flags &= ~(SC_DC_ERROR | SC_DC_FERROR); + } + break; /* * The protocol sequence is complete at this end */ - case CCP_RESETACK: - if (ppp->flags & SC_CCP_UP == 0) - break; - - if (!rcvd) { - if (ppp->sc_xc_state && - (ppp->flags & SC_COMP_RUN)) - (*ppp->sc_xcomp->comp_reset) - (ppp->sc_xc_state); - break; - } + case CCP_RESETACK: + if ((ppp->flags & SC_CCP_UP) == 0) + break; + if (!rcvd) { + if (ppp->sc_xc_state && (ppp->flags & SC_COMP_RUN)) + (*ppp->sc_xcomp->comp_reset)(ppp->sc_xc_state); + } else { if (ppp->sc_rc_state && (ppp->flags & SC_DECOMP_RUN)) { - (*ppp->sc_rcomp->decomp_reset) - (ppp->sc_rc_state); + (*ppp->sc_rcomp->decomp_reset)(ppp->sc_rc_state); ppp->flags &= ~SC_DC_ERROR; } - break; } + break; } } @@ -1516,7 +1542,6 @@ rcv_proto_ccp (struct ppp *ppp, unsigned short proto, u_char *dp, int len) ppp_proto_ccp (ppp, dp, len, 1); return rcv_proto_unknown (ppp, proto, dp, len); } -#endif /* PPP_COMPRESS */ /* * Handle a LQR packet. @@ -1529,8 +1554,8 @@ rcv_proto_ccp (struct ppp *ppp, unsigned short proto, u_char *dp, int len) static int rcv_proto_lqr (struct ppp *ppp, unsigned short proto, u_char * data, int len) { +#if 0 /* until support is in the pppd process don't corrupt the reject. */ register u_char *p; - if (len > 8) { if (len < 48) memset (&data [len], '\0', 48 - len); @@ -1546,6 +1571,7 @@ rcv_proto_lqr (struct ppp *ppp, unsigned short proto, u_char * data, int len) len = 68; } +#endif /* * Pass the frame to the pppd daemon. */ @@ -1555,15 +1581,14 @@ rcv_proto_lqr (struct ppp *ppp, unsigned short proto, u_char * data, int len) /* on entry, a received frame is in ppp->rbuf.bufr check it and dispose as appropriate */ -static void ppp_doframe_lower (struct ppp *ppp, u_char *data, int len) +static void ppp_doframe_lower (struct ppp *ppp, u_char *data, int count) { - u_short proto; - int count = len; + u_short proto = PPP_PROTOCOL (data); ppp_proto_type *proto_ptr; /* * Ignore empty frames */ - if (count <= 0) + if (count <= 4) return; /* * Count the frame and print it @@ -1571,23 +1596,6 @@ static void ppp_doframe_lower (struct ppp *ppp, u_char *data, int len) ++ppp->stats.ppp_ipackets; if (ppp->flags & SC_LOG_INPKT) ppp_print_buffer ("receive frame", data, count); -/* - * Ignore the leading ADDRESS and CONTROL fields in the frame. - */ - if ((data[0] == PPP_ALLSTATIONS) && (data[1] == PPP_UI)) { - data += 2; - count -= 2; - } -/* - * Obtain the protocol from the frame - */ - proto = (u_short) *data++; - if (proto & 1) - count--; - else { - proto = (proto << 8) | (u_short) *data++; - count -= 2; - } /* * Find the procedure to handle this protocol. The last one is marked * as a protocol 0 which is the 'catch-all' to feed it to the pppd daemon. @@ -1598,8 +1606,10 @@ static void ppp_doframe_lower (struct ppp *ppp, u_char *data, int len) /* * Update the appropriate statistic counter. */ - if ((*proto_ptr->func) (ppp, proto, data, count)) - ppp->stats.ppp_ioctects += len; + if ((*proto_ptr->func) (ppp, proto, + &data[PPP_HARD_HDR_LEN], + count - PPP_HARD_HDR_LEN)) + ppp->stats.ppp_ioctects += count; else ++ppp->stats.ppp_discards; } @@ -1612,11 +1622,9 @@ ppp_doframe (struct ppp *ppp) { u_char *data = buf_base (ppp->rbuf); int count = ppp->rbuf->count; -#ifdef PPP_COMPRESS - int proto; + int addr, ctrl, proto; int new_count; u_char *new_data; -#endif /* * If there is a pending error from the receiver then log it and discard * the damaged frame. @@ -1659,19 +1667,44 @@ ppp_doframe (struct ppp *ppp) return 0; } count -= 2; /* ignore the fcs characters */ +/* + * Ignore the leading ADDRESS and CONTROL fields in the frame. + */ + addr = PPP_ALLSTATIONS; + ctrl = PPP_UI; -#ifdef PPP_COMPRESS - proto = PPP_PROTOCOL (data); + if ((data[0] == PPP_ALLSTATIONS) && (data[1] == PPP_UI)) { + data += 2; + count -= 2; + } +/* + * Obtain the protocol from the frame + */ + proto = (u_short) *data++; + if ((proto & 1) == 0) { + proto = (proto << 8) | (u_short) *data++; + --count; + } +/* + * Rewrite the header with the full information. This may encroach upon + * the 'filler' area in the buffer header. This is the purpose for the + * filler. + */ + *(--data) = proto; + *(--data) = proto >> 8; + *(--data) = ctrl; + *(--data) = addr; + count += 3; /* * Process the active decompressor. */ if ((ppp->sc_rc_state != (void *) 0) && - ((ppp->flags & SC_DECOMP_RUN) == 0)) { + (ppp->flags & SC_DECOMP_RUN) && + ((ppp->flags & (SC_DC_FERROR | SC_DC_ERROR)) == 0)) { + if (proto == PPP_COMP) { /* * If the frame is compressed then decompress it. */ - if (((ppp->flags & (SC_DC_FERROR | SC_DC_ERROR)) == 0) && - (proto == PPP_COMP)) { new_data = kmalloc (ppp->mru + 4, GFP_ATOMIC); if (new_data == NULL) { if (ppp->flags & SC_DEBUG) @@ -1691,7 +1724,6 @@ ppp_doframe (struct ppp *ppp) count, new_data, ppp->mru + 4); - switch (new_count) { default: ppp_doframe_lower (ppp, new_data, new_count); @@ -1721,14 +1753,13 @@ ppp_doframe (struct ppp *ppp) return 1; } /* - * The frame is not special. Pass it through the decompressor without - * actually decompressing the data + * The frame is not special. Pass it through the compressor without + * actually compressing the data */ (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state, data, count); } -#endif /* * Process the uncompressed frame. */ @@ -1758,43 +1789,53 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf, #define GETC(c) \ { \ - c = buf_base (ppp->ubuf) [ppp->ubuf->tail++]; \ - ppp->ubuf->tail &= ppp->ubuf->size; \ + c = buf_base (ppp->ubuf) [ppp->ubuf->tail++]; \ + ppp->ubuf->tail &= ppp->ubuf->size; \ } /* * Validate the pointer to the PPP structure */ - if (!ppp || ppp->magic != PPP_MAGIC) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR - "ppp_tty_read: cannot find ppp channel\n"); + if (!ppp) return -EIO; - } + + if (ppp->magic != PPP_MAGIC) + return -EIO; + CHECK_PPP (-ENXIO); if (ppp->flags & SC_DEBUG) printk (KERN_DEBUG - "ppp_tty_read: called %x num %u\n", - (unsigned int) buf, - nr); + "ppp_tty_read: called buf=%p nr=%u\n", + buf, nr); /* * Acquire the read lock. */ for (;;) { + ppp = tty2ppp (tty); + if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse) + return 0; + if (set_bit (0, &ppp->ubuf->locked) != 0) { if (ppp->flags & SC_DEBUG) printk (KERN_DEBUG "ppp_tty_read: sleeping(ubuf)\n"); current->timeout = 0; - current->state = TASK_INTERRUPTIBLE; + current->state = TASK_INTERRUPTIBLE; schedule (); if (current->signal & ~current->blocked) return -EINTR; continue; } +/* + * Before we attempt to write the frame to the user, ensure that the + * user has access to the pages for the total buffer length. + */ + indx = verify_area (VERIFY_WRITE, buf, nr); + if (indx != 0) + return (indx); /* * Fetch the length of the buffer from the first two bytes. */ @@ -1833,7 +1874,6 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf, /* * Reset the time of the last read operation. */ - ppp->ddinfo.nip_rjiffies = jiffies; if (ppp->flags & SC_DEBUG) printk (KERN_DEBUG "ppp_tty_read: len = %d\n", len); /* @@ -1853,12 +1893,23 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf, ppp->stats.ppp_ierrors++; return -EOVERFLOW; } +/* + * Before we attempt to write the frame to the user, ensure that the + * page tables are proper. + */ + indx = verify_area (VERIFY_WRITE, buf, len + 2); + if (indx != 0) { + ppp->ubuf->tail += len; + ppp->ubuf->tail &= ppp->ubuf->size; + clear_bit (0, &ppp->ubuf->locked); + return (indx); + } /* * Fake the insertion of the ADDRESS and CONTROL information because these * were not saved in the buffer. */ - put_fs_byte (PPP_ALLSTATIONS, buf++); - put_fs_byte (PPP_UI, buf++); + put_byte_user (PPP_ALLSTATIONS, buf++); + put_byte_user (PPP_UI, buf++); indx = len; /* @@ -1866,7 +1917,8 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf, */ while (indx-- > 0) { GETC (c); - put_fs_byte (c, buf++); + put_byte_user (c, buf); + ++buf; } /* * Release the lock and return the character count in the buffer area. @@ -1896,7 +1948,7 @@ ppp_stuff_char (struct ppp *ppp, register struct ppp_buffer *buf, if ((buf->count < 0) || (buf->count > 3000)) printk (KERN_DEBUG "ppp_stuff_char: %x %d\n", (unsigned int) buf->count, - (unsigned int) buf->count); + (unsigned int) chr); } /* * Update the FCS and if the character needs to be escaped, do it. @@ -1922,27 +1974,47 @@ ppp_dev_xmit_lower (struct ppp *ppp, struct ppp_buffer *buf, u_char *data, int count, int non_ip) { unsigned short int write_fcs; + int address, control; + int proto; /* * Insert the leading FLAG character */ buf->count = 0; -#ifdef OPTIMIZE_FLAG_TIME - if (non_ip) + if (non_ip || flag_time == 0) ins_char (buf, PPP_FLAG); else { - if (jiffies - ppp->last_xmit > OPTIMIZE_FLAG_TIME) + if (jiffies - ppp->last_xmit > flag_time) ins_char (buf, PPP_FLAG); } ppp->last_xmit = jiffies; -#else - ins_char (buf, PPP_FLAG); -#endif + buf->fcs = PPP_INITFCS; +/* + * Emit the address/control information if needed + */ + address = PPP_ADDRESS (data); + control = PPP_CONTROL (data); + proto = PPP_PROTOCOL (data); + + if (address != PPP_ALLSTATIONS || + control != PPP_UI || + (ppp->flags & SC_COMP_AC) == 0) { + ppp_stuff_char (ppp, buf, address); + ppp_stuff_char (ppp, buf, control); + } +/* + * Emit the protocol (compressed if possible) + */ + if ((ppp->flags & SC_COMP_PROT) == 0 || (proto & 0xFF00)) + ppp_stuff_char (ppp, buf, proto >> 8); - buf->fcs = PPP_INITFCS; + ppp_stuff_char (ppp, buf, proto); /* * Insert the data */ + data += 4; + count -= 4; + while (count-- > 0) ppp_stuff_char (ppp, buf, *data++); /* @@ -1985,12 +2057,12 @@ ppp_dev_xmit_lower (struct ppp *ppp, struct ppp_buffer *buf, * 1 if frame must be re-queued for later driver support. */ -int +static int ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf, u_char *data, int count) { - int address, control; int proto; + int address, control; u_char *new_data; int new_count; /* @@ -2002,12 +2074,11 @@ ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf, * Determine if the frame may be compressed. Attempt to compress the * frame if possible. */ + proto = PPP_PROTOCOL (data); address = PPP_ADDRESS (data); control = PPP_CONTROL (data); - proto = PPP_PROTOCOL (data); -#ifdef PPP_COMPRESS - if ((ppp->flags & SC_COMP_RUN != 0) && + if (((ppp->flags & SC_COMP_RUN) != 0) && (ppp->sc_xc_state != (void *) 0) && (address == PPP_ALLSTATIONS) && (control == PPP_UI) && @@ -2029,7 +2100,7 @@ ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf, if (new_count > 0) { ++ppp->stats.ppp_opackets; - ppp->stats.ppp_ooctects += count; + ppp->stats.ppp_ooctects += new_count; ppp_dev_xmit_lower (ppp, buf, new_data, new_count, 0); @@ -2041,33 +2112,12 @@ ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf, */ kfree (new_data); } -#endif /* * The frame may not be compressed. Update the statistics before the * count field is destroyed. The frame will be transmitted. */ ++ppp->stats.ppp_opackets; ppp->stats.ppp_ooctects += count; -/* - * Do not compress the protocol id if not possible - */ - if (!(ppp->flags & SC_COMP_PROT) || (proto & 0xFF00)) { - --data; - ++count; - } - - data += 3; - count -= 3; -/* - * Do not compress the address/control if not possible. - */ - if (address != PPP_ALLSTATIONS || - control != PPP_UI || - !(ppp->flags & SC_COMP_AC)) { - *--data = control; - *--data = address; - count += 2; - } /* * Go to the escape encoding */ @@ -2098,12 +2148,12 @@ send_revise_frame (register struct ppp *ppp, u_char *data, int len) /* * Outbound compression frames */ -#ifdef PPP_COMPRESS - case PPP_COMP: - ppp_proto_ccp (ppp, data, len, 0); + case PPP_CCP: + ppp_proto_ccp (ppp, + data + PPP_HARD_HDR_LEN, + len - PPP_HARD_HDR_LEN, + 0); break; -#endif - /* * All other frame types */ @@ -2120,20 +2170,20 @@ send_revise_frame (register struct ppp *ppp, u_char *data, int len) */ static int -ppp_tty_write (struct tty_struct *tty, struct file *file, u_char * data, +ppp_tty_write (struct tty_struct *tty, struct file *file, const u_char * data, unsigned int count) { struct ppp *ppp = tty2ppp (tty); u_char *new_data; + int status; /* * Verify the pointer to the PPP data and that the tty is still in PPP mode. */ - if (!ppp || ppp->magic != PPP_MAGIC) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR - "ppp_tty_write: cannot find ppp unit\n"); + if (!ppp) + return -EIO; + + if (ppp->magic != PPP_MAGIC) return -EIO; - } CHECK_PPP (-ENXIO); /* @@ -2146,6 +2196,16 @@ ppp_tty_write (struct tty_struct *tty, struct file *file, u_char * data, "from %u to mtu %d\n", count, PPP_MTU); count = PPP_MTU; } +/* + * Allocate a buffer for the data and fetch it from the user space. + */ + new_data = kmalloc (count, GFP_KERNEL); + if (new_data == NULL) { + if (ppp->flags & SC_DEBUG) + printk (KERN_ERR + "ppp_tty_write: no memory\n"); + return 0; + } /* * lock this PPP unit so we will be the only writer; * sleep if necessary @@ -2155,19 +2215,26 @@ ppp_tty_write (struct tty_struct *tty, struct file *file, u_char * data, if (ppp->flags & SC_DEBUG) printk (KERN_DEBUG "ppp_tty_write: sleeping\n"); interruptible_sleep_on (&ppp->write_wait); - if (current->signal & ~current->blocked) + + ppp = tty2ppp (tty); + if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse) { + kfree (new_data); + return 0; + } + + if (current->signal & ~current->blocked) { + kfree (new_data); return -EINTR; + } } /* - * Allocate a buffer for the data and fetch it from the user space. + * Ensure that the caller's buffer is valid. */ - new_data = kmalloc (count, GFP_ATOMIC); - if (new_data == NULL) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR - "ppp_tty_write: no memory\n"); + status = verify_area (VERIFY_READ, data, count); + if (status != 0) { + kfree (new_data); ppp->tbuf->locked = 0; - return 0; + return status; } memcpy_fromfs (new_data, data, count); @@ -2187,80 +2254,80 @@ ppp_tty_write (struct tty_struct *tty, struct file *file, u_char * data, * Process the BSD compression IOCTL event for the tty device. */ -#ifdef PPP_COMPRESS static int ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp) { + struct compressor *cp; + struct ppp_option_data data; int error; int nb; + u_char *ptr; u_char ccp_option[CCP_MAX_OPTION_LENGTH]; - struct compressor **cp; /* - * Validate the range of the ioctl + * Fetch the compression parameters */ - error = verify_area (VERIFY_READ, odp, - (unsigned long) (&((struct ppp_option_data *) 0)->length) - + sizeof (odp->length)); - + error = verify_area (VERIFY_READ, odp, sizeof (data)); if (error == 0) { - nb = (int) get_fs_long (odp->length); - if ((unsigned long) nb-1 >= (unsigned long) CCP_MAX_OPTION_LENGTH) + memcpy_fromfs (&data, odp, sizeof (data)); + nb = data.length; + ptr = data.ptr; + if ((unsigned long) nb >= (unsigned long)CCP_MAX_OPTION_LENGTH) nb = CCP_MAX_OPTION_LENGTH; - - error = verify_area (VERIFY_READ, odp, nb); + + error = verify_area (VERIFY_READ, ptr, nb); } if (error != 0) return error; - memcpy_fromfs (ccp_option, odp, nb); + memcpy_fromfs (ccp_option, ptr, nb); + if (ccp_option[1] < 2) /* preliminary check on the length byte */ return (-EINVAL); - for (cp = ppp_compressors; *cp != NULL; ++cp) - if ((*cp)->compress_proto == ccp_option[0]) { + cp = find_compressor ((int) (unsigned) (unsigned char) ccp_option[0]); + if (cp != (struct compressor *) 0) { /* * Found a handler for the protocol - try to allocate * a compressor or decompressor. */ - error = 0; - if (odp->transmit) { - if (ppp->sc_xc_state != NULL) - (*ppp->sc_xcomp->comp_free)(ppp->sc_xc_state); - - ppp->sc_xcomp = *cp; - ppp->sc_xc_state = (*cp)->comp_alloc(ccp_option, nb); - - if (ppp->sc_xc_state == NULL) { - if (ppp->flags & SC_DEBUG) - printk("ppp%ld: comp_alloc failed\n", - ppp2dev (ppp)->base_addr); - error = -ENOBUFS; - } - ppp->flags &= ~SC_COMP_RUN; - } else { - if (ppp->sc_rc_state != NULL) - (*ppp->sc_rcomp->decomp_free)(ppp->sc_rc_state); - ppp->sc_rcomp = *cp; - ppp->sc_rc_state = (*cp)->decomp_alloc(ccp_option, nb); - if (ppp->sc_rc_state == NULL) { - if (ppp->flags & SC_DEBUG) - printk("ppp%ld: decomp_alloc failed\n", - ppp2dev (ppp)->base_addr); - error = ENOBUFS; - } - ppp->flags &= ~SC_DECOMP_RUN; + error = 0; + if (data.transmit) { + if (ppp->sc_xc_state != NULL) + (*ppp->sc_xcomp->comp_free)(ppp->sc_xc_state); + + ppp->sc_xcomp = cp; + ppp->sc_xc_state = cp->comp_alloc(ccp_option, nb); + + if (ppp->sc_xc_state == NULL) { + if (ppp->flags & SC_DEBUG) + printk("ppp%ld: comp_alloc failed\n", + ppp2dev (ppp)->base_addr); + error = -ENOBUFS; } - return (error); + ppp->flags &= ~SC_COMP_RUN; + } else { + if (ppp->sc_rc_state != NULL) + (*ppp->sc_rcomp->decomp_free)(ppp->sc_rc_state); + ppp->sc_rcomp = cp; + ppp->sc_rc_state = cp->decomp_alloc(ccp_option, nb); + if (ppp->sc_rc_state == NULL) { + if (ppp->flags & SC_DEBUG) + printk("ppp%ld: decomp_alloc failed\n", + ppp2dev (ppp)->base_addr); + error = ENOBUFS; + } + ppp->flags &= ~SC_DECOMP_RUN; } + return (error); + } if (ppp->flags & SC_DEBUG) - printk (KERN_DEBUG "ppp%ld: no compressor for [%x %x %x], %x\n", - ppp2dev (ppp)->base_addr, ccp_option[0], ccp_option[1], - ccp_option[2], nb); + printk(KERN_DEBUG "ppp%ld: no compressor for [%x %x %x], %x\n", + ppp2dev (ppp)->base_addr, ccp_option[0], ccp_option[1], + ccp_option[2], nb); return (-EINVAL); /* no handler found */ } -#endif /* PPP_COMPRESS */ /* * Process the IOCTL event for the tty device. @@ -2276,12 +2343,12 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, /* * Verify the status of the PPP device. */ - if (!ppp || ppp->magic != PPP_MAGIC) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR - "ppp_tty_ioctl: can't find PPP block from tty!\n"); + if (!ppp) return -EBADF; - } + + if (ppp->magic != PPP_MAGIC) + return -EBADF; + CHECK_PPP (-ENXIO); /* * The user must have an euid of root to do these requests. @@ -2296,7 +2363,7 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, error = verify_area (VERIFY_READ, (void *) param3, sizeof (temp_i)); if (error == 0) { - temp_i = (int) get_fs_long (param3); + temp_i = get_int_user ((int *) param3); if (ppp->flags & SC_DEBUG) printk (KERN_INFO "ppp_tty_ioctl: set mru to %x\n", temp_i); @@ -2317,7 +2384,7 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, temp_i |= SC_RCV_B7_1 | SC_RCV_B7_0 | SC_RCV_ODDP | SC_RCV_EVNP; #endif - put_fs_long ((long) temp_i, param3); + put_long_user ((long) temp_i, param3); if (ppp->flags & SC_DEBUG) printk (KERN_DEBUG "ppp_tty_ioctl: get flags: addr %lx flags " @@ -2331,15 +2398,13 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, error = verify_area (VERIFY_READ, (void *) param3, sizeof (temp_i)); if (error == 0) { - temp_i = (int) get_fs_long (param3) & SC_MASK; + temp_i = get_int_user (param3) & SC_MASK; temp_i |= (ppp->flags & ~SC_MASK); -#ifdef PPP_COMPRESS + if ((ppp->flags & SC_CCP_OPEN) && (temp_i & SC_CCP_OPEN) == 0) ppp_ccp_closed (ppp); -#else - temp_i &= ~SC_CCP_OPEN; -#endif + if ((ppp->flags | temp_i) & SC_DEBUG) printk (KERN_INFO "ppp_tty_ioctl: set flags to %x\n", temp_i); @@ -2349,12 +2414,10 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, /* * Set the compression mode */ -#ifdef PPP_COMPRESS case PPPIOCSCOMPRESS: error = ppp_set_compression (ppp, (struct ppp_option_data *) param3); break; -#endif /* * Retrieve the transmit async map */ @@ -2362,12 +2425,13 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, error = verify_area (VERIFY_WRITE, (void *) param3, sizeof (temp_i)); if (error == 0) { - put_fs_long (ppp->xmit_async_map[0], param3); + put_long_user (ppp->xmit_async_map[0], param3); if (ppp->flags & SC_DEBUG) printk (KERN_INFO - "ppp_tty_ioctl: get asyncmap: addr " - "%lx asyncmap %lx\n", - param3, ppp->xmit_async_map[0]); + "ppp_tty_ioctl: get asyncmap: addr " + "%lx asyncmap %lx\n", + param3, + (unsigned long) ppp->xmit_async_map[0]); } break; /* @@ -2377,11 +2441,11 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, error = verify_area (VERIFY_READ, (void *) param3, sizeof (temp_i)); if (error == 0) { - ppp->xmit_async_map[0] = get_fs_long (param3); + ppp->xmit_async_map[0] = get_long_user (param3); if (ppp->flags & SC_DEBUG) printk (KERN_INFO "ppp_tty_ioctl: set xmit asyncmap %lx\n", - ppp->xmit_async_map[0]); + (unsigned long) ppp->xmit_async_map[0]); } break; /* @@ -2391,11 +2455,11 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, error = verify_area (VERIFY_READ, (void *) param3, sizeof (temp_i)); if (error == 0) { - ppp->recv_async_map = get_fs_long (param3); + ppp->recv_async_map = get_long_user (param3); if (ppp->flags & SC_DEBUG) printk (KERN_INFO "ppp_tty_ioctl: set rcv asyncmap %lx\n", - ppp->recv_async_map); + (unsigned long) ppp->recv_async_map); } break; /* @@ -2405,7 +2469,7 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, error = verify_area (VERIFY_WRITE, (void *) param3, sizeof (temp_i)); if (error == 0) { - put_fs_long (ppp2dev (ppp)->base_addr, param3); + put_long_user (ppp2dev (ppp)->base_addr, param3); if (ppp->flags & SC_DEBUG) printk (KERN_INFO "ppp_tty_ioctl: get unit: %ld", @@ -2419,7 +2483,7 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, error = verify_area (VERIFY_READ, (void *) param3, sizeof (temp_i)); if (error == 0) { - temp_i = (int) (get_fs_long (param3) & 0x1F) << 16; + temp_i = (get_int_user (param3) & 0x1F) << 16; temp_i |= (ppp->flags & ~0x1F0000); if ((ppp->flags | temp_i) & SC_DEBUG) @@ -2436,7 +2500,7 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, sizeof (temp_i)); if (error == 0) { temp_i = (ppp->flags >> 16) & 0x1F; - put_fs_long ((long) temp_i, param3); + put_long_user ((long) temp_i, param3); if (ppp->flags & SC_DEBUG) printk (KERN_INFO @@ -2447,21 +2511,18 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, /* * Get the times since the last send/receive frame operation */ - case PPPIOCGTIME: + case PPPIOCGIDLE: error = verify_area (VERIFY_WRITE, (void *) param3, - sizeof (struct ppp_ddinfo)); + sizeof (struct ppp_idle)); if (error == 0) { - struct ppp_ddinfo cur_ddinfo; + struct ppp_idle cur_ddinfo; unsigned long cur_jiffies = jiffies; /* change absolute times to relative times. */ - cur_ddinfo.ip_sjiffies = cur_jiffies - ppp->ddinfo.ip_sjiffies; - cur_ddinfo.ip_rjiffies = cur_jiffies - ppp->ddinfo.ip_rjiffies; - cur_ddinfo.nip_sjiffies = cur_jiffies - ppp->ddinfo.nip_sjiffies; - cur_ddinfo.nip_rjiffies = cur_jiffies - ppp->ddinfo.nip_rjiffies; - + cur_ddinfo.xmit_idle = (cur_jiffies - ppp->ddinfo.xmit_idle) / HZ; + cur_ddinfo.recv_idle = (cur_jiffies - ppp->ddinfo.recv_idle) / HZ; memcpy_tofs ((void *) param3, &cur_ddinfo, - sizeof (struct ppp_ddinfo)); + sizeof (cur_ddinfo)); if (ppp->flags & SC_DEBUG) printk (KERN_INFO "ppp_tty_ioctl: read demand dial info\n"); @@ -2492,7 +2553,7 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, error = verify_area (VERIFY_READ, (void *) param3, sizeof (ppp->xmit_async_map)); if (error == 0) { - unsigned long temp_tbl[8]; + __u32 temp_tbl[8]; memcpy_fromfs (temp_tbl, (void *) param3, sizeof (ppp->xmit_async_map)); @@ -2521,7 +2582,7 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, error = verify_area (VERIFY_READ, (void *) param3, sizeof (temp_i)); if (error == 0) { - temp_i = (int) get_fs_long (param3) + 1; + temp_i = get_int_user (param3) + 1; if (ppp->flags & SC_DEBUG) printk (KERN_INFO "ppp_tty_ioctl: set maxcid to %d\n", @@ -2577,12 +2638,12 @@ ppp_tty_select (struct tty_struct *tty, struct inode *inode, /* * Verify the status of the PPP device. */ - if (!ppp || ppp->magic != PPP_MAGIC) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR - "ppp_tty_select: can't find PPP block from tty!\n"); + if (!ppp) return -EBADF; - } + + if (ppp->magic != PPP_MAGIC) + return -EBADF; + CHECK_PPP (0); /* * Branch on the type of select mode. A read request must lock the user @@ -2721,7 +2782,7 @@ ppp_dev_ioctl_version (struct ppp *ppp, struct ifreq *ifr) */ static int -ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr) +ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev) { struct ppp_stats *result, temp; int error; @@ -2736,15 +2797,12 @@ ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr) * Supply the information for the caller. First move the version data * then move the ppp stats; and finally the vj stats. */ - if (error == 0) { - memset (&temp, 0, sizeof(temp)); + memset (&temp, 0, sizeof(temp)); + if (error == 0 && dev->flags & IFF_UP) { memcpy (&temp.p, &ppp->stats, sizeof (struct pppstat)); -/* - * Header Compression statistics - */ if (ppp->slcomp != NULL) { - temp.vj.vjs_packets = ppp->slcomp->sls_o_nontcp + - ppp->slcomp->sls_o_tcp; + temp.vj.vjs_packets = ppp->slcomp->sls_o_compressed+ + ppp->slcomp->sls_o_uncompressed; temp.vj.vjs_compressed = ppp->slcomp->sls_o_compressed; temp.vj.vjs_searches = ppp->slcomp->sls_o_searches; temp.vj.vjs_misses = ppp->slcomp->sls_o_misses; @@ -2753,10 +2811,36 @@ ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr) temp.vj.vjs_uncompressedin = ppp->slcomp->sls_i_uncompressed; temp.vj.vjs_compressedin = ppp->slcomp->sls_i_compressed; } + } +/* + * Move the data to the caller's buffer + */ + if (error == 0) + memcpy_tofs (result, &temp, sizeof (temp)); + return error; +} + +/* + * IOCTL to read the compression statistics for the pppstats program. + */ + +static int +ppp_dev_ioctl_comp_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev) +{ + struct ppp_comp_stats *result, temp; + int error; +/* + * Must have write access to the buffer. + */ + result = (struct ppp_comp_stats *) ifr->ifr_ifru.ifru_data; + error = verify_area (VERIFY_WRITE, + result, + sizeof (temp)); /* - * Frame data compression statistics + * Supply the information for the caller. */ -#ifdef PPP_COMPRESS + memset (&temp, 0, sizeof(temp)); + if (error == 0 && dev->flags & IFF_UP) { if (ppp->sc_xc_state != NULL) (*ppp->sc_xcomp->comp_stat) (ppp->sc_xc_state, &temp.c); @@ -2764,13 +2848,12 @@ ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr) if (ppp->sc_rc_state != NULL) (*ppp->sc_rcomp->decomp_stat) (ppp->sc_rc_state, &temp.d); -#endif /* PPP_COMPRESS */ - + } /* * Move the data to the caller's buffer */ + if (error == 0) memcpy_tofs (result, &temp, sizeof (temp)); - } return error; } @@ -2788,7 +2871,11 @@ ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd) */ switch (cmd) { case SIOCGPPPSTATS: - error = ppp_dev_ioctl_stats (ppp, ifr); + error = ppp_dev_ioctl_stats (ppp, ifr, dev); + break; + + case SIOCGPPPCSTATS: + error = ppp_dev_ioctl_comp_stats (ppp, ifr, dev); break; case SIOCGPPPVER: @@ -2809,7 +2896,11 @@ ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd) * 1 if frame must be re-queued for later driver support. */ -int +#if defined(IPX_CHANGE) +#define ppp_dev_xmit_ip1 ppp_dev_xmit_ip +#endif + +static int ppp_dev_xmit_ip1 (struct device *dev, struct ppp *ppp, u_char *data) { int proto = PPP_IP; @@ -2872,7 +2963,7 @@ ppp_dev_xmit_ip1 (struct device *dev, struct ppp *ppp, u_char *data) len = slhc_compress (ppp->slcomp, data, len, buf_base (ppp->cbuf) + PPP_HARD_HDR_LEN, &data, - !(ppp->flags & SC_NO_TCP_CCID)); + (ppp->flags & SC_NO_TCP_CCID) == 0); if (data[0] & SL_TYPE_COMPRESSED_TCP) { proto = PPP_VJC_COMP; @@ -2906,10 +2997,11 @@ ppp_dev_xmit_ip1 (struct device *dev, struct ppp *ppp, u_char *data) * by this name. */ -int +#if !defined(IPX_CHANGE) +static int ppp_dev_xmit_ip (struct device *dev, struct ppp *ppp, u_char *data) { - struct ppp_hdr *hdr; + struct ppp_hdr *hdr; int len; int answer; @@ -2929,6 +3021,7 @@ ppp_dev_xmit_ip (struct device *dev, struct ppp *ppp, u_char *data) return answer; } +#endif /* !defined(IPX_CHANGE) */ /* * Send an IPX (or any other non-IP) frame to the remote. @@ -2937,7 +3030,12 @@ ppp_dev_xmit_ip (struct device *dev, struct ppp *ppp, u_char *data) * 1 if frame must be re-queued for later driver support. */ -int +#if defined(IPX_CHANGE) +#define ppp_dev_xmit_ipx1 ppp_dev_xmit_ipx +#endif + +#if defined(NEW_SKBUFF) || defined(IPX_CHANGE) +static int ppp_dev_xmit_ipx1 (struct device *dev, struct ppp *ppp, u_char *data, int len, int proto) { @@ -3008,7 +3106,8 @@ ppp_dev_xmit_ipx1 (struct device *dev, struct ppp *ppp, * by this name. */ -int +#if !defined(IPX_CHANGE) +static int ppp_dev_xmit_ipx (struct device *dev, struct ppp *ppp, u_char *data, int len, int proto) { @@ -3021,21 +3120,24 @@ ppp_dev_xmit_ipx (struct device *dev, struct ppp *ppp, answer = 1; else { memcpy (&hdr[1], data, len); - answer = (dev, ppp, (u_char *) &hdr[1], len, proto); + answer = ppp_dev_xmit_ipx1 (dev, ppp, (u_char *) &hdr[1], + len, proto); kfree (hdr); } return answer; } +#endif /* !defined(IPX_CHANGE) */ +#endif /* defined(NEW_SKBUFF) || defined(IPX_CHANGE) */ /* * Send a frame to the remote. */ -int +static int ppp_dev_xmit (sk_buff *skb, struct device *dev) { - int answer; + int answer, len; u_char *data; struct ppp *ppp = dev2ppp (dev); struct tty_struct *tty = ppp2tty (ppp); @@ -3059,8 +3161,8 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev) * Validate the tty linkage */ if (ppp->flags & SC_DEBUG) - printk (KERN_DEBUG "ppp_dev_xmit [%s]: skb %X\n", - dev->name, (int) skb); + printk (KERN_DEBUG "ppp_dev_xmit [%s]: skb %p\n", + dev->name, skb); /* * Validate the tty interface */ @@ -3075,35 +3177,49 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev) /* * Fetch the pointer to the data */ - data = skb_data (skb); + len = skb->len; + data = skb_data(skb); /* * Look at the protocol in the skb to determine the difference between * an IP frame and an IPX frame. */ -#ifdef NEW_SKBUFF - switch (skb->protocol) { - case htons (ETH_P_IPX): - answer = ppp_dev_xmit_ipx (dev, ppp, data, skb->len, PPP_IPX); +#if defined(NEW_SKBUFF) || defined(IPX_CHANGE) + switch (ntohs (skb->protocol)) { + case ETH_P_IPX: + answer = ppp_dev_xmit_ipx (dev, ppp, data, len, PPP_IPX); break; - case htons (ETH_P_IP): + case ETH_P_IP: answer = ppp_dev_xmit_ip (dev, ppp, data); break; default: /* All others have no support at this time. */ +#if 1 /* I **REALLY** want to toss this. For the time being, I'll assume + that this is IP. However, if you start to see the message below + then you should fix the skb->protocol to have the proper values. */ + + printk (KERN_ERR + "ppp: strange protocol type %x in ppp_dev_xmit\n", + skb->protocol); + answer = ppp_dev_xmit_ip (dev, ppp, data); + break; +#else /* Shortly, this is what it will be! */ dev_kfree_skb (skb, FREE_WRITE); return 0; +#endif /* if 1 */ } -#else +#else /* defined(NEW_SKBUFF) || defined(IPX_CHANGE) */ answer = ppp_dev_xmit_ip (dev, ppp, data); #endif /* * This is the end of the transmission. Release the buffer if it was sent. */ - if (answer == 0) + if (answer == 0) { dev_kfree_skb (skb, FREE_WRITE); + ppp->ddinfo.xmit_idle = jiffies; + } return answer; } @@ -3140,11 +3256,10 @@ ppp_dev_stats (struct device *dev) return &ppp_stats; } -#ifdef NEW_SKBUFF +#if defined(NEW_SKBUFF) /* - * The PPP protocol is currently pure IP (no IPX yet). This defines - * the protocol layer which is blank since the driver does all the - * cooking. + * This defines the protocol layer which is blank since the + * driver does all the cooking. */ static int ppp_dev_input (struct protocol *self, struct protocol *lower, @@ -3183,6 +3298,7 @@ static int ppp_dev_getkey(int protocol, int subid, unsigned char *key) #else +#if USE_SKB_PROTOCOL == 0 /* * Called to enquire about the type of the frame in the buffer. Return * ETH_P_IP for an IP frame, ETH_P_IPX for an IPX frame. @@ -3193,10 +3309,17 @@ ppp_dev_type (sk_buff *skb, struct device *dev) { return (htons (ETH_P_IP)); } +#endif -static int -ppp_dev_header (u_char * buff, struct device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len, sk_buff *skb) +#if USE_SKB_PROTOCOL == 0 +static int ppp_dev_header (unsigned char *buff, struct device *dev, + unsigned short type, void *daddr, void *saddr, + unsigned len, struct sk_buff *skb) +#else +static int ppp_dev_header (sk_buff *skb, struct device *dev, + unsigned short type, void *daddr, + void *saddr, unsigned len) +#endif { return (0); } @@ -3218,7 +3341,6 @@ ppp_dev_rebuild (void *buff, struct device *dev, unsigned long raddr, static struct ppp * ppp_alloc (void) { -#if 1 int if_num; int status; ppp_ctrl_t *ctl; @@ -3234,7 +3356,7 @@ ppp_alloc (void) if (!set_bit(0, &ppp->inuse)) return (ppp); ctl = ctl->next; - if (++if_num == INT_MAX) + if (++if_num == max_dev) return (NULL); } /* @@ -3270,7 +3392,7 @@ ppp_alloc (void) status = register_netdev (dev); if (status == 0) { - printk ("registered device %s\n", dev->name); + printk (KERN_INFO "registered device %s\n", dev->name); return (ppp); } @@ -3280,13 +3402,6 @@ ppp_alloc (void) /* This one will forever be busy as it is not initialized */ } return (NULL); -#else - int i; - for (i = 0; i < PPP_NRUNIT; i++) - if (!set_bit(0, &ppp_ctrl[i].inuse)) return &ppp_ctrl[i]; - - return NULL; -#endif } /* @@ -3294,7 +3409,7 @@ ppp_alloc (void) */ static void -ppp_print_hex (register u_char * out, u_char * in, int count) +ppp_print_hex (register u_char * out, const u_char * in, int count) { register u_char next_ch; static char hex[] = "0123456789ABCDEF"; @@ -3308,7 +3423,7 @@ ppp_print_hex (register u_char * out, u_char * in, int count) } static void -ppp_print_char (register u_char * out, u_char * in, int count) +ppp_print_char (register u_char * out, const u_char * in, int count) { register u_char next_ch; @@ -3327,7 +3442,7 @@ ppp_print_char (register u_char * out, u_char * in, int count) } static void -ppp_print_buffer (const u_char * name, u_char * buf, int count) +ppp_print_buffer (const u_char * name, const u_char * buf, int count) { u_char line[44]; @@ -3351,13 +3466,95 @@ ppp_print_buffer (const u_char * name, u_char * buf, int count) } } +/************************************************************* + * Compressor module interface + *************************************************************/ + +struct compressor_link { + struct compressor_link *next; + struct compressor *comp; +}; + +static struct compressor_link *ppp_compressors = (struct compressor_link *) 0; + +static struct compressor *find_compressor (int type) +{ + struct compressor_link *lnk; + unsigned long flags; + + save_flags(flags); + cli(); + + lnk = ppp_compressors; + while (lnk != (struct compressor_link *) 0) { + if ((int) (unsigned char) lnk->comp->compress_proto == type) { + restore_flags(flags); + return lnk->comp; + } + lnk = lnk->next; + } + + restore_flags(flags); + return (struct compressor *) 0; +} + +static int ppp_register_compressor (struct compressor *cp) +{ + struct compressor_link *new; + unsigned long flags; + + new = (struct compressor_link *) kmalloc (sizeof (struct compressor_link), GFP_KERNEL); + + if (new == (struct compressor_link *) 0) + return 1; + + save_flags(flags); + cli(); + + if (find_compressor (cp->compress_proto)) { + restore_flags(flags); + kfree (new); + return 0; + } + + new->next = ppp_compressors; + new->comp = cp; + ppp_compressors = new; + + restore_flags(flags); + return 0; +} + +static void ppp_unregister_compressor (struct compressor *cp) +{ + struct compressor_link *prev = (struct compressor_link *) 0; + struct compressor_link *lnk; + unsigned long flags; + + save_flags(flags); + cli(); + + lnk = ppp_compressors; + while (lnk != (struct compressor_link *) 0) { + if (lnk->comp == cp) { + if (prev) + prev->next = lnk->next; + else + ppp_compressors = lnk->next; + kfree (lnk); + break; + } + prev = lnk; + lnk = lnk->next; + } + restore_flags(flags); +} + /************************************************************* * Module support routines *************************************************************/ #ifdef MODULE -char kernel_version[] = UTS_RELEASE; - int init_module(void) { @@ -3365,10 +3562,11 @@ init_module(void) /* register our line disciplines */ status = ppp_first_time(); - if (status != 0) { + if (status != 0) printk (KERN_INFO "PPP: ppp_init() failure %d\n", status); - } + else + (void) register_symtab (&ppp_syms); return (status); } @@ -3379,27 +3577,30 @@ cleanup_module(void) ppp_ctrl_t *ctl, *next_ctl; struct device *dev; struct ppp *ppp; - int busy_flag = MOD_IN_USE; + int busy_flag = 0; /* * Ensure that the devices are not in operation. */ - if (!busy_flag) { - ctl = ppp_list; - while (ctl) { - ppp = ctl2ppp (ctl); - if (ppp->inuse && ppp->tty != NULL) { - busy_flag = 1; - break; - } + ctl = ppp_list; + while (ctl) { + ppp = ctl2ppp (ctl); + if (ppp->inuse && ppp->tty != NULL) { + busy_flag = 1; + break; + } - dev = ctl2dev (ctl); - if (dev->start || dev->flags & IFF_UP) { - busy_flag = 1; - break; - } - ctl = ctl->next; + dev = ctl2dev (ctl); + if (dev->start || dev->flags & IFF_UP) { + busy_flag = 1; + break; } + ctl = ctl->next; } +/* + * Ensure that there are no compressor modules registered + */ + if (ppp_compressors != NULL) + busy_flag = 1; if (busy_flag) { printk (KERN_INFO @@ -3417,22 +3618,19 @@ cleanup_module(void) "(err = %d)\n", status); else printk (KERN_INFO - "PPP: ppp line discipline successfully unregistered\n"); + "PPP: ppp line discipline successfully unregistered\n"); /* * De-register the devices so that there is no problem with them */ - next = ppp_list; - while (next) { - ctl = next; - ppp = ctl2ppp (ctl); - dev = ctl2dev (ctl); - - ppp_release (ppp); + next_ctl = ppp_list; + while (next_ctl) { + ctl = next_ctl; + next_ctl = ctl->next; + ppp = ctl2ppp (ctl); + dev = ctl2dev (ctl); + + ppp_release (ppp); unregister_netdev (dev); -/* - * Release the storage occupied by the control structures - */ - next = ctl->next; kfree (ctl); } } diff --git a/linux/ppp_defs.h b/linux/ppp_defs.h new file mode 100644 index 0000000..8913ae7 --- /dev/null +++ b/linux/ppp_defs.h @@ -0,0 +1,177 @@ +/* $Id: ppp_defs.h,v 1.1 1995/12/18 03:38:15 paulus Exp $ */ + +/* + * ppp_defs.h - PPP definitions. + * + * Copyright (c) 1994 The Australian National University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, provided that the above copyright + * notice appears in all copies. This software is provided without any + * warranty, express or implied. The Australian National University + * makes no representations about the suitability of this software for + * any purpose. + * + * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY + * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, + * OR MODIFICATIONS. + */ + +/* + * ==FILEVERSION 6== + * + * NOTE TO MAINTAINERS: + * If you modify this file at all, increment the number above. + * ppp_defs.h is shipped with a PPP distribution as well as with the kernel; + * if everyone increases the FILEVERSION number above, then scripts + * can do the right thing when deciding whether to install a new ppp_defs.h + * file. Don't change the format of that line otherwise, so the + * installation script can recognize it. + */ + +#ifndef _PPP_DEFS_H_ +#define _PPP_DEFS_H_ + +/* + * The basic PPP frame. + */ +#define PPP_HDRLEN 4 /* octets for standard ppp header */ +#define PPP_FCSLEN 2 /* octets for FCS */ +#define PPP_MRU 1500 /* default MRU = max length of info field */ + +#define PPP_ADDRESS(p) (((u_char *)(p))[0]) +#define PPP_CONTROL(p) (((u_char *)(p))[1]) +#define PPP_PROTOCOL(p) ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3]) + +/* + * Significant octet values. + */ +#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ +#define PPP_UI 0x03 /* Unnumbered Information */ +#define PPP_FLAG 0x7e /* Flag Sequence */ +#define PPP_ESCAPE 0x7d /* Asynchronous Control Escape */ +#define PPP_TRANS 0x20 /* Asynchronous transparency modifier */ + +/* + * Protocol field values. + */ +#define PPP_IP 0x21 /* Internet Protocol */ +#define PPP_IPX 0x2b /* IPX protocol */ +#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */ +#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */ +#define PPP_COMP 0xfd /* compressed packet */ +#define PPP_IPCP 0x8021 /* IP Control Protocol */ +#define PPP_IPXCP 0x802b /* IPX Control Protocol */ +#define PPP_CCP 0x80fd /* Compression Control Protocol */ +#define PPP_LCP 0xc021 /* Link Control Protocol */ +#define PPP_PAP 0xc023 /* Password Authentication Protocol */ +#define PPP_LQR 0xc025 /* Link Quality Report protocol */ +#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */ + +/* + * A 32-bit unsigned integral type. + */ +#ifndef __BIT_TYPES_DEFINED__ +#ifdef UINT32_T +typedef UINT32_T u_int32_t; +#else +typedef unsigned int u_int32_t; +#endif +#endif + +/* + * Extended asyncmap - allows any character to be escaped. + */ +typedef u_int32_t ext_accm[8]; + +/* + * What to do with network protocol (NP) packets. + */ +enum NPmode { + NPMODE_PASS, /* pass the packet through */ + NPMODE_DROP, /* silently drop the packet */ + NPMODE_ERROR, /* return an error */ + NPMODE_QUEUE /* save it up for later. */ +}; + +/* + * Statistics for LQRP and pppstats + */ +struct pppstat { + u_int ppp_discards; /* # frames discarded */ + + u_int ppp_ibytes; /* bytes received */ + u_int ppp_ioctects; /* bytes received not in error */ + u_int ppp_ipackets; /* packets received */ + u_int ppp_ierrors; /* receive errors */ + u_int ppp_ilqrs; /* # LQR frames received */ + + u_int ppp_obytes; /* raw bytes sent */ + u_int ppp_ooctects; /* frame bytes sent */ + u_int ppp_opackets; /* packets sent */ + u_int ppp_oerrors; /* transmit errors */ + u_int ppp_olqrs; /* # LQR frames sent */ +}; + +struct vjstat { + u_int vjs_packets; /* outbound packets */ + u_int vjs_compressed; /* outbound compressed packets */ + u_int vjs_searches; /* searches for connection state */ + u_int vjs_misses; /* times couldn't find conn. state */ + u_int vjs_uncompressedin; /* inbound uncompressed packets */ + u_int vjs_compressedin; /* inbound compressed packets */ + u_int vjs_errorin; /* inbound unknown type packets */ + u_int vjs_tossed; /* inbound packets tossed because of error */ +}; + +struct compstat { + u_int unc_bytes; /* total uncompressed bytes */ + u_int unc_packets; /* total uncompressed packets */ + u_int comp_bytes; /* compressed bytes */ + u_int comp_packets; /* compressed packets */ + u_int inc_bytes; /* incompressible bytes */ + u_int inc_packets; /* incompressible packets */ + /* the compression ratio is defined as in_count / bytes_out */ + u_int in_count; /* Bytes received */ + u_int bytes_out; /* Bytes transmitted */ + double ratio; /* not computed in kernel. */ +}; + +struct ppp_stats { + struct pppstat p; /* basic PPP statistics */ + struct vjstat vj; /* VJ header compression statistics */ +}; + +struct ppp_comp_stats { + struct compstat c; /* packet compression statistics */ + struct compstat d; /* packet decompression statistics */ +}; + +/* + * The following structure records the time in seconds since + * the last NP packet was sent or received. + */ +struct ppp_idle { + time_t xmit_idle; /* time since last NP packet sent */ + time_t recv_idle; /* time since last NP packet received */ +}; + +#ifndef __P +#ifdef __STDC__ +#define __P(x) x +#else +#define __P(x) () +#endif +#endif + +#endif /* _PPP_DEFS_H_ */ diff --git a/linux/route.h b/linux/route.h new file mode 100644 index 0000000..5be4853 --- /dev/null +++ b/linux/route.h @@ -0,0 +1,78 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Global definitions for the IP router interface. + * + * Version: @(#)route.h 1.0.3 05/27/93 + * + * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988 + * for the purposes of compatibility only. + * + * Fred N. van Kempen, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _LINUX_ROUTE_H +#define _LINUX_ROUTE_H + +#include + + +/* This structure gets passed by the SIOCADDRT and SIOCDELRT calls. */ +struct rtentry +{ + unsigned long rt_hash; /* hash key for lookups */ + struct sockaddr rt_dst; /* target address */ + struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */ + struct sockaddr rt_genmask; /* target network mask (IP) */ + short rt_flags; + short rt_refcnt; + unsigned long rt_use; + struct ifnet *rt_ifp; + short rt_metric; /* +1 for binary compatibility! */ + char *rt_dev; /* forcing the device at add */ + unsigned long rt_mss; /* per route MTU/Window */ + unsigned long rt_window; /* Window clamping */ + unsigned short rt_irtt; /* Initial RTT */ +}; + + +#define RTF_UP 0x0001 /* route usable */ +#define RTF_GATEWAY 0x0002 /* destination is a gateway */ +#define RTF_HOST 0x0004 /* host entry (net otherwise) */ +#define RTF_REINSTATE 0x0008 /* reinstate route after tmout */ +#define RTF_DYNAMIC 0x0010 /* created dyn. (by redirect) */ +#define RTF_MODIFIED 0x0020 /* modified dyn. (by redirect) */ +#define RTF_MSS 0x0040 /* specific MSS for this route */ +#define RTF_WINDOW 0x0080 /* per route window clamping */ +#define RTF_IRTT 0x0100 /* Initial round trip time */ +#define RTF_REJECT 0x0200 /* Reject route */ + +/* + * This structure is passed from the kernel to user space by netlink + * routing/device announcements + */ + +struct netlink_rtinfo +{ + unsigned long rtmsg_type; + struct sockaddr rtmsg_dst; + struct sockaddr rtmsg_gateway; + struct sockaddr rtmsg_genmask; + short rtmsg_flags; + short rtmsg_metric; + char rtmsg_device[16]; +}; + +#define RTMSG_NEWROUTE 0x01 +#define RTMSG_DELROUTE 0x02 +#define RTMSG_NEWDEVICE 0x11 +#define RTMSG_DELDEVICE 0x12 + +#endif /* _LINUX_ROUTE_H */ + diff --git a/pppd/Makefile.linux b/pppd/Makefile.linux index b1376ec..b67d854 100644 --- a/pppd/Makefile.linux +++ b/pppd/Makefile.linux @@ -1,15 +1,15 @@ # # pppd makefile for Linux -# $Id: Makefile.linux,v 1.9 1995/12/11 02:55:25 paulus Exp $ +# $Id: Makefile.linux,v 1.10 1995/12/18 03:32:57 paulus Exp $ # PPPDSRCS = main.c magic.c fsm.c lcp.c ipcp.c upap.c chap.c md5.c ccp.c \ - auth.c options.c sys-linux.c + auth.c options.c sys-linux.c ipxcp.c HEADERS = callout.h pathnames.h patchlevel.h chap.h md5.h MANPAGES = pppd.8 PPPDOBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap.o md5.o ccp.o \ - auth.o options.o sys-linux.o + auth.o options.o sys-linux.o ipxcp.o all: pppd @@ -22,12 +22,12 @@ endif # CC = gcc # DEBUG_FLAGS = -DDEBUGALL -COMPILE_FLAGS = -D_linux_=1 -DHAVE_PATHS_H +COMPILE_FLAGS = -D_linux_=1 -DHAVE_PATHS_H # -DUSE_MS_DNS=1 # -DIPX_CHANGE=1 COPTS = -g # -O2 VER = 0.2.8 LIBS = -lbsd -CFLAGS = $(COPTS) $(DEBUG_FLAGS) $(COMPILE_FLAGS) +CFLAGS= $(COPTS) $(DEBUG_FLAGS) $(COMPILE_FLAGS) SOURCE= RELNOTES Makefile.linux $(PPPDSRCS) $(HEADERS) $(MANPAGES) install: pppd diff --git a/pppd/ipxcp.c b/pppd/ipxcp.c new file mode 100644 index 0000000..fcae076 --- /dev/null +++ b/pppd/ipxcp.c @@ -0,0 +1,1360 @@ +/* + * ipxcp.c - PPP IPX Control Protocol. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifdef IPX_CHANGE +#ifndef lint +static char rcsid[] = "$Id: ipxcp.c,v 1.1 1995/12/18 03:32:59 paulus Exp $"; +#endif + +/* + * TODO: + */ + +#include +#include +#include +#include +#include +#include + +#include "pppd.h" +#include "fsm.h" +#include "ipxcp.h" +#include "pathnames.h" + +/* global vars */ +ipxcp_options ipxcp_wantoptions[NUM_PPP]; /* Options that we want to request */ +ipxcp_options ipxcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */ +ipxcp_options ipxcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */ +ipxcp_options ipxcp_hisoptions[NUM_PPP]; /* Options that we ack'd */ + +#define wo (&ipxcp_wantoptions[0]) +#define ao (&ipxcp_allowoptions[0]) +#define go (&ipxcp_gotoptions[0]) +#define ho (&ipxcp_hisoptions[0]) + +/* + * Callbacks for fsm code. (CI = Configuration Information) + */ +static void ipxcp_resetci __P((fsm *)); /* Reset our CI */ +static int ipxcp_cilen __P((fsm *)); /* Return length of our CI */ +static void ipxcp_addci __P((fsm *, u_char *, int *)); /* Add our CI */ +static int ipxcp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */ +static int ipxcp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */ +static int ipxcp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */ +static int ipxcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */ +static void ipxcp_up __P((fsm *)); /* We're UP */ +static void ipxcp_down __P((fsm *)); /* We're DOWN */ +static void ipxcp_script __P((fsm *, char *)); /* Run an up/down script */ + +fsm ipxcp_fsm[NUM_PPP]; /* IPXCP fsm structure */ + +static fsm_callbacks ipxcp_callbacks = { /* IPXCP callback routines */ + ipxcp_resetci, /* Reset our Configuration Information */ + ipxcp_cilen, /* Length of our Configuration Information */ + ipxcp_addci, /* Add our Configuration Information */ + ipxcp_ackci, /* ACK our Configuration Information */ + ipxcp_nakci, /* NAK our Configuration Information */ + ipxcp_rejci, /* Reject our Configuration Information */ + ipxcp_reqci, /* Request peer's Configuration Information */ + ipxcp_up, /* Called when fsm reaches OPENED state */ + ipxcp_down, /* Called when fsm leaves OPENED state */ + NULL, /* Called when we want the lower layer up */ + NULL, /* Called when we want the lower layer down */ + NULL, /* Called when Protocol-Reject received */ + NULL, /* Retransmission is necessary */ + NULL, /* Called to handle protocol-specific codes */ + "IPXCP" /* String name of protocol */ +}; + +struct protent ipxcp_protent = { + PPP_IPXCP, ipxcp_init, ipxcp_input, ipxcp_protrej, + ipxcp_lowerup, ipxcp_lowerdown, ipxcp_open, ipxcp_close, + ipxcp_printpkt, NULL, 0, "IPXCP" +}; + + +/* + * Lengths of configuration options. + */ + +#define CILEN_VOID 2 +#define CILEN_COMPLETE 2 /* length of complete option */ +#define CILEN_NETN 6 /* network number length option */ +#define CILEN_NODEN 8 /* node number length option */ +#define CILEN_PROTOCOL 4 /* Minimum length of routing protocol */ +#define CILEN_NAME 3 /* Minimum length of router name */ +#define CILEN_COMPRESS 4 /* Minimum length of compression protocol */ + +#define CODENAME(x) ((x) == CONFACK ? "ACK" : \ + (x) == CONFNAK ? "NAK" : "REJ") + +/* Used in printing the node number */ +#define NODE(base) base[0], base[1], base[2], base[3], base[4], base[5] + +/* Used to generate the proper bit mask */ +#define BIT(num) (1 << (num)) + +/* + * Make a string representation of a network IP address. + */ + +char * +ipx_ntoa(ipxaddr) +u_int32_t ipxaddr; +{ + static char b[64]; + sprintf(b, "%lx", ipxaddr); + return b; +} + + +/* + * ipxcp_init - Initialize IPXCP. + */ +void +ipxcp_init(unit) + int unit; +{ + fsm *f = &ipxcp_fsm[unit]; + + f->unit = unit; + f->protocol = PPP_IPXCP; + f->callbacks = &ipxcp_callbacks; + fsm_init(&ipxcp_fsm[unit]); + + memset (wo->name, 0, sizeof (wo->name)); + memset (wo->our_node, 0, sizeof (wo->our_node)); + memset (wo->his_node, 0, sizeof (wo->his_node)); + + wo->neg_nn = 1; + wo->neg_complete = 1; + wo->network = 0; + + ao->neg_node = 1; + ao->neg_nn = 1; + ao->neg_name = 1; + ao->neg_complete = 1; + ao->neg_router = 1; + + ao->accept_local = 0; + ao->accept_remote = 0; + ao->accept_network = 0; +} + +/* + * Copy the node number + */ + +static void +copy_node (src, dst) +u_char *src, *dst; +{ + memcpy (dst, src, sizeof (ipxcp_wantoptions[0].our_node)); +} + +/* + * Compare node numbers + */ + +static int +compare_node (src, dst) +u_char *src, *dst; +{ + return memcmp (dst, src, sizeof (ipxcp_wantoptions[0].our_node)) == 0; +} + +/* + * Is the node number zero? + */ + +static int +zero_node (node) +u_char *node; +{ + int indx; + for (indx = 0; indx < sizeof (ipxcp_wantoptions[0].our_node); ++indx) + if (node [indx] != 0) + return 0; + return 1; +} + +/* + * Increment the node number + */ + +static void +inc_node (node) +u_char *node; +{ + u_char *outp; + u_int32_t magic_num; + + outp = node; + magic_num = magic(); + *outp++ = '\0'; + *outp++ = '\0'; + PUTLONG (magic_num, outp); +} + +/* + * ipxcp_open - IPXCP is allowed to come up. + */ +void +ipxcp_open(unit) + int unit; +{ + fsm_open(&ipxcp_fsm[unit]); +} + +/* + * ipxcp_close - Take IPXCP down. + */ +void +ipxcp_close(unit, reason) + int unit; + char *reason; +{ + fsm_close(&ipxcp_fsm[unit], reason); +} + + +/* + * ipxcp_lowerup - The lower layer is up. + */ +void +ipxcp_lowerup(unit) + int unit; +{ + extern int ipx_enabled; + + fsm_lowerup(&ipxcp_fsm[unit], ipx_enabled); +} + + +/* + * ipxcp_lowerdown - The lower layer is down. + */ +void +ipxcp_lowerdown(unit) + int unit; +{ + fsm_lowerdown(&ipxcp_fsm[unit]); +} + + +/* + * ipxcp_input - Input IPXCP packet. + */ +void +ipxcp_input(unit, p, len) + int unit; + u_char *p; + int len; +{ + fsm_input(&ipxcp_fsm[unit], p, len); +} + + +/* + * ipxcp_protrej - A Protocol-Reject was received for IPXCP. + * + * Pretend the lower layer went down, so we shut up. + */ +void +ipxcp_protrej(unit) + int unit; +{ + fsm_lowerdown(&ipxcp_fsm[unit]); +} + + +/* + * ipxcp_resetci - Reset our CI. + */ +static void +ipxcp_resetci(f) + fsm *f; +{ + u_int32_t network; + int unit = f->unit; + + wo->req_node = wo->neg_node && ao->neg_node; + wo->req_nn = wo->neg_nn && ao->neg_nn; + + if (wo->our_network == 0) { + wo->neg_node = 1; + ao->accept_network = 1; + } +/* + * If our node number is zero then change it. + */ + if (zero_node (wo->our_node)) { + inc_node (wo->our_node); + ao->accept_local = 1; + wo->neg_node = 1; + } +/* + * If his node number is zero then change it. + */ + if (zero_node (wo->his_node)) { + inc_node (wo->his_node); + ao->accept_remote = 1; + } +/* + * Unless router protocol is suppressed then assume that we can do RIP. + */ + if (! (wo->router & BIT(0))) + wo->router |= BIT(2); +/* + * Router protocol is only negotiated if requested. Others force the + * negotiation. + */ + if (wo->router & (BIT(2) | BIT(4))) + wo->neg_router = 1; +/* + * Start with these default values + */ + *go = *wo; +} + +/* + * ipxcp_cilen - Return length of our CI. + */ +static int +ipxcp_cilen(f) + fsm *f; +{ + int unit = f->unit; + int len; + + len = go->neg_nn ? CILEN_NETN : 0; + len += go->neg_node ? CILEN_NODEN : 0; + len += go->neg_name ? CILEN_NAME + strlen (go->name) - 1 : 0; + len += go->neg_complete ? CILEN_COMPLETE : 0; +/* + * Router protocol 0 is mutually exclusive with the others. + */ + if (go->neg_router) { + if (go->router & BIT(0)) + len += CILEN_PROTOCOL; + else { + if (go->router & BIT(2)) + len += CILEN_PROTOCOL; + if (go->router & BIT(4)) + len += CILEN_PROTOCOL; + } + } + + return (len); +} + + +/* + * ipxcp_addci - Add our desired CIs to a packet. + */ +static void +ipxcp_addci(f, ucp, lenp) + fsm *f; + u_char *ucp; + int *lenp; +{ + int len = *lenp; + int unit = f->unit; +/* + * Add the options to the record. + */ + if (go->neg_nn) { + PUTCHAR (IPX_NETWORK_NUMBER, ucp); + PUTCHAR (CILEN_NETN, ucp); + PUTLONG (go->our_network, ucp); + } + + if (go->neg_node) { + int indx; + PUTCHAR (IPX_NODE_NUMBER, ucp); + PUTCHAR (CILEN_NODEN, ucp); + for (indx = 0; indx < sizeof (go->our_node); ++indx) + PUTCHAR (go->our_node[indx], ucp); + } + + if (go->neg_name) { + int cilen = strlen (go->name); + int indx; + PUTCHAR (IPX_ROUTER_NAME, ucp); + PUTCHAR (CILEN_NAME + cilen - 1, ucp); + for (indx = 0; indx < cilen; ++indx) + PUTCHAR (go->name [indx], ucp); + } + + if (go->neg_router && (go->router & (BIT(0) | BIT(2) | BIT(4)))) { + if (go->router & BIT(0)) { + PUTCHAR (IPX_ROUTER_PROTOCOL, ucp); + PUTCHAR (CILEN_PROTOCOL, ucp); + PUTSHORT (0, ucp); + } else { + if (go->router & BIT(2)) { + PUTCHAR (IPX_ROUTER_PROTOCOL, ucp); + PUTCHAR (CILEN_PROTOCOL, ucp); + PUTSHORT (2, ucp); + } + + if (go->router & BIT(4)) { + PUTCHAR (IPX_ROUTER_PROTOCOL, ucp); + PUTCHAR (CILEN_PROTOCOL, ucp); + PUTSHORT (4, ucp); + } + } + } + + if (go->neg_complete) { + PUTCHAR (IPX_COMPLETE, ucp); + PUTCHAR (CILEN_COMPLETE, ucp); + } +} + +/* + * ipxcp_ackci - Ack our CIs. + * + * Returns: + * 0 - Ack was bad. + * 1 - Ack was good. + */ +static int +ipxcp_ackci(f, p, len) + fsm *f; + u_char *p; + int len; +{ + int unit = f->unit; + u_short cilen, citype, cishort; + u_char cichar; + u_int32_t cilong; + +#define ACKCIVOID(opt, neg) \ + if (neg) { \ + if ((len -= CILEN_VOID) < 0) \ + break; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_VOID || \ + citype != opt) \ + break; \ + } + +#define ACKCICOMPLETE(opt,neg) ACKCIVOID(opt, neg) + +#define ACKCICHARS(opt, neg, val, cnt) \ + if (neg) { \ + int indx, count = cnt; \ + len -= (count + 2); \ + if (len < 0) \ + break; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != (count + 2) || \ + citype != opt) \ + break; \ + for (indx = 0; indx < count; ++indx) {\ + GETCHAR(cichar, p); \ + if (cichar != ((u_char *) &val)[indx]) \ + break; \ + }\ + if (indx != count) \ + break; \ + } + +#define ACKCINODE(opt,neg,val) ACKCICHARS(opt,neg,val,sizeof(val)) +#define ACKCINAME(opt,neg,val) ACKCICHARS(opt,neg,val,strlen(val)) + +#define ACKCINETWORK(opt, neg, val) \ + if (neg) { \ + if ((len -= CILEN_NETN) < 0) \ + break; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_NETN || \ + citype != opt) \ + break; \ + GETLONG(cilong, p); \ + if (cilong != val) \ + break; \ + } + +#define ACKCIPROTO(opt, neg, val, bit) \ + if (neg && (val & BIT(bit))) \ + { \ + if (len < 2) \ + break; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_PROTOCOL || citype != opt) \ + break; \ + len -= cilen; \ + if (len < 0) \ + break; \ + GETSHORT(cishort, p); \ + if (cishort != (bit)) \ + break; \ + } +/* + * Process the ACK frame in the order in which the frame was assembled + */ + do { + ACKCINETWORK (IPX_NETWORK_NUMBER, go->neg_nn, go->our_network); + ACKCINODE (IPX_NODE_NUMBER, go->neg_node, go->our_node); + ACKCINAME (IPX_ROUTER_NAME, go->neg_name, go->name); + ACKCIPROTO (IPX_ROUTER_PROTOCOL, go->neg_router, go->router, 0); + ACKCIPROTO (IPX_ROUTER_PROTOCOL, go->neg_router, go->router, 2); + ACKCIPROTO (IPX_ROUTER_PROTOCOL, go->neg_router, go->router, 4); + ACKCICOMPLETE (IPX_COMPLETE, go->neg_complete); +/* + * This is the end of the record. + */ + if (len == 0) + return (1); + } while (0); +/* + * The frame is invalid + */ + IPXCPDEBUG((LOG_INFO, "ipxcp_ackci: received bad Ack!")); + return (0); +} + +/* + * ipxcp_nakci - Peer has sent a NAK for some of our CIs. + * This should not modify any state if the Nak is bad + * or if IPXCP is in the OPENED state. + * + * Returns: + * 0 - Nak was bad. + * 1 - Nak was good. + */ + +static int +ipxcp_nakci(f, p, len) + fsm *f; + u_char *p; + int len; +{ + int unit = f->unit; + u_char citype, cilen, *next; + u_short s; + u_int32_t l; + ipxcp_options no; /* options we've seen Naks for */ + ipxcp_options try; /* options to request next time */ + + BZERO(&no, sizeof(no)); + try = *go; + + while (len > CILEN_VOID) { + GETCHAR (citype, p); + GETCHAR (cilen, p); + len -= cilen; + if (len < 0) + goto bad; + next = &p [cilen - CILEN_VOID]; + + switch (citype) { + case IPX_NETWORK_NUMBER: + if (!go->neg_nn || no.neg_nn || (cilen != CILEN_NETN)) + goto bad; + no.neg_nn = 1; + + GETLONG(l, p); + IPXCPDEBUG((LOG_INFO, "local IP address %d", l)); + if (l && ao->accept_network) + try.our_network = l; + break; + + case IPX_NODE_NUMBER: + if (!go->neg_node || no.neg_node || (cilen != CILEN_NODEN)) + goto bad; + no.neg_node = 1; + + IPXCPDEBUG((LOG_INFO, + "local node number %02X%02X%02X%02X%02X%02X", + NODE(p))); + + if (!zero_node (p) && ao->accept_local && + ! compare_node (p, ho->his_node)) + copy_node (p, try.our_node); + break; + + /* These have never been sent. Ignore the NAK frame */ + case IPX_COMPRESSION_PROTOCOL: + goto bad; + + case IPX_ROUTER_PROTOCOL: + if (!go->neg_router || (cilen < CILEN_PROTOCOL)) + goto bad; + + GETSHORT (s, p); + if ((s != 0) && (s != 2) && (s != 4)) + goto bad; + + if (no.router & BIT(s)) + goto bad; + + if (no.router == 0) /* Reset on first NAK only */ + try.router = 0; + no.router |= BIT(s); + try.router |= BIT(s); + try.neg_router = 1; + + IPXCPDEBUG((LOG_INFO, "Router protocol number %d", s)); + break; + + /* These, according to the RFC, must never be NAKed. */ + case IPX_ROUTER_NAME: + case IPX_COMPLETE: + goto bad; + + /* These are for options which we have not seen. */ + default: + break; + } + p = next; + } + + /* If there is still anything left, this packet is bad. */ + if (len != 0) + goto bad; + + /* + * Do not permit the peer to force a router protocol which we do not + * support. + */ + try.router &= go->router; + if (try.router == 0 && go->router != 0) { + try.neg_router = 1; + try.router = BIT(0); + } + + /* + * OK, the Nak is good. Now we can update state. + */ + if (f->state != OPENED) + *go = try; + + return 1; + +bad: + IPXCPDEBUG((LOG_INFO, "ipxcp_nakci: received bad Nak!")); + return 0; +} + +/* + * ipxcp_rejci - Reject some of our CIs. + */ +static int +ipxcp_rejci(f, p, len) + fsm *f; + u_char *p; + int len; +{ + int unit = f->unit; + u_short cilen, citype, cishort; + u_char cichar; + u_int32_t cilong; + ipxcp_options try; /* options to request next time */ + +#define REJCINETWORK(opt, neg, val) \ + if (neg) { \ + neg = 0; \ + if ((len -= CILEN_NETN) < 0) \ + break; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_NETN || \ + citype != opt) \ + break; \ + GETLONG(cilong, p); \ + if (cilong != val) \ + break; \ + IPXCPDEBUG((LOG_INFO,"ipxcp_rejci rejected long opt %d", opt)); \ + } + +#define REJCICHARS(opt, neg, val, cnt) \ + if (neg) { \ + int indx, count = cnt; \ + neg = 0; \ + len -= (count + 2); \ + if (len < 0) \ + break; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != (count + 2) || \ + citype != opt) \ + break; \ + for (indx = 0; indx < count; ++indx) {\ + GETCHAR(cichar, p); \ + if (cichar != ((u_char *) &val)[indx]) \ + break; \ + }\ + if (indx != count) \ + break; \ + IPXCPDEBUG((LOG_INFO,"ipxcp_rejci rejected opt %d", opt)); \ + } + +#define REJCINODE(opt,neg,val) REJCICHARS(opt,neg,val,sizeof(val)) +#define REJCINAME(opt,neg,val) REJCICHARS(opt,neg,val,strlen(val)) + +#define REJCIVOID(opt, neg) \ + if (neg) { \ + neg = 0; \ + if ((len -= CILEN_VOID) < 0) \ + break; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_VOID || citype != opt) \ + break; \ + IPXCPDEBUG((LOG_INFO, "ipxcp_rejci rejected void opt %d", opt)); \ + } + +#define REJCIPROTO(opt, neg, val, bit) \ + if (neg && (val & BIT(bit))) \ + { \ + if (len < 2) \ + break; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_PROTOCOL || citype != opt) \ + break; \ + len -= cilen; \ + if (len < 0) \ + break; \ + GETSHORT(cishort, p); \ + if (cishort != (bit)) \ + break; \ + IPXCPDEBUG((LOG_INFO, "ipxcp_rejci rejected router proto %d", bit)); \ + val &= ~BIT(bit); \ + if (val == 0) \ + neg = 0; \ + } + +/* + * Any Rejected CIs must be in exactly the same order that we sent. + * Check packet length and CI length at each step. + * If we find any deviations, then this packet is bad. + */ + try = *go; + + do { + REJCINETWORK (IPX_NETWORK_NUMBER, try.neg_nn, try.our_network); + REJCINODE (IPX_NODE_NUMBER, try.neg_node, try.our_node); + REJCIPROTO (IPX_ROUTER_PROTOCOL, try.neg_router, try.router, 0); + REJCIPROTO (IPX_ROUTER_PROTOCOL, try.neg_router, try.router, 2); + REJCIPROTO (IPX_ROUTER_PROTOCOL, try.neg_router, try.router, 4); + REJCINAME (IPX_ROUTER_NAME, try.neg_name, try.name); + REJCIVOID (IPX_COMPLETE, try.neg_complete); +/* + * This is the end of the record. + */ + if (len == 0) { + if (f->state != OPENED) + *go = try; + return (1); + } + } while (0); +/* + * The frame is invalid at this point. + */ + IPXCPDEBUG((LOG_INFO, "ipxcp_rejci: received bad Reject!")); + return 0; +} + +/* + * ipxcp_reqci - Check the peer's requested CIs and send appropriate response. + * + * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified + * appropriately. If reject_if_disagree is non-zero, doesn't return + * CONFNAK; returns CONFREJ if it can't return CONFACK. + */ +static int +ipxcp_reqci(f, inp, len, reject_if_disagree) + fsm *f; + u_char *inp; /* Requested CIs */ + int *len; /* Length of requested CIs */ + int reject_if_disagree; +{ + int unit = f->unit; + u_char *cip, *next; /* Pointer to current and next CIs */ + u_short cilen, citype; /* Parsed len, type */ + u_short cishort, ts; /* Parsed short value */ + u_int32_t tl, cinetwork, outnet;/* Parsed address values */ + int rc = CONFACK; /* Final packet return code */ + int orc; /* Individual option return code */ + u_char *p; /* Pointer to next char to parse */ + u_char *ucp = inp; /* Pointer to current output char */ + int l = *len; /* Length left */ + u_char maxslotindex, cflag; + + /* + * Reset all his options. + */ + BZERO(ho, sizeof(*ho)); + + /* + * Process all his options. + */ + next = inp; + while (l) { + orc = CONFACK; /* Assume success */ + cip = p = next; /* Remember begining of CI */ + if (l < 2 || /* Not enough data for CI header or */ + p[1] < 2 || /* CI length too small or */ + p[1] > l) { /* CI length too big? */ + IPXCPDEBUG((LOG_INFO, "ipxcp_reqci: bad CI length!")); + orc = CONFREJ; /* Reject bad CI */ + cilen = l; /* Reject till end of packet */ + l = 0; /* Don't loop again */ + goto endswitch; + } + GETCHAR(citype, p); /* Parse CI type */ + GETCHAR(cilen, p); /* Parse CI length */ + l -= cilen; /* Adjust remaining length */ + next += cilen; /* Step to next CI */ + + switch (citype) { /* Check CI type */ +/* + * The network number must match. Choose the larger of the two. + */ + case IPX_NETWORK_NUMBER: + IPXCPDEBUG((LOG_INFO, "ipxcp: received Network Number request")); + + /* if we wont negotiate the network number or the length is wrong + then reject the option */ + if ( !ao->neg_nn || cilen != CILEN_NETN ) { + orc = CONFREJ; + break; + } + GETLONG(cinetwork, p); + IPXCPDEBUG((LOG_INFO,"Remote proposed IPX network number is %8Lx",tl)); + + /* If the network numbers match then acknowledge them. */ + if (cinetwork != 0) { + ho->his_network = cinetwork; + ho->neg_nn = 1; + if (wo->our_network == cinetwork) + break; +/* + * If the network number is not given or we don't accept their change or + * the network number is too small then NAK it. + */ + if (! ao->accept_network || cinetwork < wo->our_network) { + DECPTR (sizeof (u_int32_t), p); + PUTLONG (wo->our_network, p); + orc = CONFNAK; + } + break; + } +/* + * The peer sent '0' for the network. Give it ours if we have one. + */ + if (go->our_network != 0) { + DECPTR (sizeof (u_int32_t), p); + PUTLONG (wo->our_network, p); + orc = CONFNAK; +/* + * We don't have one. Reject the value. + */ + } else + orc = CONFREJ; + + break; +/* + * The node number is required + */ + case IPX_NODE_NUMBER: + IPXCPDEBUG((LOG_INFO, "ipxcp: received Node Number request")); + + /* if we wont negotiate the node number or the length is wrong + then reject the option */ + if ( cilen != CILEN_NODEN ) { + orc = CONFREJ; + break; + } + + copy_node (p, ho->his_node); + ho->neg_node = 1; +/* + * If the remote does not have a number and we do then NAK it with the value + * which we have for it. (We never have a default value of zero.) + */ + if (zero_node (ho->his_node)) { + orc = CONFNAK; + copy_node (wo->his_node, p); + INCPTR (sizeof (wo->his_node), p); + break; + } +/* + * If you have given me the expected network node number then I'll accept + * it now. + */ + if (compare_node (wo->his_node, ho->his_node)) { + orc = CONFACK; + ho->neg_node = 1; + INCPTR (sizeof (wo->his_node), p); + break; + } +/* + * If his node number is the same as ours then ask him to try the next + * value. + */ + if (compare_node (ho->his_node, go->our_node)) { + inc_node (ho->his_node); + orc = CONFNAK; + copy_node (ho->his_node, p); + INCPTR (sizeof (wo->his_node), p); + break; + } +/* + * If we don't accept a new value then NAK it. + */ + if (! ao->accept_remote) { + copy_node (wo->his_node, p); + INCPTR (sizeof (wo->his_node), p); + orc = CONFNAK; + break; + } + orc = CONFACK; + ho->neg_node = 1; + INCPTR (sizeof (wo->his_node), p); + break; +/* + * Compression is not desired at this time. It is always rejected. + */ + case IPX_COMPRESSION_PROTOCOL: + IPXCPDEBUG((LOG_INFO, "ipxcp: received Compression Protocol request ")); + orc = CONFREJ; + break; +/* + * The routing protocol is a bitmask of various types. Any combination + * of the values 2 and 4 are permissible. '0' for no routing protocol must + * be specified only once. + */ + case IPX_ROUTER_PROTOCOL: + if ( !ao->neg_router || cilen < CILEN_PROTOCOL ) { + orc = CONFREJ; + break; + } + + GETSHORT (cishort, p); + IPXCPDEBUG((LOG_INFO, + "Remote router protocol number %d", + cishort)); + + if ((cishort == 0 && ho->router != 0) || (ho->router & BIT(0))) { + orc = CONFREJ; + break; + } + + if (cishort != 0 && cishort != 2 && cishort != 4) { + orc = CONFREJ; + break; + } + + if (ho->router & BIT (cishort)) { + orc = CONFREJ; + break; + } + + ho->router |= BIT (cishort); + ho->neg_router = 1; + break; +/* + * The router name is advisorary. Just accept it if it is not too large. + */ + case IPX_ROUTER_NAME: + IPXCPDEBUG((LOG_INFO, "ipxcp: received Router Name request")); + if (cilen >= CILEN_NAME) { + int name_size = cilen - CILEN_NAME; + if (name_size > sizeof (ho->name)) + name_size = sizeof (ho->name) - 1; + memset (ho->name, 0, sizeof (ho->name)); + memcpy (ho->name, p, name_size); + ho->name [name_size] = '\0'; + ho->neg_name = 1; + orc = CONFACK; + break; + } + orc = CONFREJ; + break; +/* + * This is advisorary. + */ + case IPX_COMPLETE: + IPXCPDEBUG((LOG_INFO, "ipxcp: received Complete request")); + if (cilen != CILEN_COMPLETE) + orc = CONFREJ; + else { + ho->neg_complete = 1; + orc = CONFACK; + } + break; +/* + * All other entries are not known at this time. + */ + default: + IPXCPDEBUG((LOG_INFO, "ipxcp: received Complete request")); + orc = CONFREJ; + break; + } + +endswitch: + IPXCPDEBUG((LOG_INFO, " (%s)\n", CODENAME(orc))); + + if (orc == CONFACK && /* Good CI */ + rc != CONFACK) /* but prior CI wasnt? */ + continue; /* Don't send this one */ + + if (orc == CONFNAK) { /* Nak this CI? */ + if (reject_if_disagree) /* Getting fed up with sending NAKs? */ + orc = CONFREJ; /* Get tough if so */ + if (rc == CONFREJ) /* Rejecting prior CI? */ + continue; /* Don't send this one */ + if (rc == CONFACK) { /* Ack'd all prior CIs? */ + rc = CONFNAK; /* Not anymore... */ + ucp = inp; /* Backup */ + } + } + + if (orc == CONFREJ && /* Reject this CI */ + rc != CONFREJ) { /* but no prior ones? */ + rc = CONFREJ; + ucp = inp; /* Backup */ + } + + /* Need to move CI? */ + if (ucp != cip) + BCOPY(cip, ucp, cilen); /* Move it */ + + /* Update output pointer */ + INCPTR(cilen, ucp); + } + + /* + * If we aren't rejecting this packet, and we want to negotiate + * their address, and they didn't send their address, then we + * send a NAK with a IPX_NODE_NUMBER option appended. We assume the + * input buffer is long enough that we can append the extra + * option safely. + */ + + if (rc != CONFREJ && !ho->neg_node && + wo->req_nn && !reject_if_disagree) { + u_char *ps; + if (rc == CONFACK) { + rc = CONFNAK; + wo->req_nn = 0; /* don't ask again */ + ucp = inp; /* reset pointer */ + } + + if (zero_node (wo->his_node)) + inc_node (wo->his_node); + + PUTCHAR (IPX_NODE_NUMBER, ucp); + PUTCHAR (CILEN_NODEN, ucp); + copy_node (wo->his_node, ucp); + INCPTR (sizeof (wo->his_node), ucp); + } + + *len = ucp - inp; /* Compute output length */ + IPXCPDEBUG((LOG_INFO, "ipxcp: returning Configure-%s", CODENAME(rc))); + return (rc); /* Return final code */ +} + +/* + * ipxcp_up - IPXCP has come UP. + * + * Configure the IP network interface appropriately and bring it up. + */ + +static void +ipxcp_up(f) + fsm *f; +{ + int unit = f->unit; + + IPXCPDEBUG((LOG_INFO, "ipxcp: up")); + + if (!ho->neg_nn) + ho->his_network = wo->his_network; + + if (!ho->neg_node) + copy_node (wo->his_node, ho->his_node); + + if (!wo->neg_node && !go->neg_node) + copy_node (wo->our_node, go->our_node); + + if (zero_node (go->our_node)) { + IPXCPDEBUG((LOG_ERR, "Could not determine local IPX node address")); + ipxcp_close(f->unit, "Could not determine local IPX node address"); + return; + } + + go->network = go->our_network; + if (ho->his_network != 0 && ho->his_network > go->network) + go->network = ho->his_network; + + if (go->network == 0) { + IPXCPDEBUG((LOG_ERR, "Could not determine network number")); + ipxcp_close (unit, "Could not determine network number"); + return; + } + + /* bring the interface up */ + if (!sifup(unit)) { + IPXCPDEBUG((LOG_WARNING, "sifup failed")); + ipxcp_close(unit, "Interface configuration failed"); + return; + } + + /* set the network number for IPX */ + if (!sipxfaddr(unit, go->network, go->our_node)) { + IPXCPDEBUG((LOG_WARNING, "sipxfaddr failed")); + ipxcp_close(unit, "Interface configuration failed"); + return; + } + + /* + * Execute the ipx-up script, like this: + * /etc/ppp/ipx-up interface tty speed local-IPX remote-IPX + */ + + ipxcp_script (f, "/etc/ppp/ipx-up"); +} + +/* + * ipxcp_down - IPXCP has gone DOWN. + * + * Take the IP network interface down, clear its addresses + * and delete routes through it. + */ + +static void +ipxcp_down(f) + fsm *f; +{ + u_int32_t ournn, network; + + IPXCPDEBUG((LOG_INFO, "ipxcp: down")); + + cipxfaddr (f->unit); + sifdown(f->unit); + ipxcp_script (f, "/etc/ppp/ipx-down"); +} + + +/* + * ipxcp_script - Execute a script with arguments + * interface-name tty-name speed local-IPX remote-IPX networks. + */ +static void +ipxcp_script(f, script) + fsm *f; + char *script; +{ + int unit = f->unit; + char strspeed[32], strlocal[32], strremote[32]; + char strnetwork[32], strpid[32]; + char *argv[14], strproto_lcl[32], strproto_rmt[32]; + + sprintf (strpid, "%d", getpid()); + sprintf (strspeed, "%d", baud_rate); + + strproto_lcl[0] = '\0'; + if (go->neg_router) { + if (go->router & BIT(2)) + strcpy (strproto_lcl, "RIP "); + if (go->router & BIT(4)) + strcpy (strproto_lcl, "NLSP "); + } + + if (strproto_lcl[0] == '\0') + strcpy (strproto_lcl, "NONE "); + + strproto_lcl[strlen (strproto_lcl)-1] = '\0'; + + strproto_rmt[0] = '\0'; + if (ho->neg_router) { + if (ho->router & BIT(2)) + strcpy (strproto_rmt, "RIP "); + if (ho->router & BIT(4)) + strcpy (strproto_rmt, "NLSP "); + } + + if (strproto_rmt[0] == '\0') + strcpy (strproto_rmt, "NONE "); + + strproto_rmt[strlen (strproto_rmt)-1] = '\0'; + + strcpy (strnetwork, ipx_ntoa (go->network)); + + sprintf (strlocal, + "%02X%02X%02X%02X%02X%02X", + NODE(go->our_node)); + + sprintf (strremote, + "%02X%02X%02X%02X%02X%02X", + NODE(ho->his_node)); + + argv[0] = script; + argv[1] = ifname; + argv[2] = devnam; + argv[3] = strspeed; + argv[4] = strnetwork; + argv[5] = strlocal; + argv[6] = strremote; + argv[7] = strproto_lcl; + argv[8] = strproto_rmt; + argv[9] = go->name; + argv[10] = ho->name; + argv[11] = ipparam; + argv[12] = strpid; + argv[13] = NULL; + run_program(script, argv, 0); +} + +/* + * ipxcp_printpkt - print the contents of an IPXCP packet. + */ +char *ipxcp_codenames[] = { + "ConfReq", "ConfAck", "ConfNak", "ConfRej", + "TermReq", "TermAck", "CodeRej" +}; + +int +ipxcp_printpkt(p, plen, printer, arg) + u_char *p; + int plen; + void (*printer)(); + void *arg; +{ + int code, id, len, olen; + u_char *pstart, *optend; + u_short cishort; + u_int32_t cilong; + + if (plen < HEADERLEN) + return 0; + pstart = p; + GETCHAR(code, p); + GETCHAR(id, p); + GETSHORT(len, p); + if (len < HEADERLEN || len > plen) + return 0; + + if (code >= 1 && code <= sizeof(ipxcp_codenames) / sizeof(char *)) + printer(arg, " %s", ipxcp_codenames[code-1]); + else + printer(arg, " code=0x%x", code); + printer(arg, " id=0x%x", id); + len -= HEADERLEN; + switch (code) { + case CONFREQ: + case CONFACK: + case CONFNAK: + case CONFREJ: + /* print option list */ + while (len >= 2) { + GETCHAR(code, p); + GETCHAR(olen, p); + p -= 2; + if (olen < CILEN_VOID || olen > len) { + break; + } + printer(arg, " <"); + len -= olen; + optend = p + olen; + switch (code) { + case IPX_NETWORK_NUMBER: + if (olen == CILEN_NETN) { + p += CILEN_VOID; + GETLONG(cilong, p); + printer (arg, "network %s", ipx_ntoa (cilong)); + } + break; + case IPX_NODE_NUMBER: + if (olen == CILEN_NODEN) { + p += CILEN_VOID; + printer (arg, "node "); + while (p < optend) { + GETCHAR(code, p); + printer(arg, "%.2x", code); + } + } + break; + case IPX_COMPRESSION_PROTOCOL: + if (olen == CILEN_COMPRESS) { + p += CILEN_VOID; + GETSHORT (cishort, p); + printer (arg, "compression %d", cishort); + } + break; + case IPX_ROUTER_PROTOCOL: + if (olen == CILEN_PROTOCOL) { + p += CILEN_VOID; + GETSHORT (cishort, p); + printer (arg, "router proto %d", cishort); + } + break; + case IPX_ROUTER_NAME: + if (olen >= CILEN_NAME) { + p += CILEN_VOID; + printer (arg, "router name \""); + while (p < optend) { + GETCHAR(code, p); + if (code >= 0x20 && code < 0x7E) + printer (arg, "%c", code); + else + printer (arg, " \\%.2x", code); + } + printer (arg, "\""); + } + break; + case IPX_COMPLETE: + if (olen == CILEN_COMPLETE) { + p += CILEN_VOID; + printer (arg, "complete"); + } + break; + default: + break; + } + + while (p < optend) { + GETCHAR(code, p); + printer(arg, " %.2x", code); + } + printer(arg, ">"); + } + break; + } + + /* print the rest of the bytes in the packet */ + for (; len > 0; --len) { + GETCHAR(code, p); + printer(arg, " %.2x", code); + } + + return p - pstart; +} +#endif /* ifdef IPX_CHANGE */ diff --git a/pppd/ipxcp.h b/pppd/ipxcp.h new file mode 100644 index 0000000..64cd062 --- /dev/null +++ b/pppd/ipxcp.h @@ -0,0 +1,73 @@ +/* + * ipxcp.h - IPX Control Protocol definitions. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: ipxcp.h,v 1.1 1995/12/18 03:33:00 paulus Exp $ + */ + +/* + * Options. + */ +#define IPX_NETWORK_NUMBER 1 /* IPX Network Number */ +#define IPX_NODE_NUMBER 2 +#define IPX_COMPRESSION_PROTOCOL 3 +#define IPX_ROUTER_PROTOCOL 4 +#define IPX_ROUTER_NAME 5 +#define IPX_COMPLETE 6 + + +typedef struct ipxcp_options { + int neg_node : 1; /* Negotiate IPX node number? */ + int req_node : 1; /* Ask peer to send IPX node number? */ + + int neg_nn : 1; /* Negotiate IPX network number? */ + int req_nn : 1; /* Ask peer to send IPX network number */ + + int neg_name : 1; /* Negotiate IPX router name */ + int neg_complete : 1; /* Negotiate completion */ + int neg_router : 1; /* Negotiate IPX router number */ + + int accept_local : 1; /* accept peer's value for ournode */ + int accept_remote : 1; /* accept peer's value for hisnode */ + int accept_network : 1; /* accept network number */ + + u_int32_t his_network; /* base network number */ + u_int32_t our_network; /* our value for network number */ + u_int32_t network; /* the final network number */ + + u_char his_node[6]; /* peer's node number */ + u_char our_node[6]; /* our node number */ + u_char name [48]; /* name of the router */ + int router; /* routing protocol */ +} ipxcp_options; + +extern fsm ipxcp_fsm[]; +extern ipxcp_options ipxcp_wantoptions[]; +extern ipxcp_options ipxcp_gotoptions[]; +extern ipxcp_options ipxcp_allowoptions[]; +extern ipxcp_options ipxcp_hisoptions[]; + +void ipxcp_init __P((int)); +void ipxcp_open __P((int)); +void ipxcp_close __P((int, char *)); +void ipxcp_lowerup __P((int)); +void ipxcp_lowerdown __P((int)); +void ipxcp_input __P((int, u_char *, int)); +void ipxcp_protrej __P((int)); +int ipxcp_printpkt __P((u_char *, int, void (*)(), void *)); + +extern struct protent ipxcp_protent;