]> git.neil.brown.name Git - history.git/commitdiff
Import 0.99.14p 0.99.14p
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:18 +0000 (15:09 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:18 +0000 (15:09 -0500)
47 files changed:
Makefile
drivers/FPU-emu/Makefile
drivers/FPU-emu/README
drivers/FPU-emu/errors.c
drivers/FPU-emu/fpu_trig.c
drivers/FPU-emu/reg_norm.S
drivers/FPU-emu/version.h
drivers/block/cdu31a.c
drivers/char/Makefile
drivers/char/mouse.c
drivers/char/psaux.c
drivers/char/serial.c
drivers/char/tty_io.c
drivers/net/slip.c
fs/binfmt_coff.c
fs/ext2/CHANGES
fs/ext2/dir.c
fs/ext2/file.c
fs/ext2/super.c
fs/sysv/README
fs/sysv/ialloc.c
fs/sysv/inode.c
include/linux/ext2_fs.h
include/linux/if_ether.h
include/linux/socket.h
include/linux/sockios.h
init/main.c
net/inet/arp.c
net/inet/arp.h
net/inet/datagram.c
net/inet/dev.c
net/inet/eth.c
net/inet/icmp.c
net/inet/ip.c
net/inet/ip.h
net/inet/packet.c
net/inet/raw.c
net/inet/route.c
net/inet/skbuff.c
net/inet/skbuff.h
net/inet/sock.c
net/inet/sock.h
net/inet/tcp.c
net/inet/timer.c
net/inet/udp.c
net/unix/sock.c
net/unix/unix.h

index bca493a2a7120749ebc2ee5e1d3ddd659f3dd889..1ebcf6e8682f0637ee0fa07c0ba8932ee1fa69f5 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 0.99
 PATCHLEVEL = 14
-ALPHA = o
+ALPHA = p
 
 all:   Version zImage
 
index 78ebb6421e563929ef8d6433cb101b9f5787a575..3563c1d4b9681c4e667a0eaeb2158cdc5feb05b8 100644 (file)
@@ -4,14 +4,15 @@
 
 #DEBUG = -DDEBUGGING
 DEBUG  =
+PARANOID = -DPARANOID
 REENTRANT      = -DREENTRANT_FPU
-CFLAGS := $(CFLAGS) -DPARANOID $(DEBUG) -fno-builtin
+CFLAGS := $(CFLAGS) $(PARANOID) $(DEBUG) -fno-builtin
 
 .c.o:
        $(CC) $(CFLAGS) $(MATH_EMULATION) -c $<
 
 .S.o:
-       $(CC) -D__ASSEMBLER__ $(REENTRANT) -c $<
+       $(CC) -D__ASSEMBLER__ $(PARANOID) $(REENTRANT) -c $<
 
 .s.o:
        $(CC) -c $<
index 0b1a6f328438147fbf4ce3c1b6e3ff5dd5f5a3e6..849355887616ee538b341acb2aed8acadc3a72b7 100644 (file)
@@ -1,7 +1,7 @@
  +---------------------------------------------------------------------------+
  |  wm-FPU-emu   an FPU emulator for 80386 and 80486SX microprocessors.      |
  |                                                                           |
- | 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    |
  |                                                                           |
@@ -47,7 +47,7 @@ Please report bugs, etc to me at:
 
 
 --Bill Metzenthen
-  Sept 1993
+  Jan 1994
 
 
 ----------------------- Internals of wm-FPU-emu -----------------------
@@ -305,7 +305,8 @@ Daniel Carosone, danielce@ee.mu.oz.au
 cae@jpmorgan.com
 Hamish Coleman, t933093@minyos.xx.rmit.oz.au
 Bruce Evans, bde@kralizec.zeta.org.au
-
+Timo Korvola, Timo.Korvola@hut.fi
 ...and numerous others who responded to my request for help with
 a real 80486.
 
index cd3c03a6951fb03d0a817c5b4f42018e3d476c57..85069971d7735b1fe26caefc89c1431ef108fca3 100644 (file)
@@ -3,7 +3,7 @@
  |                                                                           |
  |  The error handling functions for wm-FPU-emu                              |
  |                                                                           |
- | 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    |
  |                                                                           |
@@ -208,7 +208,7 @@ static struct {
              0x125  in fpu_trig.c
              0x126  in fpu_entry.c
              0x127  in poly_2xm1.c
-       0x2nn  in an *.s file:
+       0x2nn  in an *.S file:
               0x201  in reg_u_add.S, reg_round.S
               0x202  in reg_u_div.S
               0x203  in reg_u_div.S
@@ -227,6 +227,8 @@ static struct {
              0x216  in reg_round.S
              0x217  in reg_round.S
              0x218  in reg_round.S
+             0x220  in reg_norm.S
+             0x221  in reg_norm.S
  */
 
 void exception(int n)
index 76db016b4b97efd193c2471dd3da5edd898d7549..1de4317a5c375fff704e498780de2b4d4b1a8895 100644 (file)
@@ -3,7 +3,7 @@
  |                                                                           |
  | Implementation of the FPU "transcendental" functions.                     |
  |                                                                           |
- | 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    |
  |                                                                           |
@@ -88,9 +88,19 @@ static int trig_arg(FPU_REG *X, int even)
             128 bits precision. */
          significand(&tmp) = q + 1;
          tmp.exp = EXP_BIAS + 63;
+         tmp.tag = TW_Valid;
          normalize(&tmp);
          reg_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION);
          reg_add(X, &tmp,  X, FULL_PRECISION);
+         if ( X->sign == SIGN_NEG )
+           {
+             /* CONST_PI2extra is negative, so the result of the addition
+                can be negative. This means that the argument is actually
+                in a different quadrant. The correction is always < pi/2,
+                so it can't overflow into yet another quadrant. */
+             X->sign = SIGN_POS;
+             q++;
+           }
        }
 #endif BETTER_THAN_486
     }
@@ -107,9 +117,23 @@ static int trig_arg(FPU_REG *X, int even)
             128 bits precision. */
          significand(&tmp) = q;
          tmp.exp = EXP_BIAS + 63;
+         tmp.tag = TW_Valid;
          normalize(&tmp);
          reg_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION);
          reg_sub(X, &tmp, X, FULL_PRECISION);
+         if ( (X->exp == CONST_PI2.exp) &&
+             ((X->sigh > CONST_PI2.sigh)
+              || ((X->sigh == CONST_PI2.sigh)
+                  && (X->sigl > CONST_PI2.sigl))) )
+           {
+             /* CONST_PI2extra is negative, so the result of the
+                subtraction can be larger than pi/2. This means
+                that the argument is actually in a different quadrant.
+                The correction is always < pi/2, so it can't overflow
+                into yet another quadrant. */
+             reg_sub(&CONST_PI, X, X, FULL_PRECISION);
+             q++;
+           }
        }
     }
 #endif BETTER_THAN_486
index 8ce60a25c09fc42deababb2405f9d540e036f055..9b7a9d77d07b33d06c196a52b088ba2e3631ca95 100644 (file)
@@ -1,7 +1,7 @@
 /*---------------------------------------------------------------------------+
  |  reg_norm.S                                                               |
  |                                                                           |
- | 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    |
  |                                                                           |
@@ -29,6 +29,17 @@ _normalize:
 
        movl    PARAM1,%ebx
 
+#ifdef PARANOID
+       cmpb    TW_Valid,TAG(%ebx)
+       je      L_ok
+
+       pushl   $0x220
+       call    _exception
+       addl    $4,%esp
+
+L_ok:
+#endif PARANOID
+
        movl    SIGH(%ebx),%edx
        movl    SIGL(%ebx),%eax
 
@@ -98,6 +109,17 @@ _normalize_nuo:
 
        movl    PARAM1,%ebx
 
+#ifdef PARANOID
+       cmpb    TW_Valid,TAG(%ebx)
+       je      L_ok_nuo
+
+       pushl   $0x221
+       call    _exception
+       addl    $4,%esp
+
+L_ok_nuo:
+#endif PARANOID
+
        movl    SIGH(%ebx),%edx
        movl    SIGL(%ebx),%eax
 
index 587f36471c4d9741cf04a0f90dcf65d1aa4526d4..5ae1f490c906f7b57d3b9f9fa69436c8e4a26008 100644 (file)
@@ -2,12 +2,12 @@
  |  version.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    |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
 
-#define FPU_VERSION "wm-FPU-emu version BETA 1.6"
+#define FPU_VERSION "wm-FPU-emu version Beta 1.7"
 
index 4a56d16af23aaf6e50665f00f8a19664ecefa3bf..063da6266a684179b0deefa4ddc420b2a8925e61 100644 (file)
 #define MAJOR_NR CDU31A_CDROM_MAJOR
 #include "blk.h"
 
+#define CDU31A_MAX_CONSECUTIVE_ATTENTIONS 10
 
 static unsigned short cdu31a_addresses[] =
 {
    0x340,      /* Standard configuration Sony Interface */
    0x1f88,     /* Fusion CD-16 */
+   0x230,      /* SoundBlaster 16 card */
    0x360,      /* Secondary standard Sony Interface */
    0x320,      /* Secondary standard Sony Interface */
    0x330,      /* Secondary standard Sony Interface */
@@ -96,6 +98,13 @@ static int handle_sony_cd_attention(void);
 static int read_subcode(void);
 static void sony_get_toc(void);
 static int scd_open(struct inode *inode, struct file *filp);
+static void do_sony_cd_cmd(unsigned char cmd,
+                           unsigned char *params,
+                           unsigned int num_params,
+                           unsigned char *result_buffer,
+                           unsigned int *result_size);
+static void size_to_buf(unsigned int size,
+                        unsigned char *buf);
 
 
 /* The base I/O address of the Sony Interface.  This is a variable (not a
@@ -116,7 +125,6 @@ static volatile unsigned short sony_cd_read_reg;
 static volatile unsigned short sony_cd_fifost_reg;
 
 
-static int initialized = 0;                /* Has the drive been initialized? */
 static int sony_disc_changed = 1;          /* Has the disk been changed
                                               since the last check? */
 static int sony_toc_read = 0;              /* Has the table of contents been
@@ -306,6 +314,71 @@ write_cmd(unsigned char cmd)
    outb(SONY_RES_RDY_INT_EN_BIT, sony_cd_control_reg);
 }
 
+/*
+ * Set the drive parameters so the drive will auto-spin-up when a
+ * disk is inserted.
+ */
+static void
+set_drive_params(void)
+{
+   unsigned char res_reg[2];
+   unsigned int res_size;
+   unsigned char params[3];
+
+
+   params[0] = SONY_SD_MECH_CONTROL;
+   params[1] = 0x03;
+   do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD,
+                  params,
+                  2,
+                  res_reg,
+                  &res_size);
+   if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20))
+   {
+      printk("  Unable to set mechanical parameters: 0x%2.2x\n", res_reg[1]);
+   }
+}
+
+/*
+ * This code will reset the drive and attempt to restore sane parameters.
+ */
+static void
+restart_on_error(void)
+{
+   unsigned char res_reg[2];
+   unsigned int res_size;
+   unsigned int retry_count;
+
+
+   printk("cdu31a: Resetting drive on error\n");
+   reset_drive();
+   retry_count = jiffies + SONY_RESET_TIMEOUT;
+   while ((retry_count > jiffies) && (!is_attention()))
+   {
+      sony_sleep();
+   }
+   set_drive_params();
+   do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);
+   if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20))
+   {
+      printk("cdu31a: Unable to spin up drive: 0x%2.2x\n", res_reg[1]);
+   }
+
+   current->state = TASK_INTERRUPTIBLE;
+   current->timeout = jiffies + 200;
+   schedule();
+
+   do_sony_cd_cmd(SONY_READ_TOC_CMD, NULL, 0, res_reg, &res_size);
+   if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20))
+   {
+      printk("cdu31a: Unable to read TOC: 0x%2.2x\n", res_reg[1]);
+   }
+   sony_get_toc();
+   if (!sony_toc_read)
+   {
+      printk("cdu31a: Unable to get TOC data\n");
+   }
+}
 
 /*
  * This routine writes data to the parameter register.  Since this should
@@ -459,6 +532,39 @@ get_result(unsigned char *result_buffer,
    }
 }
 
+/*
+ * Read in a 2048 byte block of data.
+ */
+static void
+read_data_block(unsigned char *data,
+                unsigned char *result_buffer,
+                unsigned int  *result_size)
+{
+   int i;
+   unsigned int retry_count;
+
+   for (i=0; i<2048; i++)
+   {
+      retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
+      while ((retry_count > jiffies) && (!is_data_requested()))
+      {
+         while (handle_sony_cd_attention())
+            ;
+         
+         sony_sleep();
+      }
+      if (!is_data_requested())
+      {
+         result_buffer[0] = 0x20;
+         result_buffer[1] = SONY_TIMEOUT_OP_ERR;
+         *result_size = 2;
+         return;
+      }
+      
+      *data = read_data_register();
+      data++;
+   }
+}
 
 /*
  * This routine issues a read data command and gets the data.  I don't
@@ -469,35 +575,37 @@ get_result(unsigned char *result_buffer,
  * received at any time and should be handled immediately (at least
  * between every 2048 byte block) to check for errors, we can't wait
  * until all the data is read.
+ *
+ * This routine returns the total number of sectors read.  It will
+ * not return an error if it reads at least one sector successfully.
  */
-static void
-get_data(unsigned char *data,
+static unsigned int
+get_data(unsigned char *orig_data,
          unsigned char *params,         /* 6 bytes with the MSF start address
                                            and number of sectors to read. */
-         unsigned int data_size,
+         unsigned int orig_data_size,
          unsigned char *result_buffer,
          unsigned int *result_size)
 {
-   int i;
    unsigned int cur_offset;
    unsigned int retry_count;
    int result_read;
    int num_retries;
+   unsigned int num_sectors_read = 0;
+   unsigned char *data = orig_data;
+   unsigned int data_size = orig_data_size;
 
 
    cli();
-   if (current != has_cd_task) /* Allow recursive calls to this routine */
+   while (sony_inuse)
    {
-      while (sony_inuse)
+      interruptible_sleep_on(&sony_wait);
+      if (current->signal & ~current->blocked)
       {
-         interruptible_sleep_on(&sony_wait);
-         if (current->signal & ~current->blocked)
-         {
-            result_buffer[0] = 0x20;
-            result_buffer[1] = SONY_SIGNAL_OP_ERR;
-            *result_size = 2;
-            return;
-         }
+         result_buffer[0] = 0x20;
+         result_buffer[1] = SONY_SIGNAL_OP_ERR;
+         *result_size = 2;
+         return 0;
       }
    }
    sony_inuse = 1;
@@ -506,6 +614,8 @@ get_data(unsigned char *data,
 
    num_retries = 0;
 retry_data_operation:
+   result_buffer[0] = 0;
+   result_buffer[1] = 0;
 
    /*
     * Clear any outstanding attentions and wait for the drive to
@@ -522,115 +632,120 @@ retry_data_operation:
       while (handle_sony_cd_attention())
          ;
    }
+
    if (is_busy())
    {
       result_buffer[0] = 0x20;
       result_buffer[1] = SONY_TIMEOUT_OP_ERR;
       *result_size = 2;
-      goto get_data_end;
    }
+   else
+   {
+      /* Issue the command */
+      clear_result_ready();
+      clear_param_reg();
 
-   /* Issue the command */
-   clear_result_ready();
-   clear_param_reg();
-
-   write_params(params, 6);
-   write_cmd(SONY_READ_CMD);
+      write_params(params, 6);
+      write_cmd(SONY_READ_CMD);
 
-   /*
-    * Read the data from the drive one 2048 byte sector at a time.  Handle
-    * any results received between sectors, if an error result is returned
-    * terminate the operation immediately.
-    */
-   cur_offset = 0;
-   result_read = 0;
-   while (data_size > 0)
-   {
-      /* Wait for the drive to tell us we have something */
-      retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
-      while ((retry_count > jiffies) && (!(is_result_ready() || is_data_ready())))
-      {
-         while (handle_sony_cd_attention())
-            ;
-         
-         sony_sleep();
-      }
-      if (!(is_result_ready() || is_data_ready()))
+      /*
+       * Read the data from the drive one 2048 byte sector at a time.  Handle
+       * any results received between sectors, if an error result is returned
+       * terminate the operation immediately.
+       */
+      cur_offset = 0;
+      result_read = 0;
+      while ((data_size > 0) && (result_buffer[0] == 0))
       {
-         result_buffer[0] = 0x20;
-         result_buffer[1] = SONY_TIMEOUT_OP_ERR;
-         *result_size = 2;
-         goto get_data_end;
-      }
+         /* Wait for the drive to tell us we have something */
+         retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
+         while ((retry_count > jiffies) && (!(is_result_ready() || is_data_ready())))
+         {
+            while (handle_sony_cd_attention())
+               ;
+
+            sony_sleep();
+         }
+         if (!(is_result_ready() || is_data_ready()))
+         {
+            result_buffer[0] = 0x20;
+            result_buffer[1] = SONY_TIMEOUT_OP_ERR;
+            *result_size = 2;
+         }
       
-      /* Handle results first */
-      if (is_result_ready())
-      {
-         result_read = 1;
-         get_result(result_buffer, result_size);
-         if ((*result_size < 2) || (result_buffer[0] != 0))
+         /* Handle results first */
+         else if (is_result_ready())
          {
-            goto get_data_end;
+            result_read = 1;
+            get_result(result_buffer, result_size);
          }
-      }
-      else /* Handle data next */
-      {
-         /*
-          * The drive has to be polled for status on a byte-by-byte basis
-          * to know if the data is ready.  Yuck.  I really wish I could use DMA.
-          */
-         clear_data_ready();
-         for (i=0; i<2048; i++)
+         else /* Handle data next */
          {
-            retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
-            while ((retry_count > jiffies) && (!is_data_requested()))
-            {
-               while (handle_sony_cd_attention())
-                  ;
-               
-               sony_sleep();
-            }
-            if (!is_data_requested())
-            {
-               result_buffer[0] = 0x20;
-               result_buffer[1] = SONY_TIMEOUT_OP_ERR;
-               *result_size = 2;
-               goto get_data_end;
-            }
-            
-            *data = read_data_register();
-            data++;
-            data_size--;
+            /*
+             * The drive has to be polled for status on a byte-by-byte basis
+             * to know if the data is ready.  Yuck.  I really wish I could use DMA.
+             */
+            clear_data_ready();
+            read_data_block(data, result_buffer, result_size);
+            data += 2048;
+            data_size -= 2048;
+            cur_offset = cur_offset + 2048;
+            num_sectors_read++;
          }
-         cur_offset = cur_offset + 2048;
       }
-   }
 
-   /* Make sure the result has been read */
-   if (!result_read)
-   {
-      get_result(result_buffer, result_size);
+      /* Make sure the result has been read */
+      if (!result_read)
+      {
+         get_result(result_buffer, result_size);
+      }
    }
 
-get_data_end:
    if (   ((result_buffer[0] & 0x20) == 0x20)
+       && (result_buffer[1] != SONY_NOT_SPIN_ERR) /* No retry when not spin */
        && (num_retries < MAX_CDU31A_RETRIES))
    {
+      /*
+       * If an error occurs, go back and only read one sector at the
+       * given location.  Hopefully the error occurred on an unused
+       * sector after the first one.  It is hard to say which sector
+       * the error occurred on because the drive returns status before
+       * the data transfer is finished and doesn't say which sector.
+       */
+      data_size = 2048;
+      data = orig_data;
+      num_sectors_read = 0;
+      size_to_buf(1, &params[3]);
+
       num_retries++;
-      current->state = TASK_INTERRUPTIBLE;
-      current->timeout = jiffies + 10; /* Wait .1 seconds on retries */
-      schedule();
+      /* Issue a reset on an error (the second time), othersize just delay */
+      if (num_retries == 2)
+      {
+         restart_on_error();
+      }
+      else
+      {
+         current->state = TASK_INTERRUPTIBLE;
+         current->timeout = jiffies + 10;
+         schedule();
+      }
+
+      /* Restart the operation. */
       goto retry_data_operation;
    }
 
    has_cd_task = NULL;
    sony_inuse = 0;
    wake_up_interruptible(&sony_wait);
+
+   return(num_sectors_read);
 }
 
 
 /*
- * Do a command that does not involve data transfer.
+ * Do a command that does not involve data transfer.  This routine must
+ * be re-entrant from the same task to support being called from the
+ * data operation code when an error occurs.
  */
 static void
 do_sony_cd_cmd(unsigned char cmd,
@@ -641,6 +756,7 @@ do_sony_cd_cmd(unsigned char cmd,
 {
    unsigned int retry_count;
    int num_retries;
+   int recursive_call;
 
 
    cli();
@@ -657,9 +773,14 @@ do_sony_cd_cmd(unsigned char cmd,
             return;
          }
       }
+      sony_inuse = 1;
+      has_cd_task = current;
+      recursive_call = 0;
+   }
+   else
+   {
+      recursive_call = 1;
    }
-   sony_inuse = 1;
-   has_cd_task = current;
    sti();
 
    num_retries = 0;
@@ -681,18 +802,18 @@ retry_cd_operation:
       result_buffer[0] = 0x20;
       result_buffer[1] = SONY_TIMEOUT_OP_ERR;
       *result_size = 2;
-      goto do_cmd_end;
    }
+   else
+   {
+      clear_result_ready();
+      clear_param_reg();
 
-   clear_result_ready();
-   clear_param_reg();
-
-   write_params(params, num_params);
-   write_cmd(cmd);
+      write_params(params, num_params);
+      write_cmd(cmd);
 
-   get_result(result_buffer, result_size);
+      get_result(result_buffer, result_size);
+   }
 
-do_cmd_end:
    if (   ((result_buffer[0] & 0x20) == 0x20)
        && (num_retries < MAX_CDU31A_RETRIES))
    {
@@ -703,26 +824,41 @@ do_cmd_end:
       goto retry_cd_operation;
    }
 
-   has_cd_task = NULL;
-   sony_inuse = 0;
-   wake_up_interruptible(&sony_wait);
+   if (!recursive_call)
+   {
+      has_cd_task = NULL;
+      sony_inuse = 0;
+      wake_up_interruptible(&sony_wait);
+   }
 }
 
 
 /*
  * Handle an attention from the drive.  This will return 1 if it found one
  * or 0 if not (if one is found, the caller might want to call again).
+ *
+ * This routine counts the number of consecutive times it is called
+ * (since this is always called from a while loop until it returns
+ * a 0), and returns a 0 if it happens too many times.  This will help
+ * prevent a lockup.
  */
 static int
 handle_sony_cd_attention(void)
 {
    unsigned char atten_code;
-   unsigned char res_reg[2];
-   unsigned int res_size;
+   static int num_consecutive_attentions = 0;
 
 
    if (is_attention())
    {
+      if (num_consecutive_attentions > CDU31A_MAX_CONSECUTIVE_ATTENTIONS)
+      {
+         printk("cdu31a: Too many consecutive attentions: %d\n",
+                num_consecutive_attentions);
+         num_consecutive_attentions = 0;
+         return(0);
+      }
+
       clear_attention();
       atten_code = read_result_register();
 
@@ -735,11 +871,6 @@ handle_sony_cd_attention(void)
          sony_audio_status = CDROM_AUDIO_NO_STATUS;
          sony_first_block = -1;
          sony_last_block = -1;
-         if (initialized)
-         {
-            do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);
-            sony_get_toc();
-         }
          break;
 
       case SONY_AUDIO_PLAY_DONE_ATTN:
@@ -758,9 +889,12 @@ handle_sony_cd_attention(void)
          sony_audio_status = CDROM_AUDIO_ERROR;
          break;
       }
+
+      num_consecutive_attentions++;
       return(1);
    }
 
+   num_consecutive_attentions = 0;
    return(0);
 }
 
@@ -862,6 +996,7 @@ do_cdu31a_request(void)
 
    while (1)
    {
+cdu31a_request_startover:
       /*
        * The beginning here is stolen from the hard disk driver.  I hope
        * its right.
@@ -878,7 +1013,7 @@ do_cdu31a_request(void)
       if (dev != 0)
       {
          end_request(0);
-         continue;
+         goto cdu31a_request_startover;
       }
 
       switch(CURRENT->cmd)
@@ -891,12 +1026,12 @@ do_cdu31a_request(void)
          if ((block / 4) >= sony_toc->lead_out_start_lba)
          {
             end_request(0);
-            return;
+            goto cdu31a_request_startover;
          }
          if (((block + nsect) / 4) >= sony_toc->lead_out_start_lba)
          {
             end_request(0);
-            return;
+            goto cdu31a_request_startover;
          }
 
          while (nsect > 0)
@@ -916,12 +1051,10 @@ do_cdu31a_request(void)
                 */
                if (((block / 4) + sony_buffer_sectors) >= sony_toc->lead_out_start_lba)
                {
-                  sony_last_block = (sony_toc->lead_out_start_lba * 4) - 1;
                   read_size = sony_toc->lead_out_start_lba - (block / 4);
                }
                else
                {
-                  sony_last_block = sony_first_block + (sony_buffer_sectors * 4) - 1;
                   read_size = sony_buffer_sectors;
                }
                size_to_buf(read_size, &params[3]);
@@ -932,7 +1065,12 @@ do_cdu31a_request(void)
                 */
                spin_up_retry = 0;
 try_read_again:
-               get_data(sony_buffer, params, (read_size * 2048), res_reg, &res_size);
+               sony_last_block =   sony_first_block
+                                 + (get_data(sony_buffer,
+                                             params,
+                                             (read_size * 2048),
+                                             res_reg,
+                                             &res_size) * 4) - 1;
                if ((res_size < 2) || (res_reg[0] != 0))
                {
                   if ((res_reg[1] == SONY_NOT_SPIN_ERR) && (!spin_up_retry))
@@ -946,7 +1084,7 @@ try_read_again:
                   sony_first_block = -1;
                   sony_last_block = -1;
                   end_request(0);
-                  return;
+                  goto cdu31a_request_startover;
                }
             }
    
@@ -1569,7 +1707,7 @@ static char *load_mech[] = { "caddy", "tray", "pop-up", "unknown" };
 
 /* Read-ahead buffer sizes for different drives.  These are just arbitrary
    values, I don't know what is really optimum. */
-static unsigned int mem_size[] = { 4096, 8192, 16384, 2048 };
+static unsigned int mem_size[] = { 16384, 16384, 16384, 2048 };
 
 void
 get_drive_configuration(unsigned short base_io,
@@ -1640,8 +1778,6 @@ unsigned long
 cdu31a_init(unsigned long mem_start, unsigned long mem_end)
 {
    struct s_sony_drive_config drive_config;
-   unsigned char params[3];
-   unsigned char res_reg[2];
    unsigned int res_size;
    int i;
    int drive_found;
@@ -1695,17 +1831,7 @@ cdu31a_init(unsigned long mem_start, unsigned long mem_end)
          }
          printk("\n");
 
-         params[0] = SONY_SD_MECH_CONTROL;
-         params[1] = 0x03;
-         do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD,
-                        params,
-                        2,
-                        res_reg,
-                        &res_size);
-         if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20))
-         {
-            printk("  Unable to set mechanical parameters: 0x%2.2x\n", res_reg[1]);
-         }
+         set_drive_params();
 
          blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
          read_ahead[MAJOR_NR] = 8;               /* 8 sector (4kB) read-ahead */
@@ -1716,8 +1842,6 @@ cdu31a_init(unsigned long mem_start, unsigned long mem_end)
          mem_start += sizeof(*last_sony_subcode);
          sony_buffer = (unsigned char *) mem_start;
          mem_start += sony_buffer_size;
-
-         initialized = 1;
       }
 
       i++;
index b72485cd5f38320f4124845773bfd414856c2c7c..414845967eb8a0aaeb5b6e0bd3c3ac75394f25f7 100644 (file)
@@ -48,7 +48,7 @@ OBJS := $(OBJS) msbusmouse.o
 SRCS := $(SRCS) msbusmouse.c
 endif
 
-ifdef CONFIG_QUICKPORT_MOUSE
+ifdef CONFIG_82C710_MOUSE
 CONFIG_PSMOUSE = CONFIG_PSMOUSE
 endif
 
index debc6eaa183f056340fa266aefd26bc2174c5d57..107405f82525ed533c87b7071e9fbce97a7e88de 100644 (file)
@@ -45,7 +45,7 @@ static int mouse_open(struct inode * inode, struct file * file)
                        file->f_op = &bus_mouse_fops;
                        break;
 #endif
-#if defined CONFIG_PSMOUSE || defined CONFIG_QUICKPORT_MOUSE
+#if defined CONFIG_PSMOUSE || defined CONFIG_82C710_MOUSE
                case PSMOUSE_MINOR:
                        file->f_op = &psaux_fops;
                        break;
@@ -83,7 +83,7 @@ unsigned long mouse_init(unsigned long kmem_start)
 #ifdef CONFIG_BUSMOUSE
        kmem_start = bus_mouse_init(kmem_start);
 #endif
-#if defined CONFIG_PSMOUSE || defined CONFIG_QUICKPORT_MOUSE
+#if defined CONFIG_PSMOUSE || defined CONFIG_82C710_MOUSE
        kmem_start = psaux_init(kmem_start);
 #endif
 #ifdef CONFIG_MS_BUSMOUSE
index 487b16d913fccaa410faf23c5ccfcabe4de3ed85..da133b353e01fce8feb30632972a5f5da84d1196 100644 (file)
@@ -68,7 +68,7 @@
 #define AUX_DISABLE_DEV        0xf5            /* disable aux device */
 #define AUX_RESET      0xff            /* reset aux device */
 
-#define MAX_RETRIES    30              /* some aux operations take long time*/
+#define MAX_RETRIES    60              /* some aux operations take long time*/
 #define AUX_IRQ                12
 #define AUX_BUF_SIZE   2048
 
index c25c17b02bab73a514bbd351b38ea54841c11186..0330087d76fc83deae726a1c4e11d180533eadcf 100644 (file)
@@ -1574,7 +1574,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
         */
        if (info->flags & ASYNC_CLOSING) {
                interruptible_sleep_on(&info->close_wait);
-               return -EAGAIN;
+               return -ERESTARTSYS;
        }
 
        /*
@@ -1632,7 +1632,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
                current->state = TASK_INTERRUPTIBLE;
                if (tty_hung_up_p(filp) ||
                    !(info->flags & ASYNC_INITIALIZED)) {
-                       retval = -EAGAIN;
+                       retval = -ERESTARTSYS;
                        break;
                }
                if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
index 5422dcc93a36332acfc733ae4e47662971b4d831..77fb28a69ed73446999c99918075144ab07a7003 100644 (file)
@@ -1315,6 +1315,7 @@ static int tty_open(struct inode * inode, struct file * filp)
        int major, minor;
        int noctty, retval;
 
+retry_open:
        minor = MINOR(inode->i_rdev);
        major = MAJOR(inode->i_rdev);
        noctty = filp->f_flags & O_NOCTTY;
@@ -1372,7 +1373,12 @@ static int tty_open(struct inode * inode, struct file * filp)
 #endif
 
                release_dev(minor, filp);
-               return retval;
+               if (retval != -ERESTARTSYS)
+                       return retval;
+               if (current->signal & ~current->blocked)
+                       return retval;
+               schedule();
+               goto retry_open;
        }
        if (!noctty &&
            current->leader &&
index b72dbcae79c1aae4c8083b194a296ea2c919d17a..275382412cf1808c3a6a8f926405081defce299e 100644 (file)
@@ -881,6 +881,37 @@ slip_open(struct tty_struct *tty)
   return(sl->line);
 }
 
+static struct enet_statistics *
+sl_get_stats(struct device *dev)
+{
+    static struct enet_statistics stats;
+    struct slip *sl;
+    struct slcompress *comp;
+
+    /* Find the correct SLIP channel to use. */
+    sl = &sl_ctrl[dev->base_addr];
+    if (! sl)
+      return NULL;
+
+    memset(&stats, 0, sizeof(struct enet_statistics));
+
+    stats.rx_packets = sl->rpacket;
+    stats.rx_over_errors = sl->roverrun;
+    stats.tx_packets = sl->spacket;
+    stats.tx_dropped = sl->sbusy;
+    stats.rx_errors = sl->errors;
+
+    comp = sl->slcomp;
+    if (comp) {
+      stats.rx_fifo_errors = comp->sls_i_compressed;
+      stats.rx_dropped = comp->sls_i_tossed;
+      stats.tx_fifo_errors = comp->sls_o_compressed;
+      stats.collisions = comp->sls_o_misses;
+    }
+
+    return (&stats);
+}
 
 /*
  * Close down a SLIP channel.
@@ -1193,6 +1224,7 @@ slip_init(struct device *dev)
   dev->hard_header     = sl_header;
   dev->add_arp         = sl_add_arp;
   dev->type_trans      = sl_type_trans;
+  dev->get_stats       = sl_get_stats;
 #ifdef HAVE_SET_MAC_ADDR
 #ifdef CONFIG_AX25
   dev->set_mac_address  = sl_set_mac_address;
index 53b5eda0ca6168b8b3a48a1e0c59db3334705775..bf570164836234d46cfd5a08f8ac732a0106bdb3 100644 (file)
  *       Al Longyear (longyear@sii.com)
  *       Removed erroneous code which mistakenly folded .data with .bss for
  *       a shared library. 
+ *
+ *     8 Janurary 1994
+ *       Al Longyear (longyear@sii.com)
+ *       Corrected problem with read of library section returning the byte
+ *       count rather than zero. This was a change between the pl12 and
+ *       pl14 kernels which slipped by me.
  */
 
 #include <linux/fs.h>
@@ -650,12 +656,21 @@ preload_library (struct linux_binprm *exe_bprm,
                            buffer,                     /* Buffer for read   */
                            nbytes);                    /* Byte count reqd.  */
            set_fs (old_fs);                         /* Restore the selector */
+/*
+ *  Check the result. The value returned is the byte count actaully read.
+ */
+           if (status >= 0 && status != nbytes) {
+#ifdef COFF_DEBUG
+               printk ("read of lib section was short\n");
+#endif
+               status = -ENOEXEC;
+           }
        }
 /*
  *  At this point, go through the list of libraries in the data area.
  */
        phdr = (COFF_SLIBHD *) buffer;
-       while (status == 0 && nbytes > COFF_SLIBSZ) {
+       while (status >= 0 && nbytes > COFF_SLIBSZ) {
            int entry_size  = COFF_LONG (phdr->sl_entsz)   * sizeof (long);
            int header_size = COFF_LONG (phdr->sl_pathndx) * sizeof (long);
 /*
index 258bf23926df3b285c9ca725e9a9a7e3538290ab..08b7b64378cb5c0c7b0f47fffce1259527bb6a1c 100644 (file)
@@ -4,8 +4,7 @@ Changes from version 0.4a to version 0.4b
        - Clean up of balloc.c and ialloc.c.
        - More consistency checks.
        - Block preallocation added by Stephen Tweedie.
-       - Direct reads of directories disallowed if CONFIG_EXT2_FS_DIR_READ not
-         defined.
+       - Direct reads of directories disallowed.
        - Readahead implemented in readdir by Stephen Tweedie.
        - Bugs in block and inodes allocation fixed.
        - Readahead implemented in ext2_find_entry by Chip Salzenberg.
index 9cfff70a3dc1ea355ded6fe54bd3c3d9bca4d1d6..84830b8a5645a38f072f270fe13db7066c9e6c4c 100644 (file)
 
 #include <asm/segment.h>
 
-#include <linux/autoconf.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/ext2_fs.h>
 #include <linux/sched.h>
 #include <linux/stat.h>
 
-#ifndef CONFIG_EXT2_FS_DIR_READ
 static int ext2_dir_read (struct inode * inode, struct file * filp,
                            char * buf, int count)
 {
        return -EISDIR;
 }
-#else
-int ext2_file_read (struct inode *, struct file *, char *, int);
-#endif
 
 static int ext2_readdir (struct inode *, struct file *, struct dirent *, int);
 
 static struct file_operations ext2_dir_operations = {
        NULL,                   /* lseek - default */
-#ifdef CONFIG_EXT2_FS_DIR_READ
-       ext2_file_read,         /* read */
-#else
        ext2_dir_read,          /* read */
-#endif
        NULL,                   /* write - bad */
        ext2_readdir,           /* readdir */
        NULL,                   /* select - default */
index e0e9e98cdb9f4b367e9c05aaa3bea6a9c3df58b9..4f7fa7b4b5dace53769462491ec92589dec21243 100644 (file)
@@ -17,7 +17,6 @@
 #include <asm/segment.h>
 #include <asm/system.h>
 
-#include <linux/autoconf.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/ext2_fs.h>
 #include <linux/fs.h>
 #include <linux/ext2_fs.h>
 
-#ifndef CONFIG_EXT2_FS_DIR_READ
-static
-#endif
-int ext2_file_read (struct inode *, struct file *, char *, int);
+static int ext2_file_read (struct inode *, struct file *, char *, int);
 static int ext2_file_write (struct inode *, struct file *, char *, int);
 static void ext2_release_file (struct inode *, struct file *);
 
@@ -76,10 +72,7 @@ struct inode_operations ext2_file_inode_operations = {
        ext2_permission         /* permission */
 };
 
-#ifndef CONFIG_EXT2_FS_DIR_READ
-static
-#endif
-int ext2_file_read (struct inode * inode, struct file * filp,
+static int ext2_file_read (struct inode * inode, struct file * filp,
                    char * buf, int count)
 {
        int read, left, chars;
@@ -97,7 +90,7 @@ int ext2_file_read (struct inode * inode, struct file * filp,
                return -EINVAL;
        }
        sb = inode->i_sb;
-       if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) {
+       if (!S_ISREG(inode->i_mode)) {
                ext2_warning (sb, "ext2_file_read", "mode = %07o",
                              inode->i_mode);
                return -EINVAL;
index d04caeaa5c50ddd890eb4d495da78e5373723de2..6c7e7d204c2cda90aea8a2f3b1a0add3de7999f1 100644 (file)
@@ -274,7 +274,7 @@ static void ext2_setup_super (struct super_block * sb,
                printk ("EXT2-fs warning: mounting fs with errors, "
                        "running e2fsck is recommended\n");
        else if (es->s_max_mnt_count >= 0 &&
-                es->s_mnt_count >= es->s_max_mnt_count)
+                es->s_mnt_count >= (unsigned short) es->s_max_mnt_count)
                printk ("EXT2-fs warning: maximal mount count reached, "
                        "running e2fsck is recommended\n");
        if (!(sb->s_flags & MS_RDONLY)) {
index f42e57d6d30fbc064bd5e10123601d0ff4ba33e9..6257a0d2400d2740343c91e8b9c172ae601c3de7 100644 (file)
@@ -4,16 +4,11 @@ It implements all of
   - SystemV/386 FS,
   - Coherent FS.
 
-This is version alpha 5.
+This is version beta 1.
 
 To install:
-* You need Linux 0.99.14.
-* Go to /usr/src/linux, unpack the tar file there, and patch the Linux source:
-    patch -p1 < sysvfs.cdif
-  To build the Linux kernel with the patches:
-    make config
-    make depend
-    make
+* Answer the 'System V and Coherent filesystem support' question with 'y'
+  when configuring the kernel.
 * To mount a disk or a partition, use
     mount [-r] -t sysv device mountpoint
   The file system type names
index c8cc98bbdb28a0668a728c9324414d468528836a..cfa56943ddc667bf9344ab22e3ad1fbe97d0c33d 100644 (file)
@@ -65,7 +65,8 @@ void sysv_free_inode(struct inode * inode)
                return;
        }
        if (!(bh = sysv_bread(sb, inode->i_dev, sb->sv_firstinodezone + ((ino-1) >> sb->sv_inodes_per_block_bits), &bh_data))) {
-               panic("sysv_free_inode: unable to read inode block"); /* FIXME: too severe? */
+               printk("sysv_free_inode: unable to read inode block on device %d/%d\n",MAJOR(inode->i_dev),MINOR(inode->i_dev));
+               clear_inode(inode);
                return;
        }
        raw_inode = (struct sysv_inode *) bh_data + ((ino-1) & sb->sv_inodes_per_block_1);
index 4e2af917ec6f4bf834de5d3ef6f9507764f5edbd..d9eb8482d6267f0361fcc74b35613396e4f36017 100644 (file)
@@ -316,7 +316,7 @@ struct super_block *sysv_read_super(struct super_block *sb,void *data,
        sb->s_dev=0;
        unlock_super(sb);
        if (!silent)
-               printk("VFS: unable to read Xenix/SystemV/Coherent superblock\n");
+               printk("VFS: unable to read Xenix/SystemV/Coherent superblock on device %d/%d\n",MAJOR(dev),MINOR(dev));
        return NULL;
 
        ok:
index 3c384b1c05a6d2e75de6edf3cbb89283f4fa3587..7b7bfbb45e869102d3e20b55d7c2257272b68088 100644 (file)
@@ -52,7 +52,7 @@
 /*
  * The second extended file system version
  */
-#define EXT2FS_DATE            "94/01/05"
+#define EXT2FS_DATE            "94/01/08"
 #define EXT2FS_VERSION         "0.4b"
 
 /*
index 2d44fb1c56e4b07a42a9b6d4da08d0be57e23411..2fabe9b3ffbbe53a7f0908f1f5c5d96b7db02eb5 100644 (file)
@@ -31,7 +31,8 @@
 #define ETH_P_PUP      0x0400          /* Xerox PUP packet             */
 #define ETH_P_IP       0x0800          /* Internet Protocol packet     */
 #define ETH_P_ARP      0x0806          /* Address Resolution packet    */
-#define ETH_P_RARP      0x0835         /* Reverse Addr Res packet      */
+#define ETH_P_RARP      0x8035         /* Reverse Addr Res packet      */
+#define ETH_P_X25      0x0805          /* CCITT X.25                   */
 #define ETH_P_IPX      0x8137          /* IPX over DIX                 */
 #define ETH_P_802_3    0x0001          /* Dummy type for 802.3 frames  */
 #define ETH_P_AX25     0x0002          /* Dummy protocol id for AX.25  */
index 4e5fdbdf026ee451361080796db69cc786279300..e6a520bb8d7053dc8260f35d6b89697366177ed6 100644 (file)
@@ -30,10 +30,14 @@ struct linger {
 #define AF_UNSPEC      0
 #define AF_UNIX                1
 #define AF_INET                2
+#define AF_AX25                3
+#define AF_IPX         4
 
 /* Protocol families, same as address families. */
 #define PF_UNIX                AF_UNIX
 #define PF_INET                AF_INET
+#define PF_AX25                AF_AX25
+#define PF_IPX         AF_IPX
 
 /* Flags we can use with send/ and recv. */
 #define MSG_OOB                1
@@ -41,6 +45,10 @@ struct linger {
 
 /* Setsockoptions(2) level. */
 #define SOL_SOCKET     1
+#define SOL_IP         2
+#define SOL_IPX                3
+#define SOL_AX25       4
+#define SOL_TCP                5
 
 /* For setsockoptions(2) */
 #define SO_DEBUG       1
@@ -56,6 +64,19 @@ struct linger {
 #define SO_NO_CHECK    11
 #define SO_PRIORITY    12
 #define SO_LINGER      13
+/* IP options */
+#define IP_TOS         1
+#define        IPTOS_LOWDELAY          0x10
+#define        IPTOS_THROUGHPUT        0x08
+#define        IPTOS_RELIABILITY       0x04
+#define IP_TTL         2
+/* IPX options */
+#define IPX_TYPE       1
+/* AX.25 options */
+#define AX25_WINDOW    1
+/* TCP options */
+#define TCP_MSS                1
+#define TCP_NODELAY    2
 
 /* The various priorities. */
 #define SOPRI_INTERACTIVE      0
index 499b2190add5bc9557cf7158ca2fd5f2ff9f7713..2090c33c93317c11de0a4aa57b183432addfdf28 100644 (file)
@@ -28,7 +28,7 @@ struct ip_config {
   unsigned long        paddr;
   unsigned long        router;
   unsigned long        net;
-  unsigned int up:1,destroy:1;
+  unsigned long        up:1,destroy:1;
 };
 #endif /* FIXME: */
 
index c816f2cd7d2811d1eafa94c006bc81c6b92c1fd4..15e3f6b8c82c444bc7f925275308f0885bfbdca6 100644 (file)
@@ -235,7 +235,7 @@ static void calibrate_delay(void)
                                 "r" (ticks),
                                 "0" (loops_per_sec)
                                :"dx");
-                       printk("ok - %lu.%02lu BogoMips (tm)\n",
+                       printk("ok - %lu.%02lu BogoMips\n",
                                loops_per_sec/500000,
                                (loops_per_sec/5000) % 100);
                        return;
index 0b69e1f6f73ac86902a3e3a645a974777f0e1ae8..d559bcbe3d638919f5df5a97638219120ebc5efb 100644 (file)
@@ -36,6 +36,9 @@
  *             Alan Cox        :       skb->link3 maintained by letting the other xmit queue kill the packet.
  *             Alan Cox        :       Knows about type 3 devices (AX.25) using an AX.25 protocol ID not the ethernet
  *                                     one.
+ *             Dominik Kubla   :       Better checking
+ *             Tegge           :       Assorted corrections on cross port stuff
+ *             Alan Cox        :       ATF_PERM was backwards! - might be useful now (sigh)
  *
  * To Fix:
  *                             :       arp response allocates an skbuff to send. However there is a perfectly
@@ -386,7 +389,7 @@ static struct arp_table *arp_lookup_proxy(unsigned long paddr)
 
 /* Delete an ARP mapping entry in the cache. */
 void
-arp_destroy(unsigned long paddr)
+arp_destructor(unsigned long paddr, int force)
 {
   struct arp_table *apt;
   struct arp_table **lapt;
@@ -406,6 +409,8 @@ arp_destroy(unsigned long paddr)
   lapt = &arp_tables[hash];
   while ((apt = *lapt) != NULL) {
        if (apt->ip == paddr) {
+               if((apt->flags&ATF_PERM) && !force)
+                       return;
                *lapt = apt->next;
                if(apt->flags&ATF_PUBL)
                        arp_proxies--;                  
@@ -418,6 +423,23 @@ arp_destroy(unsigned long paddr)
   sti();
 }
 
+/*
+ *     Kill an entry - eg for ioctl()
+ */
+
+void arp_destroy(unsigned long paddr)
+{      
+       arp_destructor(paddr,1);
+}
+
+/*
+ *     Delete a possibly invalid entry (see timer.c)
+ */
+
+void arp_destroy_maybe(unsigned long paddr)
+{
+       arp_destructor(paddr,0);
+}
 
 /* Create an ARP entry.  The caller should check for duplicates! */
 static struct arp_table *
@@ -536,16 +558,16 @@ arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
        return(0);
   }
 
-  /*
  * A broadcast arp, ignore it
  */
+/*
+ * A broadcast arp, ignore it
+ */
 
-  if((dst&0xFF)==0xFF)
+  if(chk_addr(dst)==IS_BROADCAST)
   {
        kfree_skb(skb, FREE_READ);
        return 0;
   }
-
+  
   memcpy(&dst, ptr + (arp->ar_hln * 2) + arp->ar_pln, arp->ar_pln);
   if ((addr_hint=chk_addr(dst)) != IS_MYADDR && arp_proxies==0) {
        DPRINTF((DBG_ARP, "ARP: request was not for me!\n"));
@@ -654,8 +676,8 @@ arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
         * just pretend we did not find it, and then arp_send will
         * verify the address for us.
         */
-        if ((!(apt->flags & ATF_PERM)) ||
-           (!before(apt->last_used, jiffies+ARP_TIMEOUT) && apt->hlen != 0)) {
+        if ((apt->flags & ATF_PERM) ||
+           (apt->last_used < jiffies+ARP_TIMEOUT && apt->hlen != 0)) {
                apt->last_used = jiffies;
                memcpy(haddr, apt->ha, dev->addr_len);
                return(0);
@@ -814,6 +836,11 @@ arp_req_set(struct arpreq *req)
                htype = ARPHRD_ETHER;
                hlen = ETH_ALEN;
                break;
+               case ARPHRD_AX25:
+                       htype = ARPHRD_AX25;
+                       hlen = 7;
+                       break;
+               
        default:
                return(-EPFNOSUPPORT);
   }
index c75c6cf182d178b42d2d202bb8c7a1c4b9992325..57f41ac1b42b58a45c52fb47cfef77d813807d5e 100644 (file)
@@ -59,5 +59,6 @@ extern void   arp_add_broad(unsigned long addr, struct device *dev);
 extern void    arp_queue(struct sk_buff *skb);
 extern int     arp_get_info(char *buffer);
 extern int     arp_ioctl(unsigned int cmd, void *arg);
+extern void    arp_destroy_maybe(unsigned long paddr);
 
 #endif /* _ARP_H */
index 931d9f3b6107a694bab9d98efb3f232d9748be2d..7d0687eedc6d4d6e199e5ad881566dc9ee9571f5 100644 (file)
@@ -2,7 +2,7 @@
  *     SUCS    NET2 Debugged.
  *
  *     Generic datagram handling routines. These are generic for all protocols. Possibly a generic IP version on top
- *     of these would make sense. Not tonight however 8-). 
+ *     of these would make sense. Not tonight however 8-).
  *     This is used because UDP, RAW, PACKET and the to be released IPX layer all have identical select code and mostly
  *     identical recvfrom() code. So we share it here. The select was shared before but buried in udp.c so I moved it.
  *
@@ -13,6 +13,7 @@
  *             Alan Cox        :       Rewrote skb_read_datagram to avoid the skb_peek_copy stuff.
  *             Alan Cox        :       Added support for SOCK_SEQPACKET. IPX can no longer use the SO_TYPE hack but
  *                                     AX.25 now works right, and SPX is feasible.
+ *             Alan Cox        :       Fixed write select of non IP protocol crash.
  */
 
 #include <linux/config.h>
@@ -35,7 +36,7 @@
 #include "udp.h"
 #include "skbuff.h"
 #include "sock.h"
+
 
 /*
  *     Get a datagram skbuff, understands the peeking, nonblocking wakeups and possible
  */
 
 struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, int *err)
-{  
+{
        struct sk_buff *skb;
-       
+
        /* Socket is inuse - so the timer doesn't attack it */
 restart:
        sk->inuse = 1;
-       while(sk->rqueue == NULL)       /* No data */
-       {
-               /* If we are shutdown then no more data is going to appear. We are done */
-               if (sk->shutdown & RCV_SHUTDOWN) 
+       while(sk->rqueue == NULL)       /* No data */
+       {
+               /* If we are shutdown then no more data is going to appear. We are done */
+               if (sk->shutdown & RCV_SHUTDOWN)
                {
                        release_sock(sk);
                        *err=0;
@@ -69,7 +70,7 @@ restart:
                        sk->err=0;
                        return NULL;
                }
-               
+
                /* Sequenced packets can come disconnected. If so we report the problem */
                if(sk->type==SOCK_SEQPACKET && sk->state!=TCP_ESTABLISHED)
                {
@@ -77,24 +78,24 @@ restart:
                        *err=-ENOTCONN;
                        return NULL;
                }
-               
+
                /* User doesn't want to wait */
-               if (noblock) 
+               if (noblock)
                {
                        release_sock(sk);
                        *err=-EAGAIN;
                        return NULL;
                }
                release_sock(sk);
-               
-               /* Interrupts off so that no packet arrives before we begin sleeping. 
+
+               /* Interrupts off so that no packet arrives before we begin sleeping.
                   Otherwise we might miss our wake up */
                cli();
-               if (sk->rqueue == NULL) 
+               if (sk->rqueue == NULL)
                {
                        interruptible_sleep_on(sk->sleep);
                        /* Signals may need a restart of the syscall */
-                       if (current->signal & ~current->blocked) 
+                       if (current->signal & ~current->blocked)
                        {
                                sti();
                                *err=-ERESTARTSYS;
@@ -115,26 +116,26 @@ restart:
          }
          /* Again only user level code calls this function, so nothing interrupt level
             will suddenely eat the rqueue */
-         if (!(flags & MSG_PEEK)) 
+         if (!(flags & MSG_PEEK))
          {
-               skb=skb_dequeue(&sk->rqueue);
-               if(skb!=NULL)
-                       skb->users++;
+               skb=skb_dequeue(&sk->rqueue);
+               if(skb!=NULL)
+                       skb->users++;
                else
                        goto restart;   /* Avoid race if someone beats us to the data */
          }
          else
          {
-               cli();
-               skb=skb_peek(&sk->rqueue);
-               if(skb!=NULL)
-                       skb->users++;
-               sti();
-               if(skb==NULL)   /* shouldn't happen but .. */
-                       *err=-EAGAIN;
+               cli();
+               skb=skb_peek(&sk->rqueue);
+               if(skb!=NULL)
+                       skb->users++;
+               sti();
+               if(skb==NULL)   /* shouldn't happen but .. */
+                       *err=-EAGAIN;
          }
          return skb;
-}      
+}
 
 void skb_free_datagram(struct sk_buff *skb)
 {
@@ -156,7 +157,7 @@ void skb_free_datagram(struct sk_buff *skb)
 
 void skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size)
 {
-       /* We will know all about the fraglist options to allow >4K receives 
+       /* We will know all about the fraglist options to allow >4K receives
           but not this release */
        memcpy_tofs(to,skb->h.raw+offset,size);
 }
@@ -165,11 +166,11 @@ void skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size)
  *     Datagram select: Again totally generic. Moved from udp.c
  *     Now does seqpacket.
  */
+
 int datagram_select(struct sock *sk, int sel_type, select_table *wait)
 {
        select_wait(sk->sleep, wait);
-       switch(sel_type) 
+       switch(sel_type)
        {
                case SEL_IN:
                        if (sk->type==SOCK_SEQPACKET && sk->state==TCP_CLOSE)
@@ -177,7 +178,7 @@ int datagram_select(struct sock *sk, int sel_type, select_table *wait)
                                /* Connection closed: Wake up */
                                return(1);
                        }
-                       if (sk->rqueue != NULL || sk->err != 0) 
+                       if (sk->rqueue != NULL || sk->err != 0)
                        {       /* This appears to be consistent
                                   with other stacks */
                                return(1);
@@ -185,16 +186,20 @@ int datagram_select(struct sock *sk, int sel_type, select_table *wait)
                        return(0);
 
                case SEL_OUT:
-                       if (sk->prot->wspace(sk) >= MIN_WRITE_SPACE) 
+                       if (sk->prot->wspace(sk) >= MIN_WRITE_SPACE)
+                       {
+                               return(1);
+                       }
+                       if (sk->prot==NULL && sk->sndbuf-sk->wmem_alloc >= MIN_WRITE_SPACE)
                        {
                                return(1);
                        }
                        return(0);
-       
+
                case SEL_EX:
                        if (sk->err)
                                return(1); /* Socket has gone into error state (eg icmp error) */
                        return(0);
-       }
-       return(0);
+       }
+       return(0);
 }
index e867ae38841efd3ed2899f04a826a2a1b19bdf5b..0ce0e7bef2f76999e784e0f1aa54d8584c534b8d 100644 (file)
  *                             a) actually works for all A/B nets
  *                             b) doesn't forward off the same interface.
  *             Alan Cox:       Multiple extra protocols
+ *             Alan Cox:       Fixed ifconfig up of dud device setting the up flag
+ *             Alan Cox:       Fixed verify_area errors
+ *             Alan Cox:       Removed IP_SET_DEV as per Fred's comment. I hope this doesn't give
+ *                             anything away 8)
  *
  *             This program is free software; you can redistribute it and/or
  *             modify it under the terms of the GNU General Public License
@@ -709,9 +713,12 @@ dev_ifconf(char *arg)
   struct device *dev;
   char *pos;
   int len;
+  int err;
 
   /* Fetch the caller's info block. */
-  verify_area(VERIFY_WRITE, arg, sizeof(struct ifconf));
+  err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifconf));
+  if(err)
+       return err;
   memcpy_fromfs(&ifc, arg, sizeof(struct ifconf));
   len = ifc.ifc_len;
   pos = ifc.ifc_buf;
@@ -800,7 +807,9 @@ dev_ifsioc(void *arg, unsigned int getset)
   int ret;
 
   /* Fetch the caller's info block. */
-  verify_area(VERIFY_WRITE, arg, sizeof(struct ifreq));
+  int err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifreq));
+  if(err)
+       return err;
   memcpy_fromfs(&ifr, arg, sizeof(struct ifreq));
 
   /* See which interface the caller is talking about. */
@@ -827,8 +836,12 @@ dev_ifsioc(void *arg, unsigned int getset)
                  if ((old_flags & IFF_UP) && ((dev->flags & IFF_UP) == 0)) {
                        ret = dev_close(dev);
                  } else
+                 {
                      ret = (! (old_flags & IFF_UP) && (dev->flags & IFF_UP))
                        ? dev_open(dev) : 0;
+                     if(ret<0)
+                       dev->flags&=~IFF_UP;    /* Didnt open so down the if */
+                 }
                }
                break;
        case SIOCGIFADDR:
@@ -946,55 +959,9 @@ dev_ioctl(unsigned int cmd, void *arg)
   int ret;
 
   switch(cmd) {
-  case IP_SET_DEV:
-      {          /* Maintain backwards-compatibility, to be deleted for 1.00. */
-         struct device *dev;
-         /* The old 'struct ip_config'. */
-         struct ip_config {
-             char name[MAX_IP_NAME];
-             unsigned long paddr, router, net,up:1,destroy:1;
-         } ipc;
-         int retval, loopback;
-
-         printk("INET: Warning: old-style ioctl(IP_SET_DEV) called!\n");
-         if (!suser())
-             return (-EPERM);
-         
-         verify_area (VERIFY_WRITE, arg, sizeof (ipc));
-         memcpy_fromfs(&ipc, arg, sizeof (ipc));
-         ipc.name[MAX_IP_NAME-1] = 0;
-         loopback = (strcmp(ipc.name, "loopback") == 0);
-         dev = dev_get( loopback ? "lo" : ipc.name);
-         if (dev == NULL)
-             return -EINVAL;
-         ipc.destroy = 0;
-         dev->pa_addr = ipc.paddr;
-         dev->family = AF_INET;
-         dev->pa_mask = get_mask(dev->pa_addr);
-         dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask;
-         if (ipc.net != 0xffffffff) {
-             dev->flags |= IFF_BROADCAST;
-             dev->pa_brdaddr = ipc.net;
-         }
-         
-         /* To be proper we should delete the route here. */
-         if (ipc.up == 0)
-             return (dev->flags & IFF_UP != 0) ? dev_close(dev) : 0;
-
-         if ((dev->flags & IFF_UP) == 0
-             && (retval = dev_open(dev)) != 0)
-             return retval;
-         printk("%s: adding HOST route of %8.8lx.\n", dev->name,
-                htonl(ipc.paddr));
-         rt_add(RTF_HOST, ipc.paddr, 0, 0, dev);
-         if (ipc.router != 0 && ipc.router != -1) {
-             rt_add(RTF_GATEWAY, ipc.paddr, 0, ipc.router, dev);
-             printk("%s: adding GATEWAY route of %8.8lx.\n",
-                    dev->name, htonl(ipc.paddr));
-
-         }
-         return 0;
-      }
+         case IP_SET_DEV:
+                 printk("Your network configuration program needs upgrading.\n");
+                 return -EINVAL;
        case SIOCGIFCONF:
                (void) dev_ifconf((char *) arg);
                ret = 0;
index 01e2f51ddef6c65ce3f9ea39eea2b6247a701a22..d6d83ebedf46c92e6fc5693c686ed541c161dd57 100644 (file)
@@ -17,6 +17,7 @@
  *             Alan Cox        : eth_header ntohs should be htons
  *             Alan Cox        : eth_rebuild_header missing an htons and
  *                               minor other things.
+ *             Tegge           : Arp bug fixes. 
  *
  *             This program is free software; you can redistribute it and/or
  *             modify it under the terms of the GNU General Public License
@@ -124,7 +125,7 @@ eth_header(unsigned char *buff, struct device *dev, unsigned short type,
   cli();
   memcpy(eth->h_source, &saddr, 4);
   /* No. Ask ARP to resolve the Ethernet address. */
-  if (arp_find(eth->h_dest, daddr, dev, saddr)) 
+  if (arp_find(eth->h_dest, daddr, dev, dev->pa_addr)) 
   {
         sti();
         if(type!=ETH_P_IP)
@@ -155,7 +156,7 @@ eth_rebuild_header(void *buff, struct device *dev)
   DPRINTF((DBG_DEV, "ETH: RebuildHeader: SRC=%s ", in_ntoa(src)));
   DPRINTF((DBG_DEV, "DST=%s\n", in_ntoa(dst)));
   if(eth->h_proto!=htons(ETH_P_ARP))   /* This ntohs kind of helps a bit! */
-         if (arp_find(eth->h_dest, dst, dev, src)) return(1);
+         if (arp_find(eth->h_dest, dst, dev, dev->pa_addr /* src */)) return(1);
   memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
   return(0);
 }
index 7b953d44504d33d13db5905ef26dd97e89ef9a26..81504511a78070af11e3c91256331dbae7bc4180 100644 (file)
@@ -14,6 +14,7 @@
  * Fixes:      
  *             Alan Cox        :       Generic queue usage.
  *             Gerhard Koerting:       ICMP addressing corrected
+ *             Alan Cox        :       Use tos/ttl settings
  *
  *
  *             This program is free software; you can redistribute it and/or
@@ -108,7 +109,7 @@ icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev)
 
   /* Build Layer 2-3 headers for message back to source. */
   offset = ip_build_header(skb, dev->pa_addr, iph->saddr,
-                          &dev, IPPROTO_ICMP, NULL, len);
+                          &dev, IPPROTO_ICMP, NULL, len, skb_in->ip_hdr->tos,255);
   if (offset < 0) {
        skb->sk = NULL;
        kfree_skb(skb, FREE_READ);
@@ -255,7 +256,7 @@ icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
 
   /* Build Layer 2-3 headers for message back to source */
   offset = ip_build_header(skb2, daddr, saddr, &dev,
-                               IPPROTO_ICMP, opt, len);
+                               IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
   if (offset < 0) {
        printk("ICMP: Could not build IP Header for ICMP ECHO Response\n");
        kfree_skb(skb2,FREE_WRITE);
@@ -319,7 +320,7 @@ icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
 
   /* Build Layer 2-3 headers for message back to source */
   offset = ip_build_header(skb2, daddr, saddr, &dev,
-                               IPPROTO_ICMP, opt, len);
+                               IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
   if (offset < 0) {
        printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n");
        kfree_skb(skb2,FREE_WRITE);
index 4c9f924c3e7df4e6653458d3341ff2449888605f..091998ca4b1e3874c288d5659b421e1952d7580e 100644 (file)
@@ -31,6 +31,9 @@
  *             Gerhard Koerting:       IP interface addressing fix.
  *             Linus Torvalds  :       More robustness checks
  *             Alan Cox        :       Even more checks: Still not as robust as it ought to be
+ *             Alan Cox        :       Save IP header pointer for later
+ *             Alan Cox        :       ip option setting
+ *             Alan Cox        :       Use ip_tos/ip_ttl settings
  *
  * To Fix:
  *             IP option processing is mostly not needed. ip_forward needs to know about routing rules
@@ -198,7 +201,7 @@ ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct device *dev,
  */
 int
 ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr,
-               struct device **dev, int type, struct options *opt, int len)
+               struct device **dev, int type, struct options *opt, int len, int tos, int ttl)
 {
   static struct options optmem;
   struct iphdr *iph;
@@ -256,9 +259,9 @@ ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr,
 
   iph = (struct iphdr *)buff;
   iph->version  = 4;
-  iph->tos      = 0;
+  iph->tos      = tos;
   iph->frag_off = 0;
-  iph->ttl      = 32;
+  iph->ttl      = ttl;
   iph->daddr    = daddr;
   iph->saddr    = saddr;
   iph->protocol = type;
@@ -1267,6 +1270,8 @@ ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
   }
   
   /* Point into the IP datagram, just past the header. */
+
+  skb->ip_hdr = iph;
   skb->h.raw += iph->ihl*4;
   hash = iph->protocol & (MAX_INET_PROTOS -1);
   for (ipprot = (struct inet_protocol *)inet_protos[hash];
@@ -1504,3 +1509,72 @@ int backoff(int n)
        }
 }
 
+/*
+ *     Socket option code for IP. This is the end of the line after any TCP,UDP etc options on
+ *     an IP socket.
+ */
+int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen)
+{
+       int val,err;
+       
+       if (optval == NULL) 
+               return(-EINVAL);
+
+       err=verify_area(VERIFY_READ, optval, sizeof(int));
+       if(err)
+               return err;
+       
+       val = get_fs_long((unsigned long *)optval);
+
+       if(level!=SOL_IP)
+               return -EOPNOTSUPP;
+
+       switch(optname)
+       {
+               case IP_TOS:
+                       if(val<0||val>255)
+                               return -EINVAL;
+                       sk->ip_tos=val;
+                       return 0;
+               case IP_TTL:
+                       if(val<1||val<255)
+                               return -EINVAL;
+                       sk->ip_ttl=val;
+                       return 0;
+               /* IP_OPTIONS and friends go here eventually */
+               default:
+                       return(-ENOPROTOOPT);
+       }
+}
+
+int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen)
+{
+       int val,err;
+       
+       if(level!=SOL_IP)
+               return -EOPNOTSUPP;
+               
+       switch(optname)
+       {
+               case IP_TOS:
+                       val=sk->ip_tos;
+                       break;
+               case IP_TTL:
+                       val=sk->ip_ttl;
+                       break;
+               default:
+                       return(-ENOPROTOOPT);
+       }
+       err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
+       if(err)
+               return err;
+       put_fs_long(sizeof(int),(unsigned long *) optlen);
+
+       err=verify_area(VERIFY_WRITE, optval, sizeof(int));
+       if(err)
+               return err;
+       put_fs_long(val,(unsigned long *)optval);
+
+       return(0);
+}
index 3c01cc8e716b598e0ab264cbd1020562752c7bd2..7f2ecc00d89e18ccebe615bf338ad4a0a52fbdf2 100644 (file)
@@ -69,7 +69,8 @@ extern int            ip_build_header(struct sk_buff *skb,
                                        unsigned long saddr,
                                        unsigned long daddr,
                                        struct device **dev, int type,
-                                       struct options *opt, int len);
+                                       struct options *opt, int len,
+                                       int tos,int ttl);
 extern unsigned short  ip_compute_csum(unsigned char * buff, int len);
 extern int             ip_rcv(struct sk_buff *skb, struct device *dev,
                               struct packet_type *pt);
@@ -77,5 +78,7 @@ extern void           ip_queue_xmit(struct sock *sk,
                                      struct device *dev, struct sk_buff *skb,
                                      int free);
 extern void            ip_retransmit(struct sock *sk, int all);
+extern int             ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen);
+extern int             ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen);
 
 #endif /* _IP_H */
index c0585a670b1cfd365b4287b4f9254d851a5d9929..ec00afe9727ee4c0ae1c36951758b87663a27f1f 100644 (file)
@@ -18,6 +18,7 @@
  *                                     added. Also fixed the peek/read crash
  *                                     from all old Linux datagram code.
  *             Alan Cox        :       Uses the improved datagram code.
+ *             Alan Cox        :       Added NULL's for socket options.
  *
  *
  *             This program is free software; you can redistribute it and/or
@@ -264,6 +265,8 @@ struct proto packet_prot = {
   NULL,
   packet_init,
   NULL,
+  NULL,        /* No set/get socket options */
+  NULL,
   128,
   0,
   {NULL,},
index 75335322310074649b7b68ad4f9abf7877ab298a..249d0b2ae9d4a57277f8a1d42d330ba06ff643b9 100644 (file)
  *             Alan Cox        :       Checks sk->broadcast.
  *             Alan Cox        :       Uses skb_free_datagram/skb_copy_datagram
  *             Alan Cox        :       Raw passes ip options too
+ *             Alan Cox        :       Setsocketopt added
+ *             Alan Cox        :       Fixed error return for broadcasts
+ *             Alan Cox        :       Removed wake_up calls
+ *             Alan Cox        :       Use ttl/tos
  *
  *             This program is free software; you can redistribute it and/or
  *             modify it under the terms of the GNU General Public License
@@ -76,7 +80,7 @@ raw_err (int err, unsigned char *header, unsigned long daddr,
   }
 
   sk->err = icmp_err_convert[err & 0xff].errno;
-  wake_up(sk->sleep);
+  sk->error_report(sk);
   
   return;
 }
@@ -123,7 +127,7 @@ raw_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
   }
   sk->rmem_alloc += skb->mem_len;
   skb_queue_tail(&sk->rqueue,skb);
-  wake_up(sk->sleep);
+  sk->data_ready(sk,skb->len);
   release_sock(sk);
   return(0);
 }
@@ -169,7 +173,7 @@ raw_sendto(struct sock *sk, unsigned char *from, int len,
   if (sin.sin_port == 0) sin.sin_port = sk->protocol;
   
   if (sk->broadcast == 0 && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
-       return -ENETUNREACH;
+       return -EACCES;
 
   sk->inuse = 1;
   skb = NULL;
@@ -214,7 +218,7 @@ raw_sendto(struct sock *sk, unsigned char *from, int len,
 
   tmp = sk->prot->build_header(skb, sk->saddr, 
                               sin.sin_addr.s_addr, &dev,
-                              sk->protocol, sk->opt, skb->mem_len);
+                              sk->protocol, sk->opt, skb->mem_len, sk->ip_tos,sk->ip_ttl);
   if (tmp < 0) {
        DPRINTF((DBG_RAW, "raw_sendto: error building ip header.\n"));
        kfree_skb(skb,FREE_WRITE);
@@ -330,6 +334,13 @@ raw_recvfrom(struct sock *sk, unsigned char *to, int len,
                return err;
        put_fs_long(sizeof(*sin), addr_len);
   }
+  if(sin)
+  {
+       err=verify_area(VERIFY_WRITE, sin, sizeof(*sin));
+       if(err)
+               return err;
+  }
+  
   err=verify_area(VERIFY_WRITE,to,len);
   if(err)
        return err;
@@ -348,7 +359,6 @@ raw_recvfrom(struct sock *sk, unsigned char *to, int len,
 
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = skb->daddr;
-       verify_area(VERIFY_WRITE, sin, sizeof(*sin));
        memcpy_tofs(sin, &addr, sizeof(*sin));
   }
 
@@ -390,6 +400,8 @@ struct proto raw_prot = {
   NULL,
   raw_init,
   NULL,
+  ip_setsockopt,
+  ip_getsockopt,
   128,
   0,
   {NULL,},
index 269c80d6a896770336e130724dd3a7ef260b192c..c6bcdcefd35d256e9d82a42b305d0a54323a97ad 100644 (file)
@@ -121,21 +121,27 @@ void rt_flush(struct device *dev)
  * number of zero 8-bit net numbers, otherwise we use the "default"
  * masks judging by the destination address and our device netmask.
  */
+static inline unsigned long default_mask(unsigned long dst)
+{
+       dst = ntohl(dst);
+       if (IN_CLASSA(dst))
+               return htonl(IN_CLASSA_NET);
+       if (IN_CLASSB(dst))
+               return htonl(IN_CLASSB_NET);
+       return htonl(IN_CLASSC_NET);
+}
+
 static unsigned long guess_mask(unsigned long dst, struct device * dev)
 {
        unsigned long mask = 0xffffffff;
 
+/* this is a rather ugly optimization: works only on little-endian machines */
        while (mask & dst)
-               mask >>= 8;
+               mask <<= 8;
        if (mask)
                return ~mask;
-       dst = ntohl(dst);
-       if (IN_CLASSA(dst))
-               mask = htonl(IN_CLASSA_NET);
-       else if (IN_CLASSB(dst))
-               mask = htonl(IN_CLASSB_NET);
-       else
-               mask = htonl(IN_CLASSC_NET);
+/* ok, no more hacks.. */
+       mask = default_mask(dst);
        if (dev->flags & IFF_POINTOPOINT)
                return mask;
        if ((dst ^ dev->pa_addr) & mask)
index 1f3299d4857ced241df421a34d0bfd3ffc2c8d8f..28987293e4303cf69140646747af0714fe723ac8 100644 (file)
@@ -13,7 +13,7 @@
  *                                     and memory leak hunting.
  *             Alan Cox        :       More generic kfree handler
  */
+
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 /*
  *     Resource tracking variables
  */
+
 volatile unsigned long net_memory=0;
 volatile unsigned long net_skbcount=0;
 
 /*
  *     Debugging paranoia. Can go later when this crud stack works
- */ 
+ */
+
 
 
 void skb_check(struct sk_buff *skb, int line, char *file)
@@ -81,20 +81,20 @@ void skb_check(struct sk_buff *skb, int line, char *file)
 /*
  *     Insert an sk_buff at the start of a list.
  */
-    
+
 void skb_queue_head(struct sk_buff *volatile* list,struct sk_buff *newsk)
 {
        unsigned long flags;
-       
-       IS_SKB(newsk);  
+
+       IS_SKB(newsk);
        if(newsk->list)
                printk("Suspicious queue head: sk_buff on list!\n");
        save_flags(flags);
        cli();
        newsk->list=list;
-       
+
        newsk->next=*list;
-       
+
        if(*list)
                newsk->prev=(*list)->prev;
        else
@@ -110,14 +110,14 @@ void skb_queue_head(struct sk_buff *volatile* list,struct sk_buff *newsk)
 /*
  *     Insert an sk_buff at the end of a list.
  */
+
 void skb_queue_tail(struct sk_buff *volatile* list, struct sk_buff *newsk)
 {
        unsigned long flags;
-       
+
        if(newsk->list)
                printk("Suspicious queue tail: sk_buff on list!\n");
-       
+
        IS_SKB(newsk);
        save_flags(flags);
        cli();
@@ -137,7 +137,7 @@ void skb_queue_tail(struct sk_buff *volatile* list, struct sk_buff *newsk)
                *list=newsk;
        }
        IS_SKB(newsk->prev);
-       IS_SKB(newsk->next);            
+       IS_SKB(newsk->next);
        restore_flags(flags);
 
 }
@@ -146,21 +146,21 @@ void skb_queue_tail(struct sk_buff *volatile* list, struct sk_buff *newsk)
  *     Remove an sk_buff from a list. This routine is also interrupt safe
  *     so you can grab read and free buffers as another process adds them.
  */
+
 struct sk_buff *skb_dequeue(struct sk_buff *volatile* list)
 {
        long flags;
        struct sk_buff *result;
-       
+
        save_flags(flags);
        cli();
-       
+
        if(*list==NULL)
        {
                restore_flags(flags);
                return(NULL);
        }
-       
+
        result=*list;
        if(result->next==result)
                *list=NULL;
@@ -173,7 +173,7 @@ struct sk_buff *skb_dequeue(struct sk_buff *volatile* list)
 
        IS_SKB(result);
        restore_flags(flags);
-       
+
        if(result->list!=list)
                printk("Dequeued packet has invalid list pointer\n");
 
@@ -186,19 +186,19 @@ struct sk_buff *skb_dequeue(struct sk_buff *volatile* list)
 /*
  *     Insert a packet before another one in a list.
  */
+
 void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
 {
        unsigned long flags;
 
        IS_SKB(old);
        IS_SKB(newsk);
-               
+
        if(!old->list)
                printk("insert before unlisted item!\n");
        if(newsk->list)
                printk("inserted item is already on a list.\n");
-               
+
        save_flags(flags);
        cli();
        newsk->list=old->list;
@@ -206,18 +206,18 @@ void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
        newsk->prev=old->prev;
        newsk->next->prev=newsk;
        newsk->prev->next=newsk;
-       
+
        restore_flags(flags);
 }
 
 /*
  *     Place a packet after a given packet in a list.
  */
+
 void skb_append(struct sk_buff *old, struct sk_buff *newsk)
 {
        unsigned long flags;
-       
+
        IS_SKB(old);
        IS_SKB(newsk);
 
@@ -225,7 +225,7 @@ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
                printk("append before unlisted item!\n");
        if(newsk->list)
                printk("append item is already on a list.\n");
-               
+
        save_flags(flags);
        cli();
        newsk->list=old->list;
@@ -233,7 +233,7 @@ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
        newsk->next=old->next;
        newsk->next->prev=newsk;
        newsk->prev->next=newsk;
-       
+
        restore_flags(flags);
 }
 
@@ -243,7 +243,7 @@ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
  *     MUST EXIST when you unlink. Thus a list must have its contents unlinked
  *     _FIRST_.
  */
+
 void skb_unlink(struct sk_buff *skb)
 {
        unsigned long flags;
@@ -251,7 +251,7 @@ void skb_unlink(struct sk_buff *skb)
        cli();
 
        IS_SKB(skb);
-       
+
        if(skb->list)
        {
                skb->next->prev=skb->prev;
@@ -290,7 +290,7 @@ void skb_new_list_head(struct sk_buff *volatile* list)
                while(skb!=*list);
        }
 }
-                       
+
 /*
  *     Peek an sk_buff. Unlike most other operations you _MUST_
  *     be careful with this one. A peek leaves the buffer on the
@@ -310,14 +310,14 @@ struct sk_buff *skb_peek(struct sk_buff *volatile* list)
  *     anyway. Only the memcpy of upto 4K with ints off is not
  *     as nice as I'd like.
  */
+
 struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
 {
        struct sk_buff *orig,*newsk;
        unsigned long flags;
        unsigned int len;
        /* Now for some games to avoid races */
-       
+
        do
        {
                save_flags(flags);
@@ -336,7 +336,7 @@ struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
 
                if(newsk==NULL)         /* Oh dear... not to worry */
                        return NULL;
-       
+
                save_flags(flags);
                cli();
                if(skb_peek(list)!=orig)        /* List changed go around another time */
@@ -349,7 +349,7 @@ struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
                        kfree_skb(newsk, FREE_WRITE);
                        continue;
                }
-               
+
                IS_SKB(orig);
                IS_SKB(newsk);
                memcpy(newsk,orig,len);
@@ -364,11 +364,11 @@ struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
                newsk->free=1;
        }
        while(0);
-       
+
        restore_flags(flags);
        return(newsk);
-}      
-       
+}
+
 /*
  *     Free an sk_buff. This still knows about things it should
  *     not need to like protocols and sockets.
@@ -376,68 +376,68 @@ struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
 
 void kfree_skb(struct sk_buff *skb, int rw)
 {
-  if (skb == NULL) {
-       printk("kfree_skb: skb = NULL\n");
-       return;
-  }
-  IS_SKB(skb);
-  if(skb->free == 2)
-       printk("Warning: kfree_skb passed an skb that nobody set the free flag on!\n");
-  if(skb->list)
-       printk("Warning: kfree_skb passed an skb still on a list.\n");
-  skb->magic = 0;
-  if (skb->sk) 
-  {
-        if(skb->sk->prot!=NULL)
-        {
-               if (rw)
-                       skb->sk->prot->rfree(skb->sk, skb->mem_addr, skb->mem_len);
-               else
-                       skb->sk->prot->wfree(skb->sk, skb->mem_addr, skb->mem_len);
-
+       if (skb == NULL) {
+               printk("kfree_skb: skb = NULL\n");
+               return;
        }
-       else
+       IS_SKB(skb);
+       if(skb->free == 2)
+               printk("Warning: kfree_skb passed an skb that nobody set the free flag on!\n");
+       if(skb->list)
+               printk("Warning: kfree_skb passed an skb still on a list.\n");
+       skb->magic = 0;
+       if (skb->sk)
+       {
+             if(skb->sk->prot!=NULL)
        {
-               /* Non INET - default wmalloc/rmalloc handler */
-               if (rw)
-                       skb->sk->rmem_alloc-=skb->mem_len;
+                       if (rw)
+                               skb->sk->prot->rfree(skb->sk, skb->mem_addr, skb->mem_len);
+                       else
+                               skb->sk->prot->wfree(skb->sk, skb->mem_addr, skb->mem_len);
+
+               }
                else
-                       skb->sk->wmem_alloc-=skb->mem_len;
-               if(!skb->sk->dead)
+               {
+                       /* Non INET - default wmalloc/rmalloc handler */
+                       if (rw)
+                               skb->sk->rmem_alloc-=skb->mem_len;
+                       else
+                               skb->sk->wmem_alloc-=skb->mem_len;
+                       if(!skb->sk->dead)
                        wake_up(skb->sk->sleep);
-               kfree_skbmem(skb->mem_addr,skb->mem_len);
+                       kfree_skbmem(skb->mem_addr,skb->mem_len);
+               }
        }
-  } 
-  else 
-       kfree_skbmem(skb->mem_addr, skb->mem_len);
+       else
+               kfree_skbmem(skb->mem_addr, skb->mem_len);
 }
 
 /*
  *     Allocate a new skbuff. We do this ourselves so we can fill in a few 'private'
  *     fields and also do memory statistics to find all the [BEEP] leaks.
  */
+
  struct sk_buff *alloc_skb(unsigned int size,int priority)
  {
-       struct sk_buff *skb=(struct sk_buff *)kmalloc(size,priority);
-       if(skb==NULL)
-               return NULL;
-       skb->free= 2;   /* Invalid so we pick up forgetful users */
-       skb->list= 0;   /* Not on a list */
-       skb->truesize=size;
-       skb->mem_len=size;
-       skb->mem_addr=skb;
-       skb->fraglist=NULL;
-       net_memory+=size;
-       net_skbcount++;
-       skb->magic_debug_cookie=SK_GOOD_SKB;
-       skb->users=0;
-       return skb;
+       struct sk_buff *skb=(struct sk_buff *)kmalloc(size,priority);
+       if(skb==NULL)
+               return NULL;
+       skb->free= 2;   /* Invalid so we pick up forgetful users */
+       skb->list= 0;   /* Not on a list */
+       skb->truesize=size;
+       skb->mem_len=size;
+       skb->mem_addr=skb;
+       skb->fraglist=NULL;
+       net_memory+=size;
+       net_skbcount++;
+       skb->magic_debug_cookie=SK_GOOD_SKB;
+       skb->users=0;
+       return skb;
  }
 
 /*
  *     Free an skbuff by memory
- */    
+ */
 
 void kfree_skbmem(void *mem,unsigned size)
 {
@@ -451,4 +451,4 @@ void kfree_skbmem(void *mem,unsigned size)
                net_memory-=size;
        }
 }
+
index 6d5f8794971fb171df2b42259f99b8ddd28e1c6f..a32f5a96b0413cd8376c09ca990ff13aa22589c8 100644 (file)
@@ -60,6 +60,7 @@ struct sk_buff {
        ipx_packet      *ipx;
 #endif 
   } h;
+  struct iphdr         *ip_hdr;                /* For IPPROTO_RAW */
   unsigned long                        mem_len;
   unsigned long                len;
   unsigned long                        fraglen;
index 7ad61c90be9f408f2def4f487acb86d84c538a83..1781697a60fa686ccc71588ae04f9f03a60fe514 100644 (file)
@@ -48,6 +48,9 @@
  *             Alan Cox        :       SO_LINGER supported
  *             Alan Cox        :       Error reporting fixes
  *             Anonymous       :       inet_create tidied up (sk->reuse setting)
+ *             Alan Cox        :       inet sockets don't set sk->type!
+ *             Alan Cox        :       Split socket option code
+ *             Alan Cox        :       Callbacks
  *
  * To Fix:
  *
@@ -312,7 +315,7 @@ destroy_sock(struct sock *sk)
 
        /* Incase it's sleeping somewhere. */
        if (!sk->dead) 
-               wake_up(sk->sleep);
+               sk->write_space(sk);
 
        remove_sock(sk);
   
@@ -471,205 +474,236 @@ inet_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
   }
 }
 
-
-static int
-inet_setsockopt(struct socket *sock, int level, int optname,
+/*
+ *     Set socket options on an inet socket.
+ */
+static int inet_setsockopt(struct socket *sock, int level, int optname,
                    char *optval, int optlen)
 {
-  struct sock *sk;
-  int val;
-  int err;
-  struct linger ling;
-  
-  /* This should really pass things on to the other levels. */
-  if (level != SOL_SOCKET) return(-EOPNOTSUPP);
+       struct sock *sk = (struct sock *) sock->data;  
+       if (level == SOL_SOCKET)
+               return sock_setsockopt(sk,level,optname,optval,optlen);
+       if (sk->prot->setsockopt==NULL)
+               return(-EOPNOTSUPP);
+       else
+               return sk->prot->setsockopt(sk,level,optname,optval,optlen);
+}
 
-  sk = (struct sock *) sock->data;
-  if (sk == NULL) {
-       printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
-       return(0);
-  }
-  if (optval == NULL) return(-EINVAL);
 
-  err=verify_area(VERIFY_READ, optval, sizeof(int));
-  if(err)
-       return err;
-       
-  val = get_fs_long((unsigned long *)optval);
-  switch(optname) {
-       case SO_TYPE:
-       case SO_ERROR:
-               return(-ENOPROTOOPT);
-
-       case SO_DEBUG:  
-               sk->debug=val?1:0;
-       case SO_DONTROUTE:      /* Still to be implemented */
-               return(0);
-       case SO_BROADCAST:
-               sk->broadcast=val?1:0;
-               return 0;
-       case SO_SNDBUF:
-               if(val>32767)
-                       val=32767;
-               if(val<256)
-                       val=256;
-               sk->sndbuf=val;
-               return 0;
-       case SO_LINGER:
-               err=verify_area(VERIFY_READ,optval,sizeof(ling));
-               if(err)
-                       return err;
-               memcpy_fromfs(&ling,optval,sizeof(ling));
-               if(ling.l_onoff==0)
-                       sk->linger=0;
-               else
-               {
-                       sk->lingertime=ling.l_linger;
-                       sk->linger=1;
-               }
-               return 0;
-       case SO_RCVBUF:
-               if(val>32767)
-                       val=32767;
-               if(val<256)
-                       val=256;
-               sk->rcvbuf=val;
-               return(0);
 
-       case SO_REUSEADDR:
-               if (val) sk->reuse = 1;
-                 else sk->reuse = 0;
-               return(0);
 
-       case SO_KEEPALIVE:
-               if (val) sk->keepopen = 1;
-                 else sk->keepopen = 0;
-               return(0);
+static int inet_getsockopt(struct socket *sock, int level, int optname,
+                   char *optval, int *optlen)
+{
+       struct sock *sk = sock->data;   
+       if (level == SOL_SOCKET) 
+               return sock_getsockopt(sk,level,optname,optval,optlen);
+       if(sk->prot->getsockopt==NULL)          
+               return(-EOPNOTSUPP);
+       else
+               return sk->prot->getsockopt(sk,level,optname,optval,optlen);
+}
 
-        case SO_OOBINLINE:
-               if (val) sk->urginline = 1;
-                 else sk->urginline = 0;
-               return(0);
+/*
+ *     This is meant for all protocols to use and covers goings on
+ *     at the socket level. Everything here is generic.
+ */
 
-        case SO_NO_CHECK:
-               if (val) sk->no_check = 1;
-                 else sk->no_check = 0;
-               return(0);
+int sock_setsockopt(struct sock *sk, int level, int optname,
+               char *optval, int optlen)
+{
+       int val;
+       int err;
+       struct linger ling;
 
-        case SO_PRIORITY:
-               if (val >= 0 && val < DEV_NUMBUFFS) {
-                       sk->priority = val;
-               } else {
-                       return(-EINVAL);
-               }
-               return(0);
+       if (optval == NULL) 
+               return(-EINVAL);
 
-       default:
-               return(-ENOPROTOOPT);
-  }
+       err=verify_area(VERIFY_READ, optval, sizeof(int));
+       if(err)
+               return err;
+       
+       val = get_fs_long((unsigned long *)optval);
+       switch(optname) 
+       {
+               case SO_TYPE:
+               case SO_ERROR:
+                       return(-ENOPROTOOPT);
+
+               case SO_DEBUG:  
+                       sk->debug=val?1:0;
+               case SO_DONTROUTE:      /* Still to be implemented */
+                       return(0);
+               case SO_BROADCAST:
+                       sk->broadcast=val?1:0;
+                       return 0;
+               case SO_SNDBUF:
+                       if(val>32767)
+                               val=32767;
+                       if(val<256)
+                               val=256;
+                       sk->sndbuf=val;
+                       return 0;
+               case SO_LINGER:
+                       err=verify_area(VERIFY_READ,optval,sizeof(ling));
+                       if(err)
+                               return err;
+                       memcpy_fromfs(&ling,optval,sizeof(ling));
+                       if(ling.l_onoff==0)
+                               sk->linger=0;
+                       else
+                       {
+                               sk->lingertime=ling.l_linger;
+                               sk->linger=1;
+                       }
+                       return 0;
+               case SO_RCVBUF:
+                       if(val>32767)
+                               val=32767;
+                       if(val<256)
+                               val=256;
+                       sk->rcvbuf=val;
+                       return(0);
+
+               case SO_REUSEADDR:
+                       if (val) 
+                               sk->reuse = 1;
+                       else 
+                               sk->reuse = 0;
+                       return(0);
+
+               case SO_KEEPALIVE:
+                       if (val)
+                               sk->keepopen = 1;
+                       else 
+                               sk->keepopen = 0;
+                       return(0);
+
+               case SO_OOBINLINE:
+                       if (val) 
+                               sk->urginline = 1;
+                       else 
+                               sk->urginline = 0;
+                       return(0);
+
+               case SO_NO_CHECK:
+                       if (val) 
+                               sk->no_check = 1;
+                       else 
+                               sk->no_check = 0;
+                       return(0);
+
+                case SO_PRIORITY:
+                       if (val >= 0 && val < DEV_NUMBUFFS) 
+                       {
+                               sk->priority = val;
+                       } 
+                       else 
+                       {
+                               return(-EINVAL);
+                       }
+                       return(0);
+
+               default:
+                       return(-ENOPROTOOPT);
+       }
 }
 
 
-static int
-inet_getsockopt(struct socket *sock, int level, int optname,
-                   char *optval, int *optlen)
-{
-  struct sock *sk;
-  int val;
-  int err;
-  struct linger ling;
-  
-  /* This should really pass things on to the other levels. */
-  if (level != SOL_SOCKET) return(-EOPNOTSUPP);
+int sock_getsockopt(struct sock *sk, int level, int optname,
+                  char *optval, int *optlen)
+{              
+       int val;
+       int err;
+       struct linger ling;
 
-  sk = (struct sock *) sock->data;
-  if (sk == NULL) {
-       printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
-       return(0);
-  }
-
-  switch(optname) {
-       case SO_DEBUG:          
-               val = sk->debug;
-               break;
-               
-       case SO_DONTROUTE:      /* One last option to implement */
-               val = 0;
-               break;
+       switch(optname) 
+       {
+               case SO_DEBUG:          
+                       val = sk->debug;
+                       break;
                
-       case SO_BROADCAST:
-               val= sk->broadcast;
-               break;
+               case SO_DONTROUTE:      /* One last option to implement */
+                       val = 0;
+                       break;
                
-       case SO_LINGER:
+               case SO_BROADCAST:
+                       val= sk->broadcast;
+                       break;
                
-               err=verify_area(VERIFY_WRITE,optval,sizeof(ling));
-               if(err)
-                       return err;
-               err=verify_area(VERIFY_WRITE,optlen,sizeof(int));
-               if(err)
-                       return err;
-               put_fs_long(sizeof(ling),(unsigned long *)optlen);
-               ling.l_onoff=sk->linger;
-               ling.l_linger=sk->lingertime;
-               memcpy_tofs(optval,&ling,sizeof(ling));
-               return 0;
+               case SO_LINGER: 
+                       err=verify_area(VERIFY_WRITE,optval,sizeof(ling));
+                       if(err)
+                               return err;
+                       err=verify_area(VERIFY_WRITE,optlen,sizeof(int));
+                       if(err)
+                               return err;
+                       put_fs_long(sizeof(ling),(unsigned long *)optlen);
+                       ling.l_onoff=sk->linger;
+                       ling.l_linger=sk->lingertime;
+                       memcpy_tofs(optval,&ling,sizeof(ling));
+                       return 0;
                
-       case SO_SNDBUF:
-               val=sk->sndbuf;
-               break;
+               case SO_SNDBUF:
+                       val=sk->sndbuf;
+                       break;
                
-       case SO_RCVBUF:
-               val =sk->rcvbuf;
-               break;
-
-       case SO_REUSEADDR:
-               val = sk->reuse;
-               break;
+               case SO_RCVBUF:
+                       val =sk->rcvbuf;
+                       break;
 
-       case SO_KEEPALIVE:
-               val = sk->keepopen;
-               break;
+               case SO_REUSEADDR:
+                       val = sk->reuse;
+                       break;
 
-       case SO_TYPE:
-               if (sk->prot == &tcp_prot) val = SOCK_STREAM;
-                 else val = SOCK_DGRAM;
-               break;
+               case SO_KEEPALIVE:
+                       val = sk->keepopen;
+                       break;
 
-       case SO_ERROR:
-               val = sk->err;
-               sk->err = 0;
-               break;
+               case SO_TYPE:
+                       if (sk->prot == &tcp_prot) 
+                               val = SOCK_STREAM;
+                       else 
+                               val = SOCK_DGRAM;
+                       break;
 
-       case SO_OOBINLINE:
-               val = sk->urginline;
-               break;
+               case SO_ERROR:
+                       val = sk->err;
+                       sk->err = 0;
+                       break;
 
-       case SO_NO_CHECK:
-               val = sk->no_check;
-               break;
+               case SO_OOBINLINE:
+                       val = sk->urginline;
+                       break;
+       
+               case SO_NO_CHECK:
+                       val = sk->no_check;
+                       break;
 
-       case SO_PRIORITY:
-               val = sk->priority;
-               break;
+               case SO_PRIORITY:
+                       val = sk->priority;
+                       break;
 
-       default:
-               return(-ENOPROTOOPT);
-  }
-  err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
-  if(err)
-       return err;
-  put_fs_long(sizeof(int),(unsigned long *) optlen);
+               default:
+                       return(-ENOPROTOOPT);
+       }
+       err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
+       if(err)
+               return err;
+       put_fs_long(sizeof(int),(unsigned long *) optlen);
 
-  err=verify_area(VERIFY_WRITE, optval, sizeof(int));
-  if(err)
-       return err;
-  put_fs_long(val,(unsigned long *)optval);
+       err=verify_area(VERIFY_WRITE, optval, sizeof(int));
+       if(err)
+               return err;
+       put_fs_long(val,(unsigned long *)optval);
 
-  return(0);
+       return(0);
 }
 
 
+
+
 static int
 inet_listen(struct socket *sock, int backlog)
 {
@@ -698,6 +732,23 @@ inet_listen(struct socket *sock, int backlog)
   return(0);
 }
 
+/*
+ *     Default callbacks for user INET sockets. These just wake up
+ *     the user owning the socket.
+ */
+
+static void def_callback1(struct sock *sk)
+{
+       if(!sk->dead)
+               wake_up(sk->sleep);
+}
+
+static void def_callback2(struct sock *sk,int len)
+{
+       if(!sk->dead)
+               wake_up(sk->sleep);
+}
+
 
 static int
 inet_create(struct socket *sock, int protocol)
@@ -773,6 +824,7 @@ inet_create(struct socket *sock, int protocol)
                return(-ESOCKTNOSUPPORT);
   }
   sk->socket = sock;
+  sk->type = sock->type;
   sk->protocol = protocol;
   sk->wmem_alloc = 0;
   sk->rmem_alloc = 0;
@@ -853,6 +905,14 @@ inet_create(struct socket *sock, int protocol)
   sk->dummy_th.urg = 0;
   sk->dummy_th.dest = 0;
 
+  sk->ip_tos=0;
+  sk->ip_ttl=64;
+       
+  sk->state_change = def_callback1;
+  sk->data_ready = def_callback2;
+  sk->write_space = def_callback1;
+  sk->error_report = def_callback1;
+
   if (sk->num) {
        /*
         * It assumes that any protocol which allows
@@ -893,7 +953,7 @@ inet_release(struct socket *sock, struct socket *peer)
   if (sk == NULL) return(0);
 
   DPRINTF((DBG_INET, "inet_release(sock = %X, peer = %X)\n", sock, peer));
-  wake_up(sk->sleep);
+  sk->state_change(sk);
 
   /* Start closing the connection.  This may take a while. */
   /*
@@ -1579,7 +1639,7 @@ sock_wfree(struct sock *sk, void *mem, unsigned long size)
        sk->wmem_alloc -= size;
 
        /* In case it might be waiting for more memory. */
-       if (!sk->dead) wake_up(sk->sleep);
+       if (!sk->dead) sk->write_space(sk);
        if (sk->destroy && sk->wmem_alloc == 0 && sk->rmem_alloc == 0) {
                DPRINTF((DBG_INET,
                        "recovered lost memory, sock = %X\n", sk));
index cf6e2f3f8b6df1ffd0b174b8c04e2f8ef1bed6c6..cf8397a8940f5bdf86a2e3193fa28a7a0cb73ad6 100644 (file)
@@ -136,7 +136,11 @@ struct sock {
   char                         ax25_retxqi;
   char                         ax25_rrtimer;
   char                         ax25_timer;
+  ax25_digi                    *ax25_digipeat;
 #endif  
+/* IP 'private area' or will be eventually */
+  int                          ip_ttl;         /* TTL setting */
+  int                          ip_tos;         /* TOS */
   struct tcphdr                        dummy_th;
 
   /* This part is used for the timeout functions (timer.c). */
@@ -145,6 +149,13 @@ struct sock {
 
   /* identd */
   struct socket                        *socket;
+  
+  /* Callbacks */
+  void                         (*state_change)(struct sock *sk);
+  void                         (*data_ready)(struct sock *sk,int bytes);
+  void                         (*write_space)(struct sock *sk);
+  void                         (*error_report)(struct sock *sk);
+  
 };
 
 struct proto {
@@ -177,7 +188,7 @@ struct proto {
                                        unsigned long saddr,
                                        unsigned long daddr,
                                        struct device **dev, int type,
-                                       struct options *opt, int len);
+                                       struct options *opt, int len, int tos, int ttl);
   int                  (*connect)(struct sock *sk,
                                  struct sockaddr_in *usin, int addr_len);
   struct sock          *(*accept) (struct sock *sk, int flags);
@@ -197,6 +208,10 @@ struct proto {
                                 unsigned long arg);
   int                  (*init)(struct sock *sk);
   void                 (*shutdown)(struct sock *sk, int how);
+  int                  (*setsockopt)(struct sock *sk, int level, int optname,
+                                char *optval, int optlen);
+  int                  (*getsockopt)(struct sock *sk, int level, int optname,
+                               char *optval, int *option);      
   unsigned short       max_header;
   unsigned long                retransmits;
   struct sock          *sock_array[SOCK_ARRAY_SIZE];
@@ -238,6 +253,8 @@ extern void                 sock_rfree(struct sock *sk, void *mem,
 extern unsigned long           sock_rspace(struct sock *sk);
 extern unsigned long           sock_wspace(struct sock *sk);
 
+extern int                     sock_setsockopt(struct sock *sk,int level,int op,char *optval,int optlen);
+extern int                     sock_getsockopt(struct sock *sk,int level,int op,char *optval,int *optlen);
 
 /* declarations from timer.c */
 extern struct sock *timer_base;
index 83dfb4171ddc68d5e31ad29ee9f5752c14de4750..91608212c8b20b8620447b825236f6ef810aceea 100644 (file)
  *     Michael O'Reilly        :       ack < copied bug fix.
  *     Johannes Stille         :       Misc tcp fixes (not all in yet).
  *             Alan Cox        :       FIN with no memory -> CRASH
+ *             Alan Cox        :       Added socket option proto entries. Also added awareness of them to accept.
+ *             Alan Cox        :       Added TCP options (SOL_TCP)
+ *             Alan Cox        :       Switched wakeup calls to callbacks, so the kernel can layer network sockets.
+ *             Alan Cox        :       Use ip_tos/ip_ttl settings.
+ *             Alan Cox        :       Handle FIN (more) properly (we hope).
+ *             Alan Cox        :       RST frames sent on unsynchronised state ack error/
+ *             Alan Cox        :       Put in missing check for SYN bit.
  *
  *
  * To Fix:
@@ -155,7 +162,7 @@ static void tcp_time_wait(struct sock *sk)
   sk->state = TCP_TIME_WAIT;
   sk->shutdown = SHUTDOWN_MASK;
   if (!sk->dead)
-       wake_up(sk->sleep);
+       sk->state_change(sk);
   reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
 }
 
@@ -213,7 +220,7 @@ tcp_err(int err, unsigned char *header, unsigned long daddr,
   if(err<0)
   {
        sk->err = -err;
-       wake_up(sk->sleep);
+       sk->error_report(sk);
        return;
   }
 
@@ -237,7 +244,7 @@ tcp_err(int err, unsigned char *header, unsigned long daddr,
   if (icmp_err_convert[err & 0xff].fatal) {
        if (sk->state == TCP_SYN_SENT) {
                sk->state = TCP_CLOSE;
-               wake_up(sk->sleep);     /* Wake people up to see the error (see connect in sock.c) */
+               sk->error_report(sk);           /* Wake people up to see the error (see connect in sock.c) */
        }
   }
   return;
@@ -558,7 +565,20 @@ tcp_send_partial(struct sock *sk)
   if (sk == NULL || sk->send_tmp == NULL) return;
   
   skb = sk->send_tmp;
-
+  
+  /* If we have queued a header size packet.. */
+  if(skb->len-(unsigned long)skb->h.th + (unsigned long)(skb+1)==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");
+               kfree_skb(skb,FREE_WRITE);
+               sk->send_tmp=NULL;
+               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 +
@@ -622,7 +642,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_ack: malloc failed\n");
 
   /* Put in the IP header and routing stuff. */
   tmp = sk->prot->build_header(buff, sk->saddr, daddr, &dev,
-                               IPPROTO_TCP, sk->opt, MAX_ACK_SIZE);
+                               IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl);
   if (tmp < 0) {
        buff->free=1;
        sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
@@ -887,7 +907,7 @@ tcp_write(struct sock *sk, unsigned char *from,
         * Perhaps some hints here would be good.
         */
        tmp = prot->build_header(skb, sk->saddr, sk->daddr, &dev,
-                                IPPROTO_TCP, sk->opt, skb->mem_len);
+                                IPPROTO_TCP, sk->opt, skb->mem_len,sk->ip_tos,sk->ip_ttl);
        if (tmp < 0 ) {
                prot->wfree(sk, skb->mem_addr, skb->mem_len);
                release_sock(sk);
@@ -1008,7 +1028,7 @@ tcp_read_wakeup(struct sock *sk)
 
   /* Put in the IP header and routing stuff. */
   tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
-                              IPPROTO_TCP, sk->opt, MAX_ACK_SIZE);
+                              IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl);
   if (tmp < 0) {
        buff->free=1;
        sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
@@ -1484,7 +1504,7 @@ tcp_shutdown(struct sock *sk, int how)
   /* Put in the IP header and routing stuff. */
   tmp = prot->build_header(buff,sk->saddr, sk->daddr, &dev,
                           IPPROTO_TCP, sk->opt,
-                          sizeof(struct tcphdr));
+                          sizeof(struct tcphdr),sk->ip_tos,sk->ip_ttl);
   if (tmp < 0) {
        buff->free=1;
        prot->wfree(sk,buff->mem_addr, buff->mem_len);
@@ -1569,7 +1589,7 @@ tcp_recvfrom(struct sock *sk, unsigned char *to,
 /* This routine will send an RST to the other tcp. */
 static void
 tcp_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th,
-         struct proto *prot, struct options *opt, struct device *dev)
+         struct proto *prot, struct options *opt, struct device *dev, int tos, int ttl)
 {
   struct sk_buff *buff;
   struct tcphdr *t1;
@@ -1594,7 +1614,7 @@ tcp_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th,
 
   /* Put in the IP header and routing stuff. */
   tmp = prot->build_header(buff, saddr, daddr, &dev, IPPROTO_TCP, opt,
-                          sizeof(struct tcphdr));
+                          sizeof(struct tcphdr),tos,ttl);
   if (tmp < 0) {
        buff->free = 1;
        prot->wfree(NULL, buff->mem_addr, buff->mem_len);
@@ -1714,10 +1734,10 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
 
   /* If the socket is dead, don't accept the connection. */
   if (!sk->dead) {
-       wake_up(sk->sleep);
+       sk->data_ready(sk,0);
   } else {
        DPRINTF((DBG_TCP, "tcp_conn_request on dead socket\n"));
-       tcp_reset(daddr, saddr, th, sk->prot, opt, dev);
+       tcp_reset(daddr, saddr, th, sk->prot, opt, dev, sk->ip_tos,sk->ip_ttl);
        kfree_skb(skb, FREE_READ);
        return;
   }
@@ -1802,21 +1822,12 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
   newsk->acked_seq = skb->h.th->seq + 1;
   newsk->copied_seq = skb->h.th->seq;
 
-#ifdef OLDWAY
-  if (skb->h.th->doff == 5) {
-       newsk->mtu = dev->mtu - HEADER_SIZE;
-  } else {
-       ptr =(unsigned char *)(skb->h.th + 1);
-       if (ptr[0] != 2 || ptr[1] != 4) {
-               newsk->mtu = dev->mtu - HEADER_SIZE;
-       } else {
-               newsk->mtu = min(ptr[2] * 256 + ptr[3] - HEADER_SIZE,
-                                dev->mtu - HEADER_SIZE);
-       }
-  }
-#else
+  /* Grab the ttl and tos values and use them */
+  newsk->ip_ttl=sk->ip_ttl;
+  newsk->ip_tos=skb->ip_hdr->tos;
+
   tcp_options(newsk,skb->h.th);
-#endif
+
   buff = (struct sk_buff *) newsk->prot->wmalloc(newsk, MAX_SYN_SIZE, 1, GFP_ATOMIC);
   if (buff == NULL) {
        sk->err = -ENOMEM;
@@ -1835,7 +1846,7 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
 
   /* Put in the IP header and routing stuff. */
   tmp = sk->prot->build_header(buff, newsk->saddr, newsk->daddr, &dev,
-                              IPPROTO_TCP, NULL, MAX_SYN_SIZE);
+                              IPPROTO_TCP, NULL, MAX_SYN_SIZE,sk->ip_tos,sk->ip_ttl);
 
   /* Something went wrong. */
   if (tmp < 0) {
@@ -1912,25 +1923,13 @@ tcp_close(struct sock *sk, int timeout)
   sk->keepopen = 1;
   sk->shutdown = SHUTDOWN_MASK;
 
-  if (!sk->dead) wake_up(sk->sleep);
+  if (!sk->dead) 
+       sk->state_change(sk);
 
   /* We need to flush the recv. buffs. */
   if (skb_peek(&sk->rqueue) != NULL) 
   {
        struct sk_buff *skb;
-#ifdef OLD     
-       struct sk_buff *skb2;
-       skb = skb_peek(&sk->rqueue);
-       do {
-               skb2 =(struct sk_buff *)skb->next;
-               /* if there is some real unread data, send a reset. */
-               if (skb->len > 0 &&
-                   after(skb->h.th->seq + skb->len + 1, sk->copied_seq))
-                                                               need_reset = 1;
-               kfree_skb(skb, FREE_WRITE);
-               skb = skb2;
-       } while(skb != sk->rqueue);
-#else
        if(sk->debug)
                printk("Clean rcv queue\n");
        while((skb=skb_dequeue(&sk->rqueue))!=NULL)
@@ -1941,7 +1940,6 @@ tcp_close(struct sock *sk, int timeout)
        }
        if(sk->debug)
                printk("Cleaned.\n");
-#endif
   }
   sk->rqueue = NULL;
 
@@ -1999,7 +1997,7 @@ tcp_close(struct sock *sk, int timeout)
                /* Put in the IP header and routing stuff. */
                tmp = prot->build_header(buff,sk->saddr, sk->daddr, &dev,
                                         IPPROTO_TCP, sk->opt,
-                                        sizeof(struct tcphdr));
+                                        sizeof(struct tcphdr),sk->ip_tos,sk->ip_ttl);
                if (tmp < 0) {
                        kfree_skb(buff,FREE_WRITE);
                        DPRINTF((DBG_TCP, "Unable to build header for fin.\n"));
@@ -2088,7 +2086,7 @@ tcp_write_xmit(struct sock *sk)
                if (before(skb->h.seq, sk->rcv_ack_seq +1)) {
                        sk->retransmits = 0;
                        kfree_skb(skb, FREE_WRITE);
-                       if (!sk->dead) wake_up(sk->sleep);
+                       if (!sk->dead) sk->write_space(sk);
                } else {
                        sk->prot->queue_xmit(sk, skb->dev, skb, skb->free);
                }
@@ -2185,30 +2183,7 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
                        if (sk->packets_out > 0) sk->packets_out--;
                        /* We may need to remove this from the dev send list. */
                        if (skb->next != NULL) {
-#ifdef OLD_WAY                 
-                               int i;
-
-                               if (skb->next != skb) {
-                                       skb->next->prev = skb->prev;
-                                       skb->prev->next = skb->next;
-                               }
-
-                               for(i = 0; i < DEV_NUMBUFFS; i++) {
-                                       if (skb->dev->buffs[i] == skb) {
-                                               if (skb->next == skb)
-                                                       skb->dev->buffs[i] = NULL;
-                                                 else
-                                                       skb->dev->buffs[i] = skb->next;
-                                               break;
-                                       }
-                               }
-                               if (arp_q == skb) {
-                                       if (skb->next == skb) arp_q = NULL;
-                                         else arp_q = skb->next;
-                               }
-#else
                                skb_unlink(skb);                                
-#endif                         
                        }
                        /* Now add it to the write_queue. */
                        skb->magic = TCP_WRITE_QUEUE_MAGIC;
@@ -2272,7 +2247,7 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
                                sk->send_head, sk->send_head->h.seq, ack));
 
                /* Wake up the process, it can probably write more. */
-               if (!sk->dead) wake_up(sk->sleep);
+               if (!sk->dead) sk->write_space(sk);
 
                oskb = sk->send_head;
 
@@ -2310,7 +2285,7 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
                sti();
                oskb->magic = 0;
                kfree_skb(oskb, FREE_WRITE); /* write. */
-               if (!sk->dead) wake_up(sk->sleep);
+               if (!sk->dead) sk->write_space(sk);
        } else {
                break;
        }
@@ -2330,7 +2305,7 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
        if (sk->send_head == NULL && sk->ack_backlog == 0 &&
            sk->state != TCP_TIME_WAIT && !sk->keepopen) {
                DPRINTF((DBG_TCP, "Nothing to do, going to sleep.\n")); 
-               if (!sk->dead) wake_up(sk->sleep);
+               if (!sk->dead) sk->write_space(sk);
 
                if (sk->keepopen)
                        reset_timer(sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN);
@@ -2355,7 +2330,8 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
 
   /* See if we are done. */
   if (sk->state == TCP_TIME_WAIT) {
-       if (!sk->dead) wake_up(sk->sleep);
+       if (!sk->dead)
+               sk->state_change(sk);
        if (sk->rcv_ack_seq == sk->send_seq && sk->acked_seq == sk->fin_seq) {
                flag |= 1;
                sk->state = TCP_CLOSE;
@@ -2364,7 +2340,7 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
   }
 
   if (sk->state == TCP_LAST_ACK || sk->state == TCP_FIN_WAIT2) {
-       if (!sk->dead) wake_up(sk->sleep);
+       if (!sk->dead) sk->state_change(sk);
        if (sk->rcv_ack_seq == sk->send_seq) {
                flag |= 1;
                if (sk->acked_seq != sk->fin_seq) {
@@ -2421,13 +2397,13 @@ tcp_data(struct sk_buff *skb, struct sock *sk,
   if (sk->shutdown & RCV_SHUTDOWN) {
        sk->acked_seq = th->seq + skb->len + th->syn + th->fin;
        tcp_reset(sk->saddr, sk->daddr, skb->h.th,
-       sk->prot, NULL, skb->dev);
+       sk->prot, NULL, skb->dev, sk->ip_tos, sk->ip_ttl);
        sk->state = TCP_CLOSE;
        sk->err = EPIPE;
        sk->shutdown = SHUTDOWN_MASK;
        DPRINTF((DBG_TCP, "tcp_data: closing socket - %X\n", sk));
        kfree_skb(skb, FREE_READ);
-       if (!sk->dead) wake_up(sk->sleep);
+       if (!sk->dead) sk->state_change(sk);
        return(0);
   }
 
@@ -2523,7 +2499,7 @@ tcp_data(struct sk_buff *skb, struct sock *sk,
 
                /* When we ack the fin, we turn on the RCV_SHUTDOWN flag. */
                if (skb->h.th->fin) {
-                       if (!sk->dead) wake_up(sk->sleep);
+                       if (!sk->dead) sk->state_change(sk);
                        sk->shutdown |= RCV_SHUTDOWN;
                }
          
@@ -2541,7 +2517,7 @@ tcp_data(struct sk_buff *skb, struct sock *sk,
                                 */
                                if (skb2->h.th->fin) {
                                        sk->shutdown |= RCV_SHUTDOWN;
-                                       if (!sk->dead) wake_up(sk->sleep);
+                                       if (!sk->dead) sk->state_change(sk);
                                }
 
                                /* Force an immediate ack. */
@@ -2614,7 +2590,7 @@ tcp_data(struct sk_buff *skb, struct sock *sk,
   if (!sk->dead) {
         if(sk->debug)
                printk("Data wakeup.\n");
-       wake_up(sk->sleep);
+       sk->data_ready(sk,0);
   } else {
        DPRINTF((DBG_TCP, "data received on dead socket.\n"));
   }
@@ -2626,7 +2602,7 @@ tcp_data(struct sk_buff *skb, struct sock *sk,
 /*     tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr); */
        sk->shutdown = SHUTDOWN_MASK;
        sk->state = TCP_LAST_ACK;
-       if (!sk->dead) wake_up(sk->sleep);
+       if (!sk->dead) sk->state_change(sk);
   }
 
   return(0);
@@ -2639,7 +2615,8 @@ tcp_urg(struct sock *sk, struct tcphdr *th, unsigned long saddr)
   extern int kill_pg(int pg, int sig, int priv);
   extern int kill_proc(int pid, int sig, int priv);
     
-  if (!sk->dead) wake_up(sk->sleep);
+  if (!sk->dead) 
+       sk->data_ready(sk,0);
     
   if (sk->urginline) {
        th->urg = 0;
@@ -2662,7 +2639,7 @@ tcp_urg(struct sock *sk, struct tcphdr *th, unsigned long saddr)
 }
 
 
-/* This deals with incoming fins. */
+/* This deals with incoming fins. 'Linus at 9 O'clock' 8-) */
 static int
 tcp_fin(struct sock *sk, struct tcphdr *th, 
         unsigned long saddr, struct device *dev)
@@ -2671,7 +2648,7 @@ tcp_fin(struct sock *sk, struct tcphdr *th,
                                                sk, th, saddr, dev));
   
   if (!sk->dead) {
-       wake_up(sk->sleep);
+       sk->state_change(sk);
   }
 
   switch(sk->state) {
@@ -2813,7 +2790,7 @@ tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
   /* Put in the IP header and routing stuff. */
   /* We need to build the routing stuff fromt the things saved in skb. */
   tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
-                                       IPPROTO_TCP, NULL, MAX_SYN_SIZE);
+                                       IPPROTO_TCP, NULL, MAX_SYN_SIZE,sk->ip_tos,sk->ip_ttl);
   if (tmp < 0) {
        sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
        release_sock(sk);
@@ -2862,7 +2839,7 @@ tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
 /* This functions checks to see if the tcp header is actually acceptible. */
 static int
 tcp_sequence(struct sock *sk, struct tcphdr *th, short len,
-            struct options *opt, unsigned long saddr)
+            struct options *opt, unsigned long saddr, struct device *dev)
 {
   /*
    * This isn't quite right.  sk->acked_seq could be more recent
@@ -2882,6 +2859,19 @@ tcp_sequence(struct sock *sk, struct tcphdr *th, short len,
    }
   DPRINTF((DBG_TCP, "tcp_sequence: rejecting packet.\n"));
 
+  /*
+   *   Send a reset if we get something not ours and we are
+   *   unsynchronized. Note: We don't do anything to our end. We
+   *   are just killing the bogus remote connection then we will
+   *   connect again and it will work (with luck).
+   */
+        
+  if(sk->state==TCP_SYN_SENT||sk->state==TCP_SYN_RECV)
+  {
+       tcp_reset(sk->saddr,sk->daddr,th,sk->prot,NULL,dev, sk->ip_tos,sk->ip_ttl);
+       return(1);
+  }
+
   /*
    * If it's too far ahead, send an ack to let the
    * other end know what we expect.
@@ -2969,7 +2959,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: bad checksum\n");
                {       
                        th->seq = ntohl(th->seq);
                        /* So reset is always called with th->seq in host order */
-                       tcp_reset(daddr, saddr, th, &tcp_prot, opt,dev);
+                       tcp_reset(daddr, saddr, th, &tcp_prot, opt,dev,skb->ip_hdr->tos,255);
                }
                skb->sk = NULL;
                kfree_skb(skb, FREE_READ);
@@ -3042,7 +3032,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: bad checksum\n");
                        sk->state = TCP_CLOSE;
                        sk->shutdown = SHUTDOWN_MASK;
                        if (!sk->dead) {
-                               wake_up(sk->sleep);
+                               sk->state_change(sk);
                        }
                        kfree_skb(skb, FREE_READ);
                        release_sock(sk);
@@ -3054,7 +3044,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: bad checksum\n");
        case TCP_FIN_WAIT1:
        case TCP_FIN_WAIT2:
        case TCP_TIME_WAIT:
-               if (!tcp_sequence(sk, th, len, opt, saddr)) {
+               if (!tcp_sequence(sk, th, len, opt, saddr,dev)) {
 if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
                        if(!th->rst)
                                tcp_send_ack(sk->send_seq, sk->acked_seq, 
@@ -3077,33 +3067,32 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
                         * A reset with a fin just means that
                         * the data was not all read.
                         */
-/* The comment above appears completely bogus --clh */
-/*                     if (!th->fin) { */
-                               sk->state = TCP_CLOSE;
-                               sk->shutdown = SHUTDOWN_MASK;
-                               if (!sk->dead) {
-                                       wake_up(sk->sleep);
-                               }
-                               kfree_skb(skb, FREE_READ);
-                               release_sock(sk);
-                               return(0);
-/*                     } */
+                       sk->state = TCP_CLOSE;
+                       sk->shutdown = SHUTDOWN_MASK;
+                       if (!sk->dead) {
+                               sk->state_change(sk);
+                       }
+                       kfree_skb(skb, FREE_READ);
+                       release_sock(sk);
+                       return(0);
                }
+               if (
 #if 0
-               if (opt && (opt->security != 0 ||
-                           opt->compartment != 0 || th->syn)) {
+               if ((opt && (opt->security != 0 ||
+                           opt->compartment != 0)) || 
+#endif
+                                th->syn) {
                        sk->err = ECONNRESET;
                        sk->state = TCP_CLOSE;
                        sk->shutdown = SHUTDOWN_MASK;
-                       tcp_reset(daddr, saddr,  th, sk->prot, opt,dev);
+                       tcp_reset(daddr, saddr,  th, sk->prot, opt,dev, sk->ip_tos,sk->ip_ttl);
                        if (!sk->dead) {
-                               wake_up(sk->sleep);
+                               sk->state_change(sk);
                        }
                        kfree_skb(skb, FREE_READ);
                        release_sock(sk);
                        return(0);
                }
-#endif
                if (th->ack) {
                        if (!tcp_ack(sk, th, saddr, len)) {
                                kfree_skb(skb, FREE_READ);
@@ -3119,13 +3108,14 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
                        }
                }
 
-               if (th->fin && tcp_fin(sk, th, saddr, dev)) {
+               if (tcp_data(skb, sk, saddr, len)) {
                        kfree_skb(skb, FREE_READ);
                        release_sock(sk);
                        return(0);
                }
 
-               if (tcp_data(skb, sk, saddr, len)) {
+               /* Moved: you must do data then fin bit */
+               if (th->fin && tcp_fin(sk, th, saddr, dev)) {
                        kfree_skb(skb, FREE_READ);
                        release_sock(sk);
                        return(0);
@@ -3145,7 +3135,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
                if (!th->rst) {
                        if (!th->ack)
                                th->ack_seq = 0;
-                       tcp_reset(daddr, saddr, th, sk->prot, opt,dev);
+                       tcp_reset(daddr, saddr, th, sk->prot, opt,dev,sk->ip_tos,sk->ip_ttl);
                }
                kfree_skb(skb, FREE_READ);
                release_sock(sk);
@@ -3158,7 +3148,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
                        return(0);
                }
                if (th->ack) {
-                       tcp_reset(daddr, saddr, th, sk->prot, opt,dev);
+                       tcp_reset(daddr, saddr, th, sk->prot, opt,dev,sk->ip_tos,sk->ip_ttl);
                        kfree_skb(skb, FREE_READ);
                        release_sock(sk);
                        return(0);
@@ -3189,7 +3179,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
                return(0);
 
        default:
-               if (!tcp_sequence(sk, th, len, opt, saddr)) {
+               if (!tcp_sequence(sk, th, len, opt, saddr,dev)) {
                        kfree_skb(skb, FREE_READ);
                        release_sock(sk);
                        return(0);
@@ -3202,7 +3192,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
                        sk->shutdown = SHUTDOWN_MASK;
                        sk->zapped = 1;
                        if (!sk->dead) {
-                               wake_up(sk->sleep);
+                               sk->state_change(sk);
                        }
                        kfree_skb(skb, FREE_READ);
                        release_sock(sk);
@@ -3236,7 +3226,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
                        case TCP_SYN_SENT:
                                if (!tcp_ack(sk, th, saddr, len)) {
                                        tcp_reset(daddr, saddr, th,
-                                                       sk->prot, opt,dev);
+                                                       sk->prot, opt,dev,sk->ip_tos,sk->ip_ttl);
                                        kfree_skb(skb, FREE_READ);
                                        release_sock(sk);
                                        return(0);
@@ -3261,7 +3251,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
                        case TCP_SYN_RECV:
                                if (!tcp_ack(sk, th, saddr, len)) {
                                        tcp_reset(daddr, saddr, th,
-                                                       sk->prot, opt, dev);
+                                                       sk->prot, opt, dev,sk->ip_tos,sk->ip_ttl);
                                        kfree_skb(skb, FREE_READ);
                                        release_sock(sk);
                                        return(0);
@@ -3277,7 +3267,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
                                sk->dummy_th.dest = th->source;
                                sk->copied_seq = sk->acked_seq-1;
                                if (!sk->dead) {
-                                       wake_up(sk->sleep);
+                                       sk->state_change(sk);
                                }
 
                                /*
@@ -3354,7 +3344,7 @@ tcp_write_wakeup(struct sock *sk)
 
   /* Put in the IP header and routing stuff. */
   tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
-                               IPPROTO_TCP, sk->opt, MAX_ACK_SIZE);
+                               IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl);
   if (tmp < 0) {
        sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
        return;
@@ -3389,6 +3379,72 @@ tcp_write_wakeup(struct sock *sk)
   sk->prot->queue_xmit(sk, dev, buff, 1);
 }
 
+/*
+ *     Socket option code for TCP. 
+ */
+  
+int tcp_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen)
+{
+       int val,err;
+
+       if(level!=SOL_TCP)
+               return ip_setsockopt(sk,level,optname,optval,optlen);
+
+       if (optval == NULL) 
+               return(-EINVAL);
+
+       err=verify_area(VERIFY_READ, optval, sizeof(int));
+       if(err)
+               return err;
+       
+       val = get_fs_long((unsigned long *)optval);
+
+       switch(optname)
+       {
+               case TCP_MSS:
+                       if(val<200||val>2048)
+                               return -EINVAL;
+                       sk->mss=val;
+                       return 0;
+               case TCP_NODELAY:
+                       /* Ready for Johannes delayed ACK code */
+                       return 0;
+               default:
+                       return(-ENOPROTOOPT);
+       }
+}
+
+int tcp_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen)
+{
+       int val,err;
+
+       if(level!=SOL_TCP)
+               return ip_getsockopt(sk,level,optname,optval,optlen);
+                       
+       switch(optname)
+       {
+               case TCP_MSS:
+                       val=sk->mss;
+                       break;
+               case TCP_NODELAY:
+                       val=1;  /* Until Johannes stuff is in */
+                       break;
+               default:
+                       return(-ENOPROTOOPT);
+       }
+       err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
+       if(err)
+               return err;
+       put_fs_long(sizeof(int),(unsigned long *) optlen);
+
+       err=verify_area(VERIFY_WRITE, optval, sizeof(int));
+       if(err)
+               return err;
+       put_fs_long(val,(unsigned long *)optval);
+
+       return(0);
+}      
+
 
 struct proto tcp_prot = {
   sock_wmalloc,
@@ -3414,6 +3470,8 @@ struct proto tcp_prot = {
   tcp_ioctl,
   NULL,
   tcp_shutdown,
+  tcp_setsockopt,
+  tcp_getsockopt,
   128,
   0,
   {NULL,},
index f6540a18cf19246f355042a3baaa43ebea06165c..b5d0d136a336a43a8b7e5a4b4d07de9f065838b2 100644 (file)
@@ -141,7 +141,7 @@ net_timer (unsigned long data)
        sk->state = TCP_CLOSE;
        delete_timer (sk);
        /* Kill the ARP entry in case the hardware has changed. */
-       arp_destroy (sk->daddr);
+       arp_destroy_maybe (sk->daddr);
        if (!sk->dead)
          wake_up (sk->sleep);
        sk->shutdown = SHUTDOWN_MASK;
@@ -167,7 +167,7 @@ net_timer (unsigned long data)
          if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7))
            || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) {
            DPRINTF ((DBG_TMR, "timer.c TIME_WRITE time-out 1\n"));
-           arp_destroy (sk->daddr);
+           arp_destroy_maybe (sk->daddr);
            ip_route_check (sk->daddr);
          }
          if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) {
@@ -198,14 +198,14 @@ net_timer (unsigned long data)
        if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7))
          || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) {
          DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 1\n"));
-         arp_destroy (sk->daddr);
+         arp_destroy_maybe (sk->daddr);
          ip_route_check (sk->daddr);
          release_sock (sk);
          break;
        }
        if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) {
          DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 2\n"));
-         arp_destroy (sk->daddr);
+         arp_destroy_maybe (sk->daddr);
          sk->err = ETIMEDOUT;
          if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2) {
            sk->state = TCP_TIME_WAIT;
index 78066c3f629686d75fd2b5db8194477aa79f58ea..d6e8328a151d8bc93c07cd9e7796829e369ac93d 100644 (file)
  *                                     bug no longer crashes it.
  *             Fred Van Kempen :       Net2e support for sk->broadcast.
  *             Alan Cox        :       Uses skb_free_datagram
+ *             Alan Cox        :       Added get/set sockopt support.
+ *             Alan Cox        :       Broadcasting without option set returns EACCES.
+ *             Alan Cox        :       No wakeup calls. Instead we now use the callbacks.
+ *             Alan Cox        :       Use ip_tos and ip_ttl
  *
- * To Do:
- *             Verify all the error codes from UDP operations match the
- *             BSD behaviour, since thats effectively the formal spec.
  *
  *             This program is free software; you can redistribute it and/or
  *             modify it under the terms of the GNU General Public License
@@ -114,7 +115,7 @@ sport=%d,dport=%d", err, header, daddr, saddr, protocol, (int)th->source,(int)th
   if (err < 0)         /* As per the calling spec */
   {
        sk->err = -err;
-       wake_up(sk->sleep);     /* User process wakes to see error */
+       sk->error_report(sk);           /* User process wakes to see error */
        return;
   }
   
@@ -130,7 +131,7 @@ sport=%d,dport=%d", err, header, daddr, saddr, protocol, (int)th->source,(int)th
   if (icmp_err_convert[err & 0xff].fatal && sk->state == TCP_ESTABLISHED) {
        sk->err=ECONNREFUSED;
   }
-  wake_up(sk->sleep);
+  sk->error_report(sk);
 }
 
 
@@ -249,7 +250,7 @@ udp_send(struct sock *sk, struct sockaddr_in *sin,
   DPRINTF((DBG_UDP, "UDP: >> IP_Header: %X -> %X dev=%X prot=%X len=%d\n",
                        saddr, sin->sin_addr.s_addr, dev, IPPROTO_UDP, skb->mem_len));
   tmp = sk->prot->build_header(skb, saddr, sin->sin_addr.s_addr,
-                              &dev, IPPROTO_UDP, sk->opt, skb->mem_len);
+                              &dev, IPPROTO_UDP, sk->opt, skb->mem_len,sk->ip_tos,sk->ip_ttl);
   skb->sk=sk;  /* So memory is freed correctly */
                            
   if (tmp < 0 ) {
@@ -335,7 +336,7 @@ udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock,
   }
   
   if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
-       return -ENETUNREACH;            /* Must turn broadcast on first */
+       return -EACCES;                 /* Must turn broadcast on first */
   sk->inuse = 1;
 
   /* Send the packet. */
@@ -522,7 +523,7 @@ udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
        return(-EAFNOSUPPORT);
 
   if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
-       return -ENETUNREACH;            /* Must turn broadcast on first */
+       return -EACCES;                 /* Must turn broadcast on first */
        
   sk->daddr = sin.sin_addr.s_addr;
   sk->dummy_th.dest = sin.sin_port;
@@ -604,8 +605,9 @@ udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
 
   skb->len = len - sizeof(*uh);
 
-  if (!sk->dead) wake_up(sk->sleep);
-
+  if (!sk->dead) 
+       sk->data_ready(sk,skb->len);
+       
   release_sock(sk);
   return(0);
 }
@@ -635,6 +637,8 @@ struct proto udp_prot = {
   udp_ioctl,
   NULL,
   NULL,
+  ip_setsockopt,
+  ip_getsockopt,
   128,
   0,
   {NULL,},
index f4de8a89c14d0c4f2d295bbf4d6574daef8775ea..dff2bbeb215dac92ff702c2a6e673d430b4d8434 100644 (file)
  *
  * Fixes:
  *             Alan Cox        :       Verify Area
+ *             NET2E Team      :       Page fault locks
  *
- * BUGS
- *     Page faults on read while another process reads could lose data.
- *     Page faults on write happen to interleave data (probably not allowed)
- *     with any other simultaneous writers on the socket but dont cause harm.
+ * To Do:
+ *
+ *     Change to the NET2E3 code for Unix domain sockets in general. The
+ *     read/write logic is much better and cleaner.
  *
  *
  *             This program is free software; you can redistribute it and/or
@@ -141,6 +142,29 @@ sockaddr_un_printk(struct sockaddr_un *sockun, int sockaddr_len)
 }
   
 
+/* Support routines doing anti page fault locking 
+ * FvK & Matt Dillon (borrowed From NET2E3)
+ */
+
+/*
+ * Locking for unix-domain sockets.  We don't use the socket structure's
+ * wait queue because it is allowed to 'go away' outside of our control,
+ * whereas unix_proto_data structures stick around.
+ */
+void unix_lock(struct unix_proto_data *upd)
+{
+       while (upd->lock_flag)
+               sleep_on(&upd->wait);
+       upd->lock_flag = 1;
+}
+
+
+void unix_unlock(struct unix_proto_data *upd)
+{
+       upd->lock_flag = 0;
+       wake_up(&upd->wait);
+}
+
 /* don't have to do anything. */
 static int
 unix_proto_listen(struct socket *sock, int backlog)
@@ -598,6 +622,8 @@ unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
    * Copy from the read buffer into the user's buffer,
    * watching for wraparound. Then we wake up the writer.
    */
+   
+  unix_lock(upd);
   do {
        int part, cando;
 
@@ -612,7 +638,10 @@ unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
        dprintf(1, "UNIX: read: avail=%d, todo=%d, cando=%d\n",
                                                avail, todo, cando);
        if((er=verify_area(VERIFY_WRITE,ubuf,cando))<0)
+       {
+               unix_unlock(upd);
                return er;
+       }
        memcpy_tofs(ubuf, upd->buf + upd->bp_tail, cando);
        upd->bp_tail =(upd->bp_tail + cando) &(BUF_SIZE-1);
        ubuf += cando;
@@ -620,6 +649,7 @@ unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
        if (sock->state == SS_CONNECTED) wake_up(sock->conn->wait);
        avail = UN_BUF_AVAIL(upd);
   } while(todo && avail);
+  unix_unlock(upd);
   return(size - todo);
 }
 
@@ -666,6 +696,9 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
    * Copy from the user's buffer to the write buffer,
    * watching for wraparound. Then we wake up the reader.
    */
+   
+  unix_lock(pupd);
+  
   do {
        int part, cando;
 
@@ -681,6 +714,7 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
         */
        if (sock->state == SS_DISCONNECTING) {
                send_sig(SIGPIPE, current, 1);
+               unix_unlock(pupd);
                return(-EPIPE);
        }
        if ((cando = todo) > space) cando = space;
@@ -689,7 +723,10 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
                                                space, todo, cando);
        er=verify_area(VERIFY_READ, ubuf, cando);
        if(er)
+       {
+               unix_unlock(pupd);
                return er;
+       }
        memcpy_fromfs(pupd->buf + pupd->bp_head, ubuf, cando);
        pupd->bp_head =(pupd->bp_head + cando) &(BUF_SIZE-1);
        ubuf += cando;
@@ -697,6 +734,7 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
        if (sock->state == SS_CONNECTED) wake_up(sock->conn->wait);
        space = UN_BUF_SPACE(pupd);
   } while(todo && space);
+  unix_unlock(pupd);
   return(size - todo);
 }
 
@@ -842,6 +880,8 @@ unix_ioctl(struct inode *inode, struct file *file,
 }
 
 
+
+
 static struct file_operations unix_fops = {
   NULL,                /* LSEEK        */
   NULL,                /* READ         */
index 5b69801222aeac02f630a4fb47de49874fc38bb8..74b17778e56fea9c20bffaf9c771485e97bb8bcd 100644 (file)
@@ -35,6 +35,8 @@ struct unix_proto_data {
        int             bp_head, bp_tail;
        struct inode    *inode;
        struct unix_proto_data  *peerupd;
+       struct wait_queue *wait;        /* Lock across page faults (FvK) */
+       int             lock_flag;
 };
 
 extern struct unix_proto_data unix_datas[NSOCKETS];