Add data structures to store announcements and partly implement updates
This commit is contained in:
parent
e03169f859
commit
4a44820179
8 changed files with 300 additions and 17 deletions
|
@ -1,6 +1,7 @@
|
||||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${FFD_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${FFD_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
add_executable(ffd
|
add_executable(ffd
|
||||||
|
announce.c
|
||||||
ffd.c
|
ffd.c
|
||||||
neigh.c
|
neigh.c
|
||||||
netif.c
|
netif.c
|
||||||
|
|
83
ffd/announce.c
Normal file
83
ffd/announce.c
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2012, Matthias Schiffer <mschiffer@universe-factory.net>
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "ffd.h"
|
||||||
|
|
||||||
|
|
||||||
|
static bool is_feasable(const ffd_announce_t *announce, const ffd_nexthop_t *nexthop) {
|
||||||
|
if (FFD_IS_INFINITY(announce->feasability_distance))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
int16_t seqno_diff = nexthop->metric_seqno.seqno - announce->feasability_distance.seqno;
|
||||||
|
|
||||||
|
if (seqno_diff < 0)
|
||||||
|
return true;
|
||||||
|
if (seqno_diff == 0 && nexthop->metric_seqno.metric < announce->feasability_distance.metric)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ffd_nexthop_t* select_nexthop(const ffd_announce_t *announce) {
|
||||||
|
ffd_nexthop_t *ret = NULL;
|
||||||
|
|
||||||
|
ffd_nexthop_t *nexthop;
|
||||||
|
for (nexthop = announce->nexthop_list->next; nexthop; nexthop = nexthop->next) {
|
||||||
|
if (is_feasable(announce, nexthop))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int16_t seqno_diff = nexthop->metric_seqno.seqno - ret->metric_seqno.seqno;
|
||||||
|
|
||||||
|
if (nexthop->metric_seqno.metric < ret->metric_seqno.metric
|
||||||
|
|| (nexthop->metric_seqno.metric == ret->metric_seqno.metric && seqno_diff < 0)) {
|
||||||
|
ret = nexthop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ffd_metric_seqno_t ffd_announce_get_metric(const ffd_announce_t *announce) {
|
||||||
|
ffd_nexthop_t *nexthop = select_nexthop(announce);
|
||||||
|
|
||||||
|
if (nexthop)
|
||||||
|
return nexthop->metric_seqno;
|
||||||
|
else
|
||||||
|
return (ffd_metric_seqno_t){0xffff, 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ffd_announce_t* ffd_announce_new(size_t len) {
|
||||||
|
ffd_announce_t *a = calloc(1, sizeof(ffd_announce_t)+len);
|
||||||
|
|
||||||
|
a->len = len;
|
||||||
|
a->feasability_distance = (ffd_metric_seqno_t){0xffff, 0};
|
||||||
|
|
||||||
|
a->next = announce_list;
|
||||||
|
announce_list = a;
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
52
ffd/ffd.c
52
ffd/ffd.c
|
@ -51,14 +51,11 @@ static char *mesh = "bat0";
|
||||||
int sockfd;
|
int sockfd;
|
||||||
struct timespec now;
|
struct timespec now;
|
||||||
|
|
||||||
|
ffd_node_id_t self;
|
||||||
|
|
||||||
ffd_iface_t *iface_list = NULL;
|
ffd_iface_t *iface_list = NULL;
|
||||||
|
|
||||||
static ffd_neigh_t self;
|
ffd_announce_t *announce_list = NULL;
|
||||||
//static ffd_orig_t own_data;
|
|
||||||
|
|
||||||
/* neighs and origs that have been changed must be moved to front */
|
|
||||||
//static ffd_neigh_t *neigh_data = NULL;
|
|
||||||
//static ffd_orig_t *orig_data = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
static inline bool use_netif(const char *ifname) {
|
static inline bool use_netif(const char *ifname) {
|
||||||
|
@ -87,13 +84,27 @@ static bool init_self() {
|
||||||
if (is_eth_addr_unspec(&primary_addr))
|
if (is_eth_addr_unspec(&primary_addr))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
memset(&self, 0, sizeof(self));
|
self.id[0] = primary_addr.d[0]^0x02;
|
||||||
//memset(&own_data, 0, sizeof(own_data));
|
self.id[1] = primary_addr.d[1];
|
||||||
|
self.id[2] = primary_addr.d[2];
|
||||||
|
self.id[3] = 0xff;
|
||||||
|
self.id[4] = 0xfe;
|
||||||
|
self.id[5] = primary_addr.d[3];
|
||||||
|
self.id[6] = primary_addr.d[4];
|
||||||
|
self.id[7] = primary_addr.d[5];
|
||||||
|
|
||||||
//self.addr = own_data.addr = primary_addr;
|
ffd_announce_t *announce = announce_list = calloc(1, sizeof(ffd_announce_t));
|
||||||
|
|
||||||
//random_bytes(&self.rev, sizeof(self.rev));
|
announce->node = self;
|
||||||
//random_bytes(&own_data.rev, sizeof(own_data.rev));
|
announce->type = 1;
|
||||||
|
announce->key = 1337;
|
||||||
|
announce->interval = 6000;
|
||||||
|
|
||||||
|
ffd_nexthop_t *nexthop = announce->nexthop_list = malloc(sizeof(ffd_nexthop_t));
|
||||||
|
|
||||||
|
nexthop->addr = ETH_ADDR_UNSPEC;
|
||||||
|
nexthop->metric_seqno.metric = 0;
|
||||||
|
nexthop->metric_seqno.seqno = 0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -246,6 +257,21 @@ static void handle_tlv_ihu(const ffd_tlv_ihu_t *tlv_ihu, size_t len, const eth_a
|
||||||
fprintf(stderr, "debug: accepted IHU, txcost is %u, cost is %u now.\n", neigh->txcost, ffd_neigh_get_cost(neigh));
|
fprintf(stderr, "debug: accepted IHU, txcost is %u, cost is %u now.\n", neigh->txcost, ffd_neigh_get_cost(neigh));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_tlv_announce_req(const ffd_tlv_announce_req_t *tlv_req, size_t len, const eth_addr_t *addr, ffd_iface_t *iface) {
|
||||||
|
if (len < sizeof(ffd_tlv_announce_req_t)) {
|
||||||
|
fprintf(stderr, "warn: received short announce request TLV.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ffd_announce_t *announce = NULL;
|
||||||
|
|
||||||
|
if (!ffd_is_node_id_unspec(&tlv_req->node)) {
|
||||||
|
announce = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ffd_send_update(iface, ffd_neigh_get(iface, addr), announce);
|
||||||
|
}
|
||||||
|
|
||||||
static void handle_tlv(ffd_tlv_type_t type, const void *data, size_t len, void *arg) {
|
static void handle_tlv(ffd_tlv_type_t type, const void *data, size_t len, void *arg) {
|
||||||
const struct sockaddr_ll *from = arg;
|
const struct sockaddr_ll *from = arg;
|
||||||
const eth_addr_t *addr = (const eth_addr_t*)from->sll_addr;
|
const eth_addr_t *addr = (const eth_addr_t*)from->sll_addr;
|
||||||
|
@ -263,6 +289,10 @@ static void handle_tlv(ffd_tlv_type_t type, const void *data, size_t len, void *
|
||||||
handle_tlv_ihu(data, len, addr, iface);
|
handle_tlv_ihu(data, len, addr, iface);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
case TLV_ANNOUNCE_REQ:
|
||||||
|
handle_tlv_announce_req(data, len, addr, iface);
|
||||||
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "debug: received unknown TLV %u on %s.\n", type, iface->name);
|
fprintf(stderr, "debug: received unknown TLV %u on %s.\n", type, iface->name);
|
||||||
return;
|
return;
|
||||||
|
|
62
ffd/ffd.h
62
ffd/ffd.h
|
@ -41,13 +41,64 @@
|
||||||
#define FFD_IHU_INTERVAL (3*FFD_HELLO_INTERVAL)
|
#define FFD_IHU_INTERVAL (3*FFD_HELLO_INTERVAL)
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct __attribute__((packed)) _ffd_node_id_t {
|
||||||
|
uint8_t id[8];
|
||||||
|
} ffd_node_id_t;
|
||||||
|
|
||||||
|
|
||||||
|
#define FFD_NODE_ID_UNSPEC ((ffd_node_id_t){})
|
||||||
|
|
||||||
|
|
||||||
|
static inline bool ffd_is_node_id_unspec(const ffd_node_id_t *node) {
|
||||||
|
const uint8_t *id = node->id;
|
||||||
|
|
||||||
|
if (id[0]||id[1]||id[2]||id[3]||id[4]||id[5]||id[6]||id[7])
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool ffd_are_node_ids_equal(const ffd_node_id_t *id1, const ffd_node_id_t *id2) {
|
||||||
|
const uint8_t *a = id1->id;
|
||||||
|
const uint8_t *b = id2->id;
|
||||||
|
|
||||||
|
return (a[0]==b[0] && a[1]==b[1] && a[2]==b[2] && a[3]==b[3]
|
||||||
|
&& a[4]==b[4] && a[5]==b[5] && a[6]==b[6] && a[7]==b[7]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct _ffd_metric_seqno_t {
|
||||||
|
uint16_t metric;
|
||||||
|
uint16_t seqno;
|
||||||
|
} ffd_metric_seqno_t;
|
||||||
|
|
||||||
|
#define FFD_IS_INFINITY(m) ((m).metric == 0xffff)
|
||||||
|
|
||||||
|
typedef struct _ffd_nexthop_t {
|
||||||
|
struct _ffd_nexthop_t *next;
|
||||||
|
|
||||||
|
struct timespec last_update;
|
||||||
|
eth_addr_t addr;
|
||||||
|
ffd_metric_seqno_t metric_seqno;
|
||||||
|
} ffd_nexthop_t;
|
||||||
|
|
||||||
typedef struct _ffd_announce_t {
|
typedef struct _ffd_announce_t {
|
||||||
struct _ffd_announce_t *next;
|
struct _ffd_announce_t *next;
|
||||||
|
|
||||||
uint8_t type;
|
ffd_node_id_t node;
|
||||||
|
uint16_t type;
|
||||||
|
uint16_t key;
|
||||||
|
uint16_t interval;
|
||||||
|
|
||||||
uint8_t len;
|
uint8_t len;
|
||||||
|
|
||||||
|
ffd_metric_seqno_t feasability_distance;
|
||||||
|
|
||||||
|
ffd_nexthop_t *selected;
|
||||||
|
ffd_nexthop_t *nexthop_list;
|
||||||
|
|
||||||
uint8_t data[];
|
uint8_t data[];
|
||||||
} ffd_announce_head_t;
|
} ffd_announce_t;
|
||||||
|
|
||||||
typedef struct _ffd_neigh_t {
|
typedef struct _ffd_neigh_t {
|
||||||
struct _ffd_neigh_t *next;
|
struct _ffd_neigh_t *next;
|
||||||
|
@ -80,12 +131,17 @@ typedef struct _ffd_iface_t {
|
||||||
extern const eth_addr_t ffd_addr;
|
extern const eth_addr_t ffd_addr;
|
||||||
|
|
||||||
extern ffd_iface_t *iface_list;
|
extern ffd_iface_t *iface_list;
|
||||||
|
extern ffd_announce_t *announce_list;
|
||||||
|
|
||||||
extern int sockfd;
|
extern int sockfd;
|
||||||
extern struct timespec now;
|
extern struct timespec now;
|
||||||
|
|
||||||
|
|
||||||
|
ffd_metric_seqno_t ffd_announce_get_metric(const ffd_announce_t *announce);
|
||||||
|
ffd_announce_t* ffd_announce_new();
|
||||||
|
|
||||||
void ffd_send_hellos();
|
void ffd_send_hellos();
|
||||||
void ffd_send_announce_request(ffd_iface_t *iface, ffd_neigh_t *neigh, void *announce);
|
void ffd_send_update(ffd_iface_t *iface, ffd_neigh_t *neigh, const ffd_announce_t *announce);
|
||||||
|
void ffd_send_announce_request(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_node_id_t node, uint16_t type, uint16_t key);
|
||||||
|
|
||||||
#endif /* _FFD_FFD_H_ */
|
#endif /* _FFD_FFD_H_ */
|
||||||
|
|
|
@ -50,6 +50,9 @@ void ffd_neigh_free_list(ffd_neigh_t *neigh) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t ffd_neigh_get_rxcost(const ffd_neigh_t *neigh) {
|
uint16_t ffd_neigh_get_rxcost(const ffd_neigh_t *neigh) {
|
||||||
|
if (!neigh->hello_log || !neigh->hello_interval)
|
||||||
|
return 0xffff;
|
||||||
|
|
||||||
int timediff = timespec_diff(&now, &neigh->last_hello)/10;
|
int timediff = timespec_diff(&now, &neigh->last_hello)/10;
|
||||||
int shift = (timediff - neigh->hello_interval/2)/neigh->hello_interval;
|
int shift = (timediff - neigh->hello_interval/2)/neigh->hello_interval;
|
||||||
int received = __builtin_popcount(neigh->hello_log << shift);
|
int received = __builtin_popcount(neigh->hello_log << shift);
|
||||||
|
@ -74,5 +77,5 @@ uint16_t ffd_neigh_get_cost(const ffd_neigh_t *neigh) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ffd_neigh_reset(ffd_iface_t *iface, ffd_neigh_t *neigh) {
|
void ffd_neigh_reset(ffd_iface_t *iface, ffd_neigh_t *neigh) {
|
||||||
ffd_send_announce_request(iface, neigh, NULL);
|
ffd_send_announce_request(iface, neigh, FFD_NODE_ID_UNSPEC, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
86
ffd/send.c
86
ffd/send.c
|
@ -116,6 +116,90 @@ void ffd_send_hellos() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ffd_send_announce_request(ffd_iface_t *iface, ffd_neigh_t *neigh, void *announce) {
|
static bool add_node_id(ffd_packet_t *packet, size_t max_len, ffd_node_id_t node_id) {
|
||||||
|
ffd_tlv_node_id_t *tlv = ffd_tlv_add(packet, FFD_PACKET_MAX, TLV_NODE_ID, sizeof(ffd_tlv_node_id_t));
|
||||||
|
if (!tlv)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
tlv->id = node_id;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool add_update(ffd_packet_t *packet, size_t max_len, ffd_node_id_t *node_id, const ffd_announce_t *announce) {
|
||||||
|
uint16_t len = packet->len;
|
||||||
|
|
||||||
|
if (!node_id || !ffd_are_node_ids_equal(node_id, &announce->node)) {
|
||||||
|
if (!add_node_id(packet, max_len, announce->node))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (node_id)
|
||||||
|
*node_id = announce->node;
|
||||||
|
}
|
||||||
|
|
||||||
|
ffd_tlv_update_t *update = ffd_tlv_add(packet, FFD_PACKET_MAX, TLV_UPDATE, sizeof(ffd_tlv_update_t)+announce->len);
|
||||||
|
if (!update) {
|
||||||
|
packet->len = len;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ffd_metric_seqno_t metric = ffd_announce_get_metric(announce);
|
||||||
|
|
||||||
|
update->interval = htons(announce->interval);
|
||||||
|
update->seqno = htons(metric.seqno);
|
||||||
|
update->metric = htons(metric.metric);
|
||||||
|
update->type = htons(announce->type);
|
||||||
|
update->key = htons(announce->key);
|
||||||
|
|
||||||
|
memcpy(update->data, announce->data, announce->len);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ffd_send_update(ffd_iface_t *iface, ffd_neigh_t *neigh, const ffd_announce_t *announce) {
|
||||||
|
ffd_packet_t *packet = alloca(sizeof(ffd_packet_t)+FFD_PACKET_MAX);
|
||||||
|
|
||||||
|
packet->version_magic = htons(FFD_VERSION_MAGIC);
|
||||||
|
packet->len = 0;
|
||||||
|
|
||||||
|
if (announce) {
|
||||||
|
add_update(packet, FFD_PACKET_MAX, NULL, announce);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ffd_node_id_t node_id = FFD_NODE_ID_UNSPEC;
|
||||||
|
|
||||||
|
ffd_announce_t *a;
|
||||||
|
for (a = announce_list; a; a = a->next) {
|
||||||
|
if (!add_update(packet, FFD_PACKET_MAX, &node_id, a)) {
|
||||||
|
if (!send_eth(&ffd_addr, iface->ifindex, packet, sizeof(ffd_packet_t)+ntohs(packet->len)))
|
||||||
|
fprintf(stderr, "send_eth: %m\n");
|
||||||
|
|
||||||
|
node_id = FFD_NODE_ID_UNSPEC;
|
||||||
|
packet->len = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packet->len) {
|
||||||
|
if (!send_eth(&ffd_addr, iface->ifindex, packet, sizeof(ffd_packet_t)+ntohs(packet->len)))
|
||||||
|
fprintf(stderr, "send_eth: %m\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ffd_send_announce_request(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_node_id_t node, uint16_t type, uint16_t key) {
|
||||||
|
ffd_packet_t *packet = alloca(sizeof(ffd_packet_t)+FFD_PACKET_MAX);
|
||||||
|
|
||||||
|
packet->version_magic = htons(FFD_VERSION_MAGIC);
|
||||||
|
packet->len = 0;
|
||||||
|
|
||||||
|
ffd_tlv_announce_req_t *req = ffd_tlv_add(packet, FFD_PACKET_MAX, TLV_ANNOUNCE_REQ, sizeof(ffd_tlv_announce_req_t));
|
||||||
|
if (!req)
|
||||||
|
return;
|
||||||
|
|
||||||
|
req->node = node;
|
||||||
|
req->type = htons(type);
|
||||||
|
req->key = htons(key);
|
||||||
|
|
||||||
|
if (!send_eth(&ffd_addr, iface->ifindex, packet, sizeof(ffd_packet_t)+ntohs(packet->len)))
|
||||||
|
fprintf(stderr, "send_eth: %m\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,4 +44,30 @@ typedef struct __attribute__((packed)) _ffd_tlv_ihu_t {
|
||||||
uint8_t address[];
|
uint8_t address[];
|
||||||
} ffd_tlv_ihu_t;
|
} ffd_tlv_ihu_t;
|
||||||
|
|
||||||
|
typedef struct __attribute__((packed)) _ffd_tlv_node_id_t {
|
||||||
|
ffd_node_id_t id;
|
||||||
|
} ffd_tlv_node_id_t;
|
||||||
|
|
||||||
|
typedef struct __attribute__((packed)) _ffd_tlv_update_t {
|
||||||
|
uint16_t interval;
|
||||||
|
uint16_t seqno;
|
||||||
|
uint16_t metric;
|
||||||
|
uint16_t type;
|
||||||
|
uint16_t key;
|
||||||
|
uint8_t data[];
|
||||||
|
} ffd_tlv_update_t;
|
||||||
|
|
||||||
|
typedef struct __attribute__((packed)) _ffd_tlv_announce_req_t {
|
||||||
|
ffd_node_id_t node;
|
||||||
|
uint16_t type;
|
||||||
|
uint16_t key;
|
||||||
|
} ffd_tlv_announce_req_t;
|
||||||
|
|
||||||
|
typedef struct __attribute__((packed)) _ffd_tlv_seqno_req_t {
|
||||||
|
ffd_node_id_t node;
|
||||||
|
uint16_t type;
|
||||||
|
uint16_t key;
|
||||||
|
uint16_t seqno;
|
||||||
|
} ffd_tlv_seqno_req_t;
|
||||||
|
|
||||||
#endif /* _FFD_TLV_TYPES_H_ */
|
#endif /* _FFD_TLV_TYPES_H_ */
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
#include <net/ethernet.h>
|
#include <net/ethernet.h>
|
||||||
|
|
||||||
|
|
||||||
typedef struct __attribute__((__packed__)) _eth_addr_t {
|
typedef struct __attribute__((packed)) _eth_addr_t {
|
||||||
uint8_t d[ETH_ALEN];
|
uint8_t d[ETH_ALEN];
|
||||||
} eth_addr_t;
|
} eth_addr_t;
|
||||||
|
|
||||||
|
|
Reference in a new issue