Commit b015a5c0 authored by David S. Miller's avatar David S. Miller

Merge nuts.davemloft.net:/disk1/BK/net-exp-2.6

into nuts.davemloft.net:/disk1/BK/net-2.6
parents 101c46b5 b9b78dbe
...@@ -182,7 +182,7 @@ config CRYPTO_TEA ...@@ -182,7 +182,7 @@ config CRYPTO_TEA
many rounds for security. It is very fast and uses many rounds for security. It is very fast and uses
little memory. little memory.
Xtendend Tiny Encryption Algorithm is a modifcation to Xtendend Tiny Encryption Algorithm is a modification to
the TEA algorithm to address a potential key weakness the TEA algorithm to address a potential key weakness
in the TEA algorithm. in the TEA algorithm.
......
...@@ -160,7 +160,7 @@ gen_tabs (void) ...@@ -160,7 +160,7 @@ gen_tabs (void)
u8 p, q; u8 p, q;
/* log and power tables for GF(2**8) finite field with /* log and power tables for GF(2**8) finite field with
0x011b as modular polynomial - the simplest prmitive 0x011b as modular polynomial - the simplest primitive
root is 0x03, used here to generate the tables */ root is 0x03, used here to generate the tables */
for (i = 0, p = 1; i < 256; ++i) { for (i = 0, p = 1; i < 256; ++i) {
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* ARC4 Cipher Algorithm * ARC4 Cipher Algorithm
* *
* Jon Oberheide <jon@focalhost.com> * Jon Oberheide <jon@oberheide.org>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -100,4 +100,4 @@ module_exit(arc4_exit); ...@@ -100,4 +100,4 @@ module_exit(arc4_exit);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("ARC4 Cipher Algorithm"); MODULE_DESCRIPTION("ARC4 Cipher Algorithm");
MODULE_AUTHOR("Jon Oberheide <jon@focalhost.com>"); MODULE_AUTHOR("Jon Oberheide <jon@oberheide.org>");
...@@ -3,9 +3,9 @@ ...@@ -3,9 +3,9 @@
* *
* Blowfish Cipher Algorithm, by Bruce Schneier. * Blowfish Cipher Algorithm, by Bruce Schneier.
* http://www.counterpane.com/blowfish.html * http://www.counterpane.com/blowfish.html
* *
* Adapated from Kerneli implementation. * Adapted from Kerneli implementation.
* *
* Copyright (c) Herbert Valerio Riedel <hvr@hvrlab.org> * Copyright (c) Herbert Valerio Riedel <hvr@hvrlab.org>
* Copyright (c) Kyle McMartin <kyle@debian.org> * Copyright (c) Kyle McMartin <kyle@debian.org>
* Copyright (c) 2002 James Morris <jmorris@intercode.com.au> * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
......
...@@ -70,7 +70,7 @@ static void scatterwalk_pagedone(struct scatter_walk *walk, int out, ...@@ -70,7 +70,7 @@ static void scatterwalk_pagedone(struct scatter_walk *walk, int out,
{ {
/* walk->data may be pointing the first byte of the next page; /* walk->data may be pointing the first byte of the next page;
however, we know we transfered at least one byte. So, however, we know we transfered at least one byte. So,
walk->data - 1 will be a virutual address in the mapped page. */ walk->data - 1 will be a virtual address in the mapped page. */
if (out) if (out)
flush_dcache_page(walk->page); flush_dcache_page(walk->page);
......
...@@ -1186,7 +1186,7 @@ struct cipher_testvec tf_cbc_dec_tv_template[] = { ...@@ -1186,7 +1186,7 @@ struct cipher_testvec tf_cbc_dec_tv_template[] = {
/* /*
* Serpent test vectors. These are backwards because Serpent writes * Serpent test vectors. These are backwards because Serpent writes
* octect sequences in right-to-left mode. * octet sequences in right-to-left mode.
*/ */
#define SERPENT_ENC_TEST_VECTORS 4 #define SERPENT_ENC_TEST_VECTORS 4
#define SERPENT_DEC_TEST_VECTORS 4 #define SERPENT_DEC_TEST_VECTORS 4
......
/* /*
* Twofish for CryptoAPI * Twofish for CryptoAPI
* *
* Originaly Twofish for GPG * Originally Twofish for GPG
* By Matthew Skala <mskala@ansuz.sooke.bc.ca>, July 26, 1998 * By Matthew Skala <mskala@ansuz.sooke.bc.ca>, July 26, 1998
* 256-bit key length added March 20, 1999 * 256-bit key length added March 20, 1999
* Some modifications to reduce the text size by Werner Koch, April, 1998 * Some modifications to reduce the text size by Werner Koch, April, 1998
...@@ -514,7 +514,7 @@ static const u8 calc_sb_tbl[512] = { ...@@ -514,7 +514,7 @@ static const u8 calc_sb_tbl[512] = {
* preprocessed through q0 and q1 respectively; for longer keys they are the * preprocessed through q0 and q1 respectively; for longer keys they are the
* output of previous stages. j is the index of the first key byte to use. * output of previous stages. j is the index of the first key byte to use.
* CALC_K computes a pair of subkeys for 128-bit Twofish, by calling CALC_K_2 * CALC_K computes a pair of subkeys for 128-bit Twofish, by calling CALC_K_2
* twice, doing the Psuedo-Hadamard Transform, and doing the necessary * twice, doing the Pseudo-Hadamard Transform, and doing the necessary
* rotations. Its parameters are: a, the array to write the results into, * rotations. Its parameters are: a, the array to write the results into,
* j, the index of the first output entry, k and l, the preprocessed indices * j, the index of the first output entry, k and l, the preprocessed indices
* for index 2i, and m and n, the preprocessed indices for index 2i+1. * for index 2i, and m and n, the preprocessed indices for index 2i+1.
......
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#include <linux/random.h> #include <linux/random.h>
#include <linux/pkt_sched.h> #include <linux/pkt_sched.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/rcupdate.h>
#include <net/syncppp.h> #include <net/syncppp.h>
...@@ -767,9 +768,9 @@ static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb) ...@@ -767,9 +768,9 @@ static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb)
struct in_ifaddr *ifa; struct in_ifaddr *ifa;
u32 addr = 0, mask = ~0; /* FIXME: is the mask correct? */ u32 addr = 0, mask = ~0; /* FIXME: is the mask correct? */
#ifdef CONFIG_INET #ifdef CONFIG_INET
if ((in_dev=in_dev_get(dev)) != NULL) rcu_read_lock();
if ((in_dev = __in_dev_get(dev)) != NULL)
{ {
read_lock(&in_dev->lock);
for (ifa=in_dev->ifa_list; ifa != NULL; for (ifa=in_dev->ifa_list; ifa != NULL;
ifa=ifa->ifa_next) { ifa=ifa->ifa_next) {
if (strcmp(dev->name, ifa->ifa_label) == 0) if (strcmp(dev->name, ifa->ifa_label) == 0)
...@@ -779,9 +780,8 @@ static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb) ...@@ -779,9 +780,8 @@ static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb)
break; break;
} }
} }
read_unlock(&in_dev->lock);
in_dev_put(in_dev);
} }
rcu_read_unlock();
#endif #endif
/* I hope both addr and mask are in the net order */ /* I hope both addr and mask are in the net order */
sppp_cisco_send (sp, CISCO_ADDR_REPLY, addr, mask); sppp_cisco_send (sp, CISCO_ADDR_REPLY, addr, mask);
......
...@@ -106,6 +106,7 @@ static const char StripVersion[] = "1.3A-STUART.CHESHIRE"; ...@@ -106,6 +106,7 @@ static const char StripVersion[] = "1.3A-STUART.CHESHIRE";
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/serial.h> #include <linux/serial.h>
#include <linux/serialP.h> #include <linux/serialP.h>
#include <linux/rcupdate.h>
#include <net/arp.h> #include <net/arp.h>
#include <linux/ip.h> #include <linux/ip.h>
...@@ -1348,14 +1349,17 @@ static unsigned char *strip_make_packet(unsigned char *buffer, ...@@ -1348,14 +1349,17 @@ static unsigned char *strip_make_packet(unsigned char *buffer,
*/ */
if (haddr.c[0] == 0xFF) { if (haddr.c[0] == 0xFF) {
u32 brd = 0; u32 brd = 0;
struct in_device *in_dev = in_dev_get(strip_info->dev); struct in_device *in_dev;
if (in_dev == NULL)
rcu_read_lock();
in_dev = __in_dev_get(strip_info->dev);
if (in_dev == NULL) {
rcu_read_unlock();
return NULL; return NULL;
read_lock(&in_dev->lock); }
if (in_dev->ifa_list) if (in_dev->ifa_list)
brd = in_dev->ifa_list->ifa_broadcast; brd = in_dev->ifa_list->ifa_broadcast;
read_unlock(&in_dev->lock); rcu_read_unlock();
in_dev_put(in_dev);
/* arp_query returns 1 if it succeeds in looking up the address, 0 if it fails */ /* arp_query returns 1 if it succeeds in looking up the address, 0 if it fails */
if (!arp_query(haddr.c, brd, strip_info->dev)) { if (!arp_query(haddr.c, brd, strip_info->dev)) {
...@@ -1500,17 +1504,18 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb) ...@@ -1500,17 +1504,18 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb)
} }
if (1) { if (1) {
struct in_device *in_dev = in_dev_get(strip_info->dev); struct in_device *in_dev;
brd = addr = 0; brd = addr = 0;
rcu_read_lock();
in_dev = __in_dev_get(strip_info->dev);
if (in_dev) { if (in_dev) {
read_lock(&in_dev->lock);
if (in_dev->ifa_list) { if (in_dev->ifa_list) {
brd = in_dev->ifa_list->ifa_broadcast; brd = in_dev->ifa_list->ifa_broadcast;
addr = in_dev->ifa_list->ifa_local; addr = in_dev->ifa_list->ifa_local;
} }
read_unlock(&in_dev->lock);
in_dev_put(in_dev);
} }
rcu_read_unlock();
} }
......
...@@ -1002,7 +1002,7 @@ lcs_register_mc_addresses(void *data) ...@@ -1002,7 +1002,7 @@ lcs_register_mc_addresses(void *data)
in4_dev = in_dev_get(card->dev); in4_dev = in_dev_get(card->dev);
if (in4_dev == NULL) if (in4_dev == NULL)
return 0; return 0;
read_lock(&in4_dev->lock); read_lock(&in4_dev->mc_list_lock);
spin_lock(&card->ipm_lock); spin_lock(&card->ipm_lock);
/* Check for multicast addresses to be removed. */ /* Check for multicast addresses to be removed. */
list_for_each(l, &card->ipm_list) { list_for_each(l, &card->ipm_list) {
...@@ -1046,7 +1046,7 @@ lcs_register_mc_addresses(void *data) ...@@ -1046,7 +1046,7 @@ lcs_register_mc_addresses(void *data)
list_add(&ipm->list, &card->ipm_list); list_add(&ipm->list, &card->ipm_list);
} }
spin_unlock(&card->ipm_lock); spin_unlock(&card->ipm_lock);
read_unlock(&in4_dev->lock); read_unlock(&in4_dev->mc_list_lock);
in_dev_put(in4_dev); in_dev_put(in4_dev);
lcs_fix_multicast_list(card); lcs_fix_multicast_list(card);
return 0; return 0;
......
...@@ -73,6 +73,7 @@ qeth_eyecatcher(void) ...@@ -73,6 +73,7 @@ qeth_eyecatcher(void)
#include <linux/reboot.h> #include <linux/reboot.h>
#include <asm/qeth.h> #include <asm/qeth.h>
#include <linux/mii.h> #include <linux/mii.h>
#include <linux/rcupdate.h>
#include "qeth.h" #include "qeth.h"
#include "qeth_mpc.h" #include "qeth_mpc.h"
...@@ -4733,9 +4734,10 @@ qeth_free_vlan_addresses4(struct qeth_card *card, unsigned short vid) ...@@ -4733,9 +4734,10 @@ qeth_free_vlan_addresses4(struct qeth_card *card, unsigned short vid)
QETH_DBF_TEXT(trace, 4, "frvaddr4"); QETH_DBF_TEXT(trace, 4, "frvaddr4");
if (!card->vlangrp) if (!card->vlangrp)
return; return;
in_dev = in_dev_get(card->vlangrp->vlan_devices[vid]); rcu_read_lock();
in_dev = __in_dev_get(card->vlangrp->vlan_devices[vid]);
if (!in_dev) if (!in_dev)
return; goto out;
for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next){ for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next){
addr = qeth_get_addr_buffer(QETH_PROT_IPV4); addr = qeth_get_addr_buffer(QETH_PROT_IPV4);
if (addr){ if (addr){
...@@ -4746,7 +4748,8 @@ qeth_free_vlan_addresses4(struct qeth_card *card, unsigned short vid) ...@@ -4746,7 +4748,8 @@ qeth_free_vlan_addresses4(struct qeth_card *card, unsigned short vid)
kfree(addr); kfree(addr);
} }
} }
in_dev_put(in_dev); out:
rcu_read_unlock();
} }
static void static void
...@@ -4918,9 +4921,9 @@ qeth_add_vlan_mc(struct qeth_card *card) ...@@ -4918,9 +4921,9 @@ qeth_add_vlan_mc(struct qeth_card *card)
in_dev = in_dev_get(vg->vlan_devices[i]); in_dev = in_dev_get(vg->vlan_devices[i]);
if (!in_dev) if (!in_dev)
continue; continue;
read_lock(&in_dev->lock); read_lock(&in_dev->mc_list_lock);
qeth_add_mc(card,in_dev); qeth_add_mc(card,in_dev);
read_unlock(&in_dev->lock); read_unlock(&in_dev->mc_list_lock);
in_dev_put(in_dev); in_dev_put(in_dev);
} }
#endif #endif
...@@ -4935,10 +4938,10 @@ qeth_add_multicast_ipv4(struct qeth_card *card) ...@@ -4935,10 +4938,10 @@ qeth_add_multicast_ipv4(struct qeth_card *card)
in4_dev = in_dev_get(card->dev); in4_dev = in_dev_get(card->dev);
if (in4_dev == NULL) if (in4_dev == NULL)
return; return;
read_lock(&in4_dev->lock); read_lock(&in4_dev->mc_list_lock);
qeth_add_mc(card, in4_dev); qeth_add_mc(card, in4_dev);
qeth_add_vlan_mc(card); qeth_add_vlan_mc(card);
read_unlock(&in4_dev->lock); read_unlock(&in4_dev->mc_list_lock);
in_dev_put(in4_dev); in_dev_put(in4_dev);
} }
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <linux/rcupdate.h>
struct ipv4_devconf struct ipv4_devconf
{ {
int accept_redirects; int accept_redirects;
...@@ -31,13 +33,13 @@ extern struct ipv4_devconf ipv4_devconf; ...@@ -31,13 +33,13 @@ extern struct ipv4_devconf ipv4_devconf;
struct in_device struct in_device
{ {
struct net_device *dev; struct net_device *dev;
atomic_t refcnt; atomic_t refcnt;
rwlock_t lock;
int dead; int dead;
struct in_ifaddr *ifa_list; /* IP ifaddr chain */ struct in_ifaddr *ifa_list; /* IP ifaddr chain */
rwlock_t mc_list_lock;
struct ip_mc_list *mc_list; /* IP multicast filter chain */ struct ip_mc_list *mc_list; /* IP multicast filter chain */
rwlock_t mc_lock; /* for mc_tomb */ spinlock_t mc_tomb_lock;
struct ip_mc_list *mc_tomb; struct ip_mc_list *mc_tomb;
unsigned long mr_v1_seen; unsigned long mr_v1_seen;
unsigned long mr_v2_seen; unsigned long mr_v2_seen;
...@@ -50,6 +52,7 @@ struct in_device ...@@ -50,6 +52,7 @@ struct in_device
struct neigh_parms *arp_parms; struct neigh_parms *arp_parms;
struct ipv4_devconf cnf; struct ipv4_devconf cnf;
struct rcu_head rcu_head;
}; };
#define IN_DEV_FORWARD(in_dev) ((in_dev)->cnf.forwarding) #define IN_DEV_FORWARD(in_dev) ((in_dev)->cnf.forwarding)
...@@ -80,6 +83,7 @@ struct in_ifaddr ...@@ -80,6 +83,7 @@ struct in_ifaddr
{ {
struct in_ifaddr *ifa_next; struct in_ifaddr *ifa_next;
struct in_device *ifa_dev; struct in_device *ifa_dev;
struct rcu_head rcu_head;
u32 ifa_local; u32 ifa_local;
u32 ifa_address; u32 ifa_address;
u32 ifa_mask; u32 ifa_mask;
...@@ -133,19 +137,16 @@ static __inline__ int bad_mask(u32 mask, u32 addr) ...@@ -133,19 +137,16 @@ static __inline__ int bad_mask(u32 mask, u32 addr)
#define endfor_ifa(in_dev) } #define endfor_ifa(in_dev) }
extern rwlock_t inetdev_lock;
static __inline__ struct in_device * static __inline__ struct in_device *
in_dev_get(const struct net_device *dev) in_dev_get(const struct net_device *dev)
{ {
struct in_device *in_dev; struct in_device *in_dev;
read_lock(&inetdev_lock); rcu_read_lock();
in_dev = dev->ip_ptr; in_dev = dev->ip_ptr;
if (in_dev) if (in_dev)
atomic_inc(&in_dev->refcnt); atomic_inc(&in_dev->refcnt);
read_unlock(&inetdev_lock); rcu_read_unlock();
return in_dev; return in_dev;
} }
...@@ -157,8 +158,7 @@ __in_dev_get(const struct net_device *dev) ...@@ -157,8 +158,7 @@ __in_dev_get(const struct net_device *dev)
extern void in_dev_finish_destroy(struct in_device *idev); extern void in_dev_finish_destroy(struct in_device *idev);
static __inline__ void static inline void in_dev_put(struct in_device *idev)
in_dev_put(struct in_device *idev)
{ {
if (atomic_dec_and_test(&idev->refcnt)) if (atomic_dec_and_test(&idev->refcnt))
in_dev_finish_destroy(idev); in_dev_finish_destroy(idev);
......
...@@ -169,6 +169,7 @@ extern struct socket *sockfd_lookup(int fd, int *err); ...@@ -169,6 +169,7 @@ extern struct socket *sockfd_lookup(int fd, int *err);
extern int net_ratelimit(void); extern int net_ratelimit(void);
extern unsigned long net_random(void); extern unsigned long net_random(void);
extern void net_srandom(unsigned long); extern void net_srandom(unsigned long);
extern void net_random_init(void);
extern int kernel_sendmsg(struct socket *sock, struct msghdr *msg, extern int kernel_sendmsg(struct socket *sock, struct msghdr *msg,
struct kvec *vec, size_t num, size_t len); struct kvec *vec, size_t num, size_t len);
......
...@@ -242,7 +242,6 @@ extern u32 fib_rules_map_destination(u32 daddr, struct fib_result *res); ...@@ -242,7 +242,6 @@ extern u32 fib_rules_map_destination(u32 daddr, struct fib_result *res);
#ifdef CONFIG_NET_CLS_ROUTE #ifdef CONFIG_NET_CLS_ROUTE
extern u32 fib_rules_tclass(struct fib_result *res); extern u32 fib_rules_tclass(struct fib_result *res);
#endif #endif
extern u32 fib_rules_policy(u32 saddr, struct fib_result *res, unsigned *flags);
extern void fib_rules_init(void); extern void fib_rules_init(void);
#endif #endif
......
...@@ -73,11 +73,6 @@ struct rtable ...@@ -73,11 +73,6 @@ struct rtable
/* Miscellaneous cached information */ /* Miscellaneous cached information */
__u32 rt_spec_dst; /* RFC1122 specific destination */ __u32 rt_spec_dst; /* RFC1122 specific destination */
struct inet_peer *peer; /* long-living peer info */ struct inet_peer *peer; /* long-living peer info */
#ifdef CONFIG_IP_ROUTE_NAT
__u32 rt_src_map;
__u32 rt_dst_map;
#endif
}; };
struct ip_rt_acct struct ip_rt_acct
......
...@@ -21,13 +21,14 @@ ...@@ -21,13 +21,14 @@
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/netfilter_bridge/ebtables.h> #include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_vlan.h> #include <linux/netfilter_bridge/ebt_vlan.h>
static unsigned char debug; static int debug;
#define MODULE_VERS "0.6" #define MODULE_VERS "0.6"
MODULE_PARM(debug, "0-1b"); module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "debug=1 is turn on debug messages"); MODULE_PARM_DESC(debug, "debug=1 is turn on debug messages");
MODULE_AUTHOR("Nick Fedchik <nick@fedchik.org.ua>"); MODULE_AUTHOR("Nick Fedchik <nick@fedchik.org.ua>");
MODULE_DESCRIPTION("802.1Q match module (ebtables extension), v" MODULE_DESCRIPTION("802.1Q match module (ebtables extension), v"
......
...@@ -3280,6 +3280,8 @@ static int __init net_dev_init(void) ...@@ -3280,6 +3280,8 @@ static int __init net_dev_init(void)
BUG_ON(!dev_boot_phase); BUG_ON(!dev_boot_phase);
net_random_init();
if (dev_proc_init()) if (dev_proc_init())
goto out; goto out;
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/netpoll.h> #include <linux/netpoll.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/rcupdate.h>
#include <net/tcp.h> #include <net/tcp.h>
#include <net/udp.h> #include <net/udp.h>
...@@ -572,16 +573,18 @@ int netpoll_setup(struct netpoll *np) ...@@ -572,16 +573,18 @@ int netpoll_setup(struct netpoll *np)
memcpy(np->local_mac, ndev->dev_addr, 6); memcpy(np->local_mac, ndev->dev_addr, 6);
if (!np->local_ip) { if (!np->local_ip) {
in_dev = in_dev_get(ndev); rcu_read_lock();
in_dev = __in_dev_get(ndev);
if (!in_dev) { if (!in_dev) {
rcu_read_unlock();
printk(KERN_ERR "%s: no IP address for %s, aborting\n", printk(KERN_ERR "%s: no IP address for %s, aborting\n",
np->name, np->dev_name); np->name, np->dev_name);
goto release; goto release;
} }
np->local_ip = ntohl(in_dev->ifa_list->ifa_local); np->local_ip = ntohl(in_dev->ifa_list->ifa_local);
in_dev_put(in_dev); rcu_read_unlock();
printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n", printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n",
np->name, HIPQUAD(np->local_ip)); np->name, HIPQUAD(np->local_ip));
} }
......
...@@ -70,6 +70,7 @@ ...@@ -70,6 +70,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/inet.h> #include <linux/inet.h>
#include <linux/rcupdate.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <asm/bitops.h> #include <asm/bitops.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -263,14 +264,17 @@ static struct net_device *setup_inject(struct pktgen_info* info) ...@@ -263,14 +264,17 @@ static struct net_device *setup_inject(struct pktgen_info* info)
info->saddr_min = 0; info->saddr_min = 0;
info->saddr_max = 0; info->saddr_max = 0;
if (strlen(info->src_min) == 0) { if (strlen(info->src_min) == 0) {
struct in_device *in_dev = in_dev_get(odev); struct in_device *in_dev;
rcu_read_lock();
in_dev = __in_dev_get(odev);
if (in_dev) { if (in_dev) {
if (in_dev->ifa_list) { if (in_dev->ifa_list) {
info->saddr_min = in_dev->ifa_list->ifa_address; info->saddr_min = in_dev->ifa_list->ifa_address;
info->saddr_max = info->saddr_min; info->saddr_max = info->saddr_min;
} }
in_dev_put(in_dev);
} }
rcu_read_unlock();
} }
else { else {
info->saddr_min = in_aton(info->src_min); info->saddr_min = in_aton(info->src_min);
......
...@@ -19,22 +19,116 @@ ...@@ -19,22 +19,116 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/random.h>
#include <linux/percpu.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
static unsigned long net_rand_seed = 152L;
/*
This is a maximally equidistributed combined Tausworthe generator
based on code from GNU Scientific Library 1.5 (30 Jun 2004)
x_n = (s1_n ^ s2_n ^ s3_n)
s1_{n+1} = (((s1_n & 4294967294) <<12) ^ (((s1_n <<13) ^ s1_n) >>19))
s2_{n+1} = (((s2_n & 4294967288) << 4) ^ (((s2_n << 2) ^ s2_n) >>25))
s3_{n+1} = (((s3_n & 4294967280) <<17) ^ (((s3_n << 3) ^ s3_n) >>11))
The period of this generator is about 2^88.
From: P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe
Generators", Mathematics of Computation, 65, 213 (1996), 203--213.
This is available on the net from L'Ecuyer's home page,
http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps
ftp://ftp.iro.umontreal.ca/pub/simulation/lecuyer/papers/tausme.ps
There is an erratum in the paper "Tables of Maximally
Equidistributed Combined LFSR Generators", Mathematics of
Computation, 68, 225 (1999), 261--269:
http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps
... the k_j most significant bits of z_j must be non-
zero, for each j. (Note: this restriction also applies to the
computer code given in [4], but was mistakenly not mentioned in
that paper.)
This affects the seeding procedure by imposing the requirement
s1 > 1, s2 > 7, s3 > 15.
*/
struct nrnd_state {
u32 s1, s2, s3;
};
static DEFINE_PER_CPU(struct nrnd_state, net_rand_state);
static u32 __net_random(struct nrnd_state *state)
{
#define TAUSWORTHE(s,a,b,c,d) ((s&c)<<d) ^ (((s <<a) ^ s)>>b)
state->s1 = TAUSWORTHE(state->s1, 13, 19, 4294967294UL, 12);
state->s2 = TAUSWORTHE(state->s2, 2, 25, 4294967288UL, 4);
state->s3 = TAUSWORTHE(state->s3, 3, 11, 4294967280UL, 17);
return (state->s1 ^ state->s2 ^ state->s3);
}
static void __net_srandom(struct nrnd_state *state, unsigned long entropy)
{
u32 s = state->s1 ^ entropy;
if (s == 0)
s = 1; /* default seed is 1 */
#define LCG(n) (69069 * n)
state->s1 = LCG(s);
state->s2 = LCG(state->s1);
state->s3 = LCG(state->s2);
/* "warm it up" */
__net_random(state);
__net_random(state);
__net_random(state);
__net_random(state);
__net_random(state);
__net_random(state);
}
unsigned long net_random(void) unsigned long net_random(void)
{ {
net_rand_seed=net_rand_seed*69069L+1; unsigned long r;
return net_rand_seed^jiffies; struct nrnd_state *state = &get_cpu_var(net_rand_state);
r = __net_random(state);
put_cpu_var(state);
return r;
} }
void net_srandom(unsigned long entropy) void net_srandom(unsigned long entropy)
{ {
net_rand_seed ^= entropy; struct nrnd_state *state = &get_cpu_var(net_rand_state);
net_random(); __net_srandom(state, entropy);
put_cpu_var(state);
}
void __init net_random_init(void)
{
int i;
unsigned long seed[NR_CPUS];
get_random_bytes(seed, sizeof(seed));
for (i = 0; i < NR_CPUS; i++) {
struct nrnd_state *state = &per_cpu(net_rand_state,i);
memset(state, 0, sizeof(*state));
__net_srandom(state, seed[i]);
}
} }
int net_msg_cost = 5*HZ; int net_msg_cost = 5*HZ;
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <net/udp.h> #include <net/udp.h>
#include <net/ip.h> #include <net/ip.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/rcupdate.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -401,16 +402,17 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -401,16 +402,17 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock,
y.x maps to IP a.b.c.x. This should be replaced with something y.x maps to IP a.b.c.x. This should be replaced with something
more flexible and more aware of subnet masks. */ more flexible and more aware of subnet masks. */
{ {
struct in_device *idev = in_dev_get(dev); struct in_device *idev;
unsigned long network = 0; unsigned long network = 0;
rcu_read_lock();
idev = __in_dev_get(dev);
if (idev) { if (idev) {
read_lock(&idev->lock);
if (idev->ifa_list) if (idev->ifa_list)
network = ntohl(idev->ifa_list->ifa_address) & network = ntohl(idev->ifa_list->ifa_address) &
0xffffff00; /* !!! */ 0xffffff00; /* !!! */
read_unlock(&idev->lock);
in_dev_put(idev);
} }
rcu_read_unlock();
udpdest.sin_addr.s_addr = htonl(network | addr.station); udpdest.sin_addr.s_addr = htonl(network | addr.station);
} }
......
...@@ -82,16 +82,6 @@ config IP_ROUTE_FWMARK ...@@ -82,16 +82,6 @@ config IP_ROUTE_FWMARK
If you say Y here, you will be able to specify different routes for If you say Y here, you will be able to specify different routes for
packets with different mark values (see iptables(8), MARK target). packets with different mark values (see iptables(8), MARK target).
config IP_ROUTE_NAT
bool "IP: fast network address translation"
depends on IP_MULTIPLE_TABLES
help
If you say Y here, your router will be able to modify source and
destination addresses of packets that pass through it, in a manner
you specify. General information about Network Address Translation
can be gotten from the document
<http://www.hasenstein.com/linux-ip-nat/diplom/nat.html>.
config IP_ROUTE_MULTIPATH config IP_ROUTE_MULTIPATH
bool "IP: equal cost multipath" bool "IP: equal cost multipath"
depends on IP_ADVANCED_ROUTER depends on IP_ADVANCED_ROUTER
......
...@@ -88,31 +88,31 @@ static void devinet_sysctl_register(struct in_device *in_dev, ...@@ -88,31 +88,31 @@ static void devinet_sysctl_register(struct in_device *in_dev,
static void devinet_sysctl_unregister(struct ipv4_devconf *p); static void devinet_sysctl_unregister(struct ipv4_devconf *p);
#endif #endif
int inet_ifa_count;
int inet_dev_count;
/* Locks all the inet devices. */ /* Locks all the inet devices. */
rwlock_t inetdev_lock = RW_LOCK_UNLOCKED;
static struct in_ifaddr *inet_alloc_ifa(void) static struct in_ifaddr *inet_alloc_ifa(void)
{ {
struct in_ifaddr *ifa = kmalloc(sizeof(*ifa), GFP_KERNEL); struct in_ifaddr *ifa = kmalloc(sizeof(*ifa), GFP_KERNEL);
if (ifa) { if (ifa) {
memset(ifa, 0, sizeof(*ifa)); memset(ifa, 0, sizeof(*ifa));
inet_ifa_count++; INIT_RCU_HEAD(&ifa->rcu_head);
} }
return ifa; return ifa;
} }
static __inline__ void inet_free_ifa(struct in_ifaddr *ifa) static void inet_rcu_free_ifa(struct rcu_head *head)
{ {
struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);
if (ifa->ifa_dev) if (ifa->ifa_dev)
__in_dev_put(ifa->ifa_dev); in_dev_put(ifa->ifa_dev);
kfree(ifa); kfree(ifa);
inet_ifa_count--; }
static inline void inet_free_ifa(struct in_ifaddr *ifa)
{
call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
} }
void in_dev_finish_destroy(struct in_device *idev) void in_dev_finish_destroy(struct in_device *idev)
...@@ -129,7 +129,6 @@ void in_dev_finish_destroy(struct in_device *idev) ...@@ -129,7 +129,6 @@ void in_dev_finish_destroy(struct in_device *idev)
if (!idev->dead) if (!idev->dead)
printk("Freeing alive in_device %p\n", idev); printk("Freeing alive in_device %p\n", idev);
else { else {
inet_dev_count--;
kfree(idev); kfree(idev);
} }
} }
...@@ -144,24 +143,24 @@ struct in_device *inetdev_init(struct net_device *dev) ...@@ -144,24 +143,24 @@ struct in_device *inetdev_init(struct net_device *dev)
if (!in_dev) if (!in_dev)
goto out; goto out;
memset(in_dev, 0, sizeof(*in_dev)); memset(in_dev, 0, sizeof(*in_dev));
in_dev->lock = RW_LOCK_UNLOCKED; INIT_RCU_HEAD(&in_dev->rcu_head);
memcpy(&in_dev->cnf, &ipv4_devconf_dflt, sizeof(in_dev->cnf)); memcpy(&in_dev->cnf, &ipv4_devconf_dflt, sizeof(in_dev->cnf));
in_dev->cnf.sysctl = NULL; in_dev->cnf.sysctl = NULL;
in_dev->dev = dev; in_dev->dev = dev;
if ((in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl)) == NULL) if ((in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl)) == NULL)
goto out_kfree; goto out_kfree;
inet_dev_count++;
/* Reference in_dev->dev */ /* Reference in_dev->dev */
dev_hold(dev); dev_hold(dev);
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4, neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4,
NET_IPV4_NEIGH, "ipv4", NULL); NET_IPV4_NEIGH, "ipv4", NULL);
#endif #endif
write_lock_bh(&inetdev_lock);
dev->ip_ptr = in_dev;
/* Account for reference dev->ip_ptr */ /* Account for reference dev->ip_ptr */
in_dev_hold(in_dev); in_dev_hold(in_dev);
write_unlock_bh(&inetdev_lock); smp_wmb();
dev->ip_ptr = in_dev;
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
devinet_sysctl_register(in_dev, &in_dev->cnf); devinet_sysctl_register(in_dev, &in_dev->cnf);
#endif #endif
...@@ -176,6 +175,12 @@ struct in_device *inetdev_init(struct net_device *dev) ...@@ -176,6 +175,12 @@ struct in_device *inetdev_init(struct net_device *dev)
goto out; goto out;
} }
static void in_dev_rcu_put(struct rcu_head *head)
{
struct in_device *idev = container_of(head, struct in_device, rcu_head);
in_dev_put(idev);
}
static void inetdev_destroy(struct in_device *in_dev) static void inetdev_destroy(struct in_device *in_dev)
{ {
struct in_ifaddr *ifa; struct in_ifaddr *ifa;
...@@ -194,30 +199,28 @@ static void inetdev_destroy(struct in_device *in_dev) ...@@ -194,30 +199,28 @@ static void inetdev_destroy(struct in_device *in_dev)
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
devinet_sysctl_unregister(&in_dev->cnf); devinet_sysctl_unregister(&in_dev->cnf);
#endif #endif
write_lock_bh(&inetdev_lock);
in_dev->dev->ip_ptr = NULL; in_dev->dev->ip_ptr = NULL;
/* in_dev_put following below will kill the in_device */
write_unlock_bh(&inetdev_lock);
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
neigh_sysctl_unregister(in_dev->arp_parms); neigh_sysctl_unregister(in_dev->arp_parms);
#endif #endif
neigh_parms_release(&arp_tbl, in_dev->arp_parms); neigh_parms_release(&arp_tbl, in_dev->arp_parms);
in_dev_put(in_dev); call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
} }
int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b) int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b)
{ {
read_lock(&in_dev->lock); rcu_read_lock();
for_primary_ifa(in_dev) { for_primary_ifa(in_dev) {
if (inet_ifa_match(a, ifa)) { if (inet_ifa_match(a, ifa)) {
if (!b || inet_ifa_match(b, ifa)) { if (!b || inet_ifa_match(b, ifa)) {
read_unlock(&in_dev->lock); rcu_read_unlock();
return 1; return 1;
} }
} }
} endfor_ifa(in_dev); } endfor_ifa(in_dev);
read_unlock(&in_dev->lock); rcu_read_unlock();
return 0; return 0;
} }
...@@ -241,9 +244,8 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, ...@@ -241,9 +244,8 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
ifap1 = &ifa->ifa_next; ifap1 = &ifa->ifa_next;
continue; continue;
} }
write_lock_bh(&in_dev->lock);
*ifap1 = ifa->ifa_next; *ifap1 = ifa->ifa_next;
write_unlock_bh(&in_dev->lock);
rtmsg_ifa(RTM_DELADDR, ifa); rtmsg_ifa(RTM_DELADDR, ifa);
notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa); notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa);
...@@ -253,9 +255,7 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, ...@@ -253,9 +255,7 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
/* 2. Unlink it */ /* 2. Unlink it */
write_lock_bh(&in_dev->lock);
*ifap = ifa1->ifa_next; *ifap = ifa1->ifa_next;
write_unlock_bh(&in_dev->lock);
/* 3. Announce address deletion */ /* 3. Announce address deletion */
...@@ -317,9 +317,7 @@ static int inet_insert_ifa(struct in_ifaddr *ifa) ...@@ -317,9 +317,7 @@ static int inet_insert_ifa(struct in_ifaddr *ifa)
} }
ifa->ifa_next = *ifap; ifa->ifa_next = *ifap;
write_lock_bh(&in_dev->lock);
*ifap = ifa; *ifap = ifa;
write_unlock_bh(&in_dev->lock);
/* Send message first, then call notifier. /* Send message first, then call notifier.
Notifier will trigger FIB update, so that Notifier will trigger FIB update, so that
...@@ -771,12 +769,11 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope) ...@@ -771,12 +769,11 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope)
u32 addr = 0; u32 addr = 0;
struct in_device *in_dev; struct in_device *in_dev;
read_lock(&inetdev_lock); rcu_read_lock();
in_dev = __in_dev_get(dev); in_dev = __in_dev_get(dev);
if (!in_dev) if (!in_dev)
goto out_unlock_inetdev; goto no_in_dev;
read_lock(&in_dev->lock);
for_primary_ifa(in_dev) { for_primary_ifa(in_dev) {
if (ifa->ifa_scope > scope) if (ifa->ifa_scope > scope)
continue; continue;
...@@ -787,8 +784,8 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope) ...@@ -787,8 +784,8 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope)
if (!addr) if (!addr)
addr = ifa->ifa_local; addr = ifa->ifa_local;
} endfor_ifa(in_dev); } endfor_ifa(in_dev);
read_unlock(&in_dev->lock); no_in_dev:
read_unlock(&inetdev_lock); rcu_read_unlock();
if (addr) if (addr)
goto out; goto out;
...@@ -798,30 +795,24 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope) ...@@ -798,30 +795,24 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope)
in dev_base list. in dev_base list.
*/ */
read_lock(&dev_base_lock); read_lock(&dev_base_lock);
read_lock(&inetdev_lock); rcu_read_lock();
for (dev = dev_base; dev; dev = dev->next) { for (dev = dev_base; dev; dev = dev->next) {
if ((in_dev = __in_dev_get(dev)) == NULL) if ((in_dev = __in_dev_get(dev)) == NULL)
continue; continue;
read_lock(&in_dev->lock);
for_primary_ifa(in_dev) { for_primary_ifa(in_dev) {
if (ifa->ifa_scope != RT_SCOPE_LINK && if (ifa->ifa_scope != RT_SCOPE_LINK &&
ifa->ifa_scope <= scope) { ifa->ifa_scope <= scope) {
read_unlock(&in_dev->lock);
addr = ifa->ifa_local; addr = ifa->ifa_local;
goto out_unlock_both; goto out_unlock_both;
} }
} endfor_ifa(in_dev); } endfor_ifa(in_dev);
read_unlock(&in_dev->lock);
} }
out_unlock_both: out_unlock_both:
read_unlock(&inetdev_lock);
read_unlock(&dev_base_lock); read_unlock(&dev_base_lock);
rcu_read_unlock();
out: out:
return addr; return addr;
out_unlock_inetdev:
read_unlock(&inetdev_lock);
goto out;
} }
static u32 confirm_addr_indev(struct in_device *in_dev, u32 dst, static u32 confirm_addr_indev(struct in_device *in_dev, u32 dst,
...@@ -874,29 +865,24 @@ u32 inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scop ...@@ -874,29 +865,24 @@ u32 inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scop
struct in_device *in_dev; struct in_device *in_dev;
if (dev) { if (dev) {
read_lock(&inetdev_lock); rcu_read_lock();
if ((in_dev = __in_dev_get(dev))) { if ((in_dev = __in_dev_get(dev)))
read_lock(&in_dev->lock);
addr = confirm_addr_indev(in_dev, dst, local, scope); addr = confirm_addr_indev(in_dev, dst, local, scope);
read_unlock(&in_dev->lock); rcu_read_unlock();
}
read_unlock(&inetdev_lock);
return addr; return addr;
} }
read_lock(&dev_base_lock); read_lock(&dev_base_lock);
read_lock(&inetdev_lock); rcu_read_lock();
for (dev = dev_base; dev; dev = dev->next) { for (dev = dev_base; dev; dev = dev->next) {
if ((in_dev = __in_dev_get(dev))) { if ((in_dev = __in_dev_get(dev))) {
read_lock(&in_dev->lock);
addr = confirm_addr_indev(in_dev, dst, local, scope); addr = confirm_addr_indev(in_dev, dst, local, scope);
read_unlock(&in_dev->lock);
if (addr) if (addr)
break; break;
} }
} }
read_unlock(&inetdev_lock); rcu_read_unlock();
read_unlock(&dev_base_lock); read_unlock(&dev_base_lock);
return addr; return addr;
...@@ -1065,12 +1051,12 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1065,12 +1051,12 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
continue; continue;
if (idx > s_idx) if (idx > s_idx)
s_ip_idx = 0; s_ip_idx = 0;
read_lock(&inetdev_lock); rcu_read_lock();
if ((in_dev = __in_dev_get(dev)) == NULL) { if ((in_dev = __in_dev_get(dev)) == NULL) {
read_unlock(&inetdev_lock); rcu_read_unlock();
continue; continue;
} }
read_lock(&in_dev->lock);
for (ifa = in_dev->ifa_list, ip_idx = 0; ifa; for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
ifa = ifa->ifa_next, ip_idx++) { ifa = ifa->ifa_next, ip_idx++) {
if (ip_idx < s_ip_idx) if (ip_idx < s_ip_idx)
...@@ -1078,13 +1064,11 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1078,13 +1064,11 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid, if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, cb->nlh->nlmsg_seq,
RTM_NEWADDR) <= 0) { RTM_NEWADDR) <= 0) {
read_unlock(&in_dev->lock); rcu_read_unlock();
read_unlock(&inetdev_lock);
goto done; goto done;
} }
} }
read_unlock(&in_dev->lock); rcu_read_unlock();
read_unlock(&inetdev_lock);
} }
done: done:
...@@ -1138,11 +1122,11 @@ void inet_forward_change(void) ...@@ -1138,11 +1122,11 @@ void inet_forward_change(void)
read_lock(&dev_base_lock); read_lock(&dev_base_lock);
for (dev = dev_base; dev; dev = dev->next) { for (dev = dev_base; dev; dev = dev->next) {
struct in_device *in_dev; struct in_device *in_dev;
read_lock(&inetdev_lock); rcu_read_lock();
in_dev = __in_dev_get(dev); in_dev = __in_dev_get(dev);
if (in_dev) if (in_dev)
in_dev->cnf.forwarding = on; in_dev->cnf.forwarding = on;
read_unlock(&inetdev_lock); rcu_read_unlock();
} }
read_unlock(&dev_base_lock); read_unlock(&dev_base_lock);
...@@ -1508,6 +1492,5 @@ EXPORT_SYMBOL(devinet_ioctl); ...@@ -1508,6 +1492,5 @@ EXPORT_SYMBOL(devinet_ioctl);
EXPORT_SYMBOL(in_dev_finish_destroy); EXPORT_SYMBOL(in_dev_finish_destroy);
EXPORT_SYMBOL(inet_select_addr); EXPORT_SYMBOL(inet_select_addr);
EXPORT_SYMBOL(inetdev_by_index); EXPORT_SYMBOL(inetdev_by_index);
EXPORT_SYMBOL(inetdev_lock);
EXPORT_SYMBOL(register_inetaddr_notifier); EXPORT_SYMBOL(register_inetaddr_notifier);
EXPORT_SYMBOL(unregister_inetaddr_notifier); EXPORT_SYMBOL(unregister_inetaddr_notifier);
...@@ -172,13 +172,13 @@ int fib_validate_source(u32 src, u32 dst, u8 tos, int oif, ...@@ -172,13 +172,13 @@ int fib_validate_source(u32 src, u32 dst, u8 tos, int oif,
int ret; int ret;
no_addr = rpf = 0; no_addr = rpf = 0;
read_lock(&inetdev_lock); rcu_read_lock();
in_dev = __in_dev_get(dev); in_dev = __in_dev_get(dev);
if (in_dev) { if (in_dev) {
no_addr = in_dev->ifa_list == NULL; no_addr = in_dev->ifa_list == NULL;
rpf = IN_DEV_RPFILTER(in_dev); rpf = IN_DEV_RPFILTER(in_dev);
} }
read_unlock(&inetdev_lock); rcu_read_unlock();
if (in_dev == NULL) if (in_dev == NULL)
goto e_inval; goto e_inval;
......
...@@ -176,7 +176,7 @@ int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) ...@@ -176,7 +176,7 @@ int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
table_id = rtm->rtm_table; table_id = rtm->rtm_table;
if (table_id == RT_TABLE_UNSPEC) { if (table_id == RT_TABLE_UNSPEC) {
struct fib_table *table; struct fib_table *table;
if (rtm->rtm_type == RTN_UNICAST || rtm->rtm_type == RTN_NAT) { if (rtm->rtm_type == RTN_UNICAST) {
if ((table = fib_empty_table()) == NULL) if ((table = fib_empty_table()) == NULL)
return -ENOBUFS; return -ENOBUFS;
table_id = table->tb_id; table_id = table->tb_id;
...@@ -251,26 +251,6 @@ u32 fib_rules_map_destination(u32 daddr, struct fib_result *res) ...@@ -251,26 +251,6 @@ u32 fib_rules_map_destination(u32 daddr, struct fib_result *res)
return (daddr&~mask)|res->fi->fib_nh->nh_gw; return (daddr&~mask)|res->fi->fib_nh->nh_gw;
} }
u32 fib_rules_policy(u32 saddr, struct fib_result *res, unsigned *flags)
{
struct fib_rule *r = res->r;
if (r->r_action == RTN_NAT) {
int addrtype = inet_addr_type(r->r_srcmap);
if (addrtype == RTN_NAT) {
/* Packet is from translated source; remember it */
saddr = (saddr&~r->r_srcmask)|r->r_srcmap;
*flags |= RTCF_SNAT;
} else if (addrtype == RTN_LOCAL || r->r_srcmap == 0) {
/* Packet is from masqueraded source; remember it */
saddr = r->r_srcmap;
*flags |= RTCF_MASQ;
}
}
return saddr;
}
#ifdef CONFIG_NET_CLS_ROUTE #ifdef CONFIG_NET_CLS_ROUTE
u32 fib_rules_tclass(struct fib_result *res) u32 fib_rules_tclass(struct fib_result *res)
{ {
...@@ -334,7 +314,6 @@ FRprintk("Lookup: %u.%u.%u.%u <- %u.%u.%u.%u ", ...@@ -334,7 +314,6 @@ FRprintk("Lookup: %u.%u.%u.%u <- %u.%u.%u.%u ",
FRprintk("tb %d r %d ", r->r_table, r->r_action); FRprintk("tb %d r %d ", r->r_table, r->r_action);
switch (r->r_action) { switch (r->r_action) {
case RTN_UNICAST: case RTN_UNICAST:
case RTN_NAT:
policy = r; policy = r;
break; break;
case RTN_UNREACHABLE: case RTN_UNREACHABLE:
......
...@@ -124,17 +124,10 @@ static struct ...@@ -124,17 +124,10 @@ static struct
.error = -EAGAIN, .error = -EAGAIN,
.scope = RT_SCOPE_UNIVERSE, .scope = RT_SCOPE_UNIVERSE,
}, /* RTN_THROW */ }, /* RTN_THROW */
#ifdef CONFIG_IP_ROUTE_NAT
{
.error = 0,
.scope = RT_SCOPE_HOST,
}, /* RTN_NAT */
#else
{ {
.error = -EINVAL, .error = -EINVAL,
.scope = RT_SCOPE_NOWHERE, .scope = RT_SCOPE_NOWHERE,
}, /* RTN_NAT */ }, /* RTN_NAT */
#endif
{ {
.error = -EINVAL, .error = -EINVAL,
.scope = RT_SCOPE_NOWHERE, .scope = RT_SCOPE_NOWHERE,
...@@ -543,15 +536,6 @@ fib_create_info(const struct rtmsg *r, struct kern_rta *rta, ...@@ -543,15 +536,6 @@ fib_create_info(const struct rtmsg *r, struct kern_rta *rta,
#endif #endif
} }
#ifdef CONFIG_IP_ROUTE_NAT
if (r->rtm_type == RTN_NAT) {
if (rta->rta_gw == NULL || nhs != 1 || rta->rta_oif)
goto err_inval;
memcpy(&fi->fib_nh->nh_gw, rta->rta_gw, 4);
goto link_it;
}
#endif
if (fib_props[r->rtm_type].error) { if (fib_props[r->rtm_type].error) {
if (rta->rta_gw || rta->rta_oif || rta->rta_mp) if (rta->rta_gw || rta->rta_oif || rta->rta_mp)
goto err_inval; goto err_inval;
...@@ -629,12 +613,6 @@ fib_semantic_match(int type, struct fib_info *fi, const struct flowi *flp, struc ...@@ -629,12 +613,6 @@ fib_semantic_match(int type, struct fib_info *fi, const struct flowi *flp, struc
res->fi = fi; res->fi = fi;
switch (type) { switch (type) {
#ifdef CONFIG_IP_ROUTE_NAT
case RTN_NAT:
FIB_RES_RESET(*res);
atomic_inc(&fi->fib_clntref);
return 0;
#endif
case RTN_UNICAST: case RTN_UNICAST:
case RTN_LOCAL: case RTN_LOCAL:
case RTN_BROADCAST: case RTN_BROADCAST:
......
...@@ -508,16 +508,6 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info) ...@@ -508,16 +508,6 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
* Construct source address and options. * Construct source address and options.
*/ */
#ifdef CONFIG_IP_ROUTE_NAT
/*
* Restore original addresses if packet has been translated.
*/
if (rt->rt_flags & RTCF_NAT && IPCB(skb_in)->flags & IPSKB_TRANSLATED) {
iph->daddr = rt->fl.fl4_dst;
iph->saddr = rt->fl.fl4_src;
}
#endif
saddr = iph->daddr; saddr = iph->daddr;
if (!(rt->rt_flags & RTCF_LOCAL)) if (!(rt->rt_flags & RTCF_LOCAL))
saddr = 0; saddr = 0;
...@@ -892,7 +882,7 @@ static void icmp_address_reply(struct sk_buff *skb) ...@@ -892,7 +882,7 @@ static void icmp_address_reply(struct sk_buff *skb)
in_dev = in_dev_get(dev); in_dev = in_dev_get(dev);
if (!in_dev) if (!in_dev)
goto out; goto out;
read_lock(&in_dev->lock); rcu_read_lock();
if (in_dev->ifa_list && if (in_dev->ifa_list &&
IN_DEV_LOG_MARTIANS(in_dev) && IN_DEV_LOG_MARTIANS(in_dev) &&
IN_DEV_FORWARD(in_dev)) { IN_DEV_FORWARD(in_dev)) {
...@@ -912,7 +902,7 @@ static void icmp_address_reply(struct sk_buff *skb) ...@@ -912,7 +902,7 @@ static void icmp_address_reply(struct sk_buff *skb)
NIPQUAD(*mp), dev->name, NIPQUAD(rt->rt_src)); NIPQUAD(*mp), dev->name, NIPQUAD(rt->rt_src));
} }
} }
read_unlock(&in_dev->lock); rcu_read_unlock();
in_dev_put(in_dev); in_dev_put(in_dev);
out:; out:;
} }
......
...@@ -487,7 +487,7 @@ static int igmpv3_send_report(struct in_device *in_dev, struct ip_mc_list *pmc) ...@@ -487,7 +487,7 @@ static int igmpv3_send_report(struct in_device *in_dev, struct ip_mc_list *pmc)
int type; int type;
if (!pmc) { if (!pmc) {
read_lock(&in_dev->lock); read_lock(&in_dev->mc_list_lock);
for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) { for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) {
if (pmc->multiaddr == IGMP_ALL_HOSTS) if (pmc->multiaddr == IGMP_ALL_HOSTS)
continue; continue;
...@@ -499,7 +499,7 @@ static int igmpv3_send_report(struct in_device *in_dev, struct ip_mc_list *pmc) ...@@ -499,7 +499,7 @@ static int igmpv3_send_report(struct in_device *in_dev, struct ip_mc_list *pmc)
skb = add_grec(skb, pmc, type, 0, 0); skb = add_grec(skb, pmc, type, 0, 0);
spin_unlock_bh(&pmc->lock); spin_unlock_bh(&pmc->lock);
} }
read_unlock(&in_dev->lock); read_unlock(&in_dev->mc_list_lock);
} else { } else {
spin_lock_bh(&pmc->lock); spin_lock_bh(&pmc->lock);
if (pmc->sfcount[MCAST_EXCLUDE]) if (pmc->sfcount[MCAST_EXCLUDE])
...@@ -541,8 +541,8 @@ static void igmpv3_send_cr(struct in_device *in_dev) ...@@ -541,8 +541,8 @@ static void igmpv3_send_cr(struct in_device *in_dev)
struct sk_buff *skb = NULL; struct sk_buff *skb = NULL;
int type, dtype; int type, dtype;
read_lock(&in_dev->lock); read_lock(&in_dev->mc_list_lock);
write_lock_bh(&in_dev->mc_lock); spin_lock_bh(&in_dev->mc_tomb_lock);
/* deleted MCA's */ /* deleted MCA's */
pmc_prev = NULL; pmc_prev = NULL;
...@@ -575,7 +575,7 @@ static void igmpv3_send_cr(struct in_device *in_dev) ...@@ -575,7 +575,7 @@ static void igmpv3_send_cr(struct in_device *in_dev)
} else } else
pmc_prev = pmc; pmc_prev = pmc;
} }
write_unlock_bh(&in_dev->mc_lock); spin_unlock_bh(&in_dev->mc_tomb_lock);
/* change recs */ /* change recs */
for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) { for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) {
...@@ -601,7 +601,8 @@ static void igmpv3_send_cr(struct in_device *in_dev) ...@@ -601,7 +601,8 @@ static void igmpv3_send_cr(struct in_device *in_dev)
} }
spin_unlock_bh(&pmc->lock); spin_unlock_bh(&pmc->lock);
} }
read_unlock(&in_dev->lock); read_unlock(&in_dev->mc_list_lock);
if (!skb) if (!skb)
return; return;
(void) igmpv3_sendpack(skb); (void) igmpv3_sendpack(skb);
...@@ -759,14 +760,14 @@ static void igmp_heard_report(struct in_device *in_dev, u32 group) ...@@ -759,14 +760,14 @@ static void igmp_heard_report(struct in_device *in_dev, u32 group)
if (group == IGMP_ALL_HOSTS) if (group == IGMP_ALL_HOSTS)
return; return;
read_lock(&in_dev->lock); read_lock(&in_dev->mc_list_lock);
for (im=in_dev->mc_list; im!=NULL; im=im->next) { for (im=in_dev->mc_list; im!=NULL; im=im->next) {
if (im->multiaddr == group) { if (im->multiaddr == group) {
igmp_stop_timer(im); igmp_stop_timer(im);
break; break;
} }
} }
read_unlock(&in_dev->lock); read_unlock(&in_dev->mc_list_lock);
} }
static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
...@@ -840,7 +841,7 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, ...@@ -840,7 +841,7 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
* - Use the igmp->igmp_code field as the maximum * - Use the igmp->igmp_code field as the maximum
* delay possible * delay possible
*/ */
read_lock(&in_dev->lock); read_lock(&in_dev->mc_list_lock);
for (im=in_dev->mc_list; im!=NULL; im=im->next) { for (im=in_dev->mc_list; im!=NULL; im=im->next) {
if (group && group != im->multiaddr) if (group && group != im->multiaddr)
continue; continue;
...@@ -856,7 +857,7 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, ...@@ -856,7 +857,7 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
spin_unlock_bh(&im->lock); spin_unlock_bh(&im->lock);
igmp_mod_timer(im, max_delay); igmp_mod_timer(im, max_delay);
} }
read_unlock(&in_dev->lock); read_unlock(&in_dev->mc_list_lock);
} }
int igmp_rcv(struct sk_buff *skb) int igmp_rcv(struct sk_buff *skb)
...@@ -982,10 +983,10 @@ static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im) ...@@ -982,10 +983,10 @@ static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im)
} }
spin_unlock_bh(&im->lock); spin_unlock_bh(&im->lock);
write_lock_bh(&in_dev->mc_lock); spin_lock_bh(&in_dev->mc_tomb_lock);
pmc->next = in_dev->mc_tomb; pmc->next = in_dev->mc_tomb;
in_dev->mc_tomb = pmc; in_dev->mc_tomb = pmc;
write_unlock_bh(&in_dev->mc_lock); spin_unlock_bh(&in_dev->mc_tomb_lock);
} }
static void igmpv3_del_delrec(struct in_device *in_dev, __u32 multiaddr) static void igmpv3_del_delrec(struct in_device *in_dev, __u32 multiaddr)
...@@ -993,7 +994,7 @@ static void igmpv3_del_delrec(struct in_device *in_dev, __u32 multiaddr) ...@@ -993,7 +994,7 @@ static void igmpv3_del_delrec(struct in_device *in_dev, __u32 multiaddr)
struct ip_mc_list *pmc, *pmc_prev; struct ip_mc_list *pmc, *pmc_prev;
struct ip_sf_list *psf, *psf_next; struct ip_sf_list *psf, *psf_next;
write_lock_bh(&in_dev->mc_lock); spin_lock_bh(&in_dev->mc_tomb_lock);
pmc_prev = NULL; pmc_prev = NULL;
for (pmc=in_dev->mc_tomb; pmc; pmc=pmc->next) { for (pmc=in_dev->mc_tomb; pmc; pmc=pmc->next) {
if (pmc->multiaddr == multiaddr) if (pmc->multiaddr == multiaddr)
...@@ -1006,7 +1007,7 @@ static void igmpv3_del_delrec(struct in_device *in_dev, __u32 multiaddr) ...@@ -1006,7 +1007,7 @@ static void igmpv3_del_delrec(struct in_device *in_dev, __u32 multiaddr)
else else
in_dev->mc_tomb = pmc->next; in_dev->mc_tomb = pmc->next;
} }
write_unlock_bh(&in_dev->mc_lock); spin_unlock_bh(&in_dev->mc_tomb_lock);
if (pmc) { if (pmc) {
for (psf=pmc->tomb; psf; psf=psf_next) { for (psf=pmc->tomb; psf; psf=psf_next) {
psf_next = psf->sf_next; psf_next = psf->sf_next;
...@@ -1021,10 +1022,10 @@ static void igmpv3_clear_delrec(struct in_device *in_dev) ...@@ -1021,10 +1022,10 @@ static void igmpv3_clear_delrec(struct in_device *in_dev)
{ {
struct ip_mc_list *pmc, *nextpmc; struct ip_mc_list *pmc, *nextpmc;
write_lock_bh(&in_dev->mc_lock); spin_lock_bh(&in_dev->mc_tomb_lock);
pmc = in_dev->mc_tomb; pmc = in_dev->mc_tomb;
in_dev->mc_tomb = NULL; in_dev->mc_tomb = NULL;
write_unlock_bh(&in_dev->mc_lock); spin_unlock_bh(&in_dev->mc_tomb_lock);
for (; pmc; pmc = nextpmc) { for (; pmc; pmc = nextpmc) {
nextpmc = pmc->next; nextpmc = pmc->next;
...@@ -1033,7 +1034,7 @@ static void igmpv3_clear_delrec(struct in_device *in_dev) ...@@ -1033,7 +1034,7 @@ static void igmpv3_clear_delrec(struct in_device *in_dev)
kfree(pmc); kfree(pmc);
} }
/* clear dead sources, too */ /* clear dead sources, too */
read_lock(&in_dev->lock); read_lock(&in_dev->mc_list_lock);
for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) { for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) {
struct ip_sf_list *psf, *psf_next; struct ip_sf_list *psf, *psf_next;
...@@ -1046,7 +1047,7 @@ static void igmpv3_clear_delrec(struct in_device *in_dev) ...@@ -1046,7 +1047,7 @@ static void igmpv3_clear_delrec(struct in_device *in_dev)
kfree(psf); kfree(psf);
} }
} }
read_unlock(&in_dev->lock); read_unlock(&in_dev->mc_list_lock);
} }
#endif #endif
...@@ -1167,10 +1168,10 @@ void ip_mc_inc_group(struct in_device *in_dev, u32 addr) ...@@ -1167,10 +1168,10 @@ void ip_mc_inc_group(struct in_device *in_dev, u32 addr)
im->gsquery = 0; im->gsquery = 0;
#endif #endif
im->loaded = 0; im->loaded = 0;
write_lock_bh(&in_dev->lock); write_lock_bh(&in_dev->mc_list_lock);
im->next=in_dev->mc_list; im->next=in_dev->mc_list;
in_dev->mc_list=im; in_dev->mc_list=im;
write_unlock_bh(&in_dev->lock); write_unlock_bh(&in_dev->mc_list_lock);
#ifdef CONFIG_IP_MULTICAST #ifdef CONFIG_IP_MULTICAST
igmpv3_del_delrec(in_dev, im->multiaddr); igmpv3_del_delrec(in_dev, im->multiaddr);
#endif #endif
...@@ -1194,9 +1195,9 @@ void ip_mc_dec_group(struct in_device *in_dev, u32 addr) ...@@ -1194,9 +1195,9 @@ void ip_mc_dec_group(struct in_device *in_dev, u32 addr)
for (ip=&in_dev->mc_list; (i=*ip)!=NULL; ip=&i->next) { for (ip=&in_dev->mc_list; (i=*ip)!=NULL; ip=&i->next) {
if (i->multiaddr==addr) { if (i->multiaddr==addr) {
if (--i->users == 0) { if (--i->users == 0) {
write_lock_bh(&in_dev->lock); write_lock_bh(&in_dev->mc_list_lock);
*ip = i->next; *ip = i->next;
write_unlock_bh(&in_dev->lock); write_unlock_bh(&in_dev->mc_list_lock);
igmp_group_dropped(i); igmp_group_dropped(i);
if (!in_dev->dead) if (!in_dev->dead)
...@@ -1251,7 +1252,8 @@ void ip_mc_init_dev(struct in_device *in_dev) ...@@ -1251,7 +1252,8 @@ void ip_mc_init_dev(struct in_device *in_dev)
in_dev->mr_qrv = IGMP_Unsolicited_Report_Count; in_dev->mr_qrv = IGMP_Unsolicited_Report_Count;
#endif #endif
in_dev->mc_lock = RW_LOCK_UNLOCKED; in_dev->mc_list_lock = RW_LOCK_UNLOCKED;
in_dev->mc_tomb_lock = SPIN_LOCK_UNLOCKED;
} }
/* Device going up */ /* Device going up */
...@@ -1281,17 +1283,17 @@ void ip_mc_destroy_dev(struct in_device *in_dev) ...@@ -1281,17 +1283,17 @@ void ip_mc_destroy_dev(struct in_device *in_dev)
/* Deactivate timers */ /* Deactivate timers */
ip_mc_down(in_dev); ip_mc_down(in_dev);
write_lock_bh(&in_dev->lock); write_lock_bh(&in_dev->mc_list_lock);
while ((i = in_dev->mc_list) != NULL) { while ((i = in_dev->mc_list) != NULL) {
in_dev->mc_list = i->next; in_dev->mc_list = i->next;
write_unlock_bh(&in_dev->lock); write_unlock_bh(&in_dev->mc_list_lock);
igmp_group_dropped(i); igmp_group_dropped(i);
ip_ma_put(i); ip_ma_put(i);
write_lock_bh(&in_dev->lock); write_lock_bh(&in_dev->mc_list_lock);
} }
write_unlock_bh(&in_dev->lock); write_unlock_bh(&in_dev->mc_list_lock);
} }
static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr) static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr)
...@@ -1391,18 +1393,18 @@ int ip_mc_del_src(struct in_device *in_dev, __u32 *pmca, int sfmode, ...@@ -1391,18 +1393,18 @@ int ip_mc_del_src(struct in_device *in_dev, __u32 *pmca, int sfmode,
if (!in_dev) if (!in_dev)
return -ENODEV; return -ENODEV;
read_lock(&in_dev->lock); read_lock(&in_dev->mc_list_lock);
for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) { for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) {
if (*pmca == pmc->multiaddr) if (*pmca == pmc->multiaddr)
break; break;
} }
if (!pmc) { if (!pmc) {
/* MCA not found?? bug */ /* MCA not found?? bug */
read_unlock(&in_dev->lock); read_unlock(&in_dev->mc_list_lock);
return -ESRCH; return -ESRCH;
} }
spin_lock_bh(&pmc->lock); spin_lock_bh(&pmc->lock);
read_unlock(&in_dev->lock); read_unlock(&in_dev->mc_list_lock);
#ifdef CONFIG_IP_MULTICAST #ifdef CONFIG_IP_MULTICAST
sf_markstate(pmc); sf_markstate(pmc);
#endif #endif
...@@ -1527,18 +1529,18 @@ int ip_mc_add_src(struct in_device *in_dev, __u32 *pmca, int sfmode, ...@@ -1527,18 +1529,18 @@ int ip_mc_add_src(struct in_device *in_dev, __u32 *pmca, int sfmode,
if (!in_dev) if (!in_dev)
return -ENODEV; return -ENODEV;
read_lock(&in_dev->lock); read_lock(&in_dev->mc_list_lock);
for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) { for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) {
if (*pmca == pmc->multiaddr) if (*pmca == pmc->multiaddr)
break; break;
} }
if (!pmc) { if (!pmc) {
/* MCA not found?? bug */ /* MCA not found?? bug */
read_unlock(&in_dev->lock); read_unlock(&in_dev->mc_list_lock);
return -ESRCH; return -ESRCH;
} }
spin_lock_bh(&pmc->lock); spin_lock_bh(&pmc->lock);
read_unlock(&in_dev->lock); read_unlock(&in_dev->mc_list_lock);
#ifdef CONFIG_IP_MULTICAST #ifdef CONFIG_IP_MULTICAST
sf_markstate(pmc); sf_markstate(pmc);
...@@ -2095,7 +2097,7 @@ int ip_check_mc(struct in_device *in_dev, u32 mc_addr, u32 src_addr, u16 proto) ...@@ -2095,7 +2097,7 @@ int ip_check_mc(struct in_device *in_dev, u32 mc_addr, u32 src_addr, u16 proto)
struct ip_sf_list *psf; struct ip_sf_list *psf;
int rv = 0; int rv = 0;
read_lock(&in_dev->lock); read_lock(&in_dev->mc_list_lock);
for (im=in_dev->mc_list; im; im=im->next) { for (im=in_dev->mc_list; im; im=im->next) {
if (im->multiaddr == mc_addr) if (im->multiaddr == mc_addr)
break; break;
...@@ -2117,7 +2119,7 @@ int ip_check_mc(struct in_device *in_dev, u32 mc_addr, u32 src_addr, u16 proto) ...@@ -2117,7 +2119,7 @@ int ip_check_mc(struct in_device *in_dev, u32 mc_addr, u32 src_addr, u16 proto)
} else } else
rv = 1; /* unspecified source; tentatively allow */ rv = 1; /* unspecified source; tentatively allow */
} }
read_unlock(&in_dev->lock); read_unlock(&in_dev->mc_list_lock);
return rv; return rv;
} }
...@@ -2141,13 +2143,13 @@ static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq) ...@@ -2141,13 +2143,13 @@ static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq)
in_dev = in_dev_get(state->dev); in_dev = in_dev_get(state->dev);
if (!in_dev) if (!in_dev)
continue; continue;
read_lock(&in_dev->lock); read_lock(&in_dev->mc_list_lock);
im = in_dev->mc_list; im = in_dev->mc_list;
if (im) { if (im) {
state->in_dev = in_dev; state->in_dev = in_dev;
break; break;
} }
read_unlock(&in_dev->lock); read_unlock(&in_dev->mc_list_lock);
in_dev_put(in_dev); in_dev_put(in_dev);
} }
return im; return im;
...@@ -2159,7 +2161,7 @@ static struct ip_mc_list *igmp_mc_get_next(struct seq_file *seq, struct ip_mc_li ...@@ -2159,7 +2161,7 @@ static struct ip_mc_list *igmp_mc_get_next(struct seq_file *seq, struct ip_mc_li
im = im->next; im = im->next;
while (!im) { while (!im) {
if (likely(state->in_dev != NULL)) { if (likely(state->in_dev != NULL)) {
read_unlock(&state->in_dev->lock); read_unlock(&state->in_dev->mc_list_lock);
in_dev_put(state->in_dev); in_dev_put(state->in_dev);
} }
state->dev = state->dev->next; state->dev = state->dev->next;
...@@ -2170,7 +2172,7 @@ static struct ip_mc_list *igmp_mc_get_next(struct seq_file *seq, struct ip_mc_li ...@@ -2170,7 +2172,7 @@ static struct ip_mc_list *igmp_mc_get_next(struct seq_file *seq, struct ip_mc_li
state->in_dev = in_dev_get(state->dev); state->in_dev = in_dev_get(state->dev);
if (!state->in_dev) if (!state->in_dev)
continue; continue;
read_lock(&state->in_dev->lock); read_lock(&state->in_dev->mc_list_lock);
im = state->in_dev->mc_list; im = state->in_dev->mc_list;
} }
return im; return im;
...@@ -2206,7 +2208,7 @@ static void igmp_mc_seq_stop(struct seq_file *seq, void *v) ...@@ -2206,7 +2208,7 @@ static void igmp_mc_seq_stop(struct seq_file *seq, void *v)
{ {
struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
if (likely(state->in_dev != NULL)) { if (likely(state->in_dev != NULL)) {
read_unlock(&state->in_dev->lock); read_unlock(&state->in_dev->mc_list_lock);
in_dev_put(state->in_dev); in_dev_put(state->in_dev);
state->in_dev = NULL; state->in_dev = NULL;
} }
...@@ -2304,7 +2306,7 @@ static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq) ...@@ -2304,7 +2306,7 @@ static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq)
idev = in_dev_get(state->dev); idev = in_dev_get(state->dev);
if (unlikely(idev == NULL)) if (unlikely(idev == NULL))
continue; continue;
read_lock_bh(&idev->lock); read_lock(&idev->mc_list_lock);
im = idev->mc_list; im = idev->mc_list;
if (likely(im != NULL)) { if (likely(im != NULL)) {
spin_lock_bh(&im->lock); spin_lock_bh(&im->lock);
...@@ -2316,7 +2318,7 @@ static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq) ...@@ -2316,7 +2318,7 @@ static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq)
} }
spin_unlock_bh(&im->lock); spin_unlock_bh(&im->lock);
} }
read_unlock_bh(&idev->lock); read_unlock(&idev->mc_list_lock);
in_dev_put(idev); in_dev_put(idev);
} }
return psf; return psf;
...@@ -2332,7 +2334,7 @@ static struct ip_sf_list *igmp_mcf_get_next(struct seq_file *seq, struct ip_sf_l ...@@ -2332,7 +2334,7 @@ static struct ip_sf_list *igmp_mcf_get_next(struct seq_file *seq, struct ip_sf_l
state->im = state->im->next; state->im = state->im->next;
while (!state->im) { while (!state->im) {
if (likely(state->idev != NULL)) { if (likely(state->idev != NULL)) {
read_unlock_bh(&state->idev->lock); read_unlock(&state->idev->mc_list_lock);
in_dev_put(state->idev); in_dev_put(state->idev);
} }
state->dev = state->dev->next; state->dev = state->dev->next;
...@@ -2343,7 +2345,7 @@ static struct ip_sf_list *igmp_mcf_get_next(struct seq_file *seq, struct ip_sf_l ...@@ -2343,7 +2345,7 @@ static struct ip_sf_list *igmp_mcf_get_next(struct seq_file *seq, struct ip_sf_l
state->idev = in_dev_get(state->dev); state->idev = in_dev_get(state->dev);
if (!state->idev) if (!state->idev)
continue; continue;
read_lock_bh(&state->idev->lock); read_lock(&state->idev->mc_list_lock);
state->im = state->idev->mc_list; state->im = state->idev->mc_list;
} }
if (!state->im) if (!state->im)
...@@ -2389,7 +2391,7 @@ static void igmp_mcf_seq_stop(struct seq_file *seq, void *v) ...@@ -2389,7 +2391,7 @@ static void igmp_mcf_seq_stop(struct seq_file *seq, void *v)
state->im = NULL; state->im = NULL;
} }
if (likely(state->idev != NULL)) { if (likely(state->idev != NULL)) {
read_unlock_bh(&state->idev->lock); read_unlock(&state->idev->mc_list_lock);
in_dev_put(state->idev); in_dev_put(state->idev);
state->idev = NULL; state->idev = NULL;
} }
......
/*
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. INET is implemented using the BSD Socket
* interface as the means of communication with the user level.
*
* Dumb Network Address Translation.
*
* Version: $Id: ip_nat_dumb.c,v 1.11 2000/12/13 18:31:48 davem Exp $
*
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Fixes:
* Rani Assaf : A zero checksum is a special case
* only in UDP
* Rani Assaf : Added ICMP messages rewriting
* Rani Assaf : Repaired wrong changes, made by ANK.
*
*
* NOTE: It is just working model of real NAT.
*/
#include <linux/config.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/icmp.h>
#include <linux/netdevice.h>
#include <net/sock.h>
#include <net/ip.h>
#include <net/icmp.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <net/checksum.h>
#include <linux/route.h>
#include <net/route.h>
#include <net/ip_fib.h>
int
ip_do_nat(struct sk_buff *skb)
{
struct rtable *rt = (struct rtable*)skb->dst;
struct iphdr *iph = skb->nh.iph;
u32 odaddr = iph->daddr;
u32 osaddr = iph->saddr;
u16 check;
IPCB(skb)->flags |= IPSKB_TRANSLATED;
/* Rewrite IP header */
iph->daddr = rt->rt_dst_map;
iph->saddr = rt->rt_src_map;
iph->check = 0;
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
/* If it is the first fragment, rewrite protocol headers */
if (!(iph->frag_off & htons(IP_OFFSET))) {
u16 *cksum;
switch(iph->protocol) {
case IPPROTO_TCP:
cksum = (u16*)&((struct tcphdr*)(((char*)iph) + (iph->ihl<<2)))->check;
if ((u8*)(cksum+1) > skb->tail)
goto truncated;
check = *cksum;
if (skb->ip_summed != CHECKSUM_HW)
check = ~check;
check = csum_tcpudp_magic(iph->saddr, iph->daddr, 0, 0, check);
check = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0, ~check);
if (skb->ip_summed == CHECKSUM_HW)
check = ~check;
*cksum = check;
break;
case IPPROTO_UDP:
cksum = (u16*)&((struct udphdr*)(((char*)iph) + (iph->ihl<<2)))->check;
if ((u8*)(cksum+1) > skb->tail)
goto truncated;
if ((check = *cksum) != 0) {
check = csum_tcpudp_magic(iph->saddr, iph->daddr, 0, 0, ~check);
check = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0, ~check);
*cksum = check ? : 0xFFFF;
}
break;
case IPPROTO_ICMP:
{
struct icmphdr *icmph = (struct icmphdr*)((char*)iph + (iph->ihl<<2));
struct iphdr *ciph;
u32 idaddr, isaddr;
int updated;
if ((icmph->type != ICMP_DEST_UNREACH) &&
(icmph->type != ICMP_TIME_EXCEEDED) &&
(icmph->type != ICMP_PARAMETERPROB))
break;
ciph = (struct iphdr *) (icmph + 1);
if ((u8*)(ciph+1) > skb->tail)
goto truncated;
isaddr = ciph->saddr;
idaddr = ciph->daddr;
updated = 0;
if (rt->rt_flags&RTCF_DNAT && ciph->saddr == odaddr) {
ciph->saddr = iph->daddr;
updated = 1;
}
if (rt->rt_flags&RTCF_SNAT) {
if (ciph->daddr != osaddr) {
struct fib_result res;
unsigned flags = 0;
struct flowi fl = {
.iif = skb->dev->ifindex,
.nl_u =
{ .ip4_u =
{ .daddr = ciph->saddr,
.saddr = ciph->daddr,
#ifdef CONFIG_IP_ROUTE_TOS
.tos = RT_TOS(ciph->tos)
#endif
} },
.proto = ciph->protocol };
/* Use fib_lookup() until we get our own
* hash table of NATed hosts -- Rani
*/
if (fib_lookup(&fl, &res) == 0) {
if (res.r) {
ciph->daddr = fib_rules_policy(ciph->daddr, &res, &flags);
if (ciph->daddr != idaddr)
updated = 1;
}
fib_res_put(&res);
}
} else {
ciph->daddr = iph->saddr;
updated = 1;
}
}
if (updated) {
cksum = &icmph->checksum;
/* Using tcpudp primitive. Why not? */
check = csum_tcpudp_magic(ciph->saddr, ciph->daddr, 0, 0, ~(*cksum));
*cksum = csum_tcpudp_magic(~isaddr, ~idaddr, 0, 0, ~check);
}
break;
}
default:
break;
}
}
return NET_RX_SUCCESS;
truncated:
/* should be return NET_RX_BAD; */
return -EINVAL;
}
...@@ -1390,13 +1390,7 @@ void ip_rt_get_source(u8 *addr, struct rtable *rt) ...@@ -1390,13 +1390,7 @@ void ip_rt_get_source(u8 *addr, struct rtable *rt)
if (rt->fl.iif == 0) if (rt->fl.iif == 0)
src = rt->rt_src; src = rt->rt_src;
else if (fib_lookup(&rt->fl, &res) == 0) { else if (fib_lookup(&rt->fl, &res) == 0) {
#ifdef CONFIG_IP_ROUTE_NAT src = FIB_RES_PREFSRC(res);
if (res.type == RTN_NAT)
src = inet_select_addr(rt->u.dst.dev, rt->rt_gateway,
RT_SCOPE_UNIVERSE);
else
#endif
src = FIB_RES_PREFSRC(res);
fib_res_put(&res); fib_res_put(&res);
} else } else
src = inet_select_addr(rt->u.dst.dev, rt->rt_gateway, src = inet_select_addr(rt->u.dst.dev, rt->rt_gateway,
...@@ -1500,10 +1494,6 @@ static int ip_route_input_mc(struct sk_buff *skb, u32 daddr, u32 saddr, ...@@ -1500,10 +1494,6 @@ static int ip_route_input_mc(struct sk_buff *skb, u32 daddr, u32 saddr,
#endif #endif
rth->fl.fl4_src = saddr; rth->fl.fl4_src = saddr;
rth->rt_src = saddr; rth->rt_src = saddr;
#ifdef CONFIG_IP_ROUTE_NAT
rth->rt_dst_map = daddr;
rth->rt_src_map = saddr;
#endif
#ifdef CONFIG_NET_CLS_ROUTE #ifdef CONFIG_NET_CLS_ROUTE
rth->u.dst.tclassid = itag; rth->u.dst.tclassid = itag;
#endif #endif
...@@ -1613,31 +1603,6 @@ static int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr, ...@@ -1613,31 +1603,6 @@ static int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
RT_CACHE_STAT_INC(in_slow_tot); RT_CACHE_STAT_INC(in_slow_tot);
#ifdef CONFIG_IP_ROUTE_NAT
/* Policy is applied before mapping destination,
but rerouting after map should be made with old source.
*/
if (1) {
u32 src_map = saddr;
if (res.r)
src_map = fib_rules_policy(saddr, &res, &flags);
if (res.type == RTN_NAT) {
fl.fl4_dst = fib_rules_map_destination(daddr, &res);
fib_res_put(&res);
free_res = 0;
if (fib_lookup(&fl, &res))
goto e_inval;
free_res = 1;
if (res.type != RTN_UNICAST)
goto e_inval;
flags |= RTCF_DNAT;
}
fl.fl4_src = src_map;
}
#endif
if (res.type == RTN_BROADCAST) if (res.type == RTN_BROADCAST)
goto brd_input; goto brd_input;
...@@ -1711,12 +1676,6 @@ static int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr, ...@@ -1711,12 +1676,6 @@ static int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
rth->fl.fl4_src = saddr; rth->fl.fl4_src = saddr;
rth->rt_src = saddr; rth->rt_src = saddr;
rth->rt_gateway = daddr; rth->rt_gateway = daddr;
#ifdef CONFIG_IP_ROUTE_NAT
rth->rt_src_map = fl.fl4_src;
rth->rt_dst_map = fl.fl4_dst;
if (flags&RTCF_DNAT)
rth->rt_gateway = fl.fl4_dst;
#endif
rth->rt_iif = rth->rt_iif =
rth->fl.iif = dev->ifindex; rth->fl.iif = dev->ifindex;
rth->u.dst.dev = out_dev->dev; rth->u.dst.dev = out_dev->dev;
...@@ -1779,10 +1738,6 @@ out: return err; ...@@ -1779,10 +1738,6 @@ out: return err;
#endif #endif
rth->fl.fl4_src = saddr; rth->fl.fl4_src = saddr;
rth->rt_src = saddr; rth->rt_src = saddr;
#ifdef CONFIG_IP_ROUTE_NAT
rth->rt_dst_map = fl.fl4_dst;
rth->rt_src_map = fl.fl4_src;
#endif
#ifdef CONFIG_NET_CLS_ROUTE #ifdef CONFIG_NET_CLS_ROUTE
rth->u.dst.tclassid = itag; rth->u.dst.tclassid = itag;
#endif #endif
...@@ -1903,7 +1858,7 @@ int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr, ...@@ -1903,7 +1858,7 @@ int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
if (MULTICAST(daddr)) { if (MULTICAST(daddr)) {
struct in_device *in_dev; struct in_device *in_dev;
read_lock(&inetdev_lock); rcu_read_lock();
if ((in_dev = __in_dev_get(dev)) != NULL) { if ((in_dev = __in_dev_get(dev)) != NULL) {
int our = ip_check_mc(in_dev, daddr, saddr, int our = ip_check_mc(in_dev, daddr, saddr,
skb->nh.iph->protocol); skb->nh.iph->protocol);
...@@ -1912,12 +1867,12 @@ int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr, ...@@ -1912,12 +1867,12 @@ int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
|| (!LOCAL_MCAST(daddr) && IN_DEV_MFORWARD(in_dev)) || (!LOCAL_MCAST(daddr) && IN_DEV_MFORWARD(in_dev))
#endif #endif
) { ) {
read_unlock(&inetdev_lock); rcu_read_unlock();
return ip_route_input_mc(skb, daddr, saddr, return ip_route_input_mc(skb, daddr, saddr,
tos, dev, our); tos, dev, our);
} }
} }
read_unlock(&inetdev_lock); rcu_read_unlock();
return -EINVAL; return -EINVAL;
} }
return ip_route_input_slow(skb, daddr, saddr, tos, dev); return ip_route_input_slow(skb, daddr, saddr, tos, dev);
...@@ -2075,9 +2030,6 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp) ...@@ -2075,9 +2030,6 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
} }
free_res = 1; free_res = 1;
if (res.type == RTN_NAT)
goto e_inval;
if (res.type == RTN_LOCAL) { if (res.type == RTN_LOCAL) {
if (!fl.fl4_src) if (!fl.fl4_src)
fl.fl4_src = fl.fl4_dst; fl.fl4_src = fl.fl4_dst;
...@@ -2167,10 +2119,6 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp) ...@@ -2167,10 +2119,6 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
#endif #endif
rth->rt_dst = fl.fl4_dst; rth->rt_dst = fl.fl4_dst;
rth->rt_src = fl.fl4_src; rth->rt_src = fl.fl4_src;
#ifdef CONFIG_IP_ROUTE_NAT
rth->rt_dst_map = fl.fl4_dst;
rth->rt_src_map = fl.fl4_src;
#endif
rth->rt_iif = oldflp->oif ? : dev_out->ifindex; rth->rt_iif = oldflp->oif ? : dev_out->ifindex;
rth->u.dst.dev = dev_out; rth->u.dst.dev = dev_out;
dev_hold(dev_out); dev_hold(dev_out);
......
...@@ -303,10 +303,10 @@ void irlan_eth_send_gratuitous_arp(struct net_device *dev) ...@@ -303,10 +303,10 @@ void irlan_eth_send_gratuitous_arp(struct net_device *dev)
*/ */
#ifdef CONFIG_INET #ifdef CONFIG_INET
IRDA_DEBUG(4, "IrLAN: Sending gratuitous ARP\n"); IRDA_DEBUG(4, "IrLAN: Sending gratuitous ARP\n");
in_dev = in_dev_get(dev); rcu_read_lock();
in_dev = __in_dev_get(dev);
if (in_dev == NULL) if (in_dev == NULL)
return; goto out;
read_lock(&in_dev->lock);
if (in_dev->ifa_list) if (in_dev->ifa_list)
arp_send(ARPOP_REQUEST, ETH_P_ARP, arp_send(ARPOP_REQUEST, ETH_P_ARP,
...@@ -314,8 +314,8 @@ void irlan_eth_send_gratuitous_arp(struct net_device *dev) ...@@ -314,8 +314,8 @@ void irlan_eth_send_gratuitous_arp(struct net_device *dev)
dev, dev,
in_dev->ifa_list->ifa_address, in_dev->ifa_list->ifa_address,
NULL, dev->dev_addr, NULL); NULL, dev->dev_addr, NULL);
read_unlock(&in_dev->lock); out:
in_dev_put(in_dev); rcu_read_unlock();
#endif /* CONFIG_INET */ #endif /* CONFIG_INET */
} }
......
...@@ -148,13 +148,12 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist, ...@@ -148,13 +148,12 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist,
struct in_ifaddr *ifa; struct in_ifaddr *ifa;
struct sctp_sockaddr_entry *addr; struct sctp_sockaddr_entry *addr;
read_lock(&inetdev_lock); rcu_read_lock();
if ((in_dev = __in_dev_get(dev)) == NULL) { if ((in_dev = __in_dev_get(dev)) == NULL) {
read_unlock(&inetdev_lock); rcu_read_unlock();
return; return;
} }
read_lock(&in_dev->lock);
for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
/* Add the address to the local list. */ /* Add the address to the local list. */
addr = t_new(struct sctp_sockaddr_entry, GFP_ATOMIC); addr = t_new(struct sctp_sockaddr_entry, GFP_ATOMIC);
...@@ -166,8 +165,7 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist, ...@@ -166,8 +165,7 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist,
} }
} }
read_unlock(&in_dev->lock); rcu_read_unlock();
read_unlock(&inetdev_lock);
} }
/* Extract our IP addresses from the system and stash them in the /* Extract our IP addresses from the system and stash them in the
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment