2 * Copyright (c) 2014-2015 Timo Teräs
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.
14 #include <netinet/if_ether.h>
22 #include "nhrp_protocol.h"
25 DEFINE_MTYPE_STATIC(NHRPD
, NHRP_PEER
, "NHRP peer entry");
28 uint8_t priority_version
;
33 struct in6_addr saddr
;
34 struct in6_addr daddr
;
37 static void nhrp_packet_debug(struct zbuf
*zb
, const char *dir
);
39 static void nhrp_peer_check_delete(struct nhrp_peer
*p
)
41 struct nhrp_interface
*nifp
= p
->ifp
->info
;
43 if (p
->ref
|| notifier_active(&p
->notifier_list
))
46 debugf(NHRP_DEBUG_COMMON
, "Deleting peer ref:%d remote:%pSU local:%pSU",
47 p
->ref
, &p
->vc
->remote
.nbma
, &p
->vc
->local
.nbma
);
49 THREAD_OFF(p
->t_fallback
);
50 THREAD_OFF(p
->t_timer
);
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
);
57 static int nhrp_peer_notify_up(struct thread
*t
)
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
;
65 if (nifp
->enabled
&& (!nifp
->ipsec_profile
|| vc
->ipsec
)) {
68 notifier_call(&p
->notifier_list
, NOTIFY_PEER_UP
);
75 static void __nhrp_peer_check(struct nhrp_peer
*p
)
77 struct nhrp_vc
*vc
= p
->vc
;
78 struct interface
*ifp
= p
->ifp
;
79 struct nhrp_interface
*nifp
= ifp
->info
;
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
90 thread_add_timer_msec(master
, nhrp_peer_notify_up
, p
,
96 notifier_call(&p
->notifier_list
,
99 p
->requested
= p
->fallback_requested
= 0;
100 notifier_call(&p
->notifier_list
,
108 static void nhrp_peer_vc_notify(struct notifier_block
*n
, unsigned long cmd
)
110 struct nhrp_peer
*p
= container_of(n
, struct nhrp_peer
, vc_notifier
);
113 case NOTIFY_VC_IPSEC_CHANGED
:
114 __nhrp_peer_check(p
);
116 case NOTIFY_VC_IPSEC_UPDATE_NBMA
:
118 notifier_call(&p
->notifier_list
, NOTIFY_PEER_NBMA_CHANGING
);
124 static void nhrp_peer_ifp_notify(struct notifier_block
*n
, unsigned long cmd
)
126 struct nhrp_peer
*p
= container_of(n
, struct nhrp_peer
, ifp_notifier
);
127 struct nhrp_interface
*nifp
;
132 case NOTIFY_INTERFACE_UP
:
133 case NOTIFY_INTERFACE_DOWN
:
134 __nhrp_peer_check(p
);
136 case NOTIFY_INTERFACE_NBMA_CHANGED
:
137 /* Source NBMA changed, rebind to new VC */
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
);
143 nhrp_vc_notify_add(p
->vc
, &p
->vc_notifier
,
144 nhrp_peer_vc_notify
);
145 __nhrp_peer_check(p
);
147 /* fallthru */ /* to post config update */
148 case NOTIFY_INTERFACE_ADDRESS_CHANGED
:
149 notifier_call(&p
->notifier_list
, NOTIFY_PEER_IFCONFIG_CHANGED
);
151 case NOTIFY_INTERFACE_IPSEC_CHANGED
:
152 __nhrp_peer_check(p
);
153 notifier_call(&p
->notifier_list
, NOTIFY_PEER_IFCONFIG_CHANGED
);
155 case NOTIFY_INTERFACE_MTU_CHANGED
:
156 notifier_call(&p
->notifier_list
, NOTIFY_PEER_MTU_CHANGED
);
162 static unsigned int nhrp_peer_key(const void *peer_data
)
164 const struct nhrp_peer
*p
= peer_data
;
165 return sockunion_hash(&p
->vc
->remote
.nbma
);
168 static bool nhrp_peer_cmp(const void *cache_data
, const void *key_data
)
170 const struct nhrp_peer
*a
= cache_data
;
171 const struct nhrp_peer
*b
= key_data
;
173 return a
->ifp
== b
->ifp
&& a
->vc
== b
->vc
;
176 static void *nhrp_peer_create(void *data
)
178 struct nhrp_peer
*p
, *key
= data
;
180 p
= XMALLOC(MTYPE_NHRP_PEER
, sizeof(*p
));
182 *p
= (struct nhrp_peer
){
186 .notifier_list
= NOTIFIER_LIST_INITIALIZER(&p
->notifier_list
),
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
);
195 static void do_peer_hash_free(void *hb_data
)
197 struct nhrp_peer
*p
= (struct nhrp_peer
*)hb_data
;
199 nhrp_peer_check_delete(p
);
202 void nhrp_peer_interface_del(struct interface
*ifp
)
204 struct nhrp_interface
*nifp
= ifp
->info
;
206 debugf(NHRP_DEBUG_COMMON
, "Cleaning up undeleted peer entries (%lu)",
207 nifp
->peer_hash
? nifp
->peer_hash
->count
: 0);
209 if (nifp
->peer_hash
) {
210 hash_clean(nifp
->peer_hash
, do_peer_hash_free
);
211 assert(nifp
->peer_hash
->count
== 0);
212 hash_free(nifp
->peer_hash
);
213 nifp
->peer_hash
= NULL
;
217 struct nhrp_peer
*nhrp_peer_get(struct interface
*ifp
,
218 const union sockunion
*remote_nbma
)
220 struct nhrp_interface
*nifp
= ifp
->info
;
221 struct nhrp_peer key
, *p
;
224 if (!nifp
->peer_hash
) {
225 nifp
->peer_hash
= hash_create(nhrp_peer_key
, nhrp_peer_cmp
,
227 if (!nifp
->peer_hash
)
231 vc
= nhrp_vc_get(&nifp
->nbma
, remote_nbma
, 1);
238 p
= hash_get(nifp
->peer_hash
, &key
, nhrp_peer_create
);
241 __nhrp_peer_check(p
);
246 struct nhrp_peer
*nhrp_peer_ref(struct nhrp_peer
*p
)
253 void nhrp_peer_unref(struct nhrp_peer
*p
)
257 nhrp_peer_check_delete(p
);
261 static int nhrp_peer_request_timeout(struct thread
*t
)
263 struct nhrp_peer
*p
= THREAD_ARG(t
);
264 struct nhrp_vc
*vc
= p
->vc
;
265 struct interface
*ifp
= p
->ifp
;
266 struct nhrp_interface
*nifp
= ifp
->info
;
272 if (nifp
->ipsec_fallback_profile
&& !p
->prio
273 && !p
->fallback_requested
) {
274 p
->fallback_requested
= 1;
275 vici_request_vc(nifp
->ipsec_fallback_profile
, &vc
->local
.nbma
,
276 &vc
->remote
.nbma
, p
->prio
);
277 thread_add_timer(master
, nhrp_peer_request_timeout
, p
, 30,
280 p
->requested
= p
->fallback_requested
= 0;
286 static int nhrp_peer_defer_vici_request(struct thread
*t
)
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
;
293 THREAD_OFF(p
->t_timer
);
296 debugf(NHRP_DEBUG_COMMON
,
297 "IPsec connection to %pSU already established",
300 vici_request_vc(nifp
->ipsec_profile
, &vc
->local
.nbma
,
301 &vc
->remote
.nbma
, p
->prio
);
303 master
, nhrp_peer_request_timeout
, p
,
304 (nifp
->ipsec_fallback_profile
&& !p
->prio
) ? 15 : 30,
310 int nhrp_peer_check(struct nhrp_peer
*p
, int establish
)
312 struct nhrp_vc
*vc
= p
->vc
;
313 struct interface
*ifp
= p
->ifp
;
314 struct nhrp_interface
*nifp
= ifp
->info
;
322 if (!nifp
->ipsec_profile
)
324 if (sockunion_family(&vc
->local
.nbma
) == AF_UNSPEC
)
329 p
->prio
= establish
> 1;
332 /* All NHRP registration requests are prioritized */
334 vici_request_vc(nifp
->ipsec_profile
, &vc
->local
.nbma
,
335 &vc
->remote
.nbma
, p
->prio
);
337 master
, nhrp_peer_request_timeout
, p
,
338 (nifp
->ipsec_fallback_profile
&& !p
->prio
) ? 15 : 30,
341 /* Maximum timeout is 1 second */
342 int r_time_ms
= rand() % 1000;
344 debugf(NHRP_DEBUG_COMMON
,
345 "Initiating IPsec connection request to %pSU after %d ms:",
346 &vc
->remote
.nbma
, r_time_ms
);
347 thread_add_timer_msec(master
, nhrp_peer_defer_vici_request
,
348 p
, r_time_ms
, &p
->t_timer
);
354 void nhrp_peer_notify_add(struct nhrp_peer
*p
, struct notifier_block
*n
,
357 notifier_add(n
, &p
->notifier_list
, fn
);
360 void nhrp_peer_notify_del(struct nhrp_peer
*p
, struct notifier_block
*n
)
362 notifier_del(n
, &p
->notifier_list
);
363 nhrp_peer_check_delete(p
);
366 void nhrp_peer_send(struct nhrp_peer
*p
, struct zbuf
*zb
)
368 nhrp_packet_debug(zb
, "Send");
373 debugf(NHRP_DEBUG_KERNEL
, "PACKET: Send %pSU -> %pSU",
374 &p
->vc
->local
.nbma
, &p
->vc
->remote
.nbma
);
376 os_sendmsg(zb
->head
, zbuf_used(zb
), p
->ifp
->ifindex
,
377 sockunion_get_addr(&p
->vc
->remote
.nbma
),
378 sockunion_get_addrlen(&p
->vc
->remote
.nbma
), ETH_P_NHRP
);
382 static void nhrp_process_nat_extension(struct nhrp_packet_parser
*pp
,
383 union sockunion
*proto
,
384 union sockunion
*cie_nbma
)
386 union sockunion cie_proto
;
388 struct nhrp_extension_header
*ext
;
389 struct zbuf
*extensions
;
394 sockunion_family(cie_nbma
) = AF_UNSPEC
;
396 if (!proto
|| sockunion_family(proto
) == AF_UNSPEC
)
399 /* Handle extensions */
400 extensions
= zbuf_alloc(zbuf_used(&pp
->extensions
));
402 zbuf_copy_peek(extensions
, &pp
->extensions
,
403 zbuf_used(&pp
->extensions
));
404 while ((ext
= nhrp_ext_pull(extensions
, &payload
)) != NULL
) {
405 switch (htons(ext
->type
)
406 & ~NHRP_EXTENSION_FLAG_COMPULSORY
) {
407 case NHRP_EXTENSION_NAT_ADDRESS
:
408 /* Process the NBMA and proto address in NAT
409 * extension and update the cache without which
410 * the neighbor table in the kernel contains the
411 * source NBMA address which is not reachable
412 * since it is behind a NAT device
414 debugf(NHRP_DEBUG_COMMON
,
415 "shortcut res_resp: Processing NAT Extension for %pSU",
417 while (nhrp_cie_pull(&payload
, pp
->hdr
,
418 cie_nbma
, &cie_proto
)) {
419 if (sockunion_family(&cie_proto
)
423 if (!sockunion_cmp(proto
, &cie_proto
)) {
424 debugf(NHRP_DEBUG_COMMON
,
425 "cie_nbma for proto %pSU is %pSU",
432 zbuf_free(extensions
);
436 static void nhrp_handle_resolution_req(struct nhrp_packet_parser
*pp
)
438 struct interface
*ifp
= pp
->ifp
;
439 struct zbuf
*zb
, payload
;
440 struct nhrp_packet_header
*hdr
;
441 struct nhrp_cie_header
*cie
;
442 struct nhrp_extension_header
*ext
;
443 struct nhrp_cache
*c
;
444 union sockunion cie_nbma
, cie_nbma_nat
, cie_proto
, *proto_addr
,
445 *nbma_addr
, *claimed_nbma_addr
;
446 int holdtime
, prefix_len
, hostprefix_len
;
447 struct nhrp_interface
*nifp
= ifp
->info
;
448 struct nhrp_peer
*peer
;
451 if (!(pp
->if_ad
->flags
& NHRP_IFF_SHORTCUT
)) {
452 debugf(NHRP_DEBUG_COMMON
, "Shortcuts disabled");
453 /* FIXME: Send error indication? */
457 if (pp
->if_ad
->network_id
&& pp
->route_type
== NHRP_ROUTE_OFF_NBMA
458 && pp
->route_prefix
.prefixlen
< 8) {
459 debugf(NHRP_DEBUG_COMMON
,
460 "Shortcut to more generic than /8 dropped");
464 debugf(NHRP_DEBUG_COMMON
, "Parsing and replying to Resolution Req");
466 if (nhrp_route_address(ifp
, &pp
->src_proto
, NULL
, &peer
)
467 != NHRP_ROUTE_NBMA_NEXTHOP
)
470 /* Copy payload CIE */
471 hostprefix_len
= 8 * sockunion_get_addrlen(&pp
->if_ad
->addr
);
472 paylen
= zbuf_used(&pp
->payload
);
473 debugf(NHRP_DEBUG_COMMON
, "shortcut res_rep: paylen %zu", paylen
);
475 while ((cie
= nhrp_cie_pull(&pp
->payload
, pp
->hdr
, &cie_nbma
,
478 prefix_len
= cie
->prefix_length
;
479 debugf(NHRP_DEBUG_COMMON
,
480 "shortcut res_rep: parsing CIE with prefixlen=%u",
482 if (prefix_len
== 0 || prefix_len
>= hostprefix_len
)
483 prefix_len
= hostprefix_len
;
485 if (prefix_len
!= hostprefix_len
487 & htons(NHRP_FLAG_REGISTRATION_UNIQUE
))) {
488 cie
->code
= NHRP_CODE_BINDING_NON_UNIQUE
;
492 /* We currently support only unique prefix registrations */
493 if (prefix_len
!= hostprefix_len
) {
494 cie
->code
= NHRP_CODE_ADMINISTRATIVELY_PROHIBITED
;
498 proto_addr
= (sockunion_family(&cie_proto
) == AF_UNSPEC
)
502 /* Check for this proto_addr in NHRP_NAT_EXTENSION */
503 nhrp_process_nat_extension(pp
, proto_addr
, &cie_nbma_nat
);
505 if (sockunion_family(&cie_nbma_nat
) == AF_UNSPEC
) {
506 /* It may be possible that this resolution reply is
507 * coming directly from NATTED Spoke and there is not
508 * NAT Extension present
510 debugf(NHRP_DEBUG_COMMON
,
511 "shortcut res_rep: No NAT Extension for %pSU",
514 if (!sockunion_same(&pp
->src_nbma
,
515 &pp
->peer
->vc
->remote
.nbma
)
516 && !nhrp_nhs_match_ip(&pp
->peer
->vc
->remote
.nbma
,
518 cie_nbma_nat
= pp
->peer
->vc
->remote
.nbma
;
519 debugf(NHRP_DEBUG_COMMON
,
520 "shortcut res_rep: NAT detected using %pSU as cie_nbma",
525 if (sockunion_family(&cie_nbma_nat
) != AF_UNSPEC
)
526 nbma_addr
= &cie_nbma_nat
;
527 else if (sockunion_family(&cie_nbma
) != AF_UNSPEC
)
528 nbma_addr
= &cie_nbma
;
530 nbma_addr
= &pp
->src_nbma
;
532 if (sockunion_family(&cie_nbma
) != AF_UNSPEC
)
533 claimed_nbma_addr
= &cie_nbma
;
535 claimed_nbma_addr
= &pp
->src_nbma
;
537 holdtime
= htons(cie
->holding_time
);
538 debugf(NHRP_DEBUG_COMMON
,
539 "shortcut res_rep: holdtime is %u (if 0, using %u)",
540 holdtime
, pp
->if_ad
->holdtime
);
542 holdtime
= pp
->if_ad
->holdtime
;
544 c
= nhrp_cache_get(ifp
, proto_addr
, 1);
546 debugf(NHRP_DEBUG_COMMON
,
547 "shortcut res_rep: no cache found");
548 cie
->code
= NHRP_CODE_INSUFFICIENT_RESOURCES
;
552 debugf(NHRP_DEBUG_COMMON
,
553 "shortcut res_rep: updating binding for nmba addr %pSU",
555 if (!nhrp_cache_update_binding(
556 c
, NHRP_CACHE_DYNAMIC
, holdtime
,
557 nhrp_peer_get(pp
->ifp
, nbma_addr
), htons(cie
->mtu
),
558 nbma_addr
, claimed_nbma_addr
)) {
559 cie
->code
= NHRP_CODE_ADMINISTRATIVELY_PROHIBITED
;
563 cie
->code
= NHRP_CODE_SUCCESS
;
567 zb
= zbuf_alloc(1500);
568 hdr
= nhrp_packet_push(zb
, NHRP_PACKET_RESOLUTION_REPLY
, &pp
->src_nbma
,
569 &pp
->src_proto
, &pp
->dst_proto
);
571 /* Copied information from request */
572 hdr
->flags
= pp
->hdr
->flags
573 & htons(NHRP_FLAG_RESOLUTION_SOURCE_IS_ROUTER
574 | NHRP_FLAG_RESOLUTION_SOURCE_STABLE
);
575 hdr
->flags
|= htons(NHRP_FLAG_RESOLUTION_DESTINATION_STABLE
576 | NHRP_FLAG_RESOLUTION_AUTHORATIVE
);
577 hdr
->u
.request_id
= pp
->hdr
->u
.request_id
;
579 /* CIE payload for the reply packet */
580 cie
= nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
, &nifp
->nbma
,
582 cie
->holding_time
= htons(pp
->if_ad
->holdtime
);
583 cie
->mtu
= htons(pp
->if_ad
->mtu
);
584 if (pp
->if_ad
->network_id
&& pp
->route_type
== NHRP_ROUTE_OFF_NBMA
)
585 cie
->prefix_length
= pp
->route_prefix
.prefixlen
;
588 8 * sockunion_get_addrlen(&pp
->if_ad
->addr
);
590 /* Handle extensions */
591 while ((ext
= nhrp_ext_pull(&pp
->extensions
, &payload
)) != NULL
) {
592 switch (htons(ext
->type
) & ~NHRP_EXTENSION_FLAG_COMPULSORY
) {
593 case NHRP_EXTENSION_NAT_ADDRESS
:
594 ext
= nhrp_ext_push(zb
, hdr
,
595 NHRP_EXTENSION_NAT_ADDRESS
);
598 if (sockunion_family(&nifp
->nat_nbma
) != AF_UNSPEC
) {
599 cie
= nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
,
605 8 * sockunion_get_addrlen(
608 cie
->mtu
= htons(pp
->if_ad
->mtu
);
609 nhrp_ext_complete(zb
, ext
);
613 if (nhrp_ext_reply(zb
, hdr
, ifp
, ext
, &payload
) < 0)
618 nhrp_packet_complete(zb
, hdr
);
619 nhrp_peer_send(peer
, zb
);
621 nhrp_peer_unref(peer
);
625 static void nhrp_handle_registration_request(struct nhrp_packet_parser
*p
)
627 struct interface
*ifp
= p
->ifp
;
628 struct zbuf
*zb
, payload
;
629 struct nhrp_packet_header
*hdr
;
630 struct nhrp_cie_header
*cie
;
631 struct nhrp_extension_header
*ext
;
632 struct nhrp_cache
*c
;
633 union sockunion cie_nbma
, cie_proto
, *proto_addr
, *nbma_addr
,
635 int holdtime
, prefix_len
, hostprefix_len
, natted
= 0;
639 debugf(NHRP_DEBUG_COMMON
, "Parsing and replying to Registration Req");
640 hostprefix_len
= 8 * sockunion_get_addrlen(&p
->if_ad
->addr
);
642 if (!sockunion_same(&p
->src_nbma
, &p
->peer
->vc
->remote
.nbma
))
646 zb
= zbuf_alloc(1500);
647 hdr
= nhrp_packet_push(zb
, NHRP_PACKET_REGISTRATION_REPLY
, &p
->src_nbma
,
648 &p
->src_proto
, &p
->if_ad
->addr
);
650 /* Copied information from request */
651 hdr
->flags
= p
->hdr
->flags
& htons(NHRP_FLAG_REGISTRATION_UNIQUE
652 | NHRP_FLAG_REGISTRATION_NAT
);
653 hdr
->u
.request_id
= p
->hdr
->u
.request_id
;
655 /* Copy payload CIEs */
656 paylen
= zbuf_used(&p
->payload
);
657 pay
= zbuf_pushn(zb
, paylen
);
660 memcpy(pay
, zbuf_pulln(&p
->payload
, paylen
), paylen
);
661 zbuf_init(&payload
, pay
, paylen
, paylen
);
663 while ((cie
= nhrp_cie_pull(&payload
, hdr
, &cie_nbma
, &cie_proto
))
665 prefix_len
= cie
->prefix_length
;
666 if (prefix_len
== 0 || prefix_len
>= hostprefix_len
)
667 prefix_len
= hostprefix_len
;
669 if (prefix_len
!= hostprefix_len
671 & htons(NHRP_FLAG_REGISTRATION_UNIQUE
))) {
672 cie
->code
= NHRP_CODE_BINDING_NON_UNIQUE
;
676 /* We currently support only unique prefix registrations */
677 if (prefix_len
!= hostprefix_len
) {
678 cie
->code
= NHRP_CODE_ADMINISTRATIVELY_PROHIBITED
;
682 proto_addr
= (sockunion_family(&cie_proto
) == AF_UNSPEC
)
685 nbma_addr
= (sockunion_family(&cie_nbma
) == AF_UNSPEC
)
691 (sockunion_family(&p
->peer
->vc
->remote
.nbma
)
694 : &p
->peer
->vc
->remote
.nbma
;
697 holdtime
= htons(cie
->holding_time
);
699 holdtime
= p
->if_ad
->holdtime
;
701 c
= nhrp_cache_get(ifp
, proto_addr
, 1);
703 cie
->code
= NHRP_CODE_INSUFFICIENT_RESOURCES
;
707 if (!nhrp_cache_update_binding(c
, NHRP_CACHE_DYNAMIC
, holdtime
,
708 nhrp_peer_ref(p
->peer
),
709 htons(cie
->mtu
), nbma_natoa
,
711 cie
->code
= NHRP_CODE_ADMINISTRATIVELY_PROHIBITED
;
715 cie
->code
= NHRP_CODE_SUCCESS
;
718 /* Handle extensions */
719 while ((ext
= nhrp_ext_pull(&p
->extensions
, &payload
)) != NULL
) {
720 switch (htons(ext
->type
) & ~NHRP_EXTENSION_FLAG_COMPULSORY
) {
721 case NHRP_EXTENSION_NAT_ADDRESS
:
722 ext
= nhrp_ext_push(zb
, hdr
,
723 NHRP_EXTENSION_NAT_ADDRESS
);
726 zbuf_copy(zb
, &payload
, zbuf_used(&payload
));
728 cie
= nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
,
729 &p
->peer
->vc
->remote
.nbma
,
732 8 * sockunion_get_addrlen(
734 cie
->mtu
= htons(p
->if_ad
->mtu
);
736 nhrp_ext_complete(zb
, ext
);
739 if (nhrp_ext_reply(zb
, hdr
, ifp
, ext
, &payload
) < 0)
745 nhrp_packet_complete(zb
, hdr
);
746 nhrp_peer_send(p
->peer
, zb
);
751 static int parse_ether_packet(struct zbuf
*zb
, uint16_t protocol_type
,
752 union sockunion
*src
, union sockunion
*dst
)
754 switch (protocol_type
) {
756 struct iphdr
*iph
= zbuf_pull(zb
, struct iphdr
);
759 sockunion_set(src
, AF_INET
,
760 (uint8_t *)&iph
->saddr
,
763 sockunion_set(dst
, AF_INET
,
764 (uint8_t *)&iph
->daddr
,
769 struct ipv6hdr
*iph
= zbuf_pull(zb
, struct ipv6hdr
);
772 sockunion_set(src
, AF_INET6
,
773 (uint8_t *)&iph
->saddr
,
776 sockunion_set(dst
, AF_INET6
,
777 (uint8_t *)&iph
->daddr
,
787 void nhrp_peer_send_indication(struct interface
*ifp
, uint16_t protocol_type
,
791 struct zbuf
*zb
, payload
;
792 struct nhrp_interface
*nifp
= ifp
->info
;
793 struct nhrp_afi_data
*if_ad
;
794 struct nhrp_packet_header
*hdr
;
801 if (!parse_ether_packet(&payload
, protocol_type
, &dst
, NULL
))
804 if (nhrp_route_address(ifp
, &dst
, NULL
, &p
) != NHRP_ROUTE_NBMA_NEXTHOP
)
807 if_ad
= &nifp
->afi
[family2afi(sockunion_family(&dst
))];
808 if (!(if_ad
->flags
& NHRP_IFF_REDIRECT
)) {
809 debugf(NHRP_DEBUG_COMMON
,
810 "Send Traffic Indication to %pSU about packet to %pSU ignored",
811 &p
->vc
->remote
.nbma
, &dst
);
815 debugf(NHRP_DEBUG_COMMON
,
816 "Send Traffic Indication to %pSU (online=%d) about packet to %pSU",
817 &p
->vc
->remote
.nbma
, p
->online
, &dst
);
820 zb
= zbuf_alloc(1500);
821 hdr
= nhrp_packet_push(zb
, NHRP_PACKET_TRAFFIC_INDICATION
, &nifp
->nbma
,
825 /* Payload is the packet causing indication */
826 zbuf_copy(zb
, pkt
, zbuf_used(pkt
));
827 nhrp_packet_complete(zb
, hdr
);
828 nhrp_peer_send(p
, zb
);
833 static void nhrp_handle_error_ind(struct nhrp_packet_parser
*pp
)
835 struct zbuf origmsg
= pp
->payload
;
836 struct nhrp_packet_header
*hdr
;
837 struct nhrp_reqid
*reqid
;
838 union sockunion src_nbma
, src_proto
, dst_proto
;
840 hdr
= nhrp_packet_pull(&origmsg
, &src_nbma
, &src_proto
, &dst_proto
);
844 debugf(NHRP_DEBUG_COMMON
,
845 "Error Indication from %pSU about packet to %pSU ignored",
846 &pp
->src_proto
, &dst_proto
);
848 reqid
= nhrp_reqid_lookup(&nhrp_packet_reqid
, htonl(hdr
->u
.request_id
));
850 reqid
->cb(reqid
, pp
);
853 static void nhrp_handle_traffic_ind(struct nhrp_packet_parser
*p
)
857 if (!parse_ether_packet(&p
->payload
, htons(p
->hdr
->protocol_type
), NULL
,
861 debugf(NHRP_DEBUG_COMMON
,
862 "Traffic Indication from %pSU about packet to %pSU: %s",
864 (p
->if_ad
->flags
& NHRP_IFF_SHORTCUT
) ? "trying shortcut"
867 if (p
->if_ad
->flags
& NHRP_IFF_SHORTCUT
)
868 nhrp_shortcut_initiate(&dst
);
879 enum packet_type_t type
;
881 void (*handler
)(struct nhrp_packet_parser
*);
882 } packet_types
[] = {[0] =
884 .type
= PACKET_UNKNOWN
,
887 [NHRP_PACKET_RESOLUTION_REQUEST
] =
889 .type
= PACKET_REQUEST
,
890 .name
= "Resolution-Request",
891 .handler
= nhrp_handle_resolution_req
,
893 [NHRP_PACKET_RESOLUTION_REPLY
] =
895 .type
= PACKET_REPLY
,
896 .name
= "Resolution-Reply",
898 [NHRP_PACKET_REGISTRATION_REQUEST
] =
900 .type
= PACKET_REQUEST
,
901 .name
= "Registration-Request",
902 .handler
= nhrp_handle_registration_request
,
904 [NHRP_PACKET_REGISTRATION_REPLY
] =
906 .type
= PACKET_REPLY
,
907 .name
= "Registration-Reply",
909 [NHRP_PACKET_PURGE_REQUEST
] =
911 .type
= PACKET_REQUEST
,
912 .name
= "Purge-Request",
914 [NHRP_PACKET_PURGE_REPLY
] =
916 .type
= PACKET_REPLY
,
917 .name
= "Purge-Reply",
919 [NHRP_PACKET_ERROR_INDICATION
] =
921 .type
= PACKET_INDICATION
,
922 .name
= "Error-Indication",
923 .handler
= nhrp_handle_error_ind
,
925 [NHRP_PACKET_TRAFFIC_INDICATION
] = {
926 .type
= PACKET_INDICATION
,
927 .name
= "Traffic-Indication",
928 .handler
= nhrp_handle_traffic_ind
,
931 static void nhrp_peer_forward(struct nhrp_peer
*p
,
932 struct nhrp_packet_parser
*pp
)
934 struct zbuf
*zb
, *zb_copy
, extpl
;
935 struct nhrp_packet_header
*hdr
;
936 struct nhrp_extension_header
*ext
, *dst
;
937 struct nhrp_cie_header
*cie
;
938 struct nhrp_interface
*nifp
= pp
->ifp
->info
;
939 struct nhrp_afi_data
*if_ad
= pp
->if_ad
;
940 union sockunion cie_nbma
, cie_protocol
, cie_protocol_mandatory
, *proto
;
942 struct nhrp_cache
*c
;
944 if (pp
->hdr
->hop_count
== 0)
947 /* Create forward packet - copy header */
948 zb
= zbuf_alloc(1500);
949 zb_copy
= zbuf_alloc(1500);
951 hdr
= nhrp_packet_push(zb
, pp
->hdr
->type
, &pp
->src_nbma
, &pp
->src_proto
,
953 hdr
->flags
= pp
->hdr
->flags
;
954 hdr
->hop_count
= pp
->hdr
->hop_count
- 1;
955 hdr
->u
.request_id
= pp
->hdr
->u
.request_id
;
958 zbuf_copy_peek(zb_copy
, &pp
->payload
, zbuf_used(&pp
->payload
));
959 zbuf_copy(zb
, &pp
->payload
, zbuf_used(&pp
->payload
));
961 /* Get CIE Extension from Mandatory part */
962 sockunion_family(&cie_protocol_mandatory
) = AF_UNSPEC
;
963 nhrp_cie_pull(zb_copy
, pp
->hdr
, &cie_nbma
, &cie_protocol_mandatory
);
965 /* Copy extensions */
966 while ((ext
= nhrp_ext_pull(&pp
->extensions
, &extpl
)) != NULL
) {
967 type
= htons(ext
->type
) & ~NHRP_EXTENSION_FLAG_COMPULSORY
;
968 len
= htons(ext
->length
);
970 if (type
== NHRP_EXTENSION_END
)
973 dst
= nhrp_ext_push(zb
, hdr
, htons(ext
->type
));
978 case NHRP_EXTENSION_FORWARD_TRANSIT_NHS
:
979 case NHRP_EXTENSION_REVERSE_TRANSIT_NHS
:
980 zbuf_put(zb
, extpl
.head
, len
);
981 if ((type
== NHRP_EXTENSION_REVERSE_TRANSIT_NHS
)
982 == (packet_types
[hdr
->type
].type
== PACKET_REPLY
)) {
983 /* Check NHS list for forwarding loop */
984 while (nhrp_cie_pull(&extpl
, pp
->hdr
,
986 &cie_protocol
) != NULL
) {
987 if (sockunion_same(&p
->vc
->remote
.nbma
,
991 /* Append our selves to the list */
992 cie
= nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
,
993 &nifp
->nbma
, &if_ad
->addr
);
996 cie
->mtu
= htons(if_ad
->mtu
);
997 cie
->holding_time
= htons(if_ad
->holdtime
);
1000 case NHRP_EXTENSION_NAT_ADDRESS
:
1004 /* If NAT extension is empty then attempt to populate
1005 * it with cached NBMA information
1008 if (packet_types
[hdr
->type
].type
1009 == PACKET_REQUEST
) {
1010 debugf(NHRP_DEBUG_COMMON
,
1011 "Processing NHRP_EXTENSION_NAT_ADDRESS while forwarding the request packet");
1012 proto
= &pp
->src_proto
;
1013 } else if (packet_types
[hdr
->type
].type
1015 debugf(NHRP_DEBUG_COMMON
,
1016 "Processing NHRP_EXTENSION_NAT_ADDRESS while forwarding the reply packet");
1017 /* For reply packet use protocol
1018 * specified in CIE of mandatory part
1021 if (sockunion_family(
1022 &cie_protocol_mandatory
)
1024 proto
= &cie_protocol_mandatory
;
1029 debugf(NHRP_DEBUG_COMMON
, "Proto is %pSU",
1031 c
= nhrp_cache_get(nifp
->ifp
, proto
, 0);
1035 debugf(NHRP_DEBUG_COMMON
,
1036 "c->cur.remote_nbma_natoa is %pSU",
1037 &c
->cur
.remote_nbma_natoa
);
1038 if (sockunion_family(&c
->cur
.remote_nbma_natoa
)
1040 cie
= nhrp_cie_push(
1043 &c
->cur
.remote_nbma_natoa
,
1050 debugf(NHRP_DEBUG_COMMON
,
1051 "No cache entry for proto %pSU",
1053 /* Copy existing NAT extension to new packet if
1054 * either it was already not-empty, or we do not
1055 * have valid cache information
1057 zbuf_put(zb
, extpl
.head
, len
);
1061 if (htons(ext
->type
) & NHRP_EXTENSION_FLAG_COMPULSORY
)
1062 /* FIXME: RFC says to just copy, but not
1063 * append our selves to the transit NHS list
1067 case NHRP_EXTENSION_RESPONDER_ADDRESS
:
1068 /* Supported compulsory extensions, and any
1069 * non-compulsory that is not explicitly handled,
1070 * should be just copied.
1072 zbuf_copy(zb
, &extpl
, len
);
1075 nhrp_ext_complete(zb
, dst
);
1078 nhrp_packet_complete(zb
, hdr
);
1079 nhrp_peer_send(p
, zb
);
1084 nhrp_packet_debug(pp
->pkt
, "FWD-FAIL");
1089 static void nhrp_packet_debug(struct zbuf
*zb
, const char *dir
)
1091 char buf
[2][SU_ADDRSTRLEN
];
1092 union sockunion src_nbma
, src_proto
, dst_proto
;
1093 struct nhrp_packet_header
*hdr
;
1097 if (likely(!(debug_flags
& NHRP_DEBUG_COMMON
)))
1100 zbuf_init(&zhdr
, zb
->buf
, zb
->tail
- zb
->buf
, zb
->tail
- zb
->buf
);
1101 hdr
= nhrp_packet_pull(&zhdr
, &src_nbma
, &src_proto
, &dst_proto
);
1103 sockunion2str(&src_proto
, buf
[0], sizeof(buf
[0]));
1104 sockunion2str(&dst_proto
, buf
[1], sizeof(buf
[1]));
1106 reply
= packet_types
[hdr
->type
].type
== PACKET_REPLY
;
1107 debugf(NHRP_DEBUG_COMMON
, "%s %s(%d) %s -> %s", dir
,
1108 (packet_types
[hdr
->type
].name
? packet_types
[hdr
->type
].name
1110 hdr
->type
, reply
? buf
[1] : buf
[0], reply
? buf
[0] : buf
[1]);
1113 static int proto2afi(uint16_t proto
)
1124 struct nhrp_route_info
{
1126 struct interface
*ifp
;
1130 void nhrp_peer_recv(struct nhrp_peer
*p
, struct zbuf
*zb
)
1132 struct nhrp_packet_header
*hdr
;
1133 struct nhrp_vc
*vc
= p
->vc
;
1134 struct interface
*ifp
= p
->ifp
;
1135 struct nhrp_interface
*nifp
= ifp
->info
;
1136 struct nhrp_packet_parser pp
;
1137 struct nhrp_peer
*peer
= NULL
;
1138 struct nhrp_reqid
*reqid
;
1139 const char *info
= NULL
;
1140 union sockunion
*target_addr
;
1141 unsigned paylen
, extoff
, extlen
, realsize
;
1142 afi_t nbma_afi
, proto_afi
;
1144 debugf(NHRP_DEBUG_KERNEL
, "PACKET: Recv %pSU -> %pSU", &vc
->remote
.nbma
,
1148 info
= "peer not online";
1152 if (nhrp_packet_calculate_checksum(zb
->head
, zbuf_used(zb
)) != 0) {
1153 info
= "bad checksum";
1157 realsize
= zbuf_used(zb
);
1158 hdr
= nhrp_packet_pull(zb
, &pp
.src_nbma
, &pp
.src_proto
, &pp
.dst_proto
);
1160 info
= "corrupt header";
1169 nbma_afi
= htons(hdr
->afnum
);
1170 proto_afi
= proto2afi(htons(hdr
->protocol_type
));
1171 if (hdr
->type
> NHRP_PACKET_MAX
|| hdr
->version
!= NHRP_VERSION_RFC2332
1172 || nbma_afi
>= AFI_MAX
|| proto_afi
== AF_UNSPEC
1173 || packet_types
[hdr
->type
].type
== PACKET_UNKNOWN
1174 || htons(hdr
->packet_size
) > realsize
) {
1176 "From %pSU: error: packet type %d, version %d, AFI %d, proto %x, size %d (real size %d)",
1177 &vc
->remote
.nbma
, (int)hdr
->type
, (int)hdr
->version
,
1178 (int)nbma_afi
, (int)htons(hdr
->protocol_type
),
1179 (int)htons(hdr
->packet_size
), (int)realsize
);
1182 pp
.if_ad
= &((struct nhrp_interface
*)ifp
->info
)->afi
[proto_afi
];
1184 extoff
= htons(hdr
->extension_offset
);
1186 assert(zb
->head
> zb
->buf
);
1187 uint32_t header_offset
= zb
->head
- zb
->buf
;
1188 if (extoff
>= realsize
) {
1189 info
= "extoff larger than packet";
1192 if (extoff
< header_offset
) {
1193 info
= "extoff smaller than header offset";
1196 paylen
= extoff
- header_offset
;
1198 paylen
= zbuf_used(zb
);
1200 zbuf_init(&pp
.payload
, zbuf_pulln(zb
, paylen
), paylen
, paylen
);
1201 extlen
= zbuf_used(zb
);
1202 zbuf_init(&pp
.extensions
, zbuf_pulln(zb
, extlen
), extlen
, extlen
);
1204 if (!nifp
->afi
[proto_afi
].network_id
) {
1205 info
= "nhrp not enabled";
1209 nhrp_packet_debug(zb
, "Recv");
1211 /* FIXME: Check authentication here. This extension needs to be
1214 /* Figure out if this is local */
1215 target_addr
= (packet_types
[hdr
->type
].type
== PACKET_REPLY
)
1219 if (sockunion_same(&pp
.src_proto
, &pp
.dst_proto
))
1220 pp
.route_type
= NHRP_ROUTE_LOCAL
;
1222 pp
.route_type
= nhrp_route_address(pp
.ifp
, target_addr
,
1223 &pp
.route_prefix
, &peer
);
1225 switch (pp
.route_type
) {
1226 case NHRP_ROUTE_LOCAL
:
1227 nhrp_packet_debug(zb
, "!LOCAL");
1228 if (packet_types
[hdr
->type
].type
== PACKET_REPLY
) {
1229 reqid
= nhrp_reqid_lookup(&nhrp_packet_reqid
,
1230 htonl(hdr
->u
.request_id
));
1232 reqid
->cb(reqid
, &pp
);
1235 nhrp_packet_debug(zb
, "!UNKNOWN-REQID");
1236 /* FIXME: send error-indication */
1239 /* fallthru */ /* FIXME: double check, is this correct? */
1240 case NHRP_ROUTE_OFF_NBMA
:
1241 if (packet_types
[hdr
->type
].handler
) {
1242 packet_types
[hdr
->type
].handler(&pp
);
1246 case NHRP_ROUTE_NBMA_NEXTHOP
:
1247 nhrp_peer_forward(peer
, &pp
);
1249 case NHRP_ROUTE_BLACKHOLE
:
1255 zlog_info("From %pSU: error: %s", &vc
->remote
.nbma
, info
);
1258 nhrp_peer_unref(peer
);