⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 socket.c

📁 一种在UDP协议中实现了拥赛控制和重传机制的协议
💻 C
📖 第 1 页 / 共 5 页
字号:
/* SCTP kernel reference Implementation * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001-2003 Intel Corp. * Copyright (c) 2001-2002 Nokia, Inc. * Copyright (c) 2001 La Monte H.P. Yarroll * * This file is part of the SCTP kernel reference Implementation * * These functions interface with the sockets layer to implement the * SCTP Extensions for the Sockets API. * * Note that the descriptions from the specification are USER level * 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; * 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 * will be useful, but WITHOUT ANY WARRANTY; without even the implied *                 ************************ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU CC; see the file COPYING.  If not, write to * the Free Software Foundation, 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * Please send any bug reports or fixes you make to the * email address(es): *    lksctp developers <lksctp-developers@lists.sourceforge.net> * * Or submit a bug report through the following website: *    http://www.sf.net/projects/lksctp * * Written or modified by: *    La Monte H.P. Yarroll <piggy@acm.org> *    Narasimha Budihal     <narsi@refcode.org> *    Karl Knutson          <karl@athena.chicago.il.us> *    Jon Grimm             <jgrimm@us.ibm.com> *    Xingang Guo           <xingang.guo@intel.com> *    Daisy Chang           <daisyc@us.ibm.com> *    Sridhar Samudrala     <samudrala@us.ibm.com> *    Inaky Perez-Gonzalez  <inaky.gonzalez@intel.com> *    Ardelle Fan	    <ardelle.fan@intel.com> *    Ryan Layer	    <rmlayer@us.ibm.com> *    Anup Pemmaiah         <pemmaiah@cc.usu.edu> *    Kevin Gao             <kevin.gao@intel.com> * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. */#include <linux/config.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/wait.h>#include <linux/time.h>#include <linux/ip.h>#include <linux/fcntl.h>#include <linux/poll.h>#include <linux/init.h>#include <linux/crypto.h>#include <net/ip.h>#include <net/icmp.h>#include <net/route.h>#include <net/ipv6.h>#include <net/inet_common.h>#include <linux/socket.h> /* for sa_family_t */#include <net/sock.h>#include <net/sctp/sctp.h>#include <net/sctp/sm.h>/* WARNING:  Please do not remove the SCTP_STATIC attribute to * any of the functions below as they are used to export functions * used by a project regression testsuite. *//* Forward declarations for internal helper functions. */static int sctp_writeable(struct sock *sk);static void sctp_wfree(struct sk_buff *skb);static int sctp_wait_for_sndbuf(struct sctp_association *, long *timeo_p,				size_t msg_len);static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p);static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p);static int sctp_wait_for_accept(struct sock *sk, long timeo);static void sctp_wait_for_close(struct sock *sk, long timeo);static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt,					union sctp_addr *addr, int len);static int sctp_bindx_add(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_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_autobind(struct sock *sk);static void sctp_sock_migrate(struct sock *, struct sock *,			      struct sctp_association *, sctp_socket_type_t);static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG;extern kmem_cache_t *sctp_bucket_cachep;/* Get the sndbuf space available at the time on the association.  */static inline int sctp_wspace(struct sctp_association *asoc){	struct sock *sk = asoc->base.sk;	int amt = 0;	if (asoc->ep->sndbuf_policy) {		/* make sure that no association uses more than sk_sndbuf */		amt = sk->sk_sndbuf - asoc->sndbuf_used;	} else {		/* do socket level accounting */		amt = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);	}	if (amt < 0)		amt = 0;	return amt;}/* Increment the used sndbuf space count of the corresponding association by * the size of the outgoing data chunk. * Also, set the skb destructor for sndbuf accounting later. * * Since it is always 1-1 between chunk and skb, and also a new skb is always * allocated for chunk bundling in sctp_packet_transmit(), we can use the * destructor in the data chunk skb for the purpose of the sndbuf space * tracking. */static inline void sctp_set_owner_w(struct sctp_chunk *chunk){	struct sctp_association *asoc = chunk->asoc;	struct sock *sk = asoc->base.sk;	/* The sndbuf space is tracked per association.  */	sctp_association_hold(asoc);	skb_set_owner_w(chunk->skb, sk);	chunk->skb->destructor = sctp_wfree;	/* Save the chunk pointer in skb for sctp_wfree to use later.  */	*((struct sctp_chunk **)(chunk->skb->cb)) = chunk;	asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk) +				sizeof(struct sk_buff) +				sizeof(struct sctp_chunk);	sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk) +				sizeof(struct sk_buff) +				sizeof(struct sctp_chunk);	atomic_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc);}/* Verify that this is a valid address. */static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr,				   int len){	struct sctp_af *af;	/* Verify basic sockaddr. */	af = sctp_sockaddr_af(sctp_sk(sk), addr, len);	if (!af)		return -EINVAL;	/* Is this a valid SCTP address?  */	if (!af->addr_valid(addr, sctp_sk(sk)))		return -EINVAL;	if (!sctp_sk(sk)->pf->send_verify(sctp_sk(sk), (addr)))		return -EINVAL;	return 0;}/* Look up the association by its id.  If this is not a UDP-style * socket, the ID field is always ignored. */struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id){	struct sctp_association *asoc = NULL;	/* If this is not a UDP-style socket, assoc id should be ignored. */	if (!sctp_style(sk, UDP)) {		/* Return NULL if the socket state is not ESTABLISHED. It		 * could be a TCP-style listening socket or a socket which		 * hasn't yet called connect() to establish an association.		 */		if (!sctp_sstate(sk, ESTABLISHED))			return NULL;		/* Get the first and the only association from the list. */		if (!list_empty(&sctp_sk(sk)->ep->asocs))			asoc = list_entry(sctp_sk(sk)->ep->asocs.next,					  struct sctp_association, asocs);		return asoc;	}	/* Otherwise this is a UDP-style socket. */	if (!id || (id == (sctp_assoc_t)-1))		return NULL;	spin_lock_bh(&sctp_assocs_id_lock);	asoc = (struct sctp_association *)idr_find(&sctp_assocs_id, (int)id);	spin_unlock_bh(&sctp_assocs_id_lock);	if (!asoc || (asoc->base.sk != sk) || asoc->base.dead)		return NULL;	return asoc;}/* Look up the transport from an address and an assoc id. If both address and * id are specified, the associations matching the address and the id should be * the same. */static struct sctp_transport *sctp_addr_id2transport(struct sock *sk,					      struct sockaddr_storage *addr,					      sctp_assoc_t id){	struct sctp_association *addr_asoc = NULL, *id_asoc = NULL;	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,					       (union sctp_addr *)addr,					       &transport);	laddr->v4.sin_port = htons(laddr->v4.sin_port);	if (!addr_asoc)		return NULL;	id_asoc = sctp_id2assoc(sk, id);	if (id_asoc && (id_asoc != addr_asoc))		return NULL;	sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),						(union sctp_addr *)addr);	return transport;}/* API 3.1.2 bind() - UDP Style Syntax * The syntax of bind() is, * *   ret = bind(int sd, struct sockaddr *addr, int addrlen); * *   sd      - the socket descriptor returned by socket(). *   addr    - the address structure (struct sockaddr_in or struct *             sockaddr_in6 [RFC 2553]), *   addr_len - the size of the address structure. */SCTP_STATIC int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len){	int retval = 0;	sctp_lock_sock(sk);	SCTP_DEBUG_PRINTK("sctp_bind(sk: %p, uaddr: %p, addr_len: %d)\n",			  sk, uaddr, addr_len);	/* Disallow binding twice. */	if (!sctp_sk(sk)->ep->base.bind_addr.port)		retval = sctp_do_bind(sk, (union sctp_addr *)uaddr,				      addr_len);	else		retval = -EINVAL;	sctp_release_sock(sk);	return retval;}static long sctp_get_port_local(struct sock *, union sctp_addr *);/* Verify this is a valid sockaddr. */static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt,					union sctp_addr *addr, int len){	struct sctp_af *af;	/* Check minimum size.  */	if (len < sizeof (struct sockaddr))		return NULL;	/* Does this PF support this AF? */	if (!opt->pf->af_supported(addr->sa.sa_family, opt))		return NULL;	/* If we get this far, af is valid. */	af = sctp_get_af_specific(addr->sa.sa_family);	if (len < af->sockaddr_len)		return NULL;	return af;}/* Bind a local address either to an endpoint or to an association.  */SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len){	struct sctp_sock *sp = sctp_sk(sk);	struct sctp_endpoint *ep = sp->ep;	struct sctp_bind_addr *bp = &ep->base.bind_addr;	struct sctp_af *af;	unsigned short snum;	int ret = 0;	SCTP_DEBUG_PRINTK("sctp_do_bind(sk: %p, newaddr: %p, len: %d)\n",			  sk, addr, len);	/* Common sockaddr verification. */	af = sctp_sockaddr_af(sp, addr, len);	if (!af)		return -EINVAL;	/* PF specific bind() address verification. */	if (!sp->pf->bind_verify(sp, addr))		return -EADDRNOTAVAIL;	snum= ntohs(addr->v4.sin_port);	SCTP_DEBUG_PRINTK("sctp_do_bind: port: %d, new port: %d\n",			  bp->port, snum);	/* We must either be unbound, or bind to the same port.  */	if (bp->port && (snum != bp->port)) {		SCTP_DEBUG_PRINTK("sctp_do_bind:"				  " New port %d does not match existing port "				  "%d.\n", snum, bp->port);		return -EINVAL;	}	if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))		return -EACCES;	/* Make sure we are allowed to bind here.	 * The function sctp_get_port_local() does duplicate address	 * detection.	 */	if ((ret = sctp_get_port_local(sk, addr))) {		if (ret == (long) sk) {			/* This endpoint has a conflicting address. */			return -EINVAL;		} else {			return -EADDRINUSE;		}	}	/* Refresh ephemeral port.  */	if (!bp->port)		bp->port = inet_sk(sk)->num;	/* Add the address to the bind address list.  */	sctp_local_bh_disable();	sctp_write_lock(&ep->base.addr_lock);	/* Use GFP_ATOMIC since BHs are disabled.  */	addr->v4.sin_port = ntohs(addr->v4.sin_port);	ret = sctp_add_bind_addr(bp, addr, GFP_ATOMIC);	addr->v4.sin_port = htons(addr->v4.sin_port);	sctp_write_unlock(&ep->base.addr_lock);	sctp_local_bh_enable();	/* Copy back into socket for getsockname() use. */	if (!ret) {		inet_sk(sk)->sport = htons(inet_sk(sk)->num);		af->to_sk_saddr(addr, sk);	}	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 * association. * * Basically run through each address specified in the addrs/addrcnt * array/length pair, determine if it is IPv6 or IPv4 and call * sctp_do_bind() on it. * * If any of them fails, then the operation will be reversed and the * ones that were added will be removed. * * Only sctp_setsockopt_bindx() is supposed to call this function. */int sctp_bindx_add(struct sock *sk, struct sockaddr *addrs, int addrcnt){	int cnt;	int retval = 0;	void *addr_buf;	struct sockaddr *sa_addr;	struct sctp_af *af;	SCTP_DEBUG_PRINTK("sctp_bindx_add (sk: %p, addrs: %p, addrcnt: %d)\n",			  sk, addrs, addrcnt);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -