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