11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ipddp.c: IP to Appletalk-IP Encapsulation driver for Linux 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Appletalk-IP to IP Decapsulation driver for Linux 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Authors: 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - DDP-IP Encap by: Bradford W. Johnson <johns393@maroon.tc.umn.edu> 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - DDP-IP Decap by: Jay Schulist <jschlst@samba.org> 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Derived from: 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - Almost all code already existed in net/appletalk/ddp.c I just 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * moved/reorginized it into a driver file. Original IP-over-DDP code 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * was done by Bradford W. Johnson <johns393@maroon.tc.umn.edu> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - skeleton.c: A network driver outline for linux. 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Written 1993-94 by Donald Becker. 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - dummy.c: A dummy net driver. By Nick Holloway. 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - MacGate: A user space Daemon for Appletalk-IP Decap for 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Linux by Jay Schulist <jschlst@samba.org> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright 1993 United States Government as represented by the 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Director, National Security Agency. 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This software may be used and distributed according to the terms 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the GNU General Public License, incorporated herein by reference. 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ip.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/atalk.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_arp.h> 345a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/route.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "ipddp.h" /* Our stuff */ 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char version[] = KERN_INFO "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n"; 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct ipddp_route *ipddp_route_list; 435615968a70845157adaffc11062c997d045339eeDavid S. Millerstatic DEFINE_SPINLOCK(ipddp_route_lock); 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_IPDDP_ENCAP 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipddp_mode = IPDDP_ENCAP; 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipddp_mode = IPDDP_DECAP; 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Index to functions, as function prototypes. */ 520fc480987e69f22b9212f087545b4d1ca6950807Stephen Hemmingerstatic netdev_tx_t ipddp_xmit(struct sk_buff *skb, 530fc480987e69f22b9212f087545b4d1ca6950807Stephen Hemminger struct net_device *dev); 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipddp_create(struct ipddp_route *new_rt); 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipddp_delete(struct ipddp_route *rt); 565615968a70845157adaffc11062c997d045339eeDavid S. Millerstatic struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt); 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5943a67304a3e882ec297e08159f8698be59a235feStephen Hemmingerstatic const struct net_device_ops ipddp_netdev_ops = { 6043a67304a3e882ec297e08159f8698be59a235feStephen Hemminger .ndo_start_xmit = ipddp_xmit, 6143a67304a3e882ec297e08159f8698be59a235feStephen Hemminger .ndo_do_ioctl = ipddp_ioctl, 6243a67304a3e882ec297e08159f8698be59a235feStephen Hemminger .ndo_change_mtu = eth_change_mtu, 6343a67304a3e882ec297e08159f8698be59a235feStephen Hemminger .ndo_set_mac_address = eth_mac_addr, 6443a67304a3e882ec297e08159f8698be59a235feStephen Hemminger .ndo_validate_addr = eth_validate_addr, 6543a67304a3e882ec297e08159f8698be59a235feStephen Hemminger}; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device * __init ipddp_init(void) 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static unsigned version_printed; 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7343a67304a3e882ec297e08159f8698be59a235feStephen Hemminger dev = alloc_etherdev(0); 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev) 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ERR_PTR(-ENOMEM); 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7793f154b594fe47e4a7e5358b309add449a046cd3Eric Dumazet dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(dev->name, "ipddp%d"); 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (version_printed++ == 0) 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(version); 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 83421f91d21ad6f799dc7b489bb33cc560ccc56f98Uwe Kleine-König /* Initialize the device structure. */ 8443a67304a3e882ec297e08159f8698be59a235feStephen Hemminger dev->netdev_ops = &ipddp_netdev_ops; 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->type = ARPHRD_IPDDP; /* IP over DDP tunnel */ 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->mtu = 585; 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->flags |= IFF_NOARP; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The worst case header we will need is currently a 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ethernet header (14 bytes) and a ddp header (sizeof ddpehdr+1) 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We send over SNAP so that takes another 8 bytes. 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->hard_header_len = 14+8+sizeof(struct ddpehdr)+1; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = register_netdev(dev); 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) { 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(dev); 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ERR_PTR(err); 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Let the user now what mode we are in */ 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(ipddp_mode == IPDDP_ENCAP) 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n", 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name); 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(ipddp_mode == IPDDP_DECAP) 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s: Appletalk-IP Decap. mode by Jay Schulist <jschlst@samba.org>\n", 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name); 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return dev; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Transmit LLAP/ELAP frame using aarp_send_ddp. 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1180fc480987e69f22b9212f087545b4d1ca6950807Stephen Hemmingerstatic netdev_tx_t ipddp_xmit(struct sk_buff *skb, struct net_device *dev) 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 120511c3f92ad5b6d9f8f6464be1b4f85f0422be91aEric Dumazet __be32 paddr = skb_rtable(skb)->rt_gateway; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ddpehdr *ddp; 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipddp_route *rt; 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct atalk_addr *our_addr; 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1255615968a70845157adaffc11062c997d045339eeDavid S. Miller spin_lock(&ipddp_route_lock); 1265615968a70845157adaffc11062c997d045339eeDavid S. Miller 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Find appropriate route to use, based only on IP number. 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(rt = ipddp_route_list; rt != NULL; rt = rt->next) 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(rt->ip == paddr) 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1355615968a70845157adaffc11062c997d045339eeDavid S. Miller if(rt == NULL) { 1365615968a70845157adaffc11062c997d045339eeDavid S. Miller spin_unlock(&ipddp_route_lock); 1376ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy return NETDEV_TX_OK; 1385615968a70845157adaffc11062c997d045339eeDavid S. Miller } 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds our_addr = atalk_find_dev_addr(rt->dev); 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(ipddp_mode == IPDDP_DECAP) 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Pull off the excess room that should not be there. 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is due to a hard-header problem. This is the 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * quick fix for now though, till it breaks. 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_pull(skb, 35-(sizeof(struct ddpehdr)+1)); 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Create the Extended DDP header */ 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ddp = (struct ddpehdr *)skb->data; 1522a50f28c326d20ab4556be1b867ecddf6aefbb88Al Viro ddp->deh_len_hops = htons(skb->len + (1<<10)); 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ddp->deh_sum = 0; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For Localtalk we need aarp_send_ddp to strip the 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * long DDP header and place a shot DDP header on it. 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(rt->dev->type == ARPHRD_LOCALTLK) 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ddp->deh_dnet = 0; /* FIXME more hops?? */ 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ddp->deh_snet = 0; 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ddp->deh_dnet = rt->at.s_net; /* FIXME more hops?? */ 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ddp->deh_snet = our_addr->s_net; 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ddp->deh_dnode = rt->at.s_node; 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ddp->deh_snode = our_addr->s_node; 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ddp->deh_dport = 72; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ddp->deh_sport = 72; 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *((__u8 *)(ddp+1)) = 22; /* ddp type = IP */ 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->protocol = htons(ETH_P_ATALK); /* Protocol has changed */ 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17843a67304a3e882ec297e08159f8698be59a235feStephen Hemminger dev->stats.tx_packets++; 17943a67304a3e882ec297e08159f8698be59a235feStephen Hemminger dev->stats.tx_bytes += skb->len; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 181ffcfb8db540ff879c2a85bf7e404954281443414Arnaldo Carvalho de Melo aarp_send_ddp(rt->dev, skb, &rt->at, NULL); 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1835615968a70845157adaffc11062c997d045339eeDavid S. Miller spin_unlock(&ipddp_route_lock); 1845615968a70845157adaffc11062c997d045339eeDavid S. Miller 1856ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy return NETDEV_TX_OK; 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Create a routing entry. We first verify that the 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * record does not already exist. If it does we return -EEXIST 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipddp_create(struct ipddp_route *new_rt) 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1945cbded585d129d0226cb48ac4202b253c781be26Robert P. J. Day struct ipddp_route *rt = kmalloc(sizeof(*rt), GFP_KERNEL); 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rt == NULL) 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rt->ip = new_rt->ip; 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rt->at = new_rt->at; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rt->next = NULL; 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rt->dev = atrtr_get_dev(&rt->at)) == NULL) { 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(rt); 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENETUNREACH; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2075615968a70845157adaffc11062c997d045339eeDavid S. Miller spin_lock_bh(&ipddp_route_lock); 2085615968a70845157adaffc11062c997d045339eeDavid S. Miller if (__ipddp_find_route(rt)) { 2095615968a70845157adaffc11062c997d045339eeDavid S. Miller spin_unlock_bh(&ipddp_route_lock); 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(rt); 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EEXIST; 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rt->next = ipddp_route_list; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipddp_route_list = rt; 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2175615968a70845157adaffc11062c997d045339eeDavid S. Miller spin_unlock_bh(&ipddp_route_lock); 2185615968a70845157adaffc11062c997d045339eeDavid S. Miller 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Delete a route, we only delete a FULL match. 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If route does not exist we return -ENOENT. 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipddp_delete(struct ipddp_route *rt) 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipddp_route **r = &ipddp_route_list; 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipddp_route *tmp; 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2315615968a70845157adaffc11062c997d045339eeDavid S. Miller spin_lock_bh(&ipddp_route_lock); 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while((tmp = *r) != NULL) 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 2348e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches if(tmp->ip == rt->ip && 2358e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches tmp->at.s_net == rt->at.s_net && 2368e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches tmp->at.s_node == rt->at.s_node) 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *r = tmp->next; 2395615968a70845157adaffc11062c997d045339eeDavid S. Miller spin_unlock_bh(&ipddp_route_lock); 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(tmp); 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r = &tmp->next; 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2465615968a70845157adaffc11062c997d045339eeDavid S. Miller spin_unlock_bh(&ipddp_route_lock); 247807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet return -ENOENT; 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Find a routing entry, we only return a FULL match 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2535615968a70845157adaffc11062c997d045339eeDavid S. Millerstatic struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt) 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipddp_route *f; 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(f = ipddp_route_list; f != NULL; f = f->next) 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 2598e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches if(f->ip == rt->ip && 2608e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches f->at.s_net == rt->at.s_net && 2618e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches f->at.s_node == rt->at.s_node) 262807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet return f; 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 265807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet return NULL; 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipddp_route __user *rt = ifr->ifr_data; 2715615968a70845157adaffc11062c997d045339eeDavid S. Miller struct ipddp_route rcp, rcp2, *rp; 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(!capable(CAP_NET_ADMIN)) 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(copy_from_user(&rcp, rt, sizeof(rcp))) 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(cmd) 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIOCADDIPDDPRT: 282807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet return ipddp_create(&rcp); 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIOCFINDIPDDPRT: 2855615968a70845157adaffc11062c997d045339eeDavid S. Miller spin_lock_bh(&ipddp_route_lock); 2865615968a70845157adaffc11062c997d045339eeDavid S. Miller rp = __ipddp_find_route(&rcp); 2875615968a70845157adaffc11062c997d045339eeDavid S. Miller if (rp) 2885615968a70845157adaffc11062c997d045339eeDavid S. Miller memcpy(&rcp2, rp, sizeof(rcp2)); 2895615968a70845157adaffc11062c997d045339eeDavid S. Miller spin_unlock_bh(&ipddp_route_lock); 2905615968a70845157adaffc11062c997d045339eeDavid S. Miller 2915615968a70845157adaffc11062c997d045339eeDavid S. Miller if (rp) { 2925615968a70845157adaffc11062c997d045339eeDavid S. Miller if (copy_to_user(rt, &rcp2, 2935615968a70845157adaffc11062c997d045339eeDavid S. Miller sizeof(struct ipddp_route))) 2945615968a70845157adaffc11062c997d045339eeDavid S. Miller return -EFAULT; 2955615968a70845157adaffc11062c997d045339eeDavid S. Miller return 0; 2965615968a70845157adaffc11062c997d045339eeDavid S. Miller } else 2975615968a70845157adaffc11062c997d045339eeDavid S. Miller return -ENOENT; 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIOCDELIPDDPRT: 300807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet return ipddp_delete(&rcp); 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device *dev_ipddp; 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(ipddp_mode, int, 0); 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init ipddp_init_module(void) 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_ipddp = ipddp_init(); 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(dev_ipddp)) 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PTR_ERR(dev_ipddp); 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit ipddp_cleanup_module(void) 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipddp_route *p; 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_netdev(dev_ipddp); 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(dev_ipddp); 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (ipddp_route_list) { 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p = ipddp_route_list->next; 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(ipddp_route_list); 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipddp_route_list = p; 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(ipddp_init_module); 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(ipddp_cleanup_module); 336