PUD: nmeaTools functions are now part of nmealib
[olsrd.git] / lib / pud / src / nodeIdConversion.c
1 #include "nodeIdConversion.h"
2
3 /* Plugin includes */
4 #include "pud.h"
5 #include "configuration.h"
6 #include "networkInterfaces.h"
7
8 /* OLSR includes */
9
10 /* System includes */
11 #include <assert.h>
12 #include <arpa/inet.h>
13 #include <nmea/util.h>
14 #include <net/if.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 static unsigned char cachedNodeIdBuffer[PUD_CACHED_NODEID_BUFFER_SIZE];
28
29 /** The number of bytes stored in cachedNodeIdBuffer */
30 static 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 (!getNodeIdAsNumber(&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                 {
100                         bool invalidChars;
101                         char report[256];
102
103                         invalidChars = nmea_string_has_invalid_chars((char *) getNodeId(),
104                                         PUD_NODE_ID_NAME, &report[0], sizeof(report));
105                         if (invalidChars) {
106                                 pudError(false, &report[0]);
107                         }
108                         return !invalidChars;
109                 }
110
111                 case PUD_NODEIDTYPE_192:
112                         return setupNodeIdNumberForOlsr(0LL, 9999999LL, 3);
113
114                 case PUD_NODEIDTYPE_193:
115                         return setupNodeIdNumberForOlsr(0LL, 999999LL, 3);
116
117                 case PUD_NODEIDTYPE_194:
118                         return setupNodeIdNumberForOlsr(1LL, 8191LL, 2);
119
120                 default: /* unsupported */
121                         /* explicit return: configured nodeId is not relevant, will
122                          * fallback to IP addresses */
123                         return true;
124         }
125
126         return false;
127 }
128
129 /**
130  Convert the node information to the node information for an OLSR message and
131  put it in the PUD message in the OLSR message. Also updates the PUD message
132  smask.
133
134  @param olsrGpsMessage
135  A pointer to the PUD message in the OLSR message
136  @param olsrMessageSize
137  The maximum number of bytes available for the olsrMessage
138
139  @return
140  The number of bytes written in the PUD message in the OLSR message (for ALL
141  the node information)
142  */
143 size_t setupNodeInfoForOlsr(PudOlsrWireFormat * olsrGpsMessage,
144                 unsigned int olsrMessageSize) {
145         NodeIdType nodeIdTypeNumber = getNodeIdTypeNumber();
146         size_t length = 0;
147
148         olsrGpsMessage->nodeInfo.nodeIdType = nodeIdTypeNumber;
149         switch (nodeIdTypeNumber) {
150                 case PUD_NODEIDTYPE_MAC: /* hardware address */
151                         /* handled when the message is actually sent into OLSR, in the
152                          * pre-transmit hook */
153                         length = IFHWADDRLEN;
154                         break;
155
156                 case PUD_NODEIDTYPE_MSISDN: /* an MSISDN number */
157                 case PUD_NODEIDTYPE_TETRA: /* a Tetra number */
158                 case PUD_NODEIDTYPE_192:
159                 case PUD_NODEIDTYPE_193:
160                 case PUD_NODEIDTYPE_194:
161                         length = cachedNodeIdBufferLength;
162                         memcpy(&olsrGpsMessage->nodeInfo.nodeId, &cachedNodeIdBuffer[0],
163                                         length);
164                         break;
165
166                 case PUD_NODEIDTYPE_DNS: /* DNS name */
167                 {
168                         size_t nodeIdLength;
169                         unsigned char * nodeId = getNodeIdWithLength(&nodeIdLength);
170                         long charsAvailable = olsrMessageSize - (PUD_OLSRWIREFORMATSIZE
171                                         + sizeof(NodeInfo)
172                                         - sizeof(olsrGpsMessage->nodeInfo.nodeId)) - 1;
173
174                         length = nodeIdLength + 1;
175                         if (unlikely((long) length > charsAvailable)) {
176                                 length = charsAvailable;
177                                 pudError(false,
178                                                 "nodeId too long, truncated after %ld characters",
179                                                 charsAvailable);
180                         }
181
182                         memcpy(&olsrGpsMessage->nodeInfo.nodeId, nodeId, length);
183                         (&olsrGpsMessage->nodeInfo.nodeId)[length] = '\0';
184                 }
185                         break;
186
187                 case PUD_NODEIDTYPE_IPV4: /* IPv4 address */
188                 case PUD_NODEIDTYPE_IPV6: /* IPv6 address */
189                         /* explicit return: no nodeId information in message */
190                         return 0;
191
192                 default: /* unsupported */
193                         pudError(false, "Configuration of unsupported %s %u, using %u",
194                                         PUD_NODE_ID_TYPE_NAME, nodeIdTypeNumber,
195                                         ((olsr_cnf->ip_version == AF_INET) ? PUD_NODEIDTYPE_IPV4
196                                                         : PUD_NODEIDTYPE_IPV6));
197
198                         /* fallback to IP address */
199                         olsrGpsMessage->nodeInfo.nodeIdType = (olsr_cnf->ip_version
200                                         == AF_INET) ? PUD_NODEIDTYPE_IPV4 : PUD_NODEIDTYPE_IPV6;
201
202                         /* explicit return: no nodeId information in message */
203                         return 0;
204         }
205
206         olsrGpsMessage->smask |= PUD_FLAGS_ID;
207         return ((sizeof(NodeInfo)
208                         - (sizeof(olsrGpsMessage->nodeInfo.nodeId) /* nodeId placeholder */))
209                         + length);
210 }
211
212 /**
213  Get a nodeId number (in string representation), using a certain number of
214  bytes, from the message of an OLSR message.
215
216  @param olsrGpsMessage
217  A pointer to the OLSR message
218  @param bytes
219  The number of bytes used by the number
220  @param nodeIdBuffer
221  The buffer in which to place the nodeId number in string representation
222  @param nodeIdBufferSize
223  The size of the buffer
224
225  @return
226  A pointer to the nodeId string representation (&nodeIdBuffer[0])
227  */
228 static char *getNodeIdNumberFromOlsr(PudOlsrWireFormat * olsrGpsMessage,
229                 unsigned int bytes, char *nodeIdBuffer, socklen_t nodeIdBufferSize) {
230         unsigned char * nodeId = &(olsrGpsMessage->nodeInfo.nodeId);
231         unsigned long long val = 0;
232         unsigned int i = 0;
233         int chars;
234
235         while (i < bytes) {
236                 val <<= 8;
237                 val += nodeId[i];
238                 i++;
239         }
240
241         chars = snprintf(nodeIdBuffer, nodeIdBufferSize, "%llu", val);
242         if (likely(chars < (int) nodeIdBufferSize)) {
243                 nodeIdBuffer[chars] = '\0';
244         } else {
245                 nodeIdBuffer[nodeIdBufferSize] = '\0';
246         }
247         return &nodeIdBuffer[0];
248 }
249
250 /**
251  Convert the node information of an OLSR message to the node information for
252  internal use and set it up in the given buffers.
253
254  @param olsrMessage
255  A pointer to the OLSR message. Used to be able to retrieve the IP address of
256  the sender.
257  @param olsrGpsMessage
258  A pointer to the GPS message in the OLSR message
259  @param nodeId
260  A pointer a variable in which to store the pointer to the buffer in which the
261  nodeId string representation can be found
262  @param nodeIdBuffer
263  A pointer to the buffer in which the nodeId string representation can be
264  written
265  @param nodeIdBufferSize
266  The size of the nodeIdBuffer
267  @param nodeIdTypeString
268  A pointer to the buffer in which the nodeIdType string representation can be
269  written
270  */
271 void getNodeInfoFromOlsr(const union olsr_message *olsrMessage,
272                 PudOlsrWireFormat *olsrGpsMessage, char *nodeIdBuffer,
273                 unsigned int nodeIdBufferSize, const char **nodeId,
274                 char *nodeIdTypeString) {
275         int chars;
276
277         if (olsrGpsMessage->smask & PUD_FLAGS_ID) {
278                 switch (olsrGpsMessage->nodeInfo.nodeIdType) {
279                         case PUD_NODEIDTYPE_MAC: /* hardware address */
280                         {
281                                 unsigned char * hwAddr = &olsrGpsMessage->nodeInfo.nodeId;
282
283                                 assert (IFHWADDRLEN == 6);
284
285                                 chars = snprintf(nodeIdBuffer, nodeIdBufferSize,
286                                                 "%02x:%02x:%02x:%02x:%02x:%02x", hwAddr[0], hwAddr[1],
287                                                 hwAddr[2], hwAddr[3], hwAddr[4], hwAddr[5]);
288                                 if (likely(chars < (int) nodeIdBufferSize)) {
289                                         nodeIdBuffer[chars] = '\0';
290                                 } else {
291                                         nodeIdBuffer[nodeIdBufferSize - 1] = '\0';
292                                 }
293                                 *nodeId = &nodeIdBuffer[0];
294                         }
295                                 break;
296
297                         case PUD_NODEIDTYPE_MSISDN: /* an MSISDN number */
298                                 *nodeId = getNodeIdNumberFromOlsr(olsrGpsMessage, 7,
299                                                 nodeIdBuffer, nodeIdBufferSize);
300                                 break;
301
302                         case PUD_NODEIDTYPE_TETRA: /* a Tetra number */
303                                 *nodeId = getNodeIdNumberFromOlsr(olsrGpsMessage, 8,
304                                                 nodeIdBuffer, nodeIdBufferSize);
305                                 break;
306
307                         case PUD_NODEIDTYPE_DNS: /* DNS name */
308                                 *nodeId = (char *) &olsrGpsMessage->nodeInfo.nodeId;
309                                 break;
310
311                         case PUD_NODEIDTYPE_192:
312                         case PUD_NODEIDTYPE_193:
313                                 *nodeId = getNodeIdNumberFromOlsr(olsrGpsMessage, 3,
314                                                 nodeIdBuffer, nodeIdBufferSize);
315                                 break;
316
317                         case PUD_NODEIDTYPE_194:
318                                 *nodeId = getNodeIdNumberFromOlsr(olsrGpsMessage, 2,
319                                                 nodeIdBuffer, nodeIdBufferSize);
320                                 break;
321
322                         case PUD_NODEIDTYPE_IPV4: /* IPv4 address */
323                         case PUD_NODEIDTYPE_IPV6: /* IPv6 address */
324                                 goto noId;
325
326                         default: /* unsupported */
327                                 pudError(false,
328                                                 "Reception of unsupported %s %u, using %u",
329                                                 PUD_NODE_ID_TYPE_NAME,
330                                                 olsrGpsMessage->nodeInfo.nodeIdType,
331                                                 ((olsr_cnf->ip_version == AF_INET) ? PUD_NODEIDTYPE_IPV4
332                                                                 : PUD_NODEIDTYPE_IPV6));
333                                 olsrGpsMessage->smask &= ~PUD_FLAGS_ID;
334                                 goto noId;
335                 }
336
337                 /* nodeIdType */
338                 chars = snprintf(nodeIdTypeString, PUD_TX_NODEIDTYPE_DIGITS + 1, "%u",
339                                 olsrGpsMessage->nodeInfo.nodeIdType);
340                 if (likely(chars < PUD_TX_NODEIDTYPE_DIGITS)) {
341                         nodeIdTypeString[chars] = '\0';
342                 } else {
343                         nodeIdTypeString[PUD_TX_NODEIDTYPE_DIGITS] = '\0';
344                 }
345
346                 return;
347         }
348
349         /* message has NO nodeId information */
350         noId: {
351                 const void * addr;
352
353                 /* nodeIdType */
354                 chars = snprintf(&nodeIdTypeString[0], PUD_TX_NODEIDTYPE_DIGITS + 1,
355                                 "%u", ((olsr_cnf->ip_version == AF_INET) ? PUD_NODEIDTYPE_IPV4
356                                 : PUD_NODEIDTYPE_IPV6));
357                 if (likely(chars < PUD_TX_NODEIDTYPE_DIGITS)) {
358                         nodeIdTypeString[chars] = '\0';
359                 } else {
360                         nodeIdTypeString[PUD_TX_NODEIDTYPE_DIGITS] = '\0';
361                 }
362
363                 if (olsr_cnf->ip_version == AF_INET) {
364                         addr = (const void *) &olsrMessage->v4.originator;
365                 } else {
366                         addr = (const void *) &olsrMessage->v6.originator;
367                 }
368
369                 *nodeId = inet_ntop(olsr_cnf->ip_version, addr, nodeIdBuffer,
370                                 nodeIdBufferSize);
371         }
372
373         return;
374 }