nhrp_peer.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878
  1. /* NHRP peer functions
  2. * Copyright (c) 2014-2015 Timo Teräs
  3. *
  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.
  8. */
  9. #include <netinet/if_ether.h>
  10. #include "zebra.h"
  11. #include "memory.h"
  12. #include "thread.h"
  13. #include "hash.h"
  14. #include "nhrpd.h"
  15. #include "nhrp_protocol.h"
  16. #include "os.h"
  17. struct ipv6hdr {
  18. uint8_t priority_version;
  19. uint8_t flow_lbl[3];
  20. uint16_t payload_len;
  21. uint8_t nexthdr;
  22. uint8_t hop_limit;
  23. struct in6_addr saddr;
  24. struct in6_addr daddr;
  25. };
  26. static void nhrp_packet_debug(struct zbuf *zb, const char *dir);
  27. static void nhrp_peer_check_delete(struct nhrp_peer *p)
  28. {
  29. struct nhrp_interface *nifp = p->ifp->info;
  30. if (p->ref || notifier_active(&p->notifier_list))
  31. return;
  32. THREAD_OFF(p->t_fallback);
  33. hash_release(nifp->peer_hash, p);
  34. nhrp_interface_notify_del(p->ifp, &p->ifp_notifier);
  35. nhrp_vc_notify_del(p->vc, &p->vc_notifier);
  36. XFREE(MTYPE_NHRP_PEER, p);
  37. }
  38. static int nhrp_peer_notify_up(struct thread *t)
  39. {
  40. struct nhrp_peer *p = THREAD_ARG(t);
  41. struct nhrp_vc *vc = p->vc;
  42. struct interface *ifp = p->ifp;
  43. struct nhrp_interface *nifp = ifp->info;
  44. p->t_fallback = NULL;
  45. if (nifp->enabled && (!nifp->ipsec_profile || vc->ipsec)) {
  46. p->online = 1;
  47. nhrp_peer_ref(p);
  48. notifier_call(&p->notifier_list, NOTIFY_PEER_UP);
  49. nhrp_peer_unref(p);
  50. }
  51. return 0;
  52. }
  53. static void __nhrp_peer_check(struct nhrp_peer *p)
  54. {
  55. struct nhrp_vc *vc = p->vc;
  56. struct interface *ifp = p->ifp;
  57. struct nhrp_interface *nifp = ifp->info;
  58. unsigned online;
  59. online = nifp->enabled && (!nifp->ipsec_profile || vc->ipsec);
  60. if (p->online != online) {
  61. THREAD_OFF(p->t_fallback);
  62. if (online && notifier_active(&p->notifier_list)) {
  63. /* If we requested the IPsec connection, delay
  64. * the up notification a bit to allow things
  65. * settle down. This allows IKE to install
  66. * SPDs and SAs. */
  67. THREAD_TIMER_MSEC_ON(
  68. master, p->t_fallback,
  69. nhrp_peer_notify_up, p, 50);
  70. } else {
  71. nhrp_peer_ref(p);
  72. p->online = online;
  73. if (online) {
  74. notifier_call(&p->notifier_list, NOTIFY_PEER_UP);
  75. } else {
  76. p->requested = p->fallback_requested = 0;
  77. notifier_call(&p->notifier_list, NOTIFY_PEER_DOWN);
  78. }
  79. nhrp_peer_unref(p);
  80. }
  81. }
  82. }
  83. static void nhrp_peer_vc_notify(struct notifier_block *n, unsigned long cmd)
  84. {
  85. struct nhrp_peer *p = container_of(n, struct nhrp_peer, vc_notifier);
  86. switch (cmd) {
  87. case NOTIFY_VC_IPSEC_CHANGED:
  88. __nhrp_peer_check(p);
  89. break;
  90. case NOTIFY_VC_IPSEC_UPDATE_NBMA:
  91. nhrp_peer_ref(p);
  92. notifier_call(&p->notifier_list, NOTIFY_PEER_NBMA_CHANGING);
  93. nhrp_peer_unref(p);
  94. break;
  95. }
  96. }
  97. static void nhrp_peer_ifp_notify(struct notifier_block *n, unsigned long cmd)
  98. {
  99. struct nhrp_peer *p = container_of(n, struct nhrp_peer, ifp_notifier);
  100. struct nhrp_interface *nifp;
  101. struct nhrp_vc *vc;
  102. nhrp_peer_ref(p);
  103. switch (cmd) {
  104. case NOTIFY_INTERFACE_UP:
  105. case NOTIFY_INTERFACE_DOWN:
  106. __nhrp_peer_check(p);
  107. break;
  108. case NOTIFY_INTERFACE_NBMA_CHANGED:
  109. /* Source NBMA changed, rebind to new VC */
  110. nifp = p->ifp->info;
  111. vc = nhrp_vc_get(&nifp->nbma, &p->vc->remote.nbma, 1);
  112. if (vc && p->vc != vc) {
  113. nhrp_vc_notify_del(p->vc, &p->vc_notifier);
  114. p->vc = vc;
  115. nhrp_vc_notify_add(p->vc, &p->vc_notifier, nhrp_peer_vc_notify);
  116. __nhrp_peer_check(p);
  117. }
  118. /* Fall-through to post config update */
  119. case NOTIFY_INTERFACE_ADDRESS_CHANGED:
  120. notifier_call(&p->notifier_list, NOTIFY_PEER_IFCONFIG_CHANGED);
  121. break;
  122. case NOTIFY_INTERFACE_MTU_CHANGED:
  123. notifier_call(&p->notifier_list, NOTIFY_PEER_MTU_CHANGED);
  124. break;
  125. }
  126. nhrp_peer_unref(p);
  127. }
  128. static unsigned int nhrp_peer_key(void *peer_data)
  129. {
  130. struct nhrp_peer *p = peer_data;
  131. return sockunion_hash(&p->vc->remote.nbma);
  132. }
  133. static int nhrp_peer_cmp(const void *cache_data, const void *key_data)
  134. {
  135. const struct nhrp_peer *a = cache_data;
  136. const struct nhrp_peer *b = key_data;
  137. return a->ifp == b->ifp && a->vc == b->vc;
  138. }
  139. static void *nhrp_peer_create(void *data)
  140. {
  141. struct nhrp_peer *p, *key = data;
  142. p = XMALLOC(MTYPE_NHRP_PEER, sizeof(*p));
  143. if (p) {
  144. *p = (struct nhrp_peer) {
  145. .ref = 0,
  146. .ifp = key->ifp,
  147. .vc = key->vc,
  148. .notifier_list = NOTIFIER_LIST_INITIALIZER(&p->notifier_list),
  149. };
  150. nhrp_vc_notify_add(p->vc, &p->vc_notifier, nhrp_peer_vc_notify);
  151. nhrp_interface_notify_add(p->ifp, &p->ifp_notifier, nhrp_peer_ifp_notify);
  152. }
  153. return p;
  154. }
  155. struct nhrp_peer *nhrp_peer_get(struct interface *ifp, const union sockunion *remote_nbma)
  156. {
  157. struct nhrp_interface *nifp = ifp->info;
  158. struct nhrp_peer key, *p;
  159. struct nhrp_vc *vc;
  160. if (!nifp->peer_hash) {
  161. nifp->peer_hash = hash_create(nhrp_peer_key, nhrp_peer_cmp);
  162. if (!nifp->peer_hash) return NULL;
  163. }
  164. vc = nhrp_vc_get(&nifp->nbma, remote_nbma, 1);
  165. if (!vc) return NULL;
  166. key.ifp = ifp;
  167. key.vc = vc;
  168. p = hash_get(nifp->peer_hash, &key, nhrp_peer_create);
  169. nhrp_peer_ref(p);
  170. if (p->ref == 1) __nhrp_peer_check(p);
  171. return p;
  172. }
  173. struct nhrp_peer *nhrp_peer_ref(struct nhrp_peer *p)
  174. {
  175. if (p) p->ref++;
  176. return p;
  177. }
  178. void nhrp_peer_unref(struct nhrp_peer *p)
  179. {
  180. if (p) {
  181. p->ref--;
  182. nhrp_peer_check_delete(p);
  183. }
  184. }
  185. static int nhrp_peer_request_timeout(struct thread *t)
  186. {
  187. struct nhrp_peer *p = THREAD_ARG(t);
  188. struct nhrp_vc *vc = p->vc;
  189. struct interface *ifp = p->ifp;
  190. struct nhrp_interface *nifp = ifp->info;
  191. p->t_fallback = NULL;
  192. if (p->online)
  193. return 0;
  194. if (nifp->ipsec_fallback_profile && !p->prio && !p->fallback_requested) {
  195. p->fallback_requested = 1;
  196. vici_request_vc(nifp->ipsec_fallback_profile,
  197. &vc->local.nbma, &vc->remote.nbma, p->prio);
  198. THREAD_TIMER_ON(master, p->t_fallback, nhrp_peer_request_timeout, p, 30);
  199. } else {
  200. p->requested = p->fallback_requested = 0;
  201. }
  202. return 0;
  203. }
  204. int nhrp_peer_check(struct nhrp_peer *p, int establish)
  205. {
  206. struct nhrp_vc *vc = p->vc;
  207. struct interface *ifp = p->ifp;
  208. struct nhrp_interface *nifp = ifp->info;
  209. if (p->online)
  210. return 1;
  211. if (!establish)
  212. return 0;
  213. if (p->requested)
  214. return 0;
  215. if (!nifp->ipsec_profile)
  216. return 0;
  217. if (sockunion_family(&vc->local.nbma) == AF_UNSPEC)
  218. return 0;
  219. p->prio = establish > 1;
  220. p->requested = 1;
  221. vici_request_vc(nifp->ipsec_profile, &vc->local.nbma, &vc->remote.nbma, p->prio);
  222. THREAD_TIMER_ON(master, p->t_fallback, nhrp_peer_request_timeout, p,
  223. (nifp->ipsec_fallback_profile && !p->prio) ? 15 : 30);
  224. return 0;
  225. }
  226. void nhrp_peer_notify_add(struct nhrp_peer *p, struct notifier_block *n, notifier_fn_t fn)
  227. {
  228. notifier_add(n, &p->notifier_list, fn);
  229. }
  230. void nhrp_peer_notify_del(struct nhrp_peer *p, struct notifier_block *n)
  231. {
  232. notifier_del(n);
  233. nhrp_peer_check_delete(p);
  234. }
  235. void nhrp_peer_send(struct nhrp_peer *p, struct zbuf *zb)
  236. {
  237. char buf[2][256];
  238. nhrp_packet_debug(zb, "Send");
  239. if (!p->online)
  240. return;
  241. debugf(NHRP_DEBUG_KERNEL, "PACKET: Send %s -> %s",
  242. sockunion2str(&p->vc->local.nbma, buf[0], sizeof buf[0]),
  243. sockunion2str(&p->vc->remote.nbma, buf[1], sizeof buf[1]));
  244. os_sendmsg(zb->head, zbuf_used(zb),
  245. p->ifp->ifindex,
  246. sockunion_get_addr(&p->vc->remote.nbma),
  247. sockunion_get_addrlen(&p->vc->remote.nbma));
  248. zbuf_reset(zb);
  249. }
  250. static void nhrp_handle_resolution_req(struct nhrp_packet_parser *p)
  251. {
  252. struct zbuf *zb, payload;
  253. struct nhrp_packet_header *hdr;
  254. struct nhrp_cie_header *cie;
  255. struct nhrp_extension_header *ext;
  256. struct nhrp_interface *nifp;
  257. struct nhrp_peer *peer;
  258. if (!(p->if_ad->flags & NHRP_IFF_SHORTCUT)) {
  259. debugf(NHRP_DEBUG_COMMON, "Shortcuts disabled");
  260. /* FIXME: Send error indication? */
  261. return;
  262. }
  263. if (p->if_ad->network_id &&
  264. p->route_type == NHRP_ROUTE_OFF_NBMA &&
  265. p->route_prefix.prefixlen < 8) {
  266. debugf(NHRP_DEBUG_COMMON, "Shortcut to more generic than /8 dropped");
  267. return;
  268. }
  269. debugf(NHRP_DEBUG_COMMON, "Parsing and replying to Resolution Req");
  270. if (nhrp_route_address(p->ifp, &p->src_proto, NULL, &peer) != NHRP_ROUTE_NBMA_NEXTHOP)
  271. return;
  272. #if 0
  273. /* FIXME: Update requestors binding if CIE specifies holding time */
  274. nhrp_cache_update_binding(
  275. NHRP_CACHE_CACHED, &p->src_proto,
  276. nhrp_peer_get(p->ifp, &p->src_nbma),
  277. htons(cie->holding_time));
  278. #endif
  279. nifp = peer->ifp->info;
  280. /* Create reply */
  281. zb = zbuf_alloc(1500);
  282. hdr = nhrp_packet_push(zb, NHRP_PACKET_RESOLUTION_REPLY, &p->src_nbma, &p->src_proto, &p->dst_proto);
  283. /* Copied information from request */
  284. hdr->flags = p->hdr->flags & htons(NHRP_FLAG_RESOLUTION_SOURCE_IS_ROUTER|NHRP_FLAG_RESOLUTION_SOURCE_STABLE);
  285. hdr->flags |= htons(NHRP_FLAG_RESOLUTION_DESTINATION_STABLE | NHRP_FLAG_RESOLUTION_AUTHORATIVE);
  286. hdr->u.request_id = p->hdr->u.request_id;
  287. /* CIE payload */
  288. cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &nifp->nbma, &p->if_ad->addr);
  289. cie->holding_time = htons(p->if_ad->holdtime);
  290. cie->mtu = htons(p->if_ad->mtu);
  291. if (p->if_ad->network_id && p->route_type == NHRP_ROUTE_OFF_NBMA)
  292. cie->prefix_length = p->route_prefix.prefixlen;
  293. else
  294. cie->prefix_length = 8 * sockunion_get_addrlen(&p->if_ad->addr);
  295. /* Handle extensions */
  296. while ((ext = nhrp_ext_pull(&p->extensions, &payload)) != NULL) {
  297. switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) {
  298. case NHRP_EXTENSION_NAT_ADDRESS:
  299. if (sockunion_family(&nifp->nat_nbma) == AF_UNSPEC)
  300. break;
  301. ext = nhrp_ext_push(zb, hdr, NHRP_EXTENSION_NAT_ADDRESS);
  302. if (!ext) goto err;
  303. cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &nifp->nat_nbma, &p->if_ad->addr);
  304. if (!cie) goto err;
  305. nhrp_ext_complete(zb, ext);
  306. break;
  307. default:
  308. if (nhrp_ext_reply(zb, hdr, p->ifp, ext, &payload) < 0)
  309. goto err;
  310. break;
  311. }
  312. }
  313. nhrp_packet_complete(zb, hdr);
  314. nhrp_peer_send(peer, zb);
  315. err:
  316. nhrp_peer_unref(peer);
  317. zbuf_free(zb);
  318. }
  319. static void nhrp_handle_registration_request(struct nhrp_packet_parser *p)
  320. {
  321. struct interface *ifp = p->ifp;
  322. struct zbuf *zb, payload;
  323. struct nhrp_packet_header *hdr;
  324. struct nhrp_cie_header *cie;
  325. struct nhrp_extension_header *ext;
  326. struct nhrp_cache *c;
  327. union sockunion cie_nbma, cie_proto, *proto_addr, *nbma_addr, *nbma_natoa;
  328. int holdtime, prefix_len, hostprefix_len, natted = 0;
  329. size_t paylen;
  330. void *pay;
  331. debugf(NHRP_DEBUG_COMMON, "Parsing and replying to Registration Req");
  332. hostprefix_len = 8 * sockunion_get_addrlen(&p->if_ad->addr);
  333. if (!sockunion_same(&p->src_nbma, &p->peer->vc->remote.nbma))
  334. natted = 1;
  335. /* Create reply */
  336. zb = zbuf_alloc(1500);
  337. hdr = nhrp_packet_push(zb, NHRP_PACKET_REGISTRATION_REPLY,
  338. &p->src_nbma, &p->src_proto, &p->if_ad->addr);
  339. /* Copied information from request */
  340. hdr->flags = p->hdr->flags & htons(NHRP_FLAG_REGISTRATION_UNIQUE | NHRP_FLAG_REGISTRATION_NAT);
  341. hdr->u.request_id = p->hdr->u.request_id;
  342. /* Copy payload CIEs */
  343. paylen = zbuf_used(&p->payload);
  344. pay = zbuf_pushn(zb, paylen);
  345. if (!pay) goto err;
  346. memcpy(pay, zbuf_pulln(&p->payload, paylen), paylen);
  347. zbuf_init(&payload, pay, paylen, paylen);
  348. while ((cie = nhrp_cie_pull(&payload, hdr, &cie_nbma, &cie_proto)) != NULL) {
  349. prefix_len = cie->prefix_length;
  350. if (prefix_len == 0 || prefix_len >= hostprefix_len)
  351. prefix_len = hostprefix_len;
  352. if (prefix_len != hostprefix_len && !(p->hdr->flags & htons(NHRP_FLAG_REGISTRATION_UNIQUE))) {
  353. cie->code = NHRP_CODE_BINDING_NON_UNIQUE;
  354. continue;
  355. }
  356. /* We currently support only unique prefix registrations */
  357. if (prefix_len != hostprefix_len) {
  358. cie->code = NHRP_CODE_ADMINISTRATIVELY_PROHIBITED;
  359. continue;
  360. }
  361. proto_addr = (sockunion_family(&cie_proto) == AF_UNSPEC) ? &p->src_proto : &cie_proto;
  362. nbma_addr = (sockunion_family(&cie_nbma) == AF_UNSPEC) ? &p->src_nbma : &cie_nbma;
  363. nbma_natoa = NULL;
  364. if (natted) {
  365. nbma_natoa = nbma_addr;
  366. nbma_addr = &p->peer->vc->remote.nbma;
  367. }
  368. holdtime = htons(cie->holding_time);
  369. if (!holdtime) holdtime = p->if_ad->holdtime;
  370. c = nhrp_cache_get(ifp, proto_addr, 1);
  371. if (!c) {
  372. cie->code = NHRP_CODE_INSUFFICIENT_RESOURCES;
  373. continue;
  374. }
  375. if (!nhrp_cache_update_binding(c, NHRP_CACHE_DYNAMIC, holdtime, nhrp_peer_ref(p->peer), htons(cie->mtu), nbma_natoa)) {
  376. cie->code = NHRP_CODE_ADMINISTRATIVELY_PROHIBITED;
  377. continue;
  378. }
  379. cie->code = NHRP_CODE_SUCCESS;
  380. }
  381. /* Handle extensions */
  382. while ((ext = nhrp_ext_pull(&p->extensions, &payload)) != NULL) {
  383. switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) {
  384. case NHRP_EXTENSION_NAT_ADDRESS:
  385. ext = nhrp_ext_push(zb, hdr, NHRP_EXTENSION_NAT_ADDRESS);
  386. if (!ext) goto err;
  387. zbuf_copy(zb, &payload, zbuf_used(&payload));
  388. if (natted) {
  389. nhrp_cie_push(zb, NHRP_CODE_SUCCESS,
  390. &p->peer->vc->remote.nbma,
  391. &p->src_proto);
  392. }
  393. nhrp_ext_complete(zb, ext);
  394. break;
  395. default:
  396. if (nhrp_ext_reply(zb, hdr, ifp, ext, &payload) < 0)
  397. goto err;
  398. break;
  399. }
  400. }
  401. nhrp_packet_complete(zb, hdr);
  402. nhrp_peer_send(p->peer, zb);
  403. err:
  404. zbuf_free(zb);
  405. }
  406. static int parse_ether_packet(struct zbuf *zb, uint16_t protocol_type, union sockunion *src, union sockunion *dst)
  407. {
  408. switch (protocol_type) {
  409. case ETH_P_IP: {
  410. struct iphdr *iph = zbuf_pull(zb, struct iphdr);
  411. if (iph) {
  412. if (src) sockunion_set(src, AF_INET, (uint8_t*) &iph->saddr, sizeof(iph->saddr));
  413. if (dst) sockunion_set(dst, AF_INET, (uint8_t*) &iph->daddr, sizeof(iph->daddr));
  414. }
  415. }
  416. break;
  417. case ETH_P_IPV6: {
  418. struct ipv6hdr *iph = zbuf_pull(zb, struct ipv6hdr);
  419. if (iph) {
  420. if (src) sockunion_set(src, AF_INET6, (uint8_t*) &iph->saddr, sizeof(iph->saddr));
  421. if (dst) sockunion_set(dst, AF_INET6, (uint8_t*) &iph->daddr, sizeof(iph->daddr));
  422. }
  423. }
  424. break;
  425. default:
  426. return 0;
  427. }
  428. return 1;
  429. }
  430. void nhrp_peer_send_indication(struct interface *ifp, uint16_t protocol_type, struct zbuf *pkt)
  431. {
  432. union sockunion dst;
  433. struct zbuf *zb, payload;
  434. struct nhrp_interface *nifp = ifp->info;
  435. struct nhrp_afi_data *if_ad;
  436. struct nhrp_packet_header *hdr;
  437. struct nhrp_peer *p;
  438. char buf[2][SU_ADDRSTRLEN];
  439. if (!nifp->enabled) return;
  440. payload = *pkt;
  441. if (!parse_ether_packet(&payload, protocol_type, &dst, NULL))
  442. return;
  443. if (nhrp_route_address(ifp, &dst, NULL, &p) != NHRP_ROUTE_NBMA_NEXTHOP)
  444. return;
  445. if_ad = &nifp->afi[family2afi(sockunion_family(&dst))];
  446. if (!(if_ad->flags & NHRP_IFF_REDIRECT)) {
  447. debugf(NHRP_DEBUG_COMMON, "Send Traffic Indication to %s about packet to %s ignored",
  448. sockunion2str(&p->vc->remote.nbma, buf[0], sizeof buf[0]),
  449. sockunion2str(&dst, buf[1], sizeof buf[1]));
  450. return;
  451. }
  452. debugf(NHRP_DEBUG_COMMON, "Send Traffic Indication to %s (online=%d) about packet to %s",
  453. sockunion2str(&p->vc->remote.nbma, buf[0], sizeof buf[0]),
  454. p->online,
  455. sockunion2str(&dst, buf[1], sizeof buf[1]));
  456. /* Create reply */
  457. zb = zbuf_alloc(1500);
  458. hdr = nhrp_packet_push(zb, NHRP_PACKET_TRAFFIC_INDICATION, &nifp->nbma, &if_ad->addr, &dst);
  459. hdr->hop_count = 0;
  460. /* Payload is the packet causing indication */
  461. zbuf_copy(zb, pkt, zbuf_used(pkt));
  462. nhrp_packet_complete(zb, hdr);
  463. nhrp_peer_send(p, zb);
  464. nhrp_peer_unref(p);
  465. zbuf_free(zb);
  466. }
  467. static void nhrp_handle_error_ind(struct nhrp_packet_parser *pp)
  468. {
  469. struct zbuf origmsg = pp->payload;
  470. struct nhrp_packet_header *hdr;
  471. struct nhrp_reqid *reqid;
  472. union sockunion src_nbma, src_proto, dst_proto;
  473. char buf[2][SU_ADDRSTRLEN];
  474. hdr = nhrp_packet_pull(&origmsg, &src_nbma, &src_proto, &dst_proto);
  475. if (!hdr) return;
  476. debugf(NHRP_DEBUG_COMMON, "Error Indication from %s about packet to %s ignored",
  477. sockunion2str(&pp->src_proto, buf[0], sizeof buf[0]),
  478. sockunion2str(&dst_proto, buf[1], sizeof buf[1]));
  479. reqid = nhrp_reqid_lookup(&nhrp_packet_reqid, htonl(hdr->u.request_id));
  480. if (reqid)
  481. reqid->cb(reqid, pp);
  482. }
  483. static void nhrp_handle_traffic_ind(struct nhrp_packet_parser *p)
  484. {
  485. union sockunion dst;
  486. char buf[2][SU_ADDRSTRLEN];
  487. if (!parse_ether_packet(&p->payload, htons(p->hdr->protocol_type), NULL, &dst))
  488. return;
  489. debugf(NHRP_DEBUG_COMMON, "Traffic Indication from %s about packet to %s: %s",
  490. sockunion2str(&p->src_proto, buf[0], sizeof buf[0]),
  491. sockunion2str(&dst, buf[1], sizeof buf[1]),
  492. (p->if_ad->flags & NHRP_IFF_SHORTCUT) ? "trying shortcut" : "ignored");
  493. if (p->if_ad->flags & NHRP_IFF_SHORTCUT)
  494. nhrp_shortcut_initiate(&dst);
  495. }
  496. enum packet_type_t {
  497. PACKET_UNKNOWN = 0,
  498. PACKET_REQUEST,
  499. PACKET_REPLY,
  500. PACKET_INDICATION,
  501. };
  502. static struct {
  503. enum packet_type_t type;
  504. const char *name;
  505. void (*handler)(struct nhrp_packet_parser *);
  506. } packet_types[] = {
  507. [NHRP_PACKET_RESOLUTION_REQUEST] = {
  508. .type = PACKET_REQUEST,
  509. .name = "Resolution-Request",
  510. .handler = nhrp_handle_resolution_req,
  511. },
  512. [NHRP_PACKET_RESOLUTION_REPLY] = {
  513. .type = PACKET_REPLY,
  514. .name = "Resolution-Reply",
  515. },
  516. [NHRP_PACKET_REGISTRATION_REQUEST] = {
  517. .type = PACKET_REQUEST,
  518. .name = "Registration-Request",
  519. .handler = nhrp_handle_registration_request,
  520. },
  521. [NHRP_PACKET_REGISTRATION_REPLY] = {
  522. .type = PACKET_REPLY,
  523. .name = "Registration-Reply",
  524. },
  525. [NHRP_PACKET_PURGE_REQUEST] = {
  526. .type = PACKET_REQUEST,
  527. .name = "Purge-Request",
  528. },
  529. [NHRP_PACKET_PURGE_REPLY] = {
  530. .type = PACKET_REPLY,
  531. .name = "Purge-Reply",
  532. },
  533. [NHRP_PACKET_ERROR_INDICATION] = {
  534. .type = PACKET_INDICATION,
  535. .name = "Error-Indication",
  536. .handler = nhrp_handle_error_ind,
  537. },
  538. [NHRP_PACKET_TRAFFIC_INDICATION] = {
  539. .type = PACKET_INDICATION,
  540. .name = "Traffic-Indication",
  541. .handler = nhrp_handle_traffic_ind,
  542. }
  543. };
  544. static void nhrp_peer_forward(struct nhrp_peer *p, struct nhrp_packet_parser *pp)
  545. {
  546. struct zbuf *zb, extpl;
  547. struct nhrp_packet_header *hdr;
  548. struct nhrp_extension_header *ext, *dst;
  549. struct nhrp_cie_header *cie;
  550. struct nhrp_interface *nifp = pp->ifp->info;
  551. struct nhrp_afi_data *if_ad = pp->if_ad;
  552. union sockunion cie_nbma, cie_protocol;
  553. uint16_t type, len;
  554. if (pp->hdr->hop_count == 0)
  555. return;
  556. /* Create forward packet - copy header */
  557. zb = zbuf_alloc(1500);
  558. hdr = nhrp_packet_push(zb, pp->hdr->type, &pp->src_nbma, &pp->src_proto, &pp->dst_proto);
  559. hdr->flags = pp->hdr->flags;
  560. hdr->hop_count = pp->hdr->hop_count - 1;
  561. hdr->u.request_id = pp->hdr->u.request_id;
  562. /* Copy payload */
  563. zbuf_copy(zb, &pp->payload, zbuf_used(&pp->payload));
  564. /* Copy extensions */
  565. while ((ext = nhrp_ext_pull(&pp->extensions, &extpl)) != NULL) {
  566. type = htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY;
  567. len = htons(ext->length);
  568. if (type == NHRP_EXTENSION_END)
  569. break;
  570. dst = nhrp_ext_push(zb, hdr, htons(ext->type));
  571. if (!dst) goto err;
  572. switch (type) {
  573. case NHRP_EXTENSION_FORWARD_TRANSIT_NHS:
  574. case NHRP_EXTENSION_REVERSE_TRANSIT_NHS:
  575. zbuf_put(zb, extpl.head, len);
  576. if ((type == NHRP_EXTENSION_REVERSE_TRANSIT_NHS) ==
  577. (packet_types[hdr->type].type == PACKET_REPLY)) {
  578. /* Check NHS list for forwarding loop */
  579. while ((cie = nhrp_cie_pull(&extpl, pp->hdr, &cie_nbma, &cie_protocol)) != NULL) {
  580. if (sockunion_same(&p->vc->remote.nbma, &cie_nbma))
  581. goto err;
  582. }
  583. /* Append our selves to the list */
  584. cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &nifp->nbma, &if_ad->addr);
  585. if (!cie) goto err;
  586. cie->holding_time = htons(if_ad->holdtime);
  587. }
  588. break;
  589. default:
  590. if (htons(ext->type) & NHRP_EXTENSION_FLAG_COMPULSORY)
  591. /* FIXME: RFC says to just copy, but not
  592. * append our selves to the transit NHS list */
  593. goto err;
  594. case NHRP_EXTENSION_RESPONDER_ADDRESS:
  595. /* Supported compulsory extensions, and any
  596. * non-compulsory that is not explicitly handled,
  597. * should be just copied. */
  598. zbuf_copy(zb, &extpl, len);
  599. break;
  600. }
  601. nhrp_ext_complete(zb, dst);
  602. }
  603. nhrp_packet_complete(zb, hdr);
  604. nhrp_peer_send(p, zb);
  605. zbuf_free(zb);
  606. return;
  607. err:
  608. nhrp_packet_debug(pp->pkt, "FWD-FAIL");
  609. zbuf_free(zb);
  610. }
  611. static void nhrp_packet_debug(struct zbuf *zb, const char *dir)
  612. {
  613. char buf[2][SU_ADDRSTRLEN];
  614. union sockunion src_nbma, src_proto, dst_proto;
  615. struct nhrp_packet_header *hdr;
  616. struct zbuf zhdr;
  617. int reply;
  618. if (likely(!(debug_flags & NHRP_DEBUG_COMMON)))
  619. return;
  620. zbuf_init(&zhdr, zb->buf, zb->tail-zb->buf, zb->tail-zb->buf);
  621. hdr = nhrp_packet_pull(&zhdr, &src_nbma, &src_proto, &dst_proto);
  622. sockunion2str(&src_proto, buf[0], sizeof buf[0]);
  623. sockunion2str(&dst_proto, buf[1], sizeof buf[1]);
  624. reply = packet_types[hdr->type].type == PACKET_REPLY;
  625. debugf(NHRP_DEBUG_COMMON, "%s %s(%d) %s -> %s",
  626. dir,
  627. packet_types[hdr->type].name ? : "Unknown",
  628. hdr->type,
  629. reply ? buf[1] : buf[0],
  630. reply ? buf[0] : buf[1]);
  631. }
  632. static int proto2afi(uint16_t proto)
  633. {
  634. switch (proto) {
  635. case ETH_P_IP: return AFI_IP;
  636. case ETH_P_IPV6: return AFI_IP6;
  637. }
  638. return AF_UNSPEC;
  639. }
  640. struct nhrp_route_info {
  641. int local;
  642. struct interface *ifp;
  643. struct nhrp_vc *vc;
  644. };
  645. void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb)
  646. {
  647. char buf[2][SU_ADDRSTRLEN];
  648. struct nhrp_packet_header *hdr;
  649. struct nhrp_vc *vc = p->vc;
  650. struct interface *ifp = p->ifp;
  651. struct nhrp_interface *nifp = ifp->info;
  652. struct nhrp_packet_parser pp;
  653. struct nhrp_peer *peer = NULL;
  654. struct nhrp_reqid *reqid;
  655. const char *info = NULL;
  656. union sockunion *target_addr;
  657. unsigned paylen, extoff, extlen, realsize;
  658. afi_t nbma_afi, proto_afi;
  659. debugf(NHRP_DEBUG_KERNEL, "PACKET: Recv %s -> %s",
  660. sockunion2str(&vc->remote.nbma, buf[0], sizeof buf[0]),
  661. sockunion2str(&vc->local.nbma, buf[1], sizeof buf[1]));
  662. if (!p->online) {
  663. info = "peer not online";
  664. goto drop;
  665. }
  666. if (nhrp_packet_calculate_checksum(zb->head, zbuf_used(zb)) != 0) {
  667. info = "bad checksum";
  668. goto drop;
  669. }
  670. realsize = zbuf_used(zb);
  671. hdr = nhrp_packet_pull(zb, &pp.src_nbma, &pp.src_proto, &pp.dst_proto);
  672. if (!hdr) {
  673. info = "corrupt header";
  674. goto drop;
  675. }
  676. pp.ifp = ifp;
  677. pp.pkt = zb;
  678. pp.hdr = hdr;
  679. pp.peer = p;
  680. nbma_afi = htons(hdr->afnum);
  681. proto_afi = proto2afi(htons(hdr->protocol_type));
  682. if (hdr->type > ZEBRA_NUM_OF(packet_types) ||
  683. hdr->version != NHRP_VERSION_RFC2332 ||
  684. nbma_afi >= AFI_MAX || proto_afi == AF_UNSPEC ||
  685. packet_types[hdr->type].type == PACKET_UNKNOWN ||
  686. htons(hdr->packet_size) > realsize) {
  687. zlog_info("From %s: error: packet type %d, version %d, AFI %d, proto %x, size %d (real size %d)",
  688. sockunion2str(&vc->remote.nbma, buf[0], sizeof buf[0]),
  689. (int) hdr->type, (int) hdr->version,
  690. (int) nbma_afi, (int) htons(hdr->protocol_type),
  691. (int) htons(hdr->packet_size), (int) realsize);
  692. goto drop;
  693. }
  694. pp.if_ad = &((struct nhrp_interface *)ifp->info)->afi[proto_afi];
  695. extoff = htons(hdr->extension_offset);
  696. if (extoff) {
  697. if (extoff >= realsize) {
  698. info = "extoff larger than packet";
  699. goto drop;
  700. }
  701. paylen = extoff - (zb->head - zb->buf);
  702. } else {
  703. paylen = zbuf_used(zb);
  704. }
  705. zbuf_init(&pp.payload, zbuf_pulln(zb, paylen), paylen, paylen);
  706. extlen = zbuf_used(zb);
  707. zbuf_init(&pp.extensions, zbuf_pulln(zb, extlen), extlen, extlen);
  708. if (!nifp->afi[proto_afi].network_id) {
  709. info = "nhrp not enabled";
  710. goto drop;
  711. }
  712. nhrp_packet_debug(zb, "Recv");
  713. /* FIXME: Check authentication here. This extension needs to be
  714. * pre-handled. */
  715. /* Figure out if this is local */
  716. target_addr = (packet_types[hdr->type].type == PACKET_REPLY) ? &pp.src_proto : &pp.dst_proto;
  717. if (sockunion_same(&pp.src_proto, &pp.dst_proto))
  718. pp.route_type = NHRP_ROUTE_LOCAL;
  719. else
  720. pp.route_type = nhrp_route_address(pp.ifp, target_addr, &pp.route_prefix, &peer);
  721. switch (pp.route_type) {
  722. case NHRP_ROUTE_LOCAL:
  723. nhrp_packet_debug(zb, "!LOCAL");
  724. if (packet_types[hdr->type].type == PACKET_REPLY) {
  725. reqid = nhrp_reqid_lookup(&nhrp_packet_reqid, htonl(hdr->u.request_id));
  726. if (reqid) {
  727. reqid->cb(reqid, &pp);
  728. break;
  729. } else {
  730. nhrp_packet_debug(zb, "!UNKNOWN-REQID");
  731. /* FIXME: send error-indication */
  732. }
  733. }
  734. case NHRP_ROUTE_OFF_NBMA:
  735. if (packet_types[hdr->type].handler) {
  736. packet_types[hdr->type].handler(&pp);
  737. break;
  738. }
  739. break;
  740. case NHRP_ROUTE_NBMA_NEXTHOP:
  741. nhrp_peer_forward(peer, &pp);
  742. break;
  743. case NHRP_ROUTE_BLACKHOLE:
  744. break;
  745. }
  746. drop:
  747. if (info) {
  748. zlog_info("From %s: error: %s",
  749. sockunion2str(&vc->remote.nbma, buf[0], sizeof buf[0]),
  750. info);
  751. }
  752. if (peer) nhrp_peer_unref(peer);
  753. zbuf_free(zb);
  754. }