Blame view

RIOT/sys/net/routing/nhdp/nhdp_writer.c 9.61 KB
a752c7ab   elopes   add first test an...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
  /*
   * Copyright (C) 2014 Freie Universitรคt Berlin
   *
   * This file is subject to the terms and conditions of the GNU Lesser
   * General Public License v2.1. See the file LICENSE in the top level
   * directory for more details.
   */
  
  /**
   * @ingroup     nhdp
   * @{
   *
   * @file
   * @brief       Writer implementation for message generation in NHDP
   *
   * @author      Fabian Nack <nack@inf.fu-berlin.de>
   *
   * @}
   */
  
  #include <string.h>
  
  #include "timex.h"
  #include "mutex.h"
  
  #include "rfc5444/rfc5444.h"
  #include "rfc5444/rfc5444_iana.h"
  #include "rfc5444/rfc5444_writer.h"
  
  #include "nhdp.h"
  #include "nhdp_address.h"
  #include "nhdp_writer.h"
  #include "lib_table.h"
  #include "nib_table.h"
  #include "iib_table.h"
  
  /* Internal variables */
  static mutex_t mtx_packet_write = MUTEX_INIT;
  static struct rfc5444_writer nhdp_writer;
  static nhdp_if_entry_t *nhdp_wr_curr_if_entry;
  static uint8_t msg_buffer[NHDP_WR_MSG_BUF_SIZE];
  static uint8_t msg_addrtlvs[NHDP_WR_TLV_BUF_SIZE];
  
  /* Internal function prototypes */
  static void _nhdp_add_hello_msg_header_cb(struct rfc5444_writer *wr,
          struct rfc5444_writer_message *msg);
  static void _nhdp_add_message_tlvs_cb(struct rfc5444_writer *wr);
  static void _nhdp_add_addresses_cb(struct rfc5444_writer *wr);
  static void _nhdp_add_packet_header_cb(struct rfc5444_writer *writer,
                                         struct rfc5444_writer_target *rfc5444_target);
  static void netaddr_from_nhdp_address(struct netaddr *target, nhdp_addr_t *n_addr);
  
  /* Array containing the known Address TLVs */
  static struct rfc5444_writer_tlvtype _nhdp_addrtlvs[] = {
      [RFC5444_ADDRTLV_LOCAL_IF] = { .type = RFC5444_ADDRTLV_LOCAL_IF },
      [RFC5444_ADDRTLV_LINK_STATUS] = { .type = RFC5444_ADDRTLV_LINK_STATUS },
      [RFC5444_ADDRTLV_OTHER_NEIGHB] = { .type = RFC5444_ADDRTLV_OTHER_NEIGHB },
      [RFC5444_ADDRTLV_LINK_METRIC] = { .type = RFC5444_ADDRTLV_LINK_METRIC, .exttype = NHDP_METRIC }
  };
  
  /* Writer content provider for HELLO messages */
  static struct rfc5444_writer_content_provider _nhdp_message_content_provider = {
      .msg_type = RFC5444_MSGTYPE_HELLO,
      .addMessageTLVs = _nhdp_add_message_tlvs_cb,
      .addAddresses = _nhdp_add_addresses_cb,
  };
  
  
  /*---------------------------------------------------------------------------*
   *                            NHDP Writer API                                *
   *---------------------------------------------------------------------------*/
  
  void nhdp_writer_init(void)
  {
      struct rfc5444_writer_message *_hello_msg;
  
      mutex_lock(&mtx_packet_write);
  
      /* Reset current interface */
      nhdp_wr_curr_if_entry = NULL;
  
      /* Configure NHDP writer */
      nhdp_writer.msg_buffer = msg_buffer;
      nhdp_writer.msg_size = sizeof(msg_buffer);
      nhdp_writer.addrtlv_buffer = msg_addrtlvs;
      nhdp_writer.addrtlv_size  = sizeof(msg_addrtlvs);
  
      /* Initialize writer */
      rfc5444_writer_init(&nhdp_writer);
  
      /* Register HELLO msg with 16 byte addresses and content provider */
      rfc5444_writer_register_msgcontentprovider(&nhdp_writer,
              &_nhdp_message_content_provider, _nhdp_addrtlvs, ARRAYSIZE(_nhdp_addrtlvs));
      _hello_msg = rfc5444_writer_register_message(&nhdp_writer, RFC5444_MSGTYPE_HELLO, false, 16);
      _hello_msg->addMessageHeader = _nhdp_add_hello_msg_header_cb;
  
      mutex_unlock(&mtx_packet_write);
  }
  
  void nhdp_writer_cleanup(void)
  {
      mutex_lock(&mtx_packet_write);
  
      nhdp_wr_curr_if_entry = NULL;
      rfc5444_writer_cleanup(&nhdp_writer);
  
      mutex_unlock(&mtx_packet_write);
  }
  
  void nhdp_writer_register_if(struct rfc5444_writer_target *new_if)
  {
      mutex_lock(&mtx_packet_write);
  
      /* Add packet header callback to writer target of the interface */
      new_if->addPacketHeader = _nhdp_add_packet_header_cb;
      /* Register target interface in writer */
      rfc5444_writer_register_target(&nhdp_writer, new_if);
  
      mutex_unlock(&mtx_packet_write);
  }
  
  void nhdp_writer_send_hello(nhdp_if_entry_t *if_entry)
  {
      mutex_lock(&mtx_packet_write);
  
      /* Register interface as current sending interface */
      nhdp_wr_curr_if_entry = if_entry;
  
      /* Create HELLO message and send it using the given interface */
      rfc5444_writer_create_message(&nhdp_writer, RFC5444_MSGTYPE_HELLO,
                                    rfc5444_writer_singletarget_selector, &if_entry->wr_target);
      rfc5444_writer_flush(&nhdp_writer, &if_entry->wr_target, false);
  
      mutex_unlock(&mtx_packet_write);
  }
  
  void nhdp_writer_add_addr(struct rfc5444_writer *wr, nhdp_addr_t *addr,
                            enum rfc5444_addrtlv_iana type, uint8_t value,
                            uint16_t metric_in, uint16_t metric_out)
  {
      struct rfc5444_writer_address *wr_addr;
      struct netaddr n_addr;
  
      netaddr_from_nhdp_address(&n_addr, addr);
  
      switch (type) {
          case RFC5444_ADDRTLV_LOCAL_IF:
              /* Address is mandatory for every sub-msg (if message is splitted) */
              wr_addr = rfc5444_writer_add_address(wr, _nhdp_message_content_provider.creator,
                                                   &n_addr, true);
              break;
  
          case RFC5444_ADDRTLV_LINK_STATUS:
              /* Fall through */
  
          case RFC5444_ADDRTLV_OTHER_NEIGHB:
              /* Address only has to be included in one sub-msg (if message is splitted) */
              wr_addr = rfc5444_writer_add_address(wr, _nhdp_message_content_provider.creator,
                                                   &n_addr, false);
              break;
  
          default:
              /* Unknown type, extend switch if other types are allowed */
              return;
      }
  
      rfc5444_writer_add_addrtlv(wr, wr_addr, &_nhdp_addrtlvs[type],
                                 &value, sizeof(uint8_t), false);
  
      /* Add LINK_METRIC TLV if necessary */
      if ((NHDP_METRIC == NHDP_LMT_DAT) && (metric_in != NHDP_METRIC_UNKNOWN)) {
          switch(type) {
              case RFC5444_ADDRTLV_LINK_STATUS:
                  metric_in |= NHDP_KD_LM_INC;
                  metric_in |= (metric_in == metric_out) ? NHDP_KD_LM_OUT : 0x00;
                  break;
              case RFC5444_ADDRTLV_OTHER_NEIGHB:
                  metric_in |= NHDP_KD_NM_INC;
                  metric_in |= (metric_in == metric_out) ? NHDP_KD_NM_OUT : 0x00;
                  break;
              default:
                  /* Other types are not used and therefore no address tlv is added */
                  return;
          }
          rfc5444_writer_add_addrtlv(wr, wr_addr, &_nhdp_addrtlvs[RFC5444_ADDRTLV_LINK_METRIC],
                                     &metric_in, sizeof(metric_in), true);
      }
  }
  
  
  /*------------------------------------------------------------------------------------*/
  /*                                Internal functions                                  */
  /*------------------------------------------------------------------------------------*/
  
  /**
   * Set the header for the currently constructed HELLO message
   * Called by oonf_api during message creation
   */
  static void
  _nhdp_add_hello_msg_header_cb(struct rfc5444_writer *wr, struct rfc5444_writer_message *msg)
  {
      /* No originator, no hopcount, no hoplimit, no sequence number */
      rfc5444_writer_set_msg_header(wr, msg, false, false, false, false);
  }
  
  /**
   * Add validity time and interval time message TLVs to current message
   * Called by oonf_api during message creation
   */
  static void _nhdp_add_message_tlvs_cb(struct rfc5444_writer *wr)
  {
      uint8_t validity_time, interval_time;
      /* Convert validity time and interval time to milliseconds */
      uint64_t val_tmp = (uint64_t) nhdp_wr_curr_if_entry->validity_time.seconds * MS_PER_SEC
                         + (nhdp_wr_curr_if_entry->validity_time.microseconds / 1000ULL);
      uint64_t int_tmp = (uint64_t) nhdp_wr_curr_if_entry->hello_interval.seconds * MS_PER_SEC
                         + (nhdp_wr_curr_if_entry->hello_interval.microseconds / 1000ULL);
  
      /* Add validity time (mandatory) and interval time to msg */
      validity_time = rfc5444_timetlv_encode(val_tmp);
      interval_time = rfc5444_timetlv_encode(int_tmp);
      rfc5444_writer_add_messagetlv(wr, RFC5444_MSGTLV_VALIDITY_TIME, 0, &validity_time,
                                    sizeof(validity_time));
      rfc5444_writer_add_messagetlv(wr, RFC5444_MSGTLV_INTERVAL_TIME, 0, &interval_time,
                                    sizeof(interval_time));
  }
  
  /**
   * Add addresses and corresponding TLVs to current message
   * Called by oonf_api during message creation
   */
  static void _nhdp_add_addresses_cb(struct rfc5444_writer *wr)
  {
      lib_fill_wr_addresses(nhdp_wr_curr_if_entry->if_pid, wr);
      iib_fill_wr_addresses(nhdp_wr_curr_if_entry->if_pid, wr);
      nib_fill_wr_addresses(wr);
      nhdp_reset_addresses_tmp_usg(0);
  }
  
  /**
   * Add packet header with sequence number to current packet
   * Called by oonf_api during packet creation
   */
  static void _nhdp_add_packet_header_cb(struct rfc5444_writer *writer,
                                         struct rfc5444_writer_target *rfc5444_target)
  {
      rfc5444_writer_set_pkt_header(writer, rfc5444_target, true);
      rfc5444_writer_set_pkt_seqno(writer, rfc5444_target, ++nhdp_wr_curr_if_entry->seq_no);
  }
  
  /**
   * Construct a netaddr from a given NHDP address
   */
  static void netaddr_from_nhdp_address(struct netaddr *target, nhdp_addr_t *n_addr)
  {
      memset(target->_addr, 0, NETADDR_MAX_LENGTH);
      memcpy(target->_addr, n_addr->addr, n_addr->addr_size);
  
      switch (n_addr->addr_type) {
          case AF_CC110X:
              target->_prefix_len = 8u;
              target->_type = AF_CC110X;
              break;
  
          case AF_INET:
              target->_prefix_len = 32u;
              target->_type = AF_INET;
              break;
  
          case AF_INET6:
              /* Fall-through */
  
          default:
              target->_prefix_len = 128u;
              target->_type = AF_INET6;
              break;
      }
  }