]> git.ipfire.org Git - thirdparty/bird.git/blame - proto/bfd/packets.c
Finishes add-path.
[thirdparty/bird.git] / proto / bfd / packets.c
CommitLineData
6a8d3f1c
OZ
1/*
2 * BIRD -- Bidirectional Forwarding Detection (BFD)
3 *
4 * Can be freely distributed and used under the terms of the GNU GPL.
5 */
bf139664 6
6a8d3f1c 7#include "bfd.h"
bf139664
OZ
8
9
10struct bfd_ctl_packet
11{
12 u8 vdiag; /* version and diagnostic */
13 u8 flags; /* state and flags */
14 u8 detect_mult;
15 u8 length;
16 u32 snd_id; /* sender ID, aka 'my discriminator' */
17 u32 rcv_id; /* receiver ID, aka 'your discriminator' */
18 u32 des_min_tx_int;
19 u32 req_min_rx_int;
20 u32 req_min_echo_rx_int;
21};
22
0e175f9f
OZ
23#define BFD_BASE_LEN sizeof(struct bfd_ctl_packet)
24#define BFD_MAX_LEN 64
bf139664 25
6a8d3f1c 26static inline u8 bfd_pack_vdiag(u8 version, u8 diag)
bf139664
OZ
27{ return (version << 5) | diag; }
28
6a8d3f1c
OZ
29static inline u8 bfd_pack_flags(u8 state, u8 flags)
30{ return (state << 6) | flags; }
bf139664
OZ
31
32static inline u8 bfd_pkt_get_version(struct bfd_ctl_packet *pkt)
33{ return pkt->vdiag >> 5; }
34
35static inline u8 bfd_pkt_get_diag(struct bfd_ctl_packet *pkt)
36{ return pkt->vdiag && 0x1f; }
37
38
39static inline u8 bfd_pkt_get_state(struct bfd_ctl_packet *pkt)
40{ return pkt->flags >> 6; }
41
42static inline void bfd_pkt_set_state(struct bfd_ctl_packet *pkt, u8 val)
43{ pkt->flags = val << 6; }
44
45
0e175f9f
OZ
46char *
47bfd_format_flags(u8 flags, char *buf)
48{
49 char *bp = buf;
50 if (flags & BFD_FLAGS) *bp++ = ' ';
51 if (flags & BFD_FLAG_POLL) *bp++ = 'P';
52 if (flags & BFD_FLAG_FINAL) *bp++ = 'F';
53 if (flags & BFD_FLAG_CPI) *bp++ = 'C';
54 if (flags & BFD_FLAG_AP) *bp++ = 'A';
55 if (flags & BFD_FLAG_DEMAND) *bp++ = 'D';
56 if (flags & BFD_FLAG_MULTIPOINT) *bp++ = 'M';
57 *bp = 0;
58
59 return buf;
60}
61
bf139664
OZ
62void
63bfd_send_ctl(struct bfd_proto *p, struct bfd_session *s, int final)
64{
1ec52253 65 sock *sk = s->ifa->sk;
6a8d3f1c 66 struct bfd_ctl_packet *pkt = (struct bfd_ctl_packet *) sk->tbuf;
0e175f9f 67 char fb[8];
bf139664
OZ
68
69 pkt->vdiag = bfd_pack_vdiag(1, s->loc_diag);
70 pkt->flags = bfd_pack_flags(s->loc_state, 0);
71 pkt->detect_mult = s->detect_mult;
6a8d3f1c 72 pkt->length = BFD_BASE_LEN;
bf139664
OZ
73 pkt->snd_id = htonl(s->loc_id);
74 pkt->rcv_id = htonl(s->rem_id);
6a8d3f1c
OZ
75 pkt->des_min_tx_int = htonl(s->des_min_tx_new);
76 pkt->req_min_rx_int = htonl(s->req_min_rx_new);
bf139664
OZ
77 pkt->req_min_echo_rx_int = 0;
78
79 if (final)
80 pkt->flags |= BFD_FLAG_FINAL;
81 else if (s->poll_active)
82 pkt->flags |= BFD_FLAG_POLL;
83
6a8d3f1c 84 if (sk->tbuf != sk->tpos)
0e175f9f
OZ
85 log(L_WARN "%s: Old packet overwritten in TX buffer", p->p.name);
86
87 TRACE(D_PACKETS, "Sending CTL to %I [%s%s]", s->addr,
88 bfd_state_names[s->loc_state], bfd_format_flags(pkt->flags, fb));
6a8d3f1c
OZ
89
90 sk_send_to(sk, pkt->length, s->addr, sk->dport);
bf139664
OZ
91}
92
6a8d3f1c
OZ
93#define DROP(DSC,VAL) do { err_dsc = DSC; err_val = VAL; goto drop; } while(0)
94
95static int
96bfd_rx_hook(sock *sk, int len)
bf139664 97{
6a8d3f1c
OZ
98 struct bfd_proto *p = sk->data;
99 struct bfd_ctl_packet *pkt = (struct bfd_ctl_packet *) sk->rbuf;
100 const char *err_dsc = NULL;
101 uint err_val = 0;
0e175f9f
OZ
102 char fb[8];
103
104 if ((sk->sport == BFD_CONTROL_PORT) && (sk->ttl < 255))
105 DROP("wrong TTL", sk->ttl);
bf139664
OZ
106
107 if (len < BFD_BASE_LEN)
108 DROP("too short", len);
109
110 u8 version = bfd_pkt_get_version(pkt);
111 if (version != 1)
112 DROP("version mismatch", version);
113
114 if ((pkt->length < BFD_BASE_LEN) || (pkt->length > len))
115 DROP("length mismatch", pkt->length);
116
117 if (pkt->detect_mult == 0)
118 DROP("invalid detect mult", 0);
119
0e175f9f
OZ
120 if ((pkt->flags & BFD_FLAG_MULTIPOINT) ||
121 ((pkt->flags & BFD_FLAG_POLL) && (pkt->flags & BFD_FLAG_FINAL)))
bf139664
OZ
122 DROP("invalid flags", pkt->flags);
123
124 if (pkt->snd_id == 0)
125 DROP("invalid my discriminator", 0);
126
127 struct bfd_session *s;
128 u32 id = ntohl(pkt->rcv_id);
129
130 if (id)
131 {
132 s = bfd_find_session_by_id(p, id);
133
134 if (!s)
0e175f9f 135 DROP("unknown session id", id);
bf139664
OZ
136 }
137 else
138 {
139 u8 ps = bfd_pkt_get_state(pkt);
140 if (ps > BFD_STATE_DOWN)
141 DROP("invalid init state", ps);
142
6a8d3f1c 143 s = bfd_find_session_by_addr(p, sk->faddr);
bf139664
OZ
144
145 /* FIXME: better session matching and message */
1ec52253 146 if (!s)
6a8d3f1c 147 return 1;
bf139664
OZ
148 }
149
150 /* FIXME: better authentication handling and message */
151 if (pkt->flags & BFD_FLAG_AP)
152 DROP("authentication not supported", 0);
153
154
6a8d3f1c
OZ
155 u32 old_tx_int = s->des_min_tx_int;
156 u32 old_rx_int = s->rem_min_rx_int;
bf139664 157
1ec52253 158 s->rem_id= ntohl(pkt->snd_id);
bf139664 159 s->rem_state = bfd_pkt_get_state(pkt);
6a8d3f1c 160 s->rem_diag = bfd_pkt_get_diag(pkt);
bf139664
OZ
161 s->rem_demand_mode = pkt->flags & BFD_FLAG_DEMAND;
162 s->rem_min_tx_int = ntohl(pkt->des_min_tx_int);
163 s->rem_min_rx_int = ntohl(pkt->req_min_rx_int);
164 s->rem_detect_mult = pkt->detect_mult;
165
0e175f9f
OZ
166 TRACE(D_PACKETS, "CTL received from %I [%s%s]", sk->faddr,
167 bfd_state_names[s->rem_state], bfd_format_flags(pkt->flags, fb));
168
6a8d3f1c 169 bfd_session_process_ctl(s, pkt->flags, old_tx_int, old_rx_int);
bf139664
OZ
170 return 1;
171
172 drop:
0e175f9f 173 log(L_REMOTE "%s: Bad packet from %I - %s (%u)", p->p.name, sk->faddr, err_dsc, err_val);
bf139664
OZ
174 return 1;
175}
176
6a8d3f1c
OZ
177static void
178bfd_err_hook(sock *sk, int err)
179{
180 struct bfd_proto *p = sk->data;
181 log(L_ERR "%s: Socket error: %m", p->p.name, err);
182}
183
bf139664
OZ
184sock *
185bfd_open_rx_sk(struct bfd_proto *p, int multihop)
186{
6a8d3f1c 187 sock *sk = sk_new(p->tpool);
bf139664
OZ
188 sk->type = SK_UDP;
189 sk->sport = !multihop ? BFD_CONTROL_PORT : BFD_MULTI_CTL_PORT;
190 sk->data = p;
191
0e175f9f 192 sk->rbsize = BFD_MAX_LEN;
bf139664
OZ
193 sk->rx_hook = bfd_rx_hook;
194 sk->err_hook = bfd_err_hook;
6a8d3f1c
OZ
195
196 /* TODO: configurable ToS and priority */
197 sk->tos = IP_PREC_INTERNET_CONTROL;
198 sk->priority = sk_priority_control;
199 sk->flags = SKF_THREAD | SKF_LADDR_RX | (!multihop ? SKF_TTL_RX : 0);
200
201#ifdef IPV6
202 sk->flags |= SKF_V6ONLY;
203#endif
bf139664
OZ
204
205 if (sk_open(sk) < 0)
206 goto err;
6a8d3f1c
OZ
207
208 sk_start(sk);
209 return sk;
210
211 err:
212 rfree(sk);
213 return NULL;
bf139664
OZ
214}
215
1ec52253 216sock *
bf139664
OZ
217bfd_open_tx_sk(struct bfd_proto *p, ip_addr local, struct iface *ifa)
218{
6a8d3f1c 219 sock *sk = sk_new(p->tpool);
bf139664
OZ
220 sk->type = SK_UDP;
221 sk->saddr = local;
6a8d3f1c
OZ
222 sk->dport = ifa ? BFD_CONTROL_PORT : BFD_MULTI_CTL_PORT;
223 sk->iface = ifa;
bf139664
OZ
224 sk->data = p;
225
0e175f9f 226 sk->tbsize = BFD_MAX_LEN;
bf139664 227 sk->err_hook = bfd_err_hook;
bf139664 228
6a8d3f1c
OZ
229 /* TODO: configurable ToS, priority and TTL security */
230 sk->tos = IP_PREC_INTERNET_CONTROL;
231 sk->priority = sk_priority_control;
232 sk->ttl = ifa ? 255 : -1;
233 sk->flags = SKF_THREAD;
234
235#ifdef IPV6
236 sk->flags |= SKF_V6ONLY;
237#endif
bf139664
OZ
238
239 if (sk_open(sk) < 0)
240 goto err;
241
6a8d3f1c
OZ
242 sk_start(sk);
243 return sk;
244
245 err:
246 rfree(sk);
247 return NULL;
bf139664 248}