@@ -172,6 +172,10 @@ void PcapngImportFilter::OnFileNameChanged()
172
172
173
173
switch (m_linkType)
174
174
{
175
+ case LINK_TYPE_SOCKETCAN:
176
+ LoadSocketCAN (fp);
177
+ break ;
178
+
175
179
case LINK_TYPE_LINUX_COOKED:
176
180
// Linux cooked encapsulation is special: we don't know the output data format initially
177
181
// and there can be a mix of several which we don't currently implement!
@@ -185,6 +189,219 @@ void PcapngImportFilter::OnFileNameChanged()
185
189
fclose (fp);
186
190
}
187
191
192
+ // TODO: this shares a lot in common with LoadCANLinuxCooked, how can we share more?
193
+ bool PcapngImportFilter::LoadSocketCAN (FILE* fp)
194
+ {
195
+ LogTrace (" Loading SocketCAN packets\n " );
196
+ LogIndenter li;
197
+
198
+ // Create output waveform
199
+ auto cap = new CANWaveform;
200
+ cap->m_timescale = 1 ;
201
+ cap->m_triggerPhase = 0 ;
202
+ cap->PrepareForCpuAccess ();
203
+ SetData (cap, 0 );
204
+
205
+ bool first = true ;
206
+ int64_t baseTimestamp = 0 ;
207
+
208
+ // Calculate length of a single bit on the bus
209
+ int64_t baud = m_parameters[m_datarate].GetIntVal ();
210
+ int64_t ui = FS_PER_SECOND / baud;
211
+
212
+ uint32_t blocktype;
213
+ uint32_t blocklen;
214
+ int64_t tend = 0 ;
215
+ while (!feof (fp))
216
+ {
217
+ auto blockstart = ftell (fp);
218
+
219
+ if (1 != fread (&blocktype, sizeof (blocktype), 1 , fp))
220
+ return false ;
221
+ if (1 != fread (&blocklen, sizeof (blocklen), 1 , fp))
222
+ return false ;
223
+
224
+ // Should be an EPB, ignore anything else
225
+ switch (blocktype)
226
+ {
227
+ case 5 :
228
+ LogTrace (" Found Block Statistics (%d bytes)\n " , blocklen);
229
+ fseek (fp, blockstart + blocklen, SEEK_SET);
230
+ continue ;
231
+
232
+ case 6 :
233
+ // LogTrace("Found EPB (%d bytes)\n", blocklen);
234
+ break ;
235
+
236
+ default :
237
+ // unknown type, wut?
238
+ LogWarning (" unknown block type %d\n " , blocktype);
239
+ fseek (fp, blockstart + blocklen, SEEK_SET);
240
+ continue ;
241
+ }
242
+ LogIndenter li2;
243
+
244
+ // //////////////////////////////////////////////////////////////////////////////////////////////////////////////
245
+ // PCAPNG EPB headers
246
+
247
+ // For now, ignore interface number since we don't support mixed captures or multiple output streams yet
248
+ uint32_t ifacenum;
249
+ if (1 != fread (&ifacenum, sizeof (ifacenum), 1 , fp))
250
+ return false ;
251
+ // LogTrace("Interface %u\n", ifacenum);
252
+
253
+ // Timestamp
254
+ uint32_t tstamp[2 ];
255
+ if (2 != fread (tstamp, sizeof (uint32_t ), 2 , fp))
256
+ return false ;
257
+
258
+ // Convert from packed format in native units to a single 64-bit integer
259
+ int64_t stamp = tstamp[0 ];
260
+ stamp = (stamp << 32 ) | tstamp[1 ];
261
+
262
+ // If this is the FIRST packet in the capture, it's the base timestamp and we measure offsets from that
263
+ if (first)
264
+ {
265
+ baseTimestamp = stamp;
266
+ stamp = 0 ;
267
+ first = false ;
268
+
269
+ // Convert base timestamp to seconds and fs
270
+ int64_t ticks_per_fs = FS_PER_SECOND / m_timestampScale;
271
+ cap->m_startTimestamp = baseTimestamp / ticks_per_fs;
272
+ cap->m_startFemtoseconds = m_timestampScale * (baseTimestamp % ticks_per_fs);
273
+ }
274
+
275
+ // Not first, use relative offset
276
+ else
277
+ stamp -= baseTimestamp;
278
+
279
+ // Convert from native units to fs
280
+ stamp *= m_timestampScale;
281
+
282
+ // Actual as-captured packet length
283
+ uint32_t packlen;
284
+ if (1 != fread (&packlen, sizeof (packlen), 1 , fp))
285
+ return false ;
286
+ if (packlen < 16 )
287
+ {
288
+ LogWarning (" Invalid packet length %d (should be >= 16 to allow room for cooked headers)\n " , packlen);
289
+ fseek (fp, blockstart + blocklen, SEEK_SET);
290
+ continue ;
291
+ }
292
+
293
+ // Original packet length (might have been truncated, but ignore this)
294
+ uint32_t origlen;
295
+ if (1 != fread (&origlen, sizeof (origlen), 1 , fp))
296
+ return false ;
297
+
298
+ // Timestamps sometimes have some jitter due to USB dongles combining several into one transaction,
299
+ // without logging actual arrival timestamps. So they can appear to be coming at too high a baud rate.
300
+ // Fudge the timestamp if it claims to have come before the previous frame ended
301
+ if (stamp < tend)
302
+ stamp = tend;
303
+
304
+ // Read CAN ID (32 bit on wire)
305
+ uint32_t id;
306
+ if (1 != fread (&id, sizeof (id), 1 , fp))
307
+ return false ;
308
+ id = ntohl (id);
309
+
310
+ // Read frame length
311
+ uint8_t nbytes;
312
+ if (1 != fread (&nbytes, sizeof (nbytes), 1 , fp))
313
+ return false ;
314
+ if (nbytes > 8 )
315
+ {
316
+ LogWarning (" Invalid DLC %d (should be <= 8)\n " , nbytes);
317
+ fseek (fp, blockstart + blocklen, SEEK_SET);
318
+ continue ;
319
+ }
320
+
321
+ // Skip 3 bytes of FD flags / reserved before the payload
322
+ fseek (fp, 3 , SEEK_CUR);
323
+
324
+ // Read payload
325
+ uint8_t data[8 ];
326
+ if (nbytes != fread (data, 1 , nbytes, fp))
327
+ return false ;
328
+
329
+ // Extract header bits (packed in with ID)
330
+ bool ext = (id & 0x80000000 );
331
+ bool rtr = (id & 0x40000000 );
332
+ bool err = (id & 0x20000000 );
333
+ id &= 0x1fffffff ;
334
+ bool fd = false ;// (proto == 0x0d);
335
+
336
+ // Add timeline samples
337
+ cap->m_offsets .push_back (stamp);
338
+ cap->m_durations .push_back (ui);
339
+ cap->m_samples .push_back (CANSymbol (CANSymbol::TYPE_SOF, 0 ));
340
+
341
+ cap->m_offsets .push_back (stamp + ui);
342
+ cap->m_durations .push_back (31 * ui);
343
+ cap->m_samples .push_back (CANSymbol (CANSymbol::TYPE_ID, id));
344
+
345
+ cap->m_offsets .push_back (stamp + 32 *ui);
346
+ cap->m_durations .push_back (ui);
347
+ cap->m_samples .push_back (CANSymbol (CANSymbol::TYPE_RTR, rtr));
348
+
349
+ cap->m_offsets .push_back (stamp + 33 *ui);
350
+ cap->m_durations .push_back (ui);
351
+ cap->m_samples .push_back (CANSymbol (CANSymbol::TYPE_FD, fd));
352
+
353
+ cap->m_offsets .push_back (stamp + 34 *ui);
354
+ cap->m_durations .push_back (ui);
355
+ cap->m_samples .push_back (CANSymbol (CANSymbol::TYPE_R0, 0 ));
356
+
357
+ cap->m_offsets .push_back (stamp + 35 *ui);
358
+ cap->m_durations .push_back (ui*4 );
359
+ cap->m_samples .push_back (CANSymbol (CANSymbol::TYPE_DLC, nbytes));
360
+
361
+ // Data
362
+ for (size_t i=0 ; i<nbytes; i++)
363
+ {
364
+ cap->m_offsets .push_back (stamp + 39 *ui + i*8 *ui);
365
+ cap->m_durations .push_back (ui*8 );
366
+ cap->m_samples .push_back (CANSymbol (CANSymbol::TYPE_DATA, data[i]));
367
+ }
368
+
369
+ tend = stamp + 39 *ui + nbytes*8 *ui;
370
+
371
+ // CRC TODO
372
+ // CRC delim TODO
373
+ // ACK TODO
374
+ // ACK delim TODO
375
+
376
+ // Add the packet
377
+ // Fake the duration for now: assume 8 bytes payload, extended format, and no stuffing
378
+ // Leave format/type/ack blank, this doesn't seem to be saved in this capture format
379
+ auto pack = new Packet;
380
+ if (err)
381
+ pack->m_displayBackgroundColor = m_backgroundColors[PROTO_COLOR_ERROR];
382
+ else if (rtr)
383
+ pack->m_displayBackgroundColor = m_backgroundColors[PROTO_COLOR_DATA_READ];
384
+ else
385
+ pack->m_displayBackgroundColor = m_backgroundColors[PROTO_COLOR_DATA_WRITE];
386
+ pack->m_headers [" Format" ] = ext ? " EXT" : " BASE" ;
387
+ pack->m_headers [" ID" ] = to_string_hex (id);
388
+ pack->m_headers [" Mode" ] = fd ? " CAN-FD" : " CAN" ;
389
+ pack->m_headers [" Len" ] = to_string (nbytes);
390
+ if (err)
391
+ pack->m_headers [" Format" ] = " ERR" ;
392
+ for (size_t i=0 ; i<nbytes; i++)
393
+ pack->m_data .push_back (data[i]);
394
+ pack->m_offset = stamp;
395
+ pack->m_len = 128 * ui;
396
+ m_packets.push_back (pack);
397
+
398
+ // End of the EPB, skip any unread contents
399
+ fseek (fp, blockstart + blocklen, SEEK_SET);
400
+ }
401
+
402
+ return true ;
403
+ }
404
+
188
405
bool PcapngImportFilter::LoadLinuxCooked (FILE* fp)
189
406
{
190
407
LogTrace (" Loading Linux cooked format packets\n " );
@@ -526,6 +743,11 @@ bool PcapngImportFilter::ReadIDB(FILE* fp)
526
743
m_linkType = LINK_TYPE_CAN;
527
744
break ;
528
745
746
+ case 227 :
747
+ LogTrace (" SocketCAN data\n " );
748
+ m_linkType = LINK_TYPE_SOCKETCAN;
749
+ break ;
750
+
529
751
default :
530
752
LogWarning (" PcapNG contains unknown type data %d\n " , linktype);
531
753
m_linkType = LINK_TYPE_UNKNOWN;
0 commit comments