AIS: Add better handling of non byte aligned data blobs
authorJon Schlueter <jschlueter@redhat.com>
Thu, 8 Oct 2015 01:29:30 +0000 (21:29 -0400)
committerJon Schlueter <jschlueter@redhat.com>
Thu, 8 Oct 2015 01:32:16 +0000 (21:32 -0400)
I ran into a problem with the type 8 unstructured data. When the number
of bits available is not dividable by 8, the last byte may contain
random bits. I would expect the bits beyond the valid range to be 0.

An example of this can be found in the following message:
!AIVDM,3,1,4,A,85PH6TAKfDOkp95`nCRt5w<:qFUiaihFhBc7s4AHGsQ,0*40
!AIVDM,3,2,4,A,DcMJM18k6<=m7rwVm3b5RRWEskwJWej8uP<0:W5K6PA,0*61
!AIVDM,3,3,4,A,gPs<dwulp,4*14

The current version decodes this to:

{"class":"AIS","device":"stdin","type":8,"repeat":0,"mmsi":369493649,"scaled":true,"dac":366,"fid":57,"data":"510:47f3e09168d938bc17f30ae56971a71c16c12ac7ec44585fb854add69d048cc630dd47ebf9b50ea1628a757bcff6a7b7223d80c00a9c56c6811be0eccb3ff74e"}

The 510 bits of data are 63 full bytes and then 6 remaining bits. The
last byte has value: 4e, which is 0100 1110. I would expect 4c, 0100 1100.

To fix this, the following patch could be applied. Please note that the
problem might also be present in other message types, but I have not
encountered any problems in other message types in the 1 million
messages I have in my test dataset. Message types that could be impacted
are: 6, 17, 25 and 26, as they all use the same memcpy to get
unstructured data.

Identified by: Stefan Roels <sroels-gpsd-dev@42solutions.nl>

Added new sample entry to sample.aivdm that exercises this case
Had to regenerate large ais test data log

driver_ais.c
test/daemon/ais-nmea-sample.log.chk
test/sample.aivdm
test/sample.aivdm.chk
test/sample.aivdm.js.chk
test/sample.aivdm.ju.chk

index 535a420..a5c26c0 100644 (file)
@@ -736,10 +736,16 @@ bool ais_binary_decode(const struct gpsd_errout_t *errout,
            }
        }
        /* land here if we failed to match a known DAC/FID */
-       if (!ais->type8.structured)
-           (void)memcpy(ais->type8.bitdata,
-                        (char *)bits + (56 / CHAR_BIT),
-                        BITS_TO_BYTES(ais->type8.bitcount));
+       if (!ais->type8.structured) {
+               size_t number_of_bytes = BITS_TO_BYTES(ais->type8.bitcount);
+               (void)memcpy(ais->type8.bitdata,
+                               (char *)bits + (56 / CHAR_BIT),
+                               number_of_bytes);
+               size_t valid_bits_in_last_byte = ais->type8.bitcount % CHAR_BIT;
+               if(valid_bits_in_last_byte>0)
+                       ais->type8.bitdata[number_of_bytes-1] &= (0xFF
+                                       << (8-valid_bits_in_last_byte));
+       }
        break;
     case 9: /* Standard SAR Aircraft Position Report */
        PERMISSIVE_LENGTH_CHECK(168);
index 773600a..f231862 100644 (file)
 !AIVDM,3,1,7,A,85Mwp=iKfGwushJ?gNlt2QU3osVGe:4?cNhQqf2VH8t,0*08\r
 !AIVDM,3,2,7,A,?A;J6b7AwuiqIGLeNiKCPDR7HQR<u;TTFufegr>kCSF,0*41\r
 !AIVDM,3,3,7,A,Uq:1Kk`e8,4*27\r
-{"class":"AIS","type":8,"repeat":0,"mmsi":366999607,"scaled":false,"dac":366,"fid":57,"data":"510:7ffdef068fbded3c0a1943dfb997b4a10fadec21e6e0a6608f0f44b686a8747ff71e595dcb5ec5b4e05221d886233d2e4916f6eb6fe8ecd38d69792816f3a2d2"}\r
+{"class":"AIS","type":8,"repeat":0,"mmsi":366999607,"scaled":false,"dac":366,"fid":57,"data":"510:7ffdef068fbded3c0a1943dfb997b4a10fadec21e6e0a6608f0f44b686a8747ff71e595dcb5ec5b4e05221d886233d2e4916f6eb6fe8ecd38d69792816f3a2d0"}\r
 !AIVDM,1,1,,A,13`u57hP1?PG5<lMgTU`HgwDR<72,0*4B\r
 {"class":"AIS","type":1,"repeat":0,"mmsi":244270367,"scaled":false,"status":0,"status_text":"Under way using engine","turn":-128,"speed":79,"accuracy":true,"lon":3025306,"lat":31188118,"course":2146,"heading":511,"second":42,"maneuver":1,"raim":true,"radio":49602}\r
 !AIVDM,1,1,,B,13`e>l@P00PHpB4N3Jc5t?wB2HHN,0*1D\r
 {"class":"AIS","type":18,"repeat":0,"mmsi":265666670,"scaled":false,"reserved":0,"speed":63,"accuracy":false,"lon":10873195,"lat":35591080,"course":2773,"heading":511,"second":33,"regional":0,"cs":true,"display":false,"dsc":true,"band":true,"msg22":true,"raim":true,"radio":917510}\r
 !AIVDM,2,1,9,A,85PH9QQKfM5fLwqFUN6j3vi9Ce;nvs?bjGa11dsRJfUacSrAJ4SakTjVVjkFej9D,0*48\r
 !AIVDM,2,2,9,A,AgMm7M@j5D;w1`jwc:9<K815;kwOj:b,4*4D\r
-{"class":"AIS","type":8,"repeat":0,"mmsi":369494406,"scaled":false,"dac":366,"fid":57,"data":"510:d16e73fe5695e1b20fec494ed2f6fbb3eac97a4106cee26ae969ae3e916848e9ce4ca69b2cd6b7225446f7751dd4321542ff068cbfaca24c6c80452f3fdfc8aa"}\r
+{"class":"AIS","type":8,"repeat":0,"mmsi":369494406,"scaled":false,"dac":366,"fid":57,"data":"510:d16e73fe5695e1b20fec494ed2f6fbb3eac97a4106cee26ae969ae3e916848e9ce4ca69b2cd6b7225446f7751dd4321542ff068cbfaca24c6c80452f3fdfc8a8"}\r
 !AIVDM,1,1,,B,16:epf@P148KS@PFCtaT@gw2@0S6,0*7D\r
 {"class":"AIS","type":1,"repeat":0,"mmsi":413890745,"scaled":false,"status":0,"status_text":"Under way using engine","turn":-128,"speed":68,"accuracy":false,"lon":70720016,"lat":23395494,"course":1090,"heading":511,"second":33,"maneuver":0,"raim":false,"radio":2246}\r
 !AIVDM,1,1,,A,133s1>PP15PD@9rMdbr3?Ow22@Cb,0*1C\r
index 2f16aa7..ebc1b43 100644 (file)
@@ -1059,3 +1059,9 @@ AIVDM,2,2,1,B,00000000000,2*26
 # type 6 with unhandled type
 !AIVDM,1,1,,A,601uEPprEH2@<P<j00,4*32
 #{"class":"AIS","device":"stdin","type":6,"repeat":0,"mmsi":2053507,"scaled":true,"seqno":2,"dest_mmsi":244670500,"retransmit":false,"dac":200,"fid":3,"data":"16:3200"}
+#
+# Handle bad padding at the end of type 8 with non byte aligned data blob
+!AIVDM,3,1,7,A,85Mwp=iKfGwushJ?gNlt2QU3osVGe:4?cNhQqf2VH8t,0*08
+!AIVDM,3,2,7,A,?A;J6b7AwuiqIGLeNiKCPDR7HQR<u;TTFufegr>kCSF,0*41
+!AIVDM,3,3,7,A,Uq:1Kk`e8,4*27
+# {"class":"AIS","type":8,"repeat":0,"mmsi":366999607,"scaled":false,"dac":366,"fid":57,"data":"510:7ffdef068fbded3c0a1943dfb997b4a10fadec21e6e0a6608f0f44b686a8747ff71e595dcb5ec5b4e05221d886233d2e4916f6eb6fe8ecd38d69792816f3a2d0"}
index 0b51472..bee2d76 100644 (file)
@@ -85,3 +85,4 @@
 8|1|002300059|1|11|1325788|3622678|20T18:28Z|12|14|92|84|586|90|1023|228|2|255|511|3|255|511|255|511|31|255|511|31|255|63|511|255|63|511|15|1023|7|511|3\r
 8|0|002766080|1|11|1382800|3532000|20T18:30Z|0|0|0|0|0|0|0|0|0|0|0|0|255|0|0|0|0|0|0|0|0|3|0|0|0|0|0|1|0|0|0\r
 6|0|002053507|2|244670500|0|200|3|16:3200\r
+8|0|366999607|366|57|510:7ffdef068fbded3c0a1943dfb997b4a10fadec21e6e0a6608f0f44b686a8747ff71e595dcb5ec5b4e05221d886233d2e4916f6eb6fe8ecd38d69792816f3a2d0\r
index 82231dc..4d6b80c 100644 (file)
@@ -85,3 +85,4 @@
 {"class":"AIS","device":"stdin","type":8,"repeat":1,"mmsi":2300059,"scaled":true,"dac":1,"fid":11,"lat":60.378,"lon":22.096,"timestamp":"20T18:28Z","wspeed":12,"wgust":14,"wdir":92,"wgustdir":84,"humidity":90,"airtemp":-1.4,"dewpoint":82.3,"pressure":1028,"pressuretend":"decreasing","visibility":25.5,"waterlevel":41.1,"leveltrend":"N/A","cspeed":25.5,"cdir":511,"cspeed2":25.5,"cdir2":511,"cdepth2":31,"cspeed3":25.5,"cdir3":511,"cdepth3":31,"waveheight":25.5,"waveperiod":63,"wavedir":511,"swellheight":25.5,"swellperiod":63,"swelldir":511,"seastate":15,"watertemp":92.3,"preciptype":7,"preciptype_text":"N/A","salinity":51.1,"ice":3,"ice_text":"N/A"}\r
 {"class":"AIS","device":"stdin","type":8,"repeat":0,"mmsi":2766080,"scaled":true,"dac":1,"fid":11,"lat":58.867,"lon":23.047,"timestamp":"20T18:30Z","wspeed":0,"wgust":0,"wdir":0,"wgustdir":0,"humidity":0,"airtemp":-60.0,"dewpoint":-20.0,"pressure":800,"pressuretend":"steady","visibility":0.0,"waterlevel":-10.0,"leveltrend":"steady","cspeed":25.5,"cdir":0,"cspeed2":0.0,"cdir2":0,"cdepth2":0,"cspeed3":0.0,"cdir3":0,"cdepth3":0,"waveheight":0.0,"waveperiod":3,"wavedir":0,"swellheight":0.0,"swellperiod":0,"swelldir":0,"seastate":0,"watertemp":-9.9,"preciptype":0,"preciptype_text":"reserved","salinity":0.0,"ice":0,"ice_text":"no"}\r
 {"class":"AIS","device":"stdin","type":6,"repeat":0,"mmsi":2053507,"scaled":true,"seqno":2,"dest_mmsi":244670500,"retransmit":false,"dac":200,"fid":3,"data":"16:3200"}\r
+{"class":"AIS","device":"stdin","type":8,"repeat":0,"mmsi":366999607,"scaled":true,"dac":366,"fid":57,"data":"510:7ffdef068fbded3c0a1943dfb997b4a10fadec21e6e0a6608f0f44b686a8747ff71e595dcb5ec5b4e05221d886233d2e4916f6eb6fe8ecd38d69792816f3a2d0"}\r
index 134bada..3864e65 100644 (file)
@@ -85,3 +85,4 @@
 {"class":"AIS","device":"stdin","type":8,"repeat":1,"mmsi":2300059,"scaled":false,"dac":1,"fid":11,"lat":3622678,"lon":1325788,"timestamp":"20T18:28Z","wspeed":12,"wgust":14,"wdir":92,"wgustdir":84,"humidity":90,"airtemp":586,"dewpoint":1023,"pressure":228,"pressuretend":2,"visibility":255,"waterlevel":511,"leveltrend":3,"cspeed":255,"cdir":511,"cspeed2":255,"cdir2":511,"cdepth2":31,"cspeed3":255,"cdir3":511,"cdepth3":31,"waveheight":255,"waveperiod":63,"wavedir":511,"swellheight":255,"swellperiod":63,"swelldir":511,"seastate":15,"watertemp":1023,"preciptype":7,"preciptype_text":"N/A","salinity":511,"ice":3,"ice_text":"N/A"}\r
 {"class":"AIS","device":"stdin","type":8,"repeat":0,"mmsi":2766080,"scaled":false,"dac":1,"fid":11,"lat":3532000,"lon":1382800,"timestamp":"20T18:30Z","wspeed":0,"wgust":0,"wdir":0,"wgustdir":0,"humidity":0,"airtemp":0,"dewpoint":0,"pressure":0,"pressuretend":0,"visibility":0,"waterlevel":0,"leveltrend":0,"cspeed":255,"cdir":0,"cspeed2":0,"cdir2":0,"cdepth2":0,"cspeed3":0,"cdir3":0,"cdepth3":0,"waveheight":0,"waveperiod":3,"wavedir":0,"swellheight":0,"swellperiod":0,"swelldir":0,"seastate":0,"watertemp":1,"preciptype":0,"preciptype_text":"reserved","salinity":0,"ice":0,"ice_text":"no"}\r
 {"class":"AIS","device":"stdin","type":6,"repeat":0,"mmsi":2053507,"scaled":false,"seqno":2,"dest_mmsi":244670500,"retransmit":false,"dac":200,"fid":3,"data":"16:3200"}\r
+{"class":"AIS","device":"stdin","type":8,"repeat":0,"mmsi":366999607,"scaled":false,"dac":366,"fid":57,"data":"510:7ffdef068fbded3c0a1943dfb997b4a10fadec21e6e0a6608f0f44b686a8747ff71e595dcb5ec5b4e05221d886233d2e4916f6eb6fe8ecd38d69792816f3a2d0"}\r