/* * Handle the ioctls that control the routing functions. */ int rose_rt_ioctl(unsigned int cmd, void *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_get(rose_route.device)) == NULL) return -EINVAL; if (rose_dev_exists(&rose_route.address)) { /* Can't add routes to ourself */ dev_put(dev); 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); dev_put(dev); return err; case SIOCDELRT: if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct))) return -EFAULT; if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL) return -EINVAL; err = rose_del_node(&rose_route, dev); dev_put(dev); return err; case SIOCRSCLRRT: return rose_clear_routes(); default: return -EINVAL; } return 0; }
/* * Handle the ioctls that control the routing functions. */ int rose_rt_ioctl(unsigned int cmd, void *arg) { struct rose_route_struct rose_route; struct device *dev; int err; switch (cmd) { case SIOCADDRT: if ((err = verify_area(VERIFY_READ, arg, sizeof(struct rose_route_struct))) != 0) return err; 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_route.mask > 10) /* Mask can't be more than 10 digits */ return -EINVAL; return rose_add_node(&rose_route, dev); case SIOCDELRT: if ((err = verify_area(VERIFY_READ, arg, sizeof(struct rose_route_struct))) != 0) return err; memcpy_fromfs(&rose_route, arg, sizeof(struct rose_route_struct)); if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL) return -EINVAL; return rose_del_node(&rose_route, dev); case SIOCRSCLRRT: return rose_clear_routes(); default: return -EINVAL; } return 0; }
/* * Add a new route to a node, and in the process add the node and the * neighbour if it is new. */ static int rose_add_node(struct rose_route_struct *rose_route, struct device *dev) { 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; for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next) if ((rose_node->mask == rose_route->mask) && (rosecmpm(&rose_route->address, &rose_node->address, rose_route->mask) == 0)) break; for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0 && rose_neigh->dev == dev) break; if (rose_neigh == NULL) { if ((rose_neigh = (struct rose_neigh *)kmalloc(sizeof(*rose_neigh), GFP_ATOMIC)) == NULL) return -ENOMEM; rose_neigh->callsign = rose_route->neighbour; rose_neigh->digipeat = NULL; rose_neigh->ax25 = NULL; rose_neigh->dev = dev; rose_neigh->count = 0; rose_neigh->use = 0; rose_neigh->dce_mode = 0; rose_neigh->number = rose_neigh_no++; rose_neigh->restarted = 0; skb_queue_head_init(&rose_neigh->queue); rose_neigh->t0timer = 0; rose_neigh->ftimer = 0; init_timer(&rose_neigh->timer); if (rose_route->ndigis != 0) { if ((rose_neigh->digipeat = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) { kfree_s(rose_neigh, sizeof(*rose_neigh)); return -ENOMEM; } rose_neigh->digipeat->ndigi = rose_route->ndigis; rose_neigh->digipeat->lastrepeat = -1; for (i = 0; i < rose_route->ndigis; i++) { rose_neigh->digipeat->calls[i] = rose_route->digipeaters[i]; rose_neigh->digipeat->repeated[i] = 0; } } save_flags(flags); cli(); rose_neigh->next = rose_neigh_list; rose_neigh_list = rose_neigh; restore_flags(flags); } /* * 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; while (rose_tmpn != NULL) { if (rose_tmpn->mask > rose_route->mask) { rose_tmpp = rose_tmpn; rose_tmpn = rose_tmpn->next; } else { break; } } /* create new node */ if ((rose_node = (struct rose_node *)kmalloc(sizeof(*rose_node), GFP_ATOMIC)) == NULL) return -ENOMEM; rose_node->address = rose_route->address; rose_node->mask = rose_route->mask; rose_node->count = 1; rose_node->neighbour[0] = rose_neigh; save_flags(flags); cli(); if (rose_tmpn == NULL) { if (rose_tmpp == NULL) { /* Empty list */ rose_node_list = rose_node; rose_node->next = NULL; } else { rose_tmpp->next = rose_node; rose_node->next = NULL; } } else { if (rose_tmpp == NULL) { /* 1st node */ rose_node->next = rose_node_list; rose_node_list = rose_node; } else { rose_tmpp->next = rose_node; rose_node->next = rose_tmpn; } } restore_flags(flags); rose_neigh->count++; } 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; }