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 (!nifp->ipsec_profile)
253 if (sockunion_family(&vc->local.nbma) == AF_UNSPEC)
256 p->prio = establish > 1;
258 vici_request_vc(nifp->ipsec_profile, &vc->local.nbma, &vc->remote.nbma, p->prio);
259 THREAD_TIMER_ON(master, p->t_fallback, nhrp_peer_request_timeout, p,
260 (nifp->ipsec_fallback_profile && !p->prio) ? 15 : 30);
265 void nhrp_peer_notify_add(struct nhrp_peer *p, struct notifier_block *n, notifier_fn_t fn)
267 notifier_add(n, &p->notifier_list, fn);
270 void nhrp_peer_notify_del(struct nhrp_peer *p, struct notifier_block *n)
273 nhrp_peer_check_delete(p);
276 void nhrp_peer_send(struct nhrp_peer *p, struct zbuf *zb)
280 nhrp_packet_debug(zb, "Send");
285 debugf(NHRP_DEBUG_KERNEL, "PACKET: Send %s -> %s",
286 sockunion2str(&p->vc->local.nbma, buf[0], sizeof buf[0]),
287 sockunion2str(&p->vc->remote.nbma, buf[1], sizeof buf[1]));
289 os_sendmsg(zb->head, zbuf_used(zb),
291 sockunion_get_addr(&p->vc->remote.nbma),
292 sockunion_get_addrlen(&p->vc->remote.nbma));
296 static void nhrp_handle_resolution_req(struct nhrp_packet_parser *p)
298 struct zbuf *zb, payload;
299 struct nhrp_packet_header *hdr;
300 struct nhrp_cie_header *cie;
301 struct nhrp_extension_header *ext;
302 struct nhrp_interface *nifp;
303 struct nhrp_peer *peer;
305 if (!(p->if_ad->flags & NHRP_IFF_SHORTCUT)) {
306 debugf(NHRP_DEBUG_COMMON, "Shortcuts disabled");
307 /* FIXME: Send error indication? */
311 if (p->if_ad->network_id &&
312 p->route_type == NHRP_ROUTE_OFF_NBMA &&
313 p->route_prefix.prefixlen < 8) {
314 debugf(NHRP_DEBUG_COMMON, "Shortcut to more generic than /8 dropped");
318 debugf(NHRP_DEBUG_COMMON, "Parsing and replying to Resolution Req");
320 if (nhrp_route_address(p->ifp, &p->src_proto, NULL, &peer) != NHRP_ROUTE_NBMA_NEXTHOP)
324 /* FIXME: Update requestors binding if CIE specifies holding time */
325 nhrp_cache_update_binding(
326 NHRP_CACHE_CACHED, &p->src_proto,
327 nhrp_peer_get(p->ifp, &p->src_nbma),
328 htons(cie->holding_time));
331 nifp = peer->ifp->info;
334 zb = zbuf_alloc(1500);
335 hdr = nhrp_packet_push(zb, NHRP_PACKET_RESOLUTION_REPLY, &p->src_nbma, &p->src_proto, &p->dst_proto);
337 /* Copied information from request */
338 hdr->flags = p->hdr->flags & htons(NHRP_FLAG_RESOLUTION_SOURCE_IS_ROUTER|NHRP_FLAG_RESOLUTION_SOURCE_STABLE);
339 hdr->flags |= htons(NHRP_FLAG_RESOLUTION_DESTINATION_STABLE | NHRP_FLAG_RESOLUTION_AUTHORATIVE);
340 hdr->u.request_id = p->hdr->u.request_id;
343 cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &nifp->nbma, &p->if_ad->addr);
344 cie->holding_time = htons(p->if_ad->holdtime);
345 cie->mtu = htons(p->if_ad->mtu);
346 if (p->if_ad->network_id && p->route_type == NHRP_ROUTE_OFF_NBMA)
347 cie->prefix_length = p->route_prefix.prefixlen;
349 cie->prefix_length = 8 * sockunion_get_addrlen(&p->if_ad->addr);
351 /* Handle extensions */
352 while ((ext = nhrp_ext_pull(&p->extensions, &payload)) != NULL) {
353 switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) {
354 case NHRP_EXTENSION_NAT_ADDRESS:
355 if (sockunion_family(&nifp->nat_nbma) == AF_UNSPEC)
357 ext = nhrp_ext_push(zb, hdr, NHRP_EXTENSION_NAT_ADDRESS);
359 cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &nifp->nat_nbma, &p->if_ad->addr);
361 nhrp_ext_complete(zb, ext);
364 if (nhrp_ext_reply(zb, hdr, p->ifp, ext, &payload) < 0)
370 nhrp_packet_complete(zb, hdr);
371 nhrp_peer_send(peer, zb);
373 nhrp_peer_unref(peer);
377 static void nhrp_handle_registration_request(struct nhrp_packet_parser *p)
379 struct interface *ifp = p->ifp;
380 struct zbuf *zb, payload;
381 struct nhrp_packet_header *hdr;
382 struct nhrp_cie_header *cie;
383 struct nhrp_extension_header *ext;
384 struct nhrp_cache *c;
385 union sockunion cie_nbma, cie_proto, *proto_addr, *nbma_addr, *nbma_natoa;
386 int holdtime, prefix_len, hostprefix_len, natted = 0;
390 debugf(NHRP_DEBUG_COMMON, "Parsing and replying to Registration Req");
391 hostprefix_len = 8 * sockunion_get_addrlen(&p->if_ad->addr);
393 if (!sockunion_same(&p->src_nbma, &p->peer->vc->remote.nbma))
397 zb = zbuf_alloc(1500);
398 hdr = nhrp_packet_push(zb, NHRP_PACKET_REGISTRATION_REPLY,
399 &p->src_nbma, &p->src_proto, &p->if_ad->addr);
401 /* Copied information from request */
402 hdr->flags = p->hdr->flags & htons(NHRP_FLAG_REGISTRATION_UNIQUE | NHRP_FLAG_REGISTRATION_NAT);
403 hdr->u.request_id = p->hdr->u.request_id;
405 /* Copy payload CIEs */
406 paylen = zbuf_used(&p->payload);
407 pay = zbuf_pushn(zb, paylen);
409 memcpy(pay, zbuf_pulln(&p->payload, paylen), paylen);
410 zbuf_init(&payload, pay, paylen, paylen);
412 while ((cie = nhrp_cie_pull(&payload, hdr, &cie_nbma, &cie_proto)) != NULL) {
413 prefix_len = cie->prefix_length;
414 if (prefix_len == 0 || prefix_len >= hostprefix_len)
415 prefix_len = hostprefix_len;
417 if (prefix_len != hostprefix_len && !(p->hdr->flags & htons(NHRP_FLAG_REGISTRATION_UNIQUE))) {
418 cie->code = NHRP_CODE_BINDING_NON_UNIQUE;
422 /* We currently support only unique prefix registrations */
423 if (prefix_len != hostprefix_len) {
424 cie->code = NHRP_CODE_ADMINISTRATIVELY_PROHIBITED;
428 proto_addr = (sockunion_family(&cie_proto) == AF_UNSPEC) ? &p->src_proto : &cie_proto;
429 nbma_addr = (sockunion_family(&cie_nbma) == AF_UNSPEC) ? &p->src_nbma : &cie_nbma;
432 nbma_natoa = nbma_addr;
433 nbma_addr = &p->peer->vc->remote.nbma;
436 holdtime = htons(cie->holding_time);
437 if (!holdtime) holdtime = p->if_ad->holdtime;
439 c = nhrp_cache_get(ifp, proto_addr, 1);
441 cie->code = NHRP_CODE_INSUFFICIENT_RESOURCES;
445 if (!nhrp_cache_update_binding(c, NHRP_CACHE_DYNAMIC, holdtime, nhrp_peer_ref(p->peer), htons(cie->mtu), nbma_natoa)) {
446 cie->code = NHRP_CODE_ADMINISTRATIVELY_PROHIBITED;
450 cie->code = NHRP_CODE_SUCCESS;
453 /* Handle extensions */
454 while ((ext = nhrp_ext_pull(&p->extensions, &payload)) != NULL) {
455 switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) {
456 case NHRP_EXTENSION_NAT_ADDRESS:
457 ext = nhrp_ext_push(zb, hdr, NHRP_EXTENSION_NAT_ADDRESS);
459 zbuf_copy(zb, &payload, zbuf_used(&payload));
461 nhrp_cie_push(zb, NHRP_CODE_SUCCESS,
462 &p->peer->vc->remote.nbma,
465 nhrp_ext_complete(zb, ext);
468 if (nhrp_ext_reply(zb, hdr, ifp, ext, &payload) < 0)
474 nhrp_packet_complete(zb, hdr);
475 nhrp_peer_send(p->peer, zb);
480 static int parse_ether_packet(struct zbuf *zb, uint16_t protocol_type, union sockunion *src, union sockunion *dst)
482 switch (protocol_type) {
484 struct iphdr *iph = zbuf_pull(zb, struct iphdr);
486 if (src) sockunion_set(src, AF_INET, (uint8_t*) &iph->saddr, sizeof(iph->saddr));
487 if (dst) sockunion_set(dst, AF_INET, (uint8_t*) &iph->daddr, sizeof(iph->daddr));
492 struct ipv6hdr *iph = zbuf_pull(zb, struct ipv6hdr);
494 if (src) sockunion_set(src, AF_INET6, (uint8_t*) &iph->saddr, sizeof(iph->saddr));
495 if (dst) sockunion_set(dst, AF_INET6, (uint8_t*) &iph->daddr, sizeof(iph->daddr));
505 void nhrp_peer_send_indication(struct interface *ifp, uint16_t protocol_type, struct zbuf *pkt)
508 struct zbuf *zb, payload;
509 struct nhrp_interface *nifp = ifp->info;
510 struct nhrp_afi_data *if_ad;
511 struct nhrp_packet_header *hdr;
513 char buf[2][SU_ADDRSTRLEN];
515 if (!nifp->enabled) return;
518 if (!parse_ether_packet(&payload, protocol_type, &dst, NULL))
521 if (nhrp_route_address(ifp, &dst, NULL, &p) != NHRP_ROUTE_NBMA_NEXTHOP)
524 if_ad = &nifp->afi[family2afi(sockunion_family(&dst))];
525 if (!(if_ad->flags & NHRP_IFF_REDIRECT)) {
526 debugf(NHRP_DEBUG_COMMON, "Send Traffic Indication to %s about packet to %s ignored",
527 sockunion2str(&p->vc->remote.nbma, buf[0], sizeof buf[0]),
528 sockunion2str(&dst, buf[1], sizeof buf[1]));
532 debugf(NHRP_DEBUG_COMMON, "Send Traffic Indication to %s (online=%d) about packet to %s",
533 sockunion2str(&p->vc->remote.nbma, buf[0], sizeof buf[0]),
535 sockunion2str(&dst, buf[1], sizeof buf[1]));
538 zb = zbuf_alloc(1500);
539 hdr = nhrp_packet_push(zb, NHRP_PACKET_TRAFFIC_INDICATION, &nifp->nbma, &if_ad->addr, &dst);
542 /* Payload is the packet causing indication */
543 zbuf_copy(zb, pkt, zbuf_used(pkt));
544 nhrp_packet_complete(zb, hdr);
545 nhrp_peer_send(p, zb);
550 static void nhrp_handle_error_ind(struct nhrp_packet_parser *pp)
552 struct zbuf origmsg = pp->payload;
553 struct nhrp_packet_header *hdr;
554 struct nhrp_reqid *reqid;
555 union sockunion src_nbma, src_proto, dst_proto;
556 char buf[2][SU_ADDRSTRLEN];
558 hdr = nhrp_packet_pull(&origmsg, &src_nbma, &src_proto, &dst_proto);
561 debugf(NHRP_DEBUG_COMMON, "Error Indication from %s about packet to %s ignored",
562 sockunion2str(&pp->src_proto, buf[0], sizeof buf[0]),
563 sockunion2str(&dst_proto, buf[1], sizeof buf[1]));
565 reqid = nhrp_reqid_lookup(&nhrp_packet_reqid, htonl(hdr->u.request_id));
567 reqid->cb(reqid, pp);
570 static void nhrp_handle_traffic_ind(struct nhrp_packet_parser *p)
573 char buf[2][SU_ADDRSTRLEN];
575 if (!parse_ether_packet(&p->payload, htons(p->hdr->protocol_type), NULL, &dst))
578 debugf(NHRP_DEBUG_COMMON, "Traffic Indication from %s about packet to %s: %s",
579 sockunion2str(&p->src_proto, buf[0], sizeof buf[0]),
580 sockunion2str(&dst, buf[1], sizeof buf[1]),
581 (p->if_ad->flags & NHRP_IFF_SHORTCUT) ? "trying shortcut" : "ignored");
583 if (p->if_ad->flags & NHRP_IFF_SHORTCUT)
584 nhrp_shortcut_initiate(&dst);
595 enum packet_type_t type;
597 void (*handler)(struct nhrp_packet_parser *);
599 [NHRP_PACKET_RESOLUTION_REQUEST] = {
600 .type = PACKET_REQUEST,
601 .name = "Resolution-Request",
602 .handler = nhrp_handle_resolution_req,
604 [NHRP_PACKET_RESOLUTION_REPLY] = {
605 .type = PACKET_REPLY,
606 .name = "Resolution-Reply",
608 [NHRP_PACKET_REGISTRATION_REQUEST] = {
609 .type = PACKET_REQUEST,
610 .name = "Registration-Request",
611 .handler = nhrp_handle_registration_request,
613 [NHRP_PACKET_REGISTRATION_REPLY] = {
614 .type = PACKET_REPLY,
615 .name = "Registration-Reply",
617 [NHRP_PACKET_PURGE_REQUEST] = {
618 .type = PACKET_REQUEST,
619 .name = "Purge-Request",
621 [NHRP_PACKET_PURGE_REPLY] = {
622 .type = PACKET_REPLY,
623 .name = "Purge-Reply",
625 [NHRP_PACKET_ERROR_INDICATION] = {
626 .type = PACKET_INDICATION,
627 .name = "Error-Indication",
628 .handler = nhrp_handle_error_ind,
630 [NHRP_PACKET_TRAFFIC_INDICATION] = {
631 .type = PACKET_INDICATION,
632 .name = "Traffic-Indication",
633 .handler = nhrp_handle_traffic_ind,
637 static void nhrp_peer_forward(struct nhrp_peer *p, struct nhrp_packet_parser *pp)
639 struct zbuf *zb, extpl;
640 struct nhrp_packet_header *hdr;
641 struct nhrp_extension_header *ext, *dst;
642 struct nhrp_cie_header *cie;
643 struct nhrp_interface *nifp = pp->ifp->info;
644 struct nhrp_afi_data *if_ad = pp->if_ad;
645 union sockunion cie_nbma, cie_protocol;
648 if (pp->hdr->hop_count == 0)
651 /* Create forward packet - copy header */
652 zb = zbuf_alloc(1500);
653 hdr = nhrp_packet_push(zb, pp->hdr->type, &pp->src_nbma, &pp->src_proto, &pp->dst_proto);
654 hdr->flags = pp->hdr->flags;
655 hdr->hop_count = pp->hdr->hop_count - 1;
656 hdr->u.request_id = pp->hdr->u.request_id;
659 zbuf_copy(zb, &pp->payload, zbuf_used(&pp->payload));
661 /* Copy extensions */
662 while ((ext = nhrp_ext_pull(&pp->extensions, &extpl)) != NULL) {
663 type = htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY;
664 len = htons(ext->length);
666 if (type == NHRP_EXTENSION_END)
669 dst = nhrp_ext_push(zb, hdr, htons(ext->type));
673 case NHRP_EXTENSION_FORWARD_TRANSIT_NHS:
674 case NHRP_EXTENSION_REVERSE_TRANSIT_NHS:
675 zbuf_put(zb, extpl.head, len);
676 if ((type == NHRP_EXTENSION_REVERSE_TRANSIT_NHS) ==
677 (packet_types[hdr->type].type == PACKET_REPLY)) {
678 /* Check NHS list for forwarding loop */
679 while ((cie = nhrp_cie_pull(&extpl, pp->hdr, &cie_nbma, &cie_protocol)) != NULL) {
680 if (sockunion_same(&p->vc->remote.nbma, &cie_nbma))
683 /* Append our selves to the list */
684 cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &nifp->nbma, &if_ad->addr);
686 cie->holding_time = htons(if_ad->holdtime);
690 if (htons(ext->type) & NHRP_EXTENSION_FLAG_COMPULSORY)
691 /* FIXME: RFC says to just copy, but not
692 * append our selves to the transit NHS list */
694 case NHRP_EXTENSION_RESPONDER_ADDRESS:
695 /* Supported compulsory extensions, and any
696 * non-compulsory that is not explicitly handled,
697 * should be just copied. */
698 zbuf_copy(zb, &extpl, len);
701 nhrp_ext_complete(zb, dst);
704 nhrp_packet_complete(zb, hdr);
705 nhrp_peer_send(p, zb);
709 nhrp_packet_debug(pp->pkt, "FWD-FAIL");
713 static void nhrp_packet_debug(struct zbuf *zb, const char *dir)
715 char buf[2][SU_ADDRSTRLEN];
716 union sockunion src_nbma, src_proto, dst_proto;
717 struct nhrp_packet_header *hdr;
721 if (likely(!(debug_flags & NHRP_DEBUG_COMMON)))
724 zbuf_init(&zhdr, zb->buf, zb->tail-zb->buf, zb->tail-zb->buf);
725 hdr = nhrp_packet_pull(&zhdr, &src_nbma, &src_proto, &dst_proto);
727 sockunion2str(&src_proto, buf[0], sizeof buf[0]);
728 sockunion2str(&dst_proto, buf[1], sizeof buf[1]);
730 reply = packet_types[hdr->type].type == PACKET_REPLY;
731 debugf(NHRP_DEBUG_COMMON, "%s %s(%d) %s -> %s",
733 packet_types[hdr->type].name ? : "Unknown",
735 reply ? buf[1] : buf[0],
736 reply ? buf[0] : buf[1]);
739 static int proto2afi(uint16_t proto)
742 case ETH_P_IP: return AFI_IP;
743 case ETH_P_IPV6: return AFI_IP6;
748 struct nhrp_route_info {
750 struct interface *ifp;
754 void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb)
756 char buf[2][SU_ADDRSTRLEN];
757 struct nhrp_packet_header *hdr;
758 struct nhrp_vc *vc = p->vc;
759 struct interface *ifp = p->ifp;
760 struct nhrp_interface *nifp = ifp->info;
761 struct nhrp_packet_parser pp;
762 struct nhrp_peer *peer = NULL;
763 struct nhrp_reqid *reqid;
764 const char *info = NULL;
765 union sockunion *target_addr;
766 unsigned paylen, extoff, extlen, realsize;
767 afi_t nbma_afi, proto_afi;
769 debugf(NHRP_DEBUG_KERNEL, "PACKET: Recv %s -> %s",
770 sockunion2str(&vc->remote.nbma, buf[0], sizeof buf[0]),
771 sockunion2str(&vc->local.nbma, buf[1], sizeof buf[1]));
774 info = "peer not online";
778 if (nhrp_packet_calculate_checksum(zb->head, zbuf_used(zb)) != 0) {
779 info = "bad checksum";
783 realsize = zbuf_used(zb);
784 hdr = nhrp_packet_pull(zb, &pp.src_nbma, &pp.src_proto, &pp.dst_proto);
786 info = "corrupt header";
795 nbma_afi = htons(hdr->afnum);
796 proto_afi = proto2afi(htons(hdr->protocol_type));
797 if (hdr->type > ZEBRA_NUM_OF(packet_types) ||
798 hdr->version != NHRP_VERSION_RFC2332 ||
799 nbma_afi >= AFI_MAX || proto_afi == AF_UNSPEC ||
800 packet_types[hdr->type].type == PACKET_UNKNOWN ||
801 htons(hdr->packet_size) > realsize) {
802 zlog_info("From %s: error: packet type %d, version %d, AFI %d, proto %x, size %d (real size %d)",
803 sockunion2str(&vc->remote.nbma, buf[0], sizeof buf[0]),
804 (int) hdr->type, (int) hdr->version,
805 (int) nbma_afi, (int) htons(hdr->protocol_type),
806 (int) htons(hdr->packet_size), (int) realsize);
809 pp.if_ad = &((struct nhrp_interface *)ifp->info)->afi[proto_afi];
811 extoff = htons(hdr->extension_offset);
813 if (extoff >= realsize) {
814 info = "extoff larger than packet";
817 paylen = extoff - (zb->head - zb->buf);
819 paylen = zbuf_used(zb);
821 zbuf_init(&pp.payload, zbuf_pulln(zb, paylen), paylen, paylen);
822 extlen = zbuf_used(zb);
823 zbuf_init(&pp.extensions, zbuf_pulln(zb, extlen), extlen, extlen);
825 if (!nifp->afi[proto_afi].network_id) {
826 info = "nhrp not enabled";
830 nhrp_packet_debug(zb, "Recv");
832 /* FIXME: Check authentication here. This extension needs to be
835 /* Figure out if this is local */
836 target_addr = (packet_types[hdr->type].type == PACKET_REPLY) ? &pp.src_proto : &pp.dst_proto;
838 if (sockunion_same(&pp.src_proto, &pp.dst_proto))
839 pp.route_type = NHRP_ROUTE_LOCAL;
841 pp.route_type = nhrp_route_address(pp.ifp, target_addr, &pp.route_prefix, &peer);
843 switch (pp.route_type) {
844 case NHRP_ROUTE_LOCAL:
845 nhrp_packet_debug(zb, "!LOCAL");
846 if (packet_types[hdr->type].type == PACKET_REPLY) {
847 reqid = nhrp_reqid_lookup(&nhrp_packet_reqid, htonl(hdr->u.request_id));
849 reqid->cb(reqid, &pp);
852 nhrp_packet_debug(zb, "!UNKNOWN-REQID");
853 /* FIXME: send error-indication */
856 case NHRP_ROUTE_OFF_NBMA:
857 if (packet_types[hdr->type].handler) {
858 packet_types[hdr->type].handler(&pp);
862 case NHRP_ROUTE_NBMA_NEXTHOP:
863 nhrp_peer_forward(peer, &pp);
865 case NHRP_ROUTE_BLACKHOLE:
871 zlog_info("From %s: error: %s",
872 sockunion2str(&vc->remote.nbma, buf[0], sizeof buf[0]),
875 if (peer) nhrp_peer_unref(peer);