Merge with master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
This commit is contained in:
@@ -1744,6 +1744,7 @@ static int process_backlog(struct net_device *backlog_dev, int *budget)
|
||||
struct softnet_data *queue = &__get_cpu_var(softnet_data);
|
||||
unsigned long start_time = jiffies;
|
||||
|
||||
backlog_dev->weight = weight_p;
|
||||
for (;;) {
|
||||
struct sk_buff *skb;
|
||||
struct net_device *dev;
|
||||
|
||||
+1
-1
@@ -356,7 +356,7 @@ static int ethtool_set_coalesce(struct net_device *dev, void __user *useraddr)
|
||||
{
|
||||
struct ethtool_coalesce coalesce;
|
||||
|
||||
if (!dev->ethtool_ops->get_coalesce)
|
||||
if (!dev->ethtool_ops->set_coalesce)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (copy_from_user(&coalesce, useraddr, sizeof(coalesce)))
|
||||
|
||||
@@ -185,6 +185,22 @@ static ssize_t store_tx_queue_len(struct class_device *dev, const char *buf, siz
|
||||
static CLASS_DEVICE_ATTR(tx_queue_len, S_IRUGO | S_IWUSR, show_tx_queue_len,
|
||||
store_tx_queue_len);
|
||||
|
||||
NETDEVICE_SHOW(weight, fmt_dec);
|
||||
|
||||
static int change_weight(struct net_device *net, unsigned long new_weight)
|
||||
{
|
||||
net->weight = new_weight;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t store_weight(struct class_device *dev, const char *buf, size_t len)
|
||||
{
|
||||
return netdev_store(dev, buf, len, change_weight);
|
||||
}
|
||||
|
||||
static CLASS_DEVICE_ATTR(weight, S_IRUGO | S_IWUSR, show_weight,
|
||||
store_weight);
|
||||
|
||||
|
||||
static struct class_device_attribute *net_class_attributes[] = {
|
||||
&class_device_attr_ifindex,
|
||||
@@ -194,6 +210,7 @@ static struct class_device_attribute *net_class_attributes[] = {
|
||||
&class_device_attr_features,
|
||||
&class_device_attr_mtu,
|
||||
&class_device_attr_flags,
|
||||
&class_device_attr_weight,
|
||||
&class_device_attr_type,
|
||||
&class_device_attr_address,
|
||||
&class_device_attr_broadcast,
|
||||
|
||||
@@ -1181,6 +1181,7 @@ EXPORT_SYMBOL(inet_stream_connect);
|
||||
EXPORT_SYMBOL(inet_stream_ops);
|
||||
EXPORT_SYMBOL(inet_unregister_protosw);
|
||||
EXPORT_SYMBOL(net_statistics);
|
||||
EXPORT_SYMBOL(sysctl_ip_nonlocal_bind);
|
||||
|
||||
#ifdef INET_REFCNT_DEBUG
|
||||
EXPORT_SYMBOL(inet_sock_nr);
|
||||
|
||||
+7
-2
@@ -207,6 +207,7 @@ int sysctl_icmp_ignore_bogus_error_responses;
|
||||
|
||||
int sysctl_icmp_ratelimit = 1 * HZ;
|
||||
int sysctl_icmp_ratemask = 0x1818;
|
||||
int sysctl_icmp_errors_use_inbound_ifaddr;
|
||||
|
||||
/*
|
||||
* ICMP control array. This specifies what to do with each ICMP.
|
||||
@@ -511,8 +512,12 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
|
||||
*/
|
||||
|
||||
saddr = iph->daddr;
|
||||
if (!(rt->rt_flags & RTCF_LOCAL))
|
||||
saddr = 0;
|
||||
if (!(rt->rt_flags & RTCF_LOCAL)) {
|
||||
if (sysctl_icmp_errors_use_inbound_ifaddr)
|
||||
saddr = inet_select_addr(skb_in->dev, 0, RT_SCOPE_LINK);
|
||||
else
|
||||
saddr = 0;
|
||||
}
|
||||
|
||||
tos = icmp_pointers[type].error ? ((iph->tos & IPTOS_TOS_MASK) |
|
||||
IPTOS_PREC_INTERNETCONTROL) :
|
||||
|
||||
@@ -11,7 +11,7 @@ ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_AH) += ip_vs_proto_ah.o
|
||||
|
||||
ip_vs-objs := ip_vs_conn.o ip_vs_core.o ip_vs_ctl.o ip_vs_sched.o \
|
||||
ip_vs_xmit.o ip_vs_app.o ip_vs_sync.o \
|
||||
ip_vs_est.o ip_vs_proto.o ip_vs_proto_icmp.o \
|
||||
ip_vs_est.o ip_vs_proto.o \
|
||||
$(ip_vs_proto-objs-y)
|
||||
|
||||
|
||||
|
||||
@@ -216,9 +216,6 @@ int ip_vs_protocol_init(void)
|
||||
#ifdef CONFIG_IP_VS_PROTO_UDP
|
||||
REGISTER_PROTOCOL(&ip_vs_protocol_udp);
|
||||
#endif
|
||||
#ifdef CONFIG_IP_VS_PROTO_ICMP
|
||||
REGISTER_PROTOCOL(&ip_vs_protocol_icmp);
|
||||
#endif
|
||||
#ifdef CONFIG_IP_VS_PROTO_AH
|
||||
REGISTER_PROTOCOL(&ip_vs_protocol_ah);
|
||||
#endif
|
||||
|
||||
@@ -1,182 +0,0 @@
|
||||
/*
|
||||
* ip_vs_proto_icmp.c: ICMP load balancing support for IP Virtual Server
|
||||
*
|
||||
* Authors: Julian Anastasov <ja@ssi.bg>, March 2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation;
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/icmp.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
|
||||
#include <net/ip_vs.h>
|
||||
|
||||
|
||||
static int icmp_timeouts[1] = { 1*60*HZ };
|
||||
|
||||
static char * icmp_state_name_table[1] = { "ICMP" };
|
||||
|
||||
static struct ip_vs_conn *
|
||||
icmp_conn_in_get(const struct sk_buff *skb,
|
||||
struct ip_vs_protocol *pp,
|
||||
const struct iphdr *iph,
|
||||
unsigned int proto_off,
|
||||
int inverse)
|
||||
{
|
||||
#if 0
|
||||
struct ip_vs_conn *cp;
|
||||
|
||||
if (likely(!inverse)) {
|
||||
cp = ip_vs_conn_in_get(iph->protocol,
|
||||
iph->saddr, 0,
|
||||
iph->daddr, 0);
|
||||
} else {
|
||||
cp = ip_vs_conn_in_get(iph->protocol,
|
||||
iph->daddr, 0,
|
||||
iph->saddr, 0);
|
||||
}
|
||||
|
||||
return cp;
|
||||
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct ip_vs_conn *
|
||||
icmp_conn_out_get(const struct sk_buff *skb,
|
||||
struct ip_vs_protocol *pp,
|
||||
const struct iphdr *iph,
|
||||
unsigned int proto_off,
|
||||
int inverse)
|
||||
{
|
||||
#if 0
|
||||
struct ip_vs_conn *cp;
|
||||
|
||||
if (likely(!inverse)) {
|
||||
cp = ip_vs_conn_out_get(iph->protocol,
|
||||
iph->saddr, 0,
|
||||
iph->daddr, 0);
|
||||
} else {
|
||||
cp = ip_vs_conn_out_get(IPPROTO_UDP,
|
||||
iph->daddr, 0,
|
||||
iph->saddr, 0);
|
||||
}
|
||||
|
||||
return cp;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
icmp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp,
|
||||
int *verdict, struct ip_vs_conn **cpp)
|
||||
{
|
||||
*verdict = NF_ACCEPT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
icmp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp)
|
||||
{
|
||||
if (!(skb->nh.iph->frag_off & __constant_htons(IP_OFFSET))) {
|
||||
if (skb->ip_summed != CHECKSUM_UNNECESSARY) {
|
||||
if (ip_vs_checksum_complete(skb, skb->nh.iph->ihl * 4)) {
|
||||
IP_VS_DBG_RL_PKT(0, pp, skb, 0, "Failed checksum for");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
icmp_debug_packet(struct ip_vs_protocol *pp,
|
||||
const struct sk_buff *skb,
|
||||
int offset,
|
||||
const char *msg)
|
||||
{
|
||||
char buf[256];
|
||||
struct iphdr _iph, *ih;
|
||||
|
||||
ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
|
||||
if (ih == NULL)
|
||||
sprintf(buf, "%s TRUNCATED", pp->name);
|
||||
else if (ih->frag_off & __constant_htons(IP_OFFSET))
|
||||
sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u frag",
|
||||
pp->name, NIPQUAD(ih->saddr),
|
||||
NIPQUAD(ih->daddr));
|
||||
else {
|
||||
struct icmphdr _icmph, *ic;
|
||||
|
||||
ic = skb_header_pointer(skb, offset + ih->ihl*4,
|
||||
sizeof(_icmph), &_icmph);
|
||||
if (ic == NULL)
|
||||
sprintf(buf, "%s TRUNCATED to %u bytes\n",
|
||||
pp->name, skb->len - offset);
|
||||
else
|
||||
sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u T:%d C:%d",
|
||||
pp->name, NIPQUAD(ih->saddr),
|
||||
NIPQUAD(ih->daddr),
|
||||
ic->type, ic->code);
|
||||
}
|
||||
printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
|
||||
}
|
||||
|
||||
static int
|
||||
icmp_state_transition(struct ip_vs_conn *cp, int direction,
|
||||
const struct sk_buff *skb,
|
||||
struct ip_vs_protocol *pp)
|
||||
{
|
||||
cp->timeout = pp->timeout_table[IP_VS_ICMP_S_NORMAL];
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
icmp_set_state_timeout(struct ip_vs_protocol *pp, char *sname, int to)
|
||||
{
|
||||
int num;
|
||||
char **names;
|
||||
|
||||
num = IP_VS_ICMP_S_LAST;
|
||||
names = icmp_state_name_table;
|
||||
return ip_vs_set_state_timeout(pp->timeout_table, num, names, sname, to);
|
||||
}
|
||||
|
||||
|
||||
static void icmp_init(struct ip_vs_protocol *pp)
|
||||
{
|
||||
pp->timeout_table = icmp_timeouts;
|
||||
}
|
||||
|
||||
static void icmp_exit(struct ip_vs_protocol *pp)
|
||||
{
|
||||
}
|
||||
|
||||
struct ip_vs_protocol ip_vs_protocol_icmp = {
|
||||
.name = "ICMP",
|
||||
.protocol = IPPROTO_ICMP,
|
||||
.dont_defrag = 0,
|
||||
.init = icmp_init,
|
||||
.exit = icmp_exit,
|
||||
.conn_schedule = icmp_conn_schedule,
|
||||
.conn_in_get = icmp_conn_in_get,
|
||||
.conn_out_get = icmp_conn_out_get,
|
||||
.snat_handler = NULL,
|
||||
.dnat_handler = NULL,
|
||||
.csum_check = icmp_csum_check,
|
||||
.state_transition = icmp_state_transition,
|
||||
.register_app = NULL,
|
||||
.unregister_app = NULL,
|
||||
.app_conn_bind = NULL,
|
||||
.debug_packet = icmp_debug_packet,
|
||||
.timeout_change = NULL,
|
||||
.set_state_timeout = icmp_set_state_timeout,
|
||||
};
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <linux/igmp.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mroute.h>
|
||||
#include <linux/init.h>
|
||||
#include <net/ip.h>
|
||||
@@ -247,3 +248,4 @@ static void __exit drr_exit(void)
|
||||
|
||||
module_init(drr_init);
|
||||
module_exit(drr_exit);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <linux/igmp.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mroute.h>
|
||||
#include <linux/init.h>
|
||||
#include <net/ip.h>
|
||||
@@ -126,3 +127,4 @@ static void __exit random_exit(void)
|
||||
|
||||
module_init(random_init);
|
||||
module_exit(random_exit);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <linux/igmp.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mroute.h>
|
||||
#include <linux/init.h>
|
||||
#include <net/ip.h>
|
||||
@@ -93,3 +94,4 @@ static void __exit rr_exit(void)
|
||||
|
||||
module_init(rr_init);
|
||||
module_exit(rr_exit);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <linux/igmp.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mroute.h>
|
||||
#include <linux/init.h>
|
||||
#include <net/ip.h>
|
||||
@@ -342,3 +343,4 @@ static void __exit wrandom_exit(void)
|
||||
|
||||
module_init(wrandom_init);
|
||||
module_exit(wrandom_exit);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -256,6 +256,7 @@ static void *exp_seq_next(struct seq_file *s, void *v, loff_t *pos)
|
||||
{
|
||||
struct list_head *e = v;
|
||||
|
||||
++*pos;
|
||||
e = e->next;
|
||||
|
||||
if (e == &ip_conntrack_expect_list)
|
||||
|
||||
@@ -223,7 +223,7 @@ static int ip_recent_ctrl(struct file *file, const char __user *input, unsigned
|
||||
curr_table->table[count].last_seen = 0;
|
||||
curr_table->table[count].addr = 0;
|
||||
curr_table->table[count].ttl = 0;
|
||||
memset(curr_table->table[count].last_pkts,0,ip_pkt_list_tot*sizeof(u_int32_t));
|
||||
memset(curr_table->table[count].last_pkts,0,ip_pkt_list_tot*sizeof(unsigned long));
|
||||
curr_table->table[count].oldest_pkt = 0;
|
||||
curr_table->table[count].time_pos = 0;
|
||||
curr_table->time_info[count].position = count;
|
||||
@@ -502,7 +502,7 @@ match(const struct sk_buff *skb,
|
||||
location = time_info[curr_table->time_pos].position;
|
||||
hash_table[r_list[location].hash_entry] = -1;
|
||||
hash_table[hash_result] = location;
|
||||
memset(r_list[location].last_pkts,0,ip_pkt_list_tot*sizeof(u_int32_t));
|
||||
memset(r_list[location].last_pkts,0,ip_pkt_list_tot*sizeof(unsigned long));
|
||||
r_list[location].time_pos = curr_table->time_pos;
|
||||
r_list[location].addr = addr;
|
||||
r_list[location].ttl = ttl;
|
||||
@@ -631,7 +631,7 @@ match(const struct sk_buff *skb,
|
||||
r_list[location].last_seen = 0;
|
||||
r_list[location].addr = 0;
|
||||
r_list[location].ttl = 0;
|
||||
memset(r_list[location].last_pkts,0,ip_pkt_list_tot*sizeof(u_int32_t));
|
||||
memset(r_list[location].last_pkts,0,ip_pkt_list_tot*sizeof(unsigned long));
|
||||
r_list[location].oldest_pkt = 0;
|
||||
ans = !info->invert;
|
||||
}
|
||||
@@ -734,10 +734,10 @@ checkentry(const char *tablename,
|
||||
memset(curr_table->table,0,sizeof(struct recent_ip_list)*ip_list_tot);
|
||||
#ifdef DEBUG
|
||||
if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: Allocating %d for pkt_list.\n",
|
||||
sizeof(u_int32_t)*ip_pkt_list_tot*ip_list_tot);
|
||||
sizeof(unsigned long)*ip_pkt_list_tot*ip_list_tot);
|
||||
#endif
|
||||
|
||||
hold = vmalloc(sizeof(u_int32_t)*ip_pkt_list_tot*ip_list_tot);
|
||||
hold = vmalloc(sizeof(unsigned long)*ip_pkt_list_tot*ip_list_tot);
|
||||
#ifdef DEBUG
|
||||
if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: After pkt_list allocation.\n");
|
||||
#endif
|
||||
|
||||
@@ -23,6 +23,7 @@ extern int sysctl_ip_nonlocal_bind;
|
||||
extern int sysctl_icmp_echo_ignore_all;
|
||||
extern int sysctl_icmp_echo_ignore_broadcasts;
|
||||
extern int sysctl_icmp_ignore_bogus_error_responses;
|
||||
extern int sysctl_icmp_errors_use_inbound_ifaddr;
|
||||
|
||||
/* From ip_fragment.c */
|
||||
extern int sysctl_ipfrag_low_thresh;
|
||||
@@ -395,6 +396,14 @@ ctl_table ipv4_table[] = {
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_ICMP_ERRORS_USE_INBOUND_IFADDR,
|
||||
.procname = "icmp_errors_use_inbound_ifaddr",
|
||||
.data = &sysctl_icmp_errors_use_inbound_ifaddr,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_ROUTE,
|
||||
.procname = "route",
|
||||
|
||||
+1
-1
@@ -2338,7 +2338,7 @@ void __init tcp_init(void)
|
||||
(tcp_bhash_size * sizeof(struct tcp_bind_hashbucket));
|
||||
order++)
|
||||
;
|
||||
if (order > 4) {
|
||||
if (order >= 4) {
|
||||
sysctl_local_port_range[0] = 32768;
|
||||
sysctl_local_port_range[1] = 61000;
|
||||
sysctl_tcp_max_tw_buckets = 180000;
|
||||
|
||||
@@ -372,6 +372,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
|
||||
ndev->regen_timer.data = (unsigned long) ndev;
|
||||
if ((dev->flags&IFF_LOOPBACK) ||
|
||||
dev->type == ARPHRD_TUNNEL ||
|
||||
dev->type == ARPHRD_NONE ||
|
||||
dev->type == ARPHRD_SIT) {
|
||||
printk(KERN_INFO
|
||||
"Disabled Privacy Extensions on device %p(%s)\n",
|
||||
|
||||
+10
-4
@@ -277,8 +277,8 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
|
||||
{
|
||||
struct inet6_dev *idev = NULL;
|
||||
struct ipv6hdr *hdr = skb->nh.ipv6h;
|
||||
struct sock *sk = icmpv6_socket->sk;
|
||||
struct ipv6_pinfo *np = inet6_sk(sk);
|
||||
struct sock *sk;
|
||||
struct ipv6_pinfo *np;
|
||||
struct in6_addr *saddr = NULL;
|
||||
struct dst_entry *dst;
|
||||
struct icmp6hdr tmp_hdr;
|
||||
@@ -358,6 +358,9 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
|
||||
if (icmpv6_xmit_lock())
|
||||
return;
|
||||
|
||||
sk = icmpv6_socket->sk;
|
||||
np = inet6_sk(sk);
|
||||
|
||||
if (!icmpv6_xrlim_allow(sk, type, &fl))
|
||||
goto out;
|
||||
|
||||
@@ -423,9 +426,9 @@ out:
|
||||
|
||||
static void icmpv6_echo_reply(struct sk_buff *skb)
|
||||
{
|
||||
struct sock *sk = icmpv6_socket->sk;
|
||||
struct sock *sk;
|
||||
struct inet6_dev *idev;
|
||||
struct ipv6_pinfo *np = inet6_sk(sk);
|
||||
struct ipv6_pinfo *np;
|
||||
struct in6_addr *saddr = NULL;
|
||||
struct icmp6hdr *icmph = (struct icmp6hdr *) skb->h.raw;
|
||||
struct icmp6hdr tmp_hdr;
|
||||
@@ -454,6 +457,9 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
|
||||
if (icmpv6_xmit_lock())
|
||||
return;
|
||||
|
||||
sk = icmpv6_socket->sk;
|
||||
np = inet6_sk(sk);
|
||||
|
||||
if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst))
|
||||
fl.oif = np->mcast_oif;
|
||||
|
||||
|
||||
@@ -882,6 +882,7 @@ ip6ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p)
|
||||
t->parms.hop_limit = p->hop_limit;
|
||||
t->parms.encap_limit = p->encap_limit;
|
||||
t->parms.flowinfo = p->flowinfo;
|
||||
t->parms.link = p->link;
|
||||
ip6ip6_tnl_link_config(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -37,5 +37,4 @@ EXPORT_SYMBOL(in6_dev_finish_destroy);
|
||||
EXPORT_SYMBOL(xfrm6_rcv);
|
||||
#endif
|
||||
EXPORT_SYMBOL(rt6_lookup);
|
||||
EXPORT_SYMBOL(fl6_sock_lookup);
|
||||
EXPORT_SYMBOL(ipv6_push_nfrag_opts);
|
||||
|
||||
+1
-1
@@ -405,7 +405,7 @@ config NET_EMATCH_STACK
|
||||
---help---
|
||||
Size of the local stack variable used while evaluating the tree of
|
||||
ematches. Limits the depth of the tree, i.e. the number of
|
||||
encapsulated precedences. Every level requires 4 bytes of addtional
|
||||
encapsulated precedences. Every level requires 4 bytes of additional
|
||||
stack space.
|
||||
|
||||
config NET_EMATCH_CMP
|
||||
|
||||
+1
-1
@@ -881,7 +881,7 @@ static int __init tc_action_init(void)
|
||||
link_p[RTM_GETACTION-RTM_BASE].dumpit = tc_dump_action;
|
||||
}
|
||||
|
||||
printk("TC classifier action (bugs to netdev@oss.sgi.com cc "
|
||||
printk("TC classifier action (bugs to netdev@vger.kernel.org cc "
|
||||
"hadi@cyberus.ca)\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -261,6 +261,9 @@ static int basic_dump(struct tcf_proto *tp, unsigned long fh,
|
||||
rta = (struct rtattr *) b;
|
||||
RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
|
||||
|
||||
if (f->res.classid)
|
||||
RTA_PUT(skb, TCA_BASIC_CLASSID, sizeof(u32), &f->res.classid);
|
||||
|
||||
if (tcf_exts_dump(skb, &f->exts, &basic_ext_map) < 0 ||
|
||||
tcf_em_tree_dump(skb, &f->ematches, TCA_BASIC_EMATCHES) < 0)
|
||||
goto rtattr_failure;
|
||||
|
||||
+269
-26
@@ -32,7 +32,7 @@
|
||||
* +-----------+ +-----------+
|
||||
* | |
|
||||
* ---> meta_ops[INT][INDEV](...) |
|
||||
* | |
|
||||
* | |
|
||||
* ----------- |
|
||||
* V V
|
||||
* +-----------+ +-----------+
|
||||
@@ -70,6 +70,7 @@
|
||||
#include <net/dst.h>
|
||||
#include <net/route.h>
|
||||
#include <net/pkt_cls.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
struct meta_obj
|
||||
{
|
||||
@@ -283,6 +284,214 @@ META_COLLECTOR(int_rtiif)
|
||||
dst->value = ((struct rtable*) skb->dst)->fl.iif;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Socket Attributes
|
||||
**************************************************************************/
|
||||
|
||||
#define SKIP_NONLOCAL(skb) \
|
||||
if (unlikely(skb->sk == NULL)) { \
|
||||
*err = -1; \
|
||||
return; \
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_family)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_family;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_state)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_state;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_reuse)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_reuse;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_bound_if)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
/* No error if bound_dev_if is 0, legal userspace check */
|
||||
dst->value = skb->sk->sk_bound_dev_if;
|
||||
}
|
||||
|
||||
META_COLLECTOR(var_sk_bound_if)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
|
||||
if (skb->sk->sk_bound_dev_if == 0) {
|
||||
dst->value = (unsigned long) "any";
|
||||
dst->len = 3;
|
||||
} else {
|
||||
struct net_device *dev;
|
||||
|
||||
dev = dev_get_by_index(skb->sk->sk_bound_dev_if);
|
||||
*err = var_dev(dev, dst);
|
||||
if (dev)
|
||||
dev_put(dev);
|
||||
}
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_refcnt)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = atomic_read(&skb->sk->sk_refcnt);
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_rcvbuf)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_rcvbuf;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_shutdown)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_shutdown;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_proto)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_protocol;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_type)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_type;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_rmem_alloc)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = atomic_read(&skb->sk->sk_rmem_alloc);
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_wmem_alloc)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = atomic_read(&skb->sk->sk_wmem_alloc);
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_omem_alloc)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = atomic_read(&skb->sk->sk_omem_alloc);
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_rcv_qlen)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_receive_queue.qlen;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_snd_qlen)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_write_queue.qlen;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_wmem_queued)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_wmem_queued;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_fwd_alloc)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_forward_alloc;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_sndbuf)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_sndbuf;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_alloc)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_allocation;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_route_caps)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_route_caps;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_hashent)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_hashent;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_lingertime)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_lingertime / HZ;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_err_qlen)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_error_queue.qlen;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_ack_bl)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_ack_backlog;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_max_ack_bl)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_max_ack_backlog;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_prio)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_priority;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_rcvlowat)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_rcvlowat;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_rcvtimeo)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_rcvtimeo / HZ;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_sndtimeo)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_sndtimeo / HZ;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_sendmsg_off)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_sndmsg_off;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_write_pend)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_write_pending;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Meta value collectors assignment table
|
||||
**************************************************************************/
|
||||
@@ -293,41 +502,75 @@ struct meta_ops
|
||||
struct meta_value *, struct meta_obj *, int *);
|
||||
};
|
||||
|
||||
#define META_ID(name) TCF_META_ID_##name
|
||||
#define META_FUNC(name) { .get = meta_##name }
|
||||
|
||||
/* Meta value operations table listing all meta value collectors and
|
||||
* assigns them to a type and meta id. */
|
||||
static struct meta_ops __meta_ops[TCF_META_TYPE_MAX+1][TCF_META_ID_MAX+1] = {
|
||||
[TCF_META_TYPE_VAR] = {
|
||||
[TCF_META_ID_DEV] = { .get = meta_var_dev },
|
||||
[TCF_META_ID_INDEV] = { .get = meta_var_indev },
|
||||
[TCF_META_ID_REALDEV] = { .get = meta_var_realdev }
|
||||
[META_ID(DEV)] = META_FUNC(var_dev),
|
||||
[META_ID(INDEV)] = META_FUNC(var_indev),
|
||||
[META_ID(REALDEV)] = META_FUNC(var_realdev),
|
||||
[META_ID(SK_BOUND_IF)] = META_FUNC(var_sk_bound_if),
|
||||
},
|
||||
[TCF_META_TYPE_INT] = {
|
||||
[TCF_META_ID_RANDOM] = { .get = meta_int_random },
|
||||
[TCF_META_ID_LOADAVG_0] = { .get = meta_int_loadavg_0 },
|
||||
[TCF_META_ID_LOADAVG_1] = { .get = meta_int_loadavg_1 },
|
||||
[TCF_META_ID_LOADAVG_2] = { .get = meta_int_loadavg_2 },
|
||||
[TCF_META_ID_DEV] = { .get = meta_int_dev },
|
||||
[TCF_META_ID_INDEV] = { .get = meta_int_indev },
|
||||
[TCF_META_ID_REALDEV] = { .get = meta_int_realdev },
|
||||
[TCF_META_ID_PRIORITY] = { .get = meta_int_priority },
|
||||
[TCF_META_ID_PROTOCOL] = { .get = meta_int_protocol },
|
||||
[TCF_META_ID_SECURITY] = { .get = meta_int_security },
|
||||
[TCF_META_ID_PKTTYPE] = { .get = meta_int_pkttype },
|
||||
[TCF_META_ID_PKTLEN] = { .get = meta_int_pktlen },
|
||||
[TCF_META_ID_DATALEN] = { .get = meta_int_datalen },
|
||||
[TCF_META_ID_MACLEN] = { .get = meta_int_maclen },
|
||||
[META_ID(RANDOM)] = META_FUNC(int_random),
|
||||
[META_ID(LOADAVG_0)] = META_FUNC(int_loadavg_0),
|
||||
[META_ID(LOADAVG_1)] = META_FUNC(int_loadavg_1),
|
||||
[META_ID(LOADAVG_2)] = META_FUNC(int_loadavg_2),
|
||||
[META_ID(DEV)] = META_FUNC(int_dev),
|
||||
[META_ID(INDEV)] = META_FUNC(int_indev),
|
||||
[META_ID(REALDEV)] = META_FUNC(int_realdev),
|
||||
[META_ID(PRIORITY)] = META_FUNC(int_priority),
|
||||
[META_ID(PROTOCOL)] = META_FUNC(int_protocol),
|
||||
[META_ID(SECURITY)] = META_FUNC(int_security),
|
||||
[META_ID(PKTTYPE)] = META_FUNC(int_pkttype),
|
||||
[META_ID(PKTLEN)] = META_FUNC(int_pktlen),
|
||||
[META_ID(DATALEN)] = META_FUNC(int_datalen),
|
||||
[META_ID(MACLEN)] = META_FUNC(int_maclen),
|
||||
#ifdef CONFIG_NETFILTER
|
||||
[TCF_META_ID_NFMARK] = { .get = meta_int_nfmark },
|
||||
[META_ID(NFMARK)] = META_FUNC(int_nfmark),
|
||||
#endif
|
||||
[TCF_META_ID_TCINDEX] = { .get = meta_int_tcindex },
|
||||
[META_ID(TCINDEX)] = META_FUNC(int_tcindex),
|
||||
#ifdef CONFIG_NET_CLS_ACT
|
||||
[TCF_META_ID_TCVERDICT] = { .get = meta_int_tcverd },
|
||||
[TCF_META_ID_TCCLASSID] = { .get = meta_int_tcclassid },
|
||||
[META_ID(TCVERDICT)] = META_FUNC(int_tcverd),
|
||||
[META_ID(TCCLASSID)] = META_FUNC(int_tcclassid),
|
||||
#endif
|
||||
#ifdef CONFIG_NET_CLS_ROUTE
|
||||
[TCF_META_ID_RTCLASSID] = { .get = meta_int_rtclassid },
|
||||
[META_ID(RTCLASSID)] = META_FUNC(int_rtclassid),
|
||||
#endif
|
||||
[TCF_META_ID_RTIIF] = { .get = meta_int_rtiif }
|
||||
[META_ID(RTIIF)] = META_FUNC(int_rtiif),
|
||||
[META_ID(SK_FAMILY)] = META_FUNC(int_sk_family),
|
||||
[META_ID(SK_STATE)] = META_FUNC(int_sk_state),
|
||||
[META_ID(SK_REUSE)] = META_FUNC(int_sk_reuse),
|
||||
[META_ID(SK_BOUND_IF)] = META_FUNC(int_sk_bound_if),
|
||||
[META_ID(SK_REFCNT)] = META_FUNC(int_sk_refcnt),
|
||||
[META_ID(SK_RCVBUF)] = META_FUNC(int_sk_rcvbuf),
|
||||
[META_ID(SK_SNDBUF)] = META_FUNC(int_sk_sndbuf),
|
||||
[META_ID(SK_SHUTDOWN)] = META_FUNC(int_sk_shutdown),
|
||||
[META_ID(SK_PROTO)] = META_FUNC(int_sk_proto),
|
||||
[META_ID(SK_TYPE)] = META_FUNC(int_sk_type),
|
||||
[META_ID(SK_RMEM_ALLOC)] = META_FUNC(int_sk_rmem_alloc),
|
||||
[META_ID(SK_WMEM_ALLOC)] = META_FUNC(int_sk_wmem_alloc),
|
||||
[META_ID(SK_OMEM_ALLOC)] = META_FUNC(int_sk_omem_alloc),
|
||||
[META_ID(SK_WMEM_QUEUED)] = META_FUNC(int_sk_wmem_queued),
|
||||
[META_ID(SK_RCV_QLEN)] = META_FUNC(int_sk_rcv_qlen),
|
||||
[META_ID(SK_SND_QLEN)] = META_FUNC(int_sk_snd_qlen),
|
||||
[META_ID(SK_ERR_QLEN)] = META_FUNC(int_sk_err_qlen),
|
||||
[META_ID(SK_FORWARD_ALLOCS)] = META_FUNC(int_sk_fwd_alloc),
|
||||
[META_ID(SK_ALLOCS)] = META_FUNC(int_sk_alloc),
|
||||
[META_ID(SK_ROUTE_CAPS)] = META_FUNC(int_sk_route_caps),
|
||||
[META_ID(SK_HASHENT)] = META_FUNC(int_sk_hashent),
|
||||
[META_ID(SK_LINGERTIME)] = META_FUNC(int_sk_lingertime),
|
||||
[META_ID(SK_ACK_BACKLOG)] = META_FUNC(int_sk_ack_bl),
|
||||
[META_ID(SK_MAX_ACK_BACKLOG)] = META_FUNC(int_sk_max_ack_bl),
|
||||
[META_ID(SK_PRIO)] = META_FUNC(int_sk_prio),
|
||||
[META_ID(SK_RCVLOWAT)] = META_FUNC(int_sk_rcvlowat),
|
||||
[META_ID(SK_RCVTIMEO)] = META_FUNC(int_sk_rcvtimeo),
|
||||
[META_ID(SK_SNDTIMEO)] = META_FUNC(int_sk_sndtimeo),
|
||||
[META_ID(SK_SENDMSG_OFF)] = META_FUNC(int_sk_sendmsg_off),
|
||||
[META_ID(SK_WRITE_PENDING)] = META_FUNC(int_sk_write_pend),
|
||||
}
|
||||
};
|
||||
|
||||
@@ -396,9 +639,9 @@ static int meta_int_compare(struct meta_obj *a, struct meta_obj *b)
|
||||
/* Let gcc optimize it, the unlikely is not really based on
|
||||
* some numbers but jump free code for mismatches seems
|
||||
* more logical. */
|
||||
if (unlikely(a == b))
|
||||
if (unlikely(a->value == b->value))
|
||||
return 0;
|
||||
else if (a < b)
|
||||
else if (a->value < b->value)
|
||||
return -1;
|
||||
else
|
||||
return 1;
|
||||
|
||||
+34
-15
@@ -178,6 +178,37 @@ int sctp_rcv(struct sk_buff *skb)
|
||||
|
||||
asoc = __sctp_rcv_lookup(skb, &src, &dest, &transport);
|
||||
|
||||
if (!asoc)
|
||||
ep = __sctp_rcv_lookup_endpoint(&dest);
|
||||
|
||||
/* Retrieve the common input handling substructure. */
|
||||
rcvr = asoc ? &asoc->base : &ep->base;
|
||||
sk = rcvr->sk;
|
||||
|
||||
/*
|
||||
* If a frame arrives on an interface and the receiving socket is
|
||||
* bound to another interface, via SO_BINDTODEVICE, treat it as OOTB
|
||||
*/
|
||||
if (sk->sk_bound_dev_if && (sk->sk_bound_dev_if != af->skb_iif(skb)))
|
||||
{
|
||||
sock_put(sk);
|
||||
if (asoc) {
|
||||
sctp_association_put(asoc);
|
||||
asoc = NULL;
|
||||
} else {
|
||||
sctp_endpoint_put(ep);
|
||||
ep = NULL;
|
||||
}
|
||||
sk = sctp_get_ctl_sock();
|
||||
ep = sctp_sk(sk)->ep;
|
||||
sctp_endpoint_hold(ep);
|
||||
sock_hold(sk);
|
||||
rcvr = &ep->base;
|
||||
}
|
||||
|
||||
if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf)
|
||||
goto discard_release;
|
||||
|
||||
/*
|
||||
* RFC 2960, 8.4 - Handle "Out of the blue" Packets.
|
||||
* An SCTP packet is called an "out of the blue" (OOTB)
|
||||
@@ -187,22 +218,12 @@ int sctp_rcv(struct sk_buff *skb)
|
||||
* packet belongs.
|
||||
*/
|
||||
if (!asoc) {
|
||||
ep = __sctp_rcv_lookup_endpoint(&dest);
|
||||
if (sctp_rcv_ootb(skb)) {
|
||||
SCTP_INC_STATS_BH(SCTP_MIB_OUTOFBLUES);
|
||||
goto discard_release;
|
||||
}
|
||||
}
|
||||
|
||||
/* Retrieve the common input handling substructure. */
|
||||
rcvr = asoc ? &asoc->base : &ep->base;
|
||||
sk = rcvr->sk;
|
||||
|
||||
if ((sk) && (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf)) {
|
||||
goto discard_release;
|
||||
}
|
||||
|
||||
|
||||
/* SCTP seems to always need a timestamp right now (FIXME) */
|
||||
if (skb->stamp.tv_sec == 0) {
|
||||
do_gettimeofday(&skb->stamp);
|
||||
@@ -265,13 +286,11 @@ discard_it:
|
||||
|
||||
discard_release:
|
||||
/* Release any structures we may be holding. */
|
||||
if (asoc) {
|
||||
sock_put(asoc->base.sk);
|
||||
sock_put(sk);
|
||||
if (asoc)
|
||||
sctp_association_put(asoc);
|
||||
} else {
|
||||
sock_put(ep->base.sk);
|
||||
else
|
||||
sctp_endpoint_put(ep);
|
||||
}
|
||||
|
||||
goto discard_it;
|
||||
}
|
||||
|
||||
+15
-21
@@ -812,26 +812,23 @@ static int sctp_inet6_bind_verify(struct sctp_sock *opt, union sctp_addr *addr)
|
||||
if (addr->sa.sa_family != AF_INET6)
|
||||
af = sctp_get_af_specific(addr->sa.sa_family);
|
||||
else {
|
||||
struct sock *sk;
|
||||
int type = ipv6_addr_type(&addr->v6.sin6_addr);
|
||||
sk = sctp_opt2sk(opt);
|
||||
if (type & IPV6_ADDR_LINKLOCAL) {
|
||||
/* Note: Behavior similar to af_inet6.c:
|
||||
* 1) Overrides previous bound_dev_if
|
||||
* 2) Destructive even if bind isn't successful.
|
||||
*/
|
||||
struct net_device *dev;
|
||||
|
||||
if (addr->v6.sin6_scope_id)
|
||||
sk->sk_bound_dev_if = addr->v6.sin6_scope_id;
|
||||
if (!sk->sk_bound_dev_if)
|
||||
if (type & IPV6_ADDR_LINKLOCAL) {
|
||||
if (!addr->v6.sin6_scope_id)
|
||||
return 0;
|
||||
dev = dev_get_by_index(addr->v6.sin6_scope_id);
|
||||
if (!dev)
|
||||
return 0;
|
||||
dev_put(dev);
|
||||
}
|
||||
af = opt->pf->af;
|
||||
}
|
||||
return af->available(addr, opt);
|
||||
}
|
||||
|
||||
/* Verify that the provided sockaddr looks bindable. Common verification,
|
||||
/* Verify that the provided sockaddr looks sendable. Common verification,
|
||||
* has already been taken care of.
|
||||
*/
|
||||
static int sctp_inet6_send_verify(struct sctp_sock *opt, union sctp_addr *addr)
|
||||
@@ -842,19 +839,16 @@ static int sctp_inet6_send_verify(struct sctp_sock *opt, union sctp_addr *addr)
|
||||
if (addr->sa.sa_family != AF_INET6)
|
||||
af = sctp_get_af_specific(addr->sa.sa_family);
|
||||
else {
|
||||
struct sock *sk;
|
||||
int type = ipv6_addr_type(&addr->v6.sin6_addr);
|
||||
sk = sctp_opt2sk(opt);
|
||||
if (type & IPV6_ADDR_LINKLOCAL) {
|
||||
/* Note: Behavior similar to af_inet6.c:
|
||||
* 1) Overrides previous bound_dev_if
|
||||
* 2) Destructive even if bind isn't successful.
|
||||
*/
|
||||
struct net_device *dev;
|
||||
|
||||
if (addr->v6.sin6_scope_id)
|
||||
sk->sk_bound_dev_if = addr->v6.sin6_scope_id;
|
||||
if (!sk->sk_bound_dev_if)
|
||||
if (type & IPV6_ADDR_LINKLOCAL) {
|
||||
if (!addr->v6.sin6_scope_id)
|
||||
return 0;
|
||||
dev = dev_get_by_index(addr->v6.sin6_scope_id);
|
||||
if (!dev)
|
||||
return 0;
|
||||
dev_put(dev);
|
||||
}
|
||||
af = opt->pf->af;
|
||||
}
|
||||
|
||||
+149
-41
@@ -132,14 +132,25 @@ void sctp_snmp_proc_exit(void)
|
||||
static void sctp_seq_dump_local_addrs(struct seq_file *seq, struct sctp_ep_common *epb)
|
||||
{
|
||||
struct list_head *pos;
|
||||
struct sctp_association *asoc;
|
||||
struct sctp_sockaddr_entry *laddr;
|
||||
union sctp_addr *addr;
|
||||
struct sctp_transport *peer;
|
||||
union sctp_addr *addr, *primary = NULL;
|
||||
struct sctp_af *af;
|
||||
|
||||
if (epb->type == SCTP_EP_TYPE_ASSOCIATION) {
|
||||
asoc = sctp_assoc(epb);
|
||||
peer = asoc->peer.primary_path;
|
||||
primary = &peer->saddr;
|
||||
}
|
||||
|
||||
list_for_each(pos, &epb->bind_addr.address_list) {
|
||||
laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
|
||||
addr = (union sctp_addr *)&laddr->a;
|
||||
af = sctp_get_af_specific(addr->sa.sa_family);
|
||||
if (primary && af->cmp_addr(addr, primary)) {
|
||||
seq_printf(seq, "*");
|
||||
}
|
||||
af->seq_dump_addr(seq, addr);
|
||||
}
|
||||
}
|
||||
@@ -149,17 +160,54 @@ static void sctp_seq_dump_remote_addrs(struct seq_file *seq, struct sctp_associa
|
||||
{
|
||||
struct list_head *pos;
|
||||
struct sctp_transport *transport;
|
||||
union sctp_addr *addr;
|
||||
union sctp_addr *addr, *primary;
|
||||
struct sctp_af *af;
|
||||
|
||||
primary = &(assoc->peer.primary_addr);
|
||||
list_for_each(pos, &assoc->peer.transport_addr_list) {
|
||||
transport = list_entry(pos, struct sctp_transport, transports);
|
||||
addr = (union sctp_addr *)&transport->ipaddr;
|
||||
af = sctp_get_af_specific(addr->sa.sa_family);
|
||||
if (af->cmp_addr(addr, primary)) {
|
||||
seq_printf(seq, "*");
|
||||
}
|
||||
af->seq_dump_addr(seq, addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void * sctp_eps_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
{
|
||||
if (*pos > sctp_ep_hashsize)
|
||||
return NULL;
|
||||
|
||||
if (*pos < 0)
|
||||
*pos = 0;
|
||||
|
||||
if (*pos == 0)
|
||||
seq_printf(seq, " ENDPT SOCK STY SST HBKT LPORT UID INODE LADDRS\n");
|
||||
|
||||
++*pos;
|
||||
|
||||
return (void *)pos;
|
||||
}
|
||||
|
||||
static void sctp_eps_seq_stop(struct seq_file *seq, void *v)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void * sctp_eps_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||
{
|
||||
if (*pos > sctp_ep_hashsize)
|
||||
return NULL;
|
||||
|
||||
++*pos;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
/* Display sctp endpoints (/proc/net/sctp/eps). */
|
||||
static int sctp_eps_seq_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
@@ -167,38 +215,50 @@ static int sctp_eps_seq_show(struct seq_file *seq, void *v)
|
||||
struct sctp_ep_common *epb;
|
||||
struct sctp_endpoint *ep;
|
||||
struct sock *sk;
|
||||
int hash;
|
||||
int hash = *(int *)v;
|
||||
|
||||
seq_printf(seq, " ENDPT SOCK STY SST HBKT LPORT LADDRS\n");
|
||||
for (hash = 0; hash < sctp_ep_hashsize; hash++) {
|
||||
head = &sctp_ep_hashtable[hash];
|
||||
read_lock(&head->lock);
|
||||
for (epb = head->chain; epb; epb = epb->next) {
|
||||
ep = sctp_ep(epb);
|
||||
sk = epb->sk;
|
||||
seq_printf(seq, "%8p %8p %-3d %-3d %-4d %-5d ", ep, sk,
|
||||
sctp_sk(sk)->type, sk->sk_state, hash,
|
||||
epb->bind_addr.port);
|
||||
sctp_seq_dump_local_addrs(seq, epb);
|
||||
seq_printf(seq, "\n");
|
||||
}
|
||||
read_unlock(&head->lock);
|
||||
if (hash > sctp_ep_hashsize)
|
||||
return -ENOMEM;
|
||||
|
||||
head = &sctp_ep_hashtable[hash-1];
|
||||
sctp_local_bh_disable();
|
||||
read_lock(&head->lock);
|
||||
for (epb = head->chain; epb; epb = epb->next) {
|
||||
ep = sctp_ep(epb);
|
||||
sk = epb->sk;
|
||||
seq_printf(seq, "%8p %8p %-3d %-3d %-4d %-5d %5d %5lu ", ep, sk,
|
||||
sctp_sk(sk)->type, sk->sk_state, hash-1,
|
||||
epb->bind_addr.port,
|
||||
sock_i_uid(sk), sock_i_ino(sk));
|
||||
|
||||
sctp_seq_dump_local_addrs(seq, epb);
|
||||
seq_printf(seq, "\n");
|
||||
}
|
||||
read_unlock(&head->lock);
|
||||
sctp_local_bh_enable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct seq_operations sctp_eps_ops = {
|
||||
.start = sctp_eps_seq_start,
|
||||
.next = sctp_eps_seq_next,
|
||||
.stop = sctp_eps_seq_stop,
|
||||
.show = sctp_eps_seq_show,
|
||||
};
|
||||
|
||||
|
||||
/* Initialize the seq file operations for 'eps' object. */
|
||||
static int sctp_eps_seq_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, sctp_eps_seq_show, NULL);
|
||||
return seq_open(file, &sctp_eps_ops);
|
||||
}
|
||||
|
||||
static struct file_operations sctp_eps_seq_fops = {
|
||||
.open = sctp_eps_seq_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.release = seq_release,
|
||||
};
|
||||
|
||||
/* Set up the proc fs entry for 'eps' object. */
|
||||
@@ -221,6 +281,40 @@ void sctp_eps_proc_exit(void)
|
||||
remove_proc_entry("eps", proc_net_sctp);
|
||||
}
|
||||
|
||||
|
||||
static void * sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
{
|
||||
if (*pos > sctp_assoc_hashsize)
|
||||
return NULL;
|
||||
|
||||
if (*pos < 0)
|
||||
*pos = 0;
|
||||
|
||||
if (*pos == 0)
|
||||
seq_printf(seq, " ASSOC SOCK STY SST ST HBKT ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT "
|
||||
"RPORT LADDRS <-> RADDRS\n");
|
||||
|
||||
++*pos;
|
||||
|
||||
return (void *)pos;
|
||||
}
|
||||
|
||||
static void sctp_assocs_seq_stop(struct seq_file *seq, void *v)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void * sctp_assocs_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||
{
|
||||
if (*pos > sctp_assoc_hashsize)
|
||||
return NULL;
|
||||
|
||||
++*pos;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
/* Display sctp associations (/proc/net/sctp/assocs). */
|
||||
static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
@@ -228,43 +322,57 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
|
||||
struct sctp_ep_common *epb;
|
||||
struct sctp_association *assoc;
|
||||
struct sock *sk;
|
||||
int hash;
|
||||
int hash = *(int *)v;
|
||||
|
||||
seq_printf(seq, " ASSOC SOCK STY SST ST HBKT LPORT RPORT "
|
||||
"LADDRS <-> RADDRS\n");
|
||||
for (hash = 0; hash < sctp_assoc_hashsize; hash++) {
|
||||
head = &sctp_assoc_hashtable[hash];
|
||||
read_lock(&head->lock);
|
||||
for (epb = head->chain; epb; epb = epb->next) {
|
||||
assoc = sctp_assoc(epb);
|
||||
sk = epb->sk;
|
||||
seq_printf(seq,
|
||||
"%8p %8p %-3d %-3d %-2d %-4d %-5d %-5d ",
|
||||
assoc, sk, sctp_sk(sk)->type, sk->sk_state,
|
||||
assoc->state, hash, epb->bind_addr.port,
|
||||
assoc->peer.port);
|
||||
sctp_seq_dump_local_addrs(seq, epb);
|
||||
seq_printf(seq, "<-> ");
|
||||
sctp_seq_dump_remote_addrs(seq, assoc);
|
||||
seq_printf(seq, "\n");
|
||||
}
|
||||
read_unlock(&head->lock);
|
||||
if (hash > sctp_assoc_hashsize)
|
||||
return -ENOMEM;
|
||||
|
||||
head = &sctp_assoc_hashtable[hash-1];
|
||||
sctp_local_bh_disable();
|
||||
read_lock(&head->lock);
|
||||
for (epb = head->chain; epb; epb = epb->next) {
|
||||
assoc = sctp_assoc(epb);
|
||||
sk = epb->sk;
|
||||
seq_printf(seq,
|
||||
"%8p %8p %-3d %-3d %-2d %-4d %4d %8d %8d %7d %5lu %-5d %5d ",
|
||||
assoc, sk, sctp_sk(sk)->type, sk->sk_state,
|
||||
assoc->state, hash-1, assoc->assoc_id,
|
||||
(sk->sk_rcvbuf - assoc->rwnd),
|
||||
assoc->sndbuf_used,
|
||||
sock_i_uid(sk), sock_i_ino(sk),
|
||||
epb->bind_addr.port,
|
||||
assoc->peer.port);
|
||||
|
||||
seq_printf(seq, " ");
|
||||
sctp_seq_dump_local_addrs(seq, epb);
|
||||
seq_printf(seq, "<-> ");
|
||||
sctp_seq_dump_remote_addrs(seq, assoc);
|
||||
seq_printf(seq, "\n");
|
||||
}
|
||||
read_unlock(&head->lock);
|
||||
sctp_local_bh_enable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct seq_operations sctp_assoc_ops = {
|
||||
.start = sctp_assocs_seq_start,
|
||||
.next = sctp_assocs_seq_next,
|
||||
.stop = sctp_assocs_seq_stop,
|
||||
.show = sctp_assocs_seq_show,
|
||||
};
|
||||
|
||||
/* Initialize the seq file operations for 'assocs' object. */
|
||||
static int sctp_assocs_seq_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, sctp_assocs_seq_show, NULL);
|
||||
return seq_open(file, &sctp_assoc_ops);
|
||||
}
|
||||
|
||||
static struct file_operations sctp_assocs_seq_fops = {
|
||||
.open = sctp_assocs_seq_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.release = seq_release,
|
||||
};
|
||||
|
||||
/* Set up the proc fs entry for 'assocs' object. */
|
||||
|
||||
+5
-2
@@ -378,10 +378,13 @@ static int sctp_v4_available(union sctp_addr *addr, struct sctp_sock *sp)
|
||||
{
|
||||
int ret = inet_addr_type(addr->v4.sin_addr.s_addr);
|
||||
|
||||
/* FIXME: ip_nonlocal_bind sysctl support. */
|
||||
|
||||
if (addr->v4.sin_addr.s_addr != INADDR_ANY && ret != RTN_LOCAL)
|
||||
if (addr->v4.sin_addr.s_addr != INADDR_ANY &&
|
||||
ret != RTN_LOCAL &&
|
||||
!sp->inet.freebind &&
|
||||
!sysctl_ip_nonlocal_bind)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -4686,6 +4686,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
|
||||
struct sctp_endpoint *newep = newsp->ep;
|
||||
struct sk_buff *skb, *tmp;
|
||||
struct sctp_ulpevent *event;
|
||||
int flags = 0;
|
||||
|
||||
/* Migrate socket buffer sizes and all the socket level options to the
|
||||
* new socket.
|
||||
@@ -4707,6 +4708,17 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
|
||||
sctp_sk(newsk)->bind_hash = pp;
|
||||
inet_sk(newsk)->num = inet_sk(oldsk)->num;
|
||||
|
||||
/* Copy the bind_addr list from the original endpoint to the new
|
||||
* endpoint so that we can handle restarts properly
|
||||
*/
|
||||
if (assoc->peer.ipv4_address)
|
||||
flags |= SCTP_ADDR4_PEERSUPP;
|
||||
if (assoc->peer.ipv6_address)
|
||||
flags |= SCTP_ADDR6_PEERSUPP;
|
||||
sctp_bind_addr_copy(&newsp->ep->base.bind_addr,
|
||||
&oldsp->ep->base.bind_addr,
|
||||
SCTP_SCOPE_GLOBAL, GFP_KERNEL, flags);
|
||||
|
||||
/* Move any messages in the old socket's receive queue that are for the
|
||||
* peeled off association to the new socket's receive queue.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user