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

Conflicts:
	drivers/net/ethernet/mellanox/mlx4/main.c
	net/packet/af_packet.c

Both conflicts were cases of simple overlapping changes.

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2015-06-24 02:58:51 -07:00
commit 3a07bd6fea
29 changed files with 186 additions and 72 deletions

View File

@ -237,7 +237,7 @@ config HISAX_MIC
config HISAX_NETJET
bool "NETjet card"
depends on PCI && (BROKEN || !(PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV || (XTENSA && !CPU_LITTLE_ENDIAN)))
depends on PCI && (BROKEN || !(PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV || (XTENSA && !CPU_LITTLE_ENDIAN) || MICROBLAZE))
depends on VIRT_TO_BUS
help
This enables HiSax support for the NetJet from Traverse
@ -249,7 +249,7 @@ config HISAX_NETJET
config HISAX_NETJET_U
bool "NETspider U card"
depends on PCI && (BROKEN || !(PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV || (XTENSA && !CPU_LITTLE_ENDIAN)))
depends on PCI && (BROKEN || !(PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV || (XTENSA && !CPU_LITTLE_ENDIAN) || MICROBLAZE))
depends on VIRT_TO_BUS
help
This enables HiSax support for the Netspider U interface ISDN card

View File

@ -440,6 +440,9 @@ unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx)
struct can_frame *cf = (struct can_frame *)skb->data;
u8 dlc = cf->can_dlc;
if (!(skb->tstamp.tv64))
__net_timestamp(skb);
netif_rx(priv->echo_skb[idx]);
priv->echo_skb[idx] = NULL;
@ -575,6 +578,7 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
if (unlikely(!skb))
return NULL;
__net_timestamp(skb);
skb->protocol = htons(ETH_P_CAN);
skb->pkt_type = PACKET_BROADCAST;
skb->ip_summed = CHECKSUM_UNNECESSARY;
@ -603,6 +607,7 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,
if (unlikely(!skb))
return NULL;
__net_timestamp(skb);
skb->protocol = htons(ETH_P_CANFD);
skb->pkt_type = PACKET_BROADCAST;
skb->ip_summed = CHECKSUM_UNNECESSARY;

View File

@ -207,6 +207,7 @@ static void slc_bump(struct slcan *sl)
if (!skb)
return;
__net_timestamp(skb);
skb->dev = sl->dev;
skb->protocol = htons(ETH_P_CAN);
skb->pkt_type = PACKET_BROADCAST;

View File

@ -78,6 +78,9 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
skb->dev = dev;
skb->ip_summed = CHECKSUM_UNNECESSARY;
if (!(skb->tstamp.tv64))
__net_timestamp(skb);
netif_rx_ni(skb);
}

View File

@ -487,6 +487,9 @@ static struct sk_buff *tx_skb_align_workaround(struct net_device *dev,
{
struct sk_buff *new_skb;
if (skb_linearize(skb))
return NULL;
/* Alloc new skb */
new_skb = netdev_alloc_skb(dev, skb->len + 4);
if (!new_skb)
@ -512,12 +515,27 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
cbd_t __iomem *bdp;
int curidx;
u16 sc;
int nr_frags = skb_shinfo(skb)->nr_frags;
int nr_frags;
skb_frag_t *frag;
int len;
#ifdef CONFIG_FS_ENET_MPC5121_FEC
if (((unsigned long)skb->data) & 0x3) {
int is_aligned = 1;
int i;
if (!IS_ALIGNED((unsigned long)skb->data, 4)) {
is_aligned = 0;
} else {
nr_frags = skb_shinfo(skb)->nr_frags;
frag = skb_shinfo(skb)->frags;
for (i = 0; i < nr_frags; i++, frag++) {
if (!IS_ALIGNED(frag->page_offset, 4)) {
is_aligned = 0;
break;
}
}
}
if (!is_aligned) {
skb = tx_skb_align_workaround(dev, skb);
if (!skb) {
/*
@ -529,6 +547,7 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
}
#endif
spin_lock(&fep->tx_lock);
/*
@ -536,6 +555,7 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
*/
bdp = fep->cur_tx;
nr_frags = skb_shinfo(skb)->nr_frags;
if (fep->tx_free <= nr_frags || (CBDR_SC(bdp) & BD_ENET_TX_READY)) {
netif_stop_queue(dev);
spin_unlock(&fep->tx_lock);

View File

@ -1013,6 +1013,12 @@ static void mvneta_defaults_set(struct mvneta_port *pp)
val = mvreg_read(pp, MVNETA_GMAC_CLOCK_DIVIDER);
val |= MVNETA_GMAC_1MS_CLOCK_ENABLE;
mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER, val);
} else {
val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
val &= ~(MVNETA_GMAC_INBAND_AN_ENABLE |
MVNETA_GMAC_AN_SPEED_EN |
MVNETA_GMAC_AN_DUPLEX_EN);
mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
}
mvneta_set_ucast_table(pp, -1);

View File

@ -479,6 +479,14 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
}
}
if (mlx4_is_master(dev) && (dev->caps.num_ports == 2) &&
(port_type_array[0] == MLX4_PORT_TYPE_IB) &&
(port_type_array[1] == MLX4_PORT_TYPE_ETH)) {
mlx4_warn(dev,
"Granular QoS per VF not supported with IB/Eth configuration\n");
dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_QOS_VPP;
}
dev->caps.max_counters = dev_cap->max_counters;
dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW] = dev_cap->reserved_qps;

View File

@ -5297,7 +5297,7 @@ static int __init rocker_module_init(void)
return 0;
err_pci_register_driver:
unregister_netdevice_notifier(&rocker_netevent_nb);
unregister_netevent_notifier(&rocker_netevent_nb);
unregister_netdevice_notifier(&rocker_netdevice_nb);
return err;
}

View File

@ -158,6 +158,8 @@ struct dma_desc {
u32 buffer2_size:13;
u32 reserved4:3;
} etx; /* -- enhanced -- */
u64 all_flags;
} des01;
unsigned int des2;
unsigned int des3;

View File

@ -240,6 +240,7 @@ static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
static void enh_desc_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
int mode, int end)
{
p->des01.all_flags = 0;
p->des01.erx.own = 1;
p->des01.erx.buffer1_size = BUF_SIZE_8KiB - 1;
@ -254,7 +255,7 @@ static void enh_desc_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
static void enh_desc_init_tx_desc(struct dma_desc *p, int mode, int end)
{
p->des01.etx.own = 0;
p->des01.all_flags = 0;
if (mode == STMMAC_CHAIN_MODE)
ehn_desc_tx_set_on_chain(p, end);
else

View File

@ -123,6 +123,7 @@ static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode,
int end)
{
p->des01.all_flags = 0;
p->des01.rx.own = 1;
p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;
@ -137,7 +138,7 @@ static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode,
static void ndesc_init_tx_desc(struct dma_desc *p, int mode, int end)
{
p->des01.tx.own = 0;
p->des01.all_flags = 0;
if (mode == STMMAC_CHAIN_MODE)
ndesc_tx_set_on_chain(p, end);
else

View File

@ -1195,41 +1195,41 @@ static int alloc_dma_desc_resources(struct stmmac_priv *priv)
goto err_tx_skbuff;
if (priv->extend_desc) {
priv->dma_erx = dma_alloc_coherent(priv->device, rxsize *
sizeof(struct
dma_extended_desc),
&priv->dma_rx_phy,
GFP_KERNEL);
priv->dma_erx = dma_zalloc_coherent(priv->device, rxsize *
sizeof(struct
dma_extended_desc),
&priv->dma_rx_phy,
GFP_KERNEL);
if (!priv->dma_erx)
goto err_dma;
priv->dma_etx = dma_alloc_coherent(priv->device, txsize *
sizeof(struct
dma_extended_desc),
&priv->dma_tx_phy,
GFP_KERNEL);
priv->dma_etx = dma_zalloc_coherent(priv->device, txsize *
sizeof(struct
dma_extended_desc),
&priv->dma_tx_phy,
GFP_KERNEL);
if (!priv->dma_etx) {
dma_free_coherent(priv->device, priv->dma_rx_size *
sizeof(struct dma_extended_desc),
priv->dma_erx, priv->dma_rx_phy);
sizeof(struct dma_extended_desc),
priv->dma_erx, priv->dma_rx_phy);
goto err_dma;
}
} else {
priv->dma_rx = dma_alloc_coherent(priv->device, rxsize *
sizeof(struct dma_desc),
&priv->dma_rx_phy,
GFP_KERNEL);
priv->dma_rx = dma_zalloc_coherent(priv->device, rxsize *
sizeof(struct dma_desc),
&priv->dma_rx_phy,
GFP_KERNEL);
if (!priv->dma_rx)
goto err_dma;
priv->dma_tx = dma_alloc_coherent(priv->device, txsize *
sizeof(struct dma_desc),
&priv->dma_tx_phy,
GFP_KERNEL);
priv->dma_tx = dma_zalloc_coherent(priv->device, txsize *
sizeof(struct dma_desc),
&priv->dma_tx_phy,
GFP_KERNEL);
if (!priv->dma_tx) {
dma_free_coherent(priv->device, priv->dma_rx_size *
sizeof(struct dma_desc),
priv->dma_rx, priv->dma_rx_phy);
sizeof(struct dma_desc),
priv->dma_rx, priv->dma_rx_phy);
goto err_dma;
}
}

View File

@ -681,6 +681,9 @@ static int xen_register_watchers(struct xenbus_device *dev, struct xenvif *vif)
char *node;
unsigned maxlen = strlen(dev->nodename) + sizeof("/rate");
if (vif->credit_watch.node)
return -EADDRINUSE;
node = kmalloc(maxlen, GFP_KERNEL);
if (!node)
return -ENOMEM;
@ -770,6 +773,7 @@ static void connect(struct backend_info *be)
}
xen_net_read_rate(dev, &credit_bytes, &credit_usec);
xen_unregister_watchers(be->vif);
xen_register_watchers(dev, be->vif);
read_xenbus_vif_flags(be);

View File

@ -31,6 +31,7 @@ struct netns_sctp {
struct list_head addr_waitq;
struct timer_list addr_wq_timer;
struct list_head auto_asconf_splist;
/* Lock that protects both addr_waitq and auto_asconf_splist */
spinlock_t addr_wq_lock;
/* Lock that protects the local_addr_list writers */

View File

@ -223,6 +223,10 @@ struct sctp_sock {
atomic_t pd_mode;
/* Receive to here while partial delivery is in effect. */
struct sk_buff_head pd_lobby;
/* These must be the last fields, as they will skipped on copies,
* like on accept and peeloff operations
*/
struct list_head auto_asconf_list;
int do_auto_asconf;
};

View File

@ -247,9 +247,7 @@ static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
if (!ns_capable(dev_net(dev)->user_ns, CAP_NET_ADMIN))
return -EPERM;
spin_lock_bh(&br->lock);
br_stp_set_bridge_priority(br, args[1]);
spin_unlock_bh(&br->lock);
return 0;
case BRCTL_SET_PORT_PRIORITY:

View File

@ -37,6 +37,8 @@
static void br_multicast_start_querier(struct net_bridge *br,
struct bridge_mcast_own_query *query);
static void br_multicast_add_router(struct net_bridge *br,
struct net_bridge_port *port);
unsigned int br_mdb_rehash_seq;
static inline int br_ip_equal(const struct br_ip *a, const struct br_ip *b)
@ -936,6 +938,8 @@ void br_multicast_enable_port(struct net_bridge_port *port)
#if IS_ENABLED(CONFIG_IPV6)
br_multicast_enable(&port->ip6_own_query);
#endif
if (port->multicast_router == 2 && hlist_unhashed(&port->rlist))
br_multicast_add_router(br, port);
out:
spin_unlock(&br->multicast_lock);

View File

@ -243,12 +243,13 @@ bool br_stp_recalculate_bridge_id(struct net_bridge *br)
return true;
}
/* called under bridge lock */
/* Acquires and releases bridge lock */
void br_stp_set_bridge_priority(struct net_bridge *br, u16 newprio)
{
struct net_bridge_port *p;
int wasroot;
spin_lock_bh(&br->lock);
wasroot = br_is_root_bridge(br);
list_for_each_entry(p, &br->port_list, list) {
@ -266,6 +267,7 @@ void br_stp_set_bridge_priority(struct net_bridge *br, u16 newprio)
br_port_state_selection(br);
if (br_is_root_bridge(br) && !wasroot)
br_become_root_bridge(br);
spin_unlock_bh(&br->lock);
}
/* called under bridge lock */

View File

@ -310,8 +310,12 @@ int can_send(struct sk_buff *skb, int loop)
return err;
}
if (newskb)
if (newskb) {
if (!(newskb->tstamp.tv64))
__net_timestamp(newskb);
netif_rx_ni(newskb);
}
/* update statistics */
can_stats.tx_frames++;

View File

@ -958,6 +958,8 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
rc = 0;
if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
goto out_unlock_bh;
if (neigh->dead)
goto out_dead;
if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
if (NEIGH_VAR(neigh->parms, MCAST_PROBES) +
@ -1014,6 +1016,13 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
write_unlock(&neigh->lock);
local_bh_enable();
return rc;
out_dead:
if (neigh->nud_state & NUD_STALE)
goto out_unlock_bh;
write_unlock_bh(&neigh->lock);
kfree_skb(skb);
return 1;
}
EXPORT_SYMBOL(__neigh_event_send);
@ -1077,6 +1086,8 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
(old & (NUD_NOARP | NUD_PERMANENT)))
goto out;
if (neigh->dead)
goto out;
if (!(new & NUD_VALID)) {
neigh_del_timer(neigh);
@ -1228,6 +1239,8 @@ EXPORT_SYMBOL(neigh_update);
*/
void __neigh_set_probe_once(struct neighbour *neigh)
{
if (neigh->dead)
return;
neigh->updated = jiffies;
if (!(neigh->nud_state & NUD_FAILED))
return;

View File

@ -228,6 +228,8 @@ int inet_listen(struct socket *sock, int backlog)
err = 0;
if (err)
goto out;
tcp_fastopen_init_key_once(true);
}
err = inet_csk_listen_start(sk, backlog);
if (err)

View File

@ -432,6 +432,15 @@ void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 port, u32 inf
kfree_skb(skb);
}
/* For some errors we have valid addr_offset even with zero payload and
* zero port. Also, addr_offset should be supported if port is set.
*/
static inline bool ipv4_datagram_support_addr(struct sock_exterr_skb *serr)
{
return serr->ee.ee_origin == SO_EE_ORIGIN_ICMP ||
serr->ee.ee_origin == SO_EE_ORIGIN_LOCAL || serr->port;
}
/* IPv4 supports cmsg on all imcp errors and some timestamps
*
* Timestamp code paths do not initialize the fields expected by cmsg:
@ -498,7 +507,7 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
serr = SKB_EXT_ERR(skb);
if (sin && serr->port) {
if (sin && ipv4_datagram_support_addr(serr)) {
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = *(__be32 *)(skb_network_header(skb) +
serr->addr_offset);

View File

@ -2573,10 +2573,13 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
case TCP_FASTOPEN:
if (val >= 0 && ((1 << sk->sk_state) & (TCPF_CLOSE |
TCPF_LISTEN)))
TCPF_LISTEN))) {
tcp_fastopen_init_key_once(true);
err = fastopen_init_queue(sk, val);
else
} else {
err = -EINVAL;
}
break;
case TCP_TIMESTAMP:
if (!tp->repair)

View File

@ -78,8 +78,6 @@ static bool __tcp_fastopen_cookie_gen(const void *path,
struct tcp_fastopen_context *ctx;
bool ok = false;
tcp_fastopen_init_key_once(true);
rcu_read_lock();
ctx = rcu_dereference(tcp_fastopen_ctx);
if (ctx) {

View File

@ -325,6 +325,16 @@ void ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu)
kfree_skb(skb);
}
/* For some errors we have valid addr_offset even with zero payload and
* zero port. Also, addr_offset should be supported if port is set.
*/
static inline bool ipv6_datagram_support_addr(struct sock_exterr_skb *serr)
{
return serr->ee.ee_origin == SO_EE_ORIGIN_ICMP6 ||
serr->ee.ee_origin == SO_EE_ORIGIN_ICMP ||
serr->ee.ee_origin == SO_EE_ORIGIN_LOCAL || serr->port;
}
/* IPv6 supports cmsg on all origins aside from SO_EE_ORIGIN_LOCAL.
*
* At one point, excluding local errors was a quick test to identify icmp/icmp6
@ -389,7 +399,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
serr = SKB_EXT_ERR(skb);
if (sin && serr->port) {
if (sin && ipv6_datagram_support_addr(serr)) {
const unsigned char *nh = skb_network_header(skb);
sin->sin6_family = AF_INET6;
sin->sin6_flowinfo = 0;

View File

@ -66,12 +66,15 @@ update_vlan_tailroom_need_count(struct ieee80211_sub_if_data *sdata, int delta)
if (sdata->vif.type != NL80211_IFTYPE_AP)
return;
mutex_lock(&sdata->local->mtx);
/* crypto_tx_tailroom_needed_cnt is protected by this */
assert_key_lock(sdata->local);
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
rcu_read_lock();
list_for_each_entry_rcu(vlan, &sdata->u.ap.vlans, u.vlan.list)
vlan->crypto_tx_tailroom_needed_cnt += delta;
mutex_unlock(&sdata->local->mtx);
rcu_read_unlock();
}
static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata)
@ -95,6 +98,8 @@ static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata)
* http://mid.gmane.org/1308590980.4322.19.camel@jlt3.sipsolutions.net
*/
assert_key_lock(sdata->local);
update_vlan_tailroom_need_count(sdata, 1);
if (!sdata->crypto_tx_tailroom_needed_cnt++) {
@ -109,6 +114,8 @@ static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata)
static void decrease_tailroom_need_count(struct ieee80211_sub_if_data *sdata,
int delta)
{
assert_key_lock(sdata->local);
WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt < delta);
update_vlan_tailroom_need_count(sdata, -delta);

View File

@ -1322,16 +1322,6 @@ static void packet_sock_destruct(struct sock *sk)
sk_refcnt_debug_dec(sk);
}
static int fanout_rr_next(struct packet_fanout *f, unsigned int num)
{
int x = atomic_read(&f->rr_cur) + 1;
if (x >= num)
x = 0;
return x;
}
static bool fanout_flow_is_huge(struct packet_sock *po, struct sk_buff *skb)
{
u32 rxhash;
@ -1357,13 +1347,9 @@ static unsigned int fanout_demux_lb(struct packet_fanout *f,
struct sk_buff *skb,
unsigned int num)
{
int cur, old;
unsigned int val = atomic_inc_return(&f->rr_cur);
cur = atomic_read(&f->rr_cur);
while ((old = atomic_cmpxchg(&f->rr_cur, cur,
fanout_rr_next(f, num))) != cur)
cur = old;
return cur;
return val % num;
}
static unsigned int fanout_demux_cpu(struct packet_fanout *f,
@ -1435,7 +1421,7 @@ static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
{
struct packet_fanout *f = pt->af_packet_priv;
unsigned int num = f->num_members;
unsigned int num = READ_ONCE(f->num_members);
struct packet_sock *po;
unsigned int idx;

View File

@ -192,7 +192,8 @@ static void rose_kill_by_device(struct net_device *dev)
if (rose->device == dev) {
rose_disconnect(s, ENETUNREACH, ROSE_OUT_OF_ORDER, 0);
rose->neighbour->use--;
if (rose->neighbour)
rose->neighbour->use--;
rose->device = NULL;
}
}

View File

@ -1528,8 +1528,10 @@ static void sctp_close(struct sock *sk, long timeout)
/* Supposedly, no process has access to the socket, but
* the net layers still may.
* Also, sctp_destroy_sock() needs to be called with addr_wq_lock
* held and that should be grabbed before socket lock.
*/
local_bh_disable();
spin_lock_bh(&net->sctp.addr_wq_lock);
bh_lock_sock(sk);
/* Hold the sock, since sk_common_release() will put sock_put()
@ -1539,7 +1541,7 @@ static void sctp_close(struct sock *sk, long timeout)
sk_common_release(sk);
bh_unlock_sock(sk);
local_bh_enable();
spin_unlock_bh(&net->sctp.addr_wq_lock);
sock_put(sk);
@ -3580,6 +3582,7 @@ static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval,
if ((val && sp->do_auto_asconf) || (!val && !sp->do_auto_asconf))
return 0;
spin_lock_bh(&sock_net(sk)->sctp.addr_wq_lock);
if (val == 0 && sp->do_auto_asconf) {
list_del(&sp->auto_asconf_list);
sp->do_auto_asconf = 0;
@ -3588,6 +3591,7 @@ static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval,
&sock_net(sk)->sctp.auto_asconf_splist);
sp->do_auto_asconf = 1;
}
spin_unlock_bh(&sock_net(sk)->sctp.addr_wq_lock);
return 0;
}
@ -4121,18 +4125,28 @@ static int sctp_init_sock(struct sock *sk)
local_bh_disable();
percpu_counter_inc(&sctp_sockets_allocated);
sock_prot_inuse_add(net, sk->sk_prot, 1);
/* Nothing can fail after this block, otherwise
* sctp_destroy_sock() will be called without addr_wq_lock held
*/
if (net->sctp.default_auto_asconf) {
spin_lock(&sock_net(sk)->sctp.addr_wq_lock);
list_add_tail(&sp->auto_asconf_list,
&net->sctp.auto_asconf_splist);
sp->do_auto_asconf = 1;
} else
spin_unlock(&sock_net(sk)->sctp.addr_wq_lock);
} else {
sp->do_auto_asconf = 0;
}
local_bh_enable();
return 0;
}
/* Cleanup any SCTP per socket resources. */
/* Cleanup any SCTP per socket resources. Must be called with
* sock_net(sk)->sctp.addr_wq_lock held if sp->do_auto_asconf is true
*/
static void sctp_destroy_sock(struct sock *sk)
{
struct sctp_sock *sp;
@ -7195,6 +7209,19 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk,
newinet->mc_list = NULL;
}
static inline void sctp_copy_descendant(struct sock *sk_to,
const struct sock *sk_from)
{
int ancestor_size = sizeof(struct inet_sock) +
sizeof(struct sctp_sock) -
offsetof(struct sctp_sock, auto_asconf_list);
if (sk_from->sk_family == PF_INET6)
ancestor_size += sizeof(struct ipv6_pinfo);
__inet_sk_copy_descendant(sk_to, sk_from, ancestor_size);
}
/* Populate the fields of the newsk from the oldsk and migrate the assoc
* and its messages to the newsk.
*/
@ -7209,7 +7236,6 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
struct sk_buff *skb, *tmp;
struct sctp_ulpevent *event;
struct sctp_bind_hashbucket *head;
struct list_head tmplist;
/* Migrate socket buffer sizes and all the socket level options to the
* new socket.
@ -7217,12 +7243,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
newsk->sk_sndbuf = oldsk->sk_sndbuf;
newsk->sk_rcvbuf = oldsk->sk_rcvbuf;
/* Brute force copy old sctp opt. */
if (oldsp->do_auto_asconf) {
memcpy(&tmplist, &newsp->auto_asconf_list, sizeof(tmplist));
inet_sk_copy_descendant(newsk, oldsk);
memcpy(&newsp->auto_asconf_list, &tmplist, sizeof(tmplist));
} else
inet_sk_copy_descendant(newsk, oldsk);
sctp_copy_descendant(newsk, oldsk);
/* Restore the ep value that was overwritten with the above structure
* copy.