📄 associola.c
字号:
/* 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 Intel Corp. * Copyright (c) 2001 La Monte H.P. Yarroll * * This file is part of the SCTP kernel reference Implementation * * This module provides the abstraction for an SCTP association. * * 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> * Karl Knutson <karl@athena.chicago.il.us> * Jon Grimm <jgrimm@us.ibm.com> * Xingang Guo <xingang.guo@intel.com> * Hui Huang <hui.huang@nokia.com> * Sridhar Samudrala <sri@us.ibm.com> * Daisy Chang <daisyc@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 * be incorporated into the next SCTP release. */#include <linux/types.h>#include <linux/fcntl.h>#include <linux/poll.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/in.h>#include <net/ipv6.h>#include <net/sctp/sctp.h>#include <net/sctp/sm.h>/* Forward declarations for internal functions. */static void sctp_assoc_bh_rcv(struct sctp_association *asoc);/* 1st Level Abstractions. *//* Allocate and initialize a new association */struct sctp_association *sctp_association_new(const struct sctp_endpoint *ep, const struct sock *sk, sctp_scope_t scope, int gfp){ struct sctp_association *asoc; asoc = t_new(struct sctp_association, gfp); if (!asoc) goto fail; if (!sctp_association_init(asoc, ep, sk, scope, gfp)) goto fail_init; asoc->base.malloced = 1; SCTP_DBG_OBJCNT_INC(assoc); return asoc;fail_init: kfree(asoc);fail: return NULL;}/* Initialize a new association from provided memory. */struct sctp_association *sctp_association_init(struct sctp_association *asoc, const struct sctp_endpoint *ep, const struct sock *sk, sctp_scope_t scope, int gfp){ struct sctp_opt *sp; int i; /* Retrieve the SCTP per socket area. */ sp = sctp_sk((struct sock *)sk); /* Init all variables to a known value. */ memset(asoc, 0, sizeof(struct sctp_association)); /* Discarding const is appropriate here. */ asoc->ep = (struct sctp_endpoint *)ep; sctp_endpoint_hold(asoc->ep); /* Hold the sock. */ asoc->base.sk = (struct sock *)sk; sock_hold(asoc->base.sk); /* Initialize the common base substructure. */ asoc->base.type = SCTP_EP_TYPE_ASSOCIATION; /* Initialize the object handling fields. */ atomic_set(&asoc->base.refcnt, 1); asoc->base.dead = 0; asoc->base.malloced = 0; /* Initialize the bind addr area. */ sctp_bind_addr_init(&asoc->base.bind_addr, ep->base.bind_addr.port); asoc->base.addr_lock = RW_LOCK_UNLOCKED; asoc->state = SCTP_STATE_CLOSED; /* Set these values from the socket values, a conversion between * millsecons to seconds/microseconds must also be done. */ asoc->cookie_life.tv_sec = sp->assocparams.sasoc_cookie_life / 1000; asoc->cookie_life.tv_usec = (sp->assocparams.sasoc_cookie_life % 1000) * 1000; asoc->pmtu = 0; asoc->frag_point = 0; /* Set the association max_retrans and RTO values from the * socket values. */ asoc->max_retrans = sp->assocparams.sasoc_asocmaxrxt; asoc->rto_initial = msecs_to_jiffies(sp->rtoinfo.srto_initial); asoc->rto_max = msecs_to_jiffies(sp->rtoinfo.srto_max); asoc->rto_min = msecs_to_jiffies(sp->rtoinfo.srto_min); asoc->overall_error_count = 0; /* Initialize the maximum mumber of new data packets that can be sent * in a burst. */ asoc->max_burst = sctp_max_burst; /* Copy things from the endpoint. */ for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) { asoc->timeouts[i] = ep->timeouts[i]; init_timer(&asoc->timers[i]); asoc->timers[i].function = sctp_timer_events[i]; asoc->timers[i].data = (unsigned long) asoc; } /* Pull default initialization values from the sock options. * Note: This assumes that the values have already been * validated in the sock. */ asoc->c.sinit_max_instreams = sp->initmsg.sinit_max_instreams; asoc->c.sinit_num_ostreams = sp->initmsg.sinit_num_ostreams; asoc->max_init_attempts = sp->initmsg.sinit_max_attempts; asoc->max_init_timeo = msecs_to_jiffies(sp->initmsg.sinit_max_init_timeo); /* Allocate storage for the ssnmap after the inbound and outbound * streams have been negotiated during Init. */ asoc->ssnmap = NULL; /* Set the local window size for receive. * This is also the rcvbuf space per association. * RFC 6 - A SCTP receiver MUST be able to receive a minimum of * 1500 bytes in one SCTP packet. */ if (sk->sk_rcvbuf < SCTP_DEFAULT_MINWINDOW) asoc->rwnd = SCTP_DEFAULT_MINWINDOW; else asoc->rwnd = sk->sk_rcvbuf; asoc->a_rwnd = asoc->rwnd; asoc->rwnd_over = 0; /* Use my own max window until I learn something better. */ asoc->peer.rwnd = SCTP_DEFAULT_MAXWINDOW; /* Set the sndbuf size for transmit. */ asoc->sndbuf_used = 0; init_waitqueue_head(&asoc->wait); asoc->c.my_vtag = sctp_generate_tag(ep); asoc->peer.i.init_tag = 0; /* INIT needs a vtag of 0. */ asoc->c.peer_vtag = 0; asoc->c.my_ttag = 0; asoc->c.peer_ttag = 0; asoc->c.initial_tsn = sctp_generate_tsn(ep); asoc->next_tsn = asoc->c.initial_tsn; asoc->ctsn_ack_point = asoc->next_tsn - 1; asoc->adv_peer_ack_point = asoc->ctsn_ack_point; asoc->highest_sacked = asoc->ctsn_ack_point; asoc->last_cwr_tsn = asoc->ctsn_ack_point; asoc->unack_data = 0; SCTP_DEBUG_PRINTK("myctsnap for %s INIT as 0x%x.\n", asoc->ep->debug_name, asoc->ctsn_ack_point); /* ADDIP Section 4.1 Asconf Chunk Procedures * * When an endpoint has an ASCONF signaled change to be sent to the * remote endpoint it should do the following: * ... * A2) a serial number should be assigned to the chunk. The serial * number SHOULD be a monotonically increasing number. The serial * numbers SHOULD be initialized at the start of the * association to the same value as the initial TSN. */ asoc->addip_serial = asoc->c.initial_tsn; skb_queue_head_init(&asoc->addip_chunks); /* Make an empty list of remote transport addresses. */ INIT_LIST_HEAD(&asoc->peer.transport_addr_list); /* RFC 2960 5.1 Normal Establishment of an Association * * After the reception of the first data chunk in an * association the endpoint must immediately respond with a * sack to acknowledge the data chunk. Subsequent * acknowledgements should be done as described in Section * 6.2. * * [We implement this by telling a new association that it * already received one packet.] */ asoc->peer.sack_needed = 1; /* Assume that the peer recongizes ASCONF until reported otherwise * via an ERROR chunk. */ asoc->peer.asconf_capable = 1; /* Create an input queue. */ sctp_inq_init(&asoc->base.inqueue); sctp_inq_set_th_handler(&asoc->base.inqueue, (void (*)(void *))sctp_assoc_bh_rcv, asoc); /* Create an output queue. */ sctp_outq_init(asoc, &asoc->outqueue); if (!sctp_ulpq_init(&asoc->ulpq, asoc)) goto fail_init; /* Set up the tsn tracking. */ sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE, 0); asoc->need_ecne = 0; asoc->assoc_id = (sctp_assoc_t)-1L; /* Assume that peer would support both address types unless we are * told otherwise. */ asoc->peer.ipv4_address = 1; asoc->peer.ipv6_address = 1; INIT_LIST_HEAD(&asoc->asocs); asoc->autoclose = sp->autoclose; asoc->default_stream = sp->default_stream; asoc->default_ppid = sp->default_ppid; asoc->default_flags = sp->default_flags; asoc->default_context = sp->default_context; asoc->default_timetolive = sp->default_timetolive; return asoc;fail_init: sctp_endpoint_put(asoc->ep); sock_put(asoc->base.sk); return NULL;}/* Free this association if possible. There may still be users, so * the actual deallocation may be delayed. */void sctp_association_free(struct sctp_association *asoc){ struct sock *sk = asoc->base.sk; struct sctp_transport *transport; struct list_head *pos, *temp; int i; list_del(&asoc->asocs); /* Decrement the backlog value for a TCP-style listening socket. */ if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) sk->sk_ack_backlog--; /* Mark as dead, so other users can know this structure is * going away. */ asoc->base.dead = 1; /* Dispose of any data lying around in the outqueue. */ sctp_outq_free(&asoc->outqueue); /* Dispose of any pending messages for the upper layer. */ sctp_ulpq_free(&asoc->ulpq); /* Dispose of any pending chunks on the inqueue. */ sctp_inq_free(&asoc->base.inqueue); /* Free ssnmap storage. */ sctp_ssnmap_free(asoc->ssnmap); /* Clean up the bound address list. */ sctp_bind_addr_free(&asoc->base.bind_addr); /* Do we need to go through all of our timers and * delete them? To be safe we will try to delete all, but we * should be able to go through and make a guess based * on our state. */ for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) { if (timer_pending(&asoc->timers[i]) && del_timer(&asoc->timers[i])) sctp_association_put(asoc); } /* Free peer's cached cookie. */ if (asoc->peer.cookie) { kfree(asoc->peer.cookie); } /* Release the transport structures. */ list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { transport = list_entry(pos, struct sctp_transport, transports); list_del(pos); sctp_transport_free(transport); } /* 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);}/* Cleanup and free up an association. */static void sctp_association_destroy(struct sctp_association *asoc){ SCTP_ASSERT(asoc->base.dead, "Assoc is not dead", return); sctp_endpoint_put(asoc->ep); sock_put(asoc->base.sk); if ((long)asoc->assoc_id != -1L) { spin_lock_bh(&sctp_assocs_id_lock); idr_remove(&sctp_assocs_id, (long)asoc->assoc_id); spin_unlock_bh(&sctp_assocs_id_lock); } if (asoc->base.malloced) { kfree(asoc); SCTP_DBG_OBJCNT_DEC(assoc); }}/* Change the primary destination address for the peer. */void sctp_assoc_set_primary(struct sctp_association *asoc, struct sctp_transport *transport){ asoc->peer.primary_path = transport; /* Set a default msg_name for events. */ memcpy(&asoc->peer.primary_addr, &transport->ipaddr, sizeof(union sctp_addr)); /* If the primary path is changing, assume that the * user wants to use this new path. */ if (transport->active) asoc->peer.active_path = transport; /* * SFR-CACC algorithm: * Upon the receipt of a request to change the primary * destination address, on the data structure for the new
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -