eth_p_oui.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. * hostapd / IEEE 802 OUI Extended EtherType 88-B7
  3. * Copyright (c) 2016, Jouni Malinen <j@w1.fi>
  4. *
  5. * This software may be distributed under the terms of the BSD license.
  6. * See README for more details.
  7. */
  8. #include "utils/includes.h"
  9. #include "utils/common.h"
  10. #include "utils/eloop.h"
  11. #include "l2_packet/l2_packet.h"
  12. #include "hostapd.h"
  13. #include "eth_p_oui.h"
  14. /*
  15. * See IEEE Std 802-2014, Clause 9.2.4 for the definition of the OUI Extended
  16. * EtherType 88-B7. This file implements this with OUI 00:13:74 and
  17. * vendor-specific subtype 0x0001.
  18. */
  19. static const u8 global_oui[] = { 0x00, 0x13, 0x74, 0x00, 0x01 };
  20. struct eth_p_oui_iface {
  21. struct dl_list list;
  22. char ifname[IFNAMSIZ + 1];
  23. struct l2_packet_data *l2;
  24. struct dl_list receiver;
  25. };
  26. struct eth_p_oui_ctx {
  27. struct dl_list list;
  28. struct eth_p_oui_iface *iface;
  29. /* all data needed to deliver and unregister */
  30. u8 oui_suffix; /* last byte of OUI */
  31. void (*rx_callback)(void *ctx, const u8 *src_addr,
  32. const u8 *dst_addr, u8 oui_suffix,
  33. const u8 *buf, size_t len);
  34. void *rx_callback_ctx;
  35. };
  36. void eth_p_oui_deliver(struct eth_p_oui_ctx *ctx, const u8 *src_addr,
  37. const u8 *dst_addr, const u8 *buf, size_t len)
  38. {
  39. ctx->rx_callback(ctx->rx_callback_ctx, src_addr, dst_addr,
  40. ctx->oui_suffix, buf, len);
  41. }
  42. static void eth_p_rx(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
  43. {
  44. struct eth_p_oui_iface *iface = ctx;
  45. struct eth_p_oui_ctx *receiver;
  46. const struct l2_ethhdr *ethhdr;
  47. if (len < sizeof(*ethhdr) + sizeof(global_oui) + 1) {
  48. /* too short packet */
  49. return;
  50. }
  51. ethhdr = (struct l2_ethhdr *) buf;
  52. /* trim eth_hdr from buf and len */
  53. buf += sizeof(*ethhdr);
  54. len -= sizeof(*ethhdr);
  55. /* verify OUI and vendor-specific subtype match */
  56. if (os_memcmp(buf, global_oui, sizeof(global_oui)) != 0)
  57. return;
  58. buf += sizeof(global_oui);
  59. len -= sizeof(global_oui);
  60. dl_list_for_each(receiver, &iface->receiver,
  61. struct eth_p_oui_ctx, list) {
  62. if (buf[0] != receiver->oui_suffix)
  63. continue;
  64. eth_p_oui_deliver(receiver, ethhdr->h_source, ethhdr->h_dest,
  65. buf + 1, len - 1);
  66. }
  67. }
  68. struct eth_p_oui_ctx *
  69. eth_p_oui_register(struct hostapd_data *hapd, const char *ifname, u8 oui_suffix,
  70. void (*rx_callback)(void *ctx, const u8 *src_addr,
  71. const u8 *dst_addr, u8 oui_suffix,
  72. const u8 *buf, size_t len),
  73. void *rx_callback_ctx)
  74. {
  75. struct eth_p_oui_iface *iface;
  76. struct eth_p_oui_ctx *receiver;
  77. int found = 0;
  78. struct hapd_interfaces *interfaces;
  79. receiver = os_zalloc(sizeof(*receiver));
  80. if (!receiver)
  81. goto err;
  82. receiver->oui_suffix = oui_suffix;
  83. receiver->rx_callback = rx_callback;
  84. receiver->rx_callback_ctx = rx_callback_ctx;
  85. interfaces = hapd->iface->interfaces;
  86. dl_list_for_each(iface, &interfaces->eth_p_oui, struct eth_p_oui_iface,
  87. list) {
  88. if (os_strcmp(iface->ifname, ifname) != 0)
  89. continue;
  90. found = 1;
  91. break;
  92. }
  93. if (!found) {
  94. iface = os_zalloc(sizeof(*iface));
  95. if (!iface)
  96. goto err;
  97. os_strlcpy(iface->ifname, ifname, sizeof(iface->ifname));
  98. iface->l2 = l2_packet_init(ifname, NULL, ETH_P_OUI, eth_p_rx,
  99. iface, 1);
  100. if (!iface->l2) {
  101. os_free(iface);
  102. goto err;
  103. }
  104. dl_list_init(&iface->receiver);
  105. dl_list_add_tail(&interfaces->eth_p_oui, &iface->list);
  106. }
  107. dl_list_add_tail(&iface->receiver, &receiver->list);
  108. receiver->iface = iface;
  109. return receiver;
  110. err:
  111. os_free(receiver);
  112. return NULL;
  113. }
  114. void eth_p_oui_unregister(struct eth_p_oui_ctx *ctx)
  115. {
  116. struct eth_p_oui_iface *iface;
  117. if (!ctx)
  118. return;
  119. iface = ctx->iface;
  120. dl_list_del(&ctx->list);
  121. os_free(ctx);
  122. if (dl_list_empty(&iface->receiver)) {
  123. dl_list_del(&iface->list);
  124. l2_packet_deinit(iface->l2);
  125. os_free(iface);
  126. }
  127. }
  128. int eth_p_oui_send(struct eth_p_oui_ctx *ctx, const u8 *src_addr,
  129. const u8 *dst_addr, const u8 *buf, size_t len)
  130. {
  131. struct eth_p_oui_iface *iface = ctx->iface;
  132. u8 *packet, *p;
  133. size_t packet_len;
  134. int ret;
  135. struct l2_ethhdr *ethhdr;
  136. packet_len = sizeof(*ethhdr) + sizeof(global_oui) + 1 + len;
  137. packet = os_zalloc(packet_len);
  138. if (!packet)
  139. return -1;
  140. p = packet;
  141. ethhdr = (struct l2_ethhdr *) packet;
  142. os_memcpy(ethhdr->h_source, src_addr, ETH_ALEN);
  143. os_memcpy(ethhdr->h_dest, dst_addr, ETH_ALEN);
  144. ethhdr->h_proto = host_to_be16(ETH_P_OUI);
  145. p += sizeof(*ethhdr);
  146. os_memcpy(p, global_oui, sizeof(global_oui));
  147. p[sizeof(global_oui)] = ctx->oui_suffix;
  148. p += sizeof(global_oui) + 1;
  149. os_memcpy(p, buf, len);
  150. ret = l2_packet_send(iface->l2, NULL, 0, packet, packet_len);
  151. os_free(packet);
  152. return ret;
  153. }