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