/* * Add a new route to a node, and in the process add the node and the * neighbour if it is new.
*/ staticint __must_check rose_add_node(struct rose_route_struct *rose_route, struct net_device *dev)
{ struct rose_node *rose_node, *rose_tmpn, *rose_tmpp; struct rose_neigh *rose_neigh; int i, res = 0;
/* * This is a new node to be inserted into the list. Find where it needs * to be inserted into the list, and insert it. We want to be sure * to order the list in descending order of mask size to ensure that * later when we are searching this list the first match will be the * best match.
*/ if (rose_node == NULL) {
rose_tmpn = rose_node_list;
rose_tmpp = NULL;
/* We have space, slot it in */ if (rose_node->count < 3) {
rose_node->neighbour[rose_node->count] = rose_neigh;
rose_node->count++;
rose_neigh->count++;
rose_neigh_hold(rose_neigh);
}
while (s != NULL && s->next != NULL) { if (s->next == rose_route) {
s->next = rose_route->next;
kfree(rose_route); return;
}
s = s->next;
}
}
/* * "Delete" a node. Strictly speaking remove a route to a node. The node * is only deleted if no routes are left to it.
*/ staticint rose_del_node(struct rose_route_struct *rose_route, struct net_device *dev)
{ struct rose_node *rose_node; struct rose_neigh *rose_neigh; int i, err = 0;
/* * A device has been removed. Remove its routes and neighbours.
*/ void rose_rt_device_down(struct net_device *dev)
{ 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);
rose_neigh = rose_neigh_list; while (rose_neigh != NULL) {
s = rose_neigh;
rose_neigh = rose_neigh->next;
if (s->dev != dev) continue;
rose_node = rose_node_list;
while (rose_node != NULL) {
t = rose_node;
rose_node = rose_node->next;
for (i = t->count - 1; i >= 0; i--) { if (t->neighbour[i] != s) continue;
#if 0 /* Currently unused */ /* * A device has been removed. Remove its links.
*/ void rose_route_device_down(struct net_device *dev)
{ struct rose_route *s, *rose_route;
spin_lock_bh(&rose_route_list_lock);
rose_route = rose_route_list; while (rose_route != NULL) {
s = rose_route;
rose_route = rose_route->next;
if (s->neigh1->dev == dev || s->neigh2->dev == dev)
rose_remove_route(s);
}
spin_unlock_bh(&rose_route_list_lock);
} #endif
/* * Clear all nodes and neighbours out, except for neighbours with * active connections going through them. * Do not clear loopback neighbour and nodes.
*/ staticint rose_clear_routes(void)
{ struct rose_neigh *s, *rose_neigh; struct rose_node *t, *rose_node; int i;
/* * Check that the device given is a valid AX.25 interface that is "up". * called with RTNL
*/ staticstruct net_device *rose_ax25_dev_find(char *devname)
{ struct net_device *dev;
if ((dev = __dev_get_by_name(&init_net, devname)) == NULL) return NULL;
if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25) return dev;
return NULL;
}
/* * Find the first active ROSE device, usually "rose0".
*/ struct net_device *rose_dev_first(void)
{ struct net_device *dev, *first = NULL;
rcu_read_lock();
for_each_netdev_rcu(&init_net, dev) { if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE) if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
first = dev;
} if (first)
dev_hold(first);
rcu_read_unlock();
return first;
}
/* * Find the ROSE device for the given address.
*/ struct net_device *rose_dev_get(rose_address *addr)
{ struct net_device *dev;
/* * Find a neighbour or a route given a ROSE address.
*/ struct rose_neigh *rose_get_neigh(rose_address *addr, unsignedchar *cause, unsignedchar *diagnostic, int route_frame)
{ struct rose_neigh *res = NULL; struct rose_node *node; int failed = 0; int i;
if (!route_frame) spin_lock_bh(&rose_node_list_lock); 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]->restarted) {
res = node->neighbour[i];
rose_neigh_hold(node->neighbour[i]); goto out;
}
}
}
} if (!route_frame) { /* connect request */ 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 (!rose_ftimer_running(node->neighbour[i])) {
res = node->neighbour[i];
rose_neigh_hold(node->neighbour[i]); goto out;
}
failed = 1;
}
}
}
}
out: if (!route_frame) spin_unlock_bh(&rose_node_list_lock); return res;
}
/* * Handle the ioctls that control the routing functions.
*/ int rose_rt_ioctl(unsignedint cmd, void __user *arg)
{ struct rose_route_struct rose_route; struct net_device *dev; int err;
switch (cmd) { case SIOCADDRT: if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct))) return -EFAULT; if ((dev = rose_ax25_dev_find(rose_route.device)) == NULL) return -EINVAL; if (rose_dev_exists(&rose_route.address)) /* Can't add routes to ourself */ return -EINVAL; if (rose_route.mask > 10) /* Mask can't be more than 10 digits */ return -EINVAL; if (rose_route.ndigis > AX25_MAX_DIGIS) return -EINVAL;
err = rose_add_node(&rose_route, dev); return err;
case SIOCDELRT: if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct))) return -EFAULT; if ((dev = rose_ax25_dev_find(rose_route.device)) == NULL) return -EINVAL;
err = rose_del_node(&rose_route, dev); return err;
/* * 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. Blow away all through * routes and connections using this route.
*/ void rose_link_failed(ax25_cb *ax25, int reason)
{ struct rose_neigh *rose_neigh;
spin_lock_bh(&rose_neigh_list_lock);
rose_neigh = rose_neigh_list; while (rose_neigh != NULL) { if (rose_neigh->ax25 == ax25) break;
rose_neigh = rose_neigh->next;
}
if (rose_neigh != NULL) {
rose_neigh->ax25 = NULL;
ax25_cb_put(ax25);
/* * 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 net_device *dev)
{ struct rose_neigh *rose_neigh;
/* * Is is a Call Request and is it for us ?
*/ if (frametype == ROSE_CALL_REQUEST) if ((dev = rose_dev_get(dest_addr)) != NULL) {
res = rose_rx_call_request(skb, dev, rose_neigh, lci);
dev_put(dev); goto out;
}
if (!sysctl_rose_routing_control) {
rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 0); goto out;
}
/* * Route it to the next in line if we have an entry for it.
*/
rose_route = rose_route_list; while (rose_route != NULL) { if (rose_route->lci1 == lci &&
rose_route->neigh1 == rose_neigh) { if (frametype == ROSE_CALL_REQUEST) { /* F6FBB - Remove an existing unused route */
rose_remove_route(rose_route); break;
} elseif (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);
res = 1; goto out;
} else { if (frametype == ROSE_CLEAR_CONFIRMATION)
rose_remove_route(rose_route); goto out;
}
} if (rose_route->lci2 == lci &&
rose_route->neigh2 == rose_neigh) { if (frametype == ROSE_CALL_REQUEST) { /* F6FBB - Remove an existing unused route */
rose_remove_route(rose_route); break;
} elseif (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);
res = 1; goto out;
} else { if (frametype == ROSE_CLEAR_CONFIRMATION)
rose_remove_route(rose_route); goto out;
}
}
rose_route = rose_route->next;
}
/* * We know that: * 1. The frame isn't for us, * 2. It isn't "owned" by any existing route.
*/ if (frametype != ROSE_CALL_REQUEST) { /* XXX */
res = 0; goto out;
}
if (rose_neigh->digipeat != NULL) { for (i = 0; i < rose_neigh->digipeat->ndigi; i++)
seq_printf(seq, " %s", ax2asc(buf, &rose_neigh->digipeat->calls[i]));
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.