drivers/net/can/dev/netlink.c

Source file repositories/reference/linux-study-clean/drivers/net/can/dev/netlink.c

File Facts

System
Linux kernel
Corpus path
drivers/net/can/dev/netlink.c
Extension
.c
Size
31647 bytes
Lines
1115
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (tb_tdc[IFLA_CAN_TDC_TDCV]) {
			if (tdc_auto) {
				NL_SET_ERR_MSG(extack,
					       "TDCV is incompatible with TDC auto mode");
				return -EOPNOTSUPP;
			}
		} else {
			if (tdc_manual) {
				NL_SET_ERR_MSG(extack,
					       "TDC manual mode requires TDCV");
				return -EOPNOTSUPP;
			}
		}

		if (!tb_tdc[IFLA_CAN_TDC_TDCO]) {
			NL_SET_ERR_MSG(extack, "TDCO is missing");
			return -EOPNOTSUPP;
		}
	}

	return 0;
}

static int can_validate_pwm(struct nlattr *data[],
			    struct netlink_ext_ack *extack, u32 flags)
{
	struct nlattr *tb_pwm[IFLA_CAN_PWM_MAX + 1];
	int err;

	if (!data[IFLA_CAN_XL_PWM])
		return 0;

	if (!(flags & CAN_CTRLMODE_XL_TMS)) {
		NL_SET_ERR_MSG(extack, "PWM requires TMS");
		return -EOPNOTSUPP;
	}

	err = nla_parse_nested(tb_pwm, IFLA_CAN_PWM_MAX, data[IFLA_CAN_XL_PWM],
			       can_pwm_policy, extack);
	if (err)
		return err;

	if (!tb_pwm[IFLA_CAN_PWM_PWMS] != !tb_pwm[IFLA_CAN_PWM_PWML]) {
		NL_SET_ERR_MSG(extack,
			       "Provide either both PWMS and PWML, or none for automatic calculation");
		return -EOPNOTSUPP;
	}

	if (tb_pwm[IFLA_CAN_PWM_PWMO] &&
	    (!tb_pwm[IFLA_CAN_PWM_PWMS] || !tb_pwm[IFLA_CAN_PWM_PWML])) {
		NL_SET_ERR_MSG(extack, "PWMO requires both PWMS and PWML");
		return -EOPNOTSUPP;
	}

	return 0;
}

static int can_validate_databittiming(struct nlattr *data[],
				      struct netlink_ext_ack *extack,
				      int ifla_can_data_bittiming, u32 flags)
{
	struct nlattr *data_tdc;
	const char *type;
	u32 tdc_flags;
	bool is_on;
	int err;

	/* Make sure that valid CAN FD/XL configurations always consist of
	 * - nominal/arbitration bittiming
	 * - data bittiming
	 * - control mode with CAN_CTRLMODE_{FD,XL} set
	 * - TDC parameters are coherent (details in can_validate_tdc())
	 */

	if (ifla_can_data_bittiming == IFLA_CAN_DATA_BITTIMING) {
		data_tdc = data[IFLA_CAN_TDC];
		tdc_flags = flags & CAN_CTRLMODE_FD_TDC_MASK;
		is_on = flags & CAN_CTRLMODE_FD;
		type = "FD";
	} else {
		data_tdc = data[IFLA_CAN_XL_TDC];
		tdc_flags = flags & CAN_CTRLMODE_XL_TDC_MASK;
		is_on = flags & CAN_CTRLMODE_XL;
		type = "XL";
	}

	if (is_on) {
		if (!data[IFLA_CAN_BITTIMING] || !data[ifla_can_data_bittiming]) {
			NL_SET_ERR_MSG_FMT(extack,
					   "Provide both nominal and %s data bittiming",

Annotation

Implementation Notes