summaryrefslogtreecommitdiff
path: root/net/rose/rose_route.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/rose/rose_route.c')
-rw-r--r--net/rose/rose_route.c184
1 files changed, 76 insertions, 108 deletions
diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c
index 452bbb38d943..a1e9b05ef6f5 100644
--- a/net/rose/rose_route.c
+++ b/net/rose/rose_route.c
@@ -1,8 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * This program 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.
*
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Terry Dawson VK2KTJ (terry@animats.net)
@@ -96,16 +93,16 @@ static int __must_check rose_add_node(struct rose_route_struct *rose_route,
rose_neigh->ax25 = NULL;
rose_neigh->dev = dev;
rose_neigh->count = 0;
- rose_neigh->use = 0;
rose_neigh->dce_mode = 0;
rose_neigh->loopback = 0;
rose_neigh->number = rose_neigh_no++;
rose_neigh->restarted = 0;
+ refcount_set(&rose_neigh->use, 1);
skb_queue_head_init(&rose_neigh->queue);
- init_timer(&rose_neigh->ftimer);
- init_timer(&rose_neigh->t0timer);
+ timer_setup(&rose_neigh->ftimer, NULL, 0);
+ timer_setup(&rose_neigh->t0timer, NULL, 0);
if (rose_route->ndigis != 0) {
rose_neigh->digipeat =
@@ -181,6 +178,7 @@ static int __must_check rose_add_node(struct rose_route_struct *rose_route,
}
}
rose_neigh->count++;
+ rose_neigh_hold(rose_neigh);
goto out;
}
@@ -190,6 +188,7 @@ static int __must_check rose_add_node(struct rose_route_struct *rose_route,
rose_node->neighbour[rose_node->count] = rose_neigh;
rose_node->count++;
rose_neigh->count++;
+ rose_neigh_hold(rose_neigh);
}
out:
@@ -230,27 +229,19 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
{
struct rose_neigh *s;
- rose_stop_ftimer(rose_neigh);
- rose_stop_t0timer(rose_neigh);
+ timer_delete_sync(&rose_neigh->ftimer);
+ timer_delete_sync(&rose_neigh->t0timer);
skb_queue_purge(&rose_neigh->queue);
if ((s = rose_neigh_list) == rose_neigh) {
rose_neigh_list = rose_neigh->next;
- if (rose_neigh->ax25)
- ax25_cb_put(rose_neigh->ax25);
- kfree(rose_neigh->digipeat);
- kfree(rose_neigh);
return;
}
while (s != NULL && s->next != NULL) {
if (s->next == rose_neigh) {
s->next = rose_neigh->next;
- if (rose_neigh->ax25)
- ax25_cb_put(rose_neigh->ax25);
- kfree(rose_neigh->digipeat);
- kfree(rose_neigh);
return;
}
@@ -266,10 +257,10 @@ static void rose_remove_route(struct rose_route *rose_route)
struct rose_route *s;
if (rose_route->neigh1 != NULL)
- rose_route->neigh1->use--;
+ rose_neigh_put(rose_route->neigh1);
if (rose_route->neigh2 != NULL)
- rose_route->neigh2->use--;
+ rose_neigh_put(rose_route->neigh2);
if ((s = rose_route_list) == rose_route) {
rose_route_list = rose_route->next;
@@ -333,9 +324,12 @@ static int rose_del_node(struct rose_route_struct *rose_route,
for (i = 0; i < rose_node->count; i++) {
if (rose_node->neighbour[i] == rose_neigh) {
rose_neigh->count--;
+ rose_neigh_put(rose_neigh);
- if (rose_neigh->count == 0 && rose_neigh->use == 0)
+ if (rose_neigh->count == 0) {
rose_remove_neigh(rose_neigh);
+ rose_neigh_put(rose_neigh);
+ }
rose_node->count--;
@@ -346,9 +340,11 @@ static int rose_del_node(struct rose_route_struct *rose_route,
case 0:
rose_node->neighbour[0] =
rose_node->neighbour[1];
+ fallthrough;
case 1:
rose_node->neighbour[1] =
rose_node->neighbour[2];
+ break;
case 2:
break;
}
@@ -382,16 +378,16 @@ void rose_add_loopback_neigh(void)
sn->ax25 = NULL;
sn->dev = NULL;
sn->count = 0;
- sn->use = 0;
sn->dce_mode = 1;
sn->loopback = 1;
sn->number = rose_neigh_no++;
sn->restarted = 1;
+ refcount_set(&sn->use, 1);
skb_queue_head_init(&sn->queue);
- init_timer(&sn->ftimer);
- init_timer(&sn->t0timer);
+ timer_setup(&sn->ftimer, NULL, 0);
+ timer_setup(&sn->t0timer, NULL, 0);
spin_lock_bh(&rose_neigh_list_lock);
sn->next = rose_neigh_list;
@@ -402,7 +398,7 @@ void rose_add_loopback_neigh(void)
/*
* Add a loopback node.
*/
-int rose_add_loopback_node(rose_address *address)
+int rose_add_loopback_node(const rose_address *address)
{
struct rose_node *rose_node;
int err = 0;
@@ -437,6 +433,7 @@ int rose_add_loopback_node(rose_address *address)
rose_node_list = rose_node;
rose_loopback_neigh->count++;
+ rose_neigh_hold(rose_loopback_neigh);
out:
spin_unlock_bh(&rose_node_list_lock);
@@ -447,7 +444,7 @@ out:
/*
* Delete a loopback node.
*/
-void rose_del_loopback_node(rose_address *address)
+void rose_del_loopback_node(const rose_address *address)
{
struct rose_node *rose_node;
@@ -468,6 +465,7 @@ void rose_del_loopback_node(rose_address *address)
rose_remove_node(rose_node);
rose_loopback_neigh->count--;
+ rose_neigh_put(rose_loopback_neigh);
out:
spin_unlock_bh(&rose_node_list_lock);
@@ -498,20 +496,16 @@ void rose_rt_device_down(struct net_device *dev)
t = rose_node;
rose_node = rose_node->next;
- for (i = 0; i < t->count; i++) {
+ for (i = t->count - 1; i >= 0; i--) {
if (t->neighbour[i] != s)
continue;
t->count--;
- switch (i) {
- case 0:
- t->neighbour[0] = t->neighbour[1];
- case 1:
- t->neighbour[1] = t->neighbour[2];
- case 2:
- break;
- }
+ memmove(&t->neighbour[i], &t->neighbour[i + 1],
+ sizeof(t->neighbour[0]) *
+ (t->count - i));
+ rose_neigh_put(s);
}
if (t->count <= 0)
@@ -519,6 +513,7 @@ void rose_rt_device_down(struct net_device *dev)
}
rose_remove_neigh(s);
+ rose_neigh_put(s);
}
spin_unlock_bh(&rose_neigh_list_lock);
spin_unlock_bh(&rose_node_list_lock);
@@ -554,6 +549,7 @@ static int rose_clear_routes(void)
{
struct rose_neigh *s, *rose_neigh;
struct rose_node *t, *rose_node;
+ int i;
spin_lock_bh(&rose_node_list_lock);
spin_lock_bh(&rose_neigh_list_lock);
@@ -564,17 +560,21 @@ static int rose_clear_routes(void)
while (rose_node != NULL) {
t = rose_node;
rose_node = rose_node->next;
- if (!t->loopback)
+
+ if (!t->loopback) {
+ for (i = 0; i < t->count; i++)
+ rose_neigh_put(t->neighbour[i]);
rose_remove_node(t);
+ }
}
while (rose_neigh != NULL) {
s = rose_neigh;
rose_neigh = rose_neigh->next;
- if (s->use == 0 && !s->loopback) {
- s->count = 0;
+ if (!s->loopback) {
rose_remove_neigh(s);
+ rose_neigh_put(s);
}
}
@@ -614,6 +614,8 @@ struct net_device *rose_dev_first(void)
if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
first = dev;
}
+ if (first)
+ dev_hold(first);
rcu_read_unlock();
return first;
@@ -628,7 +630,8 @@ struct net_device *rose_dev_get(rose_address *addr)
rcu_read_lock();
for_each_netdev_rcu(&init_net, dev) {
- if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && rosecmp(addr, (rose_address *)dev->dev_addr) == 0) {
+ if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE &&
+ rosecmp(addr, (const rose_address *)dev->dev_addr) == 0) {
dev_hold(dev);
goto out;
}
@@ -645,7 +648,8 @@ static int rose_dev_exists(rose_address *addr)
rcu_read_lock();
for_each_netdev_rcu(&init_net, dev) {
- if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && rosecmp(addr, (rose_address *)dev->dev_addr) == 0)
+ if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE &&
+ rosecmp(addr, (const rose_address *)dev->dev_addr) == 0)
goto out;
}
dev = NULL;
@@ -686,6 +690,7 @@ struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause,
for (i = 0; i < node->count; i++) {
if (node->neighbour[i]->restarted) {
res = node->neighbour[i];
+ rose_neigh_hold(node->neighbour[i]);
goto out;
}
}
@@ -697,7 +702,7 @@ struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause,
for (i = 0; i < node->count; i++) {
if (!rose_ftimer_running(node->neighbour[i])) {
res = node->neighbour[i];
- failed = 0;
+ rose_neigh_hold(node->neighbour[i]);
goto out;
}
failed = 1;
@@ -787,13 +792,13 @@ static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh)
}
if (rose_route->neigh1 == rose_neigh) {
- rose_route->neigh1->use--;
+ rose_neigh_put(rose_route->neigh1);
rose_route->neigh1 = NULL;
rose_transmit_clear_request(rose_route->neigh2, rose_route->lci2, ROSE_OUT_OF_ORDER, 0);
}
if (rose_route->neigh2 == rose_neigh) {
- rose_route->neigh2->use--;
+ rose_neigh_put(rose_route->neigh2);
rose_route->neigh2 = NULL;
rose_transmit_clear_request(rose_route->neigh1, rose_route->lci1, ROSE_OUT_OF_ORDER, 0);
}
@@ -848,6 +853,7 @@ void rose_link_device_down(struct net_device *dev)
/*
* Route a frame to an appropriate AX.25 connection.
+ * A NULL ax25_cb indicates an internally generated frame.
*/
int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
{
@@ -865,6 +871,10 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
if (skb->len < ROSE_MIN_LEN)
return res;
+
+ if (!ax25)
+ return rose_loopback_queue(skb, NULL);
+
frametype = skb->data[2];
lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF);
if (frametype == ROSE_CALL_REQUEST &&
@@ -917,7 +927,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
rose_clear_queues(sk);
rose->cause = ROSE_NETWORK_CONGESTION;
rose->diagnostic = 0;
- rose->neighbour->use--;
+ rose_neigh_put(rose->neighbour);
rose->neighbour = NULL;
rose->lci = 0;
rose->state = ROSE_STATE_0;
@@ -1042,12 +1052,12 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
if ((new_lci = rose_new_lci(new_neigh)) == 0) {
rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 71);
- goto out;
+ goto put_neigh;
}
if ((rose_route = kmalloc(sizeof(*rose_route), GFP_ATOMIC)) == NULL) {
rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 120);
- goto out;
+ goto put_neigh;
}
rose_route->lci1 = lci;
@@ -1060,8 +1070,8 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
rose_route->lci2 = new_lci;
rose_route->neigh2 = new_neigh;
- rose_route->neigh1->use++;
- rose_route->neigh2->use++;
+ rose_neigh_hold(rose_route->neigh1);
+ rose_neigh_hold(rose_route->neigh2);
rose_route->next = rose_route_list;
rose_route_list = rose_route;
@@ -1073,6 +1083,8 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
rose_transmit_link(skb, rose_route->neigh2);
res = 1;
+put_neigh:
+ rose_neigh_put(new_neigh);
out:
spin_unlock_bh(&rose_route_list_lock);
spin_unlock_bh(&rose_neigh_list_lock);
@@ -1121,46 +1133,26 @@ static int rose_node_show(struct seq_file *seq, void *v)
seq_puts(seq, "address mask n neigh neigh neigh\n");
else {
const struct rose_node *rose_node = v;
- /* if (rose_node->loopback) {
- seq_printf(seq, "%-10s %04d 1 loopback\n",
- rose2asc(rsbuf, &rose_node->address),
- rose_node->mask);
- } else { */
- seq_printf(seq, "%-10s %04d %d",
- rose2asc(rsbuf, &rose_node->address),
- rose_node->mask,
- rose_node->count);
-
- for (i = 0; i < rose_node->count; i++)
- seq_printf(seq, " %05d",
- rose_node->neighbour[i]->number);
-
- seq_puts(seq, "\n");
- /* } */
+ seq_printf(seq, "%-10s %04d %d",
+ rose2asc(rsbuf, &rose_node->address),
+ rose_node->mask,
+ rose_node->count);
+
+ for (i = 0; i < rose_node->count; i++)
+ seq_printf(seq, " %05d", rose_node->neighbour[i]->number);
+
+ seq_puts(seq, "\n");
}
return 0;
}
-static const struct seq_operations rose_node_seqops = {
+const struct seq_operations rose_node_seqops = {
.start = rose_node_start,
.next = rose_node_next,
.stop = rose_node_stop,
.show = rose_node_show,
};
-static int rose_nodes_open(struct inode *inode, struct file *file)
-{
- return seq_open(file, &rose_node_seqops);
-}
-
-const struct file_operations rose_nodes_fops = {
- .owner = THIS_MODULE,
- .open = rose_nodes_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
-};
-
static void *rose_neigh_start(struct seq_file *seq, loff_t *pos)
__acquires(rose_neigh_list_lock)
{
@@ -1208,7 +1200,7 @@ static int rose_neigh_show(struct seq_file *seq, void *v)
(rose_neigh->loopback) ? "RSLOOP-0" : ax2asc(buf, &rose_neigh->callsign),
rose_neigh->dev ? rose_neigh->dev->name : "???",
rose_neigh->count,
- rose_neigh->use,
+ refcount_read(&rose_neigh->use) - rose_neigh->count - 1,
(rose_neigh->dce_mode) ? "DCE" : "DTE",
(rose_neigh->restarted) ? "yes" : "no",
ax25_display_timer(&rose_neigh->t0timer) / HZ,
@@ -1225,27 +1217,13 @@ static int rose_neigh_show(struct seq_file *seq, void *v)
}
-static const struct seq_operations rose_neigh_seqops = {
+const struct seq_operations rose_neigh_seqops = {
.start = rose_neigh_start,
.next = rose_neigh_next,
.stop = rose_neigh_stop,
.show = rose_neigh_show,
};
-static int rose_neigh_open(struct inode *inode, struct file *file)
-{
- return seq_open(file, &rose_neigh_seqops);
-}
-
-const struct file_operations rose_neigh_fops = {
- .owner = THIS_MODULE,
- .open = rose_neigh_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
-};
-
-
static void *rose_route_start(struct seq_file *seq, loff_t *pos)
__acquires(rose_route_list_lock)
{
@@ -1311,26 +1289,12 @@ static int rose_route_show(struct seq_file *seq, void *v)
return 0;
}
-static const struct seq_operations rose_route_seqops = {
+struct seq_operations rose_route_seqops = {
.start = rose_route_start,
.next = rose_route_next,
.stop = rose_route_stop,
.show = rose_route_show,
};
-
-static int rose_route_open(struct inode *inode, struct file *file)
-{
- return seq_open(file, &rose_route_seqops);
-}
-
-const struct file_operations rose_routes_fops = {
- .owner = THIS_MODULE,
- .open = rose_route_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
-};
-
#endif /* CONFIG_PROC_FS */
/*
@@ -1341,18 +1305,22 @@ void __exit rose_rt_free(void)
struct rose_neigh *s, *rose_neigh = rose_neigh_list;
struct rose_node *t, *rose_node = rose_node_list;
struct rose_route *u, *rose_route = rose_route_list;
+ int i;
while (rose_neigh != NULL) {
s = rose_neigh;
rose_neigh = rose_neigh->next;
rose_remove_neigh(s);
+ rose_neigh_put(s);
}
while (rose_node != NULL) {
t = rose_node;
rose_node = rose_node->next;
+ for (i = 0; i < t->count; i++)
+ rose_neigh_put(t->neighbour[i]);
rose_remove_node(t);
}