static int ipddp_create(struct ipddp_route *new_rt) { struct ipddp_route *rt = kmalloc(sizeof(*rt), GFP_KERNEL); if (rt == NULL) return -ENOMEM; rt->ip = new_rt->ip; rt->at = new_rt->at; rt->next = NULL; if ((rt->dev = atrtr_get_dev(&rt->at)) == NULL) { kfree(rt); return -ENETUNREACH; } spin_lock_bh(&ipddp_route_lock); if (__ipddp_find_route(rt)) { spin_unlock_bh(&ipddp_route_lock); kfree(rt); return -EEXIST; } rt->next = ipddp_route_list; ipddp_route_list = rt; spin_unlock_bh(&ipddp_route_lock); return 0; }
static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct ipddp_route __user *rt = ifr->ifr_data; struct ipddp_route rcp, rcp2, *rp; if(!capable(CAP_NET_ADMIN)) return -EPERM; if(copy_from_user(&rcp, rt, sizeof(rcp))) return -EFAULT; switch(cmd) { case SIOCADDIPDDPRT: return ipddp_create(&rcp); case SIOCFINDIPDDPRT: spin_lock_bh(&ipddp_route_lock); rp = __ipddp_find_route(&rcp); if (rp) { memset(&rcp2, 0, sizeof(rcp2)); rcp2.ip = rp->ip; rcp2.at = rp->at; rcp2.flags = rp->flags; } spin_unlock_bh(&ipddp_route_lock); if (rp) { if (copy_to_user(rt, &rcp2, sizeof(struct ipddp_route))) return -EFAULT; return 0; } else return -ENOENT; case SIOCDELIPDDPRT: return ipddp_delete(&rcp); default: return -EINVAL; } }