]> git.neil.brown.name Git - history.git/commitdiff
2.0.36prepatch 6 2.0.36pre6
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:11:56 +0000 (15:11 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:11:56 +0000 (15:11 -0500)
        ftp://ftp.linux.org.uk/pub/linux/alan/2.0.36pre/
Changes this release
o       Cyclades bug fix (Cyclades Corp)
o       440GX device ids (Leonard Zubkoff)
o       BusLogic update (Leonard Zubkoff)
o       New version of the ROSE protocol layers (F6FBB)
o       TCP works with SO_BINDTODEVICE  (Phil Gladstone)
o       TCP select error
o       Hooks for multithreaded ELF core dumps (Alan Cox)
        (Phil Gladstone maintains the ELF mt core dump stuff and gdb patch)

I was going to integrate this patch but I got some slightly odd results
that looked like a double kfree and the patch didnt seem quite perfect yet.
Anyway - you shouldnt need to hack anything to use it now
Stuff I know I have left to worry about:

o       Andre - can you check there is nothing in your jumbo patches I
        should have (I dont want to put the UDMA/new timer stuff into a
        2.0.x kernel). I couldnt see any easy way to seperate the MHz
        computation from it
o       Try and get the mt core dumps working
o       Two crash reports from AF_UNIX sockets that look like a long
        standing race.

Alan

27 files changed:
arch/i386/kernel/ksyms.c
drivers/char/cyclades.c
drivers/net/3c505.h
drivers/pci/pci.c
drivers/scsi/BusLogic.c
drivers/scsi/FlashPoint.c
drivers/scsi/README.BusLogic
drivers/scsi/README.Mylex
fs/autofs/dirhash.c
include/asm-i386/ptrace.h
include/linux/cyclades.h
include/linux/pci.h
include/linux/rose.h
include/net/rose.h
kernel/ksyms.c
net/ipv4/tcp.c
net/ipv4/tcp_output.c
net/rose/Makefile
net/rose/af_rose.c
net/rose/changes.doc [new file with mode: 0644]
net/rose/rose_in.c
net/rose/rose_link.c
net/rose/rose_loopback.c [new file with mode: 0644]
net/rose/rose_out.c
net/rose/rose_route.c
net/rose/rose_subr.c
net/rose/rose_timer.c

index 963a1c86cb1ca08dc5bc0fc81a48f36866ef2975..678a8a8044f0cd8d8f121b93f846e6f8915480ad 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <asm/semaphore.h>
 #include <asm/processor.h>
+#include <asm/ptrace.h>
 
 extern void dump_thread(struct pt_regs *, struct user *);
 extern int dump_fpu(elf_fpregset_t *);
@@ -16,6 +17,7 @@ static struct symbol_table arch_symbol_table = {
        X(x86_capability),
        X(dump_thread),
        X(dump_fpu),
+       X(get_pt_regs_for_task),
        XNOVERS(__do_delay),
        XNOVERS(down_failed),
        XNOVERS(down_failed_interruptible),
index a3f168350157141419ed9221eedc9029ca0e6d23..7c5f94efce056849e69af034cf593f863ea1546e 100644 (file)
@@ -1,7 +1,7 @@
 #define BLOCKMOVE
 #define        Z_WAKE
 static char rcsid[] =
-"$Revision: 2.1.1.6 $$Date: 1998/08/04 12:19:36 $";
+"$Revision: 2.1.1.7 $$Date: 1998/08/10 17:01:45 $";
 
 /*
  *  linux/drivers/char/cyclades.c
@@ -31,6 +31,9 @@ static char rcsid[] =
  *   void cleanup_module(void);
  *
  * $Log: cyclades.c,v $
+ * Revision 2.1.1.7  1998/08/10 17:01:45 ivan
+ * Fixed Cyclom-4Yo hardware detection bug.
+ *
  * Revision 2.1.1.6  1998/08/04 12:19:36 ivan
  * cyy_interrupt changed once more to avoid occurence of kernel
  * oopses during PPP operation.
@@ -579,7 +582,7 @@ static char rcsid[] =
 #define MIN(a,b)        ((a) < (b) ? (a) : (b))
 #endif
 
-#define IS_CYC_Z(card) ((card).num_chips == 1)
+#define IS_CYC_Z(card) ((card).num_chips == -1)
 
 #define Z_FPGA_CHECK(card) \
     ((cy_readl(&((struct RUNTIME_9060 *) \
@@ -598,7 +601,7 @@ static char rcsid[] =
 #define SERIAL_TYPE_NORMAL  1
 #define SERIAL_TYPE_CALLOUT 2
 
-#define        JIFFIES_DIFF(n, j)      ((n) >= (j) ? (n) - (j) : ULONG_MAX - (n) + (j))
+#define        JIFFIES_DIFF(n, j)      ((n) - (j))
 
 DECLARE_TASK_QUEUE(tq_cyclades);
 
@@ -3557,7 +3560,7 @@ get_modem_info(struct cyclades_port * info, unsigned int *value)
     } else {
        base_addr = (unsigned char*) (cy_card[card].base_addr);
 
-        if (cy_card[card].num_chips != 1){
+        if (cy_card[card].num_chips != -1){
            return -EINVAL;
        }
 
@@ -4958,7 +4961,7 @@ cy_detect_pci(void))
                 cy_card[j].irq = (int) cy_pci_irq;
                 cy_card[j].bus_index = 1;
                 cy_card[j].first_line = cy_next_channel;
-                cy_card[j].num_chips = 1;
+                cy_card[j].num_chips = -1;
                 IRQ_cards[cy_pci_irq] = &cy_card[j];
 
                 /* print message */
@@ -5041,7 +5044,7 @@ cy_detect_pci(void))
                 cy_card[j].irq = (int) cy_pci_irq;
                 cy_card[j].bus_index = 1;
                 cy_card[j].first_line = cy_next_channel;
-                cy_card[j].num_chips = 1;
+                cy_card[j].num_chips = -1;
                 IRQ_cards[cy_pci_irq] = &cy_card[j];
 
                 /* print message */
@@ -5114,7 +5117,7 @@ int cyclades_get_proc_info(char *buf, char **start, off_t offset, int length,
 
        if (info->count)
            size = sprintf(buf+len,
-                       "%3d %8lu %10lu %8lu %10lu %8lu %9lu %6ld\n",
+                       "%3d %8lu %10lu %8lu %10lu %8lu %9lu %6d\n",
                        info->line,
                        JIFFIES_DIFF(info->idle_stats.in_use, cur_jifs) / HZ,
                        info->idle_stats.xmit_bytes,
@@ -5272,7 +5275,7 @@ cy_init(void))
     /* initialize per-port data structures for each valid board found */
     for (board = 0 ; board < cy_nboard ; board++) {
             cinfo = &cy_card[board];
-            if (cinfo->num_chips == 1){ /* Cyclades-Z */
+            if (cinfo->num_chips == -1){ /* Cyclades-Z */
                number_z_boards++;
                mailbox = cy_readl(&((struct RUNTIME_9060 *)
                             cy_card[board].ctl_addr)->mail_box_0);
index f7d283688c4c996a547b25c7b19aabbd1fcbd685..0598ca25a2f6a4326d77c1d385c3dca0b5b01133 100644 (file)
@@ -61,7 +61,7 @@
 #define        DMA_BRST        0x01    /* DMA burst */
 
 /*
- * maximum amount of data data allowed in a PCB
+ * maximum amount of data allowed in a PCB
  */
 #define        MAX_PCB_DATA    62
 
index d35569dafa555f0520b0fe05a35e7a24f0d0eb27..55ed55217d4f60769a19fad767d80c1cd7af9aef 100644 (file)
@@ -501,6 +501,9 @@ struct pci_dev_info dev_info[] = {
        DEVICE( INTEL,          INTEL_82443BX_0,"440BX - 82443BX Host"),
        DEVICE( INTEL,          INTEL_82443BX_1,"440BX - 82443BX AGP"),
        DEVICE( INTEL,          INTEL_82443BX_2,"440BX - 82443BX Host (no AGP)"),
+       DEVICE( INTEL,          INTEL_82443GX_0,"440GX - 82443GX Host"),
+       DEVICE( INTEL,          INTEL_82443GX_1,"440GX - 82443GX AGP"),
+       DEVICE( INTEL,          INTEL_82443GX_2,"440GX - 82443GX Host (no AGP)"),
        DEVICE( INTEL,          INTEL_P6,       "Orion P6"),
        DEVICE( INTEL,          INTEL_82450GX,  "82450GX Orion P6"),
        DEVICE( KTI,            KTI_ET32P2,     "ET32P2"),
index a8418e7b33dc6817341de580e22e85ae006f281b..3c52e15487fb9e2435ba5c65408d7a0f0ba1834f 100644 (file)
@@ -26,8 +26,8 @@
 */
 
 
-#define BusLogic_DriverVersion         "2.0.14"
-#define BusLogic_DriverDate            "29 April 1998"
+#define BusLogic_DriverVersion         "2.0.15"
+#define BusLogic_DriverDate            "17 August 1998"
 
 
 #include <linux/version.h>
@@ -1190,7 +1190,8 @@ static void BusLogic_InitializeProbeInfoList(BusLogic_HostAdapter_T
                    BusLogic_ProbeInfoCount - FlashPointCount;
                  memcpy(SavedProbeInfo,
                         BusLogic_ProbeInfoList,
-                        sizeof(BusLogic_ProbeInfoList));
+                        BusLogic_ProbeInfoCount
+                        * sizeof(BusLogic_ProbeInfo_T));
                  memcpy(&BusLogic_ProbeInfoList[0],
                         &SavedProbeInfo[FlashPointCount],
                         MultiMasterCount * sizeof(BusLogic_ProbeInfo_T));
@@ -3149,25 +3150,25 @@ static void BusLogic_ProcessCompletedCCBs(BusLogic_HostAdapter_T *HostAdapter)
                  HostAdapter->TargetStatistics[CCB->TargetID]
                               .CommandsCompleted++;
                  if (BusLogic_GlobalOptions.TraceErrors)
-                     {
-                       int i;
-                       BusLogic_Notice("CCB #%ld Target %d: Result %X Host "
-                                       "Adapter Status %02X "
-                                       "Target Status %02X\n",
-                                       HostAdapter, CCB->SerialNumber,
-                                       CCB->TargetID, Command->result,
-                                       CCB->HostAdapterStatus,
-                                       CCB->TargetDeviceStatus);
-                       BusLogic_Notice("CDB   ", HostAdapter);
-                       for (i = 0; i < CCB->CDB_Length; i++)
-                         BusLogic_Notice(" %02X", HostAdapter, CCB->CDB[i]);
-                       BusLogic_Notice("\n", HostAdapter);
-                       BusLogic_Notice("Sense ", HostAdapter);
-                       for (i = 0; i < CCB->SenseDataLength; i++)
-                         BusLogic_Notice(" %02X", HostAdapter,
-                                         Command->sense_buffer[i]);
-                       BusLogic_Notice("\n", HostAdapter);
-                     }
+                   {
+                     int i;
+                     BusLogic_Notice("CCB #%ld Target %d: Result %X Host "
+                                     "Adapter Status %02X "
+                                     "Target Status %02X\n",
+                                     HostAdapter, CCB->SerialNumber,
+                                     CCB->TargetID, Command->result,
+                                     CCB->HostAdapterStatus,
+                                     CCB->TargetDeviceStatus);
+                     BusLogic_Notice("CDB   ", HostAdapter);
+                     for (i = 0; i < CCB->CDB_Length; i++)
+                       BusLogic_Notice(" %02X", HostAdapter, CCB->CDB[i]);
+                     BusLogic_Notice("\n", HostAdapter);
+                     BusLogic_Notice("Sense ", HostAdapter);
+                     for (i = 0; i < CCB->SenseDataLength; i++)
+                       BusLogic_Notice(" %02X", HostAdapter,
+                                       Command->sense_buffer[i]);
+                     BusLogic_Notice("\n", HostAdapter);
+                   }
                }
              break;
            }
@@ -4219,7 +4220,6 @@ int BusLogic_ProcDirectoryInfo(char *ProcBuffer, char **StartPointer,
   BusLogic_TargetStatistics_T *TargetStatistics;
   int TargetID, Length;
   char *Buffer;
-  if (WriteFlag) return 0;
   for (HostAdapter = BusLogic_FirstRegisteredHostAdapter;
        HostAdapter != NULL;
        HostAdapter = HostAdapter->Next)
@@ -4231,6 +4231,14 @@ int BusLogic_ProcDirectoryInfo(char *ProcBuffer, char **StartPointer,
       return 0;
     }
   TargetStatistics = HostAdapter->TargetStatistics;
+  if (WriteFlag)
+    {
+      HostAdapter->ExternalHostAdapterResets = 0;
+      HostAdapter->HostAdapterInternalErrors = 0;
+      memset(TargetStatistics, 0,
+            BusLogic_MaxTargetDevices * sizeof(BusLogic_TargetStatistics_T));
+      return 0;
+    }
   Buffer = HostAdapter->MessageBuffer;
   Length = HostAdapter->MessageBufferLength;
   Length += sprintf(&Buffer[Length], "\n\
index d94631a416e9e2ebc1549808e690c44b20c29563..7c0232fa91d64a6842860c968c78ec8cb491bef5 100644 (file)
@@ -3165,11 +3165,11 @@ STATIC s32bits probe_adapter(PADAPTER_INFO pAdapterInfo)
 
        if(RD_HARPOON(ioport + hp_page_ctrl) & BIOS_SHADOW)
        {
-               pAdapterInfo->ai_FlashRomSize = 64 * 1024;      /* 64k Rom */
+               pAdapterInfo->ai_FlashRomSize = 64 * 1024;      /* 64k ROM */
        }
        else
        {
-               pAdapterInfo->ai_FlashRomSize = 32 * 1024;      /* 32k Rom */
+               pAdapterInfo->ai_FlashRomSize = 32 * 1024;      /* 32k ROM */
        }
 
    pAdapterInfo->ai_stateinfo |= (FAST20_ENA | TAG_QUEUE_ENA);
@@ -4944,7 +4944,7 @@ int SccbMgr_isr(ULONG pCurrCard)
  *
  * Function: Sccb_bad_isr
  *
- * Description: Some type of interrupt has occured which is slightly
+ * Description: Some type of interrupt has occurred which is slightly
  *              out of the ordinary.  We will now decode it fully, in
  *              this routine.  This is broken up in an attempt to save
  *              processing time.
@@ -7038,7 +7038,7 @@ void siwidr(ULONG port, UCHAR width)
  *
  * Function: sssyncv
  *
- * Description: Write the desired value to the Sync Regisiter for the
+ * Description: Write the desired value to the Sync Register for the
  *              ID specified.
  *
  *---------------------------------------------------------------------*/
index 36a7d703be16a33c921875358c9f3b61e6613de0..3ddc8b1f10a96a295b0d57f48f5ba3e40a184fd6 100644 (file)
@@ -1,10 +1,11 @@
           BusLogic MultiMaster and FlashPoint SCSI Driver for Linux
 
-                        Version 2.0.14 for Linux 2.0
+                        Version 2.0.15 for Linux 2.0
+                        Version 2.1.15 for Linux 2.1
 
                              PRODUCTION RELEASE
 
-                                29 April 1998
+                               17 August 1998
 
                               Leonard N. Zubkoff
                               Dandelion Digital
@@ -80,7 +81,7 @@ including: ... Linux ...".
 
 Mylex Corporation is located at 34551 Ardenwood Blvd., Fremont, California
 94555, USA and can be reached at 510/796-6100 or on the World Wide Web at
-http://www.mylex.com.  Mylex Technical Support can be reached by electronic
+http://www.mylex.com.  Mylex HBA Technical Support can be reached by electronic
 mail at techsup@mylex.com, by Voice at 510/608-2400, or by FAX at 510/745-7715.
 Contact information for offices in Europe and Japan is available on the Web
 site.
@@ -584,16 +585,16 @@ NOTE: Module Utilities 2.1.71 or later is required for correct parsing
 
                              DRIVER INSTALLATION
 
-This distribution was prepared for Linux kernel version 2.0.33, but should be
+This distribution was prepared for Linux kernel version 2.0.35, but should be
 compatible with 2.0.4 or any later 2.0 series kernel.
 
 To install the new BusLogic SCSI driver, you may use the following commands,
 replacing "/usr/src" with wherever you keep your Linux kernel source tree:
 
   cd /usr/src
-  tar -xvzf BusLogic-2.0.14.tar.gz
+  tar -xvzf BusLogic-2.0.15.tar.gz
   mv README.* LICENSE.* BusLogic.[ch] FlashPoint.c linux/drivers/scsi
-  patch -p < BusLogic.patch
+  patch -p0 < BusLogic.patch (only for 2.0.33 and below)
   cd linux
   make config
   make depend
index a786fabc699187a716d0d9b6ce71cafef40520f4..cdf69293f7d5fe2441254ddb44ae86687e5122f4 100644 (file)
@@ -1,6 +1,5 @@
 Please see the file README.BusLogic for information about Linux support for
 Mylex (formerly BusLogic) MultiMaster and FlashPoint SCSI Host Adapters.
 
-The Mylex DAC960 PCI RAID Controllers are not supported at the present time,
-but work on a Linux driver for the DAC960 is in progress.  Please consult
+The Mylex DAC960 PCI RAID Controllers are now supported.  Please consult
 http://www.dandelion.com/Linux/ for further information on the DAC960 driver.
index 90c18695a094b5b9170d28cc2a79f8a865be94c2..e9d5ac0d78f150a655a9a8da7d00c9efd8ee0e24 100644 (file)
@@ -96,6 +96,8 @@ void autofs_hash_insert(struct autofs_dirhash *dh, struct autofs_dir_ent *ent)
        ent->next = *dhnp;
        ent->back = dhnp;
        *dhnp = ent;
+        if ( ent->next )
+          ent->next->back = &(ent->next);
 }
 
 void autofs_hash_delete(struct autofs_dir_ent *ent)
index 1b1b93bdb77ebf55a49be68fb791270d10d48f04..ae94eded519afe4a695c13aa1eb8370961384f9e 100644 (file)
@@ -53,6 +53,8 @@ struct pt_regs {
 #define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->cs))
 #define instruction_pointer(regs) ((regs)->eip)
 extern void show_regs(struct pt_regs *);
+struct task_struct;
+extern void get_pt_regs_for_task(struct pt_regs *, struct task_struct *p);
 #endif
 
 #endif
index de9a3d072c9ffdc13a3dd716ce88beb08c6e29a3..8ce98f5b5eaa9a17a3ae2278f40006a876f0bbd2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Revision: 2.5 $$Date: 1998/08/03 16:57:01 $
+/* $Revision: 2.6 $$Date: 1998/08/10 16:57:01 $
  * linux/include/linux/cyclades.h
  *
  * This file is maintained by Ivan Passos <ivan@cyclades.com>, 
@@ -492,7 +492,7 @@ struct cyclades_card {
     long base_addr;
     long ctl_addr;
     int irq;
-    int num_chips;     /* 0 if card absent, 1 if Z/PCI, else Y */
+    int num_chips;     /* 0 if card absent, -1 if Z/PCI, else Y */
     int first_line;    /* minor number of first channel on card */
     int bus_index;     /* address shift - 0 for ISA, 1 for PCI */
     int        inact_ctrl;     /* FW Inactivity control - 0 disabled, 1 enabled */
index 37d1fb19a7d631fffd67d05bd36161942907e13c..d5533077a0357ee738113c03a9be92978934d1b4 100644 (file)
 #define PCI_DEVICE_ID_INTEL_82443BX_0  0x7190
 #define PCI_DEVICE_ID_INTEL_82443BX_1  0x7191
 #define PCI_DEVICE_ID_INTEL_82443BX_2  0x7192
+#define PCI_DEVICE_ID_INTEL_82443GX_0  0x71A0
+#define PCI_DEVICE_ID_INTEL_82443GX_1  0x71A1
+#define PCI_DEVICE_ID_INTEL_82443GX_2  0x71A2
 #define PCI_DEVICE_ID_INTEL_P6         0x84c4
 #define PCI_DEVICE_ID_INTEL_82450GX    0x84c5
 
index 1746c67ca7a6dcbe9e15734085b833e679ae7ecf..9fb1efca57e7d0873a4ed47b1b886aaf9334b151 100644 (file)
@@ -9,6 +9,8 @@
 
 #define ROSE_MTU       251
 
+#define ROSE_MAX_DIGIS 6
+
 #define        ROSE_DEFER      1
 #define ROSE_T1                2
 #define        ROSE_T2         3
 #define        SIOCRSGCAUSE            (SIOCPROTOPRIVATE+0)
 #define        SIOCRSSCAUSE            (SIOCPROTOPRIVATE+1)
 #define        SIOCRSL2CALL            (SIOCPROTOPRIVATE+2)
+#define        SIOCRSSL2CALL           (SIOCPROTOPRIVATE+2)
 #define        SIOCRSACCEPT            (SIOCPROTOPRIVATE+3)
-#define        SIOCRSCLRRT             (SIOCPROTOPRIVATE+4)
+#define        SIOCRSCLRRT                     (SIOCPROTOPRIVATE+4)
+#define        SIOCRSGL2CALL           (SIOCPROTOPRIVATE+5)
+#define        SIOCRSGFACILITIES       (SIOCPROTOPRIVATE+6)
 
 #define        ROSE_DTE_ORIGINATED     0x00
 #define        ROSE_NUMBER_BUSY        0x01
 #define        ROSE_SHIP_ABSENT        0x39
 
 typedef struct {
-       char            rose_addr[5];
+       char                    rose_addr[5];
 } rose_address;
 
 struct sockaddr_rose {
        unsigned short  srose_family;
        rose_address    srose_addr;
        ax25_address    srose_call;
-       int             srose_ndigis;
+       unsigned int    srose_ndigis;
        ax25_address    srose_digi;
 };
 
+struct full_sockaddr_rose {
+       unsigned short  srose_family;
+       rose_address    srose_addr;
+       ax25_address    srose_call;
+       unsigned int    srose_ndigis;
+       ax25_address    srose_digis[ROSE_MAX_DIGIS];
+};
+
 struct rose_route_struct {
        rose_address    address;
        unsigned short  mask;
        ax25_address    neighbour;
-       char            device[16];
+       char                    device[16];
        unsigned char   ndigis;
        ax25_address    digipeaters[AX25_MAX_DIGIS];
 };
@@ -60,4 +73,16 @@ struct rose_cause_struct {
        unsigned char   diagnostic;
 };
 
+struct rose_facilities_struct {
+       rose_address    source_addr,   dest_addr;
+       ax25_address    source_call,   dest_call;
+       unsigned char   source_ndigis, dest_ndigis;
+       ax25_address    source_digis[ROSE_MAX_DIGIS];
+       ax25_address    dest_digis[ROSE_MAX_DIGIS];
+       unsigned int    rand;
+       rose_address    fail_addr;
+       ax25_address    fail_call;
+};
+
+
 #endif
index 4bf38063a6f9098b335b1dfdb355cf1c29b4fb82..e868e517f4ef5efec66273fb27e398a1d4fcfd09 100644 (file)
@@ -18,6 +18,7 @@
 #define        ROSE_Q_BIT                      0x80
 #define        ROSE_D_BIT                      0x40
 #define        ROSE_M_BIT                      0x10
+#define        M_BIT                           0x10
 
 #define        ROSE_CALL_REQUEST               0x0B
 #define        ROSE_CALL_ACCEPTED              0x0F
 #define        ROSE_DEFAULT_ROUTING            1                       /* Default routing flag */
 #define        ROSE_DEFAULT_FAIL_TIMEOUT       (120 * ROSE_SLOWHZ)     /* Time until link considered usable */
 #define        ROSE_DEFAULT_MAXVC              50                      /* Maximum number of VCs per neighbour */
-#define ROSE_DEFAULT_WINDOW_SIZE       3                       /* Default window value */
+#define ROSE_DEFAULT_WINDOW_SIZE       7                       /* Default window value */
 
 #define ROSE_MODULUS                   8
 #define        ROSE_MAX_PACKET_SIZE            251                     /* Maximum Packet Size */
 
+#define ROSE_MAX_WINDOW_LEN            ((AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 300) * 7)
+
 #define        ROSE_COND_ACK_PENDING           0x01
 #define        ROSE_COND_PEER_RX_BUSY          0x02
 #define        ROSE_COND_OWN_RX_BUSY           0x04
 
-#define        FAC_NATIONAL                    0x00
-#define        FAC_CCITT                       0x0F
+#define        FAC_NATIONAL                            0x00
+#define        FAC_CCITT                                       0x0F
 
-#define        FAC_NATIONAL_RAND               0x7F
-#define        FAC_NATIONAL_FLAGS              0x3F
+#define        FAC_NATIONAL_RAND                       0x7F
+#define        FAC_NATIONAL_FLAGS                      0x3F
 #define        FAC_NATIONAL_DEST_DIGI          0xE9
 #define        FAC_NATIONAL_SRC_DIGI           0xEB
+#define        FAC_NATIONAL_FAIL_CALL          0xED
+#define        FAC_NATIONAL_FAIL_ADD           0xEE
+#define        FAC_NATIONAL_DIGIS                      0xEF
 
-#define        FAC_CCITT_DEST_NSAP             0xC9
-#define        FAC_CCITT_SRC_NSAP              0xCB
+#define        FAC_CCITT_DEST_NSAP                     0xC9
+#define        FAC_CCITT_SRC_NSAP                      0xCB
 
 struct rose_neigh {
        struct rose_neigh       *next;
@@ -91,28 +97,29 @@ struct rose_neigh {
        struct timer_list       timer;
 };
 
+#define ROSE_MAX_ALTERNATE 3
 struct rose_node {
        struct rose_node        *next;
        rose_address            address;
        unsigned short          mask;
        unsigned char           count;
-       struct rose_neigh       *neighbour[3];
+       struct rose_neigh       *neighbour[ROSE_MAX_ALTERNATE];
 };
 
+typedef struct {
+       unsigned int            lci;
+       struct rose_neigh       *neigh;
+       unsigned short          vs, vr, va, vl;
+       unsigned short          pending;
+       unsigned char           state, condition;
+       struct timer_list       timer;
+} rose_tr;
+
 struct rose_route {
        struct rose_route       *next;
        rose_address            src_addr, dest_addr;
        ax25_address            src_call, dest_call;
-       unsigned int            lci1, lci2;
-       struct rose_neigh       *neigh1, *neigh2;
-       unsigned int            rand;
-};
-
-struct rose_facilities {
-       rose_address            source_addr,   dest_addr;
-       ax25_address            source_call,   dest_call;
-       unsigned char           source_ndigis, dest_ndigis;
-       ax25_address            source_digi,   dest_digi;
+       rose_tr                         tr1, tr2;
        unsigned int            rand;
 };
 
@@ -120,7 +127,8 @@ typedef struct {
        rose_address            source_addr,   dest_addr;
        ax25_address            source_call,   dest_call;
        unsigned char           source_ndigis, dest_ndigis;
-       ax25_address            source_digi,   dest_digi;
+       ax25_address            source_digis[ROSE_MAX_DIGIS];
+       ax25_address            dest_digis[ROSE_MAX_DIGIS];
        struct rose_neigh       *neighbour;
        struct device           *device;
        unsigned int            lci, rand;
@@ -129,6 +137,12 @@ typedef struct {
        unsigned short          vs, vr, va, vl;
        unsigned short          timer;
        unsigned short          t1, t2, t3, hb;
+#ifdef M_BIT
+       unsigned short          fraglen;
+       struct sk_buff_head     frag_queue;
+#endif
+       struct sk_buff_head     ack_queue;
+       struct rose_facilities_struct facilities;
        struct sock             *sk;            /* Backlink to socket */
 } rose_cb;
 
@@ -170,14 +184,19 @@ extern void rose_transmit_diagnostic(struct rose_neigh *, unsigned char);
 extern void rose_transmit_clear_request(struct rose_neigh *, unsigned int, unsigned char, unsigned char);
 extern void rose_transmit_link(struct sk_buff *, struct rose_neigh *);
 
+/* rose_loopback.c */
+extern void rose_loopback_init(void);
+extern void rose_loopback_clear(void);
+extern int rose_loopback_queue(struct sk_buff *, struct rose_neigh *);
+
 /* rose_out.c */
 extern void rose_kick(struct sock *);
 extern void rose_enquiry_response(struct sock *);
-extern void rose_check_iframes_acked(struct sock *, unsigned short);
 
 /* rose_route.c */
 extern void rose_rt_device_down(struct device *);
 extern void rose_link_device_down(struct device *);
+extern void rose_clean_neighbour(struct rose_neigh *);
 extern struct device *rose_dev_first(void);
 extern struct device *rose_dev_get(rose_address *);
 extern struct rose_route *rose_route_free_lci(unsigned int, struct rose_neigh *);
@@ -193,10 +212,11 @@ extern void rose_rt_free(void);
 
 /* rose_subr.c */
 extern void rose_clear_queues(struct sock *);
+extern void rose_frames_acked(struct sock *, unsigned short);
 extern int  rose_validate_nr(struct sock *, unsigned short);
 extern void rose_write_internal(struct sock *, int);
 extern int  rose_decode(struct sk_buff *, int *, int *, int *, int *, int *);
-extern int  rose_parse_facilities(struct sk_buff *, struct rose_facilities *);
+extern int  rose_parse_facilities(unsigned char *, struct rose_facilities_struct *);
 extern int  rose_create_facilities(unsigned char *, rose_cb *);
 
 /* rose_timer.c */
@@ -206,4 +226,8 @@ extern void rose_set_timer(struct sock *);
 extern void rose_register_sysctl(void);
 extern void rose_unregister_sysctl(void);
 
+/* rose_transit.c */
+void rose_transit(struct sk_buff *, rose_tr *, rose_tr *);
+void rose_init_transit(rose_tr *, unsigned int, struct rose_neigh *);
+
 #endif
index ad6fa4f25e83a328f7e5d72e1e05f205fabcf761..10b3849f4908049a7928730f0c5f0701cc91babe 100644 (file)
@@ -298,6 +298,7 @@ struct symbol_table symbol_table = {
        X(kill_proc),
        X(kill_pg),
        X(kill_sl),
+       X(force_sig),
 
        /* misc */
        X(panic),
index 1e72c56c7ebc35d01eeda200e03cfc272dc04bec..65a38c542cbce53dad667062017b2f48a3f6c890 100644 (file)
@@ -943,7 +943,7 @@ static int tcp_select(struct sock *sk, int sel_type, select_table *wait)
                return 1;
 
        case SEL_EX:
-               if (sk->urg_data)
+               if (sk->urg_data & URG_VALID)
                        return 1;
                break;
        }
index 24f983ec6ee0184ff70d155ea356958d196bf305..3cfb52156d456d6ca3a4673db99510fa54dc9ae4 100644 (file)
@@ -858,7 +858,7 @@ void tcp_send_fin(struct sock *sk)
        struct tcphdr *th =(struct tcphdr *)&sk->dummy_th;
        struct tcphdr *t1;
        struct sk_buff *buff;
-       struct device *dev=NULL;
+       struct device *dev=sk->bound_device;
        int tmp;
                
        buff = sock_wmalloc(sk, MAX_RESET_SIZE,1 , GFP_KERNEL);
@@ -962,7 +962,7 @@ void tcp_send_synack(struct sock * newsk, struct sock * sk, struct sk_buff * skb
        struct tcphdr *t1;
        unsigned char *ptr;
        struct sk_buff * buff;
-       struct device *ndev=NULL;
+       struct device *ndev=newsk->bound_device;
        int tmp;
 
        buff = sock_wmalloc(newsk, MAX_SYN_SIZE, 1, GFP_ATOMIC);
@@ -1121,7 +1121,7 @@ void tcp_send_ack(struct sock *sk)
 {
        struct sk_buff *buff;
        struct tcphdr *t1;
-       struct device *dev = NULL;
+       struct device *dev = sk->bound_device;
        int tmp;
 
        if(sk->zapped)
@@ -1216,7 +1216,7 @@ void tcp_write_wakeup(struct sock *sk)
 {
        struct sk_buff *buff,*skb;
        struct tcphdr *t1;
-       struct device *dev=NULL;
+       struct device *dev=sk->bound_device;
        int tmp;
 
        if (sk->zapped)
index 0d71de9cf2541f61057ef16f5fec6ff33d22d993..064fa7ca984eef496e825a137be79f0039e16f2a 100644 (file)
@@ -8,7 +8,8 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := rose.o
-O_OBJS  := af_rose.o sysctl_net_rose.o rose_dev.o rose_in.o rose_link.o rose_out.o rose_route.o rose_subr.o rose_timer.o
+O_OBJS  := af_rose.o sysctl_net_rose.o rose_dev.o rose_in.o rose_link.o \
+rose_loopback.o rose_out.o rose_route.o rose_subr.o rose_timer.o
 M_OBJS   := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
index 7cc4588a625e6daa7ca8b56e3589b19cd5333f94..368d7728ea2e9e7d7fbdc6a8dedd5bf06e691e84 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     ROSE release 003
+ *     ROSE release 006
  *
  *     This code REQUIRES 2.1.0 or higher/ NET3.029
  *
  *                     Terry (VK2KTJ)  Added support for variable length
  *                                     address masks.
  *     ROSE 002        Jonathan(G4KLX) Changed hdrincl to qbitincl.
- *                                     Added random number facilities entry.
+ *                 Added random number facilities entry.
  *     ROSE 003        Jonathan(G4KLX) Added use count to neighbour.
+ *     ROSE 004        Jean-Paul(F6FBB) Added LoopBack, M-Bit and
+ *                                     FPAC facilities.
+ *  ROSE 005    Jean-Paul(F6FBB) Added rose_clean_neighbour
+ *  ROSE 006    Jean-Paul(F6FBB) Accept up to 6 digis
+ *              Fixed a possible loop in facilities
  */
 
 #include <linux/config.h>
@@ -198,6 +203,7 @@ void rose_kill_by_neigh(struct rose_neigh *neigh)
 
        for (s = rose_list; s != NULL; s = s->next) {
                if (s->protinfo.rose->neighbour == neigh) {
+                       rose_clear_queues(s); /* F6FBB */
                        s->protinfo.rose->cause      = ROSE_OUT_OF_ORDER;
                        s->protinfo.rose->diagnostic = 0;
                        s->protinfo.rose->state     = ROSE_STATE_0;
@@ -221,6 +227,7 @@ static void rose_kill_by_device(struct device *dev)
        
        for (s = rose_list; s != NULL; s = s->next) {
                if (s->protinfo.rose->device == dev) {
+                       rose_clear_queues(s); /* F6FBB */
                        s->protinfo.rose->cause  = ROSE_OUT_OF_ORDER;
                        s->protinfo.rose->diagnostic = 0;
                        s->protinfo.rose->state  = ROSE_STATE_0;
@@ -542,7 +549,7 @@ static int rose_listen(struct socket *sock, int backlog)
                sk->protinfo.rose->dest_ndigis = 0;
                memset(&sk->protinfo.rose->dest_addr, '\0', ROSE_ADDR_LEN);
                memset(&sk->protinfo.rose->dest_call, '\0', AX25_ADDR_LEN);
-               memset(&sk->protinfo.rose->dest_digi, '\0', AX25_ADDR_LEN);
+               memset(sk->protinfo.rose->dest_digis, '\0', AX25_ADDR_LEN*ROSE_MAX_DIGIS);
                sk->max_ack_backlog = backlog;
                sk->state           = TCP_LISTEN;
                return 0;
@@ -579,7 +586,11 @@ static int rose_create(struct socket *sock, int protocol)
        skb_queue_head_init(&sk->receive_queue);
        skb_queue_head_init(&sk->write_queue);
        skb_queue_head_init(&sk->back_log);
-
+       skb_queue_head_init(&rose->ack_queue);
+#ifdef M_BIT
+       skb_queue_head_init(&rose->frag_queue);
+       rose->fraglen    = 0;
+#endif
        init_timer(&sk->timer);
 
        sk->socket        = sock;
@@ -629,6 +640,11 @@ static struct sock *rose_make_new(struct sock *osk)
        skb_queue_head_init(&sk->receive_queue);
        skb_queue_head_init(&sk->write_queue);
        skb_queue_head_init(&sk->back_log);
+       skb_queue_head_init(&rose->ack_queue);
+#ifdef M_BIT
+       skb_queue_head_init(&rose->frag_queue);
+       rose->fraglen  = 0;
+#endif
 
        init_timer(&sk->timer);
 
@@ -728,16 +744,23 @@ static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
        struct sockaddr_rose *addr = (struct sockaddr_rose *)uaddr;
        struct device *dev;
        ax25_address *user, *source;
+       int n;
 
        if (sk->zapped == 0)
                return -EINVAL;
 
-       if (addr_len != sizeof(struct sockaddr_rose))
+       if (addr_len != sizeof(struct sockaddr_rose) && addr_len != sizeof(struct full_sockaddr_rose))
                return -EINVAL;
 
        if (addr->srose_family != AF_ROSE)
                return -EINVAL;
 
+       if (addr_len == sizeof(struct sockaddr_rose) && addr->srose_ndigis > 1)
+               return -EINVAL;
+
+       if (addr->srose_ndigis > ROSE_MAX_DIGIS)
+               return -EINVAL;
+
        if ((dev = rose_dev_get(&addr->srose_addr)) == NULL) {
                if (sk->debug)
                        printk("ROSE: bind failed: invalid address\n");
@@ -752,13 +775,19 @@ static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                user = source;
        }
 
-       sk->protinfo.rose->source_addr = addr->srose_addr;
-       sk->protinfo.rose->source_call = *user;
-       sk->protinfo.rose->device      = dev;
+       sk->protinfo.rose->source_addr   = addr->srose_addr;
+       sk->protinfo.rose->source_call   = *user;
+       sk->protinfo.rose->device        = dev;
+       sk->protinfo.rose->source_ndigis = addr->srose_ndigis;
 
-       if (addr->srose_ndigis == 1) {
-               sk->protinfo.rose->source_ndigis = 1;
-               sk->protinfo.rose->source_digi   = addr->srose_digi;
+       if (addr_len == sizeof(struct full_sockaddr_rose)) {
+               struct full_sockaddr_rose *full_addr = (struct full_sockaddr_rose *)uaddr;
+               for (n = 0 ; n < addr->srose_ndigis ; n++)
+                       sk->protinfo.rose->source_digis[n] = full_addr->srose_digis[n];
+       } else {
+               if (sk->protinfo.rose->source_ndigis == 1) {
+                       sk->protinfo.rose->source_digis[0] = addr->srose_digi;
+               }
        }
 
        rose_insert_socket(sk);
@@ -778,6 +807,7 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
        unsigned char cause, diagnostic;
        ax25_address *user;
        struct device *dev;
+       int n;
 
        if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
                sock->state = SS_CONNECTED;
@@ -795,14 +825,27 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
        sk->state   = TCP_CLOSE;
        sock->state = SS_UNCONNECTED;
 
-       if (addr_len != sizeof(struct sockaddr_rose))
+       if (addr_len != sizeof(struct sockaddr_rose) && addr_len != sizeof(struct full_sockaddr_rose))
                return -EINVAL;
 
        if (addr->srose_family != AF_ROSE)
                return -EINVAL;
 
-       if ((sk->protinfo.rose->neighbour = rose_get_neigh(&addr->srose_addr, &cause, &diagnostic)) == NULL)
+       if (addr_len == sizeof(struct sockaddr_rose) && addr->srose_ndigis > 1)
+               return -EINVAL;
+
+       if (addr->srose_ndigis > ROSE_MAX_DIGIS)
+               return -EINVAL;
+
+       /* Source + Destination digis should not exceed ROSE_MAX_DIGIS */
+       if ((sk->protinfo.rose->source_ndigis + addr->srose_ndigis) > ROSE_MAX_DIGIS)
+               return -EINVAL;
+
+       if ((sk->protinfo.rose->neighbour = rose_get_neigh(&addr->srose_addr, &cause, &diagnostic)) == NULL) {
+               sk->protinfo.rose->cause = cause;
+               sk->protinfo.rose->diagnostic = diagnostic;
                return -ENETUNREACH;
+       }
 
        if ((sk->protinfo.rose->lci = rose_new_lci(sk->protinfo.rose->neighbour)) == 0)
                return -ENETUNREACH;
@@ -823,13 +866,19 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
                rose_insert_socket(sk);         /* Finish the bind */
        }
 
-       sk->protinfo.rose->dest_addr = addr->srose_addr;
-       sk->protinfo.rose->dest_call = addr->srose_call;
-       sk->protinfo.rose->rand      = ((int)sk->protinfo.rose & 0xFFFF) + sk->protinfo.rose->lci;
+       sk->protinfo.rose->dest_addr   = addr->srose_addr;
+       sk->protinfo.rose->dest_call   = addr->srose_call;
+       sk->protinfo.rose->rand        = ((int)sk->protinfo.rose & 0xFFFF) + sk->protinfo.rose->lci;
+       sk->protinfo.rose->dest_ndigis = addr->srose_ndigis;
 
-       if (addr->srose_ndigis == 1) {
-               sk->protinfo.rose->dest_ndigis = 1;
-               sk->protinfo.rose->dest_digi   = addr->srose_digi;
+       if (addr_len == sizeof(struct full_sockaddr_rose)) {
+               struct full_sockaddr_rose *full_addr = (struct full_sockaddr_rose *)uaddr;
+               for (n = 0 ; n < addr->srose_ndigis ; n++)
+                       sk->protinfo.rose->dest_digis[n] = full_addr->srose_digis[n];
+       } else {
+               if (sk->protinfo.rose->dest_ndigis == 1) {
+                       sk->protinfo.rose->dest_digis[0] = addr->srose_digi;
+               }
        }
 
        /* Move to connecting socket, start sending Connect Requests */
@@ -937,29 +986,44 @@ static int rose_getname(struct socket *sock, struct sockaddr *uaddr,
 {
        struct sockaddr_rose *srose = (struct sockaddr_rose *)uaddr;
        struct sock *sk = (struct sock *)sock->data;
+       int n;
 
        if (peer != 0) {
                if (sk->state != TCP_ESTABLISHED)
                        return -ENOTCONN;
                srose->srose_family = AF_ROSE;
-               srose->srose_ndigis = 0;
                srose->srose_addr   = sk->protinfo.rose->dest_addr;
                srose->srose_call   = sk->protinfo.rose->dest_call;
-               if (sk->protinfo.rose->dest_ndigis == 1) {
-                       srose->srose_ndigis = 1;
-                       srose->srose_digi   = sk->protinfo.rose->dest_digi;
+               srose->srose_ndigis = sk->protinfo.rose->dest_ndigis;
+               if (*uaddr_len >= sizeof(struct full_sockaddr_rose)) {
+                       struct full_sockaddr_rose *full_srose = (struct full_sockaddr_rose *)uaddr;
+                       for (n = 0 ; n < sk->protinfo.rose->dest_ndigis ; n++)
+                               full_srose->srose_digis[n] = sk->protinfo.rose->dest_digis[n];
+                       *uaddr_len = sizeof(struct full_sockaddr_rose);
+               } else {
+                       if (sk->protinfo.rose->dest_ndigis >= 1) {
+                               srose->srose_ndigis = 1;
+                               srose->srose_digi = sk->protinfo.rose->dest_digis[0];
+                       }
+                       *uaddr_len = sizeof(struct sockaddr_rose);
                }
-               *uaddr_len = sizeof(struct sockaddr_rose);
        } else {
                srose->srose_family = AF_ROSE;
-               srose->srose_ndigis = 0;
                srose->srose_addr   = sk->protinfo.rose->source_addr;
                srose->srose_call   = sk->protinfo.rose->source_call;
-               if (sk->protinfo.rose->source_ndigis == 1) {
-                       srose->srose_ndigis = 1;
-                       srose->srose_digi   = sk->protinfo.rose->source_digi;
+               srose->srose_ndigis = sk->protinfo.rose->source_ndigis;
+               if (*uaddr_len >= sizeof(struct full_sockaddr_rose)) {
+                       struct full_sockaddr_rose *full_srose = (struct full_sockaddr_rose *)uaddr;
+                       for (n = 0 ; n < sk->protinfo.rose->source_ndigis ; n++)
+                               full_srose->srose_digis[n] = sk->protinfo.rose->source_digis[n];
+                       *uaddr_len = sizeof(struct full_sockaddr_rose);
+               } else {
+                       if (sk->protinfo.rose->source_ndigis >= 1) {
+                               srose->srose_ndigis = 1;
+                               srose->srose_digi = sk->protinfo.rose->source_digis[sk->protinfo.rose->source_ndigis-1];
+                       }
+                       *uaddr_len = sizeof(struct sockaddr_rose);
                }
-               *uaddr_len = sizeof(struct sockaddr_rose);
        }
 
        return 0;
@@ -969,14 +1033,21 @@ int rose_rx_call_request(struct sk_buff *skb, struct device *dev, struct rose_ne
 {
        struct sock *sk;
        struct sock *make;
-       struct rose_facilities facilities;
-
+       struct rose_facilities_struct facilities;
+       int n, len;
+       
        skb->sk = NULL;         /* Initially we don't know who it's for */
 
        /*
         *      skb->data points to the rose frame start
         */
-       if (!rose_parse_facilities(skb, &facilities)) {
+
+       len  = (((skb->data[3] >> 4) & 0x0F) + 1) / 2;
+       len += (((skb->data[3] >> 0) & 0x0F) + 1) / 2;
+
+       memset(&facilities, 0x00, sizeof(struct rose_facilities_struct));
+       
+       if (!rose_parse_facilities(skb->data + len + 4, &facilities)) {
                rose_transmit_clear_request(neigh, lci, ROSE_INVALID_FACILITY, 76);
                return 0;
        }
@@ -998,13 +1069,16 @@ int rose_rx_call_request(struct sk_buff *skb, struct device *dev, struct rose_ne
        make->protinfo.rose->dest_addr     = facilities.dest_addr;
        make->protinfo.rose->dest_call     = facilities.dest_call;
        make->protinfo.rose->dest_ndigis   = facilities.dest_ndigis;
-       make->protinfo.rose->dest_digi     = facilities.dest_digi;
+       for (n = 0 ; n < facilities.dest_ndigis ; n++)
+               make->protinfo.rose->dest_digis[n] = facilities.dest_digis[n];
        make->protinfo.rose->source_addr   = facilities.source_addr;
        make->protinfo.rose->source_call   = facilities.source_call;
        make->protinfo.rose->source_ndigis = facilities.source_ndigis;
-       make->protinfo.rose->source_digi   = facilities.source_digi;
+       for (n = 0 ; n < facilities.source_ndigis ; n++)
+               make->protinfo.rose->source_digis[n]= facilities.source_digis[n];
        make->protinfo.rose->neighbour     = neigh;
        make->protinfo.rose->device        = dev;
+       make->protinfo.rose->facilities    = facilities;
 
        make->protinfo.rose->neighbour->use++;
 
@@ -1040,10 +1114,10 @@ static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len, int no
        struct sock *sk = (struct sock *)sock->data;
        struct sockaddr_rose *usrose = (struct sockaddr_rose *)msg->msg_name;
        int err;
-       struct sockaddr_rose srose;
+       struct full_sockaddr_rose srose;
        struct sk_buff *skb;
        unsigned char *asmptr;
-       int size, qbit = 0;
+       int n, size, qbit = 0;
 
        if (sk->err)
                return sock_error(sk);
@@ -1063,15 +1137,19 @@ static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len, int no
                return -ENETUNREACH;
 
        if (usrose != NULL) {
-               if (msg->msg_namelen < sizeof(srose))
+               if (msg->msg_namelen != sizeof(struct sockaddr_rose) && msg->msg_namelen != sizeof(struct full_sockaddr_rose))
                        return -EINVAL;
-               srose = *usrose;
+               memset(&srose, 0, sizeof(struct full_sockaddr_rose));
+               memcpy(&srose, usrose, msg->msg_namelen);
                if (rosecmp(&sk->protinfo.rose->dest_addr, &srose.srose_addr) != 0 ||
                    ax25cmp(&sk->protinfo.rose->dest_call, &srose.srose_call) != 0)
                        return -EISCONN;
-               if (srose.srose_ndigis == 1 && sk->protinfo.rose->dest_ndigis == 1) {
-                       if (ax25cmp(&sk->protinfo.rose->dest_digi, &srose.srose_digi) != 0)
-                               return -EISCONN;
+               if (srose.srose_ndigis != sk->protinfo.rose->dest_ndigis)
+                       return -EISCONN;
+               if (srose.srose_ndigis == sk->protinfo.rose->dest_ndigis) {
+                       for (n = 0 ; n < srose.srose_ndigis ; n++)
+                               if (ax25cmp(&sk->protinfo.rose->dest_digis[n], &srose.srose_digis[n]) != 0)
+                                       return -EISCONN;
                }
                if (srose.srose_family != AF_ROSE)
                        return -EINVAL;
@@ -1082,12 +1160,9 @@ static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len, int no
                srose.srose_family = AF_ROSE;
                srose.srose_addr   = sk->protinfo.rose->dest_addr;
                srose.srose_call   = sk->protinfo.rose->dest_call;
-               srose.srose_ndigis = 0;
-
-               if (sk->protinfo.rose->dest_ndigis == 1) {
-                       srose.srose_ndigis = 1;
-                       srose.srose_digi   = sk->protinfo.rose->dest_digi;
-               }
+               srose.srose_ndigis = sk->protinfo.rose->dest_ndigis;
+               for (n = 0 ; n < sk->protinfo.rose->dest_ndigis ; n++)
+                       srose.srose_digis[n] = sk->protinfo.rose->dest_digis[n];
        }
 
        if (sk->debug)
@@ -1154,10 +1229,55 @@ static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len, int no
                return -ENOTCONN;
        }
 
-       skb_queue_tail(&sk->write_queue, skb);  /* Shove it onto the queue */
+#ifdef M_BIT
+#define ROSE_PACLEN (256-ROSE_MIN_LEN)
+       if (skb->len - ROSE_MIN_LEN > ROSE_PACLEN) {
+               unsigned char header[ROSE_MIN_LEN];
+               struct sk_buff *skbn;
+               int frontlen;
+               int lg;
+               
+               /* Save a copy of the Header */
+               memcpy(header, skb->data, ROSE_MIN_LEN);
+               skb_pull(skb, ROSE_MIN_LEN);
+
+               frontlen = skb_headroom(skb);
+
+               while (skb->len > 0) {
+                       if ((skbn = sock_alloc_send_skb(sk, frontlen + ROSE_PACLEN, 0, 0, &err)) == NULL)
+                               return err;
+
+                       skbn->sk   = sk;
+                       skbn->free = 1;
+                       skbn->arp  = 1;
+
+                       skb_reserve(skbn, frontlen);
+
+                       lg = (ROSE_PACLEN > skb->len) ? skb->len : ROSE_PACLEN;
 
-       if (sk->protinfo.rose->state == ROSE_STATE_3)
-               rose_kick(sk);
+                       /* Copy the user data */
+                       memcpy(skb_put(skbn, lg), skb->data, lg);
+                       skb_pull(skb, lg);
+
+                       /* Duplicate the Header */
+                       skb_push(skbn, ROSE_MIN_LEN);
+                       memcpy(skbn->data, header, ROSE_MIN_LEN);
+
+                       if (skb->len > 0)
+                               skbn->data[2] |= M_BIT;
+               
+                       skb_queue_tail(&sk->write_queue, skbn); /* Throw it on the queue */
+               }
+               
+               skb->free = 1;
+               kfree_skb(skb, FREE_WRITE);
+       } else {
+               skb_queue_tail(&sk->write_queue, skb);          /* Throw it on the queue */
+       }
+#else
+       skb_queue_tail(&sk->write_queue, skb);  /* Shove it onto the queue */
+#endif
+       rose_kick(sk);
 
        return len;
 }
@@ -1171,7 +1291,7 @@ static int rose_recvmsg(struct socket *sock, struct msghdr *msg, int size, int n
        int copied, qbit;
        unsigned char *asmptr;
        struct sk_buff *skb;
-       int er;
+       int n, er;
 
        if (sk->err)
                return sock_error(sk);
@@ -1208,14 +1328,19 @@ static int rose_recvmsg(struct socket *sock, struct msghdr *msg, int size, int n
                srose->srose_family = AF_ROSE;
                srose->srose_addr   = sk->protinfo.rose->dest_addr;
                srose->srose_call   = sk->protinfo.rose->dest_call;
-               srose->srose_ndigis = 0;
-
-               if (sk->protinfo.rose->dest_ndigis == 1) {
-                       srose->srose_ndigis = 1;
-                       srose->srose_digi   = sk->protinfo.rose->dest_digi;
+               srose->srose_ndigis = sk->protinfo.rose->dest_ndigis;
+               if (*addr_len >= sizeof(struct full_sockaddr_rose)) {
+                       struct full_sockaddr_rose *full_srose = (struct full_sockaddr_rose *)msg->msg_name;
+                       for (n = 0 ; n < sk->protinfo.rose->dest_ndigis ; n++)
+                               full_srose->srose_digis[n] = sk->protinfo.rose->dest_digis[n];
+                       *addr_len = sizeof(struct full_sockaddr_rose);
+               } else {
+                       if (sk->protinfo.rose->dest_ndigis >= 1) {
+                               srose->srose_ndigis = 1;
+                               srose->srose_digi = sk->protinfo.rose->dest_digis[0];
+                       }
+                       *addr_len = sizeof(struct sockaddr_rose);
                }
-
-               *addr_len = sizeof(*srose);
        }
 
        skb_free_datagram(sk, skb);
@@ -1313,7 +1438,7 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                        return 0;
                }
 
-               case SIOCRSL2CALL:
+               case SIOCRSSL2CALL:
                        if (!suser()) return -EPERM;
                        if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(ax25_address))) != 0)
                                return err;
@@ -1324,6 +1449,12 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                                ax25_listen_register(&rose_callsign, NULL);
                        return 0;
 
+               case SIOCRSGL2CALL:
+                       if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(ax25_address))) != 0)
+                               return err;
+                       memcpy_tofs((void *)arg, &rose_callsign, sizeof(ax25_address));
+                       return 0;
+
                case SIOCRSACCEPT:
                        if (sk->protinfo.rose->state == ROSE_STATE_5) {
                                rose_write_internal(sk, ROSE_CALL_ACCEPTED);
@@ -1336,6 +1467,13 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                        }
                        return 0;
 
+               case SIOCRSGFACILITIES: {
+                       if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct rose_facilities_struct))) != 0)
+                               return err;
+                       memcpy_tofs((void *)arg, &sk->protinfo.rose->facilities, sizeof(struct rose_facilities_struct));
+                       return 0;
+               }
+
                default:
                        return dev_ioctl(cmd, (void *)arg);
        }
@@ -1355,7 +1493,7 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length, i
 
        cli();
 
-       len += sprintf(buffer, "dest_addr  dest_call src_addr   src_call  dev   lci st vs vr va   t  t1  t2  t3  hb    idle Snd-Q Rcv-Q Inode\n");
+       len += sprintf(buffer, "dest_addr  dest_call src_addr   src_call  dev   lci neigh st vs vr va   t  t1  t2  t3  hb    idle Snd-Q Rcv-Q Inode\n");
 
        for (s = rose_list; s != NULL; s = s->next) {
                if ((dev = s->protinfo.rose->device) == NULL)
@@ -1372,9 +1510,10 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length, i
                else
                        callsign = ax2asc(&s->protinfo.rose->source_call);
 
-               len += sprintf(buffer + len, "%-10s %-9s %-5s %3.3X  %d  %d  %d  %d %3d %3d %3d %3d %3d %3d/%03d %5d %5d %ld\n",
+               len += sprintf(buffer + len, "%-10s %-9s %-5s %3.3X %05d  %d  %d  %d  %d %3d %3d %3d %3d %3d %3d/%03d %5d %5d %ld\n",
                        rose2asc(&s->protinfo.rose->source_addr), callsign,
                        devname,  s->protinfo.rose->lci & 0x0FFF,
+                       (s->protinfo.rose->neighbour) ? s->protinfo.rose->neighbour->number : 0,
                        s->protinfo.rose->state,
                        s->protinfo.rose->vs, s->protinfo.rose->vr, s->protinfo.rose->va,
                        s->protinfo.rose->timer / ROSE_SLOWHZ,
@@ -1384,8 +1523,7 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length, i
                        s->protinfo.rose->hb    / ROSE_SLOWHZ,
                        0, 0,
                        s->wmem_alloc, s->rmem_alloc,
-                       s->socket && SOCK_INODE(s->socket) ?
-                       SOCK_INODE(s->socket)->i_ino : 0);
+                       s->socket && SOCK_INODE(s->socket) ? SOCK_INODE(s->socket)->i_ino : 0);
 
                pos = begin + len;
 
@@ -1468,7 +1606,11 @@ static struct device dev_rose[] = {
        {"rose2", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, rose_init},
        {"rose3", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, rose_init},
        {"rose4", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, rose_init},
-       {"rose5", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, rose_init}
+       {"rose5", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, rose_init},
+       {"rose6", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, rose_init},
+       {"rose7", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, rose_init},
+       {"rose8", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, rose_init},
+       {"rose9", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, rose_init}
 };
 
 void rose_proto_init(struct net_proto *pro)
@@ -1479,18 +1621,20 @@ void rose_proto_init(struct net_proto *pro)
 
        sock_register(rose_proto_ops.family, &rose_proto_ops);
        register_netdevice_notifier(&rose_dev_notifier);
-       printk(KERN_INFO "G4KLX ROSE for Linux. Version 0.3 for AX25.035 Linux 2.0\n");
+       printk(KERN_INFO "F6FBB/G4KLX ROSE for Linux. Version 0.62 for AX25.035 Linux 2.0\n");
 
        if (!ax25_protocol_register(AX25_P_ROSE, rose_route_frame))
                printk(KERN_ERR "ROSE: unable to register protocol with AX.25\n");
        if (!ax25_linkfail_register(rose_link_failed))
                printk(KERN_ERR "ROSE: unable to register linkfail handler with AX.25\n");
 
-       for (i = 0; i < 6; i++)
+       for (i = 0; i < 10; i++)
                register_netdev(&dev_rose[i]);
 
        rose_register_sysctl();
 
+       rose_loopback_init();
+
 #ifdef CONFIG_PROC_FS
        proc_net_register(&proc_net_rose);
        proc_net_register(&proc_net_rose_neigh);
@@ -1520,6 +1664,8 @@ void cleanup_module(void)
        proc_net_unregister(PROC_NET_RS_NODES);
        proc_net_unregister(PROC_NET_RS_ROUTES);
 #endif
+       rose_loopback_clear();
+
        rose_rt_free();
 
        ax25_protocol_release(AX25_P_ROSE);
@@ -1534,7 +1680,7 @@ void cleanup_module(void)
 
        sock_unregister(AF_ROSE);
 
-       for (i = 0; i < 6; i++) {
+       for (i = 0; i < 10; i++) {
                if (dev_rose[i].priv != NULL) {
                        kfree(dev_rose[i].priv);
                        dev_rose[i].priv = NULL;
diff --git a/net/rose/changes.doc b/net/rose/changes.doc
new file mode 100644 (file)
index 0000000..2d30b66
--- /dev/null
@@ -0,0 +1,10 @@
+Changes information in rose driver by F6FBB
+
+980728 : Added link add and route add from remote application
+         An adjacent is not removed if no node. It points to the
+                dummy node (0000000000)
+                
+980728 : Routing algorithm was falling to the next route if no choice
+         available for the selected address. Corrected.
+                
+980728 : Connect did not report cause and diagnostic. Added.
index 1b8be97175daa71ca7b8ca2219a0e8735f590bd7..13eebc97627b2a46451e489d925339f091828724 100644 (file)
@@ -17,7 +17,6 @@
  *
  *     History
  *     ROSE 001        Jonathan(G4KLX) Cloned from nr_in.c
- *     ROSE 003        Jonathan(G4KLX) Removed M bit processing.
  */
 
 #include <linux/config.h>
 #include <linux/interrupt.h>
 #include <net/rose.h>
 
+static int rose_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
+{
+       struct sk_buff *skbo, *skbn = skb;
+
+       if (more) {
+               sk->protinfo.rose->fraglen += skb->len;
+               skb_queue_tail(&sk->protinfo.rose->frag_queue, skb);
+               return 0;
+       }
+       
+       if (!more && sk->protinfo.rose->fraglen > 0) {  /* End of fragment */
+               sk->protinfo.rose->fraglen += skb->len;
+               skb_queue_tail(&sk->protinfo.rose->frag_queue, skb);
+
+               if ((skbn = alloc_skb(sk->protinfo.rose->fraglen, GFP_ATOMIC)) == NULL)
+                       return 1;
+
+               skbn->free = 1;
+               skbn->arp  = 1;
+               skbn->sk   = sk;
+               skbn->h.raw = skbn->data;
+
+               skbo = skb_dequeue(&sk->protinfo.rose->frag_queue);
+               memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len);
+               kfree_skb(skbo, FREE_READ);
+
+               while ((skbo = skb_dequeue(&sk->protinfo.rose->frag_queue)) != NULL) {
+                       skb_pull(skbo, ROSE_MIN_LEN);
+                       memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len);
+                       kfree_skb(skbo, FREE_READ);
+               }
+
+               sk->protinfo.rose->fraglen = 0;         
+       }
+
+       /* printk("FBB : lg=%ld\n", skbn->len); */
+       return sock_queue_rcv_skb(sk, skbn);
+}
+
 /*
  * State machine for state 1, Awaiting Call Accepted State.
  * The handling of the timer(s) is in file rose_timer.c.
@@ -52,6 +90,8 @@
  */
 static int rose_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype)
 {
+       int len;
+       
        switch (frametype) {
 
                case ROSE_CALL_ACCEPTED:
@@ -80,6 +120,18 @@ static int rose_state1_machine(struct sock *sk, struct sk_buff *skb, int framety
                        if (!sk->dead)
                                sk->state_change(sk);
                        sk->dead                 = 1;
+                       len = 5;        /* Minimum size of the frame data */
+                       if (skb->len > len) {
+                               /* Address block */
+                               len += 1;
+                               len += (((skb->data[5] >> 4) & 0x0F) + 1) / 2;
+                               len += (((skb->data[5] >> 0) & 0x0F) + 1) / 2;
+
+                               if (skb->len > len) {
+                                       /* Facilities */
+                                       rose_parse_facilities(skb->data + len, &sk->protinfo.rose->facilities);
+                               }
+                       }
                        break;
 
                default:
@@ -96,12 +148,27 @@ static int rose_state1_machine(struct sock *sk, struct sk_buff *skb, int framety
  */
 static int rose_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype)
 {
+       int len;
+       
        switch (frametype) {
 
                case ROSE_CLEAR_REQUEST:
                        rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
                        sk->protinfo.rose->cause      = skb->data[3];
                        sk->protinfo.rose->diagnostic = skb->data[4];
+                       len = 5;
+                       if (skb->len > len) {
+                               /* Address block */
+                               len += 1;
+                               len += (((skb->data[5] >> 4) & 0x0F) + 1) / 2;
+                               len += (((skb->data[5] >> 0) & 0x0F) + 1) / 2;
+
+                               if (skb->len > len) {
+                                       /* Facilities */
+                                       rose_parse_facilities(skb->data + len, &sk->protinfo.rose->facilities);
+                               }
+                       }
+                       /* fall in next case ... */
                case ROSE_CLEAR_CONFIRMATION:
                        rose_clear_queues(sk);
                        sk->protinfo.rose->neighbour->use--;
@@ -129,6 +196,7 @@ static int rose_state2_machine(struct sock *sk, struct sk_buff *skb, int framety
 static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype, int ns, int nr, int q, int d, int m)
 {
        int queued = 0;
+       int len;
 
        switch (frametype) {
 
@@ -155,14 +223,22 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
                        if (!sk->dead)
                                sk->state_change(sk);
                        sk->dead                 = 1;
+                       len = 5;
+                       if (skb->len > len) {
+                               /* Address block */
+                               len += 1;
+                               len += (((skb->data[5] >> 4) & 0x0F) + 1) / 2;
+                               len += (((skb->data[5] >> 0) & 0x0F) + 1) / 2;
+
+                               if (skb->len > len) {
+                                       /* Facilities */
+                                       rose_parse_facilities(skb->data + len, &sk->protinfo.rose->facilities);
+                               }
+                       }
                        break;
 
                case ROSE_RR:
                case ROSE_RNR:
-                       if (frametype == ROSE_RNR)
-                               sk->protinfo.rose->condition |= ROSE_COND_PEER_RX_BUSY;
-                       else
-                               sk->protinfo.rose->condition &= ~ROSE_COND_PEER_RX_BUSY;
                        if (!rose_validate_nr(sk, nr)) {
                                rose_clear_queues(sk);
                                rose_write_internal(sk, ROSE_RESET_REQUEST);
@@ -174,10 +250,12 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
                                sk->protinfo.rose->state     = ROSE_STATE_4;
                                sk->protinfo.rose->timer     = sk->protinfo.rose->t2;
                        } else {
-                               if (sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY) {
-                                       sk->protinfo.rose->va = nr;
-                               } else {
-                                       rose_check_iframes_acked(sk, nr);
+                               rose_frames_acked(sk, nr);
+                               /* F6FBB : only set the flag ! */
+                               if (frametype == ROSE_RNR)
+                                       sk->protinfo.rose->condition |= ROSE_COND_PEER_RX_BUSY;
+                               else {
+                                       sk->protinfo.rose->condition &= ~ROSE_COND_PEER_RX_BUSY;
                                }
                        }
                        break;
@@ -196,18 +274,26 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
                                sk->protinfo.rose->timer     = sk->protinfo.rose->t2;
                                break;
                        }
-                       if (sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY) {
-                               sk->protinfo.rose->va = nr;
-                       } else {
-                               rose_check_iframes_acked(sk, nr);
-                       }
-                       if (sk->protinfo.rose->condition & ROSE_COND_OWN_RX_BUSY)
-                               break;
+                       rose_frames_acked(sk, nr);
                        if (ns == sk->protinfo.rose->vr) {
-                               if (sock_queue_rcv_skb(sk, skb) == 0) {
+                               if (rose_queue_rx_frame(sk, skb, m) == 0) {
                                        sk->protinfo.rose->vr = (sk->protinfo.rose->vr + 1) % ROSE_MODULUS;
                                        queued = 1;
                                } else {
+                                       /* should never happen ! */
+                                       rose_clear_queues(sk);
+                                       rose_write_internal(sk, ROSE_RESET_REQUEST);
+                                       sk->protinfo.rose->condition = 0x00;
+                                       sk->protinfo.rose->vs        = 0;
+                                       sk->protinfo.rose->vr        = 0;
+                                       sk->protinfo.rose->va        = 0;
+                                       sk->protinfo.rose->vl        = 0;
+                                       sk->protinfo.rose->state     = ROSE_STATE_4;
+                                       sk->protinfo.rose->timer     = sk->protinfo.rose->t2;
+                                       break;
+                               }
+                               /* F6FBB : check if room enough for a full window */
+                               if (sk->rmem_alloc > (sk->rcvbuf - ROSE_MAX_WINDOW_LEN)) {
                                        sk->protinfo.rose->condition |= ROSE_COND_OWN_RX_BUSY;
                                }
                        }
@@ -240,6 +326,8 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
  */
 static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype)
 {
+       int len;
+       
        switch (frametype) {
 
                case ROSE_RESET_REQUEST:
@@ -268,6 +356,18 @@ static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int framety
                        if (!sk->dead)
                                sk->state_change(sk);
                        sk->dead                 = 1;
+                       len = 5;
+                       if (skb->len > len) {
+                               /* Address block */
+                               len += 1;
+                               len += (((skb->data[5] >> 4) & 0x0F) + 1) / 2;
+                               len += (((skb->data[5] >> 0) & 0x0F) + 1) / 2;
+
+                               if (skb->len > len) {
+                                       /* Facilities */
+                                       rose_parse_facilities(skb->data + len, &sk->protinfo.rose->facilities);
+                               }
+                       }
                        break;
 
                default:
@@ -284,6 +384,8 @@ static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int framety
  */
 static int rose_state5_machine(struct sock *sk, struct sk_buff *skb, int frametype)
 {
+       int len;
+       
        switch (frametype) {
 
                case ROSE_CLEAR_REQUEST:
@@ -299,6 +401,18 @@ static int rose_state5_machine(struct sock *sk, struct sk_buff *skb, int framety
                        if (!sk->dead)
                                sk->state_change(sk);
                        sk->dead                 = 1;
+                       len = 5;
+                       if (skb->len > len) {
+                               /* Address block */
+                               len += 1;
+                               len += (((skb->data[5] >> 4) & 0x0F) + 1) / 2;
+                               len += (((skb->data[5] >> 0) & 0x0F) + 1) / 2;
+
+                               if (skb->len > len) {
+                                       /* Facilities */
+                                       rose_parse_facilities(skb->data + len, &sk->protinfo.rose->facilities);
+                               }
+                       }
                        break;
        }
 
index 339165bd71aeb3d2625492cf79c92ed3a731df94..ff724650ab5d7c17c12cee93d9205e783477d52e 100644 (file)
@@ -101,7 +101,7 @@ static int rose_send_frame(struct sk_buff *skb, struct rose_neigh *neigh)
        else
                rose_call = &rose_callsign;
 
-       neigh->ax25 = ax25_send_frame(skb, 0, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
+       neigh->ax25 = ax25_send_frame(skb, 260, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
 
        return (neigh->ax25 != NULL);
 }
@@ -134,6 +134,8 @@ void rose_link_rx_restart(struct sk_buff *skb, struct rose_neigh *neigh, unsigne
 
        switch (frametype) {
                case ROSE_RESTART_REQUEST:
+                       /* Stop all existing routes on this link - F6FBB */
+                       rose_clean_neighbour(neigh);
                        neigh->t0timer   = 0;
                        neigh->restarted = 1;
                        neigh->dce_mode  = (skb->data[3] == ROSE_DTE_ORIGINATED);
@@ -261,10 +263,17 @@ void rose_transmit_clear_request(struct rose_neigh *neigh, unsigned int lci, uns
 {
        struct sk_buff *skb;
        unsigned char *dptr;
+       struct device *first;
        int len;
 
        len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 3;
-
+       
+       first = rose_dev_first();
+       if (first) {    
+               /* F6FBB - Adding facilities */
+               len += 6 + AX25_ADDR_LEN + 3 + ROSE_ADDR_LEN;
+       }
+       
        if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
                return;
 
@@ -272,7 +281,7 @@ void rose_transmit_clear_request(struct rose_neigh *neigh, unsigned int lci, uns
 
        skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN);
 
-       dptr = skb_put(skb, ROSE_MIN_LEN + 3);
+       dptr = skb_put(skb, skb_tailroom(skb));
 
        *dptr++ = AX25_P_ROSE;
        *dptr++ = ((lci >> 8) & 0x0F) | ROSE_GFI;
@@ -281,12 +290,29 @@ void rose_transmit_clear_request(struct rose_neigh *neigh, unsigned int lci, uns
        *dptr++ = cause;
        *dptr++ = diagnostic;
 
+       if (first) {    
+               /* F6FBB - Adding facilities */
+               *dptr++ = 0x00;         /* Address length */
+               *dptr++ = 4 + AX25_ADDR_LEN + 3 + ROSE_ADDR_LEN; /* Facilities length */
+               *dptr++ = 0;
+               *dptr++ = FAC_NATIONAL;
+               *dptr++ = FAC_NATIONAL_FAIL_CALL;
+               *dptr++ = AX25_ADDR_LEN;
+               memcpy(dptr, &rose_callsign, AX25_ADDR_LEN);
+               dptr += AX25_ADDR_LEN;
+               *dptr++ = FAC_NATIONAL_FAIL_ADD;
+               *dptr++ = ROSE_ADDR_LEN + 1;
+               *dptr++ = ROSE_ADDR_LEN * 2;
+               memcpy(dptr, first->dev_addr, ROSE_ADDR_LEN);
+       }
+       
        if (!rose_send_frame(skb, neigh))
                kfree_skb(skb, FREE_WRITE);
 }
 
 void rose_transmit_link(struct sk_buff *skb, struct rose_neigh *neigh)
 {
+       rose_address *dest_addr;
        unsigned char *dptr;
 
 #ifdef CONFIG_FIREWALL
@@ -294,6 +320,18 @@ void rose_transmit_link(struct sk_buff *skb, struct rose_neigh *neigh)
                return;
 #endif
 
+       /*
+        * Check to see if its for us, if it is put it onto the loopback
+        * queue.
+        */
+        dest_addr = (rose_address *)(skb->data + 4);
+  
+       if ((neigh->dce_mode == -1) || (rose_dev_get(dest_addr) != NULL)) {
+               neigh->dce_mode = -1;
+               rose_loopback_queue(skb, neigh);
+               return;
+       }
+
        if (!rose_link_up(neigh))
                neigh->restarted = 0;
 
diff --git a/net/rose/rose_loopback.c b/net/rose/rose_loopback.c
new file mode 100644 (file)
index 0000000..3c67076
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ *     ROSE release 003
+ *
+ *     This code REQUIRES 2.1.15 or higher/ NET3.038
+ *
+ *     This module:
+ *             This module is free software; you can redistribute it and/or
+ *             modify it under the terms of the GNU General Public License
+ *             as published by the Free Software Foundation; either version
+ *             2 of the License, or (at your option) any later version.
+ *
+ *     History
+ *     ROSE 003        Jonathan(G4KLX) Created this file from nr_loopback.c.
+ *
+ */
+
+#include <linux/config.h>
+#if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE)
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/timer.h>
+#include <net/ax25.h>
+#include <linux/skbuff.h>
+#include <net/rose.h>
+
+static struct sk_buff_head loopback_queue;
+static struct timer_list loopback_timer;
+
+static void rose_set_loopback_timer(void);
+
+void rose_loopback_init(void)
+{
+       skb_queue_head_init(&loopback_queue);
+
+       init_timer(&loopback_timer);
+}
+
+void rose_loopback_clear(void)
+{
+       struct sk_buff *skb;
+
+       del_timer(&loopback_timer);
+
+       while ((skb = skb_dequeue(&loopback_queue)) != NULL) {
+               skb->sk = NULL;
+               kfree_skb(skb, FREE_READ);
+       }
+}
+
+static int rose_loopback_running(void)
+{
+       return (loopback_timer.prev != NULL || loopback_timer.next != NULL);
+}
+
+int rose_loopback_queue(struct sk_buff *skb, struct rose_neigh *neigh)
+{
+       struct sk_buff *skbn;
+
+       skbn = skb_clone(skb, GFP_ATOMIC);
+
+       kfree_skb(skb, FREE_WRITE);
+
+       if (skbn != NULL) {
+               skbn->sk = (struct sock *)neigh;
+               skb_queue_tail(&loopback_queue, skbn);
+       }
+
+       if (!rose_loopback_running())
+       {
+               rose_set_loopback_timer();
+       }
+       return 1;
+}
+
+static void rose_loopback_timer(unsigned long);
+
+static void rose_set_loopback_timer(void)
+{
+       del_timer(&loopback_timer);
+
+       loopback_timer.data     = 0;
+       loopback_timer.function = &rose_loopback_timer;
+       loopback_timer.expires  = jiffies + 10;
+
+       add_timer(&loopback_timer);
+}
+
+static void rose_loopback_timer(unsigned long param)
+{
+       struct sk_buff *skb;
+       struct rose_neigh *rose_neigh;
+       struct sock *sk;
+       struct device *dev;
+       rose_address *dest_addr;
+       unsigned int lci;
+       unsigned short frametype;
+
+       while ((skb = skb_dequeue(&loopback_queue)) != NULL) {
+               rose_neigh = (struct rose_neigh *)skb->sk;
+               lci        = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF);
+               dest_addr = (rose_address *)(skb->data + 4);
+
+               /* F1OAT : Patch the LCI for proper loopback operation */
+               /* Work only if the system open less than 2048 VC !!! */
+               
+               lci = 4096 - lci;
+               skb->data[0] = (lci >> 8) & 0x0F;
+               skb->data[1] = lci & 0xFF;
+               
+               skb->sk = NULL;
+
+               frametype = skb->data[2];
+
+               if (frametype == ROSE_CALL_REQUEST) {
+                       if ((dev = rose_dev_get(dest_addr)) == NULL) {
+                               kfree_skb(skb, FREE_READ);
+                               continue;                       
+                       }
+                       if (!rose_rx_call_request(skb, dev, rose_neigh, lci))
+                               kfree_skb(skb, FREE_READ); 
+               }
+               else {
+                       if ((sk = rose_find_socket(lci, rose_neigh)) == NULL) {
+                               kfree_skb(skb, FREE_READ);
+                               continue;
+                       }
+                       skb->h.raw = skb->data;
+
+                       if (rose_process_rx_frame(sk, skb) == 0)
+                               kfree_skb(skb, FREE_READ); 
+               }
+       }
+}
+
+#endif
index 9b79818cc54a3259a6ffd730708d8948f94d6bc6..d8ee941ad45ae9484b2ca09080f54c604913c3a2 100644 (file)
@@ -11,7 +11,6 @@
  *
  *     History
  *     ROSE 001        Jonathan(G4KLX) Cloned from nr_out.c
- *     ROSE 003        Jonathan(G4KLX) Removed M bit processing.
  */
 
 #include <linux/config.h>
@@ -55,39 +54,56 @@ static void rose_send_iframe(struct sock *sk, struct sk_buff *skb)
 
 void rose_kick(struct sock *sk)
 {
-       struct sk_buff *skb;
-       unsigned short end;
+       struct sk_buff *skb, *skbn;
+       unsigned short start, end;
 
-       del_timer(&sk->timer);
+       if (sk->protinfo.rose->state != ROSE_STATE_3)
+               return;
 
-       end = (sk->protinfo.rose->va + sysctl_rose_window_size) % ROSE_MODULUS;
+       if (sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY)
+               return;
 
-       if (!(sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY) &&
-           sk->protinfo.rose->vs != end                             &&
-           skb_peek(&sk->write_queue) != NULL) {
-               /*
-                * Transmit data until either we're out of data to send or
-                * the window is full.
-                */
+       if (skb_peek(&sk->write_queue) == NULL)
+               return;
 
-               skb  = skb_dequeue(&sk->write_queue);
+       start = (skb_peek(&sk->protinfo.rose->ack_queue) == NULL) ? sk->protinfo.rose->va : sk->protinfo.rose->vs;
+       end   = (sk->protinfo.rose->va + sysctl_rose_window_size) % ROSE_MODULUS;
 
-               do {
-                       /*
-                        * Transmit the frame.
-                        */
-                       rose_send_iframe(sk, skb);
+       if (start == end)
+               return;
 
-                       sk->protinfo.rose->vs = (sk->protinfo.rose->vs + 1) % ROSE_MODULUS;
+       sk->protinfo.rose->vs = start;
 
-               } while (sk->protinfo.rose->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL);
+       /*
+        * Transmit data until either we're out of data to send or
+        * the window is full.
+        */
+
+       skb  = skb_dequeue(&sk->write_queue);
+
+       do {
+               if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
+                       skb_queue_head(&sk->write_queue, skb);
+                       break;
+               }
+
+               /*
+                * Transmit the frame copy.
+                */
+               rose_send_iframe(sk, skbn);
 
-               sk->protinfo.rose->vl         = sk->protinfo.rose->vr;
-               sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
-               sk->protinfo.rose->timer      = 0;
-       }
+               sk->protinfo.rose->vs = (sk->protinfo.rose->vs + 1) % ROSE_MODULUS;
 
-       rose_set_timer(sk);
+               /*
+                * Requeue the original data frame.
+                */
+               skb_queue_tail(&sk->protinfo.rose->ack_queue, skb);
+
+       } while (sk->protinfo.rose->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL);
+
+       sk->protinfo.rose->vl         = sk->protinfo.rose->vr;
+       sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
+       sk->protinfo.rose->timer      = 0;
 }
 
 /*
@@ -107,14 +123,4 @@ void rose_enquiry_response(struct sock *sk)
        sk->protinfo.rose->timer      = 0;
 }
 
-void rose_check_iframes_acked(struct sock *sk, unsigned short nr)
-{
-       if (sk->protinfo.rose->vs == nr) {
-               sk->protinfo.rose->va = nr;
-       } else {
-               if (sk->protinfo.rose->va != nr)
-                       sk->protinfo.rose->va = nr;
-       }
-}
-
 #endif
index 725abc0ba9afa41e900102085f2bfdbc6d5bd164..4634176aff651c1ecd8c84d89c38e0ed9e5552cc 100644 (file)
@@ -54,6 +54,17 @@ static struct rose_neigh *rose_neigh_list = NULL;
 static struct rose_route *rose_route_list = NULL;
 
 static void rose_remove_neigh(struct rose_neigh *);
+static int rose_del_node(struct rose_route_struct *, struct device *);
+
+static int rose_is_null(rose_address *address)
+{
+       int i;
+       
+       for (i = 0 ; i < sizeof(rose_address) ; i++)
+               if (address->rose_addr[i])
+                       return 0;
+       return 1;
+}
 
 /*
  *     Add a new route to a node, and in the process add the node and the
@@ -63,6 +74,7 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct device *de
 {
        struct rose_node  *rose_node, *rose_tmpn, *rose_tmpp;
        struct rose_neigh *rose_neigh;
+       struct rose_route_struct dummy_route;
        unsigned long flags;
        int i;
 
@@ -166,16 +178,22 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct device *de
 
                rose_neigh->count++;
 
-               return 0;
-       }
-
-       /* We have space, slot it in */
-       if (rose_node->count < 3) {
+       } else if (rose_node->count < ROSE_MAX_ALTERNATE) {
+               /* We have space, slot it in */
                rose_node->neighbour[rose_node->count] = rose_neigh;
                rose_node->count++;
                rose_neigh->count++;
        }
 
+       if (!rose_is_null(&rose_route->address))
+       {
+               /* Delete this neighbourg from the dummy node 0000000000 */
+               dummy_route = *rose_route;
+               dummy_route.mask = 10;
+               memset(&dummy_route.address, 0, sizeof(rose_address));
+               rose_del_node(&dummy_route, dev);
+       }
+       
        return 0;
 }
 
@@ -252,11 +270,11 @@ static void rose_remove_route(struct rose_route *rose_route)
        struct rose_route *s;
        unsigned long flags;
 
-       if (rose_route->neigh1 != NULL)
-               rose_route->neigh1->use--;
+       if (rose_route->tr1.neigh != NULL)
+               rose_route->tr1.neigh->use--;
 
-       if (rose_route->neigh2 != NULL)
-               rose_route->neigh2->use--;
+       if (rose_route->tr2.neigh != NULL)
+               rose_route->tr2.neigh->use--;
 
        save_flags(flags);
        cli();
@@ -290,6 +308,7 @@ static int rose_del_node(struct rose_route_struct *rose_route, struct device *de
 {
        struct rose_node  *rose_node;
        struct rose_neigh *rose_neigh;
+       struct rose_route_struct dummy_route;
        int i;
 
        for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
@@ -308,8 +327,16 @@ static int rose_del_node(struct rose_route_struct *rose_route, struct device *de
                if (rose_node->neighbour[i] == rose_neigh) {
                        rose_neigh->count--;
 
-                       if (rose_neigh->count == 0 && rose_neigh->use == 0)
+                       if (rose_neigh->count == 0) {
+                               /* Add a dummy node to keep the neighbourg still visible */
+                               dummy_route = *rose_route;
+                               dummy_route.mask = 10;
+                               memset(&dummy_route.address, 0, sizeof(rose_address));
+                               rose_add_node(&dummy_route, dev);
+                       }
+                       /* if (rose_neigh->count == 0 && rose_neigh->use == 0) {
                                rose_remove_neigh(rose_neigh);
+                       } */
 
                        rose_node->count--;
 
@@ -388,7 +415,7 @@ void rose_route_device_down(struct device *dev)
                s          = rose_route;
                rose_route = rose_route->next;
 
-               if (s->neigh1->dev == dev || s->neigh2->dev == dev)
+               if (s->tr1.neigh->dev == dev || s->tr2.neigh->dev == dev)
                        rose_remove_route(s);
        }
 }
@@ -472,8 +499,8 @@ struct rose_route *rose_route_free_lci(unsigned int lci, struct rose_neigh *neig
        struct rose_route *rose_route;
 
        for (rose_route = rose_route_list; rose_route != NULL; rose_route = rose_route->next)
-               if ((rose_route->neigh1 == neigh && rose_route->lci1 == lci) ||
-                   (rose_route->neigh2 == neigh && rose_route->lci2 == lci))
+               if ((rose_route->tr1.neigh == neigh && rose_route->tr1.lci == lci) ||
+                   (rose_route->tr2.neigh == neigh && rose_route->tr2.lci == lci))
                        return rose_route;
 
        return NULL;
@@ -496,7 +523,7 @@ struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause, unsi
                                else
                                        failed = 1;
                        }
-                       /* F6FBB : All nodes for this route are out of order */
+                       /* do not accept other node address */
                        break;
                }
        }
@@ -529,8 +556,8 @@ int rose_rt_ioctl(unsigned int cmd, void *arg)
                        memcpy_fromfs(&rose_route, arg, sizeof(struct rose_route_struct));
                        if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL)
                                return -EINVAL;
-                       if (rose_dev_get(&rose_route.address) != NULL)  /* Can't add routes to ourself */
-                               return -EINVAL;
+                       /* if (rose_dev_get(&rose_route.address) != NULL)       / Can't add routes to ourself /
+                               return -EINVAL; */
                        if (rose_route.mask > 10) /* Mask can't be more than 10 digits */
                                return -EINVAL;
 
@@ -571,25 +598,25 @@ static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh)
        rose_route = rose_route_list;
 
        while (rose_route != NULL) {
-               if ((rose_route->neigh1 == rose_neigh && rose_route->neigh2 == rose_neigh) ||
-                   (rose_route->neigh1 == rose_neigh && rose_route->neigh2 == NULL)       ||
-                   (rose_route->neigh2 == rose_neigh && rose_route->neigh1 == NULL)) {
+               if ((rose_route->tr1.neigh == rose_neigh && rose_route->tr2.neigh == rose_neigh) ||
+                   (rose_route->tr1.neigh == rose_neigh && rose_route->tr2.neigh == NULL)       ||
+                   (rose_route->tr2.neigh == rose_neigh && rose_route->tr1.neigh == NULL)) {
                        s = rose_route->next;
                        rose_remove_route(rose_route);
                        rose_route = s;
                        continue;
                }
 
-               if (rose_route->neigh1 == rose_neigh) {
-                       rose_route->neigh1->use--;
-                       rose_route->neigh1 = NULL;
-                       rose_transmit_clear_request(rose_route->neigh2, rose_route->lci2, ROSE_OUT_OF_ORDER, 0);
+               if (rose_route->tr1.neigh == rose_neigh) {
+                       rose_route->tr1.neigh->use--;
+                       rose_route->tr1.neigh = NULL;
+                       rose_transmit_clear_request(rose_route->tr2.neigh, rose_route->tr2.lci, ROSE_OUT_OF_ORDER, 0);
                }
 
-               if (rose_route->neigh2 == rose_neigh) {
-                       rose_route->neigh2->use--;
-                       rose_route->neigh2 = NULL;
-                       rose_transmit_clear_request(rose_route->neigh1, rose_route->lci1, ROSE_OUT_OF_ORDER, 0);
+               if (rose_route->tr2.neigh == rose_neigh) {
+                       rose_route->tr2.neigh->use--;
+                       rose_route->tr2.neigh = NULL;
+                       rose_transmit_clear_request(rose_route->tr1.neigh, rose_route->tr1.lci, ROSE_OUT_OF_ORDER, 0);
                }
 
                rose_route = rose_route->next;
@@ -633,6 +660,16 @@ void rose_link_device_down(struct device *dev)
        }
 }
 
+/*
+ *     A Restart has occured. Delete all existing routes to this neighbour
+ */
+void rose_clean_neighbour(struct rose_neigh *rose_neigh)
+{
+       rose_del_route_by_neigh(rose_neigh);
+       rose_kill_by_neigh(rose_neigh);
+}
+
+
 /*
  *     Route a frame to an appropriate AX.25 connection.
  */
@@ -640,7 +677,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
 {
        struct rose_neigh *rose_neigh, *new_neigh;
        struct rose_route *rose_route;
-       struct rose_facilities facilities;
+       struct rose_facilities_struct facilities;
        rose_address *src_addr, *dest_addr;
        struct sock *sk;
        unsigned short frametype;
@@ -648,6 +685,8 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
        unsigned char cause, diagnostic;
        struct device *dev;
        unsigned long flags;
+       int len;
+       struct sk_buff *skbn;
 
 #ifdef CONFIG_FIREWALL
        if (call_in_firewall(PF_ROSE, skb->dev, skb->data, NULL) != FW_ACCEPT)
@@ -663,8 +702,10 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
                if (ax25cmp(&ax25->dest_addr, &rose_neigh->callsign) == 0 && ax25->device == rose_neigh->dev)
                        break;
 
-       if (rose_neigh == NULL)
+       if (rose_neigh == NULL) {
+               printk("rose_route : unknown neighbour or device %s\n", ax2asc(&ax25->dest_addr));
                return 0;
+       }
 
        /*
         *      Obviously the link is working, halt the ftimer.
@@ -684,16 +725,36 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
         *      Find an existing socket.
         */
        if ((sk = rose_find_socket(lci, rose_neigh)) != NULL) {
-               skb->h.raw = skb->data;
-               return rose_process_rx_frame(sk, skb);
+               if (frametype == ROSE_CALL_REQUEST)
+               {
+                       /* F6FBB - Remove an existing unused socket */
+                       rose_clear_queues(sk);
+                       sk->protinfo.rose->cause      = ROSE_NETWORK_CONGESTION;
+                       sk->protinfo.rose->diagnostic = 0;
+                       sk->protinfo.rose->neighbour->use--;
+                       sk->protinfo.rose->neighbour = NULL;
+                       sk->protinfo.rose->state = ROSE_STATE_0;
+                       sk->state                = TCP_CLOSE;
+                       sk->err                  = 0;
+                       sk->shutdown            |= SEND_SHUTDOWN;
+                       if (!sk->dead)
+                               sk->state_change(sk);
+                       sk->dead                 = 1;
+               }
+               else
+               {
+                       skb->h.raw = skb->data;
+                       return rose_process_rx_frame(sk, skb);
+               }
        }
 
        /*
-        *      Is is a Call Request and is it for us ?
+        *      Is it a Call Request and is it for us ?
         */
        if (frametype == ROSE_CALL_REQUEST)
-               if ((dev = rose_dev_get(dest_addr)) != NULL)
+               if ((dev = rose_dev_get(dest_addr)) != NULL) {
                        return rose_rx_call_request(skb, dev, rose_neigh, lci);
+               }
 
        if (!sysctl_rose_routing_control) {
                rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 0);
@@ -704,12 +765,20 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
         *      Route it to the next in line if we have an entry for it.
         */
        for (rose_route = rose_route_list; rose_route != NULL; rose_route = rose_route->next) {
-               if (rose_route->lci1 == lci && rose_route->neigh1 == rose_neigh) {
-                       if (rose_route->neigh2 != NULL) {
+               if (rose_route->tr1.lci == lci && rose_route->tr1.neigh == rose_neigh) {
+                       if (frametype == ROSE_CALL_REQUEST) {
+                               /* F6FBB - Remove an existing unused route */
+                               rose_remove_route(rose_route);
+                               break;
+                       } else if (rose_route->tr2.neigh != NULL) {
+                               if ((skbn = skb_copy(skb, GFP_ATOMIC)) != NULL) {
+                                       kfree_skb(skb, FREE_READ);
+                                       skb = skbn;
+                               }
                                skb->data[0] &= 0xF0;
-                               skb->data[0] |= (rose_route->lci2 >> 8) & 0x0F;
-                               skb->data[1]  = (rose_route->lci2 >> 0) & 0xFF;
-                               rose_transmit_link(skb, rose_route->neigh2);
+                               skb->data[0] |= (rose_route->tr2.lci >> 8) & 0x0F;
+                               skb->data[1]  = (rose_route->tr2.lci >> 0) & 0xFF;
+                               rose_transmit_link(skb, rose_route->tr2.neigh);
                                if (frametype == ROSE_CLEAR_CONFIRMATION)
                                        rose_remove_route(rose_route);
                                return 1;
@@ -719,12 +788,20 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
                                return 0;
                        }
                }
-               if (rose_route->lci2 == lci && rose_route->neigh2 == rose_neigh) {
-                       if (rose_route->neigh1 != NULL) {
+               if (rose_route->tr2.lci == lci && rose_route->tr2.neigh == rose_neigh) {
+                       if (frametype == ROSE_CALL_REQUEST) {
+                               /* F6FBB - Remove an existing unused route */
+                               rose_remove_route(rose_route);
+                               break;
+                       } else if (rose_route->tr1.neigh != NULL) {
+                               if ((skbn = skb_copy(skb, GFP_ATOMIC)) != NULL) {
+                                       kfree_skb(skb, FREE_READ);
+                                       skb = skbn;
+                               }
                                skb->data[0] &= 0xF0;
-                               skb->data[0] |= (rose_route->lci1 >> 8) & 0x0F;
-                               skb->data[1]  = (rose_route->lci1 >> 0) & 0xFF;
-                               rose_transmit_link(skb, rose_route->neigh1);
+                               skb->data[0] |= (rose_route->tr1.lci >> 8) & 0x0F;
+                               skb->data[1]  = (rose_route->tr1.lci >> 0) & 0xFF;
+                               rose_transmit_link(skb, rose_route->tr1.neigh);
                                if (frametype == ROSE_CLEAR_CONFIRMATION)
                                        rose_remove_route(rose_route);
                                return 1;
@@ -741,10 +818,17 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
         *      1. The frame isn't for us,
         *      2. It isn't "owned" by any existing route.
         */
-       if (frametype != ROSE_CALL_REQUEST)     /* XXX */
+       if (frametype != ROSE_CALL_REQUEST)     { /* Trashed packet */
                return 0;
+       }
 
-       if (!rose_parse_facilities(skb, &facilities)) {
+       len  = (((skb->data[3] >> 4) & 0x0F) + 1) / 2;
+       len += (((skb->data[3] >> 0) & 0x0F) + 1) / 2;
+
+       memset(&facilities, 0x00, sizeof(struct rose_facilities_struct));
+       
+       if (!rose_parse_facilities(skb->data + len + 4, &facilities)) {
+               printk("CR : rose_parse_facilities error\n");
                rose_transmit_clear_request(rose_neigh, lci, ROSE_INVALID_FACILITY, 76);
                return 0;
        }
@@ -757,16 +841,12 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
                    rosecmp(src_addr, &rose_route->src_addr) == 0 &&
                    ax25cmp(&facilities.dest_call, &rose_route->src_call) == 0 &&
                    ax25cmp(&facilities.source_call, &rose_route->dest_call) == 0) {
-                       printk(KERN_DEBUG "ROSE: routing loop from %s\n", rose2asc(src_addr));
-                       printk(KERN_DEBUG "ROSE:                to %s\n", rose2asc(dest_addr));
                        rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 120);
                        return 0;
                }
        }
 
        if ((new_neigh = rose_get_neigh(dest_addr, &cause, &diagnostic)) == NULL) {
-               if (cause == ROSE_NOT_OBTAINABLE)
-                       printk(KERN_DEBUG "ROSE: no route to %s\n", rose2asc(dest_addr));
                rose_transmit_clear_request(rose_neigh, lci, cause, diagnostic);
                return 0;
        }
@@ -777,33 +857,38 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
        }
 
        if ((rose_route = (struct rose_route *)kmalloc(sizeof(*rose_route), GFP_ATOMIC)) == NULL) {
-               rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 120);
+               rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 121);
                return 0;
        }
 
-       rose_route->lci1      = lci;
        rose_route->src_addr  = *src_addr;
        rose_route->dest_addr = *dest_addr;
        rose_route->src_call  = facilities.dest_call;
        rose_route->dest_call = facilities.source_call;
        rose_route->rand      = facilities.rand;
-       rose_route->neigh1    = rose_neigh;
-       rose_route->lci2      = new_lci;
-       rose_route->neigh2    = new_neigh;
+       rose_route->tr1.lci   = lci;
+       rose_route->tr1.neigh = rose_neigh;
+       rose_route->tr2.lci   = new_lci;
+       rose_route->tr2.neigh = new_neigh;
 
-       rose_route->neigh1->use++;
-       rose_route->neigh2->use++;
+       rose_route->tr1.neigh->use++;
+       rose_route->tr2.neigh->use++;
 
        save_flags(flags); cli();
        rose_route->next = rose_route_list;
        rose_route_list  = rose_route;
        restore_flags(flags);
 
+       if ((skbn = skb_copy(skb, GFP_ATOMIC)) != NULL) {
+               kfree_skb(skb, FREE_READ);
+               skb = skbn;
+       }
+
        skb->data[0] &= 0xF0;
-       skb->data[0] |= (rose_route->lci2 >> 8) & 0x0F;
-       skb->data[1]  = (rose_route->lci2 >> 0) & 0xFF;
+       skb->data[0] |= (rose_route->tr2.lci >> 8) & 0x0F;
+       skb->data[1]  = (rose_route->tr2.lci >> 0) & 0xFF;
 
-       rose_transmit_link(skb, rose_route->neigh2);
+       rose_transmit_link(skb, rose_route->tr2.neigh);
 
        return 1;
 }
@@ -920,22 +1005,22 @@ int rose_routes_get_info(char *buffer, char **start, off_t offset,
        len += sprintf(buffer, "lci  address     callsign   neigh  <-> lci  address     callsign   neigh\n");
 
        for (rose_route = rose_route_list; rose_route != NULL; rose_route = rose_route->next) {
-               if (rose_route->neigh1 != NULL) {
+               if (rose_route->tr1.neigh != NULL) {
                        len += sprintf(buffer + len, "%3.3X  %-10s  %-9s  %05d      ",
-                               rose_route->lci1,
+                               rose_route->tr1.lci,
                                rose2asc(&rose_route->src_addr),
                                ax2asc(&rose_route->src_call),
-                               rose_route->neigh1->number);
+                               rose_route->tr1.neigh->number);
                } else {
                        len += sprintf(buffer + len, "000  *           *          00000      ");
                }
 
-               if (rose_route->neigh2 != NULL) {
+               if (rose_route->tr2.neigh != NULL) {
                        len += sprintf(buffer + len, "%3.3X  %-10s  %-9s  %05d\n",
-                               rose_route->lci2,
+                               rose_route->tr2.lci,
                                rose2asc(&rose_route->dest_addr),
                                ax2asc(&rose_route->dest_call),
-                               rose_route->neigh2->number);
+                               rose_route->tr2.neigh->number);
                } else {
                        len += sprintf(buffer + len, "000  *           *          00000\n");
                }
index ce25a4dce7e1e86afa3d7153c5e65bbd2f3bcc05..9fcf94b198a6e49cc12aae12f60be376dd5bec25 100644 (file)
@@ -46,6 +46,37 @@ void rose_clear_queues(struct sock *sk)
 
        while ((skb = skb_dequeue(&sk->write_queue)) != NULL)
                kfree_skb(skb, FREE_WRITE);
+
+       while ((skb = skb_dequeue(&sk->protinfo.rose->ack_queue)) != NULL)
+               kfree_skb(skb, FREE_READ);
+
+#ifdef M_BIT
+       while ((skb = skb_dequeue(&sk->protinfo.rose->frag_queue)) != NULL) {
+               kfree_skb(skb, FREE_READ);
+       }
+#endif
+}
+
+/*
+ * This routine purges the input queue of those frames that have been
+ * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
+ * SDL diagram.
+ */
+void rose_frames_acked(struct sock *sk, unsigned short nr)
+{
+       struct sk_buff *skb;
+
+       /*
+        * Remove all the ack-ed frames from the ack queue.
+        */
+       if (sk->protinfo.rose->va != nr) {
+
+               while (skb_peek(&sk->protinfo.rose->ack_queue) != NULL && sk->protinfo.rose->va != nr) {
+                       skb = skb_dequeue(&sk->protinfo.rose->ack_queue);
+                       kfree_skb(skb, FREE_WRITE);
+                       sk->protinfo.rose->va = (sk->protinfo.rose->va + 1) % ROSE_MODULUS;
+               }
+       }
 }
 
 /*
@@ -75,7 +106,7 @@ void rose_write_internal(struct sock *sk, int frametype)
        struct sk_buff *skb;
        unsigned char  *dptr;
        unsigned char  lci1, lci2;
-       char buffer[100];
+       char buffer[250];
        int len, faclen = 0;
 
        len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 1;
@@ -83,14 +114,32 @@ void rose_write_internal(struct sock *sk, int frametype)
        switch (frametype) {
                case ROSE_CALL_REQUEST:
                        len   += 1 + ROSE_ADDR_LEN + ROSE_ADDR_LEN;
+                       /* facilities */
                        faclen = rose_create_facilities(buffer, sk->protinfo.rose);
                        len   += faclen;
                        break;
                case ROSE_CALL_ACCEPTED:
-               case ROSE_CLEAR_REQUEST:
                case ROSE_RESET_REQUEST:
                        len   += 2;
                        break;
+               case ROSE_CLEAR_REQUEST:
+                       len   += 3;
+                       /* facilities */
+                       faclen = 3 + 2 + AX25_ADDR_LEN + 3 + ROSE_ADDR_LEN;
+                       dptr = buffer;
+                       *dptr++ = faclen-1;     /* Facilities length */
+                       *dptr++ = 0;
+                       *dptr++ = FAC_NATIONAL;
+                       *dptr++ = FAC_NATIONAL_FAIL_CALL;
+                       *dptr++ = AX25_ADDR_LEN;
+                       memcpy(dptr, &rose_callsign, AX25_ADDR_LEN);
+                       dptr += AX25_ADDR_LEN;
+                       *dptr++ = FAC_NATIONAL_FAIL_ADD;
+                       *dptr++ = ROSE_ADDR_LEN + 1;
+                       *dptr++ = ROSE_ADDR_LEN * 2;
+                       memcpy(dptr, &sk->protinfo.rose->source_addr, ROSE_ADDR_LEN);
+                       len   += faclen;
+                       break;
        }
 
        if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
@@ -137,6 +186,9 @@ void rose_write_internal(struct sock *sk, int frametype)
                        *dptr++ = frametype;
                        *dptr++ = sk->protinfo.rose->cause;
                        *dptr++ = sk->protinfo.rose->diagnostic;
+                       *dptr++ = 0x00;         /* Address length */
+                       memcpy(dptr, buffer, faclen);
+                       dptr   += faclen;
                        break;
 
                case ROSE_RESET_REQUEST:
@@ -144,7 +196,7 @@ void rose_write_internal(struct sock *sk, int frametype)
                        *dptr++ = lci2;
                        *dptr++ = frametype;
                        *dptr++ = ROSE_DTE_ORIGINATED;
-                       *dptr++ = 0;
+                       *dptr++ = 0x00;         /* Address length */
                        break;
 
                case ROSE_RR:
@@ -209,9 +261,11 @@ int rose_decode(struct sk_buff *skb, int *ns, int *nr, int *q, int *d, int *m)
        return ROSE_ILLEGAL;
 }
 
-static int rose_parse_national(unsigned char *p, struct rose_facilities *facilities, int len)
+static int rose_parse_national(unsigned char *p, struct rose_facilities_struct *facilities, int len)
 {
-       unsigned char l, n = 0;
+       unsigned char *pt;
+       unsigned char l, lg, n = 0;
+       int fac_national_digis_received = 0;
 
        do {
                switch (*p & 0xC0) {
@@ -238,12 +292,33 @@ static int rose_parse_national(unsigned char *p, struct rose_facilities *facilit
                        case 0xC0:
                                l = p[1];
                                if (*p == FAC_NATIONAL_DEST_DIGI) {
-                                       memcpy(&facilities->source_digi, p + 2, AX25_ADDR_LEN);
-                                       facilities->source_ndigis = 1;
+                                       if (!fac_national_digis_received) {
+                                               memcpy(&facilities->source_digis[0], p + 2, AX25_ADDR_LEN);
+                                               facilities->source_ndigis = 1;
+                                       }
+                               }
+                               else if (*p == FAC_NATIONAL_SRC_DIGI) {
+                                       if (!fac_national_digis_received) {
+                                               memcpy(&facilities->dest_digis[0], p + 2, AX25_ADDR_LEN);
+                                               facilities->dest_ndigis = 1;
+                                       }
+                               }
+                               else if (*p == FAC_NATIONAL_FAIL_CALL) {
+                                       memcpy(&facilities->fail_call, p + 2, AX25_ADDR_LEN);
+                               }
+                               else if (*p == FAC_NATIONAL_FAIL_ADD) {
+                                       memcpy(&facilities->fail_addr, p + 3, ROSE_ADDR_LEN);
                                }
-                               if (*p == FAC_NATIONAL_SRC_DIGI) {
-                                       memcpy(&facilities->dest_digi,   p + 2, AX25_ADDR_LEN);
-                                       facilities->dest_ndigis = 1;
+                               else if (*p == FAC_NATIONAL_DIGIS) {
+                                       fac_national_digis_received = 1;
+                                       facilities->source_ndigis = 0;
+                                       facilities->dest_ndigis   = 0;
+                                       for (pt = p + 2, lg = 0 ; lg < l ; pt += AX25_ADDR_LEN, lg += AX25_ADDR_LEN) {
+                                               if (pt[6] & AX25_HBIT)
+                                                       memcpy(&facilities->dest_digis[facilities->dest_ndigis++], pt, AX25_ADDR_LEN);
+                                               else
+                                                       memcpy(&facilities->source_digis[facilities->source_ndigis++], pt, AX25_ADDR_LEN);
+                                       }
                                }
                                p   += l + 2;
                                n   += l + 2;
@@ -255,7 +330,7 @@ static int rose_parse_national(unsigned char *p, struct rose_facilities *facilit
        return n;
 }
 
-static int rose_parse_ccitt(unsigned char *p, struct rose_facilities *facilities, int len)
+static int rose_parse_ccitt(unsigned char *p, struct rose_facilities_struct *facilities, int len)
 {
        unsigned char l, n = 0;
        char callsign[11];
@@ -288,7 +363,7 @@ static int rose_parse_ccitt(unsigned char *p, struct rose_facilities *facilities
                                        callsign[l - 10] = '\0';
                                        facilities->source_call = *asc2ax(callsign);
                                }
-                               if (*p == FAC_CCITT_SRC_NSAP) {
+                               else if (*p == FAC_CCITT_SRC_NSAP) {
                                        memcpy(&facilities->dest_addr, p + 7, ROSE_ADDR_LEN);
                                        memcpy(callsign, p + 12, l - 10);
                                        callsign[l - 10] = '\0';
@@ -304,17 +379,9 @@ static int rose_parse_ccitt(unsigned char *p, struct rose_facilities *facilities
        return n;
 }
 
-int rose_parse_facilities(struct sk_buff *skb, struct rose_facilities *facilities)
+int rose_parse_facilities(unsigned char *p, struct rose_facilities_struct *facilities)
 {
        int facilities_len, len;
-       unsigned char *p;
-
-       memset(facilities, 0x00, sizeof(struct rose_facilities));
-
-       len  = (((skb->data[3] >> 4) & 0x0F) + 1) / 2;
-       len += (((skb->data[3] >> 0) & 0x0F) + 1) / 2;
-
-       p = skb->data + len + 4;
 
        facilities_len = *p++;
 
@@ -327,25 +394,25 @@ int rose_parse_facilities(struct sk_buff *skb, struct rose_facilities *facilitie
                        p++;
 
                        switch (*p) {
-                               case FAC_NATIONAL:              /* National */
+                               case FAC_NATIONAL:              /* National 0x00 */
                                        len = rose_parse_national(p + 1, facilities, facilities_len - 1);
                                        facilities_len -= len + 1;
                                        p += len + 1;
                                        break;
 
-                               case FAC_CCITT:         /* CCITT */
+                               case FAC_CCITT:         /* CCITT 0x0F */
                                        len = rose_parse_ccitt(p + 1, facilities, facilities_len - 1);
                                        facilities_len -= len + 1;
                                        p += len + 1;
                                        break;
 
                                default:
-                                       printk(KERN_DEBUG "rose_parse_facilities: unknown facilities family %02X\n", *p);
                                        facilities_len--;
                                        p++;
                                        break;
                        }
-               }
+               } 
+               else break;     /* Error in facilities format */
        }
 
        return 1;
@@ -356,6 +423,7 @@ int rose_create_facilities(unsigned char *buffer, rose_cb *rose)
        unsigned char *p = buffer + 1;
        char *callsign;
        int len;
+       int nb;
 
        /* National Facilities */
        if (rose->rand != 0 || rose->source_ndigis == 1 || rose->dest_ndigis == 1) {
@@ -368,19 +436,43 @@ int rose_create_facilities(unsigned char *buffer, rose_cb *rose)
                        *p++ = (rose->rand >> 0) & 0xFF;
                }
 
-               if (rose->source_ndigis == 1) {
+               /* Sent before older facilities */
+               if ((rose->source_ndigis > 0) || (rose->dest_ndigis > 0)) {
+                       int maxdigi = 0;
+                       *p++ = FAC_NATIONAL_DIGIS;
+                       *p++ = AX25_ADDR_LEN * (rose->source_ndigis + rose->dest_ndigis);
+                       for (nb = 0 ; nb < rose->source_ndigis ; nb++) {
+                               if (++maxdigi >= ROSE_MAX_DIGIS)
+                                       break;
+                               memcpy(p, &rose->source_digis[nb], AX25_ADDR_LEN);
+                               p[6] |= AX25_HBIT;
+                               p += AX25_ADDR_LEN;
+                       }
+                       for (nb = 0 ; nb < rose->dest_ndigis ; nb++) {
+                               if (++maxdigi >= ROSE_MAX_DIGIS)
+                                       break;
+                               memcpy(p, &rose->dest_digis[nb], AX25_ADDR_LEN);
+                               p[6] &= ~AX25_HBIT;
+                               p += AX25_ADDR_LEN;
+                       }
+               }
+
+               /* For compatibility */
+               if (rose->source_ndigis > 0) {
                        *p++ = FAC_NATIONAL_SRC_DIGI;
                        *p++ = AX25_ADDR_LEN;
-                       memcpy(p, &rose->source_digi, AX25_ADDR_LEN);
+                       memcpy(p, &rose->source_digis[0], AX25_ADDR_LEN);
                        p   += AX25_ADDR_LEN;
                }
 
-               if (rose->dest_ndigis == 1) {
+               /* For compatibility */
+               if (rose->dest_ndigis > 0) {
                        *p++ = FAC_NATIONAL_DEST_DIGI;
                        *p++ = AX25_ADDR_LEN;
-                       memcpy(p, &rose->dest_digi, AX25_ADDR_LEN);
+                       memcpy(p, &rose->dest_digis[0], AX25_ADDR_LEN);
                        p   += AX25_ADDR_LEN;
                }
+               
        }
 
        *p++ = 0x00;
index 2a9927c1d81672e7b220de3b999e3be7a7766a91..a2d466ea9d9a7879da0e2877d948b069d4b09861 100644 (file)
@@ -66,6 +66,7 @@ void rose_set_timer(struct sock *sk)
 static void rose_timer(unsigned long param)
 {
        struct sock *sk = (struct sock *)param;
+       struct device *first;
 
        switch (sk->protinfo.rose->state) {
                case ROSE_STATE_0:
@@ -82,7 +83,7 @@ static void rose_timer(unsigned long param)
                        /*
                         * Check for the state of the receive buffer.
                         */
-                       if (sk->rmem_alloc < (sk->rcvbuf / 2) && (sk->protinfo.rose->condition & ROSE_COND_OWN_RX_BUSY)) {
+                       if (sk->rmem_alloc < ((sk->rcvbuf - ROSE_MAX_WINDOW_LEN) / 2) && (sk->protinfo.rose->condition & ROSE_COND_OWN_RX_BUSY)) {
                                sk->protinfo.rose->condition &= ~ROSE_COND_OWN_RX_BUSY;
                                sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
                                sk->protinfo.rose->vl         = sk->protinfo.rose->vr;
@@ -120,11 +121,25 @@ static void rose_timer(unsigned long param)
                case ROSE_STATE_1:      /* T1 */
                case ROSE_STATE_4:      /* T2 */
                        rose_write_internal(sk, ROSE_CLEAR_REQUEST);
+                       /* F6FBB - Disconnect the calling station
                        sk->protinfo.rose->state = ROSE_STATE_2;
                        sk->protinfo.rose->timer = sk->protinfo.rose->t3;
-                       break;
+                       break; */
+                       
+                       /* Falls to next case */
 
                case ROSE_STATE_2:      /* T3 */
+                       /* F6FBB - Added Cause and diagnostic */
+                       sk->protinfo.rose->cause = ROSE_DTE_ORIGINATED;
+                       sk->protinfo.rose->diagnostic = 0x30;
+                       
+                       /* F6FBB - Added Facilities */
+                       first = rose_dev_first();
+                       if (first) {    
+                               sk->protinfo.rose->facilities.fail_call = rose_callsign;
+                               memcpy(&sk->protinfo.rose->facilities.fail_addr, first->dev_addr, ROSE_ADDR_LEN);
+                       }
+       
                        rose_clear_queues(sk);
                        sk->protinfo.rose->neighbour->use--;
                        sk->protinfo.rose->state = ROSE_STATE_0;