| rjw | 1f88458 | 2022-01-06 17:20:42 +0800 | [diff] [blame] | 1 | /* SCTP kernel implementation | 
|  | 2 | * (C) Copyright IBM Corp. 2001, 2004 | 
|  | 3 | * Copyright (c) 1999-2000 Cisco, Inc. | 
|  | 4 | * Copyright (c) 1999-2001 Motorola, Inc. | 
|  | 5 | * Copyright (c) 2001-2003 Intel Corp. | 
|  | 6 | * | 
|  | 7 | * This file is part of the SCTP kernel implementation | 
|  | 8 | * | 
|  | 9 | * The base lksctp header. | 
|  | 10 | * | 
|  | 11 | * This SCTP implementation is free software; | 
|  | 12 | * you can redistribute it and/or modify it under the terms of | 
|  | 13 | * the GNU General Public License as published by | 
|  | 14 | * the Free Software Foundation; either version 2, or (at your option) | 
|  | 15 | * any later version. | 
|  | 16 | * | 
|  | 17 | * This SCTP implementation is distributed in the hope that it | 
|  | 18 | * will be useful, but WITHOUT ANY WARRANTY; without even the implied | 
|  | 19 | *                 ************************ | 
|  | 20 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | 
|  | 21 | * See the GNU General Public License for more details. | 
|  | 22 | * | 
|  | 23 | * You should have received a copy of the GNU General Public License | 
|  | 24 | * along with GNU CC; see the file COPYING.  If not, see | 
|  | 25 | * <http://www.gnu.org/licenses/>. | 
|  | 26 | * | 
|  | 27 | * Please send any bug reports or fixes you make to the | 
|  | 28 | * email address(es): | 
|  | 29 | *    lksctp developers <linux-sctp@vger.kernel.org> | 
|  | 30 | * | 
|  | 31 | * Written or modified by: | 
|  | 32 | *    La Monte H.P. Yarroll <piggy@acm.org> | 
|  | 33 | *    Xingang Guo           <xingang.guo@intel.com> | 
|  | 34 | *    Jon Grimm             <jgrimm@us.ibm.com> | 
|  | 35 | *    Daisy Chang           <daisyc@us.ibm.com> | 
|  | 36 | *    Sridhar Samudrala     <sri@us.ibm.com> | 
|  | 37 | *    Ardelle Fan           <ardelle.fan@intel.com> | 
|  | 38 | *    Ryan Layer            <rmlayer@us.ibm.com> | 
|  | 39 | *    Kevin Gao             <kevin.gao@intel.com> | 
|  | 40 | */ | 
|  | 41 |  | 
|  | 42 | #ifndef __net_sctp_h__ | 
|  | 43 | #define __net_sctp_h__ | 
|  | 44 |  | 
|  | 45 | /* Header Strategy. | 
|  | 46 | *    Start getting some control over the header file depencies: | 
|  | 47 | *       includes | 
|  | 48 | *       constants | 
|  | 49 | *       structs | 
|  | 50 | *       prototypes | 
|  | 51 | *       macros, externs, and inlines | 
|  | 52 | * | 
|  | 53 | *   Move test_frame specific items out of the kernel headers | 
|  | 54 | *   and into the test frame headers.   This is not perfect in any sense | 
|  | 55 | *   and will continue to evolve. | 
|  | 56 | */ | 
|  | 57 |  | 
|  | 58 | #include <linux/types.h> | 
|  | 59 | #include <linux/slab.h> | 
|  | 60 | #include <linux/in.h> | 
|  | 61 | #include <linux/tty.h> | 
|  | 62 | #include <linux/proc_fs.h> | 
|  | 63 | #include <linux/spinlock.h> | 
|  | 64 | #include <linux/jiffies.h> | 
|  | 65 | #include <linux/idr.h> | 
|  | 66 |  | 
|  | 67 | #if IS_ENABLED(CONFIG_IPV6) | 
|  | 68 | #include <net/ipv6.h> | 
|  | 69 | #include <net/ip6_route.h> | 
|  | 70 | #endif | 
|  | 71 |  | 
|  | 72 | #include <linux/uaccess.h> | 
|  | 73 | #include <asm/page.h> | 
|  | 74 | #include <net/sock.h> | 
|  | 75 | #include <net/snmp.h> | 
|  | 76 | #include <net/sctp/structs.h> | 
|  | 77 | #include <net/sctp/constants.h> | 
|  | 78 |  | 
|  | 79 | #ifdef CONFIG_IP_SCTP_MODULE | 
|  | 80 | #define SCTP_PROTOSW_FLAG 0 | 
|  | 81 | #else /* static! */ | 
|  | 82 | #define SCTP_PROTOSW_FLAG INET_PROTOSW_PERMANENT | 
|  | 83 | #endif | 
|  | 84 |  | 
|  | 85 | /* Round an int up to the next multiple of 4.  */ | 
|  | 86 | #define SCTP_PAD4(s) (((s)+3)&~3) | 
|  | 87 | /* Truncate to the previous multiple of 4.  */ | 
|  | 88 | #define SCTP_TRUNC4(s) ((s)&~3) | 
|  | 89 |  | 
|  | 90 | /* | 
|  | 91 | * Function declarations. | 
|  | 92 | */ | 
|  | 93 |  | 
|  | 94 | /* | 
|  | 95 | * sctp/protocol.c | 
|  | 96 | */ | 
|  | 97 | int sctp_copy_local_addr_list(struct net *net, struct sctp_bind_addr *addr, | 
|  | 98 | enum sctp_scope, gfp_t gfp, int flags); | 
|  | 99 | struct sctp_pf *sctp_get_pf_specific(sa_family_t family); | 
|  | 100 | int sctp_register_pf(struct sctp_pf *, sa_family_t); | 
|  | 101 | void sctp_addr_wq_mgmt(struct net *, struct sctp_sockaddr_entry *, int); | 
|  | 102 |  | 
|  | 103 | /* | 
|  | 104 | * sctp/socket.c | 
|  | 105 | */ | 
|  | 106 | int sctp_inet_connect(struct socket *sock, struct sockaddr *uaddr, | 
|  | 107 | int addr_len, int flags); | 
|  | 108 | int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb); | 
|  | 109 | int sctp_inet_listen(struct socket *sock, int backlog); | 
|  | 110 | void sctp_write_space(struct sock *sk); | 
|  | 111 | void sctp_data_ready(struct sock *sk); | 
|  | 112 | unsigned int sctp_poll(struct file *file, struct socket *sock, | 
|  | 113 | poll_table *wait); | 
|  | 114 | void sctp_sock_rfree(struct sk_buff *skb); | 
|  | 115 | void sctp_copy_sock(struct sock *newsk, struct sock *sk, | 
|  | 116 | struct sctp_association *asoc); | 
|  | 117 | extern struct percpu_counter sctp_sockets_allocated; | 
|  | 118 | int sctp_asconf_mgmt(struct sctp_sock *, struct sctp_sockaddr_entry *); | 
|  | 119 | struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *); | 
|  | 120 |  | 
|  | 121 | int sctp_transport_walk_start(struct rhashtable_iter *iter); | 
|  | 122 | void sctp_transport_walk_stop(struct rhashtable_iter *iter); | 
|  | 123 | struct sctp_transport *sctp_transport_get_next(struct net *net, | 
|  | 124 | struct rhashtable_iter *iter); | 
|  | 125 | struct sctp_transport *sctp_transport_get_idx(struct net *net, | 
|  | 126 | struct rhashtable_iter *iter, int pos); | 
|  | 127 | int sctp_transport_lookup_process(int (*cb)(struct sctp_transport *, void *), | 
|  | 128 | struct net *net, | 
|  | 129 | const union sctp_addr *laddr, | 
|  | 130 | const union sctp_addr *paddr, void *p); | 
|  | 131 | int sctp_for_each_transport(int (*cb)(struct sctp_transport *, void *), | 
|  | 132 | int (*cb_done)(struct sctp_transport *, void *), | 
|  | 133 | struct net *net, int *pos, void *p); | 
|  | 134 | int sctp_for_each_endpoint(int (*cb)(struct sctp_endpoint *, void *), void *p); | 
|  | 135 | int sctp_get_sctp_info(struct sock *sk, struct sctp_association *asoc, | 
|  | 136 | struct sctp_info *info); | 
|  | 137 |  | 
|  | 138 | /* | 
|  | 139 | * sctp/primitive.c | 
|  | 140 | */ | 
|  | 141 | int sctp_primitive_ASSOCIATE(struct net *, struct sctp_association *, void *arg); | 
|  | 142 | int sctp_primitive_SHUTDOWN(struct net *, struct sctp_association *, void *arg); | 
|  | 143 | int sctp_primitive_ABORT(struct net *, struct sctp_association *, void *arg); | 
|  | 144 | int sctp_primitive_SEND(struct net *, struct sctp_association *, void *arg); | 
|  | 145 | int sctp_primitive_REQUESTHEARTBEAT(struct net *, struct sctp_association *, void *arg); | 
|  | 146 | int sctp_primitive_ASCONF(struct net *, struct sctp_association *, void *arg); | 
|  | 147 | int sctp_primitive_RECONF(struct net *net, struct sctp_association *asoc, | 
|  | 148 | void *arg); | 
|  | 149 |  | 
|  | 150 | /* | 
|  | 151 | * sctp/input.c | 
|  | 152 | */ | 
|  | 153 | int sctp_rcv(struct sk_buff *skb); | 
|  | 154 | void sctp_v4_err(struct sk_buff *skb, u32 info); | 
|  | 155 | void sctp_hash_endpoint(struct sctp_endpoint *); | 
|  | 156 | void sctp_unhash_endpoint(struct sctp_endpoint *); | 
|  | 157 | struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *, | 
|  | 158 | struct sctphdr *, struct sctp_association **, | 
|  | 159 | struct sctp_transport **); | 
|  | 160 | void sctp_err_finish(struct sock *, struct sctp_transport *); | 
|  | 161 | void sctp_icmp_frag_needed(struct sock *, struct sctp_association *, | 
|  | 162 | struct sctp_transport *t, __u32 pmtu); | 
|  | 163 | void sctp_icmp_redirect(struct sock *, struct sctp_transport *, | 
|  | 164 | struct sk_buff *); | 
|  | 165 | void sctp_icmp_proto_unreachable(struct sock *sk, | 
|  | 166 | struct sctp_association *asoc, | 
|  | 167 | struct sctp_transport *t); | 
|  | 168 | void sctp_backlog_migrate(struct sctp_association *assoc, | 
|  | 169 | struct sock *oldsk, struct sock *newsk); | 
|  | 170 | int sctp_transport_hashtable_init(void); | 
|  | 171 | void sctp_transport_hashtable_destroy(void); | 
|  | 172 | int sctp_hash_transport(struct sctp_transport *t); | 
|  | 173 | void sctp_unhash_transport(struct sctp_transport *t); | 
|  | 174 | struct sctp_transport *sctp_addrs_lookup_transport( | 
|  | 175 | struct net *net, | 
|  | 176 | const union sctp_addr *laddr, | 
|  | 177 | const union sctp_addr *paddr); | 
|  | 178 | struct sctp_transport *sctp_epaddr_lookup_transport( | 
|  | 179 | const struct sctp_endpoint *ep, | 
|  | 180 | const union sctp_addr *paddr); | 
|  | 181 |  | 
|  | 182 | /* | 
|  | 183 | * sctp/proc.c | 
|  | 184 | */ | 
|  | 185 | int sctp_snmp_proc_init(struct net *net); | 
|  | 186 | void sctp_snmp_proc_exit(struct net *net); | 
|  | 187 | int sctp_eps_proc_init(struct net *net); | 
|  | 188 | void sctp_eps_proc_exit(struct net *net); | 
|  | 189 | int sctp_assocs_proc_init(struct net *net); | 
|  | 190 | void sctp_assocs_proc_exit(struct net *net); | 
|  | 191 | int sctp_remaddr_proc_init(struct net *net); | 
|  | 192 | void sctp_remaddr_proc_exit(struct net *net); | 
|  | 193 |  | 
|  | 194 | /* | 
|  | 195 | * sctp/offload.c | 
|  | 196 | */ | 
|  | 197 | int sctp_offload_init(void); | 
|  | 198 |  | 
|  | 199 | /* | 
|  | 200 | * sctp/stream.c | 
|  | 201 | */ | 
|  | 202 | int sctp_send_reset_streams(struct sctp_association *asoc, | 
|  | 203 | struct sctp_reset_streams *params); | 
|  | 204 | int sctp_send_reset_assoc(struct sctp_association *asoc); | 
|  | 205 | int sctp_send_add_streams(struct sctp_association *asoc, | 
|  | 206 | struct sctp_add_streams *params); | 
|  | 207 |  | 
|  | 208 | /* | 
|  | 209 | * Module global variables | 
|  | 210 | */ | 
|  | 211 |  | 
|  | 212 | /* | 
|  | 213 | * sctp/protocol.c | 
|  | 214 | */ | 
|  | 215 | extern struct kmem_cache *sctp_chunk_cachep __read_mostly; | 
|  | 216 | extern struct kmem_cache *sctp_bucket_cachep __read_mostly; | 
|  | 217 | extern long sysctl_sctp_mem[3]; | 
|  | 218 | extern int sysctl_sctp_rmem[3]; | 
|  | 219 | extern int sysctl_sctp_wmem[3]; | 
|  | 220 |  | 
|  | 221 | /* | 
|  | 222 | *  Section:  Macros, externs, and inlines | 
|  | 223 | */ | 
|  | 224 |  | 
|  | 225 | /* SCTP SNMP MIB stats handlers */ | 
|  | 226 | #define SCTP_INC_STATS(net, field)	SNMP_INC_STATS((net)->sctp.sctp_statistics, field) | 
|  | 227 | #define __SCTP_INC_STATS(net, field)	__SNMP_INC_STATS((net)->sctp.sctp_statistics, field) | 
|  | 228 | #define SCTP_DEC_STATS(net, field)	SNMP_DEC_STATS((net)->sctp.sctp_statistics, field) | 
|  | 229 |  | 
|  | 230 | /* sctp mib definitions */ | 
|  | 231 | enum { | 
|  | 232 | SCTP_MIB_NUM = 0, | 
|  | 233 | SCTP_MIB_CURRESTAB,			/* CurrEstab */ | 
|  | 234 | SCTP_MIB_ACTIVEESTABS,			/* ActiveEstabs */ | 
|  | 235 | SCTP_MIB_PASSIVEESTABS,			/* PassiveEstabs */ | 
|  | 236 | SCTP_MIB_ABORTEDS,			/* Aborteds */ | 
|  | 237 | SCTP_MIB_SHUTDOWNS,			/* Shutdowns */ | 
|  | 238 | SCTP_MIB_OUTOFBLUES,			/* OutOfBlues */ | 
|  | 239 | SCTP_MIB_CHECKSUMERRORS,		/* ChecksumErrors */ | 
|  | 240 | SCTP_MIB_OUTCTRLCHUNKS,			/* OutCtrlChunks */ | 
|  | 241 | SCTP_MIB_OUTORDERCHUNKS,		/* OutOrderChunks */ | 
|  | 242 | SCTP_MIB_OUTUNORDERCHUNKS,		/* OutUnorderChunks */ | 
|  | 243 | SCTP_MIB_INCTRLCHUNKS,			/* InCtrlChunks */ | 
|  | 244 | SCTP_MIB_INORDERCHUNKS,			/* InOrderChunks */ | 
|  | 245 | SCTP_MIB_INUNORDERCHUNKS,		/* InUnorderChunks */ | 
|  | 246 | SCTP_MIB_FRAGUSRMSGS,			/* FragUsrMsgs */ | 
|  | 247 | SCTP_MIB_REASMUSRMSGS,			/* ReasmUsrMsgs */ | 
|  | 248 | SCTP_MIB_OUTSCTPPACKS,			/* OutSCTPPacks */ | 
|  | 249 | SCTP_MIB_INSCTPPACKS,			/* InSCTPPacks */ | 
|  | 250 | SCTP_MIB_T1_INIT_EXPIREDS, | 
|  | 251 | SCTP_MIB_T1_COOKIE_EXPIREDS, | 
|  | 252 | SCTP_MIB_T2_SHUTDOWN_EXPIREDS, | 
|  | 253 | SCTP_MIB_T3_RTX_EXPIREDS, | 
|  | 254 | SCTP_MIB_T4_RTO_EXPIREDS, | 
|  | 255 | SCTP_MIB_T5_SHUTDOWN_GUARD_EXPIREDS, | 
|  | 256 | SCTP_MIB_DELAY_SACK_EXPIREDS, | 
|  | 257 | SCTP_MIB_AUTOCLOSE_EXPIREDS, | 
|  | 258 | SCTP_MIB_T1_RETRANSMITS, | 
|  | 259 | SCTP_MIB_T3_RETRANSMITS, | 
|  | 260 | SCTP_MIB_PMTUD_RETRANSMITS, | 
|  | 261 | SCTP_MIB_FAST_RETRANSMITS, | 
|  | 262 | SCTP_MIB_IN_PKT_SOFTIRQ, | 
|  | 263 | SCTP_MIB_IN_PKT_BACKLOG, | 
|  | 264 | SCTP_MIB_IN_PKT_DISCARDS, | 
|  | 265 | SCTP_MIB_IN_DATA_CHUNK_DISCARDS, | 
|  | 266 | __SCTP_MIB_MAX | 
|  | 267 | }; | 
|  | 268 |  | 
|  | 269 | #define SCTP_MIB_MAX    __SCTP_MIB_MAX | 
|  | 270 | struct sctp_mib { | 
|  | 271 | unsigned long   mibs[SCTP_MIB_MAX]; | 
|  | 272 | }; | 
|  | 273 |  | 
|  | 274 | /* helper function to track stats about max rto and related transport */ | 
|  | 275 | static inline void sctp_max_rto(struct sctp_association *asoc, | 
|  | 276 | struct sctp_transport *trans) | 
|  | 277 | { | 
|  | 278 | if (asoc->stats.max_obs_rto < (__u64)trans->rto) { | 
|  | 279 | asoc->stats.max_obs_rto = trans->rto; | 
|  | 280 | memset(&asoc->stats.obs_rto_ipaddr, 0, | 
|  | 281 | sizeof(struct sockaddr_storage)); | 
|  | 282 | memcpy(&asoc->stats.obs_rto_ipaddr, &trans->ipaddr, | 
|  | 283 | trans->af_specific->sockaddr_len); | 
|  | 284 | } | 
|  | 285 | } | 
|  | 286 |  | 
|  | 287 | /* | 
|  | 288 | * Macros for keeping a global reference of object allocations. | 
|  | 289 | */ | 
|  | 290 | #ifdef CONFIG_SCTP_DBG_OBJCNT | 
|  | 291 |  | 
|  | 292 | extern atomic_t sctp_dbg_objcnt_sock; | 
|  | 293 | extern atomic_t sctp_dbg_objcnt_ep; | 
|  | 294 | extern atomic_t sctp_dbg_objcnt_assoc; | 
|  | 295 | extern atomic_t sctp_dbg_objcnt_transport; | 
|  | 296 | extern atomic_t sctp_dbg_objcnt_chunk; | 
|  | 297 | extern atomic_t sctp_dbg_objcnt_bind_addr; | 
|  | 298 | extern atomic_t sctp_dbg_objcnt_bind_bucket; | 
|  | 299 | extern atomic_t sctp_dbg_objcnt_addr; | 
|  | 300 | extern atomic_t sctp_dbg_objcnt_datamsg; | 
|  | 301 | extern atomic_t sctp_dbg_objcnt_keys; | 
|  | 302 |  | 
|  | 303 | /* Macros to atomically increment/decrement objcnt counters.  */ | 
|  | 304 | #define SCTP_DBG_OBJCNT_INC(name) \ | 
|  | 305 | atomic_inc(&sctp_dbg_objcnt_## name) | 
|  | 306 | #define SCTP_DBG_OBJCNT_DEC(name) \ | 
|  | 307 | atomic_dec(&sctp_dbg_objcnt_## name) | 
|  | 308 | #define SCTP_DBG_OBJCNT(name) \ | 
|  | 309 | atomic_t sctp_dbg_objcnt_## name = ATOMIC_INIT(0) | 
|  | 310 |  | 
|  | 311 | /* Macro to help create new entries in in the global array of | 
|  | 312 | * objcnt counters. | 
|  | 313 | */ | 
|  | 314 | #define SCTP_DBG_OBJCNT_ENTRY(name) \ | 
|  | 315 | {.label= #name, .counter= &sctp_dbg_objcnt_## name} | 
|  | 316 |  | 
|  | 317 | void sctp_dbg_objcnt_init(struct net *); | 
|  | 318 | void sctp_dbg_objcnt_exit(struct net *); | 
|  | 319 |  | 
|  | 320 | #else | 
|  | 321 |  | 
|  | 322 | #define SCTP_DBG_OBJCNT_INC(name) | 
|  | 323 | #define SCTP_DBG_OBJCNT_DEC(name) | 
|  | 324 |  | 
|  | 325 | static inline void sctp_dbg_objcnt_init(struct net *net) { return; } | 
|  | 326 | static inline void sctp_dbg_objcnt_exit(struct net *net) { return; } | 
|  | 327 |  | 
|  | 328 | #endif /* CONFIG_SCTP_DBG_OBJCOUNT */ | 
|  | 329 |  | 
|  | 330 | #if defined CONFIG_SYSCTL | 
|  | 331 | void sctp_sysctl_register(void); | 
|  | 332 | void sctp_sysctl_unregister(void); | 
|  | 333 | int sctp_sysctl_net_register(struct net *net); | 
|  | 334 | void sctp_sysctl_net_unregister(struct net *net); | 
|  | 335 | #else | 
|  | 336 | static inline void sctp_sysctl_register(void) { return; } | 
|  | 337 | static inline void sctp_sysctl_unregister(void) { return; } | 
|  | 338 | static inline int sctp_sysctl_net_register(struct net *net) { return 0; } | 
|  | 339 | static inline void sctp_sysctl_net_unregister(struct net *net) { return; } | 
|  | 340 | #endif | 
|  | 341 |  | 
|  | 342 | /* Size of Supported Address Parameter for 'x' address types. */ | 
|  | 343 | #define SCTP_SAT_LEN(x) (sizeof(struct sctp_paramhdr) + (x) * sizeof(__u16)) | 
|  | 344 |  | 
|  | 345 | #if IS_ENABLED(CONFIG_IPV6) | 
|  | 346 |  | 
|  | 347 | void sctp_v6_pf_init(void); | 
|  | 348 | void sctp_v6_pf_exit(void); | 
|  | 349 | int sctp_v6_protosw_init(void); | 
|  | 350 | void sctp_v6_protosw_exit(void); | 
|  | 351 | int sctp_v6_add_protocol(void); | 
|  | 352 | void sctp_v6_del_protocol(void); | 
|  | 353 |  | 
|  | 354 | #else /* #ifdef defined(CONFIG_IPV6) */ | 
|  | 355 |  | 
|  | 356 | static inline void sctp_v6_pf_init(void) { return; } | 
|  | 357 | static inline void sctp_v6_pf_exit(void) { return; } | 
|  | 358 | static inline int sctp_v6_protosw_init(void) { return 0; } | 
|  | 359 | static inline void sctp_v6_protosw_exit(void) { return; } | 
|  | 360 | static inline int sctp_v6_add_protocol(void) { return 0; } | 
|  | 361 | static inline void sctp_v6_del_protocol(void) { return; } | 
|  | 362 |  | 
|  | 363 | #endif /* #if defined(CONFIG_IPV6) */ | 
|  | 364 |  | 
|  | 365 |  | 
|  | 366 | /* Map an association to an assoc_id. */ | 
|  | 367 | static inline sctp_assoc_t sctp_assoc2id(const struct sctp_association *asoc) | 
|  | 368 | { | 
|  | 369 | return asoc ? asoc->assoc_id : 0; | 
|  | 370 | } | 
|  | 371 |  | 
|  | 372 | static inline enum sctp_sstat_state | 
|  | 373 | sctp_assoc_to_state(const struct sctp_association *asoc) | 
|  | 374 | { | 
|  | 375 | /* SCTP's uapi always had SCTP_EMPTY(=0) as a dummy state, but we | 
|  | 376 | * got rid of it in kernel space. Therefore SCTP_CLOSED et al | 
|  | 377 | * start at =1 in user space, but actually as =0 in kernel space. | 
|  | 378 | * Now that we can not break user space and SCTP_EMPTY is exposed | 
|  | 379 | * there, we need to fix it up with an ugly offset not to break | 
|  | 380 | * applications. :( | 
|  | 381 | */ | 
|  | 382 | return asoc->state + 1; | 
|  | 383 | } | 
|  | 384 |  | 
|  | 385 | /* Look up the association by its id.  */ | 
|  | 386 | struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id); | 
|  | 387 |  | 
|  | 388 | int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp); | 
|  | 389 |  | 
|  | 390 | /* A macro to walk a list of skbs.  */ | 
|  | 391 | #define sctp_skb_for_each(pos, head, tmp) \ | 
|  | 392 | skb_queue_walk_safe(head, pos, tmp) | 
|  | 393 |  | 
|  | 394 | /** | 
|  | 395 | *	sctp_list_dequeue - remove from the head of the queue | 
|  | 396 | *	@list: list to dequeue from | 
|  | 397 | * | 
|  | 398 | *	Remove the head of the list. The head item is | 
|  | 399 | *	returned or %NULL if the list is empty. | 
|  | 400 | */ | 
|  | 401 |  | 
|  | 402 | static inline struct list_head *sctp_list_dequeue(struct list_head *list) | 
|  | 403 | { | 
|  | 404 | struct list_head *result = NULL; | 
|  | 405 |  | 
|  | 406 | if (!list_empty(list)) { | 
|  | 407 | result = list->next; | 
|  | 408 | list_del_init(result); | 
|  | 409 | } | 
|  | 410 | return result; | 
|  | 411 | } | 
|  | 412 |  | 
|  | 413 | /* SCTP version of skb_set_owner_r.  We need this one because | 
|  | 414 | * of the way we have to do receive buffer accounting on bundled | 
|  | 415 | * chunks. | 
|  | 416 | */ | 
|  | 417 | static inline void sctp_skb_set_owner_r(struct sk_buff *skb, struct sock *sk) | 
|  | 418 | { | 
|  | 419 | struct sctp_ulpevent *event = sctp_skb2event(skb); | 
|  | 420 |  | 
|  | 421 | skb_orphan(skb); | 
|  | 422 | skb->sk = sk; | 
|  | 423 | skb->destructor = sctp_sock_rfree; | 
|  | 424 | atomic_add(event->rmem_len, &sk->sk_rmem_alloc); | 
|  | 425 | /* | 
|  | 426 | * This mimics the behavior of skb_set_owner_r | 
|  | 427 | */ | 
|  | 428 | sk->sk_forward_alloc -= event->rmem_len; | 
|  | 429 | } | 
|  | 430 |  | 
|  | 431 | /* Tests if the list has one and only one entry. */ | 
|  | 432 | static inline int sctp_list_single_entry(struct list_head *head) | 
|  | 433 | { | 
|  | 434 | return (head->next != head) && (head->next == head->prev); | 
|  | 435 | } | 
|  | 436 |  | 
|  | 437 | /* Break down data chunks at this point.  */ | 
|  | 438 | static inline int sctp_frag_point(const struct sctp_association *asoc, int pmtu) | 
|  | 439 | { | 
|  | 440 | struct sctp_sock *sp = sctp_sk(asoc->base.sk); | 
|  | 441 | int frag = pmtu; | 
|  | 442 |  | 
|  | 443 | frag -= sp->pf->af->net_header_len; | 
|  | 444 | frag -= sizeof(struct sctphdr) + sizeof(struct sctp_data_chunk); | 
|  | 445 |  | 
|  | 446 | if (asoc->user_frag) | 
|  | 447 | frag = min_t(int, frag, asoc->user_frag); | 
|  | 448 |  | 
|  | 449 | frag = SCTP_TRUNC4(min_t(int, frag, SCTP_MAX_CHUNK_LEN - | 
|  | 450 | sizeof(struct sctp_data_chunk))); | 
|  | 451 |  | 
|  | 452 | return frag; | 
|  | 453 | } | 
|  | 454 |  | 
|  | 455 | static inline void sctp_assoc_pending_pmtu(struct sctp_association *asoc) | 
|  | 456 | { | 
|  | 457 | sctp_assoc_sync_pmtu(asoc); | 
|  | 458 | asoc->pmtu_pending = 0; | 
|  | 459 | } | 
|  | 460 |  | 
|  | 461 | static inline bool sctp_chunk_pending(const struct sctp_chunk *chunk) | 
|  | 462 | { | 
|  | 463 | return !list_empty(&chunk->list); | 
|  | 464 | } | 
|  | 465 |  | 
|  | 466 | /* Walk through a list of TLV parameters.  Don't trust the | 
|  | 467 | * individual parameter lengths and instead depend on | 
|  | 468 | * the chunk length to indicate when to stop.  Make sure | 
|  | 469 | * there is room for a param header too. | 
|  | 470 | */ | 
|  | 471 | #define sctp_walk_params(pos, chunk, member)\ | 
|  | 472 | _sctp_walk_params((pos), (chunk), ntohs((chunk)->chunk_hdr.length), member) | 
|  | 473 |  | 
|  | 474 | #define _sctp_walk_params(pos, chunk, end, member)\ | 
|  | 475 | for (pos.v = chunk->member;\ | 
|  | 476 | (pos.v + offsetof(struct sctp_paramhdr, length) + sizeof(pos.p->length) <=\ | 
|  | 477 | (void *)chunk + end) &&\ | 
|  | 478 | pos.v <= (void *)chunk + end - ntohs(pos.p->length) &&\ | 
|  | 479 | ntohs(pos.p->length) >= sizeof(struct sctp_paramhdr);\ | 
|  | 480 | pos.v += SCTP_PAD4(ntohs(pos.p->length))) | 
|  | 481 |  | 
|  | 482 | #define sctp_walk_errors(err, chunk_hdr)\ | 
|  | 483 | _sctp_walk_errors((err), (chunk_hdr), ntohs((chunk_hdr)->length)) | 
|  | 484 |  | 
|  | 485 | #define _sctp_walk_errors(err, chunk_hdr, end)\ | 
|  | 486 | for (err = (struct sctp_errhdr *)((void *)chunk_hdr + \ | 
|  | 487 | sizeof(struct sctp_chunkhdr));\ | 
|  | 488 | ((void *)err + offsetof(struct sctp_errhdr, length) + sizeof(err->length) <=\ | 
|  | 489 | (void *)chunk_hdr + end) &&\ | 
|  | 490 | (void *)err <= (void *)chunk_hdr + end - ntohs(err->length) &&\ | 
|  | 491 | ntohs(err->length) >= sizeof(struct sctp_errhdr); \ | 
|  | 492 | err = (struct sctp_errhdr *)((void *)err + SCTP_PAD4(ntohs(err->length)))) | 
|  | 493 |  | 
|  | 494 | #define sctp_walk_fwdtsn(pos, chunk)\ | 
|  | 495 | _sctp_walk_fwdtsn((pos), (chunk), ntohs((chunk)->chunk_hdr->length) - sizeof(struct sctp_fwdtsn_chunk)) | 
|  | 496 |  | 
|  | 497 | #define _sctp_walk_fwdtsn(pos, chunk, end)\ | 
|  | 498 | for (pos = chunk->subh.fwdtsn_hdr->skip;\ | 
|  | 499 | (void *)pos <= (void *)chunk->subh.fwdtsn_hdr->skip + end - sizeof(struct sctp_fwdtsn_skip);\ | 
|  | 500 | pos++) | 
|  | 501 |  | 
|  | 502 | /* External references. */ | 
|  | 503 |  | 
|  | 504 | extern struct proto sctp_prot; | 
|  | 505 | extern struct proto sctpv6_prot; | 
|  | 506 | void sctp_put_port(struct sock *sk); | 
|  | 507 |  | 
|  | 508 | extern struct idr sctp_assocs_id; | 
|  | 509 | extern spinlock_t sctp_assocs_id_lock; | 
|  | 510 |  | 
|  | 511 | /* Static inline functions. */ | 
|  | 512 |  | 
|  | 513 | /* Convert from an IP version number to an Address Family symbol.  */ | 
|  | 514 | static inline int ipver2af(__u8 ipver) | 
|  | 515 | { | 
|  | 516 | switch (ipver) { | 
|  | 517 | case 4: | 
|  | 518 | return  AF_INET; | 
|  | 519 | case 6: | 
|  | 520 | return AF_INET6; | 
|  | 521 | default: | 
|  | 522 | return 0; | 
|  | 523 | } | 
|  | 524 | } | 
|  | 525 |  | 
|  | 526 | /* Convert from an address parameter type to an address family.  */ | 
|  | 527 | static inline int param_type2af(__be16 type) | 
|  | 528 | { | 
|  | 529 | switch (type) { | 
|  | 530 | case SCTP_PARAM_IPV4_ADDRESS: | 
|  | 531 | return  AF_INET; | 
|  | 532 | case SCTP_PARAM_IPV6_ADDRESS: | 
|  | 533 | return AF_INET6; | 
|  | 534 | default: | 
|  | 535 | return 0; | 
|  | 536 | } | 
|  | 537 | } | 
|  | 538 |  | 
|  | 539 | /* Warning: The following hash functions assume a power of two 'size'. */ | 
|  | 540 | /* This is the hash function for the SCTP port hash table. */ | 
|  | 541 | static inline int sctp_phashfn(struct net *net, __u16 lport) | 
|  | 542 | { | 
|  | 543 | return (net_hash_mix(net) + lport) & (sctp_port_hashsize - 1); | 
|  | 544 | } | 
|  | 545 |  | 
|  | 546 | /* This is the hash function for the endpoint hash table. */ | 
|  | 547 | static inline int sctp_ep_hashfn(struct net *net, __u16 lport) | 
|  | 548 | { | 
|  | 549 | return (net_hash_mix(net) + lport) & (sctp_ep_hashsize - 1); | 
|  | 550 | } | 
|  | 551 |  | 
|  | 552 | #define sctp_for_each_hentry(epb, head) \ | 
|  | 553 | hlist_for_each_entry(epb, head, node) | 
|  | 554 |  | 
|  | 555 | /* Is a socket of this style? */ | 
|  | 556 | #define sctp_style(sk, style) __sctp_style((sk), (SCTP_SOCKET_##style)) | 
|  | 557 | static inline int __sctp_style(const struct sock *sk, | 
|  | 558 | enum sctp_socket_type style) | 
|  | 559 | { | 
|  | 560 | return sctp_sk(sk)->type == style; | 
|  | 561 | } | 
|  | 562 |  | 
|  | 563 | /* Is the association in this state? */ | 
|  | 564 | #define sctp_state(asoc, state) __sctp_state((asoc), (SCTP_STATE_##state)) | 
|  | 565 | static inline int __sctp_state(const struct sctp_association *asoc, | 
|  | 566 | enum sctp_state state) | 
|  | 567 | { | 
|  | 568 | return asoc->state == state; | 
|  | 569 | } | 
|  | 570 |  | 
|  | 571 | /* Is the socket in this state? */ | 
|  | 572 | #define sctp_sstate(sk, state) __sctp_sstate((sk), (SCTP_SS_##state)) | 
|  | 573 | static inline int __sctp_sstate(const struct sock *sk, | 
|  | 574 | enum sctp_sock_state state) | 
|  | 575 | { | 
|  | 576 | return sk->sk_state == state; | 
|  | 577 | } | 
|  | 578 |  | 
|  | 579 | /* Map v4-mapped v6 address back to v4 address */ | 
|  | 580 | static inline void sctp_v6_map_v4(union sctp_addr *addr) | 
|  | 581 | { | 
|  | 582 | addr->v4.sin_family = AF_INET; | 
|  | 583 | addr->v4.sin_port = addr->v6.sin6_port; | 
|  | 584 | addr->v4.sin_addr.s_addr = addr->v6.sin6_addr.s6_addr32[3]; | 
|  | 585 | } | 
|  | 586 |  | 
|  | 587 | /* Map v4 address to v4-mapped v6 address */ | 
|  | 588 | static inline void sctp_v4_map_v6(union sctp_addr *addr) | 
|  | 589 | { | 
|  | 590 | __be16 port; | 
|  | 591 |  | 
|  | 592 | port = addr->v4.sin_port; | 
|  | 593 | addr->v6.sin6_addr.s6_addr32[3] = addr->v4.sin_addr.s_addr; | 
|  | 594 | addr->v6.sin6_port = port; | 
|  | 595 | addr->v6.sin6_family = AF_INET6; | 
|  | 596 | addr->v6.sin6_flowinfo = 0; | 
|  | 597 | addr->v6.sin6_scope_id = 0; | 
|  | 598 | addr->v6.sin6_addr.s6_addr32[0] = 0; | 
|  | 599 | addr->v6.sin6_addr.s6_addr32[1] = 0; | 
|  | 600 | addr->v6.sin6_addr.s6_addr32[2] = htonl(0x0000ffff); | 
|  | 601 | } | 
|  | 602 |  | 
|  | 603 | /* The cookie is always 0 since this is how it's used in the | 
|  | 604 | * pmtu code. | 
|  | 605 | */ | 
|  | 606 | static inline struct dst_entry *sctp_transport_dst_check(struct sctp_transport *t) | 
|  | 607 | { | 
|  | 608 | if (t->dst && !dst_check(t->dst, t->dst_cookie)) | 
|  | 609 | sctp_transport_dst_release(t); | 
|  | 610 |  | 
|  | 611 | return t->dst; | 
|  | 612 | } | 
|  | 613 |  | 
|  | 614 | static inline bool sctp_transport_pmtu_check(struct sctp_transport *t) | 
|  | 615 | { | 
|  | 616 | __u32 pmtu = max_t(size_t, SCTP_TRUNC4(dst_mtu(t->dst)), | 
|  | 617 | SCTP_DEFAULT_MINSEGMENT); | 
|  | 618 |  | 
|  | 619 | if (t->pathmtu == pmtu) | 
|  | 620 | return true; | 
|  | 621 |  | 
|  | 622 | t->pathmtu = pmtu; | 
|  | 623 |  | 
|  | 624 | return false; | 
|  | 625 | } | 
|  | 626 |  | 
|  | 627 | #endif /* __net_sctp_h__ */ |