Coverage Report

Created: 2026-10-10 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpsd/gpsd-3.27.6~dev/drivers/driver_ais.c
Line
Count
Source
1
/*
2
 * Driver for AIS messages.
3
 *
4
 * See the file AIVDM.txt on the GPSD website for documentation and references.
5
 * AIVDM de-armoring is handled elsewhere; this is the binary-packet driver.
6
 *
7
 * Code for message types 1-15, 18-21, and 24 has been tested against
8
 * live data with known-good decodings. Code for message types 16-17,
9
 * 22-23, and 25-27 has not.
10
 * For the special IMO messages (types 6 and 8), only the following have been
11
 * tested against known-good decodings:
12
 *  - IMO236 met/hydro message: Type=8, DAC=1, FI=11
13
 *  - IMO289 met/hydro message: Type=8, DAC=1, FI=31
14
 *
15
 * This file is Copyright 2010 by the GPSD project
16
 * SPDX-License-Identifier: BSD-2-clause
17
 */
18
19
#include "../include/gpsd_config.h"   // must be before all includes
20
21
#include <ctype.h>
22
#include <stdlib.h>
23
#include <string.h>
24
25
#include "../include/gpsd.h"
26
#include "../include/bits.h"
27
28
/*
29
 * Parse the data from the device
30
 */
31
32
// beginning at bitvec bit start, unpack count sixbit characters
33
static void from_sixbit_untrimmed(const struct gpsd_errout_t *errout,
34
                                  const unsigned char *bitvec,
35
                                  const size_t bitlen,
36
                                  const unsigned start,
37
                                  unsigned count, char *to,
38
                                  const size_t to_sz)
39
0
{
40
0
    const char sixchr[65] =
41
0
        "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ !\"#$%&'()*+,-./0123456789:;<=>?";
42
0
    unsigned i;
43
44
0
    if (bitlen <= start) {
45
0
        GPSD_LOG(LOG_WARN, errout, "AIVDM bitlen %zu <=  start %u\n",
46
0
                 bitlen, start);
47
0
        to[0] = '\0';
48
0
        return;
49
0
    }
50
0
    if (to_sz <= count) {
51
0
        count = to_sz - 1;
52
0
    }
53
54
    // six-bit to ASCII
55
0
    for (i = 0; i < count; i++) {
56
0
        char newchar = sixchr[ubits(bitvec, start + 6 * i, 6U, false)];
57
58
0
        if ('@' == newchar) {
59
0
            break;
60
0
        }
61
0
        to[i] = newchar;
62
0
    }
63
0
    to[i] = '\0';
64
0
}
65
66
// trim spaces on right end
67
static void trim_spaces_on_right_end(char* to, size_t max)
68
0
{
69
0
    long long i;
70
71
    // pacify Coverity 498043, overflow
72
0
    for (i = strnlen(to, max) - 1; i >= 0; i--) {
73
0
        if (' ' == to[i] ||
74
0
            '@' == to[i]) {
75
0
            to[i] = '\0';
76
0
        } else {
77
0
            break;
78
0
        }
79
0
    }
80
0
}
81
82
/* beginning at bitvec bit start, unpack count sixbit characters
83
 * and remove trailing spaces */
84
static void from_sixbit(const struct gpsd_errout_t *errout,
85
                        const unsigned char *bitvec, const size_t bitlen,
86
                        const unsigned start,
87
                        const unsigned count, char *to, const size_t to_sz)
88
0
{
89
0
       from_sixbit_untrimmed(errout, bitvec, bitlen, start, count, to, to_sz);
90
0
       trim_spaces_on_right_end(to, count);
91
0
}
92
93
0
#define UBITS(s, l)     ubits(bits, s, l, false)
94
0
#define SBITS(s, l)     sbits(bits, s, l, false)
95
#define UCHARS(start, to)  \
96
0
    from_sixbit(errout, bits, bitlen, start, sizeof(to) - 1, to, sizeof(to))
97
98
#define ENDCHARS(start, to, to_sz)  \
99
0
    from_sixbit(errout, bits, bitlen, start, (bitlen - start) / 6, to, to_sz)
100
101
/* decode an AIS binary packet
102
 *
103
 * Return: True on success
104
 *         False on failure
105
 */
106
bool ais_binary_decode(const struct gpsd_errout_t *errout,
107
                       struct ais_t *ais,
108
                       const unsigned char *bits, size_t bitlen,
109
                       struct ais_type24_queue_t *type24_queue)
110
0
{
111
0
    unsigned int u;
112
0
    size_t bytelen = BITS_TO_BYTES(bitlen);
113
114
0
    ais->type = UBITS(0, 6);
115
0
    ais->repeat = UBITS(6, 2);
116
0
    ais->mmsi = UBITS(8, 30);
117
0
    GPSD_LOG(LOG_INF, errout,
118
0
              "AIVDM message type %d, MMSI %09d bitlen %zu bytelen %zu\n",
119
0
             ais->type, ais->mmsi, bitlen, bytelen);
120
121
0
#define PERMISSIVE_LENGTH_CHECK(correct) \
122
0
        if (bitlen < correct) { \
123
0
            GPSD_LOG(LOG_ERROR, errout, \
124
0
                     "AIVDM message type %d size < %d bits (%zd).\n",   \
125
0
                     ais->type, correct, bitlen);                       \
126
0
            return false; \
127
0
        } else if (bitlen > correct) { \
128
0
            GPSD_LOG(LOG_WARN, errout, \
129
0
                     "AIVDM message type %d size > %d bits (%zd).\n",   \
130
0
                     ais->type, correct, bitlen);                       \
131
0
        }
132
133
0
#define RANGE_CHECK(min, max) \
134
0
        if (bitlen < min || bitlen > max) { \
135
0
            GPSD_LOG(LOG_ERROR, errout, \
136
0
                     "AIVDM message type %d size is out of range: " \
137
0
                     " %u <= (%zu) <= %u.\n", \
138
0
                     ais->type, min, bitlen, max);  \
139
0
            return false; \
140
0
        }
141
142
0
#define RANGE_CHECK6(min, max) \
143
0
        if (bitlen < min || bitlen > max) { \
144
0
            GPSD_LOG(LOG_ERROR, errout, \
145
0
                     "AIVDM message type %d dac %u fid %u size is out of " \
146
0
                     "range %u <= (%zu) <= %u.\n", \
147
0
                     ais->type, ais->type6.dac, ais->type6.fid, \
148
0
                     min, bitlen, max);  \
149
0
            return false; \
150
0
        }
151
152
0
#define RANGE_CHECK8(min, max) \
153
0
        if (bitlen < min || bitlen > max) { \
154
0
            GPSD_LOG(LOG_ERROR, errout, \
155
0
                     "AIVDM message type %d dac %u fid %u size is out of " \
156
0
                     "range %u <= (%zu) <= %u.\n", \
157
0
                     ais->type, ais->type8.dac, ais->type8.fid, \
158
0
                     min, bitlen, max);  \
159
0
            return false; \
160
0
        }
161
162
    /*
163
     * Something about the shape of this switch statement confuses
164
     * GNU indent so badly that there is no point in trying to be
165
     * finer-grained than leaving it all alone.
166
     */
167
168
// calculate offset into array
169
0
#define OFF(index) (ARRAY_BASE + (ELEMENT_SIZE * index))
170
171
    // *INDENT-OFF*
172
0
    switch (ais->type) {
173
0
    case 1:     // Position Report
174
0
        FALLTHROUGH
175
0
    case 2:
176
0
        FALLTHROUGH
177
0
    case 3:
178
        // per https://www.navcen.uscg.gov/ais-class-a-reports
179
        // In 2023, most of our samples are 168, but some are 163 and 204.
180
0
        RANGE_CHECK(163, 204)
181
0
        ais->type1.status       = UBITS(38, 4);
182
0
        ais->type1.turn         = SBITS(42, 8);
183
0
        ais->type1.speed        = UBITS(50, 10);
184
0
        ais->type1.accuracy     = UBITS(60, 1) != 0;
185
0
        ais->type1.lon          = SBITS(61, 28);
186
0
        ais->type1.lat          = SBITS(89, 27);
187
0
        ais->type1.course       = UBITS(116, 12);
188
0
        ais->type1.heading      = UBITS(128, 9);
189
0
        ais->type1.second       = UBITS(137, 6);
190
0
        ais->type1.maneuver     = UBITS(143, 2);
191
        // ais->type1.spare     = UBITS(145, 3);
192
0
        ais->type1.raim         = UBITS(148, 1) != 0;
193
0
        if(bitlen >= 168) {
194
0
            ais->type1.radio        = UBITS(149, 19);
195
0
        } else {
196
            // less than 168, as of 2023 we have no examples of this.
197
0
            ais->type1.radio        = UBITS(149, bitlen - 149);
198
0
        }
199
0
        break;
200
0
    case 4:     // Base Station Report
201
0
        FALLTHROUGH
202
0
    case 11:    // UTC/Date Response
203
0
        PERMISSIVE_LENGTH_CHECK(168)
204
0
        ais->type4.year         = UBITS(38, 14);
205
0
        ais->type4.month        = UBITS(52, 4);
206
0
        ais->type4.day          = UBITS(56, 5);
207
0
        ais->type4.hour         = UBITS(61, 5);
208
0
        ais->type4.minute       = UBITS(66, 6);
209
0
        ais->type4.second       = UBITS(72, 6);
210
0
        ais->type4.accuracy     = UBITS(78, 1) != 0;
211
0
        ais->type4.lon          = SBITS(79, 28);
212
0
        ais->type4.lat          = SBITS(107, 27);
213
0
        ais->type4.epfd         = UBITS(134, 4);
214
        //ais->type4.spare      = UBITS(138, 10);
215
0
        ais->type4.raim         = UBITS(148, 1) != 0;
216
0
        ais->type4.radio        = UBITS(149, 19);
217
0
        break;
218
0
    case 5: // Ship static and voyage related data
219
0
        if (424 != bitlen) {
220
0
            GPSD_LOG(LOG_WARN, errout,
221
0
                     "AIVDM message type 5 size not 424 bits (%zd).\n",
222
0
                     bitlen);
223
            /*
224
             * For unknown reasons, a lot of transmitters in the wild ship
225
             * with a length of 420 or 422.  This is a recoverable error.
226
             */
227
0
            if (420 > bitlen) {
228
0
                return false;
229
0
            }
230
0
        }
231
0
        ais->type5.ais_version  = UBITS(38, 2);
232
0
        ais->type5.imo          = UBITS(40, 30);
233
0
        UCHARS(70, ais->type5.callsign);
234
0
        UCHARS(112, ais->type5.shipname);
235
0
        ais->type5.shiptype     = UBITS(232, 8);
236
0
        ais->type5.to_bow       = UBITS(240, 9);
237
0
        ais->type5.to_stern     = UBITS(249, 9);
238
0
        ais->type5.to_port      = UBITS(258, 6);
239
0
        ais->type5.to_starboard = UBITS(264, 6);
240
0
        ais->type5.epfd         = UBITS(270, 4);
241
0
        ais->type5.month        = UBITS(274, 4);
242
0
        ais->type5.day          = UBITS(278, 5);
243
0
        ais->type5.hour         = UBITS(283, 5);
244
0
        ais->type5.minute       = UBITS(288, 6);
245
0
        ais->type5.draught      = UBITS(294, 8);
246
0
        UCHARS(302, ais->type5.destination);
247
0
        if (423 <= bitlen) {
248
0
            ais->type5.dte          = UBITS(422, 1);
249
0
        }
250
        //ais->type5.spare        = UBITS(423, 1);
251
0
        break;
252
0
    case 6:   // Addressed Binary Message
253
0
        RANGE_CHECK(88, 1008);
254
0
        ais->type6.seqno          = UBITS(38, 2);
255
0
        ais->type6.dest_mmsi      = UBITS(40, 30);
256
0
        ais->type6.retransmit     = UBITS(70, 1) != 0;
257
        //ais->type6.spare        = UBITS(71, 1);
258
0
        ais->type6.dac            = UBITS(72, 10);
259
0
        ais->type6.fid            = UBITS(82, 6);
260
0
        ais->type6.bitcount       = bitlen - 88;
261
        // not strictly required - helps stability in testing
262
0
        (void)memset(ais->type6.bitdata, '\0', sizeof(ais->type6.bitdata));
263
0
        ais->type6.structured = false;
264
        // Inland AIS
265
0
         GPSD_LOG(LOG_PROG, errout,
266
0
                  "AIVDM: type 6 dac %u fid %u bitlen %zu\n",
267
0
                 ais->type6.dac, ais->type6.fid, bitlen);
268
0
        if (200 == ais->type6.dac) {
269
0
            switch (ais->type6.fid) {
270
0
            case 21:    // ETA at lock/bridge/terminal
271
0
                RANGE_CHECK6(248, 248);
272
0
                UCHARS(88, ais->type6.dac200fid21.country);
273
0
                UCHARS(100, ais->type6.dac200fid21.locode);
274
0
                UCHARS(118, ais->type6.dac200fid21.section);
275
0
                UCHARS(148, ais->type6.dac200fid21.terminal);
276
0
                UCHARS(178, ais->type6.dac200fid21.hectometre);
277
0
                ais->type6.dac200fid21.month    = UBITS(208, 4);
278
0
                ais->type6.dac200fid21.day      = UBITS(212, 5);
279
0
                ais->type6.dac200fid21.hour     = UBITS(217, 5);
280
0
                ais->type6.dac200fid21.minute   = UBITS(222, 6);
281
0
                ais->type6.dac200fid21.tugs     = UBITS(228, 3);
282
0
                ais->type6.dac200fid21.airdraught       = UBITS(231, 12);
283
                // skip 5 bits
284
0
                ais->type6.structured = true;
285
0
                break;
286
0
            case 22:    // RTA at lock/bridge/terminal
287
0
                RANGE_CHECK6(232, 232);
288
0
                UCHARS(88, ais->type6.dac200fid22.country);
289
0
                UCHARS(100, ais->type6.dac200fid22.locode);
290
0
                UCHARS(118, ais->type6.dac200fid22.section);
291
0
                UCHARS(148, ais->type6.dac200fid22.terminal);
292
0
                UCHARS(178, ais->type6.dac200fid22.hectometre);
293
0
                ais->type6.dac200fid22.month    = UBITS(208, 4);
294
0
                ais->type6.dac200fid22.day      = UBITS(212, 5);
295
0
                ais->type6.dac200fid22.hour     = UBITS(217, 5);
296
0
                ais->type6.dac200fid22.minute   = UBITS(222, 6);
297
0
                ais->type6.dac200fid22.status   = UBITS(228, 2);
298
                // skip 2 bits
299
0
                ais->type6.structured = true;
300
0
                break;
301
0
            case 55:    // Number of Persons On Board
302
0
                RANGE_CHECK6(168, 168);
303
0
                ais->type6.dac200fid55.crew       = UBITS(88, 8);
304
0
                ais->type6.dac200fid55.passengers = UBITS(96, 13);
305
0
                ais->type6.dac200fid55.personnel  = UBITS(109, 8);
306
                // skip 51 bits
307
0
                ais->type6.structured = true;
308
0
                break;
309
0
            }
310
0
        } else if (235 == ais->type6.dac ||
311
0
                   250 == ais->type6.dac) {
312
        // UK and Republic Of Ireland
313
0
            switch (ais->type6.fid) {
314
0
            case 10:    // GLA - AtoN monitoring data
315
0
                RANGE_CHECK6(136, 136);
316
0
                ais->type6.dac235fid10.ana_int  = UBITS(88, 10);
317
0
                ais->type6.dac235fid10.ana_ext1 = UBITS(98, 10);
318
0
                ais->type6.dac235fid10.ana_ext2 = UBITS(108, 10);
319
0
                ais->type6.dac235fid10.racon    = UBITS(118, 2);
320
0
                ais->type6.dac235fid10.light    = UBITS(120, 2);
321
0
                ais->type6.dac235fid10.alarm    = UBITS(122, 1);
322
0
                ais->type6.dac235fid10.stat_ext = UBITS(123, 8);
323
0
                ais->type6.dac235fid10.off_pos  = UBITS(131, 1);
324
                // skip 4 bits
325
0
                ais->type6.structured = true;
326
0
                break;
327
0
            }
328
0
        } else if (1 == ais->type6.dac) {
329
            // International
330
0
            switch (ais->type6.fid) {
331
0
            case 12:    // IMO236 - Dangerous cargo indication
332
0
                RANGE_CHECK6(144, 360);
333
0
                UCHARS(88, ais->type6.dac1fid12.lastport);
334
0
                ais->type6.dac1fid12.lmonth     = UBITS(118, 4);
335
0
                ais->type6.dac1fid12.lday       = UBITS(122, 5);
336
0
                ais->type6.dac1fid12.lhour      = UBITS(127, 5);
337
0
                ais->type6.dac1fid12.lminute    = UBITS(132, 6);
338
0
                if (144 < bitlen) {
339
0
                    RANGE_CHECK6(360, 360);
340
0
                    UCHARS(138, ais->type6.dac1fid12.nextport);
341
0
                    ais->type6.dac1fid12.nmonth     = UBITS(168, 4);
342
0
                    ais->type6.dac1fid12.nday       = UBITS(172, 5);
343
0
                    ais->type6.dac1fid12.nhour      = UBITS(177, 5);
344
0
                    ais->type6.dac1fid12.nminute    = UBITS(182, 6);
345
0
                    UCHARS(188, ais->type6.dac1fid12.dangerous);
346
0
                    UCHARS(308, ais->type6.dac1fid12.imdcat);
347
0
                    ais->type6.dac1fid12.unid       = UBITS(332, 13);
348
0
                    ais->type6.dac1fid12.amount     = UBITS(345, 10);
349
0
                    ais->type6.dac1fid12.unit       = UBITS(355, 2);
350
                    // skip 3 bits
351
0
                }
352
0
                ais->type6.structured = true;
353
0
                break;
354
0
            case 14:    // IMO236 - Tidal Window
355
                // similar to fid 32.
356
0
                RANGE_CHECK6(87, 1008);
357
0
                ais->type6.dac1fid32.month      = UBITS(88, 4);
358
0
                ais->type6.dac1fid32.day        = UBITS(92, 5);
359
0
#define ARRAY_BASE 97
360
0
#define ELEMENT_SIZE 93
361
0
                for (u = 0; ; u++) {
362
0
                    size_t off = OFF(u);
363
0
                    struct tidal_t *tp = &ais->type6.dac1fid32.tidals[u];
364
0
                    if (off >= bitlen ||
365
0
                        ROWS(ais->type6.dac1fid32.tidals) <= u) {
366
0
                        break;
367
0
                    }
368
0
                    tp->lat       = SBITS(off + 0, 27);
369
0
                    tp->lon       = SBITS(off + 27, 28);
370
0
                    tp->from_hour = UBITS(off + 55, 5);
371
0
                    tp->from_min  = UBITS(off + 60, 6);
372
0
                    tp->to_hour   = UBITS(off + 66, 5);
373
0
                    tp->to_min    = UBITS(off + 71, 6);
374
0
                    tp->cdir      = UBITS(off + 77, 9);
375
0
                    tp->cspeed    = UBITS(off + 86, 7);
376
0
                }
377
0
                ais->type6.dac1fid32.ntidals = u;
378
0
#undef ARRAY_BASE
379
0
#undef ELEMENT_SIZE
380
0
                ais->type6.structured = true;
381
0
                break;
382
0
            case 15:
383
                // IMO236 - Extended Ship Static and Voyage Related Data
384
0
                RANGE_CHECK6(67, 1008);
385
0
                ais->type6.dac1fid15.airdraught = UBITS(56, 11);
386
0
                ais->type6.structured = true;
387
0
                break;
388
0
            case 16:    // IMO236 - Number of persons on board
389
0
                RANGE_CHECK6(236, 289);
390
0
                if (136 == ais->type6.bitcount) {
391
0
                    ais->type6.dac1fid16.persons = UBITS(88, 13);  // 289
392
0
                } else {
393
0
                    ais->type6.dac1fid16.persons = UBITS(55, 13);  // 236
394
0
                }
395
0
                ais->type6.structured = true;
396
0
                break;
397
0
            case 18:    // IMO289 - Clearance time to enter port
398
                // sometimes bitlen == 168!
399
0
                RANGE_CHECK6(168, 1008);
400
0
                ais->type6.dac1fid18.linkage    = UBITS(88, 10);
401
0
                ais->type6.dac1fid18.month      = UBITS(98, 4);
402
0
                ais->type6.dac1fid18.day        = UBITS(102, 5);
403
0
                ais->type6.dac1fid18.hour       = UBITS(107, 5);
404
0
                ais->type6.dac1fid18.minute     = UBITS(112, 6);
405
0
                UCHARS(118, ais->type6.dac1fid18.portname);
406
0
                if (318 <=  bitlen) {
407
0
                    UCHARS(238, ais->type6.dac1fid18.destination);
408
0
                    ais->type6.dac1fid18.lon        = SBITS(268, 25);
409
0
                    ais->type6.dac1fid18.lat        = SBITS(293, 24);
410
                    // skip 43 bits
411
0
                }
412
0
                ais->type6.structured = true;
413
0
                break;
414
0
            case 20:    // IMO289 - Berthing data - addressed
415
0
                RANGE_CHECK6(360, 1008);
416
0
                ais->type6.dac1fid20.linkage      = UBITS(88, 10);
417
0
                ais->type6.dac1fid20.berth_length = UBITS(98, 9);
418
0
                ais->type6.dac1fid20.berth_depth  = UBITS(107, 8);
419
0
                ais->type6.dac1fid20.position     = UBITS(115, 3);
420
0
                ais->type6.dac1fid20.month        = UBITS(118, 4);
421
0
                ais->type6.dac1fid20.day          = UBITS(122, 5);
422
0
                ais->type6.dac1fid20.hour         = UBITS(127, 5);
423
0
                ais->type6.dac1fid20.minute       = UBITS(132, 6);
424
0
                ais->type6.dac1fid20.availability = UBITS(138, 1);
425
0
                ais->type6.dac1fid20.agent        = UBITS(139, 2);
426
0
                ais->type6.dac1fid20.fuel         = UBITS(141, 2);
427
0
                ais->type6.dac1fid20.chandler     = UBITS(143, 2);
428
0
                ais->type6.dac1fid20.stevedore    = UBITS(145, 2);
429
0
                ais->type6.dac1fid20.electrical   = UBITS(147, 2);
430
0
                ais->type6.dac1fid20.water        = UBITS(149, 2);
431
0
                ais->type6.dac1fid20.customs      = UBITS(151, 2);
432
0
                ais->type6.dac1fid20.cartage      = UBITS(153, 2);
433
0
                ais->type6.dac1fid20.crane        = UBITS(155, 2);
434
0
                ais->type6.dac1fid20.lift         = UBITS(157, 2);
435
0
                ais->type6.dac1fid20.medical      = UBITS(159, 2);
436
0
                ais->type6.dac1fid20.navrepair    = UBITS(161, 2);
437
0
                ais->type6.dac1fid20.provisions   = UBITS(163, 2);
438
0
                ais->type6.dac1fid20.shiprepair   = UBITS(165, 2);
439
0
                ais->type6.dac1fid20.surveyor     = UBITS(167, 2);
440
0
                ais->type6.dac1fid20.steam        = UBITS(169, 2);
441
0
                ais->type6.dac1fid20.tugs         = UBITS(171, 2);
442
0
                ais->type6.dac1fid20.solidwaste   = UBITS(173, 2);
443
0
                ais->type6.dac1fid20.liquidwaste  = UBITS(175, 2);
444
0
                ais->type6.dac1fid20.hazardouswaste = UBITS(177, 2);
445
0
                ais->type6.dac1fid20.ballast      = UBITS(179, 2);
446
0
                ais->type6.dac1fid20.additional   = UBITS(181, 2);
447
0
                ais->type6.dac1fid20.regional1    = UBITS(183, 2);
448
0
                ais->type6.dac1fid20.regional2    = UBITS(185, 2);
449
0
                ais->type6.dac1fid20.future1      = UBITS(187, 2);
450
0
                ais->type6.dac1fid20.future2      = UBITS(189, 2);
451
0
                UCHARS(191, ais->type6.dac1fid20.berth_name);
452
0
                ais->type6.dac1fid20.berth_lon    = SBITS(311, 25);
453
0
                ais->type6.dac1fid20.berth_lat    = SBITS(336, 24);
454
0
                ais->type6.structured = true;
455
0
                break;
456
0
            case 23:        // IMO289 - Area notice - addressed
457
0
                break;
458
0
            case 25:    // IMO289 - Dangerous cargo indication
459
0
#define ARRAY_BASE 100
460
0
#define ELEMENT_SIZE 17
461
0
                RANGE_CHECK6(100, 1008);
462
0
                ais->type6.dac1fid25.unit       = UBITS(88, 2);
463
0
                ais->type6.dac1fid25.amount     = UBITS(90, 10);
464
0
                for (u = 0; ; u++) {
465
0
                    size_t off = OFF(u);
466
0
                    if (off >= bitlen ||
467
0
                        ROWS(ais->type6.dac1fid25.cargos) <= u) {
468
0
                        break;
469
0
                    }
470
0
                    ais->type6.dac1fid25.cargos[u].code = UBITS(off, 4);
471
0
                    ais->type6.dac1fid25.cargos[u].subtype =
472
0
                        UBITS(off + 4, 13);
473
0
                }
474
0
                ais->type6.dac1fid25.ncargos = u;
475
0
                ais->type6.structured = true;
476
0
#undef ARRAY_BASE
477
0
#undef ELEMENT_SIZE
478
0
                break;
479
0
            case 28:    // IMO289 - Route info - addressed
480
0
                RANGE_CHECK6(149, 1008);
481
0
                ais->type6.dac1fid28.linkage    = UBITS(88, 10);
482
0
                ais->type6.dac1fid28.sender     = UBITS(98, 3);
483
0
                ais->type6.dac1fid28.rtype      = UBITS(101, 5);
484
0
                ais->type6.dac1fid28.month      = UBITS(106, 4);
485
0
                ais->type6.dac1fid28.day        = UBITS(110, 5);
486
0
                ais->type6.dac1fid28.hour       = UBITS(115, 5);
487
0
                ais->type6.dac1fid28.minute     = UBITS(120, 6);
488
0
                ais->type6.dac1fid28.duration   = UBITS(126, 18);
489
0
                ais->type6.dac1fid28.waycount   = UBITS(144, 5);
490
0
#define ARRAY_BASE 149
491
0
#define ELEMENT_SIZE 55
492
0
                for (u = 0; ; u++) {
493
0
                    size_t off = OFF(u);
494
0
                    if (off >= bitlen ||
495
0
                        ROWS(ais->type6.dac1fid28.waypoints) <= u ||
496
0
                        u >= ais->type6.dac1fid28.waycount) {
497
0
                        break;
498
0
                    }
499
0
                    ais->type6.dac1fid28.waypoints[u].lon = SBITS(off + 0, 28);
500
0
                    ais->type6.dac1fid28.waypoints[u].lat = SBITS(off + 28, 27);
501
0
                }
502
0
#undef ARRAY_BASE
503
0
#undef ELEMENT_SIZE
504
0
                ais->type6.structured = true;
505
0
                break;
506
0
            case 30:    // IMO289 - Text description - addressed
507
0
                RANGE_CHECK6(98, 1008);
508
0
                ais->type6.dac1fid30.linkage   = UBITS(88, 10);
509
0
                ENDCHARS(98, ais->type6.dac1fid30.text,
510
0
                         sizeof(ais->type6.dac1fid30.text));
511
0
                ais->type6.structured = true;
512
0
                break;
513
0
            case 32:    // IMO289 - Tidal Window
514
                // similar to fid 14.
515
0
                RANGE_CHECK6(97, 1008);
516
0
                ais->type6.dac1fid32.month      = UBITS(88, 4);
517
0
                ais->type6.dac1fid32.day        = UBITS(92, 5);
518
0
#define ARRAY_BASE 97
519
0
#define ELEMENT_SIZE 88
520
0
                for (u = 0; ; u++) {
521
0
                    size_t off = OFF(u);
522
0
                    if (off >= bitlen ||
523
0
                        ROWS(ais->type6.dac1fid32.tidals) <= u) {
524
0
                        break;
525
0
                    }
526
0
                    struct tidal_t *tp = &ais->type6.dac1fid32.tidals[u];
527
528
0
                    tp->lon       = SBITS(off + 0, 25);
529
0
                    tp->lat       = SBITS(off + 25, 24);
530
0
                    tp->from_hour = UBITS(off + 49, 5);
531
0
                    tp->from_min  = UBITS(off + 54, 6);
532
0
                    tp->to_hour   = UBITS(off + 60, 5);
533
0
                    tp->to_min    = UBITS(off + 65, 6);
534
0
                    tp->cdir      = UBITS(off + 71, 9);
535
0
                    tp->cspeed    = UBITS(off + 80, 8);
536
0
                }
537
0
                ais->type6.dac1fid32.ntidals = u;
538
0
#undef ARRAY_BASE
539
0
#undef ELEMENT_SIZE
540
0
                ais->type6.structured = true;
541
0
                break;
542
0
            }
543
0
        }
544
0
        if (!ais->type6.structured) {
545
0
            (void)memcpy(ais->type6.bitdata, bits + (88 / CHAR_BIT),
546
0
                         BITS_TO_BYTES(ais->type6.bitcount));
547
0
        }
548
0
        break;
549
0
    case 7:    // Binary acknowledge
550
0
        FALLTHROUGH
551
0
    case 13:   // Safety Related Acknowledge
552
0
    {
553
0
        unsigned int mmsi[4];
554
0
        unsigned seqno[4];
555
0
        RANGE_CHECK(72, 168);
556
0
#define ARRAY_BASE 40
557
0
#define ELEMENT_SIZE 32
558
0
        for (u = 0; u < ROWS(mmsi); u++) {
559
0
            size_t off = OFF(u);
560
561
0
            if (off < bitlen) {
562
0
                mmsi[u] = UBITS(off, 30);
563
0
                seqno[u] = UBITS(off + 32, 2);
564
0
            } else {
565
0
                mmsi[u] = 0;
566
0
                seqno[u] = 0;
567
0
            }
568
0
        }
569
0
#undef ARRAY_BASE
570
0
#undef ELEMENT_SIZE
571
0
        ais->type7.mmsi1 = mmsi[0];
572
0
        ais->type7.seqno1 = seqno[0];
573
0
        ais->type7.mmsi2 = mmsi[1];
574
0
        ais->type7.seqno2 = seqno[1];
575
0
        ais->type7.mmsi3 = mmsi[2];
576
0
        ais->type7.seqno3 = seqno[2];
577
0
        ais->type7.mmsi4 = mmsi[3];
578
0
        ais->type7.seqno4 = seqno[3];
579
0
        break;
580
0
    }
581
0
    case 8: // Binary Broadcast Message
582
0
        RANGE_CHECK8(56, 1008);
583
        //ais->type8.spare        = UBITS(38, 2);
584
0
        ais->type8.dac            = UBITS(40, 10);
585
0
        ais->type8.fid            = UBITS(50, 6);
586
0
        ais->type8.bitcount       = bitlen - 56;
587
        // not strictly required - helps stability in testing
588
0
        (void)memset(ais->type8.bitdata, '\0', sizeof(ais->type8.bitdata));
589
0
        ais->type8.structured = false;
590
0
        GPSD_LOG(LOG_PROG, errout, "AIVDM: type 8 dac %u fid %u bitlen %zu\n",
591
0
                 ais->type8.dac, ais->type8.fid, bitlen);
592
0
        if (1 == ais->type8.dac) {
593
0
            switch (ais->type8.fid) {
594
0
            case 11:        // IMO236 - Meteorological/Hydrological data
595
                // layout is almost identical to FID=31 from IMO289
596
                // FIXME: we get length 352??
597
0
                RANGE_CHECK8(346, 352);
598
0
                ais->type8.dac1fid11.lat        = SBITS(56, 24);
599
0
                ais->type8.dac1fid11.lon        = SBITS(80, 25);
600
0
                ais->type8.dac1fid11.day        = UBITS(105, 5);
601
0
                ais->type8.dac1fid11.hour       = UBITS(110, 5);
602
0
                ais->type8.dac1fid11.minute     = UBITS(115, 6);
603
0
                ais->type8.dac1fid11.wspeed     = UBITS(121, 7);
604
0
                ais->type8.dac1fid11.wgust      = UBITS(128, 7);
605
0
                ais->type8.dac1fid11.wdir       = UBITS(135, 9);
606
0
                ais->type8.dac1fid11.wgustdir   = UBITS(144, 9);
607
0
                ais->type8.dac1fid11.airtemp    = UBITS(153, 11);
608
0
                ais->type8.dac1fid11.humidity   = UBITS(164, 7);
609
0
                ais->type8.dac1fid11.dewpoint   = UBITS(171, 10);
610
0
                ais->type8.dac1fid11.pressure   = UBITS(181, 9);
611
0
                ais->type8.dac1fid11.pressuretend       = UBITS(190, 2);
612
0
                ais->type8.dac1fid11.visibility = UBITS(192, 8);
613
0
                ais->type8.dac1fid11.waterlevel = UBITS(200, 9);
614
0
                ais->type8.dac1fid11.leveltrend = UBITS(209, 2);
615
0
                ais->type8.dac1fid11.cspeed     = UBITS(211, 8);
616
0
                ais->type8.dac1fid11.cdir       = UBITS(219, 9);
617
0
                ais->type8.dac1fid11.cspeed2    = UBITS(228, 8);
618
0
                ais->type8.dac1fid11.cdir2      = UBITS(236, 9);
619
0
                ais->type8.dac1fid11.cdepth2    = UBITS(245, 5);
620
0
                ais->type8.dac1fid11.cspeed3    = UBITS(250, 8);
621
0
                ais->type8.dac1fid11.cdir3      = UBITS(258, 9);
622
0
                ais->type8.dac1fid11.cdepth3    = UBITS(267, 5);
623
0
                ais->type8.dac1fid11.waveheight = UBITS(272, 8);
624
0
                ais->type8.dac1fid11.waveperiod = UBITS(280, 6);
625
0
                ais->type8.dac1fid11.wavedir    = UBITS(286, 9);
626
0
                ais->type8.dac1fid11.swellheight        = UBITS(295, 8);
627
0
                ais->type8.dac1fid11.swellperiod        = UBITS(303, 6);
628
0
                ais->type8.dac1fid11.swelldir   = UBITS(309, 9);
629
0
                ais->type8.dac1fid11.seastate   = UBITS(318, 4);
630
0
                ais->type8.dac1fid11.watertemp  = UBITS(322, 10);
631
0
                ais->type8.dac1fid11.preciptype = UBITS(332, 3);
632
0
                ais->type8.dac1fid11.salinity   = UBITS(335, 9);
633
0
                ais->type8.dac1fid11.ice        = UBITS(344, 2);
634
0
                ais->type8.structured = true;
635
0
                break;
636
0
            case 13:        // IMO236 - Fairway closed
637
0
                RANGE_CHECK8(468, 468);
638
0
                UCHARS(56, ais->type8.dac1fid13.reason);
639
0
                UCHARS(176, ais->type8.dac1fid13.closefrom);
640
0
                UCHARS(296, ais->type8.dac1fid13.closeto);
641
0
                ais->type8.dac1fid13.radius     = UBITS(416, 10);
642
0
                ais->type8.dac1fid13.extunit    = UBITS(426, 2);
643
0
                ais->type8.dac1fid13.fday       = UBITS(428, 5);
644
0
                ais->type8.dac1fid13.fmonth     = UBITS(433, 4);
645
0
                ais->type8.dac1fid13.fhour      = UBITS(437, 5);
646
0
                ais->type8.dac1fid13.fminute    = UBITS(442, 6);
647
0
                ais->type8.dac1fid13.tday       = UBITS(448, 5);
648
0
                ais->type8.dac1fid13.tmonth     = UBITS(453, 4);
649
0
                ais->type8.dac1fid13.thour      = UBITS(457, 5);
650
0
                ais->type8.dac1fid13.tminute    = UBITS(462, 6);
651
                // skip 4 bits
652
0
                ais->type8.structured = true;
653
0
                break;
654
0
            case 15:        // IMO236 - Extended ship and voyage
655
0
                RANGE_CHECK8(67, 72);
656
0
                ais->type8.dac1fid15.airdraught = UBITS(56, 11);
657
                // skip 5 bits
658
0
                ais->type8.structured = true;
659
0
                break;
660
0
            case 16:        // Number of Persons On Board
661
                // dac 1, fid 18.  bitlen = 776 ???
662
0
                RANGE_CHECK8(72, 776);
663
0
                if (136 == ais->type8.bitcount) {
664
0
                    ais->type8.dac1fid16.persons = UBITS(88, 13);  // 289
665
0
                    ais->type8.structured = true;
666
0
                } else if (72 == ais->type8.bitcount) {
667
0
                    ais->type8.dac1fid16.persons = UBITS(55, 13);  // 236
668
0
                    ais->type8.structured = true;
669
0
                }
670
0
                break;
671
0
            case 17:        // IMO289 - VTS-generated/synthetic targets
672
0
                RANGE_CHECK8(56, 1008);
673
0
#define ARRAY_BASE 56
674
0
#define ELEMENT_SIZE 122
675
0
                for (u = 0; ; u++) {
676
0
                    struct target_t *tp;
677
0
                    size_t off = OFF(u);
678
0
                    if (off >= bitlen ||
679
0
                        ROWS(ais->type8.dac1fid17.targets) <= u) {
680
0
                        break;
681
0
                    }
682
0
                    tp = &ais->type8.dac1fid17.targets[u];
683
0
                    tp->idtype = UBITS(off + 0, 2);
684
0
                    switch (tp->idtype) {
685
0
                    case DAC1FID17_IDTYPE_MMSI:
686
0
                        tp->id.mmsi     = UBITS(off + 2, 42);
687
0
                        break;
688
0
                    case DAC1FID17_IDTYPE_IMO:
689
0
                        tp->id.imo      = UBITS(off + 2, 42);
690
0
                        break;
691
0
                    case DAC1FID17_IDTYPE_CALLSIGN:
692
0
                        UCHARS(off + 2, tp->id.callsign);
693
0
                        break;
694
0
                    default:
695
0
                        UCHARS(off + 2, tp->id.other);
696
0
                        break;
697
0
                    }
698
                    // skip 4 bits
699
0
                    tp->lat     = SBITS(off + 48, 24);
700
0
                    tp->lon     = SBITS(off + 72, 25);
701
0
                    tp->course  = UBITS(off + 97, 9);
702
0
                    tp->second  = UBITS(off + 106, 6);
703
0
                    tp->speed   = UBITS(off + 112, 10);
704
0
                }
705
0
                ais->type8.dac1fid17.ntargets = u;
706
0
#undef ARRAY_BASE
707
0
#undef ELEMENT_SIZE
708
0
                ais->type8.structured = true;
709
0
                break;
710
0
            case 19:        // IMO289 - Marine Traffic Signal
711
0
                RANGE_CHECK8(258, 1008);
712
0
                ais->type8.dac1fid19.linkage    = UBITS(56, 10);
713
0
                UCHARS(66, ais->type8.dac1fid19.station);
714
0
                ais->type8.dac1fid19.lon        = SBITS(186, 25);
715
0
                ais->type8.dac1fid19.lat        = SBITS(211, 24);
716
0
                ais->type8.dac1fid19.status     = UBITS(235, 2);
717
0
                ais->type8.dac1fid19.signal     = UBITS(237, 5);
718
0
                ais->type8.dac1fid19.hour       = UBITS(242, 5);
719
0
                ais->type8.dac1fid19.minute     = UBITS(247, 6);
720
0
                ais->type8.dac1fid19.nextsignal = UBITS(253, 5);
721
                // skip 102 bits
722
0
                ais->type8.structured = true;
723
0
                break;
724
0
            case 21:        // IMO289 - Weather obs. report from ship
725
0
                break;
726
0
            case 22:        // IMO289 - Area notice - broadcast
727
0
                break;
728
0
            case 24:
729
                // IMO289 - Extended ship static & voyage-related data
730
0
                break;
731
0
            case 26:        // IMO289 - Environmental
732
0
                break;
733
0
            case 27:        // IMO289 - Route information - broadcast
734
0
                RANGE_CHECK8(117, 1008);
735
0
                ais->type8.dac1fid27.linkage    = UBITS(56, 10);
736
0
                ais->type8.dac1fid27.sender     = UBITS(66, 3);
737
0
                ais->type8.dac1fid27.rtype      = UBITS(69, 5);
738
0
                ais->type8.dac1fid27.month      = UBITS(74, 4);
739
0
                ais->type8.dac1fid27.day        = UBITS(78, 5);
740
0
                ais->type8.dac1fid27.hour       = UBITS(83, 5);
741
0
                ais->type8.dac1fid27.minute     = UBITS(88, 6);
742
0
                ais->type8.dac1fid27.duration   = UBITS(94, 18);
743
0
                ais->type8.dac1fid27.waycount   = UBITS(112, 5);
744
0
#define ARRAY_BASE 117
745
0
#define ELEMENT_SIZE 55
746
0
                for (u = 0; u < ais->type8.dac1fid27.waycount; u++) {
747
0
                    size_t off = OFF(u);
748
0
                    if (off >= bitlen ||
749
0
                        ROWS(ais->type8.dac1fid27.waypoints) <= u) {
750
0
                        break;
751
0
                    }
752
0
                    ais->type8.dac1fid27.waypoints[u].lon = SBITS(off + 0, 28);
753
0
                    ais->type8.dac1fid27.waypoints[u].lat = SBITS(off + 28, 27);
754
0
                }
755
0
#undef ARRAY_BASE
756
0
#undef ELEMENT_SIZE
757
0
                ais->type8.structured = true;
758
0
                break;
759
0
            case 29:        // IMO289 - Text Description - broadcast
760
0
                RANGE_CHECK8(66, 1008);
761
0
                ais->type8.dac1fid29.linkage   = UBITS(56, 10);
762
0
                ENDCHARS(66, ais->type8.dac1fid29.text,
763
0
                         sizeof(ais->type8.dac1fid29.text));
764
0
                ais->type8.structured = true;
765
0
                break;
766
0
            case 31:        // IMO289 - Meteorological/Hydrological data
767
                // 368??
768
0
                RANGE_CHECK8(340, 368);
769
0
                ais->type8.dac1fid31.lon        = SBITS(56, 25);
770
0
                ais->type8.dac1fid31.lat        = SBITS(81, 24);
771
0
                ais->type8.dac1fid31.accuracy   = (bool)UBITS(105, 1);
772
0
                ais->type8.dac1fid31.day        = UBITS(106, 5);
773
0
                ais->type8.dac1fid31.hour       = UBITS(111, 5);
774
0
                ais->type8.dac1fid31.minute     = UBITS(116, 6);
775
0
                ais->type8.dac1fid31.wspeed     = UBITS(122, 7);
776
0
                ais->type8.dac1fid31.wgust      = UBITS(129, 7);
777
0
                ais->type8.dac1fid31.wdir       = UBITS(136, 9);
778
0
                ais->type8.dac1fid31.wgustdir   = UBITS(145, 9);
779
0
                ais->type8.dac1fid31.airtemp    = SBITS(154, 11);
780
0
                ais->type8.dac1fid31.humidity   = UBITS(165, 7);
781
0
                ais->type8.dac1fid31.dewpoint   = SBITS(172, 10);
782
0
                ais->type8.dac1fid31.pressure   = UBITS(182, 9);
783
0
                ais->type8.dac1fid31.pressuretend       = UBITS(191, 2);
784
0
                ais->type8.dac1fid31.visgreater = UBITS(193, 1);
785
0
                ais->type8.dac1fid31.visibility = UBITS(194, 7);
786
0
                ais->type8.dac1fid31.waterlevel = UBITS(201, 12);
787
0
                ais->type8.dac1fid31.leveltrend = UBITS(213, 2);
788
0
                ais->type8.dac1fid31.cspeed     = UBITS(215, 8);
789
0
                ais->type8.dac1fid31.cdir       = UBITS(223, 9);
790
0
                ais->type8.dac1fid31.cspeed2    = UBITS(232, 8);
791
0
                ais->type8.dac1fid31.cdir2      = UBITS(240, 9);
792
0
                ais->type8.dac1fid31.cdepth2    = UBITS(249, 5);
793
0
                ais->type8.dac1fid31.cspeed3    = UBITS(254, 8);
794
0
                ais->type8.dac1fid31.cdir3      = UBITS(262, 9);
795
0
                ais->type8.dac1fid31.cdepth3    = UBITS(271, 5);
796
0
                ais->type8.dac1fid31.waveheight = UBITS(276, 8);
797
0
                ais->type8.dac1fid31.waveperiod = UBITS(284, 6);
798
0
                ais->type8.dac1fid31.wavedir    = UBITS(290, 9);
799
0
                ais->type8.dac1fid31.swellheight = UBITS(299, 8);
800
0
                ais->type8.dac1fid31.swellperiod = UBITS(307, 6);
801
0
                ais->type8.dac1fid31.swelldir   = UBITS(313, 9);
802
0
                ais->type8.dac1fid31.seastate   = UBITS(322, 4);
803
0
                ais->type8.dac1fid31.watertemp  = SBITS(326, 10);
804
0
                ais->type8.dac1fid31.preciptype = UBITS(336, 3);
805
0
                ais->type8.dac1fid31.salinity   = UBITS(339, 9);
806
0
                ais->type8.dac1fid31.ice        = UBITS(348, 2);
807
0
                ais->type8.structured = true;
808
0
                break;
809
0
            }
810
0
        } else if (200 == ais->type8.dac) {
811
0
            switch (ais->type8.fid) {
812
0
            case 10:    // Inland ship static and voyage related data
813
                // bitlen = 424??
814
0
                RANGE_CHECK8(168, 424);
815
0
                UCHARS(56, ais->type8.dac200fid10.vin);
816
0
                ais->type8.dac200fid10.length   = UBITS(104, 13);
817
0
                ais->type8.dac200fid10.beam     = UBITS(117, 10);
818
0
                ais->type8.dac200fid10.shiptype = UBITS(127, 14);
819
0
                ais->type8.dac200fid10.hazard   = UBITS(141, 3);
820
0
                ais->type8.dac200fid10.draught  = UBITS(144, 11);
821
0
                ais->type8.dac200fid10.loaded   = UBITS(155, 2);
822
0
                ais->type8.dac200fid10.speed_q  = (bool)UBITS(157, 1);
823
0
                ais->type8.dac200fid10.course_q = (bool)UBITS(158, 1);
824
0
                ais->type8.dac200fid10.heading_q = (bool)UBITS(159, 1);
825
                // skip 8 bits
826
                /*
827
                 * Attempt to prevent false matches with this message type
828
                 * by range-checking certain fields.
829
                 */
830
0
                if (DAC200FID10_HAZARD_MAX < ais->type8.dac200fid10.hazard ||
831
0
                    !isascii((int)ais->type8.dac200fid10.vin[0])) {
832
0
                    ais->type8.structured = false;
833
0
                } else {
834
0
                    ais->type8.structured = true;
835
0
                }
836
0
                break;
837
0
            case 23:    // EMMA warning
838
0
                RANGE_CHECK8(256, 256);
839
0
                ais->type8.dac200fid23.start_year       = UBITS(56, 8);
840
0
                ais->type8.dac200fid23.start_month      = UBITS(64, 4);
841
0
                ais->type8.dac200fid23.start_day        = UBITS(68, 5);
842
0
                ais->type8.dac200fid23.end_year         = UBITS(73, 8);
843
0
                ais->type8.dac200fid23.end_month        = UBITS(81, 4);
844
0
                ais->type8.dac200fid23.end_day          = UBITS(85, 5);
845
0
                ais->type8.dac200fid23.start_hour       = UBITS(90, 5);
846
0
                ais->type8.dac200fid23.start_minute     = UBITS(95, 6);
847
0
                ais->type8.dac200fid23.end_hour         = UBITS(101, 5);
848
0
                ais->type8.dac200fid23.end_minute       = UBITS(106, 6);
849
0
                ais->type8.dac200fid23.start_lon        = SBITS(112, 28);
850
0
                ais->type8.dac200fid23.start_lat        = SBITS(140, 27);
851
0
                ais->type8.dac200fid23.end_lon          = SBITS(167, 28);
852
0
                ais->type8.dac200fid23.end_lat          = SBITS(195, 27);
853
0
                ais->type8.dac200fid23.type             = UBITS(222, 4);
854
0
                ais->type8.dac200fid23.min              = SBITS(226, 9);
855
0
                ais->type8.dac200fid23.max              = SBITS(235, 9);
856
0
                ais->type8.dac200fid23.intensity        = UBITS(244, 2);
857
0
                ais->type8.dac200fid23.wind             = UBITS(246, 4);
858
                // skip 6 bits
859
0
                ais->type8.structured = true;
860
0
                break;
861
0
            case 24:    // Water level
862
0
                RANGE_CHECK8(168, 168);
863
0
                UCHARS(56, ais->type8.dac200fid24.country);
864
0
#define ARRAY_BASE 68
865
0
#define ELEMENT_SIZE 25
866
0
                for (u = 0; ; u++) {
867
0
                    size_t off = OFF(u);
868
0
                    if (off >= bitlen ||
869
0
                        ROWS(ais->type8.dac200fid24.gauges) <= u) {
870
0
                        break;
871
0
                    }
872
0
                    ais->type8.dac200fid24.gauges[u].id = UBITS(off + 0,  11);
873
0
                    ais->type8.dac200fid24.gauges[u].level = SBITS(off + 11,
874
0
                                                                   14);
875
0
                }
876
0
                ais->type8.dac200fid24.ngauges = u;
877
0
#undef ARRAY_BASE
878
0
#undef ELEMENT_SIZE
879
                // skip 6 bits
880
0
                ais->type8.structured = true;
881
0
                break;
882
0
            case 40:    // Signal status
883
0
                RANGE_CHECK8(168, 168);
884
0
                ais->type8.dac200fid40.lon              = SBITS(56, 28);
885
0
                ais->type8.dac200fid40.lat              = SBITS(84, 27);
886
0
                ais->type8.dac200fid40.form             = UBITS(111, 4);
887
0
                ais->type8.dac200fid40.facing           = UBITS(115, 9);
888
0
                ais->type8.dac200fid40.direction        = UBITS(124, 3);
889
0
                ais->type8.dac200fid40.status           = UBITS(127, 30);
890
                // skip 11 bits
891
0
                ais->type8.structured = true;
892
0
                break;
893
0
            }
894
0
        }
895
        // land here if we failed to match a known DAC/FID
896
0
        if (!ais->type8.structured) {
897
0
            size_t number_of_bytes = BITS_TO_BYTES(ais->type8.bitcount);
898
0
            (void)memcpy(ais->type8.bitdata, bits + (56 / CHAR_BIT),
899
0
                         number_of_bytes);
900
0
            size_t valid_bits_in_last_byte = ais->type8.bitcount % CHAR_BIT;
901
0
            if(valid_bits_in_last_byte > 0) {
902
0
                    ais->type8.bitdata[number_of_bytes - 1] &=
903
0
                            (0xFF << (8 - valid_bits_in_last_byte));
904
0
            }
905
0
        }
906
0
        break;
907
0
    case 9: // Standard SAR Aircraft Position Report
908
0
        PERMISSIVE_LENGTH_CHECK(168);
909
0
        ais->type9.alt          = UBITS(38, 12);
910
0
        ais->type9.speed        = UBITS(50, 10);
911
0
        ais->type9.accuracy     = (bool)UBITS(60, 1);
912
0
        ais->type9.lon          = SBITS(61, 28);
913
0
        ais->type9.lat          = SBITS(89, 27);
914
0
        ais->type9.course       = UBITS(116, 12);
915
0
        ais->type9.second       = UBITS(128, 6);
916
0
        ais->type9.regional     = UBITS(134, 8);
917
0
        ais->type9.dte          = UBITS(142, 1);
918
        //ais->type9.spare      = UBITS(143, 3);
919
0
        ais->type9.assigned     = UBITS(146, 1) != 0;
920
0
        ais->type9.raim         = UBITS(147, 1) != 0;
921
0
        ais->type9.radio        = UBITS(148, 20);
922
0
        break;
923
0
    case 10: // UTC/Date inquiry
924
0
        PERMISSIVE_LENGTH_CHECK(72);
925
        //ais->type10.spare        = UBITS(38, 2);
926
0
        ais->type10.dest_mmsi      = UBITS(40, 30);
927
        //ais->type10.spare2       = UBITS(70, 2);
928
0
        break;
929
0
    case 12: // Safety Related Message
930
0
        RANGE_CHECK(72, 1008);
931
0
        ais->type12.seqno          = UBITS(38, 2);
932
0
        ais->type12.dest_mmsi      = UBITS(40, 30);
933
0
        ais->type12.retransmit     = (bool)UBITS(70, 1);
934
        //ais->type12.spare        = UBITS(71, 1);
935
0
        ENDCHARS(72, ais->type12.text, sizeof(ais->type12.text));
936
0
        break;
937
0
    case 14:    // Safety Related Broadcast Message
938
0
        RANGE_CHECK(40, 960);
939
        //ais->type14.spare          = UBITS(38, 2);
940
0
        ENDCHARS(40, ais->type14.text, sizeof(ais->type14.text));
941
0
        break;
942
0
    case 15:    // Interrogation
943
0
        RANGE_CHECK(88, 168);
944
0
        (void)memset(&ais->type15, '\0', sizeof(ais->type15));
945
        //ais->type14.spare         = UBITS(38, 2);
946
0
        ais->type15.mmsi1           = UBITS(40, 30);
947
0
        ais->type15.type1_1         = UBITS(70, 6);
948
0
        ais->type15.offset1_1       = UBITS(76, 12);
949
        //ais->type14.spare2        = UBITS(88, 2);
950
0
        if (90 < bitlen) {
951
0
            ais->type15.type1_2       = UBITS(90, 6);
952
0
            ais->type15.offset1_2     = UBITS(96, 12);
953
            //ais->type14.spare3      = UBITS(108, 2);
954
0
            if (110 < bitlen) {
955
0
                ais->type15.mmsi2       = UBITS(110, 30);
956
0
                ais->type15.type2_1     = UBITS(140, 6);
957
0
                ais->type15.offset2_1   = UBITS(146, 12);
958
                //ais->type14.spare4    = UBITS(158, 2);
959
0
            }
960
0
        }
961
0
        break;
962
0
    case 16:    // Assigned Mode Command
963
0
        RANGE_CHECK(96, 168);
964
0
        ais->type16.mmsi1       = UBITS(40, 30);
965
0
        ais->type16.offset1     = UBITS(70, 12);
966
0
        ais->type16.increment1  = UBITS(82, 10);
967
0
        if (144 > bitlen) {
968
0
            ais->type16.mmsi2=ais->type16.offset2=ais->type16.increment2 = 0;
969
0
        } else {
970
0
            ais->type16.mmsi2   = UBITS(92, 30);
971
0
            ais->type16.offset2 = UBITS(122, 12);
972
0
            ais->type16.increment2      = UBITS(134, 10);
973
0
        }
974
0
        break;
975
0
    case 17:    // GNSS Broadcast Binary Message
976
0
        RANGE_CHECK(80, 816);
977
        //ais->type17.spare     = UBITS(38, 2);
978
0
        ais->type17.lon         = SBITS(40, 18);
979
0
        ais->type17.lat         = SBITS(58, 17);
980
        //ais->type17.spare     = UBITS(75, 5);
981
0
        ais->type17.bitcount    = bitlen - 80;
982
0
        (void)memcpy(ais->type17.bitdata, bits + (80 / CHAR_BIT),
983
0
                     BITS_TO_BYTES(ais->type17.bitcount));
984
0
        break;
985
0
    case 18:    // Standard Class B CS Position Report
986
        // Per https://www.navcen.uscg.gov/ais-class-b-reports
987
0
        PERMISSIVE_LENGTH_CHECK(168)
988
0
        ais->type18.reserved    = UBITS(38, 8);
989
0
        ais->type18.speed       = UBITS(46, 10);
990
0
        ais->type18.accuracy    = UBITS(56, 1) != 0;
991
0
        ais->type18.lon         = SBITS(57, 28);
992
0
        ais->type18.lat         = SBITS(85, 27);
993
0
        ais->type18.course      = UBITS(112, 12);
994
0
        ais->type18.heading     = UBITS(124, 9);
995
0
        ais->type18.second      = UBITS(133, 6);
996
0
        ais->type18.regional    = UBITS(139, 2);
997
0
        ais->type18.cs          = UBITS(141, 1) != 0;
998
0
        ais->type18.display     = UBITS(142, 1) != 0;
999
0
        ais->type18.dsc         = UBITS(143, 1) != 0;
1000
0
        ais->type18.band        = UBITS(144, 1) != 0;
1001
0
        ais->type18.msg22       = UBITS(145, 1) != 0;
1002
0
        ais->type18.assigned    = UBITS(146, 1) != 0;
1003
0
        ais->type18.raim        = UBITS(147, 1) != 0;
1004
0
        ais->type18.radio       = UBITS(148, 20);
1005
0
        break;
1006
0
    case 19:    // Extended Class B CS Position Report
1007
0
        PERMISSIVE_LENGTH_CHECK(312)
1008
0
        ais->type19.reserved     = UBITS(38, 8);
1009
0
        ais->type19.speed        = UBITS(46, 10);
1010
0
        ais->type19.accuracy     = UBITS(56, 1) != 0;
1011
0
        ais->type19.lon          = SBITS(57, 28);
1012
0
        ais->type19.lat          = SBITS(85, 27);
1013
0
        ais->type19.course       = UBITS(112, 12);
1014
0
        ais->type19.heading      = UBITS(124, 9);
1015
0
        ais->type19.second       = UBITS(133, 6);
1016
0
        ais->type19.regional     = UBITS(139, 4);
1017
0
        UCHARS(143, ais->type19.shipname);
1018
0
        ais->type19.shiptype     = UBITS(263, 8);
1019
0
        ais->type19.to_bow       = UBITS(271, 9);
1020
0
        ais->type19.to_stern     = UBITS(280, 9);
1021
0
        ais->type19.to_port      = UBITS(289, 6);
1022
0
        ais->type19.to_starboard = UBITS(295, 6);
1023
0
        ais->type19.epfd         = UBITS(301, 4);
1024
0
        ais->type19.raim         = UBITS(305, 1) != 0;
1025
0
        ais->type19.dte          = UBITS(306, 1) != 0;
1026
0
        ais->type19.assigned     = UBITS(307, 1) != 0;
1027
        //ais->type19.spare      = UBITS(308, 4);
1028
0
        break;
1029
0
    case 20:    // Data Link Management Message
1030
0
        RANGE_CHECK(72, 186);
1031
        //ais->type20.spare     = UBITS(38, 2);
1032
0
        ais->type20.offset1     = UBITS(40, 12);
1033
0
        ais->type20.number1     = UBITS(52, 4);
1034
0
        ais->type20.timeout1    = UBITS(56, 3);
1035
0
        ais->type20.increment1  = UBITS(59, 11);
1036
0
        ais->type20.offset2     = UBITS(70, 12);
1037
0
        ais->type20.number2     = UBITS(82, 4);
1038
0
        ais->type20.timeout2    = UBITS(86, 3);
1039
0
        ais->type20.increment2  = UBITS(89, 11);
1040
0
        ais->type20.offset3     = UBITS(100, 12);
1041
0
        ais->type20.number3     = UBITS(112, 4);
1042
0
        ais->type20.timeout3    = UBITS(116, 3);
1043
0
        ais->type20.increment3  = UBITS(119, 11);
1044
0
        ais->type20.offset4     = UBITS(130, 12);
1045
0
        ais->type20.number4     = UBITS(142, 4);
1046
0
        ais->type20.timeout4    = UBITS(146, 3);
1047
0
        ais->type20.increment4  = UBITS(149, 11);
1048
0
        break;
1049
0
    case 21:    // Aid-to-Navigation Report
1050
        // Per https://www.navcen.uscg.gov/ais-class-b-reports
1051
0
        RANGE_CHECK(272, 368);
1052
0
        ais->type21.aid_type     = UBITS(38, 5);
1053
0
        from_sixbit_untrimmed(errout, bits, bitlen, 43, 20, ais->type21.name,
1054
0
                              sizeof(ais->type21.name));
1055
0
        ais->type21.accuracy     = UBITS(163, 1);
1056
0
        ais->type21.lon          = SBITS(164, 28);
1057
0
        ais->type21.lat          = SBITS(192, 27);
1058
0
        ais->type21.to_bow       = UBITS(219, 9);
1059
0
        ais->type21.to_stern     = UBITS(228, 9);
1060
0
        ais->type21.to_port      = UBITS(237, 6);
1061
0
        ais->type21.to_starboard = UBITS(243, 6);
1062
0
        ais->type21.epfd         = UBITS(249, 4);
1063
0
        ais->type21.second       = UBITS(253, 6);
1064
0
        ais->type21.off_position = UBITS(259, 1)!= 0;
1065
0
        ais->type21.regional     = UBITS(260, 8);
1066
0
        ais->type21.raim         = UBITS(268, 1) != 0;
1067
0
        ais->type21.virtual_aid  = UBITS(269, 1) != 0;
1068
0
        ais->type21.assigned     = UBITS(270, 1) != 0;
1069
        //ais->type21.spare      = UBITS(271, 1);
1070
0
        if (20 == strnlen(ais->type21.name, 21) &&
1071
0
            272 < bitlen) {
1072
0
            ENDCHARS(272, ais->type21.name + 20,
1073
0
                     sizeof(ais->type21.name) - 20);
1074
0
        }
1075
0
        trim_spaces_on_right_end(ais->type21.name, sizeof(ais->type21.name));
1076
0
        break;
1077
0
    case 22:    // Channel Management
1078
0
        PERMISSIVE_LENGTH_CHECK(168)
1079
0
        ais->type22.channel_a    = UBITS(40, 12);
1080
0
        ais->type22.channel_b    = UBITS(52, 12);
1081
0
        ais->type22.txrx         = UBITS(64, 4);
1082
0
        ais->type22.power        = UBITS(68, 1);
1083
0
        ais->type22.addressed    = UBITS(139, 1);
1084
0
        if (!ais->type22.addressed) {
1085
0
            ais->type22.area.ne_lon       = SBITS(69, 18);
1086
0
            ais->type22.area.ne_lat       = SBITS(87, 17);
1087
0
            ais->type22.area.sw_lon       = SBITS(104, 18);
1088
0
            ais->type22.area.sw_lat       = SBITS(122, 17);
1089
0
        } else {
1090
0
            ais->type22.mmsi.dest1        = UBITS(69, 30);
1091
0
            ais->type22.mmsi.dest2        = UBITS(104, 30);
1092
0
        }
1093
0
        ais->type22.band_a       = UBITS(140, 1);
1094
0
        ais->type22.band_b       = UBITS(141, 1);
1095
0
        ais->type22.zonesize     = UBITS(142, 3);
1096
0
        break;
1097
0
    case 23:    // Group Assignment Command
1098
0
        PERMISSIVE_LENGTH_CHECK(160)
1099
0
        ais->type23.ne_lon       = SBITS(40, 18);
1100
0
        ais->type23.ne_lat       = SBITS(58, 17);
1101
0
        ais->type23.sw_lon       = SBITS(75, 18);
1102
0
        ais->type23.sw_lat       = SBITS(93, 17);
1103
0
        ais->type23.stationtype  = UBITS(110, 4);
1104
0
        ais->type23.shiptype     = UBITS(114, 8);
1105
0
        ais->type23.txrx         = UBITS(144, 4);
1106
0
        ais->type23.interval     = UBITS(146, 4);
1107
0
        ais->type23.quiet        = UBITS(150, 4);
1108
0
        break;
1109
0
    case 24:    // Class B CS Static Data Report
1110
0
        switch (UBITS(38, 2)) {
1111
0
        case 0:
1112
0
            RANGE_CHECK(160, 168);
1113
            // save incoming 24A shipname/MMSI pairs in a circular queue
1114
0
            {
1115
0
                struct ais_type24a_t *saveptr =
1116
0
                        &type24_queue->ships[type24_queue->index];
1117
1118
0
                GPSD_LOG(LOG_PROG, errout, "AIVDM: 24A from %09u stashed.\n",
1119
0
                         ais->mmsi);
1120
0
                saveptr->mmsi = ais->mmsi;
1121
0
                UCHARS(40, saveptr->shipname);
1122
0
                ++type24_queue->index;
1123
0
                type24_queue->index %= MAX_TYPE24_INTERLEAVE;
1124
0
            }
1125
            //ais->type24.a.spare       = UBITS(160, 8);
1126
1127
0
            UCHARS(40, ais->type24.shipname);
1128
0
            ais->type24.part = part_a;
1129
0
            return true;
1130
0
        case 1:
1131
0
            PERMISSIVE_LENGTH_CHECK(168)
1132
0
            ais->type24.shiptype = UBITS(40, 8);
1133
            /*
1134
             * In ITU-R 1371-4, there are new model and serial fields
1135
             * carved out of the right-hand end of vendorid, which is
1136
             * reduced from 7 chars to 3.  To cope with older AIS
1137
             * implementations conforming to revision 3 and older,
1138
             * unpack the trailing bits *both* ways; truly
1139
             * revision-4-conformant implementations will have up to
1140
             * four characters of trailing garbage on the vendorid,
1141
             * and older implementations will have garbafe in the
1142
             * model and serial fields.
1143
             */
1144
0
            UCHARS(48, ais->type24.vendorid);
1145
0
            ais->type24.model = UBITS(66, 4);
1146
0
            ais->type24.serial = UBITS(70, 20);
1147
0
            UCHARS(90, ais->type24.callsign);
1148
0
            if (AIS_AUXILIARY_MMSI(ais->mmsi)) {
1149
0
                ais->type24.mothership_mmsi   = UBITS(132, 30);
1150
0
            } else {
1151
0
                ais->type24.dim.to_bow        = UBITS(132, 9);
1152
0
                ais->type24.dim.to_stern      = UBITS(141, 9);
1153
0
                ais->type24.dim.to_port       = UBITS(150, 6);
1154
0
                ais->type24.dim.to_starboard  = UBITS(156, 6);
1155
0
            }
1156
            //ais->type24.b.spare           = UBITS(162, 8);
1157
1158
            // search the 24A queue for a matching MMSI
1159
0
            for (u = 0; u < MAX_TYPE24_INTERLEAVE; u++) {
1160
0
                if (type24_queue->ships[u].mmsi == ais->mmsi) {
1161
0
                    (void)strlcpy(ais->type24.shipname,
1162
0
                                  type24_queue->ships[u].shipname,
1163
0
                                  sizeof(ais->type24.shipname));
1164
0
                    GPSD_LOG(LOG_PROG, errout,
1165
0
                             "AIVDM 24B from %09u matches a 24A.\n",
1166
0
                             ais->mmsi);
1167
                    // prevent false match if a 24B is repeated
1168
0
                    type24_queue->ships[u].mmsi = 0;
1169
0
                    ais->type24.part = both;
1170
0
                    return true;
1171
0
                }
1172
0
            }
1173
1174
            // no match, return Part B
1175
0
            ais->type24.part = part_b;
1176
0
            return true;
1177
0
        default:
1178
0
            GPSD_LOG(LOG_WARN, errout,
1179
0
                     "AIVDM message type 24 of subtype unknown.\n");
1180
0
            return false;
1181
0
        }
1182
        // break;
1183
0
    case 25:    // Binary Message, Single Slot
1184
        // this check and the following one reject line noise
1185
0
        RANGE_CHECK(40, 168);
1186
0
        ais->type25.addressed   = (bool)UBITS(38, 1);
1187
0
        ais->type25.structured  = (bool)UBITS(39, 1);
1188
1189
0
        if (bitlen < (unsigned)(40 + (16 * ais->type25.structured) +
1190
0
                                (30 * ais->type25.addressed))) {
1191
0
            GPSD_LOG(LOG_WARN, errout,
1192
0
                     "AIVDM message type 25 too short for mode.\n");
1193
0
            return false;
1194
0
        }
1195
0
        if (ais->type25.addressed) {
1196
0
            ais->type25.dest_mmsi   = UBITS(40, 30);
1197
0
        }
1198
0
        if (ais->type25.structured) {
1199
0
            ais->type25.app_id      = UBITS(40 + ais->type25.addressed * 30,16);
1200
0
        }
1201
0
        ais->type25.bitcount        = bitlen - 40 - 16 * ais->type25.structured;
1202
        // bit 40 is exactly 5 bytes in; 2 bytes is 16 bits
1203
0
        (void)memcpy(ais->type25.bitdata,
1204
0
                     bits + 5 + 2 * ais->type25.structured,
1205
0
                     BITS_TO_BYTES(ais->type25.bitcount));
1206
        // discard MMSI if addressed
1207
0
        if (ais->type25.addressed) {
1208
0
            shiftleft((unsigned char *)ais->type25.bitdata,
1209
0
                      ais->type25.bitcount, 30);
1210
0
            ais->type25.bitcount -= 30;
1211
0
        }
1212
0
        break;
1213
0
    case 26:    // Binary Message, Multiple Slot
1214
0
        RANGE_CHECK(60, 1004);
1215
0
        ais->type26.addressed   = (bool)UBITS(38, 1);
1216
0
        ais->type26.structured  = (bool)UBITS(39, 1);
1217
0
        if ((signed)bitlen < 40 + 16 * ais->type26.structured +
1218
0
                30 * ais->type26.addressed + 20) {
1219
0
            GPSD_LOG(LOG_WARN, errout,
1220
0
                     "AIVDM message type 26 too short for mode.\n");
1221
0
            return false;
1222
0
        }
1223
0
        if (ais->type26.addressed) {
1224
0
            ais->type26.dest_mmsi = UBITS(40, 30);
1225
0
        }
1226
0
        if (ais->type26.structured) {
1227
0
            ais->type26.app_id    = UBITS(40 + ais->type26.addressed * 30, 16);
1228
0
        }
1229
0
        ais->type26.bitcount      = bitlen - 60 - 16 * ais->type26.structured;
1230
0
        (void)memcpy(ais->type26.bitdata,
1231
0
                     bits + 5 + 2 * ais->type26.structured,
1232
0
                     BITS_TO_BYTES(ais->type26.bitcount));
1233
        // discard MMSI if addressed
1234
0
        if (ais->type26.addressed) {
1235
0
            shiftleft((unsigned char *)ais->type26.bitdata,
1236
0
                      ais->type26.bitcount, 30);
1237
0
            ais->type26.bitcount -= 30;
1238
0
        }
1239
0
        break;
1240
0
    case 27:    // Long Range AIS Broadcast message
1241
0
        RANGE_CHECK(96, 168);
1242
0
        if (96 != bitlen) {
1243
            /*
1244
             * This is an implementation error observed in the wild,
1245
             * sending a full 168-bit slot rather than just 96 bits.
1246
             */
1247
0
            GPSD_LOG(LOG_WARN, errout,
1248
0
                     "oversized 168-bit AIVDM message type 27.\n");
1249
0
        }
1250
0
        ais->type27.accuracy    = (bool)UBITS(38, 1);
1251
0
        ais->type27.raim        = UBITS(39, 1) != 0;
1252
0
        ais->type27.status      = UBITS(40, 4);
1253
0
        ais->type27.lon         = SBITS(44, 18);
1254
0
        ais->type27.lat         = SBITS(62, 17);
1255
0
        ais->type27.speed       = UBITS(79, 6);
1256
0
        ais->type27.course      = UBITS(85, 9);
1257
0
        ais->type27.gnss        = (bool)UBITS(94, 1);
1258
0
        break;
1259
0
    default:
1260
0
        GPSD_LOG(LOG_ERROR, errout,
1261
0
                 "Unparsed AIVDM message type %d.\n",ais->type);
1262
0
        return false;
1263
0
    }
1264
    // *INDENT-ON*
1265
0
#undef UCHARS
1266
0
#undef SBITS
1267
0
#undef UBITS
1268
1269
    // data is fully decoded
1270
0
    return true;
1271
0
}
1272
// vim: set expandtab shiftwidth=4