X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=net%2Fsctp%2Fsocket.c;h=1316694d0a21ee77fe4473565f4d820ca7d2abbd;hb=7524d7d6de5d5d3f081de8cf5479819fad339661;hp=ff8bc95670edbfa6af9ece6d74d2dc656a9c3cba;hpb=86533e80e0a20ed1a676f9eeb2dde0fa5ff23276;p=linux-2.6 diff --git a/net/sctp/socket.c b/net/sctp/socket.c index ff8bc95670..1316694d0a 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1,4 +1,4 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel implementation * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. @@ -6,7 +6,7 @@ * Copyright (c) 2001-2002 Nokia, Inc. * Copyright (c) 2001 La Monte H.P. Yarroll * - * This file is part of the SCTP kernel reference Implementation + * This file is part of the SCTP kernel implementation * * These functions interface with the sockets layer to implement the * SCTP Extensions for the Sockets API. @@ -15,13 +15,13 @@ * functions--this file is the functions which populate the struct proto * for SCTP which is the BOTTOM of the sockets interface. * - * The SCTP reference implementation is free software; + * This SCTP implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * The SCTP reference implementation is distributed in the hope that it + * This SCTP implementation is distributed in the hope that it * will be useful, but WITHOUT ANY WARRANTY; without even the implied * ************************ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. @@ -174,7 +174,8 @@ static inline void sctp_set_owner_w(struct sctp_chunk *chunk) sizeof(struct sctp_chunk); atomic_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc); - sk_charge_skb(sk, chunk->skb); + sk->sk_wmem_queued += chunk->skb->truesize; + sk_mem_charge(sk, chunk->skb->truesize); } /* Verify that this is a valid address. */ @@ -390,7 +391,7 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) /* Add the address to the bind address list. * Use GFP_ATOMIC since BHs will be disabled. */ - ret = sctp_add_bind_addr(bp, addr, 1, GFP_ATOMIC); + ret = sctp_add_bind_addr(bp, addr, SCTP_ADDR_SRC, GFP_ATOMIC); /* Copy back into socket for getsockname() use. */ if (!ret) { @@ -524,7 +525,7 @@ static int sctp_send_asconf_add_ip(struct sock *sk, ep = sp->ep; SCTP_DEBUG_PRINTK("%s: (sk: %p, addrs: %p, addrcnt: %d)\n", - __FUNCTION__, sk, addrs, addrcnt); + __func__, sk, addrs, addrcnt); list_for_each(pos, &ep->asocs) { asoc = list_entry(pos, struct sctp_association, asocs); @@ -585,8 +586,8 @@ static int sctp_send_asconf_add_ip(struct sock *sk, addr = (union sctp_addr *)addr_buf; af = sctp_get_af_specific(addr->v4.sin_family); memcpy(&saveaddr, addr, af->sockaddr_len); - retval = sctp_add_bind_addr(bp, &saveaddr, 0, - GFP_ATOMIC); + retval = sctp_add_bind_addr(bp, &saveaddr, + SCTP_ADDR_NEW, GFP_ATOMIC); addr_buf += af->sockaddr_len; } } @@ -710,7 +711,7 @@ static int sctp_send_asconf_del_ip(struct sock *sk, ep = sp->ep; SCTP_DEBUG_PRINTK("%s: (sk: %p, addrs: %p, addrcnt: %d)\n", - __FUNCTION__, sk, addrs, addrcnt); + __func__, sk, addrs, addrcnt); list_for_each(pos, &ep->asocs) { asoc = list_entry(pos, struct sctp_association, asocs); @@ -777,7 +778,7 @@ static int sctp_send_asconf_del_ip(struct sock *sk, af = sctp_get_af_specific(laddr->v4.sin_family); list_for_each_entry(saddr, &bp->address_list, list) { if (sctp_cmp_addr_exact(&saddr->a, laddr)) - saddr->use_as_src = 0; + saddr->state = SCTP_ADDR_DEL; } addr_buf += af->sockaddr_len; } @@ -1196,7 +1197,7 @@ SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk, struct sockaddr *kaddrs; SCTP_DEBUG_PRINTK("%s - sk %p addrs %p addrs_size %d\n", - __FUNCTION__, sk, addrs, addrs_size); + __func__, sk, addrs, addrs_size); if (unlikely(addrs_size <= 0)) return -EINVAL; @@ -1910,7 +1911,8 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, * rwnd by that amount. If all the data in the skb is read, * rwnd is updated when the event is freed. */ - sctp_assoc_rwnd_increase(event->asoc, copied); + if (!sctp_ulpevent_is_notification(event)) + sctp_assoc_rwnd_increase(event->asoc, copied); goto out; } else if ((event->msg_flags & MSG_NOTIFICATION) || (event->msg_flags & MSG_EOR)) @@ -1962,7 +1964,7 @@ static int sctp_setsockopt_disable_fragments(struct sock *sk, static int sctp_setsockopt_events(struct sock *sk, char __user *optval, int optlen) { - if (optlen != sizeof(struct sctp_event_subscribe)) + if (optlen > sizeof(struct sctp_event_subscribe)) return -EINVAL; if (copy_from_user(&sctp_sk(sk)->subscribe, optval, optlen)) return -EFAULT; @@ -3278,7 +3280,7 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *addr, sctp_lock_sock(sk); SCTP_DEBUG_PRINTK("%s - sk: %p, sockaddr: %p, addr_len: %d\n", - __FUNCTION__, sk, addr, addr_len); + __func__, sk, addr, addr_len); /* Validate addr_len before calling common connect/connectx routine. */ af = sctp_get_af_specific(addr->sa_family); @@ -3799,7 +3801,7 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval goto out; } - SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p\n", __FUNCTION__, sk, asoc); + SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p\n", __func__, sk, asoc); retval = sctp_do_peeloff(asoc, &newsock); if (retval < 0) @@ -3813,7 +3815,7 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval } SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p newsk: %p sd: %d\n", - __FUNCTION__, sk, asoc, newsock->sk, retval); + __func__, sk, asoc, newsock->sk, retval); /* Return the fd mapped to the new socket. */ peeloff.sd = retval; @@ -4313,6 +4315,9 @@ static int sctp_copy_laddrs_old(struct sock *sk, __u16 port, (AF_INET6 == addr->a.sa.sa_family)) continue; memcpy(&temp, &addr->a, sizeof(temp)); + if (!temp.v4.sin_port) + temp.v4.sin_port = htons(port); + sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), &temp); addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; @@ -4345,6 +4350,9 @@ static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to, (AF_INET6 == addr->a.sa.sa_family)) continue; memcpy(&temp, &addr->a, sizeof(temp)); + if (!temp.v4.sin_port) + temp.v4.sin_port = htons(port); + sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), &temp); addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; @@ -5062,6 +5070,7 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len, struct sctp_authchunks val; struct sctp_association *asoc; struct sctp_chunks_param *ch; + u32 num_chunks; char __user *to; if (len <= sizeof(struct sctp_authchunks)) @@ -5078,12 +5087,15 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len, ch = asoc->peer.peer_chunks; /* See if the user provided enough room for all the data */ - if (len < ntohs(ch->param_hdr.length)) + num_chunks = ntohs(ch->param_hdr.length) - sizeof(sctp_paramhdr_t); + if (len < num_chunks) return -EINVAL; - len = ntohs(ch->param_hdr.length); + len = num_chunks; if (put_user(len, optlen)) return -EFAULT; + if (put_user(num_chunks, &p->gauth_number_of_chunks)) + return -EFAULT; if (copy_to_user(to, ch->chunks, len)) return -EFAULT; @@ -5097,6 +5109,7 @@ static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len, struct sctp_authchunks val; struct sctp_association *asoc; struct sctp_chunks_param *ch; + u32 num_chunks; char __user *to; if (len <= sizeof(struct sctp_authchunks)) @@ -5115,12 +5128,15 @@ static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len, else ch = sctp_sk(sk)->ep->auth_chunk_list; - if (len < ntohs(ch->param_hdr.length)) + num_chunks = ntohs(ch->param_hdr.length) - sizeof(sctp_paramhdr_t); + if (len < num_chunks) return -EINVAL; - len = ntohs(ch->param_hdr.length); + len = num_chunks; if (put_user(len, optlen)) return -EFAULT; + if (put_user(num_chunks, &p->gauth_number_of_chunks)) + return -EFAULT; if (copy_to_user(to, ch->chunks, len)) return -EFAULT; @@ -6008,7 +6024,8 @@ static void __sctp_write_space(struct sctp_association *asoc) */ if (sock->fasync_list && !(sk->sk_shutdown & SEND_SHUTDOWN)) - sock_wake_async(sock, 2, POLL_OUT); + sock_wake_async(sock, + SOCK_WAKE_SPACE, POLL_OUT); } } } @@ -6034,10 +6051,10 @@ static void sctp_wfree(struct sk_buff *skb) atomic_sub(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc); /* - * This undoes what is done via sk_charge_skb + * This undoes what is done via sctp_set_owner_w and sk_mem_charge */ sk->sk_wmem_queued -= skb->truesize; - sk->sk_forward_alloc += skb->truesize; + sk_mem_uncharge(sk, skb->truesize); sock_wfree(skb); __sctp_write_space(asoc); @@ -6058,9 +6075,9 @@ void sctp_sock_rfree(struct sk_buff *skb) atomic_sub(event->rmem_len, &sk->sk_rmem_alloc); /* - * Mimic the behavior of sk_stream_rfree + * Mimic the behavior of sock_rfree */ - sk->sk_forward_alloc += event->rmem_len; + sk_mem_uncharge(sk, event->rmem_len); } @@ -6169,7 +6186,7 @@ static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p) long current_timeo = *timeo_p; DEFINE_WAIT(wait); - SCTP_DEBUG_PRINTK("%s: asoc=%p, timeo=%ld\n", __FUNCTION__, asoc, + SCTP_DEBUG_PRINTK("%s: asoc=%p, timeo=%ld\n", __func__, asoc, (long)(*timeo_p)); /* Increment the association's refcnt. */ @@ -6325,7 +6342,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, struct sctp_endpoint *newep = newsp->ep; struct sk_buff *skb, *tmp; struct sctp_ulpevent *event; - int flags = 0; + struct sctp_bind_hashbucket *head; /* Migrate socket buffer sizes and all the socket level options to the * new socket. @@ -6342,23 +6359,21 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, newsp->hmac = NULL; /* Hook this new socket in to the bind_hash list. */ + head = &sctp_port_hashtable[sctp_phashfn(inet_sk(oldsk)->num)]; + sctp_local_bh_disable(); + sctp_spin_lock(&head->lock); pp = sctp_sk(oldsk)->bind_hash; sk_add_bind_node(newsk, &pp->owner); sctp_sk(newsk)->bind_hash = pp; inet_sk(newsk)->num = inet_sk(oldsk)->num; + sctp_spin_unlock(&head->lock); + sctp_local_bh_enable(); /* Copy the bind_addr list from the original endpoint to the new * endpoint so that we can handle restarts properly */ - if (PF_INET6 == assoc->base.sk->sk_family) - flags = SCTP_ADDR6_ALLOWED; - if (assoc->peer.ipv4_address) - flags |= SCTP_ADDR4_PEERSUPP; - if (assoc->peer.ipv6_address) - flags |= SCTP_ADDR6_PEERSUPP; - sctp_bind_addr_copy(&newsp->ep->base.bind_addr, - &oldsp->ep->base.bind_addr, - SCTP_SCOPE_GLOBAL, GFP_KERNEL, flags); + sctp_bind_addr_dup(&newsp->ep->base.bind_addr, + &oldsp->ep->base.bind_addr, GFP_KERNEL); /* Move any messages in the old socket's receive queue that are for the * peeled off association to the new socket's receive queue. @@ -6481,6 +6496,7 @@ struct proto sctp_prot = { .memory_pressure = &sctp_memory_pressure, .enter_memory_pressure = sctp_enter_memory_pressure, .memory_allocated = &sctp_memory_allocated, + .sockets_allocated = &sctp_sockets_allocated, REF_PROTO_INUSE(sctp) }; @@ -6514,6 +6530,7 @@ struct proto sctpv6_prot = { .memory_pressure = &sctp_memory_pressure, .enter_memory_pressure = sctp_enter_memory_pressure, .memory_allocated = &sctp_memory_allocated, + .sockets_allocated = &sctp_sockets_allocated, REF_PROTO_INUSE(sctpv6) }; #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */