PUD: add URN nodeIdType
[olsrd.git] / lib / pud / wireformat / src / wireFormat.c
1 #include <OlsrdPudWireFormat/wireFormat.h>
2 #include <OlsrdPudWireFormat/compiler.h>
3
4 /* ************************************************************************
5  * VALIDITY TIME CACHE
6  * ************************************************************************ */
7
8 static unsigned long long cachedValidityTimeMsn[16];
9
10 static bool cachedValidityTimeMsnValid = false;
11
12 /**
13  Setup of cache of calculated most significant nibble results of the validity
14  time calculation to speed up run-time calculations. This method has to be
15  called once upon first use of ValidityTime functions.
16  */
17 static void setupCachedValidityTimeMsn(void) {
18         unsigned int msn;
19         for (msn = 0; msn < 16; msn++) {
20                 cachedValidityTimeMsn[msn] = PUD_VALIDITY_TIME_FROM_OLSR(msn, 0);
21         }
22         cachedValidityTimeMsnValid = true;
23 }
24
25 /* ************************************************************************
26  * NODEID CACHE
27  * ************************************************************************ */
28
29 /** The size of the cached nodeId buffer */
30 #define PUD_CACHED_NODEID_BUFFER_SIZE 16
31
32 /** The cached nodeId buffer: contains a pre-processed version of the nodeId
33  in order to improve performance. It is currently used for nodeIdTypes
34  PUD_NODEIDTYPE_MSISDN, PUD_NODEIDTYPE_TETRA, PUD_NODEIDTYPE_MMSI,
35  PUD_NODEIDTYPE_URN, PUD_NODEIDTYPE_192, PUD_NODEIDTYPE_193
36  (so basically for numbers that will not change) */
37 static unsigned char cachedNodeIdBuffer[PUD_CACHED_NODEID_BUFFER_SIZE];
38
39 /** The number of bytes stored in cachedNodeIdBuffer */
40 static unsigned int cachedNodeIdBufferLength = 0;
41
42 /**
43  @param nodeId
44  A pointer to the location in which to store a pointer to the nodeId cache
45  buffer
46  @param nodeIdSize
47  A pointer to the location in which to store the number of bytes in the buffer
48  */
49 static inline void getNodeIdNumberForOlsrCache(unsigned char ** nodeId,
50                 unsigned int * nodeIdSize) {
51         *nodeId = &cachedNodeIdBuffer[0];
52         *nodeIdSize = cachedNodeIdBufferLength;
53 }
54
55 /**
56  Check a nodeId number for validity and if valid set it up in the
57  cachedNodeIdBuffer. The valid range for the number is [min, max].
58
59  @param val
60  The value to setup in the cache
61  @param min
62  The lower bound for a valid number
63  @param max
64  The upper bound for a valid number
65  @param bytes
66  The number of bytes used by the number in the wire format
67
68  @return
69  - true when the number is valid
70  - false otherwise
71  */
72 bool setupNodeIdNumberForOlsrCache(unsigned long long val,
73                 unsigned long long min, unsigned long long max, unsigned int bytes) {
74         assert(bytes <= PUD_CACHED_NODEID_BUFFER_SIZE);
75
76         if ((val >= min) && (val <= max)) {
77                 int i = bytes - 1;
78                 while (i >= 0) {
79                         cachedNodeIdBuffer[i] = val & 0xff;
80                         val >>= 8;
81                         i--;
82                 }
83
84                 assert(val == 0);
85
86                 cachedNodeIdBufferLength = bytes;
87                 return true;
88         }
89
90         return false;
91 }
92
93 /* ************************************************************************
94  * Validity Time
95  * ************************************************************************ */
96
97 /* inline getValidityTime */
98
99 /**
100  Set the validity time of the position update message
101
102  @param validityTimeField
103  A pointer to the validity time field
104  @param validityTime
105  The validity time in seconds
106  */
107 void setValidityTime(uint8_t * validityTimeField,
108                 unsigned long long validityTime) {
109         unsigned int msn = 1;
110         unsigned long long lsn = 0;
111         unsigned long long upperBound;
112
113         if (!cachedValidityTimeMsnValid) {
114                 setupCachedValidityTimeMsn();
115         }
116         upperBound = cachedValidityTimeMsn[msn];
117         while ((msn < 16) && (validityTime >= upperBound)) {
118                 msn++;
119                 upperBound = cachedValidityTimeMsn[msn];
120         }
121         msn--;
122
123         if (unlikely(validityTime >= upperBound)) {
124                 lsn = 15;
125         } else {
126                 unsigned long lowerBound = PUD_VALIDITY_TIME_FROM_OLSR(msn, 0);
127                 unsigned long resolution = (1 << msn);
128                 lsn = ((validityTime - lowerBound + (resolution >> 1)) / resolution);
129         }
130
131         assert(msn <= 15);
132         assert(lsn <= 15);
133
134         *validityTimeField = ((msn << 4) | lsn);
135 }
136
137 /* ************************************************************************
138  * UplinkPositionUpdate
139  * ************************************************************************ */
140
141 /* inline uint8_t getUplinkMessageType */
142 /* inline void setUplinkMessageType */
143
144 /* inline uint16_t getUplinkMessageLength */
145 /* inline void setUplinkMessageLength */
146
147 /* inline bool getUplinkMessageIPv6 */
148 /* inline void setUplinkMessageIPv6 */
149
150 /* inline void setUplinkMessagePadding */
151
152 /* ************************************************************************
153  * OLSR Header
154  * ************************************************************************ */
155
156 /* inline union olsr_ip_addr * getOlsrMessageOriginator */
157
158 /* inline PudOlsrPositionUpdate * getOlsrMessagePayload */
159
160 /* ************************************************************************
161  * PudOlsrPositionUpdate
162  * ************************************************************************ */
163
164 /* inline uint8_t getPositionUpdateVersion */
165 /* inline void setPositionUpdateVersion */
166
167 /* inline uint8_t getPositionUpdateSmask */
168 /* inline void setPositionUpdateSmask */
169
170 /* ************************************************************************
171  * GpsInfo
172  * ************************************************************************ */
173
174 /* inline void setPositionUpdateTime */
175
176 /**
177  Convert the time of an OLSR message (the number of seconds after midnight) to
178  a time structure, based on midnight of the current day.
179
180  @param olsrGpsMessage
181  A pointer to the position update message
182  @param baseDate
183  The base date from which to determine the time (number of seconds since Epoch,
184  UTC)
185  @param nowStruct
186  A pointer to the time structure into which to put the converted time
187  */
188 void getPositionUpdateTime(PudOlsrPositionUpdate * olsrGpsMessage,
189                 time_t baseDate, struct tm *nowStruct) {
190         uint32_t olsrTime = olsrGpsMessage->gpsInfo.time;
191         unsigned int secNow;
192
193         time_t now = baseDate;
194         gmtime_r(&now, nowStruct);
195
196         secNow = ((nowStruct->tm_hour * 60 * 60) + (nowStruct->tm_min * 60)
197                         + nowStruct->tm_sec);
198
199         if (secNow <= (12 * 60 * 60)) {
200                 /* we are now in the first 12h of the day */
201                 if (unlikely(olsrTime > (secNow + (12 * 60 * 60)))) {
202                         /* the message was sent more than 12h later in time:
203                          the message was sent yesterday: adjust the date by -1 day */
204                         now -= (24 * 60 * 60);
205                         gmtime_r(&now, nowStruct);
206                 }
207         } else {
208                 /* we are now in the last 12h of the day */
209                 if (unlikely(olsrTime < (secNow - (12 * 60 * 60)))) {
210                         /* the message was sent more than 12h earlier in time:
211                          the message was sent tomorrow: adjust the date by +1 day */
212                         now += (24 * 60 * 60);
213                         gmtime_r(&now, nowStruct);
214                 }
215         }
216
217         nowStruct->tm_hour = ((olsrTime % (24 * 60 * 60)) / 3600);
218         nowStruct->tm_min = ((olsrTime % (60 * 60)) / 60);
219         nowStruct->tm_sec = (olsrTime % 60);
220 }
221
222 /* inline double getPositionUpdateLatitude */
223 /* inline void setPositionUpdateLatitude */
224
225 /* inline double getPositionUpdateLongitude */
226 /* inline void setPositionUpdateLongitude */
227
228 /* inline long getPositionUpdateAltitude */
229 /* inline void setPositionUpdateAltitude */
230
231 /* inline unsigned long getPositionUpdateSpeed */
232 /* inline void setPositionUpdateSpeed */
233
234 /* inline unsigned long getPositionUpdateTrack */
235 /* inline void setPositionUpdateTrack */
236
237 /* inline double getPositionUpdateHdop */
238 /* inline void setPositionUpdateHdop */
239
240 /* ************************************************************************
241  * NodeInfo
242  * ************************************************************************ */
243
244 /* inline NodeIdType getPositionUpdateNodeIdType */
245 /* inline void setPositionUpdateNodeIdType */
246
247 /**
248  Get the nodeId and its size, accounting for nodeId presence
249
250  @param ipVersion
251  The IP version (AF_INET or AF_INET6)
252  @param olsrMessage
253  A pointer to the OLSR message
254  @param nodeId
255  A pointer to the location where a pointer to the nodeId (as contained in the
256  olsrMessage) can be stored
257  @param nodeIdSize
258  A pointer to the location where the number of bytes in the nodeId can be
259  stored
260  */
261 void getPositionUpdateNodeId(int ipVersion, union olsr_message * olsrMessage,
262                 unsigned char ** nodeId, unsigned int * nodeIdSize) {
263         PudOlsrPositionUpdate * olsrGpsMessage = getOlsrMessagePayload(ipVersion,
264                         olsrMessage);
265
266         *nodeId = &olsrGpsMessage->nodeInfo.nodeId;
267
268         switch (getPositionUpdateNodeIdType(ipVersion, olsrGpsMessage)) {
269         case PUD_NODEIDTYPE_MAC: /* hardware address */
270                 *nodeIdSize = PUD_NODEIDTYPE_MAC_BYTES;
271                 break;
272
273         case PUD_NODEIDTYPE_MSISDN: /* an MSISDN number */
274                 *nodeIdSize = PUD_NODEIDTYPE_MSISDN_BYTES;
275                 break;
276
277         case PUD_NODEIDTYPE_TETRA: /* a Tetra number */
278                 *nodeIdSize = PUD_NODEIDTYPE_TETRA_BYTES;
279                 break;
280
281         case PUD_NODEIDTYPE_DNS: /* DNS name */
282                 *nodeIdSize = strlen((char *) *nodeId);
283                 /* FIXME for no '\0' at the end, need to scan from the end until
284                  * encountering a non-zero byte: end of string address and
285                  * subtract the string start address */
286                 break;
287
288         case PUD_NODEIDTYPE_MMSI: /* an AIS MMSI number */
289                 *nodeIdSize = PUD_NODEIDTYPE_MMSI_BYTES;
290                 break;
291
292         case PUD_NODEIDTYPE_URN: /* a URN number */
293                 *nodeIdSize = PUD_NODEIDTYPE_URN_BYTES;
294                 break;
295
296         case PUD_NODEIDTYPE_192:
297                 *nodeIdSize = PUD_NODEIDTYPE_192_BYTES;
298                 break;
299
300         case PUD_NODEIDTYPE_193:
301                 *nodeIdSize = PUD_NODEIDTYPE_193_BYTES;
302                 break;
303
304         case PUD_NODEIDTYPE_194:
305                 *nodeIdSize = PUD_NODEIDTYPE_194_BYTES;
306                 break;
307
308         case PUD_NODEIDTYPE_IPV4: /* IPv4 address */
309         case PUD_NODEIDTYPE_IPV6: /* IPv6 address */
310         default: /* unsupported */
311         {
312                 *nodeId = (unsigned char *) getOlsrMessageOriginator(ipVersion,
313                                 olsrMessage);
314                 *nodeIdSize =
315                                 (ipVersion == AF_INET) ?
316                                                 PUD_NODEIDTYPE_IPV4_BYTES : PUD_NODEIDTYPE_IPV6_BYTES;
317         }
318                 break;
319         }
320
321         return;
322 }
323
324 /**
325  Convert the node information to the node information for an OLSR message and
326  put it in the PUD message in the OLSR message. Also updates the PUD message
327  smask.
328
329  @param ipVersion
330  The IP version (AF_INET or AF_INET6)
331  @param olsrGpsMessage
332  A pointer to the PUD message in the OLSR message
333  @param olsrMessageSize
334  The maximum number of bytes available for the olsrMessage
335  @param nodeIdType
336  The nodeIdType
337  @param nodeId
338  The (configured) nodeId
339  @param nodeIdLength
340  The number of bytes in the nodeId
341
342  @return
343  The number of bytes written in the PUD message in the OLSR message (for ALL
344  the node information)
345  */
346 size_t setPositionUpdateNodeInfo(int ipVersion,
347                 PudOlsrPositionUpdate * olsrGpsMessage, unsigned int olsrMessageSize,
348                 NodeIdType nodeIdType, unsigned char * nodeId, size_t nodeIdLength) {
349         unsigned char * buffer;
350         unsigned int length = 0;
351
352         setPositionUpdateNodeIdType(olsrGpsMessage, nodeIdType);
353         switch (nodeIdType) {
354         case PUD_NODEIDTYPE_MAC: /* hardware address */
355                 length = nodeIdLength;
356                 setPositionUpdateNodeId(olsrGpsMessage, nodeId, nodeIdLength, false);
357                 break;
358
359         case PUD_NODEIDTYPE_MSISDN: /* an MSISDN number */
360         case PUD_NODEIDTYPE_TETRA: /* a Tetra number */
361         case PUD_NODEIDTYPE_MMSI: /* an AIS MMSI number */
362         case PUD_NODEIDTYPE_URN: /* a URN number */
363         case PUD_NODEIDTYPE_192:
364         case PUD_NODEIDTYPE_193:
365         case PUD_NODEIDTYPE_194:
366                 getNodeIdNumberForOlsrCache(&buffer, &length);
367                 setPositionUpdateNodeId(olsrGpsMessage, buffer, length, false);
368                 break;
369
370         case PUD_NODEIDTYPE_DNS: /* DNS name */
371         {
372                 long charsAvailable = olsrMessageSize
373                                 - (PUD_OLSRWIREFORMATSIZE + sizeof(NodeInfo)
374                                                 - sizeof(olsrGpsMessage->nodeInfo.nodeId)) - 1;
375
376                 length = nodeIdLength + 1;
377                 if (unlikely((long) length > charsAvailable)) {
378                         length = charsAvailable;
379                 }
380
381                 setPositionUpdateNodeId(olsrGpsMessage, nodeId, length, true);
382         }
383                 break;
384
385         case PUD_NODEIDTYPE_IPV4: /* IPv4 address */
386         case PUD_NODEIDTYPE_IPV6: /* IPv6 address */
387                 /* explicit return: no nodeId information in message */
388                 return 0;
389
390         default: /* unsupported */
391                 /* fallback to IP address */
392                 setPositionUpdateNodeIdType(olsrGpsMessage,
393                                 (ipVersion == AF_INET) ? PUD_NODEIDTYPE_IPV4 :
394                                 PUD_NODEIDTYPE_IPV6);
395
396                 /* explicit return: no nodeId information in message */
397                 return 0;
398         }
399
400         setPositionUpdateSmask(olsrGpsMessage,
401                         getPositionUpdateSmask(olsrGpsMessage) | PUD_FLAGS_ID);
402         return ((sizeof(NodeInfo)
403                         - (sizeof(olsrGpsMessage->nodeInfo.nodeId) /* nodeId placeholder */))
404                         + length);
405 }