1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:critical reason:data-parser
4
5#include "socketcanbackend.h"
6
7#include "libsocketcan.h"
8
9#include <QtSerialBus/qcanbusdevice.h>
10
11#include <QtCore/qdatastream.h>
12#include <QtCore/qdebug.h>
13#include <QtCore/qdiriterator.h>
14#include <QtCore/qfile.h>
15#include <QtCore/qloggingcategory.h>
16#include <QtCore/qsocketnotifier.h>
17
18#include <linux/can/error.h>
19#include <linux/can/raw.h>
20#include <linux/sockios.h>
21#include <errno.h>
22#include <unistd.h>
23#include <net/if.h>
24#include <sys/ioctl.h>
25#include <sys/time.h>
26
27#ifndef CANFD_BRS
28# define CANFD_BRS 0x01 /* bit rate switch (second bitrate for payload data) */
29#endif
30#ifndef CANFD_ESI
31# define CANFD_ESI 0x02 /* error state indicator of the transmitting node */
32#endif
33
34QT_BEGIN_NAMESPACE
35
36Q_DECLARE_LOGGING_CATEGORY(QT_CANBUS_PLUGINS_SOCKETCAN)
37
38const char sysClassNetC[] = "/sys/class/net/";
39const char interfaceC[] = "/device/interface";
40const char devIdC[] = "/dev_id";
41const char flagsC[] = "/flags";
42const char mtuC[] = "/mtu";
43const char typeC[] = "/type";
44const char virtualC[] = "virtual";
45
46enum {
47 CanFlexibleDataRateMtu = 72,
48 TypeSocketCan = 280,
49 DeviceIsActive = 1
50};
51
52static QByteArray fileContent(const QString &fileName)
53{
54 QFile file(fileName);
55 if (!file.open(flags: QIODevice::ReadOnly))
56 return QByteArray();
57
58 return file.readAll().trimmed();
59}
60
61static bool isFlexibleDataRateCapable(const QString &canDevice)
62{
63 const QString path = QLatin1String(sysClassNetC) + canDevice + QLatin1String(mtuC);
64 const int mtu = fileContent(fileName: path).toInt();
65 return mtu == CanFlexibleDataRateMtu;
66}
67
68static bool isVirtual(const QString &canDevice)
69{
70 const QFileInfo fi(QLatin1String(sysClassNetC) + canDevice);
71 return fi.canonicalPath().contains(s: QLatin1String(virtualC));
72}
73
74static quint32 flags(const QString &canDevice)
75{
76 const QString path = QLatin1String(sysClassNetC) + canDevice + QLatin1String(flagsC);
77 const quint32 result = fileContent(fileName: path).toUInt(ok: nullptr, base: 0);
78 return result;
79}
80
81static QString deviceDescription(const QString &canDevice)
82{
83 const QString path = QLatin1String(sysClassNetC) + canDevice + QLatin1String(interfaceC);
84 const QByteArray content = fileContent(fileName: path);
85 if (content.isEmpty() && isVirtual(canDevice))
86 return QStringLiteral("Virtual CAN");
87
88 return QString::fromUtf8(ba: content);
89}
90
91static int deviceChannel(const QString &canDevice)
92{
93 const QString path = QLatin1String(sysClassNetC) + canDevice + QLatin1String(devIdC);
94 const QByteArray content = fileContent(fileName: path);
95 return content.toInt(ok: nullptr, base: 0);
96}
97
98QCanBusDeviceInfo SocketCanBackend::socketCanDeviceInfo(const QString &deviceName)
99{
100 const QString serial; // exists for code readability purposes only
101 const QString alias; // exists for code readability purposes only
102 const QString description = deviceDescription(canDevice: deviceName);
103 const int channel = deviceChannel(canDevice: deviceName);
104 return createDeviceInfo(QStringLiteral("socketcan"), name: deviceName,
105 serialNumber: serial, description,
106 alias, channel, isVirtual: isVirtual(canDevice: deviceName),
107 isFlexibleDataRateCapable: isFlexibleDataRateCapable(canDevice: deviceName));
108}
109
110QList<QCanBusDeviceInfo> SocketCanBackend::interfaces()
111{
112 QList<QCanBusDeviceInfo> result;
113 QDirIterator it(sysClassNetC,
114 QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot,
115 QDirIterator::Subdirectories);
116
117 while (it.hasNext()) {
118 const QString dirEntry = it.next();
119 if (fileContent(fileName: dirEntry + QLatin1String(typeC)).toInt() != TypeSocketCan)
120 continue;
121
122 const QString deviceName = dirEntry.mid(position: strlen(s: sysClassNetC));
123 if (!(flags(canDevice: deviceName) & DeviceIsActive))
124 continue;
125
126 result.append(t: socketCanDeviceInfo(deviceName));
127 }
128
129 std::sort(first: result.begin(), last: result.end(),
130 comp: [](const QCanBusDeviceInfo &a, const QCanBusDeviceInfo &b) {
131 return a.name() < b.name();
132 });
133
134 return result;
135}
136
137QCanBusDeviceInfo SocketCanBackend::deviceInfo() const
138{
139 return socketCanDeviceInfo(deviceName: canSocketName);
140}
141
142SocketCanBackend::SocketCanBackend(const QString &name) :
143 canSocketName(name)
144{
145 QString errorString;
146 libSocketCan.reset(p: new LibSocketCan(&errorString));
147 if (Q_UNLIKELY(!errorString.isEmpty())) {
148 qCInfo(QT_CANBUS_PLUGINS_SOCKETCAN,
149 "Cannot load library libsocketcan, some functionality will not be available.\n%ls",
150 qUtf16Printable(errorString));
151 }
152
153 resetConfigurations();
154}
155
156SocketCanBackend::~SocketCanBackend()
157{
158 close();
159}
160
161void SocketCanBackend::resetConfigurations()
162{
163 QCanBusDevice::setConfigurationParameter(
164 key: QCanBusDevice::LoopbackKey, value: true);
165 QCanBusDevice::setConfigurationParameter(
166 key: QCanBusDevice::ReceiveOwnKey, value: false);
167 QCanBusDevice::setConfigurationParameter(
168 key: QCanBusDevice::ErrorFilterKey,
169 value: QVariant::fromValue(value: QCanBusFrame::FrameErrors(QCanBusFrame::AnyError)));
170 QCanBusDevice::setConfigurationParameter(
171 key: QCanBusDevice::CanFdKey, value: false);
172 QCanBusDevice::setConfigurationParameter(
173 key: QCanBusDevice::BitRateKey, value: QVariant());
174}
175
176bool SocketCanBackend::open()
177{
178 if (canSocket == -1) {
179 if (!connectSocket()) {
180 close(); // sets UnconnectedState
181 return false;
182 }
183 }
184
185 setState(QCanBusDevice::ConnectedState);
186 return true;
187}
188
189void SocketCanBackend::close()
190{
191 ::close(fd: canSocket);
192 canSocket = -1;
193
194 setState(QCanBusDevice::UnconnectedState);
195}
196
197bool SocketCanBackend::applyConfigurationParameter(ConfigurationKey key, const QVariant &value)
198{
199 bool success = false;
200
201 switch (key) {
202 case QCanBusDevice::LoopbackKey:
203 {
204 const int loopback = value.toBool() ? 1 : 0;
205 if (Q_UNLIKELY(setsockopt(canSocket, SOL_CAN_RAW, CAN_RAW_LOOPBACK,
206 &loopback, sizeof(loopback)) < 0)) {
207 setError(errorText: qt_error_string(errno),
208 QCanBusDevice::CanBusError::ConfigurationError);
209 break;
210 }
211 success = true;
212 break;
213 }
214 case QCanBusDevice::ReceiveOwnKey:
215 {
216 const int receiveOwnMessages = value.toBool() ? 1 : 0;
217 if (Q_UNLIKELY(setsockopt(canSocket, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS,
218 &receiveOwnMessages, sizeof(receiveOwnMessages)) < 0)) {
219 setError(errorText: qt_error_string(errno),
220 QCanBusDevice::CanBusError::ConfigurationError);
221 break;
222 }
223 success = true;
224 break;
225 }
226 case QCanBusDevice::ErrorFilterKey:
227 {
228 const int errorMask = value.value<QCanBusFrame::FrameErrors>();
229 if (Q_UNLIKELY(setsockopt(canSocket, SOL_CAN_RAW, CAN_RAW_ERR_FILTER,
230 &errorMask, sizeof(errorMask)) < 0)) {
231 setError(errorText: qt_error_string(errno),
232 QCanBusDevice::CanBusError::ConfigurationError);
233 break;
234 }
235 success = true;
236 break;
237 }
238 case QCanBusDevice::RawFilterKey:
239 {
240 const QList<QCanBusDevice::Filter> filterList
241 = value.value<QList<QCanBusDevice::Filter> >();
242 if (!value.isValid() || filterList.isEmpty()) {
243 // permit every frame - no restrictions (filter reset)
244 can_filter filters = {.can_id: 0, .can_mask: 0};
245 socklen_t s = sizeof(can_filter);
246 if (Q_UNLIKELY(setsockopt(canSocket, SOL_CAN_RAW, CAN_RAW_FILTER,
247 &filters, s) != 0)) {
248 qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "Cannot unset socket filters.");
249 setError(errorText: qt_error_string(errno),
250 QCanBusDevice::CanBusError::ConfigurationError);
251 break;
252 }
253 success = true;
254 break;
255 }
256
257 QList<can_filter> filters;
258 filters.resize(size: filterList.size());
259 for (int i = 0; i < filterList.size(); i++) {
260 const QCanBusDevice::Filter f = filterList.at(i);
261 can_filter filter = { .can_id: f.frameId, .can_mask: f.frameIdMask };
262
263 // frame type filter
264 switch (f.type) {
265 default:
266 // any other type cannot be filtered upon
267 setError(errorText: tr(s: "Cannot set filter for frame type: %1").arg(a: f.type),
268 QCanBusDevice::CanBusError::ConfigurationError);
269 return false;
270 case QCanBusFrame::InvalidFrame:
271 break;
272 case QCanBusFrame::DataFrame:
273 filter.can_mask |= CAN_RTR_FLAG;
274 break;
275 case QCanBusFrame::ErrorFrame:
276 filter.can_mask |= CAN_ERR_FLAG;
277 filter.can_id |= CAN_ERR_FLAG;
278 break;
279 case QCanBusFrame::RemoteRequestFrame:
280 filter.can_mask |= CAN_RTR_FLAG;
281 filter.can_id |= CAN_RTR_FLAG;
282 break;
283 }
284
285 // frame format filter
286 if ((f.format & QCanBusDevice::Filter::MatchBaseAndExtendedFormat)
287 == QCanBusDevice::Filter::MatchBaseAndExtendedFormat) {
288 // nothing
289 } else if (f.format & QCanBusDevice::Filter::MatchBaseFormat) {
290 filter.can_mask |= CAN_EFF_FLAG;
291 } else if (f.format & QCanBusDevice::Filter::MatchExtendedFormat) {
292 filter.can_mask |= CAN_EFF_FLAG;
293 filter.can_id |= CAN_EFF_FLAG;
294 }
295
296 filters[i] = filter;
297 }
298 if (Q_UNLIKELY(setsockopt(canSocket, SOL_CAN_RAW, CAN_RAW_FILTER,
299 filters.constData(), sizeof(filters[0]) * filters.size()) < 0)) {
300 setError(errorText: qt_error_string(errno),
301 QCanBusDevice::CanBusError::ConfigurationError);
302 break;
303 }
304 success = true;
305 break;
306 }
307 case QCanBusDevice::CanFdKey:
308 {
309 const int fd_frames = value.toBool() ? 1 : 0;
310 if (Q_UNLIKELY(setsockopt(canSocket, SOL_CAN_RAW, CAN_RAW_FD_FRAMES,
311 &fd_frames, sizeof(fd_frames)) < 0)) {
312 setError(errorText: qt_error_string(errno),
313 QCanBusDevice::CanBusError::ConfigurationError);
314 break;
315 }
316 success = true;
317 break;
318 }
319 case QCanBusDevice::BitRateKey:
320 {
321 if (!value.isNull()) {
322 const quint32 bitRate = value.toUInt();
323 success = libSocketCan->setBitrate(interface: canSocketName, bitrate: bitRate);
324 }
325 break;
326 }
327 default:
328 setError(errorText: tr(s: "Unsupported configuration key: %1").arg(a: key),
329 QCanBusDevice::CanBusError::ConfigurationError);
330 break;
331 }
332
333 return success;
334}
335
336bool SocketCanBackend::connectSocket()
337{
338 struct ifreq interface;
339
340 if (Q_UNLIKELY((canSocket = socket(PF_CAN, SOCK_RAW | SOCK_NONBLOCK, protocol)) < 0)) {
341 setError(errorText: qt_error_string(errno),
342 QCanBusDevice::CanBusError::ConnectionError);
343 return false;
344 }
345
346 qstrncpy(dst: interface.ifr_name, src: canSocketName.toLatin1().constData(), len: sizeof(interface.ifr_name));
347 if (Q_UNLIKELY(ioctl(canSocket, SIOCGIFINDEX, &interface) < 0)) {
348 setError(errorText: qt_error_string(errno),
349 QCanBusDevice::CanBusError::ConnectionError);
350 return false;
351 }
352
353 m_address.can_family = AF_CAN;
354 m_address.can_ifindex = interface.ifr_ifindex;
355
356 if (Q_UNLIKELY(bind(canSocket, reinterpret_cast<struct sockaddr *>(&m_address), sizeof(m_address)) < 0)) {
357 setError(errorText: qt_error_string(errno),
358 QCanBusDevice::CanBusError::ConnectionError);
359 return false;
360 }
361
362 m_iov.iov_base = &m_frame;
363 m_msg.msg_name = &m_address;
364 m_msg.msg_iov = &m_iov;
365 m_msg.msg_iovlen = 1;
366 m_msg.msg_control = &m_ctrlmsg;
367
368 delete notifier;
369
370 notifier = new QSocketNotifier(canSocket, QSocketNotifier::Read, this);
371 connect(sender: notifier, signal: &QSocketNotifier::activated,
372 context: this, slot: &SocketCanBackend::readSocket);
373
374 //apply all stored configurations
375 const auto keys = configurationKeys();
376 for (ConfigurationKey key : keys) {
377 const QVariant param = configurationParameter(key);
378 bool success = applyConfigurationParameter(key, value: param);
379 if (Q_UNLIKELY(!success)) {
380 qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "Cannot apply parameter: %d with value: %ls.",
381 key, qUtf16Printable(param.toString()));
382 }
383 }
384
385 return true;
386}
387
388void SocketCanBackend::setConfigurationParameter(ConfigurationKey key, const QVariant &value)
389{
390 if (key == QCanBusDevice::RawFilterKey) {
391 //verify valid/supported filters
392
393 const auto filters = value.value<QList<QCanBusDevice::Filter> >();
394 for (QCanBusDevice::Filter f : filters) {
395 switch (f.type) {
396 case QCanBusFrame::UnknownFrame:
397
398 default:
399 setError(errorText: tr(s: "Cannot set filter for frame type: %1").arg(a: f.type),
400 QCanBusDevice::CanBusError::ConfigurationError);
401 return;
402 case QCanBusFrame::InvalidFrame:
403 case QCanBusFrame::DataFrame:
404 case QCanBusFrame::ErrorFrame:
405 case QCanBusFrame::RemoteRequestFrame:
406 break;
407 }
408
409 if (f.frameId > 0x1FFFFFFFU) {
410 setError(errorText: tr(s: "FrameId %1 larger than 29 bit.").arg(a: f.frameId),
411 QCanBusDevice::CanBusError::ConfigurationError);
412 return;
413 }
414 }
415 } else if (key == QCanBusDevice::ProtocolKey) {
416 bool ok = false;
417 const int newProtocol = value.toInt(ok: &ok);
418 if (Q_UNLIKELY(!ok || (newProtocol < 0))) {
419 const QString errorString = tr(s: "Cannot set protocol to value %1.").arg(a: value.toString());
420 setError(errorText: errorString, QCanBusDevice::ConfigurationError);
421 qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "%ls", qUtf16Printable(errorString));
422 return;
423 }
424 protocol = newProtocol;
425 }
426 // connected & params not applyable/invalid
427 if (canSocket != -1 && !applyConfigurationParameter(key, value))
428 return;
429
430 QCanBusDevice::setConfigurationParameter(key, value);
431
432 // we need to check CAN FD option a lot -> cache it and avoid QList lookup
433 if (key == QCanBusDevice::CanFdKey)
434 canFdOptionEnabled = value.toBool();
435}
436
437bool SocketCanBackend::writeFrame(const QCanBusFrame &newData)
438{
439 if (state() != ConnectedState)
440 return false;
441
442 if (Q_UNLIKELY(!newData.isValid())) {
443 setError(errorText: tr(s: "Cannot write invalid QCanBusFrame"), QCanBusDevice::WriteError);
444 return false;
445 }
446
447 canid_t canId = newData.frameId();
448 if (newData.hasExtendedFrameFormat())
449 canId |= CAN_EFF_FLAG;
450
451 if (newData.frameType() == QCanBusFrame::RemoteRequestFrame) {
452 canId |= CAN_RTR_FLAG;
453 } else if (newData.frameType() == QCanBusFrame::ErrorFrame) {
454 canId = static_cast<canid_t>((newData.error() & QCanBusFrame::AnyError));
455 canId |= CAN_ERR_FLAG;
456 }
457
458 if (Q_UNLIKELY(!canFdOptionEnabled && newData.hasFlexibleDataRateFormat())) {
459 const QString error = tr(s: "Cannot write CAN FD frame because CAN FD option is not enabled.");
460 qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "%ls", qUtf16Printable(error));
461 setError(errorText: error, QCanBusDevice::WriteError);
462 return false;
463 }
464
465 qint64 bytesWritten = 0;
466 if (newData.hasFlexibleDataRateFormat()) {
467 canfd_frame frame = {};
468 frame.len = newData.payload().size();
469 frame.can_id = canId;
470 frame.flags = newData.hasBitrateSwitch() ? CANFD_BRS : 0;
471 frame.flags |= newData.hasErrorStateIndicator() ? CANFD_ESI : 0;
472 ::memcpy(dest: frame.data, src: newData.payload().constData(), n: frame.len);
473
474 bytesWritten = ::write(fd: canSocket, buf: &frame, n: sizeof(frame));
475 } else {
476 can_frame frame = {};
477 frame.can_dlc = newData.payload().size();
478 frame.can_id = canId;
479 ::memcpy(dest: frame.data, src: newData.payload().constData(), n: frame.can_dlc);
480
481 bytesWritten = ::write(fd: canSocket, buf: &frame, n: sizeof(frame));
482 }
483
484 if (Q_UNLIKELY(bytesWritten < 0)) {
485 setError(errorText: qt_error_string(errno),
486 QCanBusDevice::CanBusError::WriteError);
487 return false;
488 }
489
490 emit framesWritten(framesCount: 1);
491
492 return true;
493}
494
495QString SocketCanBackend::interpretErrorFrame(const QCanBusFrame &errorFrame)
496{
497 if (errorFrame.frameType() != QCanBusFrame::ErrorFrame)
498 return QString();
499
500 // the payload may contain the error details
501 const QByteArray data = errorFrame.payload();
502 QString errorMsg;
503
504 if (errorFrame.error() & QCanBusFrame::TransmissionTimeoutError)
505 errorMsg += QStringLiteral("TX timeout\n");
506
507 if (errorFrame.error() & QCanBusFrame::MissingAcknowledgmentError)
508 errorMsg += QStringLiteral("Received no ACK on transmission\n");
509
510 if (errorFrame.error() & QCanBusFrame::BusOffError)
511 errorMsg += QStringLiteral("Bus off\n");
512
513 if (errorFrame.error() & QCanBusFrame::BusError)
514 errorMsg += QStringLiteral("Bus error\n");
515
516 if (errorFrame.error() & QCanBusFrame::ControllerRestartError)
517 errorMsg += QStringLiteral("Controller restarted\n");
518
519 if (errorFrame.error() & QCanBusFrame::UnknownError)
520 errorMsg += QStringLiteral("Unknown error\n");
521
522 if (errorFrame.error() & QCanBusFrame::LostArbitrationError) {
523 errorMsg += QStringLiteral("Lost arbitration:\n");
524 if (data.size() >= 1) {
525 errorMsg += QString::number(data.at(i: 0), base: 16);
526 errorMsg += QStringLiteral(" bit\n");
527 }
528 }
529
530 if (errorFrame.error() & QCanBusFrame::ControllerError) {
531 errorMsg += QStringLiteral("Controller problem:\n");
532 if (data.size() >= 2) {
533 char b = data.at(i: 1) ;
534 if (b & CAN_ERR_CRTL_RX_OVERFLOW)
535 errorMsg += QStringLiteral(" RX buffer overflow\n");
536 if (b & CAN_ERR_CRTL_TX_OVERFLOW)
537 errorMsg += QStringLiteral(" TX buffer overflow\n");
538 if (b & CAN_ERR_CRTL_RX_WARNING)
539 errorMsg += QStringLiteral(" reached warning level for RX errors\n");
540 if (b & CAN_ERR_CRTL_TX_WARNING)
541 errorMsg += QStringLiteral(" reached warning level for TX errors\n");
542 if (b & CAN_ERR_CRTL_RX_PASSIVE)
543 errorMsg += QStringLiteral(" reached error passive status RX\n");
544 if (b & CAN_ERR_CRTL_TX_PASSIVE)
545 errorMsg += QStringLiteral(" reached error passive status TX\n");
546
547 if (b == CAN_ERR_CRTL_UNSPEC)
548 errorMsg += QStringLiteral(" Unspecified error\n");
549 }
550 }
551
552 if (errorFrame.error() & QCanBusFrame::TransceiverError) {
553 errorMsg = QStringLiteral("Transceiver status:");
554 if (data.size() >= 5) {
555 char b = data.at(i: 4);
556 if (b & CAN_ERR_TRX_CANH_NO_WIRE)
557 errorMsg += QStringLiteral(" CAN-transceiver CANH no wire\n");
558 if (b & CAN_ERR_TRX_CANH_SHORT_TO_BAT)
559 errorMsg += QStringLiteral(" CAN-transceiver CANH short to bat\n");
560 if (b & CAN_ERR_TRX_CANH_SHORT_TO_VCC)
561 errorMsg += QStringLiteral(" CAN-transceiver CANH short to vcc\n");
562 if (b & CAN_ERR_TRX_CANH_SHORT_TO_GND)
563 errorMsg += QStringLiteral(" CAN-transceiver CANH short to ground\n");
564 if (b & CAN_ERR_TRX_CANL_NO_WIRE)
565 errorMsg += QStringLiteral(" CAN-transceiver CANL no wire\n");
566 if (b & CAN_ERR_TRX_CANL_SHORT_TO_BAT)
567 errorMsg += QStringLiteral(" CAN-transceiver CANL short to bat\n");
568 if (b & CAN_ERR_TRX_CANL_SHORT_TO_VCC)
569 errorMsg += QStringLiteral(" CAN-transceiver CANL short to vcc\n");
570 if (b & CAN_ERR_TRX_CANL_SHORT_TO_GND)
571 errorMsg += QStringLiteral(" CAN-transceiver CANL short to ground\n");
572 if (b & CAN_ERR_TRX_CANL_SHORT_TO_CANH)
573 errorMsg += QStringLiteral(" CAN-transceiver CANL short to CANH\n");
574
575 if (b == CAN_ERR_TRX_UNSPEC)
576 errorMsg += QStringLiteral(" unspecified\n");
577 }
578
579 }
580
581 if (errorFrame.error() & QCanBusFrame::ProtocolViolationError) {
582 errorMsg += QStringLiteral("Protocol violation:\n");
583 if (data.size() > 3) {
584 char b = data.at(i: 2);
585 if (b & CAN_ERR_PROT_BIT)
586 errorMsg += QStringLiteral(" single bit error\n");
587 if (b & CAN_ERR_PROT_FORM)
588 errorMsg += QStringLiteral(" frame format error\n");
589 if (b & CAN_ERR_PROT_STUFF)
590 errorMsg += QStringLiteral(" bit stuffing error\n");
591 if (b & CAN_ERR_PROT_BIT0)
592 errorMsg += QStringLiteral(" unable to send dominant bit\n");
593 if (b & CAN_ERR_PROT_BIT1)
594 errorMsg += QStringLiteral(" unable to send recessive bit\n");
595 if (b & CAN_ERR_PROT_OVERLOAD)
596 errorMsg += QStringLiteral(" bus overload\n");
597 if (b & CAN_ERR_PROT_ACTIVE)
598 errorMsg += QStringLiteral(" active error announcement\n");
599 if (b & CAN_ERR_PROT_TX)
600 errorMsg += QStringLiteral(" error occurred on transmission\n");
601
602 if (b == CAN_ERR_PROT_UNSPEC)
603 errorMsg += QStringLiteral(" unspecified\n");
604 }
605 if (data.size() > 4) {
606 char b = data.at(i: 3);
607 if (b == CAN_ERR_PROT_LOC_SOF)
608 errorMsg += QStringLiteral(" start of frame\n");
609 if (b == CAN_ERR_PROT_LOC_ID28_21)
610 errorMsg += QStringLiteral(" ID bits 28 - 21 (SFF: 10 - 3)\n");
611 if (b == CAN_ERR_PROT_LOC_ID20_18)
612 errorMsg += QStringLiteral(" ID bits 20 - 18 (SFF: 2 - 0 )\n");
613 if (b == CAN_ERR_PROT_LOC_SRTR)
614 errorMsg += QStringLiteral(" substitute RTR (SFF: RTR)\n");
615 if (b == CAN_ERR_PROT_LOC_IDE)
616 errorMsg += QStringLiteral(" identifier extension\n");
617 if (b == CAN_ERR_PROT_LOC_ID17_13)
618 errorMsg += QStringLiteral(" ID bits 17-13\n");
619 if (b == CAN_ERR_PROT_LOC_ID12_05)
620 errorMsg += QStringLiteral(" ID bits 12-5\n");
621 if (b == CAN_ERR_PROT_LOC_ID04_00)
622 errorMsg += QStringLiteral(" ID bits 4-0\n");
623 if (b == CAN_ERR_PROT_LOC_RTR)
624 errorMsg += QStringLiteral(" RTR\n");
625 if (b == CAN_ERR_PROT_LOC_RES1)
626 errorMsg += QStringLiteral(" reserved bit 1\n");
627 if (b == CAN_ERR_PROT_LOC_RES0)
628 errorMsg += QStringLiteral(" reserved bit 0\n");
629 if (b == CAN_ERR_PROT_LOC_DLC)
630 errorMsg += QStringLiteral(" data length code\n");
631 if (b == CAN_ERR_PROT_LOC_DATA)
632 errorMsg += QStringLiteral(" data section\n");
633 if (b == CAN_ERR_PROT_LOC_CRC_SEQ)
634 errorMsg += QStringLiteral(" CRC sequence\n");
635 if (b == CAN_ERR_PROT_LOC_CRC_DEL)
636 errorMsg += QStringLiteral(" CRC delimiter\n");
637 if (b == CAN_ERR_PROT_LOC_ACK)
638 errorMsg += QStringLiteral(" ACK slot\n");
639 if (b == CAN_ERR_PROT_LOC_ACK_DEL)
640 errorMsg += QStringLiteral(" ACK delimiter\n");
641 if (b == CAN_ERR_PROT_LOC_EOF)
642 errorMsg += QStringLiteral(" end of frame\n");
643 if (b == CAN_ERR_PROT_LOC_INTERM)
644 errorMsg += QStringLiteral(" Intermission\n");
645
646 if (b == CAN_ERR_PROT_LOC_UNSPEC)
647 errorMsg += QStringLiteral(" unspecified\n");
648 }
649 }
650
651 // cut trailing \n
652 if (!errorMsg.isEmpty())
653 errorMsg.chop(n: 1);
654
655 return errorMsg;
656}
657
658void SocketCanBackend::readSocket()
659{
660 QList<QCanBusFrame> newFrames;
661
662 for (;;) {
663 m_frame = {};
664 m_iov.iov_len = sizeof(m_frame);
665 m_msg.msg_namelen = sizeof(m_addr);
666 m_msg.msg_controllen = sizeof(m_ctrlmsg);
667 m_msg.msg_flags = 0;
668
669 const int bytesReceived = ::recvmsg(fd: canSocket, message: &m_msg, flags: 0);
670
671 if (bytesReceived <= 0) {
672 break;
673 } else if (Q_UNLIKELY(bytesReceived != CANFD_MTU && bytesReceived != CAN_MTU)) {
674 setError(errorText: tr(s: "ERROR SocketCanBackend: incomplete CAN frame"),
675 QCanBusDevice::CanBusError::ReadError);
676 continue;
677 } else if (Q_UNLIKELY(m_frame.len > bytesReceived - offsetof(canfd_frame, data))) {
678 setError(errorText: tr(s: "ERROR SocketCanBackend: invalid CAN frame length"),
679 QCanBusDevice::CanBusError::ReadError);
680 continue;
681 }
682
683 struct timeval timeStamp = {};
684 if (Q_UNLIKELY(ioctl(canSocket, SIOCGSTAMP, &timeStamp) < 0)) {
685 setError(errorText: qt_error_string(errno),
686 QCanBusDevice::CanBusError::ReadError);
687 timeStamp = {};
688 }
689
690 const QCanBusFrame::TimeStamp stamp(timeStamp.tv_sec, timeStamp.tv_usec);
691 QCanBusFrame bufferedFrame;
692 bufferedFrame.setTimeStamp(stamp);
693 bufferedFrame.setFlexibleDataRateFormat(bytesReceived == CANFD_MTU);
694
695 bufferedFrame.setExtendedFrameFormat(m_frame.can_id & CAN_EFF_FLAG);
696 Q_ASSERT(m_frame.len <= CANFD_MAX_DLEN);
697
698 if (m_frame.can_id & CAN_RTR_FLAG)
699 bufferedFrame.setFrameType(QCanBusFrame::RemoteRequestFrame);
700 if (m_frame.can_id & CAN_ERR_FLAG)
701 bufferedFrame.setFrameType(QCanBusFrame::ErrorFrame);
702 if (m_frame.flags & CANFD_BRS)
703 bufferedFrame.setBitrateSwitch(true);
704 if (m_frame.flags & CANFD_ESI)
705 bufferedFrame.setErrorStateIndicator(true);
706 if (m_msg.msg_flags & MSG_CONFIRM)
707 bufferedFrame.setLocalEcho(true);
708
709 bufferedFrame.setFrameId(m_frame.can_id & CAN_EFF_MASK);
710
711 const QByteArray load(reinterpret_cast<char *>(m_frame.data), m_frame.len);
712 bufferedFrame.setPayload(load);
713
714 newFrames.append(t: std::move(bufferedFrame));
715 }
716
717 enqueueReceivedFrames(newFrames);
718}
719
720void SocketCanBackend::resetController()
721{
722 libSocketCan->restart(interface: canSocketName);
723}
724
725bool SocketCanBackend::hasBusStatus() const
726{
727 if (isVirtual(canDevice: canSocketName.toLatin1()))
728 return false;
729
730 return libSocketCan->hasBusStatus();
731}
732
733QCanBusDevice::CanBusStatus SocketCanBackend::busStatus()
734{
735 return libSocketCan->busStatus(interface: canSocketName);
736}
737
738QT_END_NAMESPACE
739

source code of qtserialbus/src/plugins/canbus/socketcan/socketcanbackend.cpp