#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 *);
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),
#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
* 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.
#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 *) \
#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);
} 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;
}
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 */
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 */
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,
/* 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);
#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
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"),
*/
-#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>
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));
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;
}
BusLogic_TargetStatistics_T *TargetStatistics;
int TargetID, Length;
char *Buffer;
- if (WriteFlag) return 0;
for (HostAdapter = BusLogic_FirstRegisteredHostAdapter;
HostAdapter != NULL;
HostAdapter = HostAdapter->Next)
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\
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);
*
* 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.
*
* 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.
*
*---------------------------------------------------------------------*/
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
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.
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
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.
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)
#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
-/* $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>,
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 */
#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
#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];
};
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
#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;
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;
};
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;
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;
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 *);
/* 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 */
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
X(kill_proc),
X(kill_pg),
X(kill_sl),
+ X(force_sig),
/* misc */
X(panic),
return 1;
case SEL_EX:
- if (sk->urg_data)
+ if (sk->urg_data & URG_VALID)
return 1;
break;
}
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);
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);
{
struct sk_buff *buff;
struct tcphdr *t1;
- struct device *dev = NULL;
+ struct device *dev = sk->bound_device;
int tmp;
if(sk->zapped)
{
struct sk_buff *buff,*skb;
struct tcphdr *t1;
- struct device *dev=NULL;
+ struct device *dev=sk->bound_device;
int tmp;
if (sk->zapped)
# 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
/*
- * 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>
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;
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;
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;
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;
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);
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");
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);
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;
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;
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 */
{
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;
{
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;
}
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++;
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);
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;
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)
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;
}
int copied, qbit;
unsigned char *asmptr;
struct sk_buff *skb;
- int er;
+ int n, er;
if (sk->err)
return sock_error(sk);
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);
return 0;
}
- case SIOCRSL2CALL:
+ case SIOCRSSL2CALL:
if (!suser()) return -EPERM;
if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(ax25_address))) != 0)
return err;
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);
}
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);
}
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)
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,
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;
{"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)
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);
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);
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;
--- /dev/null
+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.
*
* 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.
*/
static int rose_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype)
{
+ int len;
+
switch (frametype) {
case ROSE_CALL_ACCEPTED:
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:
*/
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--;
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) {
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);
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;
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;
}
}
*/
static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype)
{
+ int len;
+
switch (frametype) {
case ROSE_RESET_REQUEST:
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:
*/
static int rose_state5_machine(struct sock *sk, struct sk_buff *skb, int frametype)
{
+ int len;
+
switch (frametype) {
case ROSE_CLEAR_REQUEST:
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;
}
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);
}
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);
{
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;
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;
*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
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;
--- /dev/null
+/*
+ * 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
*
* History
* ROSE 001 Jonathan(G4KLX) Cloned from nr_out.c
- * ROSE 003 Jonathan(G4KLX) Removed M bit processing.
*/
#include <linux/config.h>
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;
}
/*
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
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
{
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;
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;
}
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();
{
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)
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--;
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);
}
}
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;
else
failed = 1;
}
- /* F6FBB : All nodes for this route are out of order */
+ /* do not accept other node address */
break;
}
}
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;
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;
}
}
+/*
+ * 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.
*/
{
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;
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)
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.
* 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);
* 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;
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;
* 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;
}
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;
}
}
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;
}
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");
}
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;
+ }
+ }
}
/*
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;
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)
*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:
*dptr++ = lci2;
*dptr++ = frametype;
*dptr++ = ROSE_DTE_ORIGINATED;
- *dptr++ = 0;
+ *dptr++ = 0x00; /* Address length */
break;
case ROSE_RR:
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) {
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;
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];
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';
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++;
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;
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) {
*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;
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:
/*
* 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;
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;