| Vlad Yasevich | 60c778b | 2008-01-11 09:57:09 -0500 | [diff] [blame] | 1 | /* SCTP kernel implementation | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2 | * Copyright (c) 1999-2000 Cisco, Inc. | 
|  | 3 | * Copyright (c) 1999-2001 Motorola, Inc. | 
|  | 4 | * Copyright (c) 2001-2003 International Business Machines, Corp. | 
|  | 5 | * Copyright (c) 2001 Intel Corp. | 
|  | 6 | * Copyright (c) 2001 Nokia, Inc. | 
|  | 7 | * Copyright (c) 2001 La Monte H.P. Yarroll | 
|  | 8 | * | 
| Vlad Yasevich | 60c778b | 2008-01-11 09:57:09 -0500 | [diff] [blame] | 9 | * This file is part of the SCTP kernel implementation | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 10 | * | 
|  | 11 | * These functions handle all input from the IP layer into SCTP. | 
|  | 12 | * | 
| Vlad Yasevich | 60c778b | 2008-01-11 09:57:09 -0500 | [diff] [blame] | 13 | * This SCTP implementation is free software; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 14 | * you can redistribute it and/or modify it under the terms of | 
|  | 15 | * the GNU General Public License as published by | 
|  | 16 | * the Free Software Foundation; either version 2, or (at your option) | 
|  | 17 | * any later version. | 
|  | 18 | * | 
| Vlad Yasevich | 60c778b | 2008-01-11 09:57:09 -0500 | [diff] [blame] | 19 | * This SCTP implementation is distributed in the hope that it | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 20 | * will be useful, but WITHOUT ANY WARRANTY; without even the implied | 
|  | 21 | *                 ************************ | 
|  | 22 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | 
|  | 23 | * See the GNU General Public License for more details. | 
|  | 24 | * | 
|  | 25 | * You should have received a copy of the GNU General Public License | 
|  | 26 | * along with GNU CC; see the file COPYING.  If not, write to | 
|  | 27 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 
|  | 28 | * Boston, MA 02111-1307, USA. | 
|  | 29 | * | 
|  | 30 | * Please send any bug reports or fixes you make to the | 
|  | 31 | * email address(es): | 
|  | 32 | *    lksctp developers <lksctp-developers@lists.sourceforge.net> | 
|  | 33 | * | 
|  | 34 | * Or submit a bug report through the following website: | 
|  | 35 | *    http://www.sf.net/projects/lksctp | 
|  | 36 | * | 
|  | 37 | * Written or modified by: | 
|  | 38 | *    La Monte H.P. Yarroll <piggy@acm.org> | 
|  | 39 | *    Karl Knutson <karl@athena.chicago.il.us> | 
|  | 40 | *    Xingang Guo <xingang.guo@intel.com> | 
|  | 41 | *    Jon Grimm <jgrimm@us.ibm.com> | 
|  | 42 | *    Hui Huang <hui.huang@nokia.com> | 
|  | 43 | *    Daisy Chang <daisyc@us.ibm.com> | 
|  | 44 | *    Sridhar Samudrala <sri@us.ibm.com> | 
|  | 45 | *    Ardelle Fan <ardelle.fan@intel.com> | 
|  | 46 | * | 
|  | 47 | * Any bugs reported given to us we will try to fix... any fixes shared will | 
|  | 48 | * be incorporated into the next SCTP release. | 
|  | 49 | */ | 
|  | 50 |  | 
|  | 51 | #include <linux/types.h> | 
|  | 52 | #include <linux/list.h> /* For struct list_head */ | 
|  | 53 | #include <linux/socket.h> | 
|  | 54 | #include <linux/ip.h> | 
|  | 55 | #include <linux/time.h> /* For struct timeval */ | 
|  | 56 | #include <net/ip.h> | 
|  | 57 | #include <net/icmp.h> | 
|  | 58 | #include <net/snmp.h> | 
|  | 59 | #include <net/sock.h> | 
|  | 60 | #include <net/xfrm.h> | 
|  | 61 | #include <net/sctp/sctp.h> | 
|  | 62 | #include <net/sctp/sm.h> | 
| Vlad Yasevich | 9ad0977 | 2007-12-16 14:06:41 -0800 | [diff] [blame] | 63 | #include <net/sctp/checksum.h> | 
| Pavel Emelyanov | dcfc23c | 2008-07-14 23:03:00 -0700 | [diff] [blame] | 64 | #include <net/net_namespace.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 65 |  | 
|  | 66 | /* Forward declarations for internal helpers. */ | 
|  | 67 | static int sctp_rcv_ootb(struct sk_buff *); | 
|  | 68 | static struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb, | 
|  | 69 | const union sctp_addr *laddr, | 
|  | 70 | const union sctp_addr *paddr, | 
|  | 71 | struct sctp_transport **transportp); | 
|  | 72 | static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr); | 
|  | 73 | static struct sctp_association *__sctp_lookup_association( | 
|  | 74 | const union sctp_addr *local, | 
|  | 75 | const union sctp_addr *peer, | 
|  | 76 | struct sctp_transport **pt); | 
|  | 77 |  | 
| Vladislav Yasevich | 61c9fed | 2006-05-19 11:01:18 -0700 | [diff] [blame] | 78 | static void sctp_add_backlog(struct sock *sk, struct sk_buff *skb); | 
|  | 79 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 80 |  | 
|  | 81 | /* Calculate the SCTP checksum of an SCTP packet.  */ | 
|  | 82 | static inline int sctp_rcv_checksum(struct sk_buff *skb) | 
|  | 83 | { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 84 | struct sk_buff *list = skb_shinfo(skb)->frag_list; | 
| Arnaldo Carvalho de Melo | 2c0fd38 | 2007-03-13 13:59:32 -0300 | [diff] [blame] | 85 | struct sctphdr *sh = sctp_hdr(skb); | 
| Harvey Harrison | 336d326 | 2008-07-18 23:07:09 -0700 | [diff] [blame] | 86 | __be32 cmp = sh->checksum; | 
|  | 87 | __be32 val = sctp_start_cksum((__u8 *)sh, skb_headlen(skb)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 88 |  | 
|  | 89 | for (; list; list = list->next) | 
|  | 90 | val = sctp_update_cksum((__u8 *)list->data, skb_headlen(list), | 
|  | 91 | val); | 
|  | 92 |  | 
|  | 93 | val = sctp_end_cksum(val); | 
|  | 94 |  | 
|  | 95 | if (val != cmp) { | 
|  | 96 | /* CRC failure, dump it. */ | 
|  | 97 | SCTP_INC_STATS_BH(SCTP_MIB_CHECKSUMERRORS); | 
|  | 98 | return -1; | 
|  | 99 | } | 
|  | 100 | return 0; | 
|  | 101 | } | 
|  | 102 |  | 
| David S. Miller | 79af02c | 2005-07-08 21:47:49 -0700 | [diff] [blame] | 103 | struct sctp_input_cb { | 
|  | 104 | union { | 
|  | 105 | struct inet_skb_parm	h4; | 
|  | 106 | #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) | 
|  | 107 | struct inet6_skb_parm	h6; | 
|  | 108 | #endif | 
|  | 109 | } header; | 
|  | 110 | struct sctp_chunk *chunk; | 
|  | 111 | }; | 
|  | 112 | #define SCTP_INPUT_CB(__skb)	((struct sctp_input_cb *)&((__skb)->cb[0])) | 
|  | 113 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 114 | /* | 
|  | 115 | * This is the routine which IP calls when receiving an SCTP packet. | 
|  | 116 | */ | 
|  | 117 | int sctp_rcv(struct sk_buff *skb) | 
|  | 118 | { | 
|  | 119 | struct sock *sk; | 
|  | 120 | struct sctp_association *asoc; | 
|  | 121 | struct sctp_endpoint *ep = NULL; | 
|  | 122 | struct sctp_ep_common *rcvr; | 
|  | 123 | struct sctp_transport *transport = NULL; | 
|  | 124 | struct sctp_chunk *chunk; | 
|  | 125 | struct sctphdr *sh; | 
|  | 126 | union sctp_addr src; | 
|  | 127 | union sctp_addr dest; | 
|  | 128 | int family; | 
|  | 129 | struct sctp_af *af; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 130 |  | 
|  | 131 | if (skb->pkt_type!=PACKET_HOST) | 
|  | 132 | goto discard_it; | 
|  | 133 |  | 
|  | 134 | SCTP_INC_STATS_BH(SCTP_MIB_INSCTPPACKS); | 
|  | 135 |  | 
| Herbert Xu | 28cd775 | 2006-10-29 23:46:42 -0800 | [diff] [blame] | 136 | if (skb_linearize(skb)) | 
|  | 137 | goto discard_it; | 
|  | 138 |  | 
| Arnaldo Carvalho de Melo | 2c0fd38 | 2007-03-13 13:59:32 -0300 | [diff] [blame] | 139 | sh = sctp_hdr(skb); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 140 |  | 
|  | 141 | /* Pull up the IP and SCTP headers. */ | 
| Arnaldo Carvalho de Melo | ea2ae17 | 2007-04-25 17:55:53 -0700 | [diff] [blame] | 142 | __skb_pull(skb, skb_transport_offset(skb)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 143 | if (skb->len < sizeof(struct sctphdr)) | 
|  | 144 | goto discard_it; | 
| Herbert Xu | 6047637 | 2007-04-09 11:59:39 -0700 | [diff] [blame] | 145 | if (!skb_csum_unnecessary(skb) && sctp_rcv_checksum(skb) < 0) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 146 | goto discard_it; | 
|  | 147 |  | 
|  | 148 | skb_pull(skb, sizeof(struct sctphdr)); | 
|  | 149 |  | 
|  | 150 | /* Make sure we at least have chunk headers worth of data left. */ | 
|  | 151 | if (skb->len < sizeof(struct sctp_chunkhdr)) | 
|  | 152 | goto discard_it; | 
|  | 153 |  | 
| Arnaldo Carvalho de Melo | eddc9ec | 2007-04-20 22:47:35 -0700 | [diff] [blame] | 154 | family = ipver2af(ip_hdr(skb)->version); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 155 | af = sctp_get_af_specific(family); | 
|  | 156 | if (unlikely(!af)) | 
|  | 157 | goto discard_it; | 
|  | 158 |  | 
|  | 159 | /* Initialize local addresses for lookups. */ | 
|  | 160 | af->from_skb(&src, skb, 1); | 
|  | 161 | af->from_skb(&dest, skb, 0); | 
|  | 162 |  | 
|  | 163 | /* If the packet is to or from a non-unicast address, | 
|  | 164 | * silently discard the packet. | 
|  | 165 | * | 
|  | 166 | * This is not clearly defined in the RFC except in section | 
|  | 167 | * 8.4 - OOTB handling.  However, based on the book "Stream Control | 
|  | 168 | * Transmission Protocol" 2.1, "It is important to note that the | 
|  | 169 | * IP address of an SCTP transport address must be a routable | 
|  | 170 | * unicast address.  In other words, IP multicast addresses and | 
|  | 171 | * IP broadcast addresses cannot be used in an SCTP transport | 
|  | 172 | * address." | 
|  | 173 | */ | 
| Vlad Yasevich | 5636bef | 2006-06-17 22:55:35 -0700 | [diff] [blame] | 174 | if (!af->addr_valid(&src, NULL, skb) || | 
|  | 175 | !af->addr_valid(&dest, NULL, skb)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 176 | goto discard_it; | 
|  | 177 |  | 
| Al Viro | d55c41b | 2006-11-20 17:09:40 -0800 | [diff] [blame] | 178 | asoc = __sctp_rcv_lookup(skb, &src, &dest, &transport); | 
| Al Viro | 1c7d1fc | 2006-11-20 17:08:09 -0800 | [diff] [blame] | 179 |  | 
| Neil Horman | 0fd9a65 | 2005-06-13 15:11:24 -0700 | [diff] [blame] | 180 | if (!asoc) | 
| Al Viro | d55c41b | 2006-11-20 17:09:40 -0800 | [diff] [blame] | 181 | ep = __sctp_rcv_lookup_endpoint(&dest); | 
| Neil Horman | 0fd9a65 | 2005-06-13 15:11:24 -0700 | [diff] [blame] | 182 |  | 
|  | 183 | /* Retrieve the common input handling substructure. */ | 
|  | 184 | rcvr = asoc ? &asoc->base : &ep->base; | 
|  | 185 | sk = rcvr->sk; | 
|  | 186 |  | 
|  | 187 | /* | 
|  | 188 | * If a frame arrives on an interface and the receiving socket is | 
|  | 189 | * bound to another interface, via SO_BINDTODEVICE, treat it as OOTB | 
|  | 190 | */ | 
|  | 191 | if (sk->sk_bound_dev_if && (sk->sk_bound_dev_if != af->skb_iif(skb))) | 
|  | 192 | { | 
| Neil Horman | 0fd9a65 | 2005-06-13 15:11:24 -0700 | [diff] [blame] | 193 | if (asoc) { | 
|  | 194 | sctp_association_put(asoc); | 
|  | 195 | asoc = NULL; | 
|  | 196 | } else { | 
|  | 197 | sctp_endpoint_put(ep); | 
|  | 198 | ep = NULL; | 
|  | 199 | } | 
|  | 200 | sk = sctp_get_ctl_sock(); | 
|  | 201 | ep = sctp_sk(sk)->ep; | 
|  | 202 | sctp_endpoint_hold(ep); | 
| Neil Horman | 0fd9a65 | 2005-06-13 15:11:24 -0700 | [diff] [blame] | 203 | rcvr = &ep->base; | 
|  | 204 | } | 
|  | 205 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 206 | /* | 
|  | 207 | * RFC 2960, 8.4 - Handle "Out of the blue" Packets. | 
|  | 208 | * An SCTP packet is called an "out of the blue" (OOTB) | 
|  | 209 | * packet if it is correctly formed, i.e., passed the | 
|  | 210 | * receiver's checksum check, but the receiver is not | 
|  | 211 | * able to identify the association to which this | 
|  | 212 | * packet belongs. | 
|  | 213 | */ | 
|  | 214 | if (!asoc) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 215 | if (sctp_rcv_ootb(skb)) { | 
|  | 216 | SCTP_INC_STATS_BH(SCTP_MIB_OUTOFBLUES); | 
|  | 217 | goto discard_release; | 
|  | 218 | } | 
|  | 219 | } | 
|  | 220 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 221 | if (!xfrm_policy_check(sk, XFRM_POLICY_IN, skb, family)) | 
|  | 222 | goto discard_release; | 
| Patrick McHardy | b59c270 | 2006-01-06 23:06:10 -0800 | [diff] [blame] | 223 | nf_reset(skb); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 224 |  | 
| Dmitry Mishin | fda9ef5 | 2006-08-31 15:28:39 -0700 | [diff] [blame] | 225 | if (sk_filter(sk, skb)) | 
| YOSHIFUJI Hideaki | d808ad9 | 2007-02-09 23:25:18 +0900 | [diff] [blame] | 226 | goto discard_release; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 227 |  | 
|  | 228 | /* Create an SCTP packet structure. */ | 
|  | 229 | chunk = sctp_chunkify(skb, asoc, sk); | 
| Herbert Xu | 2babf9d | 2006-03-25 01:25:29 -0800 | [diff] [blame] | 230 | if (!chunk) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 231 | goto discard_release; | 
| David S. Miller | 79af02c | 2005-07-08 21:47:49 -0700 | [diff] [blame] | 232 | SCTP_INPUT_CB(skb)->chunk = chunk; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 233 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 234 | /* Remember what endpoint is to handle this packet. */ | 
|  | 235 | chunk->rcvr = rcvr; | 
|  | 236 |  | 
|  | 237 | /* Remember the SCTP header. */ | 
|  | 238 | chunk->sctp_hdr = sh; | 
|  | 239 |  | 
|  | 240 | /* Set the source and destination addresses of the incoming chunk.  */ | 
| Al Viro | d55c41b | 2006-11-20 17:09:40 -0800 | [diff] [blame] | 241 | sctp_init_addrs(chunk, &src, &dest); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 242 |  | 
|  | 243 | /* Remember where we came from.  */ | 
|  | 244 | chunk->transport = transport; | 
|  | 245 |  | 
|  | 246 | /* Acquire access to the sock lock. Note: We are safe from other | 
|  | 247 | * bottom halves on this lock, but a user may be in the lock too, | 
|  | 248 | * so check if it is busy. | 
|  | 249 | */ | 
|  | 250 | sctp_bh_lock_sock(sk); | 
|  | 251 |  | 
| Sridhar Samudrala | ac0b046 | 2006-08-22 00:15:33 -0700 | [diff] [blame] | 252 | if (sock_owned_by_user(sk)) { | 
|  | 253 | SCTP_INC_STATS_BH(SCTP_MIB_IN_PKT_BACKLOG); | 
| Vladislav Yasevich | 61c9fed | 2006-05-19 11:01:18 -0700 | [diff] [blame] | 254 | sctp_add_backlog(sk, skb); | 
| Sridhar Samudrala | ac0b046 | 2006-08-22 00:15:33 -0700 | [diff] [blame] | 255 | } else { | 
|  | 256 | SCTP_INC_STATS_BH(SCTP_MIB_IN_PKT_SOFTIRQ); | 
| Vladislav Yasevich | 61c9fed | 2006-05-19 11:01:18 -0700 | [diff] [blame] | 257 | sctp_inq_push(&chunk->rcvr->inqueue, chunk); | 
| Sridhar Samudrala | ac0b046 | 2006-08-22 00:15:33 -0700 | [diff] [blame] | 258 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 259 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 260 | sctp_bh_unlock_sock(sk); | 
| Vladislav Yasevich | 61c9fed | 2006-05-19 11:01:18 -0700 | [diff] [blame] | 261 |  | 
|  | 262 | /* Release the asoc/ep ref we took in the lookup calls. */ | 
|  | 263 | if (asoc) | 
|  | 264 | sctp_association_put(asoc); | 
|  | 265 | else | 
|  | 266 | sctp_endpoint_put(ep); | 
| Sridhar Samudrala | 7a48f92 | 2006-01-17 11:51:28 -0800 | [diff] [blame] | 267 |  | 
| Herbert Xu | 2babf9d | 2006-03-25 01:25:29 -0800 | [diff] [blame] | 268 | return 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 269 |  | 
|  | 270 | discard_it: | 
| Sridhar Samudrala | ac0b046 | 2006-08-22 00:15:33 -0700 | [diff] [blame] | 271 | SCTP_INC_STATS_BH(SCTP_MIB_IN_PKT_DISCARDS); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 272 | kfree_skb(skb); | 
| Herbert Xu | 2babf9d | 2006-03-25 01:25:29 -0800 | [diff] [blame] | 273 | return 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 274 |  | 
|  | 275 | discard_release: | 
| Vladislav Yasevich | 61c9fed | 2006-05-19 11:01:18 -0700 | [diff] [blame] | 276 | /* Release the asoc/ep ref we took in the lookup calls. */ | 
| Neil Horman | 0fd9a65 | 2005-06-13 15:11:24 -0700 | [diff] [blame] | 277 | if (asoc) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 278 | sctp_association_put(asoc); | 
| Neil Horman | 0fd9a65 | 2005-06-13 15:11:24 -0700 | [diff] [blame] | 279 | else | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 280 | sctp_endpoint_put(ep); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 281 |  | 
|  | 282 | goto discard_it; | 
|  | 283 | } | 
|  | 284 |  | 
| Vladislav Yasevich | 61c9fed | 2006-05-19 11:01:18 -0700 | [diff] [blame] | 285 | /* Process the backlog queue of the socket.  Every skb on | 
|  | 286 | * the backlog holds a ref on an association or endpoint. | 
|  | 287 | * We hold this ref throughout the state machine to make | 
|  | 288 | * sure that the structure we need is still around. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 289 | */ | 
|  | 290 | int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) | 
|  | 291 | { | 
| David S. Miller | 79af02c | 2005-07-08 21:47:49 -0700 | [diff] [blame] | 292 | struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk; | 
| YOSHIFUJI Hideaki | d808ad9 | 2007-02-09 23:25:18 +0900 | [diff] [blame] | 293 | struct sctp_inq *inqueue = &chunk->rcvr->inqueue; | 
|  | 294 | struct sctp_ep_common *rcvr = NULL; | 
| Vladislav Yasevich | 61c9fed | 2006-05-19 11:01:18 -0700 | [diff] [blame] | 295 | int backloged = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 296 |  | 
| YOSHIFUJI Hideaki | d808ad9 | 2007-02-09 23:25:18 +0900 | [diff] [blame] | 297 | rcvr = chunk->rcvr; | 
| Sridhar Samudrala | c4d2444 | 2006-01-17 11:56:26 -0800 | [diff] [blame] | 298 |  | 
| Vladislav Yasevich | 61c9fed | 2006-05-19 11:01:18 -0700 | [diff] [blame] | 299 | /* If the rcvr is dead then the association or endpoint | 
|  | 300 | * has been deleted and we can safely drop the chunk | 
|  | 301 | * and refs that we are holding. | 
|  | 302 | */ | 
|  | 303 | if (rcvr->dead) { | 
|  | 304 | sctp_chunk_free(chunk); | 
|  | 305 | goto done; | 
|  | 306 | } | 
| Sridhar Samudrala | c4d2444 | 2006-01-17 11:56:26 -0800 | [diff] [blame] | 307 |  | 
| Vladislav Yasevich | 61c9fed | 2006-05-19 11:01:18 -0700 | [diff] [blame] | 308 | if (unlikely(rcvr->sk != sk)) { | 
|  | 309 | /* In this case, the association moved from one socket to | 
|  | 310 | * another.  We are currently sitting on the backlog of the | 
|  | 311 | * old socket, so we need to move. | 
|  | 312 | * However, since we are here in the process context we | 
|  | 313 | * need to take make sure that the user doesn't own | 
|  | 314 | * the new socket when we process the packet. | 
|  | 315 | * If the new socket is user-owned, queue the chunk to the | 
|  | 316 | * backlog of the new socket without dropping any refs. | 
|  | 317 | * Otherwise, we can safely push the chunk on the inqueue. | 
|  | 318 | */ | 
| Sridhar Samudrala | 7a48f92 | 2006-01-17 11:51:28 -0800 | [diff] [blame] | 319 |  | 
| Vladislav Yasevich | 61c9fed | 2006-05-19 11:01:18 -0700 | [diff] [blame] | 320 | sk = rcvr->sk; | 
|  | 321 | sctp_bh_lock_sock(sk); | 
|  | 322 |  | 
|  | 323 | if (sock_owned_by_user(sk)) { | 
|  | 324 | sk_add_backlog(sk, skb); | 
|  | 325 | backloged = 1; | 
|  | 326 | } else | 
|  | 327 | sctp_inq_push(inqueue, chunk); | 
|  | 328 |  | 
|  | 329 | sctp_bh_unlock_sock(sk); | 
|  | 330 |  | 
|  | 331 | /* If the chunk was backloged again, don't drop refs */ | 
|  | 332 | if (backloged) | 
|  | 333 | return 0; | 
|  | 334 | } else { | 
|  | 335 | sctp_inq_push(inqueue, chunk); | 
|  | 336 | } | 
|  | 337 |  | 
|  | 338 | done: | 
|  | 339 | /* Release the refs we took in sctp_add_backlog */ | 
|  | 340 | if (SCTP_EP_TYPE_ASSOCIATION == rcvr->type) | 
|  | 341 | sctp_association_put(sctp_assoc(rcvr)); | 
|  | 342 | else if (SCTP_EP_TYPE_SOCKET == rcvr->type) | 
|  | 343 | sctp_endpoint_put(sctp_ep(rcvr)); | 
|  | 344 | else | 
|  | 345 | BUG(); | 
|  | 346 |  | 
| YOSHIFUJI Hideaki | d808ad9 | 2007-02-09 23:25:18 +0900 | [diff] [blame] | 347 | return 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 348 | } | 
|  | 349 |  | 
| Vladislav Yasevich | 61c9fed | 2006-05-19 11:01:18 -0700 | [diff] [blame] | 350 | static void sctp_add_backlog(struct sock *sk, struct sk_buff *skb) | 
| Sridhar Samudrala | c4d2444 | 2006-01-17 11:56:26 -0800 | [diff] [blame] | 351 | { | 
| Vladislav Yasevich | 61c9fed | 2006-05-19 11:01:18 -0700 | [diff] [blame] | 352 | struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk; | 
|  | 353 | struct sctp_ep_common *rcvr = chunk->rcvr; | 
| Sridhar Samudrala | c4d2444 | 2006-01-17 11:56:26 -0800 | [diff] [blame] | 354 |  | 
| Vladislav Yasevich | 61c9fed | 2006-05-19 11:01:18 -0700 | [diff] [blame] | 355 | /* Hold the assoc/ep while hanging on the backlog queue. | 
|  | 356 | * This way, we know structures we need will not disappear from us | 
|  | 357 | */ | 
|  | 358 | if (SCTP_EP_TYPE_ASSOCIATION == rcvr->type) | 
|  | 359 | sctp_association_hold(sctp_assoc(rcvr)); | 
|  | 360 | else if (SCTP_EP_TYPE_SOCKET == rcvr->type) | 
|  | 361 | sctp_endpoint_hold(sctp_ep(rcvr)); | 
|  | 362 | else | 
|  | 363 | BUG(); | 
| Sridhar Samudrala | c4d2444 | 2006-01-17 11:56:26 -0800 | [diff] [blame] | 364 |  | 
| Vladislav Yasevich | 61c9fed | 2006-05-19 11:01:18 -0700 | [diff] [blame] | 365 | sk_add_backlog(sk, skb); | 
| Sridhar Samudrala | c4d2444 | 2006-01-17 11:56:26 -0800 | [diff] [blame] | 366 | } | 
|  | 367 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 368 | /* Handle icmp frag needed error. */ | 
|  | 369 | void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc, | 
|  | 370 | struct sctp_transport *t, __u32 pmtu) | 
|  | 371 | { | 
| Wei Yongjun | 91bd6b1 | 2008-10-23 00:59:52 -0700 | [diff] [blame] | 372 | if (!t || (t->pathmtu <= pmtu)) | 
| Frank Filz | 52ccb8e | 2005-12-22 11:36:46 -0800 | [diff] [blame] | 373 | return; | 
|  | 374 |  | 
| Vlad Yasevich | 8a47949 | 2007-06-07 14:21:05 -0400 | [diff] [blame] | 375 | if (sock_owned_by_user(sk)) { | 
|  | 376 | asoc->pmtu_pending = 1; | 
|  | 377 | t->pmtu_pending = 1; | 
|  | 378 | return; | 
|  | 379 | } | 
|  | 380 |  | 
| Frank Filz | 52ccb8e | 2005-12-22 11:36:46 -0800 | [diff] [blame] | 381 | if (t->param_flags & SPP_PMTUD_ENABLE) { | 
| Vlad Yasevich | c910b47 | 2007-06-07 13:47:03 -0400 | [diff] [blame] | 382 | /* Update transports view of the MTU */ | 
|  | 383 | sctp_transport_update_pmtu(t, pmtu); | 
| Frank Filz | 52ccb8e | 2005-12-22 11:36:46 -0800 | [diff] [blame] | 384 |  | 
|  | 385 | /* Update association pmtu. */ | 
|  | 386 | sctp_assoc_sync_pmtu(asoc); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 387 | } | 
|  | 388 |  | 
| Frank Filz | 52ccb8e | 2005-12-22 11:36:46 -0800 | [diff] [blame] | 389 | /* Retransmit with the new pmtu setting. | 
|  | 390 | * Normally, if PMTU discovery is disabled, an ICMP Fragmentation | 
|  | 391 | * Needed will never be sent, but if a message was sent before | 
|  | 392 | * PMTU discovery was disabled that was larger than the PMTU, it | 
| YOSHIFUJI Hideaki | d808ad9 | 2007-02-09 23:25:18 +0900 | [diff] [blame] | 393 | * would not be fragmented, so it must be re-transmitted fragmented. | 
| Frank Filz | 52ccb8e | 2005-12-22 11:36:46 -0800 | [diff] [blame] | 394 | */ | 
|  | 395 | sctp_retransmit(&asoc->outqueue, t, SCTP_RTXR_PMTUD); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 396 | } | 
|  | 397 |  | 
|  | 398 | /* | 
|  | 399 | * SCTP Implementer's Guide, 2.37 ICMP handling procedures | 
|  | 400 | * | 
|  | 401 | * ICMP8) If the ICMP code is a "Unrecognized next header type encountered" | 
|  | 402 | *        or a "Protocol Unreachable" treat this message as an abort | 
|  | 403 | *        with the T bit set. | 
|  | 404 | * | 
|  | 405 | * This function sends an event to the state machine, which will abort the | 
|  | 406 | * association. | 
|  | 407 | * | 
|  | 408 | */ | 
|  | 409 | void sctp_icmp_proto_unreachable(struct sock *sk, | 
| YOSHIFUJI Hideaki | d808ad9 | 2007-02-09 23:25:18 +0900 | [diff] [blame] | 410 | struct sctp_association *asoc, | 
|  | 411 | struct sctp_transport *t) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 412 | { | 
| Harvey Harrison | 0dc4787 | 2008-03-05 20:47:47 -0800 | [diff] [blame] | 413 | SCTP_DEBUG_PRINTK("%s\n",  __func__); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 414 |  | 
|  | 415 | sctp_do_sm(SCTP_EVENT_T_OTHER, | 
|  | 416 | SCTP_ST_OTHER(SCTP_EVENT_ICMP_PROTO_UNREACH), | 
| Frank Filz | 3f7a87d | 2005-06-20 13:14:57 -0700 | [diff] [blame] | 417 | asoc->state, asoc->ep, asoc, t, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 418 | GFP_ATOMIC); | 
|  | 419 |  | 
|  | 420 | } | 
|  | 421 |  | 
|  | 422 | /* Common lookup code for icmp/icmpv6 error handler. */ | 
|  | 423 | struct sock *sctp_err_lookup(int family, struct sk_buff *skb, | 
|  | 424 | struct sctphdr *sctphdr, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 425 | struct sctp_association **app, | 
|  | 426 | struct sctp_transport **tpp) | 
|  | 427 | { | 
|  | 428 | union sctp_addr saddr; | 
|  | 429 | union sctp_addr daddr; | 
|  | 430 | struct sctp_af *af; | 
|  | 431 | struct sock *sk = NULL; | 
| Sridhar Samudrala | 8de8c87 | 2006-05-19 10:58:12 -0700 | [diff] [blame] | 432 | struct sctp_association *asoc; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 433 | struct sctp_transport *transport = NULL; | 
| Wei Yongjun | 7115e63 | 2008-06-19 16:07:48 -0700 | [diff] [blame] | 434 | struct sctp_init_chunk *chunkhdr; | 
|  | 435 | __u32 vtag = ntohl(sctphdr->vtag); | 
|  | 436 | int len = skb->len - ((void *)sctphdr - (void *)skb->data); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 437 |  | 
| Sridhar Samudrala | d1ad1ff | 2005-07-18 13:44:10 -0700 | [diff] [blame] | 438 | *app = NULL; *tpp = NULL; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 439 |  | 
|  | 440 | af = sctp_get_af_specific(family); | 
|  | 441 | if (unlikely(!af)) { | 
|  | 442 | return NULL; | 
|  | 443 | } | 
|  | 444 |  | 
|  | 445 | /* Initialize local addresses for lookups. */ | 
|  | 446 | af->from_skb(&saddr, skb, 1); | 
|  | 447 | af->from_skb(&daddr, skb, 0); | 
|  | 448 |  | 
|  | 449 | /* Look for an association that matches the incoming ICMP error | 
|  | 450 | * packet. | 
|  | 451 | */ | 
| Al Viro | d55c41b | 2006-11-20 17:09:40 -0800 | [diff] [blame] | 452 | asoc = __sctp_lookup_association(&saddr, &daddr, &transport); | 
| Sridhar Samudrala | d1ad1ff | 2005-07-18 13:44:10 -0700 | [diff] [blame] | 453 | if (!asoc) | 
|  | 454 | return NULL; | 
|  | 455 |  | 
|  | 456 | sk = asoc->base.sk; | 
|  | 457 |  | 
| Wei Yongjun | 7115e63 | 2008-06-19 16:07:48 -0700 | [diff] [blame] | 458 | /* RFC 4960, Appendix C. ICMP Handling | 
|  | 459 | * | 
|  | 460 | * ICMP6) An implementation MUST validate that the Verification Tag | 
|  | 461 | * contained in the ICMP message matches the Verification Tag of | 
|  | 462 | * the peer.  If the Verification Tag is not 0 and does NOT | 
|  | 463 | * match, discard the ICMP message.  If it is 0 and the ICMP | 
|  | 464 | * message contains enough bytes to verify that the chunk type is | 
|  | 465 | * an INIT chunk and that the Initiate Tag matches the tag of the | 
|  | 466 | * peer, continue with ICMP7.  If the ICMP message is too short | 
|  | 467 | * or the chunk type or the Initiate Tag does not match, silently | 
|  | 468 | * discard the packet. | 
|  | 469 | */ | 
|  | 470 | if (vtag == 0) { | 
|  | 471 | chunkhdr = (struct sctp_init_chunk *)((void *)sctphdr | 
|  | 472 | + sizeof(struct sctphdr)); | 
|  | 473 | if (len < sizeof(struct sctphdr) + sizeof(sctp_chunkhdr_t) | 
|  | 474 | + sizeof(__be32) || | 
|  | 475 | chunkhdr->chunk_hdr.type != SCTP_CID_INIT || | 
|  | 476 | ntohl(chunkhdr->init_hdr.init_tag) != asoc->c.my_vtag) { | 
|  | 477 | goto out; | 
|  | 478 | } | 
|  | 479 | } else if (vtag != asoc->c.peer_vtag) { | 
| Sridhar Samudrala | d1ad1ff | 2005-07-18 13:44:10 -0700 | [diff] [blame] | 480 | goto out; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 481 | } | 
|  | 482 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 483 | sctp_bh_lock_sock(sk); | 
|  | 484 |  | 
|  | 485 | /* If too many ICMPs get dropped on busy | 
|  | 486 | * servers this needs to be solved differently. | 
|  | 487 | */ | 
|  | 488 | if (sock_owned_by_user(sk)) | 
| Pavel Emelyanov | de0744a | 2008-07-16 20:31:16 -0700 | [diff] [blame] | 489 | NET_INC_STATS_BH(&init_net, LINUX_MIB_LOCKDROPPEDICMPS); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 490 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 491 | *app = asoc; | 
|  | 492 | *tpp = transport; | 
|  | 493 | return sk; | 
|  | 494 |  | 
|  | 495 | out: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 496 | if (asoc) | 
|  | 497 | sctp_association_put(asoc); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 498 | return NULL; | 
|  | 499 | } | 
|  | 500 |  | 
|  | 501 | /* Common cleanup code for icmp/icmpv6 error handler. */ | 
| Sridhar Samudrala | d1ad1ff | 2005-07-18 13:44:10 -0700 | [diff] [blame] | 502 | void sctp_err_finish(struct sock *sk, struct sctp_association *asoc) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 503 | { | 
|  | 504 | sctp_bh_unlock_sock(sk); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 505 | if (asoc) | 
|  | 506 | sctp_association_put(asoc); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 507 | } | 
|  | 508 |  | 
|  | 509 | /* | 
|  | 510 | * This routine is called by the ICMP module when it gets some | 
|  | 511 | * sort of error condition.  If err < 0 then the socket should | 
|  | 512 | * be closed and the error returned to the user.  If err > 0 | 
|  | 513 | * it's just the icmp type << 8 | icmp code.  After adjustment | 
|  | 514 | * header points to the first 8 bytes of the sctp header.  We need | 
|  | 515 | * to find the appropriate port. | 
|  | 516 | * | 
|  | 517 | * The locking strategy used here is very "optimistic". When | 
|  | 518 | * someone else accesses the socket the ICMP is just dropped | 
|  | 519 | * and for some paths there is no check at all. | 
|  | 520 | * A more general error queue to queue errors for later handling | 
|  | 521 | * is probably better. | 
|  | 522 | * | 
|  | 523 | */ | 
|  | 524 | void sctp_v4_err(struct sk_buff *skb, __u32 info) | 
|  | 525 | { | 
|  | 526 | struct iphdr *iph = (struct iphdr *)skb->data; | 
| Arnaldo Carvalho de Melo | a27ef74 | 2007-03-13 17:17:10 -0300 | [diff] [blame] | 527 | const int ihlen = iph->ihl * 4; | 
| Arnaldo Carvalho de Melo | 88c7664 | 2007-03-13 14:43:18 -0300 | [diff] [blame] | 528 | const int type = icmp_hdr(skb)->type; | 
|  | 529 | const int code = icmp_hdr(skb)->code; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 530 | struct sock *sk; | 
| Sridhar Samudrala | 8de8c87 | 2006-05-19 10:58:12 -0700 | [diff] [blame] | 531 | struct sctp_association *asoc = NULL; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 532 | struct sctp_transport *transport; | 
|  | 533 | struct inet_sock *inet; | 
| Arnaldo Carvalho de Melo | 2e07fa9 | 2007-04-10 21:22:35 -0700 | [diff] [blame] | 534 | sk_buff_data_t saveip, savesctp; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 535 | int err; | 
|  | 536 |  | 
| Arnaldo Carvalho de Melo | a27ef74 | 2007-03-13 17:17:10 -0300 | [diff] [blame] | 537 | if (skb->len < ihlen + 8) { | 
| Pavel Emelyanov | dcfc23c | 2008-07-14 23:03:00 -0700 | [diff] [blame] | 538 | ICMP_INC_STATS_BH(&init_net, ICMP_MIB_INERRORS); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 539 | return; | 
|  | 540 | } | 
|  | 541 |  | 
|  | 542 | /* Fix up skb to look at the embedded net header. */ | 
| Arnaldo Carvalho de Melo | b0e380b | 2007-04-10 21:21:55 -0700 | [diff] [blame] | 543 | saveip = skb->network_header; | 
|  | 544 | savesctp = skb->transport_header; | 
| Arnaldo Carvalho de Melo | 31c7711 | 2007-03-10 19:04:55 -0300 | [diff] [blame] | 545 | skb_reset_network_header(skb); | 
| Arnaldo Carvalho de Melo | a27ef74 | 2007-03-13 17:17:10 -0300 | [diff] [blame] | 546 | skb_set_transport_header(skb, ihlen); | 
|  | 547 | sk = sctp_err_lookup(AF_INET, skb, sctp_hdr(skb), &asoc, &transport); | 
| Arnaldo Carvalho de Melo | 2e07fa9 | 2007-04-10 21:22:35 -0700 | [diff] [blame] | 548 | /* Put back, the original values. */ | 
| Arnaldo Carvalho de Melo | b0e380b | 2007-04-10 21:21:55 -0700 | [diff] [blame] | 549 | skb->network_header = saveip; | 
|  | 550 | skb->transport_header = savesctp; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 551 | if (!sk) { | 
| Pavel Emelyanov | dcfc23c | 2008-07-14 23:03:00 -0700 | [diff] [blame] | 552 | ICMP_INC_STATS_BH(&init_net, ICMP_MIB_INERRORS); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 553 | return; | 
|  | 554 | } | 
|  | 555 | /* Warning:  The sock lock is held.  Remember to call | 
|  | 556 | * sctp_err_finish! | 
|  | 557 | */ | 
|  | 558 |  | 
|  | 559 | switch (type) { | 
|  | 560 | case ICMP_PARAMETERPROB: | 
|  | 561 | err = EPROTO; | 
|  | 562 | break; | 
|  | 563 | case ICMP_DEST_UNREACH: | 
|  | 564 | if (code > NR_ICMP_UNREACH) | 
|  | 565 | goto out_unlock; | 
|  | 566 |  | 
|  | 567 | /* PMTU discovery (RFC1191) */ | 
|  | 568 | if (ICMP_FRAG_NEEDED == code) { | 
|  | 569 | sctp_icmp_frag_needed(sk, asoc, transport, info); | 
|  | 570 | goto out_unlock; | 
|  | 571 | } | 
|  | 572 | else { | 
|  | 573 | if (ICMP_PROT_UNREACH == code) { | 
| Sridhar Samudrala | d1ad1ff | 2005-07-18 13:44:10 -0700 | [diff] [blame] | 574 | sctp_icmp_proto_unreachable(sk, asoc, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 575 | transport); | 
|  | 576 | goto out_unlock; | 
|  | 577 | } | 
|  | 578 | } | 
|  | 579 | err = icmp_err_convert[code].errno; | 
|  | 580 | break; | 
|  | 581 | case ICMP_TIME_EXCEEDED: | 
|  | 582 | /* Ignore any time exceeded errors due to fragment reassembly | 
|  | 583 | * timeouts. | 
|  | 584 | */ | 
|  | 585 | if (ICMP_EXC_FRAGTIME == code) | 
|  | 586 | goto out_unlock; | 
|  | 587 |  | 
|  | 588 | err = EHOSTUNREACH; | 
|  | 589 | break; | 
|  | 590 | default: | 
|  | 591 | goto out_unlock; | 
|  | 592 | } | 
|  | 593 |  | 
|  | 594 | inet = inet_sk(sk); | 
|  | 595 | if (!sock_owned_by_user(sk) && inet->recverr) { | 
|  | 596 | sk->sk_err = err; | 
|  | 597 | sk->sk_error_report(sk); | 
|  | 598 | } else {  /* Only an error on timeout */ | 
|  | 599 | sk->sk_err_soft = err; | 
|  | 600 | } | 
|  | 601 |  | 
|  | 602 | out_unlock: | 
| Sridhar Samudrala | d1ad1ff | 2005-07-18 13:44:10 -0700 | [diff] [blame] | 603 | sctp_err_finish(sk, asoc); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 604 | } | 
|  | 605 |  | 
|  | 606 | /* | 
|  | 607 | * RFC 2960, 8.4 - Handle "Out of the blue" Packets. | 
|  | 608 | * | 
|  | 609 | * This function scans all the chunks in the OOTB packet to determine if | 
|  | 610 | * the packet should be discarded right away.  If a response might be needed | 
|  | 611 | * for this packet, or, if further processing is possible, the packet will | 
|  | 612 | * be queued to a proper inqueue for the next phase of handling. | 
|  | 613 | * | 
|  | 614 | * Output: | 
|  | 615 | * Return 0 - If further processing is needed. | 
|  | 616 | * Return 1 - If the packet can be discarded right away. | 
|  | 617 | */ | 
| sebastian@breakpoint.cc | 0467521 | 2007-07-26 23:21:31 +0200 | [diff] [blame] | 618 | static int sctp_rcv_ootb(struct sk_buff *skb) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 619 | { | 
|  | 620 | sctp_chunkhdr_t *ch; | 
|  | 621 | __u8 *ch_end; | 
|  | 622 | sctp_errhdr_t *err; | 
|  | 623 |  | 
|  | 624 | ch = (sctp_chunkhdr_t *) skb->data; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 625 |  | 
|  | 626 | /* Scan through all the chunks in the packet.  */ | 
| Tsutomu Fujii | a7d1f1b | 2006-01-17 11:57:09 -0800 | [diff] [blame] | 627 | do { | 
|  | 628 | /* Break out if chunk length is less then minimal. */ | 
|  | 629 | if (ntohs(ch->length) < sizeof(sctp_chunkhdr_t)) | 
|  | 630 | break; | 
|  | 631 |  | 
|  | 632 | ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length)); | 
| Arnaldo Carvalho de Melo | 27a884d | 2007-04-19 20:29:13 -0700 | [diff] [blame] | 633 | if (ch_end > skb_tail_pointer(skb)) | 
| Tsutomu Fujii | a7d1f1b | 2006-01-17 11:57:09 -0800 | [diff] [blame] | 634 | break; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 635 |  | 
|  | 636 | /* RFC 8.4, 2) If the OOTB packet contains an ABORT chunk, the | 
|  | 637 | * receiver MUST silently discard the OOTB packet and take no | 
|  | 638 | * further action. | 
|  | 639 | */ | 
|  | 640 | if (SCTP_CID_ABORT == ch->type) | 
|  | 641 | goto discard; | 
|  | 642 |  | 
|  | 643 | /* RFC 8.4, 6) If the packet contains a SHUTDOWN COMPLETE | 
|  | 644 | * chunk, the receiver should silently discard the packet | 
|  | 645 | * and take no further action. | 
|  | 646 | */ | 
|  | 647 | if (SCTP_CID_SHUTDOWN_COMPLETE == ch->type) | 
|  | 648 | goto discard; | 
|  | 649 |  | 
| Vlad Yasevich | 3c77f96 | 2007-09-17 15:14:28 -0400 | [diff] [blame] | 650 | /* RFC 4460, 2.11.2 | 
|  | 651 | * This will discard packets with INIT chunk bundled as | 
|  | 652 | * subsequent chunks in the packet.  When INIT is first, | 
|  | 653 | * the normal INIT processing will discard the chunk. | 
|  | 654 | */ | 
|  | 655 | if (SCTP_CID_INIT == ch->type && (void *)ch != skb->data) | 
|  | 656 | goto discard; | 
|  | 657 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 658 | /* RFC 8.4, 7) If the packet contains a "Stale cookie" ERROR | 
|  | 659 | * or a COOKIE ACK the SCTP Packet should be silently | 
|  | 660 | * discarded. | 
|  | 661 | */ | 
|  | 662 | if (SCTP_CID_COOKIE_ACK == ch->type) | 
|  | 663 | goto discard; | 
|  | 664 |  | 
|  | 665 | if (SCTP_CID_ERROR == ch->type) { | 
|  | 666 | sctp_walk_errors(err, ch) { | 
|  | 667 | if (SCTP_ERROR_STALE_COOKIE == err->cause) | 
|  | 668 | goto discard; | 
|  | 669 | } | 
|  | 670 | } | 
|  | 671 |  | 
|  | 672 | ch = (sctp_chunkhdr_t *) ch_end; | 
| Arnaldo Carvalho de Melo | 27a884d | 2007-04-19 20:29:13 -0700 | [diff] [blame] | 673 | } while (ch_end < skb_tail_pointer(skb)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 674 |  | 
|  | 675 | return 0; | 
|  | 676 |  | 
|  | 677 | discard: | 
|  | 678 | return 1; | 
|  | 679 | } | 
|  | 680 |  | 
|  | 681 | /* Insert endpoint into the hash table.  */ | 
|  | 682 | static void __sctp_hash_endpoint(struct sctp_endpoint *ep) | 
|  | 683 | { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 684 | struct sctp_ep_common *epb; | 
|  | 685 | struct sctp_hashbucket *head; | 
|  | 686 |  | 
|  | 687 | epb = &ep->base; | 
|  | 688 |  | 
|  | 689 | epb->hashent = sctp_ep_hashfn(epb->bind_addr.port); | 
|  | 690 | head = &sctp_ep_hashtable[epb->hashent]; | 
|  | 691 |  | 
|  | 692 | sctp_write_lock(&head->lock); | 
| Vlad Yasevich | d970dbf | 2007-11-09 11:43:40 -0500 | [diff] [blame] | 693 | hlist_add_head(&epb->node, &head->chain); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 694 | sctp_write_unlock(&head->lock); | 
|  | 695 | } | 
|  | 696 |  | 
|  | 697 | /* Add an endpoint to the hash. Local BH-safe. */ | 
|  | 698 | void sctp_hash_endpoint(struct sctp_endpoint *ep) | 
|  | 699 | { | 
|  | 700 | sctp_local_bh_disable(); | 
|  | 701 | __sctp_hash_endpoint(ep); | 
|  | 702 | sctp_local_bh_enable(); | 
|  | 703 | } | 
|  | 704 |  | 
|  | 705 | /* Remove endpoint from the hash table.  */ | 
|  | 706 | static void __sctp_unhash_endpoint(struct sctp_endpoint *ep) | 
|  | 707 | { | 
|  | 708 | struct sctp_hashbucket *head; | 
|  | 709 | struct sctp_ep_common *epb; | 
|  | 710 |  | 
|  | 711 | epb = &ep->base; | 
|  | 712 |  | 
| Vlad Yasevich | d970dbf | 2007-11-09 11:43:40 -0500 | [diff] [blame] | 713 | if (hlist_unhashed(&epb->node)) | 
|  | 714 | return; | 
|  | 715 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 716 | epb->hashent = sctp_ep_hashfn(epb->bind_addr.port); | 
|  | 717 |  | 
|  | 718 | head = &sctp_ep_hashtable[epb->hashent]; | 
|  | 719 |  | 
|  | 720 | sctp_write_lock(&head->lock); | 
| Vlad Yasevich | d970dbf | 2007-11-09 11:43:40 -0500 | [diff] [blame] | 721 | __hlist_del(&epb->node); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 722 | sctp_write_unlock(&head->lock); | 
|  | 723 | } | 
|  | 724 |  | 
|  | 725 | /* Remove endpoint from the hash.  Local BH-safe. */ | 
|  | 726 | void sctp_unhash_endpoint(struct sctp_endpoint *ep) | 
|  | 727 | { | 
|  | 728 | sctp_local_bh_disable(); | 
|  | 729 | __sctp_unhash_endpoint(ep); | 
|  | 730 | sctp_local_bh_enable(); | 
|  | 731 | } | 
|  | 732 |  | 
|  | 733 | /* Look up an endpoint. */ | 
|  | 734 | static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr) | 
|  | 735 | { | 
|  | 736 | struct sctp_hashbucket *head; | 
|  | 737 | struct sctp_ep_common *epb; | 
|  | 738 | struct sctp_endpoint *ep; | 
| Vlad Yasevich | d970dbf | 2007-11-09 11:43:40 -0500 | [diff] [blame] | 739 | struct hlist_node *node; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 740 | int hash; | 
|  | 741 |  | 
| Al Viro | 1c7d1fc | 2006-11-20 17:08:09 -0800 | [diff] [blame] | 742 | hash = sctp_ep_hashfn(ntohs(laddr->v4.sin_port)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 743 | head = &sctp_ep_hashtable[hash]; | 
|  | 744 | read_lock(&head->lock); | 
| Vlad Yasevich | d970dbf | 2007-11-09 11:43:40 -0500 | [diff] [blame] | 745 | sctp_for_each_hentry(epb, node, &head->chain) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 746 | ep = sctp_ep(epb); | 
|  | 747 | if (sctp_endpoint_is_match(ep, laddr)) | 
|  | 748 | goto hit; | 
|  | 749 | } | 
|  | 750 |  | 
|  | 751 | ep = sctp_sk((sctp_get_ctl_sock()))->ep; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 752 |  | 
|  | 753 | hit: | 
|  | 754 | sctp_endpoint_hold(ep); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 755 | read_unlock(&head->lock); | 
|  | 756 | return ep; | 
|  | 757 | } | 
|  | 758 |  | 
|  | 759 | /* Insert association into the hash table.  */ | 
|  | 760 | static void __sctp_hash_established(struct sctp_association *asoc) | 
|  | 761 | { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 762 | struct sctp_ep_common *epb; | 
|  | 763 | struct sctp_hashbucket *head; | 
|  | 764 |  | 
|  | 765 | epb = &asoc->base; | 
|  | 766 |  | 
|  | 767 | /* Calculate which chain this entry will belong to. */ | 
|  | 768 | epb->hashent = sctp_assoc_hashfn(epb->bind_addr.port, asoc->peer.port); | 
|  | 769 |  | 
|  | 770 | head = &sctp_assoc_hashtable[epb->hashent]; | 
|  | 771 |  | 
|  | 772 | sctp_write_lock(&head->lock); | 
| Vlad Yasevich | d970dbf | 2007-11-09 11:43:40 -0500 | [diff] [blame] | 773 | hlist_add_head(&epb->node, &head->chain); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 774 | sctp_write_unlock(&head->lock); | 
|  | 775 | } | 
|  | 776 |  | 
|  | 777 | /* Add an association to the hash. Local BH-safe. */ | 
|  | 778 | void sctp_hash_established(struct sctp_association *asoc) | 
|  | 779 | { | 
| Vlad Yasevich | de76e69 | 2006-10-30 18:55:11 -0800 | [diff] [blame] | 780 | if (asoc->temp) | 
|  | 781 | return; | 
|  | 782 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 783 | sctp_local_bh_disable(); | 
|  | 784 | __sctp_hash_established(asoc); | 
|  | 785 | sctp_local_bh_enable(); | 
|  | 786 | } | 
|  | 787 |  | 
|  | 788 | /* Remove association from the hash table.  */ | 
|  | 789 | static void __sctp_unhash_established(struct sctp_association *asoc) | 
|  | 790 | { | 
|  | 791 | struct sctp_hashbucket *head; | 
|  | 792 | struct sctp_ep_common *epb; | 
|  | 793 |  | 
|  | 794 | epb = &asoc->base; | 
|  | 795 |  | 
|  | 796 | epb->hashent = sctp_assoc_hashfn(epb->bind_addr.port, | 
|  | 797 | asoc->peer.port); | 
|  | 798 |  | 
|  | 799 | head = &sctp_assoc_hashtable[epb->hashent]; | 
|  | 800 |  | 
|  | 801 | sctp_write_lock(&head->lock); | 
| Vlad Yasevich | d970dbf | 2007-11-09 11:43:40 -0500 | [diff] [blame] | 802 | __hlist_del(&epb->node); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 803 | sctp_write_unlock(&head->lock); | 
|  | 804 | } | 
|  | 805 |  | 
|  | 806 | /* Remove association from the hash table.  Local BH-safe. */ | 
|  | 807 | void sctp_unhash_established(struct sctp_association *asoc) | 
|  | 808 | { | 
| Vlad Yasevich | de76e69 | 2006-10-30 18:55:11 -0800 | [diff] [blame] | 809 | if (asoc->temp) | 
|  | 810 | return; | 
|  | 811 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 812 | sctp_local_bh_disable(); | 
|  | 813 | __sctp_unhash_established(asoc); | 
|  | 814 | sctp_local_bh_enable(); | 
|  | 815 | } | 
|  | 816 |  | 
|  | 817 | /* Look up an association. */ | 
|  | 818 | static struct sctp_association *__sctp_lookup_association( | 
|  | 819 | const union sctp_addr *local, | 
|  | 820 | const union sctp_addr *peer, | 
|  | 821 | struct sctp_transport **pt) | 
|  | 822 | { | 
|  | 823 | struct sctp_hashbucket *head; | 
|  | 824 | struct sctp_ep_common *epb; | 
|  | 825 | struct sctp_association *asoc; | 
|  | 826 | struct sctp_transport *transport; | 
| Vlad Yasevich | d970dbf | 2007-11-09 11:43:40 -0500 | [diff] [blame] | 827 | struct hlist_node *node; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 828 | int hash; | 
|  | 829 |  | 
|  | 830 | /* Optimize here for direct hit, only listening connections can | 
|  | 831 | * have wildcards anyways. | 
|  | 832 | */ | 
| Al Viro | e2fcced | 2006-11-20 17:08:41 -0800 | [diff] [blame] | 833 | hash = sctp_assoc_hashfn(ntohs(local->v4.sin_port), ntohs(peer->v4.sin_port)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 834 | head = &sctp_assoc_hashtable[hash]; | 
|  | 835 | read_lock(&head->lock); | 
| Vlad Yasevich | d970dbf | 2007-11-09 11:43:40 -0500 | [diff] [blame] | 836 | sctp_for_each_hentry(epb, node, &head->chain) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 837 | asoc = sctp_assoc(epb); | 
|  | 838 | transport = sctp_assoc_is_match(asoc, local, peer); | 
|  | 839 | if (transport) | 
|  | 840 | goto hit; | 
|  | 841 | } | 
|  | 842 |  | 
|  | 843 | read_unlock(&head->lock); | 
|  | 844 |  | 
|  | 845 | return NULL; | 
|  | 846 |  | 
|  | 847 | hit: | 
|  | 848 | *pt = transport; | 
|  | 849 | sctp_association_hold(asoc); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 850 | read_unlock(&head->lock); | 
|  | 851 | return asoc; | 
|  | 852 | } | 
|  | 853 |  | 
|  | 854 | /* Look up an association. BH-safe. */ | 
|  | 855 | SCTP_STATIC | 
|  | 856 | struct sctp_association *sctp_lookup_association(const union sctp_addr *laddr, | 
|  | 857 | const union sctp_addr *paddr, | 
|  | 858 | struct sctp_transport **transportp) | 
|  | 859 | { | 
|  | 860 | struct sctp_association *asoc; | 
|  | 861 |  | 
|  | 862 | sctp_local_bh_disable(); | 
|  | 863 | asoc = __sctp_lookup_association(laddr, paddr, transportp); | 
|  | 864 | sctp_local_bh_enable(); | 
|  | 865 |  | 
|  | 866 | return asoc; | 
|  | 867 | } | 
|  | 868 |  | 
|  | 869 | /* Is there an association matching the given local and peer addresses? */ | 
|  | 870 | int sctp_has_association(const union sctp_addr *laddr, | 
|  | 871 | const union sctp_addr *paddr) | 
|  | 872 | { | 
|  | 873 | struct sctp_association *asoc; | 
|  | 874 | struct sctp_transport *transport; | 
|  | 875 |  | 
| Al Viro | 6c7be55 | 2006-11-20 17:11:50 -0800 | [diff] [blame] | 876 | if ((asoc = sctp_lookup_association(laddr, paddr, &transport))) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 877 | sctp_association_put(asoc); | 
|  | 878 | return 1; | 
|  | 879 | } | 
|  | 880 |  | 
|  | 881 | return 0; | 
|  | 882 | } | 
|  | 883 |  | 
|  | 884 | /* | 
|  | 885 | * SCTP Implementors Guide, 2.18 Handling of address | 
|  | 886 | * parameters within the INIT or INIT-ACK. | 
|  | 887 | * | 
|  | 888 | * D) When searching for a matching TCB upon reception of an INIT | 
|  | 889 | *    or INIT-ACK chunk the receiver SHOULD use not only the | 
|  | 890 | *    source address of the packet (containing the INIT or | 
|  | 891 | *    INIT-ACK) but the receiver SHOULD also use all valid | 
|  | 892 | *    address parameters contained within the chunk. | 
|  | 893 | * | 
|  | 894 | * 2.18.3 Solution description | 
|  | 895 | * | 
|  | 896 | * This new text clearly specifies to an implementor the need | 
|  | 897 | * to look within the INIT or INIT-ACK. Any implementation that | 
|  | 898 | * does not do this, may not be able to establish associations | 
|  | 899 | * in certain circumstances. | 
|  | 900 | * | 
|  | 901 | */ | 
|  | 902 | static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb, | 
|  | 903 | const union sctp_addr *laddr, struct sctp_transport **transportp) | 
|  | 904 | { | 
|  | 905 | struct sctp_association *asoc; | 
|  | 906 | union sctp_addr addr; | 
|  | 907 | union sctp_addr *paddr = &addr; | 
| Arnaldo Carvalho de Melo | 2c0fd38 | 2007-03-13 13:59:32 -0300 | [diff] [blame] | 908 | struct sctphdr *sh = sctp_hdr(skb); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 909 | sctp_chunkhdr_t *ch; | 
|  | 910 | union sctp_params params; | 
|  | 911 | sctp_init_chunk_t *init; | 
|  | 912 | struct sctp_transport *transport; | 
|  | 913 | struct sctp_af *af; | 
|  | 914 |  | 
|  | 915 | ch = (sctp_chunkhdr_t *) skb->data; | 
|  | 916 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 917 | /* | 
|  | 918 | * This code will NOT touch anything inside the chunk--it is | 
|  | 919 | * strictly READ-ONLY. | 
|  | 920 | * | 
|  | 921 | * RFC 2960 3  SCTP packet Format | 
|  | 922 | * | 
|  | 923 | * Multiple chunks can be bundled into one SCTP packet up to | 
|  | 924 | * the MTU size, except for the INIT, INIT ACK, and SHUTDOWN | 
|  | 925 | * COMPLETE chunks.  These chunks MUST NOT be bundled with any | 
|  | 926 | * other chunk in a packet.  See Section 6.10 for more details | 
|  | 927 | * on chunk bundling. | 
|  | 928 | */ | 
|  | 929 |  | 
|  | 930 | /* Find the start of the TLVs and the end of the chunk.  This is | 
|  | 931 | * the region we search for address parameters. | 
|  | 932 | */ | 
|  | 933 | init = (sctp_init_chunk_t *)skb->data; | 
|  | 934 |  | 
|  | 935 | /* Walk the parameters looking for embedded addresses. */ | 
|  | 936 | sctp_walk_params(params, init, init_hdr.params) { | 
|  | 937 |  | 
|  | 938 | /* Note: Ignoring hostname addresses. */ | 
|  | 939 | af = sctp_get_af_specific(param_type2af(params.p->type)); | 
|  | 940 | if (!af) | 
|  | 941 | continue; | 
|  | 942 |  | 
| Al Viro | dd86d13 | 2006-11-20 17:11:13 -0800 | [diff] [blame] | 943 | af->from_addr_param(paddr, params.addr, sh->source, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 944 |  | 
| Al Viro | dd86d13 | 2006-11-20 17:11:13 -0800 | [diff] [blame] | 945 | asoc = __sctp_lookup_association(laddr, paddr, &transport); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 946 | if (asoc) | 
|  | 947 | return asoc; | 
|  | 948 | } | 
|  | 949 |  | 
|  | 950 | return NULL; | 
|  | 951 | } | 
|  | 952 |  | 
| Vlad Yasevich | df21857 | 2007-12-20 14:10:38 -0800 | [diff] [blame] | 953 | /* ADD-IP, Section 5.2 | 
|  | 954 | * When an endpoint receives an ASCONF Chunk from the remote peer | 
|  | 955 | * special procedures may be needed to identify the association the | 
|  | 956 | * ASCONF Chunk is associated with. To properly find the association | 
|  | 957 | * the following procedures SHOULD be followed: | 
|  | 958 | * | 
|  | 959 | * D2) If the association is not found, use the address found in the | 
|  | 960 | * Address Parameter TLV combined with the port number found in the | 
|  | 961 | * SCTP common header. If found proceed to rule D4. | 
|  | 962 | * | 
|  | 963 | * D2-ext) If more than one ASCONF Chunks are packed together, use the | 
|  | 964 | * address found in the ASCONF Address Parameter TLV of each of the | 
|  | 965 | * subsequent ASCONF Chunks. If found, proceed to rule D4. | 
|  | 966 | */ | 
|  | 967 | static struct sctp_association *__sctp_rcv_asconf_lookup( | 
|  | 968 | sctp_chunkhdr_t *ch, | 
|  | 969 | const union sctp_addr *laddr, | 
| Al Viro | bc92dd1 | 2008-03-17 22:47:32 -0700 | [diff] [blame] | 970 | __be16 peer_port, | 
| Vlad Yasevich | df21857 | 2007-12-20 14:10:38 -0800 | [diff] [blame] | 971 | struct sctp_transport **transportp) | 
|  | 972 | { | 
|  | 973 | sctp_addip_chunk_t *asconf = (struct sctp_addip_chunk *)ch; | 
|  | 974 | struct sctp_af *af; | 
|  | 975 | union sctp_addr_param *param; | 
|  | 976 | union sctp_addr paddr; | 
|  | 977 |  | 
|  | 978 | /* Skip over the ADDIP header and find the Address parameter */ | 
|  | 979 | param = (union sctp_addr_param *)(asconf + 1); | 
|  | 980 |  | 
|  | 981 | af = sctp_get_af_specific(param_type2af(param->v4.param_hdr.type)); | 
|  | 982 | if (unlikely(!af)) | 
|  | 983 | return NULL; | 
|  | 984 |  | 
|  | 985 | af->from_addr_param(&paddr, param, peer_port, 0); | 
|  | 986 |  | 
|  | 987 | return __sctp_lookup_association(laddr, &paddr, transportp); | 
|  | 988 | } | 
|  | 989 |  | 
|  | 990 |  | 
| Vlad Yasevich | bbd0d59 | 2007-10-03 17:51:34 -0700 | [diff] [blame] | 991 | /* SCTP-AUTH, Section 6.3: | 
|  | 992 | *    If the receiver does not find a STCB for a packet containing an AUTH | 
|  | 993 | *    chunk as the first chunk and not a COOKIE-ECHO chunk as the second | 
|  | 994 | *    chunk, it MUST use the chunks after the AUTH chunk to look up an existing | 
|  | 995 | *    association. | 
|  | 996 | * | 
|  | 997 | * This means that any chunks that can help us identify the association need | 
|  | 998 | * to be looked at to find this assocation. | 
| Vlad Yasevich | bbd0d59 | 2007-10-03 17:51:34 -0700 | [diff] [blame] | 999 | */ | 
| Vlad Yasevich | df21857 | 2007-12-20 14:10:38 -0800 | [diff] [blame] | 1000 | static struct sctp_association *__sctp_rcv_walk_lookup(struct sk_buff *skb, | 
| Vlad Yasevich | bbd0d59 | 2007-10-03 17:51:34 -0700 | [diff] [blame] | 1001 | const union sctp_addr *laddr, | 
|  | 1002 | struct sctp_transport **transportp) | 
|  | 1003 | { | 
| Vlad Yasevich | df21857 | 2007-12-20 14:10:38 -0800 | [diff] [blame] | 1004 | struct sctp_association *asoc = NULL; | 
|  | 1005 | sctp_chunkhdr_t *ch; | 
|  | 1006 | int have_auth = 0; | 
|  | 1007 | unsigned int chunk_num = 1; | 
|  | 1008 | __u8 *ch_end; | 
|  | 1009 |  | 
|  | 1010 | /* Walk through the chunks looking for AUTH or ASCONF chunks | 
|  | 1011 | * to help us find the association. | 
| Vlad Yasevich | bbd0d59 | 2007-10-03 17:51:34 -0700 | [diff] [blame] | 1012 | */ | 
| Vlad Yasevich | df21857 | 2007-12-20 14:10:38 -0800 | [diff] [blame] | 1013 | ch = (sctp_chunkhdr_t *) skb->data; | 
|  | 1014 | do { | 
|  | 1015 | /* Break out if chunk length is less then minimal. */ | 
|  | 1016 | if (ntohs(ch->length) < sizeof(sctp_chunkhdr_t)) | 
|  | 1017 | break; | 
|  | 1018 |  | 
|  | 1019 | ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length)); | 
|  | 1020 | if (ch_end > skb_tail_pointer(skb)) | 
|  | 1021 | break; | 
|  | 1022 |  | 
|  | 1023 | switch(ch->type) { | 
|  | 1024 | case SCTP_CID_AUTH: | 
|  | 1025 | have_auth = chunk_num; | 
|  | 1026 | break; | 
|  | 1027 |  | 
|  | 1028 | case SCTP_CID_COOKIE_ECHO: | 
|  | 1029 | /* If a packet arrives containing an AUTH chunk as | 
|  | 1030 | * a first chunk, a COOKIE-ECHO chunk as the second | 
|  | 1031 | * chunk, and possibly more chunks after them, and | 
|  | 1032 | * the receiver does not have an STCB for that | 
|  | 1033 | * packet, then authentication is based on | 
|  | 1034 | * the contents of the COOKIE- ECHO chunk. | 
|  | 1035 | */ | 
|  | 1036 | if (have_auth == 1 && chunk_num == 2) | 
|  | 1037 | return NULL; | 
|  | 1038 | break; | 
|  | 1039 |  | 
|  | 1040 | case SCTP_CID_ASCONF: | 
|  | 1041 | if (have_auth || sctp_addip_noauth) | 
|  | 1042 | asoc = __sctp_rcv_asconf_lookup(ch, laddr, | 
|  | 1043 | sctp_hdr(skb)->source, | 
|  | 1044 | transportp); | 
|  | 1045 | default: | 
|  | 1046 | break; | 
|  | 1047 | } | 
|  | 1048 |  | 
|  | 1049 | if (asoc) | 
|  | 1050 | break; | 
|  | 1051 |  | 
|  | 1052 | ch = (sctp_chunkhdr_t *) ch_end; | 
|  | 1053 | chunk_num++; | 
|  | 1054 | } while (ch_end < skb_tail_pointer(skb)); | 
|  | 1055 |  | 
|  | 1056 | return asoc; | 
| Vlad Yasevich | bbd0d59 | 2007-10-03 17:51:34 -0700 | [diff] [blame] | 1057 | } | 
|  | 1058 |  | 
|  | 1059 | /* | 
|  | 1060 | * There are circumstances when we need to look inside the SCTP packet | 
|  | 1061 | * for information to help us find the association.   Examples | 
|  | 1062 | * include looking inside of INIT/INIT-ACK chunks or after the AUTH | 
|  | 1063 | * chunks. | 
|  | 1064 | */ | 
|  | 1065 | static struct sctp_association *__sctp_rcv_lookup_harder(struct sk_buff *skb, | 
| Vlad Yasevich | bbd0d59 | 2007-10-03 17:51:34 -0700 | [diff] [blame] | 1066 | const union sctp_addr *laddr, | 
|  | 1067 | struct sctp_transport **transportp) | 
|  | 1068 | { | 
|  | 1069 | sctp_chunkhdr_t *ch; | 
|  | 1070 |  | 
|  | 1071 | ch = (sctp_chunkhdr_t *) skb->data; | 
|  | 1072 |  | 
| Vlad Yasevich | df21857 | 2007-12-20 14:10:38 -0800 | [diff] [blame] | 1073 | /* The code below will attempt to walk the chunk and extract | 
|  | 1074 | * parameter information.  Before we do that, we need to verify | 
|  | 1075 | * that the chunk length doesn't cause overflow.  Otherwise, we'll | 
|  | 1076 | * walk off the end. | 
|  | 1077 | */ | 
|  | 1078 | if (WORD_ROUND(ntohs(ch->length)) > skb->len) | 
|  | 1079 | return NULL; | 
|  | 1080 |  | 
| Vlad Yasevich | bbd0d59 | 2007-10-03 17:51:34 -0700 | [diff] [blame] | 1081 | /* If this is INIT/INIT-ACK look inside the chunk too. */ | 
|  | 1082 | switch (ch->type) { | 
|  | 1083 | case SCTP_CID_INIT: | 
|  | 1084 | case SCTP_CID_INIT_ACK: | 
|  | 1085 | return __sctp_rcv_init_lookup(skb, laddr, transportp); | 
|  | 1086 | break; | 
|  | 1087 |  | 
| Vlad Yasevich | df21857 | 2007-12-20 14:10:38 -0800 | [diff] [blame] | 1088 | default: | 
|  | 1089 | return __sctp_rcv_walk_lookup(skb, laddr, transportp); | 
| Vlad Yasevich | bbd0d59 | 2007-10-03 17:51:34 -0700 | [diff] [blame] | 1090 | break; | 
|  | 1091 | } | 
|  | 1092 |  | 
| Vlad Yasevich | df21857 | 2007-12-20 14:10:38 -0800 | [diff] [blame] | 1093 |  | 
| Vlad Yasevich | bbd0d59 | 2007-10-03 17:51:34 -0700 | [diff] [blame] | 1094 | return NULL; | 
|  | 1095 | } | 
|  | 1096 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1097 | /* Lookup an association for an inbound skb. */ | 
|  | 1098 | static struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb, | 
|  | 1099 | const union sctp_addr *paddr, | 
|  | 1100 | const union sctp_addr *laddr, | 
|  | 1101 | struct sctp_transport **transportp) | 
|  | 1102 | { | 
|  | 1103 | struct sctp_association *asoc; | 
|  | 1104 |  | 
|  | 1105 | asoc = __sctp_lookup_association(laddr, paddr, transportp); | 
|  | 1106 |  | 
|  | 1107 | /* Further lookup for INIT/INIT-ACK packets. | 
|  | 1108 | * SCTP Implementors Guide, 2.18 Handling of address | 
|  | 1109 | * parameters within the INIT or INIT-ACK. | 
|  | 1110 | */ | 
|  | 1111 | if (!asoc) | 
| Vlad Yasevich | df21857 | 2007-12-20 14:10:38 -0800 | [diff] [blame] | 1112 | asoc = __sctp_rcv_lookup_harder(skb, laddr, transportp); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1113 |  | 
|  | 1114 | return asoc; | 
|  | 1115 | } |