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