1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) 2014-2015 Timo Teräs
10 #include <netinet/if_ether.h>
19 #include "nhrp_protocol.h"
22 DEFINE_MTYPE_STATIC(NHRPD
, NHRP_PEER
, "NHRP peer entry");
25 uint8_t priority_version
;
30 struct in6_addr saddr
;
31 struct in6_addr daddr
;
34 static void nhrp_packet_debug(struct zbuf
*zb
, const char *dir
);
36 static void nhrp_peer_check_delete(struct nhrp_peer
*p
)
38 struct nhrp_interface
*nifp
= p
->ifp
->info
;
40 if (p
->ref
|| notifier_active(&p
->notifier_list
))
43 debugf(NHRP_DEBUG_COMMON
, "Deleting peer ref:%d remote:%pSU local:%pSU",
44 p
->ref
, &p
->vc
->remote
.nbma
, &p
->vc
->local
.nbma
);
46 EVENT_OFF(p
->t_fallback
);
47 EVENT_OFF(p
->t_timer
);
48 hash_release(nifp
->peer_hash
, p
);
49 nhrp_interface_notify_del(p
->ifp
, &p
->ifp_notifier
);
50 nhrp_vc_notify_del(p
->vc
, &p
->vc_notifier
);
51 XFREE(MTYPE_NHRP_PEER
, p
);
54 static void nhrp_peer_notify_up(struct event
*t
)
56 struct nhrp_peer
*p
= EVENT_ARG(t
);
57 struct nhrp_vc
*vc
= p
->vc
;
58 struct interface
*ifp
= p
->ifp
;
59 struct nhrp_interface
*nifp
= ifp
->info
;
62 if (nifp
->enabled
&& (!nifp
->ipsec_profile
|| vc
->ipsec
)) {
65 notifier_call(&p
->notifier_list
, NOTIFY_PEER_UP
);
70 static void __nhrp_peer_check(struct nhrp_peer
*p
)
72 struct nhrp_vc
*vc
= p
->vc
;
73 struct interface
*ifp
= p
->ifp
;
74 struct nhrp_interface
*nifp
= ifp
->info
;
77 online
= nifp
->enabled
&& (!nifp
->ipsec_profile
|| vc
->ipsec
);
78 if (p
->online
!= online
) {
79 EVENT_OFF(p
->t_fallback
);
80 if (online
&& notifier_active(&p
->notifier_list
)) {
81 /* If we requested the IPsec connection, delay
82 * the up notification a bit to allow things
83 * settle down. This allows IKE to install
85 event_add_timer_msec(master
, nhrp_peer_notify_up
, p
, 50,
91 notifier_call(&p
->notifier_list
,
94 p
->requested
= p
->fallback_requested
= 0;
95 notifier_call(&p
->notifier_list
,
103 static void nhrp_peer_vc_notify(struct notifier_block
*n
, unsigned long cmd
)
105 struct nhrp_peer
*p
= container_of(n
, struct nhrp_peer
, vc_notifier
);
108 case NOTIFY_VC_IPSEC_CHANGED
:
109 __nhrp_peer_check(p
);
111 case NOTIFY_VC_IPSEC_UPDATE_NBMA
:
113 notifier_call(&p
->notifier_list
, NOTIFY_PEER_NBMA_CHANGING
);
119 static void nhrp_peer_ifp_notify(struct notifier_block
*n
, unsigned long cmd
)
121 struct nhrp_peer
*p
= container_of(n
, struct nhrp_peer
, ifp_notifier
);
122 struct nhrp_interface
*nifp
;
127 case NOTIFY_INTERFACE_UP
:
128 case NOTIFY_INTERFACE_DOWN
:
129 __nhrp_peer_check(p
);
131 case NOTIFY_INTERFACE_NBMA_CHANGED
:
132 /* Source NBMA changed, rebind to new VC */
134 vc
= nhrp_vc_get(&nifp
->nbma
, &p
->vc
->remote
.nbma
, 1);
135 if (vc
&& p
->vc
!= vc
) {
136 nhrp_vc_notify_del(p
->vc
, &p
->vc_notifier
);
138 nhrp_vc_notify_add(p
->vc
, &p
->vc_notifier
,
139 nhrp_peer_vc_notify
);
140 __nhrp_peer_check(p
);
142 /* fallthru */ /* to post config update */
143 case NOTIFY_INTERFACE_ADDRESS_CHANGED
:
144 notifier_call(&p
->notifier_list
, NOTIFY_PEER_IFCONFIG_CHANGED
);
146 case NOTIFY_INTERFACE_IPSEC_CHANGED
:
147 __nhrp_peer_check(p
);
148 notifier_call(&p
->notifier_list
, NOTIFY_PEER_IFCONFIG_CHANGED
);
150 case NOTIFY_INTERFACE_MTU_CHANGED
:
151 notifier_call(&p
->notifier_list
, NOTIFY_PEER_MTU_CHANGED
);
157 static unsigned int nhrp_peer_key(const void *peer_data
)
159 const struct nhrp_peer
*p
= peer_data
;
160 return sockunion_hash(&p
->vc
->remote
.nbma
);
163 static bool nhrp_peer_cmp(const void *cache_data
, const void *key_data
)
165 const struct nhrp_peer
*a
= cache_data
;
166 const struct nhrp_peer
*b
= key_data
;
168 return a
->ifp
== b
->ifp
&& a
->vc
== b
->vc
;
171 static void *nhrp_peer_create(void *data
)
173 struct nhrp_peer
*p
, *key
= data
;
175 p
= XMALLOC(MTYPE_NHRP_PEER
, sizeof(*p
));
177 *p
= (struct nhrp_peer
){
181 .notifier_list
= NOTIFIER_LIST_INITIALIZER(&p
->notifier_list
),
183 nhrp_vc_notify_add(p
->vc
, &p
->vc_notifier
, nhrp_peer_vc_notify
);
184 nhrp_interface_notify_add(p
->ifp
, &p
->ifp_notifier
,
185 nhrp_peer_ifp_notify
);
190 static void do_peer_hash_free(void *hb_data
)
192 struct nhrp_peer
*p
= (struct nhrp_peer
*)hb_data
;
194 nhrp_peer_check_delete(p
);
197 void nhrp_peer_interface_del(struct interface
*ifp
)
199 struct nhrp_interface
*nifp
= ifp
->info
;
201 debugf(NHRP_DEBUG_COMMON
, "Cleaning up undeleted peer entries (%lu)",
202 nifp
->peer_hash
? nifp
->peer_hash
->count
: 0);
204 hash_clean_and_free(&nifp
->peer_hash
, do_peer_hash_free
);
207 struct nhrp_peer
*nhrp_peer_get(struct interface
*ifp
,
208 const union sockunion
*remote_nbma
)
210 struct nhrp_interface
*nifp
= ifp
->info
;
211 struct nhrp_peer key
, *p
;
214 if (!nifp
->peer_hash
) {
215 nifp
->peer_hash
= hash_create(nhrp_peer_key
, nhrp_peer_cmp
,
217 if (!nifp
->peer_hash
)
221 vc
= nhrp_vc_get(&nifp
->nbma
, remote_nbma
, 1);
228 p
= hash_get(nifp
->peer_hash
, &key
, nhrp_peer_create
);
231 __nhrp_peer_check(p
);
236 struct nhrp_peer
*nhrp_peer_ref(struct nhrp_peer
*p
)
243 void nhrp_peer_unref(struct nhrp_peer
*p
)
247 nhrp_peer_check_delete(p
);
251 static void nhrp_peer_request_timeout(struct event
*t
)
253 struct nhrp_peer
*p
= EVENT_ARG(t
);
254 struct nhrp_vc
*vc
= p
->vc
;
255 struct interface
*ifp
= p
->ifp
;
256 struct nhrp_interface
*nifp
= ifp
->info
;
262 if (nifp
->ipsec_fallback_profile
&& !p
->prio
263 && !p
->fallback_requested
) {
264 p
->fallback_requested
= 1;
265 vici_request_vc(nifp
->ipsec_fallback_profile
, &vc
->local
.nbma
,
266 &vc
->remote
.nbma
, p
->prio
);
267 event_add_timer(master
, nhrp_peer_request_timeout
, p
, 30,
270 p
->requested
= p
->fallback_requested
= 0;
274 static void nhrp_peer_defer_vici_request(struct event
*t
)
276 struct nhrp_peer
*p
= EVENT_ARG(t
);
277 struct nhrp_vc
*vc
= p
->vc
;
278 struct interface
*ifp
= p
->ifp
;
279 struct nhrp_interface
*nifp
= ifp
->info
;
281 EVENT_OFF(p
->t_timer
);
284 debugf(NHRP_DEBUG_COMMON
,
285 "IPsec connection to %pSU already established",
288 vici_request_vc(nifp
->ipsec_profile
, &vc
->local
.nbma
,
289 &vc
->remote
.nbma
, p
->prio
);
290 event_add_timer(master
, nhrp_peer_request_timeout
, p
,
291 (nifp
->ipsec_fallback_profile
&& !p
->prio
) ? 15
297 int nhrp_peer_check(struct nhrp_peer
*p
, int establish
)
299 struct nhrp_vc
*vc
= p
->vc
;
300 struct interface
*ifp
= p
->ifp
;
301 struct nhrp_interface
*nifp
= ifp
->info
;
309 if (!nifp
->ipsec_profile
)
311 if (sockunion_family(&vc
->local
.nbma
) == AF_UNSPEC
)
316 p
->prio
= establish
> 1;
319 /* All NHRP registration requests are prioritized */
321 vici_request_vc(nifp
->ipsec_profile
, &vc
->local
.nbma
,
322 &vc
->remote
.nbma
, p
->prio
);
323 event_add_timer(master
, nhrp_peer_request_timeout
, p
,
324 (nifp
->ipsec_fallback_profile
&& !p
->prio
) ? 15
328 /* Maximum timeout is 1 second */
329 int r_time_ms
= frr_weak_random() % 1000;
331 debugf(NHRP_DEBUG_COMMON
,
332 "Initiating IPsec connection request to %pSU after %d ms:",
333 &vc
->remote
.nbma
, r_time_ms
);
334 event_add_timer_msec(master
, nhrp_peer_defer_vici_request
, p
,
335 r_time_ms
, &p
->t_timer
);
341 void nhrp_peer_notify_add(struct nhrp_peer
*p
, struct notifier_block
*n
,
344 notifier_add(n
, &p
->notifier_list
, fn
);
347 void nhrp_peer_notify_del(struct nhrp_peer
*p
, struct notifier_block
*n
)
349 notifier_del(n
, &p
->notifier_list
);
350 nhrp_peer_check_delete(p
);
353 void nhrp_peer_send(struct nhrp_peer
*p
, struct zbuf
*zb
)
355 nhrp_packet_debug(zb
, "Send");
360 debugf(NHRP_DEBUG_KERNEL
, "PACKET: Send %pSU -> %pSU",
361 &p
->vc
->local
.nbma
, &p
->vc
->remote
.nbma
);
363 os_sendmsg(zb
->head
, zbuf_used(zb
), p
->ifp
->ifindex
,
364 sockunion_get_addr(&p
->vc
->remote
.nbma
),
365 sockunion_get_addrlen(&p
->vc
->remote
.nbma
), ETH_P_NHRP
);
369 static void nhrp_process_nat_extension(struct nhrp_packet_parser
*pp
,
370 union sockunion
*proto
,
371 union sockunion
*cie_nbma
)
373 union sockunion cie_proto
;
375 struct nhrp_extension_header
*ext
;
376 struct zbuf
*extensions
;
381 sockunion_family(cie_nbma
) = AF_UNSPEC
;
383 if (!proto
|| sockunion_family(proto
) == AF_UNSPEC
)
386 /* Handle extensions */
387 extensions
= zbuf_alloc(zbuf_used(&pp
->extensions
));
389 zbuf_copy_peek(extensions
, &pp
->extensions
,
390 zbuf_used(&pp
->extensions
));
391 while ((ext
= nhrp_ext_pull(extensions
, &payload
)) != NULL
) {
392 switch (htons(ext
->type
)
393 & ~NHRP_EXTENSION_FLAG_COMPULSORY
) {
394 case NHRP_EXTENSION_NAT_ADDRESS
:
395 /* Process the NBMA and proto address in NAT
396 * extension and update the cache without which
397 * the neighbor table in the kernel contains the
398 * source NBMA address which is not reachable
399 * since it is behind a NAT device
401 debugf(NHRP_DEBUG_COMMON
,
402 "shortcut res_resp: Processing NAT Extension for %pSU",
404 while (nhrp_cie_pull(&payload
, pp
->hdr
,
405 cie_nbma
, &cie_proto
)) {
406 if (sockunion_family(&cie_proto
)
410 if (!sockunion_cmp(proto
, &cie_proto
)) {
411 debugf(NHRP_DEBUG_COMMON
,
412 "cie_nbma for proto %pSU is %pSU",
419 zbuf_free(extensions
);
423 static void nhrp_handle_resolution_req(struct nhrp_packet_parser
*pp
)
425 struct interface
*ifp
= pp
->ifp
;
426 struct zbuf
*zb
, payload
;
427 struct nhrp_packet_header
*hdr
;
428 struct nhrp_cie_header
*cie
;
429 struct nhrp_extension_header
*ext
;
430 struct nhrp_cache
*c
;
431 union sockunion cie_nbma
, cie_nbma_nat
, cie_proto
, *proto_addr
,
432 *nbma_addr
, *claimed_nbma_addr
;
433 int holdtime
, prefix_len
, hostprefix_len
;
434 struct nhrp_interface
*nifp
= ifp
->info
;
435 struct nhrp_peer
*peer
;
438 if (!(pp
->if_ad
->flags
& NHRP_IFF_SHORTCUT
)) {
439 debugf(NHRP_DEBUG_COMMON
, "Shortcuts disabled");
440 /* FIXME: Send error indication? */
444 if (pp
->if_ad
->network_id
&& pp
->route_type
== NHRP_ROUTE_OFF_NBMA
445 && pp
->route_prefix
.prefixlen
< 8) {
446 debugf(NHRP_DEBUG_COMMON
,
447 "Shortcut to more generic than /8 dropped");
451 debugf(NHRP_DEBUG_COMMON
, "Parsing and replying to Resolution Req");
453 if (nhrp_route_address(ifp
, &pp
->src_proto
, NULL
, &peer
)
454 != NHRP_ROUTE_NBMA_NEXTHOP
)
457 /* Copy payload CIE */
458 hostprefix_len
= 8 * sockunion_get_addrlen(&pp
->if_ad
->addr
);
459 paylen
= zbuf_used(&pp
->payload
);
460 debugf(NHRP_DEBUG_COMMON
, "shortcut res_rep: paylen %zu", paylen
);
462 while ((cie
= nhrp_cie_pull(&pp
->payload
, pp
->hdr
, &cie_nbma
,
465 prefix_len
= cie
->prefix_length
;
466 debugf(NHRP_DEBUG_COMMON
,
467 "shortcut res_rep: parsing CIE with prefixlen=%u",
469 if (prefix_len
== 0 || prefix_len
>= hostprefix_len
)
470 prefix_len
= hostprefix_len
;
472 if (prefix_len
!= hostprefix_len
474 & htons(NHRP_FLAG_REGISTRATION_UNIQUE
))) {
475 cie
->code
= NHRP_CODE_BINDING_NON_UNIQUE
;
479 /* We currently support only unique prefix registrations */
480 if (prefix_len
!= hostprefix_len
) {
481 cie
->code
= NHRP_CODE_ADMINISTRATIVELY_PROHIBITED
;
485 proto_addr
= (sockunion_family(&cie_proto
) == AF_UNSPEC
)
489 /* Check for this proto_addr in NHRP_NAT_EXTENSION */
490 nhrp_process_nat_extension(pp
, proto_addr
, &cie_nbma_nat
);
492 if (sockunion_family(&cie_nbma_nat
) == AF_UNSPEC
) {
493 /* It may be possible that this resolution reply is
494 * coming directly from NATTED Spoke and there is not
495 * NAT Extension present
497 debugf(NHRP_DEBUG_COMMON
,
498 "shortcut res_rep: No NAT Extension for %pSU",
501 if (!sockunion_same(&pp
->src_nbma
,
502 &pp
->peer
->vc
->remote
.nbma
)
503 && !nhrp_nhs_match_ip(&pp
->peer
->vc
->remote
.nbma
,
505 cie_nbma_nat
= pp
->peer
->vc
->remote
.nbma
;
506 debugf(NHRP_DEBUG_COMMON
,
507 "shortcut res_rep: NAT detected using %pSU as cie_nbma",
512 if (sockunion_family(&cie_nbma_nat
) != AF_UNSPEC
)
513 nbma_addr
= &cie_nbma_nat
;
514 else if (sockunion_family(&cie_nbma
) != AF_UNSPEC
)
515 nbma_addr
= &cie_nbma
;
517 nbma_addr
= &pp
->src_nbma
;
519 if (sockunion_family(&cie_nbma
) != AF_UNSPEC
)
520 claimed_nbma_addr
= &cie_nbma
;
522 claimed_nbma_addr
= &pp
->src_nbma
;
524 holdtime
= htons(cie
->holding_time
);
525 debugf(NHRP_DEBUG_COMMON
,
526 "shortcut res_rep: holdtime is %u (if 0, using %u)",
527 holdtime
, pp
->if_ad
->holdtime
);
529 holdtime
= pp
->if_ad
->holdtime
;
531 c
= nhrp_cache_get(ifp
, proto_addr
, 1);
533 debugf(NHRP_DEBUG_COMMON
,
534 "shortcut res_rep: no cache found");
535 cie
->code
= NHRP_CODE_INSUFFICIENT_RESOURCES
;
539 debugf(NHRP_DEBUG_COMMON
,
540 "shortcut res_rep: updating binding for nmba addr %pSU",
542 if (!nhrp_cache_update_binding(
543 c
, NHRP_CACHE_DYNAMIC
, holdtime
,
544 nhrp_peer_get(pp
->ifp
, nbma_addr
), htons(cie
->mtu
),
545 nbma_addr
, claimed_nbma_addr
)) {
546 cie
->code
= NHRP_CODE_ADMINISTRATIVELY_PROHIBITED
;
550 cie
->code
= NHRP_CODE_SUCCESS
;
554 zb
= zbuf_alloc(1500);
555 hdr
= nhrp_packet_push(zb
, NHRP_PACKET_RESOLUTION_REPLY
, &pp
->src_nbma
,
556 &pp
->src_proto
, &pp
->dst_proto
);
558 /* Copied information from request */
559 hdr
->flags
= pp
->hdr
->flags
560 & htons(NHRP_FLAG_RESOLUTION_SOURCE_IS_ROUTER
561 | NHRP_FLAG_RESOLUTION_SOURCE_STABLE
);
562 hdr
->flags
|= htons(NHRP_FLAG_RESOLUTION_DESTINATION_STABLE
563 | NHRP_FLAG_RESOLUTION_AUTHORATIVE
);
564 hdr
->u
.request_id
= pp
->hdr
->u
.request_id
;
566 /* CIE payload for the reply packet */
567 cie
= nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
, &nifp
->nbma
,
569 cie
->holding_time
= htons(pp
->if_ad
->holdtime
);
570 cie
->mtu
= htons(pp
->if_ad
->mtu
);
571 if (pp
->if_ad
->network_id
&& pp
->route_type
== NHRP_ROUTE_OFF_NBMA
)
572 cie
->prefix_length
= pp
->route_prefix
.prefixlen
;
575 8 * sockunion_get_addrlen(&pp
->if_ad
->addr
);
577 /* Handle extensions */
578 while ((ext
= nhrp_ext_pull(&pp
->extensions
, &payload
)) != NULL
) {
579 switch (htons(ext
->type
) & ~NHRP_EXTENSION_FLAG_COMPULSORY
) {
580 case NHRP_EXTENSION_NAT_ADDRESS
:
581 ext
= nhrp_ext_push(zb
, hdr
,
582 NHRP_EXTENSION_NAT_ADDRESS
);
585 if (sockunion_family(&nifp
->nat_nbma
) != AF_UNSPEC
) {
586 cie
= nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
,
592 8 * sockunion_get_addrlen(
595 cie
->mtu
= htons(pp
->if_ad
->mtu
);
596 nhrp_ext_complete(zb
, ext
);
600 if (nhrp_ext_reply(zb
, hdr
, ifp
, ext
, &payload
) < 0)
605 nhrp_packet_complete(zb
, hdr
);
606 nhrp_peer_send(peer
, zb
);
608 nhrp_peer_unref(peer
);
612 static void nhrp_handle_registration_request(struct nhrp_packet_parser
*p
)
614 struct interface
*ifp
= p
->ifp
;
615 struct zbuf
*zb
, payload
;
616 struct nhrp_packet_header
*hdr
;
617 struct nhrp_cie_header
*cie
;
618 struct nhrp_extension_header
*ext
;
619 struct nhrp_cache
*c
;
620 union sockunion cie_nbma
, cie_proto
, *proto_addr
, *nbma_addr
,
622 int holdtime
, prefix_len
, hostprefix_len
, natted
= 0;
626 debugf(NHRP_DEBUG_COMMON
, "Parsing and replying to Registration Req");
627 hostprefix_len
= 8 * sockunion_get_addrlen(&p
->if_ad
->addr
);
629 if (!sockunion_same(&p
->src_nbma
, &p
->peer
->vc
->remote
.nbma
))
633 zb
= zbuf_alloc(1500);
634 hdr
= nhrp_packet_push(zb
, NHRP_PACKET_REGISTRATION_REPLY
, &p
->src_nbma
,
635 &p
->src_proto
, &p
->if_ad
->addr
);
637 /* Copied information from request */
638 hdr
->flags
= p
->hdr
->flags
& htons(NHRP_FLAG_REGISTRATION_UNIQUE
639 | NHRP_FLAG_REGISTRATION_NAT
);
640 hdr
->u
.request_id
= p
->hdr
->u
.request_id
;
642 /* Copy payload CIEs */
643 paylen
= zbuf_used(&p
->payload
);
644 pay
= zbuf_pushn(zb
, paylen
);
647 memcpy(pay
, zbuf_pulln(&p
->payload
, paylen
), paylen
);
648 zbuf_init(&payload
, pay
, paylen
, paylen
);
650 while ((cie
= nhrp_cie_pull(&payload
, hdr
, &cie_nbma
, &cie_proto
))
652 prefix_len
= cie
->prefix_length
;
653 if (prefix_len
== 0 || prefix_len
>= hostprefix_len
)
654 prefix_len
= hostprefix_len
;
656 if (prefix_len
!= hostprefix_len
658 & htons(NHRP_FLAG_REGISTRATION_UNIQUE
))) {
659 cie
->code
= NHRP_CODE_BINDING_NON_UNIQUE
;
663 /* We currently support only unique prefix registrations */
664 if (prefix_len
!= hostprefix_len
) {
665 cie
->code
= NHRP_CODE_ADMINISTRATIVELY_PROHIBITED
;
669 proto_addr
= (sockunion_family(&cie_proto
) == AF_UNSPEC
)
672 nbma_addr
= (sockunion_family(&cie_nbma
) == AF_UNSPEC
)
678 (sockunion_family(&p
->peer
->vc
->remote
.nbma
)
681 : &p
->peer
->vc
->remote
.nbma
;
684 holdtime
= htons(cie
->holding_time
);
686 holdtime
= p
->if_ad
->holdtime
;
688 c
= nhrp_cache_get(ifp
, proto_addr
, 1);
690 cie
->code
= NHRP_CODE_INSUFFICIENT_RESOURCES
;
694 if (!nhrp_cache_update_binding(c
, NHRP_CACHE_DYNAMIC
, holdtime
,
695 nhrp_peer_ref(p
->peer
),
696 htons(cie
->mtu
), nbma_natoa
,
698 cie
->code
= NHRP_CODE_ADMINISTRATIVELY_PROHIBITED
;
702 cie
->code
= NHRP_CODE_SUCCESS
;
705 /* Handle extensions */
706 while ((ext
= nhrp_ext_pull(&p
->extensions
, &payload
)) != NULL
) {
707 switch (htons(ext
->type
) & ~NHRP_EXTENSION_FLAG_COMPULSORY
) {
708 case NHRP_EXTENSION_NAT_ADDRESS
:
709 ext
= nhrp_ext_push(zb
, hdr
,
710 NHRP_EXTENSION_NAT_ADDRESS
);
713 zbuf_copy(zb
, &payload
, zbuf_used(&payload
));
715 cie
= nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
,
716 &p
->peer
->vc
->remote
.nbma
,
719 8 * sockunion_get_addrlen(
721 cie
->mtu
= htons(p
->if_ad
->mtu
);
723 nhrp_ext_complete(zb
, ext
);
726 if (nhrp_ext_reply(zb
, hdr
, ifp
, ext
, &payload
) < 0)
732 nhrp_packet_complete(zb
, hdr
);
733 nhrp_peer_send(p
->peer
, zb
);
738 static int parse_ether_packet(struct zbuf
*zb
, uint16_t protocol_type
,
739 union sockunion
*src
, union sockunion
*dst
)
741 switch (protocol_type
) {
743 struct iphdr
*iph
= zbuf_pull(zb
, struct iphdr
);
746 sockunion_set(src
, AF_INET
,
747 (uint8_t *)&iph
->saddr
,
750 sockunion_set(dst
, AF_INET
,
751 (uint8_t *)&iph
->daddr
,
756 struct ipv6hdr
*iph
= zbuf_pull(zb
, struct ipv6hdr
);
759 sockunion_set(src
, AF_INET6
,
760 (uint8_t *)&iph
->saddr
,
763 sockunion_set(dst
, AF_INET6
,
764 (uint8_t *)&iph
->daddr
,
774 void nhrp_peer_send_indication(struct interface
*ifp
, uint16_t protocol_type
,
778 struct zbuf
*zb
, payload
;
779 struct nhrp_interface
*nifp
= ifp
->info
;
780 struct nhrp_afi_data
*if_ad
;
781 struct nhrp_packet_header
*hdr
;
788 if (!parse_ether_packet(&payload
, protocol_type
, &dst
, NULL
))
791 if (nhrp_route_address(ifp
, &dst
, NULL
, &p
) != NHRP_ROUTE_NBMA_NEXTHOP
)
794 if_ad
= &nifp
->afi
[family2afi(sockunion_family(&dst
))];
795 if (!(if_ad
->flags
& NHRP_IFF_REDIRECT
)) {
796 debugf(NHRP_DEBUG_COMMON
,
797 "Send Traffic Indication to %pSU about packet to %pSU ignored",
798 &p
->vc
->remote
.nbma
, &dst
);
802 debugf(NHRP_DEBUG_COMMON
,
803 "Send Traffic Indication to %pSU (online=%d) about packet to %pSU",
804 &p
->vc
->remote
.nbma
, p
->online
, &dst
);
807 zb
= zbuf_alloc(1500);
808 hdr
= nhrp_packet_push(zb
, NHRP_PACKET_TRAFFIC_INDICATION
, &nifp
->nbma
,
812 /* Payload is the packet causing indication */
813 zbuf_copy(zb
, pkt
, zbuf_used(pkt
));
814 nhrp_packet_complete(zb
, hdr
);
815 nhrp_peer_send(p
, zb
);
820 static void nhrp_handle_error_ind(struct nhrp_packet_parser
*pp
)
822 struct zbuf origmsg
= pp
->payload
;
823 struct nhrp_packet_header
*hdr
;
824 struct nhrp_reqid
*reqid
;
825 union sockunion src_nbma
, src_proto
, dst_proto
;
827 hdr
= nhrp_packet_pull(&origmsg
, &src_nbma
, &src_proto
, &dst_proto
);
831 debugf(NHRP_DEBUG_COMMON
,
832 "Error Indication from %pSU about packet to %pSU ignored",
833 &pp
->src_proto
, &dst_proto
);
835 reqid
= nhrp_reqid_lookup(&nhrp_packet_reqid
, htonl(hdr
->u
.request_id
));
837 reqid
->cb(reqid
, pp
);
840 static void nhrp_handle_traffic_ind(struct nhrp_packet_parser
*p
)
844 if (!parse_ether_packet(&p
->payload
, htons(p
->hdr
->protocol_type
), NULL
,
848 debugf(NHRP_DEBUG_COMMON
,
849 "Traffic Indication from %pSU about packet to %pSU: %s",
851 (p
->if_ad
->flags
& NHRP_IFF_SHORTCUT
) ? "trying shortcut"
854 if (p
->if_ad
->flags
& NHRP_IFF_SHORTCUT
)
855 nhrp_shortcut_initiate(&dst
);
866 enum packet_type_t type
;
868 void (*handler
)(struct nhrp_packet_parser
*);
869 } packet_types
[] = {[0] =
871 .type
= PACKET_UNKNOWN
,
874 [NHRP_PACKET_RESOLUTION_REQUEST
] =
876 .type
= PACKET_REQUEST
,
877 .name
= "Resolution-Request",
878 .handler
= nhrp_handle_resolution_req
,
880 [NHRP_PACKET_RESOLUTION_REPLY
] =
882 .type
= PACKET_REPLY
,
883 .name
= "Resolution-Reply",
885 [NHRP_PACKET_REGISTRATION_REQUEST
] =
887 .type
= PACKET_REQUEST
,
888 .name
= "Registration-Request",
889 .handler
= nhrp_handle_registration_request
,
891 [NHRP_PACKET_REGISTRATION_REPLY
] =
893 .type
= PACKET_REPLY
,
894 .name
= "Registration-Reply",
896 [NHRP_PACKET_PURGE_REQUEST
] =
898 .type
= PACKET_REQUEST
,
899 .name
= "Purge-Request",
901 [NHRP_PACKET_PURGE_REPLY
] =
903 .type
= PACKET_REPLY
,
904 .name
= "Purge-Reply",
906 [NHRP_PACKET_ERROR_INDICATION
] =
908 .type
= PACKET_INDICATION
,
909 .name
= "Error-Indication",
910 .handler
= nhrp_handle_error_ind
,
912 [NHRP_PACKET_TRAFFIC_INDICATION
] = {
913 .type
= PACKET_INDICATION
,
914 .name
= "Traffic-Indication",
915 .handler
= nhrp_handle_traffic_ind
,
918 static void nhrp_peer_forward(struct nhrp_peer
*p
,
919 struct nhrp_packet_parser
*pp
)
921 struct zbuf
*zb
, *zb_copy
, extpl
;
922 struct nhrp_packet_header
*hdr
;
923 struct nhrp_extension_header
*ext
, *dst
;
924 struct nhrp_cie_header
*cie
;
925 struct nhrp_interface
*nifp
= pp
->ifp
->info
;
926 struct nhrp_afi_data
*if_ad
= pp
->if_ad
;
927 union sockunion cie_nbma
, cie_protocol
, cie_protocol_mandatory
, *proto
;
929 struct nhrp_cache
*c
;
931 if (pp
->hdr
->hop_count
== 0)
934 /* Create forward packet - copy header */
935 zb
= zbuf_alloc(1500);
936 zb_copy
= zbuf_alloc(1500);
938 hdr
= nhrp_packet_push(zb
, pp
->hdr
->type
, &pp
->src_nbma
, &pp
->src_proto
,
940 hdr
->flags
= pp
->hdr
->flags
;
941 hdr
->hop_count
= pp
->hdr
->hop_count
- 1;
942 hdr
->u
.request_id
= pp
->hdr
->u
.request_id
;
945 zbuf_copy_peek(zb_copy
, &pp
->payload
, zbuf_used(&pp
->payload
));
946 zbuf_copy(zb
, &pp
->payload
, zbuf_used(&pp
->payload
));
948 /* Get CIE Extension from Mandatory part */
949 sockunion_family(&cie_protocol_mandatory
) = AF_UNSPEC
;
950 nhrp_cie_pull(zb_copy
, pp
->hdr
, &cie_nbma
, &cie_protocol_mandatory
);
952 /* Copy extensions */
953 while ((ext
= nhrp_ext_pull(&pp
->extensions
, &extpl
)) != NULL
) {
954 type
= htons(ext
->type
) & ~NHRP_EXTENSION_FLAG_COMPULSORY
;
955 len
= htons(ext
->length
);
957 if (type
== NHRP_EXTENSION_END
)
960 dst
= nhrp_ext_push(zb
, hdr
, htons(ext
->type
));
965 case NHRP_EXTENSION_FORWARD_TRANSIT_NHS
:
966 case NHRP_EXTENSION_REVERSE_TRANSIT_NHS
:
967 zbuf_put(zb
, extpl
.head
, len
);
968 if ((type
== NHRP_EXTENSION_REVERSE_TRANSIT_NHS
)
969 == (packet_types
[hdr
->type
].type
== PACKET_REPLY
)) {
970 /* Check NHS list for forwarding loop */
971 while (nhrp_cie_pull(&extpl
, pp
->hdr
,
973 &cie_protocol
) != NULL
) {
974 if (sockunion_same(&p
->vc
->remote
.nbma
,
978 /* Append our selves to the list */
979 cie
= nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
,
980 &nifp
->nbma
, &if_ad
->addr
);
983 cie
->mtu
= htons(if_ad
->mtu
);
984 cie
->holding_time
= htons(if_ad
->holdtime
);
987 case NHRP_EXTENSION_NAT_ADDRESS
:
991 /* If NAT extension is empty then attempt to populate
992 * it with cached NBMA information
995 if (packet_types
[hdr
->type
].type
997 debugf(NHRP_DEBUG_COMMON
,
998 "Processing NHRP_EXTENSION_NAT_ADDRESS while forwarding the request packet");
999 proto
= &pp
->src_proto
;
1000 } else if (packet_types
[hdr
->type
].type
1002 debugf(NHRP_DEBUG_COMMON
,
1003 "Processing NHRP_EXTENSION_NAT_ADDRESS while forwarding the reply packet");
1004 /* For reply packet use protocol
1005 * specified in CIE of mandatory part
1008 if (sockunion_family(
1009 &cie_protocol_mandatory
)
1011 proto
= &cie_protocol_mandatory
;
1016 debugf(NHRP_DEBUG_COMMON
, "Proto is %pSU",
1018 c
= nhrp_cache_get(nifp
->ifp
, proto
, 0);
1022 debugf(NHRP_DEBUG_COMMON
,
1023 "c->cur.remote_nbma_natoa is %pSU",
1024 &c
->cur
.remote_nbma_natoa
);
1025 if (sockunion_family(&c
->cur
.remote_nbma_natoa
)
1027 cie
= nhrp_cie_push(
1030 &c
->cur
.remote_nbma_natoa
,
1037 debugf(NHRP_DEBUG_COMMON
,
1038 "No cache entry for proto %pSU",
1040 /* Copy existing NAT extension to new packet if
1041 * either it was already not-empty, or we do not
1042 * have valid cache information
1044 zbuf_put(zb
, extpl
.head
, len
);
1048 if (htons(ext
->type
) & NHRP_EXTENSION_FLAG_COMPULSORY
)
1049 /* FIXME: RFC says to just copy, but not
1050 * append our selves to the transit NHS list
1054 case NHRP_EXTENSION_RESPONDER_ADDRESS
:
1055 /* Supported compulsory extensions, and any
1056 * non-compulsory that is not explicitly handled,
1057 * should be just copied.
1059 zbuf_copy(zb
, &extpl
, len
);
1062 nhrp_ext_complete(zb
, dst
);
1065 nhrp_packet_complete(zb
, hdr
);
1066 nhrp_peer_send(p
, zb
);
1071 nhrp_packet_debug(pp
->pkt
, "FWD-FAIL");
1076 static void nhrp_packet_debug(struct zbuf
*zb
, const char *dir
)
1078 union sockunion src_nbma
, src_proto
, dst_proto
;
1079 struct nhrp_packet_header
*hdr
;
1083 if (likely(!(debug_flags
& NHRP_DEBUG_COMMON
)))
1086 zbuf_init(&zhdr
, zb
->buf
, zb
->tail
- zb
->buf
, zb
->tail
- zb
->buf
);
1087 hdr
= nhrp_packet_pull(&zhdr
, &src_nbma
, &src_proto
, &dst_proto
);
1089 reply
= packet_types
[hdr
->type
].type
== PACKET_REPLY
;
1090 debugf(NHRP_DEBUG_COMMON
, "%s %s(%d) %pSU -> %pSU", dir
,
1091 (packet_types
[hdr
->type
].name
? packet_types
[hdr
->type
].name
1093 hdr
->type
, reply
? &dst_proto
: &src_proto
,
1094 reply
? &src_proto
: &dst_proto
);
1097 static int proto2afi(uint16_t proto
)
1108 struct nhrp_route_info
{
1110 struct interface
*ifp
;
1114 void nhrp_peer_recv(struct nhrp_peer
*p
, struct zbuf
*zb
)
1116 struct nhrp_packet_header
*hdr
;
1117 struct nhrp_vc
*vc
= p
->vc
;
1118 struct interface
*ifp
= p
->ifp
;
1119 struct nhrp_interface
*nifp
= ifp
->info
;
1120 struct nhrp_packet_parser pp
;
1121 struct nhrp_peer
*peer
= NULL
;
1122 struct nhrp_reqid
*reqid
;
1123 const char *info
= NULL
;
1124 union sockunion
*target_addr
;
1125 unsigned paylen
, extoff
, extlen
, realsize
;
1126 afi_t nbma_afi
, proto_afi
;
1128 debugf(NHRP_DEBUG_KERNEL
, "PACKET: Recv %pSU -> %pSU", &vc
->remote
.nbma
,
1132 info
= "peer not online";
1136 if (nhrp_packet_calculate_checksum(zb
->head
, zbuf_used(zb
)) != 0) {
1137 info
= "bad checksum";
1141 realsize
= zbuf_used(zb
);
1142 hdr
= nhrp_packet_pull(zb
, &pp
.src_nbma
, &pp
.src_proto
, &pp
.dst_proto
);
1144 info
= "corrupt header";
1153 nbma_afi
= htons(hdr
->afnum
);
1154 proto_afi
= proto2afi(htons(hdr
->protocol_type
));
1155 if (hdr
->type
> NHRP_PACKET_MAX
|| hdr
->version
!= NHRP_VERSION_RFC2332
1156 || nbma_afi
>= AFI_MAX
|| proto_afi
== AF_UNSPEC
1157 || packet_types
[hdr
->type
].type
== PACKET_UNKNOWN
1158 || htons(hdr
->packet_size
) > realsize
) {
1160 "From %pSU: error: packet type %d, version %d, AFI %d, proto %x, size %d (real size %d)",
1161 &vc
->remote
.nbma
, (int)hdr
->type
, (int)hdr
->version
,
1162 (int)nbma_afi
, (int)htons(hdr
->protocol_type
),
1163 (int)htons(hdr
->packet_size
), (int)realsize
);
1166 pp
.if_ad
= &((struct nhrp_interface
*)ifp
->info
)->afi
[proto_afi
];
1168 extoff
= htons(hdr
->extension_offset
);
1170 assert(zb
->head
> zb
->buf
);
1171 uint32_t header_offset
= zb
->head
- zb
->buf
;
1172 if (extoff
>= realsize
) {
1173 info
= "extoff larger than packet";
1176 if (extoff
< header_offset
) {
1177 info
= "extoff smaller than header offset";
1180 paylen
= extoff
- header_offset
;
1182 paylen
= zbuf_used(zb
);
1184 zbuf_init(&pp
.payload
, zbuf_pulln(zb
, paylen
), paylen
, paylen
);
1185 extlen
= zbuf_used(zb
);
1186 zbuf_init(&pp
.extensions
, zbuf_pulln(zb
, extlen
), extlen
, extlen
);
1188 if (!nifp
->afi
[proto_afi
].network_id
) {
1189 info
= "nhrp not enabled";
1193 nhrp_packet_debug(zb
, "Recv");
1195 /* FIXME: Check authentication here. This extension needs to be
1198 /* Figure out if this is local */
1199 target_addr
= (packet_types
[hdr
->type
].type
== PACKET_REPLY
)
1203 if (sockunion_same(&pp
.src_proto
, &pp
.dst_proto
))
1204 pp
.route_type
= NHRP_ROUTE_LOCAL
;
1206 pp
.route_type
= nhrp_route_address(pp
.ifp
, target_addr
,
1207 &pp
.route_prefix
, &peer
);
1209 switch (pp
.route_type
) {
1210 case NHRP_ROUTE_LOCAL
:
1211 nhrp_packet_debug(zb
, "!LOCAL");
1212 if (packet_types
[hdr
->type
].type
== PACKET_REPLY
) {
1213 reqid
= nhrp_reqid_lookup(&nhrp_packet_reqid
,
1214 htonl(hdr
->u
.request_id
));
1216 reqid
->cb(reqid
, &pp
);
1219 nhrp_packet_debug(zb
, "!UNKNOWN-REQID");
1220 /* FIXME: send error-indication */
1223 /* fallthru */ /* FIXME: double check, is this correct? */
1224 case NHRP_ROUTE_OFF_NBMA
:
1225 if (packet_types
[hdr
->type
].handler
) {
1226 packet_types
[hdr
->type
].handler(&pp
);
1230 case NHRP_ROUTE_NBMA_NEXTHOP
:
1231 nhrp_peer_forward(peer
, &pp
);
1233 case NHRP_ROUTE_BLACKHOLE
:
1239 zlog_info("From %pSU: error: %s", &vc
->remote
.nbma
, info
);
1242 nhrp_peer_unref(peer
);