Skip to contentSkip to conversation

pull-request: can 2026-01-16

PATCH Applied Marc Kleine-Budde 3 participants 11 messages Jan 16 – Jan 23

Subsystems (6)
lore
Share & tools
lore

Marc Kleine-Budde

author maintainer
#0 lore raw

cover pull-request: can 2026-01-16

Hello netdev-team,

this is a pull request of 7 patches for net/main.

The first patch is by me and sets the missing CAN device default capabilities in the CAN device layer.

The next patch is by me, target the gs_usb driver and adds the missing unanchor URB on usb_submit_urb() error.

The last 5 patches are also from me and fix the same USB-URB leak (as in the gs_usb driver) in the affected CAN-USB driver: ems_usb, esd_usb, kvaser_usb, mcba_usb and usb_8dev.

regards,
Marc

---

The following changes since commit a74c7a58ca2ca1cbb93f4c01421cf24b8642b962:

net: freescale: ucc_geth: Return early when TBI PHY can't be found (2026-01-15 20:04:25 -0800)

are available in the Git repository at:

git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can.git tags/linux-can-fixes-for-6.19-20260116

for you to fetch changes up to 70458a363d7cf1a6b019685d44ad5932264f8a29:

Merge patch series "can: usb: fix URB memory leaks" (2026-01-16 20:41:17 +0100)

----------------------------------------------------------------
linux-can-fixes-for-6.19-20260116

----------------------------------------------------------------
Marc Kleine-Budde (8):
can: dev: alloc_candev_mqs(): add missing default CAN capabilities
can: gs_usb: gs_usb_receive_bulk_callback(): unanchor URL on usb_submit_urb() error
can: ems_usb: ems_usb_read_bulk_callback(): fix URB memory leak
can: esd_usb: esd_usb_read_bulk_callback(): fix URB memory leak
can: kvaser_usb: kvaser_usb_read_bulk_callback(): fix URB memory leak
can: mcba_usb: mcba_usb_read_bulk_callback(): fix URB memory leak
can: usb_8dev: usb_8dev_read_bulk_callback(): fix URB memory leak Merge patch series "can: usb: fix URB memory leaks"

 drivers/net/can/dev/dev.c                        | 1 +
 drivers/net/can/usb/ems_usb.c                    | 8 +++++++-
 drivers/net/can/usb/esd_usb.c                    | 9 ++++++++-
 drivers/net/can/usb/gs_usb.c                     | 7 +++++++
 drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c | 9 ++++++++-
 drivers/net/can/usb/mcba_usb.c                   | 8 +++++++-
 drivers/net/can/usb/usb_8dev.c                   | 8 +++++++-
 7 files changed, 45 insertions(+), 5 deletions(-)
author maintainer
#1 lore raw

PATCH 1/7 can: dev: alloc_candev_mqs(): add missing default CAN capabilities

The idea behind series 6c1f5146b214 ("Merge patch series "can: raw: better approach to instantly reject unsupported CAN frames"") is to set the capabilities of a CAN device (CAN-CC, CAN-FD, CAN-XL, and listen only) [1] and, based on these capabilities, reject unsupported CAN frames in the CAN-RAW protocol [2].

This works perfectly for CAN devices configured in CAN-FD or CAN-XL mode. CAN devices with static CAN control modes define their capabilities via can_set_static_ctrlmode() -> can_set_cap_info(). CAN devices configured by the user space for CAN-FD or CAN-XL set their capabilities via can_changelink() -> can_ctrlmode_changelink() -> can_set_cap_info().

However, in commit 166e87329ce6 ("can: propagate CAN device capabilities via ml_priv"), the capabilities of CAN devices are not initialized. This results in CAN-RAW rejecting all CAN frames on devices directly after ifup if the user space has not changed the CAN control mode.

Fix this problem by setting the default capabilities to CAN-CC in alloc_candev_mqs() as soon as the CAN specific ml_priv is allocated.

[1] commit 166e87329ce6 ("can: propagate CAN device capabilities via ml_priv")
[2] commit faba5860fcf9 ("can: raw: instantly reject disabled CAN frames")

---
 drivers/net/can/dev/dev.c | 1 +
 1 file changed, 1 insertion(+)
drivers/net/can/dev/dev.c +1 -0
index 7ab9578f5b89..769745e22a3c 100644
@@ -332,6 +332,7 @@ struct net_device *alloc_candev_mqs(int sizeof_priv, unsigned int echo_skb_max,
 
 	can_ml = (void *)priv + ALIGN(sizeof_priv, NETDEV_ALIGN);
 	can_set_ml_priv(dev, can_ml);
+	can_set_cap(dev, CAN_CAP_CC);
 
 	if (echo_skb_max) {
 		priv->echo_skb_max = echo_skb_max;

base-commit: a74c7a58ca2ca1cbb93f4c01421cf24b8642b962

Signature · 1 line
2.51.0
#2 lore raw

Re: [PATCH net 1/7] can: dev: alloc_candev_mqs(): add missing default CAN capabilities

This series was applied to netdev/net.git (main) by Marc Kleine-Budde <[email protected]>:

Hello:

This series was applied to netdev/net.git (main)
by Marc Kleine-Budde <[email protected]>:

Quoted 6 lines · On Fri, 16 Jan 2026 20:55:47 +0100 you wrote:

The idea behind series 6c1f5146b214 ("Merge patch series "can: raw: better approach to instantly reject unsupported CAN frames"") is to set the capabilities of a CAN device (CAN-CC, CAN-FD, CAN-XL, and listen only) [1] and, based on these capabilities, reject unsupported CAN frames in the CAN-RAW protocol [2].

Quoted 7 lines

This works perfectly for CAN devices configured in CAN-FD or CAN-XL mode. CAN devices with static CAN control modes define their capabilities via can_set_static_ctrlmode() -> can_set_cap_info(). CAN devices configured by the user space for CAN-FD or CAN-XL set their capabilities via can_changelink() -> can_ctrlmode_changelink() -> can_set_cap_info().

[...]

Here is the summary with links:
- [net,1/7] can: dev: alloc_candev_mqs(): add missing default CAN capabilities

    https://git.kernel.org/netdev/net/c/375629c92fd8
  - [net,2/7] can: gs_usb: gs_usb_receive_bulk_callback(): unanchor URL on usb_submit_urb() error
    https://git.kernel.org/netdev/net/c/79a6d1bfe114
  - [net,3/7] can: ems_usb: ems_usb_read_bulk_callback(): fix URB memory leak
    https://git.kernel.org/netdev/net/c/0ce73a0eb5a2
  - [net,4/7] can: esd_usb: esd_usb_read_bulk_callback(): fix URB memory leak
    https://git.kernel.org/netdev/net/c/5a4391bdc6c8
  - [net,5/7] can: kvaser_usb: kvaser_usb_read_bulk_callback(): fix URB memory leak
    https://git.kernel.org/netdev/net/c/248e8e1a125f
  - [net,6/7] can: mcba_usb: mcba_usb_read_bulk_callback(): fix URB memory leak
    https://git.kernel.org/netdev/net/c/710a7529fb13
  - [net,7/7] can: usb_8dev: usb_8dev_read_bulk_callback(): fix URB memory leak
    https://git.kernel.org/netdev/net/c/f7a980b3b8f8

You are awesome, thank you!

Signature · 2 lines
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
author maintainer
#3 lore raw

PATCH 2/7 can: gs_usb: gs_usb_receive_bulk_callback(): unanchor URL on usb_submit_urb() error

In reply to Marc Kleine-Budde

In commit 7352e1d5932a ("can: gs_usb: gs_usb_receive_bulk_callback(): fix URB memory leak"), the URB was re-anchored before usb_submit_urb() in gs_usb_receive_bulk_callback() to prevent a leak of this URB during cleanup.

However, this patch did not take into account that usb_submit_urb() could fail. The URB remains anchored and usb_kill_anchored_urbs(&parent->rx_submitted) in gs_can_close() loops infinitely since the anchor list never becomes empty.

To fix the bug, unanchor the URB when an usb_submit_urb() error occurs, also print an info message.

Fixes 7352e1d5932a ("can: gs_usb: gs_usb_receive_bulk_callback(): fix URB memory leak")
---
 drivers/net/can/usb/gs_usb.c | 7 +++++++
 1 file changed, 7 insertions(+)
drivers/net/can/usb/gs_usb.c +7 -0
index d093babbc320..192338b481f2 100644
@@ -754,6 +754,10 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
 	usb_anchor_urb(urb, &parent->rx_submitted);
 
 	rc = usb_submit_urb(urb, GFP_ATOMIC);
+	if (!rc)
+		return;
+
+	usb_unanchor_urb(urb);
 
 	/* USB failure take down all interfaces */
 	if (rc == -ENODEV) {
@@ -762,6 +766,9 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
 			if (parent->canch[rc])
 				netif_device_detach(parent->canch[rc]->netdev);
 		}
+	} else if (rc != -ESHUTDOWN && net_ratelimit()) {
+		netdev_info(netdev, "failed to re-submit IN URB: %pe\n",
+			    ERR_PTR(urb->status));
 	}
 }
 
Signature · 1 line
2.51.0
maintainer
#4 lore raw

Re: [net,2/7] can: gs_usb: gs_usb_receive_bulk_callback(): unanchor URL on usb_submit_urb() error

This is an AI-generated review of your patch. The human sending this email has considered the AI review valid, or at least plausible.

For local reproduction steps see https://netdev-ai.bots.linux.dev/ai-local.html
---
can: gs_usb: gs_usb_receive_bulk_callback(): unanchor URL on usb_submit_urb() error

This patch fixes an infinite loop in gs_can_close() by unanchoring the URB when usb_submit_urb() fails after re-anchoring. It also adds an error message for non-ENODEV/ESHUTDOWN failures.

Quoted 15 lines
drivers/net/can/usb/gs_usb.c +4 -0
index d093babbc320..192338b481f2 100644
@@ -754,6 +754,10 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
 	usb_anchor_urb(urb, &parent->rx_submitted);
 
 	rc = usb_submit_urb(urb, GFP_ATOMIC);
+	if (!rc)
+		return;
+
+	usb_unanchor_urb(urb);
 
 	/* USB failure take down all interfaces */
 	if (rc == -ENODEV) {

[ ... ]

drivers/net/can/usb/gs_usb.c static void gs_usb_receive_bulk_callback(struct urb *urb) · line 771

Quoted 3 lines
drivers/net/can/usb/gs_usb.c +3 -0
+	} else if (rc != -ESHUTDOWN && net_ratelimit()) {
+		netdev_info(netdev, "failed to re-submit IN URB: %pe\n",
+			    ERR_PTR(urb->status));

Two issues with this error message:

1. The message prints urb->status, but shouldn't it print rc instead? The variable rc holds the actual error from usb_submit_urb(), while urb->status contains the completion status from the previous callback invocation (which would typically be 0 for success since we only reach resubmit_urb on successful URB completion). Other CAN USB drivers like usb_8dev print the return value from usb_submit_urb() in similar error paths.

2. The local variable netdev is uninitialized when gs_usb_receive_bulk_callback() reaches this code path via the short read case. The function declares netdev at the top without initialization, and the short read check at the beginning of the function jumps directly to resubmit_urb without ever assigning netdev. If usb_submit_urb() then fails with an error other than -ENODEV or -ESHUTDOWN, this code will pass the uninitialized netdev pointer to netdev_info().

Quoted 2 lines

}
}

author maintainer
#5 lore raw

Re: [net,2/7] can: gs_usb: gs_usb_receive_bulk_callback(): unanchor URL on usb_submit_urb() error

Quoted 44 lines · Jakub Kicinski

This is an AI-generated review of your patch. The human sending this email has considered the AI review valid, or at least plausible.

For local reproduction steps see https://netdev-ai.bots.linux.dev/ai-local.html
---
can: gs_usb: gs_usb_receive_bulk_callback(): unanchor URL on usb_submit_urb() error

This patch fixes an infinite loop in gs_can_close() by unanchoring the URB when usb_submit_urb() fails after re-anchoring. It also adds an error message for non-ENODEV/ESHUTDOWN failures.

Quoted 15 lines
drivers/net/can/usb/gs_usb.c +4 -0
index d093babbc320..192338b481f2 100644
@@ -754,6 +754,10 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
 	usb_anchor_urb(urb, &parent->rx_submitted);
 
 	rc = usb_submit_urb(urb, GFP_ATOMIC);
+	if (!rc)
+		return;
+
+	usb_unanchor_urb(urb);
 
 	/* USB failure take down all interfaces */
 	if (rc == -ENODEV) {

[ ... ]

drivers/net/can/usb/gs_usb.c static void gs_usb_receive_bulk_callback(struct urb *urb) · line 771

Quoted 3 lines
drivers/net/can/usb/gs_usb.c +3 -0
+	} else if (rc != -ESHUTDOWN && net_ratelimit()) {
+		netdev_info(netdev, "failed to re-submit IN URB: %pe\n",
+			    ERR_PTR(urb->status));

Two issues with this error message:

1. The message prints urb->status, but shouldn't it print rc instead? The variable rc holds the actual error from usb_submit_urb(), while urb->status contains the completion status from the previous callback invocation (which would typically be 0 for success since we only reach resubmit_urb on successful URB completion). Other CAN USB drivers like usb_8dev print the return value from usb_submit_urb() in similar error paths.

Quoted 6 lines

2. The local variable netdev is uninitialized when gs_usb_receive_bulk_callback() reaches this code path via the short read case. The function declares netdev at the top without initialization, and the short read check at the beginning of the function jumps directly to resubmit_urb without ever assigning netdev. If usb_submit_urb() then fails with an error other than -ENODEV or -ESHUTDOWN, this code will pass the uninitialized netdev pointer to netdev_info().

Fixed with today's PR: https://lore.kernel.org/all/[email protected]/

regards,
Marc

Signature · 4 lines
Pengutronix e.K.                 | Marc Kleine-Budde          |
Embedded Linux                   | https://www.pengutronix.de |
Vertretung Nürnberg              | Phone: +49-5121-206917-129 |
Amtsgericht Hildesheim, HRA 2686 | Fax:   +49-5121-206917-9   |
author maintainer
#6 lore raw

PATCH 3/7 can: ems_usb: ems_usb_read_bulk_callback(): fix URB memory leak

In reply to Marc Kleine-Budde

Fix similar memory leak as in commit 7352e1d5932a ("can: gs_usb:
gs_usb_receive_bulk_callback(): fix URB memory leak").

In ems_usb_open(), the URBs for USB-in transfers are allocated, added to the dev->rx_submitted anchor and submitted. In the complete callback ems_usb_read_bulk_callback(), the URBs are processed and resubmitted. In ems_usb_close() the URBs are freed by calling usb_kill_anchored_urbs(&dev->rx_submitted).

However, this does not take into account that the USB framework unanchors the URB before the complete function is called. This means that once an in-URB has been completed, it is no longer anchored and is ultimately not released in ems_usb_close().

Fix the memory leak by anchoring the URB in the ems_usb_read_bulk_callback() to the dev->rx_submitted anchor.

Fixes 702171adeed3 ("ems_usb: Added support for EMS CPC-USB/ARM7 CAN/USB interface")
---
 drivers/net/can/usb/ems_usb.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/net/can/usb/ems_usb.c +7 -1
index de8e212a1366..4c219a5b139b 100644
@@ -486,11 +486,17 @@ static void ems_usb_read_bulk_callback(struct urb *urb)
 			  urb->transfer_buffer, RX_BUFFER_SIZE,
 			  ems_usb_read_bulk_callback, dev);
 
+	usb_anchor_urb(urb, &dev->rx_submitted);
+
 	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (!retval)
+		return;
+
+	usb_unanchor_urb(urb);
 
 	if (retval == -ENODEV)
 		netif_device_detach(netdev);
-	else if (retval)
+	else
 		netdev_err(netdev,
 			   "failed resubmitting read bulk urb: %d\n", retval);
 }
Signature · 1 line
2.51.0
author maintainer
#7 lore raw

PATCH 4/7 can: esd_usb: esd_usb_read_bulk_callback(): fix URB memory leak

In reply to Marc Kleine-Budde

Fix similar memory leak as in commit 7352e1d5932a ("can: gs_usb:
gs_usb_receive_bulk_callback(): fix URB memory leak").

In esd_usb_open(), the URBs for USB-in transfers are allocated, added to the dev->rx_submitted anchor and submitted. In the complete callback esd_usb_read_bulk_callback(), the URBs are processed and resubmitted. In esd_usb_close() the URBs are freed by calling usb_kill_anchored_urbs(&dev->rx_submitted).

However, this does not take into account that the USB framework unanchors the URB before the complete function is called. This means that once an in-URB has been completed, it is no longer anchored and is ultimately not released in esd_usb_close().

Fix the memory leak by anchoring the URB in the esd_usb_read_bulk_callback() to the dev->rx_submitted anchor.

---
 drivers/net/can/usb/esd_usb.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/net/can/usb/esd_usb.c +8 -1
index 08da507faef4..8cc924c47042 100644
@@ -541,13 +541,20 @@ static void esd_usb_read_bulk_callback(struct urb *urb)
 			  urb->transfer_buffer, ESD_USB_RX_BUFFER_SIZE,
 			  esd_usb_read_bulk_callback, dev);
 
+	usb_anchor_urb(urb, &dev->rx_submitted);
+
 	err = usb_submit_urb(urb, GFP_ATOMIC);
+	if (!err)
+		return;
+
+	usb_unanchor_urb(urb);
+
 	if (err == -ENODEV) {
 		for (i = 0; i < dev->net_count; i++) {
 			if (dev->nets[i])
 				netif_device_detach(dev->nets[i]->netdev);
 		}
-	} else if (err) {
+	} else {
 		dev_err(dev->udev->dev.parent,
 			"failed resubmitting read bulk urb: %pe\n", ERR_PTR(err));
 	}
Signature · 1 line
2.51.0
author maintainer
#8 lore raw

PATCH 5/7 can: kvaser_usb: kvaser_usb_read_bulk_callback(): fix URB memory leak

In reply to Marc Kleine-Budde

Fix similar memory leak as in commit 7352e1d5932a ("can: gs_usb:
gs_usb_receive_bulk_callback(): fix URB memory leak").

In kvaser_usb_set_{,data_}bittiming() -> kvaser_usb_setup_rx_urbs(), the URBs for USB-in transfers are allocated, added to the dev->rx_submitted anchor and submitted. In the complete callback kvaser_usb_read_bulk_callback(), the URBs are processed and resubmitted. In kvaser_usb_remove_interfaces() the URBs are freed by calling usb_kill_anchored_urbs(&dev->rx_submitted).

However, this does not take into account that the USB framework unanchors the URB before the complete function is called. This means that once an in-URB has been completed, it is no longer anchored and is ultimately not released in usb_kill_anchored_urbs().

Fix the memory leak by anchoring the URB in the kvaser_usb_read_bulk_callback() to the dev->rx_submitted anchor.

---
 drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c +8 -1
index 62701ec34272..d0a2a2a33c1c 100644
@@ -361,7 +361,14 @@ static void kvaser_usb_read_bulk_callback(struct urb *urb)
 			  urb->transfer_buffer, KVASER_USB_RX_BUFFER_SIZE,
 			  kvaser_usb_read_bulk_callback, dev);
 
+	usb_anchor_urb(urb, &dev->rx_submitted);
+
 	err = usb_submit_urb(urb, GFP_ATOMIC);
+	if (!err)
+		return;
+
+	usb_unanchor_urb(urb);
+
 	if (err == -ENODEV) {
 		for (i = 0; i < dev->nchannels; i++) {
 			struct kvaser_usb_net_priv *priv;
@@ -372,7 +379,7 @@ static void kvaser_usb_read_bulk_callback(struct urb *urb)
 
 			netif_device_detach(priv->netdev);
 		}
-	} else if (err) {
+	} else {
 		dev_err(&dev->intf->dev,
 			"Failed resubmitting read bulk urb: %d\n", err);
 	}
Signature · 1 line
2.51.0
author maintainer
#9 lore raw

PATCH 6/7 can: mcba_usb: mcba_usb_read_bulk_callback(): fix URB memory leak

In reply to Marc Kleine-Budde

Fix similar memory leak as in commit 7352e1d5932a ("can: gs_usb:
gs_usb_receive_bulk_callback(): fix URB memory leak").

In mcba_usb_probe() -> mcba_usb_start(), the URBs for USB-in transfers are allocated, added to the priv->rx_submitted anchor and submitted. In the complete callback mcba_usb_read_bulk_callback(), the URBs are processed and resubmitted. In mcba_usb_close() -> mcba_urb_unlink() the URBs are freed by calling usb_kill_anchored_urbs(&priv->rx_submitted).

However, this does not take into account that the USB framework unanchors the URB before the complete function is called. This means that once an in-URB has been completed, it is no longer anchored and is ultimately not released in usb_kill_anchored_urbs().

Fix the memory leak by anchoring the URB in the mcba_usb_read_bulk_callback()to the priv->rx_submitted anchor.

---
 drivers/net/can/usb/mcba_usb.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/net/can/usb/mcba_usb.c +7 -1
index 41c0a1c399bf..04170326dc7e 100644
@@ -608,11 +608,17 @@ static void mcba_usb_read_bulk_callback(struct urb *urb)
 			  urb->transfer_buffer, MCBA_USB_RX_BUFF_SIZE,
 			  mcba_usb_read_bulk_callback, priv);
 
+	usb_anchor_urb(urb, &priv->rx_submitted);
+
 	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (!retval)
+		return;
+
+	usb_unanchor_urb(urb);
 
 	if (retval == -ENODEV)
 		netif_device_detach(netdev);
-	else if (retval)
+	else
 		netdev_err(netdev, "failed resubmitting read bulk urb: %d\n",
 			   retval);
 }
Signature · 1 line
2.51.0
author maintainer
#10 lore raw

PATCH 7/7 can: usb_8dev: usb_8dev_read_bulk_callback(): fix URB memory leak

In reply to Marc Kleine-Budde

Fix similar memory leak as in commit 7352e1d5932a ("can: gs_usb:
gs_usb_receive_bulk_callback(): fix URB memory leak").

In usb_8dev_open() -> usb_8dev_start(), the URBs for USB-in transfers are allocated, added to the priv->rx_submitted anchor and submitted. In the complete callback usb_8dev_read_bulk_callback(), the URBs are processed and resubmitted. In usb_8dev_close() -> unlink_all_urbs() the URBs are freed by calling usb_kill_anchored_urbs(&priv->rx_submitted).

However, this does not take into account that the USB framework unanchors the URB before the complete function is called. This means that once an in-URB has been completed, it is no longer anchored and is ultimately not released in usb_kill_anchored_urbs().

Fix the memory leak by anchoring the URB in the usb_8dev_read_bulk_callback() to the priv->rx_submitted anchor.

Fixes 0024d8ad1639 ("can: usb_8dev: Add support for USB2CAN interface from 8 devices")
---
 drivers/net/can/usb/usb_8dev.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/net/can/usb/usb_8dev.c +7 -1
index 7449328f7cd7..3125cf59d002 100644
@@ -541,11 +541,17 @@ static void usb_8dev_read_bulk_callback(struct urb *urb)
 			  urb->transfer_buffer, RX_BUFFER_SIZE,
 			  usb_8dev_read_bulk_callback, priv);
 
+	usb_anchor_urb(urb, &priv->rx_submitted);
+
 	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (!retval)
+		return;
+
+	usb_unanchor_urb(urb);
 
 	if (retval == -ENODEV)
 		netif_device_detach(netdev);
-	else if (retval)
+	else
 		netdev_err(netdev,
 			"failed resubmitting read bulk urb: %d\n", retval);
 }
Signature · 1 line
2.51.0