Commit d524ab44 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/davem/net-2.5

into home.osdl.org:/home/torvalds/v2.5/linux
parents 0aafd44a ba61d50f
...@@ -68,6 +68,8 @@ extern int ipv6_dev_get_saddr(struct net_device *dev, ...@@ -68,6 +68,8 @@ extern int ipv6_dev_get_saddr(struct net_device *dev,
struct in6_addr *saddr, struct in6_addr *saddr,
int onlink); int onlink);
extern int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *); extern int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *);
extern int ipv6_rcv_saddr_equal(const struct sock *sk,
const struct sock *sk2);
extern void addrconf_join_solict(struct net_device *dev, extern void addrconf_join_solict(struct net_device *dev,
struct in6_addr *addr); struct in6_addr *addr);
extern void addrconf_leave_solict(struct net_device *dev, extern void addrconf_leave_solict(struct net_device *dev,
......
...@@ -79,8 +79,7 @@ extern rwlock_t ip_ra_lock; ...@@ -79,8 +79,7 @@ extern rwlock_t ip_ra_lock;
extern void ip_mc_dropsocket(struct sock *); extern void ip_mc_dropsocket(struct sock *);
extern void ip_mc_dropdevice(struct net_device *dev); extern void ip_mc_dropdevice(struct net_device *dev);
extern int ip_mc_procinfo(char *, char **, off_t, int); extern int igmp_mc_proc_init(void);
extern int ip_mcf_procinfo(char *, char **, off_t, int);
/* /*
* Functions provided by ip.c * Functions provided by ip.c
......
...@@ -251,8 +251,21 @@ void br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source, ...@@ -251,8 +251,21 @@ void br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
write_lock_bh(&br->hash_lock); write_lock_bh(&br->hash_lock);
hlist_for_each(h, &br->hash[hash]) { hlist_for_each(h, &br->hash[hash]) {
fdb = hlist_entry(h, struct net_bridge_fdb_entry, hlist); fdb = hlist_entry(h, struct net_bridge_fdb_entry, hlist);
if (!fdb->is_local && if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) {
!memcmp(fdb->addr.addr, addr, ETH_ALEN)) { /* attempt to update an entry for a local interface */
if (unlikely(fdb->is_local)) {
if (is_local)
printk(KERN_INFO "%s: attempt to add"
" interface with same source address.\n",
source->dev->name);
else if (net_ratelimit())
printk(KERN_WARNING "%s: received packet with "
" own address as source address\n",
source->dev->name);
goto out;
}
if (likely(!fdb->is_static || is_local)) { if (likely(!fdb->is_static || is_local)) {
/* move to end of age list */ /* move to end of age list */
list_del(&fdb->age_list); list_del(&fdb->age_list);
......
...@@ -95,7 +95,7 @@ static struct net_bridge *new_nb(const char *name) ...@@ -95,7 +95,7 @@ static struct net_bridge *new_nb(const char *name)
br->bridge_id.prio[1] = 0x00; br->bridge_id.prio[1] = 0x00;
memset(br->bridge_id.addr, 0, ETH_ALEN); memset(br->bridge_id.addr, 0, ETH_ALEN);
br->stp_enabled = 1; br->stp_enabled = 0;
br->designated_root = br->bridge_id; br->designated_root = br->bridge_id;
br->root_path_cost = 0; br->root_path_cost = 0;
br->root_port = 0; br->root_port = 0;
......
...@@ -129,12 +129,15 @@ int br_handle_frame(struct sk_buff *skb) ...@@ -129,12 +129,15 @@ int br_handle_frame(struct sk_buff *skb)
if (p->br->stp_enabled && if (p->br->stp_enabled &&
!memcmp(dest, bridge_ula, 5) && !memcmp(dest, bridge_ula, 5) &&
!(dest[5] & 0xF0)) { !(dest[5] & 0xF0)) {
if (!dest[5]) if (!dest[5]) {
br_stp_handle_bpdu(skb); NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev,
goto err; NULL, br_stp_handle_bpdu);
rcu_read_unlock();
return 0;
}
} }
if (p->state == BR_STATE_FORWARDING) { else if (p->state == BR_STATE_FORWARDING) {
if (br_should_route_hook && br_should_route_hook(&skb)) { if (br_should_route_hook && br_should_route_hook(&skb)) {
rcu_read_unlock(); rcu_read_unlock();
return -1; return -1;
......
...@@ -206,7 +206,7 @@ extern void br_stp_set_path_cost(struct net_bridge_port *p, ...@@ -206,7 +206,7 @@ extern void br_stp_set_path_cost(struct net_bridge_port *p,
int path_cost); int path_cost);
/* br_stp_bpdu.c */ /* br_stp_bpdu.c */
extern void br_stp_handle_bpdu(struct sk_buff *skb); extern int br_stp_handle_bpdu(struct sk_buff *skb);
/* br_stp_timer.c */ /* br_stp_timer.c */
extern void br_stp_timer_init(struct net_bridge *br); extern void br_stp_timer_init(struct net_bridge *br);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/if_bridge.h> #include <linux/if_bridge.h>
#include <linux/netfilter_bridge.h>
#include "br_private.h" #include "br_private.h"
#include "br_private_stp.h" #include "br_private_stp.h"
...@@ -53,7 +54,8 @@ static void br_send_bpdu(struct net_bridge_port *p, unsigned char *data, int len ...@@ -53,7 +54,8 @@ static void br_send_bpdu(struct net_bridge_port *p, unsigned char *data, int len
memcpy(skb->nh.raw, data, length); memcpy(skb->nh.raw, data, length);
memset(skb->nh.raw + length, 0xa5, size - length - 2*ETH_ALEN - 2); memset(skb->nh.raw + length, 0xa5, size - length - 2*ETH_ALEN - 2);
dev_queue_xmit(skb); NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
dev_queue_xmit);
} }
static __inline__ void br_set_ticks(unsigned char *dest, int jiff) static __inline__ void br_set_ticks(unsigned char *dest, int jiff)
...@@ -130,67 +132,75 @@ void br_send_tcn_bpdu(struct net_bridge_port *p) ...@@ -130,67 +132,75 @@ void br_send_tcn_bpdu(struct net_bridge_port *p)
br_send_bpdu(p, buf, 7); br_send_bpdu(p, buf, 7);
} }
static unsigned char header[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00}; static const unsigned char header[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00};
/* NO locks */ /* NO locks */
void br_stp_handle_bpdu(struct sk_buff *skb) int br_stp_handle_bpdu(struct sk_buff *skb)
{ {
struct net_bridge_port *p = skb->dev->br_port;
struct net_bridge *br = p->br;
unsigned char *buf; unsigned char *buf;
struct net_bridge_port *p;
struct net_bridge *br;
buf = skb->mac.raw + 14; /* need at least the 802 and STP headers */
p = skb->dev->br_port; if (!pskb_may_pull(skb, sizeof(header)+1) ||
br = p->br; memcmp(skb->data, header, sizeof(header)))
goto err;
buf = skb_pull(skb, sizeof(header));
spin_lock_bh(&br->lock); spin_lock_bh(&br->lock);
if (p->state == BR_STATE_DISABLED if (p->state == BR_STATE_DISABLED
|| !(br->dev->flags & IFF_UP) || !(br->dev->flags & IFF_UP)
|| !br->stp_enabled || !br->stp_enabled)
|| memcmp(buf, header, 6))
goto out; goto out;
if (buf[6] == BPDU_TYPE_CONFIG) { if (buf[0] == BPDU_TYPE_CONFIG) {
struct br_config_bpdu bpdu; struct br_config_bpdu bpdu;
bpdu.topology_change = (buf[7] & 0x01) ? 1 : 0; if (!pskb_may_pull(skb, 32))
bpdu.topology_change_ack = (buf[7] & 0x80) ? 1 : 0; goto out;
bpdu.root.prio[0] = buf[8];
bpdu.root.prio[1] = buf[9]; buf = skb->data;
bpdu.root.addr[0] = buf[10]; bpdu.topology_change = (buf[1] & 0x01) ? 1 : 0;
bpdu.root.addr[1] = buf[11]; bpdu.topology_change_ack = (buf[1] & 0x80) ? 1 : 0;
bpdu.root.addr[2] = buf[12];
bpdu.root.addr[3] = buf[13]; bpdu.root.prio[0] = buf[2];
bpdu.root.addr[4] = buf[14]; bpdu.root.prio[1] = buf[3];
bpdu.root.addr[5] = buf[15]; bpdu.root.addr[0] = buf[4];
bpdu.root.addr[1] = buf[5];
bpdu.root.addr[2] = buf[6];
bpdu.root.addr[3] = buf[7];
bpdu.root.addr[4] = buf[8];
bpdu.root.addr[5] = buf[9];
bpdu.root_path_cost = bpdu.root_path_cost =
(buf[16] << 24) | (buf[10] << 24) |
(buf[17] << 16) | (buf[11] << 16) |
(buf[18] << 8) | (buf[12] << 8) |
buf[19]; buf[13];
bpdu.bridge_id.prio[0] = buf[20]; bpdu.bridge_id.prio[0] = buf[14];
bpdu.bridge_id.prio[1] = buf[21]; bpdu.bridge_id.prio[1] = buf[15];
bpdu.bridge_id.addr[0] = buf[22]; bpdu.bridge_id.addr[0] = buf[16];
bpdu.bridge_id.addr[1] = buf[23]; bpdu.bridge_id.addr[1] = buf[17];
bpdu.bridge_id.addr[2] = buf[24]; bpdu.bridge_id.addr[2] = buf[18];
bpdu.bridge_id.addr[3] = buf[25]; bpdu.bridge_id.addr[3] = buf[19];
bpdu.bridge_id.addr[4] = buf[26]; bpdu.bridge_id.addr[4] = buf[20];
bpdu.bridge_id.addr[5] = buf[27]; bpdu.bridge_id.addr[5] = buf[21];
bpdu.port_id = (buf[28] << 8) | buf[29]; bpdu.port_id = (buf[22] << 8) | buf[23];
bpdu.message_age = br_get_ticks(buf+30); bpdu.message_age = br_get_ticks(buf+24);
bpdu.max_age = br_get_ticks(buf+32); bpdu.max_age = br_get_ticks(buf+26);
bpdu.hello_time = br_get_ticks(buf+34); bpdu.hello_time = br_get_ticks(buf+28);
bpdu.forward_delay = br_get_ticks(buf+36); bpdu.forward_delay = br_get_ticks(buf+30);
br_received_config_bpdu(p, &bpdu); br_received_config_bpdu(p, &bpdu);
goto out;
} }
if (buf[6] == BPDU_TYPE_TCN) { else if (buf[0] == BPDU_TYPE_TCN) {
br_received_tcn_bpdu(p); br_received_tcn_bpdu(p);
goto out;
} }
out: out:
spin_unlock_bh(&br->lock); spin_unlock_bh(&br->lock);
err:
kfree(skb);
return 0;
} }
...@@ -99,7 +99,10 @@ ...@@ -99,7 +99,10 @@
#ifdef CONFIG_IP_MROUTE #ifdef CONFIG_IP_MROUTE
#include <linux/mroute.h> #include <linux/mroute.h>
#endif #endif
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#endif
#define IP_MAX_MEMBERSHIPS 20 #define IP_MAX_MEMBERSHIPS 20
...@@ -2090,127 +2093,343 @@ int ip_check_mc(struct in_device *in_dev, u32 mc_addr, u32 src_addr, u16 proto) ...@@ -2090,127 +2093,343 @@ int ip_check_mc(struct in_device *in_dev, u32 mc_addr, u32 src_addr, u16 proto)
return rv; return rv;
} }
#if defined(CONFIG_PROC_FS)
struct igmp_mc_iter_state {
struct net_device *dev;
struct in_device *in_dev;
};
#define igmp_mc_seq_private(seq) ((struct igmp_mc_iter_state *)&seq->private)
int ip_mc_procinfo(char *buffer, char **start, off_t offset, int length) static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq)
{ {
off_t pos=0, begin=0; struct ip_mc_list *im = NULL;
struct ip_mc_list *im; struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
int len=0;
struct net_device *dev;
len=sprintf(buffer,"Idx\tDevice : Count Querier\tGroup Users Timer\tReporter\n"); for (state->dev = dev_base, state->in_dev = NULL;
state->dev;
state->dev = state->dev->next) {
struct in_device *in_dev;
in_dev = in_dev_get(state->dev);
if (!in_dev)
continue;
read_lock(&in_dev->lock);
im = in_dev->mc_list;
if (im) {
state->in_dev = in_dev;
break;
}
read_unlock(&in_dev->lock);
}
return im;
}
static struct ip_mc_list *igmp_mc_get_next(struct seq_file *seq, struct ip_mc_list *im)
{
struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
im = im->next;
while (!im) {
if (likely(state->in_dev != NULL)) {
read_unlock(&state->in_dev->lock);
in_dev_put(state->in_dev);
}
state->dev = state->dev->next;
if (!state->dev) {
state->in_dev = NULL;
break;
}
state->in_dev = in_dev_get(state->dev);
if (!state->in_dev)
continue;
read_lock(&state->in_dev->lock);
im = state->in_dev->mc_list;
}
return im;
}
static struct ip_mc_list *igmp_mc_get_idx(struct seq_file *seq, loff_t pos)
{
struct ip_mc_list *im = igmp_mc_get_first(seq);
if (im)
while (pos && (im = igmp_mc_get_next(seq, im)) != NULL)
--pos;
return pos ? NULL : im;
}
static void *igmp_mc_seq_start(struct seq_file *seq, loff_t *pos)
{
read_lock(&dev_base_lock); read_lock(&dev_base_lock);
for(dev = dev_base; dev; dev = dev->next) { return *pos ? igmp_mc_get_idx(seq, *pos) : (void *)1;
struct in_device *in_dev = in_dev_get(dev); }
char *querier = "NONE";
if (in_dev == NULL) static void *igmp_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
continue; {
struct ip_mc_list *im;
if (v == (void *)1)
im = igmp_mc_get_first(seq);
else
im = igmp_mc_get_next(seq, v);
++*pos;
return im;
}
static void igmp_mc_seq_stop(struct seq_file *seq, void *v)
{
struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
if (likely(state->in_dev != NULL)) {
read_unlock(&state->in_dev->lock);
in_dev_put(state->in_dev);
}
read_unlock(&dev_base_lock);
}
static int igmp_mc_seq_show(struct seq_file *seq, void *v)
{
if (v == (void *)1)
seq_printf(seq,
"Idx\tDevice : Count Querier\tGroup Users Timer\tReporter\n");
else {
struct ip_mc_list *im = (struct ip_mc_list *)v;
struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
char *querier;
#ifdef CONFIG_IP_MULTICAST #ifdef CONFIG_IP_MULTICAST
querier = IGMP_V1_SEEN(in_dev) ? "V1" : "V2"; querier = IGMP_V1_SEEN(state->in_dev) ? "V1" : "V2";
#else
querier = "NONE";
#endif #endif
len+=sprintf(buffer+len,"%d\t%-10s: %5d %7s\n", if (state->in_dev->mc_list == im) {
dev->ifindex, dev->name, dev->mc_count, querier); seq_printf(seq, "%d\t%-10s: %5d %7s\n",
state->dev->ifindex, state->dev->name, state->dev->mc_count, querier);
}
read_lock(&in_dev->lock); seq_printf(seq,
for (im = in_dev->mc_list; im; im = im->next) {
len+=sprintf(buffer+len,
"\t\t\t\t%08lX %5d %d:%08lX\t\t%d\n", "\t\t\t\t%08lX %5d %d:%08lX\t\t%d\n",
im->multiaddr, im->users, im->multiaddr, im->users,
im->tm_running, im->timer.expires-jiffies, im->reporter); im->tm_running, im->timer.expires-jiffies, im->reporter);
pos=begin+len;
if(pos<offset)
{
len=0;
begin=pos;
} }
if(pos>offset+length) { return 0;
read_unlock(&in_dev->lock); }
in_dev_put(in_dev);
goto done; static struct seq_operations igmp_mc_seq_ops = {
.start = igmp_mc_seq_start,
.next = igmp_mc_seq_next,
.stop = igmp_mc_seq_stop,
.show = igmp_mc_seq_show,
};
static int igmp_mc_seq_open(struct inode *inode, struct file *file)
{
struct seq_file *seq;
int rc = -ENOMEM;
struct igmp_mc_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
if (!s)
goto out;
rc = seq_open(file, &igmp_mc_seq_ops);
if (rc)
goto out_kfree;
seq = file->private_data;
seq->private = s;
memset(s, 0, sizeof(*s));
out:
return rc;
out_kfree:
kfree(s);
goto out;
}
static struct file_operations igmp_mc_seq_fops = {
.owner = THIS_MODULE,
.open = igmp_mc_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_private,
};
struct igmp_mcf_iter_state {
struct net_device *dev;
struct in_device *idev;
struct ip_mc_list *im;
};
#define igmp_mcf_seq_private(seq) ((struct igmp_mcf_iter_state *)&seq->private)
static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq)
{
struct ip_sf_list *psf = NULL;
struct ip_mc_list *im = NULL;
struct igmp_mcf_iter_state *state = igmp_mcf_seq_private(seq);
for (state->dev = dev_base, state->idev = NULL, state->im = NULL;
state->dev;
state->dev = state->dev->next) {
struct in_device *idev;
idev = in_dev_get(state->dev);
if (unlikely(idev == NULL))
continue;
read_lock_bh(&idev->lock);
im = idev->mc_list;
if (likely(im != NULL)) {
spin_lock_bh(&im->lock);
psf = im->sources;
if (likely(psf != NULL)) {
state->im = im;
state->idev = idev;
break;
} }
spin_unlock_bh(&im->lock);
} }
read_unlock(&in_dev->lock); read_unlock_bh(&idev->lock);
in_dev_put(in_dev);
} }
done: return psf;
read_unlock(&dev_base_lock); }
*start=buffer+(offset-begin); static struct ip_sf_list *igmp_mcf_get_next(struct seq_file *seq, struct ip_sf_list *psf)
len-=(offset-begin); {
if(len>length) struct igmp_mcf_iter_state *state = igmp_mcf_seq_private(seq);
len=length;
if(len<0) psf = psf->sf_next;
len=0; while (!psf) {
return len; spin_unlock_bh(&state->im->lock);
state->im = state->im->next;
while (!state->im) {
if (likely(state->idev != NULL)) {
read_unlock_bh(&state->idev->lock);
in_dev_put(state->idev);
}
state->dev = state->dev->next;
if (!state->dev) {
state->idev = NULL;
goto out;
}
state->idev = in_dev_get(state->dev);
if (!state->idev)
continue;
read_lock_bh(&state->idev->lock);
state->im = state->idev->mc_list;
}
if (!state->im)
break;
spin_lock_bh(&state->im->lock);
psf = state->im->sources;
}
out:
return psf;
} }
int ip_mcf_procinfo(char *buffer, char **start, off_t offset, int length) static struct ip_sf_list *igmp_mcf_get_idx(struct seq_file *seq, loff_t pos)
{ {
off_t pos=0, begin=0; struct ip_sf_list *psf = igmp_mcf_get_first(seq);
int len=0; if (psf)
int first = 1; while (pos && (psf = igmp_mcf_get_next(seq, psf)) != NULL)
struct net_device *dev; --pos;
return pos ? NULL : psf;
}
static void *igmp_mcf_seq_start(struct seq_file *seq, loff_t *pos)
{
read_lock(&dev_base_lock); read_lock(&dev_base_lock);
for(dev=dev_base; dev; dev=dev->next) { return *pos ? igmp_mcf_get_idx(seq, *pos) : (void *)1;
struct in_device *in_dev = in_dev_get(dev); }
struct ip_mc_list *imc;
if (in_dev == NULL) static void *igmp_mcf_seq_next(struct seq_file *seq, void *v, loff_t *pos)
continue; {
struct ip_sf_list *psf;
if (v == (void *)1)
psf = igmp_mcf_get_first(seq);
else
psf = igmp_mcf_get_next(seq, v);
++*pos;
return psf;
}
read_lock(&in_dev->lock); static void igmp_mcf_seq_stop(struct seq_file *seq, void *v)
{
struct igmp_mcf_iter_state *state = igmp_mcf_seq_private(seq);
if (likely(state->im != NULL))
spin_unlock_bh(&state->im->lock);
if (likely(state->idev != NULL)) {
read_unlock_bh(&state->idev->lock);
in_dev_put(state->idev);
}
read_unlock(&dev_base_lock);
}
for (imc=in_dev->mc_list; imc; imc=imc->next) { static int igmp_mcf_seq_show(struct seq_file *seq, void *v)
struct ip_sf_list *psf; {
struct ip_sf_list *psf = (struct ip_sf_list *)v;
struct igmp_mcf_iter_state *state = igmp_mcf_seq_private(seq);
spin_lock_bh(&imc->lock); if (v == (void *)1) {
for (psf=imc->sources; psf; psf=psf->sf_next) { seq_printf(seq,
if (first) { "%3s %6s "
len += sprintf(buffer+len, "%3s %6s "
"%10s %10s %6s %6s\n", "Idx", "%10s %10s %6s %6s\n", "Idx",
"Device", "MCA", "SRC", "INC", "Device", "MCA",
"EXC"); "SRC", "INC", "EXC");
first = 0; } else {
} seq_printf(seq,
len += sprintf(buffer+len, "%3d %6.6s 0x%08x " "%3d %6.6s 0x%08x "
"0x%08x %6lu %6lu\n", dev->ifindex, "0x%08x %6lu %6lu\n",
dev->name, ntohl(imc->multiaddr), state->dev->ifindex, state->dev->name,
ntohl(state->im->multiaddr),
ntohl(psf->sf_inaddr), ntohl(psf->sf_inaddr),
psf->sf_count[MCAST_INCLUDE], psf->sf_count[MCAST_INCLUDE],
psf->sf_count[MCAST_EXCLUDE]); psf->sf_count[MCAST_EXCLUDE]);
pos=begin+len;
if(pos<offset)
{
len=0;
begin=pos;
}
if(pos>offset+length) {
spin_unlock_bh(&imc->lock);
read_unlock(&in_dev->lock);
in_dev_put(in_dev);
goto done;
} }
} return 0;
spin_unlock_bh(&imc->lock); }
}
read_unlock(&in_dev->lock); static struct seq_operations igmp_mcf_seq_ops = {
in_dev_put(in_dev); .start = igmp_mcf_seq_start,
} .next = igmp_mcf_seq_next,
done: .stop = igmp_mcf_seq_stop,
read_unlock(&dev_base_lock); .show = igmp_mcf_seq_show,
};
static int igmp_mcf_seq_open(struct inode *inode, struct file *file)
{
struct seq_file *seq;
int rc = -ENOMEM;
struct igmp_mcf_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
if (!s)
goto out;
rc = seq_open(file, &igmp_mcf_seq_ops);
if (rc)
goto out_kfree;
seq = file->private_data;
seq->private = s;
memset(s, 0, sizeof(*s));
out:
return rc;
out_kfree:
kfree(s);
goto out;
}
static struct file_operations igmp_mcf_seq_fops = {
.owner = THIS_MODULE,
.open = igmp_mcf_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_private,
};
int __init igmp_mc_proc_init(void)
{
struct proc_dir_entry *p;
p = create_proc_entry("igmp", S_IRUGO, proc_net);
if (p)
p->proc_fops = &igmp_mc_seq_fops;
*start=buffer+(offset-begin); p = create_proc_entry("mcfilter", S_IRUGO, proc_net);
len-=(offset-begin); if (p)
if(len>length) p->proc_fops = &igmp_mcf_seq_fops;
len=length; return 0;
if(len<0)
len=0;
return len;
} }
#endif
...@@ -1314,7 +1314,6 @@ void __init ip_init(void) ...@@ -1314,7 +1314,6 @@ void __init ip_init(void)
inet_initpeers(); inet_initpeers();
#ifdef CONFIG_IP_MULTICAST #ifdef CONFIG_IP_MULTICAST
proc_net_create("igmp", 0, ip_mc_procinfo); igmp_mc_proc_init();
#endif #endif
proc_net_create("mcfilter", 0, ip_mcf_procinfo);
} }
...@@ -801,7 +801,24 @@ static struct seq_operations raw_seq_ops = { ...@@ -801,7 +801,24 @@ static struct seq_operations raw_seq_ops = {
static int raw_seq_open(struct inode *inode, struct file *file) static int raw_seq_open(struct inode *inode, struct file *file)
{ {
return seq_open(file, &raw_seq_ops); struct seq_file *seq;
int rc = -ENOMEM;
struct raw_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
if (!s)
goto out;
rc = seq_open(file, &raw_seq_ops);
if (rc)
goto out_kfree;
seq = file->private_data;
seq->private = s;
memset(s, 0, sizeof(*s));
out:
return rc;
out_kfree:
kfree(s);
goto out;
} }
static struct file_operations raw_seq_fops = { static struct file_operations raw_seq_fops = {
...@@ -809,7 +826,7 @@ static struct file_operations raw_seq_fops = { ...@@ -809,7 +826,7 @@ static struct file_operations raw_seq_fops = {
.open = raw_seq_open, .open = raw_seq_open,
.read = seq_read, .read = seq_read,
.llseek = seq_lseek, .llseek = seq_lseek,
.release = seq_release, .release = seq_release_private,
}; };
int __init raw_proc_init(void) int __init raw_proc_init(void)
......
...@@ -66,6 +66,7 @@ ...@@ -66,6 +66,7 @@
#include <net/ndisc.h> #include <net/ndisc.h>
#include <net/ip6_route.h> #include <net/ip6_route.h>
#include <net/addrconf.h> #include <net/addrconf.h>
#include <net/tcp.h>
#include <net/ip.h> #include <net/ip.h>
#include <linux/if_tunnel.h> #include <linux/if_tunnel.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
...@@ -701,7 +702,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i ...@@ -701,7 +702,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i
ift = ipv6_count_addresses(idev) < IPV6_MAX_ADDRESSES ? ift = ipv6_count_addresses(idev) < IPV6_MAX_ADDRESSES ?
ipv6_add_addr(idev, &addr, tmp_plen, ipv6_add_addr(idev, &addr, tmp_plen,
ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, IFA_F_TEMPORARY) : 0; ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, IFA_F_TEMPORARY) : 0;
if (IS_ERR(ift)) { if (!ift || IS_ERR(ift)) {
in6_dev_put(idev); in6_dev_put(idev);
in6_ifa_put(ifp); in6_ifa_put(ifp);
printk(KERN_INFO printk(KERN_INFO
...@@ -969,6 +970,43 @@ struct inet6_ifaddr * ipv6_get_ifaddr(struct in6_addr *addr, struct net_device * ...@@ -969,6 +970,43 @@ struct inet6_ifaddr * ipv6_get_ifaddr(struct in6_addr *addr, struct net_device *
return ifp; return ifp;
} }
int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2)
{
struct ipv6_pinfo *np = inet6_sk(sk);
int addr_type = ipv6_addr_type(&np->rcv_saddr);
if (!inet_sk(sk2)->rcv_saddr && !ipv6_only_sock(sk))
return 1;
if (sk2->sk_family == AF_INET6 &&
ipv6_addr_any(&inet6_sk(sk2)->rcv_saddr) &&
!(ipv6_only_sock(sk2) && addr_type == IPV6_ADDR_MAPPED))
return 1;
if (addr_type == IPV6_ADDR_ANY &&
(!ipv6_only_sock(sk) ||
!(sk2->sk_family == AF_INET6 ?
(ipv6_addr_type(&inet6_sk(sk2)->rcv_saddr) == IPV6_ADDR_MAPPED) :
1)))
return 1;
if (sk2->sk_family == AF_INET6 &&
!ipv6_addr_cmp(&np->rcv_saddr,
(sk2->sk_state != TCP_TIME_WAIT ?
&inet6_sk(sk2)->rcv_saddr :
&tcptw_sk(sk)->tw_v6_rcv_saddr)))
return 1;
if (addr_type == IPV6_ADDR_MAPPED &&
!ipv6_only_sock(sk2) &&
(!inet_sk(sk2)->rcv_saddr ||
!inet_sk(sk)->rcv_saddr ||
inet_sk(sk)->rcv_saddr == inet_sk(sk2)->rcv_saddr))
return 1;
return 0;
}
/* Gets referenced address, destroys ifaddr */ /* Gets referenced address, destroys ifaddr */
void addrconf_dad_failure(struct inet6_ifaddr *ifp) void addrconf_dad_failure(struct inet6_ifaddr *ifp)
...@@ -1372,7 +1410,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) ...@@ -1372,7 +1410,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len, ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len,
addr_type&IPV6_ADDR_SCOPE_MASK, 0); addr_type&IPV6_ADDR_SCOPE_MASK, 0);
if (IS_ERR(ifp)) { if (!ifp || IS_ERR(ifp)) {
in6_dev_put(in6_dev); in6_dev_put(in6_dev);
return; return;
} }
......
...@@ -85,7 +85,8 @@ extern int udp6_proc_init(void); ...@@ -85,7 +85,8 @@ extern int udp6_proc_init(void);
extern void udp6_proc_exit(void); extern void udp6_proc_exit(void);
extern int ipv6_misc_proc_init(void); extern int ipv6_misc_proc_init(void);
extern void ipv6_misc_proc_exit(void); extern void ipv6_misc_proc_exit(void);
extern int anycast6_get_info(char *, char **, off_t, int); extern int ac6_proc_init(void);
extern void ac6_proc_exit(void);
extern int if6_proc_init(void); extern int if6_proc_init(void);
extern void if6_proc_exit(void); extern void if6_proc_exit(void);
#endif #endif
...@@ -799,7 +800,7 @@ static int __init inet6_init(void) ...@@ -799,7 +800,7 @@ static int __init inet6_init(void)
if (ipv6_misc_proc_init()) if (ipv6_misc_proc_init())
goto proc_misc6_fail; goto proc_misc6_fail;
if (!proc_net_create("anycast6", 0, anycast6_get_info)) if (ac6_proc_init())
goto proc_anycast6_fail; goto proc_anycast6_fail;
if (if6_proc_init()) if (if6_proc_init())
goto proc_if6_fail; goto proc_if6_fail;
...@@ -825,7 +826,7 @@ static int __init inet6_init(void) ...@@ -825,7 +826,7 @@ static int __init inet6_init(void)
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
proc_if6_fail: proc_if6_fail:
proc_net_remove("anycast6"); ac6_proc_exit();
proc_anycast6_fail: proc_anycast6_fail:
ipv6_misc_proc_exit(); ipv6_misc_proc_exit();
proc_misc6_fail: proc_misc6_fail:
...@@ -863,7 +864,7 @@ static void inet6_exit(void) ...@@ -863,7 +864,7 @@ static void inet6_exit(void)
sock_unregister(PF_INET6); sock_unregister(PF_INET6);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
if6_proc_exit(); if6_proc_exit();
proc_net_remove("anycast6"); ac6_proc_exit();
ipv6_misc_proc_exit(); ipv6_misc_proc_exit();
udp6_proc_exit(); udp6_proc_exit();
tcp6_proc_exit(); tcp6_proc_exit();
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/route.h> #include <linux/route.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/snmp.h> #include <net/snmp.h>
...@@ -435,56 +436,159 @@ int ipv6_chk_acast_addr(struct net_device *dev, struct in6_addr *addr) ...@@ -435,56 +436,159 @@ int ipv6_chk_acast_addr(struct net_device *dev, struct in6_addr *addr)
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
int anycast6_get_info(char *buffer, char **start, off_t offset, int length) struct ac6_iter_state {
{
off_t pos=0, begin=0;
struct ifacaddr6 *im;
int len=0;
struct net_device *dev; struct net_device *dev;
read_lock(&dev_base_lock);
for (dev = dev_base; dev; dev = dev->next) {
struct inet6_dev *idev; struct inet6_dev *idev;
};
if ((idev = in6_dev_get(dev)) == NULL) #define ac6_seq_private(seq) ((struct ac6_iter_state *)&seq->private)
continue;
read_lock_bh(&idev->lock);
for (im = idev->ac_list; im; im = im->aca_next) {
int i;
len += sprintf(buffer+len,"%-4d %-15s ", dev->ifindex, dev->name);
for (i=0; i<16; i++) static inline struct ifacaddr6 *ac6_get_first(struct seq_file *seq)
len += sprintf(buffer+len, "%02x", im->aca_addr.s6_addr[i]); {
struct ifacaddr6 *im = NULL;
len += sprintf(buffer+len, " %5d\n", im->aca_users); struct ac6_iter_state *state = ac6_seq_private(seq);
pos=begin+len; for (state->dev = dev_base, state->idev = NULL;
if (pos < offset) { state->dev;
len=0; state->dev = state->dev->next) {
begin=pos; struct inet6_dev *idev;
idev = in6_dev_get(state->dev);
if (!idev)
continue;
read_lock_bh(&idev->lock);
im = idev->ac_list;
if (im) {
state->idev = idev;
break;
} }
if (pos > offset+length) {
read_unlock_bh(&idev->lock); read_unlock_bh(&idev->lock);
in6_dev_put(idev);
goto done;
} }
return im;
}
static struct ifacaddr6 *ac6_get_next(struct seq_file *seq, struct ifacaddr6 *im)
{
struct ac6_iter_state *state = ac6_seq_private(seq);
im = im->aca_next;
while (!im) {
if (likely(state->idev != NULL)) {
read_unlock_bh(&state->idev->lock);
in6_dev_put(state->idev);
} }
read_unlock_bh(&idev->lock); state->dev = state->dev->next;
in6_dev_put(idev); if (!state->dev) {
state->idev = NULL;
break;
}
state->idev = in6_dev_get(state->dev);
if (!state->idev)
continue;
read_lock_bh(&state->idev->lock);
im = state->idev->ac_list;
} }
return im;
}
done: static struct ifacaddr6 *ac6_get_idx(struct seq_file *seq, loff_t pos)
{
struct ifacaddr6 *im = ac6_get_first(seq);
if (im)
while (pos && (im = ac6_get_next(seq, im)) != NULL)
--pos;
return pos ? NULL : im;
}
static void *ac6_seq_start(struct seq_file *seq, loff_t *pos)
{
read_lock(&dev_base_lock);
return *pos ? ac6_get_idx(seq, *pos) : ac6_get_first(seq);
}
static void *ac6_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
struct ifacaddr6 *im;
im = ac6_get_next(seq, v);
++*pos;
return im;
}
static void ac6_seq_stop(struct seq_file *seq, void *v)
{
struct ac6_iter_state *state = ac6_seq_private(seq);
if (likely(state->idev != NULL)) {
read_unlock_bh(&state->idev->lock);
in6_dev_put(state->idev);
}
read_unlock(&dev_base_lock); read_unlock(&dev_base_lock);
}
*start=buffer+(offset-begin); static int ac6_seq_show(struct seq_file *seq, void *v)
len-=(offset-begin); {
if(len>length) struct ifacaddr6 *im = (struct ifacaddr6 *)v;
len=length; struct ac6_iter_state *state = ac6_seq_private(seq);
if (len<0)
len=0; seq_printf(seq,
return len; "%-4d %-15s "
"%04x%04x%04x%04x%04x%04x%04x%04x "
"%5d\n",
state->dev->ifindex, state->dev->name,
NIP6(im->aca_addr),
im->aca_users);
return 0;
} }
static struct seq_operations ac6_seq_ops = {
.start = ac6_seq_start,
.next = ac6_seq_next,
.stop = ac6_seq_stop,
.show = ac6_seq_show,
};
static int ac6_seq_open(struct inode *inode, struct file *file)
{
struct seq_file *seq;
int rc = -ENOMEM;
struct ac6_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
if (!s)
goto out;
rc = seq_open(file, &ac6_seq_ops);
if (rc)
goto out_kfree;
seq = file->private_data;
seq->private = s;
memset(s, 0, sizeof(*s));
out:
return rc;
out_kfree:
kfree(s);
goto out;
}
static struct file_operations ac6_seq_fops = {
.owner = THIS_MODULE,
.open = ac6_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_private,
};
int __init ac6_proc_init(void)
{
struct proc_dir_entry *p;
p = create_proc_entry("anycast6", S_IRUGO, proc_net);
if (p)
p->proc_fops = &ac6_seq_fops;
return 0;
}
void ac6_proc_exit(void)
{
proc_net_remove("anycast6");
}
#endif #endif
...@@ -657,7 +657,25 @@ static struct seq_operations ip6fl_seq_ops = { ...@@ -657,7 +657,25 @@ static struct seq_operations ip6fl_seq_ops = {
static int ip6fl_seq_open(struct inode *inode, struct file *file) static int ip6fl_seq_open(struct inode *inode, struct file *file)
{ {
return seq_open(file, &ip6fl_seq_ops); struct seq_file *seq;
int rc = -ENOMEM;
struct ip6fl_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
if (!s)
goto out;
rc = seq_open(file, &ip6fl_seq_ops);
if (rc)
goto out_kfree;
seq = file->private_data;
seq->private = s;
memset(s, 0, sizeof(*s));
out:
return rc;
out_kfree:
kfree(s);
goto out;
} }
static struct file_operations ip6fl_seq_fops = { static struct file_operations ip6fl_seq_fops = {
...@@ -665,7 +683,7 @@ static struct file_operations ip6fl_seq_fops = { ...@@ -665,7 +683,7 @@ static struct file_operations ip6fl_seq_fops = {
.open = ip6fl_seq_open, .open = ip6fl_seq_open,
.read = seq_read, .read = seq_read,
.llseek = seq_lseek, .llseek = seq_lseek,
.release = seq_release, .release = seq_release_private,
}; };
#endif #endif
......
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include <linux/route.h> #include <linux/route.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/snmp.h> #include <net/snmp.h>
...@@ -2039,138 +2040,317 @@ void ipv6_mc_destroy_dev(struct inet6_dev *idev) ...@@ -2039,138 +2040,317 @@ void ipv6_mc_destroy_dev(struct inet6_dev *idev)
} }
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
static int igmp6_read_proc(char *buffer, char **start, off_t offset, struct igmp6_mc_iter_state {
int length, int *eof, void *data)
{
off_t pos=0, begin=0;
struct ifmcaddr6 *im;
int len=0;
struct net_device *dev; struct net_device *dev;
struct inet6_dev *idev;
};
read_lock(&dev_base_lock); #define igmp6_mc_seq_private(seq) ((struct igmp6_mc_iter_state *)&seq->private)
for (dev = dev_base; dev; dev = dev->next) {
static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq)
{
struct ifmcaddr6 *im = NULL;
struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);
for (state->dev = dev_base, state->idev = NULL;
state->dev;
state->dev = state->dev->next) {
struct inet6_dev *idev; struct inet6_dev *idev;
idev = in6_dev_get(state->dev);
if (!idev)
continue;
read_lock_bh(&idev->lock);
im = idev->mc_list;
if (im) {
state->idev = idev;
break;
}
read_unlock_bh(&idev->lock);
}
return im;
}
static struct ifmcaddr6 *igmp6_mc_get_next(struct seq_file *seq, struct ifmcaddr6 *im)
{
struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);
if ((idev = in6_dev_get(dev)) == NULL) im = im->next;
while (!im) {
if (likely(state->idev != NULL)) {
read_unlock_bh(&state->idev->lock);
in6_dev_put(state->idev);
}
state->dev = state->dev->next;
if (!state->dev) {
state->idev = NULL;
break;
}
state->idev = in6_dev_get(state->dev);
if (!state->idev)
continue; continue;
read_lock_bh(&state->idev->lock);
im = state->idev->mc_list;
}
return im;
}
read_lock_bh(&idev->lock); static struct ifmcaddr6 *igmp6_mc_get_idx(struct seq_file *seq, loff_t pos)
for (im = idev->mc_list; im; im = im->next) { {
int i; struct ifmcaddr6 *im = igmp6_mc_get_first(seq);
if (im)
while (pos && (im = igmp6_mc_get_next(seq, im)) != NULL)
--pos;
return pos ? NULL : im;
}
len += sprintf(buffer+len,"%-4d %-15s ", dev->ifindex, dev->name); static void *igmp6_mc_seq_start(struct seq_file *seq, loff_t *pos)
{
read_lock(&dev_base_lock);
return *pos ? igmp6_mc_get_idx(seq, *pos) : igmp6_mc_get_first(seq);
}
for (i=0; i<16; i++) static void *igmp6_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
len += sprintf(buffer+len, "%02x", im->mca_addr.s6_addr[i]); {
struct ifmcaddr6 *im;
im = igmp6_mc_get_next(seq, v);
++*pos;
return im;
}
len+=sprintf(buffer+len, static void igmp6_mc_seq_stop(struct seq_file *seq, void *v)
" %5d %08X %ld\n", {
im->mca_users, struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);
im->mca_flags, if (likely(state->idev != NULL)) {
read_unlock_bh(&state->idev->lock);
in6_dev_put(state->idev);
}
read_unlock(&dev_base_lock);
}
static int igmp6_mc_seq_show(struct seq_file *seq, void *v)
{
struct ifmcaddr6 *im = (struct ifmcaddr6 *)v;
struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);
seq_printf(seq,
"%-4d %-15s %04x%04x%04x%04x%04x%04x%04x%04x %5d %08X %ld\n",
state->dev->ifindex, state->dev->name,
NIP6(im->mca_addr),
im->mca_users, im->mca_flags,
(im->mca_flags&MAF_TIMER_RUNNING) ? im->mca_timer.expires-jiffies : 0); (im->mca_flags&MAF_TIMER_RUNNING) ? im->mca_timer.expires-jiffies : 0);
return 0;
}
pos=begin+len; static struct seq_operations igmp6_mc_seq_ops = {
if (pos < offset) { .start = igmp6_mc_seq_start,
len=0; .next = igmp6_mc_seq_next,
begin=pos; .stop = igmp6_mc_seq_stop,
} .show = igmp6_mc_seq_show,
if (pos > offset+length) { };
read_unlock_bh(&idev->lock);
in6_dev_put(idev); static int igmp6_mc_seq_open(struct inode *inode, struct file *file)
goto done; {
struct seq_file *seq;
int rc = -ENOMEM;
struct igmp6_mc_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
if (!s)
goto out;
rc = seq_open(file, &igmp6_mc_seq_ops);
if (rc)
goto out_kfree;
seq = file->private_data;
seq->private = s;
memset(s, 0, sizeof(*s));
out:
return rc;
out_kfree:
kfree(s);
goto out;
}
static struct file_operations igmp6_mc_seq_fops = {
.owner = THIS_MODULE,
.open = igmp6_mc_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_private,
};
struct igmp6_mcf_iter_state {
struct net_device *dev;
struct inet6_dev *idev;
struct ifmcaddr6 *im;
};
#define igmp6_mcf_seq_private(seq) ((struct igmp6_mcf_iter_state *)&seq->private)
static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq)
{
struct ip6_sf_list *psf = NULL;
struct ifmcaddr6 *im = NULL;
struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq);
for (state->dev = dev_base, state->idev = NULL, state->im = NULL;
state->dev;
state->dev = state->dev->next) {
struct inet6_dev *idev;
idev = in6_dev_get(state->dev);
if (unlikely(idev == NULL))
continue;
read_lock_bh(&idev->lock);
im = idev->mc_list;
if (likely(im != NULL)) {
spin_lock_bh(&im->mca_lock);
psf = im->mca_sources;
if (likely(psf != NULL)) {
state->im = im;
state->idev = idev;
break;
} }
spin_unlock_bh(&im->mca_lock);
} }
read_unlock_bh(&idev->lock); read_unlock_bh(&idev->lock);
in6_dev_put(idev);
} }
*eof = 1; return psf;
}
done:
read_unlock(&dev_base_lock);
*start=buffer+(offset-begin); static struct ip6_sf_list *igmp6_mcf_get_next(struct seq_file *seq, struct ip6_sf_list *psf)
len-=(offset-begin); {
if(len>length) struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq);
len=length;
if (len<0) psf = psf->sf_next;
len=0; while (!psf) {
return len; spin_unlock_bh(&state->im->mca_lock);
state->im = state->im->next;
while (!state->im) {
if (likely(state->idev != NULL)) {
read_unlock_bh(&state->idev->lock);
in6_dev_put(state->idev);
}
state->dev = state->dev->next;
if (!state->dev) {
state->idev = NULL;
goto out;
}
state->idev = in6_dev_get(state->dev);
if (!state->idev)
continue;
read_lock_bh(&state->idev->lock);
state->im = state->idev->mc_list;
}
if (!state->im)
break;
spin_lock_bh(&state->im->mca_lock);
psf = state->im->mca_sources;
}
out:
return psf;
} }
static int ip6_mcf_read_proc(char *buffer, char **start, off_t offset, static struct ip6_sf_list *igmp6_mcf_get_idx(struct seq_file *seq, loff_t pos)
int length, int *eof, void *data)
{ {
off_t pos=0, begin=0; struct ip6_sf_list *psf = igmp6_mcf_get_first(seq);
int len=0; if (psf)
int first=1; while (pos && (psf = igmp6_mcf_get_next(seq, psf)) != NULL)
struct net_device *dev; --pos;
return pos ? NULL : psf;
}
static void *igmp6_mcf_seq_start(struct seq_file *seq, loff_t *pos)
{
read_lock(&dev_base_lock); read_lock(&dev_base_lock);
for (dev=dev_base; dev; dev=dev->next) { return *pos ? igmp6_mcf_get_idx(seq, *pos) : (void *)1;
struct inet6_dev *idev = in6_dev_get(dev); }
struct ifmcaddr6 *imc;
if (idev == NULL) static void *igmp6_mcf_seq_next(struct seq_file *seq, void *v, loff_t *pos)
continue; {
struct ip6_sf_list *psf;
if (v == (void *)1)
psf = igmp6_mcf_get_first(seq);
else
psf = igmp6_mcf_get_next(seq, v);
++*pos;
return psf;
}
read_lock_bh(&idev->lock); static void igmp6_mcf_seq_stop(struct seq_file *seq, void *v)
{
struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq);
if (likely(state->im != NULL))
spin_unlock_bh(&state->im->mca_lock);
if (likely(state->idev != NULL)) {
read_unlock_bh(&state->idev->lock);
in6_dev_put(state->idev);
}
read_unlock(&dev_base_lock);
}
for (imc=idev->mc_list; imc; imc=imc->next) { static int igmp6_mcf_seq_show(struct seq_file *seq, void *v)
struct ip6_sf_list *psf; {
unsigned long i; struct ip6_sf_list *psf = (struct ip6_sf_list *)v;
struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq);
spin_lock_bh(&imc->mca_lock); if (v == (void *)1) {
for (psf=imc->mca_sources; psf; psf=psf->sf_next) { seq_printf(seq,
if (first) { "%3s %6s "
len += sprintf(buffer+len, "%3s %6s "
"%32s %32s %6s %6s\n", "Idx", "%32s %32s %6s %6s\n", "Idx",
"Device", "Multicast Address", "Device", "Multicast Address",
"Source Address", "INC", "EXC"); "Source Address", "INC", "EXC");
first = 0; } else {
} seq_printf(seq,
len += sprintf(buffer+len,"%3d %6.6s ", "%3d %6.6s "
dev->ifindex, dev->name); "%04x%04x%04x%04x%04x%04x%04x%04x "
"%04x%04x%04x%04x%04x%04x%04x%04x "
for (i=0; i<16; i++) "%6lu %6lu\n",
len += sprintf(buffer+len, "%02x", state->dev->ifindex, state->dev->name,
imc->mca_addr.s6_addr[i]); NIP6(state->im->mca_addr),
buffer[len++] = ' '; NIP6(psf->sf_addr),
for (i=0; i<16; i++)
len += sprintf(buffer+len, "%02x",
psf->sf_addr.s6_addr[i]);
len += sprintf(buffer+len, " %6lu %6lu\n",
psf->sf_count[MCAST_INCLUDE], psf->sf_count[MCAST_INCLUDE],
psf->sf_count[MCAST_EXCLUDE]); psf->sf_count[MCAST_EXCLUDE]);
pos = begin+len;
if (pos < offset) {
len=0;
begin=pos;
} }
if (pos > offset+length) { return 0;
spin_unlock_bh(&imc->mca_lock); }
read_unlock_bh(&idev->lock);
in6_dev_put(idev);
goto done;
}
}
spin_unlock_bh(&imc->mca_lock);
}
read_unlock_bh(&idev->lock);
in6_dev_put(idev);
}
*eof = 1;
done: static struct seq_operations igmp6_mcf_seq_ops = {
read_unlock(&dev_base_lock); .start = igmp6_mcf_seq_start,
.next = igmp6_mcf_seq_next,
.stop = igmp6_mcf_seq_stop,
.show = igmp6_mcf_seq_show,
};
static int igmp6_mcf_seq_open(struct inode *inode, struct file *file)
{
struct seq_file *seq;
int rc = -ENOMEM;
struct igmp6_mcf_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
if (!s)
goto out;
*start=buffer+(offset-begin); rc = seq_open(file, &igmp6_mcf_seq_ops);
len-=(offset-begin); if (rc)
if(len>length) goto out_kfree;
len=length;
if (len<0) seq = file->private_data;
len=0; seq->private = s;
return len; memset(s, 0, sizeof(*s));
out:
return rc;
out_kfree:
kfree(s);
goto out;
} }
static struct file_operations igmp6_mcf_seq_fops = {
.owner = THIS_MODULE,
.open = igmp6_mcf_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_private,
};
#endif #endif
int __init igmp6_init(struct net_proto_family *ops) int __init igmp6_init(struct net_proto_family *ops)
...@@ -2178,6 +2358,9 @@ int __init igmp6_init(struct net_proto_family *ops) ...@@ -2178,6 +2358,9 @@ int __init igmp6_init(struct net_proto_family *ops)
struct ipv6_pinfo *np; struct ipv6_pinfo *np;
struct sock *sk; struct sock *sk;
int err; int err;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *p;
#endif
err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &igmp6_socket); err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &igmp6_socket);
if (err < 0) { if (err < 0) {
...@@ -2194,9 +2377,14 @@ int __init igmp6_init(struct net_proto_family *ops) ...@@ -2194,9 +2377,14 @@ int __init igmp6_init(struct net_proto_family *ops)
np = inet6_sk(sk); np = inet6_sk(sk);
np->hop_limit = 1; np->hop_limit = 1;
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
create_proc_read_entry("net/igmp6", 0, 0, igmp6_read_proc, NULL); p = create_proc_entry("igmp6", S_IRUGO, proc_net);
create_proc_read_entry("net/mcfilter6", 0, 0, ip6_mcf_read_proc, NULL); if (p)
p->proc_fops = &igmp6_mc_seq_fops;
p = create_proc_entry("mcfilter6", S_IRUGO, proc_net);
if (p)
p->proc_fops = &igmp6_mcf_seq_fops;
#endif #endif
return 0; return 0;
...@@ -2207,6 +2395,7 @@ void igmp6_cleanup(void) ...@@ -2207,6 +2395,7 @@ void igmp6_cleanup(void)
sock_release(igmp6_socket); sock_release(igmp6_socket);
igmp6_socket = NULL; /* for safety */ igmp6_socket = NULL; /* for safety */
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
remove_proc_entry("net/igmp6", 0); proc_net_remove("mcfilter6");
proc_net_remove("igmp6");
#endif #endif
} }
...@@ -884,7 +884,6 @@ static void ndisc_recv_ns(struct sk_buff *skb) ...@@ -884,7 +884,6 @@ static void ndisc_recv_ns(struct sk_buff *skb)
in6_dev_put(idev); in6_dev_put(idev);
} else { } else {
struct inet6_dev *in6_dev = in6_dev_get(dev); struct inet6_dev *in6_dev = in6_dev_get(dev);
int addr_type = ipv6_addr_type(saddr);
if (in6_dev && in6_dev->cnf.forwarding && if (in6_dev && in6_dev->cnf.forwarding &&
(addr_type & IPV6_ADDR_UNICAST) && (addr_type & IPV6_ADDR_UNICAST) &&
......
...@@ -1029,7 +1029,22 @@ static struct seq_operations raw6_seq_ops = { ...@@ -1029,7 +1029,22 @@ static struct seq_operations raw6_seq_ops = {
static int raw6_seq_open(struct inode *inode, struct file *file) static int raw6_seq_open(struct inode *inode, struct file *file)
{ {
return seq_open(file, &raw6_seq_ops); struct seq_file *seq;
int rc = -ENOMEM;
struct raw6_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
if (!s)
goto out;
rc = seq_open(file, &raw6_seq_ops);
if (rc)
goto out_kfree;
seq = file->private_data;
seq->private = s;
memset(s, 0, sizeof(*s));
out:
return rc;
out_kfree:
kfree(s);
goto out;
} }
static struct file_operations raw6_seq_fops = { static struct file_operations raw6_seq_fops = {
...@@ -1037,7 +1052,7 @@ static struct file_operations raw6_seq_fops = { ...@@ -1037,7 +1052,7 @@ static struct file_operations raw6_seq_fops = {
.open = raw6_seq_open, .open = raw6_seq_open,
.read = seq_read, .read = seq_read,
.llseek = seq_lseek, .llseek = seq_lseek,
.release = seq_release, .release = seq_release_private,
}; };
int __init raw6_proc_init(void) int __init raw6_proc_init(void)
......
...@@ -93,43 +93,6 @@ static __inline__ int tcp_v6_sk_hashfn(struct sock *sk) ...@@ -93,43 +93,6 @@ static __inline__ int tcp_v6_sk_hashfn(struct sock *sk)
return tcp_v6_hashfn(laddr, lport, faddr, fport); return tcp_v6_hashfn(laddr, lport, faddr, fport);
} }
static inline int ipv6_rcv_saddr_equal(struct sock *sk, struct sock *sk2)
{
struct ipv6_pinfo *np = inet6_sk(sk);
int addr_type = ipv6_addr_type(&np->rcv_saddr);
if (!inet_sk(sk2)->rcv_saddr && !ipv6_only_sock(sk))
return 1;
if (sk2->sk_family == AF_INET6 &&
ipv6_addr_any(&inet6_sk(sk2)->rcv_saddr) &&
!(ipv6_only_sock(sk2) && addr_type == IPV6_ADDR_MAPPED))
return 1;
if (addr_type == IPV6_ADDR_ANY &&
(!ipv6_only_sock(sk) ||
!(sk2->sk_family == AF_INET6 ?
(ipv6_addr_type(&inet6_sk(sk2)->rcv_saddr) == IPV6_ADDR_MAPPED) :
1)))
return 1;
if (sk2->sk_family == AF_INET6 &&
!ipv6_addr_cmp(&np->rcv_saddr,
(sk2->sk_state != TCP_TIME_WAIT ?
&inet6_sk(sk2)->rcv_saddr :
&((struct tcp_tw_bucket *)sk)->tw_v6_rcv_saddr)))
return 1;
if (addr_type == IPV6_ADDR_MAPPED &&
!ipv6_only_sock(sk2) &&
(!inet_sk(sk2)->rcv_saddr ||
!inet_sk(sk)->rcv_saddr ||
inet_sk(sk)->rcv_saddr == inet_sk(sk2)->rcv_saddr))
return 1;
return 0;
}
static inline int tcp_v6_bind_conflict(struct sock *sk, static inline int tcp_v6_bind_conflict(struct sock *sk,
struct tcp_bind_bucket *tb) struct tcp_bind_bucket *tb)
{ {
......
...@@ -59,43 +59,6 @@ ...@@ -59,43 +59,6 @@
DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6); DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6);
/* XXX This is identical to tcp_ipv6.c:ipv6_rcv_saddr_equal, put
* XXX it somewhere common. -DaveM
*/
static __inline__ int udv6_rcv_saddr_equal(struct sock *sk, struct sock *sk2)
{
struct ipv6_pinfo *np = inet6_sk(sk);
int addr_type = ipv6_addr_type(&np->rcv_saddr);
if (!inet_sk(sk2)->rcv_saddr && !ipv6_only_sock(sk))
return 1;
if (sk2->sk_family == AF_INET6 &&
ipv6_addr_any(&inet6_sk(sk2)->rcv_saddr) &&
!(ipv6_only_sock(sk2) && addr_type == IPV6_ADDR_MAPPED))
return 1;
if (addr_type == IPV6_ADDR_ANY &&
(!ipv6_only_sock(sk) ||
!(sk2->sk_family == AF_INET6 ?
(ipv6_addr_type(&inet6_sk(sk2)->rcv_saddr) == IPV6_ADDR_MAPPED) : 1)))
return 1;
if (sk2->sk_family == AF_INET6 &&
!ipv6_addr_cmp(&inet6_sk(sk)->rcv_saddr,
&inet6_sk(sk2)->rcv_saddr))
return 1;
if (addr_type == IPV6_ADDR_MAPPED &&
!ipv6_only_sock(sk2) &&
(!inet_sk(sk2)->rcv_saddr ||
!inet_sk(sk)->rcv_saddr ||
inet_sk(sk)->rcv_saddr == inet_sk(sk2)->rcv_saddr))
return 1;
return 0;
}
/* Grrr, addr_type already calculated by caller, but I don't want /* Grrr, addr_type already calculated by caller, but I don't want
* to add some silly "cookie" argument to this method just for that. * to add some silly "cookie" argument to this method just for that.
*/ */
...@@ -151,7 +114,7 @@ static int udp_v6_get_port(struct sock *sk, unsigned short snum) ...@@ -151,7 +114,7 @@ static int udp_v6_get_port(struct sock *sk, unsigned short snum)
sk2 != sk && sk2 != sk &&
sk2->sk_bound_dev_if == sk->sk_bound_dev_if && sk2->sk_bound_dev_if == sk->sk_bound_dev_if &&
(!sk2->sk_reuse || !sk->sk_reuse) && (!sk2->sk_reuse || !sk->sk_reuse) &&
udv6_rcv_saddr_equal(sk, sk2)) ipv6_rcv_saddr_equal(sk, sk2))
goto fail; goto fail;
} }
} }
......
...@@ -67,10 +67,8 @@ int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) ...@@ -67,10 +67,8 @@ int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
xfrm_vec[xfrm_nr++].xvec = x; xfrm_vec[xfrm_nr++].xvec = x;
iph = skb->nh.ipv6h;
if (x->props.mode) { /* XXX */ if (x->props.mode) { /* XXX */
if (iph->nexthdr != IPPROTO_IPV6) if (nexthdr != IPPROTO_IPV6)
goto drop; goto drop;
skb->nh.raw = skb->data; skb->nh.raw = skb->data;
iph = skb->nh.ipv6h; iph = skb->nh.ipv6h;
......
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