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 @@
#
CONFIG_BLK_DEV_HD = CONFIG_BLK_DEV_HD
CONFIG_TCPIP = CONFIG_TCPIP
CONFIG_PROFILE = CONFIG_PROFILE
CONFIG_MAX_16M = CONFIG_MAX_16M
CONFIG_M486 = CONFIG_M486
#
# SCSI support
......
#
# Make "config" the default target if there is no configuration file
#
ifeq (.config,$(wildcard .config))
include .config
else
CONFIGURATION = config
endif
#
# 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
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
# size in blocks.
......@@ -112,20 +123,31 @@ lilo: Image
/etc/lilo/install
config:
ifdef CONFIGURATION
@echo
@echo "You have no .config: running Configure"
@echo
endif
sh Configure < config.in
ifdef CONFIGURATION
@echo
@echo "Configure successful. Try re-making (ignore the error that follows)"
@echo
exit 1
endif
linuxsubdirs: dummy
@for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE)) || exit; done
Version:
Version: dummy
@./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 LINUX_COMPILE_TIME \"`date +%T`\" >> tools/version.h
@echo \#define LINUX_COMPILE_BY \"`whoami`\" >> 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
strip system.tmp
tools/build boot/bootsect boot/setup system.tmp $(ROOT_DEV) > Image
......@@ -162,8 +184,8 @@ boot/setup: boot/setup.s
$(AS86) -o boot/setup.o boot/setup.s
$(LD86) -s -o boot/setup boot/setup.o
boot/setup.s: boot/setup.S include/linux/config.h
$(CPP) -traditional boot/setup.S -o boot/setup.s
boot/setup.s: boot/setup.S include/linux/config.h Makefile
$(CPP) -traditional $(SVGA_MODE) $(RAMDISK) boot/setup.S -o boot/setup.s
boot/bootsect.s: boot/bootsect.S include/linux/config.h Makefile
$(CPP) -traditional $(SVGA_MODE) $(RAMDISK) boot/bootsect.S -o boot/bootsect.s
......@@ -195,7 +217,7 @@ depend dep:
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
dummy:
dummy: $(CONFIGURATION)
#
# include a dependency file if one exists
......@@ -203,3 +225,4 @@ dummy:
ifeq (.depend,$(wildcard .depend))
include .depend
endif
......@@ -78,8 +78,6 @@ go: mov ax,cs
mov ds,ax
mov es,ax
push ax
mov ss,ax ! put stack at INITSEG:0x4000-12.
mov sp,dx
/*
......@@ -121,7 +119,7 @@ go: mov ax,cs
seg fs
mov 2(bx),es
pop ax
mov ax,cs
mov fs,ax
mov gs,ax
......
......@@ -10,6 +10,8 @@ Kernel profiling support
CONFIG_PROFILE y/n n
Limit to memory to low 16MB
CONFIG_MAX_16M y/n y
Use -m486 flag for 486-specific optimizations
CONFIG_M486 y/n y
:
SCSI support
.
......@@ -27,9 +29,9 @@ CONFIG_BLK_DEV_SR y/n y
.
SCSI low-level drivers
.
Adaptek AHA1542 support
Adaptec AHA1542 support
CONFIG_SCSI_AHA1542 y/n y
Adaptek AHA1740 support
Adaptec AHA1740 support
CONFIG_SCSI_AHA1740 y/n y
Always IN support
CONFIG_SCSI_ALWAYS y/n y
......@@ -67,7 +69,7 @@ Accent Async 4 serial support
CONFIG_ACCENT_ASYNC y/n n
Logitech busmouse support
CONFIG_BUSMOUSE y/n n
PS/2 mouse (aka 'auxilliary device') support
PS/2 mouse (aka 'auxiliary device') support
CONFIG_PSMOUSE y/n n
MicroSoft busmouse support
CONFIG_MS_BUSMOUSE y/n n
......
......@@ -376,17 +376,18 @@ static void read_omagic(struct inode *inode, int bytes)
if (inode->i_sb)
block_size = inode->i_sb->s_blocksize;
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));
if (bytes < n)
n = bytes;
blkno = bmap(inode, blk);
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);
brelse(bh);
}
++blk;
dest += n;
bytes -= n;
......
......@@ -12,13 +12,19 @@
#include <asm/system.h>
static struct inode inode_table[NR_INODE];
static struct inode * last_inode = inode_table;
static struct wait_queue * inode_wait;
static struct inode * inode_table;
static struct inode * last_inode;
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 *);
......
......@@ -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/iso_fs.h /usr/include/linux/fcntl.h /usr/include/linux/errno.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 \
/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 \
......
......@@ -18,10 +18,6 @@
#include <asm/segment.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);
#ifdef LEAK_CHECK
......
......@@ -304,6 +304,10 @@ int minix_mkdir(struct inode * dir, const char * name, int len, int mode)
iput(dir);
return -EEXIST;
}
if (dir->i_nlink > 250) {
iput(dir);
return -EMLINK;
}
inode = minix_new_inode(dir);
if (!inode) {
iput(dir);
......@@ -695,6 +699,9 @@ static int do_minix_rename(struct inode * old_dir, const char * old_name, int ol
goto end_rename;
if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
goto end_rename;
retval = -EMLINK;
if (new_dir->i_nlink > 250)
goto end_rename;
}
if (!new_bh)
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
/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/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
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 \
......
......@@ -3,12 +3,15 @@
*
* Copyright (C) 1992 by Linus Torvalds
* based on ideas by Darren Senn
*
* stat,statm extensions by Michael K. Johnson, johnsonm@stolaf.edu
*/
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/tty.h>
#include <asm/segment.h>
#include <asm/io.h>
......@@ -16,6 +19,17 @@
#define LOAD_INT(x) ((x) >> FSHIFT)
#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)
{
int a, b, c;
......@@ -129,6 +143,8 @@ static int get_arg(int pid, char * buffer)
static int get_stat(int pid, char * buffer)
{
struct task_struct ** p = get_task(pid);
unsigned long sigignore=0, sigcatch=0, bit=1;
int i;
char state;
if (!p || !*p)
......@@ -137,14 +153,101 @@ static int get_stat(int pid, char * buffer)
state = '.';
else
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,
(*p)->comm,
state,
(*p)->p_pptr->pid,
(*p)->pgrp,
(*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)
......@@ -181,6 +284,9 @@ static int array_read(struct inode * inode, struct file * file,char * buf, int c
case 11:
length = get_stat(pid, page);
break;
case 12:
length = get_statm(pid, page);
break;
default:
free_page((unsigned long) page);
return -EBADF;
......
......@@ -59,7 +59,8 @@ static struct proc_dir_entry base_dir[] = {
{ 8,3,"lib" },
{ 9,7,"environ" },
{ 10,7,"cmdline" },
{ 11,4,"stat" }
{ 11,4,"stat" },
{ 12,5,"statm" }
};
#define NR_BASE_DIRENTRY ((sizeof (base_dir))/(sizeof (base_dir[0])))
......
......@@ -143,6 +143,7 @@ void proc_read_inode(struct inode * inode)
case 9:
case 10:
case 11:
case 12:
inode->i_mode = S_IFREG | 0444;
inode->i_op = &proc_array_inode_operations;
return;
......
......@@ -7,8 +7,8 @@
*/
#define CONFIG_BLK_DEV_HD 1
#define CONFIG_TCPIP 1
#define CONFIG_PROFILE 1
#define CONFIG_MAX_16M 1
#define CONFIG_M486 1
/*
* SCSI support
......
......@@ -23,7 +23,7 @@
#undef NR_OPEN
#define NR_OPEN 256
#define NR_INODE 128
#define NR_INODE 256
#define NR_FILE 128
#define NR_SUPER 16
#define NR_HASH 997
......@@ -66,7 +66,7 @@
#define WRITEA 3 /* "write-ahead" - silly, but somewhat useful */
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 MINOR(a) ((a)&0xff)
......
......@@ -23,8 +23,19 @@ extern unsigned long kbd_flags;
#define KG_ALT 4
#define KG_ALTGR 5
#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..)
......@@ -80,6 +91,26 @@ extern inline void chg_kbd_flag(int 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)
{
return ((kbd->flags >> flag) & 1);
......
......@@ -136,12 +136,12 @@ sys_setreuid,sys_setregid, sys_sigsuspend, sys_sigpending,
sys_sethostname, sys_setrlimit, sys_getrlimit, sys_getrusage,
sys_gettimeofday, sys_settimeofday, sys_getgroups, sys_setgroups,
sys_select, sys_symlink, sys_lstat, sys_readlink, sys_uselib,
sys_swapon, sys_reboot, sys_readdir, sys_mmap, sys_munmap,
sys_truncate, sys_ftruncate, sys_fchmod, sys_fchown, sys_getpriority,
sys_setpriority, sys_profil, sys_statfs, sys_fstatfs, sys_ioperm,
sys_socketcall, sys_syslog, sys_setitimer, sys_getitimer, sys_newstat,
sys_newlstat, sys_newfstat, sys_newuname, sys_iopl, sys_vhangup,
sys_idle, sys_vm86, sys_wait4, sys_swapoff, sys_sysinfo };
sys_swapon, sys_reboot, sys_readdir, sys_mmap, sys_munmap, sys_truncate,
sys_ftruncate, sys_fchmod, sys_fchown, sys_getpriority, sys_setpriority,
sys_profil, sys_statfs, sys_fstatfs, sys_ioperm, sys_socketcall,
sys_syslog, sys_setitimer, sys_getitimer, sys_newstat, sys_newlstat,
sys_newfstat, sys_newuname, sys_iopl, sys_vhangup, sys_idle, sys_vm86,
sys_wait4, sys_swapoff, sys_sysinfo };
/* So we don't have to do any more manual updating.... */
int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr);
......@@ -285,6 +285,7 @@ extern int is_ignored(int sig);
extern int tty_signal(int sig, struct tty_struct *tty);
extern int kill_pg(int pgrp, 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);
/* tty write functions */
......
......@@ -133,7 +133,7 @@ static unsigned long memory_start = 0; /* After mem_init, stores the */
static unsigned long memory_end = 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 * argv_rc[] = { "/bin/sh", NULL };
......@@ -238,9 +238,9 @@ void start_kernel(void)
#ifdef CONFIG_SCSI
memory_start = scsi_dev_init(memory_start,memory_end);
#endif
memory_start = inode_init(memory_start,memory_end);
mem_init(low_memory_start,memory_start,memory_end);
buffer_init();
inode_init();
time_init();
floppy_init();
sock_init();
......
......@@ -288,6 +288,8 @@ void __math_abort(struct info * info, unsigned int signal)
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);
schedule();
}
......
......@@ -152,6 +152,8 @@ extern int ramdisk_size;
#endif
#if (MAJOR_NR != 9)
#ifndef CURRENT
#define CURRENT (blk_dev[MAJOR_NR].current_request)
#endif
......@@ -259,3 +261,4 @@ static void end_request(int uptodate)
#endif
#endif
#endif
......@@ -216,7 +216,7 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
{
char scsi_cmd[10];
if ((cmd != 0 && dev->id > NR_SCSI_DEVICES))
if ((cmd != 0 && dev->index > NR_SCSI_DEVICES))
return -ENODEV;
if ((cmd == 0 && dev->host_no > max_scsi_hosts))
return -ENODEV;
......
......@@ -97,6 +97,7 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned long cmd, unsign
int result, target;
target = MINOR(dev);
if (target >= NR_SR) return -ENODEV;
switch (cmd)
{
......
......@@ -30,7 +30,7 @@
Kai Makisara, Nov 9, 1992 email makisara@vtinsx.ins.vtt.fi or
Kai.Makisara@vtt.fi
Last changes Dec 6, 1992.
Last changes Dec 19, 1992.
*/
#include <linux/fs.h>
......@@ -56,9 +56,14 @@
before command completion. */
/* #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 ST_TIMEOUT 2000
#define ST_TIMEOUT 6000
#define ST_LONG_TIMEOUT 200000
/* Number of ST_BLOCK_SIZE blocks in the buffers */
......@@ -519,9 +524,13 @@ static void scsi_tape_close(struct inode * inode, struct file * filp)
printk("st%d: Buffer flushed, EOF written\n", dev);
#endif
}
else if (!rewind && scsi_tapes[dev].eof && !scsi_tapes[dev].eof_hit)
st_int_ioctl(inode, filp, MTBSF, 1);
/* Back over the EOF hit inadvertently */
else if (!rewind) {
if ((scsi_tapes[dev].eof == 1) && !scsi_tapes[dev].eof_hit)
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)
st_int_ioctl(inode, filp, MTREW, 1);
......@@ -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,
scsi_tapes[dev].buffer->buffer_bytes);
#endif
if ((scsi_tapes[dev].buffer->buffer_bytes == 0) && scsi_tapes[dev].eof) {
if (scsi_tapes[dev].eof == 1)
return 0;
else /* EOM or blank check */
if ((scsi_tapes[dev].buffer->buffer_bytes == 0) &&
scsi_tapes[dev].eof == 2) /* EOM or Blank Check */
return (-EIO);
}
scsi_tapes[dev].rw = 1;
......@@ -714,7 +720,8 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int 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);
cmd[0] = READ_6;
......@@ -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 );
scsi_tapes[dev].buffer->read_pointer = 0;
scsi_tapes[dev].eof_hit = 0;
if (SCpnt->result != 0 || SCpnt->sense_buffer[0] != 0) {
#ifdef DEBUG
......@@ -796,8 +804,10 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count)
}
}
else
scsi_tapes[dev].buffer->buffer_bytes = scsi_tapes[dev].buffer->buffer_size;
} /* if (SCpnt->result != 0 || SCpnt->sense_buffer[0] != 0) */
scsi_tapes[dev].buffer->buffer_bytes =
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) {
#ifdef DEBUG
......@@ -818,10 +828,11 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count)
else if (scsi_tapes[dev].eof) {
scsi_tapes[dev].eof_hit = 1;
SCpnt->request.dev = -1; /* Mark as not busy */
if (total)
return total;
else
if (total == 0 && scsi_tapes[dev].eof == 1)
scsi_tapes[dev].eof = 0;
if (total == 0 && scsi_tapes[dev].eof == 2)
return (-EIO);
return total;
}
} /* for (total = 0; total < count; ) */
......@@ -956,7 +967,7 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
cmd[0] = SPACE;
cmd[1] = 3;
#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
break;
case MTERASE:
......@@ -1050,6 +1061,8 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
if (!ioctl_result) {
if (cmd_in == MTBSFM)
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) {
scsi_tapes[dev].block_size = arg;
scsi_tapes[dev].buffer->buffer_blocks =
......
......@@ -27,10 +27,10 @@ typedef struct {
Scsi_Device* device;
unsigned dirty:1;
unsigned rw:2;
unsigned eof:1;
unsigned eof:2;
unsigned write_prot:1;
unsigned in_use:1;
unsigned eof_hit:2;
unsigned eof_hit:1;
ST_buffer * buffer;
int block_size;
int min_block;
......
......@@ -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/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/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 \
/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 \
......@@ -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/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/ctype.h /usr/include/linux/kd.h /usr/include/linux/string.h \
/usr/include/linux/keyboard.h /usr/include/asm/segment.h /usr/include/asm/bitops.h \
vt_kern.h
/usr/include/linux/timer.h /usr/include/linux/ctype.h /usr/include/linux/kd.h \
/usr/include/linux/string.h /usr/include/linux/keyboard.h /usr/include/asm/segment.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 \
/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 \
......
......@@ -170,7 +170,10 @@ static int console_blanked = 0;
#define halfcolor (vc_cons[currcons].vc_halfcolor)
#define kbdmode (vc_cons[currcons].vc_kbdmode)
#define tab_stop (vc_cons[currcons].vc_tab_stop)
#define vcmode (vt_cons[currcons].vc_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 clr_kbd(x) clr_vc_kbd_flag(kbd_table+currcons,x)
......@@ -285,7 +288,7 @@ static void set_origin(int currcons)
{
if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM)
return;
if (currcons != fg_console || console_blanked || vtmode == KD_GRAPHICS)
if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
return;
cli();
outb_p(12, video_port_reg);
......@@ -1194,7 +1197,7 @@ void con_write(struct tty_struct * tty)
state = ESnormal;
}
}
if (vtmode == KD_GRAPHICS)
if (vcmode == KD_GRAPHICS)
return;
set_cursor(currcons);
}
......@@ -1203,7 +1206,7 @@ void do_keyboard_interrupt(void)
{
TTY_READ_FLUSH(TTY_TABLE(0));
timer_active &= ~(1<<BLANK_TIMER);
if (vt_cons[fg_console].vt_mode == KD_GRAPHICS)
if (vt_cons[fg_console].vc_mode == KD_GRAPHICS)
return;
if (console_blanked) {
timer_table[BLANK_TIMER].expires = 0;
......@@ -1311,7 +1314,14 @@ long con_init(long kmem_start)
pos = origin = video_mem_start = base;
scr_end = video_mem_end = (base += screen_size);
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);
def_color = 0x07; /* white */
ulcolor = 0x0f; /* bold white */
......@@ -1360,6 +1370,8 @@ static void set_scrmem(int currcons)
void blank_screen(void)
{
if (console_blanked)
return;
timer_table[BLANK_TIMER].fn = unblank_screen;
get_scrmem(fg_console);
hide_cursor(fg_console);
......@@ -1369,6 +1381,8 @@ void blank_screen(void)
void unblank_screen(void)
{
if (!console_blanked)
return;
timer_table[BLANK_TIMER].fn = blank_screen;
if (blankinterval) {
timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
......@@ -1463,7 +1477,7 @@ void console_print(const char * b)
pos+=2;
}
set_cursor(currcons);
if (vt_cons[fg_console].vt_mode == KD_GRAPHICS)
if (vt_cons[fg_console].vc_mode == KD_GRAPHICS)
return;
timer_active &= ~(1<<BLANK_TIMER);
if (console_blanked) {
......@@ -1483,5 +1497,7 @@ int con_open(struct tty_struct *tty, struct file * filp)
{
tty->write = con_write;
tty->ioctl = vt_ioctl;
if (tty->line > NR_CONSOLES)
return -ENODEV;
return 0;
}
......@@ -32,6 +32,8 @@ extern void ctrl_alt_del(void);
extern void change_console(unsigned int new_console);
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];
static struct kbd_struct * kbd = kbd_table;
......@@ -54,27 +56,29 @@ static struct pt_regs * pt_regs;
static void keyboard_interrupt(int int_pt_regs)
{
static unsigned char rep = 0xff;
unsigned char scancode, x;
unsigned char scancode;
pt_regs = (struct pt_regs *) int_pt_regs;
scancode=inb_p(0x60);
x=inb_p(0x61);
outb_p(x|0x80, 0x61);
outb_p(x&0x7f, 0x61);
if (scancode == 0xe0)
set_kbd_flag(KG_E0);
else if (scancode == 0xe1)
set_kbd_flag(KG_E1);
while (inb_p(0x64) & 1) {
kbd_prev_dead_keys |= kbd_dead_keys;
if (!kbd_dead_keys)
kbd_prev_dead_keys = 0;
kbd_dead_keys = 0;
scancode = inb_p(0x60);
tty = TTY_TABLE(0);
kbd = kbd_table + fg_console;
if (vc_kbd_flag(kbd,VC_RAW)) {
kbd_flags = 0;
put_queue(scancode);
do_keyboard_interrupt();
return;
continue;
}
if (scancode == 0xe0) {
set_kbd_dead(KGD_E0);
continue;
} else if (scancode == 0xe1) {
set_kbd_dead(KGD_E1);
continue;
}
if (scancode == 0xe0 || scancode == 0xe1)
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
......@@ -82,11 +86,8 @@ static void keyboard_interrupt(int int_pt_regs)
* 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;
}
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
......@@ -96,17 +97,13 @@ static void keyboard_interrupt(int int_pt_regs)
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;
}
EMPTY(&tty->read_q)))))
continue;
}
rep = scancode;
key_table[scancode](scancode);
}
do_keyboard_interrupt();
clr_kbd_flag(KG_E0);
clr_kbd_flag(KG_E1);
}
static void put_queue(int ch)
......@@ -147,7 +144,7 @@ static void puts_queue(char *cp)
static void ctrl(int sc)
{
if (kbd_flag(KG_E0))
if (kbd_dead(KGD_E0))
set_kbd_flag(KG_RCTRL);
else
set_kbd_flag(KG_LCTRL);
......@@ -155,7 +152,7 @@ static void ctrl(int sc)
static void alt(int sc)
{
if (kbd_flag(KG_E0))
if (kbd_dead(KGD_E0))
set_kbd_flag(KG_ALTGR);
else
set_kbd_flag(KG_ALT);
......@@ -163,7 +160,7 @@ static void alt(int sc)
static void unctrl(int sc)
{
if (kbd_flag(KG_E0))
if (kbd_dead(KGD_E0))
clr_kbd_flag(KG_RCTRL);
else
clr_kbd_flag(KG_LCTRL);
......@@ -171,7 +168,7 @@ static void unctrl(int sc)
static void unalt(int sc)
{
if (kbd_flag(KG_E0))
if (kbd_dead(KGD_E0))
clr_kbd_flag(KG_ALTGR);
else {
clr_kbd_flag(KG_ALT);
......@@ -218,6 +215,8 @@ static void uncaps(int sc)
static void show_ptregs(void)
{
if (!pt_regs)
return;
printk("\nEIP: %04x:%08x",0xffff & pt_regs->cs,pt_regs->eip);
if (pt_regs->cs & 3)
printk(" ESP: %04x:%08x",0xffff & pt_regs->cs,pt_regs->eip);
......@@ -1167,7 +1166,7 @@ static void cursor(int sc)
ctrl_alt_del();
return;
}
if (kbd_flag(KG_E0)) {
if (kbd_dead(KGD_E0)) {
cur(sc);
return;
}
......@@ -1226,7 +1225,7 @@ static void func(int sc)
static void slash(int sc)
{
if (!kbd_flag(KG_E0))
if (!kbd_dead(KGD_E0))
do_self(sc);
else if (vc_kbd_flag(kbd,VC_APPLIC))
applkey('Q');
......@@ -1244,7 +1243,7 @@ static void star(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');
else {
put_queue(13);
......@@ -1418,7 +1417,6 @@ static fptr key_table[] = {
unsigned long kbd_init(unsigned long kmem_start)
{
int i;
unsigned char a;
struct kbd_struct * kbd;
kbd = kbd_table + 0;
......@@ -1428,8 +1426,6 @@ unsigned long kbd_init(unsigned long kmem_start)
kbd->kbd_flags = KBDFLAGS;
}
request_irq(KEYBOARD_IRQ,keyboard_interrupt);
a=inb_p(0x61);
outb_p(a|0x80,0x61);
outb_p(a,0x61);
keyboard_interrupt(0);
return kmem_start;
}
......@@ -160,8 +160,9 @@ static void aux_interrupt(int cpl)
static void release_aux(struct inode * inode, struct file * file)
{
poll_status();
outb_p(AUX_DISABLE,AUX_COMMAND); /* 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 */
free_irq(AUX_IRQ);
aux_busy = 0;
......@@ -288,6 +289,9 @@ unsigned long psaux_init(unsigned long kmem_start)
queue->head = queue->tail = 0;
queue->proc_list = NULL;
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;
}
......
......@@ -28,10 +28,8 @@ static void pty_close(struct tty_struct * tty, struct file * filp)
if (!tty->link)
return;
wake_up_interruptible(&tty->link->write_q.proc_list);
if (IS_A_PTY_MASTER(tty->line)) {
if (tty->link->session > 0)
kill_sl(tty->link->session,SIGHUP,1);
}
if (IS_A_PTY_MASTER(tty->line))
tty_hangup(tty->link);
}
static inline void pty_copy(struct tty_struct * from, struct tty_struct * to)
......
......@@ -59,7 +59,7 @@
*
*/
#define NEW_INTERRUPT_ROUTINE
#undef NEW_INTERRUPT_ROUTINE
#define WAKEUP_CHARS (3*TTY_BUF_SIZE/4)
......@@ -401,9 +401,8 @@ static void modem_status_intr(struct async_struct * info)
unsigned char status = inb(UART_MSR + info->port);
if (!(info->tty->termios->c_cflag & CLOCAL)) {
if (((status & (UART_MSR_DCD|UART_MSR_DDCD)) == UART_MSR_DDCD)
&& info->tty->session > 0)
kill_sl(info->tty->session,SIGHUP,1);
if ((status & (UART_MSR_DCD|UART_MSR_DDCD)) == UART_MSR_DDCD)
tty_hangup(info->tty);
if (info->tty->termios->c_cflag & CRTSCTS)
info->tty->stopped = !(status & UART_MSR_CTS);
......@@ -523,10 +522,8 @@ static void rs_timer(void)
if (!clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
wake_up_interruptible(&info->tty->write_q.proc_list);
}
if (!clear_bit(RS_EVENT_HUP_PGRP, &info->event)) {
if (info->tty->session > 0)
kill_sl(info->tty->session,SIGHUP,1);
}
if (!clear_bit(RS_EVENT_HUP_PGRP, &info->event))
tty_hangup(info->tty);
if (!clear_bit(RS_EVENT_BREAK_INT, &info->event)) {
flush_input(info->tty);
flush_output(info->tty);
......
......@@ -28,6 +28,7 @@
#include <linux/fcntl.h>
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/timer.h>
#include <linux/ctype.h>
#include <linux/kd.h>
#include <linux/mm.h>
......@@ -54,6 +55,11 @@ struct tty_struct * redirect = NULL;
struct wait_queue * keypress_wait = NULL;
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)
{
......@@ -105,13 +111,228 @@ void tty_read_flush(struct tty_struct * tty)
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;
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)
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);
/*
* 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)
......@@ -272,14 +493,14 @@ int is_ignored(int sig)
}
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 (current->signal & ~current->blocked)
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
return -EAGAIN;
}
} else if (L_CANON(tty)) {
wait_for_canon_input(tty);
wait_for_canon_input(file, tty);
if (current->signal & ~current->blocked)
return -ERESTARTSYS;
}
......@@ -374,6 +595,8 @@ static int read_chan(struct tty_struct * tty, struct file * file, char * buf, in
TTY_WRITE_FLUSH(tty->link);
if (!EMPTY(&tty->secondary))
continue;
if (hung_up(file))
break;
current->state = TASK_INTERRUPTIBLE;
if (EMPTY(&tty->secondary))
schedule();
......@@ -402,7 +625,7 @@ static int read_chan(struct tty_struct * tty, struct file * file, char * buf, in
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 };
......@@ -413,6 +636,8 @@ static void __wait_for_canon_input(struct tty_struct * tty)
break;
if (current->signal & ~current->blocked)
break;
if (hung_up(file))
break;
schedule();
}
current->state = TASK_RUNNING;
......@@ -447,6 +672,8 @@ static int write_chan(struct tty_struct * tty, struct file * file, char * buf, i
while (nr>0) {
if (current->signal & ~current->blocked)
break;
if (hung_up(file))
break;
if (tty->link && !tty->link->count) {
send_sig(SIGPIPE,current,0);
break;
......@@ -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)
{
int dev,i;
int dev, i, is_console;
struct tty_struct * tty;
dev = file->f_rdev;
is_console = (inode->i_rdev == 0x0400);
if (MAJOR(dev) != 4) {
printk("tty_write: pseudo-major != 4\n");
return -EINVAL;
}
dev = MINOR(dev);
if (redirect && ((dev == 0) || (dev == fg_console+1)))
if (is_console && redirect)
tty = redirect;
else
tty = TTY_TABLE(dev);
if (!tty || !tty->write)
return -EIO;
if (MINOR(inode->i_rdev) &&
L_TOSTOP(tty) && (tty->pgrp > 0) &&
if (!is_console && L_TOSTOP(tty) && (tty->pgrp > 0) &&
(current->tty == dev) && (tty->pgrp != current->pgrp)) {
if (is_orphaned_pgrp(tty->pgrp))
if (is_orphaned_pgrp(current->pgrp))
return -EIO;
if (!is_ignored(SIGTTOU)) {
(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
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
* 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
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
* prevent trojan horses by killing all processes associated with this
......@@ -920,9 +1130,9 @@ long tty_init(long kmem_start)
tty_table[i] = 0;
tty_termios[i] = 0;
}
kmem_start = kbd_init(kmem_start);
kmem_start = con_init(kmem_start);
kmem_start = rs_init(kmem_start);
kmem_start = kbd_init(kmem_start);
printk("%d virtual consoles\n\r",NR_CONSOLES);
return kmem_start;
}
......@@ -386,16 +386,22 @@ int tty_ioctl(struct inode * inode, struct file * file,
return -EINVAL;
}
case TIOCCONS:
if (!IS_A_PTY(dev))
return -EINVAL;
if (IS_A_CONSOLE(dev)) {
if (!suser())
return -EPERM;
redirect = NULL;
return 0;
}
if (redirect)
return -EBUSY;
if (!suser())
return -EPERM;
if (IS_A_PTY_MASTER(dev))
redirect = other_tty;
else
else if (IS_A_PTY_SLAVE(dev))
redirect = tty;
else
return -EINVAL;
return 0;
case FIONBIO:
arg = get_fs_long((unsigned long *) arg);
......
......@@ -20,13 +20,24 @@
#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];
extern int sys_ioperm(unsigned long from, unsigned long num, int on);
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
......@@ -37,26 +48,53 @@ extern void set_leds(void);
#define GPNUM (GPLAST - GPFIRST + 1)
/*
* turns on sound of some freq. 0 turns it off.
* stolen from console.c, so i'm not sure if its the correct interpretation
* Generates sound of some count for some number of clock ticks
* [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
kiocsound(unsigned int freq)
void
kd_nosound(void)
{
if (freq == 0) {
/* disable counter 2 */
outb(inb_p(0x61)&0xFC, 0x61);
}
else {
return;
}
void
kd_mksound(unsigned int count, unsigned int ticks)
{
if (count)
{
/* enable counter 2 */
outb_p(inb_p(0x61)|3, 0x61);
/* set command for counter 2, 2 byte write */
outb_p(0xB6, 0x43);
/* select desired HZ */
outb_p(freq & 0xff, 0x42);
outb((freq >> 8) & 0xff, 0x42);
outb_p(count & 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)
int vt_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned int arg)
{
int console;
int console, i;
unsigned char ucval;
struct kbd_struct * kbd;
......@@ -78,7 +116,22 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
kbd = kbd_table + console;
switch (cmd) {
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:
/*
......@@ -120,21 +173,25 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
default:
return -EINVAL;
}
if (vt_cons[console].vt_mode == (unsigned char) arg)
if (vt_cons[console].vc_mode == (unsigned char) arg)
return 0;
vt_cons[console].vt_mode = (unsigned char) arg;
vt_cons[console].vc_mode = (unsigned char) arg;
if (console != fg_console)
return 0;
/*
* explicitly blank/unblank the screen if switching modes
*/
if (arg == KD_TEXT)
unblank_screen();
else {
timer_active &= 1<<BLANK_TIMER;
timer_active &= ~(1<<BLANK_TIMER);
blank_screen();
}
return 0;
case KDGETMODE:
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;
case KDMAPDISP:
......@@ -155,6 +212,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
return -EINVAL;
flush_input(tty);
return 0;
case KDGKBMODE:
verify_area((void *) arg, sizeof(unsigned long));
ucval = vc_kbd_flag(kbd, VC_RAW);
......@@ -172,6 +230,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
ucval |= LED_CAP;
put_fs_byte(ucval, (unsigned char *) arg);
return 0;
case KDSETLED:
if (arg & ~7)
return -EINVAL;
......@@ -190,6 +249,95 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
set_leds();
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:
return -EINVAL;
}
......
......@@ -5,11 +5,17 @@
* this really is an extension of the vc_cons structure in console.c, but
* with information needed by the vt package
*/
#include <linux/vt.h>
extern struct vt_cons {
int vt_mode; /* KD_TEXT, ... */
unsigned char vc_mode; /* KD_TEXT, ... */
unsigned char vc_kbdraw;
unsigned char vc_kbde0;
unsigned char vc_kbdleds;
struct vt_mode vt_mode;
int vt_pid;
int vt_newvt;
} vt_cons[NR_CONSOLES];
#endif /* _VT_KERN_H */
......@@ -31,7 +31,6 @@ void verify_area(void * addr,int size)
start = (unsigned long) addr;
size += start & 0xfff;
start &= 0xfffff000;
start += get_base(current->ldt[2]);
while (size>0) {
size -= 4096;
write_verify(start);
......@@ -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)
{
int i, task_nr;
......@@ -163,7 +137,7 @@ int sys_fork(long ebx,long ecx,long edx,
if (last_task_used_math == current)
__asm__("clts ; fnsave %0 ; frstor %0"::"m" (p->tss.i387));
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;
REMOVE_LINKS(p);
free_page(p->kernel_stack_page);
......
......@@ -64,7 +64,7 @@ int sys_syslog(int type, char * buf, int len)
sti();
}
i = 0;
while (log_size && len) {
while (log_size && i < len) {
c = *((char *) log_page+log_start);
log_start++;
log_size--;
......
......@@ -229,6 +229,8 @@ int sys_ptrace(long request, long pid, long addr, long data)
current->flags |= PF_PTRACED;
return 0;
}
if (pid == 1) /* you may not mess with init */
return -EPERM;
if (!(child = get_task(pid)))
return -ESRCH;
if (request == PTRACE_ATTACH) {
......
......@@ -14,6 +14,7 @@ SUBDIRS = tcp
ifdef CONFIG_TCPIP
NET_SUBDIRS = tcp
TCP_ARCHIVE = tcp/tcpip.a
endif
.c.o:
......@@ -26,7 +27,7 @@ endif
OBJS = socket.o unix.o
net.o: $(OBJS) subdirs
$(LD) -r -o net.o $(OBJS) tcp/tcpip.o
$(LD) -r -o net.o $(OBJS) $(TCP_ARCHIVE)
subdirs: dummy
......@@ -40,8 +41,6 @@ dep:
$(CPP) -M *.c > .depend
@for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE) dep) || exit; done
socket.o: Makefile
dummy:
#
......
......@@ -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/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/vm86.h /usr/include/linux/math_emu.h /usr/include/linux/socket.h \
/usr/include/netinet/in.h /usr/include/features.h /usr/include/sys/cdefs.h /usr/include/sys/socket.h \
/usr/include/asm/system.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 \
/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/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/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/string.h /usr/include/linux/socket.h /usr/include/netinet/in.h \
/usr/include/features.h /usr/include/sys/cdefs.h /usr/include/sys/socket.h dev.h \
eth.h timer.h ip.h /usr/include/linux/sock_ioctl.h tcp.h sock.h /usr/include/linux/errno.h \
/usr/include/linux/interrupt.h arp.h
/usr/include/linux/vm86.h /usr/include/linux/math_emu.h /usr/include/linux/config.h \
/usr/include/linux/autoconf.h /usr/include/linux/socket.h /usr/include/netinet/in.h \
/usr/include/features.h /usr/include/sys/cdefs.h /usr/include/sys/socket.h /usr/include/asm/system.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/config.h \
/usr/include/linux/autoconf.h /usr/include/linux/types.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/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/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/string.h \
/usr/include/linux/socket.h /usr/include/netinet/in.h /usr/include/features.h \
/usr/include/sys/cdefs.h /usr/include/sys/socket.h dev.h eth.h timer.h ip.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 \
/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 \
......
......@@ -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 \
icmp.o protocols.o raw.o pack_type.o dev.o packet.o
tcpip.o: $(OBJS)
$(LD) -r -o tcpip.o $(OBJS)
tcpip.a: $(OBJS)
$(AR) rcs tcpip.a $(OBJS)
subdirs: dummy
for i in $(SUBDIRS); do (cd $$i; $(MAKE)); done
......
......@@ -73,19 +73,16 @@ static void
send_arp_q(void)
{
struct sk_buff *skb;
struct sk_buff *skb2;
struct sk_buff *next;
cli();
if (arp_q == NULL) return;
skb = arp_q;
do {
if (skb->magic != ARP_QUEUE_MAGIC)
{
printk ("arp.c skb with bad magic - %X: squashing queue\n");
cli();
next = arp_q;
arp_q = NULL;
sti();
while ((skb = next) != NULL) {
if (skb->magic != ARP_QUEUE_MAGIC)
{
printk ("arp.c skb with bad magic - %X: squashing queue\n", skb->magic);
return;
}
/* extra consistancy check. */
......@@ -94,46 +91,54 @@ send_arp_q(void)
|| (unsigned long)(skb->next) > 16*1024*1024
#endif
)
{
printk ("dev.c: *** bug bad skb->next, squashing queue \n");
cli();
arp_q = NULL;
sti();
return;
}
skb->magic = 0;
skb2=skb->next;
sti();
if (!skb->dev->rebuild_header (skb+1, skb->dev))
/* first remove skb from the queue. */
next = skb->next;
if (next == skb)
{
cli();
if (skb->next == skb)
{
arp_q = NULL;
next = NULL;
}
else
{
skb->next->prev = skb->prev;
skb->prev->next = skb->next;
arp_q = skb->next;
skb->prev->next = next;
next->prev = skb->prev;
}
skb->magic = 0;
skb->next = NULL;
skb->prev = NULL;
if (!skb->dev->rebuild_header (skb+1, skb->dev))
{
skb->next = NULL;
skb->prev = NULL;
skb->arp = 1;
sti();
skb->dev->queue_xmit (skb, skb->dev, 0);
if (arp_q == NULL) break;
}
else
{
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;
}
skb=skb2;
} while (skb != arp_q);
sti();
}
}
}
static void
......
......@@ -242,6 +242,12 @@ lock_skb (struct sk_buff *skb)
void
kfree_skb (struct sk_buff *skb, int rw)
{
if (skb == NULL)
{
printk ("kfree_skb: skb = NULL\n");
return;
}
if (skb->lock)
{
skb->free = 1;
......@@ -300,7 +306,7 @@ get_new_socknum(struct proto *prot, unsigned short base)
int best=0;
int size=32767; /* a big num. */
volatile struct sock *sk;
start++;
if (base == 0) base = PROT_SOCK+1+(start % 1024);
if (base <= PROT_SOCK)
{
......@@ -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
ptr. */
for (i = 0; i < SOCK_ARRAY_SIZE; i++)
for (i=0; i < SOCK_ARRAY_SIZE; i++)
{
j = 0;
sk = prot->sock_array[(i+base+1) & (SOCK_ARRAY_SIZE -1)];
......@@ -318,7 +324,13 @@ get_new_socknum(struct proto *prot, unsigned short base)
sk = sk->next;
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)
{
best = i;
......@@ -330,6 +342,7 @@ get_new_socknum(struct proto *prot, unsigned short base)
{
best += SOCK_ARRAY_SIZE;
}
PRINTK ("get_new_socknum returning %d, start = %d\n", best+base+1,start);
return (best+base+1);
}
......@@ -445,12 +458,15 @@ destroy_sock(volatile struct sock *sk)
/* just to be safe. */
sk->inuse = 1;
/* incase it's sleeping somewhere. */
if (!sk->dead) wake_up (sk->sleep);
remove_sock (sk);
/* now we can no longer get new packets. */
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. */
for (skb = sk->wfront; skb != NULL; )
......@@ -617,7 +633,7 @@ destroy_sock(volatile struct sock *sk)
/* now if everything is gone we can free the socket structure,
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));
}
......@@ -635,6 +651,8 @@ destroy_sock(volatile struct sock *sk)
reset_timer ((struct timer *)&sk->time_wait);
}
PRINTK ("leaving destroy_sock\n");
}
......@@ -1004,10 +1022,9 @@ ip_proto_create (struct socket *sock, int protocol)
/* 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 */
sk->max_ack_backlog = MAX_ACK_BACKLOG;
sk->max_ack_backlog = 0;
sk->inuse = 0;
sk->delay_acks = 1; /* default to waiting a while before sending
acks. */
sk->delay_acks = 0;
sk->wback = NULL;
sk->wfront = NULL;
sk->rqueue = NULL;
......@@ -1090,6 +1107,7 @@ ip_proto_release(struct socket *sock, struct socket *peer)
}
else
{
PRINTK ("sk->linger set.\n");
sk->prot->close(sk, 0);
cli();
while (sk->state != TCP_CLOSE)
......@@ -1109,6 +1127,7 @@ ip_proto_release(struct socket *sock, struct socket *peer)
/* this will destroy it. */
release_sock (sk);
sock->data = NULL;
PRINTK ("ip_proto_release returning\n");
return (0);
}
......
......@@ -162,6 +162,8 @@ static void
tcp_time_wait (volatile struct sock *sk)
{
sk->state = TCP_TIME_WAIT;
sk->shutdown = SHUTDOWN_MASK;
if (!sk->dead) wake_up (sk->sleep);
sk->time_wait.len = TCP_TIMEWAIT_LEN;
sk->timeout = TIME_CLOSE;
reset_timer ((struct timer *)&sk->time_wait);
......@@ -219,11 +221,14 @@ tcp_err (int err, unsigned char *header, unsigned long daddr,
return;
}
printk ("tcp.c: icmp_err got error\n");
sk->err = icmp_err_convert[err & 0xff].errno;
if (icmp_err_convert[err & 0xff].fatal)
{
if (sk->state != TCP_ESTABLISHED)
{
sk->state = TCP_CLOSE;
}
sk->prot->close(sk, 0);
}
......@@ -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
tcp_select (volatile struct sock *sk, int sel_type, select_table *wait)
{
sk->inuse = 1;
switch (sel_type)
{
case SEL_IN:
select_wait (sk->sleep, wait);
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))
if (sk->rqueue != NULL)
{
if (sk->state == TCP_LISTEN || tcp_readable(sk))
{
release_sock (sk);
return (1);
}
}
switch (sk->state)
if (sk->shutdown & RCV_SHUTDOWN)
{
case TCP_LISTEN:
case TCP_ESTABLISHED:
case TCP_FIN_WAIT1:
case TCP_SYN_SENT:
case TCP_SYN_RECV:
case TCP_FIN_WAIT2:
return (0);
default:
release_sock (sk);
return (1);
}
else
{
release_sock (sk);
return (0);
}
case SEL_OUT:
select_wait (sk->sleep, wait);
switch(sk->state)
if (sk->shutdown & SEND_SHUTDOWN)
{
default:
return (1);
case TCP_SYN_SENT:
case TCP_SYN_RECV:
release_sock (sk);
return (0);
case TCP_ESTABLISHED:
case TCP_CLOSE_WAIT:
}
/* 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) return (1);
return (0);
if (sk->prot->wspace(sk) >= MIN_WRITE_SPACE)
{
release_sock (sk);
return (1);
}
release_sock (sk);
return (0);
case SEL_EX:
select_wait(sk->sleep,wait);
if (sk->err) return (1);
if (sk->state == TCP_TIME_WAIT ||
sk->state == TCP_LAST_ACK)
if (sk->err)
{
release_sock (sk);
return (1);
}
release_sock (sk);
return (0);
}
release_sock (sk);
return (0);
}
......@@ -303,32 +351,17 @@ tcp_ioctl (volatile struct sock *sk, int cmd, unsigned long arg)
/* case FIONREAD:*/
{
unsigned long amount;
unsigned long counted;
int sum;
struct sk_buff *skb;
if (sk->state == TCP_LISTEN)
return (-EINVAL);
counted = sk->copied_seq;
amount = 0;
sk->inuse = 1;
if (sk->rqueue != NULL)
{
skb = sk->rqueue->next;
/* 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);
amount = tcp_readable(sk);
}
release_sock (sk);
PRINTK ("returning %d\n", amount);
verify_area ((void *)arg, sizeof (unsigned long));
put_fs_long (amount, (unsigned long *)arg);
......@@ -340,12 +373,14 @@ tcp_ioctl (volatile struct sock *sk, int cmd, unsigned long arg)
struct sk_buff *skb;
int answ=0;
/* try to figure out if we need to read some urgent data. */
sk->inuse = 1;
if (sk->rqueue != NULL)
{
skb = sk->rqueue->next;
if (sk->copied_seq+1 == skb->h.th->seq && skb->h.th->urg)
answ = 1;
}
release_sock (sk);
verify_area ((void *) arg, sizeof (unsigned long));
put_fs_long (answ, (void *) arg);
return (0);
......@@ -641,8 +676,8 @@ tcp_write (volatile struct sock *sk, unsigned char *from,
if (nonblock)
{
PRINTK ("tcp_write: return 2\n");
release_sock (sk);
PRINTK ("tcp_write: return 2\n");
if (copied) return (copied);
return (-EAGAIN);
}
......@@ -655,7 +690,8 @@ tcp_write (volatile struct sock *sk, unsigned char *from,
go to sleep. */
release_sock (sk);
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);
if (current->signal & ~current->blocked)
......@@ -752,7 +788,9 @@ tcp_write (volatile struct sock *sk, unsigned char *from,
/* again we will try to avoid it. */
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);
if (current->signal & ~current->blocked)
......@@ -971,20 +1009,28 @@ cleanup_rbuf (volatile struct sock *sk)
/* at this point we should send an ack if the difference in
the window, and the amount of space is bigger than
TCP_WINDOW_DIFF */
/* PRINTK ("sk->window left = %d, sk->prot->rspace(sk)=%d\n",
sk->window - sk->bytes_rcv, sk->prot->rspace(sk));*/
PRINTK ("sk->window left = %d, sk->prot->rspace(sk)=%d\n",
sk->window - sk->bytes_rcv, sk->prot->rspace(sk));
if ((sk->prot->rspace(sk) >
(sk->window - sk->bytes_rcv + TCP_WINDOW_DIFF)))
{
sk->ack_backlog++;
if (sk->ack_backlog > sk->max_ack_backlog)
{
tcp_read_wakeup (sk);
}
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,
/* now at this point, we may have gotten some data. */
release_sock (sk);
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);
if (current->signal & ~current->blocked)
......@@ -1085,7 +1132,7 @@ tcp_read_urg(volatile struct sock * sk, int nonblock,
/* This routine copies from a sock struct into the user buffer. */
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 copied=0; /* will be used to say how much has been copied. */
......@@ -1102,15 +1149,6 @@ tcp_read(volatile struct sock *sk, unsigned char *to,
/* this error should be checked. */
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. */
if ((flags & MSG_OOB))
return (tcp_read_urg (sk, nonblock, to, len, flags));
......@@ -1184,10 +1222,17 @@ tcp_read(volatile struct sock *sk, unsigned char *to,
PRINTK ("tcp_read about to sleep. state = %d\n",sk->state);
release_sock (sk); /* now we may have some data waiting. */
/* or we could have changed state. */
cli();
if ( sk->shutdown & RCV_SHUTDOWN || sk->err != 0)
{
sk->inuse = 1;
sti();
continue;
}
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);
if (current->signal & ~current->blocked)
......@@ -1299,6 +1344,7 @@ tcp_shutdown (volatile struct sock *sk, int how)
*/
if (!(how & SEND_SHUTDOWN)) return;
sk->inuse = 1;
/* clear out any half completed packets. */
if (sk->send_tmp)
......@@ -1306,11 +1352,15 @@ tcp_shutdown (volatile struct sock *sk, int how)
prot = (struct proto *)sk->prot;
th=(struct tcp_header *)&sk->dummy_th;
buff=prot->wmalloc(sk, MAX_RESET_SIZE,1, GFP_KERNEL);
if (buff == NULL) return;
release_sock (sk); /* incase the malloc sleeps. */
buff=prot->wmalloc(sk, MAX_RESET_SIZE,1 , GFP_KERNEL);
if (buff == NULL)
{
return;
}
sk->inuse = 1;
PRINTK("tcp_shutdown_send buff = %X\n", buff);
buff->mem_addr = buff;
buff->mem_len = MAX_RESET_SIZE;
......@@ -1326,8 +1376,8 @@ tcp_shutdown (volatile struct sock *sk, int how)
if (tmp < 0)
{
prot->wfree (sk,buff->mem_addr, buff->mem_len);
PRINTK ("Unable to build header for fin.\n");
release_sock(sk);
PRINTK ("Unable to build header for fin.\n");
return;
}
......@@ -1338,7 +1388,6 @@ tcp_shutdown (volatile struct sock *sk, int how)
memcpy (t1, th, sizeof (*t1));
t1->seq = net32(sk->send_seq);
sk->fin_seq = th->seq+1; /* Contains the one that needs to be acked */
sk->send_seq++;
buff->h.seq = sk->send_seq;
......@@ -1683,8 +1732,9 @@ tcp_close (volatile struct sock *sk, int timeout)
struct device *dev=NULL;
int tmp;
PRINTK ("tcp_close ((struct sock *)%X, %d)\n",sk, timeout);
print_sk (sk);
sk->inuse = 1;
sk->keepopen = 0;
sk->keepopen = 1;
sk->shutdown = SHUTDOWN_MASK;
if (!sk->dead)
......@@ -1700,10 +1750,13 @@ tcp_close (volatile struct sock *sk, int timeout)
skb = sk->rqueue;
do {
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);
skb=skb2;
} while (skb != sk->rqueue);
need_reset = 1;
}
sk->rqueue = NULL;
......@@ -1726,8 +1779,6 @@ tcp_close (volatile struct sock *sk, int timeout)
if (timeout)
tcp_time_wait(sk);
release_sock (sk);
if (!need_reset)
return;
break;
case TCP_TIME_WAIT:
......@@ -2117,14 +2168,18 @@ tcp_ack (volatile struct sock *sk, struct tcp_header *th, unsigned long saddr)
/* see if we are done. */
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->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->dead) wake_up (sk->sleep);
if (sk->rcv_ack_seq == sk->send_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)
}
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);
sk->shutdown = SHUTDOWN_MASK;
sk->state = TCP_CLOSE;
}
}
if (!sk->dead) wake_up (sk->sleep);
}
PRINTK ("leaving tcp_ack\n");
......@@ -2176,17 +2233,16 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk,
if (sk->shutdown & RCV_SHUTDOWN)
{
/* just ack everything. */
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);
if (sk->acked_seq == sk->fin_seq)
{
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);
}
......@@ -2250,7 +2306,7 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk,
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;
}
......@@ -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. */
if (skb->h.th->fin)
{
if (!sk->dead) wake_up (sk->sleep);
sk->shutdown |= RCV_SHUTDOWN;
}
......@@ -2281,6 +2338,7 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk,
if (skb2->h.th->fin)
{
sk->shutdown |= RCV_SHUTDOWN;
if (!sk->dead) wake_up (sk->sleep);
}
/* force an immediate ack. */
......@@ -2308,6 +2366,7 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk,
sk->time_wait.len = TCP_ACK_TIME;
sk->timeout = TIME_WRITE;
reset_timer ((struct timer *)&sk->time_wait);
sk->retransmits = 0;
}
}
}
......@@ -2327,10 +2386,15 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk,
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);
sk->shutdown = SHUTDOWN_MASK;
sk->state = TCP_LAST_ACK;
if (!sk->dead) wake_up (sk->sleep);
}
return (0);
......@@ -2384,19 +2448,21 @@ tcp_fin (volatile struct sock *sk, struct tcp_header *th,
wake_up (sk->sleep);
}
sk->err = 0;
switch (sk->state)
{
case TCP_SYN_RECV:
case TCP_SYN_SENT:
case TCP_ESTABLISHED:
sk->fin_seq = th->seq+1; /* Contains the one that needs to be acked */
sk->state = TCP_CLOSE_WAIT;
break;
case TCP_CLOSE_WAIT:
case TCP_FIN_WAIT2:
break; /* we got a retransmit of the fin. */
case TCP_FIN_WAIT1:
sk->fin_seq = th->seq+1; /* Contains the one that needs to be acked */
sk->state = TCP_FIN_WAIT2;
break;
......@@ -2409,9 +2475,6 @@ tcp_fin (volatile struct sock *sk, struct tcp_header *th,
reset_timer ((struct timer *)&sk->time_wait);
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
deal with it. */
......@@ -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));
if (sin.sin_family && sin.sin_family != AF_INET) return (-EAFNOSUPPORT);
sk->inuse = 1;
sk->daddr = sin.sin_addr.s_addr;
sk->send_seq = timer_seq*SEQ_TICK-seq_offset;
sk->rcv_ack_seq = sk->send_seq -1;
sk->err = 0;
sk->dummy_th.dest = sin.sin_port;
release_sock (sk);
buff=sk->prot->wmalloc(sk,MAX_SYN_SIZE,0, GFP_KERNEL);
if (buff == NULL)
......@@ -2626,7 +2690,7 @@ tcp_connect (volatile struct sock *sk, struct sockaddr_in *usin, int addr_len)
sk->time_wait.len = TCP_CONNECT_TIME;
reset_timer ((struct timer *)&sk->time_wait);
sk->retransmits = TCP_RETR1 - TCP_SYN_RETRIES;
sk->retransmits = TCP_RETR2 - TCP_SYN_RETRIES;
release_sock (sk);
return (0);
}
......@@ -2835,6 +2899,7 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
{
sk->err = ECONNRESET;
sk->state = TCP_CLOSE;
sk->shutdown = SHUTDOWN_MASK;
if (!sk->dead)
{
wake_up (sk->sleep);
......@@ -2859,8 +2924,20 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
if (th->rst)
{
/* this means the thing should really be closed. */
sk->err = ECONNRESET;
if (sk->state == TCP_CLOSE_WAIT)
{
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);
......@@ -2869,10 +2946,12 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
release_sock(sk);
return (0);
}
}
if (opt && (opt->security != 0 || opt->compartment != 0 || th->syn))
{
sk->err = ECONNRESET;
sk->state = TCP_CLOSE;
sk->state = SHUTDOWN_MASK;
tcp_reset (daddr, saddr, th, sk->prot, opt,dev);
if (!sk->dead)
{
......@@ -2902,20 +2981,20 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
}
}
if ( tcp_data (skb, sk, saddr, len))
if (th->fin && tcp_fin (sk, th, saddr, dev))
{
kfree_skb (skb, FREE_READ);
release_sock(sk);
return (0);
}
if (!th->fin)
if ( tcp_data (skb, sk, saddr, len))
{
kfree_skb (skb, FREE_READ);
release_sock(sk);
return (0);
}
tcp_fin (sk, th, saddr, dev);
release_sock(sk);
return (0);
......@@ -2989,8 +3068,9 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
case TCP_SYN_SENT:
if (th->rst)
{
sk->err = ECONNREFUSED;
sk->err = ECONNREFUSED ;
sk->state = TCP_CLOSE;
sk->state = SHUTDOWN_MASK;
if (!sk->dead)
{
wake_up (sk->sleep);
......
......@@ -84,23 +84,23 @@ enum {
#define MAX_RESET_SIZE 40 + sizeof (struct sk_buff) + MAX_HEADER
#define MAX_WINDOW 12000
#define MIN_WINDOW 2048
#define MAX_ACK_BACKLOG 8
#define MAX_ACK_BACKLOG 2
#define MIN_WRITE_SPACE 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
if the gateway is down. */
#define TCP_RETR2 10 /* this should take between 3 and
ten minutes ( 1024 * rtt). */
#define TCP_RETR2 25 /* this should take at least
90 minutes to time out. */
#define TCP_TIMEOUT_LEN 720000 /* should be about 2 hrs. */
#define TCP_TIMEWAIT_LEN 6000 /* How long to wait to sucessfully
close the socket, about 60 seconds. */
#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. */
#define TCP_WRITE_TIME 100 /* initial time to wait for an ack,
after last transmit. */
......
......@@ -232,8 +232,18 @@ net_timer (void)
break;
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 (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");
sk->prot->retransmit (sk, 0);
......@@ -268,27 +278,6 @@ net_timer (void)
release_sock (sk);
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);
break;
......@@ -298,6 +287,12 @@ net_timer (void)
if (sk->prot->write_wakeup != NULL)
sk->prot->write_wakeup(sk);
sk->retransmits ++;
if (sk->shutdown == SHUTDOWN_MASK)
{
sk->prot->close (sk,1);
sk->state = TCP_CLOSE;
}
if (sk->retransmits > TCP_RETR1)
{
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,
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 *
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) {
if (upd->refcnt && upd->socket &&
upd->socket->state == SS_UNCONNECTED &&
upd->sockaddr_len == sockaddr_len &&
memcmp(&upd->sockaddr_un, sockun, sockaddr_len) == 0)
upd->sockaddr_un.sun_family == sockun->sun_family &&
same_path(sockun->sun_path, sockaddr_len - UN_PATH_OFFSET,
upd->sockaddr_un.sun_path,
upd->sockaddr_len - UN_PATH_OFFSET))
return upd;
}
return NULL;
......
#define UTS_RELEASE "0.99-44"
#define UTS_VERSION "12/11/92"
#define LINUX_COMPILE_TIME "23:05:18"
#define UTS_RELEASE "0.99.pl1-46"
#define UTS_VERSION "12/20/92"
#define LINUX_COMPILE_TIME "14:31:20"
#define LINUX_COMPILE_BY "root"
#define LINUX_COMPILE_HOST "home"
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment