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