cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ipddp.c (9180B)


      1/*
      2 *	ipddp.c: IP to Appletalk-IP Encapsulation driver for Linux
      3 *		 Appletalk-IP to IP Decapsulation driver for Linux
      4 *
      5 *	Authors:
      6 *      - DDP-IP Encap by: Bradford W. Johnson <johns393@maroon.tc.umn.edu>
      7 *	- DDP-IP Decap by: Jay Schulist <jschlst@samba.org>
      8 *
      9 *	Derived from:
     10 *	- Almost all code already existed in net/appletalk/ddp.c I just
     11 *	  moved/reorginized it into a driver file. Original IP-over-DDP code
     12 *	  was done by Bradford W. Johnson <johns393@maroon.tc.umn.edu>
     13 *      - skeleton.c: A network driver outline for linux.
     14 *        Written 1993-94 by Donald Becker.
     15 *	- dummy.c: A dummy net driver. By Nick Holloway.
     16 *	- MacGate: A user space Daemon for Appletalk-IP Decap for
     17 *	  Linux by Jay Schulist <jschlst@samba.org>
     18 *
     19 *      Copyright 1993 United States Government as represented by the
     20 *      Director, National Security Agency.
     21 *
     22 *      This software may be used and distributed according to the terms
     23 *      of the GNU General Public License, incorporated herein by reference.
     24 */
     25
     26#include <linux/compat.h>
     27#include <linux/module.h>
     28#include <linux/kernel.h>
     29#include <linux/init.h>
     30#include <linux/netdevice.h>
     31#include <linux/etherdevice.h>
     32#include <linux/ip.h>
     33#include <linux/atalk.h>
     34#include <linux/if_arp.h>
     35#include <linux/slab.h>
     36#include <net/route.h>
     37#include <linux/uaccess.h>
     38
     39#include "ipddp.h"		/* Our stuff */
     40
     41static const char version[] = KERN_INFO "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n";
     42
     43static struct ipddp_route *ipddp_route_list;
     44static DEFINE_SPINLOCK(ipddp_route_lock);
     45
     46#ifdef CONFIG_IPDDP_ENCAP
     47static int ipddp_mode = IPDDP_ENCAP;
     48#else
     49static int ipddp_mode = IPDDP_DECAP;
     50#endif
     51
     52/* Index to functions, as function prototypes. */
     53static netdev_tx_t ipddp_xmit(struct sk_buff *skb,
     54				    struct net_device *dev);
     55static int ipddp_create(struct ipddp_route *new_rt);
     56static int ipddp_delete(struct ipddp_route *rt);
     57static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt);
     58static int ipddp_siocdevprivate(struct net_device *dev, struct ifreq *ifr,
     59				void __user *data, int cmd);
     60
     61static const struct net_device_ops ipddp_netdev_ops = {
     62	.ndo_start_xmit		= ipddp_xmit,
     63	.ndo_siocdevprivate	= ipddp_siocdevprivate,
     64	.ndo_set_mac_address 	= eth_mac_addr,
     65	.ndo_validate_addr	= eth_validate_addr,
     66};
     67
     68static struct net_device * __init ipddp_init(void)
     69{
     70	static unsigned version_printed;
     71	struct net_device *dev;
     72	int err;
     73
     74	dev = alloc_etherdev(0);
     75	if (!dev)
     76		return ERR_PTR(-ENOMEM);
     77
     78	netif_keep_dst(dev);
     79	strcpy(dev->name, "ipddp%d");
     80
     81	if (version_printed++ == 0)
     82                printk(version);
     83
     84	/* Initialize the device structure. */
     85	dev->netdev_ops = &ipddp_netdev_ops;
     86
     87        dev->type = ARPHRD_IPDDP;       	/* IP over DDP tunnel */
     88        dev->mtu = 585;
     89        dev->flags |= IFF_NOARP;
     90
     91        /*
     92         *      The worst case header we will need is currently a
     93         *      ethernet header (14 bytes) and a ddp header (sizeof ddpehdr+1)
     94         *      We send over SNAP so that takes another 8 bytes.
     95         */
     96        dev->hard_header_len = 14+8+sizeof(struct ddpehdr)+1;
     97
     98	err = register_netdev(dev);
     99	if (err) {
    100		free_netdev(dev);
    101		return ERR_PTR(err);
    102	}
    103
    104	/* Let the user now what mode we are in */
    105	if(ipddp_mode == IPDDP_ENCAP)
    106		printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n", 
    107			dev->name);
    108	if(ipddp_mode == IPDDP_DECAP)
    109		printk("%s: Appletalk-IP Decap. mode by Jay Schulist <jschlst@samba.org>\n", 
    110			dev->name);
    111
    112        return dev;
    113}
    114
    115
    116/*
    117 * Transmit LLAP/ELAP frame using aarp_send_ddp.
    118 */
    119static netdev_tx_t ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
    120{
    121        struct rtable *rtable = skb_rtable(skb);
    122        __be32 paddr = 0;
    123        struct ddpehdr *ddp;
    124        struct ipddp_route *rt;
    125        struct atalk_addr *our_addr;
    126
    127	if (rtable->rt_gw_family == AF_INET)
    128		paddr = rtable->rt_gw4;
    129
    130	spin_lock(&ipddp_route_lock);
    131
    132	/*
    133         * Find appropriate route to use, based only on IP number.
    134         */
    135        for(rt = ipddp_route_list; rt != NULL; rt = rt->next)
    136        {
    137                if(rt->ip == paddr)
    138                        break;
    139        }
    140        if(rt == NULL) {
    141		spin_unlock(&ipddp_route_lock);
    142                return NETDEV_TX_OK;
    143	}
    144
    145        our_addr = atalk_find_dev_addr(rt->dev);
    146
    147	if(ipddp_mode == IPDDP_DECAP)
    148		/* 
    149		 * Pull off the excess room that should not be there.
    150		 * This is due to a hard-header problem. This is the
    151		 * quick fix for now though, till it breaks.
    152		 */
    153		skb_pull(skb, 35-(sizeof(struct ddpehdr)+1));
    154
    155	/* Create the Extended DDP header */
    156	ddp = (struct ddpehdr *)skb->data;
    157        ddp->deh_len_hops = htons(skb->len + (1<<10));
    158        ddp->deh_sum = 0;
    159
    160	/*
    161         * For Localtalk we need aarp_send_ddp to strip the
    162         * long DDP header and place a shot DDP header on it.
    163         */
    164        if(rt->dev->type == ARPHRD_LOCALTLK)
    165        {
    166                ddp->deh_dnet  = 0;   /* FIXME more hops?? */
    167                ddp->deh_snet  = 0;
    168        }
    169        else
    170        {
    171                ddp->deh_dnet  = rt->at.s_net;   /* FIXME more hops?? */
    172                ddp->deh_snet  = our_addr->s_net;
    173        }
    174        ddp->deh_dnode = rt->at.s_node;
    175        ddp->deh_snode = our_addr->s_node;
    176        ddp->deh_dport = 72;
    177        ddp->deh_sport = 72;
    178
    179        *((__u8 *)(ddp+1)) = 22;        	/* ddp type = IP */
    180
    181        skb->protocol = htons(ETH_P_ATALK);     /* Protocol has changed */
    182
    183	dev->stats.tx_packets++;
    184	dev->stats.tx_bytes += skb->len;
    185
    186	aarp_send_ddp(rt->dev, skb, &rt->at, NULL);
    187
    188	spin_unlock(&ipddp_route_lock);
    189
    190        return NETDEV_TX_OK;
    191}
    192
    193/*
    194 * Create a routing entry. We first verify that the
    195 * record does not already exist. If it does we return -EEXIST
    196 */
    197static int ipddp_create(struct ipddp_route *new_rt)
    198{
    199        struct ipddp_route *rt = kzalloc(sizeof(*rt), GFP_KERNEL);
    200
    201        if (rt == NULL)
    202                return -ENOMEM;
    203
    204        rt->ip = new_rt->ip;
    205        rt->at = new_rt->at;
    206        rt->next = NULL;
    207        if ((rt->dev = atrtr_get_dev(&rt->at)) == NULL) {
    208		kfree(rt);
    209                return -ENETUNREACH;
    210        }
    211
    212	spin_lock_bh(&ipddp_route_lock);
    213	if (__ipddp_find_route(rt)) {
    214		spin_unlock_bh(&ipddp_route_lock);
    215		kfree(rt);
    216		return -EEXIST;
    217	}
    218
    219        rt->next = ipddp_route_list;
    220        ipddp_route_list = rt;
    221
    222	spin_unlock_bh(&ipddp_route_lock);
    223
    224        return 0;
    225}
    226
    227/*
    228 * Delete a route, we only delete a FULL match.
    229 * If route does not exist we return -ENOENT.
    230 */
    231static int ipddp_delete(struct ipddp_route *rt)
    232{
    233        struct ipddp_route **r = &ipddp_route_list;
    234        struct ipddp_route *tmp;
    235
    236	spin_lock_bh(&ipddp_route_lock);
    237        while((tmp = *r) != NULL)
    238        {
    239                if(tmp->ip == rt->ip &&
    240		   tmp->at.s_net == rt->at.s_net &&
    241		   tmp->at.s_node == rt->at.s_node)
    242                {
    243                        *r = tmp->next;
    244			spin_unlock_bh(&ipddp_route_lock);
    245                        kfree(tmp);
    246                        return 0;
    247                }
    248                r = &tmp->next;
    249        }
    250
    251	spin_unlock_bh(&ipddp_route_lock);
    252        return -ENOENT;
    253}
    254
    255/*
    256 * Find a routing entry, we only return a FULL match
    257 */
    258static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt)
    259{
    260        struct ipddp_route *f;
    261
    262        for(f = ipddp_route_list; f != NULL; f = f->next)
    263        {
    264                if(f->ip == rt->ip &&
    265		   f->at.s_net == rt->at.s_net &&
    266		   f->at.s_node == rt->at.s_node)
    267                        return f;
    268        }
    269
    270        return NULL;
    271}
    272
    273static int ipddp_siocdevprivate(struct net_device *dev, struct ifreq *ifr,
    274				void __user *data, int cmd)
    275{
    276        struct ipddp_route rcp, rcp2, *rp;
    277
    278	if (in_compat_syscall())
    279		return -EOPNOTSUPP;
    280
    281        if(!capable(CAP_NET_ADMIN))
    282                return -EPERM;
    283
    284	if (copy_from_user(&rcp, data, sizeof(rcp)))
    285		return -EFAULT;
    286
    287        switch(cmd)
    288        {
    289		case SIOCADDIPDDPRT:
    290                        return ipddp_create(&rcp);
    291
    292                case SIOCFINDIPDDPRT:
    293			spin_lock_bh(&ipddp_route_lock);
    294			rp = __ipddp_find_route(&rcp);
    295			if (rp) {
    296				memset(&rcp2, 0, sizeof(rcp2));
    297				rcp2.ip    = rp->ip;
    298				rcp2.at    = rp->at;
    299				rcp2.flags = rp->flags;
    300			}
    301			spin_unlock_bh(&ipddp_route_lock);
    302
    303			if (rp) {
    304				if (copy_to_user(data, &rcp2,
    305						 sizeof(struct ipddp_route)))
    306					return -EFAULT;
    307				return 0;
    308			} else
    309				return -ENOENT;
    310
    311                case SIOCDELIPDDPRT:
    312                        return ipddp_delete(&rcp);
    313
    314                default:
    315                        return -EINVAL;
    316        }
    317}
    318
    319static struct net_device *dev_ipddp;
    320
    321MODULE_LICENSE("GPL");
    322module_param(ipddp_mode, int, 0);
    323
    324static int __init ipddp_init_module(void)
    325{
    326	dev_ipddp = ipddp_init();
    327	return PTR_ERR_OR_ZERO(dev_ipddp);
    328}
    329
    330static void __exit ipddp_cleanup_module(void)
    331{
    332        struct ipddp_route *p;
    333
    334	unregister_netdev(dev_ipddp);
    335        free_netdev(dev_ipddp);
    336
    337        while (ipddp_route_list) {
    338                p = ipddp_route_list->next;
    339                kfree(ipddp_route_list);
    340                ipddp_route_list = p;
    341        }
    342}
    343
    344module_init(ipddp_init_module);
    345module_exit(ipddp_cleanup_module);