]> git.proxmox.com Git - mirror_frr.git/blame - nhrpd/nhrp_peer.c
nhrpd: Use correct printf format specifier
[mirror_frr.git] / nhrpd / nhrp_peer.c
CommitLineData
2fb975da
TT
1/* NHRP peer functions
2 * Copyright (c) 2014-2015 Timo Teräs
3 *
4 * This file is free software: you may copy, redistribute and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 */
9
b45ac5f5
DL
10#ifdef HAVE_CONFIG_H
11#include "config.h"
12#endif
13
2fb975da
TT
14#include <netinet/if_ether.h>
15
16#include "zebra.h"
17#include "memory.h"
18#include "thread.h"
19#include "hash.h"
20
21#include "nhrpd.h"
22#include "nhrp_protocol.h"
23#include "os.h"
24
bf8d3d6a 25DEFINE_MTYPE_STATIC(NHRPD, NHRP_PEER, "NHRP peer entry");
819dc8bb 26
2fb975da
TT
27struct ipv6hdr {
28 uint8_t priority_version;
29 uint8_t flow_lbl[3];
30 uint16_t payload_len;
31 uint8_t nexthdr;
32 uint8_t hop_limit;
33 struct in6_addr saddr;
34 struct in6_addr daddr;
35};
36
37static void nhrp_packet_debug(struct zbuf *zb, const char *dir);
38
39static void nhrp_peer_check_delete(struct nhrp_peer *p)
40{
41 struct nhrp_interface *nifp = p->ifp->info;
42
43 if (p->ref || notifier_active(&p->notifier_list))
44 return;
45
b6c48481
DS
46 debugf(NHRP_DEBUG_COMMON, "Deleting peer ref:%d remote:%pSU local:%pSU",
47 p->ref, &p->vc->remote.nbma, &p->vc->local.nbma);
ee72f0a0 48
2fb975da 49 THREAD_OFF(p->t_fallback);
bb58f442 50 THREAD_OFF(p->t_timer);
2fb975da
TT
51 hash_release(nifp->peer_hash, p);
52 nhrp_interface_notify_del(p->ifp, &p->ifp_notifier);
53 nhrp_vc_notify_del(p->vc, &p->vc_notifier);
54 XFREE(MTYPE_NHRP_PEER, p);
55}
56
57static int nhrp_peer_notify_up(struct thread *t)
58{
59 struct nhrp_peer *p = THREAD_ARG(t);
60 struct nhrp_vc *vc = p->vc;
61 struct interface *ifp = p->ifp;
62 struct nhrp_interface *nifp = ifp->info;
63
64 p->t_fallback = NULL;
65 if (nifp->enabled && (!nifp->ipsec_profile || vc->ipsec)) {
66 p->online = 1;
67 nhrp_peer_ref(p);
68 notifier_call(&p->notifier_list, NOTIFY_PEER_UP);
69 nhrp_peer_unref(p);
70 }
71
72 return 0;
73}
74
75static void __nhrp_peer_check(struct nhrp_peer *p)
76{
77 struct nhrp_vc *vc = p->vc;
78 struct interface *ifp = p->ifp;
79 struct nhrp_interface *nifp = ifp->info;
80 unsigned online;
81
82 online = nifp->enabled && (!nifp->ipsec_profile || vc->ipsec);
83 if (p->online != online) {
84 THREAD_OFF(p->t_fallback);
85 if (online && notifier_active(&p->notifier_list)) {
86 /* If we requested the IPsec connection, delay
87 * the up notification a bit to allow things
88 * settle down. This allows IKE to install
89 * SPDs and SAs. */
ffa2c898
QY
90 thread_add_timer_msec(master, nhrp_peer_notify_up, p,
91 50, &p->t_fallback);
2fb975da
TT
92 } else {
93 nhrp_peer_ref(p);
94 p->online = online;
95 if (online) {
996c9314
LB
96 notifier_call(&p->notifier_list,
97 NOTIFY_PEER_UP);
2fb975da
TT
98 } else {
99 p->requested = p->fallback_requested = 0;
996c9314
LB
100 notifier_call(&p->notifier_list,
101 NOTIFY_PEER_DOWN);
2fb975da
TT
102 }
103 nhrp_peer_unref(p);
104 }
105 }
106}
107
108static void nhrp_peer_vc_notify(struct notifier_block *n, unsigned long cmd)
109{
110 struct nhrp_peer *p = container_of(n, struct nhrp_peer, vc_notifier);
111
112 switch (cmd) {
113 case NOTIFY_VC_IPSEC_CHANGED:
114 __nhrp_peer_check(p);
115 break;
116 case NOTIFY_VC_IPSEC_UPDATE_NBMA:
117 nhrp_peer_ref(p);
118 notifier_call(&p->notifier_list, NOTIFY_PEER_NBMA_CHANGING);
119 nhrp_peer_unref(p);
120 break;
121 }
122}
123
124static void nhrp_peer_ifp_notify(struct notifier_block *n, unsigned long cmd)
125{
126 struct nhrp_peer *p = container_of(n, struct nhrp_peer, ifp_notifier);
127 struct nhrp_interface *nifp;
128 struct nhrp_vc *vc;
129
130 nhrp_peer_ref(p);
131 switch (cmd) {
132 case NOTIFY_INTERFACE_UP:
133 case NOTIFY_INTERFACE_DOWN:
134 __nhrp_peer_check(p);
135 break;
136 case NOTIFY_INTERFACE_NBMA_CHANGED:
137 /* Source NBMA changed, rebind to new VC */
138 nifp = p->ifp->info;
139 vc = nhrp_vc_get(&nifp->nbma, &p->vc->remote.nbma, 1);
140 if (vc && p->vc != vc) {
141 nhrp_vc_notify_del(p->vc, &p->vc_notifier);
142 p->vc = vc;
996c9314
LB
143 nhrp_vc_notify_add(p->vc, &p->vc_notifier,
144 nhrp_peer_vc_notify);
2fb975da
TT
145 __nhrp_peer_check(p);
146 }
acd738fc 147 /* fallthru */ /* to post config update */
2fb975da
TT
148 case NOTIFY_INTERFACE_ADDRESS_CHANGED:
149 notifier_call(&p->notifier_list, NOTIFY_PEER_IFCONFIG_CHANGED);
150 break;
58ef1668
GG
151 case NOTIFY_INTERFACE_IPSEC_CHANGED:
152 __nhrp_peer_check(p);
153 notifier_call(&p->notifier_list, NOTIFY_PEER_IFCONFIG_CHANGED);
154 break;
2fb975da
TT
155 case NOTIFY_INTERFACE_MTU_CHANGED:
156 notifier_call(&p->notifier_list, NOTIFY_PEER_MTU_CHANGED);
157 break;
158 }
159 nhrp_peer_unref(p);
160}
161
d8b87afe 162static unsigned int nhrp_peer_key(const void *peer_data)
2fb975da 163{
d8b87afe 164 const struct nhrp_peer *p = peer_data;
2fb975da
TT
165 return sockunion_hash(&p->vc->remote.nbma);
166}
167
74df8d6d 168static bool nhrp_peer_cmp(const void *cache_data, const void *key_data)
2fb975da
TT
169{
170 const struct nhrp_peer *a = cache_data;
171 const struct nhrp_peer *b = key_data;
74df8d6d 172
2fb975da
TT
173 return a->ifp == b->ifp && a->vc == b->vc;
174}
175
176static void *nhrp_peer_create(void *data)
177{
178 struct nhrp_peer *p, *key = data;
179
180 p = XMALLOC(MTYPE_NHRP_PEER, sizeof(*p));
0ce1ca80
DS
181
182 *p = (struct nhrp_peer){
183 .ref = 0,
184 .ifp = key->ifp,
185 .vc = key->vc,
611915ae 186 .notifier_list = NOTIFIER_LIST_INITIALIZER(&p->notifier_list),
0ce1ca80
DS
187 };
188 nhrp_vc_notify_add(p->vc, &p->vc_notifier, nhrp_peer_vc_notify);
189 nhrp_interface_notify_add(p->ifp, &p->ifp_notifier,
190 nhrp_peer_ifp_notify);
191
2fb975da
TT
192 return p;
193}
194
ee72f0a0
RD
195static void do_peer_hash_free(struct hash_bucket *hb,
196 void *arg __attribute__((__unused__)))
197{
198 struct nhrp_peer *p = hb->data;
199 nhrp_peer_check_delete(p);
200}
201
202void nhrp_peer_interface_del(struct interface *ifp)
203{
204 struct nhrp_interface *nifp = ifp->info;
205
206 debugf(NHRP_DEBUG_COMMON, "Cleaning up undeleted peer entries (%lu)",
207 nifp->peer_hash ? nifp->peer_hash->count : 0);
208
209 if (nifp->peer_hash) {
210 hash_iterate(nifp->peer_hash, do_peer_hash_free, NULL);
211 assert(nifp->peer_hash->count == 0);
212 hash_free(nifp->peer_hash);
213 }
214}
215
996c9314
LB
216struct nhrp_peer *nhrp_peer_get(struct interface *ifp,
217 const union sockunion *remote_nbma)
2fb975da
TT
218{
219 struct nhrp_interface *nifp = ifp->info;
220 struct nhrp_peer key, *p;
221 struct nhrp_vc *vc;
222
223 if (!nifp->peer_hash) {
996c9314 224 nifp->peer_hash = hash_create(nhrp_peer_key, nhrp_peer_cmp,
8462c0ff 225 "NHRP Peer Hash");
996c9314
LB
226 if (!nifp->peer_hash)
227 return NULL;
2fb975da
TT
228 }
229
230 vc = nhrp_vc_get(&nifp->nbma, remote_nbma, 1);
996c9314
LB
231 if (!vc)
232 return NULL;
2fb975da
TT
233
234 key.ifp = ifp;
235 key.vc = vc;
236
237 p = hash_get(nifp->peer_hash, &key, nhrp_peer_create);
238 nhrp_peer_ref(p);
996c9314
LB
239 if (p->ref == 1)
240 __nhrp_peer_check(p);
2fb975da
TT
241
242 return p;
243}
244
245struct nhrp_peer *nhrp_peer_ref(struct nhrp_peer *p)
246{
996c9314
LB
247 if (p)
248 p->ref++;
2fb975da
TT
249 return p;
250}
251
252void nhrp_peer_unref(struct nhrp_peer *p)
253{
254 if (p) {
255 p->ref--;
256 nhrp_peer_check_delete(p);
257 }
258}
259
260static int nhrp_peer_request_timeout(struct thread *t)
261{
262 struct nhrp_peer *p = THREAD_ARG(t);
263 struct nhrp_vc *vc = p->vc;
264 struct interface *ifp = p->ifp;
265 struct nhrp_interface *nifp = ifp->info;
266
267 p->t_fallback = NULL;
268
269 if (p->online)
270 return 0;
271
996c9314
LB
272 if (nifp->ipsec_fallback_profile && !p->prio
273 && !p->fallback_requested) {
2fb975da 274 p->fallback_requested = 1;
996c9314
LB
275 vici_request_vc(nifp->ipsec_fallback_profile, &vc->local.nbma,
276 &vc->remote.nbma, p->prio);
ffa2c898
QY
277 thread_add_timer(master, nhrp_peer_request_timeout, p, 30,
278 &p->t_fallback);
2fb975da
TT
279 } else {
280 p->requested = p->fallback_requested = 0;
281 }
282
283 return 0;
284}
285
bb58f442
GG
286static int nhrp_peer_defer_vici_request(struct thread *t)
287{
288 struct nhrp_peer *p = THREAD_ARG(t);
289 struct nhrp_vc *vc = p->vc;
290 struct interface *ifp = p->ifp;
291 struct nhrp_interface *nifp = ifp->info;
00683a14 292
bb58f442
GG
293 THREAD_OFF(p->t_timer);
294
611915ae
AL
295 if (p->online) {
296 debugf(NHRP_DEBUG_COMMON,
6baf035c 297 "IPsec connection to %pSU already established",
4ddc702a 298 &vc->remote.nbma);
611915ae
AL
299 } else {
300 vici_request_vc(nifp->ipsec_profile, &vc->local.nbma,
301 &vc->remote.nbma, p->prio);
302 thread_add_timer(
303 master, nhrp_peer_request_timeout, p,
304 (nifp->ipsec_fallback_profile && !p->prio) ? 15 : 30,
305 &p->t_fallback);
bb58f442
GG
306 }
307 return 0;
308}
309
2fb975da
TT
310int nhrp_peer_check(struct nhrp_peer *p, int establish)
311{
312 struct nhrp_vc *vc = p->vc;
313 struct interface *ifp = p->ifp;
314 struct nhrp_interface *nifp = ifp->info;
315
316 if (p->online)
317 return 1;
318 if (!establish)
319 return 0;
320 if (p->requested)
321 return 0;
8ec0c3c1
TT
322 if (!nifp->ipsec_profile)
323 return 0;
2fb975da
TT
324 if (sockunion_family(&vc->local.nbma) == AF_UNSPEC)
325 return 0;
6c9ca587
GG
326 if (vc->ipsec)
327 return 1;
2fb975da
TT
328
329 p->prio = establish > 1;
330 p->requested = 1;
bb58f442 331
611915ae
AL
332 /* All NHRP registration requests are prioritized */
333 if (p->prio) {
334 vici_request_vc(nifp->ipsec_profile, &vc->local.nbma,
335 &vc->remote.nbma, p->prio);
336 thread_add_timer(
337 master, nhrp_peer_request_timeout, p,
338 (nifp->ipsec_fallback_profile && !p->prio) ? 15 : 30,
339 &p->t_fallback);
340 } else {
00683a14
RD
341 /* Maximum timeout is 1 second */
342 int r_time_ms = rand() % 1000;
343
611915ae 344 debugf(NHRP_DEBUG_COMMON,
6baf035c 345 "Initiating IPsec connection request to %pSU after %d ms:",
4ddc702a 346 &vc->remote.nbma, r_time_ms);
611915ae
AL
347 thread_add_timer_msec(master, nhrp_peer_defer_vici_request,
348 p, r_time_ms, &p->t_timer);
bb58f442 349 }
2fb975da
TT
350
351 return 0;
352}
353
996c9314
LB
354void nhrp_peer_notify_add(struct nhrp_peer *p, struct notifier_block *n,
355 notifier_fn_t fn)
2fb975da
TT
356{
357 notifier_add(n, &p->notifier_list, fn);
358}
359
360void nhrp_peer_notify_del(struct nhrp_peer *p, struct notifier_block *n)
361{
362 notifier_del(n);
363 nhrp_peer_check_delete(p);
364}
365
366void nhrp_peer_send(struct nhrp_peer *p, struct zbuf *zb)
367{
2fb975da
TT
368 nhrp_packet_debug(zb, "Send");
369
370 if (!p->online)
371 return;
372
b6c48481
DS
373 debugf(NHRP_DEBUG_KERNEL, "PACKET: Send %pSU -> %pSU",
374 &p->vc->local.nbma, &p->vc->remote.nbma);
2fb975da 375
996c9314
LB
376 os_sendmsg(zb->head, zbuf_used(zb), p->ifp->ifindex,
377 sockunion_get_addr(&p->vc->remote.nbma),
fa31fcf2
AL
378 sockunion_get_addrlen(&p->vc->remote.nbma),
379 ETH_P_NHRP);
2fb975da
TT
380 zbuf_reset(zb);
381}
382
611915ae
AL
383static void nhrp_process_nat_extension(struct nhrp_packet_parser *pp,
384 union sockunion *proto,
385 union sockunion *cie_nbma)
bb58f442 386{
bb58f442
GG
387 union sockunion cie_proto;
388 struct zbuf payload;
389 struct nhrp_extension_header *ext;
390 struct zbuf *extensions;
391
9025515c 392 if (!cie_nbma)
bb58f442
GG
393 return;
394
395 sockunion_family(cie_nbma) = AF_UNSPEC;
396
9025515c
RD
397 if (!proto || sockunion_family(proto) == AF_UNSPEC)
398 return;
399
bb58f442
GG
400 /* Handle extensions */
401 extensions = zbuf_alloc(zbuf_used(&pp->extensions));
611915ae
AL
402 if (extensions) {
403 zbuf_copy_peek(extensions, &pp->extensions,
404 zbuf_used(&pp->extensions));
bb58f442 405 while ((ext = nhrp_ext_pull(extensions, &payload)) != NULL) {
611915ae
AL
406 switch (htons(ext->type)
407 & ~NHRP_EXTENSION_FLAG_COMPULSORY) {
bb58f442 408 case NHRP_EXTENSION_NAT_ADDRESS:
611915ae
AL
409 /* Process the NBMA and proto address in NAT
410 * extension and update the cache without which
411 * the neighbor table in the kernel contains the
412 * source NBMA address which is not reachable
00683a14
RD
413 * since it is behind a NAT device
414 */
611915ae 415 debugf(NHRP_DEBUG_COMMON,
0551aead 416 "shortcut res_resp: Processing NAT Extension for %pSU",
4ddc702a 417 proto);
611915ae
AL
418 while (nhrp_cie_pull(&payload, pp->hdr,
419 cie_nbma, &cie_proto)) {
420 if (sockunion_family(&cie_proto)
421 == AF_UNSPEC)
bb58f442
GG
422 continue;
423
611915ae
AL
424 if (!sockunion_cmp(proto, &cie_proto)) {
425 debugf(NHRP_DEBUG_COMMON,
0551aead 426 "\tcie_nbma for proto %pSU is %pSU",
4ddc702a 427 proto, cie_nbma);
bb58f442
GG
428 break;
429 }
430 }
431 }
432 }
433 zbuf_free(extensions);
434 }
435}
436
47d40757 437static void nhrp_handle_resolution_req(struct nhrp_packet_parser *pp)
2fb975da 438{
47d40757 439 struct interface *ifp = pp->ifp;
2fb975da
TT
440 struct zbuf *zb, payload;
441 struct nhrp_packet_header *hdr;
442 struct nhrp_cie_header *cie;
443 struct nhrp_extension_header *ext;
47d40757 444 struct nhrp_cache *c;
611915ae
AL
445 union sockunion cie_nbma, cie_nbma_nat, cie_proto, *proto_addr,
446 *nbma_addr, *claimed_nbma_addr;
47d40757
GN
447 int holdtime, prefix_len, hostprefix_len;
448 struct nhrp_interface *nifp = ifp->info;
2fb975da 449 struct nhrp_peer *peer;
47d40757 450 size_t paylen;
2fb975da 451
47d40757 452 if (!(pp->if_ad->flags & NHRP_IFF_SHORTCUT)) {
2fb975da
TT
453 debugf(NHRP_DEBUG_COMMON, "Shortcuts disabled");
454 /* FIXME: Send error indication? */
455 return;
456 }
457
47d40757
GN
458 if (pp->if_ad->network_id && pp->route_type == NHRP_ROUTE_OFF_NBMA
459 && pp->route_prefix.prefixlen < 8) {
996c9314
LB
460 debugf(NHRP_DEBUG_COMMON,
461 "Shortcut to more generic than /8 dropped");
2fb975da
TT
462 return;
463 }
464
465 debugf(NHRP_DEBUG_COMMON, "Parsing and replying to Resolution Req");
466
47d40757 467 if (nhrp_route_address(ifp, &pp->src_proto, NULL, &peer)
996c9314 468 != NHRP_ROUTE_NBMA_NEXTHOP)
2fb975da
TT
469 return;
470
47d40757
GN
471 /* Copy payload CIE */
472 hostprefix_len = 8 * sockunion_get_addrlen(&pp->if_ad->addr);
473 paylen = zbuf_used(&pp->payload);
474 debugf(NHRP_DEBUG_COMMON, "shortcut res_rep: paylen %zu", paylen);
475
476 while ((cie = nhrp_cie_pull(&pp->payload, pp->hdr, &cie_nbma,
477 &cie_proto))
478 != NULL) {
479 prefix_len = cie->prefix_length;
480 debugf(NHRP_DEBUG_COMMON,
5f36c26c 481 "shortcut res_rep: parsing CIE with prefixlen=%u",
47d40757
GN
482 prefix_len);
483 if (prefix_len == 0 || prefix_len >= hostprefix_len)
484 prefix_len = hostprefix_len;
485
486 if (prefix_len != hostprefix_len
487 && !(pp->hdr->flags
488 & htons(NHRP_FLAG_REGISTRATION_UNIQUE))) {
489 cie->code = NHRP_CODE_BINDING_NON_UNIQUE;
490 continue;
491 }
492
493 /* We currently support only unique prefix registrations */
494 if (prefix_len != hostprefix_len) {
495 cie->code = NHRP_CODE_ADMINISTRATIVELY_PROHIBITED;
496 continue;
497 }
498
499 proto_addr = (sockunion_family(&cie_proto) == AF_UNSPEC)
500 ? &pp->src_proto
501 : &cie_proto;
bb58f442 502
00683a14 503 /* Check for this proto_addr in NHRP_NAT_EXTENSION */
bb58f442
GG
504 nhrp_process_nat_extension(pp, proto_addr, &cie_nbma_nat);
505
611915ae
AL
506 if (sockunion_family(&cie_nbma_nat) == AF_UNSPEC) {
507 /* It may be possible that this resolution reply is
508 * coming directly from NATTED Spoke and there is not
00683a14
RD
509 * NAT Extension present
510 */
d0c9d09a
RD
511 debugf(NHRP_DEBUG_COMMON,
512 "shortcut res_rep: No NAT Extension for %pSU",
4ddc702a 513 proto_addr);
611915ae
AL
514
515 if (!sockunion_same(&pp->src_nbma,
516 &pp->peer->vc->remote.nbma)
517 && !nhrp_nhs_match_ip(&pp->peer->vc->remote.nbma,
518 nifp)) {
bb58f442 519 cie_nbma_nat = pp->peer->vc->remote.nbma;
611915ae 520 debugf(NHRP_DEBUG_COMMON,
0551aead 521 "shortcut res_rep: NAT detected using %pSU as cie_nbma",
4ddc702a 522 &cie_nbma_nat);
bb58f442
GG
523 }
524 }
525
611915ae 526 if (sockunion_family(&cie_nbma_nat) != AF_UNSPEC)
bb58f442 527 nbma_addr = &cie_nbma_nat;
611915ae 528 else if (sockunion_family(&cie_nbma) != AF_UNSPEC)
bb58f442
GG
529 nbma_addr = &cie_nbma;
530 else
531 nbma_addr = &pp->src_nbma;
47d40757 532
611915ae 533 if (sockunion_family(&cie_nbma) != AF_UNSPEC)
85365e51
AL
534 claimed_nbma_addr = &cie_nbma;
535 else
536 claimed_nbma_addr = &pp->src_nbma;
47d40757
GN
537
538 holdtime = htons(cie->holding_time);
539 debugf(NHRP_DEBUG_COMMON,
5f36c26c 540 "shortcut res_rep: holdtime is %u (if 0, using %u)",
47d40757
GN
541 holdtime, pp->if_ad->holdtime);
542 if (!holdtime)
543 holdtime = pp->if_ad->holdtime;
544
545 c = nhrp_cache_get(ifp, proto_addr, 1);
546 if (!c) {
547 debugf(NHRP_DEBUG_COMMON,
5f36c26c 548 "shortcut res_rep: no cache found");
47d40757
GN
549 cie->code = NHRP_CODE_INSUFFICIENT_RESOURCES;
550 continue;
551 }
47d40757
GN
552
553 debugf(NHRP_DEBUG_COMMON,
4ddc702a
RD
554 "shortcut res_rep: updating binding for nmba addr %pSU",
555 nbma_addr);
611915ae
AL
556 if (!nhrp_cache_update_binding(
557 c, NHRP_CACHE_DYNAMIC, holdtime,
558 nhrp_peer_get(pp->ifp, nbma_addr), htons(cie->mtu),
559 nbma_addr, claimed_nbma_addr)) {
47d40757
GN
560 cie->code = NHRP_CODE_ADMINISTRATIVELY_PROHIBITED;
561 continue;
562 }
2fb975da 563
47d40757
GN
564 cie->code = NHRP_CODE_SUCCESS;
565 }
2fb975da
TT
566
567 /* Create reply */
568 zb = zbuf_alloc(1500);
47d40757
GN
569 hdr = nhrp_packet_push(zb, NHRP_PACKET_RESOLUTION_REPLY, &pp->src_nbma,
570 &pp->src_proto, &pp->dst_proto);
2fb975da
TT
571
572 /* Copied information from request */
47d40757
GN
573 hdr->flags = pp->hdr->flags
574 & htons(NHRP_FLAG_RESOLUTION_SOURCE_IS_ROUTER
575 | NHRP_FLAG_RESOLUTION_SOURCE_STABLE);
996c9314
LB
576 hdr->flags |= htons(NHRP_FLAG_RESOLUTION_DESTINATION_STABLE
577 | NHRP_FLAG_RESOLUTION_AUTHORATIVE);
47d40757 578 hdr->u.request_id = pp->hdr->u.request_id;
2fb975da 579
47d40757 580 /* CIE payload for the reply packet */
996c9314 581 cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &nifp->nbma,
47d40757
GN
582 &pp->if_ad->addr);
583 cie->holding_time = htons(pp->if_ad->holdtime);
584 cie->mtu = htons(pp->if_ad->mtu);
585 if (pp->if_ad->network_id && pp->route_type == NHRP_ROUTE_OFF_NBMA)
586 cie->prefix_length = pp->route_prefix.prefixlen;
2fb975da 587 else
47d40757
GN
588 cie->prefix_length =
589 8 * sockunion_get_addrlen(&pp->if_ad->addr);
2fb975da
TT
590
591 /* Handle extensions */
47d40757 592 while ((ext = nhrp_ext_pull(&pp->extensions, &payload)) != NULL) {
2fb975da
TT
593 switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) {
594 case NHRP_EXTENSION_NAT_ADDRESS:
996c9314
LB
595 ext = nhrp_ext_push(zb, hdr,
596 NHRP_EXTENSION_NAT_ADDRESS);
597 if (!ext)
598 goto err;
5e70e83b
AL
599 if (sockunion_family(&nifp->nat_nbma) != AF_UNSPEC) {
600 cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS,
611915ae
AL
601 &nifp->nat_nbma,
602 &pp->if_ad->addr);
5e70e83b
AL
603 if (!cie)
604 goto err;
e8089de1
AL
605 cie->prefix_length =
606 8 * sockunion_get_addrlen(
607 &pp->if_ad->addr);
608
5e70e83b
AL
609 cie->mtu = htons(pp->if_ad->mtu);
610 nhrp_ext_complete(zb, ext);
611 }
2fb975da
TT
612 break;
613 default:
47d40757 614 if (nhrp_ext_reply(zb, hdr, ifp, ext, &payload) < 0)
2fb975da
TT
615 goto err;
616 break;
617 }
618 }
2fb975da
TT
619 nhrp_packet_complete(zb, hdr);
620 nhrp_peer_send(peer, zb);
621err:
622 nhrp_peer_unref(peer);
623 zbuf_free(zb);
624}
625
626static void nhrp_handle_registration_request(struct nhrp_packet_parser *p)
627{
628 struct interface *ifp = p->ifp;
629 struct zbuf *zb, payload;
630 struct nhrp_packet_header *hdr;
631 struct nhrp_cie_header *cie;
632 struct nhrp_extension_header *ext;
633 struct nhrp_cache *c;
996c9314
LB
634 union sockunion cie_nbma, cie_proto, *proto_addr, *nbma_addr,
635 *nbma_natoa;
55fd6ee9 636 int holdtime, prefix_len, hostprefix_len, natted = 0;
2fb975da
TT
637 size_t paylen;
638 void *pay;
639
640 debugf(NHRP_DEBUG_COMMON, "Parsing and replying to Registration Req");
55fd6ee9 641 hostprefix_len = 8 * sockunion_get_addrlen(&p->if_ad->addr);
2fb975da
TT
642
643 if (!sockunion_same(&p->src_nbma, &p->peer->vc->remote.nbma))
644 natted = 1;
645
646 /* Create reply */
647 zb = zbuf_alloc(1500);
996c9314
LB
648 hdr = nhrp_packet_push(zb, NHRP_PACKET_REGISTRATION_REPLY, &p->src_nbma,
649 &p->src_proto, &p->if_ad->addr);
2fb975da
TT
650
651 /* Copied information from request */
996c9314
LB
652 hdr->flags = p->hdr->flags & htons(NHRP_FLAG_REGISTRATION_UNIQUE
653 | NHRP_FLAG_REGISTRATION_NAT);
2fb975da
TT
654 hdr->u.request_id = p->hdr->u.request_id;
655
656 /* Copy payload CIEs */
657 paylen = zbuf_used(&p->payload);
658 pay = zbuf_pushn(zb, paylen);
996c9314
LB
659 if (!pay)
660 goto err;
2fb975da
TT
661 memcpy(pay, zbuf_pulln(&p->payload, paylen), paylen);
662 zbuf_init(&payload, pay, paylen, paylen);
663
996c9314
LB
664 while ((cie = nhrp_cie_pull(&payload, hdr, &cie_nbma, &cie_proto))
665 != NULL) {
55fd6ee9
TT
666 prefix_len = cie->prefix_length;
667 if (prefix_len == 0 || prefix_len >= hostprefix_len)
668 prefix_len = hostprefix_len;
669
996c9314
LB
670 if (prefix_len != hostprefix_len
671 && !(p->hdr->flags
672 & htons(NHRP_FLAG_REGISTRATION_UNIQUE))) {
2fb975da
TT
673 cie->code = NHRP_CODE_BINDING_NON_UNIQUE;
674 continue;
675 }
676
677 /* We currently support only unique prefix registrations */
55fd6ee9 678 if (prefix_len != hostprefix_len) {
2fb975da
TT
679 cie->code = NHRP_CODE_ADMINISTRATIVELY_PROHIBITED;
680 continue;
681 }
682
996c9314
LB
683 proto_addr = (sockunion_family(&cie_proto) == AF_UNSPEC)
684 ? &p->src_proto
685 : &cie_proto;
686 nbma_addr = (sockunion_family(&cie_nbma) == AF_UNSPEC)
687 ? &p->src_nbma
688 : &cie_nbma;
2fb975da
TT
689 nbma_natoa = NULL;
690 if (natted) {
611915ae
AL
691 nbma_natoa =
692 (sockunion_family(&p->peer->vc->remote.nbma)
693 == AF_UNSPEC)
694 ? nbma_addr
695 : &p->peer->vc->remote.nbma;
2fb975da
TT
696 }
697
698 holdtime = htons(cie->holding_time);
996c9314
LB
699 if (!holdtime)
700 holdtime = p->if_ad->holdtime;
2fb975da
TT
701
702 c = nhrp_cache_get(ifp, proto_addr, 1);
703 if (!c) {
704 cie->code = NHRP_CODE_INSUFFICIENT_RESOURCES;
705 continue;
706 }
707
996c9314
LB
708 if (!nhrp_cache_update_binding(c, NHRP_CACHE_DYNAMIC, holdtime,
709 nhrp_peer_ref(p->peer),
611915ae
AL
710 htons(cie->mtu), nbma_natoa,
711 nbma_addr)) {
2fb975da
TT
712 cie->code = NHRP_CODE_ADMINISTRATIVELY_PROHIBITED;
713 continue;
714 }
715
716 cie->code = NHRP_CODE_SUCCESS;
717 }
718
719 /* Handle extensions */
720 while ((ext = nhrp_ext_pull(&p->extensions, &payload)) != NULL) {
721 switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) {
722 case NHRP_EXTENSION_NAT_ADDRESS:
996c9314
LB
723 ext = nhrp_ext_push(zb, hdr,
724 NHRP_EXTENSION_NAT_ADDRESS);
725 if (!ext)
726 goto err;
2fb975da
TT
727 zbuf_copy(zb, &payload, zbuf_used(&payload));
728 if (natted) {
1e52c954 729 cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS,
611915ae
AL
730 &p->peer->vc->remote.nbma,
731 &p->src_proto);
732 cie->prefix_length =
733 8 * sockunion_get_addrlen(
734 &p->if_ad->addr);
1e52c954 735 cie->mtu = htons(p->if_ad->mtu);
2fb975da
TT
736 }
737 nhrp_ext_complete(zb, ext);
738 break;
739 default:
740 if (nhrp_ext_reply(zb, hdr, ifp, ext, &payload) < 0)
741 goto err;
742 break;
743 }
744 }
745
746 nhrp_packet_complete(zb, hdr);
747 nhrp_peer_send(p->peer, zb);
748err:
749 zbuf_free(zb);
750}
751
996c9314
LB
752static int parse_ether_packet(struct zbuf *zb, uint16_t protocol_type,
753 union sockunion *src, union sockunion *dst)
2fb975da
TT
754{
755 switch (protocol_type) {
756 case ETH_P_IP: {
996c9314
LB
757 struct iphdr *iph = zbuf_pull(zb, struct iphdr);
758 if (iph) {
759 if (src)
760 sockunion_set(src, AF_INET,
761 (uint8_t *)&iph->saddr,
762 sizeof(iph->saddr));
763 if (dst)
764 sockunion_set(dst, AF_INET,
765 (uint8_t *)&iph->daddr,
766 sizeof(iph->daddr));
2fb975da 767 }
996c9314 768 } break;
2fb975da 769 case ETH_P_IPV6: {
996c9314
LB
770 struct ipv6hdr *iph = zbuf_pull(zb, struct ipv6hdr);
771 if (iph) {
772 if (src)
773 sockunion_set(src, AF_INET6,
774 (uint8_t *)&iph->saddr,
775 sizeof(iph->saddr));
776 if (dst)
777 sockunion_set(dst, AF_INET6,
778 (uint8_t *)&iph->daddr,
779 sizeof(iph->daddr));
2fb975da 780 }
996c9314 781 } break;
2fb975da
TT
782 default:
783 return 0;
784 }
785 return 1;
786}
787
996c9314
LB
788void nhrp_peer_send_indication(struct interface *ifp, uint16_t protocol_type,
789 struct zbuf *pkt)
2fb975da
TT
790{
791 union sockunion dst;
792 struct zbuf *zb, payload;
793 struct nhrp_interface *nifp = ifp->info;
794 struct nhrp_afi_data *if_ad;
795 struct nhrp_packet_header *hdr;
796 struct nhrp_peer *p;
2fb975da 797
996c9314
LB
798 if (!nifp->enabled)
799 return;
2fb975da
TT
800
801 payload = *pkt;
802 if (!parse_ether_packet(&payload, protocol_type, &dst, NULL))
803 return;
804
805 if (nhrp_route_address(ifp, &dst, NULL, &p) != NHRP_ROUTE_NBMA_NEXTHOP)
806 return;
807
808 if_ad = &nifp->afi[family2afi(sockunion_family(&dst))];
809 if (!(if_ad->flags & NHRP_IFF_REDIRECT)) {
996c9314 810 debugf(NHRP_DEBUG_COMMON,
b6c48481
DS
811 "Send Traffic Indication to %pSU about packet to %pSU ignored",
812 &p->vc->remote.nbma, &dst);
2fb975da
TT
813 return;
814 }
815
996c9314 816 debugf(NHRP_DEBUG_COMMON,
b6c48481
DS
817 "Send Traffic Indication to %pSU (online=%d) about packet to %pSU",
818 &p->vc->remote.nbma, p->online, &dst);
2fb975da
TT
819
820 /* Create reply */
821 zb = zbuf_alloc(1500);
996c9314
LB
822 hdr = nhrp_packet_push(zb, NHRP_PACKET_TRAFFIC_INDICATION, &nifp->nbma,
823 &if_ad->addr, &dst);
6f8817b4 824 hdr->hop_count = 1;
2fb975da
TT
825
826 /* Payload is the packet causing indication */
827 zbuf_copy(zb, pkt, zbuf_used(pkt));
828 nhrp_packet_complete(zb, hdr);
829 nhrp_peer_send(p, zb);
830 nhrp_peer_unref(p);
831 zbuf_free(zb);
832}
833
834static void nhrp_handle_error_ind(struct nhrp_packet_parser *pp)
835{
836 struct zbuf origmsg = pp->payload;
837 struct nhrp_packet_header *hdr;
838 struct nhrp_reqid *reqid;
839 union sockunion src_nbma, src_proto, dst_proto;
2fb975da
TT
840
841 hdr = nhrp_packet_pull(&origmsg, &src_nbma, &src_proto, &dst_proto);
996c9314
LB
842 if (!hdr)
843 return;
2fb975da 844
996c9314 845 debugf(NHRP_DEBUG_COMMON,
b6c48481
DS
846 "Error Indication from %pSU about packet to %pSU ignored",
847 &pp->src_proto, &dst_proto);
2fb975da
TT
848
849 reqid = nhrp_reqid_lookup(&nhrp_packet_reqid, htonl(hdr->u.request_id));
850 if (reqid)
851 reqid->cb(reqid, pp);
852}
853
854static void nhrp_handle_traffic_ind(struct nhrp_packet_parser *p)
855{
856 union sockunion dst;
2fb975da 857
996c9314
LB
858 if (!parse_ether_packet(&p->payload, htons(p->hdr->protocol_type), NULL,
859 &dst))
2fb975da
TT
860 return;
861
996c9314 862 debugf(NHRP_DEBUG_COMMON,
b6c48481
DS
863 "Traffic Indication from %pSU about packet to %pSU: %s",
864 &p->src_proto, &dst,
996c9314
LB
865 (p->if_ad->flags & NHRP_IFF_SHORTCUT) ? "trying shortcut"
866 : "ignored");
2fb975da
TT
867
868 if (p->if_ad->flags & NHRP_IFF_SHORTCUT)
869 nhrp_shortcut_initiate(&dst);
870}
871
872enum packet_type_t {
873 PACKET_UNKNOWN = 0,
874 PACKET_REQUEST,
875 PACKET_REPLY,
876 PACKET_INDICATION,
877};
878
47d40757 879static struct {
2fb975da
TT
880 enum packet_type_t type;
881 const char *name;
882 void (*handler)(struct nhrp_packet_parser *);
996c9314
LB
883} packet_types[] = {[0] =
884 {
885 .type = PACKET_UNKNOWN,
886 .name = "UNKNOWN",
887 },
888 [NHRP_PACKET_RESOLUTION_REQUEST] =
889 {
890 .type = PACKET_REQUEST,
891 .name = "Resolution-Request",
892 .handler = nhrp_handle_resolution_req,
893 },
894 [NHRP_PACKET_RESOLUTION_REPLY] =
895 {
896 .type = PACKET_REPLY,
897 .name = "Resolution-Reply",
898 },
899 [NHRP_PACKET_REGISTRATION_REQUEST] =
900 {
901 .type = PACKET_REQUEST,
902 .name = "Registration-Request",
903 .handler = nhrp_handle_registration_request,
904 },
905 [NHRP_PACKET_REGISTRATION_REPLY] =
906 {
907 .type = PACKET_REPLY,
908 .name = "Registration-Reply",
909 },
910 [NHRP_PACKET_PURGE_REQUEST] =
911 {
912 .type = PACKET_REQUEST,
913 .name = "Purge-Request",
914 },
915 [NHRP_PACKET_PURGE_REPLY] =
916 {
917 .type = PACKET_REPLY,
918 .name = "Purge-Reply",
919 },
920 [NHRP_PACKET_ERROR_INDICATION] =
921 {
922 .type = PACKET_INDICATION,
923 .name = "Error-Indication",
924 .handler = nhrp_handle_error_ind,
925 },
926 [NHRP_PACKET_TRAFFIC_INDICATION] = {
927 .type = PACKET_INDICATION,
928 .name = "Traffic-Indication",
929 .handler = nhrp_handle_traffic_ind,
930 }};
931
932static void nhrp_peer_forward(struct nhrp_peer *p,
933 struct nhrp_packet_parser *pp)
2fb975da 934{
b5fc78c0 935 struct zbuf *zb, *zb_copy, extpl;
2fb975da
TT
936 struct nhrp_packet_header *hdr;
937 struct nhrp_extension_header *ext, *dst;
938 struct nhrp_cie_header *cie;
939 struct nhrp_interface *nifp = pp->ifp->info;
940 struct nhrp_afi_data *if_ad = pp->if_ad;
d0c9d09a 941 union sockunion cie_nbma, cie_protocol, cie_protocol_mandatory, *proto;
2fb975da 942 uint16_t type, len;
d0c9d09a 943 struct nhrp_cache *c;
2fb975da
TT
944
945 if (pp->hdr->hop_count == 0)
946 return;
947
948 /* Create forward packet - copy header */
949 zb = zbuf_alloc(1500);
b5fc78c0
GG
950 zb_copy = zbuf_alloc(1500);
951
996c9314
LB
952 hdr = nhrp_packet_push(zb, pp->hdr->type, &pp->src_nbma, &pp->src_proto,
953 &pp->dst_proto);
2fb975da
TT
954 hdr->flags = pp->hdr->flags;
955 hdr->hop_count = pp->hdr->hop_count - 1;
956 hdr->u.request_id = pp->hdr->u.request_id;
957
958 /* Copy payload */
b5fc78c0 959 zbuf_copy_peek(zb_copy, &pp->payload, zbuf_used(&pp->payload));
2fb975da
TT
960 zbuf_copy(zb, &pp->payload, zbuf_used(&pp->payload));
961
b5fc78c0
GG
962 /* Get CIE Extension from Mandatory part */
963 sockunion_family(&cie_protocol_mandatory) = AF_UNSPEC;
964 nhrp_cie_pull(zb_copy, pp->hdr, &cie_nbma, &cie_protocol_mandatory);
965
2fb975da
TT
966 /* Copy extensions */
967 while ((ext = nhrp_ext_pull(&pp->extensions, &extpl)) != NULL) {
968 type = htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY;
969 len = htons(ext->length);
970
971 if (type == NHRP_EXTENSION_END)
972 break;
973
974 dst = nhrp_ext_push(zb, hdr, htons(ext->type));
996c9314
LB
975 if (!dst)
976 goto err;
2fb975da
TT
977
978 switch (type) {
979 case NHRP_EXTENSION_FORWARD_TRANSIT_NHS:
980 case NHRP_EXTENSION_REVERSE_TRANSIT_NHS:
981 zbuf_put(zb, extpl.head, len);
996c9314
LB
982 if ((type == NHRP_EXTENSION_REVERSE_TRANSIT_NHS)
983 == (packet_types[hdr->type].type == PACKET_REPLY)) {
2fb975da 984 /* Check NHS list for forwarding loop */
8ba9026b
DS
985 while (nhrp_cie_pull(&extpl, pp->hdr,
986 &cie_nbma,
987 &cie_protocol) != NULL) {
996c9314
LB
988 if (sockunion_same(&p->vc->remote.nbma,
989 &cie_nbma))
2fb975da
TT
990 goto err;
991 }
992 /* Append our selves to the list */
996c9314
LB
993 cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS,
994 &nifp->nbma, &if_ad->addr);
995 if (!cie)
996 goto err;
1e52c954 997 cie->mtu = htons(if_ad->mtu);
2fb975da
TT
998 cie->holding_time = htons(if_ad->holdtime);
999 }
1000 break;
b5fc78c0 1001 case NHRP_EXTENSION_NAT_ADDRESS:
d0c9d09a
RD
1002 c = NULL;
1003 proto = NULL;
1004
1005 /* If NAT extension is empty then attempt to populate
1006 * it with cached NBMA information
1007 */
1008 if (len == 0) {
611915ae
AL
1009 if (packet_types[hdr->type].type
1010 == PACKET_REQUEST) {
1011 debugf(NHRP_DEBUG_COMMON,
1012 "Processing NHRP_EXTENSION_NAT_ADDRESS while forwarding the request packet");
1bd508da 1013 proto = &pp->src_proto;
611915ae
AL
1014 } else if (packet_types[hdr->type].type
1015 == PACKET_REPLY) {
1016 debugf(NHRP_DEBUG_COMMON,
1017 "Processing NHRP_EXTENSION_NAT_ADDRESS while forwarding the reply packet");
1018 /* For reply packet use protocol
1019 * specified in CIE of mandatory part
00683a14
RD
1020 * for cache lookup
1021 */
611915ae
AL
1022 if (sockunion_family(
1023 &cie_protocol_mandatory)
1024 != AF_UNSPEC)
1bd508da
AL
1025 proto = &cie_protocol_mandatory;
1026 }
d0c9d09a 1027 }
b5fc78c0 1028
d0c9d09a
RD
1029 if (proto) {
1030 debugf(NHRP_DEBUG_COMMON, "Proto is %pSU",
1031 proto);
1032 c = nhrp_cache_get(nifp->ifp, proto, 0);
1033 }
00683a14 1034
d0c9d09a
RD
1035 if (c) {
1036 debugf(NHRP_DEBUG_COMMON,
1037 "c->cur.remote_nbma_natoa is %pSU",
1038 &c->cur.remote_nbma_natoa);
1039 if (sockunion_family(&c->cur.remote_nbma_natoa)
1040 != AF_UNSPEC) {
1041 cie = nhrp_cie_push(
1042 zb,
1043 NHRP_CODE_SUCCESS,
1044 &c->cur.remote_nbma_natoa,
1045 proto);
1046 if (!cie)
1047 goto err;
b5fc78c0 1048 }
d0c9d09a
RD
1049 } else {
1050 if (proto)
1051 debugf(NHRP_DEBUG_COMMON,
1052 "No cache entry for proto %pSU",
1053 proto);
1054 /* Copy existing NAT extension to new packet if
1055 * either it was already not-empty, or we do not
1056 * have valid cache information
1057 */
1058 zbuf_put(zb, extpl.head, len);
b5fc78c0
GG
1059 }
1060 break;
2fb975da
TT
1061 default:
1062 if (htons(ext->type) & NHRP_EXTENSION_FLAG_COMPULSORY)
1063 /* FIXME: RFC says to just copy, but not
00683a14
RD
1064 * append our selves to the transit NHS list
1065 */
2fb975da 1066 goto err;
996c9314 1067 /* fallthru */
2fb975da
TT
1068 case NHRP_EXTENSION_RESPONDER_ADDRESS:
1069 /* Supported compulsory extensions, and any
1070 * non-compulsory that is not explicitly handled,
00683a14
RD
1071 * should be just copied.
1072 */
2fb975da
TT
1073 zbuf_copy(zb, &extpl, len);
1074 break;
1075 }
1076 nhrp_ext_complete(zb, dst);
1077 }
1078
1079 nhrp_packet_complete(zb, hdr);
1080 nhrp_peer_send(p, zb);
1081 zbuf_free(zb);
b5fc78c0 1082 zbuf_free(zb_copy);
2fb975da
TT
1083 return;
1084err:
1085 nhrp_packet_debug(pp->pkt, "FWD-FAIL");
1086 zbuf_free(zb);
ba113ac6 1087 zbuf_free(zb_copy);
2fb975da
TT
1088}
1089
1090static void nhrp_packet_debug(struct zbuf *zb, const char *dir)
1091{
1092 char buf[2][SU_ADDRSTRLEN];
1093 union sockunion src_nbma, src_proto, dst_proto;
1094 struct nhrp_packet_header *hdr;
1095 struct zbuf zhdr;
1096 int reply;
1097
1098 if (likely(!(debug_flags & NHRP_DEBUG_COMMON)))
1099 return;
1100
996c9314 1101 zbuf_init(&zhdr, zb->buf, zb->tail - zb->buf, zb->tail - zb->buf);
2fb975da
TT
1102 hdr = nhrp_packet_pull(&zhdr, &src_nbma, &src_proto, &dst_proto);
1103
0d6f7fd6
DA
1104 sockunion2str(&src_proto, buf[0], sizeof(buf[0]));
1105 sockunion2str(&dst_proto, buf[1], sizeof(buf[1]));
2fb975da
TT
1106
1107 reply = packet_types[hdr->type].type == PACKET_REPLY;
996c9314 1108 debugf(NHRP_DEBUG_COMMON, "%s %s(%d) %s -> %s", dir,
57b0ac50
A
1109 (packet_types[hdr->type].name ? packet_types[hdr->type].name
1110 : "Unknown"),
1111 hdr->type, reply ? buf[1] : buf[0], reply ? buf[0] : buf[1]);
2fb975da
TT
1112}
1113
8c01a3bd
TT
1114static int proto2afi(uint16_t proto)
1115{
1116 switch (proto) {
996c9314
LB
1117 case ETH_P_IP:
1118 return AFI_IP;
1119 case ETH_P_IPV6:
1120 return AFI_IP6;
8c01a3bd
TT
1121 }
1122 return AF_UNSPEC;
1123}
1124
2fb975da
TT
1125struct nhrp_route_info {
1126 int local;
1127 struct interface *ifp;
1128 struct nhrp_vc *vc;
1129};
1130
1131void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb)
1132{
2fb975da
TT
1133 struct nhrp_packet_header *hdr;
1134 struct nhrp_vc *vc = p->vc;
1135 struct interface *ifp = p->ifp;
1136 struct nhrp_interface *nifp = ifp->info;
1137 struct nhrp_packet_parser pp;
1138 struct nhrp_peer *peer = NULL;
1139 struct nhrp_reqid *reqid;
1140 const char *info = NULL;
1141 union sockunion *target_addr;
1142 unsigned paylen, extoff, extlen, realsize;
8c01a3bd 1143 afi_t nbma_afi, proto_afi;
2fb975da 1144
b6c48481
DS
1145 debugf(NHRP_DEBUG_KERNEL, "PACKET: Recv %pSU -> %pSU", &vc->remote.nbma,
1146 &vc->local.nbma);
2fb975da
TT
1147
1148 if (!p->online) {
1149 info = "peer not online";
1150 goto drop;
1151 }
1152
1153 if (nhrp_packet_calculate_checksum(zb->head, zbuf_used(zb)) != 0) {
1154 info = "bad checksum";
1155 goto drop;
1156 }
1157
1158 realsize = zbuf_used(zb);
1159 hdr = nhrp_packet_pull(zb, &pp.src_nbma, &pp.src_proto, &pp.dst_proto);
1160 if (!hdr) {
1161 info = "corrupt header";
1162 goto drop;
1163 }
1164
1165 pp.ifp = ifp;
1166 pp.pkt = zb;
1167 pp.hdr = hdr;
1168 pp.peer = p;
1169
8c01a3bd
TT
1170 nbma_afi = htons(hdr->afnum);
1171 proto_afi = proto2afi(htons(hdr->protocol_type));
996c9314
LB
1172 if (hdr->type > NHRP_PACKET_MAX || hdr->version != NHRP_VERSION_RFC2332
1173 || nbma_afi >= AFI_MAX || proto_afi == AF_UNSPEC
1174 || packet_types[hdr->type].type == PACKET_UNKNOWN
1175 || htons(hdr->packet_size) > realsize) {
1176 zlog_info(
b6c48481
DS
1177 "From %pSU: error: packet type %d, version %d, AFI %d, proto %x, size %d (real size %d)",
1178 &vc->remote.nbma, (int)hdr->type, (int)hdr->version,
1179 (int)nbma_afi, (int)htons(hdr->protocol_type),
996c9314 1180 (int)htons(hdr->packet_size), (int)realsize);
2fb975da
TT
1181 goto drop;
1182 }
8c01a3bd 1183 pp.if_ad = &((struct nhrp_interface *)ifp->info)->afi[proto_afi];
2fb975da
TT
1184
1185 extoff = htons(hdr->extension_offset);
1186 if (extoff) {
a7051a18
QY
1187 assert(zb->head > zb->buf);
1188 uint32_t header_offset = zb->head - zb->buf;
47d40757
GN
1189 if (extoff >= realsize) {
1190 info = "extoff larger than packet";
1191 goto drop;
1192 }
1193 if (extoff < header_offset) {
1194 info = "extoff smaller than header offset";
2fb975da
TT
1195 goto drop;
1196 }
47d40757 1197 paylen = extoff - header_offset;
2fb975da
TT
1198 } else {
1199 paylen = zbuf_used(zb);
1200 }
1201 zbuf_init(&pp.payload, zbuf_pulln(zb, paylen), paylen, paylen);
1202 extlen = zbuf_used(zb);
1203 zbuf_init(&pp.extensions, zbuf_pulln(zb, extlen), extlen, extlen);
1204
8c01a3bd 1205 if (!nifp->afi[proto_afi].network_id) {
2fb975da
TT
1206 info = "nhrp not enabled";
1207 goto drop;
1208 }
1209
1210 nhrp_packet_debug(zb, "Recv");
1211
1212 /* FIXME: Check authentication here. This extension needs to be
1213 * pre-handled. */
1214
1215 /* Figure out if this is local */
996c9314
LB
1216 target_addr = (packet_types[hdr->type].type == PACKET_REPLY)
1217 ? &pp.src_proto
1218 : &pp.dst_proto;
2fb975da
TT
1219
1220 if (sockunion_same(&pp.src_proto, &pp.dst_proto))
1221 pp.route_type = NHRP_ROUTE_LOCAL;
1222 else
996c9314
LB
1223 pp.route_type = nhrp_route_address(pp.ifp, target_addr,
1224 &pp.route_prefix, &peer);
2fb975da
TT
1225
1226 switch (pp.route_type) {
1227 case NHRP_ROUTE_LOCAL:
1228 nhrp_packet_debug(zb, "!LOCAL");
1229 if (packet_types[hdr->type].type == PACKET_REPLY) {
996c9314
LB
1230 reqid = nhrp_reqid_lookup(&nhrp_packet_reqid,
1231 htonl(hdr->u.request_id));
2fb975da
TT
1232 if (reqid) {
1233 reqid->cb(reqid, &pp);
1234 break;
1235 } else {
1236 nhrp_packet_debug(zb, "!UNKNOWN-REQID");
1237 /* FIXME: send error-indication */
1238 }
1239 }
acd738fc 1240 /* fallthru */ /* FIXME: double check, is this correct? */
2fb975da
TT
1241 case NHRP_ROUTE_OFF_NBMA:
1242 if (packet_types[hdr->type].handler) {
1243 packet_types[hdr->type].handler(&pp);
1244 break;
1245 }
1246 break;
1247 case NHRP_ROUTE_NBMA_NEXTHOP:
1248 nhrp_peer_forward(peer, &pp);
1249 break;
1250 case NHRP_ROUTE_BLACKHOLE:
1251 break;
1252 }
1253
1254drop:
1255 if (info) {
b6c48481 1256 zlog_info("From %pSU: error: %s", &vc->remote.nbma, info);
2fb975da 1257 }
996c9314
LB
1258 if (peer)
1259 nhrp_peer_unref(peer);
2fb975da
TT
1260 zbuf_free(zb);
1261}