]> git.proxmox.com Git - mirror_frr.git/blame - bfdd/bfd_packet.c
bfdd: don't poll to make echo/multiplier changes
[mirror_frr.git] / bfdd / bfd_packet.c
CommitLineData
e9e2c950
RZ
1/*********************************************************************
2 * Copyright 2017 Cumulus Networks, Inc. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the Free
6 * Software Foundation; either version 2 of the License, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; see the file COPYING; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 *
18 * bfd_packet.c: implements the BFD protocol packet handling.
19 *
20 * Authors
21 * -------
22 * Shrijeet Mukherjee [shm@cumulusnetworks.com]
23 * Kanna Rajagopal [kanna@cumulusnetworks.com]
24 * Radhika Mahankali [Radhika@cumulusnetworks.com]
25 */
26
27#include <zebra.h>
28
29#ifdef BFD_LINUX
30#include <linux/if_packet.h>
31#endif /* BFD_LINUX */
32
e9e2c950 33#include <netinet/if_ether.h>
e9e2c950 34#include <netinet/udp.h>
e9e2c950
RZ
35
36#include "lib/sockopt.h"
37
38#include "bfd.h"
39
8a9f760e 40
e9e2c950
RZ
41/*
42 * Prototypes
43 */
e9e2c950 44static int ptm_bfd_process_echo_pkt(int s);
2f11c53f
RZ
45int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data,
46 size_t datalen);
e9e2c950
RZ
47
48static void bfd_sd_reschedule(int sd);
50571b2e
RZ
49ssize_t bfd_recv_ipv4(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl,
50 char *port, size_t portlen, char *vrfname,
51 size_t vrfnamelen, struct sockaddr_any *local,
52 struct sockaddr_any *peer);
53ssize_t bfd_recv_ipv6(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl,
54 char *port, size_t portlen, char *vrfname,
55 size_t vrfnamelen, struct sockaddr_any *local,
56 struct sockaddr_any *peer);
2f11c53f
RZ
57int bp_udp_send(int sd, uint8_t ttl, uint8_t *data, size_t datalen,
58 struct sockaddr *to, socklen_t tolen);
59int bp_bfd_echo_in(int sd, uint8_t *ttl, uint32_t *my_discr);
e9e2c950
RZ
60
61/* socket related prototypes */
62static void bp_set_ipopts(int sd);
63static void bp_bind_ip(int sd, uint16_t port);
64static void bp_set_ipv6opts(int sd);
65static void bp_bind_ipv6(int sd, uint16_t port);
66
67
68/*
69 * Functions
70 */
2f11c53f
RZ
71int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data,
72 size_t datalen)
e9e2c950
RZ
73{
74 struct sockaddr *sa;
75 struct sockaddr_in sin;
76 struct sockaddr_in6 sin6;
e9e2c950
RZ
77 socklen_t slen;
78 ssize_t rv;
79 int sd = -1;
80
2f11c53f 81 if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) {
e9e2c950
RZ
82 memset(&sin6, 0, sizeof(sin6));
83 sin6.sin6_family = AF_INET6;
84 sin6.sin6_addr = bs->shop.peer.sa_sin6.sin6_addr;
85 sin6.sin6_port =
86 (port) ? *port
87 : (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
88 ? htons(BFD_DEF_MHOP_DEST_PORT)
89 : htons(BFD_DEFDESTPORT);
90
91 sd = bs->sock;
92 sa = (struct sockaddr *)&sin6;
93 slen = sizeof(sin6);
94 } else {
95 memset(&sin, 0, sizeof(sin));
96 sin.sin_family = AF_INET;
97 sin.sin_addr = bs->shop.peer.sa_sin.sin_addr;
98 sin.sin_port =
99 (port) ? *port
100 : (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
101 ? htons(BFD_DEF_MHOP_DEST_PORT)
102 : htons(BFD_DEFDESTPORT);
103
104 sd = bs->sock;
105 sa = (struct sockaddr *)&sin;
106 slen = sizeof(sin);
107 }
108
109#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
110 sa->sa_len = slen;
111#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
112 rv = sendto(sd, data, datalen, 0, sa, slen);
113 if (rv <= 0) {
03e7f088 114 log_debug("packet-send: send failure: %s", strerror(errno));
e9e2c950
RZ
115 return -1;
116 }
03e7f088
RZ
117 if (rv < (ssize_t)datalen)
118 log_debug("packet-send: send partial", strerror(errno));
e9e2c950
RZ
119
120 return 0;
121}
122
e9e2c950
RZ
123void ptm_bfd_echo_snd(struct bfd_session *bfd)
124{
2f11c53f
RZ
125 struct sockaddr_any *sa;
126 socklen_t salen;
127 int sd;
128 struct bfd_echo_pkt bep;
129 struct sockaddr_in sin;
130 struct sockaddr_in6 sin6;
e9e2c950 131
2f11c53f 132 if (!BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE))
e9e2c950 133 BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE);
e9e2c950 134
2f11c53f
RZ
135 memset(&bep, 0, sizeof(bep));
136 bep.ver = BFD_ECHO_VERSION;
137 bep.len = BFD_ECHO_PKT_LEN;
138 bep.my_discr = htonl(bfd->discrs.my_discr);
139
140 sa = BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_MH) ? &bfd->mhop.peer
141 : &bfd->shop.peer;
142 if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6)) {
143 sd = bglobal.bg_echov6;
144 sin6 = sa->sa_sin6;
145 sin6.sin6_port = htons(BFD_DEF_ECHO_PORT);
146#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
147 sin6.sin6_len = sizeof(sin6);
148#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
149
150 sa = (struct sockaddr_any *)&sin6;
151 salen = sizeof(sin6);
e9e2c950 152 } else {
2f11c53f
RZ
153 sd = bglobal.bg_echo;
154 sin = sa->sa_sin;
155 sin.sin_port = htons(BFD_DEF_ECHO_PORT);
156#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
157 sin.sin_len = sizeof(sin);
158#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
e9e2c950 159
2f11c53f
RZ
160 sa = (struct sockaddr_any *)&sin;
161 salen = sizeof(sin);
e9e2c950 162 }
2f11c53f
RZ
163 if (bp_udp_send(sd, BFD_TTL_VAL, (uint8_t *)&bep, sizeof(bep),
164 (struct sockaddr *)sa, salen)
165 == -1)
166 return;
e9e2c950
RZ
167
168 bfd->stats.tx_echo_pkt++;
169}
170
e9e2c950
RZ
171static int ptm_bfd_process_echo_pkt(int s)
172{
e9e2c950 173 struct bfd_session *bfd;
2f11c53f
RZ
174 uint32_t my_discr = 0;
175 uint8_t ttl = 0;
e9e2c950 176
2f11c53f
RZ
177 /* Receive and parse echo packet. */
178 if (bp_bfd_echo_in(s, &ttl, &my_discr) == -1)
179 return 0;
e9e2c950
RZ
180
181 /* Your discriminator not zero - use it to find session */
182 bfd = bfd_id_lookup(my_discr);
183 if (bfd == NULL) {
03e7f088 184 log_debug("echo-packet: no matching session (id:%u)", my_discr);
e9e2c950
RZ
185 return -1;
186 }
187
188 if (!BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE)) {
9835f17d
RZ
189 log_debug("echo-packet: echo disabled [%s] (id:%u)",
190 bs_to_string(bfd), my_discr);
e9e2c950
RZ
191 return -1;
192 }
193
194 bfd->stats.rx_echo_pkt++;
195
196 /* Compute detect time */
197 bfd->echo_detect_TO = bfd->remote_detect_mult * bfd->echo_xmt_TO;
198
199 /* Update echo receive timeout. */
451eb5a2
RZ
200 if (bfd->echo_detect_TO > 0)
201 bfd_echo_recvtimer_update(bfd);
e9e2c950
RZ
202
203 return 0;
204}
205
206void ptm_bfd_snd(struct bfd_session *bfd, int fbit)
207{
208 struct bfd_pkt cp;
209
e9e2c950
RZ
210 /* Set fields according to section 6.5.7 */
211 cp.diag = bfd->local_diag;
212 BFD_SETVER(cp.diag, BFD_VERSION);
213 cp.flags = 0;
214 BFD_SETSTATE(cp.flags, bfd->ses_state);
215 BFD_SETDEMANDBIT(cp.flags, BFD_DEF_DEMAND);
0592db96
RZ
216
217 /*
218 * Polling and Final can't be set at the same time.
219 *
220 * RFC 5880, Section 6.5.
221 */
e9e2c950 222 BFD_SETFBIT(cp.flags, fbit);
0592db96
RZ
223 if (fbit == 0)
224 BFD_SETPBIT(cp.flags, bfd->polling);
225
e9e2c950
RZ
226 cp.detect_mult = bfd->detect_mult;
227 cp.len = BFD_PKT_LEN;
228 cp.discrs.my_discr = htonl(bfd->discrs.my_discr);
229 cp.discrs.remote_discr = htonl(bfd->discrs.remote_discr);
230 if (bfd->polling) {
231 cp.timers.desired_min_tx =
232 htonl(bfd->new_timers.desired_min_tx);
233 cp.timers.required_min_rx =
234 htonl(bfd->new_timers.required_min_rx);
235 } else {
236 cp.timers.desired_min_tx = htonl(bfd->timers.desired_min_tx);
237 cp.timers.required_min_rx = htonl(bfd->timers.required_min_rx);
238 }
239 cp.timers.required_min_echo = htonl(bfd->timers.required_min_echo);
240
2f11c53f 241 if (_ptm_bfd_send(bfd, NULL, &cp, BFD_PKT_LEN) != 0)
e9e2c950 242 return;
e9e2c950
RZ
243
244 bfd->stats.tx_ctrl_pkt++;
245}
246
50571b2e
RZ
247ssize_t bfd_recv_ipv4(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl,
248 char *port, size_t portlen, char *vrfname,
249 size_t vrfnamelen, struct sockaddr_any *local,
250 struct sockaddr_any *peer)
e9e2c950 251{
80edb675 252 struct interface *ifp;
e9e2c950
RZ
253 struct cmsghdr *cm;
254 int ifindex;
255 ssize_t mlen;
16084964
RZ
256 struct sockaddr_in msgaddr;
257 struct msghdr msghdr;
258 struct iovec iov[1];
259 uint8_t cmsgbuf[255];
260
e10cfdaf
DL
261 port[0] = '\0';
262
16084964
RZ
263 /* Prepare the recvmsg params. */
264 iov[0].iov_base = msgbuf;
50571b2e 265 iov[0].iov_len = msgbuflen;
16084964
RZ
266
267 memset(&msghdr, 0, sizeof(msghdr));
268 msghdr.msg_name = &msgaddr;
269 msghdr.msg_namelen = sizeof(msgaddr);
270 msghdr.msg_iov = iov;
271 msghdr.msg_iovlen = 1;
272 msghdr.msg_control = cmsgbuf;
273 msghdr.msg_controllen = sizeof(cmsgbuf);
274
e9e2c950
RZ
275 mlen = recvmsg(sd, &msghdr, MSG_DONTWAIT);
276 if (mlen == -1) {
03e7f088
RZ
277 if (errno != EAGAIN)
278 log_error("ipv4-recv: recv failed: %s",
279 strerror(errno));
280
e9e2c950
RZ
281 return -1;
282 }
283
284 /* Get source address */
285 peer->sa_sin = *((struct sockaddr_in *)(msghdr.msg_name));
286
287 /* Get and check TTL */
288 for (cm = CMSG_FIRSTHDR(&msghdr); cm != NULL;
289 cm = CMSG_NXTHDR(&msghdr, cm)) {
290 if (cm->cmsg_level != IPPROTO_IP)
291 continue;
292
293 switch (cm->cmsg_type) {
294#ifdef BFD_LINUX
295 case IP_TTL: {
50571b2e
RZ
296 uint32_t ttlval;
297
298 memcpy(&ttlval, CMSG_DATA(cm), sizeof(ttlval));
299 if (ttlval > 255) {
300 log_debug("ipv4-recv: invalid TTL: %u", ttlval);
e9e2c950
RZ
301 return -1;
302 }
50571b2e 303 *ttl = ttlval;
e9e2c950
RZ
304 break;
305 }
306
307 case IP_PKTINFO: {
308 struct in_pktinfo *pi =
309 (struct in_pktinfo *)CMSG_DATA(cm);
310
311 if (pi == NULL)
312 break;
313
314 local->sa_sin.sin_family = AF_INET;
315 local->sa_sin.sin_addr = pi->ipi_addr;
f43a14d2
RZ
316#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
317 local->sa_sin.sin_len = sizeof(local->sa_sin);
318#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
80edb675
RZ
319
320 ifp = if_lookup_by_index(pi->ipi_ifindex, VRF_DEFAULT);
321 if (ifp == NULL)
322 break;
323
324 if (strlcpy(port, ifp->name, portlen) >= portlen)
325 log_debug(
326 "ipv4-recv: interface name truncated");
e9e2c950
RZ
327 break;
328 }
329#endif /* BFD_LINUX */
330#ifdef BFD_BSD
331 case IP_RECVTTL: {
50571b2e 332 memcpy(ttl, CMSG_DATA(cm), sizeof(*ttl));
e9e2c950
RZ
333 break;
334 }
335
336 case IP_RECVDSTADDR: {
337 struct in_addr ia;
338
339 memcpy(&ia, CMSG_DATA(cm), sizeof(ia));
340 local->sa_sin.sin_family = AF_INET;
341 local->sa_sin.sin_addr = ia;
f43a14d2
RZ
342#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
343 local->sa_sin.sin_len = sizeof(local->sa_sin);
344#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
e9e2c950
RZ
345 break;
346 }
347#endif /* BFD_BSD */
348
349 default:
350 /*
351 * On *BSDs we expect to land here when skipping
352 * the IP_RECVIF header. It will be handled by
353 * getsockopt_ifindex() below.
354 */
355 /* NOTHING */
356 break;
357 }
358 }
359
360 /* OS agnostic way of getting interface name. */
361 if (port[0] == 0) {
362 ifindex = getsockopt_ifindex(AF_INET, &msghdr);
80edb675
RZ
363 if (ifindex <= 0)
364 return mlen;
365
366 ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
367 if (ifp == NULL)
368 return mlen;
369
370 if (strlcpy(port, ifp->name, portlen) >= portlen)
371 log_debug("ipv4-recv: interface name truncated");
e9e2c950
RZ
372 }
373
374 return mlen;
375}
376
50571b2e
RZ
377ssize_t bfd_recv_ipv6(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl,
378 char *port, size_t portlen, char *vrfname,
379 size_t vrfnamelen, struct sockaddr_any *local,
380 struct sockaddr_any *peer)
e9e2c950 381{
80edb675 382 struct interface *ifp;
e9e2c950
RZ
383 struct cmsghdr *cm;
384 struct in6_pktinfo *pi6 = NULL;
43adc702 385 int ifindex = 0;
e9e2c950 386 ssize_t mlen;
6e01e275 387 uint32_t ttlval;
16084964
RZ
388 struct sockaddr_in6 msgaddr6;
389 struct msghdr msghdr6;
390 struct iovec iov[1];
391 uint8_t cmsgbuf6[255];
392
393 /* Prepare the recvmsg params. */
394 iov[0].iov_base = msgbuf;
50571b2e 395 iov[0].iov_len = msgbuflen;
16084964
RZ
396
397 memset(&msghdr6, 0, sizeof(msghdr6));
398 msghdr6.msg_name = &msgaddr6;
399 msghdr6.msg_namelen = sizeof(msgaddr6);
400 msghdr6.msg_iov = iov;
401 msghdr6.msg_iovlen = 1;
402 msghdr6.msg_control = cmsgbuf6;
403 msghdr6.msg_controllen = sizeof(cmsgbuf6);
404
e9e2c950
RZ
405 mlen = recvmsg(sd, &msghdr6, MSG_DONTWAIT);
406 if (mlen == -1) {
03e7f088 407 if (errno != EAGAIN)
6e01e275 408 log_error("ipv6-recv: recv failed: %s",
03e7f088
RZ
409 strerror(errno));
410
e9e2c950
RZ
411 return -1;
412 }
413
414 /* Get source address */
415 peer->sa_sin6 = *((struct sockaddr_in6 *)(msghdr6.msg_name));
416
417 /* Get and check TTL */
418 for (cm = CMSG_FIRSTHDR(&msghdr6); cm != NULL;
419 cm = CMSG_NXTHDR(&msghdr6, cm)) {
420 if (cm->cmsg_level != IPPROTO_IPV6)
421 continue;
422
423 if (cm->cmsg_type == IPV6_HOPLIMIT) {
6e01e275 424 memcpy(&ttlval, CMSG_DATA(cm), sizeof(ttlval));
50571b2e
RZ
425 if (ttlval > 255) {
426 log_debug("ipv6-recv: invalid TTL: %u", ttlval);
e9e2c950
RZ
427 return -1;
428 }
50571b2e
RZ
429
430 *ttl = ttlval;
e9e2c950
RZ
431 } else if (cm->cmsg_type == IPV6_PKTINFO) {
432 pi6 = (struct in6_pktinfo *)CMSG_DATA(cm);
433 if (pi6) {
f43a14d2 434 local->sa_sin6.sin6_family = AF_INET6;
e9e2c950 435 local->sa_sin6.sin6_addr = pi6->ipi6_addr;
f43a14d2
RZ
436#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
437 local->sa_sin6.sin6_len = sizeof(local->sa_sin6);
438#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
80edb675 439
43adc702 440 ifindex = pi6->ipi6_ifindex;
80edb675
RZ
441 ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
442 if (ifp == NULL)
443 break;
444
445 if (strlcpy(port, ifp->name, portlen)
446 >= portlen)
447 log_debug(
448 "ipv6-recv: interface name truncated");
e9e2c950
RZ
449 }
450 }
451 }
452
43adc702
RZ
453 /* Set scope ID for link local addresses. */
454 if (IN6_IS_ADDR_LINKLOCAL(&peer->sa_sin6.sin6_addr))
455 peer->sa_sin6.sin6_scope_id = ifindex;
456 if (IN6_IS_ADDR_LINKLOCAL(&local->sa_sin6.sin6_addr))
457 local->sa_sin6.sin6_scope_id = ifindex;
458
e9e2c950
RZ
459 return mlen;
460}
461
462static void bfd_sd_reschedule(int sd)
463{
464 if (sd == bglobal.bg_shop) {
8529e180 465 THREAD_OFF(bglobal.bg_ev[0]);
e9e2c950
RZ
466 thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_shop,
467 &bglobal.bg_ev[0]);
468 } else if (sd == bglobal.bg_mhop) {
8529e180 469 THREAD_OFF(bglobal.bg_ev[1]);
e9e2c950
RZ
470 thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_mhop,
471 &bglobal.bg_ev[1]);
472 } else if (sd == bglobal.bg_shop6) {
8529e180 473 THREAD_OFF(bglobal.bg_ev[2]);
e9e2c950
RZ
474 thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_shop6,
475 &bglobal.bg_ev[2]);
476 } else if (sd == bglobal.bg_mhop6) {
8529e180 477 THREAD_OFF(bglobal.bg_ev[3]);
e9e2c950
RZ
478 thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_mhop6,
479 &bglobal.bg_ev[3]);
480 } else if (sd == bglobal.bg_echo) {
8529e180 481 THREAD_OFF(bglobal.bg_ev[4]);
e9e2c950
RZ
482 thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_echo,
483 &bglobal.bg_ev[4]);
2f11c53f 484 } else if (sd == bglobal.bg_echov6) {
8529e180 485 THREAD_OFF(bglobal.bg_ev[5]);
2f11c53f
RZ
486 thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_echov6,
487 &bglobal.bg_ev[5]);
e9e2c950
RZ
488 }
489}
490
03e7f088
RZ
491static void cp_debug(bool mhop, struct sockaddr_any *peer,
492 struct sockaddr_any *local, const char *port,
493 const char *vrf, const char *fmt, ...)
494{
495 char buf[512], peerstr[128], localstr[128], portstr[64], vrfstr[64];
496 va_list vl;
497
498 if (peer->sa_sin.sin_family)
499 snprintf(peerstr, sizeof(peerstr), " peer:%s", satostr(peer));
500 else
501 peerstr[0] = 0;
502
503 if (local->sa_sin.sin_family)
504 snprintf(localstr, sizeof(localstr), " local:%s",
505 satostr(local));
506 else
507 localstr[0] = 0;
508
509 if (port[0])
510 snprintf(portstr, sizeof(portstr), " port:%s", port);
511 else
512 portstr[0] = 0;
513
514 if (vrf[0])
515 snprintf(vrfstr, sizeof(vrfstr), " vrf:%s", port);
516 else
517 vrfstr[0] = 0;
518
519 va_start(vl, fmt);
520 vsnprintf(buf, sizeof(buf), fmt, vl);
521 va_end(vl);
522
523 log_debug("control-packet: %s [mhop:%s%s%s%s%s]", buf,
524 mhop ? "yes" : "no", peerstr, localstr, portstr, vrfstr);
525}
526
e9e2c950
RZ
527int bfd_recv_cb(struct thread *t)
528{
529 int sd = THREAD_FD(t);
530 struct bfd_session *bfd;
531 struct bfd_pkt *cp;
8a9f760e 532 bool is_mhop;
e9e2c950 533 ssize_t mlen = 0;
50571b2e 534 uint8_t ttl;
e9e2c950
RZ
535 struct sockaddr_any local, peer;
536 char port[MAXNAMELEN + 1], vrfname[MAXNAMELEN + 1];
50571b2e 537 uint8_t msgbuf[1516];
e9e2c950
RZ
538
539 /* Schedule next read. */
540 bfd_sd_reschedule(sd);
541
03e7f088 542 /* Handle echo packets. */
2f11c53f 543 if (sd == bglobal.bg_echo || sd == bglobal.bg_echov6) {
e9e2c950
RZ
544 ptm_bfd_process_echo_pkt(sd);
545 return 0;
546 }
547
ff98a589
RZ
548 /* Sanitize input/output. */
549 memset(port, 0, sizeof(port));
550 memset(vrfname, 0, sizeof(vrfname));
551 memset(&local, 0, sizeof(local));
552 memset(&peer, 0, sizeof(peer));
553
03e7f088 554 /* Handle control packets. */
8a9f760e 555 is_mhop = false;
e9e2c950
RZ
556 if (sd == bglobal.bg_shop || sd == bglobal.bg_mhop) {
557 is_mhop = sd == bglobal.bg_mhop;
50571b2e
RZ
558 mlen = bfd_recv_ipv4(sd, msgbuf, sizeof(msgbuf), &ttl, port,
559 sizeof(port), vrfname, sizeof(vrfname),
560 &local, &peer);
e9e2c950
RZ
561 } else if (sd == bglobal.bg_shop6 || sd == bglobal.bg_mhop6) {
562 is_mhop = sd == bglobal.bg_mhop6;
50571b2e
RZ
563 mlen = bfd_recv_ipv6(sd, msgbuf, sizeof(msgbuf), &ttl, port,
564 sizeof(port), vrfname, sizeof(vrfname),
565 &local, &peer);
e9e2c950 566 }
e9e2c950
RZ
567
568 /* Implement RFC 5880 6.8.6 */
569 if (mlen < BFD_PKT_LEN) {
03e7f088
RZ
570 cp_debug(is_mhop, &peer, &local, port, vrfname,
571 "too small (%ld bytes)", mlen);
e9e2c950
RZ
572 return 0;
573 }
574
50571b2e
RZ
575 /* Validate packet TTL. */
576 if ((is_mhop == false) && (ttl != BFD_TTL_VAL)) {
577 cp_debug(is_mhop, &peer, &local, port, vrfname,
578 "invalid TTL: %d expected %d", ttl, BFD_TTL_VAL);
579 return 0;
580 }
581
03e7f088
RZ
582 /*
583 * Parse the control header for inconsistencies:
584 * - Invalid version;
585 * - Bad multiplier configuration;
586 * - Short packets;
587 * - Invalid discriminator;
588 */
16084964 589 cp = (struct bfd_pkt *)(msgbuf);
e9e2c950 590 if (BFD_GETVER(cp->diag) != BFD_VERSION) {
03e7f088
RZ
591 cp_debug(is_mhop, &peer, &local, port, vrfname,
592 "bad version %d", BFD_GETVER(cp->diag));
e9e2c950
RZ
593 return 0;
594 }
595
596 if (cp->detect_mult == 0) {
03e7f088
RZ
597 cp_debug(is_mhop, &peer, &local, port, vrfname,
598 "detect multiplier set to zero");
e9e2c950
RZ
599 return 0;
600 }
601
602 if ((cp->len < BFD_PKT_LEN) || (cp->len > mlen)) {
03e7f088 603 cp_debug(is_mhop, &peer, &local, port, vrfname, "too small");
e9e2c950
RZ
604 return 0;
605 }
606
607 if (cp->discrs.my_discr == 0) {
03e7f088
RZ
608 cp_debug(is_mhop, &peer, &local, port, vrfname,
609 "'my discriminator' is zero");
e9e2c950
RZ
610 return 0;
611 }
612
03e7f088 613 /* Find the session that this packet belongs. */
e9e2c950
RZ
614 bfd = ptm_bfd_sess_find(cp, port, &peer, &local, vrfname, is_mhop);
615 if (bfd == NULL) {
03e7f088
RZ
616 cp_debug(is_mhop, &peer, &local, port, vrfname,
617 "no session found");
e9e2c950
RZ
618 return 0;
619 }
620
e9e2c950 621 bfd->stats.rx_ctrl_pkt++;
03e7f088
RZ
622
623 /*
624 * Multi hop: validate packet TTL.
625 * Single hop: set local address that received the packet.
626 */
e9e2c950 627 if (is_mhop) {
6e01e275 628 if ((BFD_TTL_VAL - bfd->mh_ttl) > BFD_TTL_VAL) {
03e7f088
RZ
629 cp_debug(is_mhop, &peer, &local, port, vrfname,
630 "exceeded max hop count (expected %d, got %d)",
6e01e275 631 bfd->mh_ttl, BFD_TTL_VAL);
e9e2c950
RZ
632 return 0;
633 }
634 } else if (bfd->local_ip.sa_sin.sin_family == AF_UNSPEC) {
635 bfd->local_ip = local;
636 }
637
638 /*
639 * If no interface was detected, save the interface where the
640 * packet came in.
641 */
80edb675
RZ
642 if (bfd->ifp == NULL)
643 bfd->ifp = if_lookup_by_name(port, VRF_DEFAULT);
e9e2c950 644
03e7f088 645 /* Log remote discriminator changes. */
e9e2c950 646 if ((bfd->discrs.remote_discr != 0)
03e7f088
RZ
647 && (bfd->discrs.remote_discr != ntohl(cp->discrs.my_discr)))
648 cp_debug(is_mhop, &peer, &local, port, vrfname,
649 "remote discriminator mismatch (expected %d, got %d)",
650 bfd->discrs.remote_discr, ntohl(cp->discrs.my_discr));
e9e2c950
RZ
651
652 bfd->discrs.remote_discr = ntohl(cp->discrs.my_discr);
653
e9e2c950
RZ
654 /* Save remote diagnostics before state switch. */
655 bfd->remote_diag = cp->diag & BFD_DIAGMASK;
656
c0ef9a8a
RZ
657 /* Update remote timers settings. */
658 bfd->remote_timers.desired_min_tx = ntohl(cp->timers.desired_min_tx);
659 bfd->remote_timers.required_min_rx = ntohl(cp->timers.required_min_rx);
660 bfd->remote_timers.required_min_echo =
661 ntohl(cp->timers.required_min_echo);
662 bfd->remote_detect_mult = cp->detect_mult;
663
aef131af
RZ
664 /* State switch from section 6.2. */
665 bs_state_handler(bfd, BFD_GETSTATE(cp->flags));
e9e2c950 666
c0ef9a8a
RZ
667 /* RFC 5880, Section 6.5: handle POLL/FINAL negotiation sequence. */
668 if (bfd->polling && BFD_GETFBIT(cp->flags)) {
669 /* Disable pooling. */
670 bfd->polling = 0;
e9e2c950 671
c0ef9a8a
RZ
672 /* Handle poll finalization. */
673 bs_final_handler(bfd);
674 } else {
675 /* Received a packet, lets update the receive timer. */
676 bfd_recvtimer_update(bfd);
e9e2c950
RZ
677 }
678
c0ef9a8a
RZ
679 /* Handle echo timers changes. */
680 bs_echo_timer_handler(bfd);
e9e2c950
RZ
681
682 /*
c0ef9a8a
RZ
683 * We've received a packet with the POLL bit set, we must send
684 * a control packet back with the FINAL bit set.
685 *
686 * RFC 5880, Section 6.5.
e9e2c950 687 */
c0ef9a8a
RZ
688 if (BFD_GETPBIT(cp->flags))
689 ptm_bfd_snd(bfd, 1);
e9e2c950
RZ
690
691 return 0;
692}
693
2f11c53f
RZ
694/*
695 * bp_bfd_echo_in: proccesses an BFD echo packet. On TTL == BFD_TTL_VAL
696 * the packet is looped back or returns the my discriminator ID along
697 * with the TTL.
698 *
699 * Returns -1 on error or loopback or 0 on success.
700 */
701int bp_bfd_echo_in(int sd, uint8_t *ttl, uint32_t *my_discr)
702{
703 struct bfd_echo_pkt *bep;
704 ssize_t rlen;
705 struct sockaddr_any local, peer;
706 char port[MAXNAMELEN + 1], vrfname[MAXNAMELEN + 1];
707 uint8_t msgbuf[1516];
708
709 if (sd == bglobal.bg_echo)
710 rlen = bfd_recv_ipv4(sd, msgbuf, sizeof(msgbuf), ttl, port,
711 sizeof(port), vrfname, sizeof(vrfname),
712 &local, &peer);
713 else
714 rlen = bfd_recv_ipv6(sd, msgbuf, sizeof(msgbuf), ttl, port,
715 sizeof(port), vrfname, sizeof(vrfname),
716 &local, &peer);
717
718 /* Short packet, better not risk reading it. */
719 if (rlen < (ssize_t)sizeof(*bep)) {
720 cp_debug(false, &peer, &local, port, vrfname,
721 "small echo packet");
722 return -1;
723 }
724
725 /* Test for loopback. */
726 if (*ttl == BFD_TTL_VAL) {
727 bp_udp_send(sd, *ttl - 1, msgbuf, rlen,
728 (struct sockaddr *)&peer,
729 (sd == bglobal.bg_echo) ? sizeof(peer.sa_sin)
730 : sizeof(peer.sa_sin6));
731 return -1;
732 }
733
734 /* Read my discriminator from BFD Echo packet. */
735 bep = (struct bfd_echo_pkt *)msgbuf;
736 *my_discr = ntohl(bep->my_discr);
737 if (*my_discr == 0) {
738 cp_debug(false, &peer, &local, port, vrfname,
739 "invalid echo packet discriminator (zero)");
740 return -1;
741 }
742
743 return 0;
744}
745
746int bp_udp_send(int sd, uint8_t ttl, uint8_t *data, size_t datalen,
747 struct sockaddr *to, socklen_t tolen)
748{
749 struct cmsghdr *cmsg;
750 ssize_t wlen;
751 int ttlval = ttl;
752 bool is_ipv6 = to->sa_family == AF_INET6;
753 struct msghdr msg;
754 struct iovec iov[1];
755 uint8_t msgctl[255];
756
757 /* Prepare message data. */
758 iov[0].iov_base = data;
759 iov[0].iov_len = datalen;
760
761 memset(&msg, 0, sizeof(msg));
762 memset(msgctl, 0, sizeof(msgctl));
763 msg.msg_name = to;
764 msg.msg_namelen = tolen;
765 msg.msg_iov = iov;
766 msg.msg_iovlen = 1;
767
768 /* Prepare the packet TTL information. */
769 if (ttl > 0) {
770 /* Use ancillary data. */
771 msg.msg_control = msgctl;
772 msg.msg_controllen = CMSG_LEN(sizeof(ttlval));
773
774 /* Configure the ancillary data. */
775 cmsg = CMSG_FIRSTHDR(&msg);
776 cmsg->cmsg_len = CMSG_LEN(sizeof(ttlval));
777 if (is_ipv6) {
778 cmsg->cmsg_level = IPPROTO_IPV6;
779 cmsg->cmsg_type = IPV6_HOPLIMIT;
780 } else {
781#if BFD_LINUX
782 cmsg->cmsg_level = IPPROTO_IP;
783 cmsg->cmsg_type = IP_TTL;
784#else
785 /* FreeBSD does not support TTL in ancillary data. */
786 msg.msg_control = NULL;
787 msg.msg_controllen = 0;
788
789 bp_set_ttl(sd, ttl);
790#endif /* BFD_BSD */
791 }
792 memcpy(CMSG_DATA(cmsg), &ttlval, sizeof(ttlval));
793 }
794
795 /* Send echo back. */
796 wlen = sendmsg(sd, &msg, 0);
797 if (wlen <= 0) {
798 log_debug("udp-send: loopback failure: (%d) %s", errno, strerror(errno));
799 return -1;
800 } else if (wlen < (ssize_t)datalen) {
801 log_debug("udp-send: partial send: %ld expected %ld", wlen,
802 datalen);
803 return -1;
804 }
805
806 return 0;
807}
808
e9e2c950
RZ
809
810/*
811 * Sockets creation.
812 */
813
814
815/*
816 * IPv4 sockets
817 */
6e01e275 818int bp_set_ttl(int sd, uint8_t value)
e9e2c950 819{
6e01e275
RZ
820 int ttl = value;
821
822 if (setsockopt(sd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) == -1) {
823 log_warning("set-ttl: setsockopt(IP_TTL, %d): %s", value,
e9e2c950
RZ
824 strerror(errno));
825 return -1;
826 }
827
828 return 0;
829}
830
6e01e275 831int bp_set_tos(int sd, uint8_t value)
e9e2c950 832{
6e01e275
RZ
833 int tos = value;
834
835 if (setsockopt(sd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1) {
836 log_warning("set-tos: setsockopt(IP_TOS, %d): %s", value,
e9e2c950
RZ
837 strerror(errno));
838 return -1;
839 }
840
841 return 0;
842}
843
844static void bp_set_ipopts(int sd)
845{
6e01e275
RZ
846 int rcvttl = BFD_RCV_TTL_VAL;
847
848 if (bp_set_ttl(sd, BFD_TTL_VAL) != 0)
849 log_fatal("set-ipopts: TTL configuration failed");
e9e2c950
RZ
850
851 if (setsockopt(sd, IPPROTO_IP, IP_RECVTTL, &rcvttl, sizeof(rcvttl))
852 == -1)
6e01e275 853 log_fatal("set-ipopts: setsockopt(IP_RECVTTL, %d): %s", rcvttl,
e9e2c950
RZ
854 strerror(errno));
855
856#ifdef BFD_LINUX
857 int pktinfo = BFD_PKT_INFO_VAL;
6e01e275 858
e9e2c950
RZ
859 /* Figure out address and interface to do the peer matching. */
860 if (setsockopt(sd, IPPROTO_IP, IP_PKTINFO, &pktinfo, sizeof(pktinfo))
861 == -1)
6e01e275 862 log_fatal("set-ipopts: setsockopt(IP_PKTINFO, %d): %s", pktinfo,
e9e2c950
RZ
863 strerror(errno));
864#endif /* BFD_LINUX */
865#ifdef BFD_BSD
866 int yes = 1;
867
868 /* Find out our address for peer matching. */
869 if (setsockopt(sd, IPPROTO_IP, IP_RECVDSTADDR, &yes, sizeof(yes)) == -1)
6e01e275 870 log_fatal("set-ipopts: setsockopt(IP_RECVDSTADDR, %d): %s", yes,
e9e2c950
RZ
871 strerror(errno));
872
873 /* Find out interface where the packet came in. */
874 if (setsockopt_ifindex(AF_INET, sd, yes) == -1)
6e01e275 875 log_fatal("set-ipopts: setsockopt_ipv4_ifindex(%d): %s", yes,
e9e2c950
RZ
876 strerror(errno));
877#endif /* BFD_BSD */
878}
879
880static void bp_bind_ip(int sd, uint16_t port)
881{
882 struct sockaddr_in sin;
883
884 memset(&sin, 0, sizeof(sin));
885 sin.sin_family = AF_INET;
886 sin.sin_addr.s_addr = htonl(INADDR_ANY);
887 sin.sin_port = htons(port);
888 if (bind(sd, (struct sockaddr *)&sin, sizeof(sin)) == -1)
6e01e275 889 log_fatal("bind-ip: bind: %s", strerror(errno));
e9e2c950
RZ
890}
891
892int bp_udp_shop(void)
893{
894 int sd;
895
896 sd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC);
897 if (sd == -1)
6e01e275 898 log_fatal("udp-shop: socket: %s", strerror(errno));
e9e2c950
RZ
899
900 bp_set_ipopts(sd);
901 bp_bind_ip(sd, BFD_DEFDESTPORT);
902
903 return sd;
904}
905
906int bp_udp_mhop(void)
907{
908 int sd;
909
910 sd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC);
911 if (sd == -1)
6e01e275 912 log_fatal("udp-mhop: socket: %s", strerror(errno));
e9e2c950
RZ
913
914 bp_set_ipopts(sd);
915 bp_bind_ip(sd, BFD_DEF_MHOP_DEST_PORT);
916
917 return sd;
918}
919
920int bp_peer_socket(struct bfd_peer_cfg *bpc)
921{
922 int sd, pcount;
923 struct sockaddr_in sin;
924 static int srcPort = BFD_SRCPORTINIT;
925
926 sd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC);
03e7f088
RZ
927 if (sd == -1) {
928 log_error("ipv4-new: failed to create socket: %s",
929 strerror(errno));
e9e2c950 930 return -1;
03e7f088 931 }
e9e2c950 932
8a9f760e
RZ
933 /* Set TTL to 255 for all transmitted packets */
934 if (bp_set_ttl(sd, BFD_TTL_VAL) != 0) {
935 close(sd);
936 return -1;
e9e2c950
RZ
937 }
938
939 /* Set TOS to CS6 for all transmitted packets */
6e01e275 940 if (bp_set_tos(sd, BFD_TOS_VAL) != 0) {
e9e2c950
RZ
941 close(sd);
942 return -1;
943 }
944
8a9f760e 945 if (bpc->bpc_has_localif) {
e9e2c950
RZ
946 if (bp_bind_dev(sd, bpc->bpc_localif) != 0) {
947 close(sd);
948 return -1;
949 }
950 } else if (bpc->bpc_mhop && bpc->bpc_has_vrfname) {
951 if (bp_bind_dev(sd, bpc->bpc_vrfname) != 0) {
952 close(sd);
953 return -1;
954 }
955 }
956
957 /* Find an available source port in the proper range */
958 memset(&sin, 0, sizeof(sin));
959 sin = bpc->bpc_local.sa_sin;
960 sin.sin_family = AF_INET;
961#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
962 sin.sin_len = sizeof(sin);
963#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
8a9f760e 964 if (bpc->bpc_mhop)
e9e2c950
RZ
965 sin.sin_addr = bpc->bpc_local.sa_sin.sin_addr;
966 else
967 sin.sin_addr.s_addr = INADDR_ANY;
968
969 pcount = 0;
970 do {
971 if ((++pcount) > (BFD_SRCPORTMAX - BFD_SRCPORTINIT)) {
972 /* Searched all ports, none available */
03e7f088
RZ
973 log_error("ipv4-new: failed to bind port: %s",
974 strerror(errno));
e9e2c950
RZ
975 close(sd);
976 return -1;
977 }
978 if (srcPort >= BFD_SRCPORTMAX)
979 srcPort = BFD_SRCPORTINIT;
980 sin.sin_port = htons(srcPort++);
981 } while (bind(sd, (struct sockaddr *)&sin, sizeof(sin)) < 0);
982
983 return sd;
984}
985
986
987/*
988 * IPv6 sockets
989 */
990
991int bp_peer_socketv6(struct bfd_peer_cfg *bpc)
992{
80edb675
RZ
993 struct interface *ifp;
994 int sd, pcount;
e9e2c950
RZ
995 struct sockaddr_in6 sin6;
996 static int srcPort = BFD_SRCPORTINIT;
997
998 sd = socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC);
03e7f088
RZ
999 if (sd == -1) {
1000 log_error("ipv6-new: failed to create socket: %s",
1001 strerror(errno));
e9e2c950 1002 return -1;
03e7f088 1003 }
e9e2c950 1004
8a9f760e
RZ
1005 /* Set TTL to 255 for all transmitted packets */
1006 if (bp_set_ttlv6(sd, BFD_TTL_VAL) != 0) {
1007 close(sd);
1008 return -1;
e9e2c950
RZ
1009 }
1010
1011 /* Set TOS to CS6 for all transmitted packets */
6e01e275 1012 if (bp_set_tosv6(sd, BFD_TOS_VAL) != 0) {
e9e2c950
RZ
1013 close(sd);
1014 return -1;
1015 }
1016
1017 /* Find an available source port in the proper range */
1018 memset(&sin6, 0, sizeof(sin6));
1019 sin6.sin6_family = AF_INET6;
1020#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
1021 sin6.sin6_len = sizeof(sin6);
1022#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
1023 sin6 = bpc->bpc_local.sa_sin6;
80edb675
RZ
1024 if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr)) {
1025 ifp = if_lookup_by_name(bpc->bpc_localif, VRF_DEFAULT);
1026 sin6.sin6_scope_id =
1027 (ifp != NULL) ? ifp->ifindex : IFINDEX_INTERNAL;
1028 }
e9e2c950
RZ
1029
1030 if (bpc->bpc_has_localif) {
1031 if (bp_bind_dev(sd, bpc->bpc_localif) != 0) {
1032 close(sd);
1033 return -1;
1034 }
1035 } else if (bpc->bpc_mhop && bpc->bpc_has_vrfname) {
1036 if (bp_bind_dev(sd, bpc->bpc_vrfname) != 0) {
1037 close(sd);
1038 return -1;
1039 }
1040 }
1041
1042 pcount = 0;
1043 do {
1044 if ((++pcount) > (BFD_SRCPORTMAX - BFD_SRCPORTINIT)) {
1045 /* Searched all ports, none available */
03e7f088
RZ
1046 log_error("ipv6-new: failed to bind port: %s",
1047 strerror(errno));
e9e2c950
RZ
1048 close(sd);
1049 return -1;
1050 }
1051 if (srcPort >= BFD_SRCPORTMAX)
1052 srcPort = BFD_SRCPORTINIT;
1053 sin6.sin6_port = htons(srcPort++);
1054 } while (bind(sd, (struct sockaddr *)&sin6, sizeof(sin6)) < 0);
1055
1056 return sd;
1057}
1058
6e01e275 1059int bp_set_ttlv6(int sd, uint8_t value)
e9e2c950 1060{
6e01e275
RZ
1061 int ttl = value;
1062
1063 if (setsockopt(sd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl))
e9e2c950 1064 == -1) {
6e01e275
RZ
1065 log_warning("set-ttlv6: setsockopt(IPV6_UNICAST_HOPS, %d): %s",
1066 value, strerror(errno));
e9e2c950
RZ
1067 return -1;
1068 }
1069
1070 return 0;
1071}
1072
6e01e275 1073int bp_set_tosv6(int sd, uint8_t value)
e9e2c950 1074{
6e01e275
RZ
1075 int tos = value;
1076
1077 if (setsockopt(sd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos))
e9e2c950 1078 == -1) {
6e01e275 1079 log_warning("set-tosv6: setsockopt(IPV6_TCLASS, %d): %s", value,
e9e2c950
RZ
1080 strerror(errno));
1081 return -1;
1082 }
1083
1084 return 0;
1085}
1086
1087static void bp_set_ipv6opts(int sd)
1088{
6e01e275
RZ
1089 int ipv6_pktinfo = BFD_IPV6_PKT_INFO_VAL;
1090 int ipv6_only = BFD_IPV6_ONLY_VAL;
e9e2c950 1091
6e01e275
RZ
1092 if (bp_set_ttlv6(sd, BFD_TTL_VAL) == -1)
1093 log_fatal("set-ipv6opts: setsockopt(IPV6_UNICAST_HOPS, %d): %s",
1094 BFD_TTL_VAL, strerror(errno));
e9e2c950 1095
6e01e275
RZ
1096 if (setsockopt_ipv6_hoplimit(sd, BFD_RCV_TTL_VAL) == -1)
1097 log_fatal("set-ipv6opts: setsockopt(IPV6_HOPLIMIT, %d): %s",
1098 BFD_RCV_TTL_VAL, strerror(errno));
e9e2c950
RZ
1099
1100 if (setsockopt_ipv6_pktinfo(sd, ipv6_pktinfo) == -1)
6e01e275
RZ
1101 log_fatal("set-ipv6opts: setsockopt(IPV6_PKTINFO, %d): %s",
1102 ipv6_pktinfo, strerror(errno));
e9e2c950
RZ
1103
1104 if (setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6_only,
1105 sizeof(ipv6_only))
1106 == -1)
6e01e275
RZ
1107 log_fatal("set-ipv6opts: setsockopt(IPV6_V6ONLY, %d): %s",
1108 ipv6_only, strerror(errno));
e9e2c950
RZ
1109}
1110
1111static void bp_bind_ipv6(int sd, uint16_t port)
1112{
1113 struct sockaddr_in6 sin6;
1114
1115 memset(&sin6, 0, sizeof(sin6));
1116 sin6.sin6_family = AF_INET6;
1117 sin6.sin6_addr = in6addr_any;
1118 sin6.sin6_port = htons(port);
1119#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
1120 sin6.sin6_len = sizeof(sin6);
1121#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
1122 if (bind(sd, (struct sockaddr *)&sin6, sizeof(sin6)) == -1)
6e01e275 1123 log_fatal("bind-ipv6: bind: %s", strerror(errno));
e9e2c950
RZ
1124}
1125
1126int bp_udp6_shop(void)
1127{
1128 int sd;
1129
1130 sd = socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC);
1131 if (sd == -1)
6e01e275 1132 log_fatal("udp6-shop: socket: %s", strerror(errno));
e9e2c950
RZ
1133
1134 bp_set_ipv6opts(sd);
1135 bp_bind_ipv6(sd, BFD_DEFDESTPORT);
1136
1137 return sd;
1138}
1139
1140int bp_udp6_mhop(void)
1141{
1142 int sd;
1143
1144 sd = socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC);
1145 if (sd == -1)
6e01e275 1146 log_fatal("udp6-mhop: socket: %s", strerror(errno));
e9e2c950
RZ
1147
1148 bp_set_ipv6opts(sd);
1149 bp_bind_ipv6(sd, BFD_DEF_MHOP_DEST_PORT);
1150
1151 return sd;
1152}
2f11c53f
RZ
1153
1154int bp_echo_socket(void)
1155{
1156 int s;
1157
1158 s = socket(AF_INET, SOCK_DGRAM, 0);
1159 if (s == -1)
1160 log_fatal("echo-socket: socket: %s", strerror(errno));
1161
1162 bp_set_ipopts(s);
1163 bp_bind_ip(s, BFD_DEF_ECHO_PORT);
1164
1165 return s;
1166}
1167
1168int bp_echov6_socket(void)
1169{
1170 int s;
1171
1172 s = socket(AF_INET6, SOCK_DGRAM, 0);
1173 if (s == -1)
1174 log_fatal("echov6-socket: socket: %s", strerror(errno));
1175
1176 bp_set_ipv6opts(s);
1177 bp_bind_ipv6(s, BFD_DEF_ECHO_PORT);
1178
1179 return s;
1180}