--- /dev/null
+The PPP support for this kernel requires the 2.2.0a version of the
+pppd daemon. You will find the current version of the daemon on
+sunsite.unc.edu in the /pub/Linux/system/Network/serial directory.
+
+Sunsite has many mirror sites. Please feel free to obtain it from
+a mirror site close to you.
+
+If you attempt to use a version of pppd which is not compatible
+then you will have some error condition. It usually is reflected
+in that an ioctl operation will generate a fatal error.
+
+Please do not use earlier versions of the 2.2 package. If you
+obtained a copy from merit.edu or bellatrix then please get an
+update from the sunsite site.
+
+The CCP (Compression Control Protocol) which is supported by this
+code is functional. You will need a compatible BSD compressor on
+your peer site to use the code.
+
+The BSD compression code will only build as a loadable module. There
+was an earlier version which would build it into the kernel but that
+functionality has been removed for various reasons.
+
+--
+Al Longyear longyear@netcom.com
--- /dev/null
+\begindata{text,748928}
+\textdsversion{12}
+\template{default}
+\center{\underline{\bigger{\bigger{\bigger{An Implementation Of
+Multiprocessor Linux
+
+}}}}}
+\italic{
+}\indent{\indent{This document describes the implementation of a simple SMP
+Linux kernel extension and how to use this to develop SMP Linux kernels for
+architectures other than the Intel MP v1.1 architecture for Pentium and 486
+processors.}\italic{
+
+}}\italic{
+
+
+Alan Cox, 1995
+
+
+The author wishes to thank Caldera Inc whose donation of an ASUS dual
+pentium board made this project possible, and Thomas Radke, whose initial
+work on multiprocessor Linux formed the backbone of this project.
+
+\begindata{bp,941568}
+\enddata{bp,941568}
+\view{bpv,941568,0,0,0}
+}
+\heading{Background: The Intel MP specification.
+
+}
+ Most IBM PC style multiprocessor motherboards combine Intel 486 or Pentium
+processors and glue chipsets with a hardware/software specification. The
+specification places much of the onus for hard work on the chipset and
+hardware rather than the operating system.
+
+
+ The Intel pentium processors have a wide variety of inbuilt facilities for
+supporting multiprocessing, including hardware cache coherency, built in
+interprocessor interrupt handling and a set of atomic test and set,
+exchange and similar operations. The cache coherency in paticular makes the
+operating systems job far easier.
+
+
+ The specification defines a detailed configuration structure in ROM that
+the boot up processor can read to find the full configuration of the
+processors and busses. It also defines a procedure for starting up the
+other processors.
+
+
+\heading{Mutual Exclusion Within A Single Processor Linux Kernel
+
+}
+ For any kernel to function in a sane manner it has to provide internal
+locking and protection of its own tables to prevent two processes updating
+them at once and for example allocating the same memory block. There are
+two strategies for this within current Unix and Unixlike kernels.
+Traditional unix systems from the earliest of days use a scheme of 'Coarse
+Grained Locking' where the entire kernel is protected as a small number of
+locks only. Some modern systems use fine grained locking. Because fine
+grained locking has more overhead it is normally used only on
+multiprocessor kernels and real time kernels. In a real time kernel the
+fine grained locking reduces the amount of time locks are held and reduces
+the critical (to real time programming at least) latency times.
+
+
+ Within the Linux kernel certain guarantees are made. No process running in
+kernel mode will be pre-empted by another kernel mode process unless it
+voluntarily sleeps. This ensures that blocks of kernel code are
+effectively atomic with respect to other processes and greatly simplifies
+many operation. Secondly interrupts may pre-empt a kernel running process,
+but will always return to that process. A process in kernel mode may
+disable interrupts on the processor and guarantee such an interruption will
+not occur. The final guarantee is that an interrupt will not bne pre-empted
+by a kernel task. That is interrupts will run to completion or be
+pre-empted by other interrupts only.
+
+
+ The SMP kernel chooses to continue these basic guarantees in order to make
+initial implementation and deployment easier. A single lock is maintained
+across all processors. This lock is required to access the kernel space.
+Any processor may hold it and once it is held may also re-enter the kernel
+for interrupts and other services whenever it likes until the lock is
+relinquished. This lock ensures that a kernel mode process will not be
+pre-empted and ensures that blocking interrupts in kernel mode behaves
+correctly. This is guaranteed because only the processor holding the lock
+can be in kernel mode, only kernel mode processes can disable interrupts
+and only the processor holding the lock may handle an interrupt.
+
+
+ Such a choice is however poor for performance. In the longer term it is
+neccessary to move to finer grained parallelism in order to get the best
+system performance. This can be done heirarchically by gradually refining
+the locks to cover smaller areas. With the current kernel highly CPU bound
+process sets perform well but I/O bound task sets can easily degenerate to
+near single processor performance levels. This refinement will be needed to
+get the best from Linux/SMP.
+
+
+\subheading{\heading{Changes To The Portable Kernel Components
+
+
+}} The kernel changes are split into generic SMP support changes and
+architecture specific changes neccessary to accomodate each different
+processor type Linux is ported to.
+
+
+\subsection{Initialisation}
+
+
+ The first problem with a multiprocessor kernel is starting the other
+processors up. Linux/SMP defines that a single processor enters the normal
+kernel entry point start_kernel(). Other processors are assumed not to be
+started or to have been captured elsewhere. The first processor begins the
+normal Linux initialisation sequences and sets up paging, interrupts and
+trap handlers. After it has obtained the processor information about the
+boot CPU, the architecture specific function \
+
+
+\description{
+\leftindent{\bold{void smp_store_cpu_info(int processor_id)
+
+}}}
+is called to store any information about the processor into a per processor
+array. This includes things like the bogomips speed ratings.
+
+
+ Having completed the kernel initialisation the architecture specific
+function
+
+
+\description{\leftindent{\bold{void smp_boot_cpus(void)
+
+}}}
+is called and is expected to start up each other processor and cause it to
+enter start_kernel() with its paging registers and other control
+information correctly loaded. Each other processor skips the setup except
+for calling the trap and irq initialisation functions that are needed on
+some processors to set each CPU up correctly. These functions will
+probably need to be modified in existing kernels to cope with this.
+
+
+ Each additional CPU the calls the architecture specific function
+
+
+\description{\leftindent{\bold{void smp_callin(void)
+
+
+}}}which does any final setup and then spins the processor while the boot
+up processor forks off enough idle threads for each processor. This is
+neccessary because the scheduler assumes there is always something to run.
+ Having generated these threads and forked init the architecture specific \
+
+
+
+\bold{\description{\leftindent{void smp_commence(void)}}}
+
+
+function is invoked. This does any final setup and indicates to the system
+that multiprocessor mode is now active. All the processors spinning in the
+smp_callin() function are now released to run the idle processes, which
+they will run when they have no real work to process.
+
+
+\subsection{Scheduling
+
+}
+ The kernel scheduler implements a simple but very and effective task
+scheduler. The basic structure of this scheduler is unchanged in the
+multiprocessor kernel. A processor field is added to each task, and this
+maintains the number of the processor executing a given task, or a magic
+constant (NO_PROC_ID) indicating the job is not allocated to a processor. \
+
+
+ \
+
+
+ Each processor executes the scheduler itself and will select the next task
+to run from all runnable processes not allocated to a different processor.
+The algorithm used by the selection is otherwise unchanged. This is
+actually inadequate for the final system because there are advantages to
+keeping a process on the same CPU, especially on processor boards with per
+processor second level caches.
+
+
+ Throughout the kernel the variable 'current' is used as a global for the
+current process. In Linux/SMP this becomes a macro which expands to
+current_set[smp_processor_id()]. This enables almost the entire kernel to
+be unaware of the array of running processors, but still allows the SMP
+aware kernel modules to see all of the running processes.
+
+
+ The fork system call is modified to generate multiple processes with a
+process id of zero until the SMP kernel starts up properly. This is
+neccessary because process number 1 must be init, and it is desirable that
+all the system threads are process 0. \
+
+
+
+ The final area within the scheduling of processes that does cause problems
+is the fact the uniprocessor kernel hard codes tests for the idle threads
+as task[0] and the init process as task[1]. Because there are multiple idle
+threads it is neccessary to replace these with tests that the process id is
+0 and a search for process ID 1, respectively.
+
+\subheading{
+}\subsection{Memory Management}\heading{
+
+
+} The memory management core of the existing Linux system functions
+adequately within the multiprocessor framework providing the locking is
+used. Certain processor specific areas do need changing, in paticular
+invalidate() must invalidate the TLB's of all processors before it returns.
+
+
+\subsection{Miscellaneous Functions}
+
+\heading{
+} The portable SMP code rests on a small set of functions and variables
+that are provided by the processor specification functionality. These are
+
+
+\display{\bold{int smp_processor_id(void)
+
+
+}}which returns the identity of the process the call is executed upon. This
+call is assumed to be valid at all times. This may mean additional tests
+are needed during initialisation.
+
+
+ \display{\bold{int smp_num_cpus;
+
+}}
+ This is the number of processors in the system. \
+
+
+
+ \bold{void smp_message_pass(int target, int msg, unsigned long data,
+
+ int wait)
+
+}
+ This function passes messages between processors. At the moment it is not
+sufficiently defined to sensibly document and needs cleaning up and further
+work. Refer to the processor specific code documentation for more details.
+
+
+\heading{Architecture Specific Code For the Intel MP Port
+
+}
+ The architecture specific code for the intel port splits fairly cleanly
+into four sections. Firstly the initialisation code used to boot the
+system, secondly the message handling and support code, thirdly the
+interrupt and kernel syscall entry function handling and finally the
+extensions to standard kernel facilities to cope with multiple processors.
+
+
+\subsection{Initialisation
+
+
+} The intel MP architecture captures all the processors except for a single
+processor known as the 'boot processor' in the BIOS at boot time. Thus a
+single processor enters the kernel bootup code. The first processor
+executes the bootstrap code, loads and uncompresses the kernel. Having
+unpacked the kernel it sets up the paging and control registers then enters
+the C kernel startup.
+
+
+ The assembler startup code for the kernel is modified so that it can be
+used by the other processors to do the processor identification and various
+other low level configurations but does not execute those parts of the
+startup code that would damage the running system (such as clearing the BSS
+segment). \
+
+
+
+ In the initialisation done by the first processor the arch/i386/mm/init
+code is modified to scan the low page, top page and BIOS for intel MP
+signature blocks. This is neccessary because the MP signature blocks must
+be read and processed before the kernel is allowed to allocate and destroy
+the page at the top of low memory. Having established the number of
+processors it reserves a set of pages to provide a stack come boot up area
+for each processor in the system. These must be allocated at startup to
+ensure they fall below the 1Mb boundary.
+
+
+ Further processors are started up in smp_boot_cpus() by programming the
+APIC controller registers and sending an inter-processor interrupt (IPI) to
+the processor. This message causes the target processor to begin executing
+code at the start of any page of memory within the lowest 1Mb, in 16bit
+real mode. The kernel uses the single page it allocated for each processor
+to use as stack. Before booting a given CPU the relocatable code from
+trampoline.S and trampoline32.S is copied to the bottom of its stack page
+and used as the target for the startup. \
+
+
+
+ The trampoline code calculates the desired stack base from the code
+segment (since the code segment on startup is the bottom of the stack),
+ enters 32bit mode and jumps to the kernel entry assembler. This as
+described above is modified to only execute the parts necessary for each
+processor, and then to enter start_kernel(). On entering the kernel the
+processor initialises its trap and interrupt handlers before entering
+smp_callin(), where it reports its status and sets a flag that causes the
+boot processor to continue and look for further processors. The processor
+then spins until smp_commence() is invoked.
+
+
+ Having started each processor up the smp_commence( ) function flips a
+flag. Each processor spinning in smp_callin() then loads the task register
+with the task state segment (TSS) of its idle thread as is needed for task
+switching.
+
+
+\subsection{Message Handling and Support Code}
+
+
+ The architecture specific code implements the smp_processor_id() function
+by querying the APIC logical identity register. Because the APIC isnt
+mapped into the kernel address space at boot, the initial value returned is
+rigged by setting the APIC base pointer to point at a suitable constant.
+Once the system starts doing the SMP setup (in smp_boot_cpus()), the APIC
+is mapped with a vremap() call and the apic pointer is adjusted
+appropriately. From then on the real APIC logical identity register is
+read.
+
+
+ Message passing is accomplished using a pair of IPI's on interrupt 13
+(unused by the 80486 FPU's in SMP mode) and interrupt 16. Two are used in
+order to seperate messages that cannot be processed until the receiver
+obtains the kernel spinlock from messages that can be processed
+immediately. In effect IRQ 13 is a fast IRQ handler that does not obtain
+the locks, and cannot cause a reschedule, while IRQ 16 is a slow IRQ that
+must acquire the kernel spinlocks and can cause a reschedule. This
+interrupt is used for passing on slave timer messages from the processor
+that receives the timer interrupt to the rest of the processors, so that
+they can reschedule running tasks.
+
+
+\subsection{Entry And Exit Code}
+
+
+ A single spinlock protects the entire kernel. The interrupt handlers, the
+syscall entry code and the exception handlers all acquire the lock before
+entering the kernel proper. When the processor is trying to acquire the
+spinlock it spins continually on the lock with interrupts disabled. This
+causes a specific deadlock problem. The lock owner may need to send an
+invalidate request to the rest of the processors and wait for these to
+complete before continuing. A processor spinning on the lock would not be
+able to do thus. Thus the loop of the spinlock tests and handles invalidate
+requests. If the invalidate bit for the spinning CPU is set the processor
+invalidates its TLB and atomically clears the bit. When the spinlock is
+obtained that processor will take an IPI and in the IPI test the bit and
+skip the invalidate as the bit is clear.
+
+
+ One complexity of the spinlock is that a process running in kernel mode
+can sleep voluntarily and be pre-empted. A switch from such a process to a
+process executing in user space may reduce the lock count. To track this
+the kernel uses a syscall_count and a per process lock_depth parameter to
+track the kernel lock state. The switch_to() function is modified in SMP
+mode to adjust the lock appropriately.
+
+
+ The final problem is the idle thread. In the single processor kernel the
+idle thread executes 'hlt' instructions. This saves power and reduces the
+running temperature of the processors when they are idle. However it means
+the process spends all its time in kernel mode and would thus hold the
+kernel spinlock. The SMP idle thread continually reschedules a new task and
+returns to user mode. This is far from ideal and will be modified to use
+'hlt' instructions and release the spinlock soon. Using 'hlt' is even more
+beneficial on a multiprocessor system as it almost completely takes an idle
+processor off the bus.
+
+
+ Interrupts are distributed by an i82489 APIC. This chip is set up to work
+as an emulation of the traditional PC interrupt controllers when the
+machine boots (so that an Intel MP machine boots one CPU and PC
+compatible). The kernel has all the relevant locks but does not yet
+reprogram the 82489 to deliver interrupts to arbitary processors as it
+should. This requires further modification of the standard Linux interrupt
+handling code, and is paticularly messy as the interrupt handler behaviour
+has to change as soon as the 82489 is switched into SMP mode.
+
+
+\subsection{Extensions To Standard Facilities}
+
+
+ The kernel maintains a set of per processor control information such as
+the speed of the processor for delay loops. These functions on the SMP
+kernel look the values up in a per processor array that is set up from the
+data generated at boot up by the smp_store_cpu_info() function. This
+includes other facts such as whether there is an FPU on the processor. The
+current kernel does not handle only some processors having floating point.
+
+
+ The highly useful atomic bit operations are prefixed with the 'lock'
+prefix in the SMP kernel to maintain their atomic properties when used
+outside of (and by) the spinlock and message code. Amongst other things
+this is needed for the invalidate handler, as all CPU's will invalidate at
+the same time without any locks.
+
+
+ Interrupt 13 floating point error reporting is removed. This facility is
+not usable on a multiprocessor board, nor relevant to the Intel MP
+architecture which does not cover the 80386/80387 processor pair. \
+
+
+
+ The /proc filesystem support is changed so that the /proc/cpuinfo file
+contains a column for each processor present. This information is extracted
+from the data save by smp_store_cpu_info().
+
+\enddata{text,748928}
VERSION = 1
PATCHLEVEL = 3
-SUBLEVEL = 32
+SUBLEVEL = 33
ARCH = i386
if [ "$CONFIG_ALPHA_CABRIOLET" = "y" \
-o "$CONFIG_ALPHA_EB64" = "y" -o "$CONFIG_ALPHA_EB64P" = "y" ]
then
+ bool 'Using SRM as bootloader' CONFIG_ALPHA_SRM n
define_bool CONFIG_PCI y
define_bool CONFIG_ALPHA_APECS y
fi
bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED y
fi
tristate 'PPP (point-to-point) support' CONFIG_PPP n
-if [ "$CONFIG_PPP" != "n" ]; then
- bool ' 16 channels instead of 4' CONFIG_PPP_LOTS n
+if [ ! "$CONFIG_PPP" = "n" ]; then
+comment 'CCP compressors for PPP are only built as modules.'
fi
if [ "$CONFIG_AX25" = "y" ]; then
bool 'Z8530 SCC kiss emulation driver for AX.25' CONFIG_SCC y
machine_check(vector, la_ptr, ®s);
break;
case 3:
-#if defined(CONFIG_ALPHA_JENSEN) || defined(CONFIG_ALPHA_NONAME)
+#if defined(CONFIG_ALPHA_JENSEN) || defined(CONFIG_ALPHA_NONAME) || \
+ defined(CONFIG_ALPHA_SRM)
srm_device_interrupt(vector, ®s);
#elif defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
cabriolet_and_eb66p_device_interrupt(vector, ®s);
+/*
+ * Constants used during machine-check handling. I suppose these
+ * could be moved into lca.h but I don't see much reason why anybody
+ * else would want to use them.
+ */
+#define ESR_EAV (1UL<< 0) /* error address valid */
+#define ESR_CEE (1UL<< 1) /* correctable error */
+#define ESR_UEE (1UL<< 2) /* uncorrectable error */
+#define ESR_NXM (1UL<<12) /* non-existent memory */
+
+
void lca_machine_check (unsigned long vector, unsigned long la, struct pt_regs *regs)
{
const char * reason;
union el_lca el;
+ char buf[128];
printk("lca: machine check (la=0x%lx)\n", la);
el.c = (struct el_common *) la;
case MCHK_K_SIO_IOCHK: reason = "SIO IOCHK occurred on ISA bus"; break;
case MCHK_K_DCSR: reason = "MCHK_K_DCSR"; break;
case MCHK_K_UNKNOWN:
- default: reason = "reason for machine-check unknown"; break;
+ default:
+ sprintf(buf, "reason for machine-check unknown (0x%lx)", el.s->reason);
+ reason = buf;
+ break;
}
+ wrmces(rdmces()); /* reset machine check pending flag */
+
switch (el.c->size) {
case sizeof(struct el_lca_mcheck_short):
printk(" Reason: %s (short frame%s):\n",
- reason, el.h->retry ? ", retryable" : "");
- printk("\tesr: %lx ear: %lx\n", el.s->esr, el.s->ear);
- printk("\tdc_stat: %lx ioc_stat0: %lx ioc_stat1: %lx\n",
+ reason, el.c->retry ? ", retryable" : "");
+ printk(" esr: %lx ear: %lx\n", el.s->esr, el.s->ear);
+ printk(" dc_stat: %lx ioc_stat0: %lx ioc_stat1: %lx\n",
el.s->dc_stat, el.s->ioc_stat0, el.s->ioc_stat1);
+ if (el.c->retry &&
+ (el.s->esr & (ESR_EAV|ESR_CEE|ESR_UEE|ESR_NXM)) == (ESR_EAV|ESR_CEE))
+ {
+ unsigned long addr, val;
+
+ /* temporarily disable processor/system correctable error logging: */
+ wrmces(0x18);
+ addr = el.s->ear & ~ (0x7<<29 | 0x7);
+ addr += IDENT_ADDR;
+ printk(" correcting quadword at address %lx\n", addr);
+ val = *(volatile long *)addr;
+ *(volatile long *)addr = val;
+ /* reenable all machine checks: */
+ wrmces(0x00);
+ }
break;
case sizeof(struct el_lca_mcheck_long):
printk(" Reason: %s (long frame%s):\n",
- reason, el.h->retry ? ", retryable" : "");
- printk("\treason: %lx exc_addr: %lx dc_stat: %lx\n",
+ reason, el.c->retry ? ", retryable" : "");
+ printk(" reason: %lx exc_addr: %lx dc_stat: %lx\n",
el.l->pt[0], el.l->exc_addr, el.l->dc_stat);
- printk("\tesr: %lx ear: %lx car: %lx\n", el.l->esr, el.l->ear, el.l->car);
- printk("\tioc_stat0: %lx ioc_stat1: %lx\n", el.l->ioc_stat0, el.l->ioc_stat1);
+ printk(" esr: %lx ear: %lx car: %lx\n", el.l->esr, el.l->ear, el.l->car);
+ printk(" ioc_stat0: %lx ioc_stat1: %lx\n", el.l->ioc_stat0, el.l->ioc_stat1);
break;
default:
printk(" Unknown errorlog size %d\n", el.c->size);
}
- wrmces(rdmces()); /* reset machine check asap */
}
#endif /* CONFIG_ALPHA_LCA */
#include <linux/stat.h>
#include <linux/mman.h>
+#include <asm/reg.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <asm/io.h>
/*
* fill in the user structure for a core dump..
*/
-void dump_thread(struct pt_regs * regs, struct user * dump)
+void dump_thread(struct pt_regs * pt, struct user * dump)
{
+ /* switch stack follows right below pt_regs: */
+ struct switch_stack * sw = ((struct switch_stack *) pt) - 1;
+
+ dump->magic = CMAGIC;
+ dump->start_code = current->mm->start_code;
+ dump->start_data = current->mm->start_data;
+ dump->start_stack = rdusp() & ~(PAGE_SIZE - 1);
+ dump->u_tsize = (current->mm->end_code - dump->start_code) >> PAGE_SHIFT;
+ dump->u_dsize = (current->mm->brk + (PAGE_SIZE - 1) - dump->start_data) >> PAGE_SHIFT;
+ dump->u_ssize =
+ (current->mm->start_stack - dump->start_stack + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+ /*
+ * We store the registers in an order/format that is
+ * compatible with DEC Unix/OSF/1 as this makes life easier
+ * for gdb.
+ */
+ dump->regs[EF_V0] = pt->r0;
+ dump->regs[EF_T0] = pt->r1;
+ dump->regs[EF_T1] = pt->r2;
+ dump->regs[EF_T2] = pt->r3;
+ dump->regs[EF_T3] = pt->r4;
+ dump->regs[EF_T4] = pt->r5;
+ dump->regs[EF_T5] = pt->r6;
+ dump->regs[EF_T6] = pt->r7;
+ dump->regs[EF_T7] = pt->r8;
+ dump->regs[EF_S0] = sw->r9;
+ dump->regs[EF_S1] = sw->r10;
+ dump->regs[EF_S2] = sw->r11;
+ dump->regs[EF_S3] = sw->r12;
+ dump->regs[EF_S4] = sw->r13;
+ dump->regs[EF_S5] = sw->r14;
+ dump->regs[EF_S6] = sw->r15;
+ dump->regs[EF_A3] = pt->r19;
+ dump->regs[EF_A4] = pt->r20;
+ dump->regs[EF_A5] = pt->r21;
+ dump->regs[EF_T8] = pt->r22;
+ dump->regs[EF_T9] = pt->r23;
+ dump->regs[EF_T10] = pt->r24;
+ dump->regs[EF_T11] = pt->r25;
+ dump->regs[EF_RA] = pt->r26;
+ dump->regs[EF_T12] = pt->r27;
+ dump->regs[EF_AT] = pt->r28;
+ dump->regs[EF_SP] = rdusp();
+ dump->regs[EF_PS] = pt->ps;
+ dump->regs[EF_PC] = pt->pc;
+ dump->regs[EF_GP] = pt->gp;
+ dump->regs[EF_A0] = pt->r16;
+ dump->regs[EF_A1] = pt->r17;
+ dump->regs[EF_A2] = pt->r18;
+ memcpy((char *)dump->regs + EF_SIZE, sw->fp, 32 * 8);
}
/*
bool 'IP: firewall packet logging' CONFIG_IP_FIREWALL_VERBOSE y
bool 'IP: masquerading (ALPHA)' CONFIG_IP_MASQUERADE n
fi
-if [ "$CONFIG_IP_FORWARD" = "y" -a "$CONFIG_IP_MULTICAST" = "y" -a "$CONFIG_NET_IPIP" = "y" ]; then
+if [ "$CONFIG_IP_FORWARD" = "y" -a "$CONFIG_IP_MULTICAST" = "y" ]; then
bool 'IP: multicast routing(in progress)' CONFIG_IP_MROUTE n
fi
comment '(it is safe to leave these untouched)'
bool 'Amateur Radio NET/ROM' CONFIG_NETROM n
fi
bool 'Kernel/User network link driver(ALPHA)' CONFIG_NETLINK n
+if [ "$CONFIG_NETLINK" = "y" ]; then
+ bool 'Routing messages' CONFIG_RTNETLINK y
+fi
fi
comment 'SCSI support'
comment 'Skipping network driver configuration options...'
else
-tristate 'Dummy net driver support' CONFIG_DUMMY y
+tristate 'Dummy net driver support' CONFIG_DUMMY m
tristate 'SLIP (serial line) support' CONFIG_SLIP n
if [ "$CONFIG_SLIP" != "n" ]; then
bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED y
fi
tristate 'PPP (point-to-point) support' CONFIG_PPP n
-if [ "$CONFIG_PPP" != "n" ]; then
- bool ' 16 channels instead of 4' CONFIG_PPP_LOTS n
+if [ ! "$CONFIG_PPP" = "n" ]; then
+comment 'CCP compressors for PPP are only built as modules.'
fi
if [ "$CONFIG_AX25" = "y" ]; then
- bool 'Z8530 SCC kiss emulation driver for AX.25' CONFIG_SCC y
+ bool 'Z8530 SCC kiss emulation driver for AX.25' CONFIG_SCC n
else
bool 'Z8530 SCC kiss emulation driver for AX.25' CONFIG_SCC n
fi
tristate 'EtherExpress support' CONFIG_EEXPRESS n
bool 'NI5210 support' CONFIG_NI52 n
bool 'NI6510 support' CONFIG_NI65 n
- if [ "$CONFIG_AX25" = "y" ]; then
- bool 'Ottawa PI and PI/2 support' CONFIG_PI y
- fi
tristate 'WaveLAN support' CONFIG_WAVELAN n
fi
tristate 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS n
tristate 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN n
tristate 'HP 10/100VG PCLAN (ISA, EISA, PCI) support' CONFIG_HP100 n
tristate 'NE2000/NE1000 support' CONFIG_NE2000 y
+ if [ "$CONFIG_AX25" = "y" ]; then
+ bool 'Ottawa PI and PI/2 support' CONFIG_PI y
+ fi
bool 'SK_G16 support' CONFIG_SK_G16 n
fi
bool 'EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA n
hexify:
$(HOSTCC) hexify.c -o hexify
+smp.c: trampoline.hex
+
trampoline.hex: trampoline hexify
(dd if=trampoline bs=1 skip=32 | ./hexify >trampoline.hex )
mpf->mpf_feature1);
return;
}
+ /*
+ * Read the physical hardware table. If there isn't one
+ * the processors present are 0 and 1.
+ */
if(mpf->mpf_physptr)
smp_read_mpc((void *)mpf->mpf_physptr);
+ else
+ cpu_present_map=3;
printk("Processors: %d\n", num_processors);
}
}
# ifndef CONFIG_MODVERSIONS
char kernel_version[]= UTS_RELEASE;
# endif
+#define aztcd_init init_module
#endif
#include <linux/errno.h>
/*
* Test for presence of drive and initialize it. Called at boot time.
*/
-#ifndef MODULE
-unsigned long aztcd_init(unsigned long mem_start, unsigned long mem_end)
-#else
-int init_module(void)
-#endif
+
+int aztcd_init(void)
{ long int count, max_count;
unsigned char result[50];
int st;
if (azt_port <= 0) {
printk("aztcd: no Aztech CD-ROM Initialization");
-#ifndef MODULE
- return (mem_start);
-#else
return -EIO;
-#endif
}
printk("aztcd: Aztech, Orchid, Okano, Wearnes CD-ROM Driver (C) 1994,1995 W.Zimmermann\n");
printk("aztcd: DriverVersion=%s BaseAddress=0x%x \n",AZT_VERSION,azt_port);
if (check_region(azt_port, 4)) {
printk("aztcd: conflict, I/O port (%X) already used\n",
azt_port);
-#ifndef MODULE
- return (mem_start);
-#else
return -EIO;
-#endif
}
#ifdef AZT_SW32 /*CDROM connected to Soundwave32 card*/
if ((0xFF00 & inw(AZT_SW32_ID_REG)) != 0x4500)
{ printk("aztcd: no Soundwave32 card detected at base:%x init:%x config:%x id:%x\n",
AZT_SW32_BASE_ADDR,AZT_SW32_INIT,AZT_SW32_CONFIG_REG,AZT_SW32_ID_REG);
-#ifndef MODULE
- return (mem_start);
-#else
return -EIO;
-#endif
}
else
{ printk("aztcd: Soundwave32 card detected at %x Version %x\n",
#ifndef MODULE
if (azt_cont!=0x79)
{ printk("aztcd: no AZTECH CD-ROM drive found-Try boot parameter aztcd=<BaseAddress>,0x79\n");
- return (mem_start);
+ return -EIO;
}
#else
if (0)
STEN_LOW;
if (inb(DATA_PORT)!=AFL_OP_OK) /*OP_OK?*/
{ printk("aztcd: no AZTECH CD-ROM drive found\n");
-#ifndef MODULE
- return (mem_start);
-#else
return -EIO;
-#endif
}
for (count = 0; count < AZT_TIMEOUT; count++);
{ count=count*2; /* delay a bit */
}
if ((st=getAztStatus())==-1)
{ printk("aztcd: Drive Status Error Status=%x\n",st);
-#ifndef MODULE
- return (mem_start);
-#else
return -EIO;
-#endif
}
#ifdef AZT_DEBUG
printk("aztcd: Status = %x\n",st);
for (count=1;count<5;count++) printk("%c",result[count]);
printk("\n");
printk("aztcd: Aborted\n");
-#ifndef MODULE
- return (mem_start);
-#else
return -EIO;
-#endif
}
}
if (register_blkdev(MAJOR_NR, "aztcd", &azt_fops) != 0)
{
printk("aztcd: Unable to get major %d for Aztech CD-ROM\n",
MAJOR_NR);
-#ifndef MODULE
- return (mem_start);
-#else
return -EIO;
-#endif
}
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
read_ahead[MAJOR_NR] = 4;
aztPresent = 1;
aztCloseDoor();
printk("aztcd: End Init\n");
-#ifndef MODULE
- return (mem_start);
-#else
return (0);
-#endif
}
#define SUBSECTOR(block) (CURRENT->current_nr_sectors > 0)
#ifdef CONFIG_CDU31A
-extern unsigned long cdu31a_init(unsigned long, unsigned long);
+extern int cdu31a_init(void);
#endif CONFIG_CDU31A
#ifdef CONFIG_MCD
-extern unsigned long mcd_init(unsigned long, unsigned long);
+extern int mcd_init(void);
#endif CONFIG_MCD
#ifdef CONFIG_MCDX
-extern unsigned long mcdx_init(unsigned long, unsigned long);
+extern int mcdx_init(void);
#endif CONFIG_MCDX
#ifdef CONFIG_SBPCD
-extern unsigned long sbpcd_init(unsigned long, unsigned long);
+extern int sbpcd_init(void);
#endif CONFIG_SBPCD
#ifdef CONFIG_AZTCD
-extern unsigned long aztcd_init(unsigned long, unsigned long);
+extern int aztcd_init(void);
#endif CONFIG_AZTCD
#ifdef CONFIG_CDU535
-extern unsigned long sony535_init(unsigned long, unsigned long);
+extern int sony535_init(void);
#endif CONFIG_CDU535
#ifdef CONFIG_GSCD
-extern unsigned long gscd_init(unsigned long, unsigned long);
+extern int gscd_init(void);
#endif CONFIG_GSCD
#ifdef CONFIG_CM206
-extern unsigned long cm206_init(unsigned long, unsigned long);
+extern int cm206_init(void);
#endif CONFIG_CM206
#ifdef CONFIG_OPTCD
-extern unsigned long optcd_init(unsigned long, unsigned long);
+extern int optcd_init(void);
#endif CONFIG_OPTCD
#ifdef CONFIG_SJCD
-extern unsigned long sjcd_init(unsigned long, unsigned long);
+extern int sjcd_init(void);
#endif CONFIG_SJCD
#ifdef CONFIG_BLK_DEV_HD
-extern unsigned long hd_init(unsigned long mem_start, unsigned long mem_end);
+extern int hd_init(void);
#endif
#ifdef CONFIG_BLK_DEV_IDE
-extern unsigned long ide_init(unsigned long mem_start, unsigned long mem_end);
+extern int ide_init(void);
#endif
+#ifdef CONFIG_BLK_DEV_XD
+extern int xd_init(void);
+#endif
+
extern void set_device_ro(kdev_t dev,int flag);
extern int floppy_init(void);
extern long rd_init(long mem_start, int length);
extern int ramdisk_size;
-#ifdef CONFIG_BLK_DEV_XD
-extern unsigned long xd_init(unsigned long mem_start, unsigned long mem_end);
-#endif
-
#define RO_IOCTLS(dev,where) \
case BLKROSET: if (!suser()) return -EACCES; \
set_device_ro((dev),get_fs_long((long *) (where))); return 0; \
/*
* Initialize the driver.
*/
-#ifndef MODULE
-unsigned long
-cdu31a_init(unsigned long mem_start, unsigned long mem_end)
-#else
-int
-init_module(void)
+#ifdef MODULE
+#define cdu31a_init init_module
#endif
+
+int
+cdu31a_init(void)
{
struct s_sony_drive_config drive_config;
unsigned int res_size;
if (register_blkdev(MAJOR_NR,"cdu31a",&scd_fops))
{
printk("Unable to get major %d for CDU-31a\n", MAJOR_NR);
-#ifdef MODULE
return -EIO;
-#else
- return mem_start;
-#endif
}
if (SONY_HWC_DOUBLE_SPEED(drive_config))
disk_changed = 1;
-#ifdef MODULE
if (drive_found)
{
return(0);
{
return -EIO;
}
-#else
- return mem_start;
-#endif
}
#ifdef MODULE
#ifdef MODULE /* OK, so some of this is stolen */
#include <linux/module.h>
#include <linux/version.h>
-#include <linux/malloc.h>
#ifndef CONFIG_MODVERSIONS
char kernel_version[]=UTS_RELEASE;
#endif
#include <linux/cdrom.h>
#include <linux/ioport.h>
#include <linux/mm.h>
+#include <linux/malloc.h>
#include <asm/io.h>
free_irq(cm206_irq);
case 2:
case 1:
-#ifdef MODULE
kfree(cd);
-#endif
release_region(cm206_base, 16);
default:
}
#endif
#ifdef MODULE
-#define OK 0
-#define ERROR -EIO
static int cm206[2] = {0,0}; /* for compatible `insmod' parameter passing */
void parse_options(void)
}
}
-#else MODULE
-
-#define OK mem_start+size
-#define ERROR mem_start
+#define cm206_init init_module
#endif MODULE
-#ifdef MODULE
-int init_module(void)
-#else
-unsigned long cm206_init(unsigned long mem_start, unsigned long mem_end)
-#endif
+
+int cm206_init(void)
{
uch e=0;
long int size=sizeof(struct cm206_struct);
cm206_base = probe_base_port(auto_probe ? 0 : cm206_base);
if (!cm206_base) {
printk(" can't find adapter!\n");
- return ERROR;
+ return -EIO;
}
printk(" adapter at 0x%x", cm206_base);
request_region(cm206_base, 16, "cm206");
-#ifdef MODULE
cd = (struct cm206_struct *) kmalloc(size, GFP_KERNEL);
- if (!cd) return ERROR;
-#else
- cd = (struct cm206_struct *) mem_start;
-#endif
+ if (!cd) return -EIO;
/* Now we have found the adaptor card, try to reset it. As we have
* found out earlier, this process generates an interrupt as well,
* so we might just exploit that fact for irq probing! */
if (cm206_irq<=0) {
printk("can't find IRQ!\n");
cleanup(1);
- return ERROR;
+ return -EIO;
}
else printk(" IRQ %d found\n", cm206_irq);
#else
{
printk(" drive not there\n");
cleanup(1);
- return ERROR;
+ return -EIO;
}
e = send_receive_polled(c_gimme);
printk("Firmware revision %d", e & dcf_revision_code);
if (request_irq(cm206_irq, cm206_interrupt, 0, "cm206")) {
printk("\nUnable to reserve IRQ---aborted\n");
cleanup(2);
- return ERROR;
+ return -EIO;
}
printk(".\n");
if (register_blkdev(MAJOR_NR, "cm206", &cm206_fops) != 0) {
printk("Cannot register for major %d!\n", MAJOR_NR);
cleanup(3);
- return ERROR;
+ return -EIO;
}
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
read_ahead[MAJOR_NR] = 16; /* reads ahead what? */
cd->max_sectors = (inw(r_data_status) & ds_ram_size) ? 24 : 97;
printk("%d kB adapter memory available, "
" %ld bytes kernel memory used.\n", cd->max_sectors*2, size);
- return OK;
+ return 0;
}
-#undef OK
-#undef ERROR
#ifdef MODULE
void cleanup_module(void)
#include <linux/major.h>
#include <linux/string.h>
+#include <asm/system.h>
+
struct gendisk *gendisk_head = NULL;
static int current_minor = 0;
extern void rd_load(void);
extern int ramdisk_size;
+extern int chr_dev_init(void);
+extern int blk_dev_init(void);
+extern int scsi_dev_init(void);
+extern int net_dev_init(void);
+
static void print_minor_name (struct gendisk *hd, int minor)
{
unsigned int unit = minor >> hd->minor_shift;
print_minor_name(hd, minor);
}
+static inline int is_extended_partition(struct partition *p)
+{
+ return (p->sys_ind == DOS_EXTENDED_PARTITION ||
+ p->sys_ind == LINUX_EXTENDED_PARTITION);
+}
+
#ifdef CONFIG_MSDOS_PARTITION
/*
* Create devices for each logical partition in an extended partition.
* First process the data partition(s)
*/
for (i=0; i<4; i++, p++) {
- if (!p->nr_sects || p->sys_ind == EXTENDED_PARTITION)
+ if (!p->nr_sects || is_extended_partition(p))
continue;
/* Check the 3rd and 4th entries -
*/
p -= 4;
for (i=0; i<4; i++, p++)
- if(p->nr_sects && p->sys_ind == EXTENDED_PARTITION)
+ if(p->nr_sects && is_extended_partition(p))
break;
if (i == 4)
goto done; /* nothing left to do */
if (!p->nr_sects)
continue;
add_partition(hd, minor, first_sector+p->start_sect, p->nr_sects);
- if (p->sys_ind == EXTENDED_PARTITION) {
+ if (is_extended_partition(p)) {
printk(" <");
/*
* If we are rereading the partition table, we need
>> (BLOCK_SIZE_BITS - 9);
extended_partition(hd, MKDEV(hd->major, minor));
printk(" >");
- /* prevent someone doing mkfs or mkswap on
- an extended partition */
- hd->part[minor].nr_sects = 0;
+ /* prevent someone doing mkfs or mkswap on an
+ extended partition, but leave room for LILO */
+ if (hd->part[minor].nr_sects > 2)
+ hd->part[minor].nr_sects = 2;
}
}
/*
struct gendisk *p;
int nr=0;
+ chr_dev_init();
+ blk_dev_init();
+ sti();
+#ifdef CONFIG_SCSI
+ scsi_dev_init();
+#endif
+#ifdef CONFIG_INET
+ net_dev_init();
+#endif
console_map_init();
for (p = gendisk_head ; p ; p=p->next) {
setup_dev(p);
nr += p->nr_real;
}
-
+
if (ramdisk_size)
rd_load();
}
/* common GoldStar Initialization */
-static long my_gscd_init (unsigned long , unsigned long);
+static int my_gscd_init (void);
/* lo-level cmd-Funktionen */
long err;
- /* call the GoldStar-init with dummys */
- err = my_gscd_init ( 10, 20 );
+ /* call the GoldStar-init */
+ err = my_gscd_init ( );
if ( err < 0 )
{
- return -EIO;
+ return err;
}
else
{
/* Test for presence of drive and initialize it. Called only at boot time. */
-unsigned long gscd_init (unsigned long mem_start, unsigned long mem_end)
+int gscd_init (void)
{
-unsigned long err;
-
- err = my_gscd_init ( mem_start, mem_end );
- return ( labs(err));
+ return my_gscd_init ();
}
/* This is the common initalisation for the GoldStar drive. */
/* It is called at boot time AND for module init. */
-long my_gscd_init (unsigned long mem_start, unsigned long mem_end)
+int my_gscd_init (void)
{
int i;
int result;
if (check_region(gscd_port, 4))
{
printk("GSCD: Init failed, I/O port (%X) already in use.\n", gscd_port);
- return -mem_start;
+ return -EIO;
}
if ( result == 0x09 )
{
printk ("GSCD: DMA kann ich noch nicht!\n" );
- return -mem_start;
+ return -EIO;
}
if ( result == 0x0b )
if ( i == 0 )
{
printk ( "GSCD: GoldStar CD-ROM Drive is not found.\n" );
- return -mem_start;
+ return -EIO;
}
}
if ( (result != 0x0b) && (result != 0x09) )
{
printk ("GSCD: GoldStar Interface Adapter does not exist or H/W error\n" );
- return -mem_start;
+ return -EIO;
}
/* reset all drives */
{
printk("GSCD: Unable to get major %d for GoldStar CD-ROM\n",
MAJOR_NR);
- return -mem_start;
+ return -EIO;
}
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
request_region(gscd_port, 4, "gscd");
printk ( "GSCD: GoldStar CD-ROM Drive found.\n" );
- return mem_start;
+ return 0;
}
static void gscd_hsg2msf (long hsg, struct msf *msf)
block_fsync /* fsync */
};
-unsigned long hd_init(unsigned long mem_start, unsigned long mem_end)
+int hd_init(void)
{
if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
printk("hd: unable to get major %d for harddisk\n",MAJOR_NR);
- return mem_start;
+ return -1;
}
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read-ahead */
hd_gendisk.next = gendisk_head;
gendisk_head = &hd_gendisk;
timer_table[HD_TIMER].fn = hd_times_out;
- return mem_start;
+ return 0;
}
#define DEVICE_BUSY busy[target]
#include <linux/errno.h>
#include <linux/hdreg.h>
#include <linux/genhd.h>
+#include <linux/malloc.h>
+
#include <asm/byteorder.h>
#include <asm/irq.h>
#include <asm/segment.h>
for (unit = 0; unit < gd->nr_real; ++unit) {
ide_drive_t *drive = &hwif->drives[unit];
+#ifdef CONFIG_BLK_DEV_IDECD
+ if (drive->present && drive->media == cdrom)
+ ide_cdrom_setup(drive);
+#endif /* CONFIG_BLK_DEV_IDECD */
drive->part[0].nr_sects = current_capacity(drive);
if (!drive->present || drive->media != disk) {
drive->part[0].start_sect = -1; /* skip partition check */
gd->real_devices = hwif->drives[0].name; /* name of first drive */
}
-/*
- * ide_alloc(): memory allocation for use *only* during driver initialization.
- * If "within_area" is non-zero, the memory will be allocated such that
- * it lies entirely within a "within_area" sized area (eg. 4096). This is
- * needed for DMA stuff. "within_area" must be a power of two (not validated).
- * All allocations are longword aligned.
- */
-static unsigned long ide_mem_start = 0uL; /* used by ide_alloc() */
-
-void *ide_alloc (unsigned long bytecount, unsigned long within_area)
-{
- const unsigned long longsize_m1 = (sizeof(long) - 1);
- void *p;
-
- if (!ide_mem_start)
- panic("ide: ide_alloc() not valid now\n");
- ide_mem_start = (ide_mem_start + longsize_m1) & ~longsize_m1;
- if (within_area) {
- unsigned long fraction = within_area - (ide_mem_start & (within_area - 1));
- if (fraction < bytecount)
- ide_mem_start += fraction; /* realign to a new page */
- }
- p = (void *) ide_mem_start;
- ide_mem_start += (bytecount + longsize_m1) & ~longsize_m1;
- return p;
-}
-
/*
* init_gendisk() (as opposed to ide_geninit) is called for each major device,
* after probing for drives, to allocate partition tables and other data
break;
}
minors = units * (1<<PARTN_BITS);
- gd = ide_alloc (sizeof(struct gendisk), 0);
- gd->sizes = ide_alloc (minors * sizeof(int), 0);
- gd->part = ide_alloc (minors * sizeof(struct hd_struct), 0);
- bs = ide_alloc (minors*sizeof(int), 0);
+ gd = kmalloc (sizeof(struct gendisk), GFP_KERNEL);
+ gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL);
+ gd->part = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL);
+ bs = kmalloc (minors*sizeof(int), GFP_KERNEL);
/* cdroms and msdos f/s are examples of non-1024 blocksizes */
blksize_size[hwif->major] = bs;
struct hd_driveid *id;
unsigned long capacity, check;
- id = drive->id = ide_alloc (SECTOR_WORDS*4, 0);
+ id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_KERNEL);
ide_input_data(drive, id, SECTOR_WORDS); /* read 512 bytes of id info */
sti();
for (unit = 0; unit < 2; ++unit) { /* note the hardcoded '2' */
ide_drive_t *drive = &hwif->drives[unit];
(void) probe_for_drive (drive);
-#ifdef CONFIG_BLK_DEV_IDECD
- if (drive->present && drive->media == cdrom)
- ide_cdrom_setup(drive);
-#endif /* CONFIG_BLK_DEV_IDECD */
}
for (unit = 0; unit < MAX_DRIVES; ++unit) {
ide_drive_t *drive = &hwif->drives[unit];
* Got the irq, now set everything else up
*/
if ((hwgroup = irq_to_hwgroup[hwif->irq]) == NULL) {
- hwgroup = ide_alloc (sizeof(ide_hwgroup_t), 0);
+ hwgroup = kmalloc (sizeof(ide_hwgroup_t), GFP_KERNEL);
irq_to_hwgroup[hwif->irq] = hwgroup;
hwgroup->hwif = hwif->next = hwif;
hwgroup->rq = NULL;
/*
* This is gets invoked once during initialization, to set *everything* up
*/
-unsigned long ide_init (unsigned long mem_start, unsigned long mem_end)
+int ide_init (void)
{
int h;
- ide_mem_start = mem_start; /* for ide_alloc () */
init_ide_data ();
/*
* First, we determine what hardware is present
hwif->present = 1; /* success */
}
}
- mem_start = ide_mem_start;
- ide_mem_start = 0uL; /* prevent further use of ide_alloc() */
- return mem_start;
+ return 0;
}
}
}
-long blk_dev_init(long mem_start, long mem_end)
+int blk_dev_init(void)
{
struct request * req;
}
memset(ro_bits,0,sizeof(ro_bits));
#ifdef CONFIG_BLK_DEV_IDE
- mem_start = ide_init(mem_start,mem_end); /* this MUST preceed hd_init */
+ ide_init(); /* this MUST preceed hd_init */
#endif
#ifdef CONFIG_BLK_DEV_HD
- mem_start = hd_init(mem_start,mem_end);
+ hd_init();
#endif
#ifdef CONFIG_BLK_DEV_XD
- mem_start = xd_init(mem_start,mem_end);
+ xd_init();
#endif
#ifdef CONFIG_BLK_DEV_FD
floppy_init();
outb_p(0xc, 0x3f2);
#endif
#ifdef CONFIG_CDU31A
- mem_start = cdu31a_init(mem_start,mem_end);
+ cdu31a_init();
#endif CONFIG_CDU31A
#ifdef CONFIG_MCD
- mem_start = mcd_init(mem_start,mem_end);
+ mcd_init();
#endif CONFIG_MCD
#ifdef CONFIG_MCDX
- mem_start = mcdx_init(mem_start,mem_end);
+ mcdx_init();
#endif CONFIG_MCDX
#ifdef CONFIG_SBPCD
- mem_start = sbpcd_init(mem_start, mem_end);
+ sbpcd_init();
#endif CONFIG_SBPCD
#ifdef CONFIG_AZTCD
- mem_start = aztcd_init(mem_start,mem_end);
+ aztcd_init();
#endif CONFIG_AZTCD
#ifdef CONFIG_CDU535
- mem_start = sony535_init(mem_start,mem_end);
+ sony535_init();
#endif CONFIG_CDU535
#ifdef CONFIG_GSCD
- mem_start = gscd_init(mem_start, mem_end);
+ gscd_init();
#endif CONFIG_GSCD
#ifdef CONFIG_CM206
- mem_start = cm206_init(mem_start, mem_end);
+ cm206_init();
#endif
#ifdef CONFIG_OPTCD
- mem_start = optcd_init(mem_start,mem_end);
+ optcd_init();
#endif CONFIG_OPTCD
#ifdef CONFIG_SJCD
- mem_start = sjcd_init(mem_start,mem_end);
+ sjcd_init();
#endif CONFIG_SJCD
- if (ramdisk_size)
- mem_start += rd_init(mem_start, ramdisk_size*1024);
- return mem_start;
+ return 0;
}
# ifndef CONFIG_MODVERSIONS
char kernel_version[]= UTS_RELEASE;
# endif
+#define mcd_init init_module
#else
# define MOD_INC_USE_COUNT
# define MOD_DEC_USE_COUNT
* Test for presence of drive and initialize it. Called at boot time.
*/
-#ifndef MODULE
-unsigned long
-mcd_init(unsigned long mem_start, unsigned long mem_end)
-#else
-int init_module(void)
-#endif
+int
+mcd_init(void)
{
int count;
unsigned char result[3];
if (mcd_port <= 0 || mcd_irq <= 0) {
printk("skip mcd_init\n");
-#ifndef MODULE
- return mem_start;
-#else
return -EIO;
-#endif
}
printk("mcd=0x%x,%d: ", mcd_port, mcd_irq);
{
printk("Unable to get major %d for Mitsumi CD-ROM\n",
MAJOR_NR);
-#ifndef MODULE
- return mem_start;
-#else
return -EIO;
-#endif
-
}
if (check_region(mcd_port, 4)) {
printk("Init failed, I/O port (%X) already in use\n",
mcd_port);
-#ifndef MODULE
- return mem_start;
-#else
return -EIO;
-#endif
}
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
if (count >= 2000000) {
printk("Init failed. No mcd device at 0x%x irq %d\n",
mcd_port, mcd_irq);
-#ifndef MODULE
- return mem_start;
-#else
return -EIO;
-#endif
}
count = inb(MCDPORT(0)); /* pick up the status */
if(getValue(result+count)) {
printk("mitsumi get version failed at 0x%d\n",
mcd_port);
-#ifndef MODULE
- return mem_start;
-#else
return -EIO;
-#endif
}
if (result[0] == result[1] && result[1] == result[2])
-#ifndef MODULE
- return mem_start;
-#else
return -EIO;
-#endif
printk("Mitsumi status, type and version : %02X %c %x ",
result[0],result[1],result[2]);
if (request_irq(mcd_irq, mcd_interrupt, SA_INTERRUPT, "Mitsumi CD"))
{
printk("Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq);
-#ifndef MODULE
- return mem_start;
-#else
return -EIO;
-#endif
}
request_region(mcd_port, 4,"mcd");
mcd_invalidate_buffers();
mcdPresent = 1;
-#ifndef MODULE
- return mem_start;
-#else
return 0;
-#endif
}
changed elsewhere. */
/* declared in blk.h */
-unsigned long mcdx_init(unsigned long mem_start, unsigned long mem_end);
+int mcdx_init(void);
void do_mcdx_request(void);
int check_mcdx_media_change(kdev_t);
/* KERNEL INTERFACE FUNCTIONS **************************************/
-#ifdef MODULE
-#define free(x, y) kfree((x))
-#else
-#define free(x, y) (mem_start -= y)
-#endif
-
static int
mcdx_ioctl(
struct inode* ip, struct file* fp,
int i;
int drives = 0;
- mcdx_init(0, 0);
+ mcdx_init();
for (i = 0; i < MCDX_NDRIVES; i++) {
if (mcdx_stuffp[i]) {
TRACE((INIT, "init_module() drive %d stuff @ %p\n",
}
-unsigned long mcdx_init(unsigned long mem_start, unsigned long mem_end)
+int mcdx_init(void)
{
int drive;
TRACE((INIT, "init() try drive %d\n", drive));
-#ifdef MODULE
TRACE((MALLOC, "init() malloc %d bytes\n", size));
if (!(stuffp = kmalloc(size, GFP_KERNEL))) {
WARN(("init() malloc failed\n"));
break;
}
-#else
- TRACE((INIT, "adjust mem_start\n"));
- stuffp = (struct s_drive_stuff *) mem_start;
- mem_start += size;
-#endif
TRACE((INIT, "init() got %d bytes for drive stuff @ %p\n", sizeof(*stuffp), stuffp));
stuffp->wreg_data,
stuffp->wreg_data + MCDX_IO_SIZE - 1));
TRACE((MALLOC, "init() free stuffp @ %p\n", stuffp));
- free(stuffp, size);
+ kfree(stuffp);
TRACE((INIT, "init() continue at next drive\n"));
continue; /* next drive */
}
MCDX,
stuffp->wreg_data, stuffp->irq));
TRACE((MALLOC, "init() free stuffp @ %p\n", stuffp));
- free(stuffp, size);
+ kfree(stuffp);
TRACE((INIT, "init() continue at next drive\n"));
continue;
}
if (!stuffp->present) {
WARN(("%s=0x%3p,%d: Init failed. No Mitsumi CD-ROM?.\n",
MCDX, stuffp->wreg_data, stuffp->irq));
- free(stuffp, size);
+ kfree(stuffp);
continue; /* next drive */
}
WARN(("%s=0x%3p,%d: Init failed. Can't get major %d.\n",
MCDX,
stuffp->wreg_data, stuffp->irq, MAJOR_NR));
- free(stuffp, size);
+ kfree(stuffp);
continue; /* next drive */
}
MCDX,
stuffp->wreg_data, stuffp->irq, stuffp->irq));
stuffp->irq = 0;
- free(stuffp, size);
+ kfree(stuffp);
continue;
}
request_region((unsigned int) stuffp->wreg_data,
TRACE((INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp));
}
- return mem_start;
+ return 0;
}
# ifndef CONFIG_MODVERSIONS
char kernel_version[]= UTS_RELEASE;
# endif
+#define optcd_init init_module
#else
# define MOD_INC_USE_COUNT
# define MOD_DEC_USE_COUNT
optcd_port = ints[1];
}
-#ifndef MODULE
-#define RETURN_EIO return mem_start
-#else
-#define RETURN_EIO return -EIO
-#endif
-
/*
* Test for presence of drive and initialize it. Called at boot time.
*/
-#ifndef MODULE
-unsigned long optcd_init(unsigned long mem_start, unsigned long mem_end) {
-#else
-int init_module(void) {
-#endif
+
+int optcd_init(void) {
if (optcd_port <= 0) {
printk("optcd: no Optics Storage CDROM Initialization\n");
- RETURN_EIO;
+ return -EIO;
}
if (check_region(optcd_port, 4)) {
printk("optcd: conflict, I/O port 0x%x already used\n",
optcd_port);
- RETURN_EIO;
+ return -EIO;
}
if (!check_region(ISP16_DRIVE_SET_PORT, 5)) {
if ( isp16_config( optcd_port, ISP16_SONY, 0, 0 ) < 0 ) {
printk( "ISP16 cdrom interface has not been properly configured.\n" );
- RETURN_EIO;
+ return -EIO;
}
}
}
if (!optResetDrive()) {
printk("optcd: drive at 0x%x not ready\n", optcd_port);
- RETURN_EIO;
+ return -EIO;
}
if (!version_ok()) {
printk("optcd: unknown drive detected; aborting\n");
- RETURN_EIO;
+ return -EIO;
}
if (optCmd(COMINITDOUBLE) < 0) {
printk("optcd: cannot init double speed mode\n");
- RETURN_EIO;
+ return -EIO;
}
if (register_blkdev(MAJOR_NR, "optcd", &opt_fops) != 0)
{
printk("optcd: unable to get major %d\n", MAJOR_NR);
- RETURN_EIO;
+ return -EIO;
}
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
read_ahead[MAJOR_NR] = 4;
request_region(optcd_port, 4, "optcd");
optPresent = 1;
printk("optcd: 8000 AT CDROM at 0x%x\n", optcd_port);
-#ifndef MODULE
- return mem_start;
-#else
return 0;
-#endif
}
#ifdef MODULE
*/
#if !(SBPCD_ISSUE-1)
#define DO_SBPCD_REQUEST(a) do_sbpcd_request(a)
-#define SBPCD_INIT(a,b) sbpcd_init(a,b)
+#define SBPCD_INIT(a) sbpcd_init(a)
#endif
#if !(SBPCD_ISSUE-2)
#define DO_SBPCD_REQUEST(a) do_sbpcd2_request(a)
-#define SBPCD_INIT(a,b) sbpcd2_init(a,b)
+#define SBPCD_INIT(a) sbpcd2_init(a)
#endif
#if !(SBPCD_ISSUE-3)
#define DO_SBPCD_REQUEST(a) do_sbpcd3_request(a)
-#define SBPCD_INIT(a,b) sbpcd3_init(a,b)
+#define SBPCD_INIT(a) sbpcd3_init(a)
#endif
#if !(SBPCD_ISSUE-4)
#define DO_SBPCD_REQUEST(a) do_sbpcd4_request(a)
-#define SBPCD_INIT(a,b) sbpcd4_init(a,b)
+#define SBPCD_INIT(a) sbpcd4_init(a)
#endif
/*==========================================================================*/
#if SBPCD_DIS_IRQ
*/
#if !(SBPCD_ISSUE-1)
#ifdef CONFIG_SBPCD2
-extern unsigned long sbpcd2_init(unsigned long, unsigned long);
+extern int sbpcd2_init(void);
#endif
#ifdef CONFIG_SBPCD3
-extern unsigned long sbpcd3_init(unsigned long, unsigned long);
+extern int sbpcd3_init(void);
#endif
#ifdef CONFIG_SBPCD4
-extern unsigned long sbpcd4_init(unsigned long, unsigned long);
+extern int sbpcd4_init(void);
#endif
#endif
#ifdef MODULE
int init_module(void)
#else
- unsigned long SBPCD_INIT(u_long mem_start, u_long mem_end)
+int SBPCD_INIT(void)
#endif MODULE
{
int i=0, j=0;
D_S[j].sbp_bufsiz=SBP_BUFFER_FRAMES;
if (D_S[j].drv_type&drv_fam1)
if (READ_AUDIO>0) D_S[j].sbp_audsiz=READ_AUDIO;
-#ifdef MODULE
D_S[j].sbp_buf=(u_char *) vmalloc(D_S[j].sbp_bufsiz*CD_FRAMESIZE);
if (D_S[j].sbp_buf==NULL)
{
if (D_S[j].aud_buf==NULL) msg(DBG_INF,"audio buffer (%d frames) not available.\n",D_S[j].sbp_audsiz);
else msg(DBG_INF,"audio buffer size: %d frames.\n",D_S[j].sbp_audsiz);
}
-#else
- D_S[j].sbp_buf=(u_char *)mem_start;
- mem_start += D_S[j].sbp_bufsiz*CD_FRAMESIZE;
- if (D_S[j].sbp_audsiz>0)
- {
- D_S[j].aud_buf=(u_char *)mem_start;
- mem_start += D_S[j].sbp_audsiz*CD_FRAMESIZE_RAW;
- }
-#endif MODULE
/*
* set the block size
*/
init_done:
#if !(SBPCD_ISSUE-1)
#ifdef CONFIG_SBPCD2
- mem_start=sbpcd2_init(mem_start, mem_end);
+ sbpcd2_init();
#endif
#ifdef CONFIG_SBPCD3
- mem_start=sbpcd3_init(mem_start, mem_end);
+ sbpcd3_init();
#endif
#ifdef CONFIG_SBPCD4
- mem_start=sbpcd4_init(mem_start, mem_end);
+ sbpcd4_init();
#endif
#endif
- return (mem_start);
+ return 0;
#endif MODULE
}
/*==========================================================================*/
* Test for presence of drive and initialize it. Called at boot time.
* Probe cdrom, find out version and status.
*/
-unsigned long sjcd_init( unsigned long mem_start, unsigned long mem_end ){
+int sjcd_init( void ){
int i;
if ( (isp16_type=isp16_detect()) < 0 )
if ( isp16_config( sjcd_port, expected_drive, sjcd_irq, sjcd_dma ) < 0 ) {
printk( "ISP16 cdrom interface has not been properly configured.\n" );
- return(mem_start);
+ return -1;
}
}
if( register_blkdev( MAJOR_NR, "sjcd", &sjcd_fops ) != 0 ){
printk( "Unable to get major %d for Sanyo CD-ROM\n", MAJOR_NR );
- return( mem_start );
+ return -1;
}
blk_dev[ MAJOR_NR ].request_fn = DEVICE_REQUEST;
if( check_region( sjcd_port, 4 ) ){
printk( "Init failed, I/O port (%X) is already in use\n",
sjcd_port );
- return( mem_start );
+ return -1;
}
printk( "Sanyo CDR-H94A:" );
if( !( inb( SJCDPORT( 1 ) ) & 0x04 ) ) break;
if( i == 0 ){
printk( " No device at 0x%x found.\n", sjcd_port );
- return( mem_start );
+ return -1;
}
sjcd_send_cmd( SCMD_RESET );
( int )sjcd_version.minor );
} else {
printk( " Read version failed.\n" );
- return( mem_start );
+ return -1;
}
/*
sjcd_port, sjcd_irq );
sjcd_present++;
- return( mem_start );
+ return 0;
}
/*
#ifdef MODULE
# include <linux/module.h>
-# include <linux/malloc.h>
# include <linux/version.h>
# ifndef CONFIG_MODVERSIONS
char kernel_version[]= UTS_RELEASE;
# endif
+#define sony535_init init_module
#else
# define MOD_INC_USE_COUNT
# define MOD_DEC_USE_COUNT
#include <linux/hdreg.h>
#include <linux/genhd.h>
#include <linux/mm.h>
+#include <linux/malloc.h>
#define REALLY_SLOW_IO
#include <asm/system.h>
static int initialized = 0; /* Has the drive been initialized? */
static int sony_disc_changed = 1; /* Has the disk been changed
- since the last check? */
+ since the last check? */
static int sony_toc_read = 0; /* Has the table of contents been
- read? */
+ read? */
static unsigned int sony_buffer_size; /* Size in bytes of the read-ahead
- buffer. */
+ buffer. */
static unsigned int sony_buffer_sectors; /* Size (in 2048 byte records) of
- the read-ahead buffer. */
+ the read-ahead buffer. */
static unsigned int sony_usage = 0; /* How many processes have the
- drive open. */
+ drive open. */
static int sony_first_block = -1; /* First OS block (512 byte) in
- the read-ahead buffer */
+ the read-ahead buffer */
static int sony_last_block = -1; /* Last OS block (512 byte) in
- the read-ahead buffer */
+ the read-ahead buffer */
static struct s535_sony_toc *sony_toc; /* Points to the table of
- contents. */
+ contents. */
+
static struct s535_sony_subcode *last_sony_subcode; /* Points to the last
- subcode address read */
-#ifndef MODULE
-static Byte *sony_buffer; /* Points to the read-ahead buffer */
-#else
+ subcode address read */
static Byte **sony_buffer; /* Points to the pointers
- to the sector buffers */
-#endif
+ to the sector buffers */
+
static int sony_inuse = 0; /* is the drive in use? Only one
- open at a time allowed */
+ open at a time allowed */
/*
* The audio status uses the values from read subchannel data as specified
* it returns one of the standard error returns.
***************************************************************************/
static int
-#ifndef MODULE
-seek_and_read_N_blocks(Byte params[], int n_blocks, Byte status[2],
- Byte * data_buff, int buf_size)
-#else
seek_and_read_N_blocks(Byte params[], int n_blocks, Byte status[2],
Byte **buff, int buf_size)
-#endif
{
const int block_size = 2048;
Byte cmd_buff[7];
int i;
int read_status;
int retry_count;
-#ifndef MODULE
- Byte *start_pos = data_buff;
-#else
Byte *data_buff;
int sector_count = 0;
-#endif
if (buf_size < ((long)block_size) * n_blocks)
return NO_ROOM;
}
if ((read_status & SONY535_DATA_NOT_READY_BIT) == 0) {
/* data is ready, read it */
-#ifdef MODULE
data_buff = buff[sector_count++];
-#endif
for (i = 0; i < block_size; i++)
*data_buff++ = inb(data_reg); /* unrolling this loop does not seem to help */
break; /* exit the timeout loop */
/* read all the data, now read the status */
if ((i = read_exec_status(status)) != 0)
return i;
-#ifndef MODULE
- return data_buff - start_pos;
-#else
return block_size * sector_count;
-#endif
} /* seek_and_read_N_blocks() */
/****************************************************************************
* The data is in memory now, copy it to the buffer and advance to the
* next block to read.
*/
-#ifndef MODULE
- copyoff = (block - sony_first_block) * 512;
- memcpy(CURRENT->buffer, sony_buffer + copyoff, 512);
-#else
copyoff = block - sony_first_block;
memcpy(CURRENT->buffer,
sony_buffer[copyoff / 4] + 512 * (copyoff % 4), 512);
-#endif
block += 1;
nsect -= 1;
/*
* Initialize the driver.
*/
-#ifndef MODULE
-unsigned long
-sony535_init(unsigned long mem_start, unsigned long mem_end)
-#else
int
-init_module(void)
-#endif
+sony535_init(void)
{
struct s535_sony_drive_config drive_config;
Byte cmd_buff[3];
Byte status[2];
int retry_count;
int tmp_irq;
-#ifdef MODULE
int i;
-#endif
/* Setting the base I/O address to 0 will disable it. */
if ((sony535_cd_base_io == 0xffff)||(sony535_cd_base_io == 0))
- goto bail;
+ return 0;
/* Set up all the register locations */
result_reg = sony535_cd_base_io;
#endif
if (check_region(sony535_cd_base_io,4)) {
printk(CDU535_MESSAGE_NAME ": my base address is not free!\n");
-#ifndef MODULE
- return mem_start;
-#else
return -EIO;
-#endif
}
/* look for the CD-ROM, follows the procedure in the DOS driver */
inb(select_unit_reg);
if (register_blkdev(MAJOR_NR, CDU535_HANDLE, &cdu_fops)) {
printk("Unable to get major %d for %s\n",
MAJOR_NR, CDU535_MESSAGE_NAME);
-#ifndef MODULE
- return mem_start;
-#else
return -EIO;
-#endif
}
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read-ahead */
-#ifndef MODULE
- sony_toc = (struct s535_sony_toc *)mem_start;
- mem_start += sizeof *sony_toc;
- last_sony_subcode = (struct s535_sony_subcode *)mem_start;
- mem_start += sizeof *last_sony_subcode;
- sony_buffer = (Byte *)mem_start;
- mem_start += sony_buffer_size;
-
-#else /* MODULE */
sony_toc = (struct s535_sony_toc *)
kmalloc(sizeof *sony_toc, GFP_KERNEL);
if (sony_toc == NULL)
return -ENOMEM;
}
}
-#endif /* MODULE */
initialized = 1;
}
}
if (!initialized) {
printk("Did not find a " CDU535_MESSAGE_NAME " drive\n");
-#ifdef MODULE
return -EIO;
-#endif
- } else {
- request_region(sony535_cd_base_io, 4, CDU535_HANDLE);
}
-bail:
-#ifndef MODULE
- return mem_start;
-#else
+ request_region(sony535_cd_base_io, 4, CDU535_HANDLE);
return 0;
-#endif
}
#ifndef MODULE
#include <linux/hdreg.h>
#include <linux/pci.h>
#include <linux/bios32.h>
+
#include <asm/io.h>
+#include <asm/dma.h>
#include "ide.h"
unsigned long *table;
request_region(base, 8, hwif->name);
hwif->dma_base = base;
- table = ide_alloc(2 * PRD_ENTRIES * sizeof(long), 4096);
+ table = (void *) __get_dma_pages(GFP_KERNEL, 0);
hwif->dmatable = table;
- outl((unsigned long) table, base + 4);
+ outl(virt_to_bus(table), base + 4);
hwif->dmaproc = &triton_dmaproc;
}
printk("\n %s timing: (0x%04x) sample_CLKs=%d, recovery_CLKs=%d\n",
static u_short xd_iobase = 0;
/* xd_init: register the block device number and set up pointer tables */
-u_long xd_init (u_long mem_start,u_long mem_end)
+int xd_init (void)
{
if (register_blkdev(MAJOR_NR,"xd",&xd_fops)) {
printk("xd_init: unable to get major number %d\n",MAJOR_NR);
- return (mem_start);
+ return -1;
}
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read ahead */
xd_gendisk.next = gendisk_head;
gendisk_head = &xd_gendisk;
- return mem_start;
+ return 0;
}
/* xd_detect: scan the possible BIOS ROM locations for the signature strings */
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
+
+char kernel_version[] = UTS_RELEASE;
+#define atixl_busmouse_init init_module
#else
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
static void release_mouse(struct inode * inode, struct file * file)
{
+ fasync_mouse(inode, file, 0);
+ if (--mouse.active)
+ return;
ATIXL_MSE_INT_OFF(); /* Interrupts are really shut down here */
- mouse.active = 0;
mouse.ready = 0;
free_irq(ATIXL_MOUSE_IRQ);
- fasync_mouse(inode, file, 0);
+ MOD_DEC_USE_COUNT;
}
static int open_mouse(struct inode * inode, struct file * file)
{
if (!mouse.present)
return -EINVAL;
- if (mouse.active)
+ if (mouse.active++)
+ return 0;
+ if (request_irq(ATIXL_MOUSE_IRQ, mouse_interrupt, 0, "ATIXL mouse")) {
+ mouse.active--;
return -EBUSY;
- mouse.active = 1;
+ }
mouse.ready = 0;
mouse.dx = 0;
mouse.dy = 0;
mouse.buttons = mouse.latch_buttons = 0;
- if (request_irq(ATIXL_MOUSE_IRQ, mouse_interrupt, 0, "ATIXL mouse")) {
- mouse.active = 0;
- return -EBUSY;
- }
ATIXL_MSE_INT_ON(); /* Interrupts are really enabled here */
+ MOD_INC_USE_COUNT;
return 0;
}
ATIXL_BUSMOUSE, "atixl", &atixl_busmouse_fops
};
-#ifdef MODULE
-char kernel_version[] = UTS_RELEASE;
-int init_module(void)
-#else
-unsigned long atixl_busmouse_init(unsigned long kmem_start)
-#endif
+int atixl_busmouse_init(void)
{
unsigned char a,b,c;
printk("\nATI Inport ");
else{
mouse.present = 0;
-#ifdef MODULE
return -EIO;
-#else
- return kmem_start;
-#endif
}
outb(0x80, ATIXL_MSE_CONTROL_PORT); /* Reset the Inport device */
outb(0x07, ATIXL_MSE_CONTROL_PORT); /* Select Internal Register 7 */
mouse.wait = NULL;
printk("Bus mouse detected and installed.\n");
mouse_register(&atixl_mouse);
-#ifdef MODULE
return 0;
-#else
- return kmem_start;
-#endif
}
#ifdef MODULE
void cleanup_module(void)
{
- if (MOD_IN_USE)
+ if (MOD_IN_USE) {
printk("atixlmouse: in use, remove delayed\n");
+ return;
+ }
mouse_deregister(&atixl_mouse);
}
#endif
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
+
+char kernel_version[] = UTS_RELEASE;
+#define bus_mouse_init init_module
#else
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
}
/*
- * close access to the mouse (can deal with multiple
- * opens if allowed in the future)
+ * close access to the mouse
*/
static void close_mouse(struct inode * inode, struct file * file)
{
- if (--mouse.active == 0) {
- MSE_INT_OFF();
- free_irq(mouse_irq);
- }
fasync_mouse(inode, file, 0);
+ if (--mouse.active)
+ return;
+ MSE_INT_OFF();
+ free_irq(mouse_irq);
+ MOD_DEC_USE_COUNT;
}
/*
- * open access to the mouse, currently only one open is
- * allowed.
+ * open access to the mouse
*/
static int open_mouse(struct inode * inode, struct file * file)
{
if (!mouse.present)
return -EINVAL;
- if (mouse.active)
+ if (mouse.active++)
+ return 0;
+ if (request_irq(mouse_irq, mouse_interrupt, 0, "Busmouse")) {
+ mouse.active--;
return -EBUSY;
+ }
mouse.ready = 0;
mouse.dx = 0;
mouse.dy = 0;
mouse.buttons = 0x87;
- if (request_irq(mouse_irq, mouse_interrupt, 0, "Busmouse"))
- return -EBUSY;
- mouse.active = 1;
+ MOD_INC_USE_COUNT;
MSE_INT_ON();
return 0;
}
}
/*
- * select for mouse input, must disable the mouse interrupt while checking
- * mouse.ready/select_wait() to avoid race condition (though in reality
- * such a condition is not fatal to the proper operation of the mouse since
- * multiple interrupts generally occur).
+ * select for mouse input
*/
-
static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
{
- int r = 0;
-
- if (sel_type == SEL_IN) {
- MSE_INT_OFF();
- if (mouse.ready) {
- r = 1;
- } else {
- select_wait(&mouse.wait, wait);
+ if (sel_type == SEL_IN) {
+ if (mouse.ready)
+ return 1;
+ select_wait(&mouse.wait, wait);
}
- MSE_INT_ON();
- }
- return(r);
+ return 0;
}
struct file_operations bus_mouse_fops = {
LOGITECH_BUSMOUSE, "busmouse", &bus_mouse_fops
};
-#ifdef MODULE
-char kernel_version[] = UTS_RELEASE;
-
-int init_module(void)
-#else
-unsigned long bus_mouse_init(unsigned long kmem_start)
-#endif
+int bus_mouse_init(void)
{
int i;
/* busy loop */;
if (inb(MSE_SIGNATURE_PORT) != MSE_SIGNATURE_BYTE) {
mouse.present = 0;
-#ifdef MODULE
return -EIO;
-#else
- return kmem_start;
-#endif
}
outb(MSE_DEFAULT_MODE, MSE_CONFIG_PORT);
MSE_INT_OFF();
printk("Logitech Bus mouse detected and installed with IRQ %d.\n",
mouse_irq);
mouse_register(&bus_mouse);
-#ifdef MODULE
return 0;
-#else
- return kmem_start;
-#endif
}
#ifdef MODULE
* 'int vc_resize(unsigned long lines, unsigned long cols)'
* 'void vc_disallocate(unsigned int currcons)'
*
- * 'long con_init(long)'
+ * 'unsigned long con_init(unsigned long)'
* 'int con_open(struct tty_struct *tty, struct file * filp)'
* 'void con_write(struct tty_struct * tty)'
* 'void console_print(const char * b)'
clr_kbd(kbdapplic);
clr_kbd(lnm);
kbd_table[currcons].lockstate = 0;
+ kbd_table[currcons].slockstate = 0;
kbd_table[currcons].ledmode = LED_SHOW_FLAGS;
kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate;
set_leds();
}
/*
- * long con_init(long);
+ * unsigned long con_init(unsigned long);
*
* This routine initializes console interrupts, and does nothing
* else. If you want the screen to clear, call tty_write with
* Reads the information preserved by setup.s to determine the current display
* type and sets everything accordingly.
*/
-long con_init(long kmem_start)
+unsigned long con_init(unsigned long kmem_start)
{
const char *display_desc = "????";
int currcons = 0;
* This version does not support shared irq's.
*
* This module exports the following rs232 io functions:
- * long cy_init(long);
- * int cy_open(struct tty_struct *tty, struct file *filp);
+ * int cy_init(void);
+ * int cy_open(struct tty_struct *tty, struct file *filp);
*
* $Log: cyclades.c,v $
* Revision 1.36.3.2 1995/09/08 22:07:14 bentson
If there are more cards with more ports than have been statically
allocated above, a warning is printed and the extra ports are ignored.
*/
-long
-cy_init(long kmem_start)
+int
+cy_init(void)
{
struct cyclades_port *info;
struct cyclades_card *cinfo;
/* info->timeout */
}
}
- return kmem_start;
+ return 0;
} /* cy_init */
INIT_C_CC
};
-/*
- * Memory allocation vars. These keep track of what memory allocation
- * we can currently use. They help deal with memory in a consistent
- * way, whether during init or run-time.
- */
-static int stli_meminited = 0;
-static long stli_memend;
-
/*****************************************************************************/
/*
#ifdef MODULE
int init_module(void);
void cleanup_module(void);
-#else
-static void stli_meminit(long base);
-static long stli_memhalt(void);
#endif
static void *stli_memalloc(int len);
-long stli_init(long kmem_start);
+int stli_init(void);
static int stli_open(struct tty_struct *tty, struct file *filp);
static void stli_close(struct tty_struct *tty, struct file *filp);
static int stli_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count);
save_flags(flags);
cli();
- stli_init(0);
+ stli_init();
restore_flags(flags);
return(0);
* which are tightly controlled.
*/
-#ifndef MODULE
-
-static void stli_meminit(long base)
-{
- stli_memend = base;
- stli_meminited = 1;
-}
-
-static long stli_memhalt()
-{
- stli_meminited = 0;
- return(stli_memend);
-}
-
-#endif
-
static void *stli_memalloc(int len)
{
- void *mem;
-
- if (stli_meminited) {
- mem = (void *) stli_memend;
- stli_memend += len;
- } else {
- mem = (void *) kmalloc(len, GFP_KERNEL);
- }
- return(mem);
+ return (void *) kmalloc(len, GFP_KERNEL);
}
/*****************************************************************************/
/*****************************************************************************/
-long stli_init(long kmem_start)
+int stli_init(void)
{
printk("%s: version %s\n", stli_drvname, stli_drvversion);
-#ifndef MODULE
- stli_meminit(kmem_start);
-#endif
-
stli_brdinit();
/*
if (tty_register_driver(&stli_callout))
printk("STALLION: failed to register callout driver\n");
-#ifndef MODULE
- kmem_start = stli_memhalt();
-#endif
- return(kmem_start);
+ return 0;
}
/*****************************************************************************/
#define VC_SHIFTRLOCK KG_SHIFTR /* shiftr lock mode */
#define VC_CTRLLLOCK KG_CTRLL /* ctrll lock mode */
#define VC_CTRLRLOCK KG_CTRLR /* ctrlr lock mode */
+ unsigned char slockstate; /* for `sticky' Shift, Ctrl, etc. */
unsigned char ledmode:2; /* one 2-bit value */
#define LED_SHOW_FLAGS 0 /* traditional state */
extern struct kbd_struct kbd_table[];
-extern unsigned long kbd_init(unsigned long);
+extern int kbd_init(void);
extern unsigned char getledstate(void);
extern void setledstate(struct kbd_struct *kbd, unsigned int led);
kbd->lockstate ^= 1 << flag;
}
+extern inline void chg_vc_kbd_slock(struct kbd_struct * kbd, int flag)
+{
+ kbd->slockstate ^= 1 << flag;
+}
+
extern inline void chg_vc_kbd_mode(struct kbd_struct * kbd, int flag)
{
kbd->modeflags ^= 1 << flag;
* Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
* Added decr/incr_console, dynamic keymaps, Unicode support,
* dynamic function/string keys, led setting, Sept 1994
+ * `Sticky' modifier keys, 951006.
*
*/
static k_handfn
do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
- do_meta, do_ascii, do_lock, do_lowercase, do_ignore;
+ do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_ignore;
static k_hand key_handler[16] = {
do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
- do_meta, do_ascii, do_lock, do_lowercase,
- do_ignore, do_ignore, do_ignore, do_ignore
+ do_meta, do_ascii, do_lock, do_lowercase, do_slock,
+ do_ignore, do_ignore, do_ignore
};
typedef void (*void_fnp)(void);
const int max_vals[] = {
255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1,
NR_DEAD - 1, 255, 3, NR_SHIFT - 1,
- 255, NR_ASCII - 1, NR_LOCK - 1, 255
+ 255, NR_ASCII - 1, NR_LOCK - 1, 255,
+ NR_LOCK - 1
};
const int NR_TYPES = SIZE(max_vals);
u_char type;
/* the XOR below used to be an OR */
- int shift_final = shift_state ^ kbd->lockstate;
+ int shift_final = shift_state ^ kbd->lockstate ^ kbd->slockstate;
ushort *key_map = key_maps[shift_final];
if (key_map != NULL) {
}
}
(*key_handler[type])(keysym & 0xff, up_flag);
+ if (type != KT_SLOCK)
+ kbd->slockstate = 0;
} else {
/* maybe only if (kbd->kbdmode == VC_UNICODE) ? */
if (!up_flag)
chg_vc_kbd_lock(kbd, value);
}
+static void do_slock(unsigned char value, char up_flag)
+{
+ if (up_flag || rep)
+ return;
+ chg_vc_kbd_slock(kbd, value);
+}
+
/*
* send_data sends a character to the keyboard and waits
* for a acknowledge, possibly retrying if asked to. Returns
sti();
}
-unsigned long kbd_init(unsigned long kmem_start)
+int kbd_init(void)
{
int i;
struct kbd_struct kbd0;
kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS;
kbd0.ledmode = LED_SHOW_FLAGS;
kbd0.lockstate = KBD_DEFLOCK;
+ kbd0.slockstate = 0;
kbd0.modeflags = KBD_DEFMODE;
kbd0.kbdmode = VC_XLATE;
#endif
mark_bh(KEYBOARD_BH);
enable_bh(KEYBOARD_BH);
- return kmem_start;
+ return 0;
}
char kernel_version[]=UTS_RELEASE;
int io[] = {0, 0, 0};
int irq[] = {0, 0, 0};
-
-int init_module(void)
-#else
-long lp_init(long kmem_start)
+#define lp_init init_module
#endif
+
+int lp_init(void)
{
int offset = 0;
int count = 0;
if (register_chrdev(LP_MAJOR,"lp",&lp_fops)) {
printk("lp: unable to get major %d\n", LP_MAJOR);
-#ifdef MODULE
return -EIO;
-#else
- return kmem_start;
-#endif
}
#ifdef MODULE
/* When user feeds parameters, use them */
if (count == 0)
printk("lp: Driver configured but no interfaces found.\n");
-#ifdef MODULE
return 0;
-#else
- return kmem_start;
-#endif
}
#ifdef MODULE
#include <asm/pgtable.h>
#ifdef CONFIG_SOUND
-extern long soundcard_init(long mem_start);
+int soundcard_init(void);
#endif
static int read_ram(struct inode * inode, struct file * file, char * buf, int count)
NULL /* fsync */
};
-#ifdef CONFIG_FTAPE
-char* ftape_big_buffer;
-#endif
-
-long chr_dev_init(long mem_start, long mem_end)
+int chr_dev_init(void)
{
if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
printk("unable to get major %d for memory devs\n", MEM_MAJOR);
#ifdef CONFIG_RANDOM
rand_initialize();
#endif
- mem_start = tty_init(mem_start);
+ tty_init();
#ifdef CONFIG_PRINTER
- mem_start = lp_init(mem_start);
+ lp_init();
#endif
#if defined (CONFIG_BUSMOUSE) || defined (CONFIG_82C710_MOUSE) || \
defined (CONFIG_PSMOUSE) || defined (CONFIG_MS_BUSMOUSE) || \
defined (CONFIG_ATIXL_BUSMOUSE)
- mem_start = mouse_init(mem_start);
+ mouse_init();
#endif
#ifdef CONFIG_SOUND
- mem_start = soundcard_init(mem_start);
+ soundcard_init();
#endif
#if CONFIG_QIC02_TAPE
- mem_start = qic02_tape_init(mem_start);
+ qic02_tape_init();
#endif
-/*
- * Rude way to allocate kernel memory buffer for tape device
- */
-#ifdef CONFIG_FTAPE
- /* allocate NR_FTAPE_BUFFERS 32Kb buffers at aligned address */
- ftape_big_buffer= (char*) ((mem_start + 0x7fff) & ~0x7fff);
- printk( "ftape: allocated %d buffers aligned at: %p\n",
- NR_FTAPE_BUFFERS, ftape_big_buffer);
- mem_start = (long) ftape_big_buffer + NR_FTAPE_BUFFERS * 0x8000;
-#endif
- return mem_start;
+ return 0;
}
static struct mouse mouse_list = { 0, "head", NULL, &mouse_list, &mouse_list };
#ifndef MODULE
-extern unsigned long bus_mouse_init(unsigned long);
-extern unsigned long psaux_init(unsigned long);
-extern unsigned long ms_bus_mouse_init(unsigned long);
-extern unsigned long atixl_busmouse_init(unsigned long);
+extern int bus_mouse_init(void);
+extern int psaux_init(void);
+extern int ms_bus_mouse_init(void);
+extern int atixl_busmouse_init(void);
#endif
static int mouse_open(struct inode * inode, struct file * file)
{
if (mouse->next || mouse->prev)
return -EBUSY;
+ MOD_INC_USE_COUNT;
mouse->next = &mouse_list;
mouse->prev = mouse_list.prev;
mouse->prev->next = mouse;
{
if (!mouse->next || !mouse->prev)
return -EINVAL;
+ MOD_DEC_USE_COUNT;
mouse->prev->next = mouse->next;
mouse->next->prev = mouse->prev;
mouse->next = NULL;
#ifdef MODULE
char kernel_version[] = UTS_RELEASE;
-
-int init_module(void)
-#else
-unsigned long mouse_init(unsigned long kmem_start)
+#define mouse_init init_module
#endif
+
+int mouse_init(void)
{
#ifndef MODULE
#ifdef CONFIG_BUSMOUSE
- kmem_start = bus_mouse_init(kmem_start);
+ bus_mouse_init();
#endif
#if defined CONFIG_PSMOUSE || defined CONFIG_82C710_MOUSE
- kmem_start = psaux_init(kmem_start);
+ psaux_init();
#endif
#ifdef CONFIG_MS_BUSMOUSE
- kmem_start = ms_bus_mouse_init(kmem_start);
+ ms_bus_mouse_init();
#endif
#ifdef CONFIG_ATIXL_BUSMOUSE
- kmem_start = atixl_busmouse_init(kmem_start);
+ atixl_busmouse_init();
#endif
#endif /* !MODULE */
if (register_chrdev(MOUSE_MAJOR,"mouse",&mouse_fops)) {
printk("unable to get major %d for mouse devices\n",
MOUSE_MAJOR);
-#ifdef MODULE
return -EIO;
-#endif
}
-#ifdef MODULE
return 0;
-#else
- return kmem_start;
-#endif
}
#ifdef MODULE
void cleanup_module(void)
{
- mouse_data *c = mouse_list, *n;
if (MOD_IN_USE) {
printk("mouse: in use, remove delayed\n");
return;
}
unregister_chrdev(MOUSE_MAJOR, "mouse");
- while (c) {
- n = c->next;
- kfree(c);
- c = n;
- }
}
#endif
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
+
+char kernel_version[] = UTS_RELEASE;
+#define ms_bus_mouse_init init_module
#else
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
static void release_mouse(struct inode * inode, struct file * file)
{
+ fasync_mouse(inode, file, 0);
+ if (--mouse.active)
+ return;
MS_MSE_INT_OFF();
- mouse.active = mouse.ready = 0;
+ mouse.ready = 0;
free_irq(MOUSE_IRQ);
- fasync_mouse(inode, file, 0);
+ MOD_DEC_USE_COUNT;
}
static int open_mouse(struct inode * inode, struct file * file)
{
if (!mouse.present)
return -EINVAL;
- if (mouse.active)
- return -EBUSY;
- mouse.active = 1;
- mouse.ready = mouse.dx = mouse.dy = 0;
- mouse.buttons = 0x80;
+ if (mouse.active++)
+ return 0;
if (request_irq(MOUSE_IRQ, ms_mouse_interrupt, 0, "MS Busmouse")) {
- mouse.active = 0;
+ mouse.active--;
return -EBUSY;
}
+ mouse.ready = mouse.dx = mouse.dy = 0;
+ mouse.buttons = 0x80;
outb(MS_MSE_START, MS_MSE_CONTROL_PORT);
+ MOD_INC_USE_COUNT;
MS_MSE_INT_ON();
return 0;
}
MICROSOFT_BUSMOUSE, "msbusmouse", &ms_bus_mouse_fops
};
-#ifdef MODULE
-char kernel_version[] = UTS_RELEASE;
-
-int init_module(void)
-#else
-unsigned long ms_bus_mouse_init(unsigned long kmem_start)
-#endif
+int ms_bus_mouse_init(void)
{
int mse_byte, i;
mouse.present = 0;
}
}
- if (mouse.present == 0) {
-#ifdef MODULE
- return -EIO;
-#else
- return kmem_start;
-#endif
- }
+ if (mouse.present == 0)
+ return -EIO;
MS_MSE_INT_OFF();
request_region(MS_MSE_CONTROL_PORT, 0x04, "MS Busmouse");
printk("Microsoft BusMouse detected and installed.\n");
mouse_register(&ms_bus_mouse);
-#ifdef MODULE
return 0;
-#else
- return kmem_start;
-#endif
}
#ifdef MODULE
void cleanup_module(void)
{
- if (MOD_IN_USE)
+ if (MOD_IN_USE) {
printk("msbusmouse: in use, remove delayed\n");
- else {
- mouse_deregister(&ms_bus_mouse);
- release_region(MS_MSE_CONTROL_PORT, 0x04);
+ return;
}
+ mouse_deregister(&ms_bus_mouse);
+ release_region(MS_MSE_CONTROL_PORT, 0x04);
}
#endif
static struct aux_queue *queue;
static int aux_ready = 0;
-static int aux_busy = 0;
+static int aux_count = 0;
static int aux_present = 0;
static int poll_aux_status(void);
static int poll_aux_status_nosleep(void);
#ifdef CONFIG_82C710_MOUSE
static int qp_present = 0;
-static int qp_busy = 0;
+static int qp_count = 0;
static int qp_data = QP_DATA;
static int qp_status = QP_STATUS;
static void release_aux(struct inode * inode, struct file * file)
{
+ fasync_aux(inode, file, 0);
+ if (--aux_count)
+ return;
aux_write_cmd(AUX_INTS_OFF); /* disable controller ints */
poll_aux_status();
outb_p(AUX_DISABLE,AUX_COMMAND); /* Disable Aux device */
poll_aux_status();
free_irq(AUX_IRQ);
- fasync_aux(inode, file, 0);
- aux_busy = 0;
+ MOD_DEC_USE_COUNT;
}
#ifdef CONFIG_82C710_MOUSE
{
unsigned char status;
+ fasync_aux(inode, file, 0);
+ if (--qp_count)
+ return;
if (!poll_qp_status())
printk("Warning: Mouse device busy in release_qp()\n");
status = inb_p(qp_status);
if (!poll_qp_status())
printk("Warning: Mouse device busy in release_qp()\n");
free_irq(QP_IRQ);
- fasync_aux(inode, file, 0);
- qp_busy = 0;
+ MOD_DEC_USE_COUNT;
}
#endif
static int open_aux(struct inode * inode, struct file * file)
{
if (!aux_present)
- return -EINVAL;
- if (aux_busy)
- return -EBUSY;
- if (!poll_aux_status())
+ return -ENODEV;
+ if (aux_count++)
+ return 0;
+ if (!poll_aux_status()) {
+ aux_count--;
return -EBUSY;
- aux_busy = 1;
+ }
queue->head = queue->tail = 0; /* Flush input queue */
if (request_irq(AUX_IRQ, aux_interrupt, 0, "PS/2 Mouse")) {
- aux_busy = 0;
+ aux_count--;
return -EBUSY;
}
poll_aux_status();
aux_write_cmd(AUX_INTS_ON); /* enable controller ints */
poll_aux_status();
aux_ready = 0;
+ MOD_INC_USE_COUNT;
return 0;
}
#ifdef CONFIG_82C710_MOUSE
/*
* Install interrupt handler.
- * Enable the device, enable interrupts. Set qp_busy
- * (allow only one opener at a time.)
+ * Enable the device, enable interrupts.
*/
static int open_qp(struct inode * inode, struct file * file)
if (!qp_present)
return -EINVAL;
- if (qp_busy)
- return -EBUSY;
+ if (qp_count++)
+ return 0;
- if (request_irq(QP_IRQ, qp_interrupt, 0, "PS/2 Mouse"))
+ if (request_irq(QP_IRQ, qp_interrupt, 0, "PS/2 Mouse")) {
+ qp_count--;
return -EBUSY;
-
- qp_busy = 1;
+ }
status = inb_p(qp_status);
status |= (QP_ENABLE|QP_RESET);
while (!poll_qp_status()) {
printk("Error: Mouse device busy in open_qp()\n");
+ qp_count--;
+ status &= ~(QP_ENABLE|QP_INTS_ON);
+ outb_p(status, qp_status);
+ free_irq(QP_IRQ);
return -EBUSY;
}
outb_p(AUX_ENABLE_DEV, qp_data); /* Wake up mouse */
-
+ MOD_INC_USE_COUNT;
return 0;
}
#endif
PSMOUSE_MINOR, "ps2aux", &psaux_fops
};
-unsigned long psaux_init(unsigned long kmem_start)
+int psaux_init(void)
{
int qp_found = 0;
aux_present = 1;
kbd_read_mask = AUX_OBUF_FULL;
} else {
-#ifdef MODULE
return -EIO;
-#else
- return kmem_start; /* No mouse at all */
-#endif
}
mouse_register(&psaux_mouse);
- queue = (struct aux_queue *) kmem_start;
- kmem_start += sizeof (struct aux_queue);
+ queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
memset(queue, 0, sizeof(*queue));
queue->head = queue->tail = 0;
queue->proc_list = NULL;
poll_aux_status_nosleep(); /* Disable interrupts */
outb_p(AUX_INTS_OFF, AUX_OUTPUT_PORT); /* on the controller */
}
-#ifdef MODULE
return 0;
-#else
- return kmem_start;
-#endif
}
#ifdef MODULE
return 0;
}
-long pty_init(long kmem_start)
+int pty_init(void)
{
memset(&pty_state, 0, sizeof(pty_state));
memset(&pty_driver, 0, sizeof(struct tty_driver));
if (tty_register_driver(&pty_slave_driver))
panic("Couldn't register pty slave driver");
- return kmem_start;
+ return 0;
}
#define Z8530_MAJOR 34
#endif
-long scc_init(long kmem_start);
+int scc_init(void);
int scc_open(struct tty_struct *tty, struct file *filp);
static void scc_close(struct tty_struct *tty, struct file *filp);
/* * Init SCC driver * */
/* ******************************************************************** */
-long scc_init (long kmem_start)
+int scc_init (void)
{
int chip, chan;
register io_port ctrl;
#endif
- return kmem_start;
+ return 0;
}
#endif
*
* This module exports the following rs232 io functions:
*
- * long rs_init(long);
- * int rs_open(struct tty_struct * tty, struct file * filp)
+ * int rs_init(void);
+ * int rs_open(struct tty_struct * tty, struct file * filp)
*/
#include <linux/errno.h>
/*
* The serial driver boot-time initialization code!
*/
-long rs_init(long kmem_start)
+int rs_init(void)
{
int i;
struct async_struct * info;
break;
}
}
- return kmem_start;
+ return 0;
}
/*
/*****************************************************************************/
-/*
- * Memory allocation vars. These keep track of what memory allocation
- * we can currently use. They help deal with memory in a consistent
- * way, whether during init or run-time.
- */
-static int stl_meminited = 0;
-static long stl_memend;
-
-/*****************************************************************************/
-
/*
* Define some handy local macros...
*/
#ifdef MODULE
int init_module(void);
void cleanup_module(void);
-#else
-static void stl_meminit(long base);
-static long stl_memhalt(void);
#endif
static void *stl_memalloc(int len);
-long stl_init(long kmem_start);
+int stl_init(void);
static int stl_open(struct tty_struct *tty, struct file *filp);
static void stl_close(struct tty_struct *tty, struct file *filp);
static int stl_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count);
save_flags(flags);
cli();
- stl_init(0);
+ stl_init();
restore_flags(flags);
return(0);
* memory and it will do the right thing.
*/
-#ifndef MODULE
-
-static void stl_meminit(long base)
-{
- stl_memend = base;
- stl_meminited = 1;
-}
-
-static long stl_memhalt()
-{
- stl_meminited = 0;
- return(stl_memend);
-}
-
-#endif
-
static void *stl_memalloc(int len)
{
- void *mem;
-
- if (stl_meminited) {
- mem = (void *) stl_memend;
- stl_memend += len;
- } else {
- mem = (void *) kmalloc(len, GFP_KERNEL);
- }
- return(mem);
+ return (void *) kmalloc(len, GFP_KERNEL);
}
/*****************************************************************************/
/*****************************************************************************/
-long stl_init(long kmem_start)
+int stl_init(void)
{
printk("%s: version %s\n", stl_drvname, stl_drvversion);
-#ifndef MODULE
- stl_meminit(kmem_start);
-#endif
-
stl_initbrds();
/*
if (tty_register_driver(&stl_callout))
printk("STALLION: failed to register callout driver\n");
-#ifndef MODULE
- kmem_start = stl_memhalt();
-#endif
- return(kmem_start);
+ return 0;
}
/*****************************************************************************/
} /* qic02_get_resources */
-long qic02_tape_init(long kmem_start)
+int qic02_tape_init(void)
/* Shouldn't this be a caddr_t ? */
{
if (TPSTATSIZE != 6) {
printk(TPQIC02_NAME ": internal error: tpstatus struct incorrect!\n");
- return kmem_start;
+ return -ENODEV;
}
if ((TPQBUF_SIZE<512) || (TPQBUF_SIZE>=0x10000)) {
printk(TPQIC02_NAME ": internal error: DMA buffer size out of range\n");
- return kmem_start;
+ return -ENODEV;
}
QIC02_TAPE_DEBUG = TPQD_DEFAULT_FLAGS;
# endif
rcs_revision, rcs_date);
if (qic02_get_resources())
- return kmem_start;
+ return -ENODEV;
#else
printk(TPQIC02_NAME ": Runtime config, %s, %s\n",
rcs_revision, rcs_date);
#ifndef CONFIG_MAX_16M
if (buffaddr+TPQBUF_SIZE>=0x1000000) {
printk(TPQIC02_NAME ": DMA buffer *must* be in lower 16MB\n");
- return kmem_start;
+ return -ENODEV;
}
#endif
free_irq(QIC02_TAPE_IRQ);
free_dma(QIC02_TAPE_DMA);
#endif
- return kmem_start;
+ return -ENODEV;
}
/* prepare timer */
free_irq(QIC02_TAPE_IRQ);
free_dma(QIC02_TAPE_DMA);
unregister_chrdev(QIC02_TAPE_MAJOR, TPQIC02_NAME);
- return kmem_start;
+ return -ENODEV;
} else {
if (is_exception()) {
tpqputs(TPQD_ALWAYS, "exception detected\n");
ioctl_status.mt_fileno = 0; /* number of current file on tape */
ioctl_status.mt_blkno = 0; /* number of current (logical) block */
- return kmem_start;
+ return 0;
} /* qic02_tape_init */
* Ok, now we can initialize the rest of the tty devices and can count
* on memory allocations, interrupts etc..
*/
-long tty_init(long kmem_start)
+int tty_init(void)
{
if (sizeof(struct tty_struct) > PAGE_SIZE)
panic("size of tty structure > PAGE_SIZE!");
if (register_chrdev(TTYAUX_MAJOR,"cua",&tty_fops))
panic("unable to get major %d for tty device", TTYAUX_MAJOR);
- kmem_start = kbd_init(kmem_start);
- kmem_start = rs_init(kmem_start);
+ kbd_init();
+ rs_init();
#ifdef CONFIG_SCC
- kmem_start = scc_init(kmem_start);
+ scc_init();
#endif
#ifdef CONFIG_CYCLADES
- kmem_start = cy_init(kmem_start);
+ cy_init();
#endif
#ifdef CONFIG_STALLION
- kmem_start = stl_init(kmem_start);
+ stl_init();
#endif
#ifdef CONFIG_ISTALLION
- kmem_start = stli_init(kmem_start);
+ stli_init();
#endif
- kmem_start = pty_init(kmem_start);
- kmem_start = vcs_init(kmem_start);
- return kmem_start;
+ pty_init();
+ vcs_init();
+ return 0;
}
NULL /* fsync */
};
-long vcs_init(long kmem_start)
+int vcs_init(void)
{
- if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops))
+ int error;
+
+ error = register_chrdev(VCS_MAJOR, "vcs", &vcs_fops);
+ if (error)
printk("unable to get major %d for vcs device", VCS_MAJOR);
- return kmem_start;
+ return error;
}
request_region(ioaddr, EL2_IO_EXTENT,"3c503");
if (dev == NULL)
- dev = init_etherdev(0, sizeof(struct ei_device), 0);
+ dev = init_etherdev(0, sizeof(struct ei_device));
if (ei_debug && version_printed++ == 0)
printk(version);
adapter = (elp_device *)(dev->priv = kmalloc(sizeof(elp_device), GFP_KERNEL));
CHECK_NULL(adapter);
if (adapter == NULL)
- return -ENOMEM;
+ return;
memset(&(adapter->stats), 0, sizeof(struct enet_statistics));
/*
/* Allocate a new 'dev' if needed. */
if (dev == NULL)
- dev = init_etherdev(0, sizeof(struct net_local), 0);
+ dev = init_etherdev(0, sizeof(struct net_local));
if (net_debug && version_printed++ == 0)
printk(version);
dev->get_stats = el16_get_stats;
ether_setup(dev); /* Generic ethernet behaviour */
+
+ dev->flags&=~IFF_MULTICAST; /* Multicast doesn't work */
return 0;
}
endif
endif
+ifneq ($(CONFIG_PPP),n)
+ M_OBJS += bsd_comp.o
+endif
+
ifeq ($(CONFIG_SLIP),y)
L_OBJS += slip.o
CONFIG_SLHC_BUILTIN = y
--- /dev/null
+Behaviour of cards under Multicast. This is how they currently
+behave not what the hardware can do. In paticular all the 8390 based
+cards don't use the onboard hash filter, and the lance driver doesn't
+use its filter, even though the code for loading it is in the DEC
+lance based driver.
+
+The following multicast requirements are needed
+-----------------------------------------------
+Appletalk Multicast hardware filtering not important but
+ avoid cards only doing promisc
+IP-Multicast Multicast hardware filters really help
+IP-MRoute AllMulti hardware filters are of no help
+
+
+Board Multicast AllMulti Promisc Filter
+------------------------------------------------------------------------
+3c501 YES YES YES Software
+3c503 YES YES YES Software(#)
+3c505 YES NO YES Hardware
+3c507 NO NO NO N/A
+3c509 YES YES YES Software
+ac3200 YES YES YES Software(#)
+apricot YES PROMISC YES Hardware
+arcnet NO NO NO N/A
+at1700 **** PROMISC YES Software
+atp **** PROMISC YES Software
+de4x5 YES NO YES Hardware
+de600 NO NO NO N/A
+de620 **** PROMISC YES Software
+depca YES PROMISC YES Hardware
+e2100 YES YES YES Software(#)
+eepro YES(*) PROMISC YES Hardware
+eexpress NO NO NO N/A
+ewrk3 YES PROMISC YES Hardware
+hp-plus YES YES YES Software(#)
+hp YES YES YES Software(#)
+hp100 YES YES YES Software(#)
+ibmtr NO NO NO N/A
+lance YES YES YES Software(#)
+ne YES YES YES Software(#)
+ni52
+ni65 NO NO NO N/A
+seeq NO NO NO N/A
+sk_g16 NO NO YES N/A
+smc-ultra YES YES YES Software(#)
+tulip YES YES YES Hardware
+wavelan --------Buggy-------- YES N/A
+wd YES YES YES Software(#)
+znet YES YES YES Software
+
+
+**** = This driver would take down your entire network if you use it in a
+ multicast kernel with IP forwarding enabled (patches sent to Linus)
+YES(*) = As above but only if >64 addresses are activated.
+PROMISC = All multicasts mode is in fact promiscuous mode.
+(#) = Hardware multicast support is not used yet.
+
+
#if defined(CONFIG_PPP)
extern int ppp_init(struct device *);
-#ifdef CONFIG_PPP_LOTS
-
- static struct device ppp15_dev={"ppp15",0,0,0,0,15,0,0,0,0,NEXT_DEV,ppp_init};
- static struct device ppp14_dev={"ppp14",0,0,0,0,14,0,0,0,0,&ppp15_dev,ppp_init};
- static struct device ppp13_dev={"ppp13",0,0,0,0,13,0,0,0,0,&ppp14_dev,ppp_init};
- static struct device ppp12_dev={"ppp12",0,0,0,0,12,0,0,0,0,&ppp13_dev,ppp_init};
- static struct device ppp11_dev={"ppp11",0,0,0,0,11,0,0,0,0,&ppp12_dev,ppp_init};
- static struct device ppp10_dev={"ppp10",0,0,0,0,10,0,0,0,0,&ppp11_dev,ppp_init};
- static struct device ppp9_dev={"ppp9",0,0,0,0,9,0,0,0,0,&ppp10_dev,ppp_init};
- static struct device ppp8_dev={"ppp8",0,0,0,0,8,0,0,0,0,&ppp9_dev,ppp_init};
- static struct device ppp7_dev={"ppp7",0,0,0,0,7,0,0,0,0,&ppp8_dev,ppp_init};
- static struct device ppp6_dev={"ppp6",0,0,0,0,6,0,0,0,0,&ppp7_dev,ppp_init};
- static struct device ppp5_dev={"ppp5",0,0,0,0,5,0,0,0,0,&ppp6_dev,ppp_init};
- static struct device ppp4_dev={"ppp4",0,0,0,0,4,0,0,0,0,&ppp5_dev,ppp_init};
-# undef NEXT_DEV
-# define NEXT_DEV (&ppp4_dev)
-#endif /* CONFIG_PPP_LOTS */
-
-static struct device ppp3_dev = {
- "ppp3", 0x0, 0x0, 0x0, 0x0, 3, 0, 0, 0, 0, NEXT_DEV, ppp_init, };
-static struct device ppp2_dev = {
- "ppp2", 0x0, 0x0, 0x0, 0x0, 2, 0, 0, 0, 0, &ppp3_dev, ppp_init, };
-static struct device ppp1_dev = {
- "ppp1", 0x0, 0x0, 0x0, 0x0, 1, 0, 0, 0, 0, &ppp2_dev, ppp_init, };
-static struct device ppp0_dev = {
- "ppp0", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, &ppp1_dev, ppp_init, };
+static struct device ppp_bootstrap = {
+ "ppp_proto", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, ppp_init, };
#undef NEXT_DEV
-#define NEXT_DEV (&ppp0_dev)
+#define NEXT_DEV (&ppp_bootstrap)
#endif /* PPP */
#ifdef CONFIG_DUMMY
/* Allocate a new 'dev' if needed. */
if (dev == NULL)
- dev = init_etherdev(0, sizeof(struct net_local), 0);
+ dev = init_etherdev(0, sizeof(struct net_local));
/* Grab the region so that we can find another board if the IRQ request
fails. */
set_multicast_list(struct device *dev, int num_addrs, void *addrs)
{
short ioaddr = dev->base_addr;
- if (num_addrs) {
+ if (num_addrs)
+ {
+ /*
+ * We must make the kernel realise we had to move
+ * into promisc mode or we start all out war on
+ * the cable. - AC
+ */
+ dev->flags|=IFF_PROMISC;
+
outb(3, ioaddr + RX_MODE); /* Enable promiscuous mode */
- } else
+ }
+ else
outb(2, ioaddr + RX_MODE); /* Disable promiscuous, use normal mode */
}
#ifdef MODULE
{
struct net_local *lp = (struct net_local *)dev->priv;
short ioaddr = dev->base_addr;
+ /*
+ * We must make the kernel realise we had to move
+ * into promisc mode or we start all out war on
+ * the cable. - AC
+ */
+ if(num_addrs)
+ dev->flags|=IFF_PROMISC;
lp->addr_mode = num_addrs ? CMR2h_PROMISC : CMR2h_Normal;
write_reg_high(ioaddr, CMR2, lp->addr_mode);
}
--- /dev/null
+/* 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 4==
+ *
+ * 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.1 1994/12/08 01:59:58 paulus Exp $
+ */
+
+#ifndef MODULE
+#error This file must be compiled as a module.
+#endif
+
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <endian.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/sched.h> /* to get the struct task_struct */
+#include <linux/string.h> /* used in new tty drivers */
+#include <linux/signal.h> /* used in new tty drivers */
+
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/segment.h>
+
+#include <net/if.h>
+
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/inet.h>
+#include <linux/ioctl.h>
+
+#include <linux/ppp_defs.h>
+
+#ifdef NEW_SKBUFF
+#include <linux/netprotocol.h>
+#endif
+
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <net/if_arp.h>
+
+#undef PACKETPTR
+#define PACKETPTR 1
+#include <linux/ppp-comp.h>
+#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)
+#define RATIO_MAX (0x7fffffff>>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
+ *************************************************************/
+
+char kernel_version[] = UTS_RELEASE;
+
+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)
+{
+ if (MOD_IN_USE)
+ printk("ppp_bsd_comp: device busy, remove delayed\n");
+ else
+ ppp_unregister_compressor (&ppp_bsd_compress);
+}
ether_setup(dev);
+ dev->flags&=~IFF_MULTICAST;
+
select_prn();
return 0;
}
static void
de620_set_multicast_list(struct device *dev, int num_addrs, void *addrs)
{
- if (num_addrs) { /* Enable promiscuous mode */
+ if (num_addrs)
+ { /* Enable promiscuous mode */
+ /*
+ * We must make the kernel realise we had to move
+ * into promisc mode or we start all out war on
+ * the cable. - AC
+ */
+ dev->flags|=IFF_PROMISC;
+
de620_set_register(dev, W_TCR, (TCR_DEF & ~RXPBM) | RXALL);
}
else { /* Disable promiscuous mode, use normal mode */
short ioaddr = dev->base_addr;
unsigned short mode;
- if (num_addrs < -1 || num_addrs > 63) {
+ if (num_addrs <= -1 || num_addrs > 63) {
+ /*
+ * We must make the kernel realise we had to move
+ * into promisc mode or we start all out war on
+ * the cable. If it was a promisc rewquest the
+ * flag is already set. If not we assert it.
+ */
+ dev->flags|=IFF_PROMISC;
+
outb(BANK2_SELECT, ioaddr); /* be CAREFULL, BANK 2 now */
mode = inb(ioaddr + REG2);
outb(mode | PRMSC_Mode, ioaddr + REG2);
ether_setup(dev);
+ dev->flags&=~IFF_MULTICAST;
+
return 0;
}
} else {
release_region(thisEthwrk.base_addr, EWRK3_TOTAL_SIZE);
unregister_netdev(&thisEthwrk);
- free(thisEthwrk.priv);
+ kfree(thisEthwrk.priv);
thisEthwrk.priv = NULL;
}
}
return ENODEV;
if (dev == NULL)
- dev = init_etherdev(0, sizeof(struct ei_device), 0);
+ dev = init_etherdev(0, sizeof(struct ei_device));
printk("%s: %s at %#3x,", dev->name, name, ioaddr);
}
if (dev == NULL)
- dev = init_etherdev(0, sizeof(struct ei_device), 0);
+ dev = init_etherdev(0, sizeof(struct ei_device));
printk("%s: %s (ID %02x) at %#3x,", dev->name, name, board_id, ioaddr);
hp100_page( MAC_CTRL );
hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); /* stop rx/tx */
- if ( num_addrs < 0 )
+ if ( num_addrs == -1 )
{
lp -> mac2_mode = HP100_MAC2MODE6; /* promiscuous mode, all good */
lp -> mac1_mode = HP100_MAC1MODE6; /* packets on the net */
}
else
- if ( num_addrs > 0 )
+ if ( num_addrs != 0 )
{
lp -> mac2_mode = HP100_MAC2MODE5; /* multicast mode, packets for me */
lp -> mac1_mode = HP100_MAC1MODE5; /* broadcasts and all multicasts */
#include <linux/skbuff.h>
static unsigned int lance_portlist[] = {0x300, 0x320, 0x340, 0x360, 0};
-unsigned long lance_probe1(int ioaddr, unsigned long mem_start);
+void lance_probe1(int ioaddr);
#ifdef HAVE_DEVLIST
struct netdev_entry lance_drv =
struct lance_private {
/* The Tx and Rx ring entries must be aligned on 8-byte boundaries.
- This is accomplished by allocating 7 extra bytes for the struct
- and adjusting the start of the struct to be 8-byte aligned. */
+ This is always true for kmalloc'ed memory */
struct lance_rx_head rx_ring[RX_RING_SIZE];
struct lance_tx_head tx_ring[TX_RING_SIZE];
struct lance_init_block init_block;
before the memory management system is started, and thus well before the
other probes. */
-unsigned long lance_init(unsigned long mem_start, unsigned long mem_end)
+int lance_init(void)
{
int *port;
- if (mem_end <= 16*1024*1024)
+ if (high_memory <= 16*1024*1024)
lance_need_isa_bounce_buffers = 0;
#if defined(CONFIG_PCI)
pcibios_write_config_word(pci_bus, pci_device_fn,
PCI_COMMAND, pci_command);
}
- printk("Found PCnet/PCI at %#x, irq %d (mem_start is %#lx).\n",
- pci_ioaddr, pci_irq_line, mem_start);
- mem_start = lance_probe1(pci_ioaddr, mem_start);
+ printk("Found PCnet/PCI at %#x, irq %d.\n",
+ pci_ioaddr, pci_irq_line);
+ lance_probe1(pci_ioaddr);
pci_irq_line = 0;
}
}
if ((offset14 == 0x52 || offset14 == 0x57) &&
((offset15 = inb(ioaddr + 15)) == 0x57 || offset15 == 0x44))
- mem_start = lance_probe1(ioaddr, mem_start);
+ lance_probe1(ioaddr);
}
}
- return mem_start;
+ return 0;
}
-unsigned long lance_probe1(int ioaddr, unsigned long mem_start)
+void lance_probe1(int ioaddr)
{
struct device *dev;
struct lance_private *lp;
outw(0x0000, ioaddr+LANCE_ADDR); /* Switch to window 0 */
if (inw(ioaddr+LANCE_DATA) != 0x0004)
- return mem_start;
+ return;
/* Get the version of the chip. */
outw(88, ioaddr+LANCE_ADDR);
if (lance_debug > 2)
printk(" LANCE chip version is %#x.\n", chip_version);
if ((chip_version & 0xfff) != 0x003)
- return mem_start;
+ return;
chip_version = (chip_version >> 12) & 0xffff;
for (lance_version = 1; chip_table[lance_version].id_number; lance_version++) {
if (chip_table[lance_version].id_number == chip_version)
}
}
- dev = init_etherdev(0, 7
- + ((sizeof(struct lance_private) + 7) & ~7)
- + PKT_BUF_SZ*RX_RING_SIZE
- + (lance_need_isa_bounce_buffers
- ? PKT_BUF_SZ*TX_RING_SIZE
- : 0),
- &mem_start);
-
+ dev = init_etherdev(0, 0);
chipname = chip_table[lance_version].name;
printk("%s: %s at %#3x,", dev->name, chipname, ioaddr);
dev->base_addr = ioaddr;
request_region(ioaddr, LANCE_TOTAL_SIZE, chip_table[lance_version].name);
- /* Make certain the data structures used by the LANCE are aligned. */
- dev->priv = (void *)(((int)dev->priv + 7) & ~7);
- lp = (struct lance_private *)dev->priv;
+ /* Make certain the data structures used by the LANCE are aligned and DMAble. */
+ lp = (struct lance_private *) kmalloc(sizeof(*lp), GFP_DMA | GFP_KERNEL);
+ dev->priv = lp;
lp->name = chipname;
- lp->rx_buffs = (long)lp + ((sizeof(struct lance_private) + 7) & ~7);
- lp->tx_bounce_buffs = (char (*)[PKT_BUF_SZ])
- (lp->rx_buffs + PKT_BUF_SZ*RX_RING_SIZE);
+ lp->rx_buffs = (unsigned long) kmalloc(PKT_BUF_SZ*RX_RING_SIZE, GFP_DMA | GFP_KERNEL);
+ lp->tx_bounce_buffs = NULL;
+ if (lance_need_isa_bounce_buffers)
+ lp->tx_bounce_buffs = kmalloc(PKT_BUF_SZ*TX_RING_SIZE, GFP_DMA | GFP_KERNEL);
lp->chip_version = lance_version;
printk(", probed IRQ %d", dev->irq);
else {
printk(", failed to detect IRQ line.\n");
- return mem_start;
+ return;
}
/* Check for the initialization done bit, 0x0100, which means
} else if (dev->dma) {
if (request_dma(dev->dma, chipname)) {
printk("DMA %d allocation failed.\n", dev->dma);
- return mem_start;
+ return;
} else
printk(", assigned DMA %d.\n", dev->dma);
} else { /* OK, we have to auto-DMA. */
}
if (i == 4) { /* Failure: bail. */
printk("DMA detection failed.\n");
- return mem_start;
+ return;
}
}
dev->get_stats = &lance_get_stats;
dev->set_multicast_list = &set_multicast_list;
- return mem_start;
+ return;
}
\f
}
/* Set or clear the multicast filter for this adaptor.
+ num_addrs == -2 All multicasts
num_addrs == -1 Promiscuous mode, receive all packets
num_addrs == 0 Normal mode, clear multicast list
num_addrs > 0 Multicast mode, receive normal and MC packets, and do
outw(0, ioaddr+LANCE_ADDR);
outw(0x0004, ioaddr+LANCE_DATA); /* Temporarily stop the lance. */
- if (num_addrs >= 0) {
+ if (num_addrs >= 0 || num_addrs==-2) {
short multicast_table[4];
int i;
/* We don't use the multicast table, but rely on upper-layer filtering. */
int loopback_init(struct device *dev)
{
int i;
-
- dev->mtu = 2000; /* MTU */
+#ifdef CONFIG_SKB_LARGE
+ dev->mtu = 7900; /* MTU */
+#else
+ dev->mtu = 3800;
+#endif
dev->tbusy = 0;
dev->hard_start_xmit = loopback_xmit;
dev->open = NULL;
dev->family = AF_INET;
#ifdef CONFIG_INET
dev->pa_addr = in_aton("127.0.0.1");
- dev->pa_brdaddr = in_aton("127.255.255.255");
+ dev->pa_brdaddr = in_aton("127.255.255.255");
dev->pa_mask = in_aton("255.0.0.0");
dev->pa_alen = 4;
#endif
if (dev == NULL)
- dev = init_etherdev(0, sizeof(struct ei_device), 0);
+ dev = init_etherdev(0, sizeof(struct ei_device));
if (dev->irq < 2) {
autoirq_setup(0);
#define MAX_ETH_CARDS 16 /* same as the number if irq's in irq2dev[] */
static struct device *ethdev_index[MAX_ETH_CARDS];
-unsigned long lance_init(unsigned long mem_start, unsigned long mem_end);
-unsigned long pi_init(unsigned long mem_start, unsigned long mem_end);
-unsigned long apricot_init(unsigned long mem_start, unsigned long mem_end);
-unsigned long dec21040_init(unsigned long mem_start, unsigned long mem_end);
-
-/*
- net_dev_init() is our network device initialization routine.
- It's called from init/main.c with the start and end of free memory,
- and returns the new start of free memory.
- */
-
-unsigned long net_dev_init (unsigned long mem_start, unsigned long mem_end)
-{
-
- /* Network device initialization for devices that must allocate
- low-memory or contiguous DMA buffers.
- */
-#if defined(CONFIG_LANCE)
- mem_start = lance_init(mem_start, mem_end);
-#endif
-#if defined(CONFIG_PI)
- mem_start = pi_init(mem_start, mem_end);
-#endif
-#if defined(CONFIG_DEC_ELCP)
- mem_start = dec21040_init(mem_start, mem_end);
-#endif
- return mem_start;
-}
/* Fill in the fields of the device structure with ethernet-generic values.
*/
struct device *
-init_etherdev(struct device *dev, int sizeof_priv, unsigned long *mem_startp)
+init_etherdev(struct device *dev, int sizeof_priv)
{
int new_device = 0;
int i;
dev = cur_dev;
dev->init = NULL;
sizeof_priv = (sizeof_priv + 3) & ~3;
- if (mem_startp && *mem_startp ) {
- dev->priv = (void*) *mem_startp;
- *mem_startp += sizeof_priv;
- } else
- dev->priv = sizeof_priv
+ dev->priv = sizeof_priv
? kmalloc(sizeof_priv, GFP_KERNEL)
: NULL;
if (dev->priv) memset(dev->priv, 0, sizeof_priv);
alloc_size &= ~3; /* Round to dword boundary. */
- if (mem_startp && *mem_startp ) {
- dev = (struct device *)*mem_startp;
- *mem_startp += alloc_size;
- } else
- dev = (struct device *)kmalloc(alloc_size, GFP_KERNEL);
+ dev = (struct device *)kmalloc(alloc_size, GFP_KERNEL);
memset(dev, 0, alloc_size);
if (sizeof_priv)
dev->priv = (void *) (dev + 1);
ether_setup(dev);
+ dev->flags &= ~IFF_MULTICAST;
dev->interrupt = 0;
dev->tbusy = 0;
dev->start = 0;
#define DEF_B_SQUELDELAY 3 /* 30 mS */
#define DEF_B_CLOCKMODE 0 /* Normal clock mode */
-struct device *init_etherdev(struct device *dev, int sizeof_private,
- unsigned long *mem_startp);
-
static const char *version =
"PI: V0.8 ALPHA April 23 1995 David Perry (dp@hydra.carleton.ca)\n";
}
-unsigned long pi_init(unsigned long mem_start, unsigned long mem_end)
+int pi_init(void)
{
int *port;
int ioaddr = 0;
break;
default:
printk("PI: ERROR: No card found\n");
- return mem_start;
+ return -EIO;
}
/* Link a couple of device structures into the chain */
*/
register_netdev(&pi0a);
- pi0a.priv=(void *)mem_start;
- mem_start+=sizeof(struct pi_local) + (DMA_BUFF_SIZE + sizeof(struct mbuf)) * 4
- + 8; /* for alignment */
+ pi0a.priv = kmalloc(sizeof(struct pi_local) + (DMA_BUFF_SIZE + sizeof(struct mbuf)) * 4, GFP_KERNEL | GFP_DMA);
pi0a.dma = PI_DMA;
pi0a.base_addr = ioaddr + 2;
register_netdev(&pi0b);
pi0b.base_addr = ioaddr;
pi0b.irq = 0;
- pi0b.priv=(void *)mem_start;
- mem_start+=sizeof(struct pi_local) + (DMA_BUFF_SIZE + sizeof(struct mbuf)) * 4
- + 8; /* for alignment */
+ pi0b.priv = kmalloc(sizeof(struct pi_local) + (DMA_BUFF_SIZE + sizeof(struct mbuf)) * 4, GFP_KERNEL | GFP_DMA);
/* Now initialize them */
pi_probe(&pi0a, card_type);
pi0b.irq = pi0a.irq; /* IRQ is shared */
- return mem_start;
+ return 0;
}
static int valid_dma_page(unsigned long addr, unsigned long dev_buffsize)
-/* PPP for Linux
-*/
+/* PPP for Linux
+ *
+ * Michael Callahan <callahan@maths.ox.ac.uk>
+ * Al Longyear <longyear@netcom.com>
+ *
+ * Dynamic PPP devices by Jim Freeman <jfree@caldera.com>.
+ * ppp_tty_receive ``noisy-raise-bug'' fixed by Ove Ewerlid <ewerlid@syscon.uu.se>
+ *
+ * ==FILEVERSION 4==
+ *
+ * NOTE TO MAINTAINERS:
+ * 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 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.
+ */
/*
Sources:
Flags for this module (any combination is acceptable for testing.):
- NET02D - Define if using Net-2-Debugged in kernels earlier
- than v1.1.4.
-
- NEW_TTY_DRIVERS - Define if using new Ted Ts'o's alpha TTY drivers
- from tsx-11.mit.edu. From Ted Ts'o.
-
- OPTIMIZE_FLAG_TIME - Number of jiffies to force sending of leading flag
+ 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
- flag is always sent.
+ 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.
+
+ NEW_SKBUFF - Use NET3.020 sk_buff's
*/
-/* #define NET02D -* */
-#define NEW_TTY_DRIVERS /* */
-#define OPTIMIZE_FLAG_TIME ((HZ * 3)/2) /* */
-#define CHECK_CHARACTERS
+/* #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! */
+
+#ifdef NEW_SKBUFF
+#undef USE_SKB_PROTOCOL
+#define USE_SKB_PROTOCOL 2
+#endif
+
+#ifndef PPP_MAX_DEV
+#define PPP_MAX_DEV 256
+#endif
+
+/* $Id: ppp.c,v 1.5 1995/06/12 11:36:53 paulus Exp $
+ * Added dynamic allocation of channels to eliminate
+ * compiled-in limits on the number of channels.
+ *
+ * Dynamic channel allocation code Copyright 1995 Caldera, Inc.,
+ * released under the GNU General Public License Version 2.
+ */
-#include <linux/config.h>
-#ifdef MODULE
#include <linux/module.h>
+#ifdef MODULE
#include <linux/version.h>
-#endif
+#define STATIC
+#else
+#define STATIC static
+#endif /* def MODULE */
+#include <endian.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/malloc.h>
#include <linux/tty.h>
#include <linux/errno.h>
-#include <linux/sched.h> /* to get the struct task_struct */
-#include <linux/string.h> /* used in new tty drivers */
-#include <linux/signal.h> /* used in new tty drivers */
+#include <linux/sched.h> /* to get the struct task_struct */
+#include <linux/string.h> /* used in new tty drivers */
+#include <linux/signal.h> /* used in new tty drivers */
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/segment.h>
-
-#ifdef NET02D /* v1.1.4 net code and earlier */
-#include <dev.h>
-#include <skbuff.h>
-#include <inet.h>
-#define skb_queue_head_init(buf) *(buf) = NULL
-#else /* v1.1.5 and later */
+#include <net/if.h>
+#include <linux/if_ether.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/inet.h>
+#include <linux/ioctl.h>
+
+#ifdef NEW_SKBUFF
+#include <linux/netprotocol.h>
+#else
+typedef struct sk_buff sk_buff;
+#define skb_data(skb) ((unsigned char *) (skb)->data)
#endif
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <linux/if_arp.h>
+#include "slhc.h"
+#include <linux/ppp_defs.h>
+#include <linux/socket.h>
#include <linux/if_ppp.h>
+#include <linux/if_pppvar.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
+#undef PACKETPTR
+#define PACKETPTR 1
+#include <linux/ppp-comp.h>
+#undef PACKETPTR
-#include "slhc.h"
+#define bsd_decompress (*ppp->sc_rcomp->decompress)
+#define bsd_compress (*ppp->sc_xcomp->compress)
-#include <linux/if_arp.h>
-#ifndef ARPHRD_PPP
-#define ARPHRD_PPP 0
+#ifndef PPP_IPX
+#define PPP_IPX 0x2b /* IPX protocol over PPP */
#endif
-#define PRINTK(p) printk p ;
-#define ASSERT(p) if (!p) PRINTK ((KERN_CRIT "assertion failed: " # p))
-#define PRINTKN(n,p) {if (ppp_debug >= n) 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;}
+#ifndef PPP_LQR
+#define PPP_LQR 0xc025 /* Link Quality Reporting Protocol */
+#endif
-#define in_xmap(ppp,c) (ppp->xmit_async_map[(c) >> 5] & (1 << ((c) & 0x1f)))
-#define in_rmap(ppp,c) ((((unsigned int) (unsigned char) (c)) < 0x20) && \
- ppp->recv_async_map & (1 << (c)))
+STATIC int ppp_register_compressor (struct compressor *cp);
+STATIC void ppp_unregister_compressor (struct compressor *cp);
-#define bset(p,b) ((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
+/*
+ * Local functions
+ */
-int ppp_debug = 2;
-int ppp_debug_netpackets = 0;
+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 *, 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 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_lqr (struct ppp *, u_short, u_char *, int);
+static void ppp_doframe_lower (struct ppp *, u_char *, int);
+static int ppp_doframe (struct ppp *);
+
+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))
+
+#ifndef OPTIMIZE_FLAG_TIME
+#define OPTIMIZE_FLAG_TIME 0
+#endif
-/* Define this string only once for all macro invocations */
-static char ppp_warning[] = KERN_WARNING "PPP: ALERT! not INUSE! %d\n";
+#ifndef PPP_MAX_DEV
+#define PPP_MAX_DEV 256
+#endif
+
+/*
+ * Parameters which may be changed via insmod.
+ */
-int ppp_init(struct device *);
-static void ppp_init_ctrl_blk(struct ppp *);
-static int ppp_dev_open(struct device *);
-static int ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
-static int ppp_dev_close(struct device *);
-static void ppp_kick_tty(struct ppp *);
+STATIC int flag_time = OPTIMIZE_FLAG_TIME;
+STATIC int max_dev = PPP_MAX_DEV;
-#ifdef NEW_TTY_DRIVERS
-#define ppp_find(tty) ((struct ppp *) tty->disc_data)
-#else
-static void ppp_output_done(void *);
-static void ppp_unesc(struct ppp *ppp, unsigned char *c, int n);
-static struct ppp *ppp_find(struct tty_struct *);
-#endif
+/*
+ * The "main" procedure to the ppp device
+ */
-static void ppp_doframe(struct ppp *);
-static int ppp_do_ip(struct ppp *, unsigned short, unsigned char *, int);
-static int ppp_us_queue(struct ppp *, unsigned short, unsigned char *, int);
-static int ppp_xmit(struct sk_buff *, struct device *);
-
-#ifdef NET02D
-static int ppp_header(unsigned char *buff, struct device *dev,
- unsigned short type, unsigned long daddr,
- unsigned long saddr, unsigned len);
-static int ppp_rebuild_header(void *buff, struct device *dev);
-static void ppp_add_arp(unsigned long addr, struct sk_buff *skb,
- struct device *dev);
-#else
-static int ppp_header(struct sk_buff *, struct device *, unsigned short,
- void *, void *, unsigned);
-static int ppp_rebuild_header(void *, struct device *, unsigned long,
- struct sk_buff *);
+int ppp_init (struct device *);
+
+/*
+ * Network device driver callback routines
+ */
+
+static int ppp_dev_open (struct device *);
+static int ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd);
+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(((long *) 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),((long *) (addr)))
+
+static int ppp_dev_header (sk_buff *, struct device *, unsigned short,
+ void *, void *, unsigned);
#endif
-static struct enet_statistics *ppp_get_stats (struct device *);
-static struct ppp *ppp_alloc(void);
-static int ppp_lock(struct ppp *);
-static void ppp_unlock(struct ppp *);
-static void ppp_add_fcs(struct ppp *);
-static int ppp_check_fcs(struct ppp *);
-static void ppp_print_buffer(const char *,const char *,int,int);
-
-static int ppp_read(struct tty_struct *, struct file *, unsigned char *,
- unsigned int);
-static int ppp_write(struct tty_struct *, struct file *, const unsigned char *,
- unsigned int);
-static int ppp_ioctl(struct tty_struct *, struct file *, unsigned int,
- unsigned long);
-static int ppp_select(struct tty_struct *tty, struct inode * inode,
- struct file * filp, int sel_type, select_table * wait);
-static int ppp_open(struct tty_struct *);
-static void ppp_close(struct tty_struct *);
-
-#ifdef NEW_TTY_DRIVERS
-static int ppp_receive_room(struct tty_struct *tty);
-static void ppp_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count);
-static void ppp_write_wakeup(struct tty_struct *tty);
+#ifdef NEW_SKBUFF
+static int ppp_dev_input (struct protocol *self, struct protocol *lower,
+ sk_buff *skb, void *saddr, void *daddr);
+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 void ppp_tty_input_ready(struct tty_struct *);
+static int ppp_dev_rebuild (void *, struct device *, unsigned long,
+ sk_buff *);
#endif
-/* FCS table from RFC1331 */
-
-static unsigned short fcstab[256] = {
- 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
- 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
- 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
- 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
- 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
- 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
- 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
- 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
- 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
- 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
- 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
- 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
- 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
- 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
- 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
- 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
- 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
- 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
- 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
- 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
- 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
- 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
- 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
- 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
- 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
- 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
- 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
- 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
- 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
- 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
- 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
- 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
- };
-
-struct tty_ldisc ppp_ldisc;
-
-static struct ppp ppp_ctrl[PPP_NRUNIT];
+/*
+ * TTY callbacks
+ */
-/*************************************************************
- * INITIALIZATION
- *************************************************************/
+static int ppp_tty_read (struct tty_struct *, struct file *, u_char *,
+ unsigned int);
+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);
+static int ppp_tty_select (struct tty_struct *tty, struct inode *inode,
+ struct file *filp, int sel_type, select_table * wait);
+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, const u_char * cp,
+ char *fp, int count);
+static void ppp_tty_wakeup (struct tty_struct *tty);
+
+#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;}
-static int first_time = 1;
+#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) && \
+ ppp->recv_async_map & (1 << (c)))
-/* called at boot time for each ppp device */
+#define bset(p,b) ((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
-int
-ppp_init(struct device *dev)
-{
- struct ppp *ppp;
- int i;
+#define tty2ppp(tty) ((struct ppp *) (tty->disc_data))
+#define dev2ppp(dev) ((struct ppp *) (dev->priv))
+#define ppp2tty(ppp) ((struct tty_struct *) ppp->tty)
+#define ppp2dev(ppp) ((struct device *) ppp->dev)
- ppp = &ppp_ctrl[dev->base_addr];
+struct ppp_hdr {
+ unsigned char address;
+ unsigned char control;
+ unsigned char protocol[2];
+};
- if (first_time) {
- first_time = 0;
+#define PPP_HARD_HDR_LEN (sizeof (struct ppp_hdr))
- printk (KERN_INFO "PPP: version %s (%d channels)"
-#ifdef NET02D
- " NET02D"
-#endif
-#ifdef NEW_TTY_DRIVERS
- " NEW_TTY_DRIVERS"
-#endif
-#ifdef OPTIMIZE_FLAG_TIME
- " OPTIMIZE_FLAGS"
-#endif
- "\n", PPP_VERSION, PPP_NRUNIT);
-
- printk (KERN_INFO
- "TCP compression code copyright 1989 Regents of the "
- "University of California\n");
-
- (void) memset(&ppp_ldisc, 0, sizeof(ppp_ldisc));
- ppp_ldisc.open = ppp_open;
- ppp_ldisc.close = ppp_close;
- ppp_ldisc.read = ppp_read;
- ppp_ldisc.write = ppp_write;
- ppp_ldisc.ioctl = ppp_ioctl;
- ppp_ldisc.select = ppp_select;
-
-#ifdef NEW_TTY_DRIVERS
- ppp_ldisc.magic = TTY_LDISC_MAGIC;
- ppp_ldisc.receive_room = ppp_receive_room;
- ppp_ldisc.receive_buf = ppp_receive_buf;
- ppp_ldisc.write_wakeup = ppp_write_wakeup;
-#else
- ppp_ldisc.handler = ppp_tty_input_ready;
-#endif
+typedef struct ppp_ctrl {
+ struct ppp_ctrl *next; /* Next structure in the list */
+ char name [8]; /* Name of the device */
+ struct ppp ppp; /* PPP control table */
+ struct device dev; /* Device information table */
+} ppp_ctrl_t;
- if ((i = tty_register_ldisc(N_PPP, &ppp_ldisc)) == 0)
- printk(KERN_INFO "PPP line discipline registered.\n");
- else
- printk(KERN_ERR "error registering line discipline: %d\n", i);
- }
-
- /* initialize PPP control block */
- ppp_init_ctrl_blk (ppp);
- ppp->inuse = 0;
- ppp->line = dev->base_addr;
- ppp->tty = NULL;
- ppp->dev = dev;
-
- /* clear statistics */
- memset (&ppp->stats, '\0', sizeof (struct ppp_stats));
-
- /* device INFO */
- dev->mtu = PPP_MTU;
- dev->hard_start_xmit = ppp_xmit;
- dev->open = ppp_dev_open;
- dev->stop = ppp_dev_close;
- dev->get_stats = ppp_get_stats;
- dev->hard_header = ppp_header;
- dev->rebuild_header = ppp_rebuild_header;
- dev->hard_header_len = 0;
- dev->addr_len = 0;
- dev->type = ARPHRD_PPP;
-
-#ifdef NET02D
- dev->add_arp = ppp_add_arp;
- dev->queue_xmit = dev_queue_xmit;
-#else
- dev->do_ioctl = ppp_dev_ioctl;
-#endif
+static ppp_ctrl_t *ppp_list = NULL;
- for (i = 0; i < DEV_NUMBUFFS; i++)
- skb_queue_head_init(&dev->buffs[i]); /* = NULL if NET02D */
+#define ctl2ppp(ctl) (struct ppp *) &ctl->ppp
+#define ctl2dev(ctl) (struct device *) &ctl->dev
+#undef PPP_NRUNIT
- /* New-style flags */
- dev->flags = IFF_POINTOPOINT;
- dev->family = AF_INET;
- dev->pa_addr = 0;
- dev->pa_brdaddr = 0;
- dev->pa_mask = 0;
- dev->pa_alen = 4;
+/* Buffer types */
+#define BUFFER_TYPE_DEV_RD 0 /* ppp read buffer */
+#define BUFFER_TYPE_TTY_WR 1 /* tty write buffer */
+#define BUFFER_TYPE_DEV_WR 2 /* ppp write buffer */
+#define BUFFER_TYPE_TTY_RD 3 /* tty read buffer */
+#define BUFFER_TYPE_VJ 4 /* vj compression buffer */
- return 0;
-}
+/* Define this string only once for all macro envocations */
+static char ppp_warning[] = KERN_WARNING "PPP: ALERT! not INUSE! %d\n";
-static void
-ppp_init_ctrl_blk(struct ppp *ppp)
-{
- ppp->magic = PPP_MAGIC;
- ppp->sending = 0;
- ppp->toss = 0xFE;
- ppp->escape = 0;
-
- ppp->flags = 0;
- ppp->mtu = PPP_MTU;
- ppp->mru = PPP_MRU;
- ppp->fcs = 0;
-
- memset (ppp->xmit_async_map, 0, sizeof (ppp->xmit_async_map));
- ppp->xmit_async_map[0] = 0xffffffff;
- ppp->xmit_async_map[3] = 0x60000000;
- ppp->recv_async_map = 0x00000000;
-
- ppp->slcomp = NULL;
- ppp->rbuff = NULL;
- ppp->xbuff = NULL;
- ppp->cbuff = NULL;
-
- ppp->rhead = NULL;
- ppp->rend = NULL;
- ppp->rcount = 0;
- ppp->xhead = NULL;
- ppp->xtail = NULL;
-
- ppp->us_rbuff = NULL;
- ppp->us_rbuff_end = NULL;
- ppp->us_rbuff_head = NULL;
- ppp->us_rbuff_tail = NULL;
- ppp->read_wait = NULL;
- ppp->write_wait = NULL;
- ppp->us_rbuff_lock = 0;
- ppp->inp_sig = 0;
- ppp->inp_sig_pid = 0;
-
-#ifdef OPTIMIZE_FLAG_TIME /* ensure flag will always be sent first time */
- ppp->last_xmit = jiffies - OPTIMIZE_FLAG_TIME;
-#else
- ppp->last_xmit = 0;
+static char szVersion[] = PPP_VERSION;
+
+#ifdef NEW_SKBUFF
+static struct protocol proto_ppp;
#endif
- /* clear statistics */
- memset (&ppp->stats, '\0', sizeof (struct ppp_stats));
-
- /* Reset the demand dial information */
- ppp->ddinfo.ip_sjiffies =
- ppp->ddinfo.ip_rjiffies =
- ppp->ddinfo.nip_sjiffies =
- ppp->ddinfo.nip_rjiffies = jiffies;
-}
-
-/*
- * MTU has been changed by the IP layer. Unfortunately we are not told
- * about this, but we spot it ourselves and fix things up. We could be
- * in an upcall from the tty driver, or in an ip packet queue.
- */
-
-static void
-ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru)
-{
- struct device *dev;
- unsigned char *new_rbuff, *new_xbuff, *new_cbuff;
- unsigned char *old_rbuff, *old_xbuff, *old_cbuff;
- int mtu, mru;
/*
- * Allocate the buffer from the kernel for the data
+ * Information for the protocol decoder
*/
- dev = ppp->dev;
- mru = new_mru;
- mtu = new_mtu;
- /* RFC 1331, section 7.2 says the minimum value is 1500 bytes */
- if (mru < PPP_MRU)
- mru = PPP_MRU;
-
- mtu = (mtu * 2) + 20;
- mru = (mru * 2) + 20;
+typedef int (*pfn_proto) (struct ppp *, u_short, u_char *, int);
+
+typedef struct ppp_proto_struct {
+ int proto;
+ 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 },
+ { PPP_CCP, rcv_proto_ccp },
+ { 0, rcv_proto_unknown } /* !!! MUST BE LAST !!! */
+};
- PRINTKN (2,(KERN_INFO "ppp: channel %s mtu = %d, mru = %d\n",
- dev->name, new_mtu, new_mru));
-
- new_xbuff = (unsigned char *) kmalloc(mtu + 4, GFP_ATOMIC);
- new_rbuff = (unsigned char *) kmalloc(mru + 4, GFP_ATOMIC);
- new_cbuff = (unsigned char *) kmalloc(mru + 4, GFP_ATOMIC);
-/*
- * If the buffers failed to allocate then complain.
- */
- if (new_xbuff == NULL || new_rbuff == NULL || new_cbuff == NULL)
- {
- PRINTKN (2,(KERN_ERR "ppp: failed to allocate new buffers\n"));
/*
- * Release new buffer pointers if the updates were not performed
+ * Values for FCS calculations.
*/
- if (new_rbuff != NULL)
- kfree (new_rbuff);
- if (new_xbuff != NULL)
- kfree (new_xbuff);
+#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])
- if (new_cbuff != NULL)
- kfree (new_cbuff);
- }
-/*
- * Update the pointers to the new buffer structures.
- */
- else
- {
- cli();
- old_xbuff = ppp->xbuff;
- old_rbuff = ppp->rbuff;
- old_cbuff = ppp->cbuff;
+unsigned short ppp_crc16_table[256] =
+{
+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
- ppp->xbuff = new_xbuff;
- ppp->rbuff = new_rbuff;
- ppp->cbuff = new_cbuff;
+#ifdef CHECK_CHARACTERS
+static unsigned paritytab[8] =
+{
+ 0x96696996, 0x69969669, 0x69969669, 0x96696996,
+ 0x69969669, 0x96696996, 0x96696996, 0x69969669
+};
+#endif
- dev->mem_start = (unsigned long) new_xbuff;
- dev->mem_end = (unsigned long) (dev->mem_start + mtu);
+/* local function to store a value into the LQR frame */
+extern inline u_char * store_long (register u_char *p, register int value) {
+ *p++ = (u_char) (value >> 24);
+ *p++ = (u_char) (value >> 16);
+ *p++ = (u_char) (value >> 8);
+ *p++ = (u_char) value;
+ return p;
+}
- dev->rmem_start = (unsigned long) new_rbuff;
- ppp->rend = (unsigned char *)
- dev->rmem_end = (unsigned long) (dev->rmem_start + mru);
+/*************************************************************
+ * INITIALIZATION
+ *************************************************************/
- ppp->rhead = new_rbuff;
-/*
- * Update the parameters for the new buffer sizes
+/* This procedure is called once and once only to define who we are to
+ * the operating system and the various procedures that it may use in
+ * accessing the ppp protocol.
*/
- ppp->toss = 0xFE;
- ppp->escape = 0;
- ppp->sending = 0;
- ppp->rcount = 0;
- ppp->mru = new_mru;
+static int
+ppp_first_time (void)
+{
+ static struct tty_ldisc ppp_ldisc;
+ int status;
- ppp->mtu =
- dev->mtu = new_mtu;
+ printk (KERN_INFO
+ "PPP: version %s (dynamic channel allocation)"
+#ifdef NEW_SKBUFF
+ " NEW_SKBUFF"
+#endif
+ "\n", szVersion);
- sti();
+#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
+
+ printk (KERN_INFO
+ "PPP Dynamic channel allocation code copyright 1995 "
+ "Caldera, Inc.\n");
/*
- * Release old buffer pointers
+ * Register the protocol for the device
*/
- if (old_rbuff != NULL)
- kfree (old_rbuff);
- if (old_xbuff != NULL)
- kfree (old_xbuff);
+#ifdef NEW_SKBUFF
+ memset (&proto_ppp, 0, sizeof (proto_ppp));
- if (old_cbuff != NULL)
- kfree (old_cbuff);
- }
-}
-
-/* called when we abandon the PPP line discipline */
+ proto_ppp.name = "PPP";
+ proto_ppp.output = ppp_dev_output;
+ proto_ppp.input = ppp_dev_input;
+ 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; */
-static void
-ppp_release(struct ppp *ppp)
-{
-#ifdef NEW_TTY_DRIVERS
- if (ppp->tty != NULL && ppp->tty->disc_data == ppp)
- ppp->tty->disc_data = NULL; /* Break the tty->ppp link */
+ protocol_register(&proto_ppp);
#endif
- if (ppp->dev) {
- dev_close (ppp->dev);
- ppp->dev->flags = 0;
- }
-
- kfree (ppp->xbuff);
- kfree (ppp->cbuff);
- kfree (ppp->rbuff);
- kfree (ppp->us_rbuff);
-
- ppp->xbuff =
- ppp->cbuff =
- ppp->rbuff =
- ppp->us_rbuff = NULL;
-
- if (ppp->slcomp) {
- slhc_free(ppp->slcomp);
- ppp->slcomp = NULL;
- }
-
- ppp->inuse = 0;
- ppp->tty = NULL;
+/*
+ * Register the tty dicipline
+ */
+ (void) memset (&ppp_ldisc, 0, sizeof (ppp_ldisc));
+ ppp_ldisc.magic = TTY_LDISC_MAGIC;
+ ppp_ldisc.open = ppp_tty_open;
+ ppp_ldisc.close = ppp_tty_close;
+ ppp_ldisc.read = ppp_tty_read;
+ ppp_ldisc.write = ppp_tty_write;
+ ppp_ldisc.ioctl = ppp_tty_ioctl;
+ ppp_ldisc.select = ppp_tty_select;
+ ppp_ldisc.receive_room = ppp_tty_room;
+ ppp_ldisc.receive_buf = ppp_tty_receive;
+ ppp_ldisc.write_wakeup = ppp_tty_wakeup;
+
+ status = tty_register_ldisc (N_PPP, &ppp_ldisc);
+ if (status == 0)
+ printk (KERN_INFO "PPP line discipline registered.\n");
+ else
+ printk (KERN_ERR "error registering line discipline: %d\n",
+ status);
+ return status;
}
-static void
-ppp_close(struct tty_struct *tty)
-{
- struct ppp *ppp = ppp_find(tty);
-
- if (ppp == NULL || ppp->magic != PPP_MAGIC) {
- PRINTKN (1,(KERN_WARNING "ppp: trying to close unopened tty!\n"));
- } else {
- CHECK_PPP_VOID();
- ppp_release (ppp);
+/*************************************************************
+ * INITIALIZATION
+ *************************************************************/
- PRINTKN (2,(KERN_INFO "ppp: channel %s closing.\n", ppp->dev->name));
-#ifdef MODULE
- MOD_DEC_USE_COUNT;
-#endif
- }
-}
+/* called when the device is actually created */
-/* called when PPP line discipline is selected on a tty */
static int
-ppp_open(struct tty_struct *tty)
+ppp_init_dev (struct device *dev)
{
- struct ppp *ppp = ppp_find(tty);
+ int indx;
+#ifdef NEW_SKBUFF
+ 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; */
+#endif
- if (ppp) {
- PRINTKN (1,(KERN_ERR "ppp_open: gack! tty already associated to %s!\n",
- ppp->magic == PPP_MAGIC ? ppp->dev->name : "unknown"));
- return -EEXIST;
- }
+ /* device INFO */
+ dev->mtu = PPP_MTU;
+ dev->hard_start_xmit = ppp_dev_xmit;
+ dev->open = ppp_dev_open;
+ dev->stop = ppp_dev_close;
+ dev->get_stats = ppp_dev_stats;
+ dev->do_ioctl = ppp_dev_ioctl;
+ dev->addr_len = 0;
+ dev->type = ARPHRD_PPP;
+
+ for (indx = 0; indx < DEV_NUMBUFFS; indx++)
+ skb_queue_head_init (&dev->buffs[indx]);
+
+ /* New-style flags */
+ dev->flags = IFF_POINTOPOINT;
+ dev->family = AF_INET;
+ dev->pa_addr = 0;
+ dev->pa_brdaddr = 0;
+ dev->pa_mask = 0;
+ dev->pa_alen = 4; /* sizeof (unsigned long) */
- ppp = ppp_alloc();
- if (ppp == NULL) {
- PRINTKN (1,(KERN_ERR "ppp_open: couldn't allocate ppp channel\n"));
- return -ENFILE;
- }
+ return 0;
+}
- /* make sure the channel is actually open */
- ppp_init_ctrl_blk (ppp);
+/*
+ * Local procedure to initialize the ppp structure
+ */
- ppp->tty = tty;
+static void
+ppp_init_ctrl_blk (register struct ppp *ppp)
+{
+ ppp->magic = PPP_MAGIC;
+ ppp->toss = 0xE0;
+ ppp->escape = 0;
-#ifdef NEW_TTY_DRIVERS
- tty->disc_data = ppp;
- if (tty->driver.flush_buffer)
- tty->driver.flush_buffer(tty);
- if (tty->ldisc.flush_buffer)
- tty->ldisc.flush_buffer(tty);
-#else
- tty_read_flush (tty);
- tty_write_flush (tty);
-#endif
+ ppp->flags = 0;
+ ppp->mtu = PPP_MTU;
+ ppp->mru = PPP_MRU;
+
+ memset (ppp->xmit_async_map, 0, sizeof (ppp->xmit_async_map));
+ ppp->xmit_async_map[0] = 0xffffffff;
+ ppp->xmit_async_map[3] = 0x60000000;
+ ppp->recv_async_map = 0x00000000;
+
+ ppp->rbuf = NULL;
+ ppp->wbuf = NULL;
+ ppp->ubuf = NULL;
+ ppp->cbuf = NULL;
+ ppp->slcomp = NULL;
+ ppp->read_wait = NULL;
+ ppp->write_wait = NULL;
+ ppp->last_xmit = jiffies - flag_time;
+
+ /* clear statistics */
+ memset (&ppp->stats, '\0', sizeof (struct pppstat));
+
+ /* Reset the demand dial information */
+ ppp->ddinfo.xmit_idle= /* time since last NP packet sent */
+ ppp->ddinfo.recv_idle=jiffies; /* time since last NP packet received */
+
+ /* PPP compression data */
+ ppp->sc_xc_state =
+ ppp->sc_rc_state = NULL;
+}
- if ((ppp->slcomp = slhc_init(16, 16)) == NULL) {
- PRINTKN (1,(KERN_ERR "ppp: no space for compression buffers!\n"));
- ppp_release (ppp);
- return -ENOMEM;
- }
-
- /* Define the buffers for operation */
- ppp_changedmtu (ppp, ppp->dev->mtu, ppp->mru);
- if (ppp->rbuff == NULL) {
- ppp_release (ppp);
- return -ENOMEM;
- }
-
- /* Allocate a user-level receive buffer */
- ppp->us_rbuff = (unsigned char *) kmalloc (RBUFSIZE, GFP_KERNEL);
- if (ppp->us_rbuff == NULL) {
- PRINTKN (1,(KERN_ERR "ppp: no space for user receive buffer\n"));
- ppp_release (ppp);
- return -ENOMEM;
- }
-
- ppp->us_rbuff_head =
- ppp->us_rbuff_tail = ppp->us_rbuff;
- ppp->us_rbuff_end = ppp->us_rbuff + RBUFSIZE;
-
- PRINTKN (2,(KERN_INFO "ppp: channel %s open\n", ppp->dev->name));
+/* called at boot/load time for each ppp device defined in the kernel */
-#ifdef MODULE
- MOD_INC_USE_COUNT;
+#ifndef MODULE
+int
+ppp_init (struct device *dev)
+{
+ static int first_time = 1;
+ int answer = 0;
+
+ if (first_time) {
+ static struct symbol_table ppp_syms = {
+#include <linux/symtab_begin.h>
+ X(ppp_register_compressor),
+ X(ppp_unregister_compressor),
+ X(ppp_crc16_table),
+#include <linux/symtab_end.h>
+ };
+
+ 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.
+ */
+ unregister_netdev (dev);
+ return answer;
+}
#endif
- return (ppp->line);
-}
+/*
+ * Routine to allocate a buffer for later use by the driver.
+ */
-/* called when ppp interface goes "up". here this just means we start
- passing IP packets */
-static int
-ppp_dev_open(struct device *dev)
+static struct ppp_buffer *
+ppp_alloc_buf (int size, int type)
{
- struct ppp *ppp = &ppp_ctrl[dev->base_addr];
+ struct ppp_buffer *buf;
+
+ buf = (struct ppp_buffer *) kmalloc (size + sizeof (struct ppp_buffer),
+ GFP_ATOMIC);
+
+ if (buf != NULL) {
+ buf->size = size - 1; /* Mask for the buffer size */
+ buf->type = type;
+ buf->locked = 0;
+ buf->count = 0;
+ buf->head = 0;
+ buf->tail = 0;
+ buf->fcs = PPP_INITFCS;
+ }
+ return (buf);
+}
- /* reset POINTOPOINT every time, since dev_close zaps it! */
- dev->flags |= IFF_POINTOPOINT;
+/*
+ * Routine to release the allocated buffer.
+ */
- if (ppp->tty == NULL) {
- PRINTKN (1,(KERN_ERR "ppp: %s not connected to a TTY! can't go open!\n",
- dev->name));
- return -ENXIO;
- }
+static void
+ppp_free_buf (struct ppp_buffer *ptr)
+{
+ if (ptr != NULL)
+ kfree (ptr);
+}
- PRINTKN (2,(KERN_INFO "ppp: channel %s going up for IP packets!\n",
- dev->name));
+/*
+ * Lock the indicated transmit buffer
+ */
- CHECK_PPP(-ENXIO);
- return 0;
+extern inline int
+lock_buffer (register struct ppp_buffer *buf)
+{
+ register int state;
+ int flags;
+/*
+ * Save the current state and if free then set it to the "busy" state
+ */
+ save_flags (flags);
+ cli ();
+ state = buf->locked;
+ if (state == 0)
+ buf->locked = 2;
+/*
+ * Restore the flags and return the previous state. 0 implies success.
+ */
+ restore_flags (flags);
+ return (state);
}
+/*
+ * MTU has been changed by the IP layer. Unfortunately we are not told
+ * about this, but we spot it ourselves and fix things up. We could be
+ * in an upcall from the tty driver, or in an ip packet queue.
+ */
+
static int
-ppp_dev_close(struct device *dev)
+ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru)
{
- struct ppp *ppp = &ppp_ctrl[dev->base_addr];
+ struct device *dev;
- if (ppp->tty == NULL) {
- PRINTKN (1,(KERN_ERR "ppp: %s not connected to a TTY! can't go down!\n",
- dev->name));
- return -ENXIO;
- }
+ struct ppp_buffer *new_rbuf;
+ struct ppp_buffer *new_wbuf;
+ struct ppp_buffer *new_cbuf;
+ struct ppp_buffer *new_tbuf;
- PRINTKN (2,(KERN_INFO "ppp: channel %s going down for IP packets!\n",
- dev->name));
- CHECK_PPP(-ENXIO);
- return 0;
-}
+ struct ppp_buffer *old_rbuf;
+ struct ppp_buffer *old_wbuf;
+ struct ppp_buffer *old_cbuf;
+ struct ppp_buffer *old_tbuf;
-#ifndef NET02D
-static int ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
-{
- struct ppp *ppp = &ppp_ctrl[dev->base_addr];
- int error;
+ int mtu, mru;
+/*
+ * Allocate the buffer from the kernel for the data
+ */
+ dev = ppp2dev (ppp);
+ mru = new_mru;
+ /* allow for possible escapement of every character */
+ mtu = (new_mtu * 2) + 20;
+
+ /* RFC 1331, section 7.2 says the minimum value is 1500 bytes */
+ if (mru < PPP_MRU)
+ mru = PPP_MRU;
- struct stats
- {
- struct ppp_stats ppp_stats;
- struct slcompress slhc;
- } *result;
+ mru += 10;
+
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO "ppp: channel %s mtu = %d, mru = %d\n",
+ dev->name, new_mtu, new_mru);
+
+ new_wbuf = ppp_alloc_buf (mtu+PPP_HARD_HDR_LEN, BUFFER_TYPE_DEV_WR);
+ new_tbuf = ppp_alloc_buf ((PPP_MTU * 2) + 24, BUFFER_TYPE_TTY_WR);
+ new_rbuf = ppp_alloc_buf (mru + 84, BUFFER_TYPE_DEV_RD);
+ new_cbuf = ppp_alloc_buf (mru+PPP_HARD_HDR_LEN, BUFFER_TYPE_VJ);
+/*
+ * If the buffers failed to allocate then complain and release the partial
+ * allocations.
+ */
+ if (new_wbuf == NULL || new_tbuf == NULL ||
+ new_rbuf == NULL || new_cbuf == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp: failed to allocate new buffers\n");
+
+ ppp_free_buf (new_wbuf);
+ ppp_free_buf (new_tbuf);
+ ppp_free_buf (new_rbuf);
+ ppp_free_buf (new_cbuf);
+ return 0;
+ }
+/*
+ * Update the pointers to the new buffer structures.
+ */
+ cli ();
+ old_wbuf = ppp->wbuf;
+ old_rbuf = ppp->rbuf;
+ old_cbuf = ppp->cbuf;
+ old_tbuf = ppp->tbuf;
+
+ ppp->wbuf = new_wbuf;
+ ppp->rbuf = new_rbuf;
+ ppp->cbuf = new_cbuf;
+ ppp->tbuf = new_tbuf;
+
+ ppp->rbuf->size -= 80; /* reserve space for vj header expansion */
+
+ dev->mem_start = (unsigned long) buf_base (new_wbuf);
+ dev->mem_end = (unsigned long) (dev->mem_start + mtu);
+ dev->rmem_start = (unsigned long) buf_base (new_rbuf);
+ dev->rmem_end = (unsigned long) (dev->rmem_start + mru);
+/*
+ * Update the parameters for the new buffer sizes
+ */
+ ppp->toss = 0xE0; /* To ignore characters until new FLAG */
+ ppp->escape = 0; /* No pending escape character */
- error = verify_area (VERIFY_WRITE,
- ifr->ifr_ifru.ifru_data,
- sizeof (struct stats));
+ dev->mtu =
+ ppp->mtu = new_mtu;
+ ppp->mru = new_mru;
- if (error == 0) {
- result = (struct stats *) ifr->ifr_ifru.ifru_data;
+ ppp->s1buf = NULL;
+ ppp->s2buf = NULL;
+ ppp->xbuf = NULL;
- memcpy_tofs (&result->ppp_stats, &ppp->stats, sizeof (struct ppp_stats));
- if (ppp->slcomp)
- memcpy_tofs (&result->slhc, ppp->slcomp, sizeof (struct slcompress));
- }
+ ppp->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+ ppp->flags &= ~SC_XMIT_BUSY;
- return error;
+ sti ();
+/*
+ * Release old buffer pointers
+ */
+ ppp_free_buf (old_rbuf);
+ ppp_free_buf (old_wbuf);
+ ppp_free_buf (old_cbuf);
+ ppp_free_buf (old_tbuf);
+ return 1;
}
-#endif
-/*************************************************************
- * TTY OUTPUT
- * The following function delivers a fully-formed PPP
- * frame in ppp->xbuff to the TTY for output.
- *************************************************************/
+/*
+ * CCP is down; free (de)compressor state if necessary.
+ */
-#ifdef NEW_TTY_DRIVERS
-static inline void
-#else
static void
-#endif
-ppp_output_done (void *ppp)
+ppp_ccp_closed (struct ppp *ppp)
{
- /* unlock the transmitter queue */
- ppp_unlock ((struct ppp *) ppp);
-
- /* If the device is still up then enable the transmitter of the
- next frame. */
- if (((struct ppp *) ppp)->dev->flags & IFF_UP)
-#ifndef NET02D
- mark_bh (NET_BH);
-#else
- dev_tint (((struct ppp *) ppp)->dev);
-#endif
+ if (ppp->sc_xc_state) {
+ (*ppp->sc_xcomp->comp_free) (ppp->sc_xc_state);
+ ppp->sc_xc_state = NULL;
+ }
- /* enable any blocked process pending transmission */
- wake_up_interruptible (&((struct ppp *) ppp)->write_wait);
+ if (ppp->sc_rc_state) {
+ (*ppp->sc_rcomp->decomp_free) (ppp->sc_rc_state);
+ ppp->sc_rc_state = NULL;
+ }
}
-#ifndef NEW_TTY_DRIVERS
+/*
+ * Called to release all of the information in the current PPP structure.
+ *
+ * It is called when the ppp device goes down or if it is unable to go
+ * up.
+ */
+
static void
-ppp_kick_tty (struct ppp *ppp)
+ppp_release (struct ppp *ppp)
{
- register int count = ppp->xhead - ppp->xbuff;
- register int answer;
+ struct tty_struct *tty;
+ struct device *dev;
+
+ tty = ppp2tty (ppp);
+ dev = ppp2dev (ppp);
- ppp->stats.sbytes += count;
+ ppp_ccp_closed (ppp);
- answer = tty_write_data (ppp->tty,
- ppp->xbuff,
- count,
- ppp_output_done,
- (void *) ppp);
+ if (tty != NULL && tty->disc_data == ppp)
+ tty->disc_data = NULL; /* Break the tty->ppp link */
+
+ if (dev && dev->flags & IFF_UP) {
+ dev_close (dev); /* close the device properly */
+ dev->flags = 0; /* prevent recursion */
+ }
+
+ ppp_free_buf (ppp->rbuf);
+ ppp_free_buf (ppp->wbuf);
+ ppp_free_buf (ppp->cbuf);
+ ppp_free_buf (ppp->ubuf);
+ ppp_free_buf (ppp->tbuf);
+
+ ppp->rbuf =
+ ppp->wbuf =
+ ppp->cbuf =
+ ppp->tbuf =
+ ppp->xbuf =
+ ppp->s1buf =
+ ppp->s2buf =
+ ppp->ubuf = NULL;
+
+ if (ppp->slcomp) {
+ slhc_free (ppp->slcomp);
+ ppp->slcomp = NULL;
+ }
- if (answer == 0)
- ppp_output_done (ppp); /* Should not happen */
- else
- if (answer < 0) {
- ppp->stats.serrors++;
- ppp_output_done (ppp); /* unlock the transmitter */
- }
+ ppp->inuse = 0;
+ ppp->tty = NULL;
}
-#else
+/*
+ * Device callback.
+ *
+ * Called when the PPP device goes down in response to an ifconfig request.
+ */
static void
-ppp_kick_tty (struct ppp *ppp)
+ppp_tty_close (struct tty_struct *tty)
{
- register int count, actual;
-
- count = ppp->xhead - ppp->xbuff;
-
- actual = ppp->tty->driver.write(ppp->tty, 0, ppp->xbuff, count);
- ppp->stats.sbytes += actual;
- if (actual == count) {
- ppp_output_done(ppp);
- } else {
- ppp->xtail = ppp->xbuff + actual;
- ppp->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+ struct ppp *ppp = tty2ppp (tty);
+
+ 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;
+ }
}
}
-static void ppp_write_wakeup(struct tty_struct *tty)
+/*
+ * TTY callback.
+ *
+ * Called when the tty discipline is switched to PPP.
+ */
+
+static int
+ppp_tty_open (struct tty_struct *tty)
{
- register int count, actual;
- struct ppp *ppp = ppp_find(tty);
+ struct ppp *ppp = tty2ppp (tty);
+/*
+ * There should not be an existing table for this slot.
+ */
+ if (ppp) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp_tty_open: gack! tty already associated to %s!\n",
+ ppp->magic == PPP_MAGIC ? ppp2dev(ppp)->name
+ : "unknown");
+ return -EEXIST;
+ }
+/*
+ * Allocate the structure from the system
+ */
+ ppp = ppp_alloc();
+ if (ppp == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp_tty_open: couldn't allocate ppp channel\n");
+ return -ENFILE;
+ }
+/*
+ * Initialize the control block
+ */
+ ppp_init_ctrl_blk (ppp);
+ ppp->tty = tty;
+ tty->disc_data = ppp;
+/*
+ * Flush any pending characters in the driver and discipline.
+ */
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer (tty);
- if (!ppp || ppp->magic != PPP_MAGIC) {
- PRINTKN (1,
- (KERN_ERR "PPP: write_wakeup called but couldn't "
- "find PPP struct.\n"));
- return;
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer (tty);
+/*
+ * Allocate space for the default VJ header compression slots
+ */
+ ppp->slcomp = slhc_init (16, 16);
+ if (ppp->slcomp == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp_tty_open: no space for compression buffers!\n");
+ ppp_release (ppp);
+ return -ENOMEM;
+ }
+/*
+ * Allocate space for the MTU and MRU buffers
+ */
+ if (ppp_changedmtu (ppp, ppp2dev(ppp)->mtu, ppp->mru) == 0) {
+ ppp_release (ppp);
+ return -ENOMEM;
+ }
+/*
+ * Allocate space for a user level buffer
+ */
+ ppp->ubuf = ppp_alloc_buf (RBUFSIZE, BUFFER_TYPE_TTY_RD);
+ if (ppp->ubuf == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp_tty_open: no space for user receive buffer\n");
+ ppp_release (ppp);
+ return -ENOMEM;
}
- if (!ppp->xtail)
- return;
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO "ppp: channel %s open\n",
+ ppp2dev(ppp)->name);
- cli();
+ MOD_INC_USE_COUNT;
+ return (ppp->line);
+}
+
+/*
+ * Local function to send the next portion of the buffer.
+ *
+ * Called by the tty driver's tty_wakeup function should it be entered
+ * because the partial buffer was transmitted.
+ *
+ * Called by kick_tty to send the initial portion of the buffer.
+ *
+ * Completion processing of the buffer transmission is handled here.
+ */
+
+static void
+ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty,
+ struct ppp_buffer *xbuf)
+{
+ register int count, actual;
+/*
+ * Prevent re-entrancy by ensuring that this routine is called only once.
+ */
+ cli ();
if (ppp->flags & SC_XMIT_BUSY) {
- sti();
+ sti ();
return;
}
ppp->flags |= SC_XMIT_BUSY;
- sti();
-
- count = ppp->xhead - ppp->xtail;
-
- actual = tty->driver.write(tty, 0, ppp->xtail, count);
- ppp->stats.sbytes += actual;
- if (actual == count) {
- ppp->xtail = 0;
+ sti ();
+/*
+ * Send the next block of data to the modem
+ */
+ count = xbuf->count - xbuf->tail;
+ actual = tty->driver.write (tty, 0,
+ buf_base (xbuf) + xbuf->tail, count);
+/*
+ * Terminate transmission of any block which may have an error.
+ * This could occur should the carrier drop.
+ */
+ if (actual < 0) {
+ ppp->stats.ppp_oerrors++;
+ actual = count;
+ } else
+ ppp->bytes_sent += actual;
+/*
+ * If the buffer has been transmitted then clear the indicators.
+ */
+ xbuf->tail += actual;
+ if (actual == count) {
+ xbuf = NULL;
+ ppp->flags &= ~SC_XMIT_BUSY;
+/*
+ * Complete the transmission on the current buffer.
+ */
+ xbuf = ppp->xbuf;
+ if (xbuf != NULL) {
+ tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+ xbuf->locked = 0;
+ ppp->xbuf = NULL;
+/*
+ * If the completed buffer came from the device write, then complete the
+ * transmission block.
+ */
+ if (ppp2dev (ppp) -> flags & IFF_UP) {
+ if (xbuf->type == BUFFER_TYPE_DEV_WR)
+ ppp2dev (ppp)->tbusy = 0;
+ mark_bh (NET_BH);
+ }
+/*
+ * Wake up the transmission queue for all completion events.
+ */
+ wake_up_interruptible (&ppp->write_wait);
+/*
+ * 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;
+ }
+ }
+ }
+/*
+ * Clear the re-entry flag
+ */
+ ppp->flags &= ~SC_XMIT_BUSY;
+}
+
+/*
+ * This function is called by the tty driver when the transmit buffer has
+ * additional space. It is used by the ppp code to continue to transmit
+ * the current buffer should the buffer have been partially sent.
+ *
+ * In addition, it is used to send the first part of the buffer since the
+ * logic and the inter-locking would be identical.
+ */
+
+static void
+ppp_tty_wakeup (struct tty_struct *tty)
+{
+ struct ppp_buffer *xbuf;
+ struct ppp *ppp = tty2ppp (tty);
+
+ 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.
+ */
+ xbuf = ppp->xbuf;
+ if (xbuf == NULL)
tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+ else
+ ppp_tty_wakeup_code (ppp, tty, xbuf);
+}
- ppp_output_done(ppp);
- } else {
- ppp->xtail += actual;
+/*
+ * This function is called to transmit a buffer to the remote. The buffer
+ * is placed on the pending queue if there is presently a buffer being
+ * sent or it is transmitted with the aid of ppp_tty_wakeup.
+ */
+
+static void
+ppp_kick_tty (struct ppp *ppp, struct ppp_buffer *xbuf)
+{
+ register int flags;
+/*
+ * Hold interrupts.
+ */
+ save_flags (flags);
+ cli ();
+/*
+ * Control the flags which are best performed with the interrupts masked.
+ */
+ xbuf->locked = 1;
+ xbuf->tail = 0;
+/*
+ * If the transmitter is busy then place the buffer on the appropriate
+ * priority queue.
+ */
+ if (ppp->xbuf != NULL) {
+ if (xbuf->type == BUFFER_TYPE_TTY_WR)
+ ppp->s1buf = xbuf;
+ else
+ ppp->s2buf = xbuf;
+ restore_flags (flags);
+ return;
}
- ppp->flags &= ~SC_XMIT_BUSY;
+/*
+ * If the transmitter is not busy then this is the highest priority frame
+ */
+ ppp->flags &= ~SC_XMIT_BUSY;
+ ppp->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+ ppp->xbuf = xbuf;
+ restore_flags (flags);
+/*
+ * Do the "tty wakeup_code" to actually send this buffer.
+ */
+ ppp_tty_wakeup_code (ppp, ppp2tty (ppp), xbuf);
}
-#endif
/*************************************************************
* TTY INPUT
* The following functions handle input that arrives from
- * the TTY. It recognizes PPP frames and either hands them
+ * the TTY. It recognizes PPP frames and either hands them
* to the network layer or queues them for delivery to a
* user process reading this TTY.
*************************************************************/
-/* stuff a single character into the receive buffer */
+/*
+ * Callback function from tty driver. Return the amount of space left
+ * in the receiver's buffer to decide if remote transmitter is to be
+ * throttled.
+ */
-static inline void
-ppp_enqueue(struct ppp *ppp, unsigned char c)
+static int
+ppp_tty_room (struct tty_struct *tty)
{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- if (ppp->rhead < ppp->rend) {
- *ppp->rhead = c;
- ppp->rhead++;
- ppp->rcount++;
- } else
- ppp->stats.roverrun++;
- restore_flags(flags);
+ return 65536; /* We can handle an infinite amount of data. :-) */
}
-#ifdef CHECK_CHARACTERS
-static unsigned paritytab[8] = {
- 0x96696996, 0x69969669, 0x69969669, 0x96696996,
- 0x69969669, 0x96696996, 0x96696996, 0x69969669
-};
-#endif
-
-#ifndef NEW_TTY_DRIVERS
-static void
-ppp_dump_inqueue(struct tty_struct *tty)
-{
- int head = tty->read_q.head,
- tail = tty->read_q.tail,
- i, count;
- char buffer[8];
-
- PRINTK ((KERN_DEBUG "INQUEUE: head %d tail %d imode %x:\n", head, tail,
- (unsigned int) tty->termios->c_iflag))
-
- i = tail;
- count = 0;
-
- while (i != head) {
- buffer [count] = tty->read_q.buf[i];
- if (++count == 8) {
- ppp_print_buffer (NULL, buffer, 8, KERNEL_DS);
- count = 0;
- }
- i = (i + 1) & (TTY_BUF_SIZE - 1);
- }
- ppp_print_buffer (NULL, buffer, count, KERNEL_DS);
-}
-
-/* called by lower levels of TTY driver when data becomes available.
- all incoming data comes through this function. */
-
-void ppp_tty_input_ready(struct tty_struct *tty)
-{
- struct ppp *ppp = ppp_find(tty);
- int n, error;
- unsigned char buff[128];
-
-/* PRINTK( (KERN_DEBUG "PPP: handler called.\n") ) */
- if (!ppp || ppp->magic != PPP_MAGIC) {
- PRINTKN (1,
- (KERN_ERR "PPP: handler called but couldn't find PPP struct.\n"));
- return;
- }
-
- CHECK_PPP_VOID();
-
- /* ZZZ */
- if (ppp_debug >= 5)
- ppp_dump_inqueue(ppp->tty);
-
- do {
- n = tty_read_raw_data(tty, buff, 128);
- if ( n == 0 ) /* nothing there */
- break;
-
- if (ppp_debug >= 5)
- ppp_print_buffer ("receive buffer", buff, n > 0 ? n : -n, KERNEL_DS);
-
- if ( n < 0 ) {
- /* Last character is error flag.
- Process the previous characters, then set toss flag. */
- n = (-n) - 1;
- error = buff[n];
- } else error = 0;
- ppp->stats.rbytes += n;
- ppp_unesc(ppp,buff,n);
- if (error)
- ppp->toss = error;
- } while (1);
-}
-
-/* recover frame by undoing PPP escape mechanism;
- copies N chars of input data from C into PPP->rbuff
- calls ppp_doframe to dispose of any frames it finds
-*/
+/*
+ * Callback function when data is available at the tty driver.
+ */
static void
-ppp_unesc(struct ppp *ppp, unsigned char *c, int n)
+ppp_tty_receive (struct tty_struct *tty, const u_char * data,
+ char *flags, int count)
{
- int i;
+ register struct ppp *ppp = tty2ppp (tty);
+ 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;
- for (i = 0; i < n; i++, c++) {
- PRINTKN (6,(KERN_DEBUG "(%x)", (unsigned int) *c));
+ if (buf == NULL)
+ return;
+/*
+ * Verify the table pointer and ensure that the line is
+ * still in PPP discipline.
+ */
+ if (ppp->magic != PPP_MAGIC) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG
+ "PPP: handler called but couldn't find "
+ "PPP struct.\n");
+ return;
+ }
+ CHECK_PPP_VOID ();
+/*
+ * Print the buffer if desired
+ */
+ if (ppp->flags & SC_LOG_RAWIN)
+ ppp_print_buffer ("receive buffer", data, count);
+/*
+ * Collect the character and error condition for the character. Set the toss
+ * flag for the first character error.
+ */
+ while (count-- > 0) {
+ ppp->bytes_rcvd++;
+ chr = *data++;
+ if (flags) {
+ if (*flags && ppp->toss == 0)
+ ppp->toss = *flags;
+ ++flags;
+ }
+/*
+ * Set the flags for 8 data bits and no parity.
+ *
+ * Actually, it sets the flags for d7 being 0/1 and parity being even/odd
+ * so that the normal processing would have all flags set at the end of the
+ * session. A missing flag bit would denote an error condition.
+ */
#ifdef CHECK_CHARACTERS
- if (*c & 0x80)
- sc->sc_flags |= SC_RCV_B7_1;
- else
- sc->sc_flags |= SC_RCV_B7_0;
-
- if (paritytab[*c >> 5] & (1 << (*c & 0x1F)))
- sc->sc_flags |= SC_RCV_ODDP;
- else
- sc->sc_flags |= SC_RCV_EVNP;
+ if (chr & 0x80)
+ ppp->flags |= SC_RCV_B7_1;
+ else
+ ppp->flags |= SC_RCV_B7_0;
+
+ if (paritytab[chr >> 5] & (1 << (chr & 0x1F)))
+ ppp->flags |= SC_RCV_ODDP;
+ else
+ ppp->flags |= SC_RCV_EVNP;
#endif
+/*
+ * Branch on the character. Process the escape character. The sequence ESC ESC
+ * is defined to be ESC.
+ */
+ switch (chr) {
+ case PPP_ESCAPE: /* PPP_ESCAPE: invert bit in next character */
+ ppp->escape = PPP_TRANS;
+ break;
+/*
+ * FLAG. This is the end of the block. If the block terminated by ESC FLAG,
+ * then the block is to be ignored. In addition, characters before the very
+ * first FLAG are also tossed by this procedure.
+ */
+ case PPP_FLAG: /* PPP_FLAG: end of frame */
+ ppp->stats.ppp_ibytes += ppp->rbuf->count;
+ if (ppp->escape)
+ ppp->toss |= 0x80;
+/*
+ * Process frames which are not to be ignored. If the processing failed,
+ * then clean up the VJ tables.
+ */
+ if ((ppp->toss & 0x80) != 0 ||
+ ppp_doframe (ppp) == 0) {
+ slhc_toss (ppp->slcomp);
+ }
+/*
+ * Reset all indicators for the new frame to follow.
+ */
+ buf->count = 0;
+ buf->fcs = PPP_INITFCS;
+ ppp->escape = 0;
+ ppp->toss = 0;
+ break;
+/*
+ * All other characters in the data come here. If the character is in the
+ * receive mask then ignore the character.
+ */
+ default:
+ if (in_rmap (ppp, chr))
+ break;
+/*
+ * Adjust the character and if the frame is to be discarded then simply
+ * ignore the character until the ending FLAG is received.
+ */
+ chr ^= ppp->escape;
+ ppp->escape = 0;
- switch (*c) {
- case PPP_ESC: /* PPP_ESC: invert 0x20 in next character */
- ppp->escape = PPP_TRANS;
- break;
+ if (ppp->toss != 0)
+ break;
+/*
+ * If the count sent is within reason then store the character, bump the
+ * count, and update the FCS for the character.
+ */
+ if (buf->count < buf->size) {
+ buf_base (buf)[buf->count++] = chr;
+ buf->fcs = PPP_FCS (buf->fcs, chr);
+ break;
+ }
+/*
+ * The peer sent too much data. Set the flags to discard the current frame
+ * and wait for the re-synchronization FLAG to be sent.
+ */
+ ppp->stats.ppp_ierrors++;
+ ppp->toss |= 0xC0;
+ break;
+ }
+ }
+}
- case PPP_FLAG: /* PPP_FLAG: end of frame */
- if (ppp->escape) /* PPP_ESC just before PPP_FLAG is illegal */
- ppp->toss = 0xFF;
+/*
+ * Put the input frame into the networking system for the indicated protocol
+ */
- if ((ppp->toss & 0x80) == 0)
- ppp_doframe(ppp); /* pass frame on to next layers */
+static int
+ppp_rcv_rx (struct ppp *ppp, unsigned short proto, u_char * data, int count)
+{
+ sk_buff *skb = dev_alloc_skb (count);
+/*
+ * Generate a skb buffer for the new frame.
+ */
+ if (skb == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp_do_ip: packet dropped on %s (no memory)!\n",
+ ppp2dev (ppp)->name);
+ return 0;
+ }
+/*
+ * Move the received data from the input buffer to the skb buffer.
+ */
+ skb->dev = ppp2dev (ppp); /* We are the device */
+#if USE_SKB_PROTOCOL == 0
+ skb->len = count;
+#else
+ skb->protocol = proto;
+ skb->mac.raw = skb_data(skb);
+#endif
+ 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.recv_idle = jiffies;
+ netif_rx (skb);
+ return 1;
+}
- ppp->rcount = 0;
- ppp->rhead = ppp->rbuff;
- ppp->escape = 0;
- ppp->toss = 0;
- break;
+/*
+ * Process the receipt of an IP frame
+ */
- default: /* regular character */
- if (!in_rmap (ppp, *c)) {
- if (ppp->toss == 0)
- ppp_enqueue (ppp, *c ^ ppp->escape);
- ppp->escape = 0;
- }
- break;
- }
- }
+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);
+ }
+ return 0;
}
-#else
-static int ppp_receive_room(struct tty_struct *tty)
+/*
+ * Process the receipt of an IPX frame
+ */
+
+static int
+rcv_proto_ipx (struct ppp *ppp, unsigned short proto, u_char * data, int count)
{
- return 65536; /* We can handle an infinite amount of data. :-) */
+#ifdef NEW_SKBUFF
+ if (ppp2dev (ppp)->flags & IFF_UP) {
+ if (count > 0)
+ return ppp_rcv_rx (ppp, htons (ETH_P_IPX), data, count);
+ } else
+#endif
+ return 0;
}
+/*
+ * Process the receipt of an VJ Compressed frame
+ */
-static void ppp_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+static int
+rcv_proto_vjc_comp (struct ppp *ppp, unsigned short proto,
+ u_char *data, int count)
{
- register struct ppp *ppp = ppp_find (tty);
- unsigned char c;
-
-/* PRINTK( ("PPP: handler called.\n") ); */
+ if ((ppp->flags & SC_REJ_COMP_TCP) == 0) {
+ int new_count = slhc_uncompress (ppp->slcomp, data, count);
+ if (new_count >= 0) {
+ return rcv_proto_ip (ppp, PPP_IP, data, new_count);
+ }
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_NOTICE
+ "ppp: error in VJ decompression\n");
+ }
+ return 0;
+}
- if (!ppp || ppp->magic != PPP_MAGIC) {
- PRINTKN (1,("PPP: handler called but couldn't find "
- "PPP struct.\n"));
- return;
- }
+/*
+ * Process the receipt of an VJ Un-compressed frame
+ */
- CHECK_PPP_VOID();
-
- if (ppp_debug >= 5) {
- ppp_print_buffer ("receive buffer", cp, count, KERNEL_DS);
- }
+static int
+rcv_proto_vjc_uncomp (struct ppp *ppp, unsigned short proto,
+ u_char *data, int count)
+{
+ if ((ppp->flags & SC_REJ_COMP_TCP) == 0) {
+ if (slhc_remember (ppp->slcomp, data, count) > 0) {
+ return rcv_proto_ip (ppp, PPP_IP, data, count);
+ }
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_NOTICE
+ "ppp: error in VJ memorizing\n");
+ }
+ return 0;
+}
- ppp->stats.rbytes += count;
-
- while (count-- > 0) {
- c = *cp++;
+/*
+ * Receive all unclassified protocols.
+ */
- if (fp) {
- if (*fp && ppp->toss == 0)
- ppp->toss = *fp;
- fp++;
- }
+static int
+rcv_proto_unknown (struct ppp *ppp, unsigned short proto,
+ u_char *data, int len)
+{
+ int totlen;
+ register int current_idx;
+
+#define PUTC(c) \
+{ \
+ buf_base (ppp->ubuf) [current_idx++] = (u_char) (c); \
+ current_idx &= ppp->ubuf->size; \
+ if (current_idx == ppp->ubuf->tail) \
+ goto failure; \
+}
-#ifdef CHECK_CHARACTERS
- if (c & 0x80)
- ppp->flags |= SC_RCV_B7_1;
- else
- ppp->flags |= SC_RCV_B7_0;
-
- if (paritytab[c >> 5] & (1 << (c & 0x1F)))
- ppp->flags |= SC_RCV_ODDP;
- else
- ppp->flags |= SC_RCV_EVNP;
+/*
+ * The total length includes the protocol data.
+ * Lock the user information buffer.
+ */
+ if (set_bit (0, &ppp->ubuf->locked)) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG
+ "ppp_us_queue: can't get lock\n");
+ } else {
+ current_idx = ppp->ubuf->head;
+/*
+ * Insert the buffer length (not counted), the protocol, and the data
+ */
+ totlen = len + 2;
+ PUTC (totlen >> 8);
+ PUTC (totlen);
+
+ PUTC (proto >> 8);
+ PUTC (proto);
+
+ totlen -= 2;
+ while (totlen-- > 0) {
+ PUTC (*data++);
+ }
+#undef PUTC
+/*
+ * The frame is complete. Update the head pointer and wakeup the pppd
+ * process.
+ */
+ ppp->ubuf->head = current_idx;
+
+ clear_bit (0, &ppp->ubuf->locked);
+ wake_up_interruptible (&ppp->read_wait);
+ if (ppp->tty->fasync != NULL)
+ kill_fasync (ppp->tty->fasync, SIGIO);
+
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp: successfully queued %d bytes, flags = %x\n",
+ len + 2, ppp->flags);
+
+ return 1;
+/*
+ * The buffer is full. Unlock the header
+ */
+failure:
+ clear_bit (0, &ppp->ubuf->locked);
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_us_queue: ran out of buffer space.\n");
+ }
+/*
+ * Discard the frame. There are no takers for this protocol.
+ */
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_WARNING
+ "ppp: dropping packet on the floor.\n");
+ slhc_toss (ppp->slcomp);
+ return 0;
+}
+
+/*
+ * Handle a CCP packet.
+ *
+ * The CCP packet is passed along to the pppd process just like any
+ * other PPP frame. The difference is that some processing needs to be
+ * immediate or the compressors will become confused on the peer.
+ */
+
+static void ppp_proto_ccp (struct ppp *ppp, u_char *dp, int len, int rcvd)
+{
+ int slen = CCP_LENGTH(dp);
+ u_char *opt = dp + CCP_HDRLEN;
+ int opt_len = slen - CCP_HDRLEN;
+
+ if (slen > len)
+ return;
+
+ 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;
+
+ 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,
+ opt,
+ opt_len,
+ ppp2dev (ppp)->base_addr,
+ 0,
+ ppp->flags & SC_DEBUG))
+ 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,
+ opt,
+ opt_len,
+ ppp2dev (ppp)->base_addr,
+ 0,
+ ppp->mru,
+ ppp->flags & SC_DEBUG)) {
+ 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);
+ } else {
+ if (ppp->sc_rc_state && (ppp->flags & SC_DECOMP_RUN)) {
+ (*ppp->sc_rcomp->decomp_reset)(ppp->sc_rc_state);
+ ppp->flags &= ~SC_DC_ERROR;
+ }
+ }
+ break;
+ }
+}
+
+static int
+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);
+}
+
+/*
+ * Handle a LQR packet.
+ *
+ * The LQR packet is passed along to the pppd process just like any
+ * other PPP frame. The difference is that some processing needs to be
+ * performed to append the current data to the end of the frame.
+ */
+
+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);
+/*
+ * Fill in the fields from the driver data
+ */
+ p = &data [48];
+ p = store_long (p, ++ppp->stats.ppp_ilqrs);
+ p = store_long (p, ppp->stats.ppp_ipackets);
+ p = store_long (p, ppp->stats.ppp_discards);
+ p = store_long (p, ppp->stats.ppp_ierrors);
+ p = store_long (p, ppp->stats.ppp_ioctects + len);
+
+ len = 68;
+ }
#endif
+/*
+ * Pass the frame to the pppd daemon.
+ */
+ return rcv_proto_unknown (ppp, proto, data, len);
+}
- switch (c) {
- case PPP_ESC: /* PPP_ESC: invert 0x20 in next character */
- ppp->escape = PPP_TRANS;
- break;
+/* on entry, a received frame is in ppp->rbuf.bufr
+ check it and dispose as appropriate */
- case PPP_FLAG: /* PPP_FLAG: end of frame */
- if (ppp->escape) /* PPP_ESC just before PPP_FLAG is "cancel"*/
- ppp->toss = 0xFF;
+static void ppp_doframe_lower (struct ppp *ppp, u_char *data, int count)
+{
+ u_short proto = PPP_PROTOCOL (data);
+ ppp_proto_type *proto_ptr;
+/*
+ * Ignore empty frames
+ */
+ if (count <= 4)
+ return;
+/*
+ * Count the frame and print it
+ */
+ ++ppp->stats.ppp_ipackets;
+ if (ppp->flags & SC_LOG_INPKT)
+ ppp_print_buffer ("receive frame", data, count);
+/*
+ * 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.
+ */
+ proto_ptr = proto_list;
+ while (proto_ptr->proto != 0 && proto_ptr->proto != proto)
+ ++proto_ptr;
+/*
+ * Update the appropriate statistic counter.
+ */
+ 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;
+}
- if ((ppp->toss & 0x80) == 0)
- ppp_doframe(ppp); /* pass frame on to next layers */
+/* on entry, a received frame is in ppp->rbuf.bufr
+ check it and dispose as appropriate */
- ppp->rcount = 0;
- ppp->rhead = ppp->rbuff;
- ppp->escape = 0;
- ppp->toss = 0;
- break;
+static int
+ppp_doframe (struct ppp *ppp)
+{
+ u_char *data = buf_base (ppp->rbuf);
+ int count = ppp->rbuf->count;
+ int addr, ctrl, proto;
+ int new_count;
+ u_char *new_data;
+/*
+ * If there is a pending error from the receiver then log it and discard
+ * the damaged frame.
+ */
+ if (ppp->toss) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_WARNING
+ "ppp_toss: tossing frame, reason = %d\n",
+ ppp->toss);
+ ppp->stats.ppp_ierrors++;
+ return 0;
+ }
+/*
+ * An empty frame is ignored. This occurs if the FLAG sequence precedes and
+ * follows each frame.
+ */
+ if (count == 0)
+ return 1;
+/*
+ * Generate an error if the frame is too small.
+ */
+ if (count < PPP_HARD_HDR_LEN) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_WARNING
+ "ppp: got runt ppp frame, %d chars\n", count);
+ slhc_toss (ppp->slcomp);
+ ppp->stats.ppp_ierrors++;
+ return 1;
+ }
+/*
+ * Verify the CRC of the frame and discard the CRC characters from the
+ * end of the buffer.
+ */
+ if (ppp->rbuf->fcs != PPP_GOODFCS) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_WARNING
+ "ppp: frame with bad fcs, excess = %x\n",
+ ppp->rbuf->fcs ^ PPP_GOODFCS);
+ ppp->stats.ppp_ierrors++;
+ return 0;
+ }
+ count -= 2; /* ignore the fcs characters */
+/*
+ * Ignore the leading ADDRESS and CONTROL fields in the frame.
+ */
+ addr = PPP_ALLSTATIONS;
+ ctrl = PPP_UI;
- default: /* regular character */
- if (!in_rmap (ppp, c)) {
- if (ppp->toss == 0)
- ppp_enqueue (ppp, c ^ ppp->escape);
- ppp->escape = 0;
- }
- }
- }
+ 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) &&
+ ((ppp->flags & (SC_DC_FERROR | SC_DC_ERROR)) == 0)) {
+ if (proto == PPP_COMP) {
+/*
+ * If the frame is compressed then decompress it.
+ */
+ new_data = kmalloc (ppp->mru + 4, GFP_ATOMIC);
+ if (new_data == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp_doframe: no memory\n");
+ slhc_toss (ppp->slcomp);
+ (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state,
+ data,
+ count);
+ return 1;
+ }
+/*
+ * Decompress the frame
+ */
+ new_count = bsd_decompress (ppp->sc_rc_state,
+ data,
+ count,
+ new_data,
+ ppp->mru + 4);
+ switch (new_count) {
+ default:
+ ppp_doframe_lower (ppp, new_data, new_count);
+ kfree (new_data);
+ return 1;
+
+ case DECOMP_OK:
+ break;
+
+ case DECOMP_ERROR:
+ ppp->flags |= SC_DC_ERROR;
+ break;
+
+ case DECOMP_FATALERROR:
+ ppp->flags |= SC_DC_FERROR;
+ break;
+ }
+/*
+ * Log the error condition and discard the frame.
+ */
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp_proto_comp: "
+ "decompress err %d\n", new_count);
+ kfree (new_data);
+ slhc_toss (ppp->slcomp);
+ return 1;
+ }
+/*
+ * 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);
+ }
+/*
+ * Process the uncompressed frame.
+ */
+ ppp_doframe_lower (ppp, data, count);
+ return 1;
+}
+
+/*************************************************************
+ * LINE DISCIPLINE SUPPORT
+ * The following functions form support user programs
+ * which read and write data on a TTY with the PPP line
+ * discipline. Reading is done from a circular queue,
+ * filled by the lower TTY levels.
+ *************************************************************/
+
+/* read a PPP frame from the us_rbuff circular buffer,
+ waiting if necessary
+*/
+
+static int
+ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf,
+ unsigned int nr)
+{
+ struct ppp *ppp = tty2ppp (tty);
+ u_char c;
+ int len, indx;
+
+#define GETC(c) \
+{ \
+ c = buf_base (ppp->ubuf) [ppp->ubuf->tail++]; \
+ ppp->ubuf->tail &= ppp->ubuf->size; \
+}
+
+/*
+ * Validate the pointer to the PPP structure
+ */
+ 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 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;
+ 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.
+ */
+ if (ppp->ubuf->head == ppp->ubuf->tail)
+ len = 0;
+ else {
+ GETC (c);
+ len = c << 8;
+ GETC (c);
+ len += c;
+ }
+/*
+ * If there is no length then wait for the data to arrive.
+ */
+ if (len == 0) {
+ /* no data */
+ clear_bit (0, &ppp->ubuf->locked);
+ if (file->f_flags & O_NONBLOCK) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG
+ "ppp_tty_read: no data "
+ "(EWOULDBLOCK)\n");
+ return -EWOULDBLOCK;
+ }
+ current->timeout = 0;
+
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG
+ "ppp_tty_read: sleeping(read_wait)\n");
+
+ interruptible_sleep_on (&ppp->read_wait);
+ if (current->signal & ~current->blocked)
+ return -EINTR;
+ continue;
+ }
+/*
+ * Reset the time of the last read operation.
+ */
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG "ppp_tty_read: len = %d\n", len);
+/*
+ * Ensure that the frame will fit within the caller's buffer. If not, then
+ * discard the frame from the input buffer and return an error to the caller.
+ */
+ if (len + 2 > nr) {
+ /* Can't copy it, update us_rbuff_head */
+
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG
+ "ppp: read of %u bytes too small for %d "
+ "frame\n", nr, len + 2);
+ ppp->ubuf->tail += len;
+ ppp->ubuf->tail &= ppp->ubuf->size;
+ clear_bit (0, &ppp->ubuf->locked);
+ 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_byte_user (PPP_ALLSTATIONS, buf++);
+ put_byte_user (PPP_UI, buf++);
+
+ indx = len;
+/*
+ * Copy the received data from the buffer to the caller's area.
+ */
+ while (indx-- > 0) {
+ GETC (c);
+ put_byte_user (c, buf);
+ ++buf;
+ }
+/*
+ * Release the lock and return the character count in the buffer area.
+ */
+ clear_bit (0, &ppp->ubuf->locked);
+ len += 2; /* Account for ADDRESS and CONTROL bytes */
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG
+ "ppp_tty_read: passing %d bytes up\n", len);
+ return len;
+ }
+#undef GETC
+}
+
+/* stuff a character into the transmit buffer, using PPP's way of escaping
+ special characters.
+ also, update fcs to take account of new character */
+
+extern inline void
+ppp_stuff_char (struct ppp *ppp, register struct ppp_buffer *buf,
+ register u_char chr)
+{
+/*
+ * The buffer should not be full.
+ */
+ if (ppp->flags & SC_DEBUG) {
+ if ((buf->count < 0) || (buf->count > 3000))
+ printk (KERN_DEBUG "ppp_stuff_char: %x %d\n",
+ (unsigned int) buf->count,
+ (unsigned int) chr);
+ }
+/*
+ * Update the FCS and if the character needs to be escaped, do it.
+ */
+ buf->fcs = PPP_FCS (buf->fcs, chr);
+ if (in_xmap (ppp, chr)) {
+ chr ^= PPP_TRANS;
+ ins_char (buf, PPP_ESCAPE);
+ }
+/*
+ * Add the character to the buffer.
+ */
+ ins_char (buf, chr);
+}
+
+/*
+ * Procedure to encode the data with the proper escapement and send the
+ * data to the remote system.
+ */
+
+static void
+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;
+
+ if (non_ip || flag_time == 0)
+ ins_char (buf, PPP_FLAG);
+ else {
+ if (jiffies - ppp->last_xmit > flag_time)
+ ins_char (buf, PPP_FLAG);
+ }
+ ppp->last_xmit = jiffies;
+ 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);
+
+ ppp_stuff_char (ppp, buf, proto);
+/*
+ * Insert the data
+ */
+ data += 4;
+ count -= 4;
+
+ while (count-- > 0)
+ ppp_stuff_char (ppp, buf, *data++);
+/*
+ * Add the trailing CRC and the final flag character
+ */
+ write_fcs = buf->fcs ^ 0xFFFF;
+ ppp_stuff_char (ppp, buf, write_fcs);
+ ppp_stuff_char (ppp, buf, write_fcs >> 8);
+
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG "ppp_dev_xmit_lower: fcs is %hx\n",
+ write_fcs);
+/*
+ * Add the trailing flag character
+ */
+ ins_char (buf, PPP_FLAG);
+/*
+ * Print the buffer
+ */
+ if (ppp->flags & SC_LOG_FLUSH)
+ ppp_print_buffer ("ppp flush", buf_base (buf),
+ buf->count);
+ else {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG
+ "ppp_dev_xmit: writing %d chars\n",
+ buf->count);
+ }
+/*
+ * Send the block to the tty driver.
+ */
+ ppp->stats.ppp_obytes += buf->count;
+ ppp_kick_tty (ppp, buf);
+}
+
+/*
+ * Send an frame to the remote with the proper bsd compression.
+ *
+ * Return 0 if frame was queued for transmission.
+ * 1 if frame must be re-queued for later driver support.
+ */
+
+static int
+ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf,
+ u_char *data, int count)
+{
+ int proto;
+ int address, control;
+ u_char *new_data;
+ int new_count;
+/*
+ * Print the buffer
+ */
+ if (ppp->flags & SC_LOG_OUTPKT)
+ ppp_print_buffer ("write frame", data, count);
+/*
+ * 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);
+
+ if (((ppp->flags & SC_COMP_RUN) != 0) &&
+ (ppp->sc_xc_state != (void *) 0) &&
+ (address == PPP_ALLSTATIONS) &&
+ (control == PPP_UI) &&
+ (proto != PPP_LCP) &&
+ (proto != PPP_CCP)) {
+ new_data = kmalloc (count, GFP_ATOMIC);
+ if (new_data == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp_dev_xmit_frame: no memory\n");
+ return 1;
+ }
+
+ new_count = bsd_compress (ppp->sc_xc_state,
+ data,
+ new_data,
+ count,
+ count);
+
+ if (new_count > 0) {
+ ++ppp->stats.ppp_opackets;
+ ppp->stats.ppp_ooctects += new_count;
+
+ ppp_dev_xmit_lower (ppp, buf, new_data,
+ new_count, 0);
+ kfree (new_data);
+ return 0;
+ }
+/*
+ * The frame could not be compressed.
+ */
+ kfree (new_data);
+ }
+/*
+ * 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;
+/*
+ * Go to the escape encoding
+ */
+ ppp_dev_xmit_lower (ppp, buf, data, count, !!(proto & 0xFF00));
+ return 0;
+}
+
+/*
+ * Revise the tty frame for specific protocols.
+ */
+
+static int
+send_revise_frame (register struct ppp *ppp, u_char *data, int len)
+{
+ u_char *p;
+
+ switch (PPP_PROTOCOL (data)) {
+/*
+ * Update the LQR frame with the current MIB information. This saves having
+ * the daemon read old MIB data from the driver.
+ */
+ case PPP_LQR:
+ len = 48; /* total size of this frame */
+ p = (u_char *) &data [40]; /* Point to last two items. */
+ p = store_long (p, ppp->stats.ppp_opackets + 1);
+ p = store_long (p, ppp->stats.ppp_ooctects + len);
+ break;
+/*
+ * Outbound compression frames
+ */
+ case PPP_CCP:
+ ppp_proto_ccp (ppp,
+ data + PPP_HARD_HDR_LEN,
+ len - PPP_HARD_HDR_LEN,
+ 0);
+ break;
+/*
+ * All other frame types
+ */
+ default:
+ break;
+ }
+
+ return len;
+}
+
+/*
+ * write a frame with NR chars from BUF to TTY
+ * we have to put the FCS field on ourselves
+ */
+
+static int
+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)
+ return -EIO;
+
+ if (ppp->magic != PPP_MAGIC)
+ return -EIO;
+
+ CHECK_PPP (-ENXIO);
+/*
+ * Ensure that the caller does not wish to send too much.
+ */
+ if (count > PPP_MTU) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_WARNING
+ "ppp_tty_write: truncating user packet "
+ "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
+ */
+ while (lock_buffer (ppp->tbuf) != 0) {
+ current->timeout = 0;
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG "ppp_tty_write: sleeping\n");
+ interruptible_sleep_on (&ppp->write_wait);
+
+ 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;
+ }
+ }
+/*
+ * Ensure that the caller's buffer is valid.
+ */
+ status = verify_area (VERIFY_READ, data, count);
+ if (status != 0) {
+ kfree (new_data);
+ ppp->tbuf->locked = 0;
+ return status;
+ }
+
+ memcpy_fromfs (new_data, data, count);
+/*
+ * Change the LQR frame
+ */
+ count = send_revise_frame (ppp, new_data, count);
+/*
+ * Send the data
+ */
+ ppp_dev_xmit_frame (ppp, ppp->tbuf, new_data, count);
+ kfree (new_data);
+ return (int) count;
+}
+
+/*
+ * Process the BSD compression IOCTL event for the tty device.
+ */
+
+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];
+/*
+ * Fetch the compression parameters
+ */
+ error = verify_area (VERIFY_READ, odp, sizeof (data));
+ if (error == 0) {
+ 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, ptr, nb);
+ }
+
+ if (error != 0)
+ return error;
+
+ memcpy_fromfs (ccp_option, ptr, nb);
+
+ if (ccp_option[1] < 2) /* preliminary check on the length byte */
+ return (-EINVAL);
+
+ 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 (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;
+ }
+ 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);
+ return (-EINVAL); /* no handler found */
+}
+
+/*
+ * Process the IOCTL event for the tty device.
+ */
+
+static int
+ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
+ unsigned long param3)
+{
+ struct ppp *ppp = tty2ppp (tty);
+ register int temp_i = 0;
+ int error;
+/*
+ * Verify the status of the PPP device.
+ */
+ 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.
+ */
+ if (!suser ())
+ return -EPERM;
+/*
+ * Set the MRU value
+ */
+ switch (param2) {
+ case PPPIOCSMRU:
+ error = verify_area (VERIFY_READ, (void *) param3,
+ sizeof (temp_i));
+ if (error == 0) {
+ 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);
+
+ if (ppp->mru != temp_i)
+ ppp_changedmtu (ppp, ppp2dev (ppp)->mtu, temp_i);
+ }
+ break;
+/*
+ * Fetch the flags
+ */
+ case PPPIOCGFLAGS:
+ error = verify_area (VERIFY_WRITE, (void *) param3,
+ sizeof (temp_i));
+ if (error == 0) {
+ temp_i = (ppp->flags & SC_MASK);
+#ifndef CHECK_CHARACTERS /* Don't generate errors if we don't check chars. */
+ temp_i |= SC_RCV_B7_1 | SC_RCV_B7_0 |
+ SC_RCV_ODDP | SC_RCV_EVNP;
+#endif
+ put_long_user ((long) temp_i, param3);
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG
+ "ppp_tty_ioctl: get flags: addr %lx flags "
+ "%x\n", param3, temp_i);
+ }
+ break;
+/*
+ * Set the flags for the various options
+ */
+ case PPPIOCSFLAGS:
+ error = verify_area (VERIFY_READ, (void *) param3,
+ sizeof (temp_i));
+ if (error == 0) {
+ temp_i = get_int_user (param3) & SC_MASK;
+ temp_i |= (ppp->flags & ~SC_MASK);
+
+ if ((ppp->flags & SC_CCP_OPEN) &&
+ (temp_i & SC_CCP_OPEN) == 0)
+ ppp_ccp_closed (ppp);
+
+ if ((ppp->flags | temp_i) & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_tty_ioctl: set flags to %x\n", temp_i);
+ ppp->flags = temp_i;
+ }
+ break;
+/*
+ * Set the compression mode
+ */
+ case PPPIOCSCOMPRESS:
+ error = ppp_set_compression (ppp,
+ (struct ppp_option_data *) param3);
+ break;
+/*
+ * Retrieve the transmit async map
+ */
+ case PPPIOCGASYNCMAP:
+ error = verify_area (VERIFY_WRITE, (void *) param3,
+ sizeof (temp_i));
+ if (error == 0) {
+ 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,
+ (unsigned long) ppp->xmit_async_map[0]);
+ }
+ break;
+/*
+ * Set the transmit async map
+ */
+ case PPPIOCSASYNCMAP:
+ error = verify_area (VERIFY_READ, (void *) param3,
+ sizeof (temp_i));
+ if (error == 0) {
+ 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",
+ (unsigned long) ppp->xmit_async_map[0]);
+ }
+ break;
+/*
+ * Set the receive async map
+ */
+ case PPPIOCSRASYNCMAP:
+ error = verify_area (VERIFY_READ, (void *) param3,
+ sizeof (temp_i));
+ if (error == 0) {
+ ppp->recv_async_map = get_long_user (param3);
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_tty_ioctl: set rcv asyncmap %lx\n",
+ (unsigned long) ppp->recv_async_map);
+ }
+ break;
+/*
+ * Obtain the unit number for this device.
+ */
+ case PPPIOCGUNIT:
+ error = verify_area (VERIFY_WRITE, (void *) param3,
+ sizeof (temp_i));
+ if (error == 0) {
+ put_long_user (ppp2dev (ppp)->base_addr, param3);
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_tty_ioctl: get unit: %ld",
+ ppp2dev (ppp)->base_addr);
+ }
+ break;
+/*
+ * Set the debug level
+ */
+ case PPPIOCSDEBUG:
+ error = verify_area (VERIFY_READ, (void *) param3,
+ sizeof (temp_i));
+ if (error == 0) {
+ temp_i = (get_int_user (param3) & 0x1F) << 16;
+ temp_i |= (ppp->flags & ~0x1F0000);
+
+ if ((ppp->flags | temp_i) & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_tty_ioctl: set flags to %x\n", temp_i);
+ ppp->flags = temp_i;
+ }
+ break;
+/*
+ * Get the debug level
+ */
+ case PPPIOCGDEBUG:
+ error = verify_area (VERIFY_WRITE, (void *) param3,
+ sizeof (temp_i));
+ if (error == 0) {
+ temp_i = (ppp->flags >> 16) & 0x1F;
+ put_long_user ((long) temp_i, param3);
+
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_tty_ioctl: get debug level %d\n",
+ temp_i);
+ }
+ break;
+/*
+ * Get the times since the last send/receive frame operation
+ */
+ case PPPIOCGIDLE:
+ error = verify_area (VERIFY_WRITE, (void *) param3,
+ sizeof (struct ppp_idle));
+ if (error == 0) {
+ struct ppp_idle cur_ddinfo;
+ unsigned long cur_jiffies = jiffies;
+
+ /* change absolute times to relative times. */
+ 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 (cur_ddinfo));
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_tty_ioctl: read demand dial info\n");
+ }
+ break;
+/*
+ * Retrieve the extended async map
+ */
+ case PPPIOCGXASYNCMAP:
+ error = verify_area (VERIFY_WRITE,
+ (void *) param3,
+ sizeof (ppp->xmit_async_map));
+ if (error == 0) {
+ memcpy_tofs ((void *) param3,
+ ppp->xmit_async_map,
+ sizeof (ppp->xmit_async_map));
+
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_tty_ioctl: get xasyncmap: addr %lx\n",
+ param3);
+ }
+ break;
+/*
+ * Set the async extended map
+ */
+ case PPPIOCSXASYNCMAP:
+ error = verify_area (VERIFY_READ, (void *) param3,
+ sizeof (ppp->xmit_async_map));
+ if (error == 0) {
+ __u32 temp_tbl[8];
+
+ memcpy_fromfs (temp_tbl, (void *) param3,
+ sizeof (ppp->xmit_async_map));
+ temp_tbl[1] = 0x00000000;
+ temp_tbl[2] &= ~0x40000000;
+ temp_tbl[3] |= 0x60000000;
+
+ if ((temp_tbl[2] & temp_tbl[3]) != 0 ||
+ (temp_tbl[4] & temp_tbl[5]) != 0 ||
+ (temp_tbl[6] & temp_tbl[7]) != 0)
+ error = -EINVAL;
+ else {
+ memcpy (ppp->xmit_async_map, temp_tbl,
+ sizeof (ppp->xmit_async_map));
+
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_tty_ioctl: set xasyncmap\n");
+ }
+ }
+ break;
+/*
+ * Set the maximum VJ header compression slot number.
+ */
+ case PPPIOCSMAXCID:
+ error = verify_area (VERIFY_READ, (void *) param3,
+ sizeof (temp_i));
+ if (error == 0) {
+ temp_i = get_int_user (param3) + 1;
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_tty_ioctl: set maxcid to %d\n",
+ temp_i);
+ if (ppp->slcomp != NULL)
+ slhc_free (ppp->slcomp);
+ ppp->slcomp = slhc_init (16, temp_i);
+
+ if (ppp->slcomp == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp: no space for compression buffers!\n");
+ ppp_release (ppp);
+ error = -ENOMEM;
+ }
+ }
+ break;
+/*
+ * Allow users to read, but not set, the serial port parameters
+ */
+ case TCGETS:
+ case TCGETA:
+ error = n_tty_ioctl (tty, file, param2, param3);
+ break;
+/*
+ * All other ioctl() events will come here.
+ */
+ default:
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp_tty_ioctl: invalid ioctl: %x, addr %lx\n",
+ param2,
+ param3);
+
+ error = -ENOIOCTLCMD;
+ break;
+ }
+ return error;
+}
+
+/*
+ * TTY callback.
+ *
+ * Process the select() statement for the PPP device.
+ */
+
+static int
+ppp_tty_select (struct tty_struct *tty, struct inode *inode,
+ struct file *filp, int sel_type, select_table * wait)
+{
+ struct ppp *ppp = tty2ppp (tty);
+ int result = 1;
+/*
+ * Verify the status of the PPP device.
+ */
+ 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
+ * buffer area.
+ */
+ switch (sel_type) {
+ case SEL_IN:
+ if (set_bit (0, &ppp->ubuf->locked) == 0) {
+ /* Test for the presence of data in the queue */
+ if (ppp->ubuf->head != ppp->ubuf->tail) {
+ clear_bit (0, &ppp->ubuf->locked);
+ break;
+ }
+ clear_bit (0, &ppp->ubuf->locked);
+ } /* fall through */
+ /*
+ * Exceptions or read errors.
+ */
+ case SEL_EX:
+ /* Is this a pty link and the remote disconnected? */
+ if (tty->flags & (1 << TTY_SLAVE_CLOSED))
+ break;
+
+ /* Is this a local link and the modem disconnected? */
+ if (tty_hung_up_p (filp))
+ break;
+
+ select_wait (&ppp->read_wait, wait);
+ result = 0;
+ break;
+/*
+ * Write mode. A write is allowed if there is no current transmission.
+ */
+ case SEL_OUT:
+ if (ppp->tbuf->locked != 0) {
+ select_wait (&ppp->write_wait, wait);
+ result = 0;
+ }
+ break;
+ }
+ return result;
+}
+
+/*************************************************************
+ * NETWORK OUTPUT
+ * This routine accepts requests from the network layer
+ * and attempts to deliver the packets.
+ * It also includes various routines we are compelled to
+ * have to make the network layer work (arp, etc...).
+ *************************************************************/
+
+/*
+ * Callback from the network layer when the device goes up.
+ */
+
+static int
+ppp_dev_open (struct device *dev)
+{
+ struct ppp *ppp = dev2ppp (dev);
+
+ /* reset POINTOPOINT every time, since dev_close zaps it! */
+ dev->flags |= IFF_POINTOPOINT;
+
+ if (ppp2tty (ppp) == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp: %s not connected to a TTY! can't go open!\n",
+ dev->name);
+ return -ENXIO;
+ }
+
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp: channel %s going up for IP packets!\n",
+ dev->name);
+
+ CHECK_PPP (-ENXIO);
+ return 0;
+}
+
+/*
+ * Callback from the network layer when the ppp device goes down.
+ */
+
+static int
+ppp_dev_close (struct device *dev)
+{
+ struct ppp *ppp = dev2ppp (dev);
+
+ if (ppp2tty (ppp) == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp: %s not connected to a TTY! can't go down!\n",
+ dev->name);
+ return -ENXIO;
+ }
+/*
+ * We don't do anything about the device going down. It is not important
+ * for us.
+ */
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp: channel %s going down for IP packets!\n",
+ dev->name);
+ CHECK_PPP (-ENXIO);
+ return 0;
+}
+
+/*
+ * IOCTL operation to read the version of the driver.
+ */
+
+static int
+ppp_dev_ioctl_version (struct ppp *ppp, struct ifreq *ifr)
+{
+ int error;
+ int len;
+ char *result;
+/*
+ * Must have write access to the buffer.
+ */
+ result = (char *) ifr->ifr_ifru.ifru_data;
+ len = strlen (szVersion) + 1;
+ error = verify_area (VERIFY_WRITE, result, len);
+/*
+ * Move the version data
+ */
+ if (error == 0)
+ memcpy_tofs (result, szVersion, len);
+
+ return error;
+}
+
+/*
+ * IOCTL to read the statistics for the pppstats program.
+ */
+
+static int
+ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev)
+{
+ struct ppp_stats *result, temp;
+ int error;
+/*
+ * Must have write access to the buffer.
+ */
+ result = (struct ppp_stats *) ifr->ifr_ifru.ifru_data;
+ error = verify_area (VERIFY_WRITE,
+ result,
+ sizeof (temp));
+/*
+ * Supply the information for the caller. First move the version data
+ * then move the ppp stats; and finally the vj stats.
+ */
+ memset (&temp, 0, sizeof(temp));
+ if (error == 0 && dev->flags & IFF_UP) {
+ memcpy (&temp.p, &ppp->stats, sizeof (struct pppstat));
+ if (ppp->slcomp != NULL) {
+ 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;
+ temp.vj.vjs_errorin = ppp->slcomp->sls_i_error;
+ temp.vj.vjs_tossed = ppp->slcomp->sls_i_tossed;
+ 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));
+/*
+ * Supply the information for the caller.
+ */
+ 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);
+
+ if (ppp->sc_rc_state != NULL)
+ (*ppp->sc_rcomp->decomp_stat) (ppp->sc_rc_state,
+ &temp.d);
+ }
+/*
+ * Move the data to the caller's buffer
+ */
+ if (error == 0)
+ memcpy_tofs (result, &temp, sizeof (temp));
+ return error;
}
-#endif
-/* on entry, a received frame is in ppp->rbuff
- check it and dispose as appropriate */
-static void
-ppp_doframe(struct ppp *ppp)
-{
- u_char *c = ppp->rbuff;
- u_short proto;
- int count = ppp->rcount;
-
- /* forget it if we've already noticed an error */
- if (ppp->toss) {
- PRINTKN (1, (KERN_WARNING "ppp_toss: tossing frame, reason = %d\n",
- ppp->toss));
- slhc_toss (ppp->slcomp);
- ppp->stats.rerrors++;
- return;
- }
-
- /* do this before printing buffer to avoid generating copious output */
- if (count == 0)
- return;
-
- if (ppp_debug >= 3)
- ppp_print_buffer ("receive frame", c, count, KERNEL_DS);
-
- if (count < 4) {
- PRINTKN (1,(KERN_WARNING "ppp: got runt ppp frame, %d chars\n", count));
- slhc_toss (ppp->slcomp);
- ppp->stats.runts++;
- return;
- }
-
- /* check PPP error detection field */
- if (!ppp_check_fcs(ppp)) {
- PRINTKN (1,(KERN_WARNING "ppp: frame with bad fcs\n"));
- slhc_toss (ppp->slcomp);
- ppp->stats.rerrors++;
- return;
- }
-
- count -= 2; /* ignore last two characters */
-
- /* now we have a good frame */
- /* figure out the protocol field */
- if ((c[0] == PPP_ADDRESS) && (c[1] == PPP_CONTROL)) {
- c = c + 2; /* ADDR/CTRL not compressed, so skip */
- count -= 2;
- }
-
- proto = (u_short) *c++; /* PROTO compressed */
- if (proto & 1) {
- count--;
- } else {
- proto = (proto << 8) | (u_short) *c++; /* PROTO uncompressed */
- count -= 2;
- }
-
- /* Send the frame to the network if the ppp device is up */
- if ((ppp->dev->flags & IFF_UP) && ppp_do_ip(ppp, proto, c, count)) {
- ppp->ddinfo.ip_rjiffies = jiffies;
- return;
- }
-
- /* If we got here, it has to go to a user process doing a read,
- so queue it.
-
- User process expects to get whole frame (for some reason), so
- use count+2 so as to include FCS field. */
-
- if (ppp_us_queue (ppp, proto, c, count+2)) {
- ppp->ddinfo.nip_rjiffies = jiffies;
- ppp->stats.rothers++;
- return;
- }
-
- /* couldn't cope. */
- PRINTKN (1,(KERN_WARNING
- "ppp: dropping packet on the floor: nobody could take it.\n"));
- slhc_toss (ppp->slcomp);
- ppp->stats.tossed++;
-}
-
-/* Examine packet at C, attempt to pass up to net layer.
- PROTO is the protocol field from the PPP frame.
- Return 1 if could handle it, 0 otherwise. */
+/*
+ * Callback from the network layer to process the sockioctl functions.
+ */
static int
-ppp_do_ip (struct ppp *ppp, unsigned short proto, unsigned char *c,
- int count)
+ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd)
{
- int flags, done;
- struct sk_buff *skb;
-
- PRINTKN (4,(KERN_DEBUG "ppp_do_ip: proto %x len %d first byte %x\n",
- (int) proto, count, c[0]));
+ struct ppp *ppp = dev2ppp (dev);
+ int error;
+/*
+ * Process the requests
+ */
+ switch (cmd) {
+ case SIOCGPPPSTATS:
+ error = ppp_dev_ioctl_stats (ppp, ifr, dev);
+ break;
+
+ case SIOCGPPPCSTATS:
+ error = ppp_dev_ioctl_comp_stats (ppp, ifr, dev);
+ break;
+
+ case SIOCGPPPVER:
+ error = ppp_dev_ioctl_version (ppp, ifr);
+ break;
+
+ default:
+ error = -EINVAL;
+ break;
+ }
+ return error;
+}
- if (ppp_debug_netpackets) {
- PRINTK (("KERN_DEBUG %s <-- proto %x len %d\n", ppp->dev->name,
- (int) proto, count));
- }
-
- if (proto == PROTO_IP) {
- ppp->stats.runcomp++;
- goto sendit;
- }
-
- if ((proto == PROTO_VJCOMP) && !(ppp->flags & SC_REJ_COMP_TCP)) {
- /* get space for uncompressing the header */
- done = 0;
- save_flags (flags);
- cli();
- if ((ppp->rhead + 80) < ppp->rend) {
- ppp->rhead += 80;
- ppp->rcount += 80;
- done = 1;
- }
- restore_flags(flags);
-
- if (! done) {
- PRINTKN (1,(KERN_NOTICE
- "ppp: no space to decompress VJ compressed TCP header.\n"));
- ppp->stats.roverrun++;
- slhc_toss (ppp->slcomp);
- return 1;
- }
-
- count = slhc_uncompress(ppp->slcomp, c, count);
- if (count <= 0) {
- ppp->stats.rerrors++;
- PRINTKN (1,(KERN_NOTICE "ppp: error in VJ decompression\n"));
- slhc_toss (ppp->slcomp);
- return 1;
- }
- ppp->stats.rcomp++;
- goto sendit;
- }
-
- if ((proto == PROTO_VJUNCOMP) && !(ppp->flags & SC_REJ_COMP_TCP)) {
- if (slhc_remember(ppp->slcomp, c, count) <= 0) {
- ppp->stats.rerrors++;
- PRINTKN (1,(KERN_NOTICE "ppp: error in VJ memorizing\n"));
- slhc_toss (ppp->slcomp);
- return 1;
- }
- ppp->stats.runcomp++;
- goto sendit;
- }
-
- /* not ours */
- return 0;
-
- sendit:
- if (ppp_debug_netpackets) {
- struct iphdr *iph = (struct iphdr *) c;
- PRINTK ((KERN_INFO "%s <-- src %x dst %x len %d\n", ppp->dev->name,
- iph->saddr, iph->daddr, count))
- }
-
- /* receive the frame through the network software */
-
- skb=dev_alloc_skb(count);
- if(skb)
- {
- skb->mac.raw=skb->data;
- memcpy(skb_put(skb,count), c,count);
- skb->protocol=htons(ETH_P_IP);
- skb->dev=ppp->dev;
- netif_rx(skb);
- }
- return 1;
-}
-
-/* stuff packet at BUF, length LEN, into the us_rbuff buffer
- prepend PROTO information */
-
-#define PUTC(c,label) *ppp->us_rbuff_head++ = c; \
- if (ppp->us_rbuff_head == ppp->us_rbuff_end) \
- ppp->us_rbuff_head = ppp->us_rbuff; \
- if (ppp->us_rbuff_head == ppp->us_rbuff_tail) \
- goto label;
-#define GETC(c) c = *ppp->us_rbuff_tail++; \
- if (ppp->us_rbuff_tail == ppp->us_rbuff_end) \
- ppp->us_rbuff_tail = ppp->us_rbuff;
+/*
+ * Send an IP frame to the remote with vj header compression.
+ *
+ * Return 0 if frame was queued for transmission.
+ * 1 if frame must be re-queued for later driver support.
+ */
static int
-ppp_us_queue(struct ppp *ppp, unsigned short proto,
- unsigned char *buf, int len)
+ppp_dev_xmit_ip1 (struct device *dev, struct ppp *ppp, u_char *data)
{
- int totlen;
- unsigned char *saved_head;
-
- totlen = len+2; /* including protocol */
-
- if (set_bit(1, &ppp->us_rbuff_lock)) {
- PRINTKN (1, (KERN_NOTICE "ppp_us_queue: can't get lock\n"));
- return 0;
- }
- saved_head = ppp->us_rbuff_head;
-
- PUTC((totlen & 0xff00) >> 8, failure);
- PUTC(totlen & 0x00ff, failure);
- PUTC((proto & 0xff00) >> 8, failure);
- PUTC(proto & 0x00ff, failure);
-
- while (len-- > 0) {
- PUTC(*buf++, failure);
- }
-
- PRINTKN (3, (KERN_INFO "ppp: successfully queued %d bytes\n", totlen));
- clear_bit(1, &ppp->us_rbuff_lock);
- wake_up_interruptible (&ppp->read_wait);
-
-#ifdef NEW_TTY_DRIVERS
- kill_fasync(ppp->tty->fasync, SIGIO);
-#endif
-
- if (ppp->inp_sig && ppp->inp_sig_pid)
- if (kill_proc (ppp->inp_sig_pid, ppp->inp_sig, 1) != 0) {
- /* process is gone */
- PRINTKN (2,(KERN_NOTICE
- "ppp: process that requested notification is gone\n"));
- ppp->inp_sig = 0;
- ppp->inp_sig_pid = 0;
- }
- return 1;
-
- failure:
- ppp->us_rbuff_head = saved_head;
- clear_bit(1, &ppp->us_rbuff_lock);
+ int proto = PPP_IP;
+ int len;
+ struct ppp_hdr *hdr;
+ struct tty_struct *tty = ppp2tty (ppp);
+/*
+ * Obtain the length from the IP header.
+ */
+ len = ((struct iphdr *)data) -> tot_len;
+ len = ntohs (len);
+/*
+ * Validate the tty interface
+ */
+ if (tty == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp_dev_xmit: %s not connected to a TTY!\n",
+ dev->name);
+ return 0;
+ }
+/*
+ * Ensure that the PPP device is still up
+ */
+ if (!(dev->flags & IFF_UP)) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_WARNING
+ "ppp_dev_xmit: packet sent on interface %s,"
+ " which is down for IP\n",
+ dev->name);
+ return 0;
+ }
+/*
+ * Detect a change in the transfer size
+ */
+ if (ppp->mtu != ppp2dev (ppp)->mtu) {
+ ppp_changedmtu (ppp,
+ ppp2dev (ppp)->mtu,
+ ppp->mru);
+ }
+/*
+ * Acquire the lock on the transmission buffer. If the buffer was busy then
+ * mark the device as busy and return "failure to send, try back later" error.
+ */
+ if (lock_buffer (ppp->wbuf) != 0) {
+ dev->tbusy = 1;
+ return 1;
+ }
+/*
+ * Print the frame being sent
+ */
+ if (ppp->flags & SC_LOG_OUTPKT)
+ ppp_print_buffer ("ppp outpkt", data, len);
+/*
+ * At this point, the buffer will be transmitted. There is no other exit.
+ *
+ * Try to compress the header.
+ */
+ if (ppp->flags & SC_COMP_TCP) {
+ len = slhc_compress (ppp->slcomp, data, len,
+ buf_base (ppp->cbuf) + PPP_HARD_HDR_LEN,
+ &data,
+ (ppp->flags & SC_NO_TCP_CCID) == 0);
+
+ if (data[0] & SL_TYPE_COMPRESSED_TCP) {
+ proto = PPP_VJC_COMP;
+ data[0] ^= SL_TYPE_COMPRESSED_TCP;
+ } else {
+ if (data[0] >= SL_TYPE_UNCOMPRESSED_TCP)
+ proto = PPP_VJC_UNCOMP;
+ data[0] = (data[0] & 0x0f) | 0x40;
+ }
+ }
+/*
+ * Send the frame
+ */
+ len += PPP_HARD_HDR_LEN;
+ hdr = &((struct ppp_hdr *) data)[-1];
- PRINTKN (1, (KERN_NOTICE "ppp_us_queue: ran out of buffer space.\n"));
+ hdr->address = PPP_ALLSTATIONS;
+ hdr->control = PPP_UI;
+ hdr->protocol[0] = 0;
+ hdr->protocol[1] = proto;
- return 0;
+ return ppp_dev_xmit_frame (ppp, ppp->wbuf, (u_char *) hdr, len);
}
-/*************************************************************
- * LINE DISCIPLINE SUPPORT
- * The following functions form support user programs
- * which read and write data on a TTY with the PPP line
- * discipline. Reading is done from a circular queue,
- * filled by the lower TTY levels.
- *************************************************************/
-
-/* read a PPP frame from the us_rbuff circular buffer,
- waiting if necessary
-*/
+/*
+ * This is just an interum solution until the 1.3 kernel's networking is
+ * available. The 1.2 kernel has problems with device headers before the
+ * buffers.
+ *
+ * This routine should be deleted, and the ppp_dev_xmit_ip1 routine called
+ * by this name.
+ */
static int
-ppp_read(struct tty_struct *tty, struct file *file, unsigned char *buf, unsigned int nr)
-{
- struct ppp *ppp = ppp_find(tty);
- unsigned char c;
- int len, i;
-
- if (!ppp || ppp->magic != PPP_MAGIC) {
- PRINTKN (1,(KERN_ERR "ppp_read: cannot find ppp channel\n"));
- return -EIO;
- }
-
- CHECK_PPP(-ENXIO);
-
- PRINTKN (4,(KERN_DEBUG "ppp_read: called %p num %u\n",
- buf, nr));
-
- do {
- /* try to acquire read lock */
- if (set_bit(0, &ppp->us_rbuff_lock) == 0) {
- /* got lock */
- if (ppp->us_rbuff_head == ppp->us_rbuff_tail) {
- /* no data */
- PRINTKN (4,(KERN_DEBUG "ppp_read: no data\n"));
- clear_bit(0, &ppp->us_rbuff_lock);
- if (ppp->inp_sig) {
- PRINTKN (4,(KERN_DEBUG "ppp_read: EWOULDBLOCK\n"));
- return -EWOULDBLOCK;
- } else goto wait;
- }
-
- i = verify_area (VERIFY_WRITE,buf,nr);
- if (i != 0) {
- ppp->us_rbuff_lock = 0;
- return i;
- }
-
- /* reset the time of the last read operation */
- ppp->ddinfo.nip_rjiffies = jiffies;
-
- GETC (c); len = c << 8; GETC (c); len += c;
-
- PRINTKN (4,(KERN_DEBUG "ppp_read: len = %d\n", len));
-
- if (len + 2 > nr) {
- /* frame too big; can't copy it, but do update us_rbuff_head */
- PRINTKN (1,(KERN_DEBUG
- "ppp: read of %u bytes too small for %d frame\n",
- nr, len+2));
- ppp->us_rbuff_head += len;
- if (ppp->us_rbuff_head > ppp->us_rbuff_end)
- ppp->us_rbuff_head += - (ppp->us_rbuff_end - ppp->us_rbuff);
- clear_bit(0, &ppp->us_rbuff_lock);
- wake_up_interruptible (&ppp->read_wait);
- ppp->stats.rgiants++;
- return -EOVERFLOW; /* ZZZ; HACK! */
- } else {
- /* have the space: copy the packet, faking the first two bytes */
- put_user (PPP_ADDRESS, buf++);
- put_user (PPP_CONTROL, buf++);
- i = len;
- while (i-- > 0) {
- GETC (c);
- put_user (c, buf++);
- }
- }
-
- clear_bit(0, &ppp->us_rbuff_lock);
- PRINTKN (3,(KERN_DEBUG "ppp_read: passing %d bytes up\n", len + 2));
- ppp->stats.rothers++;
- return len + 2;
- }
-
- /* need to wait */
- wait:
- current->timeout = 0;
- PRINTKN (3,(KERN_DEBUG "ppp_read: sleeping\n"));
- interruptible_sleep_on (&ppp->read_wait);
-
- /* Ensure that the ppp device is still attached. */
- ppp = ppp_find(tty);
- if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse)
- return 0;
-
- if (current->signal & ~current->blocked)
- return -EINTR;
- } while (1);
+ppp_dev_xmit_ip (struct device *dev, struct ppp *ppp, u_char *data)
+{
+ struct ppp_hdr *hdr;
+ int len;
+ int answer;
+
+ len = ((struct iphdr *)data) -> tot_len;
+ len = ntohs (len);
+
+ hdr = (struct ppp_hdr *) kmalloc (len + sizeof (struct ppp_hdr),
+ GFP_ATOMIC);
+
+ if (hdr == NULL)
+ answer = 1;
+ else {
+ memcpy (&hdr[1], data, len);
+ answer = ppp_dev_xmit_ip1 (dev, ppp, (u_char *) &hdr[1]);
+ kfree (hdr);
+ }
+
+ return answer;
}
-/* stuff a character into the transmit buffer, using PPP's way of escaping
- special characters.
- also, update ppp->fcs to take account of new character */
-static inline void
-ppp_stuff_char(struct ppp *ppp, unsigned char c)
-{
- int curpt = ppp->xhead - ppp->xbuff;
- if ((curpt < 0) || (curpt > 3000)) {
- PRINTK ((KERN_DEBUG "ppp_stuff_char: %p %p %d\n",
- ppp->xbuff, ppp->xhead, curpt))
- }
- if (in_xmap (ppp, c)) {
- *ppp->xhead++ = PPP_ESC;
- *ppp->xhead++ = c ^ PPP_TRANS;
- } else
- *ppp->xhead++ = c;
- ppp->fcs = (ppp->fcs >> 8) ^ fcstab[(ppp->fcs ^ c) & 0xff];
-}
-
-/* write a frame with NR chars from BUF to TTY
- we have to put the FCS field on ourselves
-*/
+/*
+ * Send an IPX (or any other non-IP) frame to the remote.
+ *
+ * Return 0 if frame was queued for transmission.
+ * 1 if frame must be re-queued for later driver support.
+ */
+#ifdef NEW_SKBUFF
static int
-ppp_write(struct tty_struct *tty, struct file *file, const unsigned char *buf, unsigned int nr)
+ppp_dev_xmit_ipx1 (struct device *dev, struct ppp *ppp,
+ u_char *data, int len, int proto)
{
- struct ppp *ppp = ppp_find(tty);
- int i;
-
- if (!ppp || ppp->magic != PPP_MAGIC) {
- PRINTKN (1,(KERN_ERR "ppp_write: cannot find ppp unit\n"));
- return -EIO;
- }
-
- CHECK_PPP(-ENXIO);
-
- if (ppp->mtu != ppp->dev->mtu) /* Someone has been ifconfigging */
- ppp_changedmtu (ppp, ppp->dev->mtu, ppp->mru);
-
- if (nr > ppp->mtu) {
- PRINTKN (1,(KERN_WARNING
- "ppp_write: truncating user packet from %u to mtu %d\n",
- nr, ppp->mtu));
- nr = ppp->mtu;
- }
-
- i = verify_area (VERIFY_READ,buf,nr);
- if (i != 0)
- return i;
-
- if (ppp_debug >= 3)
- ppp_print_buffer ("write frame", buf, nr, USER_DS);
-
- /* lock this PPP unit so we will be the only writer;
- sleep if necessary */
- while ((ppp->sending == 1) || !ppp_lock(ppp)) {
- current->timeout = 0;
- PRINTKN (3,(KERN_DEBUG "ppp_write: sleeping\n"));
- interruptible_sleep_on(&ppp->write_wait);
-
- /* Ensure that the ppp device is still attached. */
- ppp = ppp_find(tty);
- if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse)
- return 0;
-
- if (current->signal & ~current->blocked)
- return -EINTR;
- }
-
- /* OK, locked. Stuff the given bytes into the buffer. */
-
- PRINTKN(4,(KERN_DEBUG "ppp_write: acquired write lock\n"));
- ppp->xhead = ppp->xbuff;
-
-#ifdef OPTIMIZE_FLAG_TIME
- if (jiffies - ppp->last_xmit > OPTIMIZE_FLAG_TIME)
- *ppp->xhead++ = PPP_FLAG;
- ppp->last_xmit = jiffies;
-#else
- *ppp->xhead++ = PPP_FLAG;
-#endif
-
- ppp->fcs = PPP_FCS_INIT;
- i = nr;
- while (i-- > 0)
- ppp_stuff_char(ppp,get_user(buf++));
+ struct tty_struct *tty = ppp2tty (ppp);
+ struct ppp_hdr *hdr;
+/*
+ * Validate the tty interface
+ */
+ if (tty == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp_dev_xmit: %s not connected to a TTY!\n",
+ dev->name);
+ return 0;
+ }
+/*
+ * Ensure that the PPP device is still up
+ */
+ if (!(dev->flags & IFF_UP)) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_WARNING
+ "ppp_dev_xmit: packet sent on interface %s,"
+ " which is down\n",
+ dev->name);
+ return 0;
+ }
+/*
+ * Detect a change in the transfer size
+ */
+ if (ppp->mtu != ppp2dev (ppp)->mtu) {
+ ppp_changedmtu (ppp,
+ ppp2dev (ppp)->mtu,
+ ppp->mru);
+ }
+/*
+ * Acquire the lock on the transmission buffer. If the buffer was busy then
+ * mark the device as busy and return "failure to send, try back later" error.
+ */
+ if (lock_buffer (ppp->wbuf) != 0) {
+ dev->tbusy = 1;
+ return 1;
+ }
+/*
+ * Print the frame being sent
+ */
+ if (ppp->flags & SC_LOG_OUTPKT)
+ ppp_print_buffer ("ppp outpkt", data, len);
+/*
+ * Send the frame
+ */
+ len += PPP_HARD_HDR_LEN;
+ hdr = &((struct ppp_hdr *) data)[-1];
- ppp_add_fcs(ppp); /* concatenate FCS at end */
+ hdr->address = PPP_ALLSTATIONS;
+ hdr->control = PPP_UI;
+ hdr->protocol[0] = proto >> 8;
+ hdr->protocol[1] = proto;
- *ppp->xhead++ = PPP_FLAG;
-
- /* reset the time of the last write operation */
- ppp->ddinfo.nip_sjiffies = jiffies;
+ return ppp_dev_xmit_frame (ppp, ppp->wbuf, (u_char *) hdr, len);
+}
- if (ppp_debug >= 6)
- ppp_print_buffer ("xmit buffer", ppp->xbuff, ppp->xhead - ppp->xbuff, KERNEL_DS);
- else {
- PRINTKN (4,(KERN_DEBUG "ppp_write: writing %d chars\n",
- (int) (ppp->xhead - ppp->xbuff)));
- }
+/*
+ * This is just an interum solution until the 1.3 kernel's networking is
+ * available. The 1.2 kernel has problems with device headers before the
+ * buffers.
+ *
+ * This routine should be deleted, and the ppp_dev_xmit_ipx1 routine called
+ * by this name.
+ */
- /* packet is ready-to-go */
- ++ppp->stats.sothers;
- ppp_kick_tty(ppp);
+static int
+ppp_dev_xmit_ipx (struct device *dev, struct ppp *ppp,
+ u_char *data, int len, int proto)
+{
+ struct ppp_hdr *hdr;
+ int answer;
+
+ hdr = (struct ppp_hdr *) kmalloc (len + sizeof (struct ppp_hdr),
+ GFP_ATOMIC);
+ if (hdr == NULL)
+ answer = 1;
+ else {
+ memcpy (&hdr[1], data, len);
+ answer = ppp_dev_xmit_ipx1 (dev, ppp, (u_char *) &hdr[1],
+ len, proto);
+ kfree (hdr);
+ }
- return((int)nr);
+ return answer;
}
-
-static int
-ppp_ioctl(struct tty_struct *tty, struct file *file, unsigned int i,
- unsigned long l)
-{
- struct ppp *ppp = ppp_find(tty);
- register int temp_i = 0;
- int error;
-
- if (!ppp || ppp->magic != PPP_MAGIC) {
- PRINTK ((KERN_ERR "ppp_ioctl: can't find PPP block from tty!\n"))
- return -EBADF;
- }
-
- CHECK_PPP(-ENXIO);
-
- /* This must be root user */
- if (!suser())
- return -EPERM;
-
- switch (i) {
- case PPPIOCSMRU:
- error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
- if (error == 0) {
- temp_i = get_user ((int *) l);
- PRINTKN (3,(KERN_INFO "ppp_ioctl: set mru to %d\n", temp_i));
- if (ppp->mru != temp_i)
- ppp_changedmtu (ppp, ppp->dev->mtu, temp_i);
- }
- break;
-
- case PPPIOCGFLAGS:
- error = verify_area (VERIFY_WRITE, (void *) l, sizeof (temp_i));
- if (error == 0) {
- temp_i = (ppp->flags & SC_MASK);
-#ifndef CHECK_CHARACTERS /* Don't generate errors if we don't check chars. */
- temp_i |= SC_RCV_B7_1 | SC_RCV_B7_0 | SC_RCV_ODDP | SC_RCV_EVNP;
-#endif
- put_user (temp_i, (int *) l);
- PRINTKN (3,(KERN_DEBUG "ppp_ioctl: get flags: addr %lx flags %x\n",
- l,
- temp_i));
- }
- break;
-
- case PPPIOCSFLAGS:
- error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
- if (error == 0) {
- temp_i = get_user ((int *) l);
- ppp->flags ^= ((ppp->flags ^ temp_i) & SC_MASK);
- PRINTKN (3,(KERN_INFO "ppp_ioctl: set flags to %x\n", temp_i));
- }
- break;
-
- case PPPIOCGASYNCMAP:
- error = verify_area (VERIFY_WRITE, (void *) l, sizeof (temp_i));
- if (error == 0) {
- put_user (ppp->xmit_async_map[0], (int *) l);
- PRINTKN (3,(KERN_INFO "ppp_ioctl: get asyncmap: addr %lx asyncmap %lx\n",
- l, (unsigned long) ppp->xmit_async_map[0]));
- }
- break;
-
- case PPPIOCSASYNCMAP:
- error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
- if (error == 0) {
- ppp->xmit_async_map[0] = get_user ((int *) l);
- bset (ppp->xmit_async_map, PPP_FLAG);
- bset (ppp->xmit_async_map, PPP_ESC);
- PRINTKN (3,(KERN_INFO "ppp_ioctl: set xmit asyncmap %lx\n",
- (unsigned long) ppp->xmit_async_map[0]));
- }
- break;
-
- case PPPIOCRASYNCMAP:
- error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
- if (error == 0) {
- ppp->recv_async_map = get_user ((int *) l);
- PRINTKN (3,(KERN_INFO "ppp_ioctl: set recv asyncmap %lx\n",
- (unsigned long) ppp->recv_async_map));
- }
- break;
-
- case PPPIOCGUNIT:
- error = verify_area (VERIFY_WRITE, (void *) l, sizeof (temp_i));
- if (error == 0) {
- put_user (ppp->dev->base_addr, (int *) l);
- PRINTKN (3,(KERN_INFO "ppp_ioctl: get unit: %ld", ppp->dev->base_addr));
- }
- break;
-
- case PPPIOCSINPSIG:
- error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
- if (error == 0) {
- ppp->inp_sig = get_user ((int *) l);
- ppp->inp_sig_pid = current->pid;
- PRINTKN (3,(KERN_INFO "ppp_ioctl: set input signal %d\n", ppp->inp_sig));
- }
- break;
-
- case PPPIOCSDEBUG:
- error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
- if (error == 0) {
- ppp_debug = get_user ((int *) l);
- ppp_debug_netpackets = (ppp_debug & 0xff00) >> 8;
- ppp_debug &= 0xff;
- PRINTKN (1, (KERN_INFO "ppp_ioctl: set debug level %d, netpacket %d\n",
- ppp_debug, ppp_debug_netpackets));
- }
- break;
-
- case PPPIOCGDEBUG:
- error = verify_area (VERIFY_WRITE, (void *) l, sizeof (temp_i));
- if (error == 0) {
- put_user ((long) (ppp_debug | (ppp_debug_netpackets << 8)), (int *) l);
- PRINTKN (3,(KERN_INFO "ppp_ioctl: get debug level %d\n",
- ppp_debug | (ppp_debug_netpackets << 8)));
- }
- break;
-
- case PPPIOCGSTAT:
- error = verify_area (VERIFY_WRITE, (void *) l, sizeof (struct ppp_stats));
- if (error == 0) {
- memcpy_tofs ((void *) l, &ppp->stats, sizeof (struct ppp_stats));
- PRINTKN (3,(KERN_INFO "ppp_ioctl: read statistics\n"));
- }
- break;
-
- case PPPIOCGTIME:
- error = verify_area (VERIFY_WRITE, (void *) l, sizeof (struct ppp_ddinfo));
- if (error == 0) {
- struct ppp_ddinfo 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;
-
- memcpy_tofs ((void *) l, &cur_ddinfo, sizeof (struct ppp_ddinfo));
- PRINTKN (3,(KERN_INFO "ppp_ioctl: read demand dial info\n"));
- }
- break;
-
- case PPPIOCGXASYNCMAP:
- error = verify_area (VERIFY_WRITE,
- (void *) l,
- sizeof (ppp->xmit_async_map));
- if (error == 0) {
- memcpy_tofs ((void *) l,
- ppp->xmit_async_map,
- sizeof (ppp->xmit_async_map));
- PRINTKN (3,(KERN_INFO "ppp_ioctl: get xasyncmap: addr %lx\n", l));
- }
- break;
-
- case PPPIOCSXASYNCMAP:
- error = verify_area (VERIFY_READ, (void *) l,
- sizeof (ppp->xmit_async_map));
- if (error == 0) {
- __u32 temp_tbl [8];
-
- memcpy_fromfs (temp_tbl, (void *) l, sizeof (ppp->xmit_async_map));
- temp_tbl[1] = 0x00000000; /* must not escape 0x20 - 0x3f */
- temp_tbl[2] &= ~0x40000000; /* must not escape 0x5e */
- temp_tbl[3] |= 0x60000000; /* must escape 0x7d and 0x7e */
-
- if ((temp_tbl[2] & temp_tbl[3]) != 0 ||
- (temp_tbl[4] & temp_tbl[5]) != 0 ||
- (temp_tbl[6] & temp_tbl[7]) != 0)
- error = -EINVAL;
- else {
- memcpy (ppp->xmit_async_map, temp_tbl, sizeof (ppp->xmit_async_map));
- PRINTKN (3,(KERN_INFO "ppp_ioctl: set xasyncmap\n"));
- }
- }
- break;
-
- case PPPIOCSMAXCID:
- error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
- if (error == 0) {
- temp_i = get_user ((int *) l) + 1;
- PRINTKN (3,(KERN_INFO "ppp_ioctl: set maxcid to %d\n", temp_i));
- if (ppp->slcomp != NULL)
- slhc_free (ppp->slcomp);
-
- ppp->slcomp = slhc_init (temp_i, temp_i);
-
- if (ppp->slcomp == NULL) {
- PRINTKN (1,(KERN_ERR "ppp: no space for compression buffers!\n"));
- ppp_release (ppp);
- error = -ENOMEM;
- }
- }
- break;
-
-#ifdef NEW_TTY_DRIVERS
- /* Allow stty to read, but not set, the serial port */
- case TCGETS:
- case TCGETA:
- error = n_tty_ioctl(tty, file, i, l);
- break;
#endif
/*
- * All other ioctl() events will come here.
+ * Send a frame to the remote.
*/
- default:
- PRINTKN (1,(KERN_ERR "ppp_ioctl: invalid ioctl: %x, addr %lx\n",
- i,
- l));
-#ifdef NEW_TTY_DRIVERS
- error = -ENOIOCTLCMD;
-#else
- error = -EINVAL;
-#endif
- break;
- }
- return error;
-}
-
static int
-ppp_select (struct tty_struct *tty, struct inode * inode,
- struct file * filp, int sel_type, select_table * wait)
+ppp_dev_xmit (sk_buff *skb, struct device *dev)
{
- struct ppp *ppp = ppp_find (tty);
-
- if (!ppp || ppp->magic != PPP_MAGIC) {
- PRINTK ((KERN_ERR "ppp_select: can't find PPP block from tty!\n"))
- return -EBADF;
- }
-
- /* If the PPP protocol is no longer active, return false */
- CHECK_PPP (0);
-
- /* Process the request based upon the type desired */
- switch (sel_type) {
- case SEL_IN:
- if (set_bit(0, &ppp->us_rbuff_lock) == 0) {
- /* Test for the presence of data in the queue */
- if (ppp->us_rbuff_head != ppp->us_rbuff_tail) {
- clear_bit (0, &ppp->us_rbuff_lock);
- return 1;
- }
- clear_bit (0, &ppp->us_rbuff_lock);
- } /* fall through */
-
- case SEL_EX:
- /* Is there a pending error condition? */
- if (tty->packet && tty->link->ctrl_status)
- return 1;
-
- /* closed? */
- if (tty->flags & (1 << TTY_SLAVE_CLOSED))
- return 1;
-
- /* If the tty is disconnected, then this is an exception too */
- if (tty_hung_up_p(filp))
- return 1;
+ int answer, len;
+ u_char *data;
+ struct ppp *ppp = dev2ppp (dev);
+ struct tty_struct *tty = ppp2tty (ppp);
+/*
+ * just a little sanity check.
+ */
+ if (skb == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_WARNING "ppp_dev_xmit: null packet!\n");
+ return 0;
+ }
+/*
+ * Avoid timing problem should tty hangup while data is queued to be sent
+ */
+ if (!ppp->inuse) {
+ dev_kfree_skb (skb, FREE_WRITE);
+ dev_close (dev);
+ return 0;
+ }
+/*
+ * Validate the tty linkage
+ */
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG "ppp_dev_xmit [%s]: skb %X\n",
+ dev->name, (int) skb);
+/*
+ * Validate the tty interface
+ */
+ if (tty == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp_dev_xmit: %s not connected to a TTY!\n",
+ dev->name);
+ dev_kfree_skb (skb, FREE_WRITE);
+ return 0;
+ }
+/*
+ * Fetch the pointer to the data
+ */
+ 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.
+ */
- select_wait (&ppp->read_wait, wait);
- break;
-
- case SEL_OUT:
- if (ppp_lock (ppp)) {
- if (ppp->sending == 0) {
- ppp_unlock (ppp);
- return 1;
- }
- ppp_unlock (ppp);
- }
- select_wait (&ppp->write_wait, wait);
- break;
- }
- return 0;
-}
+#ifdef NEW_SKBUFF
+ switch (skb->protocol) {
+ case htons (ETH_P_IPX):
+ answer = ppp_dev_xmit_ipx (dev, ppp, data, len, PPP_IPX);
+ break;
-/*************************************************************
- * NETWORK OUTPUT
- * This routine accepts requests from the network layer
- * and attempts to deliver the packets.
- * It also includes various routines we are compelled to
- * have to make the network layer work (arp, etc...).
- *************************************************************/
+ case htons (ETH_P_IP):
+ answer = ppp_dev_xmit_ip (dev, ppp, data);
+ break;
-int
-ppp_xmit(struct sk_buff *skb, struct device *dev)
-{
- struct tty_struct *tty;
- struct ppp *ppp;
- unsigned char *p;
- unsigned short proto;
- int len;
-
- /* just a little sanity check. */
- if (skb == NULL) {
- PRINTKN(3,(KERN_WARNING "ppp_xmit: null packet!\n"));
- return 0;
- }
-
- /* Get pointers to the various components */
- ppp = &ppp_ctrl[dev->base_addr];
- tty = ppp->tty;
- p = skb->data;
- len = skb->len;
- proto = PROTO_IP;
-
- PRINTKN(4,(KERN_DEBUG "ppp_xmit [%s]: skb %lX busy %d\n", dev->name,
- (unsigned long int) skb, ppp->sending));
-
- /* avoid race conditions when the link fails */
- if (!ppp->inuse) {
- dev_kfree_skb(skb, FREE_WRITE);
- dev_close (dev);
- return 0;
- }
-
- if (tty == NULL) {
- PRINTKN(1,(KERN_ERR "ppp_xmit: %s not connected to a TTY!\n", dev->name));
- goto done;
- }
-
- if (!(dev->flags & IFF_UP)) {
- PRINTKN(1,(KERN_WARNING
- "ppp_xmit: packet sent on interface %s, which is down for IP\n",
- dev->name));
- goto done;
- }
-
-#ifdef CURED_AGES_AGO
- /* get length from IP header as per Alan Cox bugfix for slip.c */
- if (len < sizeof(struct iphdr)) {
- PRINTKN(0,(KERN_ERR "ppp_xmit: given runt packet, ignoring\n"));
- goto done;
- }
- len = ntohs( ((struct iphdr *)(skb->data)) -> tot_len );
-#endif
-
- /* If doing demand dial then divert the first frame to pppd. */
- if (ppp->flags & SC_IP_DOWN) {
- if ((ppp->flags & SC_IP_FLUSH) == 0) {
- if (ppp_us_queue (ppp, proto, p, len))
- ppp->flags |= SC_IP_FLUSH;
- }
- goto done;
- }
-
- /* Attempt to acquire send lock */
- if (ppp->sending || !ppp_lock(ppp)) {
- PRINTKN(3,(KERN_WARNING "ppp_xmit: busy\n"));
- ppp->stats.sbusy++;
- return 1;
- }
-
- ppp->xhead = ppp->xbuff;
-
- /* try to compress, if VJ compression mode is on */
- if (ppp->flags & SC_COMP_TCP) {
- len = slhc_compress(ppp->slcomp, p, len, ppp->cbuff, &p,
- !(ppp->flags & SC_NO_TCP_CCID));
- if (p[0] & SL_TYPE_COMPRESSED_TCP)
- proto = PROTO_VJCOMP;
- else {
- if (p[0] >= SL_TYPE_UNCOMPRESSED_TCP) {
- proto = PROTO_VJUNCOMP;
- p[0] = (p[0] & 0x0f) | 0x40;
- }
- }
- }
-
- /* increment appropriate counter */
- if (proto == PROTO_VJCOMP)
- ++ppp->stats.scomp;
- else
- ++ppp->stats.suncomp;
-
- if (ppp_debug_netpackets) {
- struct iphdr *iph = (struct iphdr *)skb->data;
- PRINTK ((KERN_DEBUG "%s ==> proto %x len %d src %x dst %x proto %d\n",
- dev->name, (int) proto, (int) len, (int) iph->saddr,
- (int) iph->daddr, (int) iph->protocol))
- }
-
- /* start of frame: FLAG ALL_STATIONS CONTROL <protohi> <protolo> */
-#ifdef OPTIMIZE_FLAG_TIME
- if (jiffies - ppp->last_xmit > OPTIMIZE_FLAG_TIME)
- *ppp->xhead++ = PPP_FLAG;
- ppp->last_xmit = jiffies;
-#else
- *ppp->xhead++ = PPP_FLAG;
+ default: /* All others have no support at this time. */
+ dev_kfree_skb (skb, FREE_WRITE);
+ return 0;
+ }
+#else
+ answer = ppp_dev_xmit_ip (dev, ppp, data);
#endif
- ppp->fcs = PPP_FCS_INIT;
- if (!(ppp->flags & SC_COMP_AC)) {
- ppp_stuff_char(ppp, PPP_ADDRESS);
- ppp_stuff_char(ppp, PPP_CONTROL);
- }
-
- if (!(ppp->flags & SC_COMP_PROT) || (proto & 0xff00))
- ppp_stuff_char(ppp, proto>>8);
- ppp_stuff_char(ppp, proto&0xff);
-
- /* data part */
- while (len-- > 0)
- ppp_stuff_char(ppp, *p++);
-
- /* fcs and flag */
- ppp_add_fcs(ppp);
- *ppp->xhead++ = PPP_FLAG;
+/*
+ * This is the end of the transmission. Release the buffer if it was sent.
+ */
+ if (answer == 0) {
+ dev_kfree_skb (skb, FREE_WRITE);
+ ppp->ddinfo.xmit_idle = jiffies;
+ }
+ return answer;
+}
- /* update the time for demand dial function */
- ppp->ddinfo.ip_sjiffies = jiffies;
+/*
+ * Generate the statistic information for the /proc/net/dev listing.
+ */
- /* send it! */
- if (ppp_debug >= 6)
- ppp_print_buffer ("xmit buffer", ppp->xbuff, ppp->xhead - ppp->xbuff, KERNEL_DS);
- else {
- PRINTKN (4,(KERN_DEBUG "ppp_write: writing %d chars\n",
- (int) (ppp->xhead - ppp->xbuff)));
- }
+static struct enet_statistics *
+ppp_dev_stats (struct device *dev)
+{
+ struct ppp *ppp = dev2ppp (dev);
+ static struct enet_statistics ppp_stats;
+
+ ppp_stats.rx_packets = ppp->stats.ppp_ipackets;
+ ppp_stats.rx_errors = ppp->stats.ppp_ierrors;
+ ppp_stats.rx_dropped = ppp->stats.ppp_ierrors;
+ ppp_stats.rx_fifo_errors = 0;
+ ppp_stats.rx_length_errors = 0;
+ ppp_stats.rx_over_errors = 0;
+ ppp_stats.rx_crc_errors = 0;
+ ppp_stats.rx_frame_errors = 0;
+ ppp_stats.tx_packets = ppp->stats.ppp_opackets;
+ ppp_stats.tx_errors = ppp->stats.ppp_oerrors;
+ ppp_stats.tx_dropped = 0;
+ ppp_stats.tx_fifo_errors = 0;
+ ppp_stats.collisions = 0;
+ ppp_stats.tx_carrier_errors = 0;
+ ppp_stats.tx_aborted_errors = 0;
+ ppp_stats.tx_window_errors = 0;
+ ppp_stats.tx_heartbeat_errors = 0;
+
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO "ppp_dev_stats called");
+ return &ppp_stats;
+}
- ppp_kick_tty(ppp);
+#ifdef 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.
+ */
- done:
- dev_kfree_skb(skb, FREE_WRITE);
- return 0;
-}
-
-#ifdef NET02D
-static int
-ppp_header(unsigned char *buff, struct device *dev, unsigned short type,
- unsigned long daddr, unsigned long saddr, unsigned len)
+static int ppp_dev_input (struct protocol *self, struct protocol *lower,
+ sk_buff *skb, void *saddr, void *daddr)
{
- return(0);
+ return protocol_pass_demultiplex(self, NULL, skb, NULL, NULL);
}
-static int
-ppp_rebuild_header(void *buff, struct device *dev)
+static int ppp_dev_output (struct protocol *self, sk_buff *skb, int type,
+ int subid, void *saddr, void *daddr, void *opt)
{
- return(0);
+ if(skb->dev==NULL)
+ {
+ printk("ppp_dev_output: No device.\n");
+ kfree_skb(skb, FREE_WRITE);
+ return -1;
+ }
+ dev_queue_xmit(skb, skb->dev, skb->priority);
+ return 0;
}
-static void
-ppp_add_arp(unsigned long addr, struct sk_buff *skb, struct device *dev)
+static int ppp_dev_getkey(int protocol, int subid, unsigned char *key)
{
+ switch (protocol)
+ {
+ case htons (ETH_P_IP):
+ case htons (ETH_P_IPX):
+ return 0;
+
+ default:
+ break;
+ }
+
+ return -EAFNOSUPPORT;
}
#else
-static int
-ppp_header(struct sk_buff *skb, struct device *dev, unsigned short type,
- void *daddr, void *saddr, unsigned len)
+#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.
+ */
+
+static unsigned short
+ppp_dev_type (sk_buff *skb, struct device *dev)
{
- return(0);
+ return (htons (ETH_P_IP));
}
+#endif
-static int
-ppp_rebuild_header(void *buff, struct device *dev, unsigned long raddr,
- struct 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);
+ return (0);
}
-#endif
-static struct enet_statistics *
-ppp_get_stats (struct device *dev)
-{
- struct ppp *ppp = &ppp_ctrl[dev->base_addr];
- static struct enet_statistics ppp_stats;
-
- ppp_stats.rx_packets = ppp->stats.rcomp + ppp->stats.runcomp;
- ppp_stats.rx_errors = ppp->stats.rerrors;
- ppp_stats.rx_dropped = ppp->stats.tossed;
- ppp_stats.rx_fifo_errors = 0;
- ppp_stats.rx_length_errors = ppp->stats.runts;
- ppp_stats.rx_over_errors = ppp->stats.roverrun;
- ppp_stats.rx_crc_errors = 0;
- ppp_stats.rx_frame_errors = 0;
- ppp_stats.tx_packets = ppp->stats.scomp + ppp->stats.suncomp;
- ppp_stats.tx_errors = ppp->stats.serrors;
- ppp_stats.tx_dropped = 0;
- ppp_stats.tx_fifo_errors = 0;
- ppp_stats.collisions = ppp->stats.sbusy;
- ppp_stats.tx_carrier_errors = 0;
- ppp_stats.tx_aborted_errors = 0;
- ppp_stats.tx_window_errors = 0;
- ppp_stats.tx_heartbeat_errors = 0;
-
- PRINTKN (3, (KERN_INFO "ppp_get_stats called"));
- return &ppp_stats;
+static int
+ppp_dev_rebuild (void *buff, struct device *dev, unsigned long raddr,
+ sk_buff *skb)
+{
+ return (0);
}
+#endif
/*************************************************************
* UTILITIES
* Miscellany called by various functions above.
*************************************************************/
-#ifndef NEW_TTY_DRIVERS
-/* find a PPP channel given a TTY */
-struct ppp *
-ppp_find(struct tty_struct *tty)
+/* allocate or create a PPP channel */
+static struct ppp *
+ppp_alloc (void)
{
- int i;
- for (i = 0; i < PPP_NRUNIT; i++)
- if (ppp_ctrl[i].inuse && (ppp_ctrl[i].tty == tty)) return &ppp_ctrl[i];
+ int if_num;
+ int status;
+ ppp_ctrl_t *ctl;
+ struct device *dev;
+ struct ppp *ppp;
+
+ /* try to find an free device */
+ ctl = ppp_list;
+ if_num = 0;
+
+ while (ctl) {
+ ppp = ctl2ppp (ctl);
+ if (!set_bit(0, &ppp->inuse))
+ return (ppp);
+ ctl = ctl->next;
+ if (++if_num == max_dev)
+ return (NULL);
+ }
+/*
+ * There are no available items. Allocate a device from the system pool
+ */
+ ctl = (ppp_ctrl_t *) kmalloc (sizeof(ppp_ctrl_t), GFP_KERNEL);
+ if (ctl) {
+ (void) memset(ctl, 0, sizeof(ppp_ctrl_t));
+ ppp = ctl2ppp (ctl);
+ dev = ctl2dev (ctl);
+
+ /* initialize channel control data */
+ set_bit(0, &ppp->inuse);
+
+ ppp->line = if_num;
+ ppp->tty = NULL;
+ ppp->dev = dev;
+
+ dev->next = NULL;
+ dev->init = ppp_init_dev;
+ dev->name = ctl->name;
+ dev->base_addr = (unsigned long) if_num;
+ dev->priv = (void *) ppp;
- return NULL;
-}
-#endif
+ sprintf (dev->name, "ppp%d", if_num);
+
+ /* link in the new channel */
+ ctl->next = ppp_list;
+ ppp_list = ctl;
-/* allocate a PPP channel */
-static struct ppp *
-ppp_alloc(void)
-{
- int i;
- for (i = 0; i < PPP_NRUNIT; i++)
- if (!set_bit(0, &ppp_ctrl[i].inuse)) return &ppp_ctrl[i];
+/* register device so that we can be ifconfig'd */
+/* ppp_init_dev() will be called as a side-effect */
+
+ status = register_netdev (dev);
+ if (status == 0) {
+ printk ("registered device %s\n", dev->name);
+ return (ppp);
+ }
- return NULL;
+ printk (KERN_ERR
+ "ppp_alloc - register_netdev(%s) = %d failure.\n",
+ dev->name, status);
+ /* This one will forever be busy as it is not initialized */
+ }
+ return (NULL);
}
-/* marks a PPP interface 'busy'. user processes will wait, if
- they try to write, and the network code will refrain from sending
- return nonzero if succeeded in acquiring lock
-*/
+/*
+ * Utility procedures to print a buffer in hex/ascii
+ */
-static int
-ppp_lock(struct ppp *ppp)
+static void
+ppp_print_hex (register u_char * out, const u_char * in, int count)
{
- int flags, locked;
- save_flags(flags);
- cli();
- locked = ppp->sending;
- ppp->sending = 1;
- if (ppp->dev->flags & IFF_UP)
- ppp->dev->tbusy = 1;
- restore_flags(flags);
- return locked == 0;
+ register u_char next_ch;
+ static char hex[] = "0123456789ABCDEF";
+
+ while (count-- > 0) {
+ next_ch = *in++;
+ *out++ = hex[(next_ch >> 4) & 0x0F];
+ *out++ = hex[next_ch & 0x0F];
+ ++out;
+ }
}
static void
-ppp_unlock(struct ppp *ppp)
+ppp_print_char (register u_char * out, const u_char * in, int count)
{
- int flags;
- save_flags(flags);
- cli();
- ppp->sending = 0;
- if (ppp->dev->flags & IFF_UP)
- ppp->dev->tbusy = 0;
- restore_flags(flags);
-}
+ register u_char next_ch;
+
+ while (count-- > 0) {
+ next_ch = *in++;
-/* FCS support functions */
+ if (next_ch < 0x20 || next_ch > 0x7e)
+ *out++ = '.';
+ else {
+ *out++ = next_ch;
+ if (next_ch == '%') /* printk/syslogd has a bug !! */
+ *out++ = '%';
+ }
+ }
+ *out = '\0';
+}
static void
-ppp_add_fcs(struct ppp *ppp)
+ppp_print_buffer (const u_char * name, const u_char * buf, int count)
{
- unsigned short fcs = ppp->fcs;
+ u_char line[44];
+
+ if (name != (u_char *) NULL)
+ printk (KERN_DEBUG "ppp: %s, count = %d\n", name, count);
+
+ while (count > 8) {
+ memset (line, 32, 44);
+ ppp_print_hex (line, buf, 8);
+ ppp_print_char (&line[8 * 3], buf, 8);
+ printk (KERN_DEBUG "%s\n", line);
+ count -= 8;
+ buf += 8;
+ }
- fcs ^= 0xffff;
- ppp_stuff_char(ppp, fcs & 0x00ff);
- ppp_stuff_char(ppp, (fcs & 0xff00) >> 8);
- ASSERT (ppp->fcs == PPP_FCS_GOOD);
- PRINTKN (4,(KERN_DEBUG "ppp_add_fcs: fcs is %lx\n",
- (long) (unsigned long) fcs));
+ if (count > 0) {
+ memset (line, 32, 44);
+ ppp_print_hex (line, buf, count);
+ ppp_print_char (&line[8 * 3], buf, count);
+ printk (KERN_DEBUG "%s\n", line);
+ }
}
-static int
-ppp_check_fcs(struct ppp *ppp)
-{
- unsigned short fcs = PPP_FCS_INIT, msgfcs;
- unsigned char *c = ppp->rbuff;
- int i;
-
- for (i = 0; i < ppp->rcount - 2; i++, c++)
- fcs = (fcs >> 8) ^ fcstab[(fcs ^ *c) & 0xff];
+/*************************************************************
+ * Compressor module interface
+ *************************************************************/
- fcs ^= 0xffff;
- msgfcs = (c[1] << 8) + c[0];
- PRINTKN (4,(KERN_INFO "ppp_check_fcs: got %lx want %lx\n",
- (unsigned long) msgfcs, (unsigned long) fcs));
- return fcs == msgfcs;
-}
+struct compressor_link {
+ struct compressor_link *next;
+ struct compressor *comp;
+};
-static char hex[] = "0123456789ABCDEF";
+static struct compressor_link *ppp_compressors = (struct compressor_link *) 0;
-static inline void ppp_print_hex (register char *out, const char *in, int count)
+static struct compressor *find_compressor (int type)
{
- register unsigned char next_ch;
+ struct compressor_link *lnk;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
- while (count-- > 0) {
- next_ch = (unsigned char) get_user (in);
+ 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;
+ }
- *out++ = hex[(next_ch >> 4) & 0x0F];
- *out++ = hex[next_ch & 0x0F];
- ++out;
- ++in;
- }
+ restore_flags(flags);
+ return (struct compressor *) 0;
}
-static inline void ppp_print_char (register char *out, const char *in, int count)
+STATIC int ppp_register_compressor (struct compressor *cp)
{
- register unsigned char next_ch;
+ struct compressor_link *new;
+ unsigned long flags;
- while (count-- > 0) {
- next_ch = (unsigned char) get_user (in);
+ new = (struct compressor_link *) kmalloc (sizeof (struct compressor_link), GFP_KERNEL);
- if (next_ch < 0x20 || next_ch > 0x7e)
- *out++ = '.';
- else {
- *out++ = next_ch;
- if (next_ch == '%') /* printk/syslogd has a bug !! */
- *out++ = '%';
- }
- ++in;
- }
- *out = '\0';
-}
+ if (new == (struct compressor_link *) 0)
+ return 1;
-static void ppp_print_buffer(const char *name, const char *buf, int count, int seg)
-{
- char line [44];
- int old_fs = get_fs();
+ save_flags(flags);
+ cli();
+
+ if (find_compressor (cp->compress_proto)) {
+ restore_flags(flags);
+ kfree (new);
+ return 0;
+ }
- set_fs (seg);
+ new->next = ppp_compressors;
+ new->comp = cp;
+ ppp_compressors = new;
- if (name != NULL)
- PRINTK ((KERN_DEBUG "ppp: %s, count = %d\n", name, count));
+ restore_flags(flags);
+ return 0;
+}
- while (count > 8) {
- memset (line, ' ', sizeof (line));
- ppp_print_hex (line, buf, 8);
- ppp_print_char (&line[8 * 3], buf, 8);
- PRINTK ((KERN_DEBUG "%s\n", line));
- count -= 8;
- buf += 8;
- }
+STATIC void ppp_unregister_compressor (struct compressor *cp)
+{
+ struct compressor_link *prev = (struct compressor_link *) 0;
+ struct compressor_link *lnk;
+ unsigned long flags;
- if (count > 0) {
- memset (line, ' ', sizeof (line));
- ppp_print_hex (line, buf, count);
- ppp_print_char (&line[8 * 3], buf, count);
- PRINTK ((KERN_DEBUG "%s\n", line));
- }
+ save_flags(flags);
+ cli();
- set_fs (old_fs);
+ 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;
-static struct device dev_ppp[PPP_NRUNIT] = {
- {
- "ppp0", /* ppp */
- 0, 0, 0, 0, /* memory */
- 0, 0, /* base, irq */
- 0, 0, 0, NULL, ppp_init,
- }
- , { "ppp1" , 0, 0, 0, 0, 1, 0, 0, 0, 0, NULL, ppp_init }
- , { "ppp2" , 0, 0, 0, 0, 2, 0, 0, 0, 0, NULL, ppp_init }
- , { "ppp3" , 0, 0, 0, 0, 3, 0, 0, 0, 0, NULL, ppp_init }
-
-#ifdef PPP_PPP_LOTS
- , { "ppp4" , 0, 0, 0, 0, 4, 0, 0, 0, 0, NULL, ppp_init }
- , { "ppp5" , 0, 0, 0, 0, 5, 0, 0, 0, 0, NULL, ppp_init }
- , { "ppp6" , 0, 0, 0, 0, 6, 0, 0, 0, 0, NULL, ppp_init }
- , { "ppp7" , 0, 0, 0, 0, 7, 0, 0, 0, 0, NULL, ppp_init }
- , { "ppp8" , 0, 0, 0, 0, 8, 0, 0, 0, 0, NULL, ppp_init }
- , { "ppp9" , 0, 0, 0, 0, 9, 0, 0, 0, 0, NULL, ppp_init }
- , { "ppp10" , 0, 0, 0, 0, 10, 0, 0, 0, 0, NULL, ppp_init }
- , { "ppp11" , 0, 0, 0, 0, 11, 0, 0, 0, 0, NULL, ppp_init }
- , { "ppp12" , 0, 0, 0, 0, 12, 0, 0, 0, 0, NULL, ppp_init }
- , { "ppp13" , 0, 0, 0, 0, 13, 0, 0, 0, 0, NULL, ppp_init }
- , { "ppp14" , 0, 0, 0, 0, 14, 0, 0, 0, 0, NULL, ppp_init }
- , { "ppp15" , 0, 0, 0, 0, 15, 0, 0, 0, 0, NULL, ppp_init }
-#endif
-};
-
int
init_module(void)
{
- int err;
- int i,j;
-
- for (i = 0; i < PPP_NRUNIT; i++) {
- if ((err = register_netdev(&dev_ppp[i]))) {
- if (err == -EEXIST) {
- printk("PPP: devices already present. Module not loaded.\n");
- /* we must unregister already registered units */
- if(i>0) {
- for(j = 0; j < i ; j++)
- unregister_netdev(&dev_ppp[j]);
- if ((j = tty_register_ldisc(N_PPP, NULL))) {
- printk("PPP: can't unregister line discipline (err = %d)\n", j);
- }
- }
- }
- return err;
- }
- }
- return 0;
+ int status;
+
+ /* register our line disciplines */
+ status = ppp_first_time();
+ if (status != 0)
+ printk (KERN_INFO
+ "PPP: ppp_init() failure %d\n", status);
+ return (status);
}
void
cleanup_module(void)
{
- int i;
+ int status;
+ ppp_ctrl_t *ctl, *next_ctl;
+ struct device *dev;
+ struct ppp *ppp;
+ int busy_flag = MOD_IN_USE;
+/*
+ * 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;
+ }
- if (MOD_IN_USE) {
- printk("PPP: device busy, remove delayed\n");
- return;
+ dev = ctl2dev (ctl);
+ if (dev->start || dev->flags & IFF_UP) {
+ busy_flag = 1;
+ break;
+ }
+ ctl = ctl->next;
+ }
}
- for (i = 0; i < PPP_NRUNIT; i++) {
- unregister_netdev(&dev_ppp[i]);
+/*
+ * Ensure that there are no compressor modules registered
+ */
+ if (busy_flag == 0 && ppp_compressors != NULL)
+ busy_flag = 1;
+
+ if (busy_flag) {
+ printk (KERN_INFO
+ "PPP: device busy, remove delayed\n");
+ return;
}
- if ((i = tty_register_ldisc(N_PPP, NULL))) {
- printk("PPP: can't unregister line discipline (err = %d)\n", i);
+/*
+ * Release the tty registration of the line dicipline so that no new entries
+ * may be created.
+ */
+ status = tty_register_ldisc (N_PPP, NULL);
+ if (status != 0)
+ printk (KERN_INFO
+ "PPP: Unable to unregister ppp line discipline "
+ "(err = %d)\n", status);
+ else
+ printk (KERN_INFO
+ "PPP: ppp line discipline successfully unregistered\n");
+/*
+ * Remove the symbol definitions
+ */
+ (void) register_symtab ((struct symbol_table *) 0);
+/*
+ * De-register the devices so that there is no problem with them
+ */
+ 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);
+ kfree (ctl);
}
}
-
#endif
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include "seeq8005.h"
-extern struct device *init_etherdev(struct device *dev, int sizeof_private,
- unsigned long *mem_startp);
/* First, a few definitions that the brave might change. */
/* A zero-terminated list of I/O addresses to be probed. */
/* Allocate a new 'dev' if needed. */
if (dev == NULL)
- dev = init_etherdev(0, sizeof(struct net_local), 0);
+ dev = init_etherdev(0, sizeof(struct net_local));
if (net_debug && version_printed++ == 0)
printk(version);
/* Fill in the fields of the device structure with ethernet values. */
ether_setup(dev);
+
+ dev->flags &= ~IFF_MULTICAST;
return 0;
}
/* Set the generic fields of the device structure */
ether_setup(dev);
+
+ dev->flags &= ~IFF_MULTICAST;
/* Initialize private structure */
* This makes it easier to free the memory when this driver
* is used as a module.
*/
- dev = init_etherdev(0, 0, 0);
+ dev = init_etherdev(0, 0);
if (dev == NULL)
return -ENOMEM;
}
return ENODEV;
if (dev == NULL)
- dev = init_etherdev(0, sizeof(struct ei_device), 0);
+ dev = init_etherdev(0, sizeof(struct ei_device));
if (dev == NULL) /* Still.. */
return ENOMEM; /* Out of memory ?? */
int pad0, pad1; /* Used for 8-byte alignment */
};
-static unsigned long tulip_probe1(unsigned long mem_start, int ioaddr,
- int irq);
+static void tulip_probe1(int ioaddr, int irq);
static int tulip_open(struct device *dev);
static void tulip_init_ring(struct device *dev);
static int tulip_start_xmit(struct sk_buff *skb, struct device *dev);
ourselves. This is done by having the initialization occur before
the 'kmalloc()' memory management system is started. */
-unsigned long dec21040_init(unsigned long mem_start, unsigned long mem_end)
+int dec21040_init(void)
{
if (pcibios_present()) {
if (tulip_debug > 2)
printk("Found DEC PCI Tulip at I/O %#lx, IRQ %d.\n",
pci_ioaddr, pci_irq_line);
- mem_start = tulip_probe1(mem_start, pci_ioaddr, pci_irq_line);
+ tulip_probe1(pci_ioaddr, pci_irq_line);
}
}
- return mem_start;
+ return 0;
}
#endif
#ifdef MODULE
}
#endif
-unsigned long tulip_probe1(unsigned long mem_start, int ioaddr, int irq)
+static void tulip_probe1(int ioaddr, int irq)
{
static int did_version = 0; /* Already printed version info. */
struct device *dev;
if (tulip_debug > 0 && did_version++ == 0)
printk(version);
- dev = init_etherdev(0, sizeof(struct tulip_private)
- + PKT_BUF_SZ*RX_RING_SIZE,
- &mem_start);
+ dev = init_etherdev(0, 0);
printk("%s: DEC 21040 Tulip at %#3x,", dev->name, ioaddr);
dev->irq = irq;
/* Make certain the data structures are quadword aligned. */
- dev->priv = (void *)(((int)dev->priv + 7) & ~7);
- tp = (struct tulip_private *)dev->priv;
- tp->rx_buffs = (long)dev->priv + sizeof(struct tulip_private);
+ tp = kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA);
+ dev->priv = tp;
+ tp->rx_buffs = kmalloc(PKT_BUF_SZ*RX_RING_SIZE, GFP_KERNEL | GFP_DMA);
/* The Tulip-specific entries in the device structure. */
dev->open = &tulip_open;
dev->set_mac_address = &set_mac_address;
#endif
- return mem_start;
+ return;
}
\f
return ENODEV;
if (dev == NULL)
- dev = init_etherdev(0, sizeof(struct ei_device), 0);
+ dev = init_etherdev(0, sizeof(struct ei_device));
printk("%s: WD80x3 at %#3x, ", dev->name, ioaddr);
for (i = 0; i < 6; i++)
{
short ioaddr = dev->base_addr;
- if (num_addrs < 0) {
+ if (num_addrs == -1) {
/* Enable promiscuous mode */
i593_init[7] &= ~3; i593_init[7] |= 1;
i593_init[13] &= ~8; i593_init[13] |= 8;
- } else if (num_addrs > 0) {
+ } else if (num_addrs != 0) {
/* Enable accept-all-multicast mode */
i593_init[7] &= ~3; i593_init[7] |= 0;
i593_init[13] &= ~8; i593_init[13] |= 8;
return 0;
}
-/*
- * These are special functions that can be used to obtain memory at boot time.
- * They act line a malloc function, but they simply take memory from the pool
- */
-
-static unsigned long scsi_init_memory_start = 0;
-static unsigned long scsi_memory_lower_value = 0;
-static unsigned long scsi_memory_upper_value = 0;
-int scsi_loadable_module_flag; /* Set after we scan builtin drivers */
void * scsi_init_malloc(unsigned int size, int priority)
{
- unsigned long retval;
- int order, a_size;
+ void * retval;
- /* Use the statically allocated memory instead of kmalloc (DB) */
-#if defined(USE_STATIC_SCSI_MEMORY)
- if(scsi_loadable_module_flag && !(priority & GFP_DMA))
-#else
- if(scsi_loadable_module_flag)
-#endif
- {
- /*
- * For buffers used by the DMA pool, we assume page aligned
- * structures.
- */
- if ((size % PAGE_SIZE) == 0) {
- for (order = 0, a_size = PAGE_SIZE;
- a_size < size; order++, a_size <<= 1)
- ;
- retval =
- (unsigned long) __get_dma_pages(priority & GFP_LEVEL_MASK,
- order);
- }
- else
- retval = (unsigned long) kmalloc(size, priority);
+ /*
+ * For buffers used by the DMA pool, we assume page aligned
+ * structures.
+ */
+ if ((size % PAGE_SIZE) == 0) {
+ int order, a_size;
+ for (order = 0, a_size = PAGE_SIZE;
+ a_size < size; order++, a_size <<= 1)
+ ;
+ retval = (void *) __get_dma_pages(priority & GFP_LEVEL_MASK,
+ order);
+ } else
+ retval = kmalloc(size, priority);
- } else {
- /*
- * Keep all memory aligned on 16-byte boundaries. Some host
- * adaptors (e.g. BusLogic BT-445S) require DMA buffers to be
- * aligned that way.
- */
- size = (size + 15) & ~15;
-
- if(scsi_loadable_module_flag &&
- (scsi_init_memory_start + size) > scsi_memory_upper_value) {
- retval = 0;
- printk("scsi_init_malloc: no more statically allocated memory.\n");
- }
- else {
- retval = scsi_init_memory_start;
- scsi_init_memory_start += size;
- }
- }
if (retval)
- memset((void *) retval, 0, size);
- return (void *) retval;
+ memset(retval, 0, size);
+ return retval;
}
void scsi_init_free(char * ptr, unsigned int size)
{
- int order, a_size;
+ /*
+ * We need this special code here because the DMA pool assumes
+ * page aligned data. Besides, it is wasteful to allocate
+ * page sized chunks with kmalloc.
+ */
+ if ((size % PAGE_SIZE) == 0) {
+ int order, a_size;
- /* We need to compare addresses to see whether this was kmalloc'd or not */
-
- if((unsigned long) ptr >= scsi_init_memory_start ||
- (unsigned long) ptr < scsi_memory_lower_value) {
- /*
- * We need this special code here because the DMA pool assumes
- * page aligned data. Besides, it is wasteful to allocate
- * page sized chunks with kmalloc.
- */
- if ((size % PAGE_SIZE) == 0) {
- for (order = 0, a_size = PAGE_SIZE;
- a_size < size; order++, a_size <<= 1)
- ;
- free_pages((unsigned long)ptr, order);
- }
- else
- kfree(ptr);
- } else {
- /* Use the same alignment as scsi_init_malloc() */
- size = (size + 15) & ~15;
-
- if(((unsigned long) ptr) + size == scsi_init_memory_start)
- scsi_init_memory_start = (unsigned long) ptr;
- }
+ for (order = 0, a_size = PAGE_SIZE;
+ a_size < size; order++, a_size <<= 1)
+ ;
+ free_pages((unsigned long)ptr, order);
+ } else
+ kfree(ptr);
}
void scsi_build_commandblocks(Scsi_Device * SDpnt)
/*
* scsi_dev_init() is our initialization routine, which in turn calls host
- * initialization, bus scanning, and sd/st initialization routines. It
- * should be called from main().
+ * initialization, bus scanning, and sd/st initialization routines.
*/
-unsigned long scsi_dev_init (unsigned long memory_start, unsigned long memory_end)
+int scsi_dev_init(void)
{
struct Scsi_Host * host = NULL;
Scsi_Device * SDpnt;
/* Yes we're here... */
dispatch_scsi_info_ptr = dispatch_scsi_info;
- /* Init a few things so we can "malloc" memory. */
- scsi_loadable_module_flag = 0;
-
- /* Align everything on 16-byte boundaries. */
- scsi_init_memory_start = (memory_start + 15) & ~ 15;
- scsi_memory_lower_value = scsi_init_memory_start;
-
timer_table[SCSI_TIMER].fn = scsi_main_timeout;
timer_table[SCSI_TIMER].expires = 0;
if (scsi_devicelist)
dma_sectors = 16; /* Base value we use */
- if (memory_end-1 > ISA_DMA_THRESHOLD)
+ if (high_memory-1 > ISA_DMA_THRESHOLD)
scsi_need_isa_bounce_buffers = 1;
else
scsi_need_isa_bounce_buffers = 0;
host->cmd_per_lun;
if(host->unchecked_isa_dma &&
- memory_end - 1 > ISA_DMA_THRESHOLD &&
+ high_memory - 1 > ISA_DMA_THRESHOLD &&
SDpnt->type != TYPE_TAPE) {
dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
host->cmd_per_lun;
for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
if(sdtpnt->finish && sdtpnt->nr_dev)
(*sdtpnt->finish)();
-
- scsi_loadable_module_flag = 1;
-
- /* This allocates statically some extra memory to be used for modules,
- * until the kmalloc problem is fixed (DB)
- */
-
-#if defined(USE_STATIC_SCSI_MEMORY)
- scsi_memory_upper_value = scsi_init_memory_start + 256 * 1024;
- printk ("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
- (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
- (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
- (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
- return scsi_memory_upper_value;
-#else
- return scsi_init_memory_start;
-#endif
+
+ return 0;
}
static void print_inquiry(unsigned char *data)
while (HBA_ptr) {
#if 0
size += sprintf(buffer+len,"scsi%2d: %s\n", (int) HBA_ptr->host_no,
- HBA_ptr->hostt->procname);
+ HBA_ptr->hostt->procname);
len += size;
pos = begin + len;
#endif
if(shpnt->hostt == tpnt) {
if(shpnt->loaded_as_module) {
pcount = next_scsi_host;
- /* Remove the /proc/scsi directory entry */
+ /* Remove the /proc/scsi directory entry */
#if CONFIG_PROC_FS
- proc_scsi_unregister(tpnt->proc_dir,
- shpnt->host_no + PROC_SCSI_FILE);
+ proc_scsi_unregister(tpnt->proc_dir,
+ shpnt->host_no + PROC_SCSI_FILE);
#endif
if(tpnt->release)
(*tpnt->release)(shpnt);
* init function.
*/
if(tpnt->init && tpnt->dev_noticed)
- if ((*tpnt->init)()) return 1;
+ if ((*tpnt->init)()) return 1;
/*
* Now actually connect the devices to the new driver.
* Initializes all SCSI devices. This scans all scsi busses.
*/
-extern unsigned long scsi_dev_init (unsigned long, unsigned long);
+extern int scsi_dev_init (void);
struct scatterlist {
char * address; /* Location data is to be transferred to */
sound_release
};
-long
-soundcard_init (long mem_start)
+int
+soundcard_init (void)
{
#ifndef MODULE
register_chrdev (SOUND_MAJOR, "sound", &sound_fops);
soundcard_configured = 1;
- mem_start = sndtable_init (mem_start); /* Initialize call tables and
- * detect cards */
+ sndtable_init (); /* Initialize call tables and
+ * detect cards */
if (!(soundcards_installed = sndtable_get_cardcount ()))
- return mem_start; /* No cards detected */
+ return 0; /* No cards detected */
#ifndef EXCLUDE_AUDIO
if (num_audiodevs) /* Audio devices present */
{
- mem_start = DMAbuf_init (mem_start);
- mem_start = audio_init (mem_start);
+ DMAbuf_init ();
+ audio_init ();
}
#endif
#ifndef EXCLUDE_MIDI
if (num_midis)
- mem_start = MIDIbuf_init (mem_start);
+ MIDIbuf_init ();
#endif
#ifndef EXCLUDE_SEQUENCER
if (num_midis + num_synths)
- mem_start = sequencer_init (mem_start);
+ sequencer_init ();
#endif
- return mem_start;
+ return 0;
}
#ifdef MODULE
char corefile[6+sizeof(current->comm)];
unsigned long dump_start, dump_size;
struct user dump;
+#ifdef __alpha__
+# define START_DATA(u) (u.start_data)
+#else
+# define START_DATA(u) (u.u_tsize << PAGE_SHIFT)
+#endif
if (!current->dumpable)
return 0;
goto close_coredump;
has_dumped = 1;
strncpy(dump.u_comm, current->comm, sizeof(current->comm));
- dump.u_ar0 = (struct pt_regs *)(((unsigned long)(&dump.regs)) - ((unsigned long)(&dump)));
+ dump.u_ar0 = (void *)(((unsigned long)(&dump.regs)) - ((unsigned long)(&dump)));
dump.signal = signr;
dump_thread(regs, &dump);
/* make sure we actually have a data and stack area to dump */
set_fs(USER_DS);
- if (verify_area(VERIFY_READ, (void *) (dump.u_tsize << PAGE_SHIFT), dump.u_dsize << PAGE_SHIFT))
+ if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize << PAGE_SHIFT))
dump.u_dsize = 0;
if (verify_area(VERIFY_READ, (void *) dump.start_stack, dump.u_ssize << PAGE_SHIFT))
dump.u_ssize = 0;
set_fs(USER_DS);
/* Dump the data area */
if (dump.u_dsize != 0) {
- dump_start = dump.u_tsize << PAGE_SHIFT;
+ dump_start = START_DATA(dump);
dump_size = dump.u_dsize << PAGE_SHIFT;
DUMP_WRITE(dump_start,dump_size);
}
return p;
}
-unsigned long setup_arg_pages(unsigned long text_size,unsigned long * page)
+unsigned long setup_arg_pages(unsigned long text_size, unsigned long * page)
{
- unsigned long code_limit,data_limit,code_base,data_base;
+ unsigned long data_base;
int i;
- code_limit = STACK_TOP;
- data_limit = STACK_TOP;
- code_base = data_base = 0;
- current->mm->start_code = code_base;
- data_base += data_limit;
+ data_base = STACK_TOP;
for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {
data_base -= PAGE_SIZE;
if (page[i]) {
put_dirty_page(current,page[i],data_base);
}
}
- return data_limit;
+ return STACK_TOP;
}
/*
int count1;
char * pnt;
struct user dump;
+#ifdef __i386__
+# define FIRST_MAPPED PAGE_SIZE /* we don't have page 0 mapped on x86.. */
+#else
+# define FIRST_MAPPED 0
+#endif
memset(&dump, 0, sizeof(struct user));
dump.magic = CMAGIC;
dump.u_dsize = MAP_NR(high_memory);
+#ifdef __alpha__
+ dump.start_data = PAGE_OFFSET;
+#endif
if (count < 0)
return -EINVAL;
read += count1;
}
- while (p < 2*PAGE_SIZE && count > 0) {
+ while (count > 0 && p < PAGE_SIZE + FIRST_MAPPED) {
put_user(0,buf);
buf++;
p++;
count--;
read++;
}
- memcpy_tofs(buf,(void *) (PAGE_OFFSET + p - PAGE_SIZE),count);
+ memcpy_tofs(buf, (void *) (PAGE_OFFSET + p - PAGE_SIZE), count);
read += count;
file->f_pos += read;
return read;
--- /dev/null
+#ifndef __reg_h__
+#define __reg_h__
+
+/*
+ * Exception frame offsets.
+ */
+#define EF_V0 0
+#define EF_T0 1
+#define EF_T1 2
+#define EF_T2 3
+#define EF_T3 4
+#define EF_T4 5
+#define EF_T5 6
+#define EF_T6 7
+#define EF_T7 8
+#define EF_S0 9
+#define EF_S1 10
+#define EF_S2 11
+#define EF_S3 12
+#define EF_S4 13
+#define EF_S5 14
+#define EF_S6 15
+#define EF_A3 16
+#define EF_A4 17
+#define EF_A5 18
+#define EF_T8 19
+#define EF_T9 20
+#define EF_T10 21
+#define EF_T11 22
+#define EF_RA 23
+#define EF_T12 24
+#define EF_AT 25
+#define EF_SP 26
+#define EF_PS 27
+#define EF_PC 28
+#define EF_GP 29
+#define EF_A0 30
+#define EF_A1 31
+#define EF_A2 32
+
+#define EF_SIZE (33*8)
+#define HWEF_SIZE (6*8) /* size of PAL frame (PS-A2) */
+
+#define EF_SSIZE (EF_SIZE - HWEF_SIZE)
+
+/*
+ * Map register number into core file offset.
+ */
+#define CORE_REG(reg, ubase) \
+ (((unsigned long *)((unsigned long)(ubase)))[reg])
+
+#endif /* __reg_h__ */
#define SIGUSR2 31
#define SIGPOLL SIGIO
+#define SIGPWR SIGINFO
+#define SIGIOT SIGABRT
/*
* sa_flags values: SA_STACK is not currently supported, but will allow the
--- /dev/null
+#ifndef _ALPHA_USER_H
+#define _ALPHA_USER_H
+
+#include <linux/ptrace.h>
+
+#include <asm/page.h>
+#include <asm/reg.h>
+
+/*
+ * Core file format: The core file is written in such a way that gdb
+ * can understand it and provide useful information to the user (under
+ * linux we use the `trad-core' bfd, NOT the osf-core). The file contents
+ * are as follows:
+ *
+ * upage: 1 page consisting of a user struct that tells gdb
+ * what is present in the file. Directly after this is a
+ * copy of the task_struct, which is currently not used by gdb,
+ * but it may come in handy at some point. All of the registers
+ * are stored as part of the upage. The upage should always be
+ * only one page long.
+ * data: The data segment follows next. We use current->end_text to
+ * current->brk to pick up all of the user variables, plus any memory
+ * that may have been sbrk'ed. No attempt is made to determine if a
+ * page is demand-zero or if a page is totally unused, we just cover
+ * the entire range. All of the addresses are rounded in such a way
+ * that an integral number of pages is written.
+ * stack: We need the stack information in order to get a meaningful
+ * backtrace. We need to write the data from usp to
+ * current->start_stack, so we round each of these in order to be able
+ * to write an integer number of pages.
+ */
+struct user {
+ unsigned long regs[EF_SIZE/8+32]; /* integer and fp regs */
+ size_t u_tsize; /* text size (pages) */
+ size_t u_dsize; /* data size (pages) */
+ size_t u_ssize; /* stack size (pages) */
+ unsigned long start_code; /* text starting address */
+ unsigned long start_data; /* data starting address */
+ unsigned long start_stack; /* stack starting address */
+ long int signal; /* signal causing core dump */
+ struct regs * u_ar0; /* help gdb find registers */
+ unsigned long magic; /* identifies a core file */
+ char u_comm[32]; /* user command name */
+};
+
+#define NBPG PAGE_SIZE
+#define UPAGES 1
+#define HOST_TEXT_START_ADDR (u.start_code)
+#define HOST_DATA_START_ADDR (u.start_data)
+#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
+
+#endif /* _ALPHA_USER_H */
}
/*
- * These are depracated..
+ * These are deprecated..
*/
static inline unsigned char get_user_byte(const char * addr)
return waitpid(-1,wait_stat,0);
}
+/*
+ * This is the mechanism for creating a new kernel thread.
+ *
+ * NOTE! Only a kernel-only process(ie the swapper or direct descendants
+ * who haven't done an "execve()") should use this: it will work within
+ * a system call from a "real" process, but the process memory space will
+ * not be free'd until both the parent and the child have exited.
+ */
+static inline pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+ long retval;
+
+ __asm__ __volatile__(
+ "int $0x80\n\t" /* Linux/i386 system call */
+ "testl %0,%0\n\t" /* child or parent? */
+ "jne 1f\n\t" /* parent - jump */
+ "pushl %3\n\t" /* push argument */
+ "call *%4\n\t" /* call fn */
+ "movl %2,%0\n\t" /* exit */
+ "int $0x80\n"
+ "1:\t"
+ :"=a" (retval)
+ :"0" (__NR_clone), "i" (__NR_exit),
+ "r" (arg), "r" (fn),
+ "b" (flags | CLONE_VM));
+ return retval;
+}
+
#endif
#endif /* _ASM_I386_UNISTD_H_ */
--- /dev/null
+#ifndef _I386_USER_H
+#define _I386_USER_H
+
+#include <asm/page.h>
+#include <linux/ptrace.h>
+/* Core file format: The core file is written in such a way that gdb
+ can understand it and provide useful information to the user (under
+ linux we use the 'trad-core' bfd). There are quite a number of
+ obstacles to being able to view the contents of the floating point
+ registers, and until these are solved you will not be able to view the
+ contents of them. Actually, you can read in the core file and look at
+ the contents of the user struct to find out what the floating point
+ registers contain.
+ The actual file contents are as follows:
+ UPAGE: 1 page consisting of a user struct that tells gdb what is present
+ in the file. Directly after this is a copy of the task_struct, which
+ is currently not used by gdb, but it may come in useful at some point.
+ All of the registers are stored as part of the upage. The upage should
+ always be only one page.
+ DATA: The data area is stored. We use current->end_text to
+ current->brk to pick up all of the user variables, plus any memory
+ that may have been malloced. No attempt is made to determine if a page
+ is demand-zero or if a page is totally unused, we just cover the entire
+ range. All of the addresses are rounded in such a way that an integral
+ number of pages is written.
+ STACK: We need the stack information in order to get a meaningful
+ backtrace. We need to write the data from (esp) to
+ current->start_stack, so we round each of these off in order to be able
+ to write an integer number of pages.
+ The minimum core file size is 3 pages, or 12288 bytes.
+*/
+
+struct user_i387_struct {
+ long cwd;
+ long swd;
+ long twd;
+ long fip;
+ long fcs;
+ long foo;
+ long fos;
+ long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
+};
+
+/* When the kernel dumps core, it starts by dumping the user struct -
+ this will be used by gdb to figure out where the data and stack segments
+ are within the file, and what virtual addresses to use. */
+struct user{
+/* We start with the registers, to mimic the way that "memory" is returned
+ from the ptrace(3,...) function. */
+ struct pt_regs regs; /* Where the registers are actually stored */
+/* ptrace does not yet supply these. Someday.... */
+ int u_fpvalid; /* True if math co-processor being used. */
+ /* for this mess. Not yet used. */
+ struct user_i387_struct i387; /* Math Co-processor registers. */
+/* The rest of this junk is to help gdb figure out what goes where */
+ unsigned long int u_tsize; /* Text segment size (pages). */
+ unsigned long int u_dsize; /* Data segment size (pages). */
+ unsigned long int u_ssize; /* Stack segment size (pages). */
+ unsigned long start_code; /* Starting virtual address of text. */
+ unsigned long start_stack; /* Starting virtual address of stack area.
+ This is actually the bottom of the stack,
+ the top of the stack is always found in the
+ esp register. */
+ long int signal; /* Signal that caused the core dump. */
+ int reserved; /* No longer used */
+ struct pt_regs * u_ar0; /* Used by gdb to help find the values for */
+ /* the registers. */
+ struct user_i387_struct* u_fpstate; /* Math Co-processor pointer. */
+ unsigned long magic; /* To uniquely identify a core file */
+ char u_comm[32]; /* User command that was responsible */
+ int u_debugreg[8];
+};
+#define NBPG PAGE_SIZE
+#define UPAGES 1
+#define HOST_TEXT_START_ADDR (u.start_code)
+#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
+
+#endif /* _I386_USER_H */
extern void eth_header_cache(struct device *dev, struct sock *sk, unsigned long saddr, unsigned long daddr);
extern void eth_copy_and_sum(struct sk_buff *dest,
unsigned char *src, int length, int base);
-extern struct device * init_etherdev(struct device *, int, unsigned long*);
+extern struct device * init_etherdev(struct device *, int);
#endif
#ifdef __alpha__
#define CONFIG_OSF_PARTITION 1
#endif
-
-#define EXTENDED_PARTITION 5
+
+/* These two have identical behaviour; use the second one if DOS fdisk gets
+ confused about extended/logical partitions starting past cylinder 1023. */
+#define DOS_EXTENDED_PARTITION 5
+#define LINUX_EXTENDED_PARTITION 0x85
#define DM6_PARTITION 0x54 /* has DDO: use xlated geom & offset */
#define EZD_PARTITION 0x55 /* EZ-DRIVE: same as DM6 (we think) */
struct gendisk *next;
};
-extern int NR_GENDISKS; /* total */
extern struct gendisk *gendisk_head; /* linked list of disks */
#endif
-#ifndef _LINUX_IF_PPP_H
-#define _LINUX_IF_PPP_H
-
-/* definitions for kernel PPP module
- Michael Callahan <callahan@maths.ox.ac.uk>
- Nov. 4 1993 */
-
-/* how many PPP units? */
-#ifdef CONFIG_PPP_LOTS
-#define PPP_NRUNIT 16
-#else
-#define PPP_NRUNIT 4
-#endif
+/* $Id: if_ppp.h,v 1.3 1995/06/12 11:36:50 paulus Exp $ */
+
+/*
+ * if_ppp.h - Point-to-Point 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.
+ *
+ */
+
+/*
+ * ==FILEVERSION 3==
+ *
+ * NOTE TO MAINTAINERS:
+ * 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.
+ */
+
+#ifndef _IF_PPP_H_
+#define _IF_PPP_H_
+
+/*
+ * Packet sizes
+ */
+
+#define PPP_MTU 1500 /* Default MTU (size of Info field) */
+#define PPP_MAXMRU 65000 /* Largest MRU we allow */
+#define PPP_VERSION "2.2.0"
+#define PPP_MAGIC 0x5002 /* Magic value for the ppp structure */
+#define PROTO_IPX 0x002b /* protocol numbers */
+
+/*
+ * Bit definitions for flags.
+ */
-#define PPP_VERSION "0.2.7"
-
-/* line discipline number */
-#define N_PPP 3
-
-/* Magic value for the ppp structure */
-#define PPP_MAGIC 0x5002
-
-#define PPPIOCGFLAGS 0x5490 /* get configuration flags */
-#define PPPIOCSFLAGS 0x5491 /* set configuration flags */
-#define PPPIOCGASYNCMAP 0x5492 /* get async map */
-#define PPPIOCSASYNCMAP 0x5493 /* set async map */
-#define PPPIOCGUNIT 0x5494 /* get ppp unit number */
-#define PPPIOCSINPSIG 0x5495 /* set input ready signal */
-#define PPPIOCSDEBUG 0x5497 /* set debug level */
-#define PPPIOCGDEBUG 0x5498 /* get debug level */
-#define PPPIOCGSTAT 0x5499 /* read PPP statistic information */
-#define PPPIOCGTIME 0x549A /* read time delta information */
-#define PPPIOCGXASYNCMAP 0x549B /* get async table */
-#define PPPIOCSXASYNCMAP 0x549C /* set async table */
-#define PPPIOCSMRU 0x549D /* set receive unit size for PPP */
-#define PPPIOCRASYNCMAP 0x549E /* set receive async map */
-#define PPPIOCSMAXCID 0x549F /* set the maximum compression slot id */
-
-/* special characters in the framing protocol */
-#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */
-#define PPP_UI 0x03 /* Unnumbered Information */
-#define PPP_FLAG 0x7E /* frame delimiter -- marks frame boundaries */
-#define PPP_ADDRESS 0xFF /* first character of frame <-- (may be */
-#define PPP_CONTROL 0x03 /* second character of frame <-- compressed)*/
-#define PPP_TRANS 0x20 /* Asynchronous transparency modifier */
-#define PPP_ESC 0x7d /* escape character -- next character is
- data, and the PPP_TRANS bit should be
- toggled. PPP_ESC PPP_FLAG is illegal */
-
-/* protocol numbers */
-#define PROTO_IP 0x0021
-#define PROTO_VJCOMP 0x002d
-#define PROTO_VJUNCOMP 0x002f
-
-/* FCS support */
-#define PPP_FCS_INIT 0xffff
-#define PPP_FCS_GOOD 0xf0b8
-
-/* initial MTU */
-#define PPP_MTU 1500
-
-/* initial MRU */
-#define PPP_MRU PPP_MTU
-
-/* flags */
#define SC_COMP_PROT 0x00000001 /* protocol compression (output) */
#define SC_COMP_AC 0x00000002 /* header compression (output) */
#define SC_COMP_TCP 0x00000004 /* TCP (VJ) compression (output) */
#define SC_NO_TCP_CCID 0x00000008 /* disable VJ connection-id comp. */
#define SC_REJ_COMP_AC 0x00000010 /* reject adrs/ctrl comp. on input */
#define SC_REJ_COMP_TCP 0x00000020 /* reject TCP (VJ) comp. on input */
+#define SC_CCP_OPEN 0x00000040 /* Look at CCP packets */
+#define SC_CCP_UP 0x00000080 /* May send/recv compressed packets */
#define SC_ENABLE_IP 0x00000100 /* IP packets may be exchanged */
-#define SC_IP_DOWN 0x00000200 /* give ip frames to pppd */
-#define SC_IP_FLUSH 0x00000400 /* "next time" flag for IP_DOWN */
+#define SC_COMP_RUN 0x00001000 /* compressor has been inited */
+#define SC_DECOMP_RUN 0x00002000 /* decompressor has been inited */
#define SC_DEBUG 0x00010000 /* enable debug messages */
#define SC_LOG_INPKT 0x00020000 /* log contents of good pkts recvd */
#define SC_LOG_OUTPKT 0x00040000 /* log contents of pkts sent */
#define SC_LOG_RAWIN 0x00080000 /* log all chars received */
#define SC_LOG_FLUSH 0x00100000 /* log all chars flushed */
+#define SC_MASK 0x0fE0ffff /* bits that user can change */
-/* Flag bits to determine state of input characters */
-#define SC_RCV_B7_0 0x01000000 /* have rcvd char with bit 7 = 0 */
-#define SC_RCV_B7_1 0x02000000 /* have rcvd char with bit 7 = 0 */
-#define SC_RCV_EVNP 0x04000000 /* have rcvd char with even parity */
-#define SC_RCV_ODDP 0x08000000 /* have rcvd char with odd parity */
-
-#define SC_MASK 0x0fffffff /* bits that user can change */
-
-/* flag for doing transmitter lockout */
+/* state bits */
+#define SC_ESCAPED 0x80000000 /* saw a PPP_ESCAPE */
+#define SC_FLUSH 0x40000000 /* flush input until next PPP_FLAG */
+#define SC_VJ_RESET 0x20000000 /* Need to reset the VJ decompressor */
#define SC_XMIT_BUSY 0x10000000 /* ppp_write_wakeup is active */
+#define SC_RCV_ODDP 0x08000000 /* have rcvd char with odd parity */
+#define SC_RCV_EVNP 0x04000000 /* have rcvd char with even parity */
+#define SC_RCV_B7_1 0x02000000 /* have rcvd char with bit 7 = 1 */
+#define SC_RCV_B7_0 0x01000000 /* have rcvd char with bit 7 = 0 */
+#define SC_DC_FERROR 0x00800000 /* fatal decomp error detected */
+#define SC_DC_ERROR 0x00400000 /* non-fatal decomp error detected */
/*
- * This is the format of the data buffer of a LQP packet. The packet data
- * is sent/received to the peer.
- */
-
-struct ppp_lqp_packet_hdr {
- __u32 LastOutLQRs; /* Copied from PeerOutLQRs */
- __u32 LastOutPackets; /* Copied from PeerOutPackets */
- __u32 LastOutOctets; /* Copied from PeerOutOctets */
- __u32 PeerInLQRs; /* Copied from SavedInLQRs */
- __u32 PeerInPackets; /* Copied from SavedInPackets */
- __u32 PeerInDiscards; /* Copied from SavedInDiscards */
- __u32 PeerInErrors; /* Copied from SavedInErrors */
- __u32 PeerInOctets; /* Copied from SavedInOctets */
- __u32 PeerOutLQRs; /* Copied from OutLQRs, plus 1 */
- __u32 PeerOutPackets; /* Current ifOutUniPackets, + 1 */
- __u32 PeerOutOctets; /* Current ifOutOctets + LQR */
- };
-
-/*
- * This data is not sent to the remote. It is updated by the driver when
- * a packet is received.
+ * Ioctl definitions.
*/
-struct ppp_lqp_packet_trailer {
- __u32 SaveInLQRs; /* Current InLQRs on reception */
- __u32 SaveInPackets; /* Current ifInUniPackets */
- __u32 SaveInDiscards; /* Current ifInDiscards */
- __u32 SaveInErrors; /* Current ifInErrors */
- __u32 SaveInOctets; /* Current ifInOctects */
+struct npioctl {
+ int protocol; /* PPP procotol, e.g. PPP_IP */
+ enum NPmode mode;
};
-/*
- * PPP LQP packet. The packet is changed by the driver immediately prior
- * to transmission and updated upon reception with the current values.
- * So, it must be known to the driver as well as the pppd software.
- */
-
-struct ppp_lpq_packet {
- __u32 magic; /* current magic value */
- struct ppp_lqp_packet_hdr hdr; /* Header fields for structure */
- struct ppp_lqp_packet_trailer tail; /* Trailer fields (not sent) */
+/* Structure describing a CCP configuration option, for PPPIOCSCOMPRESS */
+struct ppp_option_data {
+ u_char *ptr;
+ u_int length;
+ int transmit;
};
-/*
- * PPP interface statistics. (used by LQP / pppstats)
- */
-
-struct ppp_stats {
- __u32 rbytes; /* bytes received */
- __u32 rcomp; /* compressed packets received */
- __u32 runcomp; /* uncompressed packets received */
- __u32 rothers; /* non-ip frames received */
- __u32 rerrors; /* received errors */
- __u32 roverrun; /* "buffer overrun" counter */
- __u32 tossed; /* packets discarded */
- __u32 runts; /* frames too short to process */
- __u32 rgiants; /* frames too large to process */
- __u32 sbytes; /* bytes sent */
- __u32 scomp; /* compressed packets sent */
- __u32 suncomp; /* uncompressed packets sent */
- __u32 sothers; /* non-ip frames sent */
- __u32 serrors; /* transmitter errors */
- __u32 sbusy; /* "transmitter busy" counter */
+struct ifpppstatsreq {
+ struct ifreq b;
+ struct ppp_stats stats; /* statistic information */
};
-/*
- * Demand dial fields
- */
-
-struct ppp_ddinfo {
- unsigned long ip_sjiffies; /* time when last IP frame sent */
- unsigned long ip_rjiffies; /* time when last IP frame recvd*/
- unsigned long nip_sjiffies; /* time when last NON-IP sent */
- unsigned long nip_rjiffies; /* time when last NON-IP recvd */
+struct ifpppcstatsreq {
+ struct ifreq b;
+ struct ppp_comp_stats stats;
};
-#ifdef __KERNEL__
-
-struct ppp {
- int magic; /* magic value for structure */
-
- /* Bitmapped flag fields. */
- char sending; /* "channel busy" indicator */
- char escape; /* 0x20 if prev char was PPP_ESC*/
- char toss; /* toss this frame */
- unsigned long inuse; /* are we allocated? */
-
- unsigned int flags; /* miscellany */
-
- __u32 xmit_async_map[8]; /* 1 bit means that given control
- character is quoted on output*/
-
- __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 */
- unsigned short fcs; /* FCS field of current frame */
-
- /* Various fields. */
- int line; /* PPP channel number */
- struct tty_struct *tty; /* ptr to TTY structure */
- struct device *dev; /* easy for intr handling */
- struct slcompress *slcomp; /* for header compression */
- unsigned long 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
- has to hang around for the user process to read it, it lingers in
- the user buffers below. */
- unsigned char *rbuff; /* receiver buffer */
- unsigned char *xbuff; /* transmitter buffer */
- unsigned char *cbuff; /* compression buffer */
-
- /* These are the various pointers into the buffers. */
- unsigned char *rhead; /* RECV buffer pointer (head) */
- unsigned char *rend; /* RECV buffer pointer (end) */
- int rcount; /* PPP receive counter */
- unsigned char *xhead; /* XMIT buffer pointer (head) */
- unsigned char *xtail; /* XMIT buffer pointer (end) */
-
- /* Structures for interfacing with the user process. */
-#define RBUFSIZE 4000
- unsigned char *us_rbuff; /* circular incoming packet buf.*/
- unsigned char *us_rbuff_end; /* end of allocated space */
- unsigned char *us_rbuff_head; /* head of waiting packets */
- unsigned char *us_rbuff_tail; /* tail of waiting packets */
- unsigned long us_rbuff_lock; /* lock: bit 0 head bit 1 tail */
- int inp_sig; /* input ready signal for pgrp */
- int inp_sig_pid; /* process to get notified */
-
- /* items to support the select() function */
- struct wait_queue *write_wait; /* queue for reading processes */
- struct wait_queue *read_wait; /* queue for writing processes */
-
- /* PPP interface statistics. */
- struct ppp_stats stats; /* statistic information */
-
- /* PPP demand dial information. */
- struct ppp_ddinfo ddinfo; /* demand dial information */
-};
+#define ifr__name b.ifr_ifrn.ifrn_name
+#define stats_ptr b.ifr_ifru.ifru_data
-#endif /* __KERNEL__ */
-#endif /* _LINUX_PPP_H */
+/*
+ * Ioctl definitions.
+ */
+#define PPPIOCGFLAGS _IOR('t', 90, int) /* get configuration flags */
+#define PPPIOCSFLAGS _IOW('t', 89, int) /* set configuration flags */
+#define PPPIOCGASYNCMAP _IOR('t', 88, int) /* get async map */
+#define PPPIOCSASYNCMAP _IOW('t', 87, int) /* set async map */
+#define PPPIOCGUNIT _IOR('t', 86, int) /* get ppp unit number */
+#define PPPIOCGRASYNCMAP _IOR('t', 85, int) /* get receive async map */
+#define PPPIOCSRASYNCMAP _IOW('t', 84, int) /* set receive async map */
+#define PPPIOCGMRU _IOR('t', 83, int) /* get max receive unit */
+#define PPPIOCSMRU _IOW('t', 82, int) /* set max receive unit */
+#define PPPIOCSMAXCID _IOW('t', 81, int) /* set VJ max slot ID */
+#define PPPIOCGXASYNCMAP _IOR('t', 80, ext_accm) /* get extended ACCM */
+#define PPPIOCSXASYNCMAP _IOW('t', 79, ext_accm) /* set extended ACCM */
+#define PPPIOCXFERUNIT _IO('t', 78) /* transfer PPP unit */
+#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 PPPIOCGIDLE _IOR('t', 63, struct ppp_idle) /* get idle time */
+
+#define SIOCGPPPSTATS (SIOCDEVPRIVATE + 0)
+#define SIOCGPPPVER (SIOCDEVPRIVATE + 1) /* NEVER change this!! */
+#define SIOCGPPPCSTATS (SIOCDEVPRIVATE + 2)
+
+#if !defined(ifr_mtu)
+#define ifr_mtu ifr_ifru.ifru_metric
+#endif
+#endif /* _IF_PPP_H_ */
--- /dev/null
+/* $Id: if_pppvar.h,v 1.2 1995/06/12 11:36:51 paulus Exp $ */
+/*
+ * if_pppvar.h - private structures and declarations for PPP.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+/*
+ * ==FILEVERSION 3==
+ *
+ * NOTE TO MAINTAINERS:
+ * 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.
+ */
+
+/*
+ * Supported network protocols. These values are used for
+ * indexing sc_npmode.
+ */
+
+#define NP_IP 0 /* Internet Protocol */
+#define NUM_NP 1 /* Number of NPs. */
+
+/*
+ * Buffers for the PPP process have the following structure
+ */
+
+#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 */
+ 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 */
+#define buf_base(buf) ((u_char *) (&buf[1]))
+
+/*
+ * Structure describing each ppp unit.
+ */
+
+struct ppp {
+ int magic; /* magic value for structure */
+
+ /* Bitmapped flag fields. */
+ char inuse; /* are we allocated? */
+ char escape; /* 0x20 if prev char was PPP_ESC*/
+ char toss; /* toss this frame */
+
+ unsigned int flags; /* miscellany */
+
+ ext_accm xmit_async_map; /* 1 bit means that given control
+ character is quoted on output*/
+
+ __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 */
+
+ /* Information about the current tty data */
+ int line; /* PPP channel number */
+ struct tty_struct *tty; /* ptr to TTY structure */
+ int bytes_sent; /* Bytes sent on frame */
+ int bytes_rcvd; /* Bytes recvd on frame */
+
+ /* Interface to the network layer */
+ struct device *dev; /* easy for intr handling */
+
+ /* VJ Header compression data */
+ struct slcompress *slcomp;/* for header compression */
+
+ /* Transmission information */
+ struct ppp_buffer *xbuf; /* Buffer currently being sent */
+ struct ppp_buffer *s1buf; /* Pointer to daemon buffer */
+ struct ppp_buffer *s2buf; /* Pointer to device buffer */
+
+ __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
+ has to hang around for the user process to read it, it lingers in
+ the user buffers below. */
+
+ struct ppp_buffer *wbuf; /* Transmission information */
+ struct ppp_buffer *tbuf; /* daemon transmission buffer */
+ struct ppp_buffer *rbuf; /* Receive information */
+ struct ppp_buffer *ubuf; /* User buffer information */
+ struct ppp_buffer *cbuf; /* compression buffer */
+
+ /* Queues for select() functionality */
+ struct wait_queue *write_wait; /* queue for reading processes */
+ struct wait_queue *read_wait; /* queue for writing processes */
+
+ /* Statistic 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 */
+ u_int sc_bytesrcvd; /* count of octets received */
+ enum NPmode sc_npmode[NUM_NP]; /* what to do with each NP */
+ struct compressor *sc_xcomp; /* transmit compressor */
+ void *sc_xc_state; /* transmit compressor state */
+ struct compressor *sc_rcomp; /* receive decompressor */
+ void *sc_rc_state; /* receive decompressor state */
+};
struct timer_list timer; /* Expiration timer */
__u16 protocol; /* Which protocol are we talking? */
__u32 src, dst; /* Source and destination IP addresses */
- __u16 sport,dport; /* Source and destoination ports */
+ __u16 sport,dport; /* Source and destination ports */
__u16 mport; /* Masquaraded port */
__u32 init_seq; /* Add delta from this seq. on */
short delta; /* Delta in sequence numbers */
+ short previous_delta; /* Delta in sequence numbers before last resized PORT command */
char sawfin; /* Did we saw an FIN packet? */
};
extern struct ip_masq *ip_msq_hosts;
#define PORT_MASQ_BEGIN 60000
#define PORT_MASQ_END (PORT_MASQ_BEGIN+4096)
+#define FTP_DPORT_TBD (PORT_MASQ_END+1) /* Avoid using hardcoded port 20 for ftp data connection */
#endif
#endif /* _IP_FW_H */
#define KT_META 8
#define KT_ASCII 9
#define KT_LOCK 10
+#define KT_SLOCK 12
#define K(t,v) (((t)<<8)|(v))
#define KTYP(x) ((x) >> 8)
#define K_CTRLLLOCK K(KT_LOCK,KG_CTRLL)
#define K_CTRLRLOCK K(KT_LOCK,KG_CTRLR)
+#define K_SHIFT_SLOCK K(KT_SLOCK,KG_SHIFT)
+#define K_CTRL_SLOCK K(KT_SLOCK,KG_CTRL)
+#define K_ALT_SLOCK K(KT_SLOCK,KG_ALT)
+#define K_ALTGR_SLOCK K(KT_SLOCK,KG_ALTGR)
+#define K_SHIFTL_SLOCK K(KT_SLOCK,KG_SHIFTL)
+#define K_SHIFTR_SLOCK K(KT_SLOCK,KG_SHIFTR)
+#define K_CTRLL_SLOCK K(KT_SLOCK,KG_CTRLL)
+#define K_CTRLR_SLOCK K(KT_SLOCK,KG_CTRLR)
+
#define NR_LOCK 8
#define MAX_DIACR 256
* function prototypes
*/
-extern long lp_init(long);
+extern int lp_init(void);
#endif
int Using_Versions; /* gcc will handle this global (used as a flag) correctly */
#endif
+#ifdef MODULE
#define MOD_INC_USE_COUNT mod_use_count_++
#define MOD_DEC_USE_COUNT mod_use_count_--
#define MOD_IN_USE (mod_use_count_ != 0)
+#else
+#define MOD_INC_USE_COUNT do { } while (0)
+#define MOD_DEC_USE_COUNT do { } while (0)
+#define MOD_IN_USE 1
+#endif
#endif
#define MS_BUSMOUSE_MINOR 2
#define ATIXL_BUSMOUSE_MINOR 3
-unsigned long mouse_init(unsigned long);
+extern int mouse_init(void);
struct mouse {
int minor;
--- /dev/null
+/*
+ * 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.7 1995/05/01 01:43:37 paulus Exp $
+ */
+
+/*
+ * ==FILEVERSION 3==
+ *
+ * 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 */
--- /dev/null
+/* $Id: ppp_defs.h,v 1.2 1994/09/21 01:31:06 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 4==
+ *
+ * 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_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_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_ */
* 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, <waltje@uWalt.NL.Mugnet.ORG>
*
* This program is free software; you can redistribute it and/or
/* This structure gets passed by the SIOCADDRT and SIOCDELRT calls. */
-struct rtentry {
+struct rtentry
+{
unsigned long rt_hash; /* hash key for lookups */
struct sockaddr rt_dst; /* target address */
struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */
#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 */
+
/* global functions */
-extern long scc_init(long kmem_start);
+extern int scc_init(void);
#define CLONE_FS 0x00000200 /* set if fs info shared between processes */
#define CLONE_FILES 0x00000400 /* set if open files shared between processes */
#define CLONE_SIGHAND 0x00000800 /* set if signal handlers shared */
+#define CLONE_PID 0x00001000 /* set if pid shared */
/*
* These are the constant used to fake the fixed-point load-average
};
-extern long qic02_tape_init(long); /* for mem.c */
+extern int qic02_tape_init(void); /* for mem.c */
#endif /* CONFIG_QIC02_TAPE */
extern int fg_console;
extern struct wait_queue * keypress_wait;
-extern long rs_init(long);
-extern long lp_init(long);
-extern long con_init(long);
-extern long pty_init(long);
-extern long tty_init(long);
-extern long vcs_init(long);
+extern unsigned long con_init(unsigned long);
+
+extern int rs_init(void);
+extern int lp_init(void);
+extern int pty_init(void);
+extern int tty_init(void);
+extern int vcs_init(void);
#ifdef CONFIG_CYCLADES
-extern long cy_init(long);
+extern int cy_init(void);
#endif
#ifdef CONFIG_STALLION
-extern long stl_init(long);
+extern int stl_init(void);
#endif
#ifdef CONFIG_ISTALLION
-extern long stli_init(long);
+extern int stli_init(void);
#endif
extern int tty_paranoia_check(struct tty_struct *tty, kdev_t device,
-#ifndef _LINUX_USER_H
-#define _LINUX_USER_H
-
-#include <asm/page.h>
-#include <linux/ptrace.h>
-/* Core file format: The core file is written in such a way that gdb
- can understand it and provide useful information to the user (under
- linux we use the 'trad-core' bfd). There are quite a number of
- obstacles to being able to view the contents of the floating point
- registers, and until these are solved you will not be able to view the
- contents of them. Actually, you can read in the core file and look at
- the contents of the user struct to find out what the floating point
- registers contain.
- The actual file contents are as follows:
- UPAGE: 1 page consisting of a user struct that tells gdb what is present
- in the file. Directly after this is a copy of the task_struct, which
- is currently not used by gdb, but it may come in useful at some point.
- All of the registers are stored as part of the upage. The upage should
- always be only one page.
- DATA: The data area is stored. We use current->end_text to
- current->brk to pick up all of the user variables, plus any memory
- that may have been malloced. No attempt is made to determine if a page
- is demand-zero or if a page is totally unused, we just cover the entire
- range. All of the addresses are rounded in such a way that an integral
- number of pages is written.
- STACK: We need the stack information in order to get a meaningful
- backtrace. We need to write the data from (esp) to
- current->start_stack, so we round each of these off in order to be able
- to write an integer number of pages.
- The minimum core file size is 3 pages, or 12288 bytes.
-*/
-
-struct user_i387_struct {
- long cwd;
- long swd;
- long twd;
- long fip;
- long fcs;
- long foo;
- long fos;
- long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
-};
-
-/* When the kernel dumps core, it starts by dumping the user struct -
- this will be used by gdb to figure out where the data and stack segments
- are within the file, and what virtual addresses to use. */
-struct user{
-/* We start with the registers, to mimic the way that "memory" is returned
- from the ptrace(3,...) function. */
- struct pt_regs regs; /* Where the registers are actually stored */
-/* ptrace does not yet supply these. Someday.... */
- int u_fpvalid; /* True if math co-processor being used. */
- /* for this mess. Not yet used. */
- struct user_i387_struct i387; /* Math Co-processor registers. */
-/* The rest of this junk is to help gdb figure out what goes where */
- unsigned long int u_tsize; /* Text segment size (pages). */
- unsigned long int u_dsize; /* Data segment size (pages). */
- unsigned long int u_ssize; /* Stack segment size (pages). */
- unsigned long start_code; /* Starting virtual address of text. */
- unsigned long start_stack; /* Starting virtual address of stack area.
- This is actually the bottom of the stack,
- the top of the stack is always found in the
- esp register. */
- long int signal; /* Signal that caused the core dump. */
- int reserved; /* No longer used */
- struct pt_regs * u_ar0; /* Used by gdb to help find the values for */
- /* the registers. */
- struct user_i387_struct* u_fpstate; /* Math Co-processor pointer. */
- unsigned long magic; /* To uniquely identify a core file */
- char u_comm[32]; /* User command that was responsible */
- int u_debugreg[8];
-};
-#define NBPG PAGE_SIZE
-#define UPAGES 1
-#define HOST_TEXT_START_ADDR (u.start_code)
-#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
-
-#endif
+#include <asm/user.h>
+#ifndef __NET_NETLINK_H
+#define __NET_NETLINK_H
#define NET_MAJOR 18 /* Major 18 is reserved for networking */
#define MAX_LINKS 3 /* 18,0 for route updates, 18,1 for SKIP */
#define MAX_QBYTES 32768 /* Maximum bytes in the queue */
extern int netlink_attach(int unit, int (*function)(struct sk_buff *skb));
+extern int netlink_donothing(struct sk_buff *skb);
extern void netlink_detach(int unit);
extern int netlink_post(int unit, struct sk_buff *skb);
extern void init_netlink(void);
#define NETLINK_ROUTE 0 /* Routing/device hook */
#define NETLINK_SKIP 1 /* Reserved for ENskip */
#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */
+#define NETLINK_FIREWALL 3 /* Firewalling hook */
+#ifdef CONFIG_RTNETLINK
+extern void ip_netlink_msg(unsigned long, __u32, __u32, __u32, short, short, char *);
+#else
+#define ip_netlink_msg(a,b,c,d,e,f,g)
+#endif
+#endif
extern int console_loglevel;
-extern void init(void);
+static int init(void *);
+
extern void init_IRQ(void);
extern void init_modules(void);
extern long console_init(long, long);
extern long kmalloc_init(long,long);
-extern long blk_dev_init(long,long);
-extern long chr_dev_init(long,long);
extern void sock_init(void);
extern long rd_init(long mem_start, int length);
-unsigned long net_dev_init(unsigned long, unsigned long);
extern long pci_init(long, long);
extern void bmouse_setup(char *str, int *ints);
#ifdef CONFIG_SJCD
extern void sjcd_setup(char *str, int *ints);
#endif CONFIG_SJCD
-void ramdisk_setup(char *str, int *ints);
+static void ramdisk_setup(char *str, int *ints);
#ifdef CONFIG_SYSVIPC
extern void ipc_init(void);
#endif
-#ifdef CONFIG_SCSI
-extern unsigned long scsi_dev_init(unsigned long, unsigned long);
-#endif
/*
* Boot command-line arguments
{ 0, 0 }
};
-void ramdisk_setup(char *str, int *ints)
+static void ramdisk_setup(char *str, int *ints)
{
if (ints[0] > 0 && ints[1] >= 0)
ramdisk_size = ints[1];
extern void setup_arch(char **, unsigned long *, unsigned long *);
-static char init_stack[PAGE_SIZE];
-
#ifdef CONFIG_SMP
/*
* Activate a secondary processor.
idle();
}
+int smp_idle(void * unused)
+{
+ for (;;)
+ idle();
+}
+
/*
* Called by CPU#0 to activate the rest.
*/
smp_boot_cpus();
/*
- * Create the slave init tasks. At this point
- * fork will create them all ask task 0
+ * Create the slave init tasks as sharing pid 0.
*/
for(i=1;i<smp_num_cpus;i++)
{
- fork();
- /* We are forking multiple process 0's. This makes it harder
- to tell them apart than we would like ;) */
- if(current!=task[0])
- {
- for(;;)
- idle();
- }
+ kernel_thread(smp_idle, NULL, CLONE_PID);
/*
* Assume linear processor numbering
*/
memory_start = kmalloc_init(memory_start,memory_end);
sti();
calibrate_delay();
- memory_start = chr_dev_init(memory_start,memory_end);
- memory_start = blk_dev_init(memory_start,memory_end);
- sti();
-#ifdef CONFIG_SCSI
- memory_start = scsi_dev_init(memory_start,memory_end);
-#endif
-#ifdef CONFIG_INET
- memory_start = net_dev_init(memory_start,memory_end);
-#endif
memory_start = inode_init(memory_start,memory_end);
memory_start = file_table_init(memory_start,memory_end);
memory_start = name_cache_init(memory_start,memory_end);
+ if (ramdisk_size)
+ memory_start += rd_init(memory_start, ramdisk_size*1024);
mem_init(memory_start,memory_end);
buffer_init();
sock_init();
#ifdef CONFIG_SMP
smp_init();
#endif
- /* we count on the clone going ok */
- if (!clone(CLONE_VM, init_stack+sizeof(init_stack)))
- init();
+ /* we count on the initial thread going ok */
+ kernel_thread(init, NULL, 0);
/*
* task[0] is meant to be used as an "idle" task: it may not sleep, but
* it might do some general things like count free pages or it could be
return i;
}
-void init(void)
+static int do_shell(void * input)
+{
+ close(0);
+ if (open("/etc/rc",O_RDONLY,0))
+ return -1;
+ return execve("/bin/sh",argv_rc,envp_rc);
+}
+
+static int init(void * unused)
{
int pid,i;
execve("/sbin/init",argv_init,envp_init);
/* if this fails, fall through to original stuff */
- if (!(pid=fork())) {
- close(0);
- if (open("/etc/rc",O_RDONLY,0))
- _exit(1);
- execve("/bin/sh",argv_rc,envp_rc);
- _exit(2);
- }
+ pid = kernel_thread(do_shell, "/etc/rc", 0);
if (pid>0)
while (pid != wait(&i))
/* nothing */;
printf("\n\rchild %d died with code %04x\n\r",pid,i);
sync();
}
- _exit(0);
+ return -1;
}
int nr_tasks=1;
int nr_running=1;
-long last_pid=0;
static int find_empty_process(void)
{
int i;
- int this_user_tasks;
struct task_struct *p;
if (nr_tasks >= NR_TASKS - MIN_TASKS_LEFT_FOR_ROOT) {
if (current->uid)
return -EAGAIN;
}
-repeat:
- if(smp_threads_ready) {
- if ((++last_pid) & 0xffff8000)
- last_pid=1;
- }
- this_user_tasks = 0;
- for_each_task (p) {
- if (p->uid == current->uid)
- this_user_tasks++;
- if (smp_threads_ready && (p->pid == last_pid ||
- p->pgrp == last_pid ||
- p->session == last_pid))
- goto repeat;
+ if (current->uid) {
+ long max_tasks = current->rlim[RLIMIT_NPROC].rlim_cur;
+
+ if (max_tasks < nr_tasks) {
+ for_each_task (p) {
+ if (p->uid == current->uid)
+ if (--max_tasks < 0)
+ return -EAGAIN;
+ }
+ }
}
- if (this_user_tasks > current->rlim[RLIMIT_NPROC].rlim_cur)
- if (current->uid)
- return -EAGAIN;
for (i = 0 ; i < NR_TASKS ; i++) {
if (!task[i])
return i;
return -EAGAIN;
}
+static int get_pid(unsigned long flags)
+{
+ static int last_pid = 0;
+ struct task_struct *p;
+
+ if (flags & CLONE_PID)
+ return current->pid;
+repeat:
+ if ((++last_pid) & 0xffff8000)
+ last_pid=1;
+ for_each_task (p) {
+ if (p->pid == last_pid ||
+ p->pgrp == last_pid ||
+ p->session == last_pid)
+ goto repeat;
+ }
+ return last_pid;
+}
+
static int dup_mmap(struct mm_struct * mm)
{
struct vm_area_struct * mpnt, **p, *tmp;
*(unsigned long *) p->kernel_stack_page = STACK_MAGIC;
p->state = TASK_UNINTERRUPTIBLE;
p->flags &= ~(PF_PTRACED|PF_TRACESYS);
- p->pid = last_pid;
+ p->pid = get_pid(clone_flags);
p->next_run = NULL;
p->prev_run = NULL;
p->p_pptr = p->p_opptr = current;
X(unregister_netdev),
X(ether_setup),
X(eth_type_trans),
+ X(eth_copy_and_sum),
X(alloc_skb),
X(kfree_skb),
X(dev_alloc_skb),
o IFF_ALLMULTI support for 3c501,3c509,8390 and
tulip(SMC etherpower) boards [IN]
+-------->>>>> 1.3.33 <<<<<<--------
+
+o IFF_ALLMULTI causes an address check on ether [IN]
+o Added multicast ability readme file [IN]
+o Assorted driver/multicast fixes [IN]
+o IP routing change errors resemble BSD more [IN]
+o IP port masquerading fixes [IN]
---------- Things I thought Linus had for a while and not merged ----------------
/*
* Initialise multicasting status
*/
-#ifdef CONFIG_IP_MULTICAST
- /*
- * Join the all host group
- */
- ip_mc_allhost(dev);
-#endif
dev_mc_upload(dev);
notifier_call_chain(&netdev_chain, NETDEV_UP, dev);
}
save_flags(flags);
cli();
- if (/*dev_nit && */!where) /* Always keep order. It helps other hosts
+ if (!where) /* Always keep order. It helps other hosts
far more than it costs us */
{
skb_queue_tail(dev->buffs + pri,skb);
* present) and leaves us with a valid list of present and active devices.
*
*/
-
-void dev_init(void)
+extern int lance_init(void);
+extern int pi_init(void);
+extern int dec21040_init(void);
+
+int net_dev_init(void)
{
struct device *dev, **dp;
+ /*
+ * This is VeryUgly(tm).
+ *
+ * Some devices want to be initialized eary..
+ */
+#if defined(CONFIG_LANCE)
+ lance_init();
+#endif
+#if defined(CONFIG_PI)
+ pi_init();
+#endif
+#if defined(CONFIG_DEC_ELCP)
+ dec21040_init();
+#endif
+
/*
* Add the devices.
* If the call to dev->init fails, the dev is removed
dp = &dev->next;
}
}
+
proc_net_register(&(struct proc_dir_entry) {
PROC_NET_DEV, 3, "dev",
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_net_inode_operations,
dev_get_info
});
+
+ bh_base[NET_BH].routine = net_bh;
+ enable_bh(NET_BH);
+ return 0;
}
* Greg Page : 802.2 and SNAP stuff.
* Alan Cox : MAC layer pointers/new format.
* Paul Gortmaker : eth_copy_and_sum shouldn't csum padding.
+ * Alan Cox : Protect against forwarding explosions with
+ * older network drivers and IFF_ALLMULTI
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
skb->pkt_type=PACKET_MULTICAST;
}
- else if(dev->flags&IFF_PROMISC)
+ /*
+ * This ALLMULTI check should be redundant by 1.4
+ * so don't forget to remove it.
+ */
+
+ else if(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))
{
if(memcmp(eth->h_dest,dev->dev_addr, ETH_ALEN))
skb->pkt_type=PACKET_OTHERHOST;
#if defined(CONFIG_IP_MROUTE)
ip_mr_init();
#endif
+
/*
* Create all the /proc entries.
*/
for (dev = dev_base; dev != NULL; dev = dev->next)
{
- if (!(dev->flags & IFF_UP))
+ if ((!(dev->flags & IFF_UP)) || dev->family!=AF_INET)
continue;
/*
* If the protocol address of the device is 0 this is special
* and means we are address hunting (eg bootp).
*/
- if ((dev->pa_addr == 0)/* || (dev->flags&IFF_PROMISC)*/)
+ if (dev->pa_addr == 0)
return IS_MYADDR;
/*
* Is it the exact IP address?
#include <linux/igmp.h>
#include <linux/ip_fw.h>
#include <linux/mroute.h>
+#include <net/netlink.h>
#define CONFIG_IP_DEFRAG
* If this fragment needs masquerading, make it so...
* (Dont masquerade de-masqueraded fragments)
*/
- if (!(is_frag&4) && fw_res==2)
+ if (!(is_frag&4) && fw_res==FW_MASQUERADE)
ip_fw_masquerade(&skb, dev2);
#endif
IS_SKB(skb);
NULL,
};
+#ifdef CONFIG_RTNETLINK
+
+/*
+ * Netlink hooks for IP
+ */
+
+void ip_netlink_msg(unsigned long msg, __u32 daddr, __u32 gw, __u32 mask, short flags, short metric, char *name)
+{
+ struct sk_buff *skb=alloc_skb(sizeof(struct netlink_rtinfo), GFP_ATOMIC);
+ struct netlink_rtinfo *nrt;
+ struct sockaddr_in *s;
+ if(skb==NULL)
+ return;
+ nrt=(struct netlink_rtinfo *)skb_put(skb, sizeof(struct netlink_rtinfo));
+ nrt->rtmsg_type=msg;
+ s=(struct sockaddr_in *)&nrt->rtmsg_dst;
+ s->sin_family=AF_INET;
+ s->sin_addr.s_addr=daddr;
+ s=(struct sockaddr_in *)&nrt->rtmsg_gateway;
+ s->sin_family=AF_INET;
+ s->sin_addr.s_addr=gw;
+ s=(struct sockaddr_in *)&nrt->rtmsg_genmask;
+ s->sin_family=AF_INET;
+ s->sin_addr.s_addr=mask;
+ nrt->rtmsg_flags=flags;
+ nrt->rtmsg_metric=metric;
+ strcpy(nrt->rtmsg_device,name);
+ netlink_post(NETLINK_ROUTE, skb);
+}
+
+#endif
+
/*
* Device notifier
*/
static int ip_rt_event(unsigned long event, void *ptr)
{
+ struct device *dev=ptr;
if(event==NETDEV_DOWN)
- ip_rt_flush(ptr);
+ {
+ ip_netlink_msg(RTMSG_DELDEVICE, 0,0,0,0,0,dev->name);
+ ip_rt_flush(dev);
+ }
+/*
+ * Join the intial group if multicast.
+ */
+ if(event==NETDEV_UP)
+ {
+#ifdef CONFIG_IP_MULTICAST
+ ip_mc_allhost(dev);
+#endif
+ ip_netlink_msg(RTMSG_NEWDEVICE, 0,0,0,0,0,dev->name);
+ }
return NOTIFY_DONE;
}
* Thomas Quinot : Fixed port spoofing.
* Alan Cox : Cleaned up retransmits in spoofing.
* Alan Cox : Cleaned up length setting.
+ * Wouter Gadeyne : Fixed masquerading support of ftp PORT commands
*
* All the real work was done by .....
*
struct ip_masq *ms;
char buf[24]; /* xxx.xxx.xxx.xxx,ppp,ppp\000 */
int diff;
+ __u32 seq;
/*
- * Adjust seq and ack_seq with delta-offset for
- * the packets AFTER this one...
+ * Adjust seq with delta-offset for all packets after the most recent resized PORT command
+ * and with previous_delta offset for all packets before most recent resized PORT
*/
- if (ftp->delta && after(ftp->init_seq,th->seq))
+
+ /*
+ * seq & seq_ack are in network byte order; need conversion before comparing
+ */
+ seq=ntohl(th->seq);
+ if (ftp->delta || ftp->previous_delta)
{
- th->seq += ftp->delta;
-/* th->ack_seq += ftp->delta;*/
+ if(after(seq,ftp->init_seq) )
+ {
+ th->seq = htonl(seq + ftp->delta);
+#ifdef DEBUG_MASQ
+ printk("masq_revamp : added delta (%d) to seq\n",ftp->delta);
+#endif
+ }
+ else
+ {
+ th->seq = htonl(seq + ftp->previous_delta);
+#ifdef DEBUG_MASQ
+ printk("masq_revamp : added previous_delta (%d) to seq\n",ftp->previous_delta);
+#endif
+ }
}
while (skb->len - ((unsigned char *)data - skb->h.raw) > 18)
from = (p1<<24) | (p2<<16) | (p3<<8) | p4;
port = (p5<<8) | p6;
+#ifdef MASQ_DEBUG
printk("PORT %lX:%X detected\n",from,port);
-
+#endif
/*
* Now create an masquerade entry for it
*/
ms->src = htonl(from); /* derived from PORT cmd */
ms->sport = htons(port); /* derived from PORT cmd */
ms->dst = iph->daddr;
- ms->dport = htons(20); /* ftp-data */
+ /*
+ * Hardcoding 20 as dport is not always correct
+ * At least 1 Windows ftpd uses a random port number instead of 20
+ * Leave it undefined for now & wait for the first connection request to fill it out
+ */
+ ms->dport = htons(FTP_DPORT_TBD); /* ftp-data */
ms->timer.expires = jiffies+MASQUERADE_EXPIRE_TCP_FIN;
add_timer(&ms->timer);
/*
* simple case, just replace the old PORT cmd
*/
- ftp->init_seq = 0;
memcpy(p,buf,strlen(buf));
return skb;
}
* FIXME: use ftp->init_seq_valid - 0 is a valid sequence.
*/
- if(!ftp->init_seq || after(ftp->init_seq,th->seq))
+ if(!ftp->init_seq || after(seq,ftp->init_seq) )
+ {
+ ftp->previous_delta=ftp->delta;
ftp->delta+=diff;
+ ftp->init_seq = seq;
+ }
+
/*
* Sizes differ, make a copy
*/
- printk("MASQUERADE: resizing needed for %d bytes (%ld)\n",ftp->delta, skb->len);
- if (!ftp->init_seq)
- ftp->init_seq = th->seq;
-
- skb2 = alloc_skb(MAX_HEADER + skb->len+ftp->delta, GFP_ATOMIC);
+#ifdef DEBUG_MASQ
+ printk("MASQUERADE: resizing needed for %d bytes (%ld)\n",diff, skb->len);
+#endif
+ skb2 = alloc_skb(MAX_HEADER + skb->len+diff, GFP_ATOMIC);
if (skb2 == NULL) {
printk("MASQUERADE: No memory available\n");
return skb;
}
skb2->free = skb->free;
skb_reserve(skb2,MAX_HEADER);
- skb_put(skb2,skb->len + ftp->delta);
-/* skb2->h.raw = &skb2->data[skb->h.raw - skb->data];*/
+ skb_put(skb2,skb->len + diff);
skb2->h.raw = skb2->data + (skb->h.raw - skb->data);
iph=skb2->h.iph;
/*
memcpy(&skb2->data[(p - (char *)skb->data) + strlen(buf)], data,
skb->len - (data-(char *)skb->data));
+ /*
+ * Update tot_len field in ip header !
+ * Sequence numbers were allready modified in original packet
+ */
+ iph->tot_len = htons(skb->len + diff);
+
/*
* Problem, how to replace the new skb with old one,
* preferably inplace, so all the pointers in the
ntohl(iph->saddr), ntohs(portptr[0]),
ntohl(iph->daddr), ntohs(portptr[1]));
#endif
+
/*
* reroute to original host:port if found...
*
{
if (iph->protocol==ms->protocol &&
(iph->saddr==ms->dst || iph->protocol==IPPROTO_UDP) &&
- portptr[0]==ms->dport &&
+ (ms->dport==htons(FTP_DPORT_TBD) || portptr[0]==ms->dport) &&
portptr[1]==ms->mport)
{
+
int size = skb_ptr->len - ((unsigned char *)portptr - skb_ptr->h.raw);
iph->daddr = ms->src;
portptr[1] = ms->sport;
+ if(ms->dport==htons(FTP_DPORT_TBD))
+ {
+ ms->dport=portptr[0];
+#ifdef DEBUG_MASQ
+ printk("demasq : Filled out dport entry (%d) based on initial connect attempt from FTP deamon\n",ntohs(ms->dport));
+#endif
+ }
+
/*
* Yug! adjust UDP/TCP and IP checksums
*/
recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size);
else
{
+ __u32 ack_seq;
/*
- * Adjust seq and ack_seq with delta-offset for
- * the packets AFTER this one...
+ * Adjust ack_seq with delta-offset for
+ * the packets AFTER most recent PORT command has caused a shift
+ * for packets before most recent PORT command, use previous_delta
*/
- if (ms->delta && after(ms->init_seq,th->ack_seq))
+#ifdef DEBUG_MASQ
+ printk("demasq : delta=%d ; previous_delta=%d ; init_seq=%lX ; ack_seq=%lX ; after=%d\n",ms->delta,ms->previous_delta,ntohl(ms->init_seq),ntohl(th->ack_seq),after(ntohl(th->ack_seq),ntohl(ms->init_seq)));
+#endif
+ ack_seq=ntohl(th->ack_seq);
+ if (ms->delta || ms->previous_delta)
{
-/* th->seq += ms->delta;*/
- th->ack_seq -= ms->delta;
+ if(after(ack_seq,ms->init_seq))
+ {
+ th->ack_seq = htonl(ack_seq-ms->delta);
+#ifdef DEBUG_MASQ
+ printk("demasq : substracted delta (%d) from ack_seq\n",ms->delta);
+#endif
+ }
+ else
+ {
+ th->ack_seq = htonl(ack_seq-ms->previous_delta);
+#ifdef DEBUG_MASQ
+ printk("demasq : substracted previous_delta (%d) from ack_seq\n",ms->previous_delta);
+#endif
+ }
}
tcp_send_check((struct tcphdr *)portptr,iph->saddr,iph->daddr,size,skb_ptr->sk);
}
unsigned long flags;
int len=0;
- len=sprintf(buffer,"Prc FromIP FPrt ToIP TPrt Masq Init-seq Delta Expires\n");
+ len=sprintf(buffer,"Prc FromIP FPrt ToIP TPrt Masq Init-seq Delta PDelta Expires\n");
save_flags(flags);
cli();
int timer_active = del_timer(&ms->timer);
if (!timer_active)
ms->timer.expires = jiffies;
- len+=sprintf(buffer+len,"%s %08lX:%04X %08lX:%04X %04X %08X %5d %lu\n",
+ len+=sprintf(buffer+len,"%s %08lX:%04X %08lX:%04X %04X %08X %5d %5d %lu\n",
strProt[ms->protocol==IPPROTO_TCP],
ntohl(ms->src),ntohs(ms->sport),
ntohl(ms->dst),ntohs(ms->dport),
ntohs(ms->mport),
- ms->init_seq,ms->delta,ms->timer.expires-jiffies);
+ ms->init_seq,ms->delta,ms->previous_delta,ms->timer.expires-jiffies);
if (timer_active)
add_timer(&ms->timer);
* Cache manager under test. Forwarding in vague test mode
* Todo:
* Flow control
- * Tunnels
- * Wipe cache on mrouted exit
+ * Finish Tunnels
* Debug cache ttl handling properly
- * Resolve IFF_ALLMULTI for most cards
+ * Resolve IFF_ALLMULTI for rest of cards
*/
#include <asm/system.h>
void ip_mr_init(void)
{
- printk("Linux IP multicast router 0.02pre-working 8)\n");
+ printk("Linux IP multicast router 0.04-might-work 8)\n");
register_netdevice_notifier(&ip_mr_notifier);
proc_net_register(&(struct proc_dir_entry) {
PROC_NET_IPMR_VIF, 9 ,"ip_mr_vif",
* Miquel van Smoorenburg : BSD API fixes.
* Miquel van Smoorenburg : Metrics.
* Alan Cox : Use __u32 properly
+ * Alan Cox : Aligned routing errors more closely with BSD
+ * our system is still very different.
+ * Alan Cox : Faster /proc handling
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
#include <linux/skbuff.h>
#include <net/sock.h>
#include <net/icmp.h>
+#include <net/netlink.h>
/*
* The routing table list
/*
* Remove a routing table entry.
- * Should we return a status value here ?
*/
-static void rt_del(__u32 dst, __u32 mask,
+static int rt_del(__u32 dst, __u32 mask,
char *devname, __u32 gtw, short rt_flags, short metric)
{
struct rtable *r, **rp;
unsigned long flags;
+ int found=0;
rp = &rt_base;
if (rt_loopback == r)
rt_loopback = NULL;
+ ip_netlink_msg(RTMSG_DELROUTE, dst, gtw, mask, rt_flags, metric, r->rt_dev->name);
kfree_s(r, sizeof(struct rtable));
+ found=1;
}
rt_stamp++; /* New table revision */
restore_flags(flags);
+
+ if(found)
+ return 0;
+ return -ESRCH;
}
*rp = r->rt_next;
if (rt_loopback == r)
rt_loopback = NULL;
+ ip_netlink_msg(RTMSG_DELROUTE, dst,gw, mask, flags, metric, rt->rt_dev->name);
kfree_s(r, sizeof(struct rtable));
}
/*
* Restore the interrupts and return
*/
-
+
restore_flags(cpuflags);
+ ip_netlink_msg(RTMSG_NEWROUTE, dst,gw, mask, flags, metric, rt->rt_dev->name);
return;
}
dev = dev_get(devname);
putname(devname);
if (!dev)
- return -EINVAL;
+ return -ENODEV;
}
/*
* metric can become negative here if it wasn't filled in
* but that's a fortunate accident; we really use that in rt_del.
*/
- rt_del((__u32)trg->sin_addr.s_addr, (__u32)msk->sin_addr.s_addr, devname,
+ err=rt_del((__u32)trg->sin_addr.s_addr, (__u32)msk->sin_addr.s_addr, devname,
(__u32)gtw->sin_addr.s_addr, r->rt_flags, r->rt_metric - 1);
if ( devname != NULL )
putname(devname);
- return 0;
+ return err;
}
/*
* Called from the PROCfs module. This outputs /proc/net/route.
+ *
+ * We preserve the old format but pad the buffers out. This means that
+ * we can spin over the other entries as we read them. Remember the
+ * gated BGP4 code could need to read 60,000+ routes on occasion (thats
+ * about 7Mb of data). To do that ok we will need to also cache the
+ * last route we got to (reads will generally be following on from
+ * one another without gaps).
*/
int rt_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
int len=0;
off_t pos=0;
off_t begin=0;
- int size;
+ char temp[129];
- len += sprintf(buffer,
- "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU\tWindow\tIRTT\n");
- pos=len;
-
- /*
- * This isn't quite right -- r->rt_dst is a struct!
- */
-
+ if(offset<128)
+ {
+ sprintf(buffer,"%-127s\n","Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU\tWindow\tIRTT");
+ pos=128;
+ }
+
for (r = rt_base; r != NULL; r = r->rt_next)
{
- size = sprintf(buffer+len, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\t%08lX\t%d\t%lu\t%u\n",
+ /*
+ * Spin through entries until we are ready
+ */
+ if(pos+128<offset)
+ {
+ pos+=128;
+ continue;
+ }
+
+ sprintf(temp, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\t%08lX\t%d\t%lu\t%u",
r->rt_dev->name, (unsigned long)r->rt_dst, (unsigned long)r->rt_gateway,
r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric,
(unsigned long)r->rt_mask, (int)r->rt_mss, r->rt_window, (int)r->rt_irtt);
- len+=size;
- pos+=size;
+ sprintf(buffer+len,"%-127s\n",temp);
+ len+=128;
+ pos+=128;
if(pos<offset)
{
len=0;
kfree_skb(skb, FREE_READ);
return -EUNATCH;
}
-
+
+/*
+ * Exported do nothing receiver for one way
+ * interfaces.
+ */
+
+int netlink_donothing(struct sk_buff *skb)
+{
+ kfree_skb(skb, FREE_READ);
+ return -EINVAL;
+}
+
/*
* Write a message to the kernel side of a communication link
*/
int netlink_post(int unit, struct sk_buff *skb)
{
unsigned long flags;
- int ret;
- save_flags(flags);
- cli();
- if(rdq_size[unit]+skb->len>MAX_QBYTES)
- ret=-EWOULDBLOCK;
- else
+ int ret=0;
+ if(open_map&(1<<unit))
{
- skb_queue_tail(&skb_queue_rd[unit], skb);
- rdq_size[unit]+=skb->len;
- ret=0;
- wake_up_interruptible(&read_space_wait[MAX_LINKS]);
+ save_flags(flags);
+ cli();
+ if(rdq_size[unit]+skb->len>MAX_QBYTES)
+ ret=-EWOULDBLOCK;
+ else
+ {
+ skb_queue_tail(&skb_queue_rd[unit], skb);
+ rdq_size[unit]+=skb->len;
+ ret=0;
+ wake_up_interruptible(&read_space_wait[unit]);
+ }
+ restore_flags(flags);
}
- restore_flags(flags);
return ret;
}
int init_module(void)
{
int ct;
- printk("Network Kernel/User communications module 0.01 ALPHA\n");
+ printk("Network Kernel/User communications module 0.03\n");
if (register_chrdev(NET_MAJOR,"netlink",&netlink_fops)) {
printk("netlink: unable to get major %d\n", NET_MAJOR);
return -EIO;
#ifdef CONFIG_NETLINK
init_netlink();
#endif
-
/*
- * Initialize the protocols module.
+ * Attach the routing/device information port.
*/
- proto_init();
-
-#ifdef CONFIG_NET
- /*
- * Initialize the DEV module.
- */
+#if defined(CONFIG_RTNETLINK)
+ netlink_attach(NETLINK_ROUTE, netlink_donothing);
+#endif
- dev_init();
-
/*
- * And the bottom half handler
+ * Initialize the protocols module.
*/
- bh_base[NET_BH].routine= net_bh;
- enable_bh(NET_BH);
-#endif
+ proto_init();
}
int socket_get_info(char *buffer, char **start, off_t offset, int length)