Commit 152a6a9d authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6: (21 commits)
  [IPV4] SNMP: Support OutMcastPkts and OutBcastPkts
  [IPV4] SNMP: Support InMcastPkts and InBcastPkts
  [IPV4] SNMP: Support InTruncatedPkts
  [IPV4] SNMP: Support InNoRoutes
  [SNMP]: Add definitions for {In,Out}BcastPkts
  [TCP] FRTO: RFC4138 allows Nagle override when new data must be sent
  [TCP] FRTO: Delay skb available check until it's mandatory
  [XFRM]: Restrict upper layer information by bundle.
  [TCP]: Catch skb with S+L bugs earlier
  [PATCH] INET : IPV4 UDP lookups converted to a 2 pass algo
  [L2TP]: Add the ability to autoload a pppox protocol module.
  [SKB]: Introduce skb_queue_walk_safe()
  [AF_IUCV/IUCV]: smp_call_function deadlock
  [IPV6]: Fix slab corruption running ip6sic
  [TCP]: Update references in two old comments
  [XFRM]: Export SPD info
  [IPV6]: Track device renames in snmp6.
  [SCTP]: Fix sctp_getsockopt_local_addrs_old() to use local storage.
  [NET]: Remove NETIF_F_INTERNAL_STATS, default to internal stats.
  [NETPOLL]: Remove CONFIG_NETPOLL_RX
  ...
parents cd9bb7e7 80787ebc
...@@ -109,9 +109,6 @@ static void appldata_get_net_sum_data(void *data) ...@@ -109,9 +109,6 @@ static void appldata_get_net_sum_data(void *data)
read_lock(&dev_base_lock); read_lock(&dev_base_lock);
for (dev = dev_base; dev != NULL; dev = dev->next) { for (dev = dev_base; dev != NULL; dev = dev->next) {
stats = dev->get_stats(dev); stats = dev->get_stats(dev);
if (stats == NULL) {
continue;
}
rx_packets += stats->rx_packets; rx_packets += stats->rx_packets;
tx_packets += stats->tx_packets; tx_packets += stats->tx_packets;
rx_bytes += stats->rx_bytes; rx_bytes += stats->rx_bytes;
......
...@@ -2927,11 +2927,6 @@ endif #NETDEVICES ...@@ -2927,11 +2927,6 @@ endif #NETDEVICES
config NETPOLL config NETPOLL
def_bool NETCONSOLE def_bool NETCONSOLE
config NETPOLL_RX
bool "Netpoll support for trapping incoming packets"
default n
depends on NETPOLL
config NETPOLL_TRAP config NETPOLL_TRAP
bool "Netpoll traffic trapping" bool "Netpoll traffic trapping"
default n default n
......
...@@ -1360,13 +1360,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) ...@@ -1360,13 +1360,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
goto err_undo_flags; goto err_undo_flags;
} }
if (slave_dev->get_stats == NULL) {
printk(KERN_NOTICE DRV_NAME
": %s: the driver for slave device %s does not provide "
"get_stats function, network statistics will be "
"inaccurate.\n", bond_dev->name, slave_dev->name);
}
new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL); new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
if (!new_slave) { if (!new_slave) {
res = -ENOMEM; res = -ENOMEM;
...@@ -3641,33 +3634,31 @@ static struct net_device_stats *bond_get_stats(struct net_device *bond_dev) ...@@ -3641,33 +3634,31 @@ static struct net_device_stats *bond_get_stats(struct net_device *bond_dev)
bond_for_each_slave(bond, slave, i) { bond_for_each_slave(bond, slave, i) {
sstats = slave->dev->get_stats(slave->dev); sstats = slave->dev->get_stats(slave->dev);
if (sstats) { stats->rx_packets += sstats->rx_packets;
stats->rx_packets += sstats->rx_packets; stats->rx_bytes += sstats->rx_bytes;
stats->rx_bytes += sstats->rx_bytes; stats->rx_errors += sstats->rx_errors;
stats->rx_errors += sstats->rx_errors; stats->rx_dropped += sstats->rx_dropped;
stats->rx_dropped += sstats->rx_dropped;
stats->tx_packets += sstats->tx_packets;
stats->tx_packets += sstats->tx_packets; stats->tx_bytes += sstats->tx_bytes;
stats->tx_bytes += sstats->tx_bytes; stats->tx_errors += sstats->tx_errors;
stats->tx_errors += sstats->tx_errors; stats->tx_dropped += sstats->tx_dropped;
stats->tx_dropped += sstats->tx_dropped;
stats->multicast += sstats->multicast;
stats->multicast += sstats->multicast; stats->collisions += sstats->collisions;
stats->collisions += sstats->collisions;
stats->rx_length_errors += sstats->rx_length_errors;
stats->rx_length_errors += sstats->rx_length_errors; stats->rx_over_errors += sstats->rx_over_errors;
stats->rx_over_errors += sstats->rx_over_errors; stats->rx_crc_errors += sstats->rx_crc_errors;
stats->rx_crc_errors += sstats->rx_crc_errors; stats->rx_frame_errors += sstats->rx_frame_errors;
stats->rx_frame_errors += sstats->rx_frame_errors; stats->rx_fifo_errors += sstats->rx_fifo_errors;
stats->rx_fifo_errors += sstats->rx_fifo_errors; stats->rx_missed_errors += sstats->rx_missed_errors;
stats->rx_missed_errors += sstats->rx_missed_errors;
stats->tx_aborted_errors += sstats->tx_aborted_errors;
stats->tx_aborted_errors += sstats->tx_aborted_errors; stats->tx_carrier_errors += sstats->tx_carrier_errors;
stats->tx_carrier_errors += sstats->tx_carrier_errors; stats->tx_fifo_errors += sstats->tx_fifo_errors;
stats->tx_fifo_errors += sstats->tx_fifo_errors; stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors;
stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors; stats->tx_window_errors += sstats->tx_window_errors;
stats->tx_window_errors += sstats->tx_window_errors;
}
} }
read_unlock_bh(&bond->lock); read_unlock_bh(&bond->lock);
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/ppp_defs.h> #include <linux/ppp_defs.h>
#include <linux/if_ppp.h> #include <linux/if_ppp.h>
#include <linux/ppp_channel.h> #include <linux/ppp_channel.h>
#include <linux/kmod.h>
#include <net/sock.h> #include <net/sock.h>
...@@ -114,6 +115,13 @@ static int pppox_create(struct socket *sock, int protocol) ...@@ -114,6 +115,13 @@ static int pppox_create(struct socket *sock, int protocol)
goto out; goto out;
rc = -EPROTONOSUPPORT; rc = -EPROTONOSUPPORT;
#ifdef CONFIG_KMOD
if (!pppox_protos[protocol]) {
char buffer[32];
sprintf(buffer, "pppox-proto-%d", protocol);
request_module(buffer);
}
#endif
if (!pppox_protos[protocol] || if (!pppox_protos[protocol] ||
!try_module_get(pppox_protos[protocol]->owner)) !try_module_get(pppox_protos[protocol]->owner))
goto out; goto out;
......
...@@ -373,8 +373,6 @@ static __inline__ int led_get_net_activity(void) ...@@ -373,8 +373,6 @@ static __inline__ int led_get_net_activity(void)
if (LOOPBACK(in_dev->ifa_list->ifa_local)) if (LOOPBACK(in_dev->ifa_list->ifa_local))
continue; continue;
stats = dev->get_stats(dev); stats = dev->get_stats(dev);
if (!stats)
continue;
rx_total += stats->rx_packets; rx_total += stats->rx_packets;
tx_total += stats->tx_packets; tx_total += stats->tx_packets;
} }
......
...@@ -325,7 +325,6 @@ struct net_device ...@@ -325,7 +325,6 @@ struct net_device
#define NETIF_F_VLAN_CHALLENGED 1024 /* Device cannot handle VLAN packets */ #define NETIF_F_VLAN_CHALLENGED 1024 /* Device cannot handle VLAN packets */
#define NETIF_F_GSO 2048 /* Enable software GSO. */ #define NETIF_F_GSO 2048 /* Enable software GSO. */
#define NETIF_F_LLTX 4096 /* LockLess TX */ #define NETIF_F_LLTX 4096 /* LockLess TX */
#define NETIF_F_INTERNAL_STATS 8192 /* Use stats structure in net_device */
/* Segmentation offload features */ /* Segmentation offload features */
#define NETIF_F_GSO_SHIFT 16 #define NETIF_F_GSO_SHIFT 16
...@@ -654,8 +653,10 @@ static inline void netif_start_queue(struct net_device *dev) ...@@ -654,8 +653,10 @@ static inline void netif_start_queue(struct net_device *dev)
static inline void netif_wake_queue(struct net_device *dev) static inline void netif_wake_queue(struct net_device *dev)
{ {
#ifdef CONFIG_NETPOLL_TRAP #ifdef CONFIG_NETPOLL_TRAP
if (netpoll_trap()) if (netpoll_trap()) {
clear_bit(__LINK_STATE_XOFF, &dev->state);
return; return;
}
#endif #endif
if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state)) if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state))
__netif_schedule(dev); __netif_schedule(dev);
...@@ -663,10 +664,6 @@ static inline void netif_wake_queue(struct net_device *dev) ...@@ -663,10 +664,6 @@ static inline void netif_wake_queue(struct net_device *dev)
static inline void netif_stop_queue(struct net_device *dev) static inline void netif_stop_queue(struct net_device *dev)
{ {
#ifdef CONFIG_NETPOLL_TRAP
if (netpoll_trap())
return;
#endif
set_bit(__LINK_STATE_XOFF, &dev->state); set_bit(__LINK_STATE_XOFF, &dev->state);
} }
......
...@@ -1471,6 +1471,11 @@ static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len) ...@@ -1471,6 +1471,11 @@ static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len)
prefetch(skb->next), (skb != (struct sk_buff *)(queue)); \ prefetch(skb->next), (skb != (struct sk_buff *)(queue)); \
skb = skb->next) skb = skb->next)
#define skb_queue_walk_safe(queue, skb, tmp) \
for (skb = (queue)->next, tmp = skb->next; \
skb != (struct sk_buff *)(queue); \
skb = tmp, tmp = skb->next)
#define skb_queue_reverse_walk(queue, skb) \ #define skb_queue_reverse_walk(queue, skb) \
for (skb = (queue)->prev; \ for (skb = (queue)->prev; \
prefetch(skb->prev), (skb != (struct sk_buff *)(queue)); \ prefetch(skb->prev), (skb != (struct sk_buff *)(queue)); \
......
...@@ -40,6 +40,8 @@ enum ...@@ -40,6 +40,8 @@ enum
IPSTATS_MIB_FRAGCREATES, /* FragCreates */ IPSTATS_MIB_FRAGCREATES, /* FragCreates */
IPSTATS_MIB_INMCASTPKTS, /* InMcastPkts */ IPSTATS_MIB_INMCASTPKTS, /* InMcastPkts */
IPSTATS_MIB_OUTMCASTPKTS, /* OutMcastPkts */ IPSTATS_MIB_OUTMCASTPKTS, /* OutMcastPkts */
IPSTATS_MIB_INBCASTPKTS, /* InBcastPkts */
IPSTATS_MIB_OUTBCASTPKTS, /* OutBcastPkts */
__IPSTATS_MIB_MAX __IPSTATS_MIB_MAX
}; };
......
...@@ -185,6 +185,11 @@ enum { ...@@ -185,6 +185,11 @@ enum {
#define XFRM_MSG_NEWSADINFO XFRM_MSG_NEWSADINFO #define XFRM_MSG_NEWSADINFO XFRM_MSG_NEWSADINFO
XFRM_MSG_GETSADINFO, XFRM_MSG_GETSADINFO,
#define XFRM_MSG_GETSADINFO XFRM_MSG_GETSADINFO #define XFRM_MSG_GETSADINFO XFRM_MSG_GETSADINFO
XFRM_MSG_NEWSPDINFO,
#define XFRM_MSG_NEWSPDINFO XFRM_MSG_NEWSPDINFO
XFRM_MSG_GETSPDINFO,
#define XFRM_MSG_GETSPDINFO XFRM_MSG_GETSPDINFO
__XFRM_MSG_MAX __XFRM_MSG_MAX
}; };
#define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1) #define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1)
...@@ -290,6 +295,36 @@ enum xfrm_sadattr_type_t { ...@@ -290,6 +295,36 @@ enum xfrm_sadattr_type_t {
#define XFRMA_SAD_MAX (__XFRMA_SAD_MAX - 1) #define XFRMA_SAD_MAX (__XFRMA_SAD_MAX - 1)
}; };
/* SPD Table filter flags */
enum xfrm_spd_ftype_t {
XFRM_SPD_UNSPEC,
XFRM_SPD_HMASK=1,
XFRM_SPD_HMAX=2,
XFRM_SPD_ICNT=4,
XFRM_SPD_OCNT=8,
XFRM_SPD_FCNT=16,
XFRM_SPD_ISCNT=32,
XFRM_SPD_OSCNT=64,
XFRM_SPD_FSCNT=128,
__XFRM_SPD_MAX
#define XFRM_SPD_MAX (__XFRM_SPD_MAX - 1)
};
enum xfrm_spdattr_type_t {
XFRMA_SPD_UNSPEC,
XFRMA_SPDHMASK,
XFRMA_SPDHMAX,
XFRMA_SPDICNT,
XFRMA_SPDOCNT,
XFRMA_SPDFCNT,
XFRMA_SPDISCNT,
XFRMA_SPDOSCNT,
XFRMA_SPDFSCNT,
__XFRMA_SPD_MAX
#define XFRMA_SPD_MAX (__XFRMA_SPD_MAX - 1)
};
struct xfrm_usersa_info { struct xfrm_usersa_info {
struct xfrm_selector sel; struct xfrm_selector sel;
struct xfrm_id id; struct xfrm_id id;
......
...@@ -97,4 +97,10 @@ extern void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir, ...@@ -97,4 +97,10 @@ extern void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir,
extern void flow_cache_flush(void); extern void flow_cache_flush(void);
extern atomic_t flow_cache_genid; extern atomic_t flow_cache_genid;
static inline int flow_cache_uli_match(struct flowi *fl1, struct flowi *fl2)
{
return (fl1->proto == fl2->proto &&
!memcmp(&fl1->uli_u, &fl2->uli_u, sizeof(fl1->uli_u)));
}
#endif #endif
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* completed a register, it can exploit the other functions. * completed a register, it can exploit the other functions.
* For furthur reference on all IUCV functionality, refer to the * For furthur reference on all IUCV functionality, refer to the
* CP Programming Services book, also available on the web thru * CP Programming Services book, also available on the web thru
* www.ibm.com/s390/vm/pubs, manual # SC24-5760 * www.vm.ibm.com/pubs, manual # SC24-6084
* *
* Definition of Return Codes * Definition of Return Codes
* - All positive return codes including zero are reflected back * - All positive return codes including zero are reflected back
......
...@@ -736,9 +736,7 @@ static inline __u32 tcp_current_ssthresh(const struct sock *sk) ...@@ -736,9 +736,7 @@ static inline __u32 tcp_current_ssthresh(const struct sock *sk)
static inline void tcp_sync_left_out(struct tcp_sock *tp) static inline void tcp_sync_left_out(struct tcp_sock *tp)
{ {
if (tp->rx_opt.sack_ok && BUG_ON(tp->sacked_out + tp->lost_out > tp->packets_out);
(tp->sacked_out >= tp->packets_out - tp->lost_out))
tp->sacked_out = tp->packets_out - tp->lost_out;
tp->left_out = tp->sacked_out + tp->lost_out; tp->left_out = tp->sacked_out + tp->lost_out;
} }
...@@ -1201,9 +1199,14 @@ static inline struct sk_buff *tcp_send_head(struct sock *sk) ...@@ -1201,9 +1199,14 @@ static inline struct sk_buff *tcp_send_head(struct sock *sk)
static inline void tcp_advance_send_head(struct sock *sk, struct sk_buff *skb) static inline void tcp_advance_send_head(struct sock *sk, struct sk_buff *skb)
{ {
struct tcp_sock *tp = tcp_sk(sk);
sk->sk_send_head = skb->next; sk->sk_send_head = skb->next;
if (sk->sk_send_head == (struct sk_buff *)&sk->sk_write_queue) if (sk->sk_send_head == (struct sk_buff *)&sk->sk_write_queue)
sk->sk_send_head = NULL; sk->sk_send_head = NULL;
/* Don't override Nagle indefinately with F-RTO */
if (tp->frto_counter == 2)
tp->frto_counter = 3;
} }
static inline void tcp_check_send_head(struct sock *sk, struct sk_buff *skb_unlinked) static inline void tcp_check_send_head(struct sock *sk, struct sk_buff *skb_unlinked)
......
...@@ -423,6 +423,18 @@ struct xfrm_sadinfo ...@@ -423,6 +423,18 @@ struct xfrm_sadinfo
u32 sadhmcnt; /* max allowed hash bkts */ u32 sadhmcnt; /* max allowed hash bkts */
u32 sadcnt; /* current running count */ u32 sadcnt; /* current running count */
}; };
struct xfrm_spdinfo
{
u32 incnt;
u32 outcnt;
u32 fwdcnt;
u32 inscnt;
u32 outscnt;
u32 fwdscnt;
u32 spdhcnt;
u32 spdhmcnt;
};
#ifdef CONFIG_AUDITSYSCALL #ifdef CONFIG_AUDITSYSCALL
extern void xfrm_audit_log(uid_t auid, u32 secid, int type, int result, extern void xfrm_audit_log(uid_t auid, u32 secid, int type, int result,
struct xfrm_policy *xp, struct xfrm_state *x); struct xfrm_policy *xp, struct xfrm_state *x);
...@@ -591,6 +603,10 @@ struct xfrm_dst ...@@ -591,6 +603,10 @@ struct xfrm_dst
struct rt6_info rt6; struct rt6_info rt6;
} u; } u;
struct dst_entry *route; struct dst_entry *route;
#ifdef CONFIG_XFRM_SUB_POLICY
struct flowi *origin;
struct xfrm_selector *partner;
#endif
u32 genid; u32 genid;
u32 route_mtu_cached; u32 route_mtu_cached;
u32 child_mtu_cached; u32 child_mtu_cached;
...@@ -603,6 +619,12 @@ static inline void xfrm_dst_destroy(struct xfrm_dst *xdst) ...@@ -603,6 +619,12 @@ static inline void xfrm_dst_destroy(struct xfrm_dst *xdst)
dst_release(xdst->route); dst_release(xdst->route);
if (likely(xdst->u.dst.xfrm)) if (likely(xdst->u.dst.xfrm))
xfrm_state_put(xdst->u.dst.xfrm); xfrm_state_put(xdst->u.dst.xfrm);
#ifdef CONFIG_XFRM_SUB_POLICY
kfree(xdst->origin);
xdst->origin = NULL;
kfree(xdst->partner);
xdst->partner = NULL;
#endif
} }
extern void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev); extern void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev);
...@@ -946,6 +968,7 @@ extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq); ...@@ -946,6 +968,7 @@ extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq);
extern int xfrm_state_delete(struct xfrm_state *x); extern int xfrm_state_delete(struct xfrm_state *x);
extern void xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info); extern void xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info);
extern void xfrm_sad_getinfo(struct xfrm_sadinfo *si); extern void xfrm_sad_getinfo(struct xfrm_sadinfo *si);
extern void xfrm_spd_getinfo(struct xfrm_spdinfo *si);
extern int xfrm_replay_check(struct xfrm_state *x, __be32 seq); extern int xfrm_replay_check(struct xfrm_state *x, __be32 seq);
extern void xfrm_replay_advance(struct xfrm_state *x, __be32 seq); extern void xfrm_replay_advance(struct xfrm_state *x, __be32 seq);
extern void xfrm_replay_notify(struct xfrm_state *x, int event); extern void xfrm_replay_notify(struct xfrm_state *x, int event);
......
...@@ -2101,26 +2101,23 @@ static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev) ...@@ -2101,26 +2101,23 @@ static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev)
{ {
struct net_device_stats *stats = dev->get_stats(dev); struct net_device_stats *stats = dev->get_stats(dev);
if (stats) { seq_printf(seq, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu "
seq_printf(seq, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu " "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
"%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", dev->name, stats->rx_bytes, stats->rx_packets,
dev->name, stats->rx_bytes, stats->rx_packets, stats->rx_errors,
stats->rx_errors, stats->rx_dropped + stats->rx_missed_errors,
stats->rx_dropped + stats->rx_missed_errors, stats->rx_fifo_errors,
stats->rx_fifo_errors, stats->rx_length_errors + stats->rx_over_errors +
stats->rx_length_errors + stats->rx_over_errors + stats->rx_crc_errors + stats->rx_frame_errors,
stats->rx_crc_errors + stats->rx_frame_errors, stats->rx_compressed, stats->multicast,
stats->rx_compressed, stats->multicast, stats->tx_bytes, stats->tx_packets,
stats->tx_bytes, stats->tx_packets, stats->tx_errors, stats->tx_dropped,
stats->tx_errors, stats->tx_dropped, stats->tx_fifo_errors, stats->collisions,
stats->tx_fifo_errors, stats->collisions, stats->tx_carrier_errors +
stats->tx_carrier_errors + stats->tx_aborted_errors +
stats->tx_aborted_errors + stats->tx_window_errors +
stats->tx_window_errors + stats->tx_heartbeat_errors,
stats->tx_heartbeat_errors, stats->tx_compressed);
stats->tx_compressed);
} else
seq_printf(seq, "%6s: No statistics available.\n", dev->name);
} }
/* /*
...@@ -3257,11 +3254,9 @@ void netdev_run_todo(void) ...@@ -3257,11 +3254,9 @@ void netdev_run_todo(void)
mutex_unlock(&net_todo_run_mutex); mutex_unlock(&net_todo_run_mutex);
} }
static struct net_device_stats *maybe_internal_stats(struct net_device *dev) static struct net_device_stats *internal_stats(struct net_device *dev)
{ {
if (dev->features & NETIF_F_INTERNAL_STATS) return &dev->stats;
return &dev->stats;
return NULL;
} }
/** /**
...@@ -3299,7 +3294,7 @@ struct net_device *alloc_netdev(int sizeof_priv, const char *name, ...@@ -3299,7 +3294,7 @@ struct net_device *alloc_netdev(int sizeof_priv, const char *name,
if (sizeof_priv) if (sizeof_priv)
dev->priv = netdev_priv(dev); dev->priv = netdev_priv(dev);
dev->get_stats = maybe_internal_stats; dev->get_stats = internal_stats;
setup(dev); setup(dev);
strcpy(dev->name, name); strcpy(dev->name, name);
return dev; return dev;
......
...@@ -329,6 +329,7 @@ static inline int ip_rcv_options(struct sk_buff *skb) ...@@ -329,6 +329,7 @@ static inline int ip_rcv_options(struct sk_buff *skb)
static inline int ip_rcv_finish(struct sk_buff *skb) static inline int ip_rcv_finish(struct sk_buff *skb)
{ {
const struct iphdr *iph = ip_hdr(skb); const struct iphdr *iph = ip_hdr(skb);
struct rtable *rt;
/* /*
* Initialise the virtual path cache for the packet. It describes * Initialise the virtual path cache for the packet. It describes
...@@ -340,6 +341,8 @@ static inline int ip_rcv_finish(struct sk_buff *skb) ...@@ -340,6 +341,8 @@ static inline int ip_rcv_finish(struct sk_buff *skb)
if (unlikely(err)) { if (unlikely(err)) {
if (err == -EHOSTUNREACH) if (err == -EHOSTUNREACH)
IP_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); IP_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
else if (err == -ENETUNREACH)
IP_INC_STATS_BH(IPSTATS_MIB_INNOROUTES);
goto drop; goto drop;
} }
} }
...@@ -358,6 +361,12 @@ static inline int ip_rcv_finish(struct sk_buff *skb) ...@@ -358,6 +361,12 @@ static inline int ip_rcv_finish(struct sk_buff *skb)
if (iph->ihl > 5 && ip_rcv_options(skb)) if (iph->ihl > 5 && ip_rcv_options(skb))
goto drop; goto drop;
rt = (struct rtable*)skb->dst;
if (rt->rt_type == RTN_MULTICAST)
IP_INC_STATS_BH(IPSTATS_MIB_INMCASTPKTS);
else if (rt->rt_type == RTN_BROADCAST)
IP_INC_STATS_BH(IPSTATS_MIB_INBCASTPKTS);
return dst_input(skb); return dst_input(skb);
drop: drop:
...@@ -414,7 +423,10 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, ...@@ -414,7 +423,10 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt,
goto inhdr_error; goto inhdr_error;
len = ntohs(iph->tot_len); len = ntohs(iph->tot_len);
if (skb->len < len || len < (iph->ihl*4)) if (skb->len < len) {
IP_INC_STATS_BH(IPSTATS_MIB_INTRUNCATEDPKTS);
goto drop;
} else if (len < (iph->ihl*4))
goto inhdr_error; goto inhdr_error;
/* Our transport medium may have padded the buffer out. Now we know it /* Our transport medium may have padded the buffer out. Now we know it
......
...@@ -160,9 +160,15 @@ EXPORT_SYMBOL_GPL(ip_build_and_send_pkt); ...@@ -160,9 +160,15 @@ EXPORT_SYMBOL_GPL(ip_build_and_send_pkt);
static inline int ip_finish_output2(struct sk_buff *skb) static inline int ip_finish_output2(struct sk_buff *skb)
{ {
struct dst_entry *dst = skb->dst; struct dst_entry *dst = skb->dst;
struct rtable *rt = (struct rtable *)dst;
struct net_device *dev = dst->dev; struct net_device *dev = dst->dev;
int hh_len = LL_RESERVED_SPACE(dev); int hh_len = LL_RESERVED_SPACE(dev);
if (rt->rt_type == RTN_MULTICAST)
IP_INC_STATS(IPSTATS_MIB_OUTMCASTPKTS);
else if (rt->rt_type == RTN_BROADCAST)
IP_INC_STATS(IPSTATS_MIB_OUTBCASTPKTS);
/* Be paranoid, rather than too clever. */ /* Be paranoid, rather than too clever. */
if (unlikely(skb_headroom(skb) < hh_len && dev->hard_header)) { if (unlikely(skb_headroom(skb) < hh_len && dev->hard_header)) {
struct sk_buff *skb2; struct sk_buff *skb2;
......
...@@ -1573,14 +1573,12 @@ void tcp_close(struct sock *sk, long timeout) ...@@ -1573,14 +1573,12 @@ void tcp_close(struct sock *sk, long timeout)
sk_stream_mem_reclaim(sk); sk_stream_mem_reclaim(sk);
/* As outlined in draft-ietf-tcpimpl-prob-03.txt, section /* As outlined in RFC 2525, section 2.17, we send a RST here because
* 3.10, we send a RST here because data was lost. To * data was lost. To witness the awful effects of the old behavior of
* witness the awful effects of the old behavior of always * always doing a FIN, run an older 2.1.x kernel or 2.0.x, start a bulk
* doing a FIN, run an older 2.1.x kernel or 2.0.x, start * GET in an FTP client, suspend the process, wait for the client to
* a bulk GET in an FTP client, suspend the process, wait * advertise a zero window, then kill -9 the FTP client, wheee...
* for the client to advertise a zero window, then kill -9 * Note: timeout is always zero in such a case.
* the FTP client, wheee... Note: timeout is always zero
* in such a case.
*/ */
if (data_was_unread) { if (data_was_unread) {
/* Unread data was tossed, zap the connection. */ /* Unread data was tossed, zap the connection. */
......
...@@ -1265,20 +1265,15 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ ...@@ -1265,20 +1265,15 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
return flag; return flag;
} }
/* F-RTO can only be used if these conditions are satisfied: /* F-RTO can only be used if TCP has never retransmitted anything other than
* - there must be some unsent new data * head (SACK enhanced variant from Appendix B of RFC4138 is more robust here)
* - the advertised window should allow sending it
* - TCP has never retransmitted anything other than head (SACK enhanced
* variant from Appendix B of RFC4138 is more robust here)
*/ */
int tcp_use_frto(struct sock *sk) int tcp_use_frto(struct sock *sk)
{ {
const struct tcp_sock *tp = tcp_sk(sk); const struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb; struct sk_buff *skb;
if (!sysctl_tcp_frto || !tcp_send_head(sk) || if (!sysctl_tcp_frto)
after(TCP_SKB_CB(tcp_send_head(sk))->end_seq,
tp->snd_una + tp->snd_wnd))
return 0; return 0;
if (IsSackFrto()) if (IsSackFrto())
...@@ -2642,7 +2637,9 @@ static void tcp_undo_spur_to_response(struct sock *sk, int flag) ...@@ -2642,7 +2637,9 @@ static void tcp_undo_spur_to_response(struct sock *sk, int flag)
* algorithm is not part of the F-RTO detection algorithm * algorithm is not part of the F-RTO detection algorithm
* given in RFC4138 but can be selected separately). * given in RFC4138 but can be selected separately).
* Otherwise (basically on duplicate ACK), RTO was (likely) caused by a loss * Otherwise (basically on duplicate ACK), RTO was (likely) caused by a loss
* and TCP falls back to conventional RTO recovery. * and TCP falls back to conventional RTO recovery. F-RTO allows overriding
* of Nagle, this is done using frto_counter states 2 and 3, when a new data
* segment of any size sent during F-RTO, state 2 is upgraded to 3.
* *
* Rationale: if the RTO was spurious, new ACKs should arrive from the * Rationale: if the RTO was spurious, new ACKs should arrive from the
* original window even after we transmit two new data segments. * original window even after we transmit two new data segments.
...@@ -2671,7 +2668,7 @@ static int tcp_process_frto(struct sock *sk, u32 prior_snd_una, int flag) ...@@ -2671,7 +2668,7 @@ static int tcp_process_frto(struct sock *sk, u32 prior_snd_una, int flag)
inet_csk(sk)->icsk_retransmits = 0; inet_csk(sk)->icsk_retransmits = 0;
if (!before(tp->snd_una, tp->frto_highmark)) { if (!before(tp->snd_una, tp->frto_highmark)) {
tcp_enter_frto_loss(sk, tp->frto_counter + 1, flag); tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 2 : 3), flag);
return 1; return 1;
} }
...@@ -2697,7 +2694,7 @@ static int tcp_process_frto(struct sock *sk, u32 prior_snd_una, int flag) ...@@ -2697,7 +2694,7 @@ static int tcp_process_frto(struct sock *sk, u32 prior_snd_una, int flag)
return 1; return 1;
} }
if ((tp->frto_counter == 2) && if ((tp->frto_counter >= 2) &&
(!(flag&FLAG_FORWARD_PROGRESS) || (!(flag&FLAG_FORWARD_PROGRESS) ||
((flag&FLAG_DATA_SACKED) && !(flag&FLAG_ONLY_ORIG_SACKED)))) { ((flag&FLAG_DATA_SACKED) && !(flag&FLAG_ONLY_ORIG_SACKED)))) {
/* RFC4138 shortcoming (see comment above) */ /* RFC4138 shortcoming (see comment above) */
...@@ -2710,10 +2707,19 @@ static int tcp_process_frto(struct sock *sk, u32 prior_snd_una, int flag) ...@@ -2710,10 +2707,19 @@ static int tcp_process_frto(struct sock *sk, u32 prior_snd_una, int flag)
} }
if (tp->frto_counter == 1) { if (tp->frto_counter == 1) {
/* Sending of the next skb must be allowed or no FRTO */
if (!tcp_send_head(sk) ||
after(TCP_SKB_CB(tcp_send_head(sk))->end_seq,
tp->snd_una + tp->snd_wnd)) {
tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 2 : 3),
flag);
return 1;
}
tp->snd_cwnd = tcp_packets_in_flight(tp) + 2; tp->snd_cwnd = tcp_packets_in_flight(tp) + 2;
tp->frto_counter = 2; tp->frto_counter = 2;
return 1; return 1;
} else /* frto_counter == 2 */ { } else {
switch (sysctl_tcp_frto_response) { switch (sysctl_tcp_frto_response) {
case 2: case 2:
tcp_undo_spur_to_response(sk, flag); tcp_undo_spur_to_response(sk, flag);
......
...@@ -1035,8 +1035,10 @@ static inline int tcp_nagle_test(struct tcp_sock *tp, struct sk_buff *skb, ...@@ -1035,8 +1035,10 @@ static inline int tcp_nagle_test(struct tcp_sock *tp, struct sk_buff *skb,
if (nonagle & TCP_NAGLE_PUSH) if (nonagle & TCP_NAGLE_PUSH)
return 1; return 1;
/* Don't use the nagle rule for urgent data (or for the final FIN). */ /* Don't use the nagle rule for urgent data (or for the final FIN).
if (tp->urg_mode || * Nagle can be ignored during F-RTO too (see RFC4138).
*/
if (tp->urg_mode || (tp->frto_counter == 2) ||
(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN)) (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN))
return 1; return 1;
...@@ -2035,7 +2037,7 @@ void tcp_send_fin(struct sock *sk) ...@@ -2035,7 +2037,7 @@ void tcp_send_fin(struct sock *sk)
/* We get here when a process closes a file descriptor (either due to /* We get here when a process closes a file descriptor (either due to
* an explicit close() or as a byproduct of exit()'ing) and there * an explicit close() or as a byproduct of exit()'ing) and there
* was unread data in the receive queue. This behavior is recommended * was unread data in the receive queue. This behavior is recommended
* by draft-ietf-tcpimpl-prob-03.txt section 3.10. -DaveM * by RFC 2525, section 2.17. -DaveM
*/ */
void tcp_send_active_reset(struct sock *sk, gfp_t priority) void tcp_send_active_reset(struct sock *sk, gfp_t priority)
{ {
......
...@@ -114,14 +114,33 @@ DEFINE_RWLOCK(udp_hash_lock); ...@@ -114,14 +114,33 @@ DEFINE_RWLOCK(udp_hash_lock);
static int udp_port_rover; static int udp_port_rover;
static inline int __udp_lib_lport_inuse(__u16 num, struct hlist_head udptable[]) /*
* Note about this hash function :
* Typical use is probably daddr = 0, only dport is going to vary hash
*/
static inline unsigned int hash_port_and_addr(__u16 port, __be32 addr)
{
addr ^= addr >> 16;
addr ^= addr >> 8;
return port ^ addr;
}
static inline int __udp_lib_port_inuse(unsigned int hash, int port,
__be32 daddr, struct hlist_head udptable[])
{ {
struct sock *sk; struct sock *sk;
struct hlist_node *node; struct hlist_node *node;
struct inet_sock *inet;
sk_for_each(sk, node, &udptable[num & (UDP_HTABLE_SIZE - 1)]) sk_for_each(sk, node, &udptable[hash & (UDP_HTABLE_SIZE - 1)]) {
if (sk->sk_hash == num) if (sk->sk_hash != hash)
continue;
inet = inet_sk(sk);
if (inet->num != port)
continue;
if (inet->rcv_saddr == daddr)
return 1; return 1;
}
return 0; return 0;
} }
...@@ -142,6 +161,7 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum, ...@@ -142,6 +161,7 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
struct hlist_node *node; struct hlist_node *node;
struct hlist_head *head; struct hlist_head *head;
struct sock *sk2; struct sock *sk2;
unsigned int hash;
int error = 1; int error = 1;
write_lock_bh(&udp_hash_lock); write_lock_bh(&udp_hash_lock);
...@@ -156,7 +176,9 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum, ...@@ -156,7 +176,9 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) { for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) {
int size; int size;
head = &udptable[result & (UDP_HTABLE_SIZE - 1)]; hash = hash_port_and_addr(result,
inet_sk(sk)->rcv_saddr);
head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
if (hlist_empty(head)) { if (hlist_empty(head)) {
if (result > sysctl_local_port_range[1]) if (result > sysctl_local_port_range[1])
result = sysctl_local_port_range[0] + result = sysctl_local_port_range[0] +
...@@ -181,7 +203,10 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum, ...@@ -181,7 +203,10 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
result = sysctl_local_port_range[0] result = sysctl_local_port_range[0]
+ ((result - sysctl_local_port_range[0]) & + ((result - sysctl_local_port_range[0]) &
(UDP_HTABLE_SIZE - 1)); (UDP_HTABLE_SIZE - 1));
if (! __udp_lib_lport_inuse(result, udptable)) hash = hash_port_and_addr(result,
inet_sk(sk)->rcv_saddr);
if (! __udp_lib_port_inuse(hash, result,
inet_sk(sk)->rcv_saddr, udptable))
break; break;
} }
if (i >= (1 << 16) / UDP_HTABLE_SIZE) if (i >= (1 << 16) / UDP_HTABLE_SIZE)
...@@ -189,11 +214,13 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum, ...@@ -189,11 +214,13 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
gotit: gotit:
*port_rover = snum = result; *port_rover = snum = result;
} else { } else {
head = &udptable[snum & (UDP_HTABLE_SIZE - 1)]; hash = hash_port_and_addr(snum, inet_sk(sk)->rcv_saddr);
head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
sk_for_each(sk2, node, head) sk_for_each(sk2, node, head)
if (sk2->sk_hash == snum && if (sk2->sk_hash == hash &&
sk2 != sk && sk2 != sk &&
inet_sk(sk2)->num == snum &&
(!sk2->sk_reuse || !sk->sk_reuse) && (!sk2->sk_reuse || !sk->sk_reuse) &&
(!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if
|| sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
...@@ -201,9 +228,9 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum, ...@@ -201,9 +228,9 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
goto fail; goto fail;
} }
inet_sk(sk)->num = snum; inet_sk(sk)->num = snum;
sk->sk_hash = snum; sk->sk_hash = hash;
if (sk_unhashed(sk)) { if (sk_unhashed(sk)) {
head = &udptable[snum & (UDP_HTABLE_SIZE - 1)]; head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
sk_add_node(sk, head); sk_add_node(sk, head);
sock_prot_inc_use(sk->sk_prot); sock_prot_inc_use(sk->sk_prot);
} }
...@@ -242,63 +269,78 @@ static struct sock *__udp4_lib_lookup(__be32 saddr, __be16 sport, ...@@ -242,63 +269,78 @@ static struct sock *__udp4_lib_lookup(__be32 saddr, __be16 sport,
{ {
struct sock *sk, *result = NULL; struct sock *sk, *result = NULL;
struct hlist_node *node; struct hlist_node *node;
unsigned short hnum = ntohs(dport); unsigned int hash, hashwild;
int badness = -1; int score, best = -1;
hash = hash_port_and_addr(ntohs(dport), daddr);
hashwild = hash_port_and_addr(ntohs(dport), 0);
read_lock(&udp_hash_lock); read_lock(&udp_hash_lock);
sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) {
lookup:
sk_for_each(sk, node, &udptable[hash & (UDP_HTABLE_SIZE - 1)]) {
struct inet_sock *inet = inet_sk(sk); struct inet_sock *inet = inet_sk(sk);
if (sk->sk_hash == hnum && !ipv6_only_sock(sk)) { if (sk->sk_hash != hash || ipv6_only_sock(sk) ||
int score = (sk->sk_family == PF_INET ? 1 : 0); inet->num != dport)
if (inet->rcv_saddr) { continue;
if (inet->rcv_saddr != daddr)
continue; score = (sk->sk_family == PF_INET ? 1 : 0);
score+=2; if (inet->rcv_saddr) {
} if (inet->rcv_saddr != daddr)
if (inet->daddr) { continue;
if (inet->daddr != saddr) score+=2;
continue; }
score+=2; if (inet->daddr) {
} if (inet->daddr != saddr)
if (inet->dport) { continue;
if (inet->dport != sport) score+=2;
continue; }
score+=2; if (inet->dport) {
} if (inet->dport != sport)
if (sk->sk_bound_dev_if) { continue;
if (sk->sk_bound_dev_if != dif) score+=2;
continue; }
score+=2; if (sk->sk_bound_dev_if) {
} if (sk->sk_bound_dev_if != dif)
if (score == 9) { continue;
result = sk; score+=2;
break; }
} else if (score > badness) { if (score == 9) {
result = sk; result = sk;
badness = score; goto found;
} } else if (score > best) {
result = sk;
best = score;
} }
} }
if (hash != hashwild) {
hash = hashwild;
goto lookup;
}
found:
if (result) if (result)
sock_hold(result); sock_hold(result);
read_unlock(&udp_hash_lock); read_unlock(&udp_hash_lock);
return result; return result;
} }
static inline struct sock *udp_v4_mcast_next(struct sock *sk, static inline struct sock *udp_v4_mcast_next(
__be16 loc_port, __be32 loc_addr, struct sock *sk,
__be16 rmt_port, __be32 rmt_addr, unsigned int hnum, __be16 loc_port, __be32 loc_addr,
int dif) __be16 rmt_port, __be32 rmt_addr,
int dif)
{ {
struct hlist_node *node; struct hlist_node *node;
struct sock *s = sk; struct sock *s = sk;
unsigned short hnum = ntohs(loc_port);
sk_for_each_from(s, node) { sk_for_each_from(s, node) {
struct inet_sock *inet = inet_sk(s); struct inet_sock *inet = inet_sk(s);
if (s->sk_hash != hnum || if (s->sk_hash != hnum ||
inet->num != loc_port ||
(inet->daddr && inet->daddr != rmt_addr) || (inet->daddr && inet->daddr != rmt_addr) ||
(inet->dport != rmt_port && inet->dport) || (inet->dport != rmt_port && inet->dport) ||
(inet->rcv_saddr && inet->rcv_saddr != loc_addr) || (inet->rcv_saddr && inet->rcv_saddr != loc_addr) ||
...@@ -1129,29 +1171,44 @@ static int __udp4_lib_mcast_deliver(struct sk_buff *skb, ...@@ -1129,29 +1171,44 @@ static int __udp4_lib_mcast_deliver(struct sk_buff *skb,
__be32 saddr, __be32 daddr, __be32 saddr, __be32 daddr,
struct hlist_head udptable[]) struct hlist_head udptable[])
{ {
struct sock *sk; struct sock *sk, *skw, *sknext;
int dif; int dif;
unsigned int hash = hash_port_and_addr(ntohs(uh->dest), daddr);
unsigned int hashwild = hash_port_and_addr(ntohs(uh->dest), 0);
read_lock(&udp_hash_lock);
sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]);
dif = skb->dev->ifindex; dif = skb->dev->ifindex;
sk = udp_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif);
if (sk) {
struct sock *sknext = NULL;
read_lock(&udp_hash_lock);
sk = sk_head(&udptable[hash & (UDP_HTABLE_SIZE - 1)]);
skw = sk_head(&udptable[hashwild & (UDP_HTABLE_SIZE - 1)]);
sk = udp_v4_mcast_next(sk, hash, uh->dest, daddr, uh->source, saddr, dif);
if (!sk) {
hash = hashwild;
sk = udp_v4_mcast_next(skw, hash, uh->dest, daddr, uh->source,
saddr, dif);
}
if (sk) {
do { do {
struct sk_buff *skb1 = skb; struct sk_buff *skb1 = skb;
sknext = udp_v4_mcast_next(sk_next(sk), hash, uh->dest,
sknext = udp_v4_mcast_next(sk_next(sk), uh->dest, daddr, daddr, uh->source, saddr, dif);
uh->source, saddr, dif); if (!sknext && hash != hashwild) {
hash = hashwild;
sknext = udp_v4_mcast_next(skw, hash, uh->dest,
daddr, uh->source, saddr, dif);
}
if (sknext) if (sknext)
skb1 = skb_clone(skb, GFP_ATOMIC); skb1 = skb_clone(skb, GFP_ATOMIC);
if (skb1) { if (skb1) {
int ret = udp_queue_rcv_skb(sk, skb1); int ret = udp_queue_rcv_skb(sk, skb1);
if (ret > 0) if (ret > 0)
/* we should probably re-process instead /*
* of dropping packets here. */ * we should probably re-process
* instead of dropping packets here.
*/
kfree_skb(skb1); kfree_skb(skb1);
} }
sk = sknext; sk = sknext;
......
...@@ -2359,8 +2359,9 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, ...@@ -2359,8 +2359,9 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
break; break;
case NETDEV_CHANGENAME: case NETDEV_CHANGENAME:
#ifdef CONFIG_SYSCTL
if (idev) { if (idev) {
snmp6_unregister_dev(idev);
#ifdef CONFIG_SYSCTL
addrconf_sysctl_unregister(&idev->cnf); addrconf_sysctl_unregister(&idev->cnf);
neigh_sysctl_unregister(idev->nd_parms); neigh_sysctl_unregister(idev->nd_parms);
neigh_sysctl_register(dev, idev->nd_parms, neigh_sysctl_register(dev, idev->nd_parms,
...@@ -2368,8 +2369,9 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, ...@@ -2368,8 +2369,9 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
&ndisc_ifinfo_sysctl_change, &ndisc_ifinfo_sysctl_change,
NULL); NULL);
addrconf_sysctl_register(idev, &idev->cnf); addrconf_sysctl_register(idev, &idev->cnf);
}
#endif #endif
snmp6_register_dev(idev);
}
break; break;
} }
......
...@@ -223,6 +223,7 @@ int snmp6_unregister_dev(struct inet6_dev *idev) ...@@ -223,6 +223,7 @@ int snmp6_unregister_dev(struct inet6_dev *idev)
return -EINVAL; return -EINVAL;
remove_proc_entry(idev->stats.proc_dir_entry->name, remove_proc_entry(idev->stats.proc_dir_entry->name,
proc_net_devsnmp6); proc_net_devsnmp6);
idev->stats.proc_dir_entry = NULL;
return 0; return 0;
} }
......
...@@ -261,7 +261,7 @@ static int xfrm6_tunnel_rcv(struct sk_buff *skb) ...@@ -261,7 +261,7 @@ static int xfrm6_tunnel_rcv(struct sk_buff *skb)
__be32 spi; __be32 spi;
spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr); spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr);
return xfrm6_rcv_spi(skb, spi); return xfrm6_rcv_spi(skb, spi) > 0 ? : 0;
} }
static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt, static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
......
This diff is collapsed.
...@@ -3987,7 +3987,7 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, ...@@ -3987,7 +3987,7 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
memcpy(&temp, &from->ipaddr, sizeof(temp)); memcpy(&temp, &from->ipaddr, sizeof(temp));
sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len; addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len;
if(space_left < addrlen) if (space_left < addrlen)
return -ENOMEM; return -ENOMEM;
if (copy_to_user(to, &temp, addrlen)) if (copy_to_user(to, &temp, addrlen))
return -EFAULT; return -EFAULT;
...@@ -4076,8 +4076,9 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len, ...@@ -4076,8 +4076,9 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len,
/* Helper function that copies local addresses to user and returns the number /* Helper function that copies local addresses to user and returns the number
* of addresses copied. * of addresses copied.
*/ */
static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_addrs, static int sctp_copy_laddrs_old(struct sock *sk, __u16 port,
void __user *to) int max_addrs, void *to,
int *bytes_copied)
{ {
struct list_head *pos, *next; struct list_head *pos, *next;
struct sctp_sockaddr_entry *addr; struct sctp_sockaddr_entry *addr;
...@@ -4094,10 +4095,10 @@ static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_add ...@@ -4094,10 +4095,10 @@ static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_add
sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
&temp); &temp);
addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
if (copy_to_user(to, &temp, addrlen)) memcpy(to, &temp, addrlen);
return -EFAULT;
to += addrlen; to += addrlen;
*bytes_copied += addrlen;
cnt ++; cnt ++;
if (cnt >= max_addrs) break; if (cnt >= max_addrs) break;
} }
...@@ -4105,8 +4106,8 @@ static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_add ...@@ -4105,8 +4106,8 @@ static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_add
return cnt; return cnt;
} }
static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port, static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to,
void __user **to, size_t space_left) size_t space_left, int *bytes_copied)
{ {
struct list_head *pos, *next; struct list_head *pos, *next;
struct sctp_sockaddr_entry *addr; struct sctp_sockaddr_entry *addr;
...@@ -4123,14 +4124,14 @@ static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port, ...@@ -4123,14 +4124,14 @@ static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port,
sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
&temp); &temp);
addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
if(space_left<addrlen) if (space_left < addrlen)
return -ENOMEM; return -ENOMEM;
if (copy_to_user(*to, &temp, addrlen)) memcpy(to, &temp, addrlen);
return -EFAULT;
*to += addrlen; to += addrlen;
cnt ++; cnt ++;
space_left -= addrlen; space_left -= addrlen;
bytes_copied += addrlen;
} }
return cnt; return cnt;
...@@ -4154,6 +4155,8 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len, ...@@ -4154,6 +4155,8 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
int addrlen; int addrlen;
rwlock_t *addr_lock; rwlock_t *addr_lock;
int err = 0; int err = 0;
void *addrs;
int bytes_copied = 0;
if (len != sizeof(struct sctp_getaddrs_old)) if (len != sizeof(struct sctp_getaddrs_old))
return -EINVAL; return -EINVAL;
...@@ -4181,6 +4184,15 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len, ...@@ -4181,6 +4184,15 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
to = getaddrs.addrs; to = getaddrs.addrs;
/* Allocate space for a local instance of packed array to hold all
* the data. We store addresses here first and then put write them
* to the user in one shot.
*/
addrs = kmalloc(sizeof(union sctp_addr) * getaddrs.addr_num,
GFP_KERNEL);
if (!addrs)
return -ENOMEM;
sctp_read_lock(addr_lock); sctp_read_lock(addr_lock);
/* If the endpoint is bound to 0.0.0.0 or ::0, get the valid /* If the endpoint is bound to 0.0.0.0 or ::0, get the valid
...@@ -4190,13 +4202,9 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len, ...@@ -4190,13 +4202,9 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
addr = list_entry(bp->address_list.next, addr = list_entry(bp->address_list.next,
struct sctp_sockaddr_entry, list); struct sctp_sockaddr_entry, list);
if (sctp_is_any(&addr->a)) { if (sctp_is_any(&addr->a)) {
cnt = sctp_copy_laddrs_to_user_old(sk, bp->port, cnt = sctp_copy_laddrs_old(sk, bp->port,
getaddrs.addr_num, getaddrs.addr_num,
to); addrs, &bytes_copied);
if (cnt < 0) {
err = cnt;
goto unlock;
}
goto copy_getaddrs; goto copy_getaddrs;
} }
} }
...@@ -4206,22 +4214,29 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len, ...@@ -4206,22 +4214,29 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
memcpy(&temp, &addr->a, sizeof(temp)); memcpy(&temp, &addr->a, sizeof(temp));
sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
if (copy_to_user(to, &temp, addrlen)) { memcpy(addrs, &temp, addrlen);
err = -EFAULT;
goto unlock;
}
to += addrlen; to += addrlen;
bytes_copied += addrlen;
cnt ++; cnt ++;
if (cnt >= getaddrs.addr_num) break; if (cnt >= getaddrs.addr_num) break;
} }
copy_getaddrs: copy_getaddrs:
sctp_read_unlock(addr_lock);
/* copy the entire address list into the user provided space */
if (copy_to_user(to, addrs, bytes_copied)) {
err = -EFAULT;
goto error;
}
/* copy the leading structure back to user */
getaddrs.addr_num = cnt; getaddrs.addr_num = cnt;
if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs_old))) if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs_old)))
err = -EFAULT; err = -EFAULT;
unlock: error:
sctp_read_unlock(addr_lock); kfree(addrs);
return err; return err;
} }
...@@ -4241,7 +4256,8 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, ...@@ -4241,7 +4256,8 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
rwlock_t *addr_lock; rwlock_t *addr_lock;
int err = 0; int err = 0;
size_t space_left; size_t space_left;
int bytes_copied; int bytes_copied = 0;
void *addrs;
if (len <= sizeof(struct sctp_getaddrs)) if (len <= sizeof(struct sctp_getaddrs))
return -EINVAL; return -EINVAL;
...@@ -4269,6 +4285,9 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, ...@@ -4269,6 +4285,9 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
to = optval + offsetof(struct sctp_getaddrs,addrs); to = optval + offsetof(struct sctp_getaddrs,addrs);
space_left = len - sizeof(struct sctp_getaddrs) - space_left = len - sizeof(struct sctp_getaddrs) -
offsetof(struct sctp_getaddrs,addrs); offsetof(struct sctp_getaddrs,addrs);
addrs = kmalloc(space_left, GFP_KERNEL);
if (!addrs)
return -ENOMEM;
sctp_read_lock(addr_lock); sctp_read_lock(addr_lock);
...@@ -4279,11 +4298,11 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, ...@@ -4279,11 +4298,11 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
addr = list_entry(bp->address_list.next, addr = list_entry(bp->address_list.next,
struct sctp_sockaddr_entry, list); struct sctp_sockaddr_entry, list);
if (sctp_is_any(&addr->a)) { if (sctp_is_any(&addr->a)) {
cnt = sctp_copy_laddrs_to_user(sk, bp->port, cnt = sctp_copy_laddrs(sk, bp->port, addrs,
&to, space_left); space_left, &bytes_copied);
if (cnt < 0) { if (cnt < 0) {
err = cnt; err = cnt;
goto unlock; goto error;
} }
goto copy_getaddrs; goto copy_getaddrs;
} }
...@@ -4294,26 +4313,31 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, ...@@ -4294,26 +4313,31 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
memcpy(&temp, &addr->a, sizeof(temp)); memcpy(&temp, &addr->a, sizeof(temp));
sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
if(space_left < addrlen) if (space_left < addrlen) {
return -ENOMEM; /*fixme: right error?*/ err = -ENOMEM; /*fixme: right error?*/
if (copy_to_user(to, &temp, addrlen)) { goto error;
err = -EFAULT;
goto unlock;
} }
memcpy(addrs, &temp, addrlen);
to += addrlen; to += addrlen;
bytes_copied += addrlen;
cnt ++; cnt ++;
space_left -= addrlen; space_left -= addrlen;
} }
copy_getaddrs: copy_getaddrs:
sctp_read_unlock(addr_lock);
if (copy_to_user(to, addrs, bytes_copied)) {
err = -EFAULT;
goto error;
}
if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num))
return -EFAULT; return -EFAULT;
bytes_copied = ((char __user *)to) - optval;
if (put_user(bytes_copied, optlen)) if (put_user(bytes_copied, optlen))
return -EFAULT; return -EFAULT;
unlock: error:
sctp_read_unlock(addr_lock); kfree(addrs);
return err; return err;
} }
......
...@@ -579,8 +579,22 @@ static inline int xfrm_byidx_should_resize(int total) ...@@ -579,8 +579,22 @@ static inline int xfrm_byidx_should_resize(int total)
return 0; return 0;
} }
static DEFINE_MUTEX(hash_resize_mutex); void xfrm_spd_getinfo(struct xfrm_spdinfo *si)
{
read_lock_bh(&xfrm_policy_lock);
si->incnt = xfrm_policy_count[XFRM_POLICY_IN];
si->outcnt = xfrm_policy_count[XFRM_POLICY_OUT];
si->fwdcnt = xfrm_policy_count[XFRM_POLICY_FWD];
si->inscnt = xfrm_policy_count[XFRM_POLICY_IN+XFRM_POLICY_MAX];
si->outscnt = xfrm_policy_count[XFRM_POLICY_OUT+XFRM_POLICY_MAX];
si->fwdscnt = xfrm_policy_count[XFRM_POLICY_FWD+XFRM_POLICY_MAX];
si->spdhcnt = xfrm_idx_hmask;
si->spdhmcnt = xfrm_policy_hashmax;
read_unlock_bh(&xfrm_policy_lock);
}
EXPORT_SYMBOL(xfrm_spd_getinfo);
static DEFINE_MUTEX(hash_resize_mutex);
static void xfrm_hash_resize(struct work_struct *__unused) static void xfrm_hash_resize(struct work_struct *__unused)
{ {
int dir, total; int dir, total;
...@@ -1330,6 +1344,40 @@ xfrm_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int nx, ...@@ -1330,6 +1344,40 @@ xfrm_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int nx,
return err; return err;
} }
static int inline
xfrm_dst_alloc_copy(void **target, void *src, int size)
{
if (!*target) {
*target = kmalloc(size, GFP_ATOMIC);
if (!*target)
return -ENOMEM;
}
memcpy(*target, src, size);
return 0;
}
static int inline
xfrm_dst_update_parent(struct dst_entry *dst, struct xfrm_selector *sel)
{
#ifdef CONFIG_XFRM_SUB_POLICY
struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
return xfrm_dst_alloc_copy((void **)&(xdst->partner),
sel, sizeof(*sel));
#else
return 0;
#endif
}
static int inline
xfrm_dst_update_origin(struct dst_entry *dst, struct flowi *fl)
{
#ifdef CONFIG_XFRM_SUB_POLICY
struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
return xfrm_dst_alloc_copy((void **)&(xdst->origin), fl, sizeof(*fl));
#else
return 0;
#endif
}
static int stale_bundle(struct dst_entry *dst); static int stale_bundle(struct dst_entry *dst);
...@@ -1518,6 +1566,18 @@ int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, ...@@ -1518,6 +1566,18 @@ int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
err = -EHOSTUNREACH; err = -EHOSTUNREACH;
goto error; goto error;
} }
if (npols > 1)
err = xfrm_dst_update_parent(dst, &pols[1]->selector);
else
err = xfrm_dst_update_origin(dst, fl);
if (unlikely(err)) {
write_unlock_bh(&policy->lock);
if (dst)
dst_free(dst);
goto error;
}
dst->next = policy->bundles; dst->next = policy->bundles;
policy->bundles = dst; policy->bundles = dst;
dst_hold(dst); dst_hold(dst);
...@@ -1933,6 +1993,15 @@ int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first, ...@@ -1933,6 +1993,15 @@ int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first,
if (!dst_check(dst->path, ((struct xfrm_dst *)dst)->path_cookie) || if (!dst_check(dst->path, ((struct xfrm_dst *)dst)->path_cookie) ||
(dst->dev && !netif_running(dst->dev))) (dst->dev && !netif_running(dst->dev)))
return 0; return 0;
#ifdef CONFIG_XFRM_SUB_POLICY
if (fl) {
if (first->origin && !flow_cache_uli_match(first->origin, fl))
return 0;
if (first->partner &&
!xfrm_selector_match(first->partner, fl, family))
return 0;
}
#endif
last = NULL; last = NULL;
......
...@@ -672,6 +672,81 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb, ...@@ -672,6 +672,81 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb,
return skb; return skb;
} }
static int build_spdinfo(struct sk_buff *skb, u32 pid, u32 seq, u32 flags)
{
struct xfrm_spdinfo si;
struct nlmsghdr *nlh;
u32 *f;
nlh = nlmsg_put(skb, pid, seq, XFRM_MSG_NEWSPDINFO, sizeof(u32), 0);
if (nlh == NULL) /* shouldnt really happen ... */
return -EMSGSIZE;
f = nlmsg_data(nlh);
*f = flags;
xfrm_spd_getinfo(&si);
if (flags & XFRM_SPD_HMASK)
NLA_PUT_U32(skb, XFRMA_SPDHMASK, si.spdhcnt);
if (flags & XFRM_SPD_HMAX)
NLA_PUT_U32(skb, XFRMA_SPDHMAX, si.spdhmcnt);
if (flags & XFRM_SPD_ICNT)
NLA_PUT_U32(skb, XFRMA_SPDICNT, si.incnt);
if (flags & XFRM_SPD_OCNT)
NLA_PUT_U32(skb, XFRMA_SPDOCNT, si.outcnt);
if (flags & XFRM_SPD_FCNT)
NLA_PUT_U32(skb, XFRMA_SPDFCNT, si.fwdcnt);
if (flags & XFRM_SPD_ISCNT)
NLA_PUT_U32(skb, XFRMA_SPDISCNT, si.inscnt);
if (flags & XFRM_SPD_OSCNT)
NLA_PUT_U32(skb, XFRMA_SPDOSCNT, si.inscnt);
if (flags & XFRM_SPD_FSCNT)
NLA_PUT_U32(skb, XFRMA_SPDFSCNT, si.inscnt);
return nlmsg_end(skb, nlh);
nla_put_failure:
nlmsg_cancel(skb, nlh);
return -EMSGSIZE;
}
static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
struct rtattr **xfrma)
{
struct sk_buff *r_skb;
u32 *flags = NLMSG_DATA(nlh);
u32 spid = NETLINK_CB(skb).pid;
u32 seq = nlh->nlmsg_seq;
int len = NLMSG_LENGTH(sizeof(u32));
if (*flags & XFRM_SPD_HMASK)
len += RTA_SPACE(sizeof(u32));
if (*flags & XFRM_SPD_HMAX)
len += RTA_SPACE(sizeof(u32));
if (*flags & XFRM_SPD_ICNT)
len += RTA_SPACE(sizeof(u32));
if (*flags & XFRM_SPD_OCNT)
len += RTA_SPACE(sizeof(u32));
if (*flags & XFRM_SPD_FCNT)
len += RTA_SPACE(sizeof(u32));
if (*flags & XFRM_SPD_ISCNT)
len += RTA_SPACE(sizeof(u32));
if (*flags & XFRM_SPD_OSCNT)
len += RTA_SPACE(sizeof(u32));
if (*flags & XFRM_SPD_FSCNT)
len += RTA_SPACE(sizeof(u32));
r_skb = alloc_skb(len, GFP_ATOMIC);
if (r_skb == NULL)
return -ENOMEM;
if (build_spdinfo(r_skb, spid, seq, *flags) < 0)
BUG();
return nlmsg_unicast(xfrm_nl, r_skb, spid);
}
static int build_sadinfo(struct sk_buff *skb, u32 pid, u32 seq, u32 flags) static int build_sadinfo(struct sk_buff *skb, u32 pid, u32 seq, u32 flags)
{ {
struct xfrm_sadinfo si; struct xfrm_sadinfo si;
...@@ -1879,6 +1954,7 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { ...@@ -1879,6 +1954,7 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
[XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report), [XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report),
[XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id), [XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
[XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = NLMSG_LENGTH(sizeof(u32)), [XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = NLMSG_LENGTH(sizeof(u32)),
[XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = NLMSG_LENGTH(sizeof(u32)),
}; };
#undef XMSGSIZE #undef XMSGSIZE
...@@ -1907,6 +1983,7 @@ static struct xfrm_link { ...@@ -1907,6 +1983,7 @@ static struct xfrm_link {
[XFRM_MSG_GETAE - XFRM_MSG_BASE] = { .doit = xfrm_get_ae }, [XFRM_MSG_GETAE - XFRM_MSG_BASE] = { .doit = xfrm_get_ae },
[XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = { .doit = xfrm_do_migrate }, [XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = { .doit = xfrm_do_migrate },
[XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = { .doit = xfrm_get_sadinfo }, [XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = { .doit = xfrm_get_sadinfo },
[XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = { .doit = xfrm_get_spdinfo },
}; };
static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
......
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