patch-2.1.42 linux/net/rose/rose_route.c
Next file: linux/net/rose/rose_subr.c
Previous file: linux/net/rose/rose_out.c
Back to the patch index
Back to the overall index
- Lines: 491
- Date:
Wed May 28 10:49:12 1997
- Orig file:
v2.1.41/linux/net/rose/rose_route.c
- Orig date:
Thu Mar 27 14:40:17 1997
diff -u --recursive --new-file v2.1.41/linux/net/rose/rose_route.c linux/net/rose/rose_route.c
@@ -1,8 +1,5 @@
/*
- * Rose release 001
- *
- * This is ALPHA test software. This code may break your machine, randomly fail to work with new
- * releases, misbehave and/or generally screw up. It might even work.
+ * ROSE release 002
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -13,9 +10,11 @@
* 2 of the License, or (at your option) any later version.
*
* History
- * Rose 001 Jonathan(G4KLX) Cloned from nr_route.c.
+ * ROSE 001 Jonathan(G4KLX) Cloned from nr_route.c.
* Terry(VK2KTJ) Added support for variable length
* address masks.
+ * ROSE 002 Jonathan(G4KLX) Uprated through routing of packets.
+ * Routing loop detection.
*/
#include <linux/config.h>
@@ -76,13 +75,14 @@
break;
if (rose_neigh == NULL) {
- if ((rose_neigh = (struct rose_neigh *)kmalloc(sizeof(*rose_neigh), GFP_ATOMIC)) == NULL)
+ if ((rose_neigh = kmalloc(sizeof(*rose_neigh), GFP_ATOMIC)) == NULL)
return -ENOMEM;
rose_neigh->callsign = rose_route->neighbour;
rose_neigh->digipeat = NULL;
rose_neigh->dev = dev;
rose_neigh->count = 0;
+ rose_neigh->dce_mode = 0;
rose_neigh->number = rose_neigh_no++;
rose_neigh->restarted = 0;
skb_queue_head_init(&rose_neigh->queue);
@@ -92,7 +92,7 @@
if (rose_route->ndigis != 0) {
if ((rose_neigh->digipeat = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) {
- kfree_s(rose_neigh, sizeof(*rose_neigh));
+ kfree(rose_neigh);
return -ENOMEM;
}
rose_neigh->digipeat->ndigi = rose_route->ndigis;
@@ -127,7 +127,7 @@
}
/* create new node */
- if ((rose_node = (struct rose_node *)kmalloc(sizeof(*rose_node), GFP_ATOMIC)) == NULL)
+ if ((rose_node = kmalloc(sizeof(*rose_node), GFP_ATOMIC)) == NULL)
return -ENOMEM;
rose_node->address = rose_route->address;
@@ -183,7 +183,7 @@
if ((s = rose_node_list) == rose_node) {
rose_node_list = rose_node->next;
restore_flags(flags);
- kfree_s(rose_node, sizeof(struct rose_node));
+ kfree(rose_node);
return;
}
@@ -191,7 +191,7 @@
if (s->next == rose_node) {
s->next = rose_node->next;
restore_flags(flags);
- kfree_s(rose_node, sizeof(struct rose_node));
+ kfree(rose_node);
return;
}
@@ -219,8 +219,8 @@
rose_neigh_list = rose_neigh->next;
restore_flags(flags);
if (rose_neigh->digipeat != NULL)
- kfree_s(rose_neigh->digipeat, sizeof(ax25_digi));
- kfree_s(rose_neigh, sizeof(struct rose_neigh));
+ kfree(rose_neigh->digipeat);
+ kfree(rose_neigh);
return;
}
@@ -229,8 +229,8 @@
s->next = rose_neigh->next;
restore_flags(flags);
if (rose_neigh->digipeat != NULL)
- kfree_s(rose_neigh->digipeat, sizeof(ax25_digi));
- kfree_s(rose_neigh, sizeof(struct rose_neigh));
+ kfree(rose_neigh->digipeat);
+ kfree(rose_neigh);
return;
}
@@ -251,7 +251,7 @@
if ((s = rose_route_list) == rose_route) {
rose_route_list = rose_route->next;
restore_flags(flags);
- kfree_s(rose_route, sizeof(struct rose_route));
+ kfree(rose_route);
return;
}
@@ -259,7 +259,7 @@
if (s->next == rose_route) {
s->next = rose_route->next;
restore_flags(flags);
- kfree_s(rose_route, sizeof(struct rose_route));
+ kfree(rose_route);
return;
}
@@ -372,7 +372,7 @@
struct rose_route *s, *rose_route = rose_route_list;
while (rose_route != NULL) {
- s = rose_route;
+ s = rose_route;
rose_route = rose_route->next;
if (s->neigh1->dev == dev || s->neigh2->dev == dev)
@@ -397,7 +397,7 @@
}
/*
- * Find the first active Rose device, usually "rose0".
+ * Find the first active ROSE device, usually "rose0".
*/
struct device *rose_dev_first(void)
{
@@ -412,7 +412,7 @@
}
/*
- * Find the Rose device for the given address.
+ * Find the ROSE device for the given address.
*/
struct device *rose_dev_get(rose_address *addr)
{
@@ -425,23 +425,34 @@
return NULL;
}
+struct rose_route *rose_route_free_lci(unsigned int lci, struct rose_neigh *neigh)
+{
+ 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))
+ return rose_route;
+
+ return NULL;
+}
+
/*
- * Find a neighbour given a Rose address.
+ * Find a neighbour given a ROSE address.
*/
struct rose_neigh *rose_get_neigh(rose_address *addr)
{
struct rose_node *node;
int i;
- for (node = rose_node_list; node != NULL; node = node->next)
- if (rosecmpm(addr, &node->address, node->mask) == 0)
- break;
-
- if (node == NULL) return NULL;
-
- for (i = 0; i < node->count; i++)
- if (node->neighbour[i]->ftimer == 0)
- return node->neighbour[i];
+ for (node = rose_node_list; node != NULL; node = node->next) {
+ if (rosecmpm(addr, &node->address, node->mask) == 0) {
+ for (i = 0; i < node->count; i++) {
+ if (node->neighbour[i]->ftimer == 0)
+ return node->neighbour[i];
+ }
+ }
+ }
return NULL;
}
@@ -485,14 +496,54 @@
return 0;
}
+static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh)
+{
+ struct rose_route *rose_route, *s;
+ struct sk_buff *skb;
+
+ rose_neigh->restarted = 0;
+ rose_neigh->t0timer = 0;
+ rose_neigh->ftimer = sysctl_rose_link_fail_timeout;
+
+ rose_link_set_timer(rose_neigh);
+
+ while ((skb = skb_dequeue(&rose_neigh->queue)) != NULL)
+ kfree_skb(skb, FREE_WRITE);
+
+ 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)) {
+ s = rose_route->next;
+ rose_remove_route(rose_route);
+ rose_route = s;
+ continue;
+ }
+
+ if (rose_route->neigh1 == rose_neigh) {
+ rose_route->neigh1 = NULL;
+ rose_transmit_clear_request(rose_route->neigh2, rose_route->lci2, 0x0D);
+ }
+
+ if (rose_route->neigh2 == rose_neigh) {
+ rose_route->neigh2 = NULL;
+ rose_transmit_clear_request(rose_route->neigh1, rose_route->lci1, 0x0D);
+ }
+
+ rose_route = rose_route->next;
+ }
+}
+
/*
* A level 2 link has timed out, therefore it appears to be a poor link,
- * then don't use that neighbour until it is reset. XXX others.
+ * then don't use that neighbour until it is reset. Blow away all through
+ * routes and connections using this route.
*/
void rose_link_failed(ax25_address *callsign, struct device *dev)
{
struct rose_neigh *rose_neigh;
- struct sk_buff *skb;
for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
if (ax25cmp(&rose_neigh->callsign, callsign) == 0 && rose_neigh->dev == dev)
@@ -500,33 +551,22 @@
if (rose_neigh == NULL) return;
- rose_neigh->restarted = 0;
- rose_neigh->t0timer = 0;
- rose_neigh->ftimer = sysctl_rose_link_fail_timeout;
-
- rose_link_set_timer(rose_neigh);
-
- while ((skb = skb_dequeue(&rose_neigh->queue)) != NULL)
- kfree_skb(skb, FREE_WRITE);
+ rose_del_route_by_neigh(rose_neigh);
+ rose_kill_by_neigh(rose_neigh);
}
/*
- * A device has been "downed" remove its link status. XXX others.
+ * A device has been "downed" remove its link status. Blow away all
+ * through routes and connections that use this device.
*/
void rose_link_device_down(struct device *dev)
{
struct rose_neigh *rose_neigh;
- struct sk_buff *skb;
for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) {
if (rose_neigh->dev == dev) {
- rose_neigh->restarted = 0;
- rose_neigh->t0timer = 0;
- rose_neigh->ftimer = 0;
- del_timer(&rose_neigh->timer);
-
- while ((skb = skb_dequeue(&rose_neigh->queue)) != NULL)
- kfree_skb(skb, FREE_WRITE);
+ rose_del_route_by_neigh(rose_neigh);
+ rose_kill_by_neigh(rose_neigh);
}
}
}
@@ -538,10 +578,11 @@
{
struct rose_neigh *rose_neigh, *new_neigh;
struct rose_route *rose_route;
+ struct rose_facilities facilities;
rose_address *src_addr, *dest_addr;
struct sock *sk;
unsigned short frametype;
- unsigned int lci;
+ unsigned int lci, new_lci;
struct device *dev;
unsigned long flags;
@@ -577,7 +618,7 @@
/*
* Find an existing socket.
*/
- if ((sk = rose_find_socket(lci, rose_neigh->dev)) != NULL) {
+ if ((sk = rose_find_socket(lci, rose_neigh)) != NULL) {
skb->h.raw = skb->data;
return rose_process_rx_frame(sk, skb);
}
@@ -597,29 +638,36 @@
/*
* Route it to the next in line if we have an entry for it.
*/
-
- /*
- * We should check for the random number in the facilities
- * here. XXX.
- */
for (rose_route = rose_route_list; rose_route != NULL; rose_route = rose_route->next) {
if (rose_route->lci1 == lci && rose_route->neigh1 == rose_neigh) {
- 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);
- if (frametype == ROSE_CLEAR_CONFIRMATION)
- rose_remove_route(rose_route);
- return 1;
+ if (rose_route->neigh2 != NULL) {
+ 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);
+ if (frametype == ROSE_CLEAR_CONFIRMATION)
+ rose_remove_route(rose_route);
+ return 1;
+ } else {
+ if (frametype == ROSE_CLEAR_CONFIRMATION)
+ rose_remove_route(rose_route);
+ return 0;
+ }
}
if (rose_route->lci2 == lci && rose_route->neigh2 == rose_neigh) {
- 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);
- if (frametype == ROSE_CLEAR_CONFIRMATION)
- rose_remove_route(rose_route);
- return 1;
+ if (rose_route->neigh1 != NULL) {
+ 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);
+ if (frametype == ROSE_CLEAR_CONFIRMATION)
+ rose_remove_route(rose_route);
+ return 1;
+ } else {
+ if (frametype == ROSE_CLEAR_CONFIRMATION)
+ rose_remove_route(rose_route);
+ return 0;
+ }
}
}
@@ -631,20 +679,49 @@
if (frametype != ROSE_CALL_REQUEST) /* XXX */
return 0;
+ rose_parse_facilities(skb, &facilities);
+
+ /*
+ * Check for routing loops.
+ */
+ for (rose_route = rose_route_list; rose_route != NULL; rose_route = rose_route->next) {
+ if (rose_route->rand == facilities.rand &&
+ 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, 0x0D);
+ return 0;
+ }
+ }
+
if ((new_neigh = rose_get_neigh(dest_addr)) == NULL) {
+ printk(KERN_DEBUG "ROSE: no route to %s\n", rose2asc(dest_addr));
rose_transmit_clear_request(rose_neigh, lci, 0x0D);
return 0;
}
- if ((rose_route = (struct rose_route *)kmalloc(sizeof(*rose_route), GFP_ATOMIC)) == NULL) {
+ if ((new_lci = rose_new_lci(new_neigh)) == 0) {
+ printk(KERN_DEBUG "ROSE: no spare VCs to %s\n", rose2asc(dest_addr));
rose_transmit_clear_request(rose_neigh, lci, 0x0D);
return 0;
}
- rose_route->lci1 = lci;
- rose_route->neigh1 = rose_neigh;
- rose_route->lci2 = rose_new_lci(new_neigh->dev);
- rose_route->neigh2 = new_neigh;
+ if ((rose_route = kmalloc(sizeof(*rose_route), GFP_ATOMIC)) == NULL) {
+ rose_transmit_clear_request(rose_neigh, lci, 0x0D);
+ 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;
save_flags(flags); cli();
rose_route->next = rose_route_list;
@@ -716,14 +793,15 @@
cli();
- len += sprintf(buffer, "addr callsign dev count restart t0 tf\n");
+ len += sprintf(buffer, "addr callsign dev count mode restart t0 tf\n");
for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) {
- len += sprintf(buffer + len, "%05d %-9s %-4s %3d %3s %3d %3d\n",
+ len += sprintf(buffer + len, "%05d %-9s %-4s %3d %3s %3s %3d %3d\n",
rose_neigh->number,
ax2asc(&rose_neigh->callsign),
rose_neigh->dev ? rose_neigh->dev->name : "???",
rose_neigh->count,
+ (rose_neigh->dce_mode) ? "DCE" : "DTE",
(rose_neigh->restarted) ? "yes" : "no",
rose_neigh->t0timer / ROSE_SLOWHZ,
rose_neigh->ftimer / ROSE_SLOWHZ);
@@ -759,17 +837,28 @@
cli();
- len += sprintf(buffer, "lci callsign dev <-> lci callsign dev\n");
+ 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) {
- len += sprintf(buffer + len, "%3.3X %-9s %-4s ",
- rose_route->lci1,
- ax2asc(&rose_route->neigh1->callsign),
- rose_route->neigh1->dev ? rose_route->neigh1->dev->name : "???");
- len += sprintf(buffer + len, "%3.3X %-9s %-4s\n",
- rose_route->lci2,
- ax2asc(&rose_route->neigh2->callsign),
- rose_route->neigh2->dev ? rose_route->neigh2->dev->name : "???");
+ if (rose_route->neigh1 != NULL) {
+ len += sprintf(buffer + len, "%3.3X %-10s %-9s %05d ",
+ rose_route->lci1,
+ rose2asc(&rose_route->src_addr),
+ ax2asc(&rose_route->src_call),
+ rose_route->neigh1->number);
+ } else {
+ len += sprintf(buffer + len, "000 * * 00000 ");
+ }
+
+ if (rose_route->neigh2 != NULL) {
+ len += sprintf(buffer + len, "%3.3X %-10s %-9s %05d\n",
+ rose_route->lci2,
+ rose2asc(&rose_route->dest_addr),
+ ax2asc(&rose_route->dest_call),
+ rose_route->neigh2->number);
+ } else {
+ len += sprintf(buffer + len, "000 * * 00000\n");
+ }
pos = begin + len;
@@ -795,7 +884,7 @@
#ifdef MODULE
/*
- * Release all memory associated with Rose routing structures.
+ * Release all memory associated with ROSE routing structures.
*/
void rose_rt_free(void)
{
@@ -811,7 +900,7 @@
}
while (rose_node != NULL) {
- t = rose_node;
+ t = rose_node;
rose_node = rose_node->next;
rose_remove_node(t);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov