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 THREAD_OFF(p
->t_fallback
);
47 hash_release(nifp
->peer_hash
, p
);
48 nhrp_interface_notify_del(p
->ifp
, &p
->ifp_notifier
);
49 nhrp_vc_notify_del(p
->vc
, &p
->vc_notifier
);
50 XFREE(MTYPE_NHRP_PEER
, p
);
53 static int nhrp_peer_notify_up(struct thread
*t
)
55 struct nhrp_peer
*p
= THREAD_ARG(t
);
56 struct nhrp_vc
*vc
= p
->vc
;
57 struct interface
*ifp
= p
->ifp
;
58 struct nhrp_interface
*nifp
= ifp
->info
;
61 if (nifp
->enabled
&& (!nifp
->ipsec_profile
|| vc
->ipsec
)) {
64 notifier_call(&p
->notifier_list
, NOTIFY_PEER_UP
);
71 static void __nhrp_peer_check(struct nhrp_peer
*p
)
73 struct nhrp_vc
*vc
= p
->vc
;
74 struct interface
*ifp
= p
->ifp
;
75 struct nhrp_interface
*nifp
= ifp
->info
;
78 online
= nifp
->enabled
&& (!nifp
->ipsec_profile
|| vc
->ipsec
);
79 if (p
->online
!= online
) {
80 THREAD_OFF(p
->t_fallback
);
81 if (online
&& notifier_active(&p
->notifier_list
)) {
82 /* If we requested the IPsec connection, delay
83 * the up notification a bit to allow things
84 * settle down. This allows IKE to install
86 thread_add_timer_msec(master
, nhrp_peer_notify_up
, p
,
92 notifier_call(&p
->notifier_list
,
95 p
->requested
= p
->fallback_requested
= 0;
96 notifier_call(&p
->notifier_list
,
104 static void nhrp_peer_vc_notify(struct notifier_block
*n
, unsigned long cmd
)
106 struct nhrp_peer
*p
= container_of(n
, struct nhrp_peer
, vc_notifier
);
109 case NOTIFY_VC_IPSEC_CHANGED
:
110 __nhrp_peer_check(p
);
112 case NOTIFY_VC_IPSEC_UPDATE_NBMA
:
114 notifier_call(&p
->notifier_list
, NOTIFY_PEER_NBMA_CHANGING
);
120 static void nhrp_peer_ifp_notify(struct notifier_block
*n
, unsigned long cmd
)
122 struct nhrp_peer
*p
= container_of(n
, struct nhrp_peer
, ifp_notifier
);
123 struct nhrp_interface
*nifp
;
128 case NOTIFY_INTERFACE_UP
:
129 case NOTIFY_INTERFACE_DOWN
:
130 __nhrp_peer_check(p
);
132 case NOTIFY_INTERFACE_NBMA_CHANGED
:
133 /* Source NBMA changed, rebind to new VC */
135 vc
= nhrp_vc_get(&nifp
->nbma
, &p
->vc
->remote
.nbma
, 1);
136 if (vc
&& p
->vc
!= vc
) {
137 nhrp_vc_notify_del(p
->vc
, &p
->vc_notifier
);
139 nhrp_vc_notify_add(p
->vc
, &p
->vc_notifier
,
140 nhrp_peer_vc_notify
);
141 __nhrp_peer_check(p
);
143 /* fallthru */ /* to post config update */
144 case NOTIFY_INTERFACE_ADDRESS_CHANGED
:
145 notifier_call(&p
->notifier_list
, NOTIFY_PEER_IFCONFIG_CHANGED
);
147 case NOTIFY_INTERFACE_MTU_CHANGED
:
148 notifier_call(&p
->notifier_list
, NOTIFY_PEER_MTU_CHANGED
);
154 static unsigned int nhrp_peer_key(void *peer_data
)
156 struct nhrp_peer
*p
= peer_data
;
157 return sockunion_hash(&p
->vc
->remote
.nbma
);
160 static bool nhrp_peer_cmp(const void *cache_data
, const void *key_data
)
162 const struct nhrp_peer
*a
= cache_data
;
163 const struct nhrp_peer
*b
= key_data
;
165 return a
->ifp
== b
->ifp
&& a
->vc
== b
->vc
;
168 static void *nhrp_peer_create(void *data
)
170 struct nhrp_peer
*p
, *key
= data
;
172 p
= XMALLOC(MTYPE_NHRP_PEER
, sizeof(*p
));
174 *p
= (struct nhrp_peer
){
179 NOTIFIER_LIST_INITIALIZER(&p
->notifier_list
),
181 nhrp_vc_notify_add(p
->vc
, &p
->vc_notifier
, nhrp_peer_vc_notify
);
182 nhrp_interface_notify_add(p
->ifp
, &p
->ifp_notifier
,
183 nhrp_peer_ifp_notify
);
188 struct nhrp_peer
*nhrp_peer_get(struct interface
*ifp
,
189 const union sockunion
*remote_nbma
)
191 struct nhrp_interface
*nifp
= ifp
->info
;
192 struct nhrp_peer key
, *p
;
195 if (!nifp
->peer_hash
) {
196 nifp
->peer_hash
= hash_create(nhrp_peer_key
, nhrp_peer_cmp
,
198 if (!nifp
->peer_hash
)
202 vc
= nhrp_vc_get(&nifp
->nbma
, remote_nbma
, 1);
209 p
= hash_get(nifp
->peer_hash
, &key
, nhrp_peer_create
);
212 __nhrp_peer_check(p
);
217 struct nhrp_peer
*nhrp_peer_ref(struct nhrp_peer
*p
)
224 void nhrp_peer_unref(struct nhrp_peer
*p
)
228 nhrp_peer_check_delete(p
);
232 static int nhrp_peer_request_timeout(struct thread
*t
)
234 struct nhrp_peer
*p
= THREAD_ARG(t
);
235 struct nhrp_vc
*vc
= p
->vc
;
236 struct interface
*ifp
= p
->ifp
;
237 struct nhrp_interface
*nifp
= ifp
->info
;
239 p
->t_fallback
= NULL
;
244 if (nifp
->ipsec_fallback_profile
&& !p
->prio
245 && !p
->fallback_requested
) {
246 p
->fallback_requested
= 1;
247 vici_request_vc(nifp
->ipsec_fallback_profile
, &vc
->local
.nbma
,
248 &vc
->remote
.nbma
, p
->prio
);
249 thread_add_timer(master
, nhrp_peer_request_timeout
, p
, 30,
252 p
->requested
= p
->fallback_requested
= 0;
258 int nhrp_peer_check(struct nhrp_peer
*p
, int establish
)
260 struct nhrp_vc
*vc
= p
->vc
;
261 struct interface
*ifp
= p
->ifp
;
262 struct nhrp_interface
*nifp
= ifp
->info
;
270 if (!nifp
->ipsec_profile
)
272 if (sockunion_family(&vc
->local
.nbma
) == AF_UNSPEC
)
275 p
->prio
= establish
> 1;
277 vici_request_vc(nifp
->ipsec_profile
, &vc
->local
.nbma
, &vc
->remote
.nbma
,
279 thread_add_timer(master
, nhrp_peer_request_timeout
, p
,
280 (nifp
->ipsec_fallback_profile
&& !p
->prio
) ? 15 : 30,
286 void nhrp_peer_notify_add(struct nhrp_peer
*p
, struct notifier_block
*n
,
289 notifier_add(n
, &p
->notifier_list
, fn
);
292 void nhrp_peer_notify_del(struct nhrp_peer
*p
, struct notifier_block
*n
)
295 nhrp_peer_check_delete(p
);
298 void nhrp_peer_send(struct nhrp_peer
*p
, struct zbuf
*zb
)
302 nhrp_packet_debug(zb
, "Send");
307 debugf(NHRP_DEBUG_KERNEL
, "PACKET: Send %s -> %s",
308 sockunion2str(&p
->vc
->local
.nbma
, buf
[0], sizeof buf
[0]),
309 sockunion2str(&p
->vc
->remote
.nbma
, buf
[1], sizeof buf
[1]));
311 os_sendmsg(zb
->head
, zbuf_used(zb
), p
->ifp
->ifindex
,
312 sockunion_get_addr(&p
->vc
->remote
.nbma
),
313 sockunion_get_addrlen(&p
->vc
->remote
.nbma
));
317 static void nhrp_handle_resolution_req(struct nhrp_packet_parser
*p
)
319 struct zbuf
*zb
, payload
;
320 struct nhrp_packet_header
*hdr
;
321 struct nhrp_cie_header
*cie
;
322 struct nhrp_extension_header
*ext
;
323 struct nhrp_interface
*nifp
;
324 struct nhrp_peer
*peer
;
326 if (!(p
->if_ad
->flags
& NHRP_IFF_SHORTCUT
)) {
327 debugf(NHRP_DEBUG_COMMON
, "Shortcuts disabled");
328 /* FIXME: Send error indication? */
332 if (p
->if_ad
->network_id
&& p
->route_type
== NHRP_ROUTE_OFF_NBMA
333 && p
->route_prefix
.prefixlen
< 8) {
334 debugf(NHRP_DEBUG_COMMON
,
335 "Shortcut to more generic than /8 dropped");
339 debugf(NHRP_DEBUG_COMMON
, "Parsing and replying to Resolution Req");
341 if (nhrp_route_address(p
->ifp
, &p
->src_proto
, NULL
, &peer
)
342 != NHRP_ROUTE_NBMA_NEXTHOP
)
346 /* FIXME: Update requestors binding if CIE specifies holding time */
347 nhrp_cache_update_binding(
348 NHRP_CACHE_CACHED
, &p
->src_proto
,
349 nhrp_peer_get(p
->ifp
, &p
->src_nbma
),
350 htons(cie
->holding_time
));
353 nifp
= peer
->ifp
->info
;
356 zb
= zbuf_alloc(1500);
357 hdr
= nhrp_packet_push(zb
, NHRP_PACKET_RESOLUTION_REPLY
, &p
->src_nbma
,
358 &p
->src_proto
, &p
->dst_proto
);
360 /* Copied information from request */
362 p
->hdr
->flags
& htons(NHRP_FLAG_RESOLUTION_SOURCE_IS_ROUTER
363 | NHRP_FLAG_RESOLUTION_SOURCE_STABLE
);
364 hdr
->flags
|= htons(NHRP_FLAG_RESOLUTION_DESTINATION_STABLE
365 | NHRP_FLAG_RESOLUTION_AUTHORATIVE
);
366 hdr
->u
.request_id
= p
->hdr
->u
.request_id
;
369 cie
= nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
, &nifp
->nbma
,
371 cie
->holding_time
= htons(p
->if_ad
->holdtime
);
372 cie
->mtu
= htons(p
->if_ad
->mtu
);
373 if (p
->if_ad
->network_id
&& p
->route_type
== NHRP_ROUTE_OFF_NBMA
)
374 cie
->prefix_length
= p
->route_prefix
.prefixlen
;
376 cie
->prefix_length
= 8 * sockunion_get_addrlen(&p
->if_ad
->addr
);
378 /* Handle extensions */
379 while ((ext
= nhrp_ext_pull(&p
->extensions
, &payload
)) != NULL
) {
380 switch (htons(ext
->type
) & ~NHRP_EXTENSION_FLAG_COMPULSORY
) {
381 case NHRP_EXTENSION_NAT_ADDRESS
:
382 if (sockunion_family(&nifp
->nat_nbma
) == AF_UNSPEC
)
384 ext
= nhrp_ext_push(zb
, hdr
,
385 NHRP_EXTENSION_NAT_ADDRESS
);
388 cie
= nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
,
389 &nifp
->nat_nbma
, &p
->if_ad
->addr
);
392 nhrp_ext_complete(zb
, ext
);
395 if (nhrp_ext_reply(zb
, hdr
, p
->ifp
, ext
, &payload
) < 0)
401 nhrp_packet_complete(zb
, hdr
);
402 nhrp_peer_send(peer
, zb
);
404 nhrp_peer_unref(peer
);
408 static void nhrp_handle_registration_request(struct nhrp_packet_parser
*p
)
410 struct interface
*ifp
= p
->ifp
;
411 struct zbuf
*zb
, payload
;
412 struct nhrp_packet_header
*hdr
;
413 struct nhrp_cie_header
*cie
;
414 struct nhrp_extension_header
*ext
;
415 struct nhrp_cache
*c
;
416 union sockunion cie_nbma
, cie_proto
, *proto_addr
, *nbma_addr
,
418 int holdtime
, prefix_len
, hostprefix_len
, natted
= 0;
422 debugf(NHRP_DEBUG_COMMON
, "Parsing and replying to Registration Req");
423 hostprefix_len
= 8 * sockunion_get_addrlen(&p
->if_ad
->addr
);
425 if (!sockunion_same(&p
->src_nbma
, &p
->peer
->vc
->remote
.nbma
))
429 zb
= zbuf_alloc(1500);
430 hdr
= nhrp_packet_push(zb
, NHRP_PACKET_REGISTRATION_REPLY
, &p
->src_nbma
,
431 &p
->src_proto
, &p
->if_ad
->addr
);
433 /* Copied information from request */
434 hdr
->flags
= p
->hdr
->flags
& htons(NHRP_FLAG_REGISTRATION_UNIQUE
435 | NHRP_FLAG_REGISTRATION_NAT
);
436 hdr
->u
.request_id
= p
->hdr
->u
.request_id
;
438 /* Copy payload CIEs */
439 paylen
= zbuf_used(&p
->payload
);
440 pay
= zbuf_pushn(zb
, paylen
);
443 memcpy(pay
, zbuf_pulln(&p
->payload
, paylen
), paylen
);
444 zbuf_init(&payload
, pay
, paylen
, paylen
);
446 while ((cie
= nhrp_cie_pull(&payload
, hdr
, &cie_nbma
, &cie_proto
))
448 prefix_len
= cie
->prefix_length
;
449 if (prefix_len
== 0 || prefix_len
>= hostprefix_len
)
450 prefix_len
= hostprefix_len
;
452 if (prefix_len
!= hostprefix_len
454 & htons(NHRP_FLAG_REGISTRATION_UNIQUE
))) {
455 cie
->code
= NHRP_CODE_BINDING_NON_UNIQUE
;
459 /* We currently support only unique prefix registrations */
460 if (prefix_len
!= hostprefix_len
) {
461 cie
->code
= NHRP_CODE_ADMINISTRATIVELY_PROHIBITED
;
465 proto_addr
= (sockunion_family(&cie_proto
) == AF_UNSPEC
)
468 nbma_addr
= (sockunion_family(&cie_nbma
) == AF_UNSPEC
)
473 nbma_natoa
= nbma_addr
;
476 holdtime
= htons(cie
->holding_time
);
478 holdtime
= p
->if_ad
->holdtime
;
480 c
= nhrp_cache_get(ifp
, proto_addr
, 1);
482 cie
->code
= NHRP_CODE_INSUFFICIENT_RESOURCES
;
486 if (!nhrp_cache_update_binding(c
, NHRP_CACHE_DYNAMIC
, holdtime
,
487 nhrp_peer_ref(p
->peer
),
488 htons(cie
->mtu
), nbma_natoa
)) {
489 cie
->code
= NHRP_CODE_ADMINISTRATIVELY_PROHIBITED
;
493 cie
->code
= NHRP_CODE_SUCCESS
;
496 /* Handle extensions */
497 while ((ext
= nhrp_ext_pull(&p
->extensions
, &payload
)) != NULL
) {
498 switch (htons(ext
->type
) & ~NHRP_EXTENSION_FLAG_COMPULSORY
) {
499 case NHRP_EXTENSION_NAT_ADDRESS
:
500 ext
= nhrp_ext_push(zb
, hdr
,
501 NHRP_EXTENSION_NAT_ADDRESS
);
504 zbuf_copy(zb
, &payload
, zbuf_used(&payload
));
506 nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
,
507 &p
->peer
->vc
->remote
.nbma
,
510 nhrp_ext_complete(zb
, ext
);
513 if (nhrp_ext_reply(zb
, hdr
, ifp
, ext
, &payload
) < 0)
519 nhrp_packet_complete(zb
, hdr
);
520 nhrp_peer_send(p
->peer
, zb
);
525 static int parse_ether_packet(struct zbuf
*zb
, uint16_t protocol_type
,
526 union sockunion
*src
, union sockunion
*dst
)
528 switch (protocol_type
) {
530 struct iphdr
*iph
= zbuf_pull(zb
, struct iphdr
);
533 sockunion_set(src
, AF_INET
,
534 (uint8_t *)&iph
->saddr
,
537 sockunion_set(dst
, AF_INET
,
538 (uint8_t *)&iph
->daddr
,
543 struct ipv6hdr
*iph
= zbuf_pull(zb
, struct ipv6hdr
);
546 sockunion_set(src
, AF_INET6
,
547 (uint8_t *)&iph
->saddr
,
550 sockunion_set(dst
, AF_INET6
,
551 (uint8_t *)&iph
->daddr
,
561 void nhrp_peer_send_indication(struct interface
*ifp
, uint16_t protocol_type
,
565 struct zbuf
*zb
, payload
;
566 struct nhrp_interface
*nifp
= ifp
->info
;
567 struct nhrp_afi_data
*if_ad
;
568 struct nhrp_packet_header
*hdr
;
570 char buf
[2][SU_ADDRSTRLEN
];
576 if (!parse_ether_packet(&payload
, protocol_type
, &dst
, NULL
))
579 if (nhrp_route_address(ifp
, &dst
, NULL
, &p
) != NHRP_ROUTE_NBMA_NEXTHOP
)
582 if_ad
= &nifp
->afi
[family2afi(sockunion_family(&dst
))];
583 if (!(if_ad
->flags
& NHRP_IFF_REDIRECT
)) {
584 debugf(NHRP_DEBUG_COMMON
,
585 "Send Traffic Indication to %s about packet to %s ignored",
586 sockunion2str(&p
->vc
->remote
.nbma
, buf
[0],
588 sockunion2str(&dst
, buf
[1], sizeof buf
[1]));
592 debugf(NHRP_DEBUG_COMMON
,
593 "Send Traffic Indication to %s (online=%d) about packet to %s",
594 sockunion2str(&p
->vc
->remote
.nbma
, buf
[0], sizeof buf
[0]),
595 p
->online
, sockunion2str(&dst
, buf
[1], sizeof buf
[1]));
598 zb
= zbuf_alloc(1500);
599 hdr
= nhrp_packet_push(zb
, NHRP_PACKET_TRAFFIC_INDICATION
, &nifp
->nbma
,
603 /* Payload is the packet causing indication */
604 zbuf_copy(zb
, pkt
, zbuf_used(pkt
));
605 nhrp_packet_complete(zb
, hdr
);
606 nhrp_peer_send(p
, zb
);
611 static void nhrp_handle_error_ind(struct nhrp_packet_parser
*pp
)
613 struct zbuf origmsg
= pp
->payload
;
614 struct nhrp_packet_header
*hdr
;
615 struct nhrp_reqid
*reqid
;
616 union sockunion src_nbma
, src_proto
, dst_proto
;
617 char buf
[2][SU_ADDRSTRLEN
];
619 hdr
= nhrp_packet_pull(&origmsg
, &src_nbma
, &src_proto
, &dst_proto
);
623 debugf(NHRP_DEBUG_COMMON
,
624 "Error Indication from %s about packet to %s ignored",
625 sockunion2str(&pp
->src_proto
, buf
[0], sizeof buf
[0]),
626 sockunion2str(&dst_proto
, buf
[1], sizeof buf
[1]));
628 reqid
= nhrp_reqid_lookup(&nhrp_packet_reqid
, htonl(hdr
->u
.request_id
));
630 reqid
->cb(reqid
, pp
);
633 static void nhrp_handle_traffic_ind(struct nhrp_packet_parser
*p
)
636 char buf
[2][SU_ADDRSTRLEN
];
638 if (!parse_ether_packet(&p
->payload
, htons(p
->hdr
->protocol_type
), NULL
,
642 debugf(NHRP_DEBUG_COMMON
,
643 "Traffic Indication from %s about packet to %s: %s",
644 sockunion2str(&p
->src_proto
, buf
[0], sizeof buf
[0]),
645 sockunion2str(&dst
, buf
[1], sizeof buf
[1]),
646 (p
->if_ad
->flags
& NHRP_IFF_SHORTCUT
) ? "trying shortcut"
649 if (p
->if_ad
->flags
& NHRP_IFF_SHORTCUT
)
650 nhrp_shortcut_initiate(&dst
);
661 enum packet_type_t type
;
663 void (*handler
)(struct nhrp_packet_parser
*);
664 } packet_types
[] = {[0] =
666 .type
= PACKET_UNKNOWN
,
669 [NHRP_PACKET_RESOLUTION_REQUEST
] =
671 .type
= PACKET_REQUEST
,
672 .name
= "Resolution-Request",
673 .handler
= nhrp_handle_resolution_req
,
675 [NHRP_PACKET_RESOLUTION_REPLY
] =
677 .type
= PACKET_REPLY
,
678 .name
= "Resolution-Reply",
680 [NHRP_PACKET_REGISTRATION_REQUEST
] =
682 .type
= PACKET_REQUEST
,
683 .name
= "Registration-Request",
684 .handler
= nhrp_handle_registration_request
,
686 [NHRP_PACKET_REGISTRATION_REPLY
] =
688 .type
= PACKET_REPLY
,
689 .name
= "Registration-Reply",
691 [NHRP_PACKET_PURGE_REQUEST
] =
693 .type
= PACKET_REQUEST
,
694 .name
= "Purge-Request",
696 [NHRP_PACKET_PURGE_REPLY
] =
698 .type
= PACKET_REPLY
,
699 .name
= "Purge-Reply",
701 [NHRP_PACKET_ERROR_INDICATION
] =
703 .type
= PACKET_INDICATION
,
704 .name
= "Error-Indication",
705 .handler
= nhrp_handle_error_ind
,
707 [NHRP_PACKET_TRAFFIC_INDICATION
] = {
708 .type
= PACKET_INDICATION
,
709 .name
= "Traffic-Indication",
710 .handler
= nhrp_handle_traffic_ind
,
713 static void nhrp_peer_forward(struct nhrp_peer
*p
,
714 struct nhrp_packet_parser
*pp
)
716 struct zbuf
*zb
, extpl
;
717 struct nhrp_packet_header
*hdr
;
718 struct nhrp_extension_header
*ext
, *dst
;
719 struct nhrp_cie_header
*cie
;
720 struct nhrp_interface
*nifp
= pp
->ifp
->info
;
721 struct nhrp_afi_data
*if_ad
= pp
->if_ad
;
722 union sockunion cie_nbma
, cie_protocol
;
725 if (pp
->hdr
->hop_count
== 0)
728 /* Create forward packet - copy header */
729 zb
= zbuf_alloc(1500);
730 hdr
= nhrp_packet_push(zb
, pp
->hdr
->type
, &pp
->src_nbma
, &pp
->src_proto
,
732 hdr
->flags
= pp
->hdr
->flags
;
733 hdr
->hop_count
= pp
->hdr
->hop_count
- 1;
734 hdr
->u
.request_id
= pp
->hdr
->u
.request_id
;
737 zbuf_copy(zb
, &pp
->payload
, zbuf_used(&pp
->payload
));
739 /* Copy extensions */
740 while ((ext
= nhrp_ext_pull(&pp
->extensions
, &extpl
)) != NULL
) {
741 type
= htons(ext
->type
) & ~NHRP_EXTENSION_FLAG_COMPULSORY
;
742 len
= htons(ext
->length
);
744 if (type
== NHRP_EXTENSION_END
)
747 dst
= nhrp_ext_push(zb
, hdr
, htons(ext
->type
));
752 case NHRP_EXTENSION_FORWARD_TRANSIT_NHS
:
753 case NHRP_EXTENSION_REVERSE_TRANSIT_NHS
:
754 zbuf_put(zb
, extpl
.head
, len
);
755 if ((type
== NHRP_EXTENSION_REVERSE_TRANSIT_NHS
)
756 == (packet_types
[hdr
->type
].type
== PACKET_REPLY
)) {
757 /* Check NHS list for forwarding loop */
758 while ((cie
= nhrp_cie_pull(&extpl
, pp
->hdr
,
762 if (sockunion_same(&p
->vc
->remote
.nbma
,
766 /* Append our selves to the list */
767 cie
= nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
,
768 &nifp
->nbma
, &if_ad
->addr
);
771 cie
->holding_time
= htons(if_ad
->holdtime
);
775 if (htons(ext
->type
) & NHRP_EXTENSION_FLAG_COMPULSORY
)
776 /* FIXME: RFC says to just copy, but not
777 * append our selves to the transit NHS list */
780 case NHRP_EXTENSION_RESPONDER_ADDRESS
:
781 /* Supported compulsory extensions, and any
782 * non-compulsory that is not explicitly handled,
783 * should be just copied. */
784 zbuf_copy(zb
, &extpl
, len
);
787 nhrp_ext_complete(zb
, dst
);
790 nhrp_packet_complete(zb
, hdr
);
791 nhrp_peer_send(p
, zb
);
795 nhrp_packet_debug(pp
->pkt
, "FWD-FAIL");
799 static void nhrp_packet_debug(struct zbuf
*zb
, const char *dir
)
801 char buf
[2][SU_ADDRSTRLEN
];
802 union sockunion src_nbma
, src_proto
, dst_proto
;
803 struct nhrp_packet_header
*hdr
;
807 if (likely(!(debug_flags
& NHRP_DEBUG_COMMON
)))
810 zbuf_init(&zhdr
, zb
->buf
, zb
->tail
- zb
->buf
, zb
->tail
- zb
->buf
);
811 hdr
= nhrp_packet_pull(&zhdr
, &src_nbma
, &src_proto
, &dst_proto
);
813 sockunion2str(&src_proto
, buf
[0], sizeof buf
[0]);
814 sockunion2str(&dst_proto
, buf
[1], sizeof buf
[1]);
816 reply
= packet_types
[hdr
->type
].type
== PACKET_REPLY
;
817 debugf(NHRP_DEBUG_COMMON
, "%s %s(%d) %s -> %s", dir
,
818 (packet_types
[hdr
->type
].name
? packet_types
[hdr
->type
].name
820 hdr
->type
, reply
? buf
[1] : buf
[0], reply
? buf
[0] : buf
[1]);
823 static int proto2afi(uint16_t proto
)
834 struct nhrp_route_info
{
836 struct interface
*ifp
;
840 void nhrp_peer_recv(struct nhrp_peer
*p
, struct zbuf
*zb
)
842 char buf
[2][SU_ADDRSTRLEN
];
843 struct nhrp_packet_header
*hdr
;
844 struct nhrp_vc
*vc
= p
->vc
;
845 struct interface
*ifp
= p
->ifp
;
846 struct nhrp_interface
*nifp
= ifp
->info
;
847 struct nhrp_packet_parser pp
;
848 struct nhrp_peer
*peer
= NULL
;
849 struct nhrp_reqid
*reqid
;
850 const char *info
= NULL
;
851 union sockunion
*target_addr
;
852 unsigned paylen
, extoff
, extlen
, realsize
;
853 afi_t nbma_afi
, proto_afi
;
855 debugf(NHRP_DEBUG_KERNEL
, "PACKET: Recv %s -> %s",
856 sockunion2str(&vc
->remote
.nbma
, buf
[0], sizeof buf
[0]),
857 sockunion2str(&vc
->local
.nbma
, buf
[1], sizeof buf
[1]));
860 info
= "peer not online";
864 if (nhrp_packet_calculate_checksum(zb
->head
, zbuf_used(zb
)) != 0) {
865 info
= "bad checksum";
869 realsize
= zbuf_used(zb
);
870 hdr
= nhrp_packet_pull(zb
, &pp
.src_nbma
, &pp
.src_proto
, &pp
.dst_proto
);
872 info
= "corrupt header";
881 nbma_afi
= htons(hdr
->afnum
);
882 proto_afi
= proto2afi(htons(hdr
->protocol_type
));
883 if (hdr
->type
> NHRP_PACKET_MAX
|| hdr
->version
!= NHRP_VERSION_RFC2332
884 || nbma_afi
>= AFI_MAX
|| proto_afi
== AF_UNSPEC
885 || packet_types
[hdr
->type
].type
== PACKET_UNKNOWN
886 || htons(hdr
->packet_size
) > realsize
) {
888 "From %s: error: packet type %d, version %d, AFI %d, proto %x, size %d (real size %d)",
889 sockunion2str(&vc
->remote
.nbma
, buf
[0], sizeof buf
[0]),
890 (int)hdr
->type
, (int)hdr
->version
, (int)nbma_afi
,
891 (int)htons(hdr
->protocol_type
),
892 (int)htons(hdr
->packet_size
), (int)realsize
);
895 pp
.if_ad
= &((struct nhrp_interface
*)ifp
->info
)->afi
[proto_afi
];
897 extoff
= htons(hdr
->extension_offset
);
899 if (extoff
>= realsize
) {
900 info
= "extoff larger than packet";
903 paylen
= extoff
- (zb
->head
- zb
->buf
);
905 paylen
= zbuf_used(zb
);
907 zbuf_init(&pp
.payload
, zbuf_pulln(zb
, paylen
), paylen
, paylen
);
908 extlen
= zbuf_used(zb
);
909 zbuf_init(&pp
.extensions
, zbuf_pulln(zb
, extlen
), extlen
, extlen
);
911 if (!nifp
->afi
[proto_afi
].network_id
) {
912 info
= "nhrp not enabled";
916 nhrp_packet_debug(zb
, "Recv");
918 /* FIXME: Check authentication here. This extension needs to be
921 /* Figure out if this is local */
922 target_addr
= (packet_types
[hdr
->type
].type
== PACKET_REPLY
)
926 if (sockunion_same(&pp
.src_proto
, &pp
.dst_proto
))
927 pp
.route_type
= NHRP_ROUTE_LOCAL
;
929 pp
.route_type
= nhrp_route_address(pp
.ifp
, target_addr
,
930 &pp
.route_prefix
, &peer
);
932 switch (pp
.route_type
) {
933 case NHRP_ROUTE_LOCAL
:
934 nhrp_packet_debug(zb
, "!LOCAL");
935 if (packet_types
[hdr
->type
].type
== PACKET_REPLY
) {
936 reqid
= nhrp_reqid_lookup(&nhrp_packet_reqid
,
937 htonl(hdr
->u
.request_id
));
939 reqid
->cb(reqid
, &pp
);
942 nhrp_packet_debug(zb
, "!UNKNOWN-REQID");
943 /* FIXME: send error-indication */
946 /* fallthru */ /* FIXME: double check, is this correct? */
947 case NHRP_ROUTE_OFF_NBMA
:
948 if (packet_types
[hdr
->type
].handler
) {
949 packet_types
[hdr
->type
].handler(&pp
);
953 case NHRP_ROUTE_NBMA_NEXTHOP
:
954 nhrp_peer_forward(peer
, &pp
);
956 case NHRP_ROUTE_BLACKHOLE
:
963 "From %s: error: %s",
964 sockunion2str(&vc
->remote
.nbma
, buf
[0], sizeof buf
[0]),
968 nhrp_peer_unref(peer
);