]> git.neil.brown.name Git - history.git/commitdiff
Import 1.1.47 1.1.47
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:39 +0000 (15:09 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:39 +0000 (15:09 -0500)
22 files changed:
Makefile
drivers/block/blk.h
drivers/block/floppy.c
drivers/block/hd.c
drivers/char/console.c
drivers/char/kbd_kern.h
drivers/char/keyboard.c
drivers/char/n_tty.c
drivers/char/tty_io.c
drivers/scsi/NCR5380.c
drivers/scsi/constants.h
drivers/scsi/pas16.c
drivers/scsi/sr.c
fs/ext2/balloc.c
include/asm-i386/bitops.h
include/linux/ncp.h [new file with mode: 0644]
include/linux/socket.h
net/inet/datagram.c
net/inet/ipx.c
net/inet/ncp.h [new file with mode: 0644]
net/inet/sock.h
net/socket.c

index 06004edd4ce5351beb05ae5dd57349df781bb680..c255661ffd0dab82547b2bca5cd411d045e89a6b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 46
+SUBLEVEL = 47
 
 ARCH = i386
 
index c4bf1c34a343126f64e9cf5fc3c1ea8bff239a53..35bff8c4e8e4528dd3f76a28c9d927f19ab58850 100644 (file)
@@ -223,10 +223,6 @@ static void floppy_off(unsigned int nr);
 #define DEVICE_ON(device)
 #define DEVICE_OFF(device)
 
-#else
-
-#error "unknown blk device"
-
 #endif
 
 #if (MAJOR_NR != SCSI_TAPE_MAJOR)
index 8cf568b560c1876a39e3a2cda52a2389bac230dc..6cee5470aee9a0b2c1059db0990eb04a2828255c 100644 (file)
@@ -231,7 +231,7 @@ static struct {
 {{3,  250, 16, 16, 3000, 100, 300,  0, 2, 5,  83, 3*HZ, 20, {3,1,2,0,2}, 0,
       0, { 4,22,21,30, 3, 0, 0, 0}, 150, 4 }, "720k" }, /*3 1/2 DD*/
 
-{{4,  500, 16, 16, 3000,  40, 300, 10, 2, 5,  83, 3*HZ, 20, {3,1,2,0,2}, 0,
+{{4,  500, 16, 16, 4000,  40, 300, 10, 2, 5,  83, 3*HZ, 20, {3,1,2,0,2}, 0,
       0, { 7, 4,25,22,31,21,29,11}, 150, 7 }, "1.44M" }, /*3 1/2 HD*/
 
 {{5, 1000, 15,  8, 3000,  40, 300, 10, 2, 5,  83, 3*HZ, 40, {3,1,2,0,2}, 0,
index 6dddcfaf36e718d9de5cde73b71eebafa8fa469a..c13d4e697c26ffb5b7206ae00a8c723f9987ec6f 100644 (file)
@@ -866,6 +866,7 @@ static int hd_ioctl(struct inode * inode, struct file * file,
                        if (err)
                                return err;
                        memcpy_tofs((char *)arg, (char *) hd_ident_info[dev], sizeof(struct hd_driveid));
+                       return 0;
 
                RO_IOCTLS(inode->i_rdev,arg);
                default:
index 213daad3c84219bd788311cb25dce477e0342b0c..2657e6e8a57c5e37d98c236b3f29951c36462aa6 100644 (file)
@@ -1457,13 +1457,13 @@ void poke_blanked_console(void)
        }
 }
 
-void * memsetw(void * s,unsigned short c,int count)
+void * memsetw(void * s, unsigned short c, unsigned int count)
 {
 __asm__("cld\n\t"
        "rep\n\t"
        "stosw"
        : /* no output */
-       :"a" (c),"D" (s),"c" (count)
+       :"a" (c),"D" (s),"c" (count/2)
        :"cx","di");
 return s;
 }
index 7253c8cbea3b3ef342b3073e4acb8a07d84a86ff..4f852725c602953183d1113dd815558a06f55107 100644 (file)
  * Note: lockstate is used as index in the array key_map.
  */
 struct kbd_struct {
-       unsigned char ledstate;         /* 3 bits */
+        unsigned char ledstate;                /* 3 bits */
        unsigned char default_ledstate;
-       unsigned char lockstate;        /* 3 bits */ 
 #define VC_SCROLLOCK   0       /* scroll-lock mode */
 #define VC_NUMLOCK     1       /* numeric lock mode */
 #define VC_CAPSLOCK    2       /* capslock mode */
 
+       unsigned char lockstate;        /* 4 bits - must be in 0..15 */
+#define VC_SHIFTLOCK   KG_SHIFT        /* shift lock mode */
+#define VC_ALTGRLOCK   KG_ALTGR        /* altgr lock mode */
+#define VC_CTRLLOCK    KG_CTRL         /* control lock mode */
+#define VC_ALTLOCK     KG_ALT          /* alt lock mode */
 
        unsigned char modeflags;
 #define VC_APPLIC      0       /* application key mode */
index 739507d1f07a1e2e5b197541cba82993d03fcde8..698ed92cd9f89bf0ebbaaf436289a372a479ec1e 100644 (file)
@@ -344,15 +344,15 @@ static void keyboard_interrupt(int int_pt_regs)
                u_char type;
 
                /* the XOR below used to be an OR */
-               int shift_final = shift_state ^ vc_kbd_lock(kbd,VC_CAPSLOCK);
+               int shift_final = shift_state ^ kbd->lockstate;
 
                key_code = key_map[shift_final][scancode];
                type = KTYP(key_code);
 
                if (type == KT_LETTER) {
                    type = KT_LATIN;
-                   if (vc_kbd_lock(kbd,VC_CAPSLOCK))
-                       key_code = key_map[shift_final][scancode];
+                   if (vc_kbd_led(kbd,VC_CAPSLOCK))
+                       key_code = key_map[shift_final ^ (1<<KG_SHIFT)][scancode];
                }
                (*key_handler[type])(key_code & 0xff, up_flag);
        }
@@ -404,7 +404,6 @@ static void caps_toggle(void)
        if (rep)
                return;
        chg_vc_kbd_led(kbd,VC_CAPSLOCK);
-       chg_vc_kbd_lock(kbd,VC_CAPSLOCK);
 }
 
 static void caps_on(void)
@@ -412,7 +411,6 @@ static void caps_on(void)
        if (rep)
                return;
        set_vc_kbd_led(kbd,VC_CAPSLOCK);
-       set_vc_kbd_lock(kbd,VC_CAPSLOCK);
 }
 
 static void show_ptregs(void)
@@ -463,10 +461,8 @@ static void num(void)
                applkey('P', 1);
                return;
        }
-       if (!rep) {     /* no autorepeat for numlock, ChN */
+       if (!rep)       /* no autorepeat for numlock, ChN */
                chg_vc_kbd_led(kbd,VC_NUMLOCK);
-               chg_vc_kbd_lock(kbd,VC_NUMLOCK);
-       }
 }
 
 static void lastcons(void)
@@ -647,7 +643,8 @@ static void do_pad(unsigned char value, char up_flag)
                applkey(app_map[value], 1);
                return;
        }
-       if (!vc_kbd_lock(kbd,VC_NUMLOCK))
+
+       if (!vc_kbd_led(kbd,VC_NUMLOCK))
                switch (value) {
                        case KVAL(K_PCOMMA):
                        case KVAL(K_PDOT):
@@ -709,10 +706,8 @@ static void do_shift(unsigned char value, char up_flag)
        /* kludge... */
        if (value == KVAL(K_CAPSSHIFT)) {
                value = KVAL(K_SHIFT);
-               if (!up_flag) {
+               if (!up_flag)
                        clr_vc_kbd_led(kbd, VC_CAPSLOCK);
-                       clr_vc_kbd_lock(kbd, VC_CAPSLOCK);
-               }
        }
 
        if (up_flag) {
index b0313fd96b83d5d84263b9a2819303f67df6b0b5..11189111812d866eff3bd490fda5b6edeea91c6d 100644 (file)
@@ -931,9 +931,9 @@ static int write_chan(struct tty_struct * tty, struct file * file,
                                if (opost(c, tty) < 0)
                                        break;
                                b++; nr--;
-                               if (tty->driver.flush_chars)
-                                       tty->driver.flush_chars(tty);
                        }
+                       if (tty->driver.flush_chars)
+                               tty->driver.flush_chars(tty);
                } else {
                        c = tty->driver.write(tty, 1, b, nr);
                        b += c;
index fef159189b47ce3949957a455665b38e643d04fe..57cfa0c5407d934084a6a2cf4a6b8c3ff780c050 100644 (file)
@@ -1535,8 +1535,10 @@ int tty_register_driver(struct tty_driver *driver)
                return 0;
 
        error = register_chrdev(driver->major, driver->name, &tty_fops);
-       if (error)
+       if (error < 0)
                return error;
+       else if(driver->major == 0)
+               driver->major = error;
 
        if (!driver->put_char)
                driver->put_char = tty_default_put_char;
@@ -1545,7 +1547,7 @@ int tty_register_driver(struct tty_driver *driver)
        driver->next = tty_drivers;
        tty_drivers->prev = driver;
        tty_drivers = driver;
-       return 0;
+       return error;
 }
 
 /*
@@ -1589,7 +1591,7 @@ long tty_init(long kmem_start)
                panic("size of tty structure > PAGE_SIZE!");
        if (register_chrdev(TTY_MAJOR,"tty",&tty_fops))
                panic("unable to get major %d for tty device", TTY_MAJOR);
-       if (register_chrdev(TTYAUX_MAJOR,"tty",&tty_fops))
+       if (register_chrdev(TTYAUX_MAJOR,"cua",&tty_fops))
                panic("unable to get major %d for tty device", TTYAUX_MAJOR);
 
        kmem_start = kbd_init(kmem_start);
index a0b8b40aca1a895abba0142ac046b1694e587a83..925a616307193ddaa6656da55b5536237ac3da1c 100644 (file)
  * DIFFERENTIAL - if defined, NCR53c81 chips will use external differential
  *     transceivers. 
  *
+ * LIMIT_TRANSFERSIZE - if defined, limit the pseudo-dma transfers to 512
+ *     bytes at a time.  Since interrupts are disabled by default during
+ *     these transfers, we might need this to give reasonable interrupt
+ *     service time if the transfer size gets too large.
+ *
  * LINKED - if defined, linked commands are supported.
  *
  * PSEUDO_DMA - if defined, PSEUDO DMA is used during the data transfer phases.
@@ -1980,10 +1985,16 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) {
                if (!cmd->device->borken &&
                    (transfersize = NCR5380_dma_xfer_len(instance, cmd)) != 0) {
 #else
-               if (!cmd->device->borken && 
-                   (transfersize = cmd->transfersize) && 
-                   cmd->SCp.this_residual && !(cmd->SCp.this_residual % 
-                   transfersize)) {
+                transfersize = cmd->transfersize;
+
+#ifdef LIMIT_TRANSFERSIZE  /* If we have problems with interrupt service */
+                if( transfersize > 512 )
+                    transfersize = 512;
+#endif  /* LIMIT_TRANSFERSIZE */
+
+                if (!cmd->device->borken && transfersize && 
+                    cmd->SCp.this_residual && !(cmd->SCp.this_residual % 
+                    transfersize)) {
 #endif
                    len = transfersize;
                    if (NCR5380_transfer_dma(instance, &phase,
index d3db95b8c5217c183512249454c851051fff90aa..f40f300ac2567fb1e9da7ceca820c57b35e6d2e7 100644 (file)
@@ -4,4 +4,5 @@ extern void print_command(unsigned char *);
 extern int print_msg(unsigned char *);
 extern void print_sense(char *,  Scsi_Cmnd *);
 extern void print_status(int);
+extern void print_Scsi_Cmnd (Scsi_Cmnd *);
 #endif /* def _CONSTANTS_H */
index e8fdb651ec8931ead08cad9fc8264aa5352869c3..5dad9529c84ff7ffffc785651fdfc155080c8b2f 100644 (file)
@@ -1,5 +1,7 @@
 #define AUTOSENSE
 #define PSEUDO_DMA
+#define FOO
+#define UNSAFE  /* Not unsafe for PAS16 -- use it */
 
 /*
  * This driver adapted from Drew Eckhardt's Trantor T128 driver
  * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
  *      for commands that return with a CHECK CONDITION status. 
  *
+ * LIMIT_TRANSFERSIZE - if defined, limit the pseudo-dma transfers to 512
+ *      bytes at a time.  Since interrupts are disabled by default during
+ *      these transfers, we might need this to give reasonable interrupt
+ *      service time if the transfer size gets too large.
+ *
  * PSEUDO_DMA - enables PSEUDO-DMA hardware, should give a 3-4X performance
  * increase compared to polled I/O.
  *
  * 
  * SCSI2 - enable support for SCSI-II tagged queueing.  Untested.
  *
- *
- * UNSAFE - leave interrupts enabled during pseudo-DMA transfers.  You
- *          only really want to use this if you're having a problem with
- *          dropped characters during high speed communications, and even
- *          then, you're going to be better off twiddling with transfersize.
+ * UNSAFE - leave interrupts enabled during pseudo-DMA transfers.  This
+ *         parameter comes from the NCR5380 code.  It is NOT unsafe with
+ *         the PAS16 and you should use it.  If you don't you will have
+ *         a problem with dropped characters during high speed
+ *         communications during SCSI transfers.  If you really don't
+ *         want to use UNSAFE you can try defining LIMIT_TRANSFERSIZE or
+ *         twiddle with the transfer size in the high level code.
  *
  * USLEEP - enable support for devices that don't disconnect.  Untested.
  *
@@ -242,7 +251,7 @@ void        init_board( unsigned short io_port, int irq, int force_irq )
 int     pas16_hw_detect( unsigned short  board_num )
 {
     unsigned char      board_rev, tmp;
-    unsigned short     port = bases[ board_num ].io_port;
+    unsigned short     io_port = bases[ board_num ].io_port;
 
     /* See if we can find a PAS16 board at the address associated
      * with this logical board number.
@@ -251,26 +260,39 @@ int     pas16_hw_detect( unsigned short  board_num )
     /* First, attempt to take a newer model board out of reset and
      * give it a base address.  This shouldn't affect older boards.
      */
-    enable_board( board_num, port );
+    enable_board( board_num, io_port );
 
     /* Now see if it looks like a PAS16 board */
-    board_rev = inb( port + PCB_CONFIG );
+    board_rev = inb( io_port + PCB_CONFIG );
 
     if( board_rev == 0xff )
        return 0;
 
     tmp = board_rev ^ 0xe0;
 
-    outb( tmp, port + PCB_CONFIG );
-    tmp = inb( port + PCB_CONFIG );
-    outb( board_rev, port + PCB_CONFIG );
+    outb( tmp, io_port + PCB_CONFIG );
+    tmp = inb( io_port + PCB_CONFIG );
+    outb( board_rev, io_port + PCB_CONFIG );
 
     if( board_rev != tmp )     /* Not a PAS-16 */
        return 0;
 
-    if( ( inb( port + OPERATION_MODE_1 ) & 0x03 ) != 0x03 ) 
+    if( ( inb( io_port + OPERATION_MODE_1 ) & 0x03 ) != 0x03 ) 
        return 0;       /* return if no SCSI interface found */
 
+    /* Mediavision has some new model boards that return ID bits
+     * that indicate a SCSI interface, but they're not (LMS).  We'll
+     * put in an additional test to try and weed them out.
+     */
+
+    outb( 0x01, io_port + WAIT_STATE );        /* 1 Wait state */
+    NCR5380_write( MODE_REG, 0x20 );           /* Is it really SCSI? */
+    if( NCR5380_read( MODE_REG ) != 0x20 )     /* Write to a reg.    */
+       return 0;                               /* and try to read    */
+    NCR5380_write( MODE_REG, 0x00 );           /* it back.           */
+    if( NCR5380_read( MODE_REG ) != 0x00 )
+       return 0;
+
     return 1;
 }
 
@@ -426,7 +448,15 @@ int pas16_biosparam(Disk * disk, int dev, int * ip)
   int size = disk->capacity;
   ip[0] = 64;
   ip[1] = 32;
-  ip[2] = size >> 11;
+  ip[2] = size >> 11;          /* I think I have it as /(32*64) */
+  if( ip[2] > 1024 ) {         /* yes, >, not >= */
+        ip[0]=255;
+        ip[1]=63;
+        ip[2]=size/(63*255);
+        if( ip[2] > 1023 )     /* yes >1023... */
+                ip[2] = 1023;
+  }
+
   return 0;
 }
 
index e1b450b3958b8a0b0b43c34ead3d48e7d2afdc38..2b04d78201fb5a0d7b57e0d8b76cb7e3ac52f5a0 100644 (file)
@@ -627,7 +627,20 @@ are any multiple of 512 bytes long.  */
          printk("\n");
        };
 #endif
-       
+
+/* Some dumb host adapters can speed transfers by knowing the
+ * minimum tranfersize in advance.
+ *
+ * We shouldn't disconnect in the middle of a sector, but the cdrom
+ * sector size can be larger than the size of a buffer and the
+ * transfer may be split to the size of a buffer.  So it's safe to
+ * assume that we can at least transfer the minimum of the buffer
+ * size (1024) and the sector size between each connect / disconnect.
+ */
+
+        SCpnt->transfersize = (scsi_CDs[dev].sector_size > 1024) ?
+                        1024 : scsi_CDs[dev].sector_size;
+
        SCpnt->this_count = this_count;
        scsi_do_cmd (SCpnt, (void *) cmd, buffer, 
                     realcount * scsi_CDs[dev].sector_size, 
index 60655968a14602a6edb72ae856defdfaba465127..0b09426af102e70e18d0f11a5de6ea6fac70f614 100644 (file)
@@ -316,10 +316,7 @@ repeat:
                        else
                                lmap |= 0xffffffff << (31 - (j & 31));
                        if (lmap != 0xffffffffl) {
-                               __asm__ ("bsfl %1,%0"
-                                        : "=r" (k)
-                                        : "r" (~lmap));
-                               k++;
+                               k = ffz(lmap) + 1;
                                if ((j + k) < EXT2_BLOCKS_PER_GROUP(sb)) {
                                        j += k;
                                        goto got_block;
index fd417b810941257ae8eca3b27f90cab86418669a..5e2c324cd56f9b810b3ddf3b24b5ba9764b2c692 100644 (file)
@@ -121,4 +121,16 @@ extern inline int find_next_zero_bit (unsigned long * addr, int size,
        return (offset + set + res);
 }
 
+/*
+ * ffz = Find First Zero in word. Undefined if no zero exists,
+ * so code should check against ~0UL first..
+ */
+extern inline unsigned long ffz(unsigned long word)
+{
+       __asm__("bsfl %1,%0"
+               :"=r" (word)
+               :"r" (~word));
+       return word;
+}
+
 #endif /* _I386_BITOPS_H */
diff --git a/include/linux/ncp.h b/include/linux/ncp.h
new file mode 100644 (file)
index 0000000..bd6daf2
--- /dev/null
@@ -0,0 +1,106 @@
+#ifndef _LINUX_NCP_H_
+#define _LINUX_NCP_H_
+
+#define NCP_OPEN       0x1111
+#define NCP_CLOSE      0x5555
+#define NCP_REQUEST    0x2222
+#define NCP_REPLY      0x3333
+
+struct ncp_request
+{
+       unsigned short  p_type                  __attribute__ ((packed));
+       unsigned char   seq                     __attribute__ ((packed));
+       unsigned char   c_low                   __attribute__ ((packed));
+       unsigned char   task                    __attribute__ ((packed));
+       unsigned char   c_high                  __attribute__ ((packed));
+       unsigned char   func                    __attribute__ ((packed));
+};
+
+struct ncp_request_sf
+{
+       unsigned short  p_type                  __attribute__ ((packed));
+       unsigned char   seq                     __attribute__ ((packed));
+       unsigned char   c_low                   __attribute__ ((packed));
+       unsigned char   task                    __attribute__ ((packed));
+       unsigned char   c_high                  __attribute__ ((packed));
+       unsigned char   func                    __attribute__ ((packed));
+       unsigned short  s_len                   __attribute__ ((packed));
+       unsigned char   s_func                  __attribute__ ((packed));
+};
+
+struct ncp_reply
+{
+       unsigned short  p_type                  __attribute__ ((packed));
+       unsigned char   seq                     __attribute__ ((packed));
+       unsigned char   c_low                   __attribute__ ((packed));
+       unsigned char   task                    __attribute__ ((packed));
+       unsigned char   c_high                  __attribute__ ((packed));
+       unsigned char   f_stat                  __attribute__ ((packed));
+       unsigned char   c_stat                  __attribute__ ((packed));
+};
+
+#define OTYPE_USER             0x0001
+#define OTYPE_GROUP            0x0002
+#define OTYPE_PQUEUE           0x0003
+#define OTYPE_FSERVER          0x0004
+#define OTYPE_JSERVER          0x0005
+#define OTYPE_PSERVER          0x0007
+#define OTYPE_UNKNOWN_1                0x002E
+#define OTYPE_ADV_PSERVER      0x0047
+#define OTYPE_AFSERVER         0x0107
+#define OTYPE_UNKNOWN_2                0x0143
+#define OTYPE_UNKNOWN_3                0x01F5
+#define OTYPE_UNKNOWN_4                0x023F
+
+#define LIMIT_OBJNAME  47
+
+struct bind_obj
+{
+       unsigned long   id                      __attribute__ ((packed));
+       unsigned short  type                    __attribute__ ((packed));
+       char            name[LIMIT_OBJNAME+1]   __attribute__ ((packed));
+};
+
+struct get_bind_obj
+{
+       unsigned short  type                    __attribute__ ((packed));
+       unsigned char   n_len                   __attribute__ ((packed));
+       char            name[0]                 __attribute__ ((packed));
+};
+
+struct scan_bind_obj
+{
+       unsigned long   id                      __attribute__ ((packed));
+       unsigned short  type                    __attribute__ ((packed));
+       unsigned char   n_len                   __attribute__ ((packed));
+       char            name[0]                 __attribute__ ((packed));
+};
+
+struct login_req
+{
+       unsigned char   password[8]             __attribute__ ((packed));
+       unsigned short  type                    __attribute__ ((packed));
+       unsigned char   n_len                   __attribute__ ((packed));
+       char            name[0]                 __attribute__ ((packed));
+};
+
+struct ncp_time
+{
+       unsigned char   year                    __attribute__ ((packed));
+       unsigned char   month                   __attribute__ ((packed));
+       unsigned char   day                     __attribute__ ((packed));
+       unsigned char   hours                   __attribute__ ((packed));
+       unsigned char   mins                    __attribute__ ((packed));
+       unsigned char   secs                    __attribute__ ((packed));
+       unsigned char   c_secs                  __attribute__ ((packed));
+};
+
+struct login_info
+{
+       unsigned long   id                      __attribute__ ((packed));
+       unsigned short  un1                     __attribute__ ((packed));
+       char            name[LIMIT_OBJNAME+1]   __attribute__ ((packed));
+       struct ncp_time time                    __attribute__ ((packed));
+};
+#endif
+
index 08cb0f9016970f87fa9b51f86b58f8b781076c7f..71de245419a47ea75a3f6cb2886f741112823b51 100644 (file)
@@ -20,6 +20,7 @@ struct linger {
 #define SOCK_RAW       3               /* raw socket                   */
 #define SOCK_RDM       4               /* reliably-delivered message   */
 #define SOCK_SEQPACKET 5               /* sequential packet socket     */
+#define SOCK_NCP       6               /* Novell NCP socket            */
 #define SOCK_PACKET    10              /* linux specific way of        */
                                        /* getting packets at the dev   */
                                        /* level.  For writing rarp and */
index 116c16e3e752813463c0183a81025b6f88e56401..998a978136aa52c6e470586b64584c63645bd90a 100644 (file)
@@ -177,7 +177,8 @@ int datagram_select(struct sock *sk, int sel_type, select_table *wait)
        switch(sel_type)
        {
                case SEL_IN:
-                       if (sk->type==SOCK_SEQPACKET && sk->state==TCP_CLOSE)
+                       if ((sk->type==SOCK_SEQPACKET || sk->type==SOCK_NCP)
+                               && sk->state==TCP_CLOSE)
                        {
                                /* Connection closed: Wake up */
                                return(1);
index 1578707839f8c35cc7323e57e2030da199fa4870..ca0d8c0ea27f62fe996610fbeeba47b4df052469 100644 (file)
 #include <linux/termios.h>     /* For TIOCOUTQ/INQ */
 #include <linux/interrupt.h>
 #include "p8022.h"
+#include "ncp.h"
 
 #ifdef CONFIG_IPX
+
+static void ipx_delete_timer (ipx_socket *sk);
+static int ipx_do_sendto(ipx_socket *sk, ipx_address *ipx,
+                        void *ubuf, int len, int flag, unsigned char type);
+static void ipx_add_timer (ipx_socket *sk, int len);
+static void ipx_reset_timer (ipx_socket *sk, int len);
+
 /***********************************************************************************************************************\
 *                                                                                                                      *
 *                                              Handlers for the socket list.                                           *
@@ -75,7 +83,9 @@ static ipx_socket *volatile ipx_socket_list=NULL;
 static void ipx_remove_socket(ipx_socket *sk)
 {
        ipx_socket *s;
+       unsigned long flags;
        
+       save_flags(flags);
        cli();
        s=ipx_socket_list;
        if(s==sk)
@@ -89,20 +99,23 @@ static void ipx_remove_socket(ipx_socket *sk)
                if(s->next==sk)
                {
                        s->next=sk->next;
-                       sti();
+                       restore_flags(flags);
                        return;
                }
                s=s->next;
        }
-       sti();
+       restore_flags(flags);
 }
 
 static void ipx_insert_socket(ipx_socket *sk)
 {
+       unsigned long flags;
+       
+       save_flags(flags);
        cli();
        sk->next=ipx_socket_list;
        ipx_socket_list=sk;
-       sti();
+       restore_flags(flags);
 }
 
 static ipx_socket *ipx_find_socket(int port)
@@ -133,9 +146,10 @@ static void ipx_destroy_socket(ipx_socket *sk)
        ipx_remove_socket(sk);
        
        while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
-       {
                kfree_skb(skb,FREE_READ);
-       }
+       
+       while((skb=skb_dequeue(&sk->write_queue))!=NULL)
+               kfree_skb(skb,FREE_WRITE);
        
        kfree_s(sk,sizeof(*sk));
 }
@@ -151,20 +165,24 @@ int ipx_get_info(char *buffer, char **start, off_t offset, int length)
 
        /* Theory.. Keep printing in the same place until we pass offset */
        
-       len += sprintf (buffer,"Type local_address             rem_address              tx_queue rx_queue st uid\n");
+       len += sprintf (buffer,"   local_address              rem_address                tx_queue rx_queue st uid\n");
        for (s = ipx_socket_list; s != NULL; s = s->next)
        {
-               len += sprintf (buffer+len,"%02X   ", s->ipx_type);
-               len += sprintf (buffer+len,"%08lX:%02X%02X%02X%02X%02X%02X:%02X ", htonl(s->ipx_source_addr.net),
+               len += sprintf (buffer+len,"%02X ", s->ipx_type);
+               len += sprintf (buffer+len,"%08lX:%02X%02X%02X%02X%02X%02X:%04X ", htonl(s->ipx_source_addr.net),
                        s->ipx_source_addr.node[0], s->ipx_source_addr.node[1], s->ipx_source_addr.node[2],
                        s->ipx_source_addr.node[3], s->ipx_source_addr.node[4], s->ipx_source_addr.node[5],
                        htons(s->ipx_source_addr.sock));
-               len += sprintf (buffer+len,"%08lX:%02X%02X%02X%02X%02X%02X:%02X ", htonl(s->ipx_dest_addr.net),
+               len += sprintf (buffer+len,"%08lX:%02X%02X%02X%02X%02X%02X:%04X ", htonl(s->ipx_dest_addr.net),
                        s->ipx_dest_addr.node[0], s->ipx_dest_addr.node[1], s->ipx_dest_addr.node[2],
                        s->ipx_dest_addr.node[3], s->ipx_dest_addr.node[4], s->ipx_dest_addr.node[5],
                        htons(s->ipx_dest_addr.sock));
                len += sprintf (buffer+len,"%08lX:%08lX ", s->wmem_alloc, s->rmem_alloc);
-               len += sprintf (buffer+len,"%02X %d\n", s->state, SOCK_INODE(s->socket)->i_uid);
+               len += sprintf (buffer+len,"%02X ", s->state);
+               if (s->socket)
+                       len += sprintf (buffer+len,"%d\n", SOCK_INODE(s->socket)->i_uid);
+               else
+                       len += sprintf (buffer+len,"%d\n", SOCK_INODE(s->ncp.ncp->socket)->i_uid);
                
                /* Are we still dumping unwanted data then discard the record */
                pos=begin+len;
@@ -566,20 +584,56 @@ static void def_callback2(struct sock *sk, int len)
                wake_up_interruptible(sk->sleep);
 }
 
-static int ipx_create(struct socket *sock, int protocol)
+static void watch_callback(struct sock *sk, int len)
 {
-       ipx_socket *sk;
-       sk=(ipx_socket *)kmalloc(sizeof(*sk),GFP_KERNEL);
-       if(sk==NULL)
-               return(-ENOMEM);
-       switch(sock->type)
+       ipx_packet      *ipx;
+       struct sk_buff *skb;
+       char *data;
+
+       skb=skb_dequeue(&sk->receive_queue);
+       if(skb==NULL)
+               return; 
+
+       ipx = (ipx_packet *)(skb->h.raw);
+       data = (char *)(ipx+1);
+
+        if (*(data+1) == '?')
+               ipx_do_sendto(sk,&(ipx->ipx_source),"\0Y",2,0,sk->ipx_type);
+
+       kfree_skb(skb, FREE_READ);
+}
+
+static void mail_callback(struct sock *sk, int len)
+{
+       ipx_packet      *ipx;
+       struct sk_buff *skb;
+       char *data;
+
+       skb=skb_dequeue(&sk->receive_queue);
+       if(skb==NULL)
+               return; 
+
+       ipx = (ipx_packet *)(skb->h.raw);
+       data = (char *)(ipx+1);
+        if (*(data+1) == '!')
        {
-               case SOCK_DGRAM:
-                       break;
-               default:
-                       kfree_s((void *)sk,sizeof(*sk));
-                       return(-ESOCKTNOSUPPORT);
+               struct ncp_request_sf req;
+
+               req.func=0x15;
+               req.s_func=0x01;
+               req.s_len=htons(1);
+
+               ipx_do_sendto(sk->ncp.ncp, &(sk->ncp.ncp->ipx_dest_addr),
+                               &req, sizeof(req), 0,sk->ncp.ncp->ipx_type);
        }
+
+       kfree_skb(skb, FREE_READ);
+
+}
+
+static void ipx_do_create(struct socket *sock, ipx_socket *sk)
+{
+
        sk->dead=0;
        sk->next=NULL;
        sk->broadcast=0;
@@ -598,7 +652,6 @@ static int ipx_create(struct socket *sock, int protocol)
        skb_queue_head_init(&sk->back_log);
        sk->state=TCP_CLOSE;
        sk->socket=sock;
-       sk->type=sock->type;
        sk->ipx_type=0;         /* General user level IPX */
        sk->debug=0;
        
@@ -610,14 +663,76 @@ static int ipx_create(struct socket *sock, int protocol)
        {
                sock->data=(void *)sk;
                sk->sleep=sock->wait;
+               sk->type=sock->type;
        }
+       else
+               sk->type=SOCK_DGRAM;
        
+       sk->priority=SOPRI_NORMAL;
        sk->state_change=def_callback1;
        sk->data_ready=def_callback2;
        sk->write_space=def_callback1;
        sk->error_report=def_callback1;
 
        sk->zapped=1;
+
+       return;
+}
+
+static int ncp_create(struct socket *sock, int protocol)
+{
+       ipx_socket *sk;
+       ipx_socket *skw;
+       ipx_socket *skm;
+
+       if ((sk=(ipx_socket *)kmalloc(sizeof(*sk),GFP_KERNEL))==NULL)
+               return(-ENOMEM);
+
+       if ((skw=(ipx_socket *)kmalloc(sizeof(*skw),GFP_KERNEL))==NULL)
+       {
+               kfree_s((void *)sk, sizeof(*sk));
+               return(-ENOMEM);
+       }
+
+       if ((skm=(ipx_socket *)kmalloc(sizeof(*skm),GFP_KERNEL))==NULL)
+       {
+               kfree_s((void *)skw, sizeof(*skw));
+               kfree_s((void *)sk, sizeof(*sk));
+               return(-ENOMEM);
+       }
+
+       ipx_do_create(sock, sk);
+       sk->ncp.ncp=NULL;
+       sk->ncp.watchdog=skw;
+       sk->ncp.mail=skm;
+       ipx_do_create(NULL, skw);
+       skw->ncp.ncp=sk;
+       skw->data_ready=watch_callback;
+       ipx_do_create(NULL, skm);
+       skm->ncp.ncp=sk;
+       skm->data_ready=mail_callback;
+       
+       return(0);
+}
+
+static int ipx_create(struct socket *sock, int protocol)
+{
+       ipx_socket *sk;
+
+       switch(sock->type)
+       {
+               case SOCK_DGRAM:
+                       break;
+               case SOCK_NCP:
+                       return(ncp_create(sock, protocol));
+               default:
+                       return(-ESOCKTNOSUPPORT);
+       }
+       if ((sk=(ipx_socket *)kmalloc(sizeof(*sk),GFP_KERNEL))==NULL)
+               return(-ENOMEM);
+
+       ipx_do_create(sock, sk);
+
        return(0);
 }
 
@@ -633,47 +748,79 @@ static int ipx_release(struct socket *sock, struct socket *peer)
                return(0);
        if(!sk->dead)
                sk->state_change(sk);
-       sk->dead=1;
+
        sock->data=NULL;
-       ipx_destroy_socket(sk);
+
+       if (sk->type == SOCK_NCP)
+       {
+               sk->ncp.watchdog->dead=1;
+               ipx_destroy_socket(sk->ncp.watchdog);
+               sk->ncp.mail->dead=1;
+               ipx_destroy_socket(sk->ncp.mail);
+
+               if ((sk->state == TCP_ESTABLISHED) || (sk->state == TCP_SYN_SENT))
+               {
+                       struct ncp_request req;
+               
+                       sk->state=TCP_CLOSE_WAIT;
+       
+                       ipx_do_sendto(sk, &(sk->ipx_dest_addr), &req,
+                                        sizeof(req), 0, sk->ipx_type);
+               }
+               else
+               {
+                       sk->dead=1;
+                       if (sk->state != TCP_CLOSE)
+                               ipx_delete_timer(sk);
+                       ipx_destroy_socket(sk);
+               }
+       }
+       else
+       {
+               sk->dead=1;
+               ipx_destroy_socket(sk);
+       }
        return(0);
 }
                
 static unsigned short first_free_socketnum(void)
 {
-       static unsigned short   socketNum = 0x4000;
+       static unsigned short   socketNum = 0x3fff;
 
-       while (ipx_find_socket(htons(socketNum)) != NULL)
-               if (socketNum > 0x7ffc) socketNum = 0x4000;
+       while (ipx_find_socket(htons(++socketNum)) != NULL)
+               if (socketNum > 0x7ffc) socketNum = 0x3fff;
 
-       return  htons(socketNum++);
+       return  htons(socketNum);
 }
        
 static int ipx_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len)
 {
-       ipx_socket *sk;
+       ipx_socket *sk=(ipx_socket *)sock->data;
        struct ipx_route *rt;
        unsigned char   *nodestart;
        struct sockaddr_ipx *addr=(struct sockaddr_ipx *)uaddr;
        
-       sk=(ipx_socket *)sock->data;
-       
        if(sk->zapped==0)
                return(-EIO);
                
        if(addr_len!=sizeof(struct sockaddr_ipx))
                return -EINVAL;
        
+
        if (addr->sipx_port == 0) 
        {
                addr->sipx_port = first_free_socketnum();
+               if (sk->type == SOCK_NCP)
+                       while ((ipx_find_socket(htons(ntohs(addr->sipx_port)+1)))
+                               || (ipx_find_socket(htons(ntohs(addr->sipx_port)+2))))
+                               addr->sipx_port = first_free_socketnum();
                if (addr->sipx_port == 0)
                        return -EINVAL;
        }
                
        if(ntohs(addr->sipx_port)<0x4000 && !suser())
                return(-EPERM); /* protect IPX system stuff like routing/sap */
-       
+
        /* Source addresses are easy. It must be our network:node pair for
           an interface routed to IPX with the ipx routing ioctl() */
 
@@ -685,6 +832,19 @@ static int ipx_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len)
                return -EADDRINUSE;        
        }
 
+       if (sk->type == SOCK_NCP)
+       {
+               if ((ipx_find_socket(htons(ntohs(addr->sipx_port)+1)))
+                       || (ipx_find_socket(htons(ntohs(addr->sipx_port)+2))))
+               {
+                       if(sk->debug)
+                               printk("IPX: bind failed because port %X in use.\n",
+                               (int)addr->sipx_port);
+                       return -EADDRINUSE;        
+               }
+               addr->sipx_type=IPX_TYPE_NCP;
+       }
+
        sk->ipx_source_addr.sock=addr->sipx_port;
 
        if (addr->sipx_network == 0L) 
@@ -705,6 +865,7 @@ static int ipx_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len)
        }
 
        sk->ipx_source_addr.net=rt->net;
+       sk->ipx_type=addr->sipx_type;
 
        /* IPX addresses zero pad physical addresses less than 6 */
        memset(sk->ipx_source_addr.node,'\0',6);
@@ -713,41 +874,102 @@ static int ipx_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len)
 
        ipx_insert_socket(sk);
        sk->zapped=0;
+
+       if (sk->type == SOCK_NCP)
+       {
+               sk->ncp.watchdog->ipx_source_addr.net=rt->net;
+               sk->ncp.watchdog->ipx_source_addr.sock=htons(ntohs(addr->sipx_port)+1);
+
+               memset(sk->ncp.watchdog->ipx_source_addr.node,'\0',6);
+               nodestart = sk->ncp.watchdog->ipx_source_addr.node + (6 - rt->dev->addr_len);
+               memcpy(nodestart,rt->dev->dev_addr,rt->dev->addr_len);
+       
+               ipx_insert_socket(sk->ncp.watchdog);
+               sk->ncp.watchdog->zapped=0;
+
+               sk->ncp.mail->ipx_source_addr.net=rt->net;
+               sk->ncp.mail->ipx_source_addr.sock=htons(ntohs(addr->sipx_port)+2);
+
+               memset(sk->ncp.mail->ipx_source_addr.node,'\0',6);
+               nodestart = sk->ncp.mail->ipx_source_addr.node + (6 - rt->dev->addr_len);
+               memcpy(nodestart,rt->dev->dev_addr,rt->dev->addr_len);
+
+               ipx_insert_socket(sk->ncp.mail);
+               sk->ncp.mail->zapped=0;
+
+               sk->mtu=rt->dev->mtu;
+       }
+
        if(sk->debug)
                printk("IPX: socket is bound.\n");
        return(0);
 }
 
+static int ncp_connect(struct socket *sock, ipx_socket *sk)
+{
+       struct ncp_request req;
+       int err;
+
+       sk->ncp.conn=0xffff;
+       sk->ncp.seq=0;
+       
+       sock->state = SS_CONNECTING;
+       sk->state = TCP_SYN_SENT;
+       sk->rto = 0;
+
+       ipx_do_sendto(sk, &(sk->ipx_dest_addr), &req, sizeof(req), 0, sk->ipx_type);
+
+       while(sk->state != TCP_ESTABLISHED)
+       {
+               if (sk->err)
+               {
+                       err=sk->err;
+                       sk->err=0;
+                       return -err;
+               }
+               interruptible_sleep_on(sk->sleep);
+       }
+
+       return(0);
+}
+
 static int ipx_connect(struct socket *sock, struct sockaddr *uaddr,
        int addr_len, int flags)
 {
        ipx_socket *sk=(ipx_socket *)sock->data;
-       struct sockaddr_ipx *addr;
-       
+       struct sockaddr_ipx *addr=(struct sockaddr_ipx *)uaddr;
+
        sk->state = TCP_CLOSE;  
        sock->state = SS_UNCONNECTED;
        
-       if(addr_len!=sizeof(addr))
+       if(addr_len!=sizeof(struct sockaddr_ipx))
                return(-EINVAL);
-       addr=(struct sockaddr_ipx *)uaddr;
        
-       if(sk->ipx_source_addr.net==0)
+       if(sk->ipx_source_addr.sock==0)
        /* put the autobinding in */
        {
-               struct sockaddr_ipx uaddr;
                int ret;
+               struct sockaddr_ipx addr;
        
-               uaddr.sipx_port = 0;
-               uaddr.sipx_network = 0L; 
-               ret = ipx_bind (sock, (struct sockaddr *)&uaddr, sizeof(struct sockaddr_ipx));
+               addr.sipx_type = 0;
+               addr.sipx_port = 0;
+               addr.sipx_network = 0L; 
+               ret = ipx_bind (sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_ipx));
                if (ret != 0) return (ret);
        }
+
        
        sk->ipx_dest_addr.net=addr->sipx_network;
        sk->ipx_dest_addr.sock=addr->sipx_port;
        memcpy(sk->ipx_dest_addr.node,addr->sipx_node,sizeof(sk->ipx_source_addr.node));
        if(ipxrtr_get_dev(sk->ipx_dest_addr.net)==NULL)
                return -ENETUNREACH;
+
+       if (sk->type == SOCK_NCP)
+               return(ncp_connect(sock, sk));
+
+       sk->ipx_type=addr->sipx_type;
+
        sock->state = SS_CONNECTED;
        sk->state=TCP_ESTABLISHED;
        return(0);
@@ -770,10 +992,9 @@ static int ipx_getname(struct socket *sock, struct sockaddr *uaddr,
 {
        ipx_address *addr;
        struct sockaddr_ipx sipx;
-       ipx_socket *sk;
-       
-       sk=(ipx_socket *)sock->data;
+       ipx_socket *sk=(ipx_socket *)sock->data;
        
+
        *uaddr_len = sizeof(struct sockaddr_ipx);
                
        if(peer)
@@ -783,7 +1004,21 @@ static int ipx_getname(struct socket *sock, struct sockaddr *uaddr,
                addr=&sk->ipx_dest_addr;
        }
        else
+       {
+               if(sk->ipx_source_addr.sock==0)
+               /* put the autobinding in */
+               {
+                       int ret;
+       
+                       sipx.sipx_type = 0;
+                       sipx.sipx_port = 0;
+                       sipx.sipx_network = 0L; 
+                       ret = ipx_bind (sock, (struct sockaddr *)&sipx, sizeof(struct sockaddr_ipx));
+                       if (ret != 0) return (ret);
+               }
+       
                addr=&sk->ipx_source_addr;
+       }
                
        sipx.sipx_family = AF_IPX;
        sipx.sipx_port = addr->sock;
@@ -793,6 +1028,411 @@ static int ipx_getname(struct socket *sock, struct sockaddr *uaddr,
        return(0);
 }
 
+static int ipx_build_header(ipx_address *ipx, struct sk_buff *skb,
+                               ipx_socket *sk, int len, unsigned char type)
+{
+       ipx_packet *ipx_pack;
+       ipx_route *rt;
+       struct datalink_proto *dl = NULL;
+       unsigned char IPXaddr[6];
+       int self_addressing = 0;
+       int broadcast = 0;
+
+       if(sk->debug)
+               printk("IPX: build_header: Addresses built.\n");
+
+       if(memcmp(&ipx->node,&ipx_broadcast_node,6)==0) 
+       {
+               if (!sk->broadcast)
+                       return -ENETUNREACH;
+               broadcast = 1;
+       }
+
+       /* Build a packet */
+       
+       if(sk->debug)
+               printk("IPX: build_header: building packet.\n");
+               
+       /* Find out where this has to go */
+       if (ipx->net == 0L) {
+               rt = ipxrtr_get_default_net();
+               if (rt != NULL)
+                       ipx->net = rt->net;
+       } else
+               rt=ipxrtr_get_dev(ipx->net);
+
+       if(rt==NULL)
+       {
+               return -ENETUNREACH;
+       }
+
+       dl=rt->datalink;
+
+       skb->mem_addr=skb;
+       skb->sk=sk;
+       skb->free=1;
+       skb->arp=1;
+       skb->tries=0;
+
+       if(sk->debug)
+               printk("Building MAC header.\n");               
+       skb->dev=rt->dev;
+
+       /* Build Data Link header */
+       dl->datalink_header(dl, skb, 
+               (rt->flags&IPX_RT_ROUTED)?rt->router_node:ipx->node);
+
+       /* See if we are sending to ourself */
+       memset(IPXaddr, '\0', 6);
+       memcpy(IPXaddr+(6 - skb->dev->addr_len), skb->dev->dev_addr, 
+                       skb->dev->addr_len);
+
+       self_addressing = !memcmp(IPXaddr, 
+                               (rt->flags&IPX_RT_ROUTED)?rt->router_node
+                               :ipx->node,
+                               6);
+
+       /* Now the IPX */
+       if(sk->debug)
+               printk("Building IPX Header.\n");
+       ipx_pack=(ipx_packet *)skb->h.raw;
+       ipx_pack->ipx_checksum=0xFFFF;
+       ipx_pack->ipx_pktsize=htons(len+sizeof(ipx_packet));
+       ipx_pack->ipx_tctrl=0;
+       ipx_pack->ipx_type=type;
+
+       memcpy(&ipx_pack->ipx_source,&sk->ipx_source_addr,sizeof(ipx_pack->ipx_source));
+       memcpy(&ipx_pack->ipx_dest,ipx,sizeof(ipx_pack->ipx_dest));
+
+       if((skb->dev->flags&IFF_LOOPBACK) || self_addressing)
+               skb->pkt_type=PACKET_HOST;
+       else
+               if (broadcast)
+                       skb->pkt_type=PACKET_BROADCAST;
+               else
+                       skb->pkt_type=PACKET_OTHERHOST;
+
+       return 0;
+}
+
+static int ipx_xmit(struct sk_buff *skb)
+{
+       struct sk_buff *skb1;
+       struct device *dev= skb->dev;
+       ipx_packet *ipx=(ipx_packet *)skb->h.raw; 
+       ipx_route *rt;
+       struct packet_type      pt;
+
+       if (ipx->ipx_dest.net == 0L)
+               rt = ipxrtr_get_default_net();
+       else
+               rt=ipxrtr_get_dev(ipx->ipx_dest.net);
+
+       if (rt == NULL)
+               return -ENETUNREACH;
+
+       pt.type=rt->dlink_type;
+
+       skb->tries++;
+
+       switch (skb->pkt_type)
+       {
+               case PACKET_HOST:
+                       if (!skb->free)
+                       {
+                               skb1=alloc_skb(skb->len, GFP_ATOMIC);
+                               if (skb1 != NULL)
+                               {
+                                       skb1->mem_addr=skb1;
+                                       skb1->free=1;
+                                       skb1->arp=1;
+                                       skb1->len=skb->len;
+                                       skb1->sk = NULL;
+                                       skb1->h.raw = skb1->data + rt->datalink->header_length
+                                               + dev->hard_header_len;
+                                       memcpy(skb1->data, skb->data, skb->len);
+                                       ipx_rcv(skb1,dev,&pt);
+                               }
+                       }
+                       else
+                       {
+               
+               
+                               /* loop back */
+                               skb->sk->wmem_alloc-=skb->mem_len;
+                               skb->sk = NULL;
+                               ipx_rcv(skb,dev,&pt);
+                       }
+                       break;
+
+               case PACKET_BROADCAST:
+                       skb1=alloc_skb(skb->len, GFP_ATOMIC);
+                       if (skb1 != NULL)
+                       {
+                               skb1->mem_addr=skb1;
+                               skb1->free=1;
+                               skb1->arp=1;
+                               skb1->len=skb->len;
+                               skb1->sk = NULL;
+                               skb1->h.raw = skb1->data + rt->datalink->header_length
+                                       + dev->hard_header_len;
+                               memcpy(skb1->data, skb->data, skb->len);
+                               ipx_rcv(skb1,dev,&pt);
+                       }
+               default:
+                       if (!skb->free)
+                       {
+                               skb1=alloc_skb(skb->len, GFP_ATOMIC);
+                               if (skb1 != NULL)
+                               {
+                                       skb1->mem_addr=skb1;
+                                       skb1->free=1;
+                                       skb1->arp=1;
+                                       skb1->len=skb->len;
+                                       skb1->sk = NULL;
+                                       skb1->h.raw = skb1->data + rt->datalink->header_length
+                                               + dev->hard_header_len;
+                                       memcpy(skb1->data, skb->data, skb->len);
+                               }
+                       }
+                       else
+                               skb1=skb;
+                       if (skb1 != NULL)
+                       {
+                               if (skb1->sk)
+                                       dev_queue_xmit(skb1,dev,skb->sk->priority);
+                               else
+                                       dev_queue_xmit(skb1,dev,SOPRI_NORMAL);
+                       }
+       }
+
+       return(0);
+
+}
+
+static int ipx_retransmit(ipx_socket *sk)
+{
+       struct sk_buff *skb = sk->write_queue.next;
+       int num=0;
+
+       ipx_packet *ipx;
+       struct ncp_request *req;
+
+       if (skb == NULL)
+               return(num);
+
+       if (skb == skb->next)
+               return(num);
+
+       do 
+       {
+               ipx=(ipx_packet *)skb->h.raw; 
+               req=(struct ncp_request *)(ipx+1);
+
+               ipx_xmit(skb);
+
+               num++;
+               skb=skb->next;
+       }
+       while (skb->next != sk->write_queue.next);
+
+       return (num);
+}
+
+static void ipx_timer (unsigned long data)
+{
+       ipx_socket *sk = (ipx_socket *) data;
+        int num;
+
+       cli();
+       if (in_bh)
+       {
+               sk->timer.expires = 10;
+               add_timer(&sk->timer);
+               sti();
+               return;
+       }
+       sti();
+
+       num=ipx_retransmit(sk);
+
+       sk->rto++;
+
+       if (sk->rto >= MAX_TIMEOUT)
+       {
+               struct sk_buff *skb;
+
+               while((skb=skb_dequeue(&sk->write_queue))!=NULL)
+                       kfree_skb(skb,FREE_WRITE);
+
+               sk->err=ETIMEDOUT;
+               sk->state=TCP_CLOSE;
+               sk->socket->state=SS_UNCONNECTED;
+               if(!sk->dead)
+                       sk->error_report(sk);
+               return;
+       }
+               
+       if (num)
+               ipx_reset_timer(sk, NCP_TIMEOUT);
+
+       return;
+}
+
+static void ipx_delete_timer (ipx_socket *sk)
+{
+       unsigned long flags;
+
+       save_flags (flags);
+       cli();
+
+       del_timer (&sk->timer);
+
+       restore_flags(flags);
+}
+
+static void ipx_add_timer (ipx_socket *sk, int len)
+{
+       init_timer (&sk->timer);
+       sk->timer.data = (unsigned long) sk;
+       sk->timer.function = &ipx_timer;
+       sk->timer.expires = len;
+       add_timer(&sk->timer);
+}
+
+static void ipx_reset_timer (ipx_socket *sk, int len)
+{
+
+       ipx_delete_timer (sk);
+       sk->timer.data = (unsigned long) sk;
+       sk->timer.function = &ipx_timer;
+       sk->timer.expires = len;
+       add_timer(&sk->timer);
+}
+
+static struct sk_buff *find_req(ipx_socket *sk, unsigned char seq)
+{
+       ipx_packet *ipx;
+       struct ncp_request *req;
+       struct sk_buff *skb = sk->write_queue.next;
+
+       if (skb == NULL)
+               return (NULL);
+
+       if (skb == skb->next)
+               return (NULL);
+
+       do 
+       {
+               ipx=(ipx_packet *)skb->h.raw; 
+               req=(struct ncp_request *)(ipx+1);
+               if (req->seq == seq)
+               {
+                       skb_unlink(skb);
+                       return (skb);
+               }
+               skb=skb->next;
+       }
+       while (skb->next != sk->write_queue.next);
+
+       return (NULL);
+}
+
+static int ncp_rcv(ipx_socket *sk, struct sk_buff *skb)
+{
+       ipx_packet *ipx=(ipx_packet *)skb->h.raw; 
+       struct ncp_reply *rep= (struct ncp_reply *)(ipx+1);
+       struct ncp_request_sf *req;
+       struct sk_buff *skb1;
+
+       if (rep->p_type != NCP_REPLY)
+       {
+               kfree_skb(skb, FREE_READ);
+               return (0);
+       }
+
+       skb1=find_req(sk, rep->seq);
+
+       if (skb1 == NULL)
+       {
+               kfree_skb(skb, FREE_READ);
+               return (0);
+       }
+
+       if (&sk->write_queue == sk->write_queue.next)
+       {
+               sk->rto=0;
+               ipx_delete_timer(sk);
+       }
+
+       ipx=(ipx_packet *)skb1->h.raw; 
+       req=(struct ncp_request_sf *)(ipx+1);
+
+       switch (sk->state)
+       {
+               case TCP_CLOSE_WAIT:
+                       kfree_skb(skb, FREE_READ);
+                       sk->socket->data = NULL;
+                       sk->state=TCP_CLOSE;
+                       if(!sk->dead)
+                               sk->state_change(sk);
+                       sk->dead=1;
+                       if (&sk->write_queue != sk->write_queue.next)
+                               ipx_delete_timer(sk);
+                       ipx_destroy_socket(sk);
+                       break;
+               case TCP_SYN_SENT:
+
+                       if ((rep->f_stat == 0) && (rep->c_stat == 0))
+                       {
+                               sk->state=TCP_ESTABLISHED;
+                               sk->socket->state = SS_CONNECTED;
+                               sk->ncp.conn=rep->c_low + (rep->c_high * 0xff);
+                               if(!sk->dead)
+                                       sk->state_change(sk);
+                       }
+                       else
+                       {
+                               sk->state=TCP_CLOSE;
+                               sk->socket->state = SS_UNCONNECTED;
+                               sk->err=ECONNREFUSED;
+                               if (&sk->write_queue != sk->write_queue.next)
+                                       ipx_delete_timer(sk);
+                               if(!sk->dead)
+                                       sk->error_report(sk);
+                       }
+                       kfree_skb(skb, FREE_READ);
+                       break;
+               default:
+                       if ((req->func==0x15)&&(req->s_func==0x01))
+                       {
+                               char *data = (char *)(rep+1);
+                               int len=(int)*data; 
+                               
+                               if (len != 0)
+                               {
+                                       memcpy(data, data+1, len);
+                                       *(data+len)='\0';
+                                       printk("\007%s\n",data);
+                               }
+                               kfree_skb(skb, FREE_READ);
+                       }
+                       else
+                       {
+                               sk->rmem_alloc+=skb->mem_len;
+                               skb->sk = sk;
+
+                               skb_queue_tail(&sk->receive_queue,skb);
+                               if(!sk->dead)
+                                       sk->data_ready(sk,skb->len);
+                       }
+       }       
+       
+       kfree_skb(skb1, FREE_WRITE);
+
+       return(0);
+}
+
 int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
 {
        /* NULL here for pt means the packet was looped back */
@@ -942,6 +1582,9 @@ int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
                kfree_skb(skb,FREE_READ);       /* Socket is full */
                return(0);
        }
+
+       if (sock->type == SOCK_NCP)
+               return (ncp_rcv(sock, skb));
        
        sock->rmem_alloc+=skb->mem_len;
        skb->sk = sock;
@@ -952,65 +1595,27 @@ int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
        return(0);
 }
 
-static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock,
-       unsigned flags, struct sockaddr *usip, int addr_len)
+static int ipx_do_sendto(ipx_socket *sk, ipx_address *ipx,
+                        void *ubuf, int len, int flag, unsigned char type)
 {
-       ipx_socket *sk=(ipx_socket *)sock->data;
-       struct sockaddr_ipx *usipx=(struct sockaddr_ipx *)usip;
-       struct sockaddr_ipx local_sipx;
        struct sk_buff *skb;
        struct device *dev;
-       struct ipx_packet *ipx;
+       ipx_packet *ipx_pack;
        int size;
        ipx_route *rt;
        struct datalink_proto *dl = NULL;
-       unsigned char IPXaddr[6];
-       int self_addressing = 0;
-       int broadcast = 0;
 
-       if(flags)
-               return -EINVAL;
-               
-       if(usipx)
-       {
-               if(sk->ipx_source_addr.net==0)
-               /* put the autobinding in */
-               {
-                       struct sockaddr_ipx uaddr;
-                       int ret;
-
-                       uaddr.sipx_port = 0;
-                       uaddr.sipx_network = 0L; 
-                       ret = ipx_bind (sock, (struct sockaddr *)&uaddr, sizeof(struct sockaddr_ipx));
-                       if (ret != 0) return (ret);
-               }
 
-               if(addr_len <sizeof(*usipx))
-                       return(-EINVAL);
-               if(usipx->sipx_family != AF_IPX)
-                       return -EINVAL;
-               if(htons(usipx->sipx_port)<0x4000 && !suser())
-                       return -EPERM;
-       }
-       else
-       {
-               if(sk->state!=TCP_ESTABLISHED)
-                       return -ENOTCONN;
-               usipx=&local_sipx;
-               usipx->sipx_family=AF_IPX;
-               usipx->sipx_port=sk->ipx_dest_addr.sock;
-               usipx->sipx_network=sk->ipx_dest_addr.net;
-               memcpy(usipx->sipx_node,sk->ipx_dest_addr.node,sizeof(usipx->sipx_node));
-       }
-       
        if(sk->debug)
                printk("IPX: sendto: Addresses built.\n");
 
-       if(memcmp(&usipx->sipx_node,&ipx_broadcast_node,6)==0) 
+       if ((sk->type == SOCK_NCP) && (len < sizeof (struct ncp_request)))
+               return -EINVAL;
+
+       if(memcmp(&ipx->node,&ipx_broadcast_node,6)==0) 
        {
                if (!sk->broadcast)
                        return -ENETUNREACH;
-               broadcast = 1;
        }
 
        /* Build a packet */
@@ -1021,12 +1626,12 @@ static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock,
        size=sizeof(ipx_packet)+len;    /* For mac headers */
 
        /* Find out where this has to go */
-       if (usipx->sipx_network == 0L) {
+       if (ipx->net == 0L) {
                rt = ipxrtr_get_default_net();
                if (rt != NULL)
-                       usipx->sipx_network = rt->net;
+                       ipx->net = rt->net;
        } else
-               rt=ipxrtr_get_dev(usipx->sipx_network);
+               rt=ipxrtr_get_dev(ipx->net);
 
        if(rt==NULL)
        {
@@ -1046,86 +1651,117 @@ static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock,
                return -EAGAIN;
        }
                
-       skb=alloc_skb(size,GFP_KERNEL);
+       if (flag)
+               skb=alloc_skb(size,GFP_KERNEL);
+       else
+               skb=alloc_skb(size,GFP_ATOMIC);
+
        if(skb==NULL)
                return -ENOMEM;
+
+       sk->wmem_alloc+=skb->mem_len;
                
-       skb->mem_addr=skb;
-       skb->sk=sk;
-       skb->free=1;
-       skb->arp=1;
        skb->len=size;
 
-       sk->wmem_alloc+=skb->mem_len;
+       ipx_build_header(ipx, skb, sk, len, type);
 
-       if(sk->debug)
-               printk("Building MAC header.\n");               
-       skb->dev=rt->dev;
-       
-       /* Build Data Link header */
-       dl->datalink_header(dl, skb, 
-               (rt->flags&IPX_RT_ROUTED)?rt->router_node:usipx->sipx_node);
+       ipx_pack = (ipx_packet *)(skb->h.raw);
 
-       /* See if we are sending to ourself */
-       memset(IPXaddr, '\0', 6);
-       memcpy(IPXaddr+(6 - skb->dev->addr_len), skb->dev->dev_addr, 
-                       skb->dev->addr_len);
+       /* User data follows immediately after the IPX data */
+       if (flag)
+               memcpy_fromfs((char *)(ipx_pack+1),ubuf,len);
+       else
+               memcpy((char *)(ipx_pack+1),ubuf,len);
 
-       self_addressing = !memcmp(IPXaddr, 
-                               (rt->flags&IPX_RT_ROUTED)?rt->router_node
-                               :usipx->sipx_node,
-                               6);
+       if (sk->type == SOCK_NCP)
+       {
+               struct ncp_request *req=(struct ncp_request *)(ipx_pack+1);
+
+               switch (sk->state)
+               {
+                       case TCP_SYN_SENT:
+                               req->p_type = NCP_OPEN;
+                               break;
+                       case TCP_CLOSE_WAIT:
+                               req->p_type = NCP_CLOSE;
+                               break;
+                       default:
+                               req->p_type = NCP_REQUEST;
+               }
+               req->c_low = (sk->ncp.conn) & 0xff;
+               req->c_high = (sk->ncp.conn >>8) & 0xff;
+               req->seq = (sk->ncp.seq)++;
+               req->task = 1;
+
+               skb->free=0;
+
+               if (&sk->write_queue == sk->write_queue.next)
+                       ipx_add_timer(sk, NCP_TIMEOUT);
+               else
+                       ipx_reset_timer(sk, NCP_TIMEOUT);
+       
+               skb_queue_tail(&sk->write_queue,skb);
+       }
 
-       /* Now the IPX */
-       if(sk->debug)
-               printk("Building IPX Header.\n");
-       ipx=(ipx_packet *)skb->h.raw;
-       ipx->ipx_checksum=0xFFFF;
-       ipx->ipx_pktsize=htons(len+sizeof(ipx_packet));
-       ipx->ipx_tctrl=0;
-       ipx->ipx_type=usipx->sipx_type;
-
-       memcpy(&ipx->ipx_source,&sk->ipx_source_addr,sizeof(ipx->ipx_source));
-       ipx->ipx_dest.net=usipx->sipx_network;
-       memcpy(ipx->ipx_dest.node,usipx->sipx_node,sizeof(ipx->ipx_dest.node));
-       ipx->ipx_dest.sock=usipx->sipx_port;
-       if(sk->debug)
-               printk("IPX: Appending user data.\n");
-       /* User data follows immediately after the IPX data */
-       memcpy_fromfs((char *)(ipx+1),ubuf,len);
        if(sk->debug)
                printk("IPX: Transmitting buffer\n");
-       if((dev->flags&IFF_LOOPBACK) || self_addressing) {
-               struct packet_type      pt;
-
-               /* loop back */
-               pt.type = rt->dlink_type;
-               sk->wmem_alloc-=skb->mem_len;
-               skb->sk = NULL;
-               ipx_rcv(skb,dev,&pt);
-       } else {
-               if (broadcast) {
-                       struct packet_type      pt;
-                       struct sk_buff          *skb2;
 
-                       /* loop back */
-                       pt.type = rt->dlink_type;
-                       
-                       skb2=alloc_skb(skb->len, GFP_ATOMIC);
-                       skb2->mem_addr=skb2;
-                       skb2->free=1;
-                       skb2->arp=1;
-                       skb2->len=skb->len;
-                       skb2->sk = NULL;
-                       skb2->h.raw = skb2->data + rt->datalink->header_length
-                               + dev->hard_header_len;
-                       memcpy(skb2->data, skb->data, skb->len);
-                       ipx_rcv(skb2,dev,&pt);
+       ipx_xmit(skb);
+
+       return len;
+}
+
+static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock,
+       unsigned flags, struct sockaddr *usip, int addr_len)
+{
+       ipx_socket *sk=(ipx_socket *)sock->data;
+        ipx_address ipx;
+       struct sockaddr_ipx *usipx=(struct sockaddr_ipx *)usip;
+       struct sockaddr_ipx local_sipx;
+
+       if(flags)
+               return -EINVAL;
+               
+       if(usipx)
+       {
+               if (sk->type == SOCK_NCP)
+                       return -EINVAL;
+
+               if(sk->ipx_source_addr.sock==0)
+               /* put the autobinding in */
+               {
+                       int ret;
+
+                       local_sipx.sipx_type = 0;
+                       local_sipx.sipx_port = 0;
+                       local_sipx.sipx_network = 0L; 
+                       ret = ipx_bind (sock, (struct sockaddr *)&local_sipx, sizeof(struct sockaddr_ipx));
+                       if (ret != 0) return (ret);
                }
-               dev_queue_xmit(skb,dev,SOPRI_NORMAL);
+
+               if(addr_len <sizeof(*usipx))
+                       return(-EINVAL);
+               if(usipx->sipx_family != AF_IPX)
+                       return -EINVAL;
+               if(htons(usipx->sipx_port)<0x4000 && !suser())
+                       return -EPERM;
+
+               ipx.net=usipx->sipx_network;
+               ipx.sock=usipx->sipx_port;
+               memcpy(ipx.node,usipx->sipx_node, sizeof(ipx.node));
+               return (ipx_do_sendto(sk, &ipx, ubuf, len, 1,
+                       usipx->sipx_type));
+       }
+       else
+       {
+               if(sk->state!=TCP_ESTABLISHED)
+                       return -ENOTCONN;
+
+               return (ipx_do_sendto(sk, &(sk->ipx_dest_addr), ubuf,
+                       len, 1, sk->ipx_type));
        }
-       return len;
 }
+       
 
 static int ipx_send(struct socket *sock, void *ubuf, int size, int noblock, unsigned flags)
 {
@@ -1142,7 +1778,7 @@ static int ipx_recvfrom(struct socket *sock, void *ubuf, int size, int noblock,
        int copied = 0;
        struct sk_buff *skb;
        int er;
-       
+
        if(sk->err)
        {
                er= -sk->err;
@@ -1170,12 +1806,14 @@ static int ipx_recvfrom(struct socket *sock, void *ubuf, int size, int noblock,
                sipx->sipx_type = ipx->ipx_type;
        }
        skb_free_datagram(skb);
+
        return(copied);
 }              
 
 
 static int ipx_write(struct socket *sock, char *ubuf, int size, int noblock)
 {
+
        return ipx_send(sock,ubuf,size,noblock,0);
 }
 
diff --git a/net/inet/ncp.h b/net/inet/ncp.h
new file mode 100644 (file)
index 0000000..b12011c
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ *
+ * Kernel support for NCP
+ *
+ * Mark Evans 1994
+ *
+ */
+
+#ifndef _NCP_H
+#define _NCP_H
+
+#include <linux/ncp.h>
+
+struct ncp_info
+{
+       unsigned short  conn;           /* connection number */
+       unsigned char   seq;            /* sequence number */
+       ipx_socket      *ncp;           /* ncp socket */
+       ipx_socket      *watchdog;      /* watchdog socket */
+       ipx_socket      *mail;          /* mail socket */
+};
+
+#define NCP_TIMEOUT (3*HZ)
+#define MAX_TIMEOUT 15
+
+#endif /* _NCP_H */
index 331e2cfa0ad3eee59cf742eb30f08b16bdb88fdc..5352af0bab5917f59efece72b97d641ccd89cbce 100644 (file)
@@ -41,6 +41,7 @@
 #endif
 #ifdef CONFIG_IPX
 #include "ipx.h"
+#include "ncp.h"
 #endif
 
 #define SOCK_ARRAY_SIZE        64
@@ -137,6 +138,7 @@ struct sock {
 #ifdef CONFIG_IPX
   ipx_address                  ipx_source_addr,ipx_dest_addr;
   unsigned short               ipx_type;
+  struct ncp_info              ncp;
 #endif
 #ifdef CONFIG_AX25
 /* Really we want to add a per protocol private area */
index 773fcc0f2737f7750ad93501e90d63638fe5bd38..bfb3249f303454cc6fa46626a9aa8e3d12a96064 100644 (file)
@@ -592,7 +592,8 @@ static int sock_socket(int family, int type, int protocol)
   
        if ((type != SOCK_STREAM && type != SOCK_DGRAM &&
                type != SOCK_SEQPACKET && type != SOCK_RAW &&
-               type != SOCK_PACKET) || protocol < 0)
+               type != SOCK_PACKET && type != SOCK_NCP)
+               || protocol < 0)
                        return(-EINVAL);
 
 /*