diff options
author | Linus Torvalds <torvalds@cc.helsinki.fi> | 1994-01-26 12:08:25 +0000 |
---|---|---|
committer | Nicolas Pitre <nico@cam.org> | 2007-08-19 14:19:29 -0400 |
commit | cdf6bc43e624291b32c55a499e40625aff5de89b (patch) | |
tree | 42ec33965866208fdfa03de1aaa1cb53aee4b90f | |
parent | 95c5f0cce26ec795afe80ee9fb9a48f22aba2ae2 (diff) | |
download | archive-cdf6bc43e624291b32c55a499e40625aff5de89b.tar.gz |
ALPHA-pl14v
37 files changed, 1167 insertions, 939 deletions
@@ -1,6 +1,6 @@ VERSION = 0.99 PATCHLEVEL = 14 -ALPHA = u +ALPHA = v all: Version zImage diff --git a/drivers/FPU-emu/errors.c b/drivers/FPU-emu/errors.c index 8506997..309ba60 100644 --- a/drivers/FPU-emu/errors.c +++ b/drivers/FPU-emu/errors.c @@ -38,7 +38,8 @@ void Un_impl(void) { unsigned char byte1, FPU_modrm; - RE_ENTRANT_CHECK_OFF + RE_ENTRANT_CHECK_OFF; + /* No need to verify_area(), we have previously fetched these bytes. */ byte1 = get_fs_byte((unsigned char *) FPU_ORIG_EIP); FPU_modrm = get_fs_byte(1 + (unsigned char *) FPU_ORIG_EIP); @@ -49,7 +50,7 @@ void Un_impl(void) printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7); else printk("/%d\n", (FPU_modrm >> 3) & 7); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; EXCEPTION(EX_Invalid); @@ -65,7 +66,8 @@ void emu_printall() "DeNorm", "Inf", "NaN", "Empty" }; unsigned char byte1, FPU_modrm; - RE_ENTRANT_CHECK_OFF + RE_ENTRANT_CHECK_OFF; + /* No need to verify_area(), we have previously fetched these bytes. */ byte1 = get_fs_byte((unsigned char *) FPU_ORIG_EIP); FPU_modrm = get_fs_byte(1 + (unsigned char *) FPU_ORIG_EIP); partial_status = status_word(); @@ -154,7 +156,7 @@ printk(" CW: ic=%d rc=%ld%ld pc=%ld%ld iem=%d ef=%d%d%d%d%d%d\n", (long)(FPU_loaded_data.sigl & 0xFFFF), FPU_loaded_data.exp - EXP_BIAS + 1); printk("%s\n", tag_desc[(int) (unsigned) FPU_loaded_data.tag]); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; } @@ -261,7 +263,7 @@ void exception(int n) } } - RE_ENTRANT_CHECK_OFF + RE_ENTRANT_CHECK_OFF; if ( (~control_word & n & CW_Exceptions) || (n == EX_INTERNAL) ) { #ifdef PRINT_MESSAGES @@ -303,7 +305,7 @@ void exception(int n) */ /* regs[0].tag |= TW_FPU_Interrupt; */ } - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; #ifdef __DEBUG__ math_abort(FPU_info,SIGFPE); diff --git a/drivers/FPU-emu/fpu_emu.h b/drivers/FPU-emu/fpu_emu.h index 6d7c2db..597189a 100644 --- a/drivers/FPU-emu/fpu_emu.h +++ b/drivers/FPU-emu/fpu_emu.h @@ -1,7 +1,7 @@ /*---------------------------------------------------------------------------+ | fpu_emu.h | | | - | Copyright (C) 1992,1993 | + | Copyright (C) 1992,1993,1994 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | Australia. E-mail billm@vaxc.cc.monash.edu.au | | | @@ -62,8 +62,8 @@ #ifdef PARANOID extern char emulating; -# define RE_ENTRANT_CHECK_OFF emulating = 0; -# define RE_ENTRANT_CHECK_ON emulating = 1; +# define RE_ENTRANT_CHECK_OFF emulating = 0 +# define RE_ENTRANT_CHECK_ON emulating = 1 #else # define RE_ENTRANT_CHECK_OFF # define RE_ENTRANT_CHECK_ON diff --git a/drivers/FPU-emu/fpu_entry.c b/drivers/FPU-emu/fpu_entry.c index 0498a1a..527cb36 100644 --- a/drivers/FPU-emu/fpu_entry.c +++ b/drivers/FPU-emu/fpu_entry.c @@ -209,6 +209,7 @@ asmlinkage void math_emulate(long arg) do_another_FPU_instruction: RE_ENTRANT_CHECK_OFF; + FPU_code_verify_area(1); code = get_fs_word((unsigned short *) FPU_EIP); RE_ENTRANT_CHECK_ON; @@ -301,6 +302,7 @@ do_another_FPU_instruction: { FPU_EIP++; RE_ENTRANT_CHECK_OFF; + FPU_code_verify_area(1); code = get_fs_word((unsigned short *) FPU_EIP); RE_ENTRANT_CHECK_ON; } @@ -560,6 +562,7 @@ FPU_fwait_done: unsigned char next; RE_ENTRANT_CHECK_OFF; + FPU_code_verify_area(1); next = get_fs_byte((unsigned char *) FPU_EIP); RE_ENTRANT_CHECK_ON; if ( valid_prefix(next) ) @@ -591,8 +594,10 @@ static int valid_prefix(unsigned char byte) case PREFIX_GS: case OP_SIZE_PREFIX: /* Used often by gcc, but has no effect. */ + FPU_EIP++; RE_ENTRANT_CHECK_OFF; - byte = get_fs_byte((unsigned char *) (++FPU_EIP)); + FPU_code_verify_area(1); + byte = get_fs_byte((unsigned char *) (FPU_EIP)); RE_ENTRANT_CHECK_ON; break; case FWAIT_OPCODE: diff --git a/drivers/FPU-emu/fpu_system.h b/drivers/FPU-emu/fpu_system.h index e8e50c5..52ae0f7 100644 --- a/drivers/FPU-emu/fpu_system.h +++ b/drivers/FPU-emu/fpu_system.h @@ -1,7 +1,8 @@ /*---------------------------------------------------------------------------+ | fpu_system.h | | | - | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Copyright (C) 1992,1994 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | Australia. E-mail billm@vaxc.cc.monash.edu.au | | | +---------------------------------------------------------------------------*/ @@ -41,6 +42,23 @@ #define data_operand_offset (I387.soft.foo) #define operand_selector (I387.soft.fos) +#define FPU_verify_area(x,y,z) if ( verify_area(x,y,z) ) \ + math_abort(FPU_info,SIGSEGV) + +#undef FPU_IGNORE_CODE_SEGV +#ifdef FPU_IGNORE_CODE_SEGV +/* verify_area() is very expensive, and causes the emulator to run + about 20% slower if applied to the code. Anyway, errors due to bad + code addresses should be much rarer than errors due to bad data + addresses. */ +#define FPU_code_verify_area(z) +#else +/* A simpler test than verify_area() can probably be done for + FPU_code_verify_area() because the only possible error is to step + past the upper boundary of a legal code area. */ +#define FPU_code_verify_area(z) FPU_verify_area(VERIFY_READ,(void *)FPU_EIP,z) +#endif + /* ######## temporary and ugly ;-) */ #define FPU_data_address ((void *)(I387.soft.twd)) diff --git a/drivers/FPU-emu/get_address.c b/drivers/FPU-emu/get_address.c index 98f97d6..7742661 100644 --- a/drivers/FPU-emu/get_address.c +++ b/drivers/FPU-emu/get_address.c @@ -3,7 +3,7 @@ | | | Get the effective address from an FPU instruction. | | | - | Copyright (C) 1992,1993 | + | Copyright (C) 1992,1993,1994 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | Australia. E-mail billm@vaxc.cc.monash.edu.au | | | @@ -46,9 +46,10 @@ static void *sib(int mod) unsigned char ss,index,base; long offset; - RE_ENTRANT_CHECK_OFF + RE_ENTRANT_CHECK_OFF; + FPU_code_verify_area(1); base = get_fs_byte((char *) FPU_EIP); /* The SIB byte */ - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; FPU_EIP++; ss = base >> 6; index = (base >> 3) & 7; @@ -74,17 +75,19 @@ static void *sib(int mod) if (mod == 1) { /* 8 bit signed displacement */ - RE_ENTRANT_CHECK_OFF + RE_ENTRANT_CHECK_OFF; + FPU_code_verify_area(1); offset += (signed char) get_fs_byte((char *) FPU_EIP); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; FPU_EIP++; } else if (mod == 2 || base == 5) /* The second condition also has mod==0 */ { /* 32 bit displacment */ - RE_ENTRANT_CHECK_OFF + RE_ENTRANT_CHECK_OFF; + FPU_code_verify_area(4); offset += (signed) get_fs_long((unsigned long *) FPU_EIP); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; FPU_EIP += 4; } @@ -135,9 +138,10 @@ void get_address(unsigned char FPU_modrm) if (FPU_rm == 5) { /* Special case: disp32 */ - RE_ENTRANT_CHECK_OFF + RE_ENTRANT_CHECK_OFF; + FPU_code_verify_area(4); offset = get_fs_long((unsigned long *) FPU_EIP); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; FPU_EIP += 4; FPU_data_address = (void *) offset; return; @@ -150,16 +154,18 @@ void get_address(unsigned char FPU_modrm) } case 1: /* 8 bit signed displacement */ - RE_ENTRANT_CHECK_OFF + RE_ENTRANT_CHECK_OFF; + FPU_code_verify_area(1); offset = (signed char) get_fs_byte((char *) FPU_EIP); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; FPU_EIP++; break; case 2: /* 32 bit displacement */ - RE_ENTRANT_CHECK_OFF + RE_ENTRANT_CHECK_OFF; + FPU_code_verify_area(4); offset = (signed) get_fs_long((unsigned long *) FPU_EIP); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; FPU_EIP += 4; break; case 3: diff --git a/drivers/FPU-emu/load_store.c b/drivers/FPU-emu/load_store.c index 2966b07..f7b6c9c 100644 --- a/drivers/FPU-emu/load_store.c +++ b/drivers/FPU-emu/load_store.c @@ -4,7 +4,7 @@ | This file contains most of the code to interpret the FPU instructions | | which load and store from user memory. | | | - | Copyright (C) 1992,1993 | + | Copyright (C) 1992,1993,1994 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | Australia. E-mail billm@vaxc.cc.monash.edu.au | | | @@ -168,6 +168,7 @@ switch ( type ) break; case 024: /* fldcw */ RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_READ, FPU_data_address, 2); control_word = get_fs_word((unsigned short *) FPU_data_address); RE_ENTRANT_CHECK_ON; if ( partial_status & ~control_word & CW_Exceptions ) @@ -206,7 +207,7 @@ switch ( type ) break; case 034: /* fstcw m16int */ RE_ENTRANT_CHECK_OFF; - verify_area(VERIFY_WRITE,FPU_data_address,2); + FPU_verify_area(VERIFY_WRITE,FPU_data_address,2); put_fs_word(control_word, (short *) FPU_data_address); RE_ENTRANT_CHECK_ON; NO_NET_DATA_EFFECT; @@ -220,7 +221,7 @@ switch ( type ) break; case 036: /* fstsw m2byte */ RE_ENTRANT_CHECK_OFF; - verify_area(VERIFY_WRITE,FPU_data_address,2); + FPU_verify_area(VERIFY_WRITE,FPU_data_address,2); put_fs_word(status_word(),(short *) FPU_data_address); RE_ENTRANT_CHECK_ON; NO_NET_DATA_EFFECT; diff --git a/drivers/FPU-emu/poly_sin.c b/drivers/FPU-emu/poly_sin.c index b6a0507..aa43448 100644 --- a/drivers/FPU-emu/poly_sin.c +++ b/drivers/FPU-emu/poly_sin.c @@ -3,7 +3,7 @@ | | | Computation of an approximation of the sin function by a polynomial | | | - | Copyright (C) 1992,1993 | + | Copyright (C) 1992,1993,1994 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | Australia. E-mail billm@vaxc.cc.monash.edu.au | | | @@ -128,20 +128,20 @@ void poly_sine(FPU_REG const *arg, FPU_REG *result) ) { #ifdef DEBUGGING - RE_ENTRANT_CHECK_OFF + RE_ENTRANT_CHECK_OFF; printk("\nEXP=%d, MS=%08x, LS=%08x\n", result->exp, result->sigh, result->sigl); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; #endif DEBUGGING EXCEPTION(EX_INTERNAL|0x103); } #ifdef DEBUGGING - RE_ENTRANT_CHECK_OFF + RE_ENTRANT_CHECK_OFF; printk("\n***CORRECTING ILLEGAL RESULT*** in poly_sin() computation\n"); printk("EXP=%d, MS=%08x, LS=%08x\n", result->exp, result->sigh, result->sigl); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; #endif DEBUGGING result->sigl = 0; /* Truncate the result to 1.00 */ diff --git a/drivers/FPU-emu/reg_ld_str.c b/drivers/FPU-emu/reg_ld_str.c index c9d7495..7210a0a 100644 --- a/drivers/FPU-emu/reg_ld_str.c +++ b/drivers/FPU-emu/reg_ld_str.c @@ -3,7 +3,7 @@ | | | All of the functions which transfer data between user memory and FPU_REGs.| | | - | Copyright (C) 1992,1993 | + | Copyright (C) 1992,1993,1994 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | Australia. E-mail billm@vaxc.cc.monash.edu.au | | | @@ -49,13 +49,14 @@ int reg_load_extended(void) long double *s = (long double *)FPU_data_address; unsigned long sigl, sigh, exp; - RE_ENTRANT_CHECK_OFF + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_READ, s, 10); /* Use temporary variables here because FPU_loaded data is static and hence re-entrancy problems can arise */ sigl = get_fs_long((unsigned long *) s); sigh = get_fs_long(1 + (unsigned long *) s); exp = get_fs_word(4 + (unsigned short *) s); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; FPU_loaded_data.tag = TW_Valid; /* Default */ FPU_loaded_data.sigl = sigl; @@ -150,10 +151,11 @@ int reg_load_double(void) int exp; unsigned m64, l64; - RE_ENTRANT_CHECK_OFF + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_READ, dfloat, 8); m64 = get_fs_long(1 + (unsigned long *) dfloat); l64 = get_fs_long((unsigned long *) dfloat); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; if (m64 & 0x80000000) FPU_loaded_data.sign = SIGN_NEG; @@ -227,9 +229,10 @@ int reg_load_single(void) unsigned m32; int exp; - RE_ENTRANT_CHECK_OFF + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_READ, single, 4); m32 = get_fs_long((unsigned long *) single); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; if (m32 & 0x80000000) FPU_loaded_data.sign = SIGN_NEG; @@ -295,10 +298,11 @@ void reg_load_int64(void) int e; long long s; - RE_ENTRANT_CHECK_OFF + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_READ, _s, 8); ((unsigned long *)&s)[0] = get_fs_long((unsigned long *) _s); ((unsigned long *)&s)[1] = get_fs_long(1 + (unsigned long *) _s); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; if (s == 0) { reg_move(&CONST_Z, &FPU_loaded_data); return; } @@ -326,9 +330,10 @@ void reg_load_int32(void) long s; int e; - RE_ENTRANT_CHECK_OFF + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_READ, _s, 4); s = (long)get_fs_long((unsigned long *) _s); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; if (s == 0) { reg_move(&CONST_Z, &FPU_loaded_data); return; } @@ -356,10 +361,11 @@ void reg_load_int16(void) short *_s = (short *)FPU_data_address; int s, e; - RE_ENTRANT_CHECK_OFF + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_READ, _s, 2); /* Cast as short to get the sign extended. */ s = (short)get_fs_word((unsigned short *) _s); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; if (s == 0) { reg_move(&CONST_Z, &FPU_loaded_data); return; } @@ -390,12 +396,15 @@ void reg_load_bcd(void) unsigned char bcd; long long l=0; + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_READ, s, 10); + RE_ENTRANT_CHECK_ON; for ( pos = 8; pos >= 0; pos--) { l *= 10; - RE_ENTRANT_CHECK_OFF + RE_ENTRANT_CHECK_OFF; bcd = (unsigned char)get_fs_byte((unsigned char *) s+pos); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; l += bcd >> 4; l *= 10; l += bcd & 0x0f; @@ -403,11 +412,11 @@ void reg_load_bcd(void) /* Finish all access to user memory before putting stuff into the static FPU_loaded_data */ - RE_ENTRANT_CHECK_OFF + RE_ENTRANT_CHECK_OFF; FPU_loaded_data.sign = ((unsigned char)get_fs_byte((unsigned char *) s+9)) & 0x80 ? SIGN_NEG : SIGN_POS; - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; if (l == 0) { @@ -438,7 +447,9 @@ int reg_store_extended(void) if ( FPU_st0_tag != TW_Empty ) { - verify_area(VERIFY_WRITE, d, 10); + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE, d, 10); + RE_ENTRANT_CHECK_ON; write_to_extended(FPU_st0_ptr, (char *) FPU_data_address); return 1; } @@ -450,7 +461,7 @@ int reg_store_extended(void) /* The masked response */ /* Put out the QNaN indefinite */ RE_ENTRANT_CHECK_OFF; - verify_area(VERIFY_WRITE,d,10); + FPU_verify_area(VERIFY_WRITE,d,10); put_fs_long(0, (unsigned long *) d); put_fs_long(0xc0000000, 1 + (unsigned long *) d); put_fs_word(0xffff, 4 + (short *) d); @@ -635,11 +646,11 @@ int reg_store_double(void) { /* The masked response */ /* Put out the QNaN indefinite */ - RE_ENTRANT_CHECK_OFF - verify_area(VERIFY_WRITE,(void *)dfloat,8); + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8); put_fs_long(0, (unsigned long *) dfloat); put_fs_long(0xfff80000, 1 + (unsigned long *) dfloat); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; return 1; } else @@ -648,11 +659,11 @@ int reg_store_double(void) if (FPU_st0_ptr->sign) l[1] |= 0x80000000; - RE_ENTRANT_CHECK_OFF - verify_area(VERIFY_WRITE,(void *)dfloat,8); + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8); put_fs_long(l[0], (unsigned long *)dfloat); put_fs_long(l[1], 1 + (unsigned long *)dfloat); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; return 1; } @@ -819,10 +830,10 @@ int reg_store_single(void) { /* The masked response */ /* Put out the QNaN indefinite */ - RE_ENTRANT_CHECK_OFF - verify_area(VERIFY_WRITE,(void *)single,4); + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,(void *)single,4); put_fs_long(0xffc00000, (unsigned long *) single); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; return 1; } else @@ -838,10 +849,10 @@ int reg_store_single(void) if (FPU_st0_ptr->sign) templ |= 0x80000000; - RE_ENTRANT_CHECK_OFF - verify_area(VERIFY_WRITE,(void *)single,4); + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,(void *)single,4); put_fs_long(templ,(unsigned long *) single); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; return 1; } @@ -896,11 +907,11 @@ int reg_store_int64(void) tll = - tll; } - RE_ENTRANT_CHECK_OFF - verify_area(VERIFY_WRITE,(void *)d,8); + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,(void *)d,8); put_fs_long(((long *)&tll)[0],(unsigned long *) d); put_fs_long(((long *)&tll)[1],1 + (unsigned long *) d); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; return 1; } @@ -951,10 +962,10 @@ int reg_store_int32(void) t.sigl = -(long)t.sigl; } - RE_ENTRANT_CHECK_OFF - verify_area(VERIFY_WRITE,d,4); + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,d,4); put_fs_long(t.sigl, (unsigned long *) d); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; return 1; } @@ -1005,10 +1016,10 @@ int reg_store_int16(void) t.sigl = -t.sigl; } - RE_ENTRANT_CHECK_OFF - verify_area(VERIFY_WRITE,d,2); + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,d,2); put_fs_word((short)t.sigl,(short *) d); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; return 1; } @@ -1045,14 +1056,14 @@ int reg_store_bcd(void) if ( control_word & CW_Invalid ) { /* Produce the QNaN "indefinite" */ - RE_ENTRANT_CHECK_OFF - verify_area(VERIFY_WRITE,d,10); + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,d,10); for ( i = 0; i < 7; i++) put_fs_byte(0, (unsigned char *) d+i); /* These bytes "undefined" */ put_fs_byte(0xc0, (unsigned char *) d+7); /* This byte "undefined" */ put_fs_byte(0xff, (unsigned char *) d+8); put_fs_byte(0xff, (unsigned char *) d+9); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; return 1; } else @@ -1064,18 +1075,20 @@ int reg_store_bcd(void) set_precision_flag(precision_loss); } - verify_area(VERIFY_WRITE,d,10); + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,d,10); + RE_ENTRANT_CHECK_ON; for ( i = 0; i < 9; i++) { b = div_small(&ll, 10); b |= (div_small(&ll, 10)) << 4; - RE_ENTRANT_CHECK_OFF + RE_ENTRANT_CHECK_OFF; put_fs_byte(b,(unsigned char *) d+i); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; } - RE_ENTRANT_CHECK_OFF + RE_ENTRANT_CHECK_OFF; put_fs_byte(sign,(unsigned char *) d+9); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; return 1; } @@ -1157,7 +1170,8 @@ char *fldenv(void) unsigned char tag; int i; - RE_ENTRANT_CHECK_OFF + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_READ, s, 0x1c); control_word = get_fs_word((unsigned short *) s); partial_status = get_fs_word((unsigned short *) (s+4)); tag_word = get_fs_word((unsigned short *) (s+8)); @@ -1165,7 +1179,7 @@ char *fldenv(void) cs_selector = get_fs_long((unsigned long *) (s+0x10)); data_operand_offset = get_fs_long((unsigned long *) (s+0x14)); operand_selector = get_fs_long((unsigned long *) (s+0x18)); - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; top = (partial_status >> SW_Top_Shift) & 7; @@ -1275,9 +1289,8 @@ char *fstenv(void) { char *d = (char *)FPU_data_address; - verify_area(VERIFY_WRITE,d,28); - - RE_ENTRANT_CHECK_OFF + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,d,28); #ifdef PECULIAR_486 /* An 80486 sets all the reserved bits to 1. */ put_fs_long(0xffff0040 | (control_word & ~0xe080), (unsigned long *) d); @@ -1297,7 +1310,7 @@ char *fstenv(void) #else put_fs_long(operand_selector, (unsigned long *) (d+0x18)); #endif PECULIAR_486 - RE_ENTRANT_CHECK_ON + RE_ENTRANT_CHECK_ON; control_word |= CW_Exceptions; partial_status &= ~(SW_Summary | SW_Backward); @@ -1312,7 +1325,9 @@ void fsave(void) int i; d = fstenv(); - verify_area(VERIFY_WRITE,d,80); + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,d,80); + RE_ENTRANT_CHECK_ON; for ( i = 0; i < 8; i++ ) write_to_extended(®s[(top + i) & 7], d + 10 * i); @@ -1324,7 +1339,7 @@ void fsave(void) /* A call to this function must be preceeded by a call to - verify_area() to verify access to the 10 bytes at d + FPU_verify_area() to verify access to the 10 bytes at d */ static void write_to_extended(FPU_REG *rp, char *d) { diff --git a/drivers/FPU-emu/version.h b/drivers/FPU-emu/version.h index 5ae1f49..807066c 100644 --- a/drivers/FPU-emu/version.h +++ b/drivers/FPU-emu/version.h @@ -9,5 +9,5 @@ | | +---------------------------------------------------------------------------*/ -#define FPU_VERSION "wm-FPU-emu version Beta 1.7" +#define FPU_VERSION "wm-FPU-emu version Beta 1.8" diff --git a/drivers/char/atixlmouse.c b/drivers/char/atixlmouse.c index 9b9f114..c9952fc 100644 --- a/drivers/char/atixlmouse.c +++ b/drivers/char/atixlmouse.c @@ -11,7 +11,6 @@ #include <linux/kernel.h> #include <linux/sched.h> -#include <linux/tty.h> #include <linux/signal.h> #include <linux/errno.h> diff --git a/drivers/char/busmouse.c b/drivers/char/busmouse.c index 6e3792c..0d7a3be 100644 --- a/drivers/char/busmouse.c +++ b/drivers/char/busmouse.c @@ -26,7 +26,6 @@ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/busmouse.h> -#include <linux/tty.h> #include <linux/signal.h> #include <linux/errno.h> diff --git a/drivers/char/console.c b/drivers/char/console.c index c153a74..690250b 100644 --- a/drivers/char/console.c +++ b/drivers/char/console.c @@ -967,7 +967,6 @@ void con_write(struct tty_struct * tty) int c; unsigned int currcons; - wake_up_interruptible(&tty->write_q.proc_list); currcons = tty->line - 1; if (currcons >= NR_CONSOLES) { printk("con_write: illegal tty (%d)\n", currcons); @@ -1279,6 +1278,8 @@ void con_write(struct tty_struct * tty) if (vcmode != KD_GRAPHICS) set_cursor(currcons); enable_bh(KEYBOARD_BH); + if (LEFT(&tty->write_q) > WAKEUP_CHARS) + wake_up_interruptible(&tty->write_q.proc_list); } void do_keyboard_interrupt(void) diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index c509482..adec0e5 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -126,6 +126,8 @@ static unsigned char handle_diacr(unsigned char); /* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */ static struct pt_regs * pt_regs; +static int got_break = 0; + static inline void kb_wait(void) { int i; @@ -343,7 +345,6 @@ static void put_queue(int ch) if (LEFT(qp)) { qp->buf[qp->head] = ch; INC(qp->head); - wake_up_interruptible(&qp->proc_list); } } @@ -364,7 +365,6 @@ static void puts_queue(char *cp) INC(qp->head); } } - wake_up_interruptible(&qp->proc_list); } static void applkey(int key, char mode) @@ -419,13 +419,13 @@ static void hold(void) { if (rep || !tty) return; - if (vc_kbd_flag(kbd, VC_SCROLLOCK)) - /* pressing srcoll lock 2nd time sends ^Q, ChN */ - put_queue(START_CHAR(tty)); + /* pressing scroll lock 1st time sends ^S, ChN */ + /* pressing scroll lock 2nd time sends ^Q, ChN */ + /* now done directly without regard to ISIG -- jlc */ + if (!vc_kbd_flag(kbd, VC_SCROLLOCK)) + stop_tty(tty); else - /* pressing scroll lock 1st time sends ^S, ChN */ - put_queue(STOP_CHAR(tty)); - chg_vc_kbd_flag(kbd,VC_SCROLLOCK); + start_tty(tty); } static void num(void) @@ -453,8 +453,7 @@ static void lastcons(void) static void send_intr(void) { - if (tty) - put_queue(INTR_CHAR(tty)); + got_break = 1; } static void scrll_forw(void) @@ -814,6 +813,26 @@ static void kbd_bh(void * unused) } want_console = -1; } + if (got_break) { + if (tty && !I_IGNBRK(tty)) { + if (I_BRKINT(tty)) { + flush_input(tty); + flush_output(tty); + if (tty->pgrp > 0) + kill_pg(tty->pgrp, SIGINT, 1); + } else { + cli(); + if (LEFT(&tty->read_q) >= 2) { + set_bit(tty->read_q.head, + &tty->readq_flags); + put_queue(TTY_BREAK); + put_queue(0); + } + sti(); + } + } + got_break = 0; + } do_keyboard_interrupt(); cli(); if ((inb_p(0x64) & kbd_read_mask) == 0x01) diff --git a/drivers/char/msbusmouse.c b/drivers/char/msbusmouse.c index 8a5bef4..6db02c0 100644 --- a/drivers/char/msbusmouse.c +++ b/drivers/char/msbusmouse.c @@ -31,7 +31,6 @@ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/busmouse.h> -#include <linux/tty.h> #include <linux/signal.h> #include <linux/errno.h> diff --git a/drivers/char/pty.c b/drivers/char/pty.c index f3ee83b..4797597 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -17,17 +17,20 @@ #include <linux/tty.h> #include <linux/fcntl.h> #include <linux/interrupt.h> +#include <linux/string.h> #include <asm/system.h> #include <asm/bitops.h> +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + static void pty_close(struct tty_struct * tty, struct file * filp) { if (!tty) return; if (IS_A_PTY_MASTER(tty->line)) { if (tty->count > 1) - return; + printk("master pty_close: count = %d!!\n", tty->count); } else { if (tty->count > 2) return; @@ -40,32 +43,39 @@ static void pty_close(struct tty_struct * tty, struct file * filp) wake_up_interruptible(&tty->link->secondary.proc_list); wake_up_interruptible(&tty->link->read_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)) tty_hangup(tty->link); - flush_input(tty); - flush_output(tty); + else { + start_tty(tty); + set_bit(TTY_SLAVE_CLOSED, &tty->link->flags); } } static inline void pty_copy(struct tty_struct * from, struct tty_struct * to) { - int c; + unsigned long count, n; + struct tty_queue *fq, *tq; - while (!from->stopped && !EMPTY(&from->write_q)) { - if (FULL(&to->read_q)) { - TTY_READ_FLUSH(to); - if (FULL(&to->read_q)) - break; - continue; - } - c = get_tty_queue(&from->write_q); - put_tty_queue(c, &to->read_q); - if (current->signal & ~current->blocked) - break; + if (from->stopped || EMPTY(&from->write_q)) + return; + fq = &from->write_q; + /* Bypass the read_q if this is a pty master. */ + tq = IS_A_PTY_MASTER(to->line) ? &to->secondary : &to->read_q; + count = MIN(CHARS(fq), LEFT(tq)); + while (count) { + n = MIN(MIN(TTY_BUF_SIZE - fq->tail, TTY_BUF_SIZE - tq->head), + count); + memcpy(&tq->buf[tq->head], &fq->buf[fq->tail], n); + count -= n; + fq->tail = (fq->tail + n) & (TTY_BUF_SIZE - 1); + tq->head = (tq->head + n) & (TTY_BUF_SIZE - 1); } - TTY_READ_FLUSH(to); - if (!FULL(&from->write_q)) - wake_up_interruptible(&from->write_q.proc_list); + if (IS_A_PTY_MASTER(to->line)) + wake_up_interruptible(&tq->proc_list); + else + TTY_READ_FLUSH(to); + if (LEFT(fq) > WAKEUP_CHARS) + wake_up_interruptible(&fq->proc_list); if (from->write_data_cnt) { set_bit(from->line, &tty_check_write); mark_bh(TTY_BH); @@ -87,10 +97,8 @@ int pty_open(struct tty_struct *tty, struct file * filp) { if (!tty || !tty->link) return -ENODEV; - if (IS_A_PTY_MASTER(tty->line)) - clear_bit(TTY_SLAVE_OPENED, &tty->flags); - else - set_bit(TTY_SLAVE_OPENED, &tty->link->flags); + if (IS_A_PTY_SLAVE(tty->line)) + clear_bit(TTY_SLAVE_CLOSED, &tty->link->flags); tty->write = tty->link->write = pty_write; tty->close = tty->link->close = pty_close; wake_up_interruptible(&tty->read_q.proc_list); diff --git a/drivers/char/serial.c b/drivers/char/serial.c index ffb7f93..2b6aa0c 100644 --- a/drivers/char/serial.c +++ b/drivers/char/serial.c @@ -58,8 +58,6 @@ #undef ISR_HACK -#define WAKEUP_CHARS (3*TTY_BUF_SIZE/4) - /* * rs_event - Bitfield of serial lines that events pending * to be processed at the next clock tick. @@ -418,7 +416,7 @@ static inline int check_modem_status(struct async_struct *info) status = serial_in(info, UART_MSR); - if ((status & UART_MSR_DDCD) && !C_LOCAL(info->tty)) { + if ((status & UART_MSR_DDCD) && !C_CLOCAL(info->tty)) { #if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) printk("ttys%d CD now %s...", info->line, (status & UART_MSR_DCD) ? "on" : "off"); @@ -433,7 +431,7 @@ static inline int check_modem_status(struct async_struct *info) rs_sched_event(info, RS_EVENT_HANGUP); } } - if (C_RTSCTS(info->tty)) { + if (C_CRTSCTS(info->tty)) { if (info->tty->hw_stopped) { if (status & UART_MSR_CTS) { #ifdef SERIAL_DEBUG_INTR @@ -562,7 +560,7 @@ static inline void handle_rs_break(struct async_struct *info) if (info->flags & ASYNC_SAK) do_SAK(info->tty); - if (I_BRKINT(info->tty)) { + if (!I_IGNBRK(info->tty) && I_BRKINT(info->tty)) { flush_input(info->tty); flush_output(info->tty); if (info->tty->pgrp > 0) @@ -1066,7 +1064,7 @@ static void rs_throttle(struct tty_struct * tty, int status) switch (status) { case TTY_THROTTLE_RQ_FULL: info = rs_table + DEV_TO_SL(tty->line); - if (tty->termios->c_iflag & IXOFF) { + if (I_IXOFF(tty)) { info->x_char = STOP_CHAR(tty); } else { mcr = serial_inp(info, UART_MCR); @@ -1076,7 +1074,7 @@ static void rs_throttle(struct tty_struct * tty, int status) break; case TTY_THROTTLE_RQ_AVAIL: info = rs_table + DEV_TO_SL(tty->line); - if (tty->termios->c_iflag & IXOFF) { + if (I_IXOFF(tty)) { if (info->x_char) info->x_char = 0; else @@ -1382,7 +1380,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long)); if (error) return error; - put_fs_long(C_LOCAL(tty) ? 1 : 0, + put_fs_long(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); return 0; case TIOCSSOFTCAR: @@ -1591,7 +1589,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, { struct wait_queue wait = { current, NULL }; int retval; - int do_clocal = C_LOCAL(tty); + int do_clocal = C_CLOCAL(tty); /* * If the device is in the middle of being closed, then block diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index c07c194..c2da44d 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -32,6 +32,9 @@ * Added functionality to the OPOST tty handling. No delays, but all * other bits should be there. * -- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993. + * + * Rewrote canonical mode and added more termios flags. + * -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94 */ #include <linux/types.h> @@ -98,7 +101,7 @@ int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc) return 0; } -void put_tty_queue(char c, struct tty_queue * queue) +void put_tty_queue(unsigned char c, struct tty_queue * queue) { int head; unsigned long flags; @@ -121,8 +124,8 @@ int get_tty_queue(struct tty_queue * queue) save_flags(flags); cli(); if (queue->tail != queue->head) { - result = 0xff & queue->buf[queue->tail]; - queue->tail = (queue->tail + 1) & (TTY_BUF_SIZE-1); + result = queue->buf[queue->tail]; + INC(queue->tail); } restore_flags(flags); return result; @@ -499,7 +502,220 @@ void wait_for_keypress(void) sleep_on(&keypress_wait); } -void copy_to_cooked(struct tty_struct * tty) +void stop_tty(struct tty_struct *tty) +{ + if (tty->stopped) + return; + tty->stopped = 1; + if (tty->link && tty->link->packet) { + tty->ctrl_status &= ~TIOCPKT_START; + tty->ctrl_status |= TIOCPKT_STOP; + wake_up_interruptible(&tty->link->secondary.proc_list); + } + if (tty->stop) + (tty->stop)(tty); + if (IS_A_CONSOLE(tty->line)) { + set_vc_kbd_flag(kbd_table + fg_console, VC_SCROLLOCK); + set_leds(); + } +} + +void start_tty(struct tty_struct *tty) +{ + if (!tty->stopped) + return; + tty->stopped = 0; + if (tty->link && tty->link->packet) { + tty->ctrl_status &= ~TIOCPKT_STOP; + tty->ctrl_status |= TIOCPKT_START; + wake_up_interruptible(&tty->link->secondary.proc_list); + } + if (tty->start) + (tty->start)(tty); + if (IS_A_CONSOLE(tty->line)) { + clr_vc_kbd_flag(kbd_table + fg_console, VC_SCROLLOCK); + set_leds(); + } + TTY_WRITE_FLUSH(tty); +} + +/* Perform OPOST processing. Returns -1 when the write_q becomes full + and the character must be retried. */ + +static int opost(unsigned char c, struct tty_struct *tty) +{ + if (FULL(&tty->write_q)) + return -1; + if (O_OPOST(tty)) { + switch (c) { + case '\n': + if (O_ONLRET(tty)) + tty->column = 0; + if (O_ONLCR(tty)) { + if (LEFT(&tty->write_q) < 2) + return -1; + put_tty_queue('\r', &tty->write_q); + tty->column = 0; + } + tty->canon_column = tty->column; + break; + case '\r': + if (O_ONOCR(tty) && tty->column == 0) + return 0; + if (O_OCRNL(tty)) { + c = '\n'; + if (O_ONLRET(tty)) + tty->canon_column = tty->column = 0; + break; + } + tty->canon_column = tty->column = 0; + break; + case '\t': + if (O_TABDLY(tty) == XTABS) { + if (LEFT(&tty->write_q) < 8) + return -1; + do + put_tty_queue(' ', &tty->write_q); + while (++tty->column % 8); + return 0; + } + tty->column = (tty->column | 7) + 1; + break; + case '\b': + if (tty->column > 0) + tty->column--; + break; + default: + if (O_OLCUC(tty)) + c = toupper(c); + if (!iscntrl(c)) + tty->column++; + break; + } + } + put_tty_queue(c, &tty->write_q); + return 0; +} + +/* Must be called only when L_ECHO(tty) is true. */ + +static void echo_char(unsigned char c, struct tty_struct *tty) +{ + if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') { + opost('^', tty); + opost(c ^ 0100, tty); + } else + opost(c, tty); +} + +static void eraser(unsigned char c, struct tty_struct *tty) +{ + enum { ERASE, WERASE, KILL } kill_type; + int seen_alnums; + + if (tty->secondary.head == tty->canon_head) { + /* opost('\a', tty); */ /* what do you think? */ + return; + } + if (c == ERASE_CHAR(tty)) + kill_type = ERASE; + else if (c == WERASE_CHAR(tty)) + kill_type = WERASE; + else { + if (!L_ECHO(tty)) { + tty->secondary.head = tty->canon_head; + return; + } + if (!L_ECHOK(tty) || !L_ECHOKE(tty)) { + tty->secondary.head = tty->canon_head; + if (tty->erasing) { + opost('/', tty); + tty->erasing = 0; + } + echo_char(KILL_CHAR(tty), tty); + /* Add a newline if ECHOK is on and ECHOKE is off. */ + if (L_ECHOK(tty)) + opost('\n', tty); + return; + } + kill_type = KILL; + } + + seen_alnums = 0; + while (tty->secondary.head != tty->canon_head) { + c = LAST(&tty->secondary); + if (kill_type == WERASE) { + /* Equivalent to BSD's ALTWERASE. */ + if (isalnum(c) || c == '_') + seen_alnums++; + else if (seen_alnums) + break; + } + DEC(tty->secondary.head); + if (L_ECHO(tty)) { + if (L_ECHOPRT(tty)) { + if (!tty->erasing) { + opost('\\', tty); + tty->erasing = 1; + } + echo_char(c, tty); + } else if (!L_ECHOE(tty)) { + echo_char(ERASE_CHAR(tty), tty); + } else if (c == '\t') { + unsigned int col = tty->canon_column; + unsigned long tail = tty->canon_head; + + /* Find the column of the last char. */ + while (tail != tty->secondary.head) { + c = tty->secondary.buf[tail]; + if (c == '\t') + col = (col | 7) + 1; + else if (iscntrl(c)) { + if (L_ECHOCTL(tty)) + col += 2; + } else + col++; + INC(tail); + } + + /* Now backup to that column. */ + while (tty->column > col) { + /* Can't use opost here. */ + put_tty_queue('\b', &tty->write_q); + tty->column--; + } + } else { + if (iscntrl(c) && L_ECHOCTL(tty)) { + opost('\b', tty); + opost(' ', tty); + opost('\b', tty); + } + if (!iscntrl(c) || L_ECHOCTL(tty)) { + opost('\b', tty); + opost(' ', tty); + opost('\b', tty); + } + } + } + if (kill_type == ERASE) + break; + } + if (tty->erasing && tty->secondary.head == tty->canon_head) { + opost('/', tty); + tty->erasing = 0; + } +} + +static void isig(int sig, struct tty_struct *tty) +{ + kill_pg(tty->pgrp, sig, 1); + if (!L_NOFLSH(tty)) { + flush_input(tty); + flush_output(tty); + } +} + +static void copy_to_cooked(struct tty_struct * tty) { int c, special_flag; unsigned long flags; @@ -525,19 +741,18 @@ void copy_to_cooked(struct tty_struct * tty) if (c == 0) break; save_flags(flags); cli(); - if (tty->read_q.tail != tty->read_q.head) { - c = 0xff & tty->read_q.buf[tty->read_q.tail]; + if (!EMPTY(&tty->read_q)) { + c = tty->read_q.buf[tty->read_q.tail]; special_flag = clear_bit(tty->read_q.tail, - &tty->readq_flags); - tty->read_q.tail = (tty->read_q.tail + 1) & - (TTY_BUF_SIZE-1); + &tty->readq_flags); + INC(tty->read_q.tail); restore_flags(flags); } else { restore_flags(flags); break; } if (special_flag) { - tty->char_error = c & 7; + tty->char_error = c; continue; } if (tty->char_error) { @@ -545,6 +760,9 @@ void copy_to_cooked(struct tty_struct * tty) tty->char_error = 0; if (I_IGNBRK(tty)) continue; + /* A break is handled by the lower levels. */ + if (I_BRKINT(tty)) + continue; if (I_PARMRK(tty)) { put_tty_queue('\377', &tty->secondary); put_tty_queue('\0', &tty->secondary); @@ -570,157 +788,131 @@ void copy_to_cooked(struct tty_struct * tty) put_tty_queue('\0', &tty->secondary); continue; } - if (I_STRP(tty)) + if (I_ISTRIP(tty)) c &= 0x7f; - else if (I_PARMRK(tty) && (c == '\377')) - put_tty_queue('\377', &tty->secondary); - if (c==13) { - if (I_CRNL(tty)) - c=10; - else if (I_NOCR(tty)) - continue; - } else if (c==10 && I_NLCR(tty)) - c=13; - if (I_UCLC(tty)) + if (!tty->lnext) { + if (c == '\r') { + if (I_IGNCR(tty)) + continue; + if (I_ICRNL(tty)) + c = '\n'; + } else if (c == '\n' && I_INLCR(tty)) + c = '\r'; + } + if (I_IUCLC(tty) && L_IEXTEN(tty)) c=tolower(c); if (c == __DISABLED_CHAR) tty->lnext = 1; - if (L_CANON(tty) && !tty->lnext) { - if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) || c == WERASE_CHAR(tty)) { - int seen_alnums = - (c == WERASE_CHAR(tty)) ? 0 : -1; - int cc; - - /* deal with killing in the input line */ - while(!(EMPTY(&tty->secondary) || - (cc=LAST(&tty->secondary))==10 || - ((EOF_CHAR(tty) != __DISABLED_CHAR) && - (cc==EOF_CHAR(tty))))) { - /* if killing just a word, kill all - non-alnum chars, then all alnum - chars. */ - if (seen_alnums >= 0) { - if (isalnum(cc)) - seen_alnums++; - else if (seen_alnums) - break; + if (L_ICANON(tty) && !tty->lnext) { + if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) || + (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) { + eraser(c, tty); + continue; + } + if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) { + tty->lnext = 1; + if (L_ECHO(tty)) { + if (tty->erasing) { + opost('/', tty); + tty->erasing = 0; } - if (L_ECHO(tty)) { - int ct = 1; - if (cc < 32) - ct = (L_ECHOCTL(tty) ? 2 : 0); - while(ct--) { - put_tty_queue('\b', &tty->write_q); - put_tty_queue(' ', &tty->write_q); - put_tty_queue('\b',&tty->write_q); - } + if (L_ECHOCTL(tty)) { + opost('^', tty); + opost('\b', tty); } - DEC(tty->secondary.head); - if(c == ERASE_CHAR(tty)) - break; } continue; } - if (c == LNEXT_CHAR(tty)) { - tty->lnext = 1; - if (L_ECHO(tty)) { - put_tty_queue('^',&tty->write_q); - put_tty_queue('\b',&tty->write_q); + if (c == REPRINT_CHAR(tty) && L_ECHO(tty) && + L_IEXTEN(tty)) { + unsigned long tail = tty->canon_head; + + if (tty->erasing) { + opost('/', tty); + tty->erasing = 0; + } + echo_char(c, tty); + opost('\n', tty); + while (tail != tty->secondary.head) { + echo_char(tty->secondary.buf[tail], + tty); + INC(tail); } continue; } } if (I_IXON(tty) && !tty->lnext) { - if (c == STOP_CHAR(tty)) { - tty->ctrl_status &= ~(TIOCPKT_START); - tty->ctrl_status |= TIOCPKT_STOP; - if (tty->link) - wake_up_interruptible(&tty->link->except_q); - tty->stopped=1; - if (tty->stop) - (tty->stop)(tty); - if (IS_A_CONSOLE(tty->line)) { - set_vc_kbd_flag(kbd_table + fg_console, VC_SCROLLOCK); - set_leds(); - } + if ((tty->stopped && I_IXANY(tty) && L_IEXTEN(tty)) || + c == START_CHAR(tty)) { + start_tty(tty); continue; } - if (((I_IXANY(tty)) && tty->stopped) || - (c == START_CHAR(tty))) { - tty->ctrl_status &= ~(TIOCPKT_STOP); - tty->ctrl_status |= TIOCPKT_START; - tty->stopped=0; - if (tty->link) - wake_up_interruptible(&tty->link->except_q); - if (tty->start) - (tty->start)(tty); - if (IS_A_CONSOLE(tty->line)) { - clr_vc_kbd_flag(kbd_table + fg_console, VC_SCROLLOCK); - set_leds(); - } + if (c == STOP_CHAR(tty)) { + stop_tty(tty); continue; } } if (L_ISIG(tty) && !tty->lnext) { if (c == INTR_CHAR(tty)) { - kill_pg(tty->pgrp, SIGINT, 1); - if (! _L_FLAG(tty, NOFLSH)) { - flush_input(tty); - flush_output(tty); - } + isig(SIGINT, tty); continue; } if (c == QUIT_CHAR(tty)) { - kill_pg(tty->pgrp, SIGQUIT, 1); - if (! _L_FLAG(tty, NOFLSH)) { - flush_input(tty); - flush_output(tty); - } + isig(SIGQUIT, tty); continue; } - if (c == SUSPEND_CHAR(tty)) { - if (!is_orphaned_pgrp(tty->pgrp)) { - kill_pg(tty->pgrp, SIGTSTP, 1); - if (! _L_FLAG(tty, NOFLSH)) { - flush_input(tty); - flush_output(tty); - } - } + if (c == SUSP_CHAR(tty)) { + if (!is_orphaned_pgrp(tty->pgrp)) + isig(SIGTSTP, tty); continue; } } - if (c==10 || (EOF_CHAR(tty) != __DISABLED_CHAR && - c==EOF_CHAR(tty))) - tty->secondary.data++; - if ((c==10) && (L_ECHO(tty) || (L_CANON(tty) && L_ECHONL(tty)))) { - put_tty_queue('\n',&tty->write_q); - put_tty_queue('\r',&tty->write_q); + + if (tty->erasing) { + opost('/', tty); + tty->erasing = 0; + } + if (c == '\n' && !tty->lnext) { + if (L_ECHO(tty) || (L_ICANON(tty) && L_ECHONL(tty))) + opost('\n', tty); } else if (L_ECHO(tty)) { - if (c<32 && L_ECHOCTL(tty)) { - put_tty_queue('^',&tty->write_q); - put_tty_queue(c+'A'-1, &tty->write_q); - if (EOF_CHAR(tty) != __DISABLED_CHAR && - c==EOF_CHAR(tty) && !tty->lnext) { - put_tty_queue('\b',&tty->write_q); - put_tty_queue('\b',&tty->write_q); - } - } else - put_tty_queue(c, &tty->write_q); + /* Don't echo the EOF char in canonical mode. Sun + handles this differently by echoing the char and + then backspacing, but that's a hack. */ + if (c != EOF_CHAR(tty) || !L_ICANON(tty) || + tty->lnext) { + /* Record the column of first canon char. */ + if (tty->canon_head == tty->secondary.head) + tty->canon_column = tty->column; + echo_char(c, tty); + } } + + if (I_PARMRK(tty) && c == (unsigned char) '\377' && + (c != EOF_CHAR(tty) || !L_ICANON(tty) || tty->lnext)) + put_tty_queue(c, &tty->secondary); + + if (L_ICANON(tty) && !tty->lnext && + (c == '\n' || c == EOF_CHAR(tty) || c == EOL_CHAR(tty) || + (c == EOL2_CHAR(tty) && L_IEXTEN(tty)))) { + if (c == EOF_CHAR(tty)) + c = __DISABLED_CHAR; + set_bit(tty->secondary.head, &tty->secondary_flags); + put_tty_queue(c, &tty->secondary); + tty->canon_head = tty->secondary.head; + tty->canon_data++; + } else + put_tty_queue(c, &tty->secondary); tty->lnext = 0; - put_tty_queue(c, &tty->secondary); } - TTY_WRITE_FLUSH(tty); - if (!EMPTY(&tty->secondary)) + if (!EMPTY(&tty->write_q)) + TTY_WRITE_FLUSH(tty); + if (L_ICANON(tty) ? tty->canon_data : !EMPTY(&tty->secondary)) wake_up_interruptible(&tty->secondary.proc_list); - if (tty->write_q.proc_list && LEFT(&tty->write_q) > TTY_BUF_SIZE/2) - wake_up_interruptible(&tty->write_q.proc_list); + if (tty->throttle && (LEFT(&tty->read_q) >= RQ_THRESHOLD_HW) && clear_bit(TTY_RQ_THROTTLED, &tty->flags)) tty->throttle(tty, TTY_THROTTLE_RQ_AVAIL); - if (tty->throttle && (LEFT(&tty->secondary) >= SQ_THRESHOLD_HW) - && clear_bit(TTY_SQ_THROTTLED, &tty->flags)) - tty->throttle(tty, TTY_THROTTLE_SQ_AVAIL); } int is_ignored(int sig) @@ -729,278 +921,205 @@ int is_ignored(int sig) (current->sigaction[sig-1].sa_handler == SIG_IGN)); } -static int available_canon_input(struct tty_struct *); -static void __wait_for_canon_input(struct file * file, struct tty_struct *); - -static void wait_for_canon_input(struct file * file, struct tty_struct * tty) +static inline int input_available_p(struct tty_struct *tty) { - if (!available_canon_input(tty)) { - if (current->signal & ~current->blocked) - return; - __wait_for_canon_input(file, tty); - } + /* Avoid calling TTY_READ_FLUSH unnecessarily. */ + if (L_ICANON(tty)) { + if (tty->canon_data || FULL(&tty->read_q)) + return 1; + } else if (!EMPTY(&tty->secondary)) + return 1; + + /* Shuffle any pending data down the queues. */ + TTY_READ_FLUSH(tty); + if (tty->link) + TTY_WRITE_FLUSH(tty->link); + + if (L_ICANON(tty)) { + if (tty->canon_data || FULL(&tty->read_q)) + return 1; + } else if (!EMPTY(&tty->secondary)) + return 1; + return 0; } -static int read_chan(struct tty_struct * tty, struct file * file, char * buf, int nr) +static int read_chan(struct tty_struct *tty, struct file *file, + unsigned char *buf, unsigned int nr) { struct wait_queue wait = { current, NULL }; int c; - char * b=buf; - int minimum,time; + unsigned char *b = buf; + int minimum, time; + int retval = 0; - if (L_CANON(tty)) - minimum = time = current->timeout = 0; - else { - time = 10L*tty->termios->c_cc[VTIME]; - minimum = tty->termios->c_cc[VMIN]; + if (L_ICANON(tty)) { + minimum = time = 0; + current->timeout = (unsigned long) -1; + } else { + time = (HZ / 10) * TIME_CHAR(tty); + minimum = MIN_CHAR(tty); if (minimum) - current->timeout = 0xffffffff; + current->timeout = (unsigned long) -1; else { - if (time) + if (time) { current->timeout = time + jiffies; - else + time = 0; + } else current->timeout = 0; - time = 0; minimum = 1; } } - if (file->f_flags & O_NONBLOCK) { - time = current->timeout = 0; - if (L_CANON(tty) && !available_canon_input(tty)) - return -EAGAIN; - } else if (L_CANON(tty)) { - wait_for_canon_input(file, tty); - if (current->signal & ~current->blocked) - return -ERESTARTSYS; - } - if (minimum>nr) - minimum = nr; - /* deal with packet mode: First test for status change */ - if (tty->packet && tty->link && tty->link->ctrl_status) { - put_fs_byte (tty->link->ctrl_status, b); - tty->link->ctrl_status = 0; - return 1; - } - - /* now bump the buffer up one. */ - if (tty->packet) { - put_fs_byte (0,b++); - nr--; - /* this really shouldn't happen, but we need to - put it here. */ - if (nr == 0) - return 1; - } add_wait_queue(&tty->secondary.proc_list, &wait); - while (nr>0) { - if (tty_hung_up_p(file)) { - file->f_flags &= ~O_NONBLOCK; - break; /* force read() to return 0 */ - } - TTY_READ_FLUSH(tty); - if (tty->link) - TTY_WRITE_FLUSH(tty->link); - while (nr > 0 && ((c = get_tty_queue(&tty->secondary)) >= 0)) { - if ((EOF_CHAR(tty) != __DISABLED_CHAR && - c==EOF_CHAR(tty)) || c==10) - tty->secondary.data--; - if ((EOF_CHAR(tty) != __DISABLED_CHAR && - c==EOF_CHAR(tty)) && L_CANON(tty)) - break; - put_fs_byte(c,b++); - nr--; - if (time) - current->timeout = time+jiffies; - if (c==10 && L_CANON(tty)) - break; - }; - wake_up_interruptible(&tty->read_q.proc_list); - /* - * If there is enough space in the secondary queue - * now, let the low-level driver know. - */ - if (tty->throttle && (LEFT(&tty->secondary) >= SQ_THRESHOLD_HW) - && clear_bit(TTY_SQ_THROTTLED, &tty->flags)) - tty->throttle(tty, TTY_THROTTLE_SQ_AVAIL); - if (tty->link) { - if (IS_A_PTY_MASTER(tty->line)) { - if ((tty->flags & (1 << TTY_SLAVE_OPENED)) - && tty->link->count <= 1) { - file->f_flags &= ~O_NONBLOCK; + while (1) { + /* Job control check -- must be done at start and after + every sleep (POSIX.1 7.1.1.4). */ + /* don't stop on /dev/console */ + if (file->f_inode->i_rdev != CONSOLE_DEV && + current->tty == tty->line) { + if (tty->pgrp <= 0) + printk("read_chan: tty->pgrp <= 0!\n"); + else if (current->pgrp != tty->pgrp) { + if (is_ignored(SIGTTIN) || + is_orphaned_pgrp(current->pgrp)) { + retval = -EIO; break; } - } else if (!tty->link->count) { - file->f_flags &= ~O_NONBLOCK; + kill_pg(current->pgrp, SIGTTIN, 1); + retval = -ERESTARTSYS; break; } } - if (b-buf >= minimum || !current->timeout) - break; - if (current->signal & ~current->blocked) + /* First test for status change. */ + if (tty->packet && tty->link->ctrl_status) { + if (b != buf) + break; + put_fs_byte(tty->link->ctrl_status, b++); + tty->link->ctrl_status = 0; break; - TTY_READ_FLUSH(tty); - if (tty->link) - TTY_WRITE_FLUSH(tty->link); - if (!EMPTY(&tty->secondary)) - continue; + } + /* This statement must be first before checking for input + so that any interrupt will set the state back to + TASK_RUNNING. */ current->state = TASK_INTERRUPTIBLE; - if (EMPTY(&tty->secondary)) + if (!input_available_p(tty)) { + if (tty->flags & (1 << TTY_SLAVE_CLOSED)) { + retval = -EIO; + break; + } + if (tty_hung_up_p(file)) + break; + if (!current->timeout) + break; + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + if (current->signal & ~current->blocked) { + retval = -ERESTARTSYS; + break; + } schedule(); + continue; + } current->state = TASK_RUNNING; - } - remove_wait_queue(&tty->secondary.proc_list, &wait); - TTY_READ_FLUSH(tty); - if (tty->link && tty->link->write) - TTY_WRITE_FLUSH(tty->link); - current->timeout = 0; - /* packet mode sticks in an extra 0. If that's all we've got, - we should count it a zero bytes. */ - if (tty->packet) { - if ((b-buf) > 1) - return b-buf; - } else { - if (b-buf) - return b-buf; - } + /* Deal with packet mode. */ + if (tty->packet && b == buf) { + put_fs_byte(TIOCPKT_DATA, b++); + nr--; + } - if (current->signal & ~current->blocked) - return -ERESTARTSYS; - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - if (IS_A_PTY_MASTER(tty->line)) - return -EIO; - return 0; -} + while (nr > 0) { + int eol; -static void __wait_for_canon_input(struct file * file, struct tty_struct * tty) -{ - struct wait_queue wait = { current, NULL }; + cli(); + if (EMPTY(&tty->secondary)) { + sti(); + break; + } + eol = clear_bit(tty->secondary.tail, + &tty->secondary_flags); + c = tty->secondary.buf[tty->secondary.tail]; + INC(tty->secondary.tail); + sti(); + if (eol) { + if (--tty->canon_data < 0) { + printk("read_chan: canon_data < 0!\n"); + tty->canon_data = 0; + } + if (c == __DISABLED_CHAR) + break; + put_fs_byte(c, b++); + nr--; + break; + } + put_fs_byte(c, b++); + nr--; + } - add_wait_queue(&tty->secondary.proc_list, &wait); - while (1) { - current->state = TASK_INTERRUPTIBLE; - if (available_canon_input(tty)) - break; - if (current->signal & ~current->blocked) - break; - if (tty_hung_up_p(file)) + /* If there is enough space in the secondary queue now, let the + low-level driver know. */ + if (tty->throttle && (LEFT(&tty->secondary) >= SQ_THRESHOLD_HW) + && !clear_bit(TTY_SQ_THROTTLED, &tty->flags)) + tty->throttle(tty, TTY_THROTTLE_SQ_AVAIL); + + /* XXX packet mode's status byte is mistakenly counted */ + if (b - buf >= minimum || !nr) break; - schedule(); + if (time) + current->timeout = time + jiffies; } - current->state = TASK_RUNNING; remove_wait_queue(&tty->secondary.proc_list, &wait); + current->state = TASK_RUNNING; + current->timeout = 0; + return (b - buf) ? b - buf : retval; } -static int available_canon_input(struct tty_struct * tty) -{ - TTY_READ_FLUSH(tty); - if (tty->link) - if (tty->link->count) - TTY_WRITE_FLUSH(tty->link); - else - return 1; - if (FULL(&tty->read_q)) - return 1; - if (tty->secondary.data) - return 1; - return 0; -} - -static int write_chan(struct tty_struct * tty, struct file * file, char * buf, int nr) +static int write_chan(struct tty_struct * tty, struct file * file, + unsigned char * buf, unsigned int nr) { struct wait_queue wait = { current, NULL }; - char c, *b=buf; + int c; + unsigned char *b = buf; + int retval = 0; + + /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */ + if (L_TOSTOP(tty) && file->f_inode->i_rdev != CONSOLE_DEV) { + retval = check_change(tty, tty->line); + if (retval) + return retval; + } - if (nr < 0) - return -EINVAL; - if (!nr) - return 0; add_wait_queue(&tty->write_q.proc_list, &wait); - while (nr>0) { - if (current->signal & ~current->blocked) - break; - if (tty_hung_up_p(file)) - break; - if (tty->link && !tty->link->count) { - send_sig(SIGPIPE,current,0); + while (1) { + current->state = TASK_INTERRUPTIBLE; + if (current->signal & ~current->blocked) { + retval = -ERESTARTSYS; break; } - current->state = TASK_INTERRUPTIBLE; - if (FULL(&tty->write_q)) { - TTY_WRITE_FLUSH(tty); - if (FULL(&tty->write_q)) - schedule(); - current->state = TASK_RUNNING; - continue; + if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) { + retval = -EIO; + break; } - current->state = TASK_RUNNING; - while (nr>0 && !FULL(&tty->write_q)) { - c=get_fs_byte(b); - if (O_POST(tty)) { - switch (c) { - case '\n': - if (O_NLRET(tty)) { - tty->column = 0; - } - if (O_NLCR(tty)) { - if (!set_bit(TTY_CR_PENDING,&tty->flags)) { - c = '\r'; - tty->column = 0; - b--; nr++; - } else { - clear_bit(TTY_CR_PENDING,&tty->flags); - } - } - break; - case '\r': - if (O_NOCR(tty) && tty->column == 0) { - b++; nr--; - continue; - } - if (O_CRNL(tty)) { - c = '\n'; - if (O_NLRET(tty)) - tty->column = 0; - break; - } - tty->column = 0; - break; - case '\t': - if (O_TABDLY(tty) == XTABS) { - c = ' '; - tty->column++; - if (tty->column % 8 != 0) { - b--; nr++; - } - } - break; - case '\b': - tty->column--; - break; - default: - if (O_LCUC(tty)) - c = toupper(c); - tty->column++; - break; - } - } + while (nr > 0) { + c = get_fs_byte(b); + /* Care is needed here: opost() can abort even + if the write_q is not full. */ + if (opost(c, tty) < 0) + break; b++; nr--; - put_tty_queue(c,&tty->write_q); } - if (need_resched) - schedule(); + TTY_WRITE_FLUSH(tty); + if (!nr) + break; + if (EMPTY(&tty->write_q) && !need_resched) + continue; + schedule(); } + current->state = TASK_RUNNING; remove_wait_queue(&tty->write_q.proc_list, &wait); - TTY_WRITE_FLUSH(tty); - if (b-buf) - return b-buf; - if (tty->link && !tty->link->count) - return -EPIPE; - if (current->signal & ~current->blocked) - return -ERESTARTSYS; - return 0; + return (b - buf) ? b - buf : retval; } static int tty_read(struct inode * inode, struct file * file, char * buf, int count) @@ -1017,6 +1136,12 @@ static int tty_read(struct inode * inode, struct file * file, char * buf, int co tty = TTY_TABLE(dev); if (!tty || (tty->flags & (1 << TTY_IO_ERROR))) return -EIO; + + /* This check not only needs to be done before reading, but also + whenever read_chan() gets woken up after sleeping, so I've + moved it to there. This should only be done for the N_TTY + line discipline, anyway. Same goes for write_chan(). -- jlc. */ +#if 0 if ((inode->i_rdev != CONSOLE_DEV) && /* don't stop on /dev/console */ (tty->pgrp > 0) && (current->tty == dev) && @@ -1027,8 +1152,10 @@ static int tty_read(struct inode * inode, struct file * file, char * buf, int co (void) kill_pg(current->pgrp, SIGTTIN, 1); return -ERESTARTSYS; } +#endif if (ldiscs[tty->disc].read) - i = (ldiscs[tty->disc].read)(tty,file,buf,count); + /* XXX casts are for what kernel-wide prototypes should be. */ + i = (ldiscs[tty->disc].read)(tty,file,(unsigned char *)buf,(unsigned int)count); else i = -EIO; if (i > 0) @@ -1054,6 +1181,7 @@ static int tty_write(struct inode * inode, struct file * file, char * buf, int c tty = TTY_TABLE(dev); if (!tty || !tty->write || (tty->flags & (1 << TTY_IO_ERROR))) return -EIO; +#if 0 if (!is_console && L_TOSTOP(tty) && (tty->pgrp > 0) && (current->tty == dev) && (tty->pgrp != current->pgrp)) { if (is_orphaned_pgrp(current->pgrp)) @@ -1063,8 +1191,10 @@ static int tty_write(struct inode * inode, struct file * file, char * buf, int c return -ERESTARTSYS; } } +#endif if (ldiscs[tty->disc].write) - i = (ldiscs[tty->disc].write)(tty,file,buf,count); + /* XXX casts are for what kernel-wide prototypes should be. */ + i = (ldiscs[tty->disc].write)(tty,file,(unsigned char *)buf,(unsigned int)count); else i = -EIO; if (i > 0) @@ -1349,6 +1479,7 @@ retry_open: if (test_bit(TTY_EXCLUSIVE, &tty->flags) && !suser()) return -EBUSY; +#if 0 /* clean up the packet stuff. */ /* * Why is this not done in init_dev? Right here, if another @@ -1358,9 +1489,12 @@ retry_open: * * Not to worry, a pty master can only be opened once. * And rlogind and telnetd both use packet mode. -- jrs + * + * Not needed. These are cleared in initialize_tty_struct. -- jlc */ tty->ctrl_status = 0; tty->packet = 0; +#endif if (tty->open) { retval = tty->open(tty, filp); @@ -1441,26 +1575,16 @@ static int normal_select(struct tty_struct * tty, struct inode * inode, { switch (sel_type) { case SEL_IN: - if (L_CANON(tty)) { - if (available_canon_input(tty)) - return 1; - } else if (!EMPTY(&tty->secondary)) + if (input_available_p(tty)) return 1; - if (tty->link) { - if (IS_A_PTY_MASTER(tty->line)) { - if ((tty->flags & (1 << TTY_SLAVE_OPENED)) - && tty->link->count <= 1) - return 1; - } else { - if (!tty->link->count) - return 1; - } - } - - /* see if the status byte can be read. */ - if (tty->packet && tty->link && tty->link->ctrl_status) + /* fall through */ + case SEL_EX: + if (tty->packet && tty->link->ctrl_status) + return 1; + if (tty->flags & (1 << TTY_SLAVE_CLOSED)) + return 1; + if (tty_hung_up_p(file)) return 1; - select_wait(&tty->secondary.proc_list, wait); return 0; case SEL_OUT: @@ -1468,22 +1592,6 @@ static int normal_select(struct tty_struct * tty, struct inode * inode, return 1; select_wait(&tty->write_q.proc_list, wait); return 0; - case SEL_EX: - if (tty->link) { - if (IS_A_PTY_MASTER(tty->line)) { - if ((tty->flags & (1 << TTY_SLAVE_OPENED)) - && tty->link->count <= 1) - return 1; - if (tty->packet - && tty->link->ctrl_status) - return 1; - } else { - if (!tty->link->count) - return 1; - } - } - select_wait(&tty->except_q, wait); - return 0; } return 0; } @@ -1645,8 +1753,6 @@ static void initialize_tty_struct(int line, struct tty_struct *tty) tty->line = line; tty->disc = N_TTY; tty->pgrp = -1; - tty->winsize.ws_row = 0; - tty->winsize.ws_col = 0; if (IS_A_CONSOLE(line)) { tty->open = con_open; tty->winsize.ws_row = video_num_lines; @@ -1656,31 +1762,26 @@ static void initialize_tty_struct(int line, struct tty_struct *tty) } else if IS_A_PTY(line) { tty->open = pty_open; } - tty->except_q = NULL; } static void initialize_termios(int line, struct termios * tp) { memset(tp, 0, sizeof(struct termios)); memcpy(tp->c_cc, INIT_C_CC, NCCS); - if (IS_A_CONSOLE(line)) { + if (IS_A_CONSOLE(line) || IS_A_PTY_SLAVE(line)) { tp->c_iflag = ICRNL | IXON; tp->c_oflag = OPOST | ONLCR; tp->c_cflag = B38400 | CS8 | CREAD; - tp->c_lflag = ISIG | ICANON | ECHO | - ECHOCTL | ECHOKE; + tp->c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | + ECHOCTL | ECHOKE | IEXTEN; } else if (IS_A_SERIAL(line)) { - tp->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + tp->c_iflag = ICRNL | IXON; tp->c_oflag = OPOST | ONLCR | XTABS; - } else if (IS_A_PTY_MASTER(line)) { + tp->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + tp->c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | + ECHOCTL | ECHOKE | IEXTEN; + } else if (IS_A_PTY_MASTER(line)) tp->c_cflag = B9600 | CS8 | CREAD; - } else if (IS_A_PTY_SLAVE(line)) { - tp->c_iflag = ICRNL | IXON; - tp->c_oflag = OPOST | ONLCR; - tp->c_cflag = B38400 | CS8 | CREAD; - tp->c_lflag = ISIG | ICANON | ECHO | - ECHOCTL | ECHOKE; - } } static struct tty_ldisc tty_ldisc_N_TTY = { diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index b6d7b48..8f4a744 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -17,6 +17,7 @@ #include <linux/major.h> #include <linux/tty.h> #include <linux/fcntl.h> +#include <linux/string.h> #include <asm/io.h> #include <asm/bitops.h> @@ -41,44 +42,43 @@ extern int paste_selection(struct tty_struct *tty); static int tty_set_ldisc(struct tty_struct *tty, int ldisc); -static void flush(struct tty_queue * queue) -{ - if (queue) { - cli(); - queue->head = queue->tail; - sti(); - wake_up_interruptible(&queue->proc_list); - } -} - void flush_input(struct tty_struct * tty) { - tty->ctrl_status |= TIOCPKT_FLUSHREAD; - if (tty->link) - wake_up_interruptible(&tty->link->except_q); - flush(&tty->read_q); - wake_up_interruptible(&tty->read_q.proc_list); - flush(&tty->secondary); - tty->secondary.data = 0; - - if ((tty = tty->link) != NULL) { - flush(&tty->write_q); - wake_up_interruptible(&tty->write_q.proc_list); + cli(); + tty->read_q.head = tty->read_q.tail = 0; + tty->secondary.head = tty->secondary.tail = 0; + tty->canon_head = tty->canon_data = tty->erasing = 0; + memset(&tty->readq_flags, 0, sizeof tty->readq_flags); + memset(&tty->secondary_flags, 0, sizeof tty->secondary_flags); + sti(); + if (!tty->link) + return; + /* No cli() since ptys don't use interrupts. */ + tty->link->write_q.head = tty->link->write_q.tail = 0; + wake_up_interruptible(&tty->link->write_q.proc_list); + if (tty->link->packet) { + tty->ctrl_status |= TIOCPKT_FLUSHREAD; + wake_up_interruptible(&tty->link->secondary.proc_list); } } void flush_output(struct tty_struct * tty) { - tty->ctrl_status |= TIOCPKT_FLUSHWRITE; - if (tty->link) - wake_up_interruptible(&tty->link->except_q); - flush(&tty->write_q); + cli(); + tty->write_q.head = tty->write_q.tail = 0; + sti(); wake_up_interruptible(&tty->write_q.proc_list); - if ((tty = tty->link) != NULL) { - flush(&tty->read_q); - wake_up_interruptible(&tty->read_q.proc_list); - flush(&tty->secondary); - tty->secondary.data = 0; + if (!tty->link) + return; + /* No cli() since ptys don't use interrupts. */ + tty->link->read_q.head = tty->link->read_q.tail = 0; + tty->link->secondary.head = tty->link->secondary.tail = 0; + tty->link->canon_head = tty->link->canon_data = tty->link->erasing = 0; + memset(&tty->link->readq_flags, 0, sizeof tty->readq_flags); + memset(&tty->link->secondary_flags, 0, sizeof tty->secondary_flags); + if (tty->link->packet) { + tty->ctrl_status |= TIOCPKT_FLUSHWRITE; + wake_up_interruptible(&tty->link->secondary.proc_list); } } @@ -156,65 +156,61 @@ static void unset_locked_termios(struct termios *termios, old->c_cc[i] : termios->c_cc[i]; } -static int get_termios(struct tty_struct * tty, struct termios * termios) -{ - int i; - - i = verify_area(VERIFY_WRITE, termios, sizeof (*termios)); - if (i) - return i; - for (i=0 ; i< (sizeof (*termios)) ; i++) - put_fs_byte( ((char *)tty->termios)[i] , i+(char *)termios ); - return 0; -} - -static int check_change(struct tty_struct * tty, int channel) +int check_change(struct tty_struct * tty, int channel) { /* If we try to set the state of terminal and we're not in the foreground, send a SIGTTOU. If the signal is blocked or ignored, go ahead and perform the operation. POSIX 7.2) */ if (current->tty != channel) return 0; - if (tty->pgrp <= 0 || tty->pgrp == current->pgrp) + if (tty->pgrp <= 0) { + printk("check_change: tty->pgrp <= 0!\n"); + return 0; + } + if (current->pgrp == tty->pgrp) return 0; - if (is_orphaned_pgrp(current->pgrp)) - return -EIO; if (is_ignored(SIGTTOU)) return 0; + if (is_orphaned_pgrp(current->pgrp)) + return -EIO; (void) kill_pg(current->pgrp,SIGTTOU,1); return -ERESTARTSYS; } -static int set_termios(struct tty_struct * tty, struct termios * termios, - int channel) +static int set_termios_2(struct tty_struct * tty, struct termios * termios) { - int i, old_flow, new_flow; struct termios old_termios = *tty->termios; - - i = check_change(tty, channel); - if (i) - return i; - for (i=0 ; i< (sizeof (*termios)) ; i++) - ((char *)tty->termios)[i]=get_fs_byte(i+(char *)termios); + int canon_change; + + canon_change = (old_termios.c_lflag ^ termios->c_lflag) & ICANON; + cli(); + *tty->termios = *termios; + if (canon_change) { + memset(&tty->secondary_flags, 0, sizeof tty->secondary_flags); + tty->canon_head = tty->secondary.tail; + tty->canon_data = 0; + tty->erasing = 0; + } + sti(); + if (canon_change && !(tty->termios->c_lflag & ICANON) && + !EMPTY(&tty->secondary)) + /* Get characters left over from canonical mode. */ + wake_up_interruptible(&tty->secondary.proc_list); /* see if packet mode change of state */ - old_flow = (old_termios.c_iflag & IXON) && - (old_termios.c_cc[VSTOP] == '\023') && - (old_termios.c_cc[VSTART] == '\021'); - - new_flow = (tty->termios->c_iflag & IXON) && - (tty->termios->c_cc[VSTOP] == '\023') && - (tty->termios->c_cc[VSTART] == '\021'); - - if (old_flow != new_flow) { - tty->ctrl_status &= ~(TIOCPKT_DOSTOP|TIOCPKT_NOSTOP); - if (new_flow) + /* The BSD man page pty.4 says that TIOCPKT_NOSTOP should be sent + if the new state differs from ^S/^Q, but that's a bad way of + detecting a new flow control scheme. Instead, a status byte + is only sent if IXON has changed. */ + if (tty->link && tty->link->packet && + (old_termios.c_iflag ^ tty->termios->c_iflag) & IXON) { + tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP); + if (tty->termios->c_iflag & IXON) tty->ctrl_status |= TIOCPKT_DOSTOP; else - tty->ctrl_status |= TIOCPKT_NOSTOP; - if (tty->link) - wake_up_interruptible(&tty->link->except_q); + tty->ctrl_status |= TIOCPKT_NOSTOP; + wake_up_interruptible(&tty->link->secondary.proc_list); } #if 0 @@ -241,12 +237,21 @@ static int set_termios(struct tty_struct * tty, struct termios * termios, return 0; } +static int set_termios(struct tty_struct * tty, struct termios * termios, + int channel) +{ + struct termios tmp_termios; + + memcpy_fromfs(&tmp_termios, termios, sizeof (struct termios)); + return set_termios_2(tty, &tmp_termios); +} + static int get_termio(struct tty_struct * tty, struct termio * termio) { int i; struct termio tmp_termio; - i = verify_area(VERIFY_WRITE, termio, sizeof (*termio)); + i = verify_area(VERIFY_WRITE, termio, sizeof (struct termio)); if (i) return i; tmp_termio.c_iflag = tty->termios->c_iflag; @@ -256,128 +261,41 @@ static int get_termio(struct tty_struct * tty, struct termio * termio) tmp_termio.c_line = tty->termios->c_line; for(i=0 ; i < NCC ; i++) tmp_termio.c_cc[i] = tty->termios->c_cc[i]; - for (i=0 ; i< (sizeof (*termio)) ; i++) - put_fs_byte( ((char *)&tmp_termio)[i] , i+(char *)termio ); + memcpy_tofs(termio, &tmp_termio, sizeof (struct termio)); return 0; } static int set_termio(struct tty_struct * tty, struct termio * termio, - int channel) + int channel) { - int i, old_flow, new_flow; struct termio tmp_termio; - struct termios old_termios = *tty->termios; + struct termios tmp_termios; -#define SET_LOW_BITS(x,y) ((x) = (0xffff0000 & (x)) | (y)) - - i = check_change(tty, channel); - if (i) - return i; - memcpy_fromfs(&tmp_termio, termio, sizeof(*termio)); - - SET_LOW_BITS(tty->termios->c_iflag, tmp_termio.c_iflag); - SET_LOW_BITS(tty->termios->c_oflag, tmp_termio.c_oflag); - SET_LOW_BITS(tty->termios->c_cflag, tmp_termio.c_cflag); - SET_LOW_BITS(tty->termios->c_lflag, tmp_termio.c_lflag); - memcpy(tty->termios->c_cc, tmp_termio.c_cc, NCC); - - /* see if packet mode change of state */ - - old_flow = (old_termios.c_iflag & IXON) && - (old_termios.c_cc[VSTOP] == '\023') && - (old_termios.c_cc[VSTART] == '\021'); - - new_flow = (tty->termios->c_iflag & IXON) && - (tty->termios->c_cc[VSTOP] == '\023') && - (tty->termios->c_cc[VSTART] == '\021'); + tmp_termios = *tty->termios; + memcpy_fromfs(&tmp_termio, termio, sizeof (struct termio)); - if (old_flow != new_flow) { - tty->ctrl_status &= ~(TIOCPKT_DOSTOP|TIOCPKT_NOSTOP); - if (new_flow) - tty->ctrl_status |= TIOCPKT_DOSTOP; - else - tty->ctrl_status |= TIOCPKT_NOSTOP; - if (tty->link) - wake_up_interruptible(&tty->link->except_q); - } - - unset_locked_termios(tty->termios, &old_termios, - termios_locked[tty->line]); - -#if 0 - retval = tty_set_ldisc(tty, tmp_termio.c_line); - if (retval) - return retval; -#endif - - if (tty->set_termios) - (*tty->set_termios)(tty, &old_termios); - - return 0; -} - -static int get_lcktrmios(struct tty_struct * tty, struct termios * termios, - int channel) -{ - int i; - - i = verify_area(VERIFY_WRITE, termios, sizeof (*termios)); - if (i) - return i; - for (i=0 ; i< (sizeof (*termios)) ; i++) - put_fs_byte( ((char *)termios_locked[channel])[i], - i+(char *)termios); - return 0; -} +#define SET_LOW_BITS(x,y) ((x) = (0xffff0000 & (x)) | (y)) -static int set_lcktrmios(struct tty_struct * tty, struct termios * termios, - int channel) -{ - int i; + SET_LOW_BITS(tmp_termios.c_iflag, tmp_termio.c_iflag); + SET_LOW_BITS(tmp_termios.c_oflag, tmp_termio.c_oflag); + SET_LOW_BITS(tmp_termios.c_cflag, tmp_termio.c_cflag); + SET_LOW_BITS(tmp_termios.c_lflag, tmp_termio.c_lflag); + memcpy(&tmp_termios.c_cc, &tmp_termio.c_cc, NCC); - if (!suser()) - return -EPERM; - for (i=0 ; i< (sizeof (*termios)) ; i++) - ((char *)termios_locked[channel])[i] = - get_fs_byte(i+(char *)termios); +#undef SET_LOW_BITS - return 0; + return set_termios_2(tty, &tmp_termios); } static int set_window_size(struct tty_struct * tty, struct winsize * ws) { - int i,changed; - char c, * tmp; + struct winsize tmp_ws; - if (!ws) - return -EINVAL; - tmp = (char *) &tty->winsize; - changed = 0; - for (i = 0; i < sizeof (*ws) ; i++,tmp++) { - c = get_fs_byte(i + (char *) ws); - if (c == *tmp) - continue; - changed = 1; - *tmp = c; - } - if (changed) + memcpy_fromfs(&tmp_ws, ws, sizeof (struct winsize)); + if (memcmp(&tmp_ws, &tty->winsize, sizeof (struct winsize)) && + tty->pgrp > 0) kill_pg(tty->pgrp, SIGWINCH, 1); - return 0; -} - -static int get_window_size(struct tty_struct * tty, struct winsize * ws) -{ - int i; - char * tmp; - - if (!ws) - return -EINVAL; - i = verify_area(VERIFY_WRITE, ws, sizeof (*ws)); - if (i) - return i; - tmp = (char *) ws; - for (i = 0; i < sizeof (struct winsize) ; i++,tmp++) - put_fs_byte(((char *) &tty->winsize)[i], tmp); + tty->winsize = tmp_ws; return 0; } @@ -406,20 +324,19 @@ static int tty_set_ldisc(struct tty_struct *tty, int ldisc) return 0; } -static int inq_canon(struct tty_struct * tty) +static unsigned long inq_canon(struct tty_struct * tty) { int nr, head, tail; - if (!tty->secondary.data) + if (!tty->canon_data) return 0; - head = tty->secondary.head; + head = tty->canon_head; tail = tty->secondary.tail; nr = (head - tail) & (TTY_BUF_SIZE-1); /* Skip EOF-chars.. */ - if (EOF_CHAR(tty) == __DISABLED_CHAR) - return nr; while (head != tail) { - if (tty->secondary.buf[tail] == EOF_CHAR(tty)) + if (test_bit(tail, &tty->secondary_flags) && + tty->secondary.buf[tail] == __DISABLED_CHAR) nr--; INC(tail); } @@ -432,7 +349,7 @@ int tty_ioctl(struct inode * inode, struct file * file, struct tty_struct * tty; struct tty_struct * other_tty; struct tty_struct * termios_tty; - int pgrp; + pid_t pgrp; int dev; int termios_dev; int retval; @@ -449,68 +366,93 @@ int tty_ioctl(struct inode * inode, struct file * file, other_tty = tty_table[PTY_OTHER(dev)]; else other_tty = NULL; - termios_tty = tty; - termios_dev = dev; if (IS_A_PTY_MASTER(dev)) { termios_tty = other_tty; termios_dev = PTY_OTHER(dev); + } else { + termios_tty = tty; + termios_dev = dev; } switch (cmd) { case TCGETS: - return get_termios(termios_tty,(struct termios *) arg); + retval = verify_area(VERIFY_WRITE, (void *) arg, + sizeof (struct termios)); + if (retval) + return retval; + memcpy_tofs((struct termios *) arg, + termios_tty->termios, + sizeof (struct termios)); + return 0; case TCSETSF: - flush_input(tty); - /* fallthrough */ case TCSETSW: - wait_until_sent(tty); - /* fallthrough */ case TCSETS: - return set_termios(termios_tty,(struct termios *) arg, termios_dev); + retval = check_change(termios_tty, termios_dev); + if (retval) + return retval; + if (cmd == TCSETSF || cmd == TCSETSW) { + if (cmd == TCSETSF) + flush_input(tty); + wait_until_sent(tty); + } + return set_termios(termios_tty, (struct termios *) arg, + termios_dev); case TCGETA: return get_termio(termios_tty,(struct termio *) arg); case TCSETAF: - flush_input(tty); - /* fallthrough */ case TCSETAW: - wait_until_sent(tty); /* fallthrough */ case TCSETA: - return set_termio(termios_tty,(struct termio *) arg, termios_dev); + retval = check_change(termios_tty, termios_dev); + if (retval) + return retval; + if (cmd == TCSETAF || cmd == TCSETAW) { + if (cmd == TCSETAF) + flush_input(tty); + wait_until_sent(tty); + } + return set_termio(termios_tty, (struct termio *) arg, + termios_dev); case TCXONC: + retval = check_change(tty, dev); + if (retval) + return retval; switch (arg) { case TCOOFF: - tty->stopped = 1; - if (tty->stop) - (tty->stop)(tty); - TTY_WRITE_FLUSH(tty); - return 0; + stop_tty(tty); + break; case TCOON: - tty->stopped = 0; - if (tty->start) - (tty->start)(tty); - TTY_WRITE_FLUSH(tty); - return 0; + start_tty(tty); + break; case TCIOFF: - if (STOP_CHAR(tty)) + if (STOP_CHAR(tty) != __DISABLED_CHAR) put_tty_queue(STOP_CHAR(tty), &tty->write_q); - return 0; + break; case TCION: - if (START_CHAR(tty)) + if (START_CHAR(tty) != __DISABLED_CHAR) put_tty_queue(START_CHAR(tty), &tty->write_q); - return 0; + break; + default: + return -EINVAL; } - return -EINVAL; /* not implemented */ + return 0; case TCFLSH: - if (arg==0) + retval = check_change(tty, dev); + if (retval) + return retval; + switch (arg) { + case TCIFLUSH: flush_input(tty); - else if (arg==1) - flush_output(tty); - else if (arg==2) { + break; + case TCIOFLUSH: flush_input(tty); + /* fall through */ + case TCOFLUSH: flush_output(tty); - } else + break; + default: return -EINVAL; + } return 0; case TIOCEXCL: set_bit(TTY_EXCLUSIVE, &tty->flags); @@ -550,16 +492,21 @@ int tty_ioctl(struct inode * inode, struct file * file, tty->pgrp = current->pgrp; return 0; case TIOCGPGRP: - retval = verify_area(VERIFY_WRITE, (void *) arg,4); - if (!retval) - put_fs_long(termios_tty->pgrp,(unsigned long *) arg); - return retval; + retval = verify_area(VERIFY_WRITE, (void *) arg, + sizeof (pid_t)); + if (retval) + return retval; + put_fs_long(termios_tty->pgrp, (pid_t *) arg); + return 0; case TIOCSPGRP: + retval = check_change(tty, dev); + if (retval) + return retval; if ((current->tty < 0) || (current->tty != termios_dev) || (termios_tty->session != current->session)) return -ENOTTY; - pgrp=get_fs_long((unsigned long *) arg); + pgrp = get_fs_long((pid_t *) arg); if (pgrp < 0) return -EINVAL; if (session_of_pgrp(pgrp) != current->session) @@ -567,16 +514,19 @@ int tty_ioctl(struct inode * inode, struct file * file, termios_tty->pgrp = pgrp; return 0; case TIOCOUTQ: - retval = verify_area(VERIFY_WRITE, (void *) arg,4); - if (!retval) - put_fs_long(CHARS(&tty->write_q), + retval = verify_area(VERIFY_WRITE, (void *) arg, + sizeof (unsigned long)); + if (retval) + return retval; + put_fs_long(CHARS(&tty->write_q), (unsigned long *) arg); - return retval; + return 0; case TIOCINQ: - retval = verify_area(VERIFY_WRITE, (void *) arg,4); + retval = verify_area(VERIFY_WRITE, (void *) arg, + sizeof (unsigned long)); if (retval) return retval; - if (L_CANON(tty)) + if (L_ICANON(tty)) put_fs_long(inq_canon(tty), (unsigned long *) arg); else @@ -587,17 +537,20 @@ int tty_ioctl(struct inode * inode, struct file * file, if ((current->tty != dev) && !suser()) return -EACCES; put_tty_queue(get_fs_byte((char *) arg), &tty->read_q); + TTY_READ_FLUSH(tty); return 0; case TIOCGWINSZ: - return get_window_size(tty,(struct winsize *) arg); + retval = verify_area(VERIFY_WRITE, (void *) arg, + sizeof (struct winsize)); + if (retval) + return retval; + memcpy_tofs((struct winsize *) arg, &tty->winsize, + sizeof (struct winsize)); + return 0; case TIOCSWINSZ: if (IS_A_PTY_MASTER(dev)) set_window_size(other_tty,(struct winsize *) arg); return set_window_size(tty,(struct winsize *) arg); - case TIOCGSOFTCAR: - return -EINVAL; /* not implemented */ - case TIOCSSOFTCAR: - return -EINVAL; /* not implemented */ case TIOCLINUX: switch (get_fs_byte((char *)arg)) { @@ -647,31 +600,55 @@ int tty_ioctl(struct inode * inode, struct file * file, current->tty = -1; return 0; case TIOCGETD: - retval = verify_area(VERIFY_WRITE, (void *) arg,4); - if (!retval) - put_fs_long(tty->disc, (unsigned long *) arg); - return retval; + retval = verify_area(VERIFY_WRITE, (void *) arg, + sizeof (unsigned long)); + if (retval) + return retval; + put_fs_long(tty->disc, (unsigned long *) arg); + return 0; case TIOCSETD: + retval = check_change(tty, dev); + if (retval) + return retval; arg = get_fs_long((unsigned long *) arg); return tty_set_ldisc(tty, arg); case TIOCGLCKTRMIOS: arg = get_fs_long((unsigned long *) arg); - return get_lcktrmios(tty, (struct termios *) arg, - termios_dev); + retval = verify_area(VERIFY_WRITE, (void *) arg, + sizeof (struct termios)); + if (retval) + return retval; + memcpy_tofs((struct termios *) arg, + &termios_locked[termios_dev], + sizeof (struct termios)); + return 0; case TIOCSLCKTRMIOS: + if (!suser()) + return -EPERM; arg = get_fs_long((unsigned long *) arg); - return set_lcktrmios(tty, (struct termios *) arg, - termios_dev); + memcpy_fromfs(&termios_locked[termios_dev], + (struct termios *) arg, + sizeof (struct termios)); + return 0; case TIOCPKT: if (!IS_A_PTY_MASTER(dev)) return -EINVAL; - retval = verify_area(VERIFY_READ, - (unsigned long *)arg, sizeof (unsigned long)); + retval = verify_area(VERIFY_READ, (void *) arg, + sizeof (unsigned long)); if (retval) return retval; - tty->packet = (get_fs_long ((unsigned long *)arg) != 0); + if (get_fs_long(arg)) { + if (!tty->packet) { + tty->packet = 1; + tty->ctrl_status = 0; + } + } else + tty->packet = 0; return 0; case TCSBRK: case TCSBRKP: + retval = check_change(tty, dev); + if (retval) + return retval; wait_until_sent(tty); if (!tty->ioctl) return 0; diff --git a/drivers/net/8390.c b/drivers/net/8390.c index f4f5641..e6759ea 100644 --- a/drivers/net/8390.c +++ b/drivers/net/8390.c @@ -36,7 +36,6 @@ static char *version = #include <linux/kernel.h> #include <linux/sched.h> #include <linux/fs.h> -#include <linux/tty.h> #include <linux/types.h> #include <linux/ptrace.h> #include <linux/string.h> diff --git a/drivers/net/lance.c b/drivers/net/lance.c index 4e9642b..d6c77ed 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -563,8 +563,12 @@ lance_start_xmit(struct sk_buff *skb, struct device *dev) if (skb->free) kfree_skb (skb, FREE_WRITE); } else + { + /* Gimme!!! */ + if(skb->free==0) + skb_kept_by_device(skb); lp->tx_ring[entry].base = (int)(skb+1) | 0x83000000; - + } lp->cur_tx++; /* Trigger an immediate send poll. */ @@ -648,6 +652,9 @@ lance_interrupt(int reg_ptr) struct sk_buff *skb = ((struct sk_buff *)databuff) - 1; if (skb->free) kfree_skb(skb, FREE_WRITE); + else + skb_device_release(skb,FREE_WRITE); + /* Warning: skb may well vanish at the point you call device_release! */ } dirty_tx++; } diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 2f3ea0d..fb722fd 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -31,13 +31,11 @@ #include <linux/string.h> #include <linux/mm.h> #include <linux/socket.h> -#include <linux/termios.h> #include <linux/sockios.h> #include <linux/interrupt.h> #include <linux/tty.h> #include <linux/errno.h> #include <linux/stat.h> -#include <linux/tty.h> #include <linux/in.h> #include "inet.h" #include "dev.h" @@ -262,6 +262,8 @@ asmlinkage int sys_fchmod(unsigned int fd, mode_t mode) return -EPERM; if (IS_RDONLY(inode)) return -EROFS; + if (mode == (mode_t) -1) + mode = inode->i_mode; inode->i_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); if (!suser() && !in_group_p(inode->i_gid)) inode->i_mode &= ~S_ISGID; @@ -286,6 +288,8 @@ asmlinkage int sys_chmod(const char * filename, mode_t mode) iput(inode); return -EROFS; } + if (mode == (mode_t) -1) + mode = inode->i_mode; inode->i_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); if (!suser() && !in_group_p(inode->i_gid)) inode->i_mode &= ~S_ISGID; diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 1da619d..665e42f 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -14,11 +14,6 @@ #define LONG_MAX ((long)(~0UL>>1)) #define ULONG_MAX (~0UL) -#define VERIFY_READ 0 -#define VERIFY_WRITE 1 - -int verify_area(int type, void * addr, unsigned long count); - #define KERN_EMERG "<0>" /* system is unusable */ #define KERN_ALERT "<1>" /* action must be taken immediately */ #define KERN_CRIT "<2>" /* critical conditions */ diff --git a/include/linux/mm.h b/include/linux/mm.h index 89e7fe2..d890096 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2,9 +2,26 @@ #define _LINUX_MM_H #include <linux/page.h> -#include <linux/fs.h> +#include <linux/sched.h> +#include <linux/errno.h> #include <linux/kernel.h> +#define VERIFY_READ 0 +#define VERIFY_WRITE 1 + +int __verify_write(unsigned long addr, unsigned long count); + +extern inline int verify_area(int type, void * addr, unsigned long size) +{ + if (TASK_SIZE <= (unsigned long) addr) + return -EFAULT; + if (size > TASK_SIZE - (unsigned long) addr) + return -EFAULT; + if (wp_works_ok || type == VERIFY_READ || !size) + return 0; + return __verify_write((unsigned long) addr,size); +} + /* * Linux kernel virtual memory manager primitives. * The idea being to have a "virtual" mm in the same way diff --git a/include/linux/sched.h b/include/linux/sched.h index 9a335a0..6ee77bf 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -13,6 +13,21 @@ #define HZ 100 +/* + * System setup flags.. + */ +extern int hard_math; +extern int x86; +extern int ignore_irq13; +extern int wp_works_ok; + +/* + * Bus types (default is ISA, but people can check others with these..) + * MCA_bus hardcoded to 0 for now. + */ +extern int EISA_bus; +#define MCA_bus 0 + #include <linux/tasks.h> #include <asm/system.h> @@ -290,21 +305,6 @@ extern unsigned long volatile jiffies; extern struct timeval xtime; extern int need_resched; -/* - * System setup flags.. - */ -extern int hard_math; -extern int x86; -extern int ignore_irq13; -extern int wp_works_ok; - -/* - * Bus types (default is ISA, but people can check others with these..) - * MCA_bus hardcoded to 0 for now. - */ -extern int EISA_bus; -#define MCA_bus 0 - #define CURRENT_TIME (xtime.tv_sec) extern void sleep_on(struct wait_queue ** p); diff --git a/include/linux/termios.h b/include/linux/termios.h index 85948ec..a2528bd 100644 --- a/include/linux/termios.h +++ b/include/linux/termios.h @@ -51,6 +51,7 @@ #define TIOCSLCKTRMIOS 0x5457 /* Used for packet mode */ +#define TIOCPKT_DATA 0 #define TIOCPKT_FLUSHREAD 1 #define TIOCPKT_FLUSHWRITE 2 #define TIOCPKT_STOP 4 diff --git a/include/linux/tty.h b/include/linux/tty.h index 12530e7..732bd4e 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -62,7 +62,6 @@ extern struct screen_info screen_info; #define TTY_BUF_SIZE 1024 /* Must be a power of 2 */ struct tty_queue { - unsigned long data; unsigned long head; unsigned long tail; struct wait_queue * proc_list; @@ -143,60 +142,88 @@ struct serial_struct { #define FULL(a) (!LEFT(a)) #define CHARS(a) (((a)->head-(a)->tail)&(TTY_BUF_SIZE-1)) -extern void put_tty_queue(char c, struct tty_queue * queue); +extern void put_tty_queue(unsigned char c, struct tty_queue * queue); extern int get_tty_queue(struct tty_queue * queue); #define INTR_CHAR(tty) ((tty)->termios->c_cc[VINTR]) #define QUIT_CHAR(tty) ((tty)->termios->c_cc[VQUIT]) #define ERASE_CHAR(tty) ((tty)->termios->c_cc[VERASE]) #define KILL_CHAR(tty) ((tty)->termios->c_cc[VKILL]) -#define WERASE_CHAR(tty) ((tty)->termios->c_cc[VWERASE]) #define EOF_CHAR(tty) ((tty)->termios->c_cc[VEOF]) +#define TIME_CHAR(tty) ((tty)->termios->c_cc[VTIME]) +#define MIN_CHAR(tty) ((tty)->termios->c_cc[VMIN]) +#define SWTC_CHAR(tty) ((tty)->termios->c_cc[VSWTC]) #define START_CHAR(tty) ((tty)->termios->c_cc[VSTART]) #define STOP_CHAR(tty) ((tty)->termios->c_cc[VSTOP]) -#define SUSPEND_CHAR(tty) ((tty)->termios->c_cc[VSUSP]) +#define SUSP_CHAR(tty) ((tty)->termios->c_cc[VSUSP]) +#define EOL_CHAR(tty) ((tty)->termios->c_cc[VEOL]) +#define REPRINT_CHAR(tty) ((tty)->termios->c_cc[VREPRINT]) +#define DISCARD_CHAR(tty) ((tty)->termios->c_cc[VDISCARD]) +#define WERASE_CHAR(tty) ((tty)->termios->c_cc[VWERASE]) #define LNEXT_CHAR(tty) ((tty)->termios->c_cc[VLNEXT]) +#define EOL2_CHAR(tty) ((tty)->termios->c_cc[VEOL2]) -#define _L_FLAG(tty,f) ((tty)->termios->c_lflag & f) -#define _I_FLAG(tty,f) ((tty)->termios->c_iflag & f) -#define _O_FLAG(tty,f) ((tty)->termios->c_oflag & f) -#define _C_FLAG(tty,f) ((tty)->termios->c_cflag & f) - -#define L_CANON(tty) _L_FLAG((tty),ICANON) -#define L_ISIG(tty) _L_FLAG((tty),ISIG) -#define L_ECHO(tty) _L_FLAG((tty),ECHO) -#define L_ECHOE(tty) _L_FLAG((tty),ECHOE) -#define L_ECHOK(tty) _L_FLAG((tty),ECHOK) -#define L_ECHONL(tty) _L_FLAG((tty),ECHONL) -#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL) -#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE) -#define L_TOSTOP(tty) _L_FLAG((tty),TOSTOP) +#define _I_FLAG(tty,f) ((tty)->termios->c_iflag & (f)) +#define _O_FLAG(tty,f) ((tty)->termios->c_oflag & (f)) +#define _C_FLAG(tty,f) ((tty)->termios->c_cflag & (f)) +#define _L_FLAG(tty,f) ((tty)->termios->c_lflag & (f)) #define I_IGNBRK(tty) _I_FLAG((tty),IGNBRK) #define I_BRKINT(tty) _I_FLAG((tty),BRKINT) #define I_IGNPAR(tty) _I_FLAG((tty),IGNPAR) #define I_PARMRK(tty) _I_FLAG((tty),PARMRK) #define I_INPCK(tty) _I_FLAG((tty),INPCK) -#define I_UCLC(tty) _I_FLAG((tty),IUCLC) -#define I_NLCR(tty) _I_FLAG((tty),INLCR) -#define I_CRNL(tty) _I_FLAG((tty),ICRNL) -#define I_NOCR(tty) _I_FLAG((tty),IGNCR) +#define I_ISTRIP(tty) _I_FLAG((tty),ISTRIP) +#define I_INLCR(tty) _I_FLAG((tty),INLCR) +#define I_IGNCR(tty) _I_FLAG((tty),IGNCR) +#define I_ICRNL(tty) _I_FLAG((tty),ICRNL) +#define I_IUCLC(tty) _I_FLAG((tty),IUCLC) #define I_IXON(tty) _I_FLAG((tty),IXON) #define I_IXANY(tty) _I_FLAG((tty),IXANY) -#define I_STRP(tty) _I_FLAG((tty),ISTRIP) - -#define O_POST(tty) _O_FLAG((tty),OPOST) -#define O_LCUC(tty) _O_FLAG((tty),OLCUC) -#define O_NLCR(tty) _O_FLAG((tty),ONLCR) -#define O_CRNL(tty) _O_FLAG((tty),OCRNL) -#define O_NOCR(tty) _O_FLAG((tty),ONOCR) -#define O_NLRET(tty) _O_FLAG((tty),ONLRET) +#define I_IXOFF(tty) _I_FLAG((tty),IXOFF) +#define I_IMAXBEL(tty) _I_FLAG((tty),IMAXBEL) + +#define O_OPOST(tty) _O_FLAG((tty),OPOST) +#define O_OLCUC(tty) _O_FLAG((tty),OLCUC) +#define O_ONLCR(tty) _O_FLAG((tty),ONLCR) +#define O_OCRNL(tty) _O_FLAG((tty),OCRNL) +#define O_ONOCR(tty) _O_FLAG((tty),ONOCR) +#define O_ONLRET(tty) _O_FLAG((tty),ONLRET) +#define O_OFILL(tty) _O_FLAG((tty),OFILL) +#define O_OFDEL(tty) _O_FLAG((tty),OFDEL) +#define O_NLDLY(tty) _O_FLAG((tty),NLDLY) +#define O_CRDLY(tty) _O_FLAG((tty),CRDLY) #define O_TABDLY(tty) _O_FLAG((tty),TABDLY) +#define O_BSDLY(tty) _O_FLAG((tty),BSDLY) +#define O_VTDLY(tty) _O_FLAG((tty),VTDLY) +#define O_FFDLY(tty) _O_FLAG((tty),FFDLY) + +#define C_BAUD(tty) _C_FLAG((tty),CBAUD) +#define C_CSIZE(tty) _C_FLAG((tty),CSIZE) +#define C_CSTOPB(tty) _C_FLAG((tty),CSTOPB) +#define C_CREAD(tty) _C_FLAG((tty),CREAD) +#define C_PARENB(tty) _C_FLAG((tty),PARENB) +#define C_PARODD(tty) _C_FLAG((tty),PARODD) +#define C_HUPCL(tty) _C_FLAG((tty),HUPCL) +#define C_CLOCAL(tty) _C_FLAG((tty),CLOCAL) +#define C_CIBAUD(tty) _C_FLAG((tty),CIBAUD) +#define C_CRTSCTS(tty) _C_FLAG((tty),CRTSCTS) -#define C_LOCAL(tty) _C_FLAG((tty),CLOCAL) -#define C_RTSCTS(tty) _C_FLAG((tty),CRTSCTS) -#define C_SPEED(tty) ((tty)->termios->c_cflag & CBAUD) -#define C_HUP(tty) (C_SPEED((tty)) == B0) +#define L_ISIG(tty) _L_FLAG((tty),ISIG) +#define L_ICANON(tty) _L_FLAG((tty),ICANON) +#define L_XCASE(tty) _L_FLAG((tty),XCASE) +#define L_ECHO(tty) _L_FLAG((tty),ECHO) +#define L_ECHOE(tty) _L_FLAG((tty),ECHOE) +#define L_ECHOK(tty) _L_FLAG((tty),ECHOK) +#define L_ECHONL(tty) _L_FLAG((tty),ECHONL) +#define L_NOFLSH(tty) _L_FLAG((tty),NOFLSH) +#define L_TOSTOP(tty) _L_FLAG((tty),TOSTOP) +#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL) +#define L_ECHOPRT(tty) _L_FLAG((tty),ECHOPRT) +#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE) +#define L_FLUSHO(tty) _L_FLAG((tty),FLUSHO) +#define L_PENDIN(tty) _L_FLAG((tty),PENDIN) +#define L_IEXTEN(tty) _L_FLAG((tty),IEXTEN) /* * Where all of the state associated with a tty is kept while the tty @@ -218,12 +245,13 @@ struct tty_struct { int session; unsigned char stopped:1, hw_stopped:1, packet:1, lnext:1; unsigned char char_error:3; + unsigned char erasing:1; unsigned char ctrl_status; short line; int disc; int flags; int count; - int column; + unsigned int column; struct winsize winsize; int (*open)(struct tty_struct * tty, struct file * filp); void (*close)(struct tty_struct * tty, struct file * filp); @@ -241,10 +269,13 @@ struct tty_struct { void (*write_data_callback)(void * data); void * write_data_arg; int readq_flags[TTY_BUF_SIZE/32]; + int secondary_flags[TTY_BUF_SIZE/32]; + int canon_data; + unsigned long canon_head; + unsigned int canon_column; struct tty_queue read_q; struct tty_queue write_q; struct tty_queue secondary; - struct wait_queue * except_q; void *disc_data; }; @@ -256,9 +287,9 @@ struct tty_ldisc { int (*open)(struct tty_struct *); void (*close)(struct tty_struct *); int (*read)(struct tty_struct * tty, struct file * file, - char * buf, int nr); + unsigned char * buf, unsigned int nr); int (*write)(struct tty_struct * tty, struct file * file, - char * buf, int nr); + unsigned char * buf, unsigned int nr); int (*ioctl)(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg); int (*select)(struct tty_struct * tty, struct inode * inode, @@ -313,12 +344,11 @@ struct tty_ldisc { */ #define TTY_WRITE_BUSY 0 #define TTY_READ_BUSY 1 -#define TTY_CR_PENDING 2 -#define TTY_SQ_THROTTLED 3 -#define TTY_RQ_THROTTLED 4 -#define TTY_IO_ERROR 5 -#define TTY_SLAVE_OPENED 6 -#define TTY_EXCLUSIVE 7 +#define TTY_SQ_THROTTLED 2 +#define TTY_RQ_THROTTLED 3 +#define TTY_IO_ERROR 4 +#define TTY_SLAVE_CLOSED 5 +#define TTY_EXCLUSIVE 6 /* * When a break, frame error, or parity error happens, these codes are @@ -336,6 +366,10 @@ struct tty_ldisc { extern void tty_write_flush(struct tty_struct *); extern void tty_read_flush(struct tty_struct *); +/* Number of chars that must be available in a write queue before + the queue is awakened. */ +#define WAKEUP_CHARS (3*TTY_BUF_SIZE/4) + extern struct tty_struct *tty_table[]; extern struct termios *tty_termios[]; extern struct termios *termios_locked[]; @@ -366,7 +400,9 @@ extern long tty_init(long); extern void flush_input(struct tty_struct * tty); extern void flush_output(struct tty_struct * tty); extern void wait_until_sent(struct tty_struct * tty); -extern void copy_to_cooked(struct tty_struct * tty); +extern int check_change(struct tty_struct * tty, int channel); +extern void stop_tty(struct tty_struct * tty); +extern void start_tty(struct tty_struct * tty); extern int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc); extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp, int buflen); diff --git a/kernel/fork.c b/kernel/fork.c index 48589f5..306ddab 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -56,7 +56,8 @@ repeat: } if (task[i]->uid == current->uid) this_user_tasks++; - if (task[i]->pid == last_pid || task[i]->pgrp == last_pid) + if (task[i]->pid == last_pid || task[i]->pgrp == last_pid || + task[i]->session == last_pid) goto repeat; } if (tasks_free <= MIN_TASKS_LEFT_FOR_ROOT || diff --git a/kernel/ksyms.S b/kernel/ksyms.S index d30cbed..acb4752 100644 --- a/kernel/ksyms.S +++ b/kernel/ksyms.S @@ -9,7 +9,7 @@ _register_chrdev _unregister_chrdev -_verify_area +___verify_write _wake_up_interruptible _current diff --git a/kernel/sys.c b/kernel/sys.c index 1327564..a158393 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -7,7 +7,6 @@ #include <linux/config.h> #include <linux/errno.h> #include <linux/sched.h> -#include <linux/tty.h> #include <linux/kernel.h> #include <linux/times.h> #include <linux/utsname.h> @@ -510,7 +509,7 @@ asmlinkage int sys_getpgrp(void) asmlinkage int sys_setsid(void) { - if (current->leader && !suser()) + if (current->leader) return -EPERM; current->leader = 1; current->session = current->pgrp = current->pid; diff --git a/mm/memory.c b/mm/memory.c index 3c2e49e..57cee25 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -651,17 +651,8 @@ void do_wp_page(unsigned long error_code, unsigned long address, *pg_table = 0; } -int verify_area(int type, void * addr, unsigned long size) +int __verify_write(unsigned long start, unsigned long size) { - unsigned long start; - - start = (unsigned long) addr; - if (start >= TASK_SIZE) - return -EFAULT; - if (size > TASK_SIZE - start) - return -EFAULT; - if (wp_works_ok || type == VERIFY_READ || !size) - return 0; size--; size += start & ~PAGE_MASK; size >>= PAGE_SHIFT; diff --git a/net/inet/ip.c b/net/inet/ip.c index 4cd04a4..af6fdbf 100644 --- a/net/inet/ip.c +++ b/net/inet/ip.c @@ -1464,7 +1464,8 @@ ip_retransmit(struct sock *sk, int all) /* If the interface is (still) up and running, kick it. */ if (dev->flags & IFF_UP) { - if (sk) dev->queue_xmit(skb, dev, sk->priority); + if (sk && !skb_device_locked(skb)) + dev->queue_xmit(skb, dev, sk->priority); /* else dev->queue_xmit(skb, dev, SOPRI_NORMAL ); CANNOT HAVE SK=NULL HERE */ } diff --git a/net/inet/skbuff.c b/net/inet/skbuff.c index 2898729..506e95d 100644 --- a/net/inet/skbuff.c +++ b/net/inet/skbuff.c @@ -381,6 +381,12 @@ void kfree_skb(struct sk_buff *skb, int rw) return; } IS_SKB(skb); + if(skb->lock) + { + skb->free=1; /* Free when unlocked */ + return; + } + if(skb->free == 2) printk("Warning: kfree_skb passed an skb that nobody set the free flag on!\n"); if(skb->list) @@ -424,6 +430,7 @@ void kfree_skb(struct sk_buff *skb, int rw) return NULL; skb->free= 2; /* Invalid so we pick up forgetful users */ skb->list= 0; /* Not on a list */ + skb->lock= 0; skb->truesize=size; skb->mem_len=size; skb->mem_addr=skb; @@ -452,3 +459,31 @@ void kfree_skbmem(void *mem,unsigned size) } } +/* + * Skbuff device locking + */ + +void skb_kept_by_device(struct sk_buff *skb) +{ + skb->lock++; +} + +void skb_device_release(struct sk_buff *skb, int mode) +{ + unsigned long flags; + save_flags(flags); + skb->lock--; + if(skb->lock==0) + { + if(skb->free==1) + kfree_skb(skb,mode); + } + restore_flags(flags); +} + +int skb_device_locked(struct sk_buff *skb) +{ + if(skb->lock) + return 1; + return 0; +} diff --git a/net/inet/skbuff.h b/net/inet/skbuff.h index fb7595a..e976385 100644 --- a/net/inet/skbuff.h +++ b/net/inet/skbuff.h @@ -99,7 +99,9 @@ extern struct sk_buff * skb_peek(struct sk_buff * volatile *list); extern struct sk_buff * skb_peek_copy(struct sk_buff * volatile *list); extern struct sk_buff * alloc_skb(unsigned int size, int priority); extern void kfree_skbmem(void *mem, unsigned size); - +extern void skb_kept_by_device(struct sk_buff *skb); +extern void skb_device_release(struct sk_buff *skb, int mode); +extern int skb_device_locked(struct sk_buff *skb); extern void skb_check(struct sk_buff *skb,int, char *); #define IS_SKB(skb) skb_check((skb),__LINE__,__FILE__) diff --git a/net/inet/tcp.c b/net/inet/tcp.c index a3375d4..4de3e1e 100644 --- a/net/inet/tcp.c +++ b/net/inet/tcp.c @@ -583,64 +583,41 @@ tcp_check(struct tcphdr *th, int len, } -void -tcp_send_check(struct tcphdr *th, unsigned long saddr, - unsigned long daddr, int len, struct sock *sk) -{ - th->check = 0; - th->check = tcp_check(th, len, saddr, daddr); - return; -} - -static struct sk_buff * dequeue_partial(struct sock * sk) +void tcp_send_check(struct tcphdr *th, unsigned long saddr, + unsigned long daddr, int len, struct sock *sk) { - struct sk_buff * skb; - unsigned long flags; - - save_flags(flags); - cli(); - skb = sk->send_tmp; - if (skb) { - sk->send_tmp = skb->next; - skb->next = NULL; - } - restore_flags(flags); - return skb; + th->check = 0; + th->check = tcp_check(th, len, saddr, daddr); + return; } -static void enqueue_partial(struct sk_buff * skb, struct sock * sk) +static void tcp_send_skb(struct sock *sk, struct sk_buff *skb) { - unsigned long flags; + int size; - save_flags(flags); - cli(); - skb->next = sk->send_tmp; - sk->send_tmp = skb; - restore_flags(flags); -} + /* length of packet (not counting length of pre-tcp headers) */ + size = skb->len - ((unsigned char *) skb->h.th - skb->data); -static void tcp_send_partial(struct sock *sk) -{ - struct sk_buff *skb; + /* sanity check it.. */ + if (size < sizeof(struct tcphdr) || size > skb->len) { + printk("tcp_send_skb: bad skb (skb = %p, data = %p, th = %p, len = %lu)\n", + skb, skb->data, skb->h.th, skb->len); + kfree_skb(skb, FREE_WRITE); + return; + } - if (sk == NULL) - return; - while ((skb = dequeue_partial(sk)) != NULL) { - /* If we have queued a header size packet.. */ - if(skb->len-(unsigned long)skb->h.th + (unsigned long)skb->data == sizeof(struct tcphdr)) { + if (size == sizeof(struct tcphdr)) { /* If its got a syn or fin its notionally included in the size..*/ if(!skb->h.th->syn && !skb->h.th->fin) { - printk("tcp_send_partial: attempt to queue a bogon.\n"); + printk("tcp_send_skb: attempt to queue a bogon.\n"); kfree_skb(skb,FREE_WRITE); return; } } /* We need to complete and send the packet. */ - tcp_send_check(skb->h.th, sk->saddr, sk->daddr, - skb->len-(unsigned long)skb->h.th + - (unsigned long)skb->data, sk); + tcp_send_check(skb->h.th, sk->saddr, sk->daddr, size, sk); skb->h.seq = sk->send_seq; if (after(sk->send_seq , sk->window_seq) || @@ -664,9 +641,49 @@ static void tcp_send_partial(struct sock *sk) reset_timer(sk, TIME_PROBE0, backoff(sk->backoff) * (2 * sk->mdev + sk->rtt)); } else { - sk->prot->queue_xmit(sk, skb->dev, skb,0); + sk->prot->queue_xmit(sk, skb->dev, skb, 0); } - } +} + +static struct sk_buff * dequeue_partial(struct sock * sk) +{ + struct sk_buff * skb; + unsigned long flags; + + save_flags(flags); + cli(); + skb = sk->send_tmp; + if (skb) { + sk->send_tmp = skb->next; + skb->next = NULL; + } + restore_flags(flags); + return skb; +} + +static void enqueue_partial(struct sk_buff * skb, struct sock * sk) +{ + struct sk_buff * tmp; + unsigned long flags; + + skb->next = NULL; + save_flags(flags); + cli(); + tmp = sk->send_tmp; + sk->send_tmp = skb; + restore_flags(flags); + if (tmp) + tcp_send_skb(sk, tmp); +} + +static void tcp_send_partial(struct sock *sk) +{ + struct sk_buff *skb; + + if (sk == NULL) + return; + while ((skb = dequeue_partial(sk)) != NULL) + tcp_send_skb(sk, skb); } @@ -901,6 +918,7 @@ tcp_write(struct sock *sk, unsigned char *from, continue; } +#if 0 /* * We also need to worry about the window. * If window < 1/4 offered window, don't use it. That's @@ -915,6 +933,10 @@ tcp_write(struct sock *sk, unsigned char *from, copy = sk->mtu; copy = min(copy, sk->mtu); copy = min(copy, len); +#else + /* This also prevents silly windows by simply ignoring the offered window.. */ + copy = min(sk->mtu, len); +#endif /* We should really check the window here also. */ if (sk->packets_out && copy < sk->mtu && !(flags & MSG_OOB)) { @@ -1011,34 +1033,7 @@ tcp_write(struct sock *sk, unsigned char *from, enqueue_partial(send_tmp, sk); continue; } - - tcp_send_check((struct tcphdr *)buff, sk->saddr, sk->daddr, - copy + sizeof(struct tcphdr), sk); - - skb->h.seq = sk->send_seq; - if (after(sk->send_seq , sk->window_seq) || - (sk->retransmits && sk->timeout == TIME_WRITE) || - sk->packets_out >= sk->cong_window) { - DPRINTF((DBG_TCP, "sk->cong_window = %d, sk->packets_out = %d\n", - sk->cong_window, sk->packets_out)); - DPRINTF((DBG_TCP, "sk->send_seq = %d, sk->window_seq = %d\n", - sk->send_seq, sk->window_seq)); - skb->next = NULL; - skb->magic = TCP_WRITE_QUEUE_MAGIC; - if (sk->wback == NULL) { - sk->wfront = skb; - } else { - sk->wback->next = skb; - } - sk->wback = skb; - if (before(sk->window_seq, sk->wfront->h.seq) && - sk->send_head == NULL && - sk->ack_backlog == 0) - reset_timer(sk, TIME_PROBE0, - backoff(sk->backoff) * (2 * sk->mdev + sk->rtt)); - } else { - prot->queue_xmit(sk, dev, skb,0); - } + tcp_send_skb(sk, skb); } sk->err = 0; @@ -3604,7 +3599,7 @@ tcp_send_probe0(struct sock *sk) len = hlen + sizeof(struct tcphdr) + (data ? 1 : 0); /* Allocate buffer. */ - if ((skb2 = alloc_skb(sizeof(struct sk_buff) + len,GFP_KERNEL)) == NULL) { + if ((skb2 = alloc_skb(sizeof(struct sk_buff) + len, GFP_ATOMIC)) == NULL) { /* printk("alloc failed raw %x th %x hlen %d data %d len %d\n", raw, skb->h.th, hlen, data, len); */ reset_timer (sk, TIME_PROBE0, 10); /* try again real soon */ diff --git a/net/socket.c b/net/socket.c index e679128..6caa65b 100644 --- a/net/socket.c +++ b/net/socket.c @@ -28,7 +28,6 @@ #include <linux/stat.h> #include <linux/socket.h> #include <linux/fcntl.h> -#include <linux/termios.h> #include <linux/net.h> #include <linux/ddi.h> |