Commit 3940ed85 authored by Linus Torvalds's avatar Linus Torvalds

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

into home.osdl.org:/home/torvalds/v2.5/linux
parents 4d53a003 4705cae7
...@@ -1697,7 +1697,7 @@ config NET_POCKET ...@@ -1697,7 +1697,7 @@ config NET_POCKET
<file:Documentation/Changes>) and you can say N here. <file:Documentation/Changes>) and you can say N here.
Laptop users should read the Linux Laptop home page at Laptop users should read the Linux Laptop home page at
<http://www.cs.utexas.edu/users/kharker/linux-laptop/>. <http://www.linux-on-laptops.com/>.
Note that the answer to this question doesn't directly affect the Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all kernel: saying N will just cause the configurator to skip all
......
...@@ -439,12 +439,13 @@ typedef enum { ...@@ -439,12 +439,13 @@ typedef enum {
* 0x0101 Operation Refused Due to Resource Shortage. * 0x0101 Operation Refused Due to Resource Shortage.
* 0x0102 Request to Delete Source IP Address. * 0x0102 Request to Delete Source IP Address.
* 0x0103 Association Aborted due to illegal ASCONF-ACK * 0x0103 Association Aborted due to illegal ASCONF-ACK
* 0x0104 Request refused - no authorization.
*/ */
SCTP_ERROR_DEL_LAST_IP = __constant_htons(0x0100), SCTP_ERROR_DEL_LAST_IP = __constant_htons(0x0100),
SCTP_ERROR_RSRC_LOW = __constant_htons(0x0101), SCTP_ERROR_RSRC_LOW = __constant_htons(0x0101),
SCTP_ERROR_DEL_SRC_IP = __constant_htons(0x0102), SCTP_ERROR_DEL_SRC_IP = __constant_htons(0x0102),
SCTP_ERROR_ASCONF_ACK = __constant_htons(0x0103), SCTP_ERROR_ASCONF_ACK = __constant_htons(0x0103),
SCTP_ERROR_REQ_REFUSED = __constant_htons(0x0104)
} sctp_error_t; } sctp_error_t;
......
...@@ -580,6 +580,7 @@ enum { ...@@ -580,6 +580,7 @@ enum {
NET_SCTP_HB_INTERVAL = 10, NET_SCTP_HB_INTERVAL = 10,
NET_SCTP_PRESERVE_ENABLE = 11, NET_SCTP_PRESERVE_ENABLE = 11,
NET_SCTP_MAX_BURST = 12, NET_SCTP_MAX_BURST = 12,
NET_SCTP_ADDIP_ENABLE = 13,
}; };
/* /proc/sys/net/bridge */ /* /proc/sys/net/bridge */
...@@ -737,6 +738,8 @@ extern int proc_dointvec_minmax(ctl_table *, int, struct file *, ...@@ -737,6 +738,8 @@ extern int proc_dointvec_minmax(ctl_table *, int, struct file *,
void __user *, size_t *); void __user *, size_t *);
extern int proc_dointvec_jiffies(ctl_table *, int, struct file *, extern int proc_dointvec_jiffies(ctl_table *, int, struct file *,
void __user *, size_t *); void __user *, size_t *);
extern int proc_dointvec_userhz_jiffies(ctl_table *, int, struct file *,
void __user *, size_t *);
extern int proc_doulongvec_minmax(ctl_table *, int, struct file *, extern int proc_doulongvec_minmax(ctl_table *, int, struct file *,
void __user *, size_t *); void __user *, size_t *);
extern int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int, extern int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int,
......
...@@ -47,9 +47,7 @@ ...@@ -47,9 +47,7 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/err.h> #include <linux/err.h>
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h> #include <linux/sysctl.h>
#endif
#define NUD_IN_TIMER (NUD_INCOMPLETE|NUD_DELAY|NUD_PROBE) #define NUD_IN_TIMER (NUD_INCOMPLETE|NUD_DELAY|NUD_PROBE)
#define NUD_VALID (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE|NUD_PROBE|NUD_STALE|NUD_DELAY) #define NUD_VALID (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE|NUD_PROBE|NUD_STALE|NUD_DELAY)
......
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001-2002 International Business Machines Corp.
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
...@@ -75,8 +75,6 @@ enum { SCTP_DEFAULT_INSTREAMS = SCTP_MAX_STREAM }; ...@@ -75,8 +75,6 @@ enum { SCTP_DEFAULT_INSTREAMS = SCTP_MAX_STREAM };
#define SCTP_NUM_BASE_CHUNK_TYPES (SCTP_CID_BASE_MAX + 1) #define SCTP_NUM_BASE_CHUNK_TYPES (SCTP_CID_BASE_MAX + 1)
#define SCTP_NUM_CHUNK_TYPES (SCTP_NUM_BASE_CHUNKTYPES + 2) #define SCTP_NUM_CHUNK_TYPES (SCTP_NUM_BASE_CHUNKTYPES + 2)
#define SCTP_CID_ADDIP_MIN SCTP_CID_ASCONF
#define SCTP_CID_ADDIP_MAX SCTP_CID_ASCONF_ACK
#define SCTP_NUM_ADDIP_CHUNK_TYPES 2 #define SCTP_NUM_ADDIP_CHUNK_TYPES 2
/* These are the different flavours of event. */ /* These are the different flavours of event. */
......
...@@ -115,8 +115,10 @@ ...@@ -115,8 +115,10 @@
#define SCTP_STATIC static #define SCTP_STATIC static
#endif #endif
#define MSECS_TO_JIFFIES(msec) (msec * HZ / 1000) #define MSECS_TO_JIFFIES(msec) \
#define JIFFIES_TO_MSECS(jiff) (jiff * 1000 / HZ) (((msec / 1000) * HZ) + ((msec % 1000) * HZ) / 1000)
#define JIFFIES_TO_MSECS(jiff) \
(((jiff / HZ) * 1000) + ((jiff % HZ) * 1000) / HZ)
/* /*
* Function declarations. * Function declarations.
......
...@@ -268,15 +268,15 @@ struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc, ...@@ -268,15 +268,15 @@ struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *, struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *,
union sctp_addr *, union sctp_addr *,
struct sockaddr *, struct sockaddr *,
int, int); int, __u16);
struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc, struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc,
union sctp_addr *addr); union sctp_addr *addr);
struct sctp_chunk *sctp_make_asconf_ack(struct sctp_association *asoc, struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *asoc,
int serial, int vparam_len); __u32 serial, int vparam_len);
struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
struct sctp_chunk *asconf, struct sctp_chunk *asconf);
int vparam_len); int sctp_process_asconf_ack(struct sctp_association *asoc,
struct sctp_chunk *asconf_ack);
void sctp_chunk_assign_tsn(struct sctp_chunk *); void sctp_chunk_assign_tsn(struct sctp_chunk *);
void sctp_chunk_assign_ssn(struct sctp_chunk *); void sctp_chunk_assign_ssn(struct sctp_chunk *);
...@@ -431,6 +431,21 @@ static inline int SSN_lte(__u16 s, __u16 t) ...@@ -431,6 +431,21 @@ static inline int SSN_lte(__u16 s, __u16 t)
return (((s) == (t)) || (((s) - (t)) & SSN_SIGN_BIT)); return (((s) == (t)) || (((s) - (t)) & SSN_SIGN_BIT));
} }
/*
* ADDIP 3.1.1
* The valid range of Serial Number is from 0 to 4294967295 (2**32 - 1). Serial
* Numbers wrap back to 0 after reaching 4294967295.
*/
enum {
ADDIP_SERIAL_SIGN_BIT = (1<<31)
};
static inline int ADDIP_SERIAL_gte(__u16 s, __u16 t)
{
return (((s) == (t)) || (((t) - (s)) & ADDIP_SERIAL_SIGN_BIT));
}
/* Run sctp_add_cmd() generating a BUG() if there is a failure. */ /* Run sctp_add_cmd() generating a BUG() if there is a failure. */
static inline void sctp_add_cmd_sf(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj) static inline void sctp_add_cmd_sf(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj)
{ {
......
...@@ -190,6 +190,9 @@ extern struct sctp_globals { ...@@ -190,6 +190,9 @@ extern struct sctp_globals {
*/ */
struct list_head local_addr_list; struct list_head local_addr_list;
spinlock_t local_addr_lock; spinlock_t local_addr_lock;
/* Flag to indicate if addip is enabled. */
int addip_enable;
} sctp_globals; } sctp_globals;
#define sctp_rto_initial (sctp_globals.rto_initial) #define sctp_rto_initial (sctp_globals.rto_initial)
...@@ -217,6 +220,7 @@ extern struct sctp_globals { ...@@ -217,6 +220,7 @@ extern struct sctp_globals {
#define sctp_port_hashtable (sctp_globals.port_hashtable) #define sctp_port_hashtable (sctp_globals.port_hashtable)
#define sctp_local_addr_list (sctp_globals.local_addr_list) #define sctp_local_addr_list (sctp_globals.local_addr_list)
#define sctp_local_addr_lock (sctp_globals.local_addr_lock) #define sctp_local_addr_lock (sctp_globals.local_addr_lock)
#define sctp_addip_enable (sctp_globals.addip_enable)
/* SCTP Socket type: UDP or TCP style. */ /* SCTP Socket type: UDP or TCP style. */
typedef enum { typedef enum {
...@@ -1397,6 +1401,11 @@ struct sctp_association { ...@@ -1397,6 +1401,11 @@ struct sctp_association {
/* Does peer support ADDIP? */ /* Does peer support ADDIP? */
__u8 asconf_capable; __u8 asconf_capable;
/* This mask is used to disable sending the ASCONF chunk
* with specified parameter to peer.
*/
__u16 addip_disabled_mask;
struct sctp_inithdr i; struct sctp_inithdr i;
int cookie_len; int cookie_len;
void *cookie; void *cookie;
...@@ -1708,6 +1717,8 @@ int sctp_assoc_lookup_laddr(struct sctp_association *asoc, ...@@ -1708,6 +1717,8 @@ int sctp_assoc_lookup_laddr(struct sctp_association *asoc,
struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *, struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *,
const union sctp_addr *address, const union sctp_addr *address,
const int gfp); const int gfp);
void sctp_assoc_del_peer(struct sctp_association *asoc,
const union sctp_addr *addr);
void sctp_assoc_control_transport(struct sctp_association *, void sctp_assoc_control_transport(struct sctp_association *,
struct sctp_transport *, struct sctp_transport *,
sctp_transport_cmd_t, sctp_sn_error_t); sctp_transport_cmd_t, sctp_sn_error_t);
......
This diff is collapsed.
...@@ -1526,7 +1526,12 @@ static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -1526,7 +1526,12 @@ static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock,
SOCK_DEBUG(sk, "AX.25: Appending user data\n"); SOCK_DEBUG(sk, "AX.25: Appending user data\n");
/* User data follows immediately after the AX.25 data */ /* User data follows immediately after the AX.25 data */
memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
err = -EFAULT;
kfree_skb(skb);
goto out;
}
skb->nh.raw = skb->data; skb->nh.raw = skb->data;
/* Add the PID if one is not supplied by the user in the skb */ /* Add the PID if one is not supplied by the user in the skb */
......
...@@ -435,8 +435,10 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff **pskb, ...@@ -435,8 +435,10 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff **pskb,
struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)(skb->mac.ethernet); struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)(skb->mac.ethernet);
struct net_device **d = (struct net_device **)(skb->cb); struct net_device **d = (struct net_device **)(skb->cb);
#ifdef CONFIG_SYSCTL
if (!brnf_call_arptables) if (!brnf_call_arptables)
return NF_ACCEPT; return NF_ACCEPT;
#endif
if (skb->protocol != __constant_htons(ETH_P_ARP)) { if (skb->protocol != __constant_htons(ETH_P_ARP)) {
if (!IS_VLAN_ARP) if (!IS_VLAN_ARP)
......
...@@ -40,7 +40,7 @@ static void dst_run_gc(unsigned long); ...@@ -40,7 +40,7 @@ static void dst_run_gc(unsigned long);
static void ___dst_free(struct dst_entry * dst); static void ___dst_free(struct dst_entry * dst);
static struct timer_list dst_gc_timer = static struct timer_list dst_gc_timer =
TIMER_INITIALIZER(dst_run_gc, 0, DST_GC_MIN); TIMER_INITIALIZER(dst_run_gc, DST_GC_MIN, 0);
static void dst_run_gc(unsigned long dummy) static void dst_run_gc(unsigned long dummy)
{ {
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
#include <linux/sysctl.h> #include <linux/sysctl.h>
#endif #endif
#include <linux/times.h>
#include <net/neighbour.h> #include <net/neighbour.h>
#include <net/dst.h> #include <net/dst.h>
#include <net/sock.h> #include <net/sock.h>
...@@ -1510,7 +1511,7 @@ struct neigh_sysctl_table { ...@@ -1510,7 +1511,7 @@ struct neigh_sysctl_table {
.procname = "retrans_time", .procname = "retrans_time",
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec, .proc_handler = &proc_dointvec_userhz_jiffies,
}, },
{ {
.ctl_name = NET_NEIGH_REACHABLE_TIME, .ctl_name = NET_NEIGH_REACHABLE_TIME,
...@@ -1555,21 +1556,21 @@ struct neigh_sysctl_table { ...@@ -1555,21 +1556,21 @@ struct neigh_sysctl_table {
.procname = "anycast_delay", .procname = "anycast_delay",
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec, .proc_handler = &proc_dointvec_userhz_jiffies,
}, },
{ {
.ctl_name = NET_NEIGH_PROXY_DELAY, .ctl_name = NET_NEIGH_PROXY_DELAY,
.procname = "proxy_delay", .procname = "proxy_delay",
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec, .proc_handler = &proc_dointvec_userhz_jiffies,
}, },
{ {
.ctl_name = NET_NEIGH_LOCKTIME, .ctl_name = NET_NEIGH_LOCKTIME,
.procname = "locktime", .procname = "locktime",
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec, .proc_handler = &proc_dointvec_userhz_jiffies,
}, },
{ {
.ctl_name = NET_NEIGH_GC_INTERVAL, .ctl_name = NET_NEIGH_GC_INTERVAL,
......
...@@ -88,7 +88,7 @@ ...@@ -88,7 +88,7 @@
#define cycles() ((u32)get_cycles()) #define cycles() ((u32)get_cycles())
#define VERSION "pktgen version 1.3" #define VERSION "pktgen version 1.31"
static char version[] __initdata = static char version[] __initdata =
"pktgen.c: v1.3: Packet Generator for packet performance testing.\n"; "pktgen.c: v1.3: Packet Generator for packet performance testing.\n";
...@@ -720,8 +720,18 @@ static void inject(struct pktgen_info* info) ...@@ -720,8 +720,18 @@ static void inject(struct pktgen_info* info)
{ {
char *p = info->result; char *p = info->result;
__u64 pps = (__u32)(info->sofar * 1000) / ((__u32)(total) / 1000); __u64 bps, pps = 0;
__u64 bps = pps * 8 * (info->pkt_size + 4); /* take 32bit ethernet CRC into account */
if (total > 1000)
pps = (__u32)(info->sofar * 1000) / ((__u32)(total) / 1000);
else if(total > 100)
pps = (__u32)(info->sofar * 10000) / ((__u32)(total) / 100);
else if(total > 10)
pps = (__u32)(info->sofar * 100000) / ((__u32)(total) / 10);
else if(total > 1)
pps = (__u32)(info->sofar * 1000000) / (__u32)total;
bps = pps * 8 * (info->pkt_size + 4); /* take 32bit ethernet CRC into account */
p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags) %llupps %lluMb/sec (%llubps) errors: %llu", p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags) %llupps %lluMb/sec (%llubps) errors: %llu",
(unsigned long long) total, (unsigned long long) total,
(unsigned long long) (total - idle), (unsigned long long) (total - idle),
......
...@@ -90,7 +90,7 @@ config IP_ROUTE_NAT ...@@ -90,7 +90,7 @@ config IP_ROUTE_NAT
destination addresses of packets that pass through it, in a manner destination addresses of packets that pass through it, in a manner
you specify. General information about Network Address Translation you specify. General information about Network Address Translation
can be gotten from the document can be gotten from the document
<http://www.csn.tu-chemnitz.de/~mha/linux-ip-nat/diplom/nat.html>. <http://www.hasenstein.com/linux-ip-nat/diplom/nat.html>.
config IP_ROUTE_MULTIPATH config IP_ROUTE_MULTIPATH
bool "IP: equal cost multipath" bool "IP: equal cost multipath"
......
...@@ -3039,7 +3039,7 @@ static int addrconf_sysctl_forward_strategy(ctl_table *table, ...@@ -3039,7 +3039,7 @@ static int addrconf_sysctl_forward_strategy(ctl_table *table,
static struct addrconf_sysctl_table static struct addrconf_sysctl_table
{ {
struct ctl_table_header *sysctl_header; struct ctl_table_header *sysctl_header;
ctl_table addrconf_vars[16]; ctl_table addrconf_vars[17];
ctl_table addrconf_dev[2]; ctl_table addrconf_dev[2];
ctl_table addrconf_conf_dir[2]; ctl_table addrconf_conf_dir[2];
ctl_table addrconf_proto_dir[2]; ctl_table addrconf_proto_dir[2];
...@@ -3180,6 +3180,9 @@ static struct addrconf_sysctl_table ...@@ -3180,6 +3180,9 @@ static struct addrconf_sysctl_table
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec, .proc_handler = &proc_dointvec,
}, },
{
.ctl_name = 0, /* sentinel */
}
}, },
.addrconf_dev = { .addrconf_dev = {
{ {
......
...@@ -294,6 +294,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ...@@ -294,6 +294,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
__u32 v4addr = 0; __u32 v4addr = 0;
unsigned short snum; unsigned short snum;
int addr_type = 0; int addr_type = 0;
int err = 0;
/* If the socket has its own bind function then use it. */ /* If the socket has its own bind function then use it. */
if (sk->sk_prot->bind) if (sk->sk_prot->bind)
...@@ -305,24 +306,6 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ...@@ -305,24 +306,6 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
if ((addr_type & IPV6_ADDR_MULTICAST) && sock->type == SOCK_STREAM) if ((addr_type & IPV6_ADDR_MULTICAST) && sock->type == SOCK_STREAM)
return -EINVAL; return -EINVAL;
/* Check if the address belongs to the host. */
if (addr_type == IPV6_ADDR_MAPPED) {
v4addr = addr->sin6_addr.s6_addr32[3];
if (inet_addr_type(v4addr) != RTN_LOCAL)
return -EADDRNOTAVAIL;
} else {
if (addr_type != IPV6_ADDR_ANY) {
/* ipv4 addr of the socket is invalid. Only the
* unspecified and mapped address have a v4 equivalent.
*/
v4addr = LOOPBACK4_IPV6;
if (!(addr_type & IPV6_ADDR_MULTICAST)) {
if (!ipv6_chk_addr(&addr->sin6_addr, NULL))
return -EADDRNOTAVAIL;
}
}
}
snum = ntohs(addr->sin6_port); snum = ntohs(addr->sin6_port);
if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
return -EACCES; return -EACCES;
...@@ -331,10 +314,21 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ...@@ -331,10 +314,21 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
/* Check these errors (active socket, double bind). */ /* Check these errors (active socket, double bind). */
if (sk->sk_state != TCP_CLOSE || inet->num) { if (sk->sk_state != TCP_CLOSE || inet->num) {
release_sock(sk); err = -EINVAL;
return -EINVAL; goto out;
} }
/* Check if the address belongs to the host. */
if (addr_type == IPV6_ADDR_MAPPED) {
v4addr = addr->sin6_addr.s6_addr32[3];
if (inet_addr_type(v4addr) != RTN_LOCAL) {
err = -EADDRNOTAVAIL;
goto out;
}
} else {
if (addr_type != IPV6_ADDR_ANY) {
struct net_device *dev = NULL;
if (addr_type & IPV6_ADDR_LINKLOCAL) { if (addr_type & IPV6_ADDR_LINKLOCAL) {
if (addr_len >= sizeof(struct sockaddr_in6) && if (addr_len >= sizeof(struct sockaddr_in6) &&
addr->sin6_scope_id) { addr->sin6_scope_id) {
...@@ -346,8 +340,30 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ...@@ -346,8 +340,30 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
/* Binding to link-local address requires an interface */ /* Binding to link-local address requires an interface */
if (!sk->sk_bound_dev_if) { if (!sk->sk_bound_dev_if) {
release_sock(sk); err = -EINVAL;
return -EINVAL; goto out;
}
dev = dev_get_by_index(sk->sk_bound_dev_if);
if (!dev) {
err = -ENODEV;
goto out;
}
}
/* ipv4 addr of the socket is invalid. Only the
* unspecified and mapped address have a v4 equivalent.
*/
v4addr = LOOPBACK4_IPV6;
if (!(addr_type & IPV6_ADDR_MULTICAST)) {
if (!ipv6_chk_addr(&addr->sin6_addr, dev)) {
if (dev)
dev_put(dev);
err = -EADDRNOTAVAIL;
goto out;
}
}
if (dev)
dev_put(dev);
} }
} }
...@@ -362,8 +378,8 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ...@@ -362,8 +378,8 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
/* Make sure we are allowed to bind here. */ /* Make sure we are allowed to bind here. */
if (sk->sk_prot->get_port(sk, snum)) { if (sk->sk_prot->get_port(sk, snum)) {
inet_reset_saddr(sk); inet_reset_saddr(sk);
release_sock(sk); err = -EADDRINUSE;
return -EADDRINUSE; goto out;
} }
if (addr_type != IPV6_ADDR_ANY) if (addr_type != IPV6_ADDR_ANY)
...@@ -373,9 +389,9 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ...@@ -373,9 +389,9 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
inet->sport = ntohs(inet->num); inet->sport = ntohs(inet->num);
inet->dport = 0; inet->dport = 0;
inet->daddr = 0; inet->daddr = 0;
out:
release_sock(sk); release_sock(sk);
return err;
return 0;
} }
int inet6_release(struct socket *sock) int inet6_release(struct socket *sock)
......
...@@ -265,6 +265,8 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl, ...@@ -265,6 +265,8 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
int err = 0; int err = 0;
for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
int addr_type;
struct net_device *dev = NULL;
if (cmsg->cmsg_len < sizeof(struct cmsghdr) || if (cmsg->cmsg_len < sizeof(struct cmsghdr) ||
(unsigned long)(((char*)cmsg - (char*)msg->msg_control) (unsigned long)(((char*)cmsg - (char*)msg->msg_control)
...@@ -291,16 +293,30 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl, ...@@ -291,16 +293,30 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
fl->oif = src_info->ipi6_ifindex; fl->oif = src_info->ipi6_ifindex;
} }
if (!ipv6_addr_any(&src_info->ipi6_addr)) { addr_type = ipv6_addr_type(&src_info->ipi6_addr);
if (!ipv6_chk_addr(&src_info->ipi6_addr, NULL)) {
if (ipv6_addr_type == IPV6_ADDR_ANY)
break;
if (addr_type & IPV6_ADDR_LINKLOCAL) {
if (!src_info->ipi6_ifindex)
return -EINVAL;
else {
dev = dev_get_by_index(src_info->ipi6_ifindex);
if (!dev)
return -ENODEV;
}
}
if (!ipv6_chk_addr(&src_info->ipi6_addr, dev)) {
if (dev)
dev_put(dev);
err = -EINVAL; err = -EINVAL;
goto exit_f; goto exit_f;
} }
if (dev)
dev_put(dev);
ipv6_addr_copy(&fl->fl6_src, ipv6_addr_copy(&fl->fl6_src, &src_info->ipi6_addr);
&src_info->ipi6_addr);
}
break; break;
case IPV6_FLOWINFO: case IPV6_FLOWINFO:
......
...@@ -197,11 +197,15 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) ...@@ -197,11 +197,15 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
if (sk->sk_state != TCP_CLOSE) if (sk->sk_state != TCP_CLOSE)
goto out; goto out;
/* Check if the address belongs to the host. */
if (addr_type != IPV6_ADDR_ANY) {
struct net_device *dev = NULL;
if (addr_type & IPV6_ADDR_LINKLOCAL) { if (addr_type & IPV6_ADDR_LINKLOCAL) {
if (addr_len >= sizeof(struct sockaddr_in6) && if (addr_len >= sizeof(struct sockaddr_in6) &&
addr->sin6_scope_id) { addr->sin6_scope_id) {
/* Override any existing binding, if another one /* Override any existing binding, if another
* is supplied by user. * one is supplied by user.
*/ */
sk->sk_bound_dev_if = addr->sin6_scope_id; sk->sk_bound_dev_if = addr->sin6_scope_id;
} }
...@@ -209,20 +213,29 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) ...@@ -209,20 +213,29 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
/* Binding to link-local address requires an interface */ /* Binding to link-local address requires an interface */
if (!sk->sk_bound_dev_if) if (!sk->sk_bound_dev_if)
goto out; goto out;
dev = dev_get_by_index(sk->sk_bound_dev_if);
if (!dev) {
err = -ENODEV;
goto out;
}
} }
/* Check if the address belongs to the host. */
if (addr_type != IPV6_ADDR_ANY) {
/* ipv4 addr of the socket is invalid. Only the /* ipv4 addr of the socket is invalid. Only the
* unpecified and mapped address have a v4 equivalent. * unpecified and mapped address have a v4 equivalent.
*/ */
v4addr = LOOPBACK4_IPV6; v4addr = LOOPBACK4_IPV6;
if (!(addr_type & IPV6_ADDR_MULTICAST)) { if (!(addr_type & IPV6_ADDR_MULTICAST)) {
err = -EADDRNOTAVAIL; err = -EADDRNOTAVAIL;
if (!ipv6_chk_addr(&addr->sin6_addr, NULL)) if (!ipv6_chk_addr(&addr->sin6_addr, dev)) {
if (dev)
dev_put(dev);
goto out; goto out;
} }
} }
if (dev)
dev_put(dev);
}
inet->rcv_saddr = inet->saddr = v4addr; inet->rcv_saddr = inet->saddr = v4addr;
ipv6_addr_copy(&np->rcv_saddr, &addr->sin6_addr); ipv6_addr_copy(&np->rcv_saddr, &addr->sin6_addr);
......
...@@ -1974,6 +1974,7 @@ ctl_table ipv6_route_table[] = { ...@@ -1974,6 +1974,7 @@ ctl_table ipv6_route_table[] = {
.proc_handler = &proc_dointvec_jiffies, .proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies, .strategy = &sysctl_jiffies,
}, },
{ .ctl_name = 0 }
}; };
#endif #endif
......
...@@ -485,7 +485,8 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -485,7 +485,8 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
{ .daddr = dst, { .daddr = dst,
.saddr = tiph->saddr, .saddr = tiph->saddr,
.tos = RT_TOS(tos) } }, .tos = RT_TOS(tos) } },
.oif = tunnel->parms.link }; .oif = tunnel->parms.link,
.proto = IPPROTO_IPV6 };
if (ip_route_output_key(&rt, &fl)) { if (ip_route_output_key(&rt, &fl)) {
tunnel->stat.tx_carrier_errors++; tunnel->stat.tx_carrier_errors++;
goto tx_error_icmp; goto tx_error_icmp;
...@@ -757,7 +758,8 @@ static int ipip6_tunnel_init(struct net_device *dev) ...@@ -757,7 +758,8 @@ static int ipip6_tunnel_init(struct net_device *dev)
{ .daddr = iph->daddr, { .daddr = iph->daddr,
.saddr = iph->saddr, .saddr = iph->saddr,
.tos = RT_TOS(iph->tos) } }, .tos = RT_TOS(iph->tos) } },
.oif = tunnel->parms.link }; .oif = tunnel->parms.link,
.proto = IPPROTO_IPV6 };
struct rtable *rt; struct rtable *rt;
if (!ip_route_output_key(&rt, &fl)) { if (!ip_route_output_key(&rt, &fl)) {
tdev = rt->u.dst.dev; tdev = rt->u.dst.dev;
......
...@@ -1307,7 +1307,11 @@ static int irda_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -1307,7 +1307,11 @@ static int irda_sendmsg(struct kiocb *iocb, struct socket *sock,
skb_reserve(skb, self->max_header_size + 16); skb_reserve(skb, self->max_header_size + 16);
asmptr = skb->h.raw = skb_put(skb, len); asmptr = skb->h.raw = skb_put(skb, len);
memcpy_fromiovec(asmptr, msg->msg_iov, len); err = memcpy_fromiovec(asmptr, msg->msg_iov, len);
if (err) {
kfree_skb(skb);
return err;
}
/* /*
* Just send the message to TinyTP, and let it deal with possible * Just send the message to TinyTP, and let it deal with possible
...@@ -1550,7 +1554,11 @@ static int irda_sendmsg_dgram(struct kiocb *iocb, struct socket *sock, ...@@ -1550,7 +1554,11 @@ static int irda_sendmsg_dgram(struct kiocb *iocb, struct socket *sock,
IRDA_DEBUG(4, "%s(), appending user data\n", __FUNCTION__); IRDA_DEBUG(4, "%s(), appending user data\n", __FUNCTION__);
asmptr = skb->h.raw = skb_put(skb, len); asmptr = skb->h.raw = skb_put(skb, len);
memcpy_fromiovec(asmptr, msg->msg_iov, len); err = memcpy_fromiovec(asmptr, msg->msg_iov, len);
if (err) {
kfree_skb(skb);
return err;
}
/* /*
* Just send the message to TinyTP, and let it deal with possible * Just send the message to TinyTP, and let it deal with possible
...@@ -1613,7 +1621,11 @@ static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock, ...@@ -1613,7 +1621,11 @@ static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock,
IRDA_DEBUG(4, "%s(), appending user data\n", __FUNCTION__); IRDA_DEBUG(4, "%s(), appending user data\n", __FUNCTION__);
asmptr = skb->h.raw = skb_put(skb, len); asmptr = skb->h.raw = skb_put(skb, len);
memcpy_fromiovec(asmptr, msg->msg_iov, len); err = memcpy_fromiovec(asmptr, msg->msg_iov, len);
if (err) {
kfree_skb(skb);
return err;
}
err = irlmp_connless_data_request(self->lsap, skb); err = irlmp_connless_data_request(self->lsap, skb);
if (err) { if (err) {
......
...@@ -1101,7 +1101,12 @@ static int nr_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -1101,7 +1101,12 @@ static int nr_sendmsg(struct kiocb *iocb, struct socket *sock,
SOCK_DEBUG(sk, "NET/ROM: Appending user data\n"); SOCK_DEBUG(sk, "NET/ROM: Appending user data\n");
/* User data follows immediately after the NET/ROM transport header */ /* User data follows immediately after the NET/ROM transport header */
memcpy_fromiovec(asmptr, msg->msg_iov, len); if (memcpy_fromiovec(asmptr, msg->msg_iov, len)) {
kfree_skb(skb);
err = -EFAULT;
goto out;
}
SOCK_DEBUG(sk, "NET/ROM: Transmitting buffer\n"); SOCK_DEBUG(sk, "NET/ROM: Transmitting buffer\n");
if (sk->sk_state != TCP_ESTABLISHED) { if (sk->sk_state != TCP_ESTABLISHED) {
......
...@@ -1083,7 +1083,11 @@ static int rose_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -1083,7 +1083,11 @@ static int rose_sendmsg(struct kiocb *iocb, struct socket *sock,
asmptr = skb->h.raw = skb_put(skb, len); asmptr = skb->h.raw = skb_put(skb, len);
memcpy_fromiovec(asmptr, msg->msg_iov, len); err = memcpy_fromiovec(asmptr, msg->msg_iov, len);
if (err) {
kfree_skb(skb);
return err;
}
/* /*
* If the Q BIT Include socket option is in force, the first * If the Q BIT Include socket option is in force, the first
...@@ -1133,8 +1137,10 @@ static int rose_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -1133,8 +1137,10 @@ static int rose_sendmsg(struct kiocb *iocb, struct socket *sock,
frontlen = skb_headroom(skb); frontlen = skb_headroom(skb);
while (skb->len > 0) { while (skb->len > 0) {
if ((skbn = sock_alloc_send_skb(sk, frontlen + ROSE_PACLEN, 0, &err)) == NULL) if ((skbn = sock_alloc_send_skb(sk, frontlen + ROSE_PACLEN, 0, &err)) == NULL) {
kfree_skb(skb);
return err; return err;
}
skbn->sk = sk; skbn->sk = sk;
skbn->free = 1; skbn->free = 1;
...@@ -1159,7 +1165,7 @@ static int rose_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -1159,7 +1165,7 @@ static int rose_sendmsg(struct kiocb *iocb, struct socket *sock,
} }
skb->free = 1; skb->free = 1;
kfree_skb(skb, FREE_WRITE); kfree_skb(skb);
} else { } else {
skb_queue_tail(&sk->sk_write_queue, skb); /* Throw it on the queue */ skb_queue_tail(&sk->sk_write_queue, skb); /* Throw it on the queue */
} }
......
...@@ -362,6 +362,14 @@ void sctp_association_free(struct sctp_association *asoc) ...@@ -362,6 +362,14 @@ void sctp_association_free(struct sctp_association *asoc)
asoc->eyecatcher = 0; asoc->eyecatcher = 0;
/* Free any cached ASCONF_ACK chunk. */
if (asoc->addip_last_asconf_ack)
sctp_chunk_free(asoc->addip_last_asconf_ack);
/* Free any cached ASCONF chunk. */
if (asoc->addip_last_asconf)
sctp_chunk_free(asoc->addip_last_asconf);
sctp_association_put(asoc); sctp_association_put(asoc);
} }
...@@ -525,6 +533,45 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, ...@@ -525,6 +533,45 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
return peer; return peer;
} }
/* Delete a transport address from an association. */
void sctp_assoc_del_peer(struct sctp_association *asoc,
const union sctp_addr *addr)
{
struct list_head *pos;
struct list_head *temp;
struct sctp_transport *peer = NULL;
struct sctp_transport *transport;
list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
transport = list_entry(pos, struct sctp_transport, transports);
if (sctp_cmp_addr_exact(addr, &transport->ipaddr)) {
peer = transport;
list_del(pos);
break;
}
}
/* The address we want delete is not in the association. */
if (!peer)
return;
/* Get the first transport of asoc. */
pos = asoc->peer.transport_addr_list.next;
transport = list_entry(pos, struct sctp_transport, transports);
/* Update any entries that match the peer to be deleted. */
if (asoc->peer.primary_path == peer)
sctp_assoc_set_primary(asoc, transport);
if (asoc->peer.active_path == peer)
asoc->peer.active_path = transport;
if (asoc->peer.retran_path == peer)
asoc->peer.retran_path = transport;
if (asoc->peer.last_data_from == peer)
asoc->peer.last_data_from = transport;
sctp_transport_free(peer);
}
/* Lookup a transport by address. */ /* Lookup a transport by address. */
struct sctp_transport *sctp_assoc_lookup_paddr( struct sctp_transport *sctp_assoc_lookup_paddr(
const struct sctp_association *asoc, const struct sctp_association *asoc,
......
...@@ -124,16 +124,16 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -124,16 +124,16 @@ int sctp_rcv(struct sk_buff *skb)
/* Pull up the IP and SCTP headers. */ /* Pull up the IP and SCTP headers. */
__skb_pull(skb, skb->h.raw - skb->data); __skb_pull(skb, skb->h.raw - skb->data);
if (skb->len < sizeof(struct sctphdr)) if (skb->len < sizeof(struct sctphdr))
goto bad_packet; goto discard_it;
if (sctp_rcv_checksum(skb) < 0) if (sctp_rcv_checksum(skb) < 0)
goto bad_packet; goto discard_it;
skb_pull(skb, sizeof(struct sctphdr)); skb_pull(skb, sizeof(struct sctphdr));
family = ipver2af(skb->nh.iph->version); family = ipver2af(skb->nh.iph->version);
af = sctp_get_af_specific(family); af = sctp_get_af_specific(family);
if (unlikely(!af)) if (unlikely(!af))
goto bad_packet; goto discard_it;
/* Initialize local addresses for lookups. */ /* Initialize local addresses for lookups. */
af->from_skb(&src, skb, 1); af->from_skb(&src, skb, 1);
...@@ -223,9 +223,6 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -223,9 +223,6 @@ int sctp_rcv(struct sk_buff *skb)
sock_put(sk); sock_put(sk);
return ret; return ret;
bad_packet:
SCTP_INC_STATS(SctpChecksumErrors);
discard_it: discard_it:
kfree_skb(skb); kfree_skb(skb);
return ret; return ret;
......
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2004
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2003 International Business Machines, Corp.
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
...@@ -350,7 +350,6 @@ int sctp_packet_transmit(struct sctp_packet *packet) ...@@ -350,7 +350,6 @@ int sctp_packet_transmit(struct sctp_packet *packet)
*/ */
SCTP_DEBUG_PRINTK("***sctp_transmit_packet***\n"); SCTP_DEBUG_PRINTK("***sctp_transmit_packet***\n");
while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) { while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) {
if (sctp_chunk_is_data(chunk)) { if (sctp_chunk_is_data(chunk)) {
if (!chunk->has_tsn) { if (!chunk->has_tsn) {
......
...@@ -150,7 +150,7 @@ static inline int sctp_cacc_skip_3_1(struct sctp_transport *primary, ...@@ -150,7 +150,7 @@ static inline int sctp_cacc_skip_3_1(struct sctp_transport *primary,
if (!primary->cacc.cycling_changeover) { if (!primary->cacc.cycling_changeover) {
if (sctp_cacc_skip_3_1_d(primary, transport, count_of_newacks)) if (sctp_cacc_skip_3_1_d(primary, transport, count_of_newacks))
return 1; return 1;
if (sctp_cacc_skip_3_1_f(transport, count_of_newacks)); if (sctp_cacc_skip_3_1_f(transport, count_of_newacks))
return 1; return 1;
return 0; return 0;
} }
......
...@@ -1115,6 +1115,9 @@ __init int sctp_init(void) ...@@ -1115,6 +1115,9 @@ __init int sctp_init(void)
"(established %d bind %d)\n", "(established %d bind %d)\n",
sctp_assoc_hashsize, sctp_port_hashsize); sctp_assoc_hashsize, sctp_port_hashsize);
/* Disable ADDIP by default. */
sctp_addip_enable = 0;
sctp_sysctl_register(); sctp_sysctl_register();
INIT_LIST_HEAD(&sctp_address_families); INIT_LIST_HEAD(&sctp_address_families);
......
This diff is collapsed.
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003 * (C) Copyright IBM Corp. 2001, 2004
* Copyright (c) 1999 Cisco, Inc. * Copyright (c) 1999 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* *
...@@ -663,10 +663,11 @@ static void sctp_cmd_delete_tcb(sctp_cmd_seq_t *cmds, ...@@ -663,10 +663,11 @@ static void sctp_cmd_delete_tcb(sctp_cmd_seq_t *cmds,
struct sock *sk = asoc->base.sk; struct sock *sk = asoc->base.sk;
/* If it is a non-temporary association belonging to a TCP-style /* If it is a non-temporary association belonging to a TCP-style
* listening socket, do not free it so that accept() can pick it * listening socket that is not closed, do not free it so that accept()
* up later. * can pick it up later.
*/ */
if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING) && (!asoc->temp)) if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING) &&
(!asoc->temp) && (sk->sk_shutdown != SHUTDOWN_MASK))
return; return;
sctp_unhash_established(asoc); sctp_unhash_established(asoc);
...@@ -676,8 +677,8 @@ static void sctp_cmd_delete_tcb(sctp_cmd_seq_t *cmds, ...@@ -676,8 +677,8 @@ static void sctp_cmd_delete_tcb(sctp_cmd_seq_t *cmds,
/* /*
* ADDIP Section 4.1 ASCONF Chunk Procedures * ADDIP Section 4.1 ASCONF Chunk Procedures
* A4) Start a T-4 RTO timer, using the RTO value of the selected * A4) Start a T-4 RTO timer, using the RTO value of the selected
* destination address (normally the primary path; see RFC2960 * destination address (we use active path instead of primary path just
* section 6.4 for details). * because primary path may be inactive.
*/ */
static void sctp_cmd_setup_t4(sctp_cmd_seq_t *cmds, static void sctp_cmd_setup_t4(sctp_cmd_seq_t *cmds,
struct sctp_association *asoc, struct sctp_association *asoc,
...@@ -685,7 +686,7 @@ static void sctp_cmd_setup_t4(sctp_cmd_seq_t *cmds, ...@@ -685,7 +686,7 @@ static void sctp_cmd_setup_t4(sctp_cmd_seq_t *cmds,
{ {
struct sctp_transport *t; struct sctp_transport *t;
t = asoc->peer.primary_path; t = asoc->peer.active_path;
asoc->timeouts[SCTP_EVENT_TIMEOUT_T4_RTO] = t->rto; asoc->timeouts[SCTP_EVENT_TIMEOUT_T4_RTO] = t->rto;
chunk->transport = t; chunk->transport = t;
} }
......
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003 * (C) Copyright IBM Corp. 2001, 2004
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2002 Intel Corp. * Copyright (c) 2001-2002 Intel Corp.
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
* Daisy Chang <daisyc@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.com> * Ardelle Fan <ardelle.fan@intel.com>
* Ryan Layer <rmlayer@us.ibm.com> * Ryan Layer <rmlayer@us.ibm.com>
* Kevin Gao <kevin.gao@intel.com>
* *
* Any bugs reported given to us we will try to fix... any fixes shared will * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
...@@ -3066,19 +3067,57 @@ sctp_disposition_t sctp_sf_do_8_5_1_E_sa(const struct sctp_endpoint *ep, ...@@ -3066,19 +3067,57 @@ sctp_disposition_t sctp_sf_do_8_5_1_E_sa(const struct sctp_endpoint *ep,
return sctp_sf_shut_8_4_5(ep, NULL, type, arg, commands); return sctp_sf_shut_8_4_5(ep, NULL, type, arg, commands);
} }
/* /* ADDIP Section 4.2 Upon reception of an ASCONF Chunk. */
* ADDIP Section 4.2 Upon reception of an ASCONF Chunk
* When an endpoint receive an ASCONF Chunk from the remote peer
* special procedures MAY be needed to identify the association the
* ASCONF Chunk is associated with. To properly find the association
* the following procedures should be L1 to L4 and C1 to C5
*/
sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep, sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
const struct sctp_association *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, void *arg, const sctp_subtype_t type, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
// FIXME: Handle the ASCONF chunk struct sctp_chunk *chunk = arg;
struct sctp_chunk *asconf_ack = NULL;
sctp_addiphdr_t *hdr;
__u32 serial;
hdr = (sctp_addiphdr_t *)chunk->skb->data;
serial = ntohl(hdr->serial);
/* ADDIP 4.2 C1) Compare the value of the serial number to the value
* the endpoint stored in a new association variable
* 'Peer-Serial-Number'.
*/
if (serial == asoc->peer.addip_serial + 1) {
/* ADDIP 4.2 C2) If the value found in the serial number is
* equal to the ('Peer-Serial-Number' + 1), the endpoint MUST
* do V1-V5.
*/
asconf_ack = sctp_process_asconf((struct sctp_association *)
asoc, chunk);
if (!asconf_ack)
return SCTP_DISPOSITION_NOMEM;
} else if (serial == asoc->peer.addip_serial) {
/* ADDIP 4.2 C3) If the value found in the serial number is
* equal to the value stored in the 'Peer-Serial-Number'
* IMPLEMENTATION NOTE: As an optimization a receiver may wish
* to save the last ASCONF-ACK for some predetermined period of * time and instead of re-processing the ASCONF (with the same
* serial number) it may just re-transmit the ASCONF-ACK.
*/
if (asoc->addip_last_asconf_ack)
asconf_ack = asoc->addip_last_asconf_ack;
else
return SCTP_DISPOSITION_DISCARD;
} else {
/* ADDIP 4.2 C4) Otherwise, the ASCONF Chunk is discarded since
* it must be either a stale packet or from an attacker.
*/
return SCTP_DISPOSITION_DISCARD;
}
/* ADDIP 4.2 C5) In both cases C2 and C3 the ASCONF-ACK MUST be sent
* back to the source address contained in the IP header of the ASCONF
* being responded to.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(asconf_ack));
return SCTP_DISPOSITION_CONSUME; return SCTP_DISPOSITION_CONSUME;
} }
...@@ -3092,8 +3131,77 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep, ...@@ -3092,8 +3131,77 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
const sctp_subtype_t type, void *arg, const sctp_subtype_t type, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
// FIXME: Handle the ASCONF-ACK chunk struct sctp_chunk *asconf_ack = arg;
struct sctp_chunk *last_asconf = asoc->addip_last_asconf;
struct sctp_chunk *abort;
sctp_addiphdr_t *addip_hdr;
__u32 sent_serial, rcvd_serial;
addip_hdr = (sctp_addiphdr_t *)asconf_ack->skb->data;
rcvd_serial = ntohl(addip_hdr->serial);
if (last_asconf) {
addip_hdr = (sctp_addiphdr_t *)last_asconf->subh.addip_hdr;
sent_serial = ntohl(addip_hdr->serial);
} else {
sent_serial = asoc->addip_serial - 1;
}
/* D0) If an endpoint receives an ASCONF-ACK that is greater than or
* equal to the next serial number to be used but no ASCONF chunk is
* outstanding the endpoint MUST ABORT the association. Note that a
* sequence number is greater than if it is no more than 2^^31-1
* larger than the current sequence number (using serial arithmetic).
*/
if (ADDIP_SERIAL_gte(rcvd_serial, sent_serial + 1) &&
!(asoc->addip_last_asconf)) {
abort = sctp_make_abort(asoc, asconf_ack,
sizeof(sctp_errhdr_t));
if (abort) {
sctp_init_cause(abort, SCTP_ERROR_ASCONF_ACK, NULL, 0);
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
SCTP_CHUNK(abort));
}
/* We are going to ABORT, so we might as well stop
* processing the rest of the chunks in the packet.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO));
sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL());
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
SCTP_U32(SCTP_ERROR_ASCONF_ACK));
SCTP_INC_STATS(SctpAborteds);
SCTP_DEC_STATS(SctpCurrEstab);
return SCTP_DISPOSITION_ABORT;
}
if ((rcvd_serial == sent_serial) && asoc->addip_last_asconf) {
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO));
if (!sctp_process_asconf_ack((struct sctp_association *)asoc,
asconf_ack))
return SCTP_DISPOSITION_CONSUME; return SCTP_DISPOSITION_CONSUME;
abort = sctp_make_abort(asoc, asconf_ack,
sizeof(sctp_errhdr_t));
if (abort) {
sctp_init_cause(abort, SCTP_ERROR_RSRC_LOW, NULL, 0);
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
SCTP_CHUNK(abort));
}
/* We are going to ABORT, so we might as well stop
* processing the rest of the chunks in the packet.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL());
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
SCTP_U32(SCTP_ERROR_ASCONF_ACK));
SCTP_INC_STATS(SctpAborteds);
SCTP_DEC_STATS(SctpCurrEstab);
return SCTP_DISPOSITION_ABORT;
}
return SCTP_DISPOSITION_DISCARD;
} }
/* /*
...@@ -4269,7 +4377,7 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep, ...@@ -4269,7 +4377,7 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep,
/* /*
* ADDIP Section 4.1 ASCONF CHunk Procedures * ADDIP Section 4.1 ASCONF CHunk Procedures
* If the T-4 RTO timer expires the endpoint should do B1 to B5 * If the T4 RTO timer expires the endpoint should do B1 to B5
*/ */
sctp_disposition_t sctp_sf_t4_timer_expire( sctp_disposition_t sctp_sf_t4_timer_expire(
const struct sctp_endpoint *ep, const struct sctp_endpoint *ep,
...@@ -4278,7 +4386,55 @@ sctp_disposition_t sctp_sf_t4_timer_expire( ...@@ -4278,7 +4386,55 @@ sctp_disposition_t sctp_sf_t4_timer_expire(
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
// FIXME: need to handle t4 expire struct sctp_chunk *chunk = asoc->addip_last_asconf;
struct sctp_transport *transport = chunk->transport;
/* ADDIP 4.1 B1) Increment the error counters and perform path failure
* detection on the appropriate destination address as defined in
* RFC2960 [5] section 8.1 and 8.2.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE, SCTP_TRANSPORT(transport));
/* Reconfig T4 timer and transport. */
sctp_add_cmd_sf(commands, SCTP_CMD_SETUP_T4, SCTP_CHUNK(chunk));
/* ADDIP 4.1 B2) Increment the association error counters and perform
* endpoint failure detection on the association as defined in
* RFC2960 [5] section 8.1 and 8.2.
* association error counter is incremented in SCTP_CMD_STRIKE.
*/
if (asoc->overall_error_count >= asoc->max_retrans) {
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO));
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
SCTP_U32(SCTP_ERROR_NO_ERROR));
SCTP_INC_STATS(SctpAborteds);
SCTP_INC_STATS(SctpCurrEstab);
return SCTP_DISPOSITION_ABORT;
}
/* ADDIP 4.1 B3) Back-off the destination address RTO value to which
* the ASCONF chunk was sent by doubling the RTO timer value.
* This is done in SCTP_CMD_STRIKE.
*/
/* ADDIP 4.1 B4) Re-transmit the ASCONF Chunk last sent and if possible
* choose an alternate destination address (please refer to RFC2960
* [5] section 6.4.1). An endpoint MUST NOT add new parameters to this
* chunk, it MUST be the same (including its serial number) as the last
* ASCONF sent.
*/
sctp_chunk_hold(asoc->addip_last_asconf);
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
SCTP_CHUNK(asoc->addip_last_asconf));
/* ADDIP 4.1 B5) Restart the T-4 RTO timer. Note that if a different
* destination is selected, then the RTO used will be that of the new
* destination address.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO));
return SCTP_DISPOSITION_CONSUME; return SCTP_DISPOSITION_CONSUME;
} }
......
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2003 International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 Nokia, Inc.
* *
...@@ -921,13 +921,15 @@ const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid, ...@@ -921,13 +921,15 @@ const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid,
if (state > SCTP_STATE_MAX) if (state > SCTP_STATE_MAX)
return &bug; return &bug;
if (cid >= 0 && cid <= SCTP_CID_BASE_MAX) { if (cid >= 0 && cid <= SCTP_CID_BASE_MAX)
return &chunk_event_table[cid][state]; return &chunk_event_table[cid][state];
}
if (cid >= SCTP_CID_ADDIP_MIN && cid <= SCTP_CID_ADDIP_MAX) { if (sctp_addip_enable) {
return &addip_chunk_event_table if (cid == SCTP_CID_ASCONF)
[cid - SCTP_CID_ADDIP_MIN][state]; return &addip_chunk_event_table[0][state];
if (cid == SCTP_CID_ASCONF_ACK)
return &addip_chunk_event_table[1][state];
} }
return &chunk_event_table_unknown[state]; return &chunk_event_table_unknown[state];
......
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003 * (C) Copyright IBM Corp. 2001, 2004
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2003 Intel Corp. * Copyright (c) 2001-2003 Intel Corp.
...@@ -100,6 +100,8 @@ static int sctp_bindx_add(struct sock *, struct sockaddr *, int); ...@@ -100,6 +100,8 @@ static int sctp_bindx_add(struct sock *, struct sockaddr *, int);
static int sctp_bindx_rem(struct sock *, struct sockaddr *, int); static int sctp_bindx_rem(struct sock *, struct sockaddr *, int);
static int sctp_send_asconf_add_ip(struct sock *, struct sockaddr *, int); static int sctp_send_asconf_add_ip(struct sock *, struct sockaddr *, int);
static int sctp_send_asconf_del_ip(struct sock *, struct sockaddr *, int); static int sctp_send_asconf_del_ip(struct sock *, struct sockaddr *, int);
static int sctp_send_asconf(struct sctp_association *asoc,
struct sctp_chunk *chunk);
static int sctp_do_bind(struct sock *, union sctp_addr *, int); static int sctp_do_bind(struct sock *, union sctp_addr *, int);
static int sctp_autobind(struct sock *sk); static int sctp_autobind(struct sock *sk);
static void sctp_sock_migrate(struct sock *, struct sock *, static void sctp_sock_migrate(struct sock *, struct sock *,
...@@ -150,10 +152,14 @@ struct sctp_transport *sctp_addr_id2transport(struct sock *sk, ...@@ -150,10 +152,14 @@ struct sctp_transport *sctp_addr_id2transport(struct sock *sk,
{ {
struct sctp_association *addr_asoc = NULL, *id_asoc = NULL; struct sctp_association *addr_asoc = NULL, *id_asoc = NULL;
struct sctp_transport *transport; struct sctp_transport *transport;
union sctp_addr *laddr = (union sctp_addr *)addr;
laddr->v4.sin_port = ntohs(laddr->v4.sin_port);
addr_asoc = sctp_endpoint_lookup_assoc(sctp_sk(sk)->ep, addr_asoc = sctp_endpoint_lookup_assoc(sctp_sk(sk)->ep,
(union sctp_addr *)addr, (union sctp_addr *)addr,
&transport); &transport);
laddr->v4.sin_port = htons(laddr->v4.sin_port);
if (!addr_asoc) if (!addr_asoc)
return NULL; return NULL;
...@@ -300,6 +306,41 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) ...@@ -300,6 +306,41 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
return ret; return ret;
} }
/* ADDIP Section 4.1.1 Congestion Control of ASCONF Chunks
*
* R1) One and only one ASCONF Chunk MAY be in transit and unacknowledged
* at any one time. If a sender, after sending an ASCONF chunk, decides
* it needs to transfer another ASCONF Chunk, it MUST wait until the
* ASCONF-ACK Chunk returns from the previous ASCONF Chunk before sending a
* subsequent ASCONF. Note this restriction binds each side, so at any
* time two ASCONF may be in-transit on any given association (one sent
* from each endpoint).
*/
static int sctp_send_asconf(struct sctp_association *asoc,
struct sctp_chunk *chunk)
{
int retval = 0;
/* If there is an outstanding ASCONF chunk, queue it for later
* transmission.
*/
if (asoc->addip_last_asconf) {
__skb_queue_tail(&asoc->addip_chunks, (struct sk_buff *)chunk);
goto out;
}
/* Hold the chunk until an ASCONF_ACK is received. */
sctp_chunk_hold(chunk);
retval = sctp_primitive_ASCONF(asoc, chunk);
if (retval)
sctp_chunk_free(chunk);
else
asoc->addip_last_asconf = chunk;
out:
return retval;
}
/* Add a list of addresses as bind addresses to local endpoint or /* Add a list of addresses as bind addresses to local endpoint or
* association. * association.
* *
...@@ -380,6 +421,9 @@ static int sctp_send_asconf_add_ip(struct sock *sk, ...@@ -380,6 +421,9 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
int i; int i;
int retval = 0; int retval = 0;
if (!sctp_addip_enable)
return retval;
sp = sctp_sk(sk); sp = sctp_sk(sk);
ep = sp->ep; ep = sp->ep;
...@@ -389,10 +433,13 @@ static int sctp_send_asconf_add_ip(struct sock *sk, ...@@ -389,10 +433,13 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
list_for_each(pos, &ep->asocs) { list_for_each(pos, &ep->asocs) {
asoc = list_entry(pos, struct sctp_association, asocs); asoc = list_entry(pos, struct sctp_association, asocs);
if (!sctp_state(asoc, ESTABLISHED)) if (!asoc->peer.asconf_capable)
continue; continue;
if (!asoc->peer.asconf_capable) if (asoc->peer.addip_disabled_mask & SCTP_PARAM_ADD_IP)
continue;
if (!sctp_state(asoc, ESTABLISHED))
continue; continue;
/* Check if any address in the packed array of addresses is /* Check if any address in the packed array of addresses is
...@@ -433,11 +480,7 @@ static int sctp_send_asconf_add_ip(struct sock *sk, ...@@ -433,11 +480,7 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
goto out; goto out;
} }
retval = sctp_primitive_ASCONF(asoc, chunk); retval = sctp_send_asconf(asoc, chunk);
if (retval) {
sctp_chunk_free(chunk);
goto out;
}
/* FIXME: After sending the add address ASCONF chunk, we /* FIXME: After sending the add address ASCONF chunk, we
* cannot append the address to the association's binding * cannot append the address to the association's binding
...@@ -565,6 +608,9 @@ static int sctp_send_asconf_del_ip(struct sock *sk, ...@@ -565,6 +608,9 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
int i; int i;
int retval = 0; int retval = 0;
if (!sctp_addip_enable)
return retval;
sp = sctp_sk(sk); sp = sctp_sk(sk);
ep = sp->ep; ep = sp->ep;
...@@ -574,10 +620,13 @@ static int sctp_send_asconf_del_ip(struct sock *sk, ...@@ -574,10 +620,13 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
list_for_each(pos, &ep->asocs) { list_for_each(pos, &ep->asocs) {
asoc = list_entry(pos, struct sctp_association, asocs); asoc = list_entry(pos, struct sctp_association, asocs);
if (!sctp_state(asoc, ESTABLISHED)) if (!asoc->peer.asconf_capable)
continue; continue;
if (!asoc->peer.asconf_capable) if (asoc->peer.addip_disabled_mask & SCTP_PARAM_DEL_IP)
continue;
if (!sctp_state(asoc, ESTABLISHED))
continue; continue;
/* Check if any address in the packed array of addresses is /* Check if any address in the packed array of addresses is
...@@ -622,11 +671,7 @@ static int sctp_send_asconf_del_ip(struct sock *sk, ...@@ -622,11 +671,7 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
goto out; goto out;
} }
retval = sctp_primitive_ASCONF(asoc, chunk); retval = sctp_send_asconf(asoc, chunk);
if (retval) {
sctp_chunk_free(chunk);
goto out;
}
/* FIXME: After sending the delete address ASCONF chunk, we /* FIXME: After sending the delete address ASCONF chunk, we
* cannot remove the addresses from the association's bind * cannot remove the addresses from the association's bind
...@@ -1920,6 +1965,9 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char *optval, ...@@ -1920,6 +1965,9 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char *optval,
sp = sctp_sk(sk); sp = sctp_sk(sk);
ep = sp->ep; ep = sp->ep;
if (!sctp_addip_enable)
return -EPERM;
if (optlen != sizeof(struct sctp_setpeerprim)) if (optlen != sizeof(struct sctp_setpeerprim))
return -EINVAL; return -EINVAL;
...@@ -1930,6 +1978,12 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char *optval, ...@@ -1930,6 +1978,12 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char *optval,
if (!asoc) if (!asoc)
return -EINVAL; return -EINVAL;
if (!asoc->peer.asconf_capable)
return -EPERM;
if (asoc->peer.addip_disabled_mask & SCTP_PARAM_SET_PRIMARY)
return -EPERM;
if (!sctp_state(asoc, ESTABLISHED)) if (!sctp_state(asoc, ESTABLISHED))
return -ENOTCONN; return -ENOTCONN;
...@@ -1942,15 +1996,11 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char *optval, ...@@ -1942,15 +1996,11 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char *optval,
if (!chunk) if (!chunk)
return -ENOMEM; return -ENOMEM;
err = sctp_primitive_ASCONF(asoc, chunk); err = sctp_send_asconf(asoc, chunk);
if (err) {
sctp_chunk_free(chunk);
return err;
}
SCTP_DEBUG_PRINTK("We set peer primary addr primitively.\n"); SCTP_DEBUG_PRINTK("We set peer primary addr primitively.\n");
return 0; return err;
} }
...@@ -2963,8 +3013,12 @@ static int sctp_getsockopt_primary_addr(struct sock *sk, int len, ...@@ -2963,8 +3013,12 @@ static int sctp_getsockopt_primary_addr(struct sock *sk, int len,
if (!asoc->peer.primary_path) if (!asoc->peer.primary_path)
return -ENOTCONN; return -ENOTCONN;
asoc->peer.primary_path->ipaddr.v4.sin_port =
htons(asoc->peer.primary_path->ipaddr.v4.sin_port);
memcpy(&prim.ssp_addr, &asoc->peer.primary_path->ipaddr, memcpy(&prim.ssp_addr, &asoc->peer.primary_path->ipaddr,
sizeof(union sctp_addr)); sizeof(union sctp_addr));
asoc->peer.primary_path->ipaddr.v4.sin_port =
ntohs(asoc->peer.primary_path->ipaddr.v4.sin_port);
sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp,
(union sctp_addr *)&prim.ssp_addr); (union sctp_addr *)&prim.ssp_addr);
......
...@@ -162,6 +162,14 @@ static ctl_table sctp_table[] = { ...@@ -162,6 +162,14 @@ static ctl_table sctp_table[] = {
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec .proc_handler = &proc_dointvec
}, },
{
.ctl_name = NET_SCTP_ADDIP_ENABLE,
.procname = "addip_enable",
.data = &sctp_addip_enable,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec
},
{ .ctl_name = 0 } { .ctl_name = 0 }
}; };
......
...@@ -81,7 +81,8 @@ proc_dodebug(ctl_table *table, int write, struct file *file, ...@@ -81,7 +81,8 @@ proc_dodebug(ctl_table *table, int write, struct file *file,
if (left > sizeof(tmpbuf) - 1) if (left > sizeof(tmpbuf) - 1)
return -EINVAL; return -EINVAL;
copy_from_user(tmpbuf, p, left); if (copy_from_user(tmpbuf, p, left))
return -EFAULT;
tmpbuf[left] = '\0'; tmpbuf[left] = '\0';
for (p = tmpbuf, value = 0; '0' <= *p && *p <= '9'; p++, left--) for (p = tmpbuf, value = 0; '0' <= *p && *p <= '9'; p++, left--)
...@@ -101,9 +102,11 @@ proc_dodebug(ctl_table *table, int write, struct file *file, ...@@ -101,9 +102,11 @@ proc_dodebug(ctl_table *table, int write, struct file *file,
len = sprintf(tmpbuf, "%d", *(unsigned int *) table->data); len = sprintf(tmpbuf, "%d", *(unsigned int *) table->data);
if (len > left) if (len > left)
len = left; len = left;
__copy_to_user(buffer, tmpbuf, len); if (__copy_to_user(buffer, tmpbuf, len))
return -EFAULT;
if ((left -= len) > 0) { if ((left -= len) > 0) {
put_user('\n', (char *)buffer + len); if (put_user('\n', (char *)buffer + len))
return -EFAULT;
left--; left--;
} }
} }
......
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