From 29acaf4b3b2e023b39661401c2293ed716353106 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 23 Nov 2007 15:11:56 -0500 Subject: [PATCH] 2.0.36prepatch 6 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 --- arch/i386/kernel/ksyms.c | 2 + drivers/char/cyclades.c | 19 ++- drivers/net/3c505.h | 2 +- drivers/pci/pci.c | 3 + drivers/scsi/BusLogic.c | 54 ++++--- drivers/scsi/FlashPoint.c | 8 +- drivers/scsi/README.BusLogic | 13 +- drivers/scsi/README.Mylex | 3 +- fs/autofs/dirhash.c | 2 + include/asm-i386/ptrace.h | 2 + include/linux/cyclades.h | 4 +- include/linux/pci.h | 3 + include/linux/rose.h | 33 ++++- include/net/rose.h | 66 ++++++--- kernel/ksyms.c | 1 + net/ipv4/tcp.c | 2 +- net/ipv4/tcp_output.c | 8 +- net/rose/Makefile | 3 +- net/rose/af_rose.c | 280 ++++++++++++++++++++++++++--------- net/rose/changes.doc | 10 ++ net/rose/rose_in.c | 148 +++++++++++++++--- net/rose/rose_link.c | 44 +++++- net/rose/rose_loopback.c | 135 +++++++++++++++++ net/rose/rose_out.c | 76 +++++----- net/rose/rose_route.c | 215 +++++++++++++++++++-------- net/rose/rose_subr.c | 150 +++++++++++++++---- net/rose/rose_timer.c | 19 ++- 27 files changed, 1010 insertions(+), 295 deletions(-) create mode 100644 net/rose/changes.doc create mode 100644 net/rose/rose_loopback.c diff --git a/arch/i386/kernel/ksyms.c b/arch/i386/kernel/ksyms.c index 963a1c86cb1c..678a8a8044f0 100644 --- a/arch/i386/kernel/ksyms.c +++ b/arch/i386/kernel/ksyms.c @@ -6,6 +6,7 @@ #include #include +#include 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), diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index a3f168350157..7c5f94efce05 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -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); diff --git a/drivers/net/3c505.h b/drivers/net/3c505.h index f7d283688c4c..0598ca25a2f6 100644 --- a/drivers/net/3c505.h +++ b/drivers/net/3c505.h @@ -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 diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index d35569dafa55..55ed55217d4f 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -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"), diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index a8418e7b33dc..3c52e15487fb 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -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 @@ -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\ diff --git a/drivers/scsi/FlashPoint.c b/drivers/scsi/FlashPoint.c index d94631a416e9..7c0232fa91d6 100644 --- a/drivers/scsi/FlashPoint.c +++ b/drivers/scsi/FlashPoint.c @@ -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. * *---------------------------------------------------------------------*/ diff --git a/drivers/scsi/README.BusLogic b/drivers/scsi/README.BusLogic index 36a7d703be16..3ddc8b1f10a9 100644 --- a/drivers/scsi/README.BusLogic +++ b/drivers/scsi/README.BusLogic @@ -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 diff --git a/drivers/scsi/README.Mylex b/drivers/scsi/README.Mylex index a786fabc6991..cdf69293f7d5 100644 --- a/drivers/scsi/README.Mylex +++ b/drivers/scsi/README.Mylex @@ -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. diff --git a/fs/autofs/dirhash.c b/fs/autofs/dirhash.c index 90c18695a094..e9d5ac0d78f1 100644 --- a/fs/autofs/dirhash.c +++ b/fs/autofs/dirhash.c @@ -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) diff --git a/include/asm-i386/ptrace.h b/include/asm-i386/ptrace.h index 1b1b93bdb77e..ae94eded519a 100644 --- a/include/asm-i386/ptrace.h +++ b/include/asm-i386/ptrace.h @@ -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 diff --git a/include/linux/cyclades.h b/include/linux/cyclades.h index de9a3d072c9f..8ce98f5b5eaa 100644 --- a/include/linux/cyclades.h +++ b/include/linux/cyclades.h @@ -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 , @@ -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 */ diff --git a/include/linux/pci.h b/include/linux/pci.h index 37d1fb19a7d6..d5533077a035 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -920,6 +920,9 @@ #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 diff --git a/include/linux/rose.h b/include/linux/rose.h index 1746c67ca7a6..9fb1efca57e7 100644 --- a/include/linux/rose.h +++ b/include/linux/rose.h @@ -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 @@ -20,8 +22,11 @@ #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 @@ -35,22 +40,30 @@ #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 diff --git a/include/net/rose.h b/include/net/rose.h index 4bf38063a6f9..e868e517f4ef 100644 --- a/include/net/rose.h +++ b/include/net/rose.h @@ -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 @@ -55,25 +56,30 @@ #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 diff --git a/kernel/ksyms.c b/kernel/ksyms.c index ad6fa4f25e83..10b3849f4908 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -298,6 +298,7 @@ struct symbol_table symbol_table = { X(kill_proc), X(kill_pg), X(kill_sl), + X(force_sig), /* misc */ X(panic), diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 1e72c56c7ebc..65a38c542cbc 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -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; } diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 24f983ec6ee0..3cfb52156d45 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -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) diff --git a/net/rose/Makefile b/net/rose/Makefile index 0d71de9cf254..064fa7ca984e 100644 --- a/net/rose/Makefile +++ b/net/rose/Makefile @@ -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 diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 7cc4588a625e..368d7728ea2e 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -1,5 +1,5 @@ /* - * ROSE release 003 + * ROSE release 006 * * This code REQUIRES 2.1.0 or higher/ NET3.029 * @@ -14,8 +14,13 @@ * 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 @@ -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 index 000000000000..2d30b6612754 --- /dev/null +++ b/net/rose/changes.doc @@ -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. diff --git a/net/rose/rose_in.c b/net/rose/rose_in.c index 1b8be97175da..13eebc97627b 100644 --- a/net/rose/rose_in.c +++ b/net/rose/rose_in.c @@ -17,7 +17,6 @@ * * History * ROSE 001 Jonathan(G4KLX) Cloned from nr_in.c - * ROSE 003 Jonathan(G4KLX) Removed M bit processing. */ #include @@ -45,6 +44,45 @@ #include #include +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; } diff --git a/net/rose/rose_link.c b/net/rose/rose_link.c index 339165bd71ae..ff724650ab5d 100644 --- a/net/rose/rose_link.c +++ b/net/rose/rose_link.c @@ -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 index 000000000000..3c6707648ddc --- /dev/null +++ b/net/rose/rose_loopback.c @@ -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 +#if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE) +#include +#include +#include +#include +#include +#include + +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 diff --git a/net/rose/rose_out.c b/net/rose/rose_out.c index 9b79818cc54a..d8ee941ad45a 100644 --- a/net/rose/rose_out.c +++ b/net/rose/rose_out.c @@ -11,7 +11,6 @@ * * History * ROSE 001 Jonathan(G4KLX) Cloned from nr_out.c - * ROSE 003 Jonathan(G4KLX) Removed M bit processing. */ #include @@ -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 diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c index 725abc0ba9af..4634176aff65 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c @@ -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"); } diff --git a/net/rose/rose_subr.c b/net/rose/rose_subr.c index ce25a4dce7e1..9fcf94b198a6 100644 --- a/net/rose/rose_subr.c +++ b/net/rose/rose_subr.c @@ -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; diff --git a/net/rose/rose_timer.c b/net/rose/rose_timer.c index 2a9927c1d816..a2d466ea9d9a 100644 --- a/net/rose/rose_timer.c +++ b/net/rose/rose_timer.c @@ -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; -- 2.39.5