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
)
42 struct nhrp_interface
*nifp
= p
->ifp
->info
;
44 if (p
->ref
|| notifier_active(&p
->notifier_list
))
47 debugf(NHRP_DEBUG_COMMON
, "Deleting peer ref:%d remote:%s local:%s",
49 sockunion2str(&p
->vc
->remote
.nbma
, buf
[0], sizeof(buf
[0])),
50 sockunion2str(&p
->vc
->local
.nbma
, buf
[1], sizeof(buf
[1])));
52 THREAD_OFF(p
->t_fallback
);
53 hash_release(nifp
->peer_hash
, p
);
54 nhrp_interface_notify_del(p
->ifp
, &p
->ifp_notifier
);
55 nhrp_vc_notify_del(p
->vc
, &p
->vc_notifier
);
56 XFREE(MTYPE_NHRP_PEER
, p
);
59 static int nhrp_peer_notify_up(struct thread
*t
)
61 struct nhrp_peer
*p
= THREAD_ARG(t
);
62 struct nhrp_vc
*vc
= p
->vc
;
63 struct interface
*ifp
= p
->ifp
;
64 struct nhrp_interface
*nifp
= ifp
->info
;
67 if (nifp
->enabled
&& (!nifp
->ipsec_profile
|| vc
->ipsec
)) {
70 notifier_call(&p
->notifier_list
, NOTIFY_PEER_UP
);
77 static void __nhrp_peer_check(struct nhrp_peer
*p
)
79 struct nhrp_vc
*vc
= p
->vc
;
80 struct interface
*ifp
= p
->ifp
;
81 struct nhrp_interface
*nifp
= ifp
->info
;
84 online
= nifp
->enabled
&& (!nifp
->ipsec_profile
|| vc
->ipsec
);
85 if (p
->online
!= online
) {
86 THREAD_OFF(p
->t_fallback
);
87 if (online
&& notifier_active(&p
->notifier_list
)) {
88 /* If we requested the IPsec connection, delay
89 * the up notification a bit to allow things
90 * settle down. This allows IKE to install
92 thread_add_timer_msec(master
, nhrp_peer_notify_up
, p
,
98 notifier_call(&p
->notifier_list
,
101 p
->requested
= p
->fallback_requested
= 0;
102 notifier_call(&p
->notifier_list
,
110 static void nhrp_peer_vc_notify(struct notifier_block
*n
, unsigned long cmd
)
112 struct nhrp_peer
*p
= container_of(n
, struct nhrp_peer
, vc_notifier
);
115 case NOTIFY_VC_IPSEC_CHANGED
:
116 __nhrp_peer_check(p
);
118 case NOTIFY_VC_IPSEC_UPDATE_NBMA
:
120 notifier_call(&p
->notifier_list
, NOTIFY_PEER_NBMA_CHANGING
);
126 static void nhrp_peer_ifp_notify(struct notifier_block
*n
, unsigned long cmd
)
128 struct nhrp_peer
*p
= container_of(n
, struct nhrp_peer
, ifp_notifier
);
129 struct nhrp_interface
*nifp
;
134 case NOTIFY_INTERFACE_UP
:
135 case NOTIFY_INTERFACE_DOWN
:
136 __nhrp_peer_check(p
);
138 case NOTIFY_INTERFACE_NBMA_CHANGED
:
139 /* Source NBMA changed, rebind to new VC */
141 vc
= nhrp_vc_get(&nifp
->nbma
, &p
->vc
->remote
.nbma
, 1);
142 if (vc
&& p
->vc
!= vc
) {
143 nhrp_vc_notify_del(p
->vc
, &p
->vc_notifier
);
145 nhrp_vc_notify_add(p
->vc
, &p
->vc_notifier
,
146 nhrp_peer_vc_notify
);
147 __nhrp_peer_check(p
);
149 /* fallthru */ /* to post config update */
150 case NOTIFY_INTERFACE_ADDRESS_CHANGED
:
151 notifier_call(&p
->notifier_list
, NOTIFY_PEER_IFCONFIG_CHANGED
);
153 case NOTIFY_INTERFACE_MTU_CHANGED
:
154 notifier_call(&p
->notifier_list
, NOTIFY_PEER_MTU_CHANGED
);
160 static unsigned int nhrp_peer_key(const void *peer_data
)
162 const struct nhrp_peer
*p
= peer_data
;
163 return sockunion_hash(&p
->vc
->remote
.nbma
);
166 static bool nhrp_peer_cmp(const void *cache_data
, const void *key_data
)
168 const struct nhrp_peer
*a
= cache_data
;
169 const struct nhrp_peer
*b
= key_data
;
171 return a
->ifp
== b
->ifp
&& a
->vc
== b
->vc
;
174 static void *nhrp_peer_create(void *data
)
176 struct nhrp_peer
*p
, *key
= data
;
178 p
= XMALLOC(MTYPE_NHRP_PEER
, sizeof(*p
));
180 *p
= (struct nhrp_peer
){
185 NOTIFIER_LIST_INITIALIZER(&p
->notifier_list
),
187 nhrp_vc_notify_add(p
->vc
, &p
->vc_notifier
, nhrp_peer_vc_notify
);
188 nhrp_interface_notify_add(p
->ifp
, &p
->ifp_notifier
,
189 nhrp_peer_ifp_notify
);
194 static void do_peer_hash_free(struct hash_bucket
*hb
,
195 void *arg
__attribute__((__unused__
)))
197 struct nhrp_peer
*p
= hb
->data
;
198 nhrp_peer_check_delete(p
);
201 void nhrp_peer_interface_del(struct interface
*ifp
)
203 struct nhrp_interface
*nifp
= ifp
->info
;
205 debugf(NHRP_DEBUG_COMMON
, "Cleaning up undeleted peer entries (%lu)",
206 nifp
->peer_hash
? nifp
->peer_hash
->count
: 0);
208 if (nifp
->peer_hash
) {
209 hash_iterate(nifp
->peer_hash
, do_peer_hash_free
, NULL
);
210 assert(nifp
->peer_hash
->count
== 0);
211 hash_free(nifp
->peer_hash
);
215 struct nhrp_peer
*nhrp_peer_get(struct interface
*ifp
,
216 const union sockunion
*remote_nbma
)
218 struct nhrp_interface
*nifp
= ifp
->info
;
219 struct nhrp_peer key
, *p
;
222 if (!nifp
->peer_hash
) {
223 nifp
->peer_hash
= hash_create(nhrp_peer_key
, nhrp_peer_cmp
,
225 if (!nifp
->peer_hash
)
229 vc
= nhrp_vc_get(&nifp
->nbma
, remote_nbma
, 1);
236 p
= hash_get(nifp
->peer_hash
, &key
, nhrp_peer_create
);
239 __nhrp_peer_check(p
);
244 struct nhrp_peer
*nhrp_peer_ref(struct nhrp_peer
*p
)
251 void nhrp_peer_unref(struct nhrp_peer
*p
)
255 nhrp_peer_check_delete(p
);
259 static int nhrp_peer_request_timeout(struct thread
*t
)
261 struct nhrp_peer
*p
= THREAD_ARG(t
);
262 struct nhrp_vc
*vc
= p
->vc
;
263 struct interface
*ifp
= p
->ifp
;
264 struct nhrp_interface
*nifp
= ifp
->info
;
266 p
->t_fallback
= NULL
;
271 if (nifp
->ipsec_fallback_profile
&& !p
->prio
272 && !p
->fallback_requested
) {
273 p
->fallback_requested
= 1;
274 vici_request_vc(nifp
->ipsec_fallback_profile
, &vc
->local
.nbma
,
275 &vc
->remote
.nbma
, p
->prio
);
276 thread_add_timer(master
, nhrp_peer_request_timeout
, p
, 30,
279 p
->requested
= p
->fallback_requested
= 0;
285 int nhrp_peer_check(struct nhrp_peer
*p
, int establish
)
287 struct nhrp_vc
*vc
= p
->vc
;
288 struct interface
*ifp
= p
->ifp
;
289 struct nhrp_interface
*nifp
= ifp
->info
;
297 if (!nifp
->ipsec_profile
)
299 if (sockunion_family(&vc
->local
.nbma
) == AF_UNSPEC
)
304 p
->prio
= establish
> 1;
306 vici_request_vc(nifp
->ipsec_profile
, &vc
->local
.nbma
, &vc
->remote
.nbma
,
308 thread_add_timer(master
, nhrp_peer_request_timeout
, p
,
309 (nifp
->ipsec_fallback_profile
&& !p
->prio
) ? 15 : 30,
315 void nhrp_peer_notify_add(struct nhrp_peer
*p
, struct notifier_block
*n
,
318 notifier_add(n
, &p
->notifier_list
, fn
);
321 void nhrp_peer_notify_del(struct nhrp_peer
*p
, struct notifier_block
*n
)
324 nhrp_peer_check_delete(p
);
327 void nhrp_peer_send(struct nhrp_peer
*p
, struct zbuf
*zb
)
331 nhrp_packet_debug(zb
, "Send");
336 debugf(NHRP_DEBUG_KERNEL
, "PACKET: Send %s -> %s",
337 sockunion2str(&p
->vc
->local
.nbma
, buf
[0], sizeof(buf
[0])),
338 sockunion2str(&p
->vc
->remote
.nbma
, buf
[1], sizeof(buf
[1])));
340 os_sendmsg(zb
->head
, zbuf_used(zb
), p
->ifp
->ifindex
,
341 sockunion_get_addr(&p
->vc
->remote
.nbma
),
342 sockunion_get_addrlen(&p
->vc
->remote
.nbma
));
346 static void nhrp_handle_resolution_req(struct nhrp_packet_parser
*pp
)
348 struct interface
*ifp
= pp
->ifp
;
349 struct zbuf
*zb
, payload
;
350 struct nhrp_packet_header
*hdr
;
351 struct nhrp_cie_header
*cie
;
352 struct nhrp_extension_header
*ext
;
353 struct nhrp_cache
*c
;
354 union sockunion cie_nbma
, cie_proto
, *proto_addr
, *nbma_addr
;
355 int holdtime
, prefix_len
, hostprefix_len
;
356 struct nhrp_interface
*nifp
= ifp
->info
;
357 struct nhrp_peer
*peer
;
359 char buf
[SU_ADDRSTRLEN
];
361 if (!(pp
->if_ad
->flags
& NHRP_IFF_SHORTCUT
)) {
362 debugf(NHRP_DEBUG_COMMON
, "Shortcuts disabled");
363 /* FIXME: Send error indication? */
367 if (pp
->if_ad
->network_id
&& pp
->route_type
== NHRP_ROUTE_OFF_NBMA
368 && pp
->route_prefix
.prefixlen
< 8) {
369 debugf(NHRP_DEBUG_COMMON
,
370 "Shortcut to more generic than /8 dropped");
374 debugf(NHRP_DEBUG_COMMON
, "Parsing and replying to Resolution Req");
376 if (nhrp_route_address(ifp
, &pp
->src_proto
, NULL
, &peer
)
377 != NHRP_ROUTE_NBMA_NEXTHOP
)
380 /* Copy payload CIE */
381 hostprefix_len
= 8 * sockunion_get_addrlen(&pp
->if_ad
->addr
);
382 paylen
= zbuf_used(&pp
->payload
);
383 debugf(NHRP_DEBUG_COMMON
, "shortcut res_rep: paylen %zu", paylen
);
385 while ((cie
= nhrp_cie_pull(&pp
->payload
, pp
->hdr
, &cie_nbma
,
388 prefix_len
= cie
->prefix_length
;
389 debugf(NHRP_DEBUG_COMMON
,
390 "shortcut res_rep: parsing CIE with prefixlen=%u",
392 if (prefix_len
== 0 || prefix_len
>= hostprefix_len
)
393 prefix_len
= hostprefix_len
;
395 if (prefix_len
!= hostprefix_len
397 & htons(NHRP_FLAG_REGISTRATION_UNIQUE
))) {
398 cie
->code
= NHRP_CODE_BINDING_NON_UNIQUE
;
402 /* We currently support only unique prefix registrations */
403 if (prefix_len
!= hostprefix_len
) {
404 cie
->code
= NHRP_CODE_ADMINISTRATIVELY_PROHIBITED
;
408 proto_addr
= (sockunion_family(&cie_proto
) == AF_UNSPEC
)
411 nbma_addr
= (sockunion_family(&cie_nbma
) == AF_UNSPEC
)
415 holdtime
= htons(cie
->holding_time
);
416 debugf(NHRP_DEBUG_COMMON
,
417 "shortcut res_rep: holdtime is %u (if 0, using %u)",
418 holdtime
, pp
->if_ad
->holdtime
);
420 holdtime
= pp
->if_ad
->holdtime
;
422 c
= nhrp_cache_get(ifp
, proto_addr
, 1);
424 debugf(NHRP_DEBUG_COMMON
,
425 "shortcut res_rep: no cache found");
426 cie
->code
= NHRP_CODE_INSUFFICIENT_RESOURCES
;
430 sockunion2str(nbma_addr
, buf
, sizeof(buf
));
432 debugf(NHRP_DEBUG_COMMON
,
433 "shortcut res_rep: updating binding for nmba addr %s",
434 nbma_addr
? buf
: "(NULL)");
435 if (!nhrp_cache_update_binding(c
, NHRP_CACHE_DYNAMIC
, holdtime
,
436 nhrp_peer_ref(pp
->peer
),
437 htons(cie
->mtu
), nbma_addr
)) {
438 cie
->code
= NHRP_CODE_ADMINISTRATIVELY_PROHIBITED
;
442 cie
->code
= NHRP_CODE_SUCCESS
;
446 zb
= zbuf_alloc(1500);
447 hdr
= nhrp_packet_push(zb
, NHRP_PACKET_RESOLUTION_REPLY
, &pp
->src_nbma
,
448 &pp
->src_proto
, &pp
->dst_proto
);
450 /* Copied information from request */
451 hdr
->flags
= pp
->hdr
->flags
452 & htons(NHRP_FLAG_RESOLUTION_SOURCE_IS_ROUTER
453 | NHRP_FLAG_RESOLUTION_SOURCE_STABLE
);
454 hdr
->flags
|= htons(NHRP_FLAG_RESOLUTION_DESTINATION_STABLE
455 | NHRP_FLAG_RESOLUTION_AUTHORATIVE
);
456 hdr
->u
.request_id
= pp
->hdr
->u
.request_id
;
458 /* CIE payload for the reply packet */
459 cie
= nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
, &nifp
->nbma
,
461 cie
->holding_time
= htons(pp
->if_ad
->holdtime
);
462 cie
->mtu
= htons(pp
->if_ad
->mtu
);
463 if (pp
->if_ad
->network_id
&& pp
->route_type
== NHRP_ROUTE_OFF_NBMA
)
464 cie
->prefix_length
= pp
->route_prefix
.prefixlen
;
467 8 * sockunion_get_addrlen(&pp
->if_ad
->addr
);
469 /* Handle extensions */
470 while ((ext
= nhrp_ext_pull(&pp
->extensions
, &payload
)) != NULL
) {
471 switch (htons(ext
->type
) & ~NHRP_EXTENSION_FLAG_COMPULSORY
) {
472 case NHRP_EXTENSION_NAT_ADDRESS
:
473 if (sockunion_family(&nifp
->nat_nbma
) == AF_UNSPEC
)
475 ext
= nhrp_ext_push(zb
, hdr
,
476 NHRP_EXTENSION_NAT_ADDRESS
);
479 cie
= nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
,
480 &nifp
->nat_nbma
, &pp
->if_ad
->addr
);
483 nhrp_ext_complete(zb
, ext
);
486 if (nhrp_ext_reply(zb
, hdr
, ifp
, ext
, &payload
) < 0)
492 nhrp_packet_complete(zb
, hdr
);
493 nhrp_peer_send(peer
, zb
);
495 nhrp_peer_unref(peer
);
499 static void nhrp_handle_registration_request(struct nhrp_packet_parser
*p
)
501 struct interface
*ifp
= p
->ifp
;
502 struct zbuf
*zb
, payload
;
503 struct nhrp_packet_header
*hdr
;
504 struct nhrp_cie_header
*cie
;
505 struct nhrp_extension_header
*ext
;
506 struct nhrp_cache
*c
;
507 union sockunion cie_nbma
, cie_proto
, *proto_addr
, *nbma_addr
,
509 int holdtime
, prefix_len
, hostprefix_len
, natted
= 0;
513 debugf(NHRP_DEBUG_COMMON
, "Parsing and replying to Registration Req");
514 hostprefix_len
= 8 * sockunion_get_addrlen(&p
->if_ad
->addr
);
516 if (!sockunion_same(&p
->src_nbma
, &p
->peer
->vc
->remote
.nbma
))
520 zb
= zbuf_alloc(1500);
521 hdr
= nhrp_packet_push(zb
, NHRP_PACKET_REGISTRATION_REPLY
, &p
->src_nbma
,
522 &p
->src_proto
, &p
->if_ad
->addr
);
524 /* Copied information from request */
525 hdr
->flags
= p
->hdr
->flags
& htons(NHRP_FLAG_REGISTRATION_UNIQUE
526 | NHRP_FLAG_REGISTRATION_NAT
);
527 hdr
->u
.request_id
= p
->hdr
->u
.request_id
;
529 /* Copy payload CIEs */
530 paylen
= zbuf_used(&p
->payload
);
531 pay
= zbuf_pushn(zb
, paylen
);
534 memcpy(pay
, zbuf_pulln(&p
->payload
, paylen
), paylen
);
535 zbuf_init(&payload
, pay
, paylen
, paylen
);
537 while ((cie
= nhrp_cie_pull(&payload
, hdr
, &cie_nbma
, &cie_proto
))
539 prefix_len
= cie
->prefix_length
;
540 if (prefix_len
== 0 || prefix_len
>= hostprefix_len
)
541 prefix_len
= hostprefix_len
;
543 if (prefix_len
!= hostprefix_len
545 & htons(NHRP_FLAG_REGISTRATION_UNIQUE
))) {
546 cie
->code
= NHRP_CODE_BINDING_NON_UNIQUE
;
550 /* We currently support only unique prefix registrations */
551 if (prefix_len
!= hostprefix_len
) {
552 cie
->code
= NHRP_CODE_ADMINISTRATIVELY_PROHIBITED
;
556 proto_addr
= (sockunion_family(&cie_proto
) == AF_UNSPEC
)
559 nbma_addr
= (sockunion_family(&cie_nbma
) == AF_UNSPEC
)
564 nbma_natoa
= nbma_addr
;
567 holdtime
= htons(cie
->holding_time
);
569 holdtime
= p
->if_ad
->holdtime
;
571 c
= nhrp_cache_get(ifp
, proto_addr
, 1);
573 cie
->code
= NHRP_CODE_INSUFFICIENT_RESOURCES
;
577 if (!nhrp_cache_update_binding(c
, NHRP_CACHE_DYNAMIC
, holdtime
,
578 nhrp_peer_ref(p
->peer
),
579 htons(cie
->mtu
), nbma_natoa
)) {
580 cie
->code
= NHRP_CODE_ADMINISTRATIVELY_PROHIBITED
;
584 cie
->code
= NHRP_CODE_SUCCESS
;
587 /* Handle extensions */
588 while ((ext
= nhrp_ext_pull(&p
->extensions
, &payload
)) != NULL
) {
589 switch (htons(ext
->type
) & ~NHRP_EXTENSION_FLAG_COMPULSORY
) {
590 case NHRP_EXTENSION_NAT_ADDRESS
:
591 ext
= nhrp_ext_push(zb
, hdr
,
592 NHRP_EXTENSION_NAT_ADDRESS
);
595 zbuf_copy(zb
, &payload
, zbuf_used(&payload
));
597 nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
,
598 &p
->peer
->vc
->remote
.nbma
,
601 nhrp_ext_complete(zb
, ext
);
604 if (nhrp_ext_reply(zb
, hdr
, ifp
, ext
, &payload
) < 0)
610 nhrp_packet_complete(zb
, hdr
);
611 nhrp_peer_send(p
->peer
, zb
);
616 static int parse_ether_packet(struct zbuf
*zb
, uint16_t protocol_type
,
617 union sockunion
*src
, union sockunion
*dst
)
619 switch (protocol_type
) {
621 struct iphdr
*iph
= zbuf_pull(zb
, struct iphdr
);
624 sockunion_set(src
, AF_INET
,
625 (uint8_t *)&iph
->saddr
,
628 sockunion_set(dst
, AF_INET
,
629 (uint8_t *)&iph
->daddr
,
634 struct ipv6hdr
*iph
= zbuf_pull(zb
, struct ipv6hdr
);
637 sockunion_set(src
, AF_INET6
,
638 (uint8_t *)&iph
->saddr
,
641 sockunion_set(dst
, AF_INET6
,
642 (uint8_t *)&iph
->daddr
,
652 void nhrp_peer_send_indication(struct interface
*ifp
, uint16_t protocol_type
,
656 struct zbuf
*zb
, payload
;
657 struct nhrp_interface
*nifp
= ifp
->info
;
658 struct nhrp_afi_data
*if_ad
;
659 struct nhrp_packet_header
*hdr
;
661 char buf
[2][SU_ADDRSTRLEN
];
667 if (!parse_ether_packet(&payload
, protocol_type
, &dst
, NULL
))
670 if (nhrp_route_address(ifp
, &dst
, NULL
, &p
) != NHRP_ROUTE_NBMA_NEXTHOP
)
673 if_ad
= &nifp
->afi
[family2afi(sockunion_family(&dst
))];
674 if (!(if_ad
->flags
& NHRP_IFF_REDIRECT
)) {
675 debugf(NHRP_DEBUG_COMMON
,
676 "Send Traffic Indication to %s about packet to %s ignored",
677 sockunion2str(&p
->vc
->remote
.nbma
, buf
[0],
679 sockunion2str(&dst
, buf
[1], sizeof(buf
[1])));
683 debugf(NHRP_DEBUG_COMMON
,
684 "Send Traffic Indication to %s (online=%d) about packet to %s",
685 sockunion2str(&p
->vc
->remote
.nbma
, buf
[0], sizeof(buf
[0])),
686 p
->online
, sockunion2str(&dst
, buf
[1], sizeof(buf
[1])));
689 zb
= zbuf_alloc(1500);
690 hdr
= nhrp_packet_push(zb
, NHRP_PACKET_TRAFFIC_INDICATION
, &nifp
->nbma
,
694 /* Payload is the packet causing indication */
695 zbuf_copy(zb
, pkt
, zbuf_used(pkt
));
696 nhrp_packet_complete(zb
, hdr
);
697 nhrp_peer_send(p
, zb
);
702 static void nhrp_handle_error_ind(struct nhrp_packet_parser
*pp
)
704 struct zbuf origmsg
= pp
->payload
;
705 struct nhrp_packet_header
*hdr
;
706 struct nhrp_reqid
*reqid
;
707 union sockunion src_nbma
, src_proto
, dst_proto
;
708 char buf
[2][SU_ADDRSTRLEN
];
710 hdr
= nhrp_packet_pull(&origmsg
, &src_nbma
, &src_proto
, &dst_proto
);
714 debugf(NHRP_DEBUG_COMMON
,
715 "Error Indication from %s about packet to %s ignored",
716 sockunion2str(&pp
->src_proto
, buf
[0], sizeof(buf
[0])),
717 sockunion2str(&dst_proto
, buf
[1], sizeof(buf
[1])));
719 reqid
= nhrp_reqid_lookup(&nhrp_packet_reqid
, htonl(hdr
->u
.request_id
));
721 reqid
->cb(reqid
, pp
);
724 static void nhrp_handle_traffic_ind(struct nhrp_packet_parser
*p
)
727 char buf
[2][SU_ADDRSTRLEN
];
729 if (!parse_ether_packet(&p
->payload
, htons(p
->hdr
->protocol_type
), NULL
,
733 debugf(NHRP_DEBUG_COMMON
,
734 "Traffic Indication from %s about packet to %s: %s",
735 sockunion2str(&p
->src_proto
, buf
[0], sizeof(buf
[0])),
736 sockunion2str(&dst
, buf
[1], sizeof(buf
[1])),
737 (p
->if_ad
->flags
& NHRP_IFF_SHORTCUT
) ? "trying shortcut"
740 if (p
->if_ad
->flags
& NHRP_IFF_SHORTCUT
)
741 nhrp_shortcut_initiate(&dst
);
752 enum packet_type_t type
;
754 void (*handler
)(struct nhrp_packet_parser
*);
755 } packet_types
[] = {[0] =
757 .type
= PACKET_UNKNOWN
,
760 [NHRP_PACKET_RESOLUTION_REQUEST
] =
762 .type
= PACKET_REQUEST
,
763 .name
= "Resolution-Request",
764 .handler
= nhrp_handle_resolution_req
,
766 [NHRP_PACKET_RESOLUTION_REPLY
] =
768 .type
= PACKET_REPLY
,
769 .name
= "Resolution-Reply",
771 [NHRP_PACKET_REGISTRATION_REQUEST
] =
773 .type
= PACKET_REQUEST
,
774 .name
= "Registration-Request",
775 .handler
= nhrp_handle_registration_request
,
777 [NHRP_PACKET_REGISTRATION_REPLY
] =
779 .type
= PACKET_REPLY
,
780 .name
= "Registration-Reply",
782 [NHRP_PACKET_PURGE_REQUEST
] =
784 .type
= PACKET_REQUEST
,
785 .name
= "Purge-Request",
787 [NHRP_PACKET_PURGE_REPLY
] =
789 .type
= PACKET_REPLY
,
790 .name
= "Purge-Reply",
792 [NHRP_PACKET_ERROR_INDICATION
] =
794 .type
= PACKET_INDICATION
,
795 .name
= "Error-Indication",
796 .handler
= nhrp_handle_error_ind
,
798 [NHRP_PACKET_TRAFFIC_INDICATION
] = {
799 .type
= PACKET_INDICATION
,
800 .name
= "Traffic-Indication",
801 .handler
= nhrp_handle_traffic_ind
,
804 static void nhrp_peer_forward(struct nhrp_peer
*p
,
805 struct nhrp_packet_parser
*pp
)
807 struct zbuf
*zb
, extpl
;
808 struct nhrp_packet_header
*hdr
;
809 struct nhrp_extension_header
*ext
, *dst
;
810 struct nhrp_cie_header
*cie
;
811 struct nhrp_interface
*nifp
= pp
->ifp
->info
;
812 struct nhrp_afi_data
*if_ad
= pp
->if_ad
;
813 union sockunion cie_nbma
, cie_protocol
;
816 if (pp
->hdr
->hop_count
== 0)
819 /* Create forward packet - copy header */
820 zb
= zbuf_alloc(1500);
821 hdr
= nhrp_packet_push(zb
, pp
->hdr
->type
, &pp
->src_nbma
, &pp
->src_proto
,
823 hdr
->flags
= pp
->hdr
->flags
;
824 hdr
->hop_count
= pp
->hdr
->hop_count
- 1;
825 hdr
->u
.request_id
= pp
->hdr
->u
.request_id
;
828 zbuf_copy(zb
, &pp
->payload
, zbuf_used(&pp
->payload
));
830 /* Copy extensions */
831 while ((ext
= nhrp_ext_pull(&pp
->extensions
, &extpl
)) != NULL
) {
832 type
= htons(ext
->type
) & ~NHRP_EXTENSION_FLAG_COMPULSORY
;
833 len
= htons(ext
->length
);
835 if (type
== NHRP_EXTENSION_END
)
838 dst
= nhrp_ext_push(zb
, hdr
, htons(ext
->type
));
843 case NHRP_EXTENSION_FORWARD_TRANSIT_NHS
:
844 case NHRP_EXTENSION_REVERSE_TRANSIT_NHS
:
845 zbuf_put(zb
, extpl
.head
, len
);
846 if ((type
== NHRP_EXTENSION_REVERSE_TRANSIT_NHS
)
847 == (packet_types
[hdr
->type
].type
== PACKET_REPLY
)) {
848 /* Check NHS list for forwarding loop */
849 while (nhrp_cie_pull(&extpl
, pp
->hdr
,
851 &cie_protocol
) != NULL
) {
852 if (sockunion_same(&p
->vc
->remote
.nbma
,
856 /* Append our selves to the list */
857 cie
= nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
,
858 &nifp
->nbma
, &if_ad
->addr
);
861 cie
->holding_time
= htons(if_ad
->holdtime
);
865 if (htons(ext
->type
) & NHRP_EXTENSION_FLAG_COMPULSORY
)
866 /* FIXME: RFC says to just copy, but not
867 * append our selves to the transit NHS list */
870 case NHRP_EXTENSION_RESPONDER_ADDRESS
:
871 /* Supported compulsory extensions, and any
872 * non-compulsory that is not explicitly handled,
873 * should be just copied. */
874 zbuf_copy(zb
, &extpl
, len
);
877 nhrp_ext_complete(zb
, dst
);
880 nhrp_packet_complete(zb
, hdr
);
881 nhrp_peer_send(p
, zb
);
885 nhrp_packet_debug(pp
->pkt
, "FWD-FAIL");
889 static void nhrp_packet_debug(struct zbuf
*zb
, const char *dir
)
891 char buf
[2][SU_ADDRSTRLEN
];
892 union sockunion src_nbma
, src_proto
, dst_proto
;
893 struct nhrp_packet_header
*hdr
;
897 if (likely(!(debug_flags
& NHRP_DEBUG_COMMON
)))
900 zbuf_init(&zhdr
, zb
->buf
, zb
->tail
- zb
->buf
, zb
->tail
- zb
->buf
);
901 hdr
= nhrp_packet_pull(&zhdr
, &src_nbma
, &src_proto
, &dst_proto
);
903 sockunion2str(&src_proto
, buf
[0], sizeof(buf
[0]));
904 sockunion2str(&dst_proto
, buf
[1], sizeof(buf
[1]));
906 reply
= packet_types
[hdr
->type
].type
== PACKET_REPLY
;
907 debugf(NHRP_DEBUG_COMMON
, "%s %s(%d) %s -> %s", dir
,
908 (packet_types
[hdr
->type
].name
? packet_types
[hdr
->type
].name
910 hdr
->type
, reply
? buf
[1] : buf
[0], reply
? buf
[0] : buf
[1]);
913 static int proto2afi(uint16_t proto
)
924 struct nhrp_route_info
{
926 struct interface
*ifp
;
930 void nhrp_peer_recv(struct nhrp_peer
*p
, struct zbuf
*zb
)
932 char buf
[2][SU_ADDRSTRLEN
];
933 struct nhrp_packet_header
*hdr
;
934 struct nhrp_vc
*vc
= p
->vc
;
935 struct interface
*ifp
= p
->ifp
;
936 struct nhrp_interface
*nifp
= ifp
->info
;
937 struct nhrp_packet_parser pp
;
938 struct nhrp_peer
*peer
= NULL
;
939 struct nhrp_reqid
*reqid
;
940 const char *info
= NULL
;
941 union sockunion
*target_addr
;
942 unsigned paylen
, extoff
, extlen
, realsize
;
943 afi_t nbma_afi
, proto_afi
;
945 debugf(NHRP_DEBUG_KERNEL
, "PACKET: Recv %s -> %s",
946 sockunion2str(&vc
->remote
.nbma
, buf
[0], sizeof(buf
[0])),
947 sockunion2str(&vc
->local
.nbma
, buf
[1], sizeof(buf
[1])));
950 info
= "peer not online";
954 if (nhrp_packet_calculate_checksum(zb
->head
, zbuf_used(zb
)) != 0) {
955 info
= "bad checksum";
959 realsize
= zbuf_used(zb
);
960 hdr
= nhrp_packet_pull(zb
, &pp
.src_nbma
, &pp
.src_proto
, &pp
.dst_proto
);
962 info
= "corrupt header";
971 nbma_afi
= htons(hdr
->afnum
);
972 proto_afi
= proto2afi(htons(hdr
->protocol_type
));
973 if (hdr
->type
> NHRP_PACKET_MAX
|| hdr
->version
!= NHRP_VERSION_RFC2332
974 || nbma_afi
>= AFI_MAX
|| proto_afi
== AF_UNSPEC
975 || packet_types
[hdr
->type
].type
== PACKET_UNKNOWN
976 || htons(hdr
->packet_size
) > realsize
) {
978 "From %s: error: packet type %d, version %d, AFI %d, proto %x, size %d (real size %d)",
979 sockunion2str(&vc
->remote
.nbma
, buf
[0], sizeof(buf
[0])),
980 (int)hdr
->type
, (int)hdr
->version
, (int)nbma_afi
,
981 (int)htons(hdr
->protocol_type
),
982 (int)htons(hdr
->packet_size
), (int)realsize
);
985 pp
.if_ad
= &((struct nhrp_interface
*)ifp
->info
)->afi
[proto_afi
];
987 extoff
= htons(hdr
->extension_offset
);
989 assert(zb
->head
> zb
->buf
);
990 uint32_t header_offset
= zb
->head
- zb
->buf
;
991 if (extoff
>= realsize
) {
992 info
= "extoff larger than packet";
995 if (extoff
< header_offset
) {
996 info
= "extoff smaller than header offset";
999 paylen
= extoff
- header_offset
;
1001 paylen
= zbuf_used(zb
);
1003 zbuf_init(&pp
.payload
, zbuf_pulln(zb
, paylen
), paylen
, paylen
);
1004 extlen
= zbuf_used(zb
);
1005 zbuf_init(&pp
.extensions
, zbuf_pulln(zb
, extlen
), extlen
, extlen
);
1007 if (!nifp
->afi
[proto_afi
].network_id
) {
1008 info
= "nhrp not enabled";
1012 nhrp_packet_debug(zb
, "Recv");
1014 /* FIXME: Check authentication here. This extension needs to be
1017 /* Figure out if this is local */
1018 target_addr
= (packet_types
[hdr
->type
].type
== PACKET_REPLY
)
1022 if (sockunion_same(&pp
.src_proto
, &pp
.dst_proto
))
1023 pp
.route_type
= NHRP_ROUTE_LOCAL
;
1025 pp
.route_type
= nhrp_route_address(pp
.ifp
, target_addr
,
1026 &pp
.route_prefix
, &peer
);
1028 switch (pp
.route_type
) {
1029 case NHRP_ROUTE_LOCAL
:
1030 nhrp_packet_debug(zb
, "!LOCAL");
1031 if (packet_types
[hdr
->type
].type
== PACKET_REPLY
) {
1032 reqid
= nhrp_reqid_lookup(&nhrp_packet_reqid
,
1033 htonl(hdr
->u
.request_id
));
1035 reqid
->cb(reqid
, &pp
);
1038 nhrp_packet_debug(zb
, "!UNKNOWN-REQID");
1039 /* FIXME: send error-indication */
1042 /* fallthru */ /* FIXME: double check, is this correct? */
1043 case NHRP_ROUTE_OFF_NBMA
:
1044 if (packet_types
[hdr
->type
].handler
) {
1045 packet_types
[hdr
->type
].handler(&pp
);
1049 case NHRP_ROUTE_NBMA_NEXTHOP
:
1050 nhrp_peer_forward(peer
, &pp
);
1052 case NHRP_ROUTE_BLACKHOLE
:
1059 "From %s: error: %s",
1060 sockunion2str(&vc
->remote
.nbma
, buf
[0], sizeof(buf
[0])),
1064 nhrp_peer_unref(peer
);