Commit e25f5340 authored by Linus Torvalds's avatar Linus Torvalds

[PATCH] Linux-0.98 (September 29, 1992)

Real networking (TCP) merged! This is the now-called "net-1" code by
Ross Biro.  Boy, was it ugly, but it made for a big jump from not having
any at all.

(And add support for up the 32MB of memory ;)

[Original announcement below]

Sorry for being late - I can't even show any great new features in 0.98,
but at least it's out now, and available at the normal place (ie at
nic.funet.fi, pub/OS/Linux/testing/Linus).  So far there is only a
full-source version available, although I'll probably make it available
as a patch too tomorrow or so (but the patch won't contain the tcp/ip
stuff).

0.98 is essentially the same as 0.97.pl6 - the changes are mostly:
 - tcp/ip (0.8.1) is in.  It's not compiled into the standard bootimage,
   and you'd better be on the tcpip mailing-list to use it, but it's
   there. I've been unable to test it further than just watch it
   compile...
 - extfs patch to correct the problem with big directories with holes.
 - mouse patches (ie improved detection-routines)
 - minor scsi patches (ultrastor driver change)
 - swiss keyboard
 - some serial driver patches
 - the 32mb patches are in, so if you aren't using a DMA-SCSI driver,
   and have more than 16MB physical memory, you can get it recognized.
 - edited hd.c
 - corrected core-dumping routines

I didn't get my mm patches working yet, so they'll have to wait.  The
above are almost 100% by others - I have edited some of the patches, but
there is nothing major new by me.  Most of it is minor bug-fixes, and
the only thing that might be a bit of a problem are the hd.c changes:
but I hope they'll solve more problems than they cause.  Knock wood.

At nic.funet.fi you can currently find (a) the full sources (b) a
bootimage (US keyboard, floppy root, no tcp/ip) and (c) the protocols.h
file needed for compiling the tcp/ip directory (which should go into
/usr/include/netinet/).  I hope people try it out, and that there are no
new problems with this release.

                Linus
parent d9723f6c
......@@ -4,14 +4,14 @@
# default of FLOPPY is used by 'build'.
#
ROOT_DEV = /dev/hdb1
ROOT_DEV =# /dev/hdb1
#
# uncomment this if you want kernel profiling: the profile_shift is the
# granularity of the profiling (5 = 32-byte granularity)
#
PROFILING = -DPROFILE_SHIFT=2
PROFILING =# -DPROFILE_SHIFT=2
#
# uncomment the correct keyboard:
......@@ -30,9 +30,9 @@ PROFILING = -DPROFILE_SHIFT=2
# 0x08 - tilde (~)
# 0x10 - dieresis (umlaut)
KEYBOARD = -DKBD_FINNISH -DKBDFLAGS=0
# KEYBOARD = -DKBD_FINNISH -DKBDFLAGS=0
# KEYBOARD = -DKBD_FINNISH_LATIN1 -DKBDFLAGS=0x9F
# KEYBOARD = -DKBD_US -DKBDFLAGS=0
KEYBOARD = -DKBD_US -DKBDFLAGS=0
# KEYBOARD = -DKBD_GR -DKBDFLAGS=0
# KEYBOARD = -DKBD_GR_LATIN1 -DKBDFLAGS=0x9F
# KEYBOARD = -DKBD_FR -DKBDFLAGS=0
......@@ -43,6 +43,8 @@ KEYBOARD = -DKBD_FINNISH -DKBDFLAGS=0
# KEYBOARD = -DKBD_DVORAK -DKBDFLAGS=0
# KEYBOARD = -DKBD_SG -DKBDFLAGS=0
# KEYBOARD = -DKBD_SG_LATIN1 -DKBDFLAGS=0x9F
# KEYBOARD = -DKBD_SF -DKBDFLAGS=0
# KEYBOARD = -DKBD_SF_LATIN1 -DKBDFLAGS=0x9F
# KEYBOARD = -DKDB_NO
#
......@@ -51,11 +53,24 @@ KEYBOARD = -DKBD_FINNISH -DKBDFLAGS=0
MATH_EMULATION = -DKERNEL_MATH_EMULATION
#
# Maximum memory used by the kernel. This is normally 16MB - some of the
# SCSI drivers may have problems with anything else due to DMA limits. The
# drivers should check, but they don't. The ONLY valid values for
# MAX_MEGABYTES are 16 and 32 - anything else needs kernel diffs.
#
# EVEN IF YOU HAVE > 16MB, YOU SHOULD EDIT THIS ONLY IF YOU ARE 100%
# SURE YOU AREN'T USING ANY DEVICE THAT DOES UNCHECKED DMA!! THE
# FLOPPY DRIVER IS OK, BUT OTHERS MIGHT HAVE PROBLEMS.
#
MAX_MEGABYTES = 16
#
# standard CFLAGS
#
CFLAGS =-Wall -O6 -fomit-frame-pointer
CFLAGS =-Wall -O6 -fomit-frame-pointer -DMAX_MEGABYTES=$(MAX_MEGABYTES)
#
# if you want the ram-disk device, define this to be the
......@@ -80,7 +95,7 @@ LD =ld
HOSTCC =gcc -static
CC =gcc -DKERNEL
MAKE =make
CPP =$(CC) -E
CPP =$(CC) -E -DMAX_MEGABYTES=$(MAX_MEGABYTES)
AR =ar
ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o net/net.o
......@@ -112,7 +127,7 @@ linuxsubdirs: dummy
Version:
@./makever.sh
@echo \#define UTS_RELEASE \"0.97.pl6-`cat .version`\" > tools/version.h
@echo \#define UTS_RELEASE \"0.98-`cat .version`\" > tools/version.h
@echo \#define UTS_VERSION \"`date +%D`\" >> tools/version.h
@echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> tools/version.h
@echo \#define LINUX_COMPILE_BY \"`whoami`\" >> tools/version.h
......@@ -134,6 +149,9 @@ tools/build: tools/build.c
boot/head.o: boot/head.s
boot/head.s: boot/head.S
$(CPP) -traditional boot/head.S -o boot/head.s
tools/version.o: tools/version.c tools/version.h
init/main.o: init/main.c
......@@ -173,7 +191,7 @@ kernel: dummy
clean:
rm -f Image System.map tmp_make core boot/bootsect boot/setup \
boot/bootsect.s boot/setup.s init/main.s
boot/bootsect.s boot/setup.s boot/head.s init/main.s
rm -f init/*.o tools/system tools/build boot/*.o tools/*.o
for i in $(SUBDIRS); do (cd $$i && $(MAKE) clean); done
......
......@@ -72,10 +72,24 @@ want to include these in the kernel, do the following:
- remove the corresponding lines in the initialization of
file_systems in fs/super.c.
5. To configure more ptys do this:
- change NR_PTYS in include/linux/tty.h to the number you want
- create the new files in /dev
- recompile the kernel
5. The TCP/IP code is in the standard sources as of version 0.98, but
it is not compiled into the normal binary. To get TCP/IP working, you
have to:
- edit 'net/Makefile', defining the SUBDIRS and SOCK_FLAGS
variables correctly (currently commented out). Likewise, you
have to edit the rule for linking net.o in the Makefile (again
removing a '#' to make tcp/tcpip.o active)
- make sure you have the /usr/include/netinet/protocols.h header
file. If you don't have it, you should be able to find it at
the same place you got the kernel, or with a newer compiler
version.
- remove all object (*.o) files in the net/ subdirectory, making
sure that they are recompiled with the correct Makefile
definitions.
- Additionally, you obviously need the tcp/ip programs to make any
use of the kernel feature. If you haven't joined the TCP/IP
mailing list, do so.
* Running make
......@@ -105,7 +119,8 @@ copy. This requires dd.
"make dep" updates all dependencies. This requires sed. It modifies
the makefiles directly (the end of them, starting at the ###Dependencies
-line at the end).
-line at the end). "make dep" is required after patching, or the kernel
may not compile cleanly.
"make clean" will remove all object files and other files created by the
compilation. This requires basename.
......@@ -120,4 +135,4 @@ The tee part is so that you can check what is going on while the
compilation runs. If you have GNU emacs and use M-x compile you don't
need this, of course.
Lars Wirzeniu
Lars Wirzenius
......@@ -4,6 +4,10 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*/
#if (MAX_MEGABYTES != 16) && (MAX_MEGABYTES != 32)
#error "MAX_MEGABYTES must be 16 or 32"
#endif
/*
* head.s contains the 32-bit startup code.
*
......@@ -114,6 +118,8 @@ rp_sidt:
* I put the kernel page tables right after the page directory,
* using 4 of them to span 16 Mb of physical memory. People with
* more than 16MB will have to expand this.
* When MAX_MEGABYTES == 32, this is set up for a maximum of 32 MB
* (ref: 17Apr92) (redone for 0.97 kernel changes, 1Aug92, ref)
*/
.org 0x1000
pg0:
......@@ -128,6 +134,20 @@ pg2:
pg3:
.org 0x5000
#if MAX_MEGABYTES == 32
pg4:
.org 0x6000
pg5:
.org 0x7000
pg6:
.org 0x8000
pg7:
.org 0x9000
#endif
/*
* empty_bad_page is a bogus page that will be used when out of memory,
* so that a process isn't accidentally killed due to a page fault when
......@@ -136,7 +156,11 @@ pg3:
.globl _empty_bad_page
_empty_bad_page:
#if MAX_MEGABYTES == 32
.org 0xa000
#else
.org 0x6000
#endif
/*
* empty_bad_page_table is similar to the above, but is used when the
* system needs a bogus page-table
......@@ -144,7 +168,11 @@ _empty_bad_page:
.globl _empty_bad_page_table
_empty_bad_page_table:
#if MAX_MEGABYTES == 32
.org 0xb000
#else
.org 0x7000
#endif
/*
* tmp_floppy_area is used by the floppy-driver when DMA cannot
* reach to a buffer-block. It needs to be aligned, so that it isn't
......@@ -232,10 +260,17 @@ ignore_int:
* I've tried to show which constants to change by having
* some kind of marker at them (search for "16Mb"), but I
* won't guarantee that's all :-( )
*
* (ref: added support for up to 32mb, 17Apr92) -- Rik Faith
* (ref: update, 25Sept92) -- croutons@crunchy.uucp
*/
.align 2
setup_paging:
#if MAXMEGABYTES == 32
movl $1024*9,%ecx /* 9 pages - swapper_pg_dir+8 page tables */
#else
movl $1024*5,%ecx /* 5 pages - swapper_pg_dir+4 page tables */
#endif
xorl %eax,%eax
xorl %edi,%edi /* swapper_pg_dir is at 0x000 */
cld;rep;stosl
......@@ -246,8 +281,18 @@ setup_paging:
movl $pg1+7,_swapper_pg_dir+3076 /* --------- " " --------- */
movl $pg2+7,_swapper_pg_dir+3080 /* --------- " " --------- */
movl $pg3+7,_swapper_pg_dir+3084 /* --------- " " --------- */
#if MAX_MEGABYTES == 32
movl $pg4+7,_swapper_pg_dir+3088 /* --------- " " --------- */
movl $pg5+7,_swapper_pg_dir+3092 /* --------- " " --------- */
movl $pg6+7,_swapper_pg_dir+3096 /* --------- " " --------- */
movl $pg7+7,_swapper_pg_dir+3100 /* --------- " " --------- */
movl $pg7+4092,%edi
movl $0x1fff007,%eax /* 32Mb - 4096 + 7 (r/w user,p) */
#else
movl $pg3+4092,%edi
movl $0xfff007,%eax /* 16Mb - 4096 + 7 (r/w user,p) */
movl $0x0fff007,%eax /* 16Mb - 4096 + 7 (r/w user,p) */
#endif
std
1: stosl /* fill pages backwards - more efficient :-) */
subl $0x1000,%eax
......@@ -282,10 +327,14 @@ gdt_descr:
.word 256*8-1
.long 0xc0000000+_gdt
/*
* This gdt setup gives the kernel a 1GB address space at virtual
* address 0xC0000000 - space enough for expansion, I hope.
*/
.align 4
_gdt:
.quad 0x0000000000000000 /* NULL descriptor */
.quad 0xc0c09a0000000fff /* 16Mb at 0xC0000000 */
.quad 0xc0c0920000000fff /* 16Mb */
.quad 0xc0c39a000000ffff /* 1GB at 0xC0000000 */
.quad 0xc0c392000000ffff /* 1GB */
.quad 0x0000000000000000 /* TEMPORARY - don't use */
.fill 252,8,0 /* space for LDT's and TSS's etc */
......@@ -28,7 +28,7 @@
#include <asm/system.h>
#include <asm/io.h>
#ifdef CONFIG_BLK_DEV_SR
#if defined(CONFIG_BLK_DEV_SR) && defined(CONFIG_SCSI)
extern int check_cdrom_media_change(int, int);
#endif
......@@ -133,7 +133,7 @@ void check_disk_change(int dev)
brelse(bh);
break;
#ifdef CONFIG_BLK_DEV_SR
#if defined(CONFIG_BLK_DEV_SR) && defined(CONFIG_SCSI)
case 11: /* CDROM */
i = check_cdrom_media_change(dev, 0);
if (i) printk("Flushing buffers and inodes for CDROM\n");
......
......@@ -101,13 +101,16 @@ int core_dump(long signr, struct pt_regs * regs)
if (!file.f_op->write)
goto close_coredump;
has_dumped = 1;
/* write and seek example: from kernel space */
__asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
/* changed the size calculations - should hopefully work better. lbt */
dump.magic = CMAGIC;
dump.u_tsize = current->end_code / PAGE_SIZE;
dump.u_dsize = (current->brk - current->end_code) / PAGE_SIZE;
dump.u_ssize =((current->start_stack +(PAGE_SIZE-1)) / PAGE_SIZE) -
(regs->esp/ PAGE_SIZE);
dump.start_code = 0;
dump.start_stack = regs->esp & ~(PAGE_SIZE - 1);
dump.u_tsize = ((unsigned long) current->end_code) >> 12;
dump.u_dsize = ((unsigned long) (current->brk + (PAGE_SIZE-1))) >> 12;
dump.u_dsize -= dump.u_tsize;
dump.u_ssize = 0;
if (dump.start_stack < TASK_SIZE)
dump.u_ssize = ((unsigned long) (TASK_SIZE - dump.start_stack)) >> 12;
/* If the size of the dump file exceeds the rlimit, then see what would happen
if we wrote the stack, but not the data area. */
if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE/1024 >
......@@ -121,8 +124,6 @@ int core_dump(long signr, struct pt_regs * regs)
dump.u_ar0 = (struct pt_regs *)(((int)(&dump.regs)) -((int)(&dump)));
dump.signal = signr;
dump.regs = *regs;
dump.start_code = 0;
dump.start_stack = regs->esp & ~(PAGE_SIZE - 1);
/* Flag indicating the math stuff is valid. */
if (dump.u_fpvalid = current->used_math) {
if (last_task_used_math == current)
......@@ -130,6 +131,7 @@ int core_dump(long signr, struct pt_regs * regs)
else
memcpy(&dump.i387,&current->tss.i387,sizeof(dump.i387));
};
__asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
DUMP_WRITE(&dump,sizeof(dump));
DUMP_SEEK(sizeof(dump));
/* Dump the task struct. Not be used by gdb, but could be useful */
......@@ -140,14 +142,14 @@ int core_dump(long signr, struct pt_regs * regs)
__asm__("mov %0,%%fs"::"r" ((unsigned short) 0x17));
/* Dump the data area */
if (dump.u_dsize != 0) {
dump_start = current->end_code;
dump_size = current->brk - current->end_code;
dump_start = dump.u_tsize << 12;
dump_size = dump.u_dsize << 12;
DUMP_WRITE(dump_start,dump_size);
};
/* Now prepare to dump the stack area */
if (dump.u_ssize != 0) {
dump_start = regs->esp & ~(PAGE_SIZE - 1);
dump_size = dump.u_ssize * PAGE_SIZE;
dump_start = dump.start_stack;
dump_size = dump.u_ssize << 12;
DUMP_WRITE(dump_start,dump_size);
};
close_coredump:
......
......@@ -50,12 +50,12 @@ chrdev.o : chrdev.c /usr/include/linux/sched.h /usr/include/linux/head.h /usr/in
/usr/include/linux/vm86.h /usr/include/linux/ext_fs.h /usr/include/linux/tty.h \
/usr/include/linux/termios.h /usr/include/asm/system.h /usr/include/linux/stat.h \
/usr/include/linux/fcntl.h /usr/include/linux/errno.h
dir.o : dir.c /usr/include/asm/segment.h /usr/include/linux/errno.h /usr/include/linux/fs.h \
/usr/include/linux/limits.h /usr/include/linux/wait.h /usr/include/linux/types.h \
/usr/include/linux/dirent.h /usr/include/linux/vfs.h /usr/include/linux/pipe_fs_i.h \
/usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h /usr/include/linux/msdos_fs_i.h \
/usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
/usr/include/linux/ext_fs.h /usr/include/linux/stat.h
dir.o : dir.c /usr/include/asm/segment.h /usr/include/linux/errno.h /usr/include/linux/kernel.h \
/usr/include/linux/fs.h /usr/include/linux/limits.h /usr/include/linux/wait.h \
/usr/include/linux/types.h /usr/include/linux/dirent.h /usr/include/linux/vfs.h \
/usr/include/linux/pipe_fs_i.h /usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h \
/usr/include/linux/msdos_fs_i.h /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h \
/usr/include/linux/msdos_fs_sb.h /usr/include/linux/ext_fs.h /usr/include/linux/stat.h
fifo.o : fifo.c /usr/include/linux/sched.h /usr/include/linux/head.h /usr/include/linux/fs.h \
/usr/include/linux/limits.h /usr/include/linux/wait.h /usr/include/linux/types.h \
/usr/include/linux/dirent.h /usr/include/linux/vfs.h /usr/include/linux/pipe_fs_i.h \
......
......@@ -15,6 +15,7 @@
#include <asm/segment.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/ext_fs.h>
#include <linux/stat.h>
......@@ -73,6 +74,13 @@ static int ext_readdir(struct inode * inode, struct file * filp,
while (offset < 1024 && filp->f_pos < inode->i_size) {
offset += de->rec_len;
filp->f_pos += de->rec_len;
if (de->rec_len < 8 || de->rec_len % 4 != 0 ||
de->rec_len < de->name_len + 8) {
printk ("ext_readdir: bad directory entry\n");
printk ("dev=%d, dir=%d, offset=%d, rec_len=%d, name_len=%d\n",
inode->i_dev, inode->i_ino, offset, de->rec_len, de->name_len);
return 0;
}
if (de->inode) {
for (i = 0; i < de->name_len; i++)
if (c = de->name[i])
......
......@@ -122,6 +122,14 @@ static struct buffer_head * ext_find_entry(struct inode * dir,
if (prev_dir)
*prev_dir = NULL;
}
if (de->rec_len < 8 || de->rec_len % 4 != 0 ||
de->rec_len < de->name_len + 8) {
printk ("ext_find_entry: bad dir entry\n");
printk ("dev=%d, dir=%d, offset=%d, rec_len=%d, name_len=%d\n",
dir->i_dev, dir->i_ino, offset, de->rec_len, de->name_len);
brelse (bh);
return NULL;
}
if (ext_match(namelen,name,de)) {
*res_dir = de;
if (next_dir)
......@@ -253,6 +261,14 @@ printk ("ext_add_entry : creating next block\n");
dir->i_dirt = 1;
dir->i_ctime = CURRENT_TIME;
}
if (de->rec_len < 8 || de->rec_len % 4 != 0 ||
de->rec_len < de->name_len + 8) {
printk ("ext_addr_entry: bad dir entry\n");
printk ("dev=%d, dir=%d, offset=%d, rec_len=%d, name_len=%d\n",
dir->i_dev, dir->i_ino, offset, de->rec_len, de->name_len);
brelse (bh);
return NULL;
}
if (!de->inode && de->rec_len >= rec_len) {
if (de->rec_len > rec_len
&& de->rec_len - rec_len >= EXT_DIR_MIN_SIZE) {
......@@ -471,6 +487,14 @@ static int empty_dir(struct inode * inode)
}
de = (struct ext_dir_entry *) bh->b_data;
}
if (de->rec_len < 8 || de->rec_len %4 != 0 ||
de->rec_len < de->name_len + 8) {
printk ("empty_dir: bad dir entry\n");
printk ("dev=%d, dir=%d, offset=%d, rec_len=%d, name_len=%d\n",
inode->i_dev, inode->i_ino, offset, de->rec_len, de->name_len);
brelse (bh);
return 1;
}
if (de->inode) {
brelse(bh);
return 0;
......
......@@ -60,7 +60,7 @@
/*--------- MICROSOFT BUSMOUSE ITEMS -------------*/
#define MS_MSE_DATA_PORT 0x23d
#define MS_MSE_SIGNATURE_PORT 0x23d
#define MS_MSE_SIGNATURE_PORT 0x23e
#define MS_MSE_CONTROL_PORT 0x23c
#define MS_MSE_CONFIG_PORT 0x23f
......
......@@ -22,7 +22,7 @@
#define DEF_INITSEG 0x9000
#define DEF_SYSSEG 0x1000
#define DEF_SETUPSEG 0x9020
#define DEF_SYSSIZE 0x5000
#define DEF_SYSSIZE 0x7000
/*
* The root-device is no longer hard-coded. You can change the default
......
......@@ -48,6 +48,13 @@ struct sockaddr {
#define SO_KEEPALIVE 9
#define SO_OOBINLINE 10
#define SO_NO_CHECK 11
#define SO_PRIORITY 12
#define SO_LINGER 13
/* the different priorities */
#define SOPRI_INTERACTIVE 0
#define SOPRI_NORMAL 1
#define SOPRI_BACKGROUND 2
/* setsockoptions level */
#define SOL_SOCKET 1
......
#ifndef _LINUX_VMM_H
#define _LINUX_VMM_H
/*
* Linux kernel virtual memory manager primitives.
* The idea being to have a "virtual" mm in the same way
* we have a virtual fs - giving a cleaner interface to the
* mm details, and allowing different kinds of memory mappings
* (from shared memory to executable loading to arbitrary
* mmap() functions).
*/
/*
* This struct defines a memory VMM memory area. There is one of these
* per VM-area/task. A VM area is any part of the process virtual memory
* space that has a special rule for the page-fault handlers (ie a shared
* library, the executable area etc).
*/
struct vm_area_struct {
unsigned long vm_start; /* VM area parameters */
unsigned long vm_end;
struct vm_area_struct * vm_next; /* ordered linked list */
struct vm_area_struct * vm_share; /* circular linked list */
struct inode * vm_inode;
unsigned long vm_offset;
struct vm_operations_struct * vm_ops;
unsigned long vm_flags;
};
struct vm_operations_struct {
void (*open)(struct task_struct * tsk, struct vm_area_struct * area);
void (*close)(struct task_struct * tsk, struct vm_area_struct * area);
void (*nopage)(struct task_struct * tsk, struct vm_area_struct * area, unsigned long address);
void (*wppage)(struct task_struct * tsk, struct vm_area_struct * area, unsigned long address);
};
#endif
......@@ -162,8 +162,8 @@ void start_kernel(void)
envp_init[1] = term;
memory_end = (1<<20) + (EXT_MEM_K<<10);
memory_end &= 0xfffff000;
if (memory_end > 16*1024*1024)
memory_end = 16*1024*1024;
if (memory_end > MAX_MEGABYTES*1024*1024)
memory_end = MAX_MEGABYTES*1024*1024;
memory_start = 1024*1024;
low_memory_start = (unsigned long) &end;
low_memory_start += 0xfff;
......
......@@ -63,7 +63,7 @@ static void extended_partition(struct gendisk *hd, int dev)
goto done; /* shouldn't happen */
hd->part[current_minor].start_sect = this_sector + p->start_sect;
printk(" Logical part %d start %d size %d end %d\n\r",
current_minor, hd->part[current_minor].start_sect,
mask & current_minor, hd->part[current_minor].start_sect,
hd->part[current_minor].nr_sects,
hd->part[current_minor].start_sect +
hd->part[current_minor].nr_sects - 1);
......@@ -96,6 +96,7 @@ static void check_partition(struct gendisk *hd, unsigned int dev)
struct buffer_head *bh;
struct partition *p;
unsigned long first_sector;
int mask = (1 << hd->minor_shift) - 1;
first_sector = hd->part[MINOR(dev)].start_sect;
......@@ -103,7 +104,7 @@ static void check_partition(struct gendisk *hd, unsigned int dev)
printk("Unable to read partition table of device %04x\n",dev);
return;
}
printk("%s%d :\n\r", hd->major_name, minor >> hd->minor_shift);
printk("%s%c :\n\r", hd->major_name, 'a'+(minor >> hd->minor_shift));
current_minor += 4; /* first "extra" minor */
if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
p = 0x1BE + (void *)bh->b_data;
......@@ -127,14 +128,14 @@ static void check_partition(struct gendisk *hd, unsigned int dev)
p = 0x1BE + (void *)bh->b_data;
for (i = 4 ; i < 16 ; i++, current_minor++) {
p--;
if ((current_minor & 0x3f) >= 60)
if ((current_minor & mask) >= mask-2)
break;
if (!(p->start_sect && p->nr_sects))
continue;
hd->part[current_minor].start_sect = p->start_sect;
hd->part[current_minor].nr_sects = p->nr_sects;
printk(" DM part %d start %d size %d end %d\n\r",
current_minor,
current_minor & mask,
hd->part[current_minor].start_sect,
hd->part[current_minor].nr_sects,
hd->part[current_minor].start_sect +
......
......@@ -251,23 +251,27 @@ static inline int wait_DRQ(void)
static void read_intr(void)
{
int i;
int retries = 100000;
do {
i = (unsigned) inb_p(HD_STATUS);
if ((i & STAT_MASK) != STAT_OK) {
if ((i & STAT_MASK) != STAT_OK)
break;
if (i & DRQ_STAT)
goto ok_to_read;
} while (--retries > 0);
sti();
printk("HD: read_intr: status = 0x%02x\n",i);
goto bad_read;
}
if (wait_DRQ()) {
printk("HD: read_intr: no DRQ\n");
goto bad_read;
if (i & ERR_STAT) {
i = (unsigned) inb(HD_ERROR);
printk("HD: read_intr: error = 0x%02x\n",i);
}
bad_rw_intr();
cli();
do_hd_request();
return;
ok_to_read:
port_read(HD_DATA,CURRENT->buffer,256);
i = (unsigned) inb_p(HD_STATUS);
if (!(i & BUSY_STAT))
if ((i & STAT_MASK) != STAT_OK) {
printk("HD: read_intr: second status = 0x%02x\n",i);
goto bad_read;
}
CURRENT->errors = 0;
CURRENT->buffer += 512;
CURRENT->sector++;
......@@ -290,29 +294,31 @@ static void read_intr(void)
#endif
do_hd_request();
return;
bad_read:
if (i & ERR_STAT) {
i = (unsigned) inb(HD_ERROR);
printk("HD: read_intr: error = 0x%02x\n",i);
}
bad_rw_intr();
do_hd_request();
return;
}
static void write_intr(void)
{
int i;
int retries = 100000;
do {
i = (unsigned) inb_p(HD_STATUS);
if ((i & STAT_MASK) != STAT_OK) {
if ((i & STAT_MASK) != STAT_OK)
break;
if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT))
goto ok_to_write;
} while (--retries > 0);
sti();
printk("HD: write_intr: status = 0x%02x\n",i);
goto bad_write;
}
if (CURRENT->nr_sectors > 1 && wait_DRQ()) {
printk("HD: write_intr: no DRQ\n");
goto bad_write;
if (i & ERR_STAT) {
i = (unsigned) inb(HD_ERROR);
printk("HD: write_intr: error = 0x%02x\n",i);
}
bad_rw_intr();
cli();
do_hd_request();
return;
ok_to_write:
CURRENT->sector++;
i = --CURRENT->nr_sectors;
--CURRENT->current_nr_sectors;
......@@ -330,16 +336,6 @@ static void write_intr(void)
do_hd_request();
}
return;
bad_write:
sti();
if (i & ERR_STAT) {
i = (unsigned) inb(HD_ERROR);
printk("HD: write_intr: error = 0x%02x\n",i);
}
bad_rw_intr();
cli();
do_hd_request();
return;
}
static void recal_intr(void)
......@@ -587,7 +583,7 @@ static void hd_interrupt(int unused)
}
/*
* This is the harddisk IRQ descruption. The SA_INTERRUPT in sa_flags
* This is the harddisk IRQ description. The SA_INTERRUPT in sa_flags
* means we run the IRQ-handler with interrupts disabled: this is bad for
* interrupt latency, but anything else has led to problems on some
* machines...
......
/*
* ultrastor.c Copyright (C) 1991, 1992 David B. Gentzel
* ultrastor.c Copyright (C) 1992 David B. Gentzel
* Low-level SCSI driver for UltraStor 14F
* by David B. Gentzel, Whitfield Software Services, Carnegie, PA
* (gentzel@nova.enet.dec.com)
......@@ -24,9 +24,8 @@
/*
* CAVEATS: ???
* This driver is VERY stupid. It takes no advantage of much of the power
* of the UltraStor controller. We just sit-and-spin while waiting for
* commands to complete. I hope to go back and beat it into shape, but
* PLEASE, anyone else who would like to, please make improvements!
* of the UltraStor controller. I hope to go back and beat it into shape,
* but PLEASE, anyone else who would like to, please make improvements!
*
* By defining NO_QUEUEING in ultrastor.h, you disable the queueing feature
* of the mid-level SCSI driver. Once I'm satisfied that the queueing
......@@ -155,7 +154,7 @@ static const unsigned short ultrastor_ports[] = {
};
#endif
void ultrastor_interrupt(void);
static void ultrastor_interrupt(int cpl);
static void (*ultrastor_done)(int, int) = 0;
......@@ -292,11 +291,19 @@ int ultrastor_14f_detect(int hostnum)
host_number = hostnum;
scsi_hosts[hostnum].this_id = config.ha_scsi_id;
#ifndef NO_QUEUEING
set_intr_gate(0x20 + config.interrupt, ultrastor_interrupt);
/* gate to PIC 2 */
outb_p(inb_p(0x21) & ~BIT(2), 0x21);
/* enable the interrupt */
outb(inb_p(0xA1) & ~BIT(config.interrupt - 8), 0xA1);
{
struct sigaction sa;
sa.sa_handler = ultrastor_interrupt;
sa.sa_mask = 0;
sa.sa_flags = SA_INTERRUPT; /* ??? Do we really need this? */
sa.sa_restorer = 0;
if (irqaction(config.interrupt, &sa)) {
printk("Unable to get IRQ%u for UltraStor controller\n",
config.interrupt);
return FALSE;
}
}
#endif
return TRUE;
}
......@@ -309,7 +316,7 @@ const char *ultrastor_14f_info(void)
}
static struct mscp mscp = {
OP_SCSI, DTD_SCSI, FALSE, TRUE, FALSE /* This stuff doesn't change */
OP_SCSI, DTD_SCSI, 0, 1, 0 /* This stuff doesn't change */
};
int ultrastor_14f_queuecommand(unsigned char target, const void *cmnd,
......@@ -437,15 +444,15 @@ int ultrastor_14f_reset(void)
}
#ifndef NO_QUEUEING
void ultrastor_interrupt_service(void)
static void ultrastor_interrupt(int cpl)
{
#if (ULTRASTOR_DEBUG & UD_INTERRUPT)
printk("US14F: interrupt_service: called: status = %08X\n",
printk("US14F: interrupt: called: status = %08X\n",
(mscp.adapter_status << 16) | mscp.target_status);
#endif
if (ultrastor_done == 0)
panic("US14F: interrupt_service: unexpected interrupt!\n");
panic("US14F: interrupt: unexpected interrupt!\n");
else {
void (*done)(int, int);
......@@ -464,40 +471,9 @@ void ultrastor_interrupt_service(void)
}
#if (ULTRASTOR_DEBUG & UD_INTERRUPT)
printk("US14F: interrupt_service: returning\n");
printk("US14F: interrupt: returning\n");
#endif
}
__asm__("
_ultrastor_interrupt:
cld
pushl %eax
pushl %ecx
pushl %edx
push %ds
push %es
push %fs
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
movl $0x17,%eax
mov %ax,%fs
movb $0x20,%al
outb %al,$0xA0 # EOI to interrupt controller #1
outb %al,$0x80 # give port chance to breathe
outb %al,$0x80
outb %al,$0x80
outb %al,$0x80
outb %al,$0x20
call _ultrastor_interrupt_service
pop %fs
pop %es
pop %ds
popl %edx
popl %ecx
popl %eax
iret
");
#endif
#endif
......@@ -31,7 +31,12 @@
* Added a couple of new functions to handle differences in using
* MS vs. Logitech (where the int variable wasn't appropriate).
*
* version 0.2
* Modified by Peter Cervasio (address above) (26SEP92)
* Changes: Included code to (properly?) detect when a Microsoft mouse is
* really attached to the machine. Don't know what this does to
* Logitech bus mice, but all it does is read ports.
*
* version 0.3
*/
#include <linux/kernel.h>
......@@ -254,8 +259,39 @@ long bus_mouse_init(long kmem_start)
return kmem_start;
}
#define MS_DELAY 100000
long ms_bus_mouse_init(long kmem_start)
{
register int mse_byte;
int i, delay_val, msfound = 1;
if (inb(MS_MSE_SIGNATURE_PORT) == 0xde) {
for (delay_val=0; delay_val<MS_DELAY;) delay_val++;
mse_byte = inb(MS_MSE_SIGNATURE_PORT);
for (delay_val=0; delay_val<MS_DELAY; ) delay_val++;
for (i = 0; i < 4; i++) {
for (delay_val=0; delay_val<MS_DELAY;) delay_val++;
if (inb(MS_MSE_SIGNATURE_PORT) == 0xde) {
for (delay_val=0; delay_val<MS_DELAY; ) delay_val++;
if (inb(MS_MSE_SIGNATURE_PORT) == mse_byte)
msfound = 0;
else
msfound = 1;
}
else
msfound = 1;
}
}
if (msfound == 1) {
printk("No Microsoft bus mouse detected.\n");
mouse.present = 0;
return kmem_start;
}
MS_MSE_INT_OFF();
......
......@@ -963,6 +963,95 @@ static unsigned char alt_map[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0 };
#elif defined KBD_SF
static unsigned char key_map[] = {
0, 27, '1', '2', '3', '4', '5', '6',
'7', '8', '9', '0', '\'', '^', 127, 9,
'q', 'w', 'e', 'r', 't', 'z', 'u', 'i',
'o', 'p', 0, 0, 13, 0, 'a', 's',
'd', 'f', 'g', 'h', 'j', 'k', 'l', 0,
0, 0, 0, '$', 'y', 'x', 'c', 'v',
'b', 'n', 'm', ',', '.', '-', 0, '*',
0, 32, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, '-', 0, 0, 0, '+', 0,
0, 0, 0, 0, 0, 0, '<', 0,
0, 0, 0, 0, 0, 0, 0, 0,
0 };
static unsigned char shift_map[] = {
0, 27, '+', '"', '*', 0, '%', '&',
'/', '(', ')', '=', '?', '`', 127, 9,
'Q', 'W', 'E', 'R', 'T', 'Z', 'U', 'I',
'O', 'P', 0, '!', 13, 0, 'A', 'S',
'D', 'F', 'G', 'H', 'J', 'K', 'L', 0,
0, 0, 0, 0, 'Y', 'X', 'C', 'V',
'B', 'N', 'M', ';', ':', '_', 0, '*',
0, 32, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, '-', 0, 0, 0, '+', 0,
0, 0, 0, 0, 0, 0, '>', 0,
0, 0, 0, 0, 0, 0, 0, 0,
0 };
static unsigned char alt_map[] = {
0, 0, 0, '@', '#', 0, 0, 0,
'|', 0, 0, 0, '\'', '~', 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, '[', ']', 13, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
'{', 0, 0, '}', 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, '\\', 0,
0, 0, 0, 0, 0, 0, 0, 0,
0 };
#elif defined KBD_SF_LATIN1
static unsigned char key_map[] = {
0, 27, '1', '2', '3', '4', '5', '6',
'7', '8', '9', '0', '\'', '^', 127, 9,
'q', 'w', 'e', 'r', 't', 'z', 'u', 'i',
'o', 'p', 232, 168, 13, 0, 'a', 's',
'd', 'f', 'g', 'h', 'j', 'k', 'l', 233,
224, 167, 0, '$', 'y', 'x', 'c', 'v',
'b', 'n', 'm', ',', '.', '-', 0, '*',
0, 32, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, '-', 0, 0, 0, '+', 0,
0, 0, 0, 0, 0, 0, '<', 0,
0, 0, 0, 0, 0, 0, 0, 0,
0 };
static unsigned char shift_map[] = {
0, 27, '+', '"', '*', 231, '%', '&',
'/', '(', ')', '=', '?', '`', 127, 9,
'Q', 'W', 'E', 'R', 'T', 'Z', 'U', 'I',
'O', 'P', 252, '!', 13, 0, 'A', 'S',
'D', 'F', 'G', 'H', 'J', 'K', 'L', 246,
228, 176, 0, 163, 'Y', 'X', 'C', 'V',
'B', 'N', 'M', ';', ':', '_', 0, '*',
0, 32, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, '-', 0, 0, 0, '+', 0,
0, 0, 0, 0, 0, 0, '>', 0,
0, 0, 0, 0, 0, 0, 0, 0,
0 };
static unsigned char alt_map[] = {
0, 0, 0, '@', '#', 0, 0, 172,
'|', 162, 0, 0, 180, '~', 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, '[', ']', 13, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
'{', 0, 0, '}', 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, '\\', 0,
0, 0, 0, 0, 0, 0, 0, 0,
0 };
#else
#error "KBD-type not defined"
#endif
......
......@@ -328,7 +328,7 @@ static void init(struct async_struct * info)
outb_p(UART_MCR_LOOP | 0x0A, UART_MCR + port);
status1 = inb_p(UART_MSR + port) & 0xF0;
outb_p(scratch, UART_MCR + port);
outb_p(scratch, UART_MSR + port);
outb_p(scratch2, UART_MSR + port);
if (status1 != 0x90) {
info->type = PORT_UNKNOWN;
return;
......@@ -379,9 +379,7 @@ static void init(struct async_struct * info)
*/
void rs_write(struct tty_struct * tty)
{
int line = tty->line - 64;
do_rs_write(rs_table+line);
do_rs_write(rs_table+DEV_TO_SL(tty->line));
}
/*
......@@ -571,6 +569,10 @@ static int set_serial_info(struct async_struct * info,
irq = ISR->irq;
if (irq == 2)
irq = 9;
if (!new_irq)
new_irq = irq;
if (!new_port)
new_port = info->port;
if (irq != new_irq) {
/*
* We need to change the IRQ for this board. OK, if
......@@ -582,7 +584,7 @@ static int set_serial_info(struct async_struct * info,
sa.sa_flags = (SA_INTERRUPT);
sa.sa_mask = 0;
sa.sa_restorer = NULL;
retval = irqaction(irq,&sa);
retval = irqaction(new_irq,&sa);
if (retval)
return retval;
}
......@@ -608,6 +610,7 @@ static int set_serial_info(struct async_struct * info,
if (ISR->next_ISR)
ISR->next_ISR->prev_ISR = ISR;
IRQ_ISR[new_irq] = ISR;
ISR->irq = new_irq;
}
cli();
if (new_port != info->port) {
......
......@@ -155,7 +155,7 @@ static void mark_screen_rdonly(struct task_struct * tsk)
tmp = *(unsigned long *) tmp;
if (tmp & PAGE_PRESENT) {
tmp &= 0xfffff000;
pg_table = (0xA00000 >> PAGE_SHIFT) + (unsigned long *) tmp;
pg_table = (0xA0000 >> PAGE_SHIFT) + (unsigned long *) tmp;
tmp = 32;
while (tmp--) {
if (PAGE_PRESENT & *pg_table)
......
......@@ -792,6 +792,10 @@ void do_page_fault(unsigned long *esp, unsigned long error_code)
/* get the address */
__asm__("movl %%cr2,%0":"=r" (address));
if (address >= TASK_SIZE) {
printk("Unable to handle kernel paging request at address %08x\n",address);
do_exit(SIGSEGV);
}
if (esp[2] & VM_MASK) {
unsigned int bit;
......
......@@ -32,6 +32,7 @@ subdirs: dummy
clean:
rm -f core *.o *.a tmp_make
for i in *.c;do rm -f `basename $$i .c`.s;done
@for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE) clean) || exit; done
dep:
sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
......
This diff is collapsed.
/* Space.c */
/* Holds initial configuration information for devices. */
#include "dev.h"
#include <linux/stddef.h>
extern void wd8003_init(struct device *);
static struct device wd8003_dev =
{
"eth0",
0xd2000, /* recv memory end. */
0xd0600, /* recv memory start. */
0xd2000, /* memory end. */
0xd0000, /* memory start. */
0x280, /* base i/o address. */
5, /* irq */
0,0,0,0,0, /* flags */
NULL, /* next device */
wd8003_init,
/* wd8003_init should set up the rest. */
0, /* trans start. */
{NULL}, /* buffs */
NULL, /* backlog */
NULL, /* open */
NULL, /* stop */
NULL, /* hard_start_xmit */
NULL, /* hard_header */
NULL, /* add arp */
NULL, /* queue xmit */
NULL, /* rebuild header */
NULL, /* type_trans */
NULL, /* send_packet */
NULL, /* private */
0, /* type. */
0, /* hard_header_len */
0, /* mtu */
{0,}, /* broadcast address */
{0,}, /* device address */
0 /* addr len */
};
extern void loopback_init(struct device *dev);
static struct device loopback_dev =
{
"loopback",
-1, /* recv memory end. */
0x0, /* recv memory start. */
-1, /* memory end. */
0, /* memory start. */
0, /* base i/o address. */
0, /* irq */
0,0,1,0,0, /* flags */
&wd8003_dev, /* next device */
loopback_init,
/* loopback_init should set up the rest. */
0, /* trans start. */
{NULL}, /* buffs */
NULL, /* backlog */
NULL, /* open */
NULL, /* stop */
NULL, /* hard_start_xmit */
NULL, /* hard_header */
NULL, /* add arp */
NULL, /* queue xmit */
NULL, /* rebuild header */
NULL, /* type_trans */
NULL, /* send_packet */
NULL, /* private */
0, /* type. */
0, /* hard_header_len */
0, /* mtu */
{0,}, /* broadcast address */
{0,}, /* device address */
0 /* addr len */
};
struct device *dev_base = &loopback_dev;
This diff is collapsed.
/* arp.h */
/*
Copyright (C) 1992 Ross Biro
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
#ifndef _TCP_ARP_H
#define _TCP_ARP_H
struct arp
{
unsigned short hrd;
unsigned short pro;
unsigned char hlen;
unsigned char plen;
unsigned short op;
};
struct arp_table
{
struct arp_table *next;
unsigned long last_used;
unsigned long ip;
unsigned char hlen;
unsigned char hard[MAX_ADDR_LEN];
};
int arp_rcv(struct sk_buff *, struct device *, struct packet_type *);
void arp_snd (unsigned long, struct device *, unsigned long);
int arp_find (unsigned char *, unsigned long, struct device *dev,
unsigned long);
void arp_add_broad (unsigned long, struct device *dev);
void arp_destroy (unsigned long);
void arp_add (unsigned long addr, unsigned char *haddr, struct device *dev);
void arp_queue (struct sk_buff *skb);
#define ARP_TABLE_SIZE 16
#define ARP_IP_PROT ETHERTYPE_IP
#define ARP_REQUEST 1
#define ARP_REPLY 2
#define ARP_TIMEOUT 8640000 /* about 8 hours. */
#define ARP_RES_TIME 250 /* 2.5 seconds. */
#endif
/* dev.c */
/*
Copyright (C) 1992 Ross Biro
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
#include <asm/segment.h>
#include <asm/system.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/socket.h>
#include <netinet/in.h>
#include <asm/memory.h>
#include "dev.h"
#include "eth.h"
#include "timer.h"
#include "ip.h"
#include "tcp.h"
#include "sock.h"
#include <linux/errno.h>
#include "arp.h"
#undef DEV_DEBUG
#ifdef DEV_DEBUG
#define PRINTK printk
#else
#define PRINTK dummy_routine
#endif
static unsigned long
min(unsigned long a, unsigned long b)
{
if (a < b) return (a);
return (b);
}
void
dev_add_pack (struct packet_type *pt)
{
struct packet_type *p1;
pt->next = ptype_base;
/* see if we need to copy it. */
for (p1 = ptype_base; p1 != NULL; p1 = p1->next)
{
if (p1->type == pt->type)
{
pt->copy = 1;
break;
}
}
ptype_base = pt;
}
void
dev_remove_pack (struct packet_type *pt)
{
struct packet_type *lpt, *pt1;
if (pt == ptype_base)
{
ptype_base = pt->next;
return;
}
lpt = NULL;
for (pt1 = ptype_base; pt1->next != NULL; pt1=pt1->next)
{
if (pt1->next == pt )
{
cli();
if (!pt->copy && lpt)
lpt->copy = 0;
pt1->next = pt->next;
sti();
return;
}
if (pt1->next -> type == pt ->type)
{
lpt = pt1->next;
}
}
}
struct device *
get_dev (char *name)
{
struct device *dev;
for (dev = dev_base; dev != NULL; dev=dev->next)
{
if (strcmp (dev->name, name) == 0) return (dev);
}
return (NULL);
}
void
dev_queue_xmit (struct sk_buff *skb, struct device *dev, int pri)
{
struct sk_buff *skb2;
PRINTK ("eth_queue_xmit (skb=%X, dev=%X, pri = %d)\n", skb, dev, pri);
skb->dev = dev;
if (pri < 0 || pri >= DEV_NUMBUFFS)
{
printk ("bad priority in dev_queue_xmit.\n");
pri = 1;
}
if (dev->hard_start_xmit(skb, dev) == 0)
{
return;
}
if (skb->next != NULL)
{
printk ("retransmitted packet still on queue. \n");
return;
}
/* used to say it is not currently on a send list. */
skb->next = NULL;
/* put skb into a bidirectional circular linked list. */
PRINTK ("eth_queue dev->buffs[%d]=%X\n",pri, dev->buffs[pri]);
/* interrupts should already be cleared by hard_start_xmit. */
cli();
if (dev->buffs[pri] == NULL)
{
dev->buffs[pri]=skb;
skb->next = skb;
skb->prev = skb;
}
else
{
skb2=dev->buffs[pri];
skb->next = skb2;
skb->prev = skb2->prev;
skb->next->prev = skb;
skb->prev->next = skb;
}
sti();
}
/* this routine now just gets the data out of the card and returns.
it's return values now mean.
1 <- exit even if you have more packets.
0 <- call me again no matter what.
-1 <- last packet not processed, try again. */
int
dev_rint(unsigned char *buff, unsigned long len, int flags,
struct device * dev)
{
struct sk_buff *skb=NULL;
struct packet_type *ptype;
unsigned short type;
unsigned char flag =0;
unsigned char *to;
int amount;
/* try to grab some memory. */
if (len > 0 && buff != NULL)
{
skb = malloc (sizeof (*skb) + len);
skb->mem_len = sizeof (*skb) + len;
skb->mem_addr = skb;
}
/* firs we copy the packet into a buffer, and save it for later. */
if (buff != NULL && skb != NULL)
{
if ( !(flags & IN_SKBUFF))
{
to = (unsigned char *)(skb+1);
while (len > 0)
{
amount = min (len, (unsigned long) dev->rmem_end -
(unsigned long) buff);
memcpy (to, buff, amount);
len -= amount;
buff += amount;
to += amount;
if ((unsigned long)buff == dev->rmem_end)
buff = (unsigned char *)dev->rmem_start;
}
}
else
{
free_s (skb->mem_addr, skb->mem_len);
skb = (struct sk_buff *)buff;
}
skb->len = len;
skb->dev = dev;
skb->sk = NULL;
/* now add it to the dev backlog. */
cli();
if (dev-> backlog == NULL)
{
skb->prev = skb;
skb->next = skb;
dev->backlog = skb;
}
else
{
skb ->prev = dev->backlog->prev;
skb->next = dev->backlog;
skb->next->prev = skb;
skb->prev->next = skb;
}
sti();
return (0);
}
if (skb != NULL)
free_s (skb->mem_addr, skb->mem_len);
/* anything left to process? */
if (dev->backlog == NULL)
{
if (buff == NULL)
{
sti();
return (1);
}
if (skb != NULL)
{
sti();
return (-1);
}
sti();
printk ("dev_rint:Dropping packets due to lack of memory\n");
return (1);
}
skb= dev->backlog;
if (skb->next == skb)
{
dev->backlog = NULL;
}
else
{
dev->backlog = skb->next;
skb->next->prev = skb->prev;
skb->prev->next = skb->next;
}
sti();
/* bump the pointer to the next structure. */
skb->h.raw = (unsigned char *)(skb+1) + dev->hard_header_len;
skb->len -= dev->hard_header_len;
/* convert the type to an ethernet type. */
type = dev->type_trans (skb, dev);
/* if there get to be a lot of types we should changes this to
a bunch of linked lists like we do for ip protocols. */
for (ptype = ptype_base; ptype != NULL; ptype=ptype->next)
{
if (ptype->type == type)
{
struct sk_buff *skb2;
/* copy the packet if we need to. */
if (ptype->copy)
{
skb2 = malloc (skb->mem_len);
if (skb2 == NULL) continue;
memcpy (skb2, skb, skb->mem_len);
skb2->mem_addr = skb2;
}
else
{
skb2 = skb;
flag = 1;
}
ptype->func (skb2, dev, ptype);
}
}
if (!flag)
{
PRINTK ("discarding packet type = %X\n", type);
free_skb (skb, FREE_READ);
}
if (buff == NULL)
return (0);
else
return (-1);
}
/* This routine is called when an device interface is ready to
transmit a packet. Buffer points to where the packet should
be put, and the routine returns the length of the packet. A
length of zero is interrpreted to mean the transmit buffers
are empty, and the transmitter should be shut down. */
unsigned long
dev_tint(unsigned char *buff, struct device *dev)
{
int i;
int tmp;
struct sk_buff *skb;
for (i=0; i < DEV_NUMBUFFS; i++)
{
while (dev->buffs[i]!=NULL)
{
cli();
skb=dev->buffs[i];
if (skb->next == skb)
{
dev->buffs[i] = NULL;
}
else
{
dev->buffs[i]=skb->next;
skb->prev->next = skb->next;
skb->next->prev = skb->prev;
}
skb->next = NULL;
skb->prev = NULL;
sti();
tmp = skb->len;
if (!skb->arp)
{
if (dev->rebuild_header (skb+1, dev))
{
skb->dev = dev;
arp_queue (skb);
continue;
}
}
if (tmp <= dev->mtu)
{
if (dev->send_packet != NULL)
{
dev->send_packet(skb, dev);
}
if (buff != NULL)
memcpy (buff, skb + 1, tmp);
PRINTK (">>\n");
print_eth ((struct enet_header *)(skb+1));
}
else
{
printk ("**** bug len bigger than mtu. \n");
}
if (skb->free)
{
free_skb(skb, FREE_WRITE);
}
if (tmp != 0)
return (tmp);
}
}
PRINTK ("dev_tint returning 0 \n");
return (0);
}
/* dev.h */
/*
Copyright (C) 1992 Ross Biro
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
#ifndef _TCP_DEV_H
#define _TCP_DEV_H
/* for future expansion when we will have different priorities. */
#define DEV_NUMBUFFS 3
#define MAX_ADDR_LEN 6
#define MAX_HEADER 14
#define MAX_ROUTE 16
struct device
{
char *name;
unsigned long rmem_end;
unsigned long rmem_start;
unsigned long mem_end;
unsigned long mem_start;
unsigned short base_addr;
unsigned char irq;
unsigned char start:1,
tbusy:1,
loopback:1,
interrupt:1,
up:1;
struct device *next;
void (*init)(struct device *dev);
unsigned long trans_start;
struct sk_buff *buffs[DEV_NUMBUFFS];
struct sk_buff *backlog;
int (*open)(struct device *dev);
int (*stop)(struct device *dev);
int (*hard_start_xmit) (struct sk_buff *skb, struct device *dev);
int (*hard_header) (unsigned char *buff, struct device *dev,
unsigned short type, unsigned long daddr,
unsigned long saddr, unsigned len);
void (*add_arp) (unsigned long addr, struct sk_buff *skb,
struct device *dev);
void (*queue_xmit)(struct sk_buff *skb, struct device *dev, int pri);
int (*rebuild_header)(void *eth, struct device *dev);
unsigned short (*type_trans) (struct sk_buff *skb, struct device *dev);
void (*send_packet)(struct sk_buff *skb, struct device *dev);
void *private;
unsigned short type;
unsigned short hard_header_len;
unsigned short mtu;
unsigned char broadcast[MAX_ADDR_LEN];
unsigned char dev_addr[MAX_ADDR_LEN];
unsigned char addr_len;
};
extern struct device *dev_base;
struct packet_type
{
unsigned short type; /* This is really NET16(ether_type) other devices
will have to translate appropriately. */
unsigned short copy:1;
int (*func) (struct sk_buff *, struct device *, struct packet_type *);
void *data;
struct packet_type *next;
};
/* used by dev_rint */
#define IN_SKBUFF 1
extern struct packet_type *ptype_base;
void dev_queue_xmit (struct sk_buff *skb, struct device *dev, int pri);
int dev_rint (unsigned char *buff, unsigned long len, int flags,
struct device *dev);
unsigned long dev_tint (unsigned char *buff, struct device *dev);
void dev_add_pack (struct packet_type *pt);
void dev_remove_pack (struct packet_type *pt);
struct device *get_dev (char *name);
#endif
/* eth.c */
/*
Copyright (C) 1992 Ross Biro
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
#include <asm/segment.h>
#include <asm/system.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/socket.h>
#include <netinet/in.h>
#include <asm/memory.h>
#include "dev.h"
#include "eth.h"
#include "timer.h"
#include "ip.h"
#include "tcp.h"
#include "sock.h"
#include <linux/errno.h>
#include "arp.h"
#undef ETH_DEBUG
#ifdef ETH_DEBUG
#define PRINTK printk
#else
#define PRINTK dummy_routine
#endif
void
print_eth (struct enet_header *eth)
{
int i;
PRINTK ("ether source addr: ");
for (i =0 ; i < ETHER_ADDR_LEN; i++)
{
PRINTK ("0x%2X ",eth->saddr[i]);
}
PRINTK ("\n");
PRINTK ("ether dest addr: ");
for (i =0 ; i < ETHER_ADDR_LEN; i++)
{
PRINTK ("0x%2X ",eth->daddr[i]);
}
PRINTK ("\n");
PRINTK ("ethertype = %X\n",net16(eth->type));
}
int
eth_hard_header (unsigned char *buff, struct device *dev,
unsigned short type, unsigned long daddr,
unsigned long saddr, unsigned len)
{
struct enet_header *eth;
eth = (struct enet_header *)buff;
eth->type = net16(type);
memcpy (eth->saddr, dev->dev_addr, dev->addr_len);
if (daddr == 0)
{
memset (eth->daddr, 0xff, dev->addr_len);
return (14);
}
if (!arp_find (eth->daddr, daddr, dev, saddr))
{
return (14);
}
else
{
*(unsigned long *)eth->saddr = saddr;
return (-14);
}
}
int
eth_rebuild_header (void *buff, struct device *dev)
{
struct enet_header *eth;
eth = buff;
if (arp_find(eth->daddr, *(unsigned long*)eth->daddr, dev,
*(unsigned long *)eth->saddr))
return (1);
memcpy (eth->saddr, dev->dev_addr, dev->addr_len);
return (0);
}
void
eth_add_arp (unsigned long addr, struct sk_buff *skb, struct device *dev)
{
struct enet_header *eh;
eh = (struct enet_header *)(skb + 1);
arp_add (addr, eh->saddr, dev);
}
unsigned short
eth_type_trans (struct sk_buff *skb, struct device *dev)
{
struct enet_header *eh;
eh = (struct enet_header *)(skb + 1);
return (eh->type);
}
/* eth.h */
/*
Copyright (C) 1992 Ross Biro
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
#ifndef _TCP_ETH_H
#define _TCP_ETH_H
#define ETHER_MIN_LEN 64
#define ETHER_ADDR_LEN 6
#define ETHERTYPE_ARP 0x806
#define ETHERTYPE_IP 0x800
#define ETHER_TYPE 1
/* Reciever modes */
#define ETH_MODE_MONITOR 1 /* Monitor mode - no receive */
#define ETH_MODE_PHYSICAL 2 /* Physical address receive only */
#define ETH_MODE_BROADCAST 3 /* Broadcast receive + mode 2 */
#define ETH_MODE_MULTICAST 4 /* Multicast receive + mode 3 */
#define ETH_MODE_PROMISCUOUS 5 /* Promiscuous mode - receive all */
#define WD_RX_SAVE_ERRORS 1 /* save error packets */
#define WD_RX_RUNT 2 /* accept runt packets */
#define WD_RX_BROAD 4 /* accept broadcast packets */
#define WD_RX_MULTI 8 /* accept multicast packets */
#define WD_RX_PROM 0x10 /* accept all packets */
#define WD_RX_MON 0x20 /* monitor mode (just count packets) */
#define NET16(x) (((x&0xff)<<8)|((x>>8)&0xff))
struct enet_header
{
unsigned char daddr[ETHER_ADDR_LEN];
unsigned char saddr[ETHER_ADDR_LEN];
unsigned short type;
};
#define ETHER_HEADER sizeof(struct enet_header)
struct enet_statistics{
int rx_packets; /* total packets received */
int tx_packets; /* total packets transmitted */
int rx_errors; /* bad packets received */
int tx_errors; /* packet transmit problems */
int rx_dropped; /* no space in linux buffers */
int tx_dropped; /* no space available in linux */
int collisions; /* total number of collisions */
int multicast; /* multicast packets received */
/* detailed rx_errors: */
int rx_length_errors;
int rx_over_errors; /* receiver overwrote ring buffer in card */
int rx_crc_errors; /* received packet with crc error */
int rx_frame_errors; /* received frame alignment error */
int rx_fifo_errors; /* receiver fifo overrun */
int rx_missed_errors; /* receiver missed packet */
/* detailed tx_errors */
int tx_aborted_errors;
int tx_carrier_errors;
int tx_fifo_errors;
int tx_heartbeat_errors;
int tx_window_errors;
};
void print_eth(struct enet_header *eth);
int eth_hard_header (unsigned char *buff, struct device *dev,
unsigned short type, unsigned long daddr,
unsigned long saddr, unsigned len);
int eth_rebuild_header(void *eth, struct device *dev);
void eth_add_arp (unsigned long addr, struct sk_buff *skb,
struct device *dev);
unsigned short eth_type_trans (struct sk_buff *skb, struct device *dev);
#endif
/* Internet Control Message Protocol (ICMP) icmp.c */
/*
Copyright (C) 1992 Bob Harris
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The Author of tcpip package may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
The author of this file may be reached at rth@sparta.com or Sparta, Inc.
7926 Jones Branch Dr. Suite 900, McLean Va 22102.
*/
/* modified by Ross Biro bir7@leland.stanford.edu to do more than just
echo responses. */
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/kernel.h> /* free_s */
#include <linux/fcntl.h>
#include <linux/socket.h>
#include <netinet/in.h>
#include "timer.h"
#include "ip.h"
#include "tcp.h"
#include "sock.h"
#include <linux/errno.h>
#include <linux/timer.h>
#include <asm/system.h>
#include <asm/segment.h>
#include "../kern_sock.h" /* for PRINTK */
#include "icmp.h"
#define min(a,b) ((a)<(b)?(a):(b))
/* an array of errno for error messages from dest unreach. */
struct icmp_err icmp_err_convert[]=
{
{ENETUNREACH, 1},
{EHOSTUNREACH, 1},
{ENOPROTOOPT, 1},
{ECONNREFUSED, 1},
{EOPNOTSUPP, 0},
{EOPNOTSUPP, 0},
{ENETUNREACH, 1},
{EHOSTDOWN, 1},
{ENONET, 1},
{ENETUNREACH, 1},
{EHOSTUNREACH, 1},
{EOPNOTSUPP, 0},
{EOPNOTSUPP, 0}
};
void
print_icmph (struct icmp_header *icmph)
{
PRINTK (" type = %d, code = %d, checksum = %X\n", icmph->type,
icmph->code, icmph->checksum);
PRINTK (" gateway = %X\n", icmph->un.gateway);
}
/* sends an icmp message in response to a packet. */
void
icmp_reply (struct sk_buff *skb_in, int type, int code, struct device *dev)
{
struct sk_buff *skb;
struct ip_header *iph;
int offset;
struct icmp_header *icmph;
int len;
/* get some memory for the replay. */
len = sizeof (*skb) + 8 /* amount of header to return. */ +
sizeof (struct icmp_header) +
64 /* enough for an ip header. */ +
dev->hard_header_len;
skb = malloc (len);
if (skb == NULL) return;
skb->mem_addr = skb;
skb->mem_len = len;
len -= sizeof (*skb);
/* find the ip header. */
iph = (struct ip_header *)(skb_in+1);
iph = (struct ip_header *)((unsigned char *)iph + dev->hard_header_len);
/* Build Layer 2-3 headers for message back to source */
offset = ip_build_header( skb, iph->daddr, iph->saddr,
&dev, IP_ICMP, NULL, len );
if (offset < 0)
{
skb->sk = NULL;
free_skb (skb, FREE_READ);
return;
}
/* Readjust length according to actual IP header size */
skb->len = offset + sizeof (struct icmp_header) + 8;
icmph = (struct icmp_header *)((unsigned char *)(skb+1) + offset);
icmph->type = type;
icmph->code = code;
icmph->checksum = 0; /* we don't need to compute this. */
icmph->un.gateway = 0; /* might as well 0 it. */
memcpy (icmph+1, iph+1, 8);
/* send it and free it. */
ip_queue_xmit (NULL, dev, skb, 1);
}
/* deals with incoming icmp packets. */
int
icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
unsigned long daddr, unsigned short len,
unsigned long saddr, int redo, struct ip_protocol *protocol )
{
int size, offset;
struct icmp_header *icmph, *icmphr;
struct sk_buff *skb;
unsigned char *buff;
/* drop broadcast packets. */
if ((daddr & 0xff000000) == 0 || (daddr & 0xff000000) == 0xff000000)
{
skb1->sk = NULL;
free_skb (skb1, FREE_READ);
return (0);
}
buff = skb1->h.raw;
icmph = (struct icmp_header *)buff;
/* Validate the packet first */
if( icmph->checksum )
{ /* Checksums Enabled? */
if( ip_compute_csum( (unsigned char *)icmph, len ) )
{
/* Failed checksum! */
PRINTK("\nICMP ECHO failed checksum!");
skb1->sk = NULL;
free_skb (skb1, FREE_READ);
return (0);
}
}
print_icmph(icmph);
/* Parse the ICMP message */
switch( icmph->type )
{
case ICMP_DEST_UNREACH:
case ICMP_SOURCE_QUENCH:
{
struct ip_header *iph;
struct ip_protocol *ipprot;
unsigned char hash;
int err;
err = icmph->type << 8 | icmph->code;
/* we need to cause the socket to be closed and the error message
to be set appropriately. */
iph = (struct ip_header *)(icmph+1);
/* get the protocol(s) */
hash = iph->protocol & (MAX_IP_PROTOS -1 );
for (ipprot = ip_protos[hash]; ipprot != NULL; ipprot=ipprot->next)
{
/* pass it off to everyone who wants it. */
ipprot->err_handler (err, (unsigned char *)iph+4*iph->ihl,
iph->daddr, iph->saddr, ipprot);
}
skb1->sk = NULL;
free_skb (skb1, FREE_READ);
return (0);
}
case ICMP_REDIRECT:
{
/* we need to put a new route in the routing table. */
struct rtable *rt; /* we will add a new route. */
struct ip_header *iph;
iph = (struct ip_header *)(icmph+1);
rt = malloc (sizeof (*rt));
if (rt != NULL)
{
rt->net = iph->daddr;
/* assume class C network. Technically this is incorrect,
but will give it a try. */
if ((icmph->code & 1) == 0) rt->net &= 0x00ffffff;
rt->dev = dev;
rt->router = icmph->un.gateway;
add_route (rt);
}
skb1->sk = NULL;
free_skb (skb1, FREE_READ);
return (0);
}
case ICMP_ECHO:
/* Allocate an sk_buff response buffer (assume 64 byte IP header) */
size = sizeof( struct sk_buff ) + dev->hard_header_len + 64 + len;
skb = malloc( size );
if (skb == NULL)
{
skb1->sk = NULL;
free_skb (skb1, FREE_READ);
return (0);
}
skb->sk = NULL;
skb->mem_addr = skb;
skb->mem_len = size;
/* Build Layer 2-3 headers for message back to source */
offset = ip_build_header( skb, daddr, saddr, &dev, IP_ICMP, opt, len );
if (offset < 0)
{
/* Problems building header */
PRINTK("\nCould not build IP Header for ICMP ECHO Response");
free_s (skb->mem_addr, skb->mem_len);
skb1->sk = NULL;
free_skb (skb1, FREE_READ);
return( 0 ); /* just toss the received packet */
}
/* Readjust length according to actual IP header size */
skb->len = offset + len;
/* Build ICMP_ECHO Response message */
icmphr = (struct icmp_header *)( (char *)( skb + 1 ) + offset );
memcpy( (char *)icmphr, (char *)icmph, len );
icmphr->type = ICMP_ECHOREPLY;
icmphr->code = 0;
icmphr->checksum = 0;
if( icmph->checksum )
{ /* Calculate Checksum */
icmphr->checksum = ip_compute_csum( (void *)icmphr, len );
}
/* Ship it out - free it when done */
ip_queue_xmit( (volatile struct sock *)NULL, dev, skb, 1 );
skb1->sk = NULL;
free_skb (skb1, FREE_READ);
return( 0 );
default:
PRINTK("\nUnsupported ICMP type = x%x", icmph->type );
skb1->sk = NULL;
free_skb (skb1, FREE_READ);
return( 0 ); /* just toss the packet */
}
/* should be unecessary, but just in case. */
skb1->sk = NULL;
free_skb (skb1, FREE_READ);
return( 0 ); /* just toss the packet */
}
/* Internet Control Message Protocol (ICMP) header file */
#define ICMP_ECHOREPLY 0
#define ICMP_DEST_UNREACH 3
#define ICMP_SOURCE_QUENCH 4
#define ICMP_REDIRECT 5
#define ICMP_ECHO 8
#define ICMP_TIME_EXCEEDED 11
#define ICMP_PARAMETERPROB 12
#define ICMP_TIMESTAMP 13
#define ICMP_TIMESTAMPREPLY 14
#define ICMP_INFO_REQUEST 15
#define ICMP_INFO_REPLY 16
/* used by unreachable. */
#define ICMP_NET_UNREACH 0
#define ICMP_HOST_UNREACH 1
#define ICMP_PROT_UNREACH 2
#define ICMP_PORT_UNREACH 3 /* lots of room for confusion. */
#define ICMP_FRAG_NNEDED 4
#define ICMP_SR_FAILED 5
#define ICMP_NET_UNKNOWN 6
#define ICMP_HOST_UNKNOWN 7
#define ICMP_HOST_ISOLATED 8
#define ICMP_NET_ANO 9
#define ICMP_HOST_ANO 10
#define ICMP_NET_UNR_TOS 11
#define ICMP_HOST_UNR_TOS 12
struct icmp_header
{
unsigned char type;
unsigned char code;
unsigned short checksum;
union
{
struct
{
unsigned short id;
unsigned short sequence;
} echo;
unsigned long gateway;
} un;
};
struct icmp_err
{
int errno;
unsigned fatal:1;
};
extern struct icmp_err icmp_err_convert[];
int
icmp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
unsigned long daddr, unsigned short len,
unsigned long saddr, int redo, struct ip_protocol *protocol);
void
icmp_reply (struct sk_buff *skb_in, int type, int code, struct device *dev);
This diff is collapsed.
/* ip.h */
/*
Copyright (C) 1992 Ross Biro
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
#ifndef _TCP_IP_H
#define _TCP_IP_H
#include "dev.h"
#include <linux/sock_ioctl.h>
#include <netinet/protocols.h>
struct rtable
{
unsigned long net;
unsigned long router;
struct device *dev;
struct rtable *next;
};
struct route
{
char route_size;
char pointer;
unsigned long route[MAX_ROUTE];
};
struct timestamp
{
unsigned char len;
unsigned char ptr;
union
{
unsigned char flags:4, overflow:4;
unsigned char full_char;
} x;
unsigned long data[9];
};
struct options
{
struct route record_route;
struct route loose_route;
struct route strict_route;
struct timestamp tstamp;
unsigned short security;
unsigned short compartment;
unsigned short handling;
unsigned short stream;
unsigned tcc;
};
struct ip_header
{
unsigned char ihl:4, version:4;
unsigned char tos;
unsigned short tot_len;
unsigned short id;
unsigned short frag_off;
unsigned char ttl;
unsigned char protocol;
unsigned short check;
unsigned long saddr;
unsigned long daddr;
/*The options start here. */
};
#define IPOPT_END 0
#define IPOPT_NOOP 1
#define IPOPT_SEC 130
#define IPOPT_LSRR 131
#define IPOPT_SSRR 137
#define IPOPT_RR 7
#define IPOPT_SID 136
#define IPOPT_TIMESTAMP 68
#define IP_LOOPBACK_ADDR 0x0100007f
static inline unsigned short
net16(unsigned short x)
{
__asm__("xchgb %%cl,%%ch": "=c" (x) : "0" (x) : "cx");
return (x);
}
static inline unsigned long
net32(unsigned long x)
{
__asm__("xchgb %%cl,%%ch\n"
"\t roll $16,%%ecx\n"
"\t xchgb %%cl,%%ch":"=c" (x):"0"(x):"cx");
return (x);
}
/* change the name of this. */
#define MAX_IP_PROTOS 32 /* Must be a power of 2 */
/* This is used to register protocols. */
struct ip_protocol
{
int (*handler) (struct sk_buff *skb, struct device *dev,
struct options *opt, unsigned long daddr,
unsigned short len, unsigned long saddr,
int redo, struct ip_protocol *protocol);
void (*err_handler) (int err, unsigned char *buff, unsigned long daddr,
unsigned long saddr, struct ip_protocol *ipprot);
struct ip_protocol *next;
unsigned char protocol;
unsigned char copy:1;
void *data;
};
extern struct ip_protocol *ip_protocol_base;
extern struct ip_protocol *ip_protos[MAX_IP_PROTOS];
#define MAX_IP_ADDRES 5
extern unsigned long ip_addr[MAX_IP_ADDRES];
#define MY_IP_ADDR ip_addr[0];
int my_ip_addr(unsigned long);
#include "eth.h"
void
print_iph (struct ip_header *);
void
print_eth (struct enet_header *);
int ip_set_dev (struct ip_config *);
int ip_build_header(struct sk_buff *skb, unsigned long saddr,
unsigned long daddr, struct device **dev, int type,
struct options *opt, int len);
void ip_queue_xmit (volatile struct sock *sk, struct device *dev,
struct sk_buff *skb, int free);
void ip_retransmit(volatile struct sock *sk, int all);
int ip_rcv(struct sk_buff *buff, struct device *dev, struct packet_type *);
void add_ip_protocol (struct ip_protocol *);
int delete_ip_protocol (struct ip_protocol *);
int ip_handoff (volatile struct sock *sk);
unsigned short ip_compute_csum (unsigned char *buff, int len);
int ip_addr_match (unsigned long, unsigned long);
void add_route (struct rtable *rt);
void ip_route_check (unsigned long daddr);
#endif
/* loopback.c contains the loopback device functions. */
/*
Copyright (C) 1992 Ross Biro
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/tty.h>
#include <linux/types.h>
#include <linux/ptrace.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/io.h>
#include <asm/memory.h>
#include <errno.h>
#include <linux/fcntl.h>
#include <netinet/in.h>
#include "dev.h"
#include "eth.h"
#include "timer.h"
#include "ip.h"
#include "tcp.h"
#include "sock.h"
#include "arp.h"
#include "../kern_sock.h" /* for PRINTK */
static int
loopback_xmit(struct sk_buff *skb, struct device *dev)
{
static int inuse=0;
struct enet_header *eth;
int i;
int done;
static unsigned char buff[2048];
unsigned char *tmp;
PRINTK ("loopback_xmit (dev = %X)\n", dev);
cli();
if (inuse)
{
sti();
return (1);
}
inuse = 1;
sti();
tmp = NULL;
done = dev_rint ((unsigned char *)(skb+1), skb->len, 0, dev);
if (skb->free)
free_skb (skb, FREE_WRITE);
while (done != 1)
{
if (done != -1 && (i = dev_tint (buff,dev)) != 0)
{
/* print out the buffer. */
PRINTK ("ethernet xmit: \n");
eth = (struct enet_header *)buff;
print_eth (eth);
tmp = buff;
done = dev_rint (buff, i, 0, dev);
if (done != -1) tmp = NULL;
}
else
{
done = dev_rint (tmp, 0, 0, dev);
}
}
inuse = 0;
return (0);
}
void
loopback_init(struct device *dev)
{
printk ("Loopback device init\n");
/* initialize the rest of the device structure. */
dev->mtu = 2000; /* mtu */
dev->hard_start_xmit = loopback_xmit;
dev->open = NULL;
dev->hard_header = eth_hard_header;
dev->add_arp = NULL;
dev->hard_header_len = sizeof (struct enet_header);
dev->addr_len = ETHER_ADDR_LEN;
dev->type = ETHER_TYPE;
dev->queue_xmit = dev_queue_xmit;
dev->rebuild_header = eth_rebuild_header;
dev->type_trans = eth_type_trans;
dev->loopback = 1;
}
/* pack_type.c - implements raw packet sockets. */
/*
Copyright (C) 1992 Ross Biro
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
#include <linux/stddef.h>
#include "dev.h"
#include "eth.h"
extern int arp_rcv (struct sk_buff *skb, struct device *dev,
struct packet_type *pt);
static struct packet_type arp_packet_type=
{
NET16(ETHERTYPE_ARP),
0, /* copy */
arp_rcv,
NULL,
NULL /* next */
};
extern int ip_rcv (struct sk_buff *skb, struct device *dev,
struct packet_type *pt);
static struct packet_type ip_packet_type=
{
NET16(ETHERTYPE_IP),
0, /* copy */
ip_rcv,
NULL,
&arp_packet_type
};
struct packet_type *ptype_base = &ip_packet_type;
/* packet.c - implements raw packet sockets. */
/*
Copyright (C) 1992 Ross Biro
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/fcntl.h>
#include <linux/socket.h>
#include <netinet/in.h>
#include "timer.h"
#include "ip.h"
#include "tcp.h"
#include "sock.h"
#include <linux/errno.h>
#include <linux/timer.h>
#include <asm/system.h>
#include <asm/segment.h>
#include "../kern_sock.h" /* for PRINTK */
extern struct proto raw_prot;
static unsigned long
min(unsigned long a, unsigned long b)
{
if (a < b) return (a);
return (b);
}
/* this should be the easiest of all, all we do is copy it into
a buffer. */
int
packet_rcv (struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{
volatile struct sock *sk;
sk = pt->data;
skb->dev = dev;
skb->len += dev->hard_header_len;
/* now see if we are in use. */
cli();
if (sk->inuse)
{
sti();
/* drop any packets if we can't currently deal with them.
Assume that the other end will retransmit if it was
important. */
skb->sk = NULL;
free_skb (skb, FREE_READ);
return (0);
}
sk->inuse = 1;
sti ();
skb->sk = sk;
/* charge it too the socket. */
if (sk->rmem_alloc + skb->mem_len >= SK_RMEM_MAX)
{
skb->sk = NULL;
free_skb (skb, FREE_READ);
return (0);
}
sk->rmem_alloc += skb->mem_len;
/* now just put it onto the queue. */
if (sk->rqueue == NULL)
{
sk->rqueue = skb;
skb->next = skb;
skb->prev = skb;
}
else
{
skb->next = sk->rqueue;
skb->prev = sk->rqueue->prev;
skb->prev->next = skb;
skb->next->prev = skb;
}
wake_up (sk->sleep);
release_sock (sk);
return (0);
}
/* this will do terrible things if len + ipheader + devheader > dev->mtu */
static int
packet_sendto (volatile struct sock *sk, unsigned char *from, int len,
int noblock,
unsigned flags, struct sockaddr_in *usin, int addr_len)
{
struct sk_buff *skb;
struct device *dev;
struct sockaddr saddr;
/* check the flags. */
if (flags) return (-EINVAL);
if (len < 0) return (-EINVAL);
/* get and verify the address. */
if (usin)
{
if (addr_len < sizeof (saddr))
return (-EINVAL);
verify_area (usin, sizeof (saddr));
memcpy_fromfs (&saddr, usin, sizeof(saddr));
}
else
return (-EINVAL);
skb = sk->prot->wmalloc (sk, len+sizeof (*skb) + sk->prot->max_header, 0);
/* this shouldn't happen, but it could. */
if (skb == NULL)
{
PRINTK ("packet_sendto: write buffer full?\n");
print_sk (sk);
return (-EAGAIN);
}
skb->mem_addr = skb;
skb->mem_len = len + sizeof (*skb) +sk->prot->max_header;
skb->sk = sk;
skb->free = 1;
saddr.sa_data[13] = 0;
dev = get_dev (saddr.sa_data);
if (dev == NULL)
{
sk->prot->wfree (sk, skb->mem_addr, skb->mem_len);
return (-ENXIO);
}
verify_area (from, len);
memcpy_fromfs (skb+1, from, len);
skb->len = len;
skb->next = NULL;
if (dev->up)
dev->queue_xmit (skb, dev, sk->priority);
else
free_skb (skb, FREE_WRITE);
return (len);
}
static int
packet_write (volatile struct sock *sk, unsigned char *buff,
int len, int noblock, unsigned flags)
{
return (packet_sendto (sk, buff, len, noblock, flags, NULL, 0));
}
static void
packet_close (volatile struct sock *sk, int timeout)
{
sk->inuse = 1;
sk->state = TCP_CLOSE;
dev_remove_pack ((struct packet_type *)sk->pair);
free_s ((void *)sk->pair, sizeof (struct packet_type));
release_sock (sk);
}
static int
packet_init (volatile struct sock *sk)
{
struct packet_type *p;
p = malloc (sizeof (*p));
if (p == NULL) return (-ENOMEM);
p->func = packet_rcv;
p->type = sk->num;
p->data = (void *)sk;
dev_add_pack (p);
/* we need to remember this somewhere. */
sk->pair = (volatile struct sock *)p;
return (0);
}
int
packet_recvfrom (volatile struct sock *sk, unsigned char *to, int len,
int noblock,
unsigned flags, struct sockaddr_in *sin, int *addr_len)
{
/* this should be easy, if there is something there we
return it, otherwise we block. */
int copied=0;
struct sk_buff *skb;
struct sockaddr *saddr;
saddr = (struct sockaddr *)sin;
if (len == 0) return (0);
if (len < 0) return (-EINVAL);
if (addr_len)
{
verify_area (addr_len, sizeof(*addr_len));
put_fs_long (sizeof (*saddr), addr_len);
}
sk->inuse = 1;
while (sk->rqueue == NULL)
{
if (noblock)
{
release_sock (sk);
return (-EAGAIN);
}
release_sock (sk);
cli();
if (sk->rqueue == NULL)
{
interruptible_sleep_on (sk->sleep);
if (current->signal & ~current->blocked)
{
return (-ERESTARTSYS);
}
}
sti();
}
skb = sk->rqueue;
if (!(flags & MSG_PEEK))
{
if (skb->next == skb )
{
sk->rqueue = NULL;
}
else
{
sk->rqueue = sk->rqueue ->next;
skb->prev->next = skb->next;
skb->next->prev = skb->prev;
}
}
copied = min (len, skb->len);
verify_area (to, copied);
memcpy_tofs (to, skb+1, copied);
/* copy the address. */
if (saddr)
{
struct sockaddr addr;
addr.sa_family = skb->dev->type;
memcpy (addr.sa_data,skb->dev->name, 14);
verify_area (saddr, sizeof (*saddr));
memcpy_tofs(saddr, &addr, sizeof (*saddr));
}
if (!(flags & MSG_PEEK))
{
free_skb (skb, FREE_READ);
}
release_sock (sk);
return (copied);
}
int
packet_read (volatile struct sock *sk, unsigned char *buff,
int len, int noblock, unsigned flags)
{
return (packet_recvfrom (sk, buff, len, noblock, flags, NULL, NULL));
}
int udp_connect (volatile struct sock *sk, struct sockaddr_in *usin,
int addr_len);
int udp_select (volatile struct sock *sk, int sel_type, select_table *wait);
struct proto packet_prot =
{
sock_wmalloc,
sock_rmalloc,
sock_wfree,
sock_rfree,
sock_rspace,
sock_wspace,
packet_close,
packet_read,
packet_write,
packet_sendto,
packet_recvfrom,
ip_build_header,
udp_connect,
NULL,
ip_queue_xmit,
ip_retransmit,
NULL,
NULL,
NULL,
udp_select,
NULL,
packet_init,
128,
0,
{NULL,}
};
/* protocols.c */
/* these headers are overkill, but until I clean up the socket header
files, this is the best way. */
#include <asm/segment.h>
#include <asm/system.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/socket.h>
#include <netinet/in.h>
#include "timer.h"
#include "ip.h"
#include "tcp.h"
#include "sock.h"
#include "icmp.h"
int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
unsigned long daddr, unsigned short len,
unsigned long saddr, int redo, struct ip_protocol *protocol);
void udp_err (int err, unsigned char *header, unsigned long daddr,
unsigned long saddr, struct ip_protocol *protocol);
int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
unsigned long daddr, unsigned short len,
unsigned long saddr, int redo, struct ip_protocol *protocol);
void tcp_err (int err, unsigned char *header, unsigned long daddr,
unsigned long saddr, struct ip_protocol *protocol);
int icmp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
unsigned long daddr, unsigned short len,
unsigned long saddr, int redo, struct ip_protocol *protocol);
static struct ip_protocol tcp_protocol =
{
tcp_rcv,
tcp_err,
NULL,
IP_TCP,
0, /* copy */
NULL
};
static struct ip_protocol udp_protocol =
{
udp_rcv,
udp_err,
&tcp_protocol,
IP_UDP,
0, /* copy */
NULL
};
static struct ip_protocol icmp_protocol =
{
icmp_rcv,
NULL,
&udp_protocol,
IP_ICMP,
0, /* copy */
NULL
};
struct ip_protocol *ip_protocol_base = &icmp_protocol;
/* raw.c - implements raw ip sockets. */
/*
Copyright (C) 1992 Ross Biro
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/fcntl.h>
#include <linux/socket.h>
#include <netinet/in.h>
#include "timer.h"
#include "ip.h"
#include "tcp.h"
#include "sock.h"
#include <linux/errno.h>
#include <linux/timer.h>
#include <asm/system.h>
#include <asm/segment.h>
#include "../kern_sock.h" /* for PRINTK */
extern struct proto raw_prot;
static unsigned long
min(unsigned long a, unsigned long b)
{
if (a < b) return (a);
return (b);
}
/* this should be the easiest of all, all we do is copy it into
a buffer. */
int
raw_rcv (struct sk_buff *skb, struct device *dev, struct options *opt,
unsigned long daddr, unsigned short len, unsigned long saddr,
int redo, struct ip_protocol *protocol)
{
volatile struct sock *sk;
sk = protocol->data;
/* now we need to copy this into memory. */
if (!redo )
{
skb->dev = dev;
skb->saddr = daddr;
skb->daddr = saddr;
/* now see if we are in use. */
cli();
if (sk->inuse)
{
PRINTK ("raw_rcv adding to backlog. \n");
if (sk->back_log == NULL)
{
sk->back_log = skb;
skb->next = skb;
skb->prev = skb;
}
else
{
skb->next = sk->back_log;
skb->prev = sk->back_log->prev;
skb->prev->next = skb;
skb->next->prev = skb;
}
sti();
return (0);
}
sk->inuse = 1;
sti();
}
skb->sk = sk;
skb->len = len;
/* charge it too the socket. */
if (sk->rmem_alloc + skb->mem_len >= SK_RMEM_MAX)
{
skb->sk = NULL;
free_skb (skb, FREE_READ);
return (0);
}
sk->rmem_alloc += skb->mem_len;
/* now just put it onto the queue. */
if (sk->rqueue == NULL)
{
sk->rqueue = skb;
skb->next = skb;
skb->prev = skb;
}
else
{
skb->next = sk->rqueue;
skb->prev = sk->rqueue->prev;
skb->prev->next = skb;
skb->next->prev = skb;
}
skb->len = len;
wake_up (sk->sleep);
release_sock (sk);
return (0);
}
static int
raw_loopback (volatile struct sock *sk, int prot, char *from, int len,
unsigned long daddr)
{
/* just pretend it just came in. */
struct sk_buff *skb;
int err;
skb = malloc (len+sizeof (*skb));
if (skb == NULL) return (-ENOMEM);
skb->mem_addr = skb;
skb->mem_len = len + sizeof (*skb);
skb->h.raw = (unsigned char *)(skb+1);
verify_area (from, len);
memcpy_fromfs (skb+1, from, len);
err = raw_rcv (skb, NULL, NULL, daddr, len, sk->saddr, prot, 0);
return (err);
}
/* this will do terrible things if len + ipheader + devheader > dev->mtu */
static int
raw_sendto (volatile struct sock *sk, unsigned char *from, int len,
int noblock,
unsigned flags, struct sockaddr_in *usin, int addr_len)
{
struct sk_buff *skb;
struct device *dev=NULL;
struct sockaddr_in sin;
int tmp;
/* check the flags. */
if (flags) return (-EINVAL);
if (len < 0) return (-EINVAL);
/* get and verify the address. */
if (usin)
{
if (addr_len < sizeof (sin))
return (-EINVAL);
verify_area (usin, sizeof (sin));
memcpy_fromfs (&sin, usin, sizeof(sin));
if (sin.sin_family &&
sin.sin_family != AF_INET)
return (-EINVAL);
}
else
{
if (sk->state != TCP_ESTABLISHED)
return (-EINVAL);
sin.sin_family = AF_INET;
sin.sin_port = sk->protocol;
sin.sin_addr.s_addr = sk->daddr;
}
if (sin.sin_port == 0) sin.sin_port = sk->protocol;
if ((sin.sin_addr.s_addr & 0xff000000) == 0)
{
int err;
err = raw_loopback (sk, sin.sin_port, from, len,
sin.sin_addr.s_addr);
if (err < 0) return (err);
}
sk->inuse = 1;
skb = sk->prot->wmalloc (sk, len+sizeof (*skb) + sk->prot->max_header, 0);
/* this shouldn't happen, but it could. */
if (skb == NULL)
{
PRINTK ("raw_sendto: write buffer full?\n");
print_sk (sk);
release_sock (sk);
return (-EAGAIN);
}
skb->mem_addr = skb;
skb->mem_len = len + sizeof (*skb) +sk->prot->max_header;
skb->sk = sk;
skb->free = 1; /* these two should be unecessary. */
skb->arp = 0;
tmp = sk->prot->build_header (skb, sk->saddr,
sin.sin_addr.s_addr, &dev,
sk->protocol, sk->opt, skb->mem_len);
if (tmp < 0)
{
sk->prot->wfree (sk, skb->mem_addr, skb->mem_len);
release_sock (sk);
return (tmp);
}
verify_area (from, len);
memcpy_fromfs (skb+1, from, len);
skb->len = tmp + len;
sk->prot->queue_xmit (sk, dev, skb, 1);
return (len);
}
static int
raw_write (volatile struct sock *sk, unsigned char *buff, int len, int noblock,
unsigned flags)
{
return (raw_sendto (sk, buff, len, noblock, flags, NULL, 0));
}
static void
raw_close (volatile struct sock *sk, int timeout)
{
sk->inuse = 1;
sk->state = TCP_CLOSE;
delete_ip_protocol ((struct ip_protocol *)sk->pair);
free_s ((void *)sk->pair, sizeof (struct ip_protocol));
release_sock (sk);
}
static int
raw_init (volatile struct sock *sk)
{
struct ip_protocol *p;
p = malloc (sizeof (*p));
if (p == NULL) return (-ENOMEM);
p->handler = raw_rcv;
p->protocol = sk->protocol;
p->data = (void *)sk;
add_ip_protocol (p);
/* we need to remember this somewhere. */
sk->pair = (volatile struct sock *)p;
return (0);
}
int
raw_recvfrom (volatile struct sock *sk, unsigned char *to, int len,
int noblock,
unsigned flags, struct sockaddr_in *sin, int *addr_len)
{
/* this should be easy, if there is something there we
return it, otherwise we block. */
int copied=0;
struct sk_buff *skb;
if (len == 0) return (0);
if (len < 0) return (-EINVAL);
if (addr_len)
{
verify_area (addr_len, sizeof(*addr_len));
put_fs_long (sizeof (*sin), addr_len);
}
sk->inuse = 1;
while (sk->rqueue == NULL)
{
if (noblock)
{
release_sock (sk);
return (-EAGAIN);
}
release_sock (sk);
cli();
if (sk->rqueue == NULL)
{
interruptible_sleep_on (sk->sleep);
if (current->signal & ~current->blocked)
{
return (-ERESTARTSYS);
}
}
sti();
}
skb = sk->rqueue;
if (!(flags & MSG_PEEK))
{
if (skb->next == skb )
{
sk->rqueue = NULL;
}
else
{
sk->rqueue = sk->rqueue ->next;
skb->prev->next = skb->next;
skb->next->prev = skb->prev;
}
}
copied = min (len, skb->len);
verify_area (to, copied);
memcpy_tofs (to, skb->h.raw, copied);
/* copy the address. */
if (sin)
{
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = skb->daddr;
verify_area (sin, sizeof (*sin));
memcpy_tofs(sin, &addr, sizeof (*sin));
}
if (!(flags & MSG_PEEK))
{
free_skb (skb, FREE_READ);
}
release_sock (sk);
return (copied);
}
int
raw_read (volatile struct sock *sk, unsigned char *buff, int len, int noblock,
unsigned flags)
{
return (raw_recvfrom (sk, buff, len, noblock, flags, NULL, NULL));
}
int udp_connect (volatile struct sock *sk, struct sockaddr_in *usin,
int addr_len);
int udp_select (volatile struct sock *sk, int sel_type, select_table *wait);
struct proto raw_prot =
{
sock_wmalloc,
sock_rmalloc,
sock_wfree,
sock_rfree,
sock_rspace,
sock_wspace,
raw_close,
raw_read,
raw_write,
raw_sendto,
raw_recvfrom,
ip_build_header,
udp_connect,
NULL,
ip_queue_xmit,
ip_retransmit,
NULL,
NULL,
raw_rcv,
udp_select,
NULL,
raw_init,
128,
0,
{NULL,}
};
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* timer.h */
/*
Copyright (C) 1992 Ross Biro
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
#ifndef _TCP_TIMER_H
#define _TCP_TIMER_H
struct timer
{
unsigned long len;
volatile struct sock *sk;
unsigned long when;
struct timer *next;
};
void delete_timer (struct timer *);
void reset_timer (struct timer *);
void net_timer (void);
#define SEQ_TICK 3
#define timer_seq jiffies
extern unsigned long seq_offset;
#endif
This diff is collapsed.
/* udp.h */
/*
Copyright (C) 1992 Ross Biro
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
#ifndef _TCP_UDP_H
#define _TCP_UDP_H
struct udp_header
{
unsigned short source;
unsigned short dest;
unsigned short len;
unsigned short check;
};
extern struct proto udp_prot;
#define UDP_NO_CHECK 1
#endif
This diff is collapsed.
This diff is collapsed.
......@@ -32,7 +32,7 @@
#define MINIX_HEADER 32
#define GCC_HEADER 1024
#define SYS_SIZE 0x5000
#define SYS_SIZE 0x7000
#define DEFAULT_MAJOR_ROOT 0
#define DEFAULT_MINOR_ROOT 0
......
#define UTS_RELEASE "0.97.pl5-15"
#define UTS_VERSION "09/19/92"
#define LINUX_COMPILE_TIME "13:29:53"
#define UTS_RELEASE "0.98-21"
#define UTS_VERSION "09/29/92"
#define LINUX_COMPILE_TIME "20:36:17"
#define LINUX_COMPILE_BY "root"
#define LINUX_COMPILE_HOST "home"
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment