xref: /titanic_52/usr/src/uts/common/inet/sctp/sctp_heartbeat.c (revision c7158ae983f5a04c4a998f468ecefba6d23ba721)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/systm.h>
31 #include <sys/stream.h>
32 #include <sys/cmn_err.h>
33 #include <sys/strsubr.h>
34 
35 #include <netinet/in.h>
36 #include <netinet/ip6.h>
37 
38 #include <inet/common.h>
39 #include <inet/ip.h>
40 #include <inet/mib2.h>
41 #include <inet/ipclassifier.h>
42 #include "sctp_impl.h"
43 
44 void
45 sctp_return_heartbeat(sctp_t *sctp, sctp_chunk_hdr_t *hbcp, mblk_t *mp)
46 {
47 	mblk_t *smp;
48 	sctp_chunk_hdr_t *cp;
49 	ipha_t *iniph;
50 	ip6_t *inip6h;
51 	int isv4;
52 	in6_addr_t addr;
53 	sctp_faddr_t *fp;
54 	uint16_t len;
55 	sctp_stack_t	*sctps = sctp->sctp_sctps;
56 
57 	BUMP_LOCAL(sctp->sctp_ibchunks);
58 
59 	/* Update the faddr for the src addr */
60 	isv4 = (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION);
61 	if (isv4) {
62 		iniph = (ipha_t *)mp->b_rptr;
63 		IN6_IPADDR_TO_V4MAPPED(iniph->ipha_src, &addr);
64 	} else {
65 		inip6h = (ip6_t *)mp->b_rptr;
66 		addr = inip6h->ip6_src;
67 	}
68 	fp = sctp_lookup_faddr(sctp, &addr);
69 	ASSERT(fp != NULL);
70 
71 	dprint(3, ("sctp_return_heartbeat: %p got hb from %x:%x:%x:%x\n",
72 	    (void *)sctp, SCTP_PRINTADDR(addr)));
73 
74 	/*
75 	 * XXX It's really tempting to reuse the heartbeat mblk. But
76 	 * this complicates processing in sctp_dispatch (i.e. it will
77 	 * screw up sctp_next_chunk since we will set the chunk
78 	 * header's length into network byte-order), and if we ever
79 	 * encounter a heartbeat bundled with other chunks...
80 	 * So we take the slower-but-safe route.
81 	 */
82 	len = ntohs(hbcp->sch_len);
83 
84 	/* Create an IP header, returning to the src addr from the heartbt */
85 	smp = sctp_make_mp(sctp, fp, len);
86 	if (smp == NULL) {
87 		SCTP_KSTAT(sctps, sctp_return_hb_failed);
88 		return;
89 	}
90 
91 	cp = (sctp_chunk_hdr_t *)smp->b_wptr;
92 	cp->sch_id = CHUNK_HEARTBEAT_ACK;
93 	cp->sch_flags = 0;
94 	cp->sch_len = htons(len);
95 
96 	/* Copy the information field from the heartbeat */
97 	bcopy((void *)(hbcp + 1), (void *)(cp + 1), len - sizeof (*cp));
98 
99 	smp->b_wptr += len;
100 
101 	sctp_set_iplen(sctp, smp);
102 
103 	BUMP_LOCAL(sctp->sctp_obchunks);
104 	sctp_add_sendq(sctp, smp);
105 }
106 
107 /*
108  * The data section of the heartbeat contains a time field (lbolt64),
109  * a 64 bit secret, followed by the v6 (possible a v4mapped) address this
110  * heartbeat was sent to.  No byte-ordering is done, since the heartbeat
111  * is not interpreted by the peer.
112  */
113 void
114 sctp_send_heartbeat(sctp_t *sctp, sctp_faddr_t *fp)
115 {
116 	sctp_chunk_hdr_t *cp;
117 	sctp_parm_hdr_t *hpp;
118 	int64_t *t;
119 	int64_t now;
120 	in6_addr_t *a;
121 	mblk_t *hbmp;
122 	size_t hblen;
123 	sctp_stack_t	*sctps = sctp->sctp_sctps;
124 
125 	dprint(3, ("sctp_send_heartbeat: to %x:%x:%x:%x from %x:%x:%x:%x\n",
126 	    SCTP_PRINTADDR(fp->faddr), SCTP_PRINTADDR(fp->saddr)));
127 
128 	hblen = sizeof (*cp) +
129 		sizeof (*hpp) +
130 		sizeof (*t) +
131 		sizeof (fp->hb_secret) +
132 		sizeof (fp->faddr);
133 	hbmp = sctp_make_mp(sctp, fp, hblen);
134 	if (hbmp == NULL) {
135 		SCTP_KSTAT(sctps, sctp_send_hb_failed);
136 		return;
137 	}
138 
139 	cp = (sctp_chunk_hdr_t *)hbmp->b_wptr;
140 	cp->sch_id = CHUNK_HEARTBEAT;
141 	cp->sch_flags = 0;
142 	cp->sch_len = hblen;
143 	cp->sch_len = htons(cp->sch_len);
144 
145 	hpp = (sctp_parm_hdr_t *)(cp + 1);
146 	hpp->sph_type = htons(PARM_HBINFO);
147 	hpp->sph_len = hblen - sizeof (*cp);
148 	hpp->sph_len = htons(hpp->sph_len);
149 
150 	/*
151 	 * Timestamp
152 	 *
153 	 * Copy the current time to the heartbeat and we can use it to
154 	 * calculate the RTT when we get it back in the heartbeat ACK.
155 	 */
156 	now = lbolt64;
157 	t = (int64_t *)(hpp + 1);
158 	bcopy(&now, t, sizeof (now));
159 
160 	/*
161 	 * Secret
162 	 *
163 	 * The per peer address secret is used to make sure that the heartbeat
164 	 * ack is really in response to our heartbeat.  This prevents blind
165 	 * spoofing of heartbeat ack to fake the validity of an address.
166 	 */
167 	t++;
168 	bcopy(&fp->hb_secret, t, sizeof (uint64_t));
169 
170 	/*
171 	 * Peer address
172 	 *
173 	 * The peer address is used to associate the heartbeat ack with
174 	 * the correct peer address.  The reason is that the peer is
175 	 * multihomed so that it may not use the same address as source
176 	 * in response to our heartbeat.
177 	 */
178 	a = (in6_addr_t *)(t + 1);
179 	bcopy(&fp->faddr, a, sizeof (*a));
180 
181 	hbmp->b_wptr += hblen;
182 
183 	sctp_set_iplen(sctp, hbmp);
184 
185 	/* Update the faddr's info */
186 	fp->lastactive = now;
187 	fp->hb_pending = B_TRUE;
188 
189 	BUMP_LOCAL(sctp->sctp_obchunks);
190 	BUMP_MIB(&sctps->sctps_mib, sctpTimHeartBeatProbe);
191 
192 	sctp_add_sendq(sctp, hbmp);
193 }
194 
195 /*
196  * Call right after any address change to validate peer addresses.
197  */
198 void
199 sctp_validate_peer(sctp_t *sctp)
200 {
201 	sctp_faddr_t	*fp;
202 	int		cnt;
203 	int64_t		now;
204 	int64_t		earliest_expiry;
205 	sctp_stack_t	*sctps = sctp->sctp_sctps;
206 
207 	now = lbolt64;
208 	earliest_expiry = 0;
209 	cnt = sctps->sctps_maxburst;
210 
211 	/*
212 	 * Loop thru the list looking for unconfirmed addresses and
213 	 * send a heartbeat.  But we should only send at most sctp_maxburst
214 	 * heartbeats.
215 	 */
216 	for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->next) {
217 		/* No need to validate unreachable address. */
218 		if (fp->state == SCTP_FADDRS_UNREACH)
219 			continue;
220 		if (fp->state == SCTP_FADDRS_UNCONFIRMED) {
221 			if (cnt-- > 0) {
222 				fp->hb_expiry = now + fp->rto;
223 				sctp_send_heartbeat(sctp, fp);
224 			} else {
225 				/*
226 				 * If we cannot send now, be more aggressive
227 				 * and try again about half of RTO.  Note that
228 				 * all the unsent probes are set to expire at
229 				 * the same time.
230 				 */
231 				fp->hb_expiry = now +
232 				    (sctp->sctp_rto_initial >> 1);
233 			}
234 		}
235 		/* Find the earliest heartbeat expiry time for ALL fps. */
236 		if (fp->hb_interval != 0 && (earliest_expiry == 0 ||
237 		    fp->hb_expiry < earliest_expiry)) {
238 			earliest_expiry = fp->hb_expiry;
239 		}
240 	}
241 	/* We use heartbeat timer for autoclose. */
242 	if (sctp->sctp_autoclose != 0) {
243 		int64_t expire;
244 
245 		expire = sctp->sctp_active + sctp->sctp_autoclose;
246 		if (earliest_expiry == 0 || expire < earliest_expiry)
247 			earliest_expiry = expire;
248 	}
249 
250 	/*
251 	 * Set the timer to fire for the earliest heartbeat unless
252 	 * heartbeat is disabled for all addresses.
253 	 */
254 	if (earliest_expiry != 0) {
255 		earliest_expiry -= now;
256 		if (earliest_expiry < 0)
257 			earliest_expiry = 1;
258 		sctp_timer(sctp, sctp->sctp_heartbeat_mp, earliest_expiry);
259 	}
260 }
261 
262 /*
263  * Process an incoming heartbeat ack.  When sending a heartbeat, we
264  * put the timestamp, a secret and the peer address the heartbeat is
265  * sent in the data part of the heartbeat.  We will extract this info
266  * and verify that this heartbeat ack is valid.
267  */
268 void
269 sctp_process_heartbeat(sctp_t *sctp, sctp_chunk_hdr_t *cp)
270 {
271 	int64_t *sentp, sent;
272 	uint64_t secret;
273 	in6_addr_t addr;
274 	sctp_faddr_t *fp;
275 	sctp_parm_hdr_t *hpp;
276 	int64_t now;
277 
278 	BUMP_LOCAL(sctp->sctp_ibchunks);
279 
280 	/* Sanity checks */
281 	ASSERT(OK_32PTR(cp));
282 	if (ntohs(cp->sch_len) < (sizeof (*cp) + sizeof (*hpp) +
283 	    sizeof (sent) + sizeof (secret) + sizeof (addr))) {
284 		/* drop it */
285 		dprint(2, ("sctp_process_heartbeat: malformed ack %p\n",
286 		    (void *)sctp));
287 		return;
288 	}
289 
290 	hpp = (sctp_parm_hdr_t *)(cp + 1);
291 	if (ntohs(hpp->sph_type) != PARM_HBINFO ||
292 	    ntohs(hpp->sph_len) != (ntohs(cp->sch_len) - sizeof (*cp))) {
293 		dprint(2,
294 		    ("sctp_process_heartbeat: malformed param in ack %p\n",
295 		    (void *)sctp));
296 		return;
297 	}
298 
299 	/*
300 	 * Pull out the time sent from the ack.
301 	 * SCTP is 32-bit aligned, so copy 64 bit quantity.  Since we
302 	 * put it in, it should be in our byte order.
303 	 */
304 	sentp = (int64_t *)(hpp + 1);
305 	bcopy(sentp, &sent, sizeof (sent));
306 
307 	/* Grab the secret to make sure that this heartbeat is valid */
308 	bcopy(++sentp, &secret, sizeof (secret));
309 
310 	/* Next, verify the address to make sure that it is the right one. */
311 	bcopy(++sentp, &addr, sizeof (addr));
312 	fp = sctp_lookup_faddr(sctp, &addr);
313 	if (fp == NULL) {
314 		dprint(2, ("sctp_process_heartbeat: invalid faddr (sctp=%p)\n",
315 		    (void *)sctp));
316 		return;
317 	}
318 	if (secret != fp->hb_secret) {
319 		dprint(2,
320 		    ("sctp_process_heartbeat: invalid secret in ack %p\n",
321 		    (void *)sctp));
322 		return;
323 	}
324 
325 	/* This address is now confirmed and alive. */
326 	sctp_faddr_alive(sctp, fp);
327 	now = lbolt64;
328 	sctp_update_rtt(sctp, fp, now - sent);
329 
330 	/*
331 	 * Note that the heartbeat timer should still be running, we don't
332 	 * reset it to avoid going through the whole list of peer addresses
333 	 * for each heartbeat ack as we probably are in interrupt context.
334 	 */
335 	fp->hb_expiry = now + SET_HB_INTVL(fp);
336 }
337