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.
10 #include <netinet/if_ether.h>
18 #include "nhrp_protocol.h"
22 uint8_t priority_version
;
27 struct in6_addr saddr
;
28 struct in6_addr daddr
;
31 static void nhrp_packet_debug(struct zbuf
*zb
, const char *dir
);
33 static void nhrp_peer_check_delete(struct nhrp_peer
*p
)
35 struct nhrp_interface
*nifp
= p
->ifp
->info
;
37 if (p
->ref
|| notifier_active(&p
->notifier_list
))
40 THREAD_OFF(p
->t_fallback
);
41 hash_release(nifp
->peer_hash
, p
);
42 nhrp_interface_notify_del(p
->ifp
, &p
->ifp_notifier
);
43 nhrp_vc_notify_del(p
->vc
, &p
->vc_notifier
);
44 XFREE(MTYPE_NHRP_PEER
, p
);
47 static int nhrp_peer_notify_up(struct thread
*t
)
49 struct nhrp_peer
*p
= THREAD_ARG(t
);
50 struct nhrp_vc
*vc
= p
->vc
;
51 struct interface
*ifp
= p
->ifp
;
52 struct nhrp_interface
*nifp
= ifp
->info
;
55 if (nifp
->enabled
&& (!nifp
->ipsec_profile
|| vc
->ipsec
)) {
58 notifier_call(&p
->notifier_list
, NOTIFY_PEER_UP
);
65 static void __nhrp_peer_check(struct nhrp_peer
*p
)
67 struct nhrp_vc
*vc
= p
->vc
;
68 struct interface
*ifp
= p
->ifp
;
69 struct nhrp_interface
*nifp
= ifp
->info
;
72 online
= nifp
->enabled
&& (!nifp
->ipsec_profile
|| vc
->ipsec
);
73 if (p
->online
!= online
) {
74 THREAD_OFF(p
->t_fallback
);
75 if (online
&& notifier_active(&p
->notifier_list
)) {
76 /* If we requested the IPsec connection, delay
77 * the up notification a bit to allow things
78 * settle down. This allows IKE to install
81 master
, p
->t_fallback
,
82 nhrp_peer_notify_up
, p
, 50);
87 notifier_call(&p
->notifier_list
, NOTIFY_PEER_UP
);
89 p
->requested
= p
->fallback_requested
= 0;
90 notifier_call(&p
->notifier_list
, NOTIFY_PEER_DOWN
);
97 static void nhrp_peer_vc_notify(struct notifier_block
*n
, unsigned long cmd
)
99 struct nhrp_peer
*p
= container_of(n
, struct nhrp_peer
, vc_notifier
);
102 case NOTIFY_VC_IPSEC_CHANGED
:
103 __nhrp_peer_check(p
);
105 case NOTIFY_VC_IPSEC_UPDATE_NBMA
:
107 notifier_call(&p
->notifier_list
, NOTIFY_PEER_NBMA_CHANGING
);
113 static void nhrp_peer_ifp_notify(struct notifier_block
*n
, unsigned long cmd
)
115 struct nhrp_peer
*p
= container_of(n
, struct nhrp_peer
, ifp_notifier
);
116 struct nhrp_interface
*nifp
;
121 case NOTIFY_INTERFACE_UP
:
122 case NOTIFY_INTERFACE_DOWN
:
123 __nhrp_peer_check(p
);
125 case NOTIFY_INTERFACE_NBMA_CHANGED
:
126 /* Source NBMA changed, rebind to new VC */
128 vc
= nhrp_vc_get(&nifp
->nbma
, &p
->vc
->remote
.nbma
, 1);
129 if (vc
&& p
->vc
!= vc
) {
130 nhrp_vc_notify_del(p
->vc
, &p
->vc_notifier
);
132 nhrp_vc_notify_add(p
->vc
, &p
->vc_notifier
, nhrp_peer_vc_notify
);
133 __nhrp_peer_check(p
);
135 /* Fall-through to post config update */
136 case NOTIFY_INTERFACE_ADDRESS_CHANGED
:
137 notifier_call(&p
->notifier_list
, NOTIFY_PEER_IFCONFIG_CHANGED
);
139 case NOTIFY_INTERFACE_MTU_CHANGED
:
140 notifier_call(&p
->notifier_list
, NOTIFY_PEER_MTU_CHANGED
);
146 static unsigned int nhrp_peer_key(void *peer_data
)
148 struct nhrp_peer
*p
= peer_data
;
149 return sockunion_hash(&p
->vc
->remote
.nbma
);
152 static int nhrp_peer_cmp(const void *cache_data
, const void *key_data
)
154 const struct nhrp_peer
*a
= cache_data
;
155 const struct nhrp_peer
*b
= key_data
;
156 return a
->ifp
== b
->ifp
&& a
->vc
== b
->vc
;
159 static void *nhrp_peer_create(void *data
)
161 struct nhrp_peer
*p
, *key
= data
;
163 p
= XMALLOC(MTYPE_NHRP_PEER
, sizeof(*p
));
165 *p
= (struct nhrp_peer
) {
169 .notifier_list
= NOTIFIER_LIST_INITIALIZER(&p
->notifier_list
),
171 nhrp_vc_notify_add(p
->vc
, &p
->vc_notifier
, nhrp_peer_vc_notify
);
172 nhrp_interface_notify_add(p
->ifp
, &p
->ifp_notifier
, nhrp_peer_ifp_notify
);
177 struct nhrp_peer
*nhrp_peer_get(struct interface
*ifp
, const union sockunion
*remote_nbma
)
179 struct nhrp_interface
*nifp
= ifp
->info
;
180 struct nhrp_peer key
, *p
;
183 if (!nifp
->peer_hash
) {
184 nifp
->peer_hash
= hash_create(nhrp_peer_key
, nhrp_peer_cmp
);
185 if (!nifp
->peer_hash
) return NULL
;
188 vc
= nhrp_vc_get(&nifp
->nbma
, remote_nbma
, 1);
189 if (!vc
) return NULL
;
194 p
= hash_get(nifp
->peer_hash
, &key
, nhrp_peer_create
);
196 if (p
->ref
== 1) __nhrp_peer_check(p
);
201 struct nhrp_peer
*nhrp_peer_ref(struct nhrp_peer
*p
)
207 void nhrp_peer_unref(struct nhrp_peer
*p
)
211 nhrp_peer_check_delete(p
);
215 static int nhrp_peer_request_timeout(struct thread
*t
)
217 struct nhrp_peer
*p
= THREAD_ARG(t
);
218 struct nhrp_vc
*vc
= p
->vc
;
219 struct interface
*ifp
= p
->ifp
;
220 struct nhrp_interface
*nifp
= ifp
->info
;
222 p
->t_fallback
= NULL
;
227 if (nifp
->ipsec_fallback_profile
&& !p
->prio
&& !p
->fallback_requested
) {
228 p
->fallback_requested
= 1;
229 vici_request_vc(nifp
->ipsec_fallback_profile
,
230 &vc
->local
.nbma
, &vc
->remote
.nbma
, p
->prio
);
231 THREAD_TIMER_ON(master
, p
->t_fallback
, nhrp_peer_request_timeout
, p
, 30);
233 p
->requested
= p
->fallback_requested
= 0;
239 int nhrp_peer_check(struct nhrp_peer
*p
, int establish
)
241 struct nhrp_vc
*vc
= p
->vc
;
242 struct interface
*ifp
= p
->ifp
;
243 struct nhrp_interface
*nifp
= ifp
->info
;
251 if (sockunion_family(&vc
->local
.nbma
) == AF_UNSPEC
)
254 p
->prio
= establish
> 1;
256 vici_request_vc(nifp
->ipsec_profile
, &vc
->local
.nbma
, &vc
->remote
.nbma
, p
->prio
);
257 THREAD_TIMER_ON(master
, p
->t_fallback
, nhrp_peer_request_timeout
, p
,
258 (nifp
->ipsec_fallback_profile
&& !p
->prio
) ? 15 : 30);
263 void nhrp_peer_notify_add(struct nhrp_peer
*p
, struct notifier_block
*n
, notifier_fn_t fn
)
265 notifier_add(n
, &p
->notifier_list
, fn
);
268 void nhrp_peer_notify_del(struct nhrp_peer
*p
, struct notifier_block
*n
)
271 nhrp_peer_check_delete(p
);
274 void nhrp_peer_send(struct nhrp_peer
*p
, struct zbuf
*zb
)
278 nhrp_packet_debug(zb
, "Send");
283 debugf(NHRP_DEBUG_KERNEL
, "PACKET: Send %s -> %s",
284 sockunion2str(&p
->vc
->local
.nbma
, buf
[0], sizeof buf
[0]),
285 sockunion2str(&p
->vc
->remote
.nbma
, buf
[1], sizeof buf
[1]));
287 os_sendmsg(zb
->head
, zbuf_used(zb
),
289 sockunion_get_addr(&p
->vc
->remote
.nbma
),
290 sockunion_get_addrlen(&p
->vc
->remote
.nbma
));
294 static void nhrp_handle_resolution_req(struct nhrp_packet_parser
*p
)
296 struct zbuf
*zb
, payload
;
297 struct nhrp_packet_header
*hdr
;
298 struct nhrp_cie_header
*cie
;
299 struct nhrp_extension_header
*ext
;
300 struct nhrp_interface
*nifp
;
301 struct nhrp_peer
*peer
;
303 if (!(p
->if_ad
->flags
& NHRP_IFF_SHORTCUT
)) {
304 debugf(NHRP_DEBUG_COMMON
, "Shortcuts disabled");
305 /* FIXME: Send error indication? */
309 if (p
->if_ad
->network_id
&&
310 p
->route_type
== NHRP_ROUTE_OFF_NBMA
&&
311 p
->route_prefix
.prefixlen
< 8) {
312 debugf(NHRP_DEBUG_COMMON
, "Shortcut to more generic than /8 dropped");
316 debugf(NHRP_DEBUG_COMMON
, "Parsing and replying to Resolution Req");
318 if (nhrp_route_address(p
->ifp
, &p
->src_proto
, NULL
, &peer
) != NHRP_ROUTE_NBMA_NEXTHOP
)
322 /* FIXME: Update requestors binding if CIE specifies holding time */
323 nhrp_cache_update_binding(
324 NHRP_CACHE_CACHED
, &p
->src_proto
,
325 nhrp_peer_get(p
->ifp
, &p
->src_nbma
),
326 htons(cie
->holding_time
));
329 nifp
= peer
->ifp
->info
;
332 zb
= zbuf_alloc(1500);
333 hdr
= nhrp_packet_push(zb
, NHRP_PACKET_RESOLUTION_REPLY
, &p
->src_nbma
, &p
->src_proto
, &p
->dst_proto
);
335 /* Copied information from request */
336 hdr
->flags
= p
->hdr
->flags
& htons(NHRP_FLAG_RESOLUTION_SOURCE_IS_ROUTER
|NHRP_FLAG_RESOLUTION_SOURCE_STABLE
);
337 hdr
->flags
|= htons(NHRP_FLAG_RESOLUTION_DESTINATION_STABLE
| NHRP_FLAG_RESOLUTION_AUTHORATIVE
);
338 hdr
->u
.request_id
= p
->hdr
->u
.request_id
;
341 cie
= nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
, &nifp
->nbma
, &p
->if_ad
->addr
);
342 cie
->holding_time
= htons(p
->if_ad
->holdtime
);
343 cie
->mtu
= htons(p
->if_ad
->mtu
);
344 if (p
->if_ad
->network_id
&& p
->route_type
== NHRP_ROUTE_OFF_NBMA
)
345 cie
->prefix_length
= p
->route_prefix
.prefixlen
;
347 cie
->prefix_length
= 8 * sockunion_get_addrlen(&p
->if_ad
->addr
);
349 /* Handle extensions */
350 while ((ext
= nhrp_ext_pull(&p
->extensions
, &payload
)) != NULL
) {
351 switch (htons(ext
->type
) & ~NHRP_EXTENSION_FLAG_COMPULSORY
) {
352 case NHRP_EXTENSION_NAT_ADDRESS
:
353 if (sockunion_family(&nifp
->nat_nbma
) == AF_UNSPEC
)
355 ext
= nhrp_ext_push(zb
, hdr
, NHRP_EXTENSION_NAT_ADDRESS
);
357 cie
= nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
, &nifp
->nat_nbma
, &p
->if_ad
->addr
);
359 nhrp_ext_complete(zb
, ext
);
362 if (nhrp_ext_reply(zb
, hdr
, p
->ifp
, ext
, &payload
) < 0)
368 nhrp_packet_complete(zb
, hdr
);
369 nhrp_peer_send(peer
, zb
);
371 nhrp_peer_unref(peer
);
375 static void nhrp_handle_registration_request(struct nhrp_packet_parser
*p
)
377 struct interface
*ifp
= p
->ifp
;
378 struct zbuf
*zb
, payload
;
379 struct nhrp_packet_header
*hdr
;
380 struct nhrp_cie_header
*cie
;
381 struct nhrp_extension_header
*ext
;
382 struct nhrp_cache
*c
;
383 union sockunion cie_nbma
, cie_proto
, *proto_addr
, *nbma_addr
, *nbma_natoa
;
384 int holdtime
, natted
= 0;
388 debugf(NHRP_DEBUG_COMMON
, "Parsing and replying to Registration Req");
390 if (!sockunion_same(&p
->src_nbma
, &p
->peer
->vc
->remote
.nbma
))
394 zb
= zbuf_alloc(1500);
395 hdr
= nhrp_packet_push(zb
, NHRP_PACKET_REGISTRATION_REPLY
,
396 &p
->src_nbma
, &p
->src_proto
, &p
->if_ad
->addr
);
398 /* Copied information from request */
399 hdr
->flags
= p
->hdr
->flags
& htons(NHRP_FLAG_REGISTRATION_UNIQUE
| NHRP_FLAG_REGISTRATION_NAT
);
400 hdr
->u
.request_id
= p
->hdr
->u
.request_id
;
402 /* Copy payload CIEs */
403 paylen
= zbuf_used(&p
->payload
);
404 pay
= zbuf_pushn(zb
, paylen
);
406 memcpy(pay
, zbuf_pulln(&p
->payload
, paylen
), paylen
);
407 zbuf_init(&payload
, pay
, paylen
, paylen
);
409 while ((cie
= nhrp_cie_pull(&payload
, hdr
, &cie_nbma
, &cie_proto
)) != NULL
) {
410 if (cie
->prefix_length
!= 0xff && !(p
->hdr
->flags
& htons(NHRP_FLAG_REGISTRATION_UNIQUE
))) {
411 cie
->code
= NHRP_CODE_BINDING_NON_UNIQUE
;
415 /* We currently support only unique prefix registrations */
416 if (cie
->prefix_length
!= 0xff) {
417 cie
->code
= NHRP_CODE_ADMINISTRATIVELY_PROHIBITED
;
421 proto_addr
= (sockunion_family(&cie_proto
) == AF_UNSPEC
) ? &p
->src_proto
: &cie_proto
;
422 nbma_addr
= (sockunion_family(&cie_nbma
) == AF_UNSPEC
) ? &p
->src_nbma
: &cie_nbma
;
425 nbma_natoa
= nbma_addr
;
426 nbma_addr
= &p
->peer
->vc
->remote
.nbma
;
429 holdtime
= htons(cie
->holding_time
);
430 if (!holdtime
) holdtime
= p
->if_ad
->holdtime
;
432 c
= nhrp_cache_get(ifp
, proto_addr
, 1);
434 cie
->code
= NHRP_CODE_INSUFFICIENT_RESOURCES
;
438 if (!nhrp_cache_update_binding(c
, NHRP_CACHE_DYNAMIC
, holdtime
, nhrp_peer_ref(p
->peer
), htons(cie
->mtu
), nbma_natoa
)) {
439 cie
->code
= NHRP_CODE_ADMINISTRATIVELY_PROHIBITED
;
443 cie
->code
= NHRP_CODE_SUCCESS
;
446 /* Handle extensions */
447 while ((ext
= nhrp_ext_pull(&p
->extensions
, &payload
)) != NULL
) {
448 switch (htons(ext
->type
) & ~NHRP_EXTENSION_FLAG_COMPULSORY
) {
449 case NHRP_EXTENSION_NAT_ADDRESS
:
450 ext
= nhrp_ext_push(zb
, hdr
, NHRP_EXTENSION_NAT_ADDRESS
);
452 zbuf_copy(zb
, &payload
, zbuf_used(&payload
));
454 nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
,
455 &p
->peer
->vc
->remote
.nbma
,
458 nhrp_ext_complete(zb
, ext
);
461 if (nhrp_ext_reply(zb
, hdr
, ifp
, ext
, &payload
) < 0)
467 nhrp_packet_complete(zb
, hdr
);
468 nhrp_peer_send(p
->peer
, zb
);
473 static int parse_ether_packet(struct zbuf
*zb
, uint16_t protocol_type
, union sockunion
*src
, union sockunion
*dst
)
475 switch (protocol_type
) {
477 struct iphdr
*iph
= zbuf_pull(zb
, struct iphdr
);
479 if (src
) sockunion_set(src
, AF_INET
, (uint8_t*) &iph
->saddr
, sizeof(iph
->saddr
));
480 if (dst
) sockunion_set(dst
, AF_INET
, (uint8_t*) &iph
->daddr
, sizeof(iph
->daddr
));
485 struct ipv6hdr
*iph
= zbuf_pull(zb
, struct ipv6hdr
);
487 if (src
) sockunion_set(src
, AF_INET6
, (uint8_t*) &iph
->saddr
, sizeof(iph
->saddr
));
488 if (dst
) sockunion_set(dst
, AF_INET6
, (uint8_t*) &iph
->daddr
, sizeof(iph
->daddr
));
498 void nhrp_peer_send_indication(struct interface
*ifp
, uint16_t protocol_type
, struct zbuf
*pkt
)
501 struct zbuf
*zb
, payload
;
502 struct nhrp_interface
*nifp
= ifp
->info
;
503 struct nhrp_afi_data
*if_ad
;
504 struct nhrp_packet_header
*hdr
;
506 char buf
[2][SU_ADDRSTRLEN
];
508 if (!nifp
->enabled
) return;
511 if (!parse_ether_packet(&payload
, protocol_type
, &dst
, NULL
))
514 if (nhrp_route_address(ifp
, &dst
, NULL
, &p
) != NHRP_ROUTE_NBMA_NEXTHOP
)
517 if_ad
= &nifp
->afi
[family2afi(sockunion_family(&dst
))];
518 if (!(if_ad
->flags
& NHRP_IFF_REDIRECT
)) {
519 debugf(NHRP_DEBUG_COMMON
, "Send Traffic Indication to %s about packet to %s ignored",
520 sockunion2str(&p
->vc
->remote
.nbma
, buf
[0], sizeof buf
[0]),
521 sockunion2str(&dst
, buf
[1], sizeof buf
[1]));
525 debugf(NHRP_DEBUG_COMMON
, "Send Traffic Indication to %s (online=%d) about packet to %s",
526 sockunion2str(&p
->vc
->remote
.nbma
, buf
[0], sizeof buf
[0]),
528 sockunion2str(&dst
, buf
[1], sizeof buf
[1]));
531 zb
= zbuf_alloc(1500);
532 hdr
= nhrp_packet_push(zb
, NHRP_PACKET_TRAFFIC_INDICATION
, &nifp
->nbma
, &if_ad
->addr
, &dst
);
535 /* Payload is the packet causing indication */
536 zbuf_copy(zb
, pkt
, zbuf_used(pkt
));
537 nhrp_packet_complete(zb
, hdr
);
538 nhrp_peer_send(p
, zb
);
543 static void nhrp_handle_error_ind(struct nhrp_packet_parser
*pp
)
545 struct zbuf origmsg
= pp
->payload
;
546 struct nhrp_packet_header
*hdr
;
547 struct nhrp_reqid
*reqid
;
548 union sockunion src_nbma
, src_proto
, dst_proto
;
549 char buf
[2][SU_ADDRSTRLEN
];
551 hdr
= nhrp_packet_pull(&origmsg
, &src_nbma
, &src_proto
, &dst_proto
);
554 debugf(NHRP_DEBUG_COMMON
, "Error Indication from %s about packet to %s ignored",
555 sockunion2str(&pp
->src_proto
, buf
[0], sizeof buf
[0]),
556 sockunion2str(&dst_proto
, buf
[1], sizeof buf
[1]));
558 reqid
= nhrp_reqid_lookup(&nhrp_packet_reqid
, htonl(hdr
->u
.request_id
));
560 reqid
->cb(reqid
, pp
);
563 static void nhrp_handle_traffic_ind(struct nhrp_packet_parser
*p
)
566 char buf
[2][SU_ADDRSTRLEN
];
568 if (!parse_ether_packet(&p
->payload
, htons(p
->hdr
->protocol_type
), NULL
, &dst
))
571 debugf(NHRP_DEBUG_COMMON
, "Traffic Indication from %s about packet to %s: %s",
572 sockunion2str(&p
->src_proto
, buf
[0], sizeof buf
[0]),
573 sockunion2str(&dst
, buf
[1], sizeof buf
[1]),
574 (p
->if_ad
->flags
& NHRP_IFF_SHORTCUT
) ? "trying shortcut" : "ignored");
576 if (p
->if_ad
->flags
& NHRP_IFF_SHORTCUT
)
577 nhrp_shortcut_initiate(&dst
);
588 enum packet_type_t type
;
590 void (*handler
)(struct nhrp_packet_parser
*);
592 [NHRP_PACKET_RESOLUTION_REQUEST
] = {
593 .type
= PACKET_REQUEST
,
594 .name
= "Resolution-Request",
595 .handler
= nhrp_handle_resolution_req
,
597 [NHRP_PACKET_RESOLUTION_REPLY
] = {
598 .type
= PACKET_REPLY
,
599 .name
= "Resolution-Reply",
601 [NHRP_PACKET_REGISTRATION_REQUEST
] = {
602 .type
= PACKET_REQUEST
,
603 .name
= "Registration-Request",
604 .handler
= nhrp_handle_registration_request
,
606 [NHRP_PACKET_REGISTRATION_REPLY
] = {
607 .type
= PACKET_REPLY
,
608 .name
= "Registration-Reply",
610 [NHRP_PACKET_PURGE_REQUEST
] = {
611 .type
= PACKET_REQUEST
,
612 .name
= "Purge-Request",
614 [NHRP_PACKET_PURGE_REPLY
] = {
615 .type
= PACKET_REPLY
,
616 .name
= "Purge-Reply",
618 [NHRP_PACKET_ERROR_INDICATION
] = {
619 .type
= PACKET_INDICATION
,
620 .name
= "Error-Indication",
621 .handler
= nhrp_handle_error_ind
,
623 [NHRP_PACKET_TRAFFIC_INDICATION
] = {
624 .type
= PACKET_INDICATION
,
625 .name
= "Traffic-Indication",
626 .handler
= nhrp_handle_traffic_ind
,
630 static void nhrp_peer_forward(struct nhrp_peer
*p
, struct nhrp_packet_parser
*pp
)
632 struct zbuf
*zb
, extpl
;
633 struct nhrp_packet_header
*hdr
;
634 struct nhrp_extension_header
*ext
, *dst
;
635 struct nhrp_cie_header
*cie
;
636 struct nhrp_interface
*nifp
= pp
->ifp
->info
;
637 struct nhrp_afi_data
*if_ad
= pp
->if_ad
;
638 union sockunion cie_nbma
, cie_protocol
;
641 if (pp
->hdr
->hop_count
== 0)
644 /* Create forward packet - copy header */
645 zb
= zbuf_alloc(1500);
646 hdr
= nhrp_packet_push(zb
, pp
->hdr
->type
, &pp
->src_nbma
, &pp
->src_proto
, &pp
->dst_proto
);
647 hdr
->flags
= pp
->hdr
->flags
;
648 hdr
->hop_count
= pp
->hdr
->hop_count
- 1;
649 hdr
->u
.request_id
= pp
->hdr
->u
.request_id
;
652 zbuf_copy(zb
, &pp
->payload
, zbuf_used(&pp
->payload
));
654 /* Copy extensions */
655 while ((ext
= nhrp_ext_pull(&pp
->extensions
, &extpl
)) != NULL
) {
656 type
= htons(ext
->type
) & ~NHRP_EXTENSION_FLAG_COMPULSORY
;
657 len
= htons(ext
->length
);
659 if (type
== NHRP_EXTENSION_END
)
662 dst
= nhrp_ext_push(zb
, hdr
, htons(ext
->type
));
666 case NHRP_EXTENSION_FORWARD_TRANSIT_NHS
:
667 case NHRP_EXTENSION_REVERSE_TRANSIT_NHS
:
668 zbuf_put(zb
, extpl
.head
, len
);
669 if ((type
== NHRP_EXTENSION_REVERSE_TRANSIT_NHS
) ==
670 (packet_types
[hdr
->type
].type
== PACKET_REPLY
)) {
671 /* Check NHS list for forwarding loop */
672 while ((cie
= nhrp_cie_pull(&extpl
, pp
->hdr
, &cie_nbma
, &cie_protocol
)) != NULL
) {
673 if (sockunion_same(&p
->vc
->remote
.nbma
, &cie_nbma
))
676 /* Append our selves to the list */
677 cie
= nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
, &nifp
->nbma
, &if_ad
->addr
);
679 cie
->holding_time
= htons(if_ad
->holdtime
);
683 if (htons(ext
->type
) & NHRP_EXTENSION_FLAG_COMPULSORY
)
684 /* FIXME: RFC says to just copy, but not
685 * append our selves to the transit NHS list */
687 case NHRP_EXTENSION_RESPONDER_ADDRESS
:
688 /* Supported compulsory extensions, and any
689 * non-compulsory that is not explicitly handled,
690 * should be just copied. */
691 zbuf_copy(zb
, &extpl
, len
);
694 nhrp_ext_complete(zb
, dst
);
697 nhrp_packet_complete(zb
, hdr
);
698 nhrp_peer_send(p
, zb
);
702 nhrp_packet_debug(pp
->pkt
, "FWD-FAIL");
706 static void nhrp_packet_debug(struct zbuf
*zb
, const char *dir
)
708 char buf
[2][SU_ADDRSTRLEN
];
709 union sockunion src_nbma
, src_proto
, dst_proto
;
710 struct nhrp_packet_header
*hdr
;
714 if (likely(!(debug_flags
& NHRP_DEBUG_COMMON
)))
717 zbuf_init(&zhdr
, zb
->buf
, zb
->tail
-zb
->buf
, zb
->tail
-zb
->buf
);
718 hdr
= nhrp_packet_pull(&zhdr
, &src_nbma
, &src_proto
, &dst_proto
);
720 sockunion2str(&src_proto
, buf
[0], sizeof buf
[0]);
721 sockunion2str(&dst_proto
, buf
[1], sizeof buf
[1]);
723 reply
= packet_types
[hdr
->type
].type
== PACKET_REPLY
;
724 debugf(NHRP_DEBUG_COMMON
, "%s %s(%d) %s -> %s",
726 packet_types
[hdr
->type
].name
? : "Unknown",
728 reply
? buf
[1] : buf
[0],
729 reply
? buf
[0] : buf
[1]);
732 struct nhrp_route_info
{
734 struct interface
*ifp
;
738 void nhrp_peer_recv(struct nhrp_peer
*p
, struct zbuf
*zb
)
740 char buf
[2][SU_ADDRSTRLEN
];
741 struct nhrp_packet_header
*hdr
;
742 struct nhrp_vc
*vc
= p
->vc
;
743 struct interface
*ifp
= p
->ifp
;
744 struct nhrp_interface
*nifp
= ifp
->info
;
745 struct nhrp_packet_parser pp
;
746 struct nhrp_peer
*peer
= NULL
;
747 struct nhrp_reqid
*reqid
;
748 const char *info
= NULL
;
749 union sockunion
*target_addr
;
750 unsigned paylen
, extoff
, extlen
, realsize
;
753 debugf(NHRP_DEBUG_KERNEL
, "PACKET: Recv %s -> %s",
754 sockunion2str(&vc
->remote
.nbma
, buf
[0], sizeof buf
[0]),
755 sockunion2str(&vc
->local
.nbma
, buf
[1], sizeof buf
[1]));
758 info
= "peer not online";
762 if (nhrp_packet_calculate_checksum(zb
->head
, zbuf_used(zb
)) != 0) {
763 info
= "bad checksum";
767 realsize
= zbuf_used(zb
);
768 hdr
= nhrp_packet_pull(zb
, &pp
.src_nbma
, &pp
.src_proto
, &pp
.dst_proto
);
770 info
= "corrupt header";
779 afi
= htons(hdr
->afnum
);
780 if (hdr
->type
> ZEBRA_NUM_OF(packet_types
) ||
781 hdr
->version
!= NHRP_VERSION_RFC2332
||
783 packet_types
[hdr
->type
].type
== PACKET_UNKNOWN
||
784 htons(hdr
->packet_size
) > realsize
) {
785 zlog_info("From %s: error: packet type %d, version %d, AFI %d, size %d (real size %d)",
786 sockunion2str(&vc
->remote
.nbma
, buf
[0], sizeof buf
[0]),
787 (int) hdr
->type
, (int) hdr
->version
, (int) afi
,
788 (int) htons(hdr
->packet_size
),
792 pp
.if_ad
= &((struct nhrp_interface
*)ifp
->info
)->afi
[afi
];
794 extoff
= htons(hdr
->extension_offset
);
796 if (extoff
>= realsize
) {
797 info
= "extoff larger than packet";
800 paylen
= extoff
- (zb
->head
- zb
->buf
);
802 paylen
= zbuf_used(zb
);
804 zbuf_init(&pp
.payload
, zbuf_pulln(zb
, paylen
), paylen
, paylen
);
805 extlen
= zbuf_used(zb
);
806 zbuf_init(&pp
.extensions
, zbuf_pulln(zb
, extlen
), extlen
, extlen
);
808 if (!nifp
->afi
[afi
].network_id
) {
809 info
= "nhrp not enabled";
813 nhrp_packet_debug(zb
, "Recv");
815 /* FIXME: Check authentication here. This extension needs to be
818 /* Figure out if this is local */
819 target_addr
= (packet_types
[hdr
->type
].type
== PACKET_REPLY
) ? &pp
.src_proto
: &pp
.dst_proto
;
821 if (sockunion_same(&pp
.src_proto
, &pp
.dst_proto
))
822 pp
.route_type
= NHRP_ROUTE_LOCAL
;
824 pp
.route_type
= nhrp_route_address(pp
.ifp
, target_addr
, &pp
.route_prefix
, &peer
);
826 switch (pp
.route_type
) {
827 case NHRP_ROUTE_LOCAL
:
828 nhrp_packet_debug(zb
, "!LOCAL");
829 if (packet_types
[hdr
->type
].type
== PACKET_REPLY
) {
830 reqid
= nhrp_reqid_lookup(&nhrp_packet_reqid
, htonl(hdr
->u
.request_id
));
832 reqid
->cb(reqid
, &pp
);
835 nhrp_packet_debug(zb
, "!UNKNOWN-REQID");
836 /* FIXME: send error-indication */
839 case NHRP_ROUTE_OFF_NBMA
:
840 if (packet_types
[hdr
->type
].handler
) {
841 packet_types
[hdr
->type
].handler(&pp
);
845 case NHRP_ROUTE_NBMA_NEXTHOP
:
846 nhrp_peer_forward(peer
, &pp
);
848 case NHRP_ROUTE_BLACKHOLE
:
854 zlog_info("From %s: error: %s",
855 sockunion2str(&vc
->remote
.nbma
, buf
[0], sizeof buf
[0]),
858 if (peer
) nhrp_peer_unref(peer
);