| File: | drivers/net/appletalk/ipddp.c |
| Warning: | line 292, column 9 Copies out a struct with uncleared padding (>= 4 bytes) |
| 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 <[email protected]> | |||
| 7 | * - DDP-IP Decap by: Jay Schulist <[email protected]> | |||
| 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 <[email protected]> | |||
| 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 <[email protected]> | |||
| 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 <linux1/module.h> | |||
| 27 | #include <linux1/kernel.h> | |||
| 28 | #include <linux1/init.h> | |||
| 29 | #include <linux1/netdevice.h> | |||
| 30 | #include <linux1/etherdevice.h> | |||
| 31 | #include <linux1/ip.h> | |||
| 32 | #include <linux1/atalk.h> | |||
| 33 | #include <linux1/if_arp.h> | |||
| 34 | #include <linux1/slab.h> | |||
| 35 | #include <net/route.h> | |||
| 36 | #include <asm/uaccess.h> | |||
| 37 | ||||
| 38 | #include "ipddp.h" /* Our stuff */ | |||
| 39 | ||||
| 40 | static const char version[] = KERN_INFO"\001" "6" "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <[email protected]>\n"; | |||
| 41 | ||||
| 42 | static struct ipddp_route *ipddp_route_list; | |||
| 43 | static DEFINE_SPINLOCK(ipddp_route_lock)spinlock_t ipddp_route_lock = (spinlock_t ) { { .rlock = { .raw_lock = { { (0) } }, .magic = 0xdead4ead, .owner_cpu = -1, .owner = ((void *)-1L), .dep_map = { .name = "ipddp_route_lock" } } } }; | |||
| 44 | ||||
| 45 | #ifdef CONFIG_IPDDP_ENCAP1 | |||
| 46 | static int ipddp_mode = IPDDP_ENCAP1; | |||
| 47 | #else | |||
| 48 | static int ipddp_mode = IPDDP_DECAP2; | |||
| 49 | #endif | |||
| 50 | ||||
| 51 | /* Index to functions, as function prototypes. */ | |||
| 52 | static netdev_tx_t ipddp_xmit(struct sk_buff *skb, | |||
| 53 | struct net_device *dev); | |||
| 54 | static int ipddp_create(struct ipddp_route *new_rt); | |||
| 55 | static int ipddp_delete(struct ipddp_route *rt); | |||
| 56 | static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt); | |||
| 57 | static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); | |||
| 58 | ||||
| 59 | static const struct net_device_ops ipddp_netdev_ops = { | |||
| 60 | .ndo_start_xmit = ipddp_xmit, | |||
| 61 | .ndo_do_ioctl = ipddp_ioctl, | |||
| 62 | .ndo_change_mtu = eth_change_mtu, | |||
| 63 | .ndo_set_mac_address = eth_mac_addr, | |||
| 64 | .ndo_validate_addr = eth_validate_addr, | |||
| 65 | }; | |||
| 66 | ||||
| 67 | static struct net_device * __init__attribute__ ((__section__(".init.text"))) __attribute__((no_instrument_function )) ipddp_init(void) | |||
| 68 | { | |||
| 69 | static unsigned version_printed; | |||
| 70 | struct net_device *dev; | |||
| 71 | int err; | |||
| 72 | ||||
| 73 | dev = alloc_etherdev(0)alloc_etherdev_mqs(0, 1, 1); | |||
| 74 | if (!dev) | |||
| 75 | return ERR_PTR(-ENOMEM12); | |||
| 76 | ||||
| 77 | netif_keep_dst(dev); | |||
| 78 | strcpy(dev->name, "ipddp%d"); | |||
| 79 | ||||
| 80 | if (version_printed++ == 0) | |||
| 81 | printk(version); | |||
| 82 | ||||
| 83 | /* Initialize the device structure. */ | |||
| 84 | dev->netdev_ops = &ipddp_netdev_ops; | |||
| 85 | ||||
| 86 | dev->type = ARPHRD_IPDDP777; /* IP over DDP tunnel */ | |||
| 87 | dev->mtu = 585; | |||
| 88 | dev->flags |= IFF_NOARPIFF_NOARP; | |||
| 89 | ||||
| 90 | /* | |||
| 91 | * The worst case header we will need is currently a | |||
| 92 | * ethernet header (14 bytes) and a ddp header (sizeof ddpehdr+1) | |||
| 93 | * We send over SNAP so that takes another 8 bytes. | |||
| 94 | */ | |||
| 95 | dev->hard_header_len = 14+8+sizeof(struct ddpehdr)+1; | |||
| 96 | ||||
| 97 | err = register_netdev(dev); | |||
| 98 | if (err) { | |||
| 99 | free_netdev(dev); | |||
| 100 | return ERR_PTR(err); | |||
| 101 | } | |||
| 102 | ||||
| 103 | /* Let the user now what mode we are in */ | |||
| 104 | if(ipddp_mode == IPDDP_ENCAP1) | |||
| 105 | printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson <[email protected]>\n", | |||
| 106 | dev->name); | |||
| 107 | if(ipddp_mode == IPDDP_DECAP2) | |||
| 108 | printk("%s: Appletalk-IP Decap. mode by Jay Schulist <[email protected]>\n", | |||
| 109 | dev->name); | |||
| 110 | ||||
| 111 | return dev; | |||
| 112 | } | |||
| 113 | ||||
| 114 | ||||
| 115 | /* | |||
| 116 | * Transmit LLAP/ELAP frame using aarp_send_ddp. | |||
| 117 | */ | |||
| 118 | static netdev_tx_t ipddp_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 119 | { | |||
| 120 | __be32 paddr = skb_rtable(skb)->rt_gateway; | |||
| 121 | struct ddpehdr *ddp; | |||
| 122 | struct ipddp_route *rt; | |||
| 123 | struct atalk_addr *our_addr; | |||
| 124 | ||||
| 125 | spin_lock(&ipddp_route_lock); | |||
| 126 | ||||
| 127 | /* | |||
| 128 | * Find appropriate route to use, based only on IP number. | |||
| 129 | */ | |||
| 130 | for(rt = ipddp_route_list; rt != NULL((void *)0); rt = rt->next) | |||
| 131 | { | |||
| 132 | if(rt->ip == paddr) | |||
| 133 | break; | |||
| 134 | } | |||
| 135 | if(rt == NULL((void *)0)) { | |||
| 136 | spin_unlock(&ipddp_route_lock); | |||
| 137 | return NETDEV_TX_OK; | |||
| 138 | } | |||
| 139 | ||||
| 140 | our_addr = atalk_find_dev_addr(rt->dev); | |||
| 141 | ||||
| 142 | if(ipddp_mode == IPDDP_DECAP2) | |||
| 143 | /* | |||
| 144 | * Pull off the excess room that should not be there. | |||
| 145 | * This is due to a hard-header problem. This is the | |||
| 146 | * quick fix for now though, till it breaks. | |||
| 147 | */ | |||
| 148 | skb_pull(skb, 35-(sizeof(struct ddpehdr)+1)); | |||
| 149 | ||||
| 150 | /* Create the Extended DDP header */ | |||
| 151 | ddp = (struct ddpehdr *)skb->data; | |||
| 152 | ddp->deh_len_hops = htons(skb->len + (1<<10))(( __be16)(__builtin_constant_p((__u16)((skb->len + (1<< 10)))) ? ((__u16)( (((__u16)((skb->len + (1<<10))) & (__u16)0x00ffU) << 8) | (((__u16)((skb->len + (1<< 10))) & (__u16)0xff00U) >> 8))) : __fswab16((skb-> len + (1<<10))))); | |||
| 153 | ddp->deh_sum = 0; | |||
| 154 | ||||
| 155 | /* | |||
| 156 | * For Localtalk we need aarp_send_ddp to strip the | |||
| 157 | * long DDP header and place a shot DDP header on it. | |||
| 158 | */ | |||
| 159 | if(rt->dev->type == ARPHRD_LOCALTLK773) | |||
| 160 | { | |||
| 161 | ddp->deh_dnet = 0; /* FIXME more hops?? */ | |||
| 162 | ddp->deh_snet = 0; | |||
| 163 | } | |||
| 164 | else | |||
| 165 | { | |||
| 166 | ddp->deh_dnet = rt->at.s_net; /* FIXME more hops?? */ | |||
| 167 | ddp->deh_snet = our_addr->s_net; | |||
| 168 | } | |||
| 169 | ddp->deh_dnode = rt->at.s_node; | |||
| 170 | ddp->deh_snode = our_addr->s_node; | |||
| 171 | ddp->deh_dport = 72; | |||
| 172 | ddp->deh_sport = 72; | |||
| 173 | ||||
| 174 | *((__u8 *)(ddp+1)) = 22; /* ddp type = IP */ | |||
| 175 | ||||
| 176 | skb->protocol = htons(ETH_P_ATALK)(( __be16)(__builtin_constant_p((__u16)((0x809B))) ? ((__u16) ( (((__u16)((0x809B)) & (__u16)0x00ffU) << 8) | ((( __u16)((0x809B)) & (__u16)0xff00U) >> 8))) : __fswab16 ((0x809B)))); /* Protocol has changed */ | |||
| 177 | ||||
| 178 | dev->stats.tx_packets++; | |||
| 179 | dev->stats.tx_bytes += skb->len; | |||
| 180 | ||||
| 181 | aarp_send_ddp(rt->dev, skb, &rt->at, NULL((void *)0)); | |||
| 182 | ||||
| 183 | spin_unlock(&ipddp_route_lock); | |||
| 184 | ||||
| 185 | return NETDEV_TX_OK; | |||
| 186 | } | |||
| 187 | ||||
| 188 | /* | |||
| 189 | * Create a routing entry. We first verify that the | |||
| 190 | * record does not already exist. If it does we return -EEXIST | |||
| 191 | */ | |||
| 192 | static int ipddp_create(struct ipddp_route *new_rt) | |||
| 193 | { | |||
| 194 | struct ipddp_route *rt = kmalloc(sizeof(*rt), GFP_KERNEL((( gfp_t)(0x400000u|0x2000000u)) | (( gfp_t)0x40u) | (( gfp_t )0x80u))); | |||
| 195 | ||||
| 196 | if (rt == NULL((void *)0)) | |||
| 197 | return -ENOMEM12; | |||
| 198 | ||||
| 199 | rt->ip = new_rt->ip; | |||
| 200 | rt->at = new_rt->at; | |||
| 201 | rt->next = NULL((void *)0); | |||
| 202 | if ((rt->dev = atrtr_get_dev(&rt->at)) == NULL((void *)0)) { | |||
| 203 | kfree(rt); | |||
| 204 | return -ENETUNREACH101; | |||
| 205 | } | |||
| 206 | ||||
| 207 | spin_lock_bh(&ipddp_route_lock); | |||
| 208 | if (__ipddp_find_route(rt)) { | |||
| 209 | spin_unlock_bh(&ipddp_route_lock); | |||
| 210 | kfree(rt); | |||
| 211 | return -EEXIST17; | |||
| 212 | } | |||
| 213 | ||||
| 214 | rt->next = ipddp_route_list; | |||
| 215 | ipddp_route_list = rt; | |||
| 216 | ||||
| 217 | spin_unlock_bh(&ipddp_route_lock); | |||
| 218 | ||||
| 219 | return 0; | |||
| 220 | } | |||
| 221 | ||||
| 222 | /* | |||
| 223 | * Delete a route, we only delete a FULL match. | |||
| 224 | * If route does not exist we return -ENOENT. | |||
| 225 | */ | |||
| 226 | static int ipddp_delete(struct ipddp_route *rt) | |||
| 227 | { | |||
| 228 | struct ipddp_route **r = &ipddp_route_list; | |||
| 229 | struct ipddp_route *tmp; | |||
| 230 | ||||
| 231 | spin_lock_bh(&ipddp_route_lock); | |||
| 232 | while((tmp = *r) != NULL((void *)0)) | |||
| 233 | { | |||
| 234 | if(tmp->ip == rt->ip && | |||
| 235 | tmp->at.s_net == rt->at.s_net && | |||
| 236 | tmp->at.s_node == rt->at.s_node) | |||
| 237 | { | |||
| 238 | *r = tmp->next; | |||
| 239 | spin_unlock_bh(&ipddp_route_lock); | |||
| 240 | kfree(tmp); | |||
| 241 | return 0; | |||
| 242 | } | |||
| 243 | r = &tmp->next; | |||
| 244 | } | |||
| 245 | ||||
| 246 | spin_unlock_bh(&ipddp_route_lock); | |||
| 247 | return -ENOENT2; | |||
| 248 | } | |||
| 249 | ||||
| 250 | /* | |||
| 251 | * Find a routing entry, we only return a FULL match | |||
| 252 | */ | |||
| 253 | static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt) | |||
| 254 | { | |||
| 255 | struct ipddp_route *f; | |||
| 256 | ||||
| 257 | for(f = ipddp_route_list; f != NULL((void *)0); f = f->next) | |||
| 258 | { | |||
| 259 | if(f->ip == rt->ip && | |||
| 260 | f->at.s_net == rt->at.s_net && | |||
| 261 | f->at.s_node == rt->at.s_node) | |||
| 262 | return f; | |||
| 263 | } | |||
| 264 | ||||
| 265 | return NULL((void *)0); | |||
| 266 | } | |||
| 267 | ||||
| 268 | static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
| 269 | { | |||
| 270 | struct ipddp_route __user *rt = ifr->ifr_dataifr_ifru.ifru_data; | |||
| 271 | struct ipddp_route rcp, rcp2, *rp; | |||
| 272 | ||||
| 273 | if(!capable(CAP_NET_ADMIN12)) | |||
| ||||
| 274 | return -EPERM1; | |||
| 275 | ||||
| 276 | if(copy_from_user(&rcp, rt, sizeof(rcp))) | |||
| 277 | return -EFAULT14; | |||
| 278 | ||||
| 279 | switch(cmd) | |||
| 280 | { | |||
| 281 | case SIOCADDIPDDPRT(0x89F0): | |||
| 282 | return ipddp_create(&rcp); | |||
| 283 | ||||
| 284 | case SIOCFINDIPDDPRT(0x89F0 +2): | |||
| 285 | spin_lock_bh(&ipddp_route_lock); | |||
| 286 | rp = __ipddp_find_route(&rcp); | |||
| 287 | if (rp) | |||
| 288 | memcpy(&rcp2, rp, sizeof(rcp2))({ size_t __len = (sizeof(rcp2)); void *__ret; if (__builtin_constant_p (sizeof(rcp2)) && __len >= 64) __ret = __memcpy((& rcp2), (rp), __len); else __ret = __builtin_memcpy((&rcp2 ), (rp), __len); __ret; }); | |||
| 289 | spin_unlock_bh(&ipddp_route_lock); | |||
| 290 | ||||
| 291 | if (rp) { | |||
| 292 | if (copy_to_user(rt, &rcp2, | |||
| ||||
| 293 | sizeof(struct ipddp_route))) | |||
| 294 | return -EFAULT14; | |||
| 295 | return 0; | |||
| 296 | } else | |||
| 297 | return -ENOENT2; | |||
| 298 | ||||
| 299 | case SIOCDELIPDDPRT(0x89F0 +1): | |||
| 300 | return ipddp_delete(&rcp); | |||
| 301 | ||||
| 302 | default: | |||
| 303 | return -EINVAL22; | |||
| 304 | } | |||
| 305 | } | |||
| 306 | ||||
| 307 | static struct net_device *dev_ipddp; | |||
| 308 | ||||
| 309 | MODULE_LICENSE("GPL")struct __UNIQUE_ID_license54 {}; | |||
| 310 | module_param(ipddp_mode, int, 0)static inline __attribute__((no_instrument_function)) int __attribute__ ((unused)) *__check_ipddp_mode(void) { return(&(ipddp_mode )); }; static const char __param_str_ipddp_mode[] = "ipddp" "." "ipddp_mode"; static struct kernel_param const __param_ipddp_mode __attribute__((__used__)) __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) = { __param_str_ipddp_mode , ((struct module *)0), ¶m_ops_int, ((sizeof(struct { int:-!!((0) < 0); })) + (sizeof(struct { int:-!!((0) > 0777); })) + (sizeof(struct { int:-!!((((0) >> 6) & 4) < (((0) >> 3) & 4)); })) + (sizeof(struct { int :-!!((((0) >> 3) & 4) < ((0) & 4)); })) + (sizeof (struct { int:-!!((((0) >> 6) & 2) < (((0) >> 3) & 2)); })) + (sizeof(struct { int:-!!((0) & 2); } )) + (0)), -1, 0, { &ipddp_mode } }; struct __UNIQUE_ID_ipddp_modetype55 {}; | |||
| 311 | ||||
| 312 | static int __init__attribute__ ((__section__(".init.text"))) __attribute__((no_instrument_function )) ipddp_init_module(void) | |||
| 313 | { | |||
| 314 | dev_ipddp = ipddp_init(); | |||
| 315 | if (IS_ERR(dev_ipddp)) | |||
| 316 | return PTR_ERR(dev_ipddp); | |||
| 317 | return 0; | |||
| 318 | } | |||
| 319 | ||||
| 320 | static void __exit__attribute__ ((__section__(".exit.text"))) __attribute__((__used__ )) __attribute__((no_instrument_function)) ipddp_cleanup_module(void) | |||
| 321 | { | |||
| 322 | struct ipddp_route *p; | |||
| 323 | ||||
| 324 | unregister_netdev(dev_ipddp); | |||
| 325 | free_netdev(dev_ipddp); | |||
| 326 | ||||
| 327 | while (ipddp_route_list) { | |||
| 328 | p = ipddp_route_list->next; | |||
| 329 | kfree(ipddp_route_list); | |||
| 330 | ipddp_route_list = p; | |||
| 331 | } | |||
| 332 | } | |||
| 333 | ||||
| 334 | module_init(ipddp_init_module)static initcall_t __initcall_ipddp_init_module6 __attribute__ ((__used__)) __attribute__((__section__(".initcall" "6" ".init" ))) = ipddp_init_module;;; | |||
| 335 | module_exit(ipddp_cleanup_module)static exitcall_t __exitcall_ipddp_cleanup_module __attribute__ ((__used__)) __attribute__ ((__section__(".exitcall.exit"))) = ipddp_cleanup_module;; |