|
1 /*- |
|
2 * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. |
|
3 * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. |
|
4 * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. |
|
5 * |
|
6 * Redistribution and use in source and binary forms, with or without |
|
7 * modification, are permitted provided that the following conditions are met: |
|
8 * |
|
9 * a) Redistributions of source code must retain the above copyright notice, |
|
10 * this list of conditions and the following disclaimer. |
|
11 * |
|
12 * b) Redistributions in binary form must reproduce the above copyright |
|
13 * notice, this list of conditions and the following disclaimer in |
|
14 * the documentation and/or other materials provided with the distribution. |
|
15 * |
|
16 * c) Neither the name of Cisco Systems, Inc. nor the names of its |
|
17 * contributors may be used to endorse or promote products derived |
|
18 * from this software without specific prior written permission. |
|
19 * |
|
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
|
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
|
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
|
30 * THE POSSIBILITY OF SUCH DAMAGE. |
|
31 */ |
|
32 |
|
33 #ifdef __FreeBSD__ |
|
34 #include <sys/cdefs.h> |
|
35 __FBSDID("$FreeBSD: head/sys/netinet/sctp_asconf.c 257803 2013-11-07 17:08:09Z tuexen $"); |
|
36 #endif |
|
37 |
|
38 #include <netinet/sctp_os.h> |
|
39 #include <netinet/sctp_var.h> |
|
40 #include <netinet/sctp_sysctl.h> |
|
41 #include <netinet/sctp_pcb.h> |
|
42 #include <netinet/sctp_header.h> |
|
43 #include <netinet/sctputil.h> |
|
44 #include <netinet/sctp_output.h> |
|
45 #include <netinet/sctp_asconf.h> |
|
46 #include <netinet/sctp_timer.h> |
|
47 |
|
48 /* |
|
49 * debug flags: |
|
50 * SCTP_DEBUG_ASCONF1: protocol info, general info and errors |
|
51 * SCTP_DEBUG_ASCONF2: detailed info |
|
52 */ |
|
53 |
|
54 #if defined(__APPLE__) |
|
55 #define APPLE_FILE_NO 1 |
|
56 #endif |
|
57 |
|
58 /* |
|
59 * RFC 5061 |
|
60 * |
|
61 * An ASCONF parameter queue exists per asoc which holds the pending address |
|
62 * operations. Lists are updated upon receipt of ASCONF-ACK. |
|
63 * |
|
64 * A restricted_addrs list exists per assoc to hold local addresses that are |
|
65 * not (yet) usable by the assoc as a source address. These addresses are |
|
66 * either pending an ASCONF operation (and exist on the ASCONF parameter |
|
67 * queue), or they are permanently restricted (the peer has returned an |
|
68 * ERROR indication to an ASCONF(ADD), or the peer does not support ASCONF). |
|
69 * |
|
70 * Deleted addresses are always immediately removed from the lists as they will |
|
71 * (shortly) no longer exist in the kernel. We send ASCONFs as a courtesy, |
|
72 * only if allowed. |
|
73 */ |
|
74 |
|
75 /* |
|
76 * ASCONF parameter processing. |
|
77 * response_required: set if a reply is required (eg. SUCCESS_REPORT). |
|
78 * returns a mbuf to an "error" response parameter or NULL/"success" if ok. |
|
79 * FIX: allocating this many mbufs on the fly is pretty inefficient... |
|
80 */ |
|
81 static struct mbuf * |
|
82 sctp_asconf_success_response(uint32_t id) |
|
83 { |
|
84 struct mbuf *m_reply = NULL; |
|
85 struct sctp_asconf_paramhdr *aph; |
|
86 |
|
87 m_reply = sctp_get_mbuf_for_msg(sizeof(struct sctp_asconf_paramhdr), |
|
88 0, M_NOWAIT, 1, MT_DATA); |
|
89 if (m_reply == NULL) { |
|
90 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
91 "asconf_success_response: couldn't get mbuf!\n"); |
|
92 return (NULL); |
|
93 } |
|
94 aph = mtod(m_reply, struct sctp_asconf_paramhdr *); |
|
95 aph->correlation_id = id; |
|
96 aph->ph.param_type = htons(SCTP_SUCCESS_REPORT); |
|
97 aph->ph.param_length = sizeof(struct sctp_asconf_paramhdr); |
|
98 SCTP_BUF_LEN(m_reply) = aph->ph.param_length; |
|
99 aph->ph.param_length = htons(aph->ph.param_length); |
|
100 |
|
101 return (m_reply); |
|
102 } |
|
103 |
|
104 static struct mbuf * |
|
105 sctp_asconf_error_response(uint32_t id, uint16_t cause, uint8_t *error_tlv, |
|
106 uint16_t tlv_length) |
|
107 { |
|
108 struct mbuf *m_reply = NULL; |
|
109 struct sctp_asconf_paramhdr *aph; |
|
110 struct sctp_error_cause *error; |
|
111 uint8_t *tlv; |
|
112 |
|
113 m_reply = sctp_get_mbuf_for_msg((sizeof(struct sctp_asconf_paramhdr) + |
|
114 tlv_length + |
|
115 sizeof(struct sctp_error_cause)), |
|
116 0, M_NOWAIT, 1, MT_DATA); |
|
117 if (m_reply == NULL) { |
|
118 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
119 "asconf_error_response: couldn't get mbuf!\n"); |
|
120 return (NULL); |
|
121 } |
|
122 aph = mtod(m_reply, struct sctp_asconf_paramhdr *); |
|
123 error = (struct sctp_error_cause *)(aph + 1); |
|
124 |
|
125 aph->correlation_id = id; |
|
126 aph->ph.param_type = htons(SCTP_ERROR_CAUSE_IND); |
|
127 error->code = htons(cause); |
|
128 error->length = tlv_length + sizeof(struct sctp_error_cause); |
|
129 aph->ph.param_length = error->length + |
|
130 sizeof(struct sctp_asconf_paramhdr); |
|
131 |
|
132 if (aph->ph.param_length > MLEN) { |
|
133 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
134 "asconf_error_response: tlv_length (%xh) too big\n", |
|
135 tlv_length); |
|
136 sctp_m_freem(m_reply); /* discard */ |
|
137 return (NULL); |
|
138 } |
|
139 if (error_tlv != NULL) { |
|
140 tlv = (uint8_t *) (error + 1); |
|
141 memcpy(tlv, error_tlv, tlv_length); |
|
142 } |
|
143 SCTP_BUF_LEN(m_reply) = aph->ph.param_length; |
|
144 error->length = htons(error->length); |
|
145 aph->ph.param_length = htons(aph->ph.param_length); |
|
146 |
|
147 return (m_reply); |
|
148 } |
|
149 |
|
150 static struct mbuf * |
|
151 sctp_process_asconf_add_ip(struct sockaddr *src, struct sctp_asconf_paramhdr *aph, |
|
152 struct sctp_tcb *stcb, int send_hb, int response_required) |
|
153 { |
|
154 struct sctp_nets *net; |
|
155 struct mbuf *m_reply = NULL; |
|
156 struct sockaddr_storage sa_store; |
|
157 struct sctp_paramhdr *ph; |
|
158 uint16_t param_type, aparam_length; |
|
159 #if defined(INET) || defined(INET6) |
|
160 uint16_t param_length; |
|
161 #endif |
|
162 struct sockaddr *sa; |
|
163 int zero_address = 0; |
|
164 int bad_address = 0; |
|
165 #ifdef INET |
|
166 struct sockaddr_in *sin; |
|
167 struct sctp_ipv4addr_param *v4addr; |
|
168 #endif |
|
169 #ifdef INET6 |
|
170 struct sockaddr_in6 *sin6; |
|
171 struct sctp_ipv6addr_param *v6addr; |
|
172 #endif |
|
173 |
|
174 aparam_length = ntohs(aph->ph.param_length); |
|
175 ph = (struct sctp_paramhdr *)(aph + 1); |
|
176 param_type = ntohs(ph->param_type); |
|
177 #if defined(INET) || defined(INET6) |
|
178 param_length = ntohs(ph->param_length); |
|
179 #endif |
|
180 sa = (struct sockaddr *)&sa_store; |
|
181 switch (param_type) { |
|
182 #ifdef INET |
|
183 case SCTP_IPV4_ADDRESS: |
|
184 if (param_length != sizeof(struct sctp_ipv4addr_param)) { |
|
185 /* invalid param size */ |
|
186 return (NULL); |
|
187 } |
|
188 v4addr = (struct sctp_ipv4addr_param *)ph; |
|
189 sin = (struct sockaddr_in *)&sa_store; |
|
190 bzero(sin, sizeof(*sin)); |
|
191 sin->sin_family = AF_INET; |
|
192 #ifdef HAVE_SIN_LEN |
|
193 sin->sin_len = sizeof(struct sockaddr_in); |
|
194 #endif |
|
195 sin->sin_port = stcb->rport; |
|
196 sin->sin_addr.s_addr = v4addr->addr; |
|
197 if ((sin->sin_addr.s_addr == INADDR_BROADCAST) || |
|
198 IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { |
|
199 bad_address = 1; |
|
200 } |
|
201 if (sin->sin_addr.s_addr == INADDR_ANY) |
|
202 zero_address = 1; |
|
203 SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_add_ip: adding "); |
|
204 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); |
|
205 break; |
|
206 #endif |
|
207 #ifdef INET6 |
|
208 case SCTP_IPV6_ADDRESS: |
|
209 if (param_length != sizeof(struct sctp_ipv6addr_param)) { |
|
210 /* invalid param size */ |
|
211 return (NULL); |
|
212 } |
|
213 v6addr = (struct sctp_ipv6addr_param *)ph; |
|
214 sin6 = (struct sockaddr_in6 *)&sa_store; |
|
215 bzero(sin6, sizeof(*sin6)); |
|
216 sin6->sin6_family = AF_INET6; |
|
217 #ifdef HAVE_SIN6_LEN |
|
218 sin6->sin6_len = sizeof(struct sockaddr_in6); |
|
219 #endif |
|
220 sin6->sin6_port = stcb->rport; |
|
221 memcpy((caddr_t)&sin6->sin6_addr, v6addr->addr, |
|
222 sizeof(struct in6_addr)); |
|
223 if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { |
|
224 bad_address = 1; |
|
225 } |
|
226 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) |
|
227 zero_address = 1; |
|
228 SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_add_ip: adding "); |
|
229 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); |
|
230 break; |
|
231 #endif |
|
232 default: |
|
233 m_reply = sctp_asconf_error_response(aph->correlation_id, |
|
234 SCTP_CAUSE_INVALID_PARAM, (uint8_t *) aph, |
|
235 aparam_length); |
|
236 return (m_reply); |
|
237 } /* end switch */ |
|
238 |
|
239 /* if 0.0.0.0/::0, add the source address instead */ |
|
240 if (zero_address && SCTP_BASE_SYSCTL(sctp_nat_friendly)) { |
|
241 sa = src; |
|
242 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
243 "process_asconf_add_ip: using source addr "); |
|
244 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, src); |
|
245 } |
|
246 /* add the address */ |
|
247 if (bad_address) { |
|
248 m_reply = sctp_asconf_error_response(aph->correlation_id, |
|
249 SCTP_CAUSE_INVALID_PARAM, (uint8_t *) aph, |
|
250 aparam_length); |
|
251 } else if (sctp_add_remote_addr(stcb, sa, &net, SCTP_DONOT_SETSCOPE, |
|
252 SCTP_ADDR_DYNAMIC_ADDED) != 0) { |
|
253 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
254 "process_asconf_add_ip: error adding address\n"); |
|
255 m_reply = sctp_asconf_error_response(aph->correlation_id, |
|
256 SCTP_CAUSE_RESOURCE_SHORTAGE, (uint8_t *) aph, |
|
257 aparam_length); |
|
258 } else { |
|
259 /* notify upper layer */ |
|
260 sctp_ulp_notify(SCTP_NOTIFY_ASCONF_ADD_IP, stcb, 0, sa, SCTP_SO_NOT_LOCKED); |
|
261 if (response_required) { |
|
262 m_reply = |
|
263 sctp_asconf_success_response(aph->correlation_id); |
|
264 } |
|
265 sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net); |
|
266 sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, |
|
267 stcb, net); |
|
268 if (send_hb) { |
|
269 sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED); |
|
270 } |
|
271 } |
|
272 return (m_reply); |
|
273 } |
|
274 |
|
275 static int |
|
276 sctp_asconf_del_remote_addrs_except(struct sctp_tcb *stcb, struct sockaddr *src) |
|
277 { |
|
278 struct sctp_nets *src_net, *net; |
|
279 |
|
280 /* make sure the source address exists as a destination net */ |
|
281 src_net = sctp_findnet(stcb, src); |
|
282 if (src_net == NULL) { |
|
283 /* not found */ |
|
284 return (-1); |
|
285 } |
|
286 |
|
287 /* delete all destination addresses except the source */ |
|
288 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { |
|
289 if (net != src_net) { |
|
290 /* delete this address */ |
|
291 sctp_remove_net(stcb, net); |
|
292 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
293 "asconf_del_remote_addrs_except: deleting "); |
|
294 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, |
|
295 (struct sockaddr *)&net->ro._l_addr); |
|
296 /* notify upper layer */ |
|
297 sctp_ulp_notify(SCTP_NOTIFY_ASCONF_DELETE_IP, stcb, 0, |
|
298 (struct sockaddr *)&net->ro._l_addr, SCTP_SO_NOT_LOCKED); |
|
299 } |
|
300 } |
|
301 return (0); |
|
302 } |
|
303 |
|
304 static struct mbuf * |
|
305 sctp_process_asconf_delete_ip(struct sockaddr *src, |
|
306 struct sctp_asconf_paramhdr *aph, |
|
307 struct sctp_tcb *stcb, int response_required) |
|
308 { |
|
309 struct mbuf *m_reply = NULL; |
|
310 struct sockaddr_storage sa_store; |
|
311 struct sctp_paramhdr *ph; |
|
312 uint16_t param_type, aparam_length; |
|
313 #if defined(INET) || defined(INET6) |
|
314 uint16_t param_length; |
|
315 #endif |
|
316 struct sockaddr *sa; |
|
317 int zero_address = 0; |
|
318 int result; |
|
319 #ifdef INET |
|
320 struct sockaddr_in *sin; |
|
321 struct sctp_ipv4addr_param *v4addr; |
|
322 #endif |
|
323 #ifdef INET6 |
|
324 struct sockaddr_in6 *sin6; |
|
325 struct sctp_ipv6addr_param *v6addr; |
|
326 #endif |
|
327 |
|
328 aparam_length = ntohs(aph->ph.param_length); |
|
329 ph = (struct sctp_paramhdr *)(aph + 1); |
|
330 param_type = ntohs(ph->param_type); |
|
331 #if defined(INET) || defined(INET6) |
|
332 param_length = ntohs(ph->param_length); |
|
333 #endif |
|
334 sa = (struct sockaddr *)&sa_store; |
|
335 switch (param_type) { |
|
336 #ifdef INET |
|
337 case SCTP_IPV4_ADDRESS: |
|
338 if (param_length != sizeof(struct sctp_ipv4addr_param)) { |
|
339 /* invalid param size */ |
|
340 return (NULL); |
|
341 } |
|
342 v4addr = (struct sctp_ipv4addr_param *)ph; |
|
343 sin = (struct sockaddr_in *)&sa_store; |
|
344 bzero(sin, sizeof(*sin)); |
|
345 sin->sin_family = AF_INET; |
|
346 #ifdef HAVE_SIN_LEN |
|
347 sin->sin_len = sizeof(struct sockaddr_in); |
|
348 #endif |
|
349 sin->sin_port = stcb->rport; |
|
350 sin->sin_addr.s_addr = v4addr->addr; |
|
351 if (sin->sin_addr.s_addr == INADDR_ANY) |
|
352 zero_address = 1; |
|
353 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
354 "process_asconf_delete_ip: deleting "); |
|
355 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); |
|
356 break; |
|
357 #endif |
|
358 #ifdef INET6 |
|
359 case SCTP_IPV6_ADDRESS: |
|
360 if (param_length != sizeof(struct sctp_ipv6addr_param)) { |
|
361 /* invalid param size */ |
|
362 return (NULL); |
|
363 } |
|
364 v6addr = (struct sctp_ipv6addr_param *)ph; |
|
365 sin6 = (struct sockaddr_in6 *)&sa_store; |
|
366 bzero(sin6, sizeof(*sin6)); |
|
367 sin6->sin6_family = AF_INET6; |
|
368 #ifdef HAVE_SIN6_LEN |
|
369 sin6->sin6_len = sizeof(struct sockaddr_in6); |
|
370 #endif |
|
371 sin6->sin6_port = stcb->rport; |
|
372 memcpy(&sin6->sin6_addr, v6addr->addr, |
|
373 sizeof(struct in6_addr)); |
|
374 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) |
|
375 zero_address = 1; |
|
376 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
377 "process_asconf_delete_ip: deleting "); |
|
378 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); |
|
379 break; |
|
380 #endif |
|
381 default: |
|
382 m_reply = sctp_asconf_error_response(aph->correlation_id, |
|
383 SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *) aph, |
|
384 aparam_length); |
|
385 return (m_reply); |
|
386 } |
|
387 |
|
388 /* make sure the source address is not being deleted */ |
|
389 if (sctp_cmpaddr(sa, src)) { |
|
390 /* trying to delete the source address! */ |
|
391 SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_delete_ip: tried to delete source addr\n"); |
|
392 m_reply = sctp_asconf_error_response(aph->correlation_id, |
|
393 SCTP_CAUSE_DELETING_SRC_ADDR, (uint8_t *) aph, |
|
394 aparam_length); |
|
395 return (m_reply); |
|
396 } |
|
397 |
|
398 /* if deleting 0.0.0.0/::0, delete all addresses except src addr */ |
|
399 if (zero_address && SCTP_BASE_SYSCTL(sctp_nat_friendly)) { |
|
400 result = sctp_asconf_del_remote_addrs_except(stcb, src); |
|
401 |
|
402 if (result) { |
|
403 /* src address did not exist? */ |
|
404 SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_delete_ip: src addr does not exist?\n"); |
|
405 /* what error to reply with?? */ |
|
406 m_reply = |
|
407 sctp_asconf_error_response(aph->correlation_id, |
|
408 SCTP_CAUSE_REQUEST_REFUSED, (uint8_t *) aph, |
|
409 aparam_length); |
|
410 } else if (response_required) { |
|
411 m_reply = |
|
412 sctp_asconf_success_response(aph->correlation_id); |
|
413 } |
|
414 return (m_reply); |
|
415 } |
|
416 |
|
417 /* delete the address */ |
|
418 result = sctp_del_remote_addr(stcb, sa); |
|
419 /* |
|
420 * note if result == -2, the address doesn't exist in the asoc but |
|
421 * since it's being deleted anyways, we just ack the delete -- but |
|
422 * this probably means something has already gone awry |
|
423 */ |
|
424 if (result == -1) { |
|
425 /* only one address in the asoc */ |
|
426 SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_delete_ip: tried to delete last IP addr!\n"); |
|
427 m_reply = sctp_asconf_error_response(aph->correlation_id, |
|
428 SCTP_CAUSE_DELETING_LAST_ADDR, (uint8_t *) aph, |
|
429 aparam_length); |
|
430 } else { |
|
431 if (response_required) { |
|
432 m_reply = sctp_asconf_success_response(aph->correlation_id); |
|
433 } |
|
434 /* notify upper layer */ |
|
435 sctp_ulp_notify(SCTP_NOTIFY_ASCONF_DELETE_IP, stcb, 0, sa, SCTP_SO_NOT_LOCKED); |
|
436 } |
|
437 return (m_reply); |
|
438 } |
|
439 |
|
440 static struct mbuf * |
|
441 sctp_process_asconf_set_primary(struct sockaddr *src, |
|
442 struct sctp_asconf_paramhdr *aph, |
|
443 struct sctp_tcb *stcb, int response_required) |
|
444 { |
|
445 struct mbuf *m_reply = NULL; |
|
446 struct sockaddr_storage sa_store; |
|
447 struct sctp_paramhdr *ph; |
|
448 uint16_t param_type, aparam_length; |
|
449 #if defined(INET) || defined(INET6) |
|
450 uint16_t param_length; |
|
451 #endif |
|
452 struct sockaddr *sa; |
|
453 int zero_address = 0; |
|
454 #ifdef INET |
|
455 struct sockaddr_in *sin; |
|
456 struct sctp_ipv4addr_param *v4addr; |
|
457 #endif |
|
458 #ifdef INET6 |
|
459 struct sockaddr_in6 *sin6; |
|
460 struct sctp_ipv6addr_param *v6addr; |
|
461 #endif |
|
462 |
|
463 aparam_length = ntohs(aph->ph.param_length); |
|
464 ph = (struct sctp_paramhdr *)(aph + 1); |
|
465 param_type = ntohs(ph->param_type); |
|
466 #if defined(INET) || defined(INET6) |
|
467 param_length = ntohs(ph->param_length); |
|
468 #endif |
|
469 sa = (struct sockaddr *)&sa_store; |
|
470 switch (param_type) { |
|
471 #ifdef INET |
|
472 case SCTP_IPV4_ADDRESS: |
|
473 if (param_length != sizeof(struct sctp_ipv4addr_param)) { |
|
474 /* invalid param size */ |
|
475 return (NULL); |
|
476 } |
|
477 v4addr = (struct sctp_ipv4addr_param *)ph; |
|
478 sin = (struct sockaddr_in *)&sa_store; |
|
479 bzero(sin, sizeof(*sin)); |
|
480 sin->sin_family = AF_INET; |
|
481 #ifdef HAVE_SIN_LEN |
|
482 sin->sin_len = sizeof(struct sockaddr_in); |
|
483 #endif |
|
484 sin->sin_addr.s_addr = v4addr->addr; |
|
485 if (sin->sin_addr.s_addr == INADDR_ANY) |
|
486 zero_address = 1; |
|
487 SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_set_primary: "); |
|
488 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); |
|
489 break; |
|
490 #endif |
|
491 #ifdef INET6 |
|
492 case SCTP_IPV6_ADDRESS: |
|
493 if (param_length != sizeof(struct sctp_ipv6addr_param)) { |
|
494 /* invalid param size */ |
|
495 return (NULL); |
|
496 } |
|
497 v6addr = (struct sctp_ipv6addr_param *)ph; |
|
498 sin6 = (struct sockaddr_in6 *)&sa_store; |
|
499 bzero(sin6, sizeof(*sin6)); |
|
500 sin6->sin6_family = AF_INET6; |
|
501 #ifdef HAVE_SIN6_LEN |
|
502 sin6->sin6_len = sizeof(struct sockaddr_in6); |
|
503 #endif |
|
504 memcpy((caddr_t)&sin6->sin6_addr, v6addr->addr, |
|
505 sizeof(struct in6_addr)); |
|
506 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) |
|
507 zero_address = 1; |
|
508 SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_set_primary: "); |
|
509 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); |
|
510 break; |
|
511 #endif |
|
512 default: |
|
513 m_reply = sctp_asconf_error_response(aph->correlation_id, |
|
514 SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *) aph, |
|
515 aparam_length); |
|
516 return (m_reply); |
|
517 } |
|
518 |
|
519 /* if 0.0.0.0/::0, use the source address instead */ |
|
520 if (zero_address && SCTP_BASE_SYSCTL(sctp_nat_friendly)) { |
|
521 sa = src; |
|
522 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
523 "process_asconf_set_primary: using source addr "); |
|
524 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, src); |
|
525 } |
|
526 /* set the primary address */ |
|
527 if (sctp_set_primary_addr(stcb, sa, NULL) == 0) { |
|
528 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
529 "process_asconf_set_primary: primary address set\n"); |
|
530 /* notify upper layer */ |
|
531 sctp_ulp_notify(SCTP_NOTIFY_ASCONF_SET_PRIMARY, stcb, 0, sa, SCTP_SO_NOT_LOCKED); |
|
532 if ((stcb->asoc.primary_destination->dest_state & SCTP_ADDR_REACHABLE) && |
|
533 (!(stcb->asoc.primary_destination->dest_state & SCTP_ADDR_PF)) && |
|
534 (stcb->asoc.alternate)) { |
|
535 sctp_free_remote_addr(stcb->asoc.alternate); |
|
536 stcb->asoc.alternate = NULL; |
|
537 } |
|
538 if (response_required) { |
|
539 m_reply = sctp_asconf_success_response(aph->correlation_id); |
|
540 } |
|
541 /* Mobility adaptation. |
|
542 Ideally, when the reception of SET PRIMARY with DELETE IP |
|
543 ADDRESS of the previous primary destination, unacknowledged |
|
544 DATA are retransmitted immediately to the new primary |
|
545 destination for seamless handover. |
|
546 If the destination is UNCONFIRMED and marked to REQ_PRIM, |
|
547 The retransmission occur when reception of the |
|
548 HEARTBEAT-ACK. (See sctp_handle_heartbeat_ack in |
|
549 sctp_input.c) |
|
550 Also, when change of the primary destination, it is better |
|
551 that all subsequent new DATA containing already queued DATA |
|
552 are transmitted to the new primary destination. (by micchie) |
|
553 */ |
|
554 if ((sctp_is_mobility_feature_on(stcb->sctp_ep, |
|
555 SCTP_MOBILITY_BASE) || |
|
556 sctp_is_mobility_feature_on(stcb->sctp_ep, |
|
557 SCTP_MOBILITY_FASTHANDOFF)) && |
|
558 sctp_is_mobility_feature_on(stcb->sctp_ep, |
|
559 SCTP_MOBILITY_PRIM_DELETED) && |
|
560 (stcb->asoc.primary_destination->dest_state & |
|
561 SCTP_ADDR_UNCONFIRMED) == 0) { |
|
562 |
|
563 sctp_timer_stop(SCTP_TIMER_TYPE_PRIM_DELETED, stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_TIMER+SCTP_LOC_7); |
|
564 if (sctp_is_mobility_feature_on(stcb->sctp_ep, |
|
565 SCTP_MOBILITY_FASTHANDOFF)) { |
|
566 sctp_assoc_immediate_retrans(stcb, |
|
567 stcb->asoc.primary_destination); |
|
568 } |
|
569 if (sctp_is_mobility_feature_on(stcb->sctp_ep, |
|
570 SCTP_MOBILITY_BASE)) { |
|
571 sctp_move_chunks_from_net(stcb, |
|
572 stcb->asoc.deleted_primary); |
|
573 } |
|
574 sctp_delete_prim_timer(stcb->sctp_ep, stcb, |
|
575 stcb->asoc.deleted_primary); |
|
576 } |
|
577 } else { |
|
578 /* couldn't set the requested primary address! */ |
|
579 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
580 "process_asconf_set_primary: set primary failed!\n"); |
|
581 /* must have been an invalid address, so report */ |
|
582 m_reply = sctp_asconf_error_response(aph->correlation_id, |
|
583 SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *) aph, |
|
584 aparam_length); |
|
585 } |
|
586 |
|
587 return (m_reply); |
|
588 } |
|
589 |
|
590 /* |
|
591 * handles an ASCONF chunk. |
|
592 * if all parameters are processed ok, send a plain (empty) ASCONF-ACK |
|
593 */ |
|
594 void |
|
595 sctp_handle_asconf(struct mbuf *m, unsigned int offset, |
|
596 struct sockaddr *src, |
|
597 struct sctp_asconf_chunk *cp, struct sctp_tcb *stcb, |
|
598 int first) |
|
599 { |
|
600 struct sctp_association *asoc; |
|
601 uint32_t serial_num; |
|
602 struct mbuf *n, *m_ack, *m_result, *m_tail; |
|
603 struct sctp_asconf_ack_chunk *ack_cp; |
|
604 struct sctp_asconf_paramhdr *aph, *ack_aph; |
|
605 struct sctp_ipv6addr_param *p_addr; |
|
606 unsigned int asconf_limit, cnt; |
|
607 int error = 0; /* did an error occur? */ |
|
608 |
|
609 /* asconf param buffer */ |
|
610 uint8_t aparam_buf[SCTP_PARAM_BUFFER_SIZE]; |
|
611 struct sctp_asconf_ack *ack, *ack_next; |
|
612 |
|
613 /* verify minimum length */ |
|
614 if (ntohs(cp->ch.chunk_length) < sizeof(struct sctp_asconf_chunk)) { |
|
615 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
616 "handle_asconf: chunk too small = %xh\n", |
|
617 ntohs(cp->ch.chunk_length)); |
|
618 return; |
|
619 } |
|
620 asoc = &stcb->asoc; |
|
621 serial_num = ntohl(cp->serial_number); |
|
622 |
|
623 if (SCTP_TSN_GE(asoc->asconf_seq_in, serial_num)) { |
|
624 /* got a duplicate ASCONF */ |
|
625 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
626 "handle_asconf: got duplicate serial number = %xh\n", |
|
627 serial_num); |
|
628 return; |
|
629 } else if (serial_num != (asoc->asconf_seq_in + 1)) { |
|
630 SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: incorrect serial number = %xh (expected next = %xh)\n", |
|
631 serial_num, asoc->asconf_seq_in + 1); |
|
632 return; |
|
633 } |
|
634 |
|
635 /* it's the expected "next" sequence number, so process it */ |
|
636 asoc->asconf_seq_in = serial_num; /* update sequence */ |
|
637 /* get length of all the param's in the ASCONF */ |
|
638 asconf_limit = offset + ntohs(cp->ch.chunk_length); |
|
639 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
640 "handle_asconf: asconf_limit=%u, sequence=%xh\n", |
|
641 asconf_limit, serial_num); |
|
642 |
|
643 if (first) { |
|
644 /* delete old cache */ |
|
645 SCTPDBG(SCTP_DEBUG_ASCONF1,"handle_asconf: Now processing first ASCONF. Try to delete old cache\n"); |
|
646 |
|
647 TAILQ_FOREACH_SAFE(ack, &asoc->asconf_ack_sent, next, ack_next) { |
|
648 if (ack->serial_number == serial_num) |
|
649 break; |
|
650 SCTPDBG(SCTP_DEBUG_ASCONF1,"handle_asconf: delete old(%u) < first(%u)\n", |
|
651 ack->serial_number, serial_num); |
|
652 TAILQ_REMOVE(&asoc->asconf_ack_sent, ack, next); |
|
653 if (ack->data != NULL) { |
|
654 sctp_m_freem(ack->data); |
|
655 } |
|
656 SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asconf_ack), ack); |
|
657 } |
|
658 } |
|
659 |
|
660 m_ack = sctp_get_mbuf_for_msg(sizeof(struct sctp_asconf_ack_chunk), 0, |
|
661 M_NOWAIT, 1, MT_DATA); |
|
662 if (m_ack == NULL) { |
|
663 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
664 "handle_asconf: couldn't get mbuf!\n"); |
|
665 return; |
|
666 } |
|
667 m_tail = m_ack; /* current reply chain's tail */ |
|
668 |
|
669 /* fill in ASCONF-ACK header */ |
|
670 ack_cp = mtod(m_ack, struct sctp_asconf_ack_chunk *); |
|
671 ack_cp->ch.chunk_type = SCTP_ASCONF_ACK; |
|
672 ack_cp->ch.chunk_flags = 0; |
|
673 ack_cp->serial_number = htonl(serial_num); |
|
674 /* set initial lengths (eg. just an ASCONF-ACK), ntohx at the end! */ |
|
675 SCTP_BUF_LEN(m_ack) = sizeof(struct sctp_asconf_ack_chunk); |
|
676 ack_cp->ch.chunk_length = sizeof(struct sctp_asconf_ack_chunk); |
|
677 |
|
678 /* skip the lookup address parameter */ |
|
679 offset += sizeof(struct sctp_asconf_chunk); |
|
680 p_addr = (struct sctp_ipv6addr_param *)sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr), (uint8_t *)&aparam_buf); |
|
681 if (p_addr == NULL) { |
|
682 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
683 "handle_asconf: couldn't get lookup addr!\n"); |
|
684 /* respond with a missing/invalid mandatory parameter error */ |
|
685 return; |
|
686 } |
|
687 /* param_length is already validated in process_control... */ |
|
688 offset += ntohs(p_addr->ph.param_length); /* skip lookup addr */ |
|
689 |
|
690 /* get pointer to first asconf param in ASCONF-ACK */ |
|
691 ack_aph = (struct sctp_asconf_paramhdr *)(mtod(m_ack, caddr_t) + sizeof(struct sctp_asconf_ack_chunk)); |
|
692 if (ack_aph == NULL) { |
|
693 SCTPDBG(SCTP_DEBUG_ASCONF1, "Gak in asconf2\n"); |
|
694 return; |
|
695 } |
|
696 /* get pointer to first asconf param in ASCONF */ |
|
697 aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, sizeof(struct sctp_asconf_paramhdr), (uint8_t *)&aparam_buf); |
|
698 if (aph == NULL) { |
|
699 SCTPDBG(SCTP_DEBUG_ASCONF1, "Empty ASCONF received?\n"); |
|
700 goto send_reply; |
|
701 } |
|
702 /* process through all parameters */ |
|
703 cnt = 0; |
|
704 while (aph != NULL) { |
|
705 unsigned int param_length, param_type; |
|
706 |
|
707 param_type = ntohs(aph->ph.param_type); |
|
708 param_length = ntohs(aph->ph.param_length); |
|
709 if (offset + param_length > asconf_limit) { |
|
710 /* parameter goes beyond end of chunk! */ |
|
711 sctp_m_freem(m_ack); |
|
712 return; |
|
713 } |
|
714 m_result = NULL; |
|
715 |
|
716 if (param_length > sizeof(aparam_buf)) { |
|
717 SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: param length (%u) larger than buffer size!\n", param_length); |
|
718 sctp_m_freem(m_ack); |
|
719 return; |
|
720 } |
|
721 if (param_length <= sizeof(struct sctp_paramhdr)) { |
|
722 SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: param length (%u) too short\n", param_length); |
|
723 sctp_m_freem(m_ack); |
|
724 } |
|
725 /* get the entire parameter */ |
|
726 aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, param_length, aparam_buf); |
|
727 if (aph == NULL) { |
|
728 SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: couldn't get entire param\n"); |
|
729 sctp_m_freem(m_ack); |
|
730 return; |
|
731 } |
|
732 switch (param_type) { |
|
733 case SCTP_ADD_IP_ADDRESS: |
|
734 asoc->peer_supports_asconf = 1; |
|
735 m_result = sctp_process_asconf_add_ip(src, aph, stcb, |
|
736 (cnt < SCTP_BASE_SYSCTL(sctp_hb_maxburst)), error); |
|
737 cnt++; |
|
738 break; |
|
739 case SCTP_DEL_IP_ADDRESS: |
|
740 asoc->peer_supports_asconf = 1; |
|
741 m_result = sctp_process_asconf_delete_ip(src, aph, stcb, |
|
742 error); |
|
743 break; |
|
744 case SCTP_ERROR_CAUSE_IND: |
|
745 /* not valid in an ASCONF chunk */ |
|
746 break; |
|
747 case SCTP_SET_PRIM_ADDR: |
|
748 asoc->peer_supports_asconf = 1; |
|
749 m_result = sctp_process_asconf_set_primary(src, aph, |
|
750 stcb, error); |
|
751 break; |
|
752 case SCTP_NAT_VTAGS: |
|
753 SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: sees a NAT VTAG state parameter\n"); |
|
754 break; |
|
755 case SCTP_SUCCESS_REPORT: |
|
756 /* not valid in an ASCONF chunk */ |
|
757 break; |
|
758 case SCTP_ULP_ADAPTATION: |
|
759 /* FIX */ |
|
760 break; |
|
761 default: |
|
762 if ((param_type & 0x8000) == 0) { |
|
763 /* Been told to STOP at this param */ |
|
764 asconf_limit = offset; |
|
765 /* |
|
766 * FIX FIX - We need to call |
|
767 * sctp_arethere_unrecognized_parameters() |
|
768 * to get a operr and send it for any |
|
769 * param's with the 0x4000 bit set OR do it |
|
770 * here ourselves... note we still must STOP |
|
771 * if the 0x8000 bit is clear. |
|
772 */ |
|
773 } |
|
774 /* unknown/invalid param type */ |
|
775 break; |
|
776 } /* switch */ |
|
777 |
|
778 /* add any (error) result to the reply mbuf chain */ |
|
779 if (m_result != NULL) { |
|
780 SCTP_BUF_NEXT(m_tail) = m_result; |
|
781 m_tail = m_result; |
|
782 /* update lengths, make sure it's aligned too */ |
|
783 SCTP_BUF_LEN(m_result) = SCTP_SIZE32(SCTP_BUF_LEN(m_result)); |
|
784 ack_cp->ch.chunk_length += SCTP_BUF_LEN(m_result); |
|
785 /* set flag to force success reports */ |
|
786 error = 1; |
|
787 } |
|
788 offset += SCTP_SIZE32(param_length); |
|
789 /* update remaining ASCONF message length to process */ |
|
790 if (offset >= asconf_limit) { |
|
791 /* no more data in the mbuf chain */ |
|
792 break; |
|
793 } |
|
794 /* get pointer to next asconf param */ |
|
795 aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, |
|
796 sizeof(struct sctp_asconf_paramhdr), |
|
797 (uint8_t *)&aparam_buf); |
|
798 if (aph == NULL) { |
|
799 /* can't get an asconf paramhdr */ |
|
800 SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: can't get asconf param hdr!\n"); |
|
801 /* FIX ME - add error here... */ |
|
802 } |
|
803 } |
|
804 |
|
805 send_reply: |
|
806 ack_cp->ch.chunk_length = htons(ack_cp->ch.chunk_length); |
|
807 /* save the ASCONF-ACK reply */ |
|
808 ack = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_asconf_ack), |
|
809 struct sctp_asconf_ack); |
|
810 if (ack == NULL) { |
|
811 sctp_m_freem(m_ack); |
|
812 return; |
|
813 } |
|
814 ack->serial_number = serial_num; |
|
815 ack->last_sent_to = NULL; |
|
816 ack->data = m_ack; |
|
817 ack->len = 0; |
|
818 for (n = m_ack; n != NULL; n = SCTP_BUF_NEXT(n)) { |
|
819 ack->len += SCTP_BUF_LEN(n); |
|
820 } |
|
821 TAILQ_INSERT_TAIL(&stcb->asoc.asconf_ack_sent, ack, next); |
|
822 |
|
823 /* see if last_control_chunk_from is set properly (use IP src addr) */ |
|
824 if (stcb->asoc.last_control_chunk_from == NULL) { |
|
825 /* |
|
826 * this could happen if the source address was just newly |
|
827 * added |
|
828 */ |
|
829 SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: looking up net for IP source address\n"); |
|
830 SCTPDBG(SCTP_DEBUG_ASCONF1, "Looking for IP source: "); |
|
831 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, src); |
|
832 /* look up the from address */ |
|
833 stcb->asoc.last_control_chunk_from = sctp_findnet(stcb, src); |
|
834 #ifdef SCTP_DEBUG |
|
835 if (stcb->asoc.last_control_chunk_from == NULL) { |
|
836 SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: IP source address not found?!\n"); |
|
837 } |
|
838 #endif |
|
839 } |
|
840 } |
|
841 |
|
842 /* |
|
843 * does the address match? returns 0 if not, 1 if so |
|
844 */ |
|
845 static uint32_t |
|
846 sctp_asconf_addr_match(struct sctp_asconf_addr *aa, struct sockaddr *sa) |
|
847 { |
|
848 switch (sa->sa_family) { |
|
849 #ifdef INET6 |
|
850 case AF_INET6: |
|
851 { |
|
852 /* XXX scopeid */ |
|
853 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; |
|
854 |
|
855 if ((aa->ap.addrp.ph.param_type == SCTP_IPV6_ADDRESS) && |
|
856 (memcmp(&aa->ap.addrp.addr, &sin6->sin6_addr, |
|
857 sizeof(struct in6_addr)) == 0)) { |
|
858 return (1); |
|
859 } |
|
860 break; |
|
861 } |
|
862 #endif |
|
863 #ifdef INET |
|
864 case AF_INET: |
|
865 { |
|
866 struct sockaddr_in *sin = (struct sockaddr_in *)sa; |
|
867 |
|
868 if ((aa->ap.addrp.ph.param_type == SCTP_IPV4_ADDRESS) && |
|
869 (memcmp(&aa->ap.addrp.addr, &sin->sin_addr, |
|
870 sizeof(struct in_addr)) == 0)) { |
|
871 return (1); |
|
872 } |
|
873 break; |
|
874 } |
|
875 #endif |
|
876 default: |
|
877 break; |
|
878 } |
|
879 return (0); |
|
880 } |
|
881 |
|
882 /* |
|
883 * does the address match? returns 0 if not, 1 if so |
|
884 */ |
|
885 static uint32_t |
|
886 sctp_addr_match(struct sctp_paramhdr *ph, struct sockaddr *sa) |
|
887 { |
|
888 #if defined(INET) || defined(INET6) |
|
889 uint16_t param_type, param_length; |
|
890 |
|
891 param_type = ntohs(ph->param_type); |
|
892 param_length = ntohs(ph->param_length); |
|
893 #endif |
|
894 switch (sa->sa_family) { |
|
895 #ifdef INET6 |
|
896 case AF_INET6: |
|
897 { |
|
898 /* XXX scopeid */ |
|
899 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; |
|
900 struct sctp_ipv6addr_param *v6addr; |
|
901 |
|
902 v6addr = (struct sctp_ipv6addr_param *)ph; |
|
903 if ((param_type == SCTP_IPV6_ADDRESS) && |
|
904 (param_length == sizeof(struct sctp_ipv6addr_param)) && |
|
905 (memcmp(&v6addr->addr, &sin6->sin6_addr, |
|
906 sizeof(struct in6_addr)) == 0)) { |
|
907 return (1); |
|
908 } |
|
909 break; |
|
910 } |
|
911 #endif |
|
912 #ifdef INET |
|
913 case AF_INET: |
|
914 { |
|
915 struct sockaddr_in *sin = (struct sockaddr_in *)sa; |
|
916 struct sctp_ipv4addr_param *v4addr; |
|
917 |
|
918 v4addr = (struct sctp_ipv4addr_param *)ph; |
|
919 if ((param_type == SCTP_IPV4_ADDRESS) && |
|
920 (param_length == sizeof(struct sctp_ipv4addr_param)) && |
|
921 (memcmp(&v4addr->addr, &sin->sin_addr, |
|
922 sizeof(struct in_addr)) == 0)) { |
|
923 return (1); |
|
924 } |
|
925 break; |
|
926 } |
|
927 #endif |
|
928 default: |
|
929 break; |
|
930 } |
|
931 return (0); |
|
932 } |
|
933 /* |
|
934 * Cleanup for non-responded/OP ERR'd ASCONF |
|
935 */ |
|
936 void |
|
937 sctp_asconf_cleanup(struct sctp_tcb *stcb, struct sctp_nets *net) |
|
938 { |
|
939 /* mark peer as ASCONF incapable */ |
|
940 stcb->asoc.peer_supports_asconf = 0; |
|
941 /* |
|
942 * clear out any existing asconfs going out |
|
943 */ |
|
944 sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, net, |
|
945 SCTP_FROM_SCTP_ASCONF+SCTP_LOC_2); |
|
946 stcb->asoc.asconf_seq_out_acked = stcb->asoc.asconf_seq_out; |
|
947 /* remove the old ASCONF on our outbound queue */ |
|
948 sctp_toss_old_asconf(stcb); |
|
949 } |
|
950 |
|
951 /* |
|
952 * cleanup any cached source addresses that may be topologically |
|
953 * incorrect after a new address has been added to this interface. |
|
954 */ |
|
955 static void |
|
956 sctp_asconf_nets_cleanup(struct sctp_tcb *stcb, struct sctp_ifn *ifn) |
|
957 { |
|
958 struct sctp_nets *net; |
|
959 |
|
960 /* |
|
961 * Ideally, we want to only clear cached routes and source addresses |
|
962 * that are topologically incorrect. But since there is no easy way |
|
963 * to know whether the newly added address on the ifn would cause a |
|
964 * routing change (i.e. a new egress interface would be chosen) |
|
965 * without doing a new routing lookup and source address selection, |
|
966 * we will (for now) just flush any cached route using a different |
|
967 * ifn (and cached source addrs) and let output re-choose them during |
|
968 * the next send on that net. |
|
969 */ |
|
970 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { |
|
971 /* |
|
972 * clear any cached route (and cached source address) if the |
|
973 * route's interface is NOT the same as the address change. |
|
974 * If it's the same interface, just clear the cached source |
|
975 * address. |
|
976 */ |
|
977 if (SCTP_ROUTE_HAS_VALID_IFN(&net->ro) && |
|
978 ((ifn == NULL) || |
|
979 (SCTP_GET_IF_INDEX_FROM_ROUTE(&net->ro) != ifn->ifn_index))) { |
|
980 /* clear any cached route */ |
|
981 RTFREE(net->ro.ro_rt); |
|
982 net->ro.ro_rt = NULL; |
|
983 } |
|
984 /* clear any cached source address */ |
|
985 if (net->src_addr_selected) { |
|
986 sctp_free_ifa(net->ro._s_addr); |
|
987 net->ro._s_addr = NULL; |
|
988 net->src_addr_selected = 0; |
|
989 } |
|
990 } |
|
991 } |
|
992 |
|
993 |
|
994 void |
|
995 sctp_assoc_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *dstnet) |
|
996 { |
|
997 int error; |
|
998 |
|
999 if (dstnet->dest_state & SCTP_ADDR_UNCONFIRMED) { |
|
1000 return; |
|
1001 } |
|
1002 if (stcb->asoc.deleted_primary == NULL) { |
|
1003 return; |
|
1004 } |
|
1005 |
|
1006 if (!TAILQ_EMPTY(&stcb->asoc.sent_queue)) { |
|
1007 SCTPDBG(SCTP_DEBUG_ASCONF1, "assoc_immediate_retrans: Deleted primary is "); |
|
1008 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &stcb->asoc.deleted_primary->ro._l_addr.sa); |
|
1009 SCTPDBG(SCTP_DEBUG_ASCONF1, "Current Primary is "); |
|
1010 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &stcb->asoc.primary_destination->ro._l_addr.sa); |
|
1011 sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, |
|
1012 stcb->asoc.deleted_primary, |
|
1013 SCTP_FROM_SCTP_TIMER+SCTP_LOC_8); |
|
1014 stcb->asoc.num_send_timers_up--; |
|
1015 if (stcb->asoc.num_send_timers_up < 0) { |
|
1016 stcb->asoc.num_send_timers_up = 0; |
|
1017 } |
|
1018 SCTP_TCB_LOCK_ASSERT(stcb); |
|
1019 error = sctp_t3rxt_timer(stcb->sctp_ep, stcb, |
|
1020 stcb->asoc.deleted_primary); |
|
1021 if (error) { |
|
1022 SCTP_INP_DECR_REF(stcb->sctp_ep); |
|
1023 return; |
|
1024 } |
|
1025 SCTP_TCB_LOCK_ASSERT(stcb); |
|
1026 #ifdef SCTP_AUDITING_ENABLED |
|
1027 sctp_auditing(4, stcb->sctp_ep, stcb, stcb->asoc.deleted_primary); |
|
1028 #endif |
|
1029 sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); |
|
1030 if ((stcb->asoc.num_send_timers_up == 0) && |
|
1031 (stcb->asoc.sent_queue_cnt > 0)) { |
|
1032 struct sctp_tmit_chunk *chk; |
|
1033 |
|
1034 chk = TAILQ_FIRST(&stcb->asoc.sent_queue); |
|
1035 sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, |
|
1036 stcb, chk->whoTo); |
|
1037 } |
|
1038 } |
|
1039 return; |
|
1040 } |
|
1041 |
|
1042 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Userspace__) |
|
1043 static int |
|
1044 sctp_asconf_queue_mgmt(struct sctp_tcb *, struct sctp_ifa *, uint16_t); |
|
1045 |
|
1046 void |
|
1047 sctp_net_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *net) |
|
1048 { |
|
1049 struct sctp_tmit_chunk *chk; |
|
1050 |
|
1051 SCTPDBG(SCTP_DEBUG_ASCONF1, "net_immediate_retrans: RTO is %d\n", net->RTO); |
|
1052 sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net, |
|
1053 SCTP_FROM_SCTP_TIMER+SCTP_LOC_5); |
|
1054 stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net); |
|
1055 net->error_count = 0; |
|
1056 TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { |
|
1057 if (chk->whoTo == net) { |
|
1058 if (chk->sent < SCTP_DATAGRAM_RESEND) { |
|
1059 chk->sent = SCTP_DATAGRAM_RESEND; |
|
1060 sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); |
|
1061 sctp_flight_size_decrease(chk); |
|
1062 sctp_total_flight_decrease(stcb, chk); |
|
1063 net->marked_retrans++; |
|
1064 stcb->asoc.marked_retrans++; |
|
1065 } |
|
1066 } |
|
1067 } |
|
1068 if (net->marked_retrans) { |
|
1069 sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); |
|
1070 } |
|
1071 } |
|
1072 |
|
1073 static void |
|
1074 sctp_path_check_and_react(struct sctp_tcb *stcb, struct sctp_ifa *newifa) |
|
1075 { |
|
1076 struct sctp_nets *net; |
|
1077 int addrnum, changed; |
|
1078 |
|
1079 /* If number of local valid addresses is 1, the valid address is |
|
1080 probably newly added address. |
|
1081 Several valid addresses in this association. A source address |
|
1082 may not be changed. Additionally, they can be configured on a |
|
1083 same interface as "alias" addresses. (by micchie) |
|
1084 */ |
|
1085 addrnum = sctp_local_addr_count(stcb); |
|
1086 SCTPDBG(SCTP_DEBUG_ASCONF1, "p_check_react(): %d local addresses\n", |
|
1087 addrnum); |
|
1088 if (addrnum == 1) { |
|
1089 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { |
|
1090 /* clear any cached route and source address */ |
|
1091 if (net->ro.ro_rt) { |
|
1092 RTFREE(net->ro.ro_rt); |
|
1093 net->ro.ro_rt = NULL; |
|
1094 } |
|
1095 if (net->src_addr_selected) { |
|
1096 sctp_free_ifa(net->ro._s_addr); |
|
1097 net->ro._s_addr = NULL; |
|
1098 net->src_addr_selected = 0; |
|
1099 } |
|
1100 /* Retransmit unacknowledged DATA chunks immediately */ |
|
1101 if (sctp_is_mobility_feature_on(stcb->sctp_ep, |
|
1102 SCTP_MOBILITY_FASTHANDOFF)) { |
|
1103 sctp_net_immediate_retrans(stcb, net); |
|
1104 } |
|
1105 /* also, SET PRIMARY is maybe already sent */ |
|
1106 } |
|
1107 return; |
|
1108 } |
|
1109 |
|
1110 /* Multiple local addresses exsist in the association. */ |
|
1111 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { |
|
1112 /* clear any cached route and source address */ |
|
1113 if (net->ro.ro_rt) { |
|
1114 RTFREE(net->ro.ro_rt); |
|
1115 net->ro.ro_rt = NULL; |
|
1116 } |
|
1117 if (net->src_addr_selected) { |
|
1118 sctp_free_ifa(net->ro._s_addr); |
|
1119 net->ro._s_addr = NULL; |
|
1120 net->src_addr_selected = 0; |
|
1121 } |
|
1122 /* Check if the nexthop is corresponding to the new address. |
|
1123 If the new address is corresponding to the current nexthop, |
|
1124 the path will be changed. |
|
1125 If the new address is NOT corresponding to the current |
|
1126 nexthop, the path will not be changed. |
|
1127 */ |
|
1128 SCTP_RTALLOC((sctp_route_t *)&net->ro, |
|
1129 stcb->sctp_ep->def_vrf_id); |
|
1130 if (net->ro.ro_rt == NULL) |
|
1131 continue; |
|
1132 |
|
1133 changed = 0; |
|
1134 switch (net->ro._l_addr.sa.sa_family) { |
|
1135 #ifdef INET |
|
1136 case AF_INET: |
|
1137 if (sctp_v4src_match_nexthop(newifa, (sctp_route_t *)&net->ro)) { |
|
1138 changed = 1; |
|
1139 } |
|
1140 break; |
|
1141 #endif |
|
1142 #ifdef INET6 |
|
1143 case AF_INET6: |
|
1144 if (sctp_v6src_match_nexthop( |
|
1145 &newifa->address.sin6, (sctp_route_t *)&net->ro)) { |
|
1146 changed = 1; |
|
1147 } |
|
1148 break; |
|
1149 #endif |
|
1150 default: |
|
1151 break; |
|
1152 } |
|
1153 /* if the newly added address does not relate routing |
|
1154 information, we skip. |
|
1155 */ |
|
1156 if (changed == 0) |
|
1157 continue; |
|
1158 /* Retransmit unacknowledged DATA chunks immediately */ |
|
1159 if (sctp_is_mobility_feature_on(stcb->sctp_ep, |
|
1160 SCTP_MOBILITY_FASTHANDOFF)) { |
|
1161 sctp_net_immediate_retrans(stcb, net); |
|
1162 } |
|
1163 /* Send SET PRIMARY for this new address */ |
|
1164 if (net == stcb->asoc.primary_destination) { |
|
1165 (void)sctp_asconf_queue_mgmt(stcb, newifa, |
|
1166 SCTP_SET_PRIM_ADDR); |
|
1167 } |
|
1168 } |
|
1169 } |
|
1170 #endif /* __FreeBSD__ __APPLE__ __Userspace__ */ |
|
1171 |
|
1172 /* |
|
1173 * process an ADD/DELETE IP ack from peer. |
|
1174 * addr: corresponding sctp_ifa to the address being added/deleted. |
|
1175 * type: SCTP_ADD_IP_ADDRESS or SCTP_DEL_IP_ADDRESS. |
|
1176 * flag: 1=success, 0=failure. |
|
1177 */ |
|
1178 static void |
|
1179 sctp_asconf_addr_mgmt_ack(struct sctp_tcb *stcb, struct sctp_ifa *addr, uint32_t flag) |
|
1180 { |
|
1181 /* |
|
1182 * do the necessary asoc list work- if we get a failure indication, |
|
1183 * leave the address on the assoc's restricted list. If we get a |
|
1184 * success indication, remove the address from the restricted list. |
|
1185 */ |
|
1186 /* |
|
1187 * Note: this will only occur for ADD_IP_ADDRESS, since |
|
1188 * DEL_IP_ADDRESS is never actually added to the list... |
|
1189 */ |
|
1190 if (flag) { |
|
1191 /* success case, so remove from the restricted list */ |
|
1192 sctp_del_local_addr_restricted(stcb, addr); |
|
1193 |
|
1194 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Userspace__) |
|
1195 if (sctp_is_mobility_feature_on(stcb->sctp_ep, |
|
1196 SCTP_MOBILITY_BASE) || |
|
1197 sctp_is_mobility_feature_on(stcb->sctp_ep, |
|
1198 SCTP_MOBILITY_FASTHANDOFF)) { |
|
1199 sctp_path_check_and_react(stcb, addr); |
|
1200 return; |
|
1201 } |
|
1202 #endif /* __FreeBSD__ __APPLE__ __Userspace__ */ |
|
1203 /* clear any cached/topologically incorrect source addresses */ |
|
1204 sctp_asconf_nets_cleanup(stcb, addr->ifn_p); |
|
1205 } |
|
1206 /* else, leave it on the list */ |
|
1207 } |
|
1208 |
|
1209 /* |
|
1210 * add an asconf add/delete/set primary IP address parameter to the queue. |
|
1211 * type = SCTP_ADD_IP_ADDRESS, SCTP_DEL_IP_ADDRESS, SCTP_SET_PRIM_ADDR. |
|
1212 * returns 0 if queued, -1 if not queued/removed. |
|
1213 * NOTE: if adding, but a delete for the same address is already scheduled |
|
1214 * (and not yet sent out), simply remove it from queue. Same for deleting |
|
1215 * an address already scheduled for add. If a duplicate operation is found, |
|
1216 * ignore the new one. |
|
1217 */ |
|
1218 static int |
|
1219 sctp_asconf_queue_mgmt(struct sctp_tcb *stcb, struct sctp_ifa *ifa, |
|
1220 uint16_t type) |
|
1221 { |
|
1222 struct sctp_asconf_addr *aa, *aa_next; |
|
1223 |
|
1224 /* make sure the request isn't already in the queue */ |
|
1225 TAILQ_FOREACH_SAFE(aa, &stcb->asoc.asconf_queue, next, aa_next) { |
|
1226 /* address match? */ |
|
1227 if (sctp_asconf_addr_match(aa, &ifa->address.sa) == 0) |
|
1228 continue; |
|
1229 /* is the request already in queue but not sent? |
|
1230 * pass the request already sent in order to resolve the following case: |
|
1231 * 1. arrival of ADD, then sent |
|
1232 * 2. arrival of DEL. we can't remove the ADD request already sent |
|
1233 * 3. arrival of ADD |
|
1234 */ |
|
1235 if (aa->ap.aph.ph.param_type == type && aa->sent == 0) { |
|
1236 return (-1); |
|
1237 } |
|
1238 /* is the negative request already in queue, and not sent */ |
|
1239 if ((aa->sent == 0) && (type == SCTP_ADD_IP_ADDRESS) && |
|
1240 (aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS)) { |
|
1241 /* add requested, delete already queued */ |
|
1242 TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next); |
|
1243 /* remove the ifa from the restricted list */ |
|
1244 sctp_del_local_addr_restricted(stcb, ifa); |
|
1245 /* free the asconf param */ |
|
1246 SCTP_FREE(aa, SCTP_M_ASC_ADDR); |
|
1247 SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_mgmt: add removes queued entry\n"); |
|
1248 return (-1); |
|
1249 } |
|
1250 if ((aa->sent == 0) && (type == SCTP_DEL_IP_ADDRESS) && |
|
1251 (aa->ap.aph.ph.param_type == SCTP_ADD_IP_ADDRESS)) { |
|
1252 /* delete requested, add already queued */ |
|
1253 TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next); |
|
1254 /* remove the aa->ifa from the restricted list */ |
|
1255 sctp_del_local_addr_restricted(stcb, aa->ifa); |
|
1256 /* free the asconf param */ |
|
1257 SCTP_FREE(aa, SCTP_M_ASC_ADDR); |
|
1258 SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_mgmt: delete removes queued entry\n"); |
|
1259 return (-1); |
|
1260 } |
|
1261 } /* for each aa */ |
|
1262 |
|
1263 /* adding new request to the queue */ |
|
1264 SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa), |
|
1265 SCTP_M_ASC_ADDR); |
|
1266 if (aa == NULL) { |
|
1267 /* didn't get memory */ |
|
1268 SCTPDBG(SCTP_DEBUG_ASCONF1, "asconf_queue_mgmt: failed to get memory!\n"); |
|
1269 return (-1); |
|
1270 } |
|
1271 aa->special_del = 0; |
|
1272 /* fill in asconf address parameter fields */ |
|
1273 /* top level elements are "networked" during send */ |
|
1274 aa->ap.aph.ph.param_type = type; |
|
1275 aa->ifa = ifa; |
|
1276 atomic_add_int(&ifa->refcount, 1); |
|
1277 /* correlation_id filled in during send routine later... */ |
|
1278 switch (ifa->address.sa.sa_family) { |
|
1279 #ifdef INET6 |
|
1280 case AF_INET6: |
|
1281 { |
|
1282 struct sockaddr_in6 *sin6; |
|
1283 |
|
1284 sin6 = (struct sockaddr_in6 *)&ifa->address.sa; |
|
1285 aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS; |
|
1286 aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv6addr_param)); |
|
1287 aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) + |
|
1288 sizeof(struct sctp_ipv6addr_param); |
|
1289 memcpy(&aa->ap.addrp.addr, &sin6->sin6_addr, |
|
1290 sizeof(struct in6_addr)); |
|
1291 break; |
|
1292 } |
|
1293 #endif |
|
1294 #ifdef INET |
|
1295 case AF_INET: |
|
1296 { |
|
1297 struct sockaddr_in *sin; |
|
1298 |
|
1299 sin= (struct sockaddr_in *)&ifa->address.sa; |
|
1300 aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS; |
|
1301 aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv4addr_param)); |
|
1302 aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) + |
|
1303 sizeof(struct sctp_ipv4addr_param); |
|
1304 memcpy(&aa->ap.addrp.addr, &sin->sin_addr, |
|
1305 sizeof(struct in_addr)); |
|
1306 break; |
|
1307 } |
|
1308 #endif |
|
1309 default: |
|
1310 /* invalid family! */ |
|
1311 SCTP_FREE(aa, SCTP_M_ASC_ADDR); |
|
1312 sctp_free_ifa(ifa); |
|
1313 return (-1); |
|
1314 } |
|
1315 aa->sent = 0; /* clear sent flag */ |
|
1316 |
|
1317 TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next); |
|
1318 #ifdef SCTP_DEBUG |
|
1319 if (SCTP_BASE_SYSCTL(sctp_debug_on) & SCTP_DEBUG_ASCONF2) { |
|
1320 if (type == SCTP_ADD_IP_ADDRESS) { |
|
1321 SCTP_PRINTF("asconf_queue_mgmt: inserted asconf ADD_IP_ADDRESS: "); |
|
1322 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, &ifa->address.sa); |
|
1323 } else if (type == SCTP_DEL_IP_ADDRESS) { |
|
1324 SCTP_PRINTF("asconf_queue_mgmt: appended asconf DEL_IP_ADDRESS: "); |
|
1325 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, &ifa->address.sa); |
|
1326 } else { |
|
1327 SCTP_PRINTF("asconf_queue_mgmt: appended asconf SET_PRIM_ADDR: "); |
|
1328 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, &ifa->address.sa); |
|
1329 } |
|
1330 } |
|
1331 #endif |
|
1332 |
|
1333 return (0); |
|
1334 } |
|
1335 |
|
1336 |
|
1337 /* |
|
1338 * add an asconf operation for the given ifa and type. |
|
1339 * type = SCTP_ADD_IP_ADDRESS, SCTP_DEL_IP_ADDRESS, SCTP_SET_PRIM_ADDR. |
|
1340 * returns 0 if completed, -1 if not completed, 1 if immediate send is |
|
1341 * advisable. |
|
1342 */ |
|
1343 static int |
|
1344 sctp_asconf_queue_add(struct sctp_tcb *stcb, struct sctp_ifa *ifa, |
|
1345 uint16_t type) |
|
1346 { |
|
1347 uint32_t status; |
|
1348 int pending_delete_queued = 0; |
|
1349 |
|
1350 /* see if peer supports ASCONF */ |
|
1351 if (stcb->asoc.peer_supports_asconf == 0) { |
|
1352 return (-1); |
|
1353 } |
|
1354 |
|
1355 /* |
|
1356 * if this is deleting the last address from the assoc, mark it as |
|
1357 * pending. |
|
1358 */ |
|
1359 if ((type == SCTP_DEL_IP_ADDRESS) && !stcb->asoc.asconf_del_pending && |
|
1360 (sctp_local_addr_count(stcb) < 2)) { |
|
1361 /* set the pending delete info only */ |
|
1362 stcb->asoc.asconf_del_pending = 1; |
|
1363 stcb->asoc.asconf_addr_del_pending = ifa; |
|
1364 atomic_add_int(&ifa->refcount, 1); |
|
1365 SCTPDBG(SCTP_DEBUG_ASCONF2, |
|
1366 "asconf_queue_add: mark delete last address pending\n"); |
|
1367 return (-1); |
|
1368 } |
|
1369 |
|
1370 /* queue an asconf parameter */ |
|
1371 status = sctp_asconf_queue_mgmt(stcb, ifa, type); |
|
1372 |
|
1373 /* |
|
1374 * if this is an add, and there is a delete also pending (i.e. the |
|
1375 * last local address is being changed), queue the pending delete too. |
|
1376 */ |
|
1377 if ((type == SCTP_ADD_IP_ADDRESS) && stcb->asoc.asconf_del_pending && (status == 0)) { |
|
1378 /* queue in the pending delete */ |
|
1379 if (sctp_asconf_queue_mgmt(stcb, |
|
1380 stcb->asoc.asconf_addr_del_pending, |
|
1381 SCTP_DEL_IP_ADDRESS) == 0) { |
|
1382 SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_add: queing pending delete\n"); |
|
1383 pending_delete_queued = 1; |
|
1384 /* clear out the pending delete info */ |
|
1385 stcb->asoc.asconf_del_pending = 0; |
|
1386 sctp_free_ifa(stcb->asoc.asconf_addr_del_pending); |
|
1387 stcb->asoc.asconf_addr_del_pending = NULL; |
|
1388 } |
|
1389 } |
|
1390 |
|
1391 if (pending_delete_queued) { |
|
1392 struct sctp_nets *net; |
|
1393 /* |
|
1394 * since we know that the only/last address is now being |
|
1395 * changed in this case, reset the cwnd/rto on all nets to |
|
1396 * start as a new address and path. Also clear the error |
|
1397 * counts to give the assoc the best chance to complete the |
|
1398 * address change. |
|
1399 */ |
|
1400 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { |
|
1401 stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, |
|
1402 net); |
|
1403 net->RTO = 0; |
|
1404 net->error_count = 0; |
|
1405 } |
|
1406 stcb->asoc.overall_error_count = 0; |
|
1407 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { |
|
1408 sctp_misc_ints(SCTP_THRESHOLD_CLEAR, |
|
1409 stcb->asoc.overall_error_count, |
|
1410 0, |
|
1411 SCTP_FROM_SCTP_ASCONF, |
|
1412 __LINE__); |
|
1413 } |
|
1414 |
|
1415 /* queue in an advisory set primary too */ |
|
1416 (void)sctp_asconf_queue_mgmt(stcb, ifa, SCTP_SET_PRIM_ADDR); |
|
1417 /* let caller know we should send this out immediately */ |
|
1418 status = 1; |
|
1419 } |
|
1420 return (status); |
|
1421 } |
|
1422 |
|
1423 /*- |
|
1424 * add an asconf delete IP address parameter to the queue by sockaddr and |
|
1425 * possibly with no sctp_ifa available. This is only called by the routine |
|
1426 * that checks the addresses in an INIT-ACK against the current address list. |
|
1427 * returns 0 if completed, non-zero if not completed. |
|
1428 * NOTE: if an add is already scheduled (and not yet sent out), simply |
|
1429 * remove it from queue. If a duplicate operation is found, ignore the |
|
1430 * new one. |
|
1431 */ |
|
1432 static int |
|
1433 sctp_asconf_queue_sa_delete(struct sctp_tcb *stcb, struct sockaddr *sa) |
|
1434 { |
|
1435 struct sctp_ifa *ifa; |
|
1436 struct sctp_asconf_addr *aa, *aa_next; |
|
1437 uint32_t vrf_id; |
|
1438 |
|
1439 if (stcb == NULL) { |
|
1440 return (-1); |
|
1441 } |
|
1442 /* see if peer supports ASCONF */ |
|
1443 if (stcb->asoc.peer_supports_asconf == 0) { |
|
1444 return (-1); |
|
1445 } |
|
1446 /* make sure the request isn't already in the queue */ |
|
1447 TAILQ_FOREACH_SAFE(aa, &stcb->asoc.asconf_queue, next, aa_next) { |
|
1448 /* address match? */ |
|
1449 if (sctp_asconf_addr_match(aa, sa) == 0) |
|
1450 continue; |
|
1451 /* is the request already in queue (sent or not) */ |
|
1452 if (aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS) { |
|
1453 return (-1); |
|
1454 } |
|
1455 /* is the negative request already in queue, and not sent */ |
|
1456 if (aa->sent == 1) |
|
1457 continue; |
|
1458 if (aa->ap.aph.ph.param_type == SCTP_ADD_IP_ADDRESS) { |
|
1459 /* add already queued, so remove existing entry */ |
|
1460 TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next); |
|
1461 sctp_del_local_addr_restricted(stcb, aa->ifa); |
|
1462 /* free the entry */ |
|
1463 SCTP_FREE(aa, SCTP_M_ASC_ADDR); |
|
1464 return (-1); |
|
1465 } |
|
1466 } /* for each aa */ |
|
1467 |
|
1468 /* find any existing ifa-- NOTE ifa CAN be allowed to be NULL */ |
|
1469 if (stcb) { |
|
1470 vrf_id = stcb->asoc.vrf_id; |
|
1471 } else { |
|
1472 vrf_id = SCTP_DEFAULT_VRFID; |
|
1473 } |
|
1474 ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED); |
|
1475 |
|
1476 /* adding new request to the queue */ |
|
1477 SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa), |
|
1478 SCTP_M_ASC_ADDR); |
|
1479 if (aa == NULL) { |
|
1480 /* didn't get memory */ |
|
1481 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
1482 "sctp_asconf_queue_sa_delete: failed to get memory!\n"); |
|
1483 return (-1); |
|
1484 } |
|
1485 aa->special_del = 0; |
|
1486 /* fill in asconf address parameter fields */ |
|
1487 /* top level elements are "networked" during send */ |
|
1488 aa->ap.aph.ph.param_type = SCTP_DEL_IP_ADDRESS; |
|
1489 aa->ifa = ifa; |
|
1490 if (ifa) |
|
1491 atomic_add_int(&ifa->refcount, 1); |
|
1492 /* correlation_id filled in during send routine later... */ |
|
1493 switch (sa->sa_family) { |
|
1494 #ifdef INET6 |
|
1495 case AF_INET6: |
|
1496 { |
|
1497 /* IPv6 address */ |
|
1498 struct sockaddr_in6 *sin6; |
|
1499 |
|
1500 sin6 = (struct sockaddr_in6 *)sa; |
|
1501 aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS; |
|
1502 aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv6addr_param)); |
|
1503 aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_ipv6addr_param); |
|
1504 memcpy(&aa->ap.addrp.addr, &sin6->sin6_addr, |
|
1505 sizeof(struct in6_addr)); |
|
1506 break; |
|
1507 } |
|
1508 #endif |
|
1509 #ifdef INET |
|
1510 case AF_INET: |
|
1511 { |
|
1512 /* IPv4 address */ |
|
1513 struct sockaddr_in *sin = (struct sockaddr_in *)sa; |
|
1514 |
|
1515 aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS; |
|
1516 aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv4addr_param)); |
|
1517 aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_ipv4addr_param); |
|
1518 memcpy(&aa->ap.addrp.addr, &sin->sin_addr, |
|
1519 sizeof(struct in_addr)); |
|
1520 break; |
|
1521 } |
|
1522 #endif |
|
1523 default: |
|
1524 /* invalid family! */ |
|
1525 SCTP_FREE(aa, SCTP_M_ASC_ADDR); |
|
1526 if (ifa) |
|
1527 sctp_free_ifa(ifa); |
|
1528 return (-1); |
|
1529 } |
|
1530 aa->sent = 0; /* clear sent flag */ |
|
1531 |
|
1532 /* delete goes to the back of the queue */ |
|
1533 TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next); |
|
1534 |
|
1535 /* sa_ignore MEMLEAK {memory is put on the tailq} */ |
|
1536 return (0); |
|
1537 } |
|
1538 |
|
1539 /* |
|
1540 * find a specific asconf param on our "sent" queue |
|
1541 */ |
|
1542 static struct sctp_asconf_addr * |
|
1543 sctp_asconf_find_param(struct sctp_tcb *stcb, uint32_t correlation_id) |
|
1544 { |
|
1545 struct sctp_asconf_addr *aa; |
|
1546 |
|
1547 TAILQ_FOREACH(aa, &stcb->asoc.asconf_queue, next) { |
|
1548 if (aa->ap.aph.correlation_id == correlation_id && |
|
1549 aa->sent == 1) { |
|
1550 /* found it */ |
|
1551 return (aa); |
|
1552 } |
|
1553 } |
|
1554 /* didn't find it */ |
|
1555 return (NULL); |
|
1556 } |
|
1557 |
|
1558 /* |
|
1559 * process an SCTP_ERROR_CAUSE_IND for a ASCONF-ACK parameter and do |
|
1560 * notifications based on the error response |
|
1561 */ |
|
1562 static void |
|
1563 sctp_asconf_process_error(struct sctp_tcb *stcb, |
|
1564 struct sctp_asconf_paramhdr *aph) |
|
1565 { |
|
1566 struct sctp_error_cause *eh; |
|
1567 struct sctp_paramhdr *ph; |
|
1568 uint16_t param_type; |
|
1569 uint16_t error_code; |
|
1570 |
|
1571 eh = (struct sctp_error_cause *)(aph + 1); |
|
1572 ph = (struct sctp_paramhdr *)(eh + 1); |
|
1573 /* validate lengths */ |
|
1574 if (htons(eh->length) + sizeof(struct sctp_error_cause) > |
|
1575 htons(aph->ph.param_length)) { |
|
1576 /* invalid error cause length */ |
|
1577 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
1578 "asconf_process_error: cause element too long\n"); |
|
1579 return; |
|
1580 } |
|
1581 if (htons(ph->param_length) + sizeof(struct sctp_paramhdr) > |
|
1582 htons(eh->length)) { |
|
1583 /* invalid included TLV length */ |
|
1584 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
1585 "asconf_process_error: included TLV too long\n"); |
|
1586 return; |
|
1587 } |
|
1588 /* which error code ? */ |
|
1589 error_code = ntohs(eh->code); |
|
1590 param_type = ntohs(aph->ph.param_type); |
|
1591 /* FIX: this should go back up the REMOTE_ERROR ULP notify */ |
|
1592 switch (error_code) { |
|
1593 case SCTP_CAUSE_RESOURCE_SHORTAGE: |
|
1594 /* we allow ourselves to "try again" for this error */ |
|
1595 break; |
|
1596 default: |
|
1597 /* peer can't handle it... */ |
|
1598 switch (param_type) { |
|
1599 case SCTP_ADD_IP_ADDRESS: |
|
1600 case SCTP_DEL_IP_ADDRESS: |
|
1601 stcb->asoc.peer_supports_asconf = 0; |
|
1602 break; |
|
1603 case SCTP_SET_PRIM_ADDR: |
|
1604 stcb->asoc.peer_supports_asconf = 0; |
|
1605 break; |
|
1606 default: |
|
1607 break; |
|
1608 } |
|
1609 } |
|
1610 } |
|
1611 |
|
1612 /* |
|
1613 * process an asconf queue param. |
|
1614 * aparam: parameter to process, will be removed from the queue. |
|
1615 * flag: 1=success case, 0=failure case |
|
1616 */ |
|
1617 static void |
|
1618 sctp_asconf_process_param_ack(struct sctp_tcb *stcb, |
|
1619 struct sctp_asconf_addr *aparam, uint32_t flag) |
|
1620 { |
|
1621 uint16_t param_type; |
|
1622 |
|
1623 /* process this param */ |
|
1624 param_type = aparam->ap.aph.ph.param_type; |
|
1625 switch (param_type) { |
|
1626 case SCTP_ADD_IP_ADDRESS: |
|
1627 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
1628 "process_param_ack: added IP address\n"); |
|
1629 sctp_asconf_addr_mgmt_ack(stcb, aparam->ifa, flag); |
|
1630 break; |
|
1631 case SCTP_DEL_IP_ADDRESS: |
|
1632 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
1633 "process_param_ack: deleted IP address\n"); |
|
1634 /* nothing really to do... lists already updated */ |
|
1635 break; |
|
1636 case SCTP_SET_PRIM_ADDR: |
|
1637 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
1638 "process_param_ack: set primary IP address\n"); |
|
1639 /* nothing to do... peer may start using this addr */ |
|
1640 if (flag == 0) |
|
1641 stcb->asoc.peer_supports_asconf = 0; |
|
1642 break; |
|
1643 default: |
|
1644 /* should NEVER happen */ |
|
1645 break; |
|
1646 } |
|
1647 |
|
1648 /* remove the param and free it */ |
|
1649 TAILQ_REMOVE(&stcb->asoc.asconf_queue, aparam, next); |
|
1650 if (aparam->ifa) |
|
1651 sctp_free_ifa(aparam->ifa); |
|
1652 SCTP_FREE(aparam, SCTP_M_ASC_ADDR); |
|
1653 } |
|
1654 |
|
1655 /* |
|
1656 * cleanup from a bad asconf ack parameter |
|
1657 */ |
|
1658 static void |
|
1659 sctp_asconf_ack_clear(struct sctp_tcb *stcb) |
|
1660 { |
|
1661 /* assume peer doesn't really know how to do asconfs */ |
|
1662 stcb->asoc.peer_supports_asconf = 0; |
|
1663 /* XXX we could free the pending queue here */ |
|
1664 } |
|
1665 |
|
1666 void |
|
1667 sctp_handle_asconf_ack(struct mbuf *m, int offset, |
|
1668 struct sctp_asconf_ack_chunk *cp, struct sctp_tcb *stcb, |
|
1669 struct sctp_nets *net, int *abort_no_unlock) |
|
1670 { |
|
1671 struct sctp_association *asoc; |
|
1672 uint32_t serial_num; |
|
1673 uint16_t ack_length; |
|
1674 struct sctp_asconf_paramhdr *aph; |
|
1675 struct sctp_asconf_addr *aa, *aa_next; |
|
1676 uint32_t last_error_id = 0; /* last error correlation id */ |
|
1677 uint32_t id; |
|
1678 struct sctp_asconf_addr *ap; |
|
1679 |
|
1680 /* asconf param buffer */ |
|
1681 uint8_t aparam_buf[SCTP_PARAM_BUFFER_SIZE]; |
|
1682 |
|
1683 /* verify minimum length */ |
|
1684 if (ntohs(cp->ch.chunk_length) < sizeof(struct sctp_asconf_ack_chunk)) { |
|
1685 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
1686 "handle_asconf_ack: chunk too small = %xh\n", |
|
1687 ntohs(cp->ch.chunk_length)); |
|
1688 return; |
|
1689 } |
|
1690 asoc = &stcb->asoc; |
|
1691 serial_num = ntohl(cp->serial_number); |
|
1692 |
|
1693 /* |
|
1694 * NOTE: we may want to handle this differently- currently, we will |
|
1695 * abort when we get an ack for the expected serial number + 1 (eg. |
|
1696 * we didn't send it), process an ack normally if it is the expected |
|
1697 * serial number, and re-send the previous ack for *ALL* other |
|
1698 * serial numbers |
|
1699 */ |
|
1700 |
|
1701 /* |
|
1702 * if the serial number is the next expected, but I didn't send it, |
|
1703 * abort the asoc, since someone probably just hijacked us... |
|
1704 */ |
|
1705 if (serial_num == (asoc->asconf_seq_out + 1)) { |
|
1706 SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf_ack: got unexpected next serial number! Aborting asoc!\n"); |
|
1707 sctp_abort_an_association(stcb->sctp_ep, stcb, NULL, SCTP_SO_NOT_LOCKED); |
|
1708 *abort_no_unlock = 1; |
|
1709 return; |
|
1710 } |
|
1711 if (serial_num != asoc->asconf_seq_out_acked + 1) { |
|
1712 /* got a duplicate/unexpected ASCONF-ACK */ |
|
1713 SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf_ack: got duplicate/unexpected serial number = %xh (expected = %xh)\n", |
|
1714 serial_num, asoc->asconf_seq_out_acked + 1); |
|
1715 return; |
|
1716 } |
|
1717 |
|
1718 if (serial_num == asoc->asconf_seq_out - 1) { |
|
1719 /* stop our timer */ |
|
1720 sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, net, |
|
1721 SCTP_FROM_SCTP_ASCONF+SCTP_LOC_3); |
|
1722 } |
|
1723 |
|
1724 /* process the ASCONF-ACK contents */ |
|
1725 ack_length = ntohs(cp->ch.chunk_length) - |
|
1726 sizeof(struct sctp_asconf_ack_chunk); |
|
1727 offset += sizeof(struct sctp_asconf_ack_chunk); |
|
1728 /* process through all parameters */ |
|
1729 while (ack_length >= sizeof(struct sctp_asconf_paramhdr)) { |
|
1730 unsigned int param_length, param_type; |
|
1731 |
|
1732 /* get pointer to next asconf parameter */ |
|
1733 aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, |
|
1734 sizeof(struct sctp_asconf_paramhdr), aparam_buf); |
|
1735 if (aph == NULL) { |
|
1736 /* can't get an asconf paramhdr */ |
|
1737 sctp_asconf_ack_clear(stcb); |
|
1738 return; |
|
1739 } |
|
1740 param_type = ntohs(aph->ph.param_type); |
|
1741 param_length = ntohs(aph->ph.param_length); |
|
1742 if (param_length > ack_length) { |
|
1743 sctp_asconf_ack_clear(stcb); |
|
1744 return; |
|
1745 } |
|
1746 if (param_length < sizeof(struct sctp_paramhdr)) { |
|
1747 sctp_asconf_ack_clear(stcb); |
|
1748 return; |
|
1749 } |
|
1750 /* get the complete parameter... */ |
|
1751 if (param_length > sizeof(aparam_buf)) { |
|
1752 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
1753 "param length (%u) larger than buffer size!\n", param_length); |
|
1754 sctp_asconf_ack_clear(stcb); |
|
1755 return; |
|
1756 } |
|
1757 aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, param_length, aparam_buf); |
|
1758 if (aph == NULL) { |
|
1759 sctp_asconf_ack_clear(stcb); |
|
1760 return; |
|
1761 } |
|
1762 /* correlation_id is transparent to peer, no ntohl needed */ |
|
1763 id = aph->correlation_id; |
|
1764 |
|
1765 switch (param_type) { |
|
1766 case SCTP_ERROR_CAUSE_IND: |
|
1767 last_error_id = id; |
|
1768 /* find the corresponding asconf param in our queue */ |
|
1769 ap = sctp_asconf_find_param(stcb, id); |
|
1770 if (ap == NULL) { |
|
1771 /* hmm... can't find this in our queue! */ |
|
1772 break; |
|
1773 } |
|
1774 /* process the parameter, failed flag */ |
|
1775 sctp_asconf_process_param_ack(stcb, ap, 0); |
|
1776 /* process the error response */ |
|
1777 sctp_asconf_process_error(stcb, aph); |
|
1778 break; |
|
1779 case SCTP_SUCCESS_REPORT: |
|
1780 /* find the corresponding asconf param in our queue */ |
|
1781 ap = sctp_asconf_find_param(stcb, id); |
|
1782 if (ap == NULL) { |
|
1783 /* hmm... can't find this in our queue! */ |
|
1784 break; |
|
1785 } |
|
1786 /* process the parameter, success flag */ |
|
1787 sctp_asconf_process_param_ack(stcb, ap, 1); |
|
1788 break; |
|
1789 default: |
|
1790 break; |
|
1791 } /* switch */ |
|
1792 |
|
1793 /* update remaining ASCONF-ACK message length to process */ |
|
1794 ack_length -= SCTP_SIZE32(param_length); |
|
1795 if (ack_length <= 0) { |
|
1796 /* no more data in the mbuf chain */ |
|
1797 break; |
|
1798 } |
|
1799 offset += SCTP_SIZE32(param_length); |
|
1800 } /* while */ |
|
1801 |
|
1802 /* |
|
1803 * if there are any "sent" params still on the queue, these are |
|
1804 * implicitly "success", or "failed" (if we got an error back) ... |
|
1805 * so process these appropriately |
|
1806 * |
|
1807 * we assume that the correlation_id's are monotonically increasing |
|
1808 * beginning from 1 and that we don't have *that* many outstanding |
|
1809 * at any given time |
|
1810 */ |
|
1811 if (last_error_id == 0) |
|
1812 last_error_id--; /* set to "max" value */ |
|
1813 TAILQ_FOREACH_SAFE(aa, &stcb->asoc.asconf_queue, next, aa_next) { |
|
1814 if (aa->sent == 1) { |
|
1815 /* |
|
1816 * implicitly successful or failed if correlation_id |
|
1817 * < last_error_id, then success else, failure |
|
1818 */ |
|
1819 if (aa->ap.aph.correlation_id < last_error_id) |
|
1820 sctp_asconf_process_param_ack(stcb, aa, 1); |
|
1821 else |
|
1822 sctp_asconf_process_param_ack(stcb, aa, 0); |
|
1823 } else { |
|
1824 /* |
|
1825 * since we always process in order (FIFO queue) if |
|
1826 * we reach one that hasn't been sent, the rest |
|
1827 * should not have been sent either. so, we're |
|
1828 * done... |
|
1829 */ |
|
1830 break; |
|
1831 } |
|
1832 } |
|
1833 |
|
1834 /* update the next sequence number to use */ |
|
1835 asoc->asconf_seq_out_acked++; |
|
1836 /* remove the old ASCONF on our outbound queue */ |
|
1837 sctp_toss_old_asconf(stcb); |
|
1838 if (!TAILQ_EMPTY(&stcb->asoc.asconf_queue)) { |
|
1839 #ifdef SCTP_TIMER_BASED_ASCONF |
|
1840 /* we have more params, so restart our timer */ |
|
1841 sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, |
|
1842 stcb, net); |
|
1843 #else |
|
1844 /* we have more params, so send out more */ |
|
1845 sctp_send_asconf(stcb, net, SCTP_ADDR_NOT_LOCKED); |
|
1846 #endif |
|
1847 } |
|
1848 } |
|
1849 |
|
1850 #ifdef INET6 |
|
1851 static uint32_t |
|
1852 sctp_is_scopeid_in_nets(struct sctp_tcb *stcb, struct sockaddr *sa) |
|
1853 { |
|
1854 struct sockaddr_in6 *sin6, *net6; |
|
1855 struct sctp_nets *net; |
|
1856 |
|
1857 if (sa->sa_family != AF_INET6) { |
|
1858 /* wrong family */ |
|
1859 return (0); |
|
1860 } |
|
1861 sin6 = (struct sockaddr_in6 *)sa; |
|
1862 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) == 0) { |
|
1863 /* not link local address */ |
|
1864 return (0); |
|
1865 } |
|
1866 /* hunt through our destination nets list for this scope_id */ |
|
1867 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { |
|
1868 if (((struct sockaddr *)(&net->ro._l_addr))->sa_family != |
|
1869 AF_INET6) |
|
1870 continue; |
|
1871 net6 = (struct sockaddr_in6 *)&net->ro._l_addr; |
|
1872 if (IN6_IS_ADDR_LINKLOCAL(&net6->sin6_addr) == 0) |
|
1873 continue; |
|
1874 if (sctp_is_same_scope(sin6, net6)) { |
|
1875 /* found one */ |
|
1876 return (1); |
|
1877 } |
|
1878 } |
|
1879 /* didn't find one */ |
|
1880 return (0); |
|
1881 } |
|
1882 #endif |
|
1883 |
|
1884 /* |
|
1885 * address management functions |
|
1886 */ |
|
1887 static void |
|
1888 sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, |
|
1889 struct sctp_ifa *ifa, uint16_t type, int addr_locked) |
|
1890 { |
|
1891 int status; |
|
1892 |
|
1893 if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0 || |
|
1894 sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_ASCONF)) { |
|
1895 /* subset bound, no ASCONF allowed case, so ignore */ |
|
1896 return; |
|
1897 } |
|
1898 /* |
|
1899 * note: we know this is not the subset bound, no ASCONF case eg. |
|
1900 * this is boundall or subset bound w/ASCONF allowed |
|
1901 */ |
|
1902 |
|
1903 /* first, make sure it's a good address family */ |
|
1904 switch (ifa->address.sa.sa_family) { |
|
1905 #ifdef INET6 |
|
1906 case AF_INET6: |
|
1907 break; |
|
1908 #endif |
|
1909 #ifdef INET |
|
1910 case AF_INET: |
|
1911 break; |
|
1912 #endif |
|
1913 default: |
|
1914 return; |
|
1915 } |
|
1916 #ifdef INET6 |
|
1917 /* make sure we're "allowed" to add this type of addr */ |
|
1918 if (ifa->address.sa.sa_family == AF_INET6) { |
|
1919 /* invalid if we're not a v6 endpoint */ |
|
1920 if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) |
|
1921 return; |
|
1922 /* is the v6 addr really valid ? */ |
|
1923 if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) { |
|
1924 return; |
|
1925 } |
|
1926 } |
|
1927 #endif |
|
1928 /* put this address on the "pending/do not use yet" list */ |
|
1929 sctp_add_local_addr_restricted(stcb, ifa); |
|
1930 /* |
|
1931 * check address scope if address is out of scope, don't queue |
|
1932 * anything... note: this would leave the address on both inp and |
|
1933 * asoc lists |
|
1934 */ |
|
1935 switch (ifa->address.sa.sa_family) { |
|
1936 #ifdef INET6 |
|
1937 case AF_INET6: |
|
1938 { |
|
1939 struct sockaddr_in6 *sin6; |
|
1940 |
|
1941 sin6 = (struct sockaddr_in6 *)&ifa->address.sin6; |
|
1942 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { |
|
1943 /* we skip unspecifed addresses */ |
|
1944 return; |
|
1945 } |
|
1946 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { |
|
1947 if (stcb->asoc.scope.local_scope == 0) { |
|
1948 return; |
|
1949 } |
|
1950 /* is it the right link local scope? */ |
|
1951 if (sctp_is_scopeid_in_nets(stcb, &ifa->address.sa) == 0) { |
|
1952 return; |
|
1953 } |
|
1954 } |
|
1955 if (stcb->asoc.scope.site_scope == 0 && |
|
1956 IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) { |
|
1957 return; |
|
1958 } |
|
1959 break; |
|
1960 } |
|
1961 #endif |
|
1962 #ifdef INET |
|
1963 case AF_INET: |
|
1964 { |
|
1965 struct sockaddr_in *sin; |
|
1966 struct in6pcb *inp6; |
|
1967 |
|
1968 inp6 = (struct in6pcb *)&inp->ip_inp.inp; |
|
1969 /* invalid if we are a v6 only endpoint */ |
|
1970 if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && |
|
1971 SCTP_IPV6_V6ONLY(inp6)) |
|
1972 return; |
|
1973 |
|
1974 sin = (struct sockaddr_in *)&ifa->address.sa; |
|
1975 if (sin->sin_addr.s_addr == 0) { |
|
1976 /* we skip unspecifed addresses */ |
|
1977 return; |
|
1978 } |
|
1979 if (stcb->asoc.scope.ipv4_local_scope == 0 && |
|
1980 IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) { |
|
1981 return; |
|
1982 } |
|
1983 break; |
|
1984 } |
|
1985 #endif |
|
1986 default: |
|
1987 /* else, not AF_INET or AF_INET6, so skip */ |
|
1988 return; |
|
1989 } |
|
1990 |
|
1991 /* queue an asconf for this address add/delete */ |
|
1992 if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF)) { |
|
1993 /* does the peer do asconf? */ |
|
1994 if (stcb->asoc.peer_supports_asconf) { |
|
1995 /* queue an asconf for this addr */ |
|
1996 status = sctp_asconf_queue_add(stcb, ifa, type); |
|
1997 |
|
1998 /* |
|
1999 * if queued ok, and in the open state, send out the |
|
2000 * ASCONF. If in the non-open state, these will be |
|
2001 * sent when the state goes open. |
|
2002 */ |
|
2003 if (status == 0 && |
|
2004 SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) { |
|
2005 #ifdef SCTP_TIMER_BASED_ASCONF |
|
2006 sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp, |
|
2007 stcb, stcb->asoc.primary_destination); |
|
2008 #else |
|
2009 sctp_send_asconf(stcb, NULL, addr_locked); |
|
2010 #endif |
|
2011 } |
|
2012 } |
|
2013 } |
|
2014 } |
|
2015 |
|
2016 |
|
2017 int |
|
2018 sctp_asconf_iterator_ep(struct sctp_inpcb *inp, void *ptr, uint32_t val SCTP_UNUSED) |
|
2019 { |
|
2020 struct sctp_asconf_iterator *asc; |
|
2021 struct sctp_ifa *ifa; |
|
2022 struct sctp_laddr *l; |
|
2023 int cnt_invalid = 0; |
|
2024 |
|
2025 asc = (struct sctp_asconf_iterator *)ptr; |
|
2026 LIST_FOREACH(l, &asc->list_of_work, sctp_nxt_addr) { |
|
2027 ifa = l->ifa; |
|
2028 switch (ifa->address.sa.sa_family) { |
|
2029 #ifdef INET6 |
|
2030 case AF_INET6: |
|
2031 /* invalid if we're not a v6 endpoint */ |
|
2032 if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { |
|
2033 cnt_invalid++; |
|
2034 if (asc->cnt == cnt_invalid) |
|
2035 return (1); |
|
2036 } |
|
2037 break; |
|
2038 #endif |
|
2039 #ifdef INET |
|
2040 case AF_INET: |
|
2041 { |
|
2042 /* invalid if we are a v6 only endpoint */ |
|
2043 struct in6pcb *inp6; |
|
2044 inp6 = (struct in6pcb *)&inp->ip_inp.inp; |
|
2045 if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && |
|
2046 SCTP_IPV6_V6ONLY(inp6)) { |
|
2047 cnt_invalid++; |
|
2048 if (asc->cnt == cnt_invalid) |
|
2049 return (1); |
|
2050 } |
|
2051 break; |
|
2052 } |
|
2053 #endif |
|
2054 default: |
|
2055 /* invalid address family */ |
|
2056 cnt_invalid++; |
|
2057 if (asc->cnt == cnt_invalid) |
|
2058 return (1); |
|
2059 } |
|
2060 } |
|
2061 return (0); |
|
2062 } |
|
2063 |
|
2064 static int |
|
2065 sctp_asconf_iterator_ep_end(struct sctp_inpcb *inp, void *ptr, uint32_t val SCTP_UNUSED) |
|
2066 { |
|
2067 struct sctp_ifa *ifa; |
|
2068 struct sctp_asconf_iterator *asc; |
|
2069 struct sctp_laddr *laddr, *nladdr, *l; |
|
2070 |
|
2071 /* Only for specific case not bound all */ |
|
2072 asc = (struct sctp_asconf_iterator *)ptr; |
|
2073 LIST_FOREACH(l, &asc->list_of_work, sctp_nxt_addr) { |
|
2074 ifa = l->ifa; |
|
2075 if (l->action == SCTP_ADD_IP_ADDRESS) { |
|
2076 LIST_FOREACH(laddr, &inp->sctp_addr_list, |
|
2077 sctp_nxt_addr) { |
|
2078 if (laddr->ifa == ifa) { |
|
2079 laddr->action = 0; |
|
2080 break; |
|
2081 } |
|
2082 |
|
2083 } |
|
2084 } else if (l->action == SCTP_DEL_IP_ADDRESS) { |
|
2085 LIST_FOREACH_SAFE(laddr, &inp->sctp_addr_list, sctp_nxt_addr, nladdr) { |
|
2086 /* remove only after all guys are done */ |
|
2087 if (laddr->ifa == ifa) { |
|
2088 sctp_del_local_addr_ep(inp, ifa); |
|
2089 } |
|
2090 } |
|
2091 } |
|
2092 } |
|
2093 return (0); |
|
2094 } |
|
2095 |
|
2096 void |
|
2097 sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb, |
|
2098 void *ptr, uint32_t val SCTP_UNUSED) |
|
2099 { |
|
2100 struct sctp_asconf_iterator *asc; |
|
2101 struct sctp_ifa *ifa; |
|
2102 struct sctp_laddr *l; |
|
2103 int cnt_invalid = 0; |
|
2104 int type, status; |
|
2105 int num_queued = 0; |
|
2106 |
|
2107 asc = (struct sctp_asconf_iterator *)ptr; |
|
2108 LIST_FOREACH(l, &asc->list_of_work, sctp_nxt_addr) { |
|
2109 ifa = l->ifa; |
|
2110 type = l->action; |
|
2111 |
|
2112 /* address's vrf_id must be the vrf_id of the assoc */ |
|
2113 if (ifa->vrf_id != stcb->asoc.vrf_id) { |
|
2114 continue; |
|
2115 } |
|
2116 |
|
2117 /* Same checks again for assoc */ |
|
2118 switch (ifa->address.sa.sa_family) { |
|
2119 #ifdef INET6 |
|
2120 case AF_INET6: |
|
2121 { |
|
2122 /* invalid if we're not a v6 endpoint */ |
|
2123 struct sockaddr_in6 *sin6; |
|
2124 |
|
2125 if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { |
|
2126 cnt_invalid++; |
|
2127 if (asc->cnt == cnt_invalid) |
|
2128 return; |
|
2129 else |
|
2130 continue; |
|
2131 } |
|
2132 sin6 = (struct sockaddr_in6 *)&ifa->address.sin6; |
|
2133 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { |
|
2134 /* we skip unspecifed addresses */ |
|
2135 continue; |
|
2136 } |
|
2137 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { |
|
2138 if (stcb->asoc.scope.local_scope == 0) { |
|
2139 continue; |
|
2140 } |
|
2141 /* is it the right link local scope? */ |
|
2142 if (sctp_is_scopeid_in_nets(stcb, &ifa->address.sa) == 0) { |
|
2143 continue; |
|
2144 } |
|
2145 } |
|
2146 break; |
|
2147 } |
|
2148 #endif |
|
2149 #ifdef INET |
|
2150 case AF_INET: |
|
2151 { |
|
2152 /* invalid if we are a v6 only endpoint */ |
|
2153 struct in6pcb *inp6; |
|
2154 struct sockaddr_in *sin; |
|
2155 |
|
2156 inp6 = (struct in6pcb *)&inp->ip_inp.inp; |
|
2157 /* invalid if we are a v6 only endpoint */ |
|
2158 if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && |
|
2159 SCTP_IPV6_V6ONLY(inp6)) |
|
2160 continue; |
|
2161 |
|
2162 sin = (struct sockaddr_in *)&ifa->address.sa; |
|
2163 if (sin->sin_addr.s_addr == 0) { |
|
2164 /* we skip unspecifed addresses */ |
|
2165 continue; |
|
2166 } |
|
2167 if (stcb->asoc.scope.ipv4_local_scope == 0 && |
|
2168 IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) { |
|
2169 continue; |
|
2170 } |
|
2171 if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && |
|
2172 SCTP_IPV6_V6ONLY(inp6)) { |
|
2173 cnt_invalid++; |
|
2174 if (asc->cnt == cnt_invalid) |
|
2175 return; |
|
2176 else |
|
2177 continue; |
|
2178 } |
|
2179 break; |
|
2180 } |
|
2181 #endif |
|
2182 default: |
|
2183 /* invalid address family */ |
|
2184 cnt_invalid++; |
|
2185 if (asc->cnt == cnt_invalid) |
|
2186 return; |
|
2187 else |
|
2188 continue; |
|
2189 break; |
|
2190 } |
|
2191 |
|
2192 if (type == SCTP_ADD_IP_ADDRESS) { |
|
2193 /* prevent this address from being used as a source */ |
|
2194 sctp_add_local_addr_restricted(stcb, ifa); |
|
2195 } else if (type == SCTP_DEL_IP_ADDRESS) { |
|
2196 struct sctp_nets *net; |
|
2197 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { |
|
2198 sctp_rtentry_t *rt; |
|
2199 |
|
2200 /* delete this address if cached */ |
|
2201 if (net->ro._s_addr == ifa) { |
|
2202 sctp_free_ifa(net->ro._s_addr); |
|
2203 net->ro._s_addr = NULL; |
|
2204 net->src_addr_selected = 0; |
|
2205 rt = net->ro.ro_rt; |
|
2206 if (rt) { |
|
2207 RTFREE(rt); |
|
2208 net->ro.ro_rt = NULL; |
|
2209 } |
|
2210 /* |
|
2211 * Now we deleted our src address, |
|
2212 * should we not also now reset the |
|
2213 * cwnd/rto to start as if its a new |
|
2214 * address? |
|
2215 */ |
|
2216 stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net); |
|
2217 net->RTO = 0; |
|
2218 |
|
2219 } |
|
2220 } |
|
2221 } else if (type == SCTP_SET_PRIM_ADDR) { |
|
2222 if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) { |
|
2223 /* must validate the ifa is in the ep */ |
|
2224 if (sctp_is_addr_in_ep(stcb->sctp_ep,ifa) == 0) { |
|
2225 continue; |
|
2226 } |
|
2227 } else { |
|
2228 /* Need to check scopes for this guy */ |
|
2229 if (sctp_is_address_in_scope(ifa, &stcb->asoc.scope, 0) == 0) { |
|
2230 continue; |
|
2231 } |
|
2232 } |
|
2233 } |
|
2234 /* queue an asconf for this address add/delete */ |
|
2235 if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF) && |
|
2236 stcb->asoc.peer_supports_asconf) { |
|
2237 /* queue an asconf for this addr */ |
|
2238 status = sctp_asconf_queue_add(stcb, ifa, type); |
|
2239 /* |
|
2240 * if queued ok, and in the open state, update the |
|
2241 * count of queued params. If in the non-open state, |
|
2242 * these get sent when the assoc goes open. |
|
2243 */ |
|
2244 if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) { |
|
2245 if (status >= 0) { |
|
2246 num_queued++; |
|
2247 } |
|
2248 } |
|
2249 } |
|
2250 } |
|
2251 /* |
|
2252 * If we have queued params in the open state, send out an ASCONF. |
|
2253 */ |
|
2254 if (num_queued > 0) { |
|
2255 sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED); |
|
2256 } |
|
2257 } |
|
2258 |
|
2259 void |
|
2260 sctp_asconf_iterator_end(void *ptr, uint32_t val SCTP_UNUSED) |
|
2261 { |
|
2262 struct sctp_asconf_iterator *asc; |
|
2263 struct sctp_ifa *ifa; |
|
2264 struct sctp_laddr *l, *nl; |
|
2265 |
|
2266 asc = (struct sctp_asconf_iterator *)ptr; |
|
2267 LIST_FOREACH_SAFE(l, &asc->list_of_work, sctp_nxt_addr, nl) { |
|
2268 ifa = l->ifa; |
|
2269 if (l->action == SCTP_ADD_IP_ADDRESS) { |
|
2270 /* Clear the defer use flag */ |
|
2271 ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE; |
|
2272 } |
|
2273 sctp_free_ifa(ifa); |
|
2274 SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_laddr), l); |
|
2275 SCTP_DECR_LADDR_COUNT(); |
|
2276 } |
|
2277 SCTP_FREE(asc, SCTP_M_ASC_IT); |
|
2278 } |
|
2279 |
|
2280 /* |
|
2281 * sa is the sockaddr to ask the peer to set primary to. |
|
2282 * returns: 0 = completed, -1 = error |
|
2283 */ |
|
2284 int32_t |
|
2285 sctp_set_primary_ip_address_sa(struct sctp_tcb *stcb, struct sockaddr *sa) |
|
2286 { |
|
2287 uint32_t vrf_id; |
|
2288 struct sctp_ifa *ifa; |
|
2289 |
|
2290 /* find the ifa for the desired set primary */ |
|
2291 vrf_id = stcb->asoc.vrf_id; |
|
2292 ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED); |
|
2293 if (ifa == NULL) { |
|
2294 /* Invalid address */ |
|
2295 return (-1); |
|
2296 } |
|
2297 |
|
2298 /* queue an ASCONF:SET_PRIM_ADDR to be sent */ |
|
2299 if (!sctp_asconf_queue_add(stcb, ifa, SCTP_SET_PRIM_ADDR)) { |
|
2300 /* set primary queuing succeeded */ |
|
2301 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
2302 "set_primary_ip_address_sa: queued on tcb=%p, ", |
|
2303 (void *)stcb); |
|
2304 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); |
|
2305 if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) { |
|
2306 #ifdef SCTP_TIMER_BASED_ASCONF |
|
2307 sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, |
|
2308 stcb->sctp_ep, stcb, |
|
2309 stcb->asoc.primary_destination); |
|
2310 #else |
|
2311 sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED); |
|
2312 #endif |
|
2313 } |
|
2314 } else { |
|
2315 SCTPDBG(SCTP_DEBUG_ASCONF1, "set_primary_ip_address_sa: failed to add to queue on tcb=%p, ", |
|
2316 (void *)stcb); |
|
2317 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); |
|
2318 return (-1); |
|
2319 } |
|
2320 return (0); |
|
2321 } |
|
2322 |
|
2323 void |
|
2324 sctp_set_primary_ip_address(struct sctp_ifa *ifa) |
|
2325 { |
|
2326 struct sctp_inpcb *inp; |
|
2327 |
|
2328 /* go through all our PCB's */ |
|
2329 LIST_FOREACH(inp, &SCTP_BASE_INFO(listhead), sctp_list) { |
|
2330 struct sctp_tcb *stcb; |
|
2331 |
|
2332 /* process for all associations for this endpoint */ |
|
2333 LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { |
|
2334 /* queue an ASCONF:SET_PRIM_ADDR to be sent */ |
|
2335 if (!sctp_asconf_queue_add(stcb, ifa, |
|
2336 SCTP_SET_PRIM_ADDR)) { |
|
2337 /* set primary queuing succeeded */ |
|
2338 SCTPDBG(SCTP_DEBUG_ASCONF1, "set_primary_ip_address: queued on stcb=%p, ", |
|
2339 (void *)stcb); |
|
2340 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &ifa->address.sa); |
|
2341 if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) { |
|
2342 #ifdef SCTP_TIMER_BASED_ASCONF |
|
2343 sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, |
|
2344 stcb->sctp_ep, stcb, |
|
2345 stcb->asoc.primary_destination); |
|
2346 #else |
|
2347 sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED); |
|
2348 #endif |
|
2349 } |
|
2350 } |
|
2351 } /* for each stcb */ |
|
2352 } /* for each inp */ |
|
2353 } |
|
2354 |
|
2355 int |
|
2356 sctp_is_addr_pending(struct sctp_tcb *stcb, struct sctp_ifa *sctp_ifa) |
|
2357 { |
|
2358 struct sctp_tmit_chunk *chk, *nchk; |
|
2359 unsigned int offset, asconf_limit; |
|
2360 struct sctp_asconf_chunk *acp; |
|
2361 struct sctp_asconf_paramhdr *aph; |
|
2362 uint8_t aparam_buf[SCTP_PARAM_BUFFER_SIZE]; |
|
2363 struct sctp_paramhdr *ph; |
|
2364 int add_cnt, del_cnt; |
|
2365 uint16_t last_param_type; |
|
2366 |
|
2367 add_cnt = del_cnt = 0; |
|
2368 last_param_type = 0; |
|
2369 TAILQ_FOREACH_SAFE(chk, &stcb->asoc.asconf_send_queue, sctp_next, nchk) { |
|
2370 if (chk->data == NULL) { |
|
2371 SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: No mbuf data?\n"); |
|
2372 continue; |
|
2373 } |
|
2374 offset = 0; |
|
2375 acp = mtod(chk->data, struct sctp_asconf_chunk *); |
|
2376 offset += sizeof(struct sctp_asconf_chunk); |
|
2377 asconf_limit = ntohs(acp->ch.chunk_length); |
|
2378 ph = (struct sctp_paramhdr *)sctp_m_getptr(chk->data, offset, sizeof(struct sctp_paramhdr), aparam_buf); |
|
2379 if (ph == NULL) { |
|
2380 SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: couldn't get lookup addr!\n"); |
|
2381 continue; |
|
2382 } |
|
2383 offset += ntohs(ph->param_length); |
|
2384 |
|
2385 aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(chk->data, offset, sizeof(struct sctp_asconf_paramhdr), aparam_buf); |
|
2386 if (aph == NULL) { |
|
2387 SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: Empty ASCONF will be sent?\n"); |
|
2388 continue; |
|
2389 } |
|
2390 while (aph != NULL) { |
|
2391 unsigned int param_length, param_type; |
|
2392 |
|
2393 param_type = ntohs(aph->ph.param_type); |
|
2394 param_length = ntohs(aph->ph.param_length); |
|
2395 if (offset + param_length > asconf_limit) { |
|
2396 /* parameter goes beyond end of chunk! */ |
|
2397 break; |
|
2398 } |
|
2399 if (param_length > sizeof(aparam_buf)) { |
|
2400 SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: param length (%u) larger than buffer size!\n", param_length); |
|
2401 break; |
|
2402 } |
|
2403 if (param_length <= sizeof(struct sctp_paramhdr)) { |
|
2404 SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: param length(%u) too short\n", param_length); |
|
2405 break; |
|
2406 } |
|
2407 |
|
2408 aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(chk->data, offset, param_length, aparam_buf); |
|
2409 if (aph == NULL) { |
|
2410 SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: couldn't get entire param\n"); |
|
2411 break; |
|
2412 } |
|
2413 |
|
2414 ph = (struct sctp_paramhdr *)(aph + 1); |
|
2415 if (sctp_addr_match(ph, &sctp_ifa->address.sa) != 0) { |
|
2416 switch (param_type) { |
|
2417 case SCTP_ADD_IP_ADDRESS: |
|
2418 add_cnt++; |
|
2419 break; |
|
2420 case SCTP_DEL_IP_ADDRESS: |
|
2421 del_cnt++; |
|
2422 break; |
|
2423 default: |
|
2424 break; |
|
2425 } |
|
2426 last_param_type = param_type; |
|
2427 } |
|
2428 |
|
2429 offset += SCTP_SIZE32(param_length); |
|
2430 if (offset >= asconf_limit) { |
|
2431 /* no more data in the mbuf chain */ |
|
2432 break; |
|
2433 } |
|
2434 /* get pointer to next asconf param */ |
|
2435 aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(chk->data, offset, sizeof(struct sctp_asconf_paramhdr), aparam_buf); |
|
2436 } |
|
2437 } |
|
2438 |
|
2439 /* we want to find the sequences which consist of ADD -> DEL -> ADD or DEL -> ADD */ |
|
2440 if (add_cnt > del_cnt || |
|
2441 (add_cnt == del_cnt && last_param_type == SCTP_ADD_IP_ADDRESS)) { |
|
2442 return (1); |
|
2443 } |
|
2444 return (0); |
|
2445 } |
|
2446 |
|
2447 static struct sockaddr * |
|
2448 sctp_find_valid_localaddr(struct sctp_tcb *stcb, int addr_locked) |
|
2449 { |
|
2450 struct sctp_vrf *vrf = NULL; |
|
2451 struct sctp_ifn *sctp_ifn; |
|
2452 struct sctp_ifa *sctp_ifa; |
|
2453 |
|
2454 if (addr_locked == SCTP_ADDR_NOT_LOCKED) |
|
2455 SCTP_IPI_ADDR_RLOCK(); |
|
2456 vrf = sctp_find_vrf(stcb->asoc.vrf_id); |
|
2457 if (vrf == NULL) { |
|
2458 if (addr_locked == SCTP_ADDR_NOT_LOCKED) |
|
2459 SCTP_IPI_ADDR_RUNLOCK(); |
|
2460 return (NULL); |
|
2461 } |
|
2462 LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { |
|
2463 if (stcb->asoc.scope.loopback_scope == 0 && |
|
2464 SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { |
|
2465 /* Skip if loopback_scope not set */ |
|
2466 continue; |
|
2467 } |
|
2468 LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { |
|
2469 switch (sctp_ifa->address.sa.sa_family) { |
|
2470 #ifdef INET |
|
2471 case AF_INET: |
|
2472 if (stcb->asoc.scope.ipv4_addr_legal) { |
|
2473 struct sockaddr_in *sin; |
|
2474 |
|
2475 sin = (struct sockaddr_in *)&sctp_ifa->address.sa; |
|
2476 if (sin->sin_addr.s_addr == 0) { |
|
2477 /* skip unspecifed addresses */ |
|
2478 continue; |
|
2479 } |
|
2480 if (stcb->asoc.scope.ipv4_local_scope == 0 && |
|
2481 IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) |
|
2482 continue; |
|
2483 |
|
2484 if (sctp_is_addr_restricted(stcb, sctp_ifa) && |
|
2485 (!sctp_is_addr_pending(stcb, sctp_ifa))) |
|
2486 continue; |
|
2487 /* found a valid local v4 address to use */ |
|
2488 if (addr_locked == SCTP_ADDR_NOT_LOCKED) |
|
2489 SCTP_IPI_ADDR_RUNLOCK(); |
|
2490 return (&sctp_ifa->address.sa); |
|
2491 } |
|
2492 break; |
|
2493 #endif |
|
2494 #ifdef INET6 |
|
2495 case AF_INET6: |
|
2496 if (stcb->asoc.scope.ipv6_addr_legal) { |
|
2497 struct sockaddr_in6 *sin6; |
|
2498 |
|
2499 if (sctp_ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) { |
|
2500 continue; |
|
2501 } |
|
2502 |
|
2503 sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sa; |
|
2504 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { |
|
2505 /* we skip unspecifed addresses */ |
|
2506 continue; |
|
2507 } |
|
2508 if (stcb->asoc.scope.local_scope == 0 && |
|
2509 IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) |
|
2510 continue; |
|
2511 if (stcb->asoc.scope.site_scope == 0 && |
|
2512 IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) |
|
2513 continue; |
|
2514 |
|
2515 if (sctp_is_addr_restricted(stcb, sctp_ifa) && |
|
2516 (!sctp_is_addr_pending(stcb, sctp_ifa))) |
|
2517 continue; |
|
2518 /* found a valid local v6 address to use */ |
|
2519 if (addr_locked == SCTP_ADDR_NOT_LOCKED) |
|
2520 SCTP_IPI_ADDR_RUNLOCK(); |
|
2521 return (&sctp_ifa->address.sa); |
|
2522 } |
|
2523 break; |
|
2524 #endif |
|
2525 default: |
|
2526 break; |
|
2527 } |
|
2528 } |
|
2529 } |
|
2530 /* no valid addresses found */ |
|
2531 if (addr_locked == SCTP_ADDR_NOT_LOCKED) |
|
2532 SCTP_IPI_ADDR_RUNLOCK(); |
|
2533 return (NULL); |
|
2534 } |
|
2535 |
|
2536 static struct sockaddr * |
|
2537 sctp_find_valid_localaddr_ep(struct sctp_tcb *stcb) |
|
2538 { |
|
2539 struct sctp_laddr *laddr; |
|
2540 |
|
2541 LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) { |
|
2542 if (laddr->ifa == NULL) { |
|
2543 continue; |
|
2544 } |
|
2545 /* is the address restricted ? */ |
|
2546 if (sctp_is_addr_restricted(stcb, laddr->ifa) && |
|
2547 (!sctp_is_addr_pending(stcb, laddr->ifa))) |
|
2548 continue; |
|
2549 |
|
2550 /* found a valid local address to use */ |
|
2551 return (&laddr->ifa->address.sa); |
|
2552 } |
|
2553 /* no valid addresses found */ |
|
2554 return (NULL); |
|
2555 } |
|
2556 |
|
2557 /* |
|
2558 * builds an ASCONF chunk from queued ASCONF params. |
|
2559 * returns NULL on error (no mbuf, no ASCONF params queued, etc). |
|
2560 */ |
|
2561 struct mbuf * |
|
2562 sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen, int addr_locked) |
|
2563 { |
|
2564 struct mbuf *m_asconf, *m_asconf_chk; |
|
2565 struct sctp_asconf_addr *aa; |
|
2566 struct sctp_asconf_chunk *acp; |
|
2567 struct sctp_asconf_paramhdr *aph; |
|
2568 struct sctp_asconf_addr_param *aap; |
|
2569 uint32_t p_length; |
|
2570 uint32_t correlation_id = 1; /* 0 is reserved... */ |
|
2571 caddr_t ptr, lookup_ptr; |
|
2572 uint8_t lookup_used = 0; |
|
2573 |
|
2574 /* are there any asconf params to send? */ |
|
2575 TAILQ_FOREACH(aa, &stcb->asoc.asconf_queue, next) { |
|
2576 if (aa->sent == 0) |
|
2577 break; |
|
2578 } |
|
2579 if (aa == NULL) |
|
2580 return (NULL); |
|
2581 |
|
2582 /* |
|
2583 * get a chunk header mbuf and a cluster for the asconf params since |
|
2584 * it's simpler to fill in the asconf chunk header lookup address on |
|
2585 * the fly |
|
2586 */ |
|
2587 m_asconf_chk = sctp_get_mbuf_for_msg(sizeof(struct sctp_asconf_chunk), 0, M_NOWAIT, 1, MT_DATA); |
|
2588 if (m_asconf_chk == NULL) { |
|
2589 /* no mbuf's */ |
|
2590 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
2591 "compose_asconf: couldn't get chunk mbuf!\n"); |
|
2592 return (NULL); |
|
2593 } |
|
2594 m_asconf = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA); |
|
2595 if (m_asconf == NULL) { |
|
2596 /* no mbuf's */ |
|
2597 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
2598 "compose_asconf: couldn't get mbuf!\n"); |
|
2599 sctp_m_freem(m_asconf_chk); |
|
2600 return (NULL); |
|
2601 } |
|
2602 SCTP_BUF_LEN(m_asconf_chk) = sizeof(struct sctp_asconf_chunk); |
|
2603 SCTP_BUF_LEN(m_asconf) = 0; |
|
2604 acp = mtod(m_asconf_chk, struct sctp_asconf_chunk *); |
|
2605 bzero(acp, sizeof(struct sctp_asconf_chunk)); |
|
2606 /* save pointers to lookup address and asconf params */ |
|
2607 lookup_ptr = (caddr_t)(acp + 1); /* after the header */ |
|
2608 ptr = mtod(m_asconf, caddr_t); /* beginning of cluster */ |
|
2609 |
|
2610 /* fill in chunk header info */ |
|
2611 acp->ch.chunk_type = SCTP_ASCONF; |
|
2612 acp->ch.chunk_flags = 0; |
|
2613 acp->serial_number = htonl(stcb->asoc.asconf_seq_out); |
|
2614 stcb->asoc.asconf_seq_out++; |
|
2615 |
|
2616 /* add parameters... up to smallest MTU allowed */ |
|
2617 TAILQ_FOREACH(aa, &stcb->asoc.asconf_queue, next) { |
|
2618 if (aa->sent) |
|
2619 continue; |
|
2620 /* get the parameter length */ |
|
2621 p_length = SCTP_SIZE32(aa->ap.aph.ph.param_length); |
|
2622 /* will it fit in current chunk? */ |
|
2623 if ((SCTP_BUF_LEN(m_asconf) + p_length > stcb->asoc.smallest_mtu) || |
|
2624 (SCTP_BUF_LEN(m_asconf) + p_length > MCLBYTES)) { |
|
2625 /* won't fit, so we're done with this chunk */ |
|
2626 break; |
|
2627 } |
|
2628 /* assign (and store) a correlation id */ |
|
2629 aa->ap.aph.correlation_id = correlation_id++; |
|
2630 |
|
2631 /* |
|
2632 * fill in address if we're doing a delete this is a simple |
|
2633 * way for us to fill in the correlation address, which |
|
2634 * should only be used by the peer if we're deleting our |
|
2635 * source address and adding a new address (e.g. renumbering |
|
2636 * case) |
|
2637 */ |
|
2638 if (lookup_used == 0 && |
|
2639 (aa->special_del == 0) && |
|
2640 aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS) { |
|
2641 struct sctp_ipv6addr_param *lookup; |
|
2642 uint16_t p_size, addr_size; |
|
2643 |
|
2644 lookup = (struct sctp_ipv6addr_param *)lookup_ptr; |
|
2645 lookup->ph.param_type = |
|
2646 htons(aa->ap.addrp.ph.param_type); |
|
2647 if (aa->ap.addrp.ph.param_type == SCTP_IPV6_ADDRESS) { |
|
2648 /* copy IPv6 address */ |
|
2649 p_size = sizeof(struct sctp_ipv6addr_param); |
|
2650 addr_size = sizeof(struct in6_addr); |
|
2651 } else { |
|
2652 /* copy IPv4 address */ |
|
2653 p_size = sizeof(struct sctp_ipv4addr_param); |
|
2654 addr_size = sizeof(struct in_addr); |
|
2655 } |
|
2656 lookup->ph.param_length = htons(SCTP_SIZE32(p_size)); |
|
2657 memcpy(lookup->addr, &aa->ap.addrp.addr, addr_size); |
|
2658 SCTP_BUF_LEN(m_asconf_chk) += SCTP_SIZE32(p_size); |
|
2659 lookup_used = 1; |
|
2660 } |
|
2661 /* copy into current space */ |
|
2662 memcpy(ptr, &aa->ap, p_length); |
|
2663 |
|
2664 /* network elements and update lengths */ |
|
2665 aph = (struct sctp_asconf_paramhdr *)ptr; |
|
2666 aap = (struct sctp_asconf_addr_param *)ptr; |
|
2667 /* correlation_id is transparent to peer, no htonl needed */ |
|
2668 aph->ph.param_type = htons(aph->ph.param_type); |
|
2669 aph->ph.param_length = htons(aph->ph.param_length); |
|
2670 aap->addrp.ph.param_type = htons(aap->addrp.ph.param_type); |
|
2671 aap->addrp.ph.param_length = htons(aap->addrp.ph.param_length); |
|
2672 |
|
2673 SCTP_BUF_LEN(m_asconf) += SCTP_SIZE32(p_length); |
|
2674 ptr += SCTP_SIZE32(p_length); |
|
2675 |
|
2676 /* |
|
2677 * these params are removed off the pending list upon |
|
2678 * getting an ASCONF-ACK back from the peer, just set flag |
|
2679 */ |
|
2680 aa->sent = 1; |
|
2681 } |
|
2682 /* check to see if the lookup addr has been populated yet */ |
|
2683 if (lookup_used == 0) { |
|
2684 /* NOTE: if the address param is optional, can skip this... */ |
|
2685 /* add any valid (existing) address... */ |
|
2686 struct sctp_ipv6addr_param *lookup; |
|
2687 uint16_t p_size, addr_size; |
|
2688 struct sockaddr *found_addr; |
|
2689 caddr_t addr_ptr; |
|
2690 |
|
2691 if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) |
|
2692 found_addr = sctp_find_valid_localaddr(stcb, |
|
2693 addr_locked); |
|
2694 else |
|
2695 found_addr = sctp_find_valid_localaddr_ep(stcb); |
|
2696 |
|
2697 lookup = (struct sctp_ipv6addr_param *)lookup_ptr; |
|
2698 if (found_addr != NULL) { |
|
2699 switch (found_addr->sa_family) { |
|
2700 #ifdef INET6 |
|
2701 case AF_INET6: |
|
2702 /* copy IPv6 address */ |
|
2703 lookup->ph.param_type = |
|
2704 htons(SCTP_IPV6_ADDRESS); |
|
2705 p_size = sizeof(struct sctp_ipv6addr_param); |
|
2706 addr_size = sizeof(struct in6_addr); |
|
2707 addr_ptr = (caddr_t)&((struct sockaddr_in6 *) |
|
2708 found_addr)->sin6_addr; |
|
2709 break; |
|
2710 #endif |
|
2711 #ifdef INET |
|
2712 case AF_INET: |
|
2713 /* copy IPv4 address */ |
|
2714 lookup->ph.param_type = |
|
2715 htons(SCTP_IPV4_ADDRESS); |
|
2716 p_size = sizeof(struct sctp_ipv4addr_param); |
|
2717 addr_size = sizeof(struct in_addr); |
|
2718 addr_ptr = (caddr_t)&((struct sockaddr_in *) |
|
2719 found_addr)->sin_addr; |
|
2720 break; |
|
2721 #endif |
|
2722 default: |
|
2723 p_size = 0; |
|
2724 addr_size = 0; |
|
2725 addr_ptr = NULL; |
|
2726 break; |
|
2727 } |
|
2728 lookup->ph.param_length = htons(SCTP_SIZE32(p_size)); |
|
2729 memcpy(lookup->addr, addr_ptr, addr_size); |
|
2730 SCTP_BUF_LEN(m_asconf_chk) += SCTP_SIZE32(p_size); |
|
2731 } else { |
|
2732 /* uh oh... don't have any address?? */ |
|
2733 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
2734 "compose_asconf: no lookup addr!\n"); |
|
2735 /* XXX for now, we send a IPv4 address of 0.0.0.0 */ |
|
2736 lookup->ph.param_type = htons(SCTP_IPV4_ADDRESS); |
|
2737 lookup->ph.param_length = htons(SCTP_SIZE32(sizeof(struct sctp_ipv4addr_param))); |
|
2738 bzero(lookup->addr, sizeof(struct in_addr)); |
|
2739 SCTP_BUF_LEN(m_asconf_chk) += SCTP_SIZE32(sizeof(struct sctp_ipv4addr_param)); |
|
2740 } |
|
2741 } |
|
2742 /* chain it all together */ |
|
2743 SCTP_BUF_NEXT(m_asconf_chk) = m_asconf; |
|
2744 *retlen = SCTP_BUF_LEN(m_asconf_chk) + SCTP_BUF_LEN(m_asconf); |
|
2745 acp->ch.chunk_length = htons(*retlen); |
|
2746 |
|
2747 return (m_asconf_chk); |
|
2748 } |
|
2749 |
|
2750 /* |
|
2751 * section to handle address changes before an association is up eg. changes |
|
2752 * during INIT/INIT-ACK/COOKIE-ECHO handshake |
|
2753 */ |
|
2754 |
|
2755 /* |
|
2756 * processes the (local) addresses in the INIT-ACK chunk |
|
2757 */ |
|
2758 static void |
|
2759 sctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m, |
|
2760 unsigned int offset, unsigned int length) |
|
2761 { |
|
2762 struct sctp_paramhdr tmp_param, *ph; |
|
2763 uint16_t plen, ptype; |
|
2764 struct sctp_ifa *sctp_ifa; |
|
2765 #ifdef INET6 |
|
2766 struct sctp_ipv6addr_param addr6_store; |
|
2767 struct sockaddr_in6 sin6; |
|
2768 #endif |
|
2769 #ifdef INET |
|
2770 struct sctp_ipv4addr_param addr4_store; |
|
2771 struct sockaddr_in sin; |
|
2772 #endif |
|
2773 struct sockaddr *sa; |
|
2774 uint32_t vrf_id; |
|
2775 |
|
2776 SCTPDBG(SCTP_DEBUG_ASCONF2, "processing init-ack addresses\n"); |
|
2777 if (stcb == NULL) /* Un-needed check for SA */ |
|
2778 return; |
|
2779 |
|
2780 /* convert to upper bound */ |
|
2781 length += offset; |
|
2782 |
|
2783 if ((offset + sizeof(struct sctp_paramhdr)) > length) { |
|
2784 return; |
|
2785 } |
|
2786 /* init the addresses */ |
|
2787 #ifdef INET6 |
|
2788 bzero(&sin6, sizeof(sin6)); |
|
2789 sin6.sin6_family = AF_INET6; |
|
2790 #ifdef HAVE_SIN6_LEN |
|
2791 sin6.sin6_len = sizeof(sin6); |
|
2792 #endif |
|
2793 sin6.sin6_port = stcb->rport; |
|
2794 #endif |
|
2795 |
|
2796 #ifdef INET |
|
2797 bzero(&sin, sizeof(sin)); |
|
2798 sin.sin_family = AF_INET; |
|
2799 #ifdef HAVE_SIN_LEN |
|
2800 sin.sin_len = sizeof(sin); |
|
2801 #endif |
|
2802 sin.sin_port = stcb->rport; |
|
2803 #endif |
|
2804 |
|
2805 /* go through the addresses in the init-ack */ |
|
2806 ph = (struct sctp_paramhdr *) |
|
2807 sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr), |
|
2808 (uint8_t *)&tmp_param); |
|
2809 while (ph != NULL) { |
|
2810 ptype = ntohs(ph->param_type); |
|
2811 plen = ntohs(ph->param_length); |
|
2812 switch (ptype) { |
|
2813 #ifdef INET6 |
|
2814 case SCTP_IPV6_ADDRESS: |
|
2815 { |
|
2816 struct sctp_ipv6addr_param *a6p; |
|
2817 |
|
2818 /* get the entire IPv6 address param */ |
|
2819 a6p = (struct sctp_ipv6addr_param *) |
|
2820 sctp_m_getptr(m, offset, |
|
2821 sizeof(struct sctp_ipv6addr_param), |
|
2822 (uint8_t *)&addr6_store); |
|
2823 if (plen != sizeof(struct sctp_ipv6addr_param) || |
|
2824 a6p == NULL) { |
|
2825 return; |
|
2826 } |
|
2827 memcpy(&sin6.sin6_addr, a6p->addr, |
|
2828 sizeof(struct in6_addr)); |
|
2829 sa = (struct sockaddr *)&sin6; |
|
2830 break; |
|
2831 } |
|
2832 #endif |
|
2833 #ifdef INET |
|
2834 case SCTP_IPV4_ADDRESS: |
|
2835 { |
|
2836 struct sctp_ipv4addr_param *a4p; |
|
2837 |
|
2838 /* get the entire IPv4 address param */ |
|
2839 a4p = (struct sctp_ipv4addr_param *)sctp_m_getptr(m, offset, |
|
2840 sizeof(struct sctp_ipv4addr_param), |
|
2841 (uint8_t *)&addr4_store); |
|
2842 if (plen != sizeof(struct sctp_ipv4addr_param) || |
|
2843 a4p == NULL) { |
|
2844 return; |
|
2845 } |
|
2846 sin.sin_addr.s_addr = a4p->addr; |
|
2847 sa = (struct sockaddr *)&sin; |
|
2848 break; |
|
2849 } |
|
2850 #endif |
|
2851 default: |
|
2852 goto next_addr; |
|
2853 } |
|
2854 |
|
2855 /* see if this address really (still) exists */ |
|
2856 if (stcb) { |
|
2857 vrf_id = stcb->asoc.vrf_id; |
|
2858 } else { |
|
2859 vrf_id = SCTP_DEFAULT_VRFID; |
|
2860 } |
|
2861 sctp_ifa = sctp_find_ifa_by_addr(sa, vrf_id, |
|
2862 SCTP_ADDR_NOT_LOCKED); |
|
2863 if (sctp_ifa == NULL) { |
|
2864 /* address doesn't exist anymore */ |
|
2865 int status; |
|
2866 |
|
2867 /* are ASCONFs allowed ? */ |
|
2868 if ((sctp_is_feature_on(stcb->sctp_ep, |
|
2869 SCTP_PCB_FLAGS_DO_ASCONF)) && |
|
2870 stcb->asoc.peer_supports_asconf) { |
|
2871 /* queue an ASCONF DEL_IP_ADDRESS */ |
|
2872 status = sctp_asconf_queue_sa_delete(stcb, sa); |
|
2873 /* |
|
2874 * if queued ok, and in correct state, send |
|
2875 * out the ASCONF. |
|
2876 */ |
|
2877 if (status == 0 && |
|
2878 SCTP_GET_STATE(&stcb->asoc) == |
|
2879 SCTP_STATE_OPEN) { |
|
2880 #ifdef SCTP_TIMER_BASED_ASCONF |
|
2881 sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, |
|
2882 stcb->sctp_ep, stcb, |
|
2883 stcb->asoc.primary_destination); |
|
2884 #else |
|
2885 sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED); |
|
2886 #endif |
|
2887 } |
|
2888 } |
|
2889 } |
|
2890 |
|
2891 next_addr: |
|
2892 /* |
|
2893 * Sanity check: Make sure the length isn't 0, otherwise |
|
2894 * we'll be stuck in this loop for a long time... |
|
2895 */ |
|
2896 if (SCTP_SIZE32(plen) == 0) { |
|
2897 SCTP_PRINTF("process_initack_addrs: bad len (%d) type=%xh\n", |
|
2898 plen, ptype); |
|
2899 return; |
|
2900 } |
|
2901 /* get next parameter */ |
|
2902 offset += SCTP_SIZE32(plen); |
|
2903 if ((offset + sizeof(struct sctp_paramhdr)) > length) |
|
2904 return; |
|
2905 ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, |
|
2906 sizeof(struct sctp_paramhdr), (uint8_t *) & tmp_param); |
|
2907 } /* while */ |
|
2908 } |
|
2909 |
|
2910 /* FIX ME: need to verify return result for v6 address type if v6 disabled */ |
|
2911 /* |
|
2912 * checks to see if a specific address is in the initack address list returns |
|
2913 * 1 if found, 0 if not |
|
2914 */ |
|
2915 static uint32_t |
|
2916 sctp_addr_in_initack(struct mbuf *m, uint32_t offset, uint32_t length, struct sockaddr *sa) |
|
2917 { |
|
2918 struct sctp_paramhdr tmp_param, *ph; |
|
2919 uint16_t plen, ptype; |
|
2920 #ifdef INET |
|
2921 struct sockaddr_in *sin; |
|
2922 struct sctp_ipv4addr_param *a4p; |
|
2923 struct sctp_ipv6addr_param addr4_store; |
|
2924 #endif |
|
2925 #ifdef INET6 |
|
2926 struct sockaddr_in6 *sin6; |
|
2927 struct sctp_ipv6addr_param *a6p; |
|
2928 struct sctp_ipv6addr_param addr6_store; |
|
2929 #ifdef SCTP_EMBEDDED_V6_SCOPE |
|
2930 struct sockaddr_in6 sin6_tmp; |
|
2931 #endif |
|
2932 #endif |
|
2933 |
|
2934 switch (sa->sa_family) { |
|
2935 #ifdef INET |
|
2936 case AF_INET: |
|
2937 break; |
|
2938 #endif |
|
2939 #ifdef INET6 |
|
2940 case AF_INET6: |
|
2941 break; |
|
2942 #endif |
|
2943 default: |
|
2944 return (0); |
|
2945 } |
|
2946 |
|
2947 SCTPDBG(SCTP_DEBUG_ASCONF2, "find_initack_addr: starting search for "); |
|
2948 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, sa); |
|
2949 /* convert to upper bound */ |
|
2950 length += offset; |
|
2951 |
|
2952 if ((offset + sizeof(struct sctp_paramhdr)) > length) { |
|
2953 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
2954 "find_initack_addr: invalid offset?\n"); |
|
2955 return (0); |
|
2956 } |
|
2957 /* go through the addresses in the init-ack */ |
|
2958 ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, |
|
2959 sizeof(struct sctp_paramhdr), (uint8_t *) & tmp_param); |
|
2960 while (ph != NULL) { |
|
2961 ptype = ntohs(ph->param_type); |
|
2962 plen = ntohs(ph->param_length); |
|
2963 switch (ptype) { |
|
2964 #ifdef INET6 |
|
2965 case SCTP_IPV6_ADDRESS: |
|
2966 if (sa->sa_family == AF_INET6) { |
|
2967 /* get the entire IPv6 address param */ |
|
2968 if (plen != sizeof(struct sctp_ipv6addr_param)) { |
|
2969 break; |
|
2970 } |
|
2971 /* get the entire IPv6 address param */ |
|
2972 a6p = (struct sctp_ipv6addr_param *) |
|
2973 sctp_m_getptr(m, offset, |
|
2974 sizeof(struct sctp_ipv6addr_param), |
|
2975 (uint8_t *)&addr6_store); |
|
2976 if (a6p == NULL) { |
|
2977 return (0); |
|
2978 } |
|
2979 sin6 = (struct sockaddr_in6 *)sa; |
|
2980 #ifdef SCTP_EMBEDDED_V6_SCOPE |
|
2981 if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) { |
|
2982 /* create a copy and clear scope */ |
|
2983 memcpy(&sin6_tmp, sin6, |
|
2984 sizeof(struct sockaddr_in6)); |
|
2985 sin6 = &sin6_tmp; |
|
2986 in6_clearscope(&sin6->sin6_addr); |
|
2987 } |
|
2988 #endif /* SCTP_EMBEDDED_V6_SCOPE */ |
|
2989 if (memcmp(&sin6->sin6_addr, a6p->addr, |
|
2990 sizeof(struct in6_addr)) == 0) { |
|
2991 /* found it */ |
|
2992 return (1); |
|
2993 } |
|
2994 } |
|
2995 break; |
|
2996 #endif /* INET6 */ |
|
2997 #ifdef INET |
|
2998 case SCTP_IPV4_ADDRESS: |
|
2999 if (sa->sa_family == AF_INET) { |
|
3000 if (plen != sizeof(struct sctp_ipv4addr_param)) { |
|
3001 break; |
|
3002 } |
|
3003 /* get the entire IPv4 address param */ |
|
3004 a4p = (struct sctp_ipv4addr_param *) |
|
3005 sctp_m_getptr(m, offset, |
|
3006 sizeof(struct sctp_ipv4addr_param), |
|
3007 (uint8_t *)&addr4_store); |
|
3008 if (a4p == NULL) { |
|
3009 return (0); |
|
3010 } |
|
3011 sin = (struct sockaddr_in *)sa; |
|
3012 if (sin->sin_addr.s_addr == a4p->addr) { |
|
3013 /* found it */ |
|
3014 return (1); |
|
3015 } |
|
3016 } |
|
3017 break; |
|
3018 #endif |
|
3019 default: |
|
3020 break; |
|
3021 } |
|
3022 /* get next parameter */ |
|
3023 offset += SCTP_SIZE32(plen); |
|
3024 if (offset + sizeof(struct sctp_paramhdr) > length) { |
|
3025 return (0); |
|
3026 } |
|
3027 ph = (struct sctp_paramhdr *) |
|
3028 sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr), |
|
3029 (uint8_t *) & tmp_param); |
|
3030 } /* while */ |
|
3031 /* not found! */ |
|
3032 return (0); |
|
3033 } |
|
3034 |
|
3035 /* |
|
3036 * makes sure that the current endpoint local addr list is consistent with |
|
3037 * the new association (eg. subset bound, asconf allowed) adds addresses as |
|
3038 * necessary |
|
3039 */ |
|
3040 static void |
|
3041 sctp_check_address_list_ep(struct sctp_tcb *stcb, struct mbuf *m, int offset, |
|
3042 int length, struct sockaddr *init_addr) |
|
3043 { |
|
3044 struct sctp_laddr *laddr; |
|
3045 |
|
3046 /* go through the endpoint list */ |
|
3047 LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) { |
|
3048 /* be paranoid and validate the laddr */ |
|
3049 if (laddr->ifa == NULL) { |
|
3050 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
3051 "check_addr_list_ep: laddr->ifa is NULL"); |
|
3052 continue; |
|
3053 } |
|
3054 if (laddr->ifa == NULL) { |
|
3055 SCTPDBG(SCTP_DEBUG_ASCONF1, "check_addr_list_ep: laddr->ifa->ifa_addr is NULL"); |
|
3056 continue; |
|
3057 } |
|
3058 /* do i have it implicitly? */ |
|
3059 if (sctp_cmpaddr(&laddr->ifa->address.sa, init_addr)) { |
|
3060 continue; |
|
3061 } |
|
3062 /* check to see if in the init-ack */ |
|
3063 if (!sctp_addr_in_initack(m, offset, length, &laddr->ifa->address.sa)) { |
|
3064 /* try to add it */ |
|
3065 sctp_addr_mgmt_assoc(stcb->sctp_ep, stcb, laddr->ifa, |
|
3066 SCTP_ADD_IP_ADDRESS, SCTP_ADDR_NOT_LOCKED); |
|
3067 } |
|
3068 } |
|
3069 } |
|
3070 |
|
3071 /* |
|
3072 * makes sure that the current kernel address list is consistent with the new |
|
3073 * association (with all addrs bound) adds addresses as necessary |
|
3074 */ |
|
3075 static void |
|
3076 sctp_check_address_list_all(struct sctp_tcb *stcb, struct mbuf *m, int offset, |
|
3077 int length, struct sockaddr *init_addr, |
|
3078 uint16_t local_scope, uint16_t site_scope, |
|
3079 uint16_t ipv4_scope, uint16_t loopback_scope) |
|
3080 { |
|
3081 struct sctp_vrf *vrf = NULL; |
|
3082 struct sctp_ifn *sctp_ifn; |
|
3083 struct sctp_ifa *sctp_ifa; |
|
3084 uint32_t vrf_id; |
|
3085 #ifdef INET |
|
3086 struct sockaddr_in *sin; |
|
3087 #endif |
|
3088 #ifdef INET6 |
|
3089 struct sockaddr_in6 *sin6; |
|
3090 #endif |
|
3091 |
|
3092 if (stcb) { |
|
3093 vrf_id = stcb->asoc.vrf_id; |
|
3094 } else { |
|
3095 return; |
|
3096 } |
|
3097 SCTP_IPI_ADDR_RLOCK(); |
|
3098 vrf = sctp_find_vrf(vrf_id); |
|
3099 if (vrf == NULL) { |
|
3100 SCTP_IPI_ADDR_RUNLOCK(); |
|
3101 return; |
|
3102 } |
|
3103 /* go through all our known interfaces */ |
|
3104 LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { |
|
3105 if (loopback_scope == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { |
|
3106 /* skip loopback interface */ |
|
3107 continue; |
|
3108 } |
|
3109 /* go through each interface address */ |
|
3110 LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { |
|
3111 /* do i have it implicitly? */ |
|
3112 if (sctp_cmpaddr(&sctp_ifa->address.sa, init_addr)) { |
|
3113 continue; |
|
3114 } |
|
3115 switch (sctp_ifa->address.sa.sa_family) { |
|
3116 #ifdef INET |
|
3117 case AF_INET: |
|
3118 sin = (struct sockaddr_in *)&sctp_ifa->address.sin; |
|
3119 if ((ipv4_scope == 0) && |
|
3120 (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { |
|
3121 /* private address not in scope */ |
|
3122 continue; |
|
3123 } |
|
3124 break; |
|
3125 #endif |
|
3126 #ifdef INET6 |
|
3127 case AF_INET6: |
|
3128 sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sin6; |
|
3129 if ((local_scope == 0) && |
|
3130 (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))) { |
|
3131 continue; |
|
3132 } |
|
3133 if ((site_scope == 0) && |
|
3134 (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { |
|
3135 continue; |
|
3136 } |
|
3137 break; |
|
3138 #endif |
|
3139 default: |
|
3140 break; |
|
3141 } |
|
3142 /* check to see if in the init-ack */ |
|
3143 if (!sctp_addr_in_initack(m, offset, length, &sctp_ifa->address.sa)) { |
|
3144 /* try to add it */ |
|
3145 sctp_addr_mgmt_assoc(stcb->sctp_ep, stcb, |
|
3146 sctp_ifa, SCTP_ADD_IP_ADDRESS, |
|
3147 SCTP_ADDR_LOCKED); |
|
3148 } |
|
3149 } /* end foreach ifa */ |
|
3150 } /* end foreach ifn */ |
|
3151 SCTP_IPI_ADDR_RUNLOCK(); |
|
3152 } |
|
3153 |
|
3154 /* |
|
3155 * validates an init-ack chunk (from a cookie-echo) with current addresses |
|
3156 * adds addresses from the init-ack into our local address list, if needed |
|
3157 * queues asconf adds/deletes addresses as needed and makes appropriate list |
|
3158 * changes for source address selection m, offset: points to the start of the |
|
3159 * address list in an init-ack chunk length: total length of the address |
|
3160 * params only init_addr: address where my INIT-ACK was sent from |
|
3161 */ |
|
3162 void |
|
3163 sctp_check_address_list(struct sctp_tcb *stcb, struct mbuf *m, int offset, |
|
3164 int length, struct sockaddr *init_addr, |
|
3165 uint16_t local_scope, uint16_t site_scope, |
|
3166 uint16_t ipv4_scope, uint16_t loopback_scope) |
|
3167 { |
|
3168 /* process the local addresses in the initack */ |
|
3169 sctp_process_initack_addresses(stcb, m, offset, length); |
|
3170 |
|
3171 if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { |
|
3172 /* bound all case */ |
|
3173 sctp_check_address_list_all(stcb, m, offset, length, init_addr, |
|
3174 local_scope, site_scope, ipv4_scope, loopback_scope); |
|
3175 } else { |
|
3176 /* subset bound case */ |
|
3177 if (sctp_is_feature_on(stcb->sctp_ep, |
|
3178 SCTP_PCB_FLAGS_DO_ASCONF)) { |
|
3179 /* asconf's allowed */ |
|
3180 sctp_check_address_list_ep(stcb, m, offset, length, |
|
3181 init_addr); |
|
3182 } |
|
3183 /* else, no asconfs allowed, so what we sent is what we get */ |
|
3184 } |
|
3185 } |
|
3186 |
|
3187 /* |
|
3188 * sctp_bindx() support |
|
3189 */ |
|
3190 uint32_t |
|
3191 sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa, |
|
3192 uint32_t type, uint32_t vrf_id, struct sctp_ifa *sctp_ifap) |
|
3193 { |
|
3194 struct sctp_ifa *ifa; |
|
3195 struct sctp_laddr *laddr, *nladdr; |
|
3196 |
|
3197 #ifdef HAVE_SA_LEN |
|
3198 if (sa->sa_len == 0) { |
|
3199 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EINVAL); |
|
3200 return (EINVAL); |
|
3201 } |
|
3202 #endif |
|
3203 if (sctp_ifap) { |
|
3204 ifa = sctp_ifap; |
|
3205 } else if (type == SCTP_ADD_IP_ADDRESS) { |
|
3206 /* For an add the address MUST be on the system */ |
|
3207 ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED); |
|
3208 } else if (type == SCTP_DEL_IP_ADDRESS) { |
|
3209 /* For a delete we need to find it in the inp */ |
|
3210 ifa = sctp_find_ifa_in_ep(inp, sa, SCTP_ADDR_NOT_LOCKED); |
|
3211 } else { |
|
3212 ifa = NULL; |
|
3213 } |
|
3214 if (ifa != NULL) { |
|
3215 if (type == SCTP_ADD_IP_ADDRESS) { |
|
3216 sctp_add_local_addr_ep(inp, ifa, type); |
|
3217 } else if (type == SCTP_DEL_IP_ADDRESS) { |
|
3218 if (inp->laddr_count < 2) { |
|
3219 /* can't delete the last local address */ |
|
3220 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EINVAL); |
|
3221 return (EINVAL); |
|
3222 } |
|
3223 LIST_FOREACH(laddr, &inp->sctp_addr_list, |
|
3224 sctp_nxt_addr) { |
|
3225 if (ifa == laddr->ifa) { |
|
3226 /* Mark in the delete */ |
|
3227 laddr->action = type; |
|
3228 } |
|
3229 } |
|
3230 } |
|
3231 if (LIST_EMPTY(&inp->sctp_asoc_list)) { |
|
3232 /* |
|
3233 * There is no need to start the iterator if |
|
3234 * the inp has no associations. |
|
3235 */ |
|
3236 if (type == SCTP_DEL_IP_ADDRESS) { |
|
3237 LIST_FOREACH_SAFE(laddr, &inp->sctp_addr_list, sctp_nxt_addr, nladdr) { |
|
3238 if (laddr->ifa == ifa) { |
|
3239 sctp_del_local_addr_ep(inp, ifa); |
|
3240 } |
|
3241 } |
|
3242 } |
|
3243 } else { |
|
3244 struct sctp_asconf_iterator *asc; |
|
3245 struct sctp_laddr *wi; |
|
3246 |
|
3247 SCTP_MALLOC(asc, struct sctp_asconf_iterator *, |
|
3248 sizeof(struct sctp_asconf_iterator), |
|
3249 SCTP_M_ASC_IT); |
|
3250 if (asc == NULL) { |
|
3251 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, ENOMEM); |
|
3252 return (ENOMEM); |
|
3253 } |
|
3254 wi = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_laddr), struct sctp_laddr); |
|
3255 if (wi == NULL) { |
|
3256 SCTP_FREE(asc, SCTP_M_ASC_IT); |
|
3257 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, ENOMEM); |
|
3258 return (ENOMEM); |
|
3259 } |
|
3260 LIST_INIT(&asc->list_of_work); |
|
3261 asc->cnt = 1; |
|
3262 SCTP_INCR_LADDR_COUNT(); |
|
3263 wi->ifa = ifa; |
|
3264 wi->action = type; |
|
3265 atomic_add_int(&ifa->refcount, 1); |
|
3266 LIST_INSERT_HEAD(&asc->list_of_work, wi, sctp_nxt_addr); |
|
3267 (void)sctp_initiate_iterator(sctp_asconf_iterator_ep, |
|
3268 sctp_asconf_iterator_stcb, |
|
3269 sctp_asconf_iterator_ep_end, |
|
3270 SCTP_PCB_ANY_FLAGS, |
|
3271 SCTP_PCB_ANY_FEATURES, |
|
3272 SCTP_ASOC_ANY_STATE, |
|
3273 (void *)asc, 0, |
|
3274 sctp_asconf_iterator_end, inp, 0); |
|
3275 } |
|
3276 return (0); |
|
3277 } else { |
|
3278 /* invalid address! */ |
|
3279 SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EADDRNOTAVAIL); |
|
3280 return (EADDRNOTAVAIL); |
|
3281 } |
|
3282 } |
|
3283 |
|
3284 void |
|
3285 sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb, |
|
3286 struct sctp_nets *net) |
|
3287 { |
|
3288 struct sctp_asconf_addr *aa; |
|
3289 struct sctp_ifa *sctp_ifap; |
|
3290 struct sctp_asconf_tag_param *vtag; |
|
3291 #ifdef INET |
|
3292 struct sockaddr_in *to; |
|
3293 #endif |
|
3294 #ifdef INET6 |
|
3295 struct sockaddr_in6 *to6; |
|
3296 #endif |
|
3297 if (net == NULL) { |
|
3298 SCTPDBG(SCTP_DEBUG_ASCONF1, "sctp_asconf_send_nat_state_update: Missing net\n"); |
|
3299 return; |
|
3300 } |
|
3301 if (stcb == NULL) { |
|
3302 SCTPDBG(SCTP_DEBUG_ASCONF1, "sctp_asconf_send_nat_state_update: Missing stcb\n"); |
|
3303 return; |
|
3304 } |
|
3305 /* Need to have in the asconf: |
|
3306 * - vtagparam(my_vtag/peer_vtag) |
|
3307 * - add(0.0.0.0) |
|
3308 * - del(0.0.0.0) |
|
3309 * - Any global addresses add(addr) |
|
3310 */ |
|
3311 SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa), |
|
3312 SCTP_M_ASC_ADDR); |
|
3313 if (aa == NULL) { |
|
3314 /* didn't get memory */ |
|
3315 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
3316 "sctp_asconf_send_nat_state_update: failed to get memory!\n"); |
|
3317 return; |
|
3318 } |
|
3319 aa->special_del = 0; |
|
3320 /* fill in asconf address parameter fields */ |
|
3321 /* top level elements are "networked" during send */ |
|
3322 aa->ifa = NULL; |
|
3323 aa->sent = 0; /* clear sent flag */ |
|
3324 vtag = (struct sctp_asconf_tag_param *)&aa->ap.aph; |
|
3325 vtag->aph.ph.param_type = SCTP_NAT_VTAGS; |
|
3326 vtag->aph.ph.param_length = sizeof(struct sctp_asconf_tag_param); |
|
3327 vtag->local_vtag = htonl(stcb->asoc.my_vtag); |
|
3328 vtag->remote_vtag = htonl(stcb->asoc.peer_vtag); |
|
3329 TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next); |
|
3330 |
|
3331 SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa), |
|
3332 SCTP_M_ASC_ADDR); |
|
3333 if (aa == NULL) { |
|
3334 /* didn't get memory */ |
|
3335 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
3336 "sctp_asconf_send_nat_state_update: failed to get memory!\n"); |
|
3337 return; |
|
3338 } |
|
3339 memset(aa, 0, sizeof(struct sctp_asconf_addr)); |
|
3340 /* fill in asconf address parameter fields */ |
|
3341 /* ADD(0.0.0.0) */ |
|
3342 switch (net->ro._l_addr.sa.sa_family) { |
|
3343 #ifdef INET |
|
3344 case AF_INET: |
|
3345 aa->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS; |
|
3346 aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addrv4_param); |
|
3347 aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS; |
|
3348 aa->ap.addrp.ph.param_length = sizeof (struct sctp_ipv4addr_param); |
|
3349 /* No need to add an address, we are using 0.0.0.0 */ |
|
3350 TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next); |
|
3351 break; |
|
3352 #endif |
|
3353 #ifdef INET6 |
|
3354 case AF_INET6: |
|
3355 aa->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS; |
|
3356 aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addr_param); |
|
3357 aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS; |
|
3358 aa->ap.addrp.ph.param_length = sizeof (struct sctp_ipv6addr_param); |
|
3359 /* No need to add an address, we are using 0.0.0.0 */ |
|
3360 TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next); |
|
3361 break; |
|
3362 #endif |
|
3363 } |
|
3364 SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa), |
|
3365 SCTP_M_ASC_ADDR); |
|
3366 if (aa == NULL) { |
|
3367 /* didn't get memory */ |
|
3368 SCTPDBG(SCTP_DEBUG_ASCONF1, |
|
3369 "sctp_asconf_send_nat_state_update: failed to get memory!\n"); |
|
3370 return; |
|
3371 } |
|
3372 memset(aa, 0, sizeof(struct sctp_asconf_addr)); |
|
3373 /* fill in asconf address parameter fields */ |
|
3374 /* ADD(0.0.0.0) */ |
|
3375 switch (net->ro._l_addr.sa.sa_family) { |
|
3376 #ifdef INET |
|
3377 case AF_INET: |
|
3378 aa->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS; |
|
3379 aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addrv4_param); |
|
3380 aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS; |
|
3381 aa->ap.addrp.ph.param_length = sizeof (struct sctp_ipv4addr_param); |
|
3382 /* No need to add an address, we are using 0.0.0.0 */ |
|
3383 TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next); |
|
3384 break; |
|
3385 #endif |
|
3386 #ifdef INET6 |
|
3387 case AF_INET6: |
|
3388 aa->ap.aph.ph.param_type = SCTP_DEL_IP_ADDRESS; |
|
3389 aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addr_param); |
|
3390 aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS; |
|
3391 aa->ap.addrp.ph.param_length = sizeof (struct sctp_ipv6addr_param); |
|
3392 /* No need to add an address, we are using 0.0.0.0 */ |
|
3393 TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next); |
|
3394 break; |
|
3395 #endif |
|
3396 } |
|
3397 /* Now we must hunt the addresses and add all global addresses */ |
|
3398 if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { |
|
3399 struct sctp_vrf *vrf = NULL; |
|
3400 struct sctp_ifn *sctp_ifnp; |
|
3401 uint32_t vrf_id; |
|
3402 |
|
3403 vrf_id = stcb->sctp_ep->def_vrf_id; |
|
3404 vrf = sctp_find_vrf(vrf_id); |
|
3405 if (vrf == NULL) { |
|
3406 goto skip_rest; |
|
3407 } |
|
3408 |
|
3409 SCTP_IPI_ADDR_RLOCK(); |
|
3410 LIST_FOREACH(sctp_ifnp, &vrf->ifnlist, next_ifn) { |
|
3411 LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) { |
|
3412 switch (sctp_ifap->address.sa.sa_family) { |
|
3413 #ifdef INET |
|
3414 case AF_INET: |
|
3415 to = &sctp_ifap->address.sin; |
|
3416 if (IN4_ISPRIVATE_ADDRESS(&to->sin_addr)) { |
|
3417 continue; |
|
3418 } |
|
3419 if (IN4_ISLOOPBACK_ADDRESS(&to->sin_addr)) { |
|
3420 continue; |
|
3421 } |
|
3422 break; |
|
3423 #endif |
|
3424 #ifdef INET6 |
|
3425 case AF_INET6: |
|
3426 to6 = &sctp_ifap->address.sin6; |
|
3427 if (IN6_IS_ADDR_LOOPBACK(&to6->sin6_addr)) { |
|
3428 continue; |
|
3429 } |
|
3430 if (IN6_IS_ADDR_LINKLOCAL(&to6->sin6_addr)) { |
|
3431 continue; |
|
3432 } |
|
3433 break; |
|
3434 #endif |
|
3435 default: |
|
3436 continue; |
|
3437 } |
|
3438 sctp_asconf_queue_mgmt(stcb, sctp_ifap, SCTP_ADD_IP_ADDRESS); |
|
3439 } |
|
3440 } |
|
3441 SCTP_IPI_ADDR_RUNLOCK(); |
|
3442 } else { |
|
3443 struct sctp_laddr *laddr; |
|
3444 |
|
3445 LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) { |
|
3446 if (laddr->ifa == NULL) { |
|
3447 continue; |
|
3448 } |
|
3449 if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED) |
|
3450 /* Address being deleted by the system, dont |
|
3451 * list. |
|
3452 */ |
|
3453 continue; |
|
3454 if (laddr->action == SCTP_DEL_IP_ADDRESS) { |
|
3455 /* Address being deleted on this ep |
|
3456 * don't list. |
|
3457 */ |
|
3458 continue; |
|
3459 } |
|
3460 sctp_ifap = laddr->ifa; |
|
3461 switch (sctp_ifap->address.sa.sa_family) { |
|
3462 #ifdef INET |
|
3463 case AF_INET: |
|
3464 to = &sctp_ifap->address.sin; |
|
3465 if (IN4_ISPRIVATE_ADDRESS(&to->sin_addr)) { |
|
3466 continue; |
|
3467 } |
|
3468 if (IN4_ISLOOPBACK_ADDRESS(&to->sin_addr)) { |
|
3469 continue; |
|
3470 } |
|
3471 break; |
|
3472 #endif |
|
3473 #ifdef INET6 |
|
3474 case AF_INET6: |
|
3475 to6 = &sctp_ifap->address.sin6; |
|
3476 if (IN6_IS_ADDR_LOOPBACK(&to6->sin6_addr)) { |
|
3477 continue; |
|
3478 } |
|
3479 if (IN6_IS_ADDR_LINKLOCAL(&to6->sin6_addr)) { |
|
3480 continue; |
|
3481 } |
|
3482 break; |
|
3483 #endif |
|
3484 default: |
|
3485 continue; |
|
3486 } |
|
3487 sctp_asconf_queue_mgmt(stcb, sctp_ifap, SCTP_ADD_IP_ADDRESS); |
|
3488 } |
|
3489 } |
|
3490 skip_rest: |
|
3491 /* Now we must send the asconf into the queue */ |
|
3492 sctp_send_asconf(stcb, net, SCTP_ADDR_NOT_LOCKED); |
|
3493 } |