PUD: add plugin
[olsrd.git] / lib / pud / src / nodeIdConversion.c
1 #include "nodeIdConversion.h"
2
3 /* Plugin includes */
4 #include "pud.h"
5 #include "nmeaTools.h"
6 #include "configuration.h"
7 #include "networkInterfaces.h"
8
9 /* OLSR includes */
10
11 /* System includes */
12 #include <assert.h>
13 #include <string.h>
14 #include <arpa/inet.h>
15
16 /* ************************************************************************
17  * Node Information
18  * ************************************************************************ */
19
20 /** The size of the cached nodeId buffer */
21 #define PUD_CACHED_NODEID_BUFFER_SIZE 16
22
23 /** The cached nodeId buffer: contains a pre-processed version of the nodeId
24  in order to improve performance. It is currently used for nodeIdTypes
25  PUD_NODEIDTYPE_MSISDN, PUD_NODEIDTYPE_TETRA, PUD_NODEIDTYPE_192,
26  PUD_NODEIDTYPE_193 (so basically for numbers that will not change) */
27 unsigned char cachedNodeIdBuffer[PUD_CACHED_NODEID_BUFFER_SIZE];
28
29 /** The number of bytes stored in cachedNodeIdBuffer */
30 unsigned char cachedNodeIdBufferLength = 0;
31
32 /**
33  Check a nodeId number for validity and if valid set it up in the
34  cachedNodeIdBuffer. The valid range for the number is [min, max].
35
36  @param min
37  The lower bound for a valid number
38  @param max
39  The upper bound for a valid number
40  @param bytes
41  The number of bytes used by the number in the wire format
42
43  @return
44  - true when the number is valid
45  - false otherwise
46  */
47 static bool setupNodeIdNumberForOlsr(unsigned long long min,
48                 unsigned long long max, unsigned int bytes) {
49         unsigned long long val;
50
51         assert (bytes <= PUD_CACHED_NODEID_BUFFER_SIZE);
52
53         if (!readULL(PUD_NODE_ID_NAME, (char *) getNodeId(), &val)) {
54                 return false;
55         }
56
57         if ((val >= min) && (val <= max)) {
58                 int i = bytes - 1;
59                 while (i >= 0) {
60                         cachedNodeIdBuffer[i] = val & 0xff;
61                         val >>= 8;
62                         i--;
63                 }
64
65                 assert(val == 0);
66
67                 cachedNodeIdBufferLength = bytes;
68                 return true;
69         }
70
71         pudError(false, "%s value %llu is out of range [%llu,%llu]",
72                         PUD_NODE_ID_NAME, val, min, max);
73         return false;
74 }
75
76 /**
77  Validate whether the configured nodeId is valid w.r.t. the configured
78  nodeIdType
79
80  @return
81  - true when ok
82  - false on failure
83  */
84 bool validateNodeId(NodeIdType nodeIdTypeNumber) {
85         switch (nodeIdTypeNumber) {
86                 case PUD_NODEIDTYPE_IPV4: /* IPv4 address */
87                 case PUD_NODEIDTYPE_IPV6: /* IPv6 address */
88                 case PUD_NODEIDTYPE_MAC: /* hardware address */
89                         /* explicit return: configured nodeId is not relevant */
90                         return true;
91
92                 case PUD_NODEIDTYPE_MSISDN: /* an MSISDN number */
93                         return setupNodeIdNumberForOlsr(0LL, 999999999999999LL, 7);
94
95                 case PUD_NODEIDTYPE_TETRA: /* a Tetra number */
96                         return setupNodeIdNumberForOlsr(0LL, 99999999999999999LL, 8);
97
98                 case PUD_NODEIDTYPE_DNS: /* DNS name */
99                         return !hasInvalidNmeaChars((char *) getNodeId(), PUD_NODE_ID_NAME);
100
101                 case PUD_NODEIDTYPE_192:
102                         return setupNodeIdNumberForOlsr(0LL, 9999999LL, 3);
103
104                 case PUD_NODEIDTYPE_193:
105                         return setupNodeIdNumberForOlsr(0LL, 999999LL, 3);
106
107                 case PUD_NODEIDTYPE_194:
108                         return setupNodeIdNumberForOlsr(1LL, 8191LL, 2);
109
110                 default: /* unsupported */
111                         /* explicit return: configured nodeId is not relevant, will
112                          * fallback to IP addresses */
113                         return true;
114         }
115
116         return false;
117 }
118
119 /**
120  Convert the node information to the node information for an OLSR message and
121  put it in the PUD message in the OLSR message. Also updates the PUD message
122  smask.
123
124  @param olsrGpsMessage
125  A pointer to the PUD message in the OLSR message
126  @param olsrMessageSize
127  The maximum number of bytes available for the olsrMessage
128
129  @return
130  The number of bytes written in the PUD message in the OLSR message (for ALL
131  the node information)
132  */
133 size_t setupNodeInfoForOlsr(PudOlsrWireFormat * olsrGpsMessage,
134                 unsigned int olsrMessageSize) {
135         NodeIdType nodeIdTypeNumber = getNodeIdTypeNumber();
136         size_t length = 0;
137
138         olsrGpsMessage->nodeInfo.nodeIdType = nodeIdTypeNumber;
139         switch (nodeIdTypeNumber) {
140                 case PUD_NODEIDTYPE_MAC: /* hardware address */
141                         /* handled when the message is actually sent into OLSR, in the
142                          * pre-transmit hook */
143                         length = PUD_HWADDR_SIZE;
144                         break;
145
146                 case PUD_NODEIDTYPE_MSISDN: /* an MSISDN number */
147                 case PUD_NODEIDTYPE_TETRA: /* a Tetra number */
148                 case PUD_NODEIDTYPE_192:
149                 case PUD_NODEIDTYPE_193:
150                 case PUD_NODEIDTYPE_194:
151                         length = cachedNodeIdBufferLength;
152                         memcpy(&olsrGpsMessage->nodeInfo.nodeId, &cachedNodeIdBuffer[0],
153                                         length);
154                         break;
155
156                 case PUD_NODEIDTYPE_DNS: /* DNS name */
157                 {
158                         size_t nodeIdLength;
159                         unsigned char * nodeId = getNodeIdWithLength(&nodeIdLength);
160                         long charsAvailable = olsrMessageSize - (PUD_OLSRWIREFORMATSIZE
161                                         + sizeof(NodeInfo)
162                                         - sizeof(olsrGpsMessage->nodeInfo.nodeId)) - 1;
163
164                         length = nodeIdLength + 1;
165                         if (unlikely((long) length > charsAvailable)) {
166                                 length = charsAvailable;
167                                 pudError(false,
168                                                 "nodeId too long, truncated after %ld characters",
169                                                 charsAvailable);
170                         }
171
172                         memcpy(&olsrGpsMessage->nodeInfo.nodeId, nodeId, length);
173                         (&olsrGpsMessage->nodeInfo.nodeId)[length] = '\0';
174                 }
175                         break;
176
177                 case PUD_NODEIDTYPE_IPV4: /* IPv4 address */
178                 case PUD_NODEIDTYPE_IPV6: /* IPv6 address */
179                         /* explicit return: no nodeId information in message */
180                         return 0;
181
182                 default: /* unsupported */
183                         pudError(false, "Configuration of unsupported %s %u, using %u",
184                                         PUD_NODE_ID_TYPE_NAME, nodeIdTypeNumber,
185                                         ((olsr_cnf->ip_version == AF_INET) ? PUD_NODEIDTYPE_IPV4
186                                                         : PUD_NODEIDTYPE_IPV6));
187
188                         /* fallback to IP address */
189                         olsrGpsMessage->nodeInfo.nodeIdType = (olsr_cnf->ip_version
190                                         == AF_INET) ? PUD_NODEIDTYPE_IPV4 : PUD_NODEIDTYPE_IPV6;
191
192                         /* explicit return: no nodeId information in message */
193                         return 0;
194         }
195
196         olsrGpsMessage->smask |= PUD_FLAGS_ID;
197         return ((sizeof(NodeInfo)
198                         - (sizeof(olsrGpsMessage->nodeInfo.nodeId) /* nodeId placeholder */))
199                         + length);
200 }
201
202 /**
203  This function is called every time before a message is sent on a specific
204  interface. It can manipulate the outgoing message.
205  Note that a change to the outgoing messages is carried over to the message
206  that goes out on the next interface when the message is _not_ reset
207  before it is sent out on the next interface.
208
209  @param olsrMessage
210  A pointer to the outgoing message
211  @param ifn
212  A pointer to the OLSR interface structure
213  */
214 void nodeIdPreTransmitHook(union olsr_message *olsrMessage,
215                 struct interface *ifn) {
216         /* set the MAC address in the message when needed */
217         if (unlikely(getNodeIdTypeNumber() == PUD_NODEIDTYPE_MAC)) {
218                 PudOlsrWireFormat * olsrGpsMessage;
219                 TOLSRNetworkInterface * olsrIf = getOlsrNetworkInterface(ifn);
220
221                 if (olsr_cnf->ip_version == AF_INET) {
222                         olsrGpsMessage = (PudOlsrWireFormat *) &olsrMessage->v4.message;
223                 } else {
224                         olsrGpsMessage = (PudOlsrWireFormat *) &olsrMessage->v6.message;
225                 }
226
227                 if (likely(olsrIf != NULL)) {
228                         memcpy(&olsrGpsMessage->nodeInfo.nodeId, &olsrIf->hwAddress[0],
229                                         sizeof(PUD_HWADDR_SIZE));
230                 } else {
231                         pudError(false, "Could not find OLSR interface %s, cleared its"
232                                 " MAC address in the OLSR message\n", ifn->int_name);
233                         memset(&olsrGpsMessage->nodeInfo.nodeId, 0, sizeof(PUD_HWADDR_SIZE));
234                 }
235         }
236 }
237
238 /**
239  Get a nodeId number (in string representation), using a certain number of
240  bytes, from the message of an OLSR message.
241
242  @param olsrGpsMessage
243  A pointer to the OLSR message
244  @param bytes
245  The number of bytes used by the number
246  @param nodeIdBuffer
247  The buffer in which to place the nodeId number in string representation
248  @param nodeIdBufferSize
249  The size of the buffer
250
251  @return
252  A pointer to the nodeId string representation (&nodeIdBuffer[0])
253  */
254 static char *getNodeIdNumberFromOlsr(PudOlsrWireFormat * olsrGpsMessage,
255                 unsigned int bytes, char *nodeIdBuffer, socklen_t nodeIdBufferSize) {
256         unsigned char * nodeId = &(olsrGpsMessage->nodeInfo.nodeId);
257         unsigned long long val = 0;
258         unsigned int i = 0;
259         int chars;
260
261         while (i < bytes) {
262                 val <<= 8;
263                 val += nodeId[i];
264                 i++;
265         }
266
267         chars = snprintf(nodeIdBuffer, nodeIdBufferSize, "%llu", val);
268         if (likely(chars < (int) nodeIdBufferSize)) {
269                 nodeIdBuffer[chars] = '\0';
270         } else {
271                 nodeIdBuffer[nodeIdBufferSize] = '\0';
272         }
273         return &nodeIdBuffer[0];
274 }
275
276 /**
277  Convert the node information of an OLSR message to the node information for
278  internal use and set it up in the given buffers.
279
280  @param olsrMessage
281  A pointer to the OLSR message. Used to be able to retrieve the IP address of
282  the sender.
283  @param olsrGpsMessage
284  A pointer to the GPS message in the OLSR message
285  @param nodeId
286  A pointer a variable in which to store the pointer to the buffer in which the
287  nodeId string representation can be found
288  @param nodeIdBuffer
289  A pointer to the buffer in which the nodeId string representation can be
290  written
291  @param nodeIdBufferSize
292  The size of the nodeIdBuffer
293  @param nodeIdTypeString
294  A pointer to the buffer in which the nodeIdType string representation can be
295  written
296  */
297 void getNodeInfoFromOlsr(const union olsr_message *olsrMessage,
298                 PudOlsrWireFormat *olsrGpsMessage, char *nodeIdBuffer,
299                 unsigned int nodeIdBufferSize, const char **nodeId,
300                 char *nodeIdTypeString) {
301         int chars;
302
303         if (olsrGpsMessage->smask & PUD_FLAGS_ID) {
304                 switch (olsrGpsMessage->nodeInfo.nodeIdType) {
305                         case PUD_NODEIDTYPE_MAC: /* hardware address */
306                         {
307                                 unsigned char * hwAddr = &olsrGpsMessage->nodeInfo.nodeId;
308
309                                 assert (PUD_HWADDR_SIZE == 6);
310
311                                 chars = snprintf(nodeIdBuffer, nodeIdBufferSize,
312                                                 "%02x:%02x:%02x:%02x:%02x:%02x", hwAddr[0], hwAddr[1],
313                                                 hwAddr[2], hwAddr[3], hwAddr[4], hwAddr[5]);
314                                 if (likely(chars < (int) nodeIdBufferSize)) {
315                                         nodeIdBuffer[chars] = '\0';
316                                 } else {
317                                         nodeIdBuffer[nodeIdBufferSize - 1] = '\0';
318                                 }
319                                 *nodeId = &nodeIdBuffer[0];
320                         }
321                                 break;
322
323                         case PUD_NODEIDTYPE_MSISDN: /* an MSISDN number */
324                                 *nodeId = getNodeIdNumberFromOlsr(olsrGpsMessage, 7,
325                                                 nodeIdBuffer, nodeIdBufferSize);
326                                 break;
327
328                         case PUD_NODEIDTYPE_TETRA: /* a Tetra number */
329                                 *nodeId = getNodeIdNumberFromOlsr(olsrGpsMessage, 8,
330                                                 nodeIdBuffer, nodeIdBufferSize);
331                                 break;
332
333                         case PUD_NODEIDTYPE_DNS: /* DNS name */
334                                 *nodeId = (char *) &olsrGpsMessage->nodeInfo.nodeId;
335                                 break;
336
337                         case PUD_NODEIDTYPE_192:
338                         case PUD_NODEIDTYPE_193:
339                                 *nodeId = getNodeIdNumberFromOlsr(olsrGpsMessage, 3,
340                                                 nodeIdBuffer, nodeIdBufferSize);
341                                 break;
342
343                         case PUD_NODEIDTYPE_194:
344                                 *nodeId = getNodeIdNumberFromOlsr(olsrGpsMessage, 2,
345                                                 nodeIdBuffer, nodeIdBufferSize);
346                                 break;
347
348                         case PUD_NODEIDTYPE_IPV4: /* IPv4 address */
349                         case PUD_NODEIDTYPE_IPV6: /* IPv6 address */
350                                 goto noId;
351
352                         default: /* unsupported */
353                                 pudError(false,
354                                                 "Reception of unsupported %s %u, using %u",
355                                                 PUD_NODE_ID_TYPE_NAME,
356                                                 olsrGpsMessage->nodeInfo.nodeIdType,
357                                                 ((olsr_cnf->ip_version == AF_INET) ? PUD_NODEIDTYPE_IPV4
358                                                                 : PUD_NODEIDTYPE_IPV6));
359                                 olsrGpsMessage->smask &= ~PUD_FLAGS_ID;
360                                 goto noId;
361                 }
362
363                 /* nodeIdType */
364                 chars = snprintf(nodeIdTypeString, PUD_TX_NODEIDTYPE_DIGITS + 1, "%u",
365                                 olsrGpsMessage->nodeInfo.nodeIdType);
366                 if (likely(chars < PUD_TX_NODEIDTYPE_DIGITS)) {
367                         nodeIdTypeString[chars] = '\0';
368                 } else {
369                         nodeIdTypeString[PUD_TX_NODEIDTYPE_DIGITS] = '\0';
370                 }
371
372                 return;
373         }
374
375         /* message has NO nodeId information */
376         noId: {
377                 const void * addr;
378
379                 /* nodeIdType */
380                 chars = snprintf(&nodeIdTypeString[0], PUD_TX_NODEIDTYPE_DIGITS + 1,
381                                 "%u", olsrGpsMessage->nodeInfo.nodeIdType);
382                 if (likely(chars < PUD_TX_NODEIDTYPE_DIGITS)) {
383                         nodeIdTypeString[chars] = '\0';
384                 } else {
385                         nodeIdTypeString[PUD_TX_NODEIDTYPE_DIGITS] = '\0';
386                 }
387
388                 if (olsr_cnf->ip_version == AF_INET) {
389                         addr = (const void *) &olsrMessage->v4.originator;
390                 } else {
391                         addr = (const void *) &olsrMessage->v6.originator;
392                 }
393
394                 *nodeId = inet_ntop(olsr_cnf->ip_version, addr, nodeIdBuffer,
395                                 nodeIdBufferSize);
396         }
397
398         return;
399 }