Commit 26a34b16 authored by Linus Torvalds's avatar Linus Torvalds

[PATCH] Linux-0.99.1 (December 21, 1992)

Patch 1 addresses the following problems:
 - configuration. Hope there are no silly problems left..
 - inode.c: initialization changes (the missing NULL and some other
   minor fixes).
 - some SCSI tape driver patches (Kai M{kisara)
 - tcp/ip patches (Ross Biro, some code by me)
 - keyboard patches (mainly changed initialization - hope the keyboard
   lockups are gone).
 - completed /proc-fs: it should now contain all info needed by 'ps'
   (Micheal K Johnson).
 - various minor fixes (the minix-fs link overflow checking etc)

Patch1 also contains support for extended VC switching - this is for the
upcoming X11 that understands VC's.  One result of this is that console
redirection now redirects *only* messages actually sent to /dev/console
(aka /dev/tty0), not just to any foreground VC.  Wait for Xfree-1.2 to
be able to switch VC's while under X (yes, including several X-sessions
active at the same time..).

I hope there are still people out there that aren't too busy stuffing
themself with turkey to try out a new kernel release.  There is just
over a week left of this year, and I need feedback in order to be able
to release 1.0.

                Linus

PS.  Thanks to everybody who has sent me Christmas/New Year/Birthday
cards.  Some contained money, some didn't, and I enjoyed them all.
Thanks.
parent ad094925
...@@ -7,8 +7,8 @@ ...@@ -7,8 +7,8 @@
# #
CONFIG_BLK_DEV_HD = CONFIG_BLK_DEV_HD CONFIG_BLK_DEV_HD = CONFIG_BLK_DEV_HD
CONFIG_TCPIP = CONFIG_TCPIP CONFIG_TCPIP = CONFIG_TCPIP
CONFIG_PROFILE = CONFIG_PROFILE
CONFIG_MAX_16M = CONFIG_MAX_16M CONFIG_MAX_16M = CONFIG_MAX_16M
CONFIG_M486 = CONFIG_M486
# #
# SCSI support # SCSI support
......
#
# Make "config" the default target if there is no configuration file
#
ifeq (.config,$(wildcard .config))
include .config include .config
else
CONFIGURATION = config
endif
# #
# ROOT_DEV specifies the default root-device when making the image. # ROOT_DEV specifies the default root-device when making the image.
...@@ -69,6 +76,10 @@ SOUND_SUPPORT = -DKERNEL_SOUNDCARD -DDSP_BUFFSIZE=16384 -DSBC_IRQ=7 -DPAS_IRQ=5 ...@@ -69,6 +76,10 @@ SOUND_SUPPORT = -DKERNEL_SOUNDCARD -DDSP_BUFFSIZE=16384 -DSBC_IRQ=7 -DPAS_IRQ=5
CFLAGS = -Wall -O6 -fomit-frame-pointer CFLAGS = -Wall -O6 -fomit-frame-pointer
ifdef CONFIG_M486
CFLAGS := $(CFLAGS) -m486
endif
# #
# if you want the ram-disk device, define this to be the # if you want the ram-disk device, define this to be the
# size in blocks. # size in blocks.
...@@ -112,20 +123,31 @@ lilo: Image ...@@ -112,20 +123,31 @@ lilo: Image
/etc/lilo/install /etc/lilo/install
config: config:
ifdef CONFIGURATION
@echo
@echo "You have no .config: running Configure"
@echo
endif
sh Configure < config.in sh Configure < config.in
ifdef CONFIGURATION
@echo
@echo "Configure successful. Try re-making (ignore the error that follows)"
@echo
exit 1
endif
linuxsubdirs: dummy linuxsubdirs: dummy
@for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE)) || exit; done @for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE)) || exit; done
Version: Version: dummy
@./makever.sh @./makever.sh
@echo \#define UTS_RELEASE \"0.99-`cat .version`\" > tools/version.h @echo \#define UTS_RELEASE \"0.99.pl1-`cat .version`\" > tools/version.h
@echo \#define UTS_VERSION \"`date +%D`\" >> 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_TIME \"`date +%T`\" >> tools/version.h
@echo \#define LINUX_COMPILE_BY \"`whoami`\" >> tools/version.h @echo \#define LINUX_COMPILE_BY \"`whoami`\" >> tools/version.h
@echo \#define LINUX_COMPILE_HOST \"`hostname`\" >> tools/version.h @echo \#define LINUX_COMPILE_HOST \"`hostname`\" >> tools/version.h
Image: boot/bootsect boot/setup tools/system tools/build Image: $(CONFIGURATION) boot/bootsect boot/setup tools/system tools/build
cp tools/system system.tmp cp tools/system system.tmp
strip system.tmp strip system.tmp
tools/build boot/bootsect boot/setup system.tmp $(ROOT_DEV) > Image tools/build boot/bootsect boot/setup system.tmp $(ROOT_DEV) > Image
...@@ -162,8 +184,8 @@ boot/setup: boot/setup.s ...@@ -162,8 +184,8 @@ boot/setup: boot/setup.s
$(AS86) -o boot/setup.o boot/setup.s $(AS86) -o boot/setup.o boot/setup.s
$(LD86) -s -o boot/setup boot/setup.o $(LD86) -s -o boot/setup boot/setup.o
boot/setup.s: boot/setup.S include/linux/config.h boot/setup.s: boot/setup.S include/linux/config.h Makefile
$(CPP) -traditional boot/setup.S -o boot/setup.s $(CPP) -traditional $(SVGA_MODE) $(RAMDISK) boot/setup.S -o boot/setup.s
boot/bootsect.s: boot/bootsect.S include/linux/config.h Makefile boot/bootsect.s: boot/bootsect.S include/linux/config.h Makefile
$(CPP) -traditional $(SVGA_MODE) $(RAMDISK) boot/bootsect.S -o boot/bootsect.s $(CPP) -traditional $(SVGA_MODE) $(RAMDISK) boot/bootsect.S -o boot/bootsect.s
...@@ -195,7 +217,7 @@ depend dep: ...@@ -195,7 +217,7 @@ depend dep:
for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done > .depend for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done > .depend
for i in $(SUBDIRS); do (cd $$i && $(MAKE) dep) || exit; done for i in $(SUBDIRS); do (cd $$i && $(MAKE) dep) || exit; done
dummy: dummy: $(CONFIGURATION)
# #
# include a dependency file if one exists # include a dependency file if one exists
...@@ -203,3 +225,4 @@ dummy: ...@@ -203,3 +225,4 @@ dummy:
ifeq (.depend,$(wildcard .depend)) ifeq (.depend,$(wildcard .depend))
include .depend include .depend
endif endif
...@@ -78,8 +78,6 @@ go: mov ax,cs ...@@ -78,8 +78,6 @@ go: mov ax,cs
mov ds,ax mov ds,ax
mov es,ax mov es,ax
push ax
mov ss,ax ! put stack at INITSEG:0x4000-12. mov ss,ax ! put stack at INITSEG:0x4000-12.
mov sp,dx mov sp,dx
/* /*
...@@ -121,7 +119,7 @@ go: mov ax,cs ...@@ -121,7 +119,7 @@ go: mov ax,cs
seg fs seg fs
mov 2(bx),es mov 2(bx),es
pop ax mov ax,cs
mov fs,ax mov fs,ax
mov gs,ax mov gs,ax
......
...@@ -10,6 +10,8 @@ Kernel profiling support ...@@ -10,6 +10,8 @@ Kernel profiling support
CONFIG_PROFILE y/n n CONFIG_PROFILE y/n n
Limit to memory to low 16MB Limit to memory to low 16MB
CONFIG_MAX_16M y/n y CONFIG_MAX_16M y/n y
Use -m486 flag for 486-specific optimizations
CONFIG_M486 y/n y
: :
SCSI support SCSI support
. .
...@@ -27,9 +29,9 @@ CONFIG_BLK_DEV_SR y/n y ...@@ -27,9 +29,9 @@ CONFIG_BLK_DEV_SR y/n y
. .
SCSI low-level drivers SCSI low-level drivers
. .
Adaptek AHA1542 support Adaptec AHA1542 support
CONFIG_SCSI_AHA1542 y/n y CONFIG_SCSI_AHA1542 y/n y
Adaptek AHA1740 support Adaptec AHA1740 support
CONFIG_SCSI_AHA1740 y/n y CONFIG_SCSI_AHA1740 y/n y
Always IN support Always IN support
CONFIG_SCSI_ALWAYS y/n y CONFIG_SCSI_ALWAYS y/n y
...@@ -67,7 +69,7 @@ Accent Async 4 serial support ...@@ -67,7 +69,7 @@ Accent Async 4 serial support
CONFIG_ACCENT_ASYNC y/n n CONFIG_ACCENT_ASYNC y/n n
Logitech busmouse support Logitech busmouse support
CONFIG_BUSMOUSE y/n n CONFIG_BUSMOUSE y/n n
PS/2 mouse (aka 'auxilliary device') support PS/2 mouse (aka 'auxiliary device') support
CONFIG_PSMOUSE y/n n CONFIG_PSMOUSE y/n n
MicroSoft busmouse support MicroSoft busmouse support
CONFIG_MS_BUSMOUSE y/n n CONFIG_MS_BUSMOUSE y/n n
......
...@@ -376,17 +376,18 @@ static void read_omagic(struct inode *inode, int bytes) ...@@ -376,17 +376,18 @@ static void read_omagic(struct inode *inode, int bytes)
if (inode->i_sb) if (inode->i_sb)
block_size = inode->i_sb->s_blocksize; block_size = inode->i_sb->s_blocksize;
while (bytes > 0) { while (bytes > 0) {
if (!(blkno = bmap(inode, blk)))
sys_exit(-1);
if (!(bh = bread(inode->i_dev, blkno, block_size)))
sys_exit(-1);
n = (blk ? block_size : block_size - sizeof(struct exec)); n = (blk ? block_size : block_size - sizeof(struct exec));
if (bytes < n) if (bytes < n)
n = bytes; n = bytes;
blkno = bmap(inode, blk);
memcpy_tofs(dest, (blk ? bh->b_data : if (blkno) {
bh = bread(inode->i_dev, blkno, block_size);
if (!bh)
sys_exit(-1);
memcpy_tofs(dest, (blk ? bh->b_data :
bh->b_data + sizeof(struct exec)), n); bh->b_data + sizeof(struct exec)), n);
brelse(bh); brelse(bh);
}
++blk; ++blk;
dest += n; dest += n;
bytes -= n; bytes -= n;
......
...@@ -12,13 +12,19 @@ ...@@ -12,13 +12,19 @@
#include <asm/system.h> #include <asm/system.h>
static struct inode inode_table[NR_INODE]; static struct inode * inode_table;
static struct inode * last_inode = inode_table; static struct inode * last_inode;
static struct wait_queue * inode_wait; static struct wait_queue * inode_wait = NULL;
void inode_init(void) unsigned long inode_init(unsigned long start, unsigned long end)
{ {
memset(inode_table,0,sizeof(inode_table)); start += 0x0000000f;
start &= 0xfffffff0;
inode_table = (struct inode *) start;
last_inode = inode_table;
start = (unsigned long) (inode_table + NR_INODE);
memset(inode_table,0,NR_INODE*sizeof(struct inode));
return start;
} }
static void __wait_on_inode(struct inode *); static void __wait_on_inode(struct inode *);
......
...@@ -53,6 +53,19 @@ file.o : file.c /usr/include/asm/segment.h /usr/include/asm/system.h /usr/includ ...@@ -53,6 +53,19 @@ file.o : file.c /usr/include/asm/segment.h /usr/include/asm/system.h /usr/includ
/usr/include/linux/resource.h /usr/include/linux/vm86.h /usr/include/linux/math_emu.h \ /usr/include/linux/resource.h /usr/include/linux/vm86.h /usr/include/linux/math_emu.h \
/usr/include/linux/iso_fs.h /usr/include/linux/fcntl.h /usr/include/linux/errno.h \ /usr/include/linux/iso_fs.h /usr/include/linux/fcntl.h /usr/include/linux/errno.h \
/usr/include/linux/stat.h /usr/include/linux/locks.h /usr/include/linux/stat.h /usr/include/linux/locks.h
inode.o : inode.c /usr/include/linux/config.h /usr/include/linux/autoconf.h \
/usr/include/linux/stat.h /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 /usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h \
/usr/include/linux/msdos_fs_i.h /usr/include/linux/iso_fs_i.h /usr/include/linux/nfs_fs_i.h \
/usr/include/linux/nfs.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/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h \
/usr/include/linux/mm.h /usr/include/linux/kernel.h /usr/include/linux/signal.h \
/usr/include/linux/time.h /usr/include/linux/param.h /usr/include/linux/resource.h \
/usr/include/linux/vm86.h /usr/include/linux/math_emu.h /usr/include/linux/iso_fs.h \
/usr/include/linux/string.h /usr/include/linux/locks.h /usr/include/asm/system.h \
/usr/include/asm/segment.h /usr/include/linux/errno.h
namei.o : namei.c /usr/include/linux/sched.h /usr/include/linux/head.h /usr/include/linux/fs.h \ namei.o : namei.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/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/dirent.h /usr/include/linux/vfs.h /usr/include/linux/pipe_fs_i.h \
......
...@@ -18,10 +18,6 @@ ...@@ -18,10 +18,6 @@
#include <asm/segment.h> #include <asm/segment.h>
#include <linux/errno.h> #include <linux/errno.h>
#ifndef CONFIG_BLK_DEV_SR
#error The iso9660 filesystem can only be used with CDROM.
#endif
extern int check_cdrom_media_change(int, int); extern int check_cdrom_media_change(int, int);
#ifdef LEAK_CHECK #ifdef LEAK_CHECK
......
...@@ -304,6 +304,10 @@ int minix_mkdir(struct inode * dir, const char * name, int len, int mode) ...@@ -304,6 +304,10 @@ int minix_mkdir(struct inode * dir, const char * name, int len, int mode)
iput(dir); iput(dir);
return -EEXIST; return -EEXIST;
} }
if (dir->i_nlink > 250) {
iput(dir);
return -EMLINK;
}
inode = minix_new_inode(dir); inode = minix_new_inode(dir);
if (!inode) { if (!inode) {
iput(dir); iput(dir);
...@@ -695,6 +699,9 @@ static int do_minix_rename(struct inode * old_dir, const char * old_name, int ol ...@@ -695,6 +699,9 @@ static int do_minix_rename(struct inode * old_dir, const char * old_name, int ol
goto end_rename; goto end_rename;
if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino) if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
goto end_rename; goto end_rename;
retval = -EMLINK;
if (new_dir->i_nlink > 250)
goto end_rename;
} }
if (!new_bh) if (!new_bh)
new_bh = minix_add_entry(new_dir,new_name,new_len,&new_de); new_bh = minix_add_entry(new_dir,new_name,new_len,&new_de);
......
...@@ -7,7 +7,8 @@ array.o : array.c /usr/include/linux/types.h /usr/include/linux/errno.h /usr/inc ...@@ -7,7 +7,8 @@ array.o : array.c /usr/include/linux/types.h /usr/include/linux/errno.h /usr/inc
/usr/include/linux/msdos_fs_sb.h /usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h \ /usr/include/linux/msdos_fs_sb.h /usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h \
/usr/include/linux/mm.h /usr/include/linux/kernel.h /usr/include/linux/signal.h \ /usr/include/linux/mm.h /usr/include/linux/kernel.h /usr/include/linux/signal.h \
/usr/include/linux/time.h /usr/include/linux/param.h /usr/include/linux/resource.h \ /usr/include/linux/time.h /usr/include/linux/param.h /usr/include/linux/resource.h \
/usr/include/linux/vm86.h /usr/include/linux/math_emu.h /usr/include/asm/segment.h \ /usr/include/linux/vm86.h /usr/include/linux/math_emu.h /usr/include/linux/tty.h \
/usr/include/linux/termios.h /usr/include/asm/system.h /usr/include/asm/segment.h \
/usr/include/asm/io.h /usr/include/asm/io.h
base.o : base.c /usr/include/asm/segment.h /usr/include/linux/errno.h /usr/include/linux/sched.h \ base.o : base.c /usr/include/asm/segment.h /usr/include/linux/errno.h /usr/include/linux/sched.h \
/usr/include/linux/head.h /usr/include/linux/fs.h /usr/include/linux/limits.h \ /usr/include/linux/head.h /usr/include/linux/fs.h /usr/include/linux/limits.h \
......
...@@ -3,12 +3,15 @@ ...@@ -3,12 +3,15 @@
* *
* Copyright (C) 1992 by Linus Torvalds * Copyright (C) 1992 by Linus Torvalds
* based on ideas by Darren Senn * based on ideas by Darren Senn
*
* stat,statm extensions by Michael K. Johnson, johnsonm@stolaf.edu
*/ */
#include <linux/types.h> #include <linux/types.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/tty.h>
#include <asm/segment.h> #include <asm/segment.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -16,6 +19,17 @@ ...@@ -16,6 +19,17 @@
#define LOAD_INT(x) ((x) >> FSHIFT) #define LOAD_INT(x) ((x) >> FSHIFT)
#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
#define KSTK_EIP(stack) (((char *)stack)[1019])
#define KSTK_ESP(stack) (((char *)stack)[1022])
#define _SSIZE(stack) (TASK_SIZE - KSTK_ESP(stack))
#define SSIZE(stack) (KSTK_ESP(stack) ? _SSIZE(stack) : 0)
#define VSIZE(task,stack) ((task)->brk + 1023 + SSIZE(stack))
#define SIZE(task,stack) (((task)->brk - (task)->end_code + 1023 + \
SSIZE(stack)) / 1024)
static int get_loadavg(char * buffer) static int get_loadavg(char * buffer)
{ {
int a, b, c; int a, b, c;
...@@ -129,6 +143,8 @@ static int get_arg(int pid, char * buffer) ...@@ -129,6 +143,8 @@ static int get_arg(int pid, char * buffer)
static int get_stat(int pid, char * buffer) static int get_stat(int pid, char * buffer)
{ {
struct task_struct ** p = get_task(pid); struct task_struct ** p = get_task(pid);
unsigned long sigignore=0, sigcatch=0, bit=1;
int i;
char state; char state;
if (!p || !*p) if (!p || !*p)
...@@ -137,14 +153,101 @@ static int get_stat(int pid, char * buffer) ...@@ -137,14 +153,101 @@ static int get_stat(int pid, char * buffer)
state = '.'; state = '.';
else else
state = "RSDZTD"[(*p)->state]; state = "RSDZTD"[(*p)->state];
return sprintf(buffer,"%d (%s) %c %d %d %d %d\n", for(i=0; i<32; ++i) {
switch((int) (*p)->sigaction[i].sa_handler) {
case 1: sigignore |= bit; break;
case 0: break;
default: sigcatch |= bit;
} bit <<= 1;
}
return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %u %u \
%u %u %u %d %d %d %d %d %d %u %u %d %u %u %u %u %u %u %u %u %d \
%d %d %d %u\n",
pid, pid,
(*p)->comm, (*p)->comm,
state, state,
(*p)->p_pptr->pid, (*p)->p_pptr->pid,
(*p)->pgrp, (*p)->pgrp,
(*p)->session, (*p)->session,
(*p)->tty); (*p)->tty,
((*p)->tty == -1) ? -1 :
tty_table[(*p)->tty]->pgrp,
(*p)->flags,
(*p)->min_flt,
(*p)->cmin_flt,
(*p)->maj_flt,
(*p)->cmaj_flt,
(*p)->utime,
(*p)->stime,
(*p)->cutime,
(*p)->cstime,
(*p)->counter, /* this is the kernel priority ---
subtract 30 in your user-level program. */
(*p)->priority, /* this is the nice value ---
subtract 15 in your user-level program. */
(*p)->timeout,
(*p)->it_real_value,
(*p)->start_time,
VSIZE((*p),(*p)->kernel_stack_page),
(*p)->rss, /* you might want to shift this left 3 */
(*p)->rlim[RLIMIT_RSS].rlim_cur,
(*p)->start_code,
(*p)->end_code,
(*p)->start_stack,
KSTK_ESP((*p)->kernel_stack_page),
KSTK_EIP((*p)->kernel_stack_page),
(*p)->signal,
(*p)->blocked,
sigignore,
sigcatch,
(*p)->tss.eip);
}
static int get_statm(int pid, char * buffer)
{
struct task_struct ** p = get_task(pid);
int i, tpag;
int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0;
unsigned long ptbl, *buf, *pte, *pagedir, map_nr;
if (!p || !*p)
return 0;
tpag = (*p)->end_code / PAGE_SIZE;
if ((*p)->state != TASK_ZOMBIE) {
pagedir = (void *)((*p)->tss.cr3 + ((*p)->start_code >> 20));
for (i = 0; i < 0x300; ++i) {
if ((ptbl = pagedir[i]) == 0) {
tpag -= 1024;
continue;
}
buf = (void *)(ptbl & 0xfffff000);
for (pte = buf; pte < (buf + 1024); ++pte) {
if (*pte != 0) {
++size;
if (*pte & 1) {
++resident;
if (tpag > 0)
++trs;
else
++drs;
if (i >= 15 && i < 0x2f0) {
++lrs;
if (*pte & 0x40)
++dt;
else
--drs;
}
map_nr = MAP_NR(*pte);
if (map_nr < (high_memory / 4096) && mem_map[map_nr] > 1)
++share;
}
}
--tpag;
}
}
}
return sprintf(buffer,"%d %d %d %d %d %d %d\n",
size, resident, share, trs, lrs, drs, dt);
} }
static int array_read(struct inode * inode, struct file * file,char * buf, int count) static int array_read(struct inode * inode, struct file * file,char * buf, int count)
...@@ -181,6 +284,9 @@ static int array_read(struct inode * inode, struct file * file,char * buf, int c ...@@ -181,6 +284,9 @@ static int array_read(struct inode * inode, struct file * file,char * buf, int c
case 11: case 11:
length = get_stat(pid, page); length = get_stat(pid, page);
break; break;
case 12:
length = get_statm(pid, page);
break;
default: default:
free_page((unsigned long) page); free_page((unsigned long) page);
return -EBADF; return -EBADF;
......
...@@ -59,7 +59,8 @@ static struct proc_dir_entry base_dir[] = { ...@@ -59,7 +59,8 @@ static struct proc_dir_entry base_dir[] = {
{ 8,3,"lib" }, { 8,3,"lib" },
{ 9,7,"environ" }, { 9,7,"environ" },
{ 10,7,"cmdline" }, { 10,7,"cmdline" },
{ 11,4,"stat" } { 11,4,"stat" },
{ 12,5,"statm" }
}; };
#define NR_BASE_DIRENTRY ((sizeof (base_dir))/(sizeof (base_dir[0]))) #define NR_BASE_DIRENTRY ((sizeof (base_dir))/(sizeof (base_dir[0])))
......
...@@ -143,6 +143,7 @@ void proc_read_inode(struct inode * inode) ...@@ -143,6 +143,7 @@ void proc_read_inode(struct inode * inode)
case 9: case 9:
case 10: case 10:
case 11: case 11:
case 12:
inode->i_mode = S_IFREG | 0444; inode->i_mode = S_IFREG | 0444;
inode->i_op = &proc_array_inode_operations; inode->i_op = &proc_array_inode_operations;
return; return;
......
...@@ -7,8 +7,8 @@ ...@@ -7,8 +7,8 @@
*/ */
#define CONFIG_BLK_DEV_HD 1 #define CONFIG_BLK_DEV_HD 1
#define CONFIG_TCPIP 1 #define CONFIG_TCPIP 1
#define CONFIG_PROFILE 1
#define CONFIG_MAX_16M 1 #define CONFIG_MAX_16M 1
#define CONFIG_M486 1
/* /*
* SCSI support * SCSI support
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#undef NR_OPEN #undef NR_OPEN
#define NR_OPEN 256 #define NR_OPEN 256
#define NR_INODE 128 #define NR_INODE 256
#define NR_FILE 128 #define NR_FILE 128
#define NR_SUPER 16 #define NR_SUPER 16
#define NR_HASH 997 #define NR_HASH 997
...@@ -66,7 +66,7 @@ ...@@ -66,7 +66,7 @@
#define WRITEA 3 /* "write-ahead" - silly, but somewhat useful */ #define WRITEA 3 /* "write-ahead" - silly, but somewhat useful */
extern void buffer_init(void); extern void buffer_init(void);
extern void inode_init(void); extern unsigned long inode_init(unsigned long start, unsigned long end);
#define MAJOR(a) (((unsigned)(a))>>8) #define MAJOR(a) (((unsigned)(a))>>8)
#define MINOR(a) ((a)&0xff) #define MINOR(a) ((a)&0xff)
......
...@@ -23,8 +23,19 @@ extern unsigned long kbd_flags; ...@@ -23,8 +23,19 @@ extern unsigned long kbd_flags;
#define KG_ALT 4 #define KG_ALT 4
#define KG_ALTGR 5 #define KG_ALTGR 5
#define KG_CAPSLOCK 6 #define KG_CAPSLOCK 6
#define KG_E0 7
#define KG_E1 8 /*
* "dead" keys - prefix key values that are valid only for the next
* character code (sticky shift, E0/E1 special scancodes, diacriticals)
*/
extern unsigned long kbd_dead_keys;
extern unsigned long kbd_prev_dead_keys;
/*
* these are the hardcoded dead key flags
*/
#define KGD_E0 0
#define KGD_E1 1
/* /*
* kbd->xxx contains the VC-local things (flag settings etc..) * kbd->xxx contains the VC-local things (flag settings etc..)
...@@ -80,6 +91,26 @@ extern inline void chg_kbd_flag(int flag) ...@@ -80,6 +91,26 @@ extern inline void chg_kbd_flag(int flag)
kbd_flags ^= 1 << flag; kbd_flags ^= 1 << flag;
} }
extern inline int kbd_dead(int flag)
{
return kbd_prev_dead_keys & (1 << flag);
}
extern inline void set_kbd_dead(int flag)
{
kbd_dead_keys |= 1 << flag;
}
extern inline void clr_kbd_dead(int flag)
{
kbd_dead_keys &= ~(1 << flag);
}
extern inline void chg_kbd_dead(int flag)
{
kbd_dead_keys ^= 1 << flag;
}
extern inline int vc_kbd_flag(struct kbd_struct * kbd, int flag) extern inline int vc_kbd_flag(struct kbd_struct * kbd, int flag)
{ {
return ((kbd->flags >> flag) & 1); return ((kbd->flags >> flag) & 1);
......
...@@ -134,14 +134,14 @@ sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid, ...@@ -134,14 +134,14 @@ sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid,
sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask, sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask,
sys_setreuid,sys_setregid, sys_sigsuspend, sys_sigpending, sys_setreuid,sys_setregid, sys_sigsuspend, sys_sigpending,
sys_sethostname, sys_setrlimit, sys_getrlimit, sys_getrusage, sys_sethostname, sys_setrlimit, sys_getrlimit, sys_getrusage,
sys_gettimeofday, sys_settimeofday, sys_getgroups, sys_setgroups, sys_gettimeofday, sys_settimeofday, sys_getgroups, sys_setgroups,
sys_select, sys_symlink, sys_lstat, sys_readlink, sys_uselib, sys_select, sys_symlink, sys_lstat, sys_readlink, sys_uselib,
sys_swapon, sys_reboot, sys_readdir, sys_mmap, sys_munmap, sys_swapon, sys_reboot, sys_readdir, sys_mmap, sys_munmap, sys_truncate,
sys_truncate, sys_ftruncate, sys_fchmod, sys_fchown, sys_getpriority, sys_ftruncate, sys_fchmod, sys_fchown, sys_getpriority, sys_setpriority,
sys_setpriority, sys_profil, sys_statfs, sys_fstatfs, sys_ioperm, sys_profil, sys_statfs, sys_fstatfs, sys_ioperm, sys_socketcall,
sys_socketcall, sys_syslog, sys_setitimer, sys_getitimer, sys_newstat, sys_syslog, sys_setitimer, sys_getitimer, sys_newstat, sys_newlstat,
sys_newlstat, sys_newfstat, sys_newuname, sys_iopl, sys_vhangup, sys_newfstat, sys_newuname, sys_iopl, sys_vhangup, sys_idle, sys_vm86,
sys_idle, sys_vm86, sys_wait4, sys_swapoff, sys_sysinfo }; sys_wait4, sys_swapoff, sys_sysinfo };
/* So we don't have to do any more manual updating.... */ /* So we don't have to do any more manual updating.... */
int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr); int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr);
...@@ -285,6 +285,7 @@ extern int is_ignored(int sig); ...@@ -285,6 +285,7 @@ extern int is_ignored(int sig);
extern int tty_signal(int sig, struct tty_struct *tty); extern int tty_signal(int sig, struct tty_struct *tty);
extern int kill_pg(int pgrp, int sig, int priv); extern int kill_pg(int pgrp, int sig, int priv);
extern int kill_sl(int sess, int sig, int priv); extern int kill_sl(int sess, int sig, int priv);
extern void tty_hangup(struct tty_struct * tty);
extern void do_SAK(struct tty_struct *tty); extern void do_SAK(struct tty_struct *tty);
/* tty write functions */ /* tty write functions */
......
...@@ -133,7 +133,7 @@ static unsigned long memory_start = 0; /* After mem_init, stores the */ ...@@ -133,7 +133,7 @@ static unsigned long memory_start = 0; /* After mem_init, stores the */
static unsigned long memory_end = 0; static unsigned long memory_end = 0;
static unsigned long low_memory_start = 0; static unsigned long low_memory_start = 0;
static char * argv_init[MAX_INIT_ARGS+2] = { "/bin/init", NULL, }; static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
static char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=console", NULL, }; static char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=console", NULL, };
static char * argv_rc[] = { "/bin/sh", NULL }; static char * argv_rc[] = { "/bin/sh", NULL };
...@@ -238,9 +238,9 @@ void start_kernel(void) ...@@ -238,9 +238,9 @@ void start_kernel(void)
#ifdef CONFIG_SCSI #ifdef CONFIG_SCSI
memory_start = scsi_dev_init(memory_start,memory_end); memory_start = scsi_dev_init(memory_start,memory_end);
#endif #endif
memory_start = inode_init(memory_start,memory_end);
mem_init(low_memory_start,memory_start,memory_end); mem_init(low_memory_start,memory_start,memory_end);
buffer_init(); buffer_init();
inode_init();
time_init(); time_init();
floppy_init(); floppy_init();
sock_init(); sock_init();
......
...@@ -288,6 +288,8 @@ void __math_abort(struct info * info, unsigned int signal) ...@@ -288,6 +288,8 @@ void __math_abort(struct info * info, unsigned int signal)
void math_emulate(long arg) void math_emulate(long arg)
{ {
printk("math-meulation not enabled and no coprocessor found.\n");
printk("killing %s.\n",current->comm);
send_sig(SIGFPE,current,1); send_sig(SIGFPE,current,1);
schedule(); schedule();
} }
......
...@@ -152,6 +152,8 @@ extern int ramdisk_size; ...@@ -152,6 +152,8 @@ extern int ramdisk_size;
#endif #endif
#if (MAJOR_NR != 9)
#ifndef CURRENT #ifndef CURRENT
#define CURRENT (blk_dev[MAJOR_NR].current_request) #define CURRENT (blk_dev[MAJOR_NR].current_request)
#endif #endif
...@@ -259,3 +261,4 @@ static void end_request(int uptodate) ...@@ -259,3 +261,4 @@ static void end_request(int uptodate)
#endif #endif
#endif #endif
#endif
...@@ -216,7 +216,7 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg) ...@@ -216,7 +216,7 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
{ {
char scsi_cmd[10]; char scsi_cmd[10];
if ((cmd != 0 && dev->id > NR_SCSI_DEVICES)) if ((cmd != 0 && dev->index > NR_SCSI_DEVICES))
return -ENODEV; return -ENODEV;
if ((cmd == 0 && dev->host_no > max_scsi_hosts)) if ((cmd == 0 && dev->host_no > max_scsi_hosts))
return -ENODEV; return -ENODEV;
......
...@@ -97,6 +97,7 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned long cmd, unsign ...@@ -97,6 +97,7 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned long cmd, unsign
int result, target; int result, target;
target = MINOR(dev); target = MINOR(dev);
if (target >= NR_SR) return -ENODEV;
switch (cmd) switch (cmd)
{ {
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
Kai Makisara, Nov 9, 1992 email makisara@vtinsx.ins.vtt.fi or Kai Makisara, Nov 9, 1992 email makisara@vtinsx.ins.vtt.fi or
Kai.Makisara@vtt.fi Kai.Makisara@vtt.fi
Last changes Dec 6, 1992. Last changes Dec 19, 1992.
*/ */
#include <linux/fs.h> #include <linux/fs.h>
...@@ -56,9 +56,14 @@ ...@@ -56,9 +56,14 @@
before command completion. */ before command completion. */
/* #define ST_NOWAIT */ /* #define ST_NOWAIT */
/* Uncomment the following if you want the tape to be positioned correctly
within file after close (the tape is positioned correctly with respect
to the filemarks even wihout ST_IN_FILE_POS defined */
/* #define ST_IN_FILE_POS */
/* #define DEBUG */ /* #define DEBUG */
#define ST_TIMEOUT 2000 #define ST_TIMEOUT 6000
#define ST_LONG_TIMEOUT 200000 #define ST_LONG_TIMEOUT 200000
/* Number of ST_BLOCK_SIZE blocks in the buffers */ /* Number of ST_BLOCK_SIZE blocks in the buffers */
...@@ -519,9 +524,13 @@ static void scsi_tape_close(struct inode * inode, struct file * filp) ...@@ -519,9 +524,13 @@ static void scsi_tape_close(struct inode * inode, struct file * filp)
printk("st%d: Buffer flushed, EOF written\n", dev); printk("st%d: Buffer flushed, EOF written\n", dev);
#endif #endif
} }
else if (!rewind && scsi_tapes[dev].eof && !scsi_tapes[dev].eof_hit) else if (!rewind) {
st_int_ioctl(inode, filp, MTBSF, 1); if ((scsi_tapes[dev].eof == 1) && !scsi_tapes[dev].eof_hit)
/* Back over the EOF hit inadvertently */ st_int_ioctl(inode, filp, MTBSF, 1); /* Back over the EOF hit */
#ifdef ST_IN_FILE_POS
flush_buffer(inode, filp, 0);
#endif
}
if (rewind) if (rewind)
st_int_ioctl(inode, filp, MTREW, 1); st_int_ioctl(inode, filp, MTREW, 1);
...@@ -701,12 +710,9 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count) ...@@ -701,12 +710,9 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count)
printk("st%d: EOF flag up. Bytes %d\n", dev, printk("st%d: EOF flag up. Bytes %d\n", dev,
scsi_tapes[dev].buffer->buffer_bytes); scsi_tapes[dev].buffer->buffer_bytes);
#endif #endif
if ((scsi_tapes[dev].buffer->buffer_bytes == 0) && scsi_tapes[dev].eof) { if ((scsi_tapes[dev].buffer->buffer_bytes == 0) &&
if (scsi_tapes[dev].eof == 1) scsi_tapes[dev].eof == 2) /* EOM or Blank Check */
return 0; return (-EIO);
else /* EOM or blank check */
return (-EIO);
}
scsi_tapes[dev].rw = 1; scsi_tapes[dev].rw = 1;
...@@ -714,7 +720,8 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count) ...@@ -714,7 +720,8 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count)
for (total = 0; total < count; ) { for (total = 0; total < count; ) {
if (scsi_tapes[dev].buffer->buffer_bytes == 0 && scsi_tapes[dev].eof == 0) { if (scsi_tapes[dev].buffer->buffer_bytes == 0 &&
scsi_tapes[dev].eof == 0) {
memset(cmd, 0, 10); memset(cmd, 0, 10);
cmd[0] = READ_6; cmd[0] = READ_6;
...@@ -734,6 +741,7 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count) ...@@ -734,6 +741,7 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count)
if (SCpnt->request.dev == dev) sleep_on( &scsi_tapes[dev].waiting ); if (SCpnt->request.dev == dev) sleep_on( &scsi_tapes[dev].waiting );
scsi_tapes[dev].buffer->read_pointer = 0; scsi_tapes[dev].buffer->read_pointer = 0;
scsi_tapes[dev].eof_hit = 0;
if (SCpnt->result != 0 || SCpnt->sense_buffer[0] != 0) { if (SCpnt->result != 0 || SCpnt->sense_buffer[0] != 0) {
#ifdef DEBUG #ifdef DEBUG
...@@ -796,8 +804,10 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count) ...@@ -796,8 +804,10 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count)
} }
} }
else else
scsi_tapes[dev].buffer->buffer_bytes = scsi_tapes[dev].buffer->buffer_size; scsi_tapes[dev].buffer->buffer_bytes =
} /* if (SCpnt->result != 0 || SCpnt->sense_buffer[0] != 0) */ scsi_tapes[dev].buffer->buffer_size;
} /* if (scsi_tapes[dev].buffer->buffer_bytes == 0 &&
scsi_tapes[dev].eof == 0) */
if (scsi_tapes[dev].buffer->buffer_bytes > 0) { if (scsi_tapes[dev].buffer->buffer_bytes > 0) {
#ifdef DEBUG #ifdef DEBUG
...@@ -818,10 +828,11 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count) ...@@ -818,10 +828,11 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count)
else if (scsi_tapes[dev].eof) { else if (scsi_tapes[dev].eof) {
scsi_tapes[dev].eof_hit = 1; scsi_tapes[dev].eof_hit = 1;
SCpnt->request.dev = -1; /* Mark as not busy */ SCpnt->request.dev = -1; /* Mark as not busy */
if (total) if (total == 0 && scsi_tapes[dev].eof == 1)
return total; scsi_tapes[dev].eof = 0;
else if (total == 0 && scsi_tapes[dev].eof == 2)
return (-EIO); return (-EIO);
return total;
} }
} /* for (total = 0; total < count; ) */ } /* for (total = 0; total < count; ) */
...@@ -956,7 +967,7 @@ static int st_int_ioctl(struct inode * inode,struct file * file, ...@@ -956,7 +967,7 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
cmd[0] = SPACE; cmd[0] = SPACE;
cmd[1] = 3; cmd[1] = 3;
#ifdef DEBUG #ifdef DEBUG
printk("st%d: Spacing to end of tape media.\n", dev); printk("st%d: Spacing to end of recorded medium.\n", dev);
#endif #endif
break; break;
case MTERASE: case MTERASE:
...@@ -1050,6 +1061,8 @@ static int st_int_ioctl(struct inode * inode,struct file * file, ...@@ -1050,6 +1061,8 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
if (!ioctl_result) { if (!ioctl_result) {
if (cmd_in == MTBSFM) if (cmd_in == MTBSFM)
ioctl_result = st_int_ioctl(inode, file, MTFSF, 1); ioctl_result = st_int_ioctl(inode, file, MTFSF, 1);
else if (cmd_in == MTFSFM)
ioctl_result = st_int_ioctl(inode, file, MTBSF, 1);
else if (cmd_in == MTSETBLK) { else if (cmd_in == MTSETBLK) {
scsi_tapes[dev].block_size = arg; scsi_tapes[dev].block_size = arg;
scsi_tapes[dev].buffer->buffer_blocks = scsi_tapes[dev].buffer->buffer_blocks =
......
...@@ -27,10 +27,10 @@ typedef struct { ...@@ -27,10 +27,10 @@ typedef struct {
Scsi_Device* device; Scsi_Device* device;
unsigned dirty:1; unsigned dirty:1;
unsigned rw:2; unsigned rw:2;
unsigned eof:1; unsigned eof:2;
unsigned write_prot:1; unsigned write_prot:1;
unsigned in_use:1; unsigned in_use:1;
unsigned eof_hit:2; unsigned eof_hit:1;
ST_buffer * buffer; ST_buffer * buffer;
int block_size; int block_size;
int min_block; int min_block;
......
...@@ -36,7 +36,7 @@ console.o : console.c /usr/include/linux/sched.h /usr/include/linux/head.h /usr/ ...@@ -36,7 +36,7 @@ console.o : console.c /usr/include/linux/sched.h /usr/include/linux/head.h /usr/
/usr/include/linux/termios.h /usr/include/asm/system.h /usr/include/linux/config.h \ /usr/include/linux/termios.h /usr/include/asm/system.h /usr/include/linux/config.h \
/usr/include/linux/autoconf.h /usr/include/linux/string.h /usr/include/linux/errno.h \ /usr/include/linux/autoconf.h /usr/include/linux/string.h /usr/include/linux/errno.h \
/usr/include/linux/kd.h /usr/include/linux/keyboard.h /usr/include/asm/io.h \ /usr/include/linux/kd.h /usr/include/linux/keyboard.h /usr/include/asm/io.h \
/usr/include/asm/segment.h vt_kern.h /usr/include/asm/segment.h vt_kern.h /usr/include/linux/vt.h
keyboard.o : keyboard.c /usr/include/linux/sched.h /usr/include/linux/head.h \ keyboard.o : keyboard.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/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/types.h /usr/include/linux/dirent.h /usr/include/linux/vfs.h \
...@@ -143,9 +143,9 @@ tty_io.o : tty_io.c /usr/include/linux/types.h /usr/include/linux/errno.h /usr/i ...@@ -143,9 +143,9 @@ tty_io.o : tty_io.c /usr/include/linux/types.h /usr/include/linux/errno.h /usr/i
/usr/include/linux/kernel.h /usr/include/linux/time.h /usr/include/linux/param.h \ /usr/include/linux/kernel.h /usr/include/linux/time.h /usr/include/linux/param.h \
/usr/include/linux/resource.h /usr/include/linux/vm86.h /usr/include/linux/math_emu.h \ /usr/include/linux/resource.h /usr/include/linux/vm86.h /usr/include/linux/math_emu.h \
/usr/include/linux/tty.h /usr/include/linux/termios.h /usr/include/asm/system.h \ /usr/include/linux/tty.h /usr/include/linux/termios.h /usr/include/asm/system.h \
/usr/include/linux/ctype.h /usr/include/linux/kd.h /usr/include/linux/string.h \ /usr/include/linux/timer.h /usr/include/linux/ctype.h /usr/include/linux/kd.h \
/usr/include/linux/keyboard.h /usr/include/asm/segment.h /usr/include/asm/bitops.h \ /usr/include/linux/string.h /usr/include/linux/keyboard.h /usr/include/asm/segment.h \
vt_kern.h /usr/include/asm/bitops.h vt_kern.h /usr/include/linux/vt.h
tty_ioctl.o : tty_ioctl.c /usr/include/linux/types.h /usr/include/linux/termios.h \ tty_ioctl.o : tty_ioctl.c /usr/include/linux/types.h /usr/include/linux/termios.h \
/usr/include/linux/errno.h /usr/include/linux/sched.h /usr/include/linux/head.h \ /usr/include/linux/errno.h /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/fs.h /usr/include/linux/limits.h /usr/include/linux/wait.h \
......
...@@ -170,7 +170,10 @@ static int console_blanked = 0; ...@@ -170,7 +170,10 @@ static int console_blanked = 0;
#define halfcolor (vc_cons[currcons].vc_halfcolor) #define halfcolor (vc_cons[currcons].vc_halfcolor)
#define kbdmode (vc_cons[currcons].vc_kbdmode) #define kbdmode (vc_cons[currcons].vc_kbdmode)
#define tab_stop (vc_cons[currcons].vc_tab_stop) #define tab_stop (vc_cons[currcons].vc_tab_stop)
#define vcmode (vt_cons[currcons].vc_mode)
#define vtmode (vt_cons[currcons].vt_mode) #define vtmode (vt_cons[currcons].vt_mode)
#define vtpid (vt_cons[currcons].vt_pid)
#define vtnewvt (vt_cons[currcons].vt_newvt)
#define set_kbd(x) set_vc_kbd_flag(kbd_table+currcons,x) #define set_kbd(x) set_vc_kbd_flag(kbd_table+currcons,x)
#define clr_kbd(x) clr_vc_kbd_flag(kbd_table+currcons,x) #define clr_kbd(x) clr_vc_kbd_flag(kbd_table+currcons,x)
...@@ -285,7 +288,7 @@ static void set_origin(int currcons) ...@@ -285,7 +288,7 @@ static void set_origin(int currcons)
{ {
if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM) if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM)
return; return;
if (currcons != fg_console || console_blanked || vtmode == KD_GRAPHICS) if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
return; return;
cli(); cli();
outb_p(12, video_port_reg); outb_p(12, video_port_reg);
...@@ -1194,7 +1197,7 @@ void con_write(struct tty_struct * tty) ...@@ -1194,7 +1197,7 @@ void con_write(struct tty_struct * tty)
state = ESnormal; state = ESnormal;
} }
} }
if (vtmode == KD_GRAPHICS) if (vcmode == KD_GRAPHICS)
return; return;
set_cursor(currcons); set_cursor(currcons);
} }
...@@ -1203,7 +1206,7 @@ void do_keyboard_interrupt(void) ...@@ -1203,7 +1206,7 @@ void do_keyboard_interrupt(void)
{ {
TTY_READ_FLUSH(TTY_TABLE(0)); TTY_READ_FLUSH(TTY_TABLE(0));
timer_active &= ~(1<<BLANK_TIMER); timer_active &= ~(1<<BLANK_TIMER);
if (vt_cons[fg_console].vt_mode == KD_GRAPHICS) if (vt_cons[fg_console].vc_mode == KD_GRAPHICS)
return; return;
if (console_blanked) { if (console_blanked) {
timer_table[BLANK_TIMER].expires = 0; timer_table[BLANK_TIMER].expires = 0;
...@@ -1311,7 +1314,14 @@ long con_init(long kmem_start) ...@@ -1311,7 +1314,14 @@ long con_init(long kmem_start)
pos = origin = video_mem_start = base; pos = origin = video_mem_start = base;
scr_end = video_mem_end = (base += screen_size); scr_end = video_mem_end = (base += screen_size);
vc_scrbuf[currcons] = (unsigned short *) origin; vc_scrbuf[currcons] = (unsigned short *) origin;
vtmode = KD_TEXT; vcmode = KD_TEXT;
vtmode.mode = VT_AUTO;
vtmode.waitv = 0;
vtmode.relsig = 0;
vtmode.acqsig = 0;
vtmode.frsig = 0;
vtpid = -1;
vtnewvt = -1;
clr_kbd(kbdraw); clr_kbd(kbdraw);
def_color = 0x07; /* white */ def_color = 0x07; /* white */
ulcolor = 0x0f; /* bold white */ ulcolor = 0x0f; /* bold white */
...@@ -1360,6 +1370,8 @@ static void set_scrmem(int currcons) ...@@ -1360,6 +1370,8 @@ static void set_scrmem(int currcons)
void blank_screen(void) void blank_screen(void)
{ {
if (console_blanked)
return;
timer_table[BLANK_TIMER].fn = unblank_screen; timer_table[BLANK_TIMER].fn = unblank_screen;
get_scrmem(fg_console); get_scrmem(fg_console);
hide_cursor(fg_console); hide_cursor(fg_console);
...@@ -1369,6 +1381,8 @@ void blank_screen(void) ...@@ -1369,6 +1381,8 @@ void blank_screen(void)
void unblank_screen(void) void unblank_screen(void)
{ {
if (!console_blanked)
return;
timer_table[BLANK_TIMER].fn = blank_screen; timer_table[BLANK_TIMER].fn = blank_screen;
if (blankinterval) { if (blankinterval) {
timer_table[BLANK_TIMER].expires = jiffies + blankinterval; timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
...@@ -1463,7 +1477,7 @@ void console_print(const char * b) ...@@ -1463,7 +1477,7 @@ void console_print(const char * b)
pos+=2; pos+=2;
} }
set_cursor(currcons); set_cursor(currcons);
if (vt_cons[fg_console].vt_mode == KD_GRAPHICS) if (vt_cons[fg_console].vc_mode == KD_GRAPHICS)
return; return;
timer_active &= ~(1<<BLANK_TIMER); timer_active &= ~(1<<BLANK_TIMER);
if (console_blanked) { if (console_blanked) {
...@@ -1483,5 +1497,7 @@ int con_open(struct tty_struct *tty, struct file * filp) ...@@ -1483,5 +1497,7 @@ int con_open(struct tty_struct *tty, struct file * filp)
{ {
tty->write = con_write; tty->write = con_write;
tty->ioctl = vt_ioctl; tty->ioctl = vt_ioctl;
if (tty->line > NR_CONSOLES)
return -ENODEV;
return 0; return 0;
} }
...@@ -32,6 +32,8 @@ extern void ctrl_alt_del(void); ...@@ -32,6 +32,8 @@ extern void ctrl_alt_del(void);
extern void change_console(unsigned int new_console); extern void change_console(unsigned int new_console);
unsigned long kbd_flags = 0; unsigned long kbd_flags = 0;
unsigned long kbd_dead_keys = 0;
unsigned long kbd_prev_dead_keys = 0;
struct kbd_struct kbd_table[NR_CONSOLES]; struct kbd_struct kbd_table[NR_CONSOLES];
static struct kbd_struct * kbd = kbd_table; static struct kbd_struct * kbd = kbd_table;
...@@ -54,59 +56,54 @@ static struct pt_regs * pt_regs; ...@@ -54,59 +56,54 @@ static struct pt_regs * pt_regs;
static void keyboard_interrupt(int int_pt_regs) static void keyboard_interrupt(int int_pt_regs)
{ {
static unsigned char rep = 0xff; static unsigned char rep = 0xff;
unsigned char scancode, x; unsigned char scancode;
pt_regs = (struct pt_regs *) int_pt_regs; pt_regs = (struct pt_regs *) int_pt_regs;
scancode=inb_p(0x60); while (inb_p(0x64) & 1) {
x=inb_p(0x61); kbd_prev_dead_keys |= kbd_dead_keys;
outb_p(x|0x80, 0x61); if (!kbd_dead_keys)
outb_p(x&0x7f, 0x61); kbd_prev_dead_keys = 0;
if (scancode == 0xe0) kbd_dead_keys = 0;
set_kbd_flag(KG_E0); scancode = inb_p(0x60);
else if (scancode == 0xe1) tty = TTY_TABLE(0);
set_kbd_flag(KG_E1); kbd = kbd_table + fg_console;
tty = TTY_TABLE(0); if (vc_kbd_flag(kbd,VC_RAW)) {
kbd = kbd_table + fg_console; kbd_flags = 0;
if (vc_kbd_flag(kbd,VC_RAW)) { put_queue(scancode);
kbd_flags = 0; continue;
put_queue(scancode); }
do_keyboard_interrupt(); if (scancode == 0xe0) {
return; set_kbd_dead(KGD_E0);
} continue;
if (scancode == 0xe0 || scancode == 0xe1) } else if (scancode == 0xe1) {
return; set_kbd_dead(KGD_E1);
/* continue;
* The keyboard maintains its own internal caps lock and num lock
* statuses. In caps lock mode E0 AA precedes make code and E0 2A
* follows break code. In num lock mode, E0 2A precedes make
* code and E0 AA follows break code. We do our own book-keeping,
* so we will just ignore these.
*/
if (kbd_flag(KG_E0) && (scancode == 0x2a || scancode == 0xaa)) {
clr_kbd_flag(KG_E0);
clr_kbd_flag(KG_E1);
return;
}
/*
* Repeat a key only if the input buffers are empty or the
* characters get echoed locally. This makes key repeat usable
* with slow applications and unders heavy loads.
*/
if (scancode == rep) {
if (!(vc_kbd_flag(kbd,VC_REPEAT) && tty &&
(L_ECHO(tty) ||
(EMPTY(&tty->secondary) &&
EMPTY(&tty->read_q))))) {
clr_kbd_flag(KG_E0);
clr_kbd_flag(KG_E1);
return;
} }
/*
* The keyboard maintains its own internal caps lock and num lock
* statuses. In caps lock mode E0 AA precedes make code and E0 2A
* follows break code. In num lock mode, E0 2A precedes make
* code and E0 AA follows break code. We do our own book-keeping,
* so we will just ignore these.
*/
if (kbd_dead(KGD_E0) && (scancode == 0x2a || scancode == 0xaa))
continue;
/*
* Repeat a key only if the input buffers are empty or the
* characters get echoed locally. This makes key repeat usable
* with slow applications and unders heavy loads.
*/
if (scancode == rep) {
if (!(vc_kbd_flag(kbd,VC_REPEAT) && tty &&
(L_ECHO(tty) ||
(EMPTY(&tty->secondary) &&
EMPTY(&tty->read_q)))))
continue;
}
rep = scancode;
key_table[scancode](scancode);
} }
rep = scancode;
key_table[scancode](scancode);
do_keyboard_interrupt(); do_keyboard_interrupt();
clr_kbd_flag(KG_E0);
clr_kbd_flag(KG_E1);
} }
static void put_queue(int ch) static void put_queue(int ch)
...@@ -147,7 +144,7 @@ static void puts_queue(char *cp) ...@@ -147,7 +144,7 @@ static void puts_queue(char *cp)
static void ctrl(int sc) static void ctrl(int sc)
{ {
if (kbd_flag(KG_E0)) if (kbd_dead(KGD_E0))
set_kbd_flag(KG_RCTRL); set_kbd_flag(KG_RCTRL);
else else
set_kbd_flag(KG_LCTRL); set_kbd_flag(KG_LCTRL);
...@@ -155,7 +152,7 @@ static void ctrl(int sc) ...@@ -155,7 +152,7 @@ static void ctrl(int sc)
static void alt(int sc) static void alt(int sc)
{ {
if (kbd_flag(KG_E0)) if (kbd_dead(KGD_E0))
set_kbd_flag(KG_ALTGR); set_kbd_flag(KG_ALTGR);
else else
set_kbd_flag(KG_ALT); set_kbd_flag(KG_ALT);
...@@ -163,7 +160,7 @@ static void alt(int sc) ...@@ -163,7 +160,7 @@ static void alt(int sc)
static void unctrl(int sc) static void unctrl(int sc)
{ {
if (kbd_flag(KG_E0)) if (kbd_dead(KGD_E0))
clr_kbd_flag(KG_RCTRL); clr_kbd_flag(KG_RCTRL);
else else
clr_kbd_flag(KG_LCTRL); clr_kbd_flag(KG_LCTRL);
...@@ -171,7 +168,7 @@ static void unctrl(int sc) ...@@ -171,7 +168,7 @@ static void unctrl(int sc)
static void unalt(int sc) static void unalt(int sc)
{ {
if (kbd_flag(KG_E0)) if (kbd_dead(KGD_E0))
clr_kbd_flag(KG_ALTGR); clr_kbd_flag(KG_ALTGR);
else { else {
clr_kbd_flag(KG_ALT); clr_kbd_flag(KG_ALT);
...@@ -218,6 +215,8 @@ static void uncaps(int sc) ...@@ -218,6 +215,8 @@ static void uncaps(int sc)
static void show_ptregs(void) static void show_ptregs(void)
{ {
if (!pt_regs)
return;
printk("\nEIP: %04x:%08x",0xffff & pt_regs->cs,pt_regs->eip); printk("\nEIP: %04x:%08x",0xffff & pt_regs->cs,pt_regs->eip);
if (pt_regs->cs & 3) if (pt_regs->cs & 3)
printk(" ESP: %04x:%08x",0xffff & pt_regs->cs,pt_regs->eip); printk(" ESP: %04x:%08x",0xffff & pt_regs->cs,pt_regs->eip);
...@@ -1167,7 +1166,7 @@ static void cursor(int sc) ...@@ -1167,7 +1166,7 @@ static void cursor(int sc)
ctrl_alt_del(); ctrl_alt_del();
return; return;
} }
if (kbd_flag(KG_E0)) { if (kbd_dead(KGD_E0)) {
cur(sc); cur(sc);
return; return;
} }
...@@ -1226,7 +1225,7 @@ static void func(int sc) ...@@ -1226,7 +1225,7 @@ static void func(int sc)
static void slash(int sc) static void slash(int sc)
{ {
if (!kbd_flag(KG_E0)) if (!kbd_dead(KGD_E0))
do_self(sc); do_self(sc);
else if (vc_kbd_flag(kbd,VC_APPLIC)) else if (vc_kbd_flag(kbd,VC_APPLIC))
applkey('Q'); applkey('Q');
...@@ -1244,7 +1243,7 @@ static void star(int sc) ...@@ -1244,7 +1243,7 @@ static void star(int sc)
static void enter(int sc) static void enter(int sc)
{ {
if (kbd_flag(KG_E0) && vc_kbd_flag(kbd,VC_APPLIC)) if (kbd_dead(KGD_E0) && vc_kbd_flag(kbd,VC_APPLIC))
applkey('M'); applkey('M');
else { else {
put_queue(13); put_queue(13);
...@@ -1418,7 +1417,6 @@ static fptr key_table[] = { ...@@ -1418,7 +1417,6 @@ static fptr key_table[] = {
unsigned long kbd_init(unsigned long kmem_start) unsigned long kbd_init(unsigned long kmem_start)
{ {
int i; int i;
unsigned char a;
struct kbd_struct * kbd; struct kbd_struct * kbd;
kbd = kbd_table + 0; kbd = kbd_table + 0;
...@@ -1428,8 +1426,6 @@ unsigned long kbd_init(unsigned long kmem_start) ...@@ -1428,8 +1426,6 @@ unsigned long kbd_init(unsigned long kmem_start)
kbd->kbd_flags = KBDFLAGS; kbd->kbd_flags = KBDFLAGS;
} }
request_irq(KEYBOARD_IRQ,keyboard_interrupt); request_irq(KEYBOARD_IRQ,keyboard_interrupt);
a=inb_p(0x61); keyboard_interrupt(0);
outb_p(a|0x80,0x61);
outb_p(a,0x61);
return kmem_start; return kmem_start;
} }
...@@ -160,8 +160,9 @@ static void aux_interrupt(int cpl) ...@@ -160,8 +160,9 @@ static void aux_interrupt(int cpl)
static void release_aux(struct inode * inode, struct file * file) static void release_aux(struct inode * inode, struct file * file)
{ {
poll_status(); poll_status();
outb_p(AUX_DISABLE,AUX_COMMAND); /* Disable Aux device */
aux_write_dev(AUX_DISABLE_DEV); /* disable aux device */ aux_write_dev(AUX_DISABLE_DEV); /* disable aux device */
poll_status();
outb_p(AUX_DISABLE,AUX_COMMAND); /* Disable Aux device */
aux_write_cmd(AUX_INTS_OFF); /* disable controller ints */ aux_write_cmd(AUX_INTS_OFF); /* disable controller ints */
free_irq(AUX_IRQ); free_irq(AUX_IRQ);
aux_busy = 0; aux_busy = 0;
...@@ -288,6 +289,9 @@ unsigned long psaux_init(unsigned long kmem_start) ...@@ -288,6 +289,9 @@ unsigned long psaux_init(unsigned long kmem_start)
queue->head = queue->tail = 0; queue->head = queue->tail = 0;
queue->proc_list = NULL; queue->proc_list = NULL;
aux_present = 1; aux_present = 1;
poll_status();
outb_p(AUX_DISABLE,AUX_COMMAND); /* Disable Aux device */
aux_write_cmd(AUX_INTS_OFF); /* disable controller ints */
return kmem_start; return kmem_start;
} }
......
...@@ -28,10 +28,8 @@ static void pty_close(struct tty_struct * tty, struct file * filp) ...@@ -28,10 +28,8 @@ static void pty_close(struct tty_struct * tty, struct file * filp)
if (!tty->link) if (!tty->link)
return; return;
wake_up_interruptible(&tty->link->write_q.proc_list); wake_up_interruptible(&tty->link->write_q.proc_list);
if (IS_A_PTY_MASTER(tty->line)) { if (IS_A_PTY_MASTER(tty->line))
if (tty->link->session > 0) tty_hangup(tty->link);
kill_sl(tty->link->session,SIGHUP,1);
}
} }
static inline void pty_copy(struct tty_struct * from, struct tty_struct * to) static inline void pty_copy(struct tty_struct * from, struct tty_struct * to)
......
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
* *
*/ */
#define NEW_INTERRUPT_ROUTINE #undef NEW_INTERRUPT_ROUTINE
#define WAKEUP_CHARS (3*TTY_BUF_SIZE/4) #define WAKEUP_CHARS (3*TTY_BUF_SIZE/4)
...@@ -401,9 +401,8 @@ static void modem_status_intr(struct async_struct * info) ...@@ -401,9 +401,8 @@ static void modem_status_intr(struct async_struct * info)
unsigned char status = inb(UART_MSR + info->port); unsigned char status = inb(UART_MSR + info->port);
if (!(info->tty->termios->c_cflag & CLOCAL)) { if (!(info->tty->termios->c_cflag & CLOCAL)) {
if (((status & (UART_MSR_DCD|UART_MSR_DDCD)) == UART_MSR_DDCD) if ((status & (UART_MSR_DCD|UART_MSR_DDCD)) == UART_MSR_DDCD)
&& info->tty->session > 0) tty_hangup(info->tty);
kill_sl(info->tty->session,SIGHUP,1);
if (info->tty->termios->c_cflag & CRTSCTS) if (info->tty->termios->c_cflag & CRTSCTS)
info->tty->stopped = !(status & UART_MSR_CTS); info->tty->stopped = !(status & UART_MSR_CTS);
...@@ -523,10 +522,8 @@ static void rs_timer(void) ...@@ -523,10 +522,8 @@ static void rs_timer(void)
if (!clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { if (!clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
wake_up_interruptible(&info->tty->write_q.proc_list); wake_up_interruptible(&info->tty->write_q.proc_list);
} }
if (!clear_bit(RS_EVENT_HUP_PGRP, &info->event)) { if (!clear_bit(RS_EVENT_HUP_PGRP, &info->event))
if (info->tty->session > 0) tty_hangup(info->tty);
kill_sl(info->tty->session,SIGHUP,1);
}
if (!clear_bit(RS_EVENT_BREAK_INT, &info->event)) { if (!clear_bit(RS_EVENT_BREAK_INT, &info->event)) {
flush_input(info->tty); flush_input(info->tty);
flush_output(info->tty); flush_output(info->tty);
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/fcntl.h> #include <linux/fcntl.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/timer.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/kd.h> #include <linux/kd.h>
#include <linux/mm.h> #include <linux/mm.h>
...@@ -54,6 +55,11 @@ struct tty_struct * redirect = NULL; ...@@ -54,6 +55,11 @@ struct tty_struct * redirect = NULL;
struct wait_queue * keypress_wait = NULL; struct wait_queue * keypress_wait = NULL;
static int initialize_tty_struct(struct tty_struct *tty, int line); static int initialize_tty_struct(struct tty_struct *tty, int line);
static int tty_read(struct inode *, struct file *, char *, int);
static int tty_write(struct inode *, struct file *, char *, int);
static int tty_select(struct inode *, struct file *, int, select_table *);
static int tty_open(struct inode *, struct file *);
static void tty_release(struct inode *, struct file *);
void put_tty_queue(char c, struct tty_queue * queue) void put_tty_queue(char c, struct tty_queue * queue)
{ {
...@@ -105,13 +111,228 @@ void tty_read_flush(struct tty_struct * tty) ...@@ -105,13 +111,228 @@ void tty_read_flush(struct tty_struct * tty)
printk("tty_read_flush: bit already cleared\n"); printk("tty_read_flush: bit already cleared\n");
} }
void change_console(unsigned int new_console) static int hung_up_tty_read(struct inode * inode, struct file * file, char * buf, int count)
{
return 0;
}
static int hung_up_tty_write(struct inode * inode, struct file * file, char * buf, int count)
{
return -EIO;
}
static int hung_up_tty_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
{
return 1;
}
static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
{
return -EBADF;
}
static struct file_operations tty_fops = {
tty_lseek,
tty_read,
tty_write,
NULL, /* tty_readdir */
tty_select,
tty_ioctl,
NULL, /* tty_mmap */
tty_open,
tty_release
};
static struct file_operations hung_up_tty_fops = {
tty_lseek,
hung_up_tty_read,
hung_up_tty_write,
NULL, /* hung_up_tty_readdir */
hung_up_tty_select,
tty_ioctl,
NULL, /* hung_up_tty_mmap */
tty_open,
tty_release
};
void tty_hangup(struct tty_struct * tty)
{ {
if (vt_cons[fg_console].vt_mode == KD_GRAPHICS) struct file * filp;
int dev;
if (!tty)
return; return;
dev = 0x0400 + tty->line;
filp = file_table + NR_FILE;
while (filp-- > file_table) {
if (!filp->f_count)
continue;
if (filp->f_rdev != dev)
continue;
if (filp->f_op != &tty_fops)
continue;
filp->f_op = &hung_up_tty_fops;
}
wake_up_interruptible(&tty->secondary.proc_list);
wake_up_interruptible(&tty->read_q.proc_list);
wake_up_interruptible(&tty->write_q.proc_list);
if (tty->session > 0)
kill_sl(tty->session,SIGHUP,1);
}
static inline int hung_up(struct file * filp)
{
return filp->f_op == &hung_up_tty_fops;
}
extern int kill_proc(int pid, int sig, int priv);
/*
* Performs the back end of a vt switch
*/
void complete_change_console(unsigned int new_console)
{
unsigned char old_vc_mode;
if (new_console == fg_console || new_console >= NR_CONSOLES) if (new_console == fg_console || new_console >= NR_CONSOLES)
return; return;
/*
* If we're switching, we could be going from KD_GRAPHICS to
* KD_TEXT mode or vice versa, which means we need to blank or
* unblank the screen later.
*/
old_vc_mode = vt_cons[fg_console].vc_mode;
update_screen(new_console); update_screen(new_console);
/*
* If this new console is under process control, send it a signal
* telling it that it has acquired. Also check if it has died and
* clean up (similar to logic employed in change_console())
*/
if (vt_cons[new_console].vt_mode.mode == VT_PROCESS)
{
/*
* Send the signal as privileged - kill_proc() will
* tell us if the process has gone or something else
* is awry
*/
if (kill_proc(vt_cons[new_console].vt_pid,
vt_cons[new_console].vt_mode.acqsig,
1) != 0)
{
/*
* The controlling process has died, so we revert back to
* normal operation. In this case, we'll also change back
* to KD_TEXT mode. I'm not sure if this is strictly correct
* but it saves the agony when the X server dies and the screen
* remains blanked due to KD_GRAPHICS! It would be nice to do
* this outside of VT_PROCESS but there is no single process
* to account for and tracking tty count may be undesirable.
*/
vt_cons[new_console].vc_mode = KD_TEXT;
clr_vc_kbd_flag(kbd_table + new_console, VC_RAW);
vt_cons[new_console].vt_mode.mode = VT_AUTO;
vt_cons[new_console].vt_mode.waitv = 0;
vt_cons[new_console].vt_mode.relsig = 0;
vt_cons[new_console].vt_mode.acqsig = 0;
vt_cons[new_console].vt_mode.frsig = 0;
vt_cons[new_console].vt_pid = -1;
vt_cons[new_console].vt_newvt = -1;
}
}
/*
* We do this here because the controlling process above may have
* gone, and so there is now a new vc_mode
*/
if (old_vc_mode != vt_cons[new_console].vc_mode)
{
if (vt_cons[new_console].vc_mode == KD_TEXT)
unblank_screen();
else
{
timer_active &= ~(1<<BLANK_TIMER);
blank_screen();
}
}
return;
}
/*
* Performs the front-end of a vt switch
*/
void change_console(unsigned int new_console)
{
if (new_console == fg_console || new_console >= NR_CONSOLES)
return;
/*
* If this vt is in process mode, then we need to handshake with
* that process before switching. Essentially, we store where that
* vt wants to switch to and wait for it to tell us when it's done
* (via VT_RELDISP ioctl).
*
* We also check to see if the controlling process still exists.
* If it doesn't, we reset this vt to auto mode and continue.
* This is a cheap way to track process control. The worst thing
* that can happen is: we send a signal to a process, it dies, and
* the switch gets "lost" waiting for a response; hopefully, the
* user will try again, we'll detect the process is gone (unless
* the user waits just the right amount of time :-) and revert the
* vt to auto control.
*/
if (vt_cons[fg_console].vt_mode.mode == VT_PROCESS)
{
/*
* Send the signal as privileged - kill_proc() will
* tell us if the process has gone or something else
* is awry
*/
if (kill_proc(vt_cons[fg_console].vt_pid,
vt_cons[fg_console].vt_mode.relsig,
1) == 0)
{
/*
* It worked. Mark the vt to switch to and
* return. The process needs to send us a
* VT_RELDISP ioctl to complete the switch.
*/
vt_cons[fg_console].vt_newvt = new_console;
return;
}
/*
* The controlling process has died, so we revert back to
* normal operation. In this case, we'll also change back
* to KD_TEXT mode. I'm not sure if this is strictly correct
* but it saves the agony when the X server dies and the screen
* remains blanked due to KD_GRAPHICS! It would be nice to do
* this outside of VT_PROCESS but there is no single process
* to account for and tracking tty count may be undesirable.
*/
vt_cons[fg_console].vc_mode = KD_TEXT;
clr_vc_kbd_flag(kbd_table + fg_console, VC_RAW);
vt_cons[fg_console].vt_mode.mode = VT_AUTO;
vt_cons[fg_console].vt_mode.waitv = 0;
vt_cons[fg_console].vt_mode.relsig = 0;
vt_cons[fg_console].vt_mode.acqsig = 0;
vt_cons[fg_console].vt_mode.frsig = 0;
vt_cons[fg_console].vt_pid = -1;
vt_cons[fg_console].vt_newvt = -1;
/*
* Fall through to normal (VT_AUTO) handling of the switch...
*/
}
/*
* Ignore all switches in KD_GRAPHICS+VT_AUTO mode
*/
if (vt_cons[fg_console].vc_mode == KD_GRAPHICS)
return;
complete_change_console(new_console);
} }
void wait_for_keypress(void) void wait_for_keypress(void)
...@@ -272,14 +493,14 @@ int is_ignored(int sig) ...@@ -272,14 +493,14 @@ int is_ignored(int sig)
} }
static int available_canon_input(struct tty_struct *); static int available_canon_input(struct tty_struct *);
static void __wait_for_canon_input(struct tty_struct *); static void __wait_for_canon_input(struct file * file, struct tty_struct *);
static void wait_for_canon_input(struct tty_struct * tty) static void wait_for_canon_input(struct file * file, struct tty_struct * tty)
{ {
if (!available_canon_input(tty)) { if (!available_canon_input(tty)) {
if (current->signal & ~current->blocked) if (current->signal & ~current->blocked)
return; return;
__wait_for_canon_input(tty); __wait_for_canon_input(file, tty);
} }
} }
...@@ -313,7 +534,7 @@ static int read_chan(struct tty_struct * tty, struct file * file, char * buf, in ...@@ -313,7 +534,7 @@ static int read_chan(struct tty_struct * tty, struct file * file, char * buf, in
return -EAGAIN; return -EAGAIN;
} }
} else if (L_CANON(tty)) { } else if (L_CANON(tty)) {
wait_for_canon_input(tty); wait_for_canon_input(file, tty);
if (current->signal & ~current->blocked) if (current->signal & ~current->blocked)
return -ERESTARTSYS; return -ERESTARTSYS;
} }
...@@ -374,6 +595,8 @@ static int read_chan(struct tty_struct * tty, struct file * file, char * buf, in ...@@ -374,6 +595,8 @@ static int read_chan(struct tty_struct * tty, struct file * file, char * buf, in
TTY_WRITE_FLUSH(tty->link); TTY_WRITE_FLUSH(tty->link);
if (!EMPTY(&tty->secondary)) if (!EMPTY(&tty->secondary))
continue; continue;
if (hung_up(file))
break;
current->state = TASK_INTERRUPTIBLE; current->state = TASK_INTERRUPTIBLE;
if (EMPTY(&tty->secondary)) if (EMPTY(&tty->secondary))
schedule(); schedule();
...@@ -402,7 +625,7 @@ static int read_chan(struct tty_struct * tty, struct file * file, char * buf, in ...@@ -402,7 +625,7 @@ static int read_chan(struct tty_struct * tty, struct file * file, char * buf, in
return 0; return 0;
} }
static void __wait_for_canon_input(struct tty_struct * tty) static void __wait_for_canon_input(struct file * file, struct tty_struct * tty)
{ {
struct wait_queue wait = { current, NULL }; struct wait_queue wait = { current, NULL };
...@@ -413,6 +636,8 @@ static void __wait_for_canon_input(struct tty_struct * tty) ...@@ -413,6 +636,8 @@ static void __wait_for_canon_input(struct tty_struct * tty)
break; break;
if (current->signal & ~current->blocked) if (current->signal & ~current->blocked)
break; break;
if (hung_up(file))
break;
schedule(); schedule();
} }
current->state = TASK_RUNNING; current->state = TASK_RUNNING;
...@@ -447,6 +672,8 @@ static int write_chan(struct tty_struct * tty, struct file * file, char * buf, i ...@@ -447,6 +672,8 @@ static int write_chan(struct tty_struct * tty, struct file * file, char * buf, i
while (nr>0) { while (nr>0) {
if (current->signal & ~current->blocked) if (current->signal & ~current->blocked)
break; break;
if (hung_up(file))
break;
if (tty->link && !tty->link->count) { if (tty->link && !tty->link->count) {
send_sig(SIGPIPE,current,0); send_sig(SIGPIPE,current,0);
break; break;
...@@ -524,25 +751,25 @@ static int tty_read(struct inode * inode, struct file * file, char * buf, int co ...@@ -524,25 +751,25 @@ static int tty_read(struct inode * inode, struct file * file, char * buf, int co
static int tty_write(struct inode * inode, struct file * file, char * buf, int count) static int tty_write(struct inode * inode, struct file * file, char * buf, int count)
{ {
int dev,i; int dev, i, is_console;
struct tty_struct * tty; struct tty_struct * tty;
dev = file->f_rdev; dev = file->f_rdev;
is_console = (inode->i_rdev == 0x0400);
if (MAJOR(dev) != 4) { if (MAJOR(dev) != 4) {
printk("tty_write: pseudo-major != 4\n"); printk("tty_write: pseudo-major != 4\n");
return -EINVAL; return -EINVAL;
} }
dev = MINOR(dev); dev = MINOR(dev);
if (redirect && ((dev == 0) || (dev == fg_console+1))) if (is_console && redirect)
tty = redirect; tty = redirect;
else else
tty = TTY_TABLE(dev); tty = TTY_TABLE(dev);
if (!tty || !tty->write) if (!tty || !tty->write)
return -EIO; return -EIO;
if (MINOR(inode->i_rdev) && if (!is_console && L_TOSTOP(tty) && (tty->pgrp > 0) &&
L_TOSTOP(tty) && (tty->pgrp > 0) &&
(current->tty == dev) && (tty->pgrp != current->pgrp)) { (current->tty == dev) && (tty->pgrp != current->pgrp)) {
if (is_orphaned_pgrp(tty->pgrp)) if (is_orphaned_pgrp(current->pgrp))
return -EIO; return -EIO;
if (!is_ignored(SIGTTOU)) { if (!is_ignored(SIGTTOU)) {
(void) kill_pg(current->pgrp, SIGTTOU, 1); (void) kill_pg(current->pgrp, SIGTTOU, 1);
...@@ -555,11 +782,6 @@ static int tty_write(struct inode * inode, struct file * file, char * buf, int c ...@@ -555,11 +782,6 @@ static int tty_write(struct inode * inode, struct file * file, char * buf, int c
return i; return i;
} }
static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
{
return -EBADF;
}
/* /*
* tty_open and tty_release keep up the tty count that contains the * tty_open and tty_release keep up the tty count that contains the
* number of opens done on a tty. We cannot use the inode-count, as * number of opens done on a tty. We cannot use the inode-count, as
...@@ -803,18 +1025,6 @@ static int tty_select(struct inode * inode, struct file * filp, int sel_type, se ...@@ -803,18 +1025,6 @@ static int tty_select(struct inode * inode, struct file * filp, int sel_type, se
return 0; return 0;
} }
static struct file_operations tty_fops = {
tty_lseek,
tty_read,
tty_write,
NULL, /* tty_readdir */
tty_select,
tty_ioctl,
NULL, /* tty_mmap */
tty_open,
tty_release
};
/* /*
* This implements the "Secure Attention Key" --- the idea is to * This implements the "Secure Attention Key" --- the idea is to
* prevent trojan horses by killing all processes associated with this * prevent trojan horses by killing all processes associated with this
...@@ -920,9 +1130,9 @@ long tty_init(long kmem_start) ...@@ -920,9 +1130,9 @@ long tty_init(long kmem_start)
tty_table[i] = 0; tty_table[i] = 0;
tty_termios[i] = 0; tty_termios[i] = 0;
} }
kmem_start = kbd_init(kmem_start);
kmem_start = con_init(kmem_start); kmem_start = con_init(kmem_start);
kmem_start = rs_init(kmem_start); kmem_start = rs_init(kmem_start);
kmem_start = kbd_init(kmem_start);
printk("%d virtual consoles\n\r",NR_CONSOLES); printk("%d virtual consoles\n\r",NR_CONSOLES);
return kmem_start; return kmem_start;
} }
...@@ -386,16 +386,22 @@ int tty_ioctl(struct inode * inode, struct file * file, ...@@ -386,16 +386,22 @@ int tty_ioctl(struct inode * inode, struct file * file,
return -EINVAL; return -EINVAL;
} }
case TIOCCONS: case TIOCCONS:
if (!IS_A_PTY(dev)) if (IS_A_CONSOLE(dev)) {
return -EINVAL; if (!suser())
return -EPERM;
redirect = NULL;
return 0;
}
if (redirect) if (redirect)
return -EBUSY; return -EBUSY;
if (!suser()) if (!suser())
return -EPERM; return -EPERM;
if (IS_A_PTY_MASTER(dev)) if (IS_A_PTY_MASTER(dev))
redirect = other_tty; redirect = other_tty;
else else if (IS_A_PTY_SLAVE(dev))
redirect = tty; redirect = tty;
else
return -EINVAL;
return 0; return 0;
case FIONBIO: case FIONBIO:
arg = get_fs_long((unsigned long *) arg); arg = get_fs_long((unsigned long *) arg);
......
...@@ -20,13 +20,24 @@ ...@@ -20,13 +20,24 @@
#include "vt_kern.h" #include "vt_kern.h"
/* /*
* console (vt and kd) routines, as defined by usl svr4 manual * Console (vt and kd) routines, as defined by USL SVR4 manual
*
* One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and
* /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console,
* and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will
* always treat our set of vt as numbered 1..NR_CONSOLES (corresponding to
* ttys 0..NR_CONSOLES-1).
*
* Mostly done for X386, but with some slight differences and omissions.
* Should be useable by other SYSV programs in the future.
*/ */
struct vt_cons vt_cons[NR_CONSOLES]; struct vt_cons vt_cons[NR_CONSOLES];
extern int sys_ioperm(unsigned long from, unsigned long num, int on); extern int sys_ioperm(unsigned long from, unsigned long num, int on);
extern void set_leds(void); extern void set_leds(void);
extern void change_console(unsigned int new_console);
extern void complete_change_console(unsigned int new_console);
/* /*
* these are the valid i/o ports we're allowed to change. they map all the * these are the valid i/o ports we're allowed to change. they map all the
...@@ -37,26 +48,53 @@ extern void set_leds(void); ...@@ -37,26 +48,53 @@ extern void set_leds(void);
#define GPNUM (GPLAST - GPFIRST + 1) #define GPNUM (GPLAST - GPFIRST + 1)
/* /*
* turns on sound of some freq. 0 turns it off. * Generates sound of some count for some number of clock ticks
* stolen from console.c, so i'm not sure if its the correct interpretation * [count = 1193180 / frequency]
*
* If freq is 0, will turn off sound, else will turn it on for that time.
* If msec is 0, will return immediately, else will sleep for msec time, then
* turn sound off.
*
* We use the BEEP_TIMER vector since we're using the same method to
* generate sound, and we'll overwrite any beep in progress. That may
* be something to fix later, if we like.
*
* We also return immediately, which is what was implied within the X
* comments - KDMKTONE doesn't put the process to sleep.
*/ */
static int void
kiocsound(unsigned int freq) kd_nosound(void)
{ {
if (freq == 0) { /* disable counter 2 */
/* disable counter 2 */ outb(inb_p(0x61)&0xFC, 0x61);
outb(inb_p(0x61)&0xFC, 0x61); return;
} }
else {
void
kd_mksound(unsigned int count, unsigned int ticks)
{
if (count)
{
/* enable counter 2 */ /* enable counter 2 */
outb_p(inb_p(0x61)|3, 0x61); outb_p(inb_p(0x61)|3, 0x61);
/* set command for counter 2, 2 byte write */ /* set command for counter 2, 2 byte write */
outb_p(0xB6, 0x43); outb_p(0xB6, 0x43);
/* select desired HZ */ /* select desired HZ */
outb_p(freq & 0xff, 0x42); outb_p(count & 0xff, 0x42);
outb((freq >> 8) & 0xff, 0x42); outb((count >> 8) & 0xff, 0x42);
if (ticks)
{
timer_table[BEEP_TIMER].expires = jiffies + ticks;
timer_table[BEEP_TIMER].fn = kd_nosound;
timer_active |= (1 << BEEP_TIMER);
}
} }
return 0;
else
kd_nosound();
return;
} }
/* /*
...@@ -66,7 +104,7 @@ kiocsound(unsigned int freq) ...@@ -66,7 +104,7 @@ kiocsound(unsigned int freq)
int vt_ioctl(struct tty_struct *tty, struct file * file, int vt_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned int arg) unsigned int cmd, unsigned int arg)
{ {
int console; int console, i;
unsigned char ucval; unsigned char ucval;
struct kbd_struct * kbd; struct kbd_struct * kbd;
...@@ -78,7 +116,22 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, ...@@ -78,7 +116,22 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
kbd = kbd_table + console; kbd = kbd_table + console;
switch (cmd) { switch (cmd) {
case KIOCSOUND: case KIOCSOUND:
return kiocsound((unsigned int)arg); kd_mksound((unsigned int)arg, 0);
return 0;
case KDMKTONE:
{
unsigned int ticks = HZ * ((arg >> 16) & 0xffff) / 1000;
/*
* Generate the tone for the appropriate number of ticks.
* If the time is zero, turn off sound ourselves.
*/
kd_mksound(arg & 0xffff, ticks);
if (ticks == 0)
kd_nosound();
return 0;
}
case KDGKBTYPE: case KDGKBTYPE:
/* /*
...@@ -120,21 +173,25 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, ...@@ -120,21 +173,25 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
default: default:
return -EINVAL; return -EINVAL;
} }
if (vt_cons[console].vt_mode == (unsigned char) arg) if (vt_cons[console].vc_mode == (unsigned char) arg)
return 0; return 0;
vt_cons[console].vt_mode = (unsigned char) arg; vt_cons[console].vc_mode = (unsigned char) arg;
if (console != fg_console) if (console != fg_console)
return 0; return 0;
/*
* explicitly blank/unblank the screen if switching modes
*/
if (arg == KD_TEXT) if (arg == KD_TEXT)
unblank_screen(); unblank_screen();
else { else {
timer_active &= 1<<BLANK_TIMER; timer_active &= ~(1<<BLANK_TIMER);
blank_screen(); blank_screen();
} }
return 0; return 0;
case KDGETMODE: case KDGETMODE:
verify_area((void *) arg, sizeof(unsigned long)); verify_area((void *) arg, sizeof(unsigned long));
put_fs_long(vt_cons[console].vt_mode, (unsigned long *) arg); put_fs_long(vt_cons[console].vc_mode, (unsigned long *) arg);
return 0; return 0;
case KDMAPDISP: case KDMAPDISP:
...@@ -155,6 +212,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, ...@@ -155,6 +212,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
return -EINVAL; return -EINVAL;
flush_input(tty); flush_input(tty);
return 0; return 0;
case KDGKBMODE: case KDGKBMODE:
verify_area((void *) arg, sizeof(unsigned long)); verify_area((void *) arg, sizeof(unsigned long));
ucval = vc_kbd_flag(kbd, VC_RAW); ucval = vc_kbd_flag(kbd, VC_RAW);
...@@ -172,6 +230,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, ...@@ -172,6 +230,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
ucval |= LED_CAP; ucval |= LED_CAP;
put_fs_byte(ucval, (unsigned char *) arg); put_fs_byte(ucval, (unsigned char *) arg);
return 0; return 0;
case KDSETLED: case KDSETLED:
if (arg & ~7) if (arg & ~7)
return -EINVAL; return -EINVAL;
...@@ -190,6 +249,95 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, ...@@ -190,6 +249,95 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
set_leds(); set_leds();
return 0; return 0;
case VT_SETMODE:
{
struct vt_mode *vtmode = (struct vt_mode *)arg;
char mode;
verify_area((void *)vtmode, sizeof(struct vt_mode));
mode = get_fs_byte(&vtmode->mode);
if (mode != VT_AUTO && mode != VT_PROCESS)
return -EINVAL;
vt_cons[console].vt_mode.mode = mode;
vt_cons[console].vt_mode.waitv = get_fs_byte(&vtmode->waitv);
vt_cons[console].vt_mode.relsig = get_fs_word(&vtmode->relsig);
vt_cons[console].vt_mode.acqsig = get_fs_word(&vtmode->acqsig);
/* the frsig is ignored, so we set it to 0 */
vt_cons[console].vt_mode.frsig = 0;
vt_cons[console].vt_pid = current->pid;
vt_cons[console].vt_newvt = 0;
return 0;
}
case VT_GETMODE:
{
struct vt_mode *vtmode = (struct vt_mode *)arg;
verify_area((void *)arg, sizeof(struct vt_mode));
put_fs_byte(vt_cons[console].vt_mode.mode, &vtmode->mode);
put_fs_byte(vt_cons[console].vt_mode.waitv, &vtmode->waitv);
put_fs_word(vt_cons[console].vt_mode.relsig, &vtmode->relsig);
put_fs_word(vt_cons[console].vt_mode.acqsig, &vtmode->acqsig);
put_fs_word(vt_cons[console].vt_mode.frsig, &vtmode->frsig);
return 0;
}
/*
* Returns the first available (non-opened) console.
*/
case VT_OPENQRY:
verify_area((void *) arg, sizeof(long));
for (i = 1; i <= NR_CONSOLES; ++i)
if (!tty_table[i] || tty_table[i]->count == 0)
break;
put_fs_long(i <= NR_CONSOLES ? i : -1, (unsigned long *)arg);
return 0;
/*
* ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num,
* with num >= 1 (switches to vt 0, our console) are not allowed, just
* to preserve sanity.
*/
case VT_ACTIVATE:
if (arg == 0 || arg > NR_CONSOLES)
return -ENXIO;
change_console(arg - 1);
return 0;
/*
* If a vt is under process control, the kernel will not switch to it
* immediately, but postpone the operation until the process calls this
* ioctl, allowing the switch to complete.
*
* XXX Under X, the switching code calls VT_RELDISP with an arg of 2
* when it has switched back to it's vt. That's not kosher according
* to my documentation, which says this is only called when releasing
* the vt under your control.
*/
case VT_RELDISP:
if (vt_cons[console].vt_mode.mode != VT_PROCESS ||
vt_cons[console].vt_newvt < 0)
return -EINVAL;
if (arg != 0)
{
/*
* If arg is nonzero, the current vt has been released,
* so we can go ahead and complete the switch.
*/
int newvt = vt_cons[console].vt_newvt;
vt_cons[console].vt_newvt = -1;
complete_change_console(newvt);
}
else
{
/*
* Mark that we've performed our part and return.
*/
vt_cons[console].vt_newvt = -1;
}
return 0;
default: default:
return -EINVAL; return -EINVAL;
} }
......
...@@ -5,11 +5,17 @@ ...@@ -5,11 +5,17 @@
* this really is an extension of the vc_cons structure in console.c, but * this really is an extension of the vc_cons structure in console.c, but
* with information needed by the vt package * with information needed by the vt package
*/ */
#include <linux/vt.h>
extern struct vt_cons { extern struct vt_cons {
int vt_mode; /* KD_TEXT, ... */ unsigned char vc_mode; /* KD_TEXT, ... */
unsigned char vc_kbdraw; unsigned char vc_kbdraw;
unsigned char vc_kbde0; unsigned char vc_kbde0;
unsigned char vc_kbdleds; unsigned char vc_kbdleds;
struct vt_mode vt_mode;
int vt_pid;
int vt_newvt;
} vt_cons[NR_CONSOLES]; } vt_cons[NR_CONSOLES];
#endif /* _VT_KERN_H */ #endif /* _VT_KERN_H */
...@@ -31,7 +31,6 @@ void verify_area(void * addr,int size) ...@@ -31,7 +31,6 @@ void verify_area(void * addr,int size)
start = (unsigned long) addr; start = (unsigned long) addr;
size += start & 0xfff; size += start & 0xfff;
start &= 0xfffff000; start &= 0xfffff000;
start += get_base(current->ldt[2]);
while (size>0) { while (size>0) {
size -= 4096; size -= 4096;
write_verify(start); write_verify(start);
...@@ -39,31 +38,6 @@ void verify_area(void * addr,int size) ...@@ -39,31 +38,6 @@ void verify_area(void * addr,int size)
} }
} }
int copy_mem(int nr,struct task_struct * p)
{
unsigned long old_data_base,new_data_base,data_limit;
unsigned long old_code_base,new_code_base,code_limit;
code_limit = get_limit(0x0f);
data_limit = get_limit(0x17);
old_code_base = get_base(current->ldt[1]);
old_data_base = get_base(current->ldt[2]);
if (old_data_base != old_code_base) {
printk("ldt[0]: %08x %08x\n",current->ldt[0].a,current->ldt[0].b);
printk("ldt[1]: %08x %08x\n",current->ldt[1].a,current->ldt[1].b);
printk("ldt[2]: %08x %08x\n",current->ldt[2].a,current->ldt[2].b);
panic("We don't support separate I&D");
}
if (data_limit < code_limit)
panic("Bad data_limit");
new_data_base = old_data_base;
new_code_base = old_code_base;
p->start_code = new_code_base;
set_base(p->ldt[1],new_code_base);
set_base(p->ldt[2],new_data_base);
return copy_page_tables(p);
}
static int find_empty_process(void) static int find_empty_process(void)
{ {
int i, task_nr; int i, task_nr;
...@@ -163,7 +137,7 @@ int sys_fork(long ebx,long ecx,long edx, ...@@ -163,7 +137,7 @@ int sys_fork(long ebx,long ecx,long edx,
if (last_task_used_math == current) if (last_task_used_math == current)
__asm__("clts ; fnsave %0 ; frstor %0"::"m" (p->tss.i387)); __asm__("clts ; fnsave %0 ; frstor %0"::"m" (p->tss.i387));
p->kernel_stack_page = get_free_page(GFP_KERNEL); p->kernel_stack_page = get_free_page(GFP_KERNEL);
if (!p->kernel_stack_page || copy_mem(nr,p)) { if (!p->kernel_stack_page || copy_page_tables(p)) {
task[nr] = NULL; task[nr] = NULL;
REMOVE_LINKS(p); REMOVE_LINKS(p);
free_page(p->kernel_stack_page); free_page(p->kernel_stack_page);
......
...@@ -64,7 +64,7 @@ int sys_syslog(int type, char * buf, int len) ...@@ -64,7 +64,7 @@ int sys_syslog(int type, char * buf, int len)
sti(); sti();
} }
i = 0; i = 0;
while (log_size && len) { while (log_size && i < len) {
c = *((char *) log_page+log_start); c = *((char *) log_page+log_start);
log_start++; log_start++;
log_size--; log_size--;
......
...@@ -229,6 +229,8 @@ int sys_ptrace(long request, long pid, long addr, long data) ...@@ -229,6 +229,8 @@ int sys_ptrace(long request, long pid, long addr, long data)
current->flags |= PF_PTRACED; current->flags |= PF_PTRACED;
return 0; return 0;
} }
if (pid == 1) /* you may not mess with init */
return -EPERM;
if (!(child = get_task(pid))) if (!(child = get_task(pid)))
return -ESRCH; return -ESRCH;
if (request == PTRACE_ATTACH) { if (request == PTRACE_ATTACH) {
......
...@@ -14,6 +14,7 @@ SUBDIRS = tcp ...@@ -14,6 +14,7 @@ SUBDIRS = tcp
ifdef CONFIG_TCPIP ifdef CONFIG_TCPIP
NET_SUBDIRS = tcp NET_SUBDIRS = tcp
TCP_ARCHIVE = tcp/tcpip.a
endif endif
.c.o: .c.o:
...@@ -26,7 +27,7 @@ endif ...@@ -26,7 +27,7 @@ endif
OBJS = socket.o unix.o OBJS = socket.o unix.o
net.o: $(OBJS) subdirs net.o: $(OBJS) subdirs
$(LD) -r -o net.o $(OBJS) tcp/tcpip.o $(LD) -r -o net.o $(OBJS) $(TCP_ARCHIVE)
subdirs: dummy subdirs: dummy
...@@ -40,8 +41,6 @@ dep: ...@@ -40,8 +41,6 @@ dep:
$(CPP) -M *.c > .depend $(CPP) -M *.c > .depend
@for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE) dep) || exit; done @for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE) dep) || exit; done
socket.o: Makefile
dummy: dummy:
# #
......
...@@ -8,24 +8,25 @@ arp.o : arp.c /usr/include/linux/types.h /usr/include/linux/string.h /usr/includ ...@@ -8,24 +8,25 @@ arp.o : arp.c /usr/include/linux/types.h /usr/include/linux/string.h /usr/includ
/usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h /usr/include/linux/iso_fs_sb.h \ /usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h /usr/include/linux/iso_fs_sb.h \
/usr/include/linux/nfs_fs_sb.h /usr/include/linux/mm.h /usr/include/linux/signal.h \ /usr/include/linux/nfs_fs_sb.h /usr/include/linux/mm.h /usr/include/linux/signal.h \
/usr/include/linux/time.h /usr/include/linux/param.h /usr/include/linux/resource.h \ /usr/include/linux/time.h /usr/include/linux/param.h /usr/include/linux/resource.h \
/usr/include/linux/vm86.h /usr/include/linux/math_emu.h /usr/include/linux/socket.h \ /usr/include/linux/vm86.h /usr/include/linux/math_emu.h /usr/include/linux/config.h \
/usr/include/netinet/in.h /usr/include/features.h /usr/include/sys/cdefs.h /usr/include/sys/socket.h \ /usr/include/linux/autoconf.h /usr/include/linux/socket.h /usr/include/netinet/in.h \
/usr/include/asm/system.h timer.h ip.h dev.h /usr/include/linux/sock_ioctl.h \ /usr/include/features.h /usr/include/sys/cdefs.h /usr/include/sys/socket.h /usr/include/asm/system.h \
eth.h tcp.h sock.h arp.h timer.h ip.h dev.h /usr/include/linux/sock_ioctl.h eth.h tcp.h sock.h arp.h
dev.o : dev.c /usr/include/asm/segment.h /usr/include/asm/system.h /usr/include/linux/types.h \ dev.o : dev.c /usr/include/asm/segment.h /usr/include/asm/system.h /usr/include/linux/config.h \
/usr/include/linux/kernel.h /usr/include/linux/sched.h /usr/include/linux/head.h \ /usr/include/linux/autoconf.h /usr/include/linux/types.h /usr/include/linux/kernel.h \
/usr/include/linux/fs.h /usr/include/linux/limits.h /usr/include/linux/wait.h \ /usr/include/linux/sched.h /usr/include/linux/head.h /usr/include/linux/fs.h \
/usr/include/linux/dirent.h /usr/include/linux/vfs.h /usr/include/linux/pipe_fs_i.h \ /usr/include/linux/limits.h /usr/include/linux/wait.h /usr/include/linux/dirent.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/vfs.h /usr/include/linux/pipe_fs_i.h /usr/include/linux/minix_fs_i.h \
/usr/include/linux/iso_fs_i.h /usr/include/linux/nfs_fs_i.h /usr/include/linux/nfs.h \ /usr/include/linux/ext_fs_i.h /usr/include/linux/msdos_fs_i.h /usr/include/linux/iso_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/nfs_fs_i.h /usr/include/linux/nfs.h /usr/include/linux/minix_fs_sb.h \
/usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h /usr/include/linux/mm.h \ /usr/include/linux/ext_fs_sb.h /usr/include/linux/msdos_fs_sb.h /usr/include/linux/iso_fs_sb.h \
/usr/include/linux/signal.h /usr/include/linux/time.h /usr/include/linux/param.h \ /usr/include/linux/nfs_fs_sb.h /usr/include/linux/mm.h /usr/include/linux/signal.h \
/usr/include/linux/resource.h /usr/include/linux/vm86.h /usr/include/linux/math_emu.h \ /usr/include/linux/time.h /usr/include/linux/param.h /usr/include/linux/resource.h \
/usr/include/linux/string.h /usr/include/linux/socket.h /usr/include/netinet/in.h \ /usr/include/linux/vm86.h /usr/include/linux/math_emu.h /usr/include/linux/string.h \
/usr/include/features.h /usr/include/sys/cdefs.h /usr/include/sys/socket.h dev.h \ /usr/include/linux/socket.h /usr/include/netinet/in.h /usr/include/features.h \
eth.h timer.h ip.h /usr/include/linux/sock_ioctl.h tcp.h sock.h /usr/include/linux/errno.h \ /usr/include/sys/cdefs.h /usr/include/sys/socket.h dev.h eth.h timer.h ip.h \
/usr/include/linux/interrupt.h arp.h /usr/include/linux/sock_ioctl.h tcp.h sock.h /usr/include/linux/errno.h /usr/include/linux/interrupt.h \
arp.h
eth.o : eth.c /usr/include/asm/segment.h /usr/include/asm/system.h /usr/include/linux/types.h \ eth.o : eth.c /usr/include/asm/segment.h /usr/include/asm/system.h /usr/include/linux/types.h \
/usr/include/linux/kernel.h /usr/include/linux/sched.h /usr/include/linux/head.h \ /usr/include/linux/kernel.h /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/fs.h /usr/include/linux/limits.h /usr/include/linux/wait.h \
......
...@@ -19,8 +19,8 @@ ...@@ -19,8 +19,8 @@
OBJS = sock.o tcp.o ip.o timer.o we.o arp.o udp.o eth.o Space.o loopback.o \ OBJS = sock.o tcp.o ip.o timer.o we.o arp.o udp.o eth.o Space.o loopback.o \
icmp.o protocols.o raw.o pack_type.o dev.o packet.o icmp.o protocols.o raw.o pack_type.o dev.o packet.o
tcpip.o: $(OBJS) tcpip.a: $(OBJS)
$(LD) -r -o tcpip.o $(OBJS) $(AR) rcs tcpip.a $(OBJS)
subdirs: dummy subdirs: dummy
for i in $(SUBDIRS); do (cd $$i; $(MAKE)); done for i in $(SUBDIRS); do (cd $$i; $(MAKE)); done
......
...@@ -73,19 +73,16 @@ static void ...@@ -73,19 +73,16 @@ static void
send_arp_q(void) send_arp_q(void)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct sk_buff *skb2; struct sk_buff *next;
cli(); cli();
if (arp_q == NULL) return; next = arp_q;
arp_q = NULL;
skb = arp_q; sti();
do { while ((skb = next) != NULL) {
if (skb->magic != ARP_QUEUE_MAGIC) if (skb->magic != ARP_QUEUE_MAGIC)
{ {
printk ("arp.c skb with bad magic - %X: squashing queue\n"); printk ("arp.c skb with bad magic - %X: squashing queue\n", skb->magic);
cli();
arp_q = NULL;
sti();
return; return;
} }
/* extra consistancy check. */ /* extra consistancy check. */
...@@ -94,46 +91,54 @@ send_arp_q(void) ...@@ -94,46 +91,54 @@ send_arp_q(void)
|| (unsigned long)(skb->next) > 16*1024*1024 || (unsigned long)(skb->next) > 16*1024*1024
#endif #endif
) )
{ {
printk ("dev.c: *** bug bad skb->next, squashing queue \n"); printk ("dev.c: *** bug bad skb->next, squashing queue \n");
cli();
arp_q = NULL;
sti();
return; return;
} }
/* first remove skb from the queue. */
next = skb->next;
if (next == skb)
{
next = NULL;
}
else
{
skb->prev->next = next;
next->prev = skb->prev;
}
skb->magic = 0; skb->magic = 0;
skb2=skb->next; skb->next = NULL;
skb->prev = NULL;
sti();
if (!skb->dev->rebuild_header (skb+1, skb->dev)) if (!skb->dev->rebuild_header (skb+1, skb->dev))
{ {
cli();
if (skb->next == skb)
{
arp_q = NULL;
}
else
{
skb->next->prev = skb->prev;
skb->prev->next = skb->next;
arp_q = skb->next;
}
skb->next = NULL; skb->next = NULL;
skb->prev = NULL; skb->prev = NULL;
skb->arp = 1; skb->arp = 1;
sti();
skb->dev->queue_xmit (skb, skb->dev, 0); skb->dev->queue_xmit (skb, skb->dev, 0);
if (arp_q == NULL) break;
cli();
} }
skb=skb2; else
} while (skb != arp_q); {
sti(); cli();
skb->magic = ARP_QUEUE_MAGIC;
if (arp_q == NULL)
{
skb->next = skb;
skb->prev = skb;
arp_q = skb;
}
else
{
skb->next = arp_q;
skb->prev = arp_q->prev;
arp_q->prev->next = skb;
arp_q->prev = skb;
}
sti();
}
}
} }
static void static void
......
...@@ -242,6 +242,12 @@ lock_skb (struct sk_buff *skb) ...@@ -242,6 +242,12 @@ lock_skb (struct sk_buff *skb)
void void
kfree_skb (struct sk_buff *skb, int rw) kfree_skb (struct sk_buff *skb, int rw)
{ {
if (skb == NULL)
{
printk ("kfree_skb: skb = NULL\n");
return;
}
if (skb->lock) if (skb->lock)
{ {
skb->free = 1; skb->free = 1;
...@@ -300,7 +306,7 @@ get_new_socknum(struct proto *prot, unsigned short base) ...@@ -300,7 +306,7 @@ get_new_socknum(struct proto *prot, unsigned short base)
int best=0; int best=0;
int size=32767; /* a big num. */ int size=32767; /* a big num. */
volatile struct sock *sk; volatile struct sock *sk;
start++;
if (base == 0) base = PROT_SOCK+1+(start % 1024); if (base == 0) base = PROT_SOCK+1+(start % 1024);
if (base <= PROT_SOCK) if (base <= PROT_SOCK)
{ {
...@@ -309,7 +315,7 @@ get_new_socknum(struct proto *prot, unsigned short base) ...@@ -309,7 +315,7 @@ get_new_socknum(struct proto *prot, unsigned short base)
/* now look through the entire array and try to find an empty /* now look through the entire array and try to find an empty
ptr. */ ptr. */
for (i = 0; i < SOCK_ARRAY_SIZE; i++) for (i=0; i < SOCK_ARRAY_SIZE; i++)
{ {
j = 0; j = 0;
sk = prot->sock_array[(i+base+1) & (SOCK_ARRAY_SIZE -1)]; sk = prot->sock_array[(i+base+1) & (SOCK_ARRAY_SIZE -1)];
...@@ -318,7 +324,13 @@ get_new_socknum(struct proto *prot, unsigned short base) ...@@ -318,7 +324,13 @@ get_new_socknum(struct proto *prot, unsigned short base)
sk = sk->next; sk = sk->next;
j++; j++;
} }
if (j == 0) return (i+base+1); if (j == 0)
{
start = (i+1+start )%1024;
PRINTK ("get_new_socknum returning %d, start = %d\n",
i+base+1,start);
return (i+base+1);
}
if (j < size) if (j < size)
{ {
best = i; best = i;
...@@ -330,6 +342,7 @@ get_new_socknum(struct proto *prot, unsigned short base) ...@@ -330,6 +342,7 @@ get_new_socknum(struct proto *prot, unsigned short base)
{ {
best += SOCK_ARRAY_SIZE; best += SOCK_ARRAY_SIZE;
} }
PRINTK ("get_new_socknum returning %d, start = %d\n", best+base+1,start);
return (best+base+1); return (best+base+1);
} }
...@@ -445,12 +458,15 @@ destroy_sock(volatile struct sock *sk) ...@@ -445,12 +458,15 @@ destroy_sock(volatile struct sock *sk)
/* just to be safe. */ /* just to be safe. */
sk->inuse = 1; sk->inuse = 1;
/* incase it's sleeping somewhere. */
if (!sk->dead) wake_up (sk->sleep);
remove_sock (sk); remove_sock (sk);
/* now we can no longer get new packets. */ /* now we can no longer get new packets. */
delete_timer((struct timer *)&sk->time_wait); delete_timer((struct timer *)&sk->time_wait);
if (sk->send_tmp) kfree_skb (sk->send_tmp, FREE_WRITE); if (sk->send_tmp != NULL) kfree_skb (sk->send_tmp, FREE_WRITE);
/* cleanup up the write buffer. */ /* cleanup up the write buffer. */
for (skb = sk->wfront; skb != NULL; ) for (skb = sk->wfront; skb != NULL; )
...@@ -617,7 +633,7 @@ destroy_sock(volatile struct sock *sk) ...@@ -617,7 +633,7 @@ destroy_sock(volatile struct sock *sk)
/* now if everything is gone we can free the socket structure, /* now if everything is gone we can free the socket structure,
otherwise we need to keep it around until everything is gone. */ otherwise we need to keep it around until everything is gone. */
if (sk->rmem_alloc <= 0 && sk->wmem_alloc <= 0) if (sk->rmem_alloc == 0 && sk->wmem_alloc == 0)
{ {
kfree_s ((void *)sk,sizeof (*sk)); kfree_s ((void *)sk,sizeof (*sk));
} }
...@@ -634,6 +650,8 @@ destroy_sock(volatile struct sock *sk) ...@@ -634,6 +650,8 @@ destroy_sock(volatile struct sock *sk)
sk->timeout = TIME_DESTROY; sk->timeout = TIME_DESTROY;
reset_timer ((struct timer *)&sk->time_wait); reset_timer ((struct timer *)&sk->time_wait);
} }
PRINTK ("leaving destroy_sock\n");
} }
...@@ -1004,10 +1022,9 @@ ip_proto_create (struct socket *sock, int protocol) ...@@ -1004,10 +1022,9 @@ ip_proto_create (struct socket *sock, int protocol)
/* how many packets we should send before forcing an ack. /* how many packets we should send before forcing an ack.
if this is set to zero it is the same as sk->delay_acks = 0 */ if this is set to zero it is the same as sk->delay_acks = 0 */
sk->max_ack_backlog = MAX_ACK_BACKLOG; sk->max_ack_backlog = 0;
sk->inuse = 0; sk->inuse = 0;
sk->delay_acks = 1; /* default to waiting a while before sending sk->delay_acks = 0;
acks. */
sk->wback = NULL; sk->wback = NULL;
sk->wfront = NULL; sk->wfront = NULL;
sk->rqueue = NULL; sk->rqueue = NULL;
...@@ -1090,6 +1107,7 @@ ip_proto_release(struct socket *sock, struct socket *peer) ...@@ -1090,6 +1107,7 @@ ip_proto_release(struct socket *sock, struct socket *peer)
} }
else else
{ {
PRINTK ("sk->linger set.\n");
sk->prot->close(sk, 0); sk->prot->close(sk, 0);
cli(); cli();
while (sk->state != TCP_CLOSE) while (sk->state != TCP_CLOSE)
...@@ -1109,6 +1127,7 @@ ip_proto_release(struct socket *sock, struct socket *peer) ...@@ -1109,6 +1127,7 @@ ip_proto_release(struct socket *sock, struct socket *peer)
/* this will destroy it. */ /* this will destroy it. */
release_sock (sk); release_sock (sk);
sock->data = NULL; sock->data = NULL;
PRINTK ("ip_proto_release returning\n");
return (0); return (0);
} }
......
...@@ -162,6 +162,8 @@ static void ...@@ -162,6 +162,8 @@ static void
tcp_time_wait (volatile struct sock *sk) tcp_time_wait (volatile struct sock *sk)
{ {
sk->state = TCP_TIME_WAIT; sk->state = TCP_TIME_WAIT;
sk->shutdown = SHUTDOWN_MASK;
if (!sk->dead) wake_up (sk->sleep);
sk->time_wait.len = TCP_TIMEWAIT_LEN; sk->time_wait.len = TCP_TIMEWAIT_LEN;
sk->timeout = TIME_CLOSE; sk->timeout = TIME_CLOSE;
reset_timer ((struct timer *)&sk->time_wait); reset_timer ((struct timer *)&sk->time_wait);
...@@ -219,11 +221,14 @@ tcp_err (int err, unsigned char *header, unsigned long daddr, ...@@ -219,11 +221,14 @@ tcp_err (int err, unsigned char *header, unsigned long daddr,
return; return;
} }
printk ("tcp.c: icmp_err got error\n");
sk->err = icmp_err_convert[err & 0xff].errno; sk->err = icmp_err_convert[err & 0xff].errno;
if (icmp_err_convert[err & 0xff].fatal) if (icmp_err_convert[err & 0xff].fatal)
{ {
if (sk->state != TCP_ESTABLISHED) if (sk->state != TCP_ESTABLISHED)
sk->state = TCP_CLOSE; {
sk->state = TCP_CLOSE;
}
sk->prot->close(sk, 0); sk->prot->close(sk, 0);
} }
...@@ -231,62 +236,105 @@ tcp_err (int err, unsigned char *header, unsigned long daddr, ...@@ -231,62 +236,105 @@ tcp_err (int err, unsigned char *header, unsigned long daddr,
} }
static int
tcp_readable (volatile struct sock *sk)
{
unsigned long counted;
unsigned long amount;
struct sk_buff *skb;
int count=0;
int sum;
if (sk == NULL || sk->rqueue == NULL) return (0);
counted = sk->copied_seq;
amount = 0;
skb = sk->rqueue->next;
/* go until a push or until we are out of data. */
do {
count ++;
if (count > 20)
{
printk ("tcp_readable, more than 20 packets without a psh\n");
printk ("possible read_queue corruption.\n");
return (amount);
}
if (before (counted+1, skb->h.th->seq)) break;
sum = skb->len - ( counted - skb->h.th->seq);
if (skb->h.th->syn) sum ++;
if (sum >= 0)
{
amount += sum;
if (skb->h.th->syn) amount --;
counted += sum;
if (skb->h.th->psh) break;
}
skb = skb->next;
} while (skb != sk->rqueue->next);
return (amount);
}
static int static int
tcp_select (volatile struct sock *sk, int sel_type, select_table *wait) tcp_select (volatile struct sock *sk, int sel_type, select_table *wait)
{ {
sk->inuse = 1;
switch (sel_type) switch (sel_type)
{ {
case SEL_IN: case SEL_IN:
select_wait (sk->sleep, wait); select_wait (sk->sleep, wait);
if (sk->rqueue != NULL && if (sk->rqueue != NULL)
(between (sk->copied_seq, sk->rqueue->next->h.th->seq - 1,
sk->rqueue->next->h.th->seq + sk->rqueue->next->len) ||
sk->state == TCP_LISTEN))
{ {
return (1); if (sk->state == TCP_LISTEN || tcp_readable(sk))
{
release_sock (sk);
return (1);
}
} }
switch (sk->state) if (sk->shutdown & RCV_SHUTDOWN)
{ {
case TCP_LISTEN: release_sock (sk);
case TCP_ESTABLISHED:
case TCP_FIN_WAIT1:
case TCP_SYN_SENT:
case TCP_SYN_RECV:
case TCP_FIN_WAIT2:
return (0);
default:
return (1); return (1);
}
else
{
release_sock (sk);
return (0);
} }
case SEL_OUT: case SEL_OUT:
select_wait (sk->sleep, wait); select_wait (sk->sleep, wait);
switch(sk->state) if (sk->shutdown & SEND_SHUTDOWN)
{
release_sock (sk);
return (0);
}
/* hack so it will probably be able to write something
if it says it's ok to write. */
if (sk->prot->wspace(sk) >= MIN_WRITE_SPACE)
{ {
default: release_sock (sk);
return (1); return (1);
}
release_sock (sk);
return (0);
case TCP_SYN_SENT:
case TCP_SYN_RECV:
return (0);
case TCP_ESTABLISHED: case SEL_EX:
case TCP_CLOSE_WAIT: select_wait(sk->sleep,wait);
/* hack so it will probably be able to write something if (sk->err)
if it says it's ok to write. */ {
if (sk->prot->wspace(sk) >= MIN_WRITE_SPACE) return (1); release_sock (sk);
return (0); return (1);
} }
release_sock (sk);
return (0);
}
case SEL_EX: release_sock (sk);
select_wait(sk->sleep,wait);
if (sk->err) return (1);
if (sk->state == TCP_TIME_WAIT ||
sk->state == TCP_LAST_ACK)
return (1);
return (0);
}
return (0); return (0);
} }
...@@ -303,32 +351,17 @@ tcp_ioctl (volatile struct sock *sk, int cmd, unsigned long arg) ...@@ -303,32 +351,17 @@ tcp_ioctl (volatile struct sock *sk, int cmd, unsigned long arg)
/* case FIONREAD:*/ /* case FIONREAD:*/
{ {
unsigned long amount; unsigned long amount;
unsigned long counted;
int sum;
struct sk_buff *skb;
if (sk->state == TCP_LISTEN) if (sk->state == TCP_LISTEN)
return (-EINVAL); return (-EINVAL);
counted = sk->copied_seq;
amount = 0; amount = 0;
sk->inuse = 1;
if (sk->rqueue != NULL) if (sk->rqueue != NULL)
{ {
skb = sk->rqueue->next; amount = tcp_readable(sk);
/* go until a push or until we are out of data. */
do {
if (before (counted+1, skb->h.th->seq)) break;
sum = skb->len + skb->h.th->seq - counted;
if (sum > 0)
{
amount += sum;
counted += sum;
}
if (skb->h.th->psh) break;
skb = skb->next;
} while (skb != sk->rqueue->next);
} }
release_sock (sk);
PRINTK ("returning %d\n", amount); PRINTK ("returning %d\n", amount);
verify_area ((void *)arg, sizeof (unsigned long)); verify_area ((void *)arg, sizeof (unsigned long));
put_fs_long (amount, (unsigned long *)arg); put_fs_long (amount, (unsigned long *)arg);
...@@ -340,12 +373,14 @@ tcp_ioctl (volatile struct sock *sk, int cmd, unsigned long arg) ...@@ -340,12 +373,14 @@ tcp_ioctl (volatile struct sock *sk, int cmd, unsigned long arg)
struct sk_buff *skb; struct sk_buff *skb;
int answ=0; int answ=0;
/* try to figure out if we need to read some urgent data. */ /* try to figure out if we need to read some urgent data. */
sk->inuse = 1;
if (sk->rqueue != NULL) if (sk->rqueue != NULL)
{ {
skb = sk->rqueue->next; skb = sk->rqueue->next;
if (sk->copied_seq+1 == skb->h.th->seq && skb->h.th->urg) if (sk->copied_seq+1 == skb->h.th->seq && skb->h.th->urg)
answ = 1; answ = 1;
} }
release_sock (sk);
verify_area ((void *) arg, sizeof (unsigned long)); verify_area ((void *) arg, sizeof (unsigned long));
put_fs_long (answ, (void *) arg); put_fs_long (answ, (void *) arg);
return (0); return (0);
...@@ -641,8 +676,8 @@ tcp_write (volatile struct sock *sk, unsigned char *from, ...@@ -641,8 +676,8 @@ tcp_write (volatile struct sock *sk, unsigned char *from,
if (nonblock) if (nonblock)
{ {
PRINTK ("tcp_write: return 2\n");
release_sock (sk); release_sock (sk);
PRINTK ("tcp_write: return 2\n");
if (copied) return (copied); if (copied) return (copied);
return (-EAGAIN); return (-EAGAIN);
} }
...@@ -655,7 +690,8 @@ tcp_write (volatile struct sock *sk, unsigned char *from, ...@@ -655,7 +690,8 @@ tcp_write (volatile struct sock *sk, unsigned char *from,
go to sleep. */ go to sleep. */
release_sock (sk); release_sock (sk);
cli(); cli();
if (sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT) if (sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT &&
sk->err == 0)
{ {
interruptible_sleep_on (sk->sleep); interruptible_sleep_on (sk->sleep);
if (current->signal & ~current->blocked) if (current->signal & ~current->blocked)
...@@ -752,7 +788,9 @@ tcp_write (volatile struct sock *sk, unsigned char *from, ...@@ -752,7 +788,9 @@ tcp_write (volatile struct sock *sk, unsigned char *from,
/* again we will try to avoid it. */ /* again we will try to avoid it. */
cli (); cli ();
if (tmp <= sk->wmem_alloc) if (tmp <= sk->wmem_alloc
&& (sk->state == TCP_ESTABLISHED || sk->state == TCP_CLOSE_WAIT )
&& sk->err == 0)
{ {
interruptible_sleep_on (sk->sleep); interruptible_sleep_on (sk->sleep);
if (current->signal & ~current->blocked) if (current->signal & ~current->blocked)
...@@ -971,18 +1009,26 @@ cleanup_rbuf (volatile struct sock *sk) ...@@ -971,18 +1009,26 @@ cleanup_rbuf (volatile struct sock *sk)
/* at this point we should send an ack if the difference in /* at this point we should send an ack if the difference in
the window, and the amount of space is bigger than the window, and the amount of space is bigger than
TCP_WINDOW_DIFF */ TCP_WINDOW_DIFF */
/* PRINTK ("sk->window left = %d, sk->prot->rspace(sk)=%d\n", PRINTK ("sk->window left = %d, sk->prot->rspace(sk)=%d\n",
sk->window - sk->bytes_rcv, sk->prot->rspace(sk));*/ sk->window - sk->bytes_rcv, sk->prot->rspace(sk));
if ((sk->prot->rspace(sk) > if ((sk->prot->rspace(sk) >
(sk->window - sk->bytes_rcv + TCP_WINDOW_DIFF))) (sk->window - sk->bytes_rcv + TCP_WINDOW_DIFF)))
{ {
sk->ack_backlog++; sk->ack_backlog++;
/* force it to send an ack soon. */ if (sk->ack_backlog > sk->max_ack_backlog)
if ( before (jiffies + TCP_ACK_TIME, sk->time_wait.when))
{ {
sk->time_wait.len = TCP_ACK_TIME; tcp_read_wakeup (sk);
reset_timer ((struct timer *)&sk->time_wait); }
else
{
/* force it to send an ack soon. */
if ( before (jiffies + TCP_ACK_TIME, sk->time_wait.when))
{
sk->time_wait.len = TCP_ACK_TIME;
sk->timeout = TIME_WRITE;
reset_timer ((struct timer *)&sk->time_wait);
}
} }
} }
...@@ -1043,7 +1089,8 @@ tcp_read_urg(volatile struct sock * sk, int nonblock, ...@@ -1043,7 +1089,8 @@ tcp_read_urg(volatile struct sock * sk, int nonblock,
/* now at this point, we may have gotten some data. */ /* now at this point, we may have gotten some data. */
release_sock (sk); release_sock (sk);
cli(); cli();
if (sk->urg == 0 || sk->rqueue == NULL) if ((sk->urg == 0 || sk->rqueue == NULL) && sk->err == 0
&& !(sk->shutdown & RCV_SHUTDOWN) )
{ {
interruptible_sleep_on (sk->sleep); interruptible_sleep_on (sk->sleep);
if (current->signal & ~current->blocked) if (current->signal & ~current->blocked)
...@@ -1085,8 +1132,8 @@ tcp_read_urg(volatile struct sock * sk, int nonblock, ...@@ -1085,8 +1132,8 @@ tcp_read_urg(volatile struct sock * sk, int nonblock,
/* This routine copies from a sock struct into the user buffer. */ /* This routine copies from a sock struct into the user buffer. */
static int static int
tcp_read(volatile struct sock *sk, unsigned char *to, tcp_read (volatile struct sock *sk, unsigned char *to,
int len, int nonblock, unsigned flags) int len, int nonblock, unsigned flags)
{ {
int copied=0; /* will be used to say how much has been copied. */ int copied=0; /* will be used to say how much has been copied. */
struct sk_buff *skb; struct sk_buff *skb;
...@@ -1102,15 +1149,6 @@ tcp_read(volatile struct sock *sk, unsigned char *to, ...@@ -1102,15 +1149,6 @@ tcp_read(volatile struct sock *sk, unsigned char *to,
/* this error should be checked. */ /* this error should be checked. */
if (sk->state == TCP_LISTEN) return (-ENOTCONN); if (sk->state == TCP_LISTEN) return (-ENOTCONN);
/* will catch some errors. */
if (sk->err)
{
int err;
err = -sk->err;
sk->err = 0;
return (err);
}
/* urgent data needs to be handled specially. */ /* urgent data needs to be handled specially. */
if ((flags & MSG_OOB)) if ((flags & MSG_OOB))
return (tcp_read_urg (sk, nonblock, to, len, flags)); return (tcp_read_urg (sk, nonblock, to, len, flags));
...@@ -1184,10 +1222,17 @@ tcp_read(volatile struct sock *sk, unsigned char *to, ...@@ -1184,10 +1222,17 @@ tcp_read(volatile struct sock *sk, unsigned char *to,
PRINTK ("tcp_read about to sleep. state = %d\n",sk->state); PRINTK ("tcp_read about to sleep. state = %d\n",sk->state);
release_sock (sk); /* now we may have some data waiting. */ release_sock (sk); /* now we may have some data waiting. */
/* or we could have changed state. */
cli(); cli();
if ( sk->shutdown & RCV_SHUTDOWN || sk->err != 0)
{
sk->inuse = 1;
sti();
continue;
}
if ( sk->rqueue == NULL || if ( sk->rqueue == NULL ||
before (sk->copied_seq+1, sk->rqueue->next->h.th->seq)) before (sk->copied_seq+1, sk->rqueue->next->h.th->seq) )
{ {
interruptible_sleep_on (sk->sleep); interruptible_sleep_on (sk->sleep);
if (current->signal & ~current->blocked) if (current->signal & ~current->blocked)
...@@ -1299,6 +1344,7 @@ tcp_shutdown (volatile struct sock *sk, int how) ...@@ -1299,6 +1344,7 @@ tcp_shutdown (volatile struct sock *sk, int how)
*/ */
if (!(how & SEND_SHUTDOWN)) return; if (!(how & SEND_SHUTDOWN)) return;
sk->inuse = 1;
/* clear out any half completed packets. */ /* clear out any half completed packets. */
if (sk->send_tmp) if (sk->send_tmp)
...@@ -1306,11 +1352,15 @@ tcp_shutdown (volatile struct sock *sk, int how) ...@@ -1306,11 +1352,15 @@ tcp_shutdown (volatile struct sock *sk, int how)
prot = (struct proto *)sk->prot; prot = (struct proto *)sk->prot;
th=(struct tcp_header *)&sk->dummy_th; th=(struct tcp_header *)&sk->dummy_th;
buff=prot->wmalloc(sk, MAX_RESET_SIZE,1, GFP_KERNEL); release_sock (sk); /* incase the malloc sleeps. */
if (buff == NULL) return; buff=prot->wmalloc(sk, MAX_RESET_SIZE,1 , GFP_KERNEL);
if (buff == NULL)
{
return;
}
sk->inuse = 1; sk->inuse = 1;
PRINTK("tcp_shutdown_send buff = %X\n", buff); PRINTK("tcp_shutdown_send buff = %X\n", buff);
buff->mem_addr = buff; buff->mem_addr = buff;
buff->mem_len = MAX_RESET_SIZE; buff->mem_len = MAX_RESET_SIZE;
...@@ -1326,8 +1376,8 @@ tcp_shutdown (volatile struct sock *sk, int how) ...@@ -1326,8 +1376,8 @@ tcp_shutdown (volatile struct sock *sk, int how)
if (tmp < 0) if (tmp < 0)
{ {
prot->wfree (sk,buff->mem_addr, buff->mem_len); prot->wfree (sk,buff->mem_addr, buff->mem_len);
PRINTK ("Unable to build header for fin.\n");
release_sock(sk); release_sock(sk);
PRINTK ("Unable to build header for fin.\n");
return; return;
} }
...@@ -1338,7 +1388,6 @@ tcp_shutdown (volatile struct sock *sk, int how) ...@@ -1338,7 +1388,6 @@ tcp_shutdown (volatile struct sock *sk, int how)
memcpy (t1, th, sizeof (*t1)); memcpy (t1, th, sizeof (*t1));
t1->seq = net32(sk->send_seq); t1->seq = net32(sk->send_seq);
sk->fin_seq = th->seq+1; /* Contains the one that needs to be acked */
sk->send_seq++; sk->send_seq++;
buff->h.seq = sk->send_seq; buff->h.seq = sk->send_seq;
...@@ -1683,8 +1732,9 @@ tcp_close (volatile struct sock *sk, int timeout) ...@@ -1683,8 +1732,9 @@ tcp_close (volatile struct sock *sk, int timeout)
struct device *dev=NULL; struct device *dev=NULL;
int tmp; int tmp;
PRINTK ("tcp_close ((struct sock *)%X, %d)\n",sk, timeout); PRINTK ("tcp_close ((struct sock *)%X, %d)\n",sk, timeout);
print_sk (sk);
sk->inuse = 1; sk->inuse = 1;
sk->keepopen = 0; sk->keepopen = 1;
sk->shutdown = SHUTDOWN_MASK; sk->shutdown = SHUTDOWN_MASK;
if (!sk->dead) if (!sk->dead)
...@@ -1700,10 +1750,13 @@ tcp_close (volatile struct sock *sk, int timeout) ...@@ -1700,10 +1750,13 @@ tcp_close (volatile struct sock *sk, int timeout)
skb = sk->rqueue; skb = sk->rqueue;
do { do {
skb2=skb->next; skb2=skb->next;
/* if there is some real unread data, send a reset. */
if (skb->len > 0 &&
after (skb->h.th->seq + skb->len + 1, sk->copied_seq))
need_reset = 1;
kfree_skb (skb, FREE_READ); kfree_skb (skb, FREE_READ);
skb=skb2; skb=skb2;
} while (skb != sk->rqueue); } while (skb != sk->rqueue);
need_reset = 1;
} }
sk->rqueue = NULL; sk->rqueue = NULL;
...@@ -1726,8 +1779,6 @@ tcp_close (volatile struct sock *sk, int timeout) ...@@ -1726,8 +1779,6 @@ tcp_close (volatile struct sock *sk, int timeout)
if (timeout) if (timeout)
tcp_time_wait(sk); tcp_time_wait(sk);
release_sock (sk); release_sock (sk);
if (!need_reset)
return;
break; break;
case TCP_TIME_WAIT: case TCP_TIME_WAIT:
...@@ -2117,14 +2168,18 @@ tcp_ack (volatile struct sock *sk, struct tcp_header *th, unsigned long saddr) ...@@ -2117,14 +2168,18 @@ tcp_ack (volatile struct sock *sk, struct tcp_header *th, unsigned long saddr)
/* see if we are done. */ /* see if we are done. */
if ( sk->state == TCP_TIME_WAIT) if ( sk->state == TCP_TIME_WAIT)
{ {
if (sk->rcv_ack_seq == sk->send_seq &&
sk->acked_seq == sk->fin_seq);
if (!sk->dead) wake_up (sk->sleep); if (!sk->dead) wake_up (sk->sleep);
sk->state = TCP_CLOSE; if (sk->rcv_ack_seq == sk->send_seq &&
sk->acked_seq == sk->fin_seq)
{
sk->state = TCP_CLOSE;
sk->shutdown = SHUTDOWN_MASK;
}
} }
if (sk->state == TCP_LAST_ACK || sk->state == TCP_FIN_WAIT2) if (sk->state == TCP_LAST_ACK || sk->state == TCP_FIN_WAIT2)
{ {
if (!sk->dead) wake_up (sk->sleep);
if (sk->rcv_ack_seq == sk->send_seq) if (sk->rcv_ack_seq == sk->send_seq)
{ {
if (sk->acked_seq != sk->fin_seq) if (sk->acked_seq != sk->fin_seq)
...@@ -2133,11 +2188,13 @@ tcp_ack (volatile struct sock *sk, struct tcp_header *th, unsigned long saddr) ...@@ -2133,11 +2188,13 @@ tcp_ack (volatile struct sock *sk, struct tcp_header *th, unsigned long saddr)
} }
else else
{ {
PRINTK ("tcp_ack closing socket - %X\n", sk);
print_sk (sk);
tcp_send_ack (sk->send_seq, sk->acked_seq, sk, th, sk->daddr); tcp_send_ack (sk->send_seq, sk->acked_seq, sk, th, sk->daddr);
sk->state = TCP_CLOSE; sk->shutdown = SHUTDOWN_MASK;
sk->state = TCP_CLOSE;
} }
} }
if (!sk->dead) wake_up (sk->sleep);
} }
PRINTK ("leaving tcp_ack\n"); PRINTK ("leaving tcp_ack\n");
...@@ -2176,17 +2233,16 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk, ...@@ -2176,17 +2233,16 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk,
if (sk->shutdown & RCV_SHUTDOWN) if (sk->shutdown & RCV_SHUTDOWN)
{ {
/* just ack everything. */
sk->acked_seq = th->seq + skb->len + th->syn + th->fin; sk->acked_seq = th->seq + skb->len + th->syn + th->fin;
tcp_send_ack (sk->send_seq, sk->acked_seq, sk, skb->h.th, saddr); tcp_reset (sk->saddr, sk->daddr, skb->h.th,
sk->prot, NULL, skb->dev);
sk->state = TCP_CLOSE;
sk->err = EPIPE;
sk->shutdown = SHUTDOWN_MASK;
PRINTK ("tcp_data: closing socket - %X\n", sk);
print_sk (sk);
kfree_skb (skb, FREE_READ); kfree_skb (skb, FREE_READ);
if (sk->acked_seq == sk->fin_seq) if (!sk->dead) wake_up (sk->sleep);
{
if (!sk->dead) wake_up (sk->sleep);
if (sk->state == TCP_TIME_WAIT || sk->state == TCP_LAST_ACK
|| sk->state == TCP_FIN_WAIT2)
sk->state = TCP_CLOSE;
}
return (0); return (0);
} }
...@@ -2250,7 +2306,7 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk, ...@@ -2250,7 +2306,7 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk,
if (before (sk->acked_seq, sk->copied_seq)) if (before (sk->acked_seq, sk->copied_seq))
{ {
PRINTK ("*** tcp.c:tcp_data bug acked < copied\n"); printk ("*** tcp.c:tcp_data bug acked < copied\n");
sk->acked_seq = sk->copied_seq; sk->acked_seq = sk->copied_seq;
} }
...@@ -2266,6 +2322,7 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk, ...@@ -2266,6 +2322,7 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk,
/* when we ack the fin, we turn on the RCV_SHUTDOWN flag. */ /* when we ack the fin, we turn on the RCV_SHUTDOWN flag. */
if (skb->h.th->fin) if (skb->h.th->fin)
{ {
if (!sk->dead) wake_up (sk->sleep);
sk->shutdown |= RCV_SHUTDOWN; sk->shutdown |= RCV_SHUTDOWN;
} }
...@@ -2281,6 +2338,7 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk, ...@@ -2281,6 +2338,7 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk,
if (skb2->h.th->fin) if (skb2->h.th->fin)
{ {
sk->shutdown |= RCV_SHUTDOWN; sk->shutdown |= RCV_SHUTDOWN;
if (!sk->dead) wake_up (sk->sleep);
} }
/* force an immediate ack. */ /* force an immediate ack. */
...@@ -2308,6 +2366,7 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk, ...@@ -2308,6 +2366,7 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk,
sk->time_wait.len = TCP_ACK_TIME; sk->time_wait.len = TCP_ACK_TIME;
sk->timeout = TIME_WRITE; sk->timeout = TIME_WRITE;
reset_timer ((struct timer *)&sk->time_wait); reset_timer ((struct timer *)&sk->time_wait);
sk->retransmits = 0;
} }
} }
} }
...@@ -2327,10 +2386,15 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk, ...@@ -2327,10 +2386,15 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk,
PRINTK ("data received on dead socket. \n"); PRINTK ("data received on dead socket. \n");
} }
if (sk->state == TCP_FIN_WAIT2 && sk->acked_seq == sk->fin_seq) if (sk->state == TCP_FIN_WAIT2 && sk->acked_seq == sk->fin_seq
&& sk->rcv_ack_seq == sk->send_seq)
{ {
PRINTK ("tcp_data: entering last_ack state sk = %X\n", sk);
print_sk (sk);
tcp_send_ack (sk->send_seq, sk->acked_seq, sk, th, saddr); tcp_send_ack (sk->send_seq, sk->acked_seq, sk, th, saddr);
sk->shutdown = SHUTDOWN_MASK;
sk->state = TCP_LAST_ACK; sk->state = TCP_LAST_ACK;
if (!sk->dead) wake_up (sk->sleep);
} }
return (0); return (0);
...@@ -2384,19 +2448,21 @@ tcp_fin (volatile struct sock *sk, struct tcp_header *th, ...@@ -2384,19 +2448,21 @@ tcp_fin (volatile struct sock *sk, struct tcp_header *th,
wake_up (sk->sleep); wake_up (sk->sleep);
} }
sk->err = 0;
switch (sk->state) switch (sk->state)
{ {
case TCP_SYN_RECV: case TCP_SYN_RECV:
case TCP_SYN_SENT: case TCP_SYN_SENT:
case TCP_ESTABLISHED: case TCP_ESTABLISHED:
sk->fin_seq = th->seq+1; /* Contains the one that needs to be acked */
sk->state = TCP_CLOSE_WAIT; sk->state = TCP_CLOSE_WAIT;
break; break;
case TCP_CLOSE_WAIT: case TCP_CLOSE_WAIT:
case TCP_FIN_WAIT2:
break; /* we got a retransmit of the fin. */ break; /* we got a retransmit of the fin. */
case TCP_FIN_WAIT1: case TCP_FIN_WAIT1:
sk->fin_seq = th->seq+1; /* Contains the one that needs to be acked */
sk->state = TCP_FIN_WAIT2; sk->state = TCP_FIN_WAIT2;
break; break;
...@@ -2409,9 +2475,6 @@ tcp_fin (volatile struct sock *sk, struct tcp_header *th, ...@@ -2409,9 +2475,6 @@ tcp_fin (volatile struct sock *sk, struct tcp_header *th,
reset_timer ((struct timer *)&sk->time_wait); reset_timer ((struct timer *)&sk->time_wait);
return (0); return (0);
case TCP_FIN_WAIT2:
sk->state = TCP_CLOSE;
return (0);
} }
/* there is no longer any reason to do this. Just let tcp_data /* there is no longer any reason to do this. Just let tcp_data
deal with it. */ deal with it. */
...@@ -2563,12 +2626,13 @@ tcp_connect (volatile struct sock *sk, struct sockaddr_in *usin, int addr_len) ...@@ -2563,12 +2626,13 @@ tcp_connect (volatile struct sock *sk, struct sockaddr_in *usin, int addr_len)
memcpy_fromfs (&sin,usin, min(sizeof (sin), addr_len)); memcpy_fromfs (&sin,usin, min(sizeof (sin), addr_len));
if (sin.sin_family && sin.sin_family != AF_INET) return (-EAFNOSUPPORT); if (sin.sin_family && sin.sin_family != AF_INET) return (-EAFNOSUPPORT);
sk->inuse = 1;
sk->daddr = sin.sin_addr.s_addr; sk->daddr = sin.sin_addr.s_addr;
sk->send_seq = timer_seq*SEQ_TICK-seq_offset; sk->send_seq = timer_seq*SEQ_TICK-seq_offset;
sk->rcv_ack_seq = sk->send_seq -1; sk->rcv_ack_seq = sk->send_seq -1;
sk->err = 0; sk->err = 0;
sk->dummy_th.dest = sin.sin_port; sk->dummy_th.dest = sin.sin_port;
release_sock (sk);
buff=sk->prot->wmalloc(sk,MAX_SYN_SIZE,0, GFP_KERNEL); buff=sk->prot->wmalloc(sk,MAX_SYN_SIZE,0, GFP_KERNEL);
if (buff == NULL) if (buff == NULL)
...@@ -2626,7 +2690,7 @@ tcp_connect (volatile struct sock *sk, struct sockaddr_in *usin, int addr_len) ...@@ -2626,7 +2690,7 @@ tcp_connect (volatile struct sock *sk, struct sockaddr_in *usin, int addr_len)
sk->time_wait.len = TCP_CONNECT_TIME; sk->time_wait.len = TCP_CONNECT_TIME;
reset_timer ((struct timer *)&sk->time_wait); reset_timer ((struct timer *)&sk->time_wait);
sk->retransmits = TCP_RETR1 - TCP_SYN_RETRIES; sk->retransmits = TCP_RETR2 - TCP_SYN_RETRIES;
release_sock (sk); release_sock (sk);
return (0); return (0);
} }
...@@ -2835,6 +2899,7 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, ...@@ -2835,6 +2899,7 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
{ {
sk->err = ECONNRESET; sk->err = ECONNRESET;
sk->state = TCP_CLOSE; sk->state = TCP_CLOSE;
sk->shutdown = SHUTDOWN_MASK;
if (!sk->dead) if (!sk->dead)
{ {
wake_up (sk->sleep); wake_up (sk->sleep);
...@@ -2859,20 +2924,34 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, ...@@ -2859,20 +2924,34 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
if (th->rst) if (th->rst)
{ {
/* this means the thing should really be closed. */
sk->err = ECONNRESET; sk->err = ECONNRESET;
sk->state = TCP_CLOSE;
if (!sk->dead) if (sk->state == TCP_CLOSE_WAIT)
{ {
wake_up (sk->sleep); sk->err = EPIPE;
}
/* a reset with a fin just means that the
data was not all read. */
if (!th->fin)
{
sk->state = TCP_CLOSE;
sk->shutdown = SHUTDOWN_MASK;
if (!sk->dead)
{
wake_up (sk->sleep);
}
kfree_skb (skb, FREE_READ);
release_sock(sk);
return (0);
} }
kfree_skb (skb, FREE_READ);
release_sock(sk);
return (0);
} }
if (opt && (opt->security != 0 || opt->compartment != 0 || th->syn)) if (opt && (opt->security != 0 || opt->compartment != 0 || th->syn))
{ {
sk->err = ECONNRESET; sk->err = ECONNRESET;
sk->state = TCP_CLOSE; sk->state = TCP_CLOSE;
sk->state = SHUTDOWN_MASK;
tcp_reset (daddr, saddr, th, sk->prot, opt,dev); tcp_reset (daddr, saddr, th, sk->prot, opt,dev);
if (!sk->dead) if (!sk->dead)
{ {
...@@ -2902,6 +2981,13 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, ...@@ -2902,6 +2981,13 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
} }
} }
if (th->fin && tcp_fin (sk, th, saddr, dev))
{
kfree_skb (skb, FREE_READ);
release_sock(sk);
return (0);
}
if ( tcp_data (skb, sk, saddr, len)) if ( tcp_data (skb, sk, saddr, len))
{ {
kfree_skb (skb, FREE_READ); kfree_skb (skb, FREE_READ);
...@@ -2909,13 +2995,6 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, ...@@ -2909,13 +2995,6 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
return (0); return (0);
} }
if (!th->fin)
{
release_sock(sk);
return (0);
}
tcp_fin (sk, th, saddr, dev);
release_sock(sk); release_sock(sk);
return (0); return (0);
...@@ -2989,8 +3068,9 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, ...@@ -2989,8 +3068,9 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
case TCP_SYN_SENT: case TCP_SYN_SENT:
if (th->rst) if (th->rst)
{ {
sk->err = ECONNREFUSED; sk->err = ECONNREFUSED ;
sk->state = TCP_CLOSE; sk->state = TCP_CLOSE;
sk->state = SHUTDOWN_MASK;
if (!sk->dead) if (!sk->dead)
{ {
wake_up (sk->sleep); wake_up (sk->sleep);
......
...@@ -84,23 +84,23 @@ enum { ...@@ -84,23 +84,23 @@ enum {
#define MAX_RESET_SIZE 40 + sizeof (struct sk_buff) + MAX_HEADER #define MAX_RESET_SIZE 40 + sizeof (struct sk_buff) + MAX_HEADER
#define MAX_WINDOW 12000 #define MAX_WINDOW 12000
#define MIN_WINDOW 2048 #define MIN_WINDOW 2048
#define MAX_ACK_BACKLOG 8 #define MAX_ACK_BACKLOG 2
#define MIN_WRITE_SPACE 2048 #define MIN_WRITE_SPACE 2048
#define TCP_WINDOW_DIFF 2048 #define TCP_WINDOW_DIFF 2048
#define TCP_RETR1 7 /* this is howmany retries it does #define TCP_RETR1 10 /* this is howmany retries it does
before it tries to figure out before it tries to figure out
if the gateway is down. */ if the gateway is down. */
#define TCP_RETR2 10 /* this should take between 3 and #define TCP_RETR2 25 /* this should take at least
ten minutes ( 1024 * rtt). */ 90 minutes to time out. */
#define TCP_TIMEOUT_LEN 720000 /* should be about 2 hrs. */ #define TCP_TIMEOUT_LEN 720000 /* should be about 2 hrs. */
#define TCP_TIMEWAIT_LEN 6000 /* How long to wait to sucessfully #define TCP_TIMEWAIT_LEN 6000 /* How long to wait to sucessfully
close the socket, about 60 seconds. */ close the socket, about 60 seconds. */
#define TCP_ACK_TIME 35 /* time to delay before sending an ack. */ #define TCP_ACK_TIME 35 /* time to delay before sending an ack. */
#define TCP_DONE_TIME 2500 /* maximum time to wait before actually destroying #define TCP_DONE_TIME 250 /* maximum time to wait before actually destroying
a socket. */ a socket. */
#define TCP_WRITE_TIME 100 /* initial time to wait for an ack, #define TCP_WRITE_TIME 100 /* initial time to wait for an ack,
after last transmit. */ after last transmit. */
......
...@@ -232,8 +232,18 @@ net_timer (void) ...@@ -232,8 +232,18 @@ net_timer (void)
break; break;
case TIME_WRITE: /* try to retransmit. */ case TIME_WRITE: /* try to retransmit. */
/* it could be we got here because we needed
to send an ack. So we need to check for that. */
if (sk->send_head != NULL) if (sk->send_head != NULL)
{ {
if (before (jiffies, sk->send_head->when + 2*sk->rtt))
{
sk->time_wait.len = 2*sk->rtt;
sk->timeout = TIME_WRITE;
reset_timer ((struct timer *)&sk->time_wait);
release_sock (sk);
break;
}
PRINTK ("retransmitting.\n"); PRINTK ("retransmitting.\n");
sk->prot->retransmit (sk, 0); sk->prot->retransmit (sk, 0);
...@@ -268,27 +278,6 @@ net_timer (void) ...@@ -268,27 +278,6 @@ net_timer (void)
release_sock (sk); release_sock (sk);
break; break;
} }
/* if we have stuff which hasn't been written because the
window is too small, fall throught to TIME_KEEPOPEN */
if (sk->wfront == NULL && sk->send_tmp == NULL)
{
release_sock (sk);
break;
}
/* this basically assumes tcp here. */
/* exponential fall back. */
/* The rtt should quickly get back to normal once
we start sending packets again. */
sk->rtt *= 2;
sk->time_wait.len = sk->rtt;
sk->timeout = TIME_WRITE;
if (sk->prot->write_wakeup != NULL)
sk->prot->write_wakeup(sk);
reset_timer ((struct timer *)&sk->time_wait);
release_sock (sk); release_sock (sk);
break; break;
...@@ -298,6 +287,12 @@ net_timer (void) ...@@ -298,6 +287,12 @@ net_timer (void)
if (sk->prot->write_wakeup != NULL) if (sk->prot->write_wakeup != NULL)
sk->prot->write_wakeup(sk); sk->prot->write_wakeup(sk);
sk->retransmits ++; sk->retransmits ++;
if (sk->shutdown == SHUTDOWN_MASK)
{
sk->prot->close (sk,1);
sk->state = TCP_CLOSE;
}
if (sk->retransmits > TCP_RETR1) if (sk->retransmits > TCP_RETR1)
{ {
PRINTK ("timer.c TIME_KEEPOPEN time-out 1\n"); PRINTK ("timer.c TIME_KEEPOPEN time-out 1\n");
......
...@@ -184,6 +184,26 @@ unix_proto_recv(struct socket *sock, void *buff, int len, int nonblock, ...@@ -184,6 +184,26 @@ unix_proto_recv(struct socket *sock, void *buff, int len, int nonblock,
return (unix_proto_read (sock, buff, len, nonblock)); return (unix_proto_read (sock, buff, len, nonblock));
} }
/*
* Since unix domain sockets use filenames to communicate, two sockets are
* the same if their strings are the same, even if their lengths are different
* (due to possible null terminations). Verified under SunOS 4.1.2
*/
static int
same_path(char *s1, int l1, char *s2, int l2)
{
/*
* Skip chars while they're equal
*/
for (; l1 && l2 && *s1 == *s2; ++s1, ++s2, --l1, --l2);
/*
* Both must be exhausted, or one must be null terminated and the
* other either exhausted or null terminated, for the paths to be
* equivalent
*/
return ((l1 == 0 || *s1 == '\0') && (l2 == 0 || *s2 == '\0'));
}
static struct unix_proto_data * static struct unix_proto_data *
unix_data_lookup(struct sockaddr_un *sockun, int sockaddr_len) unix_data_lookup(struct sockaddr_un *sockun, int sockaddr_len)
...@@ -193,8 +213,10 @@ unix_data_lookup(struct sockaddr_un *sockun, int sockaddr_len) ...@@ -193,8 +213,10 @@ unix_data_lookup(struct sockaddr_un *sockun, int sockaddr_len)
for (upd = unix_datas; upd <= last_unix_data; ++upd) { for (upd = unix_datas; upd <= last_unix_data; ++upd) {
if (upd->refcnt && upd->socket && if (upd->refcnt && upd->socket &&
upd->socket->state == SS_UNCONNECTED && upd->socket->state == SS_UNCONNECTED &&
upd->sockaddr_len == sockaddr_len && upd->sockaddr_un.sun_family == sockun->sun_family &&
memcmp(&upd->sockaddr_un, sockun, sockaddr_len) == 0) same_path(sockun->sun_path, sockaddr_len - UN_PATH_OFFSET,
upd->sockaddr_un.sun_path,
upd->sockaddr_len - UN_PATH_OFFSET))
return upd; return upd;
} }
return NULL; return NULL;
......
#define UTS_RELEASE "0.99-44" #define UTS_RELEASE "0.99.pl1-46"
#define UTS_VERSION "12/11/92" #define UTS_VERSION "12/20/92"
#define LINUX_COMPILE_TIME "23:05:18" #define LINUX_COMPILE_TIME "14:31:20"
#define LINUX_COMPILE_BY "root" #define LINUX_COMPILE_BY "root"
#define LINUX_COMPILE_HOST "home" #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