1 /*
2  * Copyright (c) 2018 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(net_ethernet_mgmt, CONFIG_NET_L2_ETHERNET_LOG_LEVEL);
9 
10 #include <errno.h>
11 
12 #include <zephyr/net/net_core.h>
13 #include <zephyr/net/net_if.h>
14 #include <zephyr/net/ethernet_mgmt.h>
15 
is_hw_caps_supported(const struct device * dev,enum ethernet_hw_caps caps)16 static inline bool is_hw_caps_supported(const struct device *dev,
17 					enum ethernet_hw_caps caps)
18 {
19 	const struct ethernet_api *api = dev->api;
20 
21 	if (!api || !api->get_capabilities) {
22 		return false;
23 	}
24 
25 	return ((api->get_capabilities(dev) & caps) != 0);
26 }
27 
ethernet_set_config(uint64_t mgmt_request,struct net_if * iface,void * data,size_t len)28 static int ethernet_set_config(uint64_t mgmt_request,
29 			       struct net_if *iface,
30 			       void *data, size_t len)
31 {
32 	struct ethernet_req_params *params = (struct ethernet_req_params *)data;
33 	const struct device *dev = net_if_get_device(iface);
34 	const struct ethernet_api *api = dev->api;
35 	struct ethernet_config config = { 0 };
36 	enum ethernet_config_type type;
37 
38 	if (!api) {
39 		return -ENOENT;
40 	}
41 
42 	if (!api->set_config) {
43 		return -ENOTSUP;
44 	}
45 
46 	if (!data || (len != sizeof(struct ethernet_req_params))) {
47 		return -EINVAL;
48 	}
49 
50 	if (mgmt_request == NET_REQUEST_ETHERNET_SET_MAC_ADDRESS) {
51 		if (net_if_is_admin_up(iface)) {
52 			return -EACCES;
53 		}
54 
55 		/* We need to remove the old IPv6 link layer address, that is
56 		 * generated from old MAC address, from network interface if
57 		 * needed.
58 		 */
59 		if (IS_ENABLED(CONFIG_NET_NATIVE_IPV6) &&
60 		    IS_ENABLED(CONFIG_NET_IPV6_IID_EUI_64)) {
61 			struct in6_addr iid;
62 
63 			net_ipv6_addr_create_iid(&iid,
64 						 net_if_get_link_addr(iface));
65 
66 			/* No need to check the return value in this case. It
67 			 * is not an error if the address is not found atm.
68 			 */
69 			(void)net_if_ipv6_addr_rm(iface, &iid);
70 		}
71 
72 		memcpy(&config.mac_address, &params->mac_address,
73 		       sizeof(struct net_eth_addr));
74 		type = ETHERNET_CONFIG_TYPE_MAC_ADDRESS;
75 	} else if (mgmt_request == NET_REQUEST_ETHERNET_SET_QAV_PARAM) {
76 		if (!is_hw_caps_supported(dev, ETHERNET_QAV)) {
77 			return -ENOTSUP;
78 		}
79 
80 		/* Validate params which need global validating */
81 		switch (params->qav_param.type) {
82 		case ETHERNET_QAV_PARAM_TYPE_DELTA_BANDWIDTH:
83 			if (params->qav_param.delta_bandwidth > 100) {
84 				return -EINVAL;
85 			}
86 			break;
87 		case ETHERNET_QAV_PARAM_TYPE_OPER_IDLE_SLOPE:
88 		case ETHERNET_QAV_PARAM_TYPE_TRAFFIC_CLASS:
89 			/* Read-only parameters */
90 			return -EINVAL;
91 		default:
92 			/* No validation needed */
93 			break;
94 		}
95 
96 		memcpy(&config.qav_param, &params->qav_param,
97 		       sizeof(struct ethernet_qav_param));
98 		type = ETHERNET_CONFIG_TYPE_QAV_PARAM;
99 	} else if (mgmt_request == NET_REQUEST_ETHERNET_SET_QBV_PARAM) {
100 		if (!is_hw_caps_supported(dev, ETHERNET_QBV)) {
101 			return -ENOTSUP;
102 		}
103 
104 		/* Validate params which need global validating */
105 		if (params->qbv_param.state == ETHERNET_QBV_STATE_TYPE_OPER) {
106 			/* Read-only parameters */
107 			return -EINVAL;
108 		}
109 
110 		if (params->qbv_param.type == ETHERNET_QBV_PARAM_TYPE_TIME &&
111 		    (params->qbv_param.cycle_time.nanosecond >= 1000000000 ||
112 		     params->qbv_param.base_time.fract_nsecond >= 1000000000)) {
113 			return -EINVAL;
114 		}
115 
116 		memcpy(&config.qbv_param, &params->qbv_param,
117 		       sizeof(struct ethernet_qbv_param));
118 		type = ETHERNET_CONFIG_TYPE_QBV_PARAM;
119 	} else if (mgmt_request == NET_REQUEST_ETHERNET_SET_QBU_PARAM) {
120 		if (!is_hw_caps_supported(dev, ETHERNET_QBU)) {
121 			return -ENOTSUP;
122 		}
123 
124 		if (params->qbu_param.type ==
125 		    ETHERNET_QBR_PARAM_TYPE_LINK_PARTNER_STATUS) {
126 			/* Read only parameter */
127 			return -EINVAL;
128 		}
129 
130 		/* All other fields are rw */
131 
132 		memcpy(&config.qbu_param, &params->qbu_param,
133 		       sizeof(struct ethernet_qbu_param));
134 		type = ETHERNET_CONFIG_TYPE_QBU_PARAM;
135 	} else if (mgmt_request == NET_REQUEST_ETHERNET_SET_TXTIME_PARAM) {
136 		if (!is_hw_caps_supported(dev, ETHERNET_TXTIME)) {
137 			return -ENOTSUP;
138 		}
139 
140 		if (net_if_is_up(iface)) {
141 			return -EACCES;
142 		}
143 
144 		memcpy(&config.txtime_param, &params->txtime_param,
145 		       sizeof(struct ethernet_txtime_param));
146 		type = ETHERNET_CONFIG_TYPE_TXTIME_PARAM;
147 	} else if (mgmt_request == NET_REQUEST_ETHERNET_SET_PROMISC_MODE) {
148 		if (!is_hw_caps_supported(dev, ETHERNET_PROMISC_MODE)) {
149 			return -ENOTSUP;
150 		}
151 
152 		config.promisc_mode = params->promisc_mode;
153 		type = ETHERNET_CONFIG_TYPE_PROMISC_MODE;
154 	} else if (mgmt_request == NET_REQUEST_ETHERNET_SET_T1S_PARAM) {
155 		if (net_if_is_up(iface)) {
156 			return -EACCES;
157 		}
158 
159 		memcpy(&config.t1s_param, &params->t1s_param,
160 		       sizeof(struct ethernet_t1s_param));
161 		type = ETHERNET_CONFIG_TYPE_T1S_PARAM;
162 	} else if (mgmt_request == NET_REQUEST_ETHERNET_SET_TXINJECTION_MODE) {
163 		if (!is_hw_caps_supported(dev, ETHERNET_TXINJECTION_MODE)) {
164 			return -ENOTSUP;
165 		}
166 
167 		config.txinjection_mode = params->txinjection_mode;
168 		type = ETHERNET_CONFIG_TYPE_TXINJECTION_MODE;
169 	} else if (mgmt_request == NET_REQUEST_ETHERNET_SET_MAC_FILTER) {
170 		if (!is_hw_caps_supported(dev, ETHERNET_HW_FILTERING)) {
171 			return -ENOTSUP;
172 		}
173 
174 		memcpy(&config.filter, &params->filter, sizeof(struct ethernet_filter));
175 		type = ETHERNET_CONFIG_TYPE_FILTER;
176 	} else {
177 		return -EINVAL;
178 	}
179 
180 	return api->set_config(net_if_get_device(iface), type, &config);
181 }
182 
183 NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_MAC_ADDRESS,
184 				  ethernet_set_config);
185 
186 NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_QAV_PARAM,
187 				  ethernet_set_config);
188 
189 NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_QBV_PARAM,
190 				  ethernet_set_config);
191 
192 NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_QBU_PARAM,
193 				  ethernet_set_config);
194 
195 NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_TXTIME_PARAM,
196 				  ethernet_set_config);
197 
198 NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_PROMISC_MODE,
199 				  ethernet_set_config);
200 
201 NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_T1S_PARAM,
202 				  ethernet_set_config);
203 
204 NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_TXINJECTION_MODE,
205 				  ethernet_set_config);
206 
207 NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_SET_MAC_FILTER,
208 				  ethernet_set_config);
209 
ethernet_get_config(uint64_t mgmt_request,struct net_if * iface,void * data,size_t len)210 static int ethernet_get_config(uint64_t mgmt_request,
211 			       struct net_if *iface,
212 			       void *data, size_t len)
213 {
214 	struct ethernet_req_params *params = (struct ethernet_req_params *)data;
215 	const struct device *dev = net_if_get_device(iface);
216 	const struct ethernet_api *api = dev->api;
217 	struct ethernet_config config = { 0 };
218 	int ret = 0;
219 	enum ethernet_config_type type;
220 
221 	if (!api) {
222 		return -ENOENT;
223 	}
224 
225 	if (!api->get_config) {
226 		return -ENOTSUP;
227 	}
228 
229 	if (!data || (len != sizeof(struct ethernet_req_params))) {
230 		return -EINVAL;
231 	}
232 
233 	if (mgmt_request == NET_REQUEST_ETHERNET_GET_PRIORITY_QUEUES_NUM) {
234 		if (!is_hw_caps_supported(dev, ETHERNET_PRIORITY_QUEUES)) {
235 			return -ENOTSUP;
236 		}
237 
238 		type = ETHERNET_CONFIG_TYPE_PRIORITY_QUEUES_NUM;
239 
240 		ret = api->get_config(dev, type, &config);
241 		if (ret) {
242 			return ret;
243 		}
244 
245 		params->priority_queues_num = config.priority_queues_num;
246 	} else if (mgmt_request == NET_REQUEST_ETHERNET_GET_QAV_PARAM) {
247 		if (!is_hw_caps_supported(dev, ETHERNET_QAV)) {
248 			return -ENOTSUP;
249 		}
250 
251 		config.qav_param.queue_id = params->qav_param.queue_id;
252 		config.qav_param.type = params->qav_param.type;
253 
254 		type = ETHERNET_CONFIG_TYPE_QAV_PARAM;
255 
256 		ret = api->get_config(dev, type, &config);
257 		if (ret) {
258 			return ret;
259 		}
260 
261 		switch (config.qav_param.type) {
262 		case ETHERNET_QAV_PARAM_TYPE_DELTA_BANDWIDTH:
263 			params->qav_param.delta_bandwidth =
264 				config.qav_param.delta_bandwidth;
265 			break;
266 		case ETHERNET_QAV_PARAM_TYPE_IDLE_SLOPE:
267 			params->qav_param.idle_slope =
268 				config.qav_param.idle_slope;
269 			break;
270 		case ETHERNET_QAV_PARAM_TYPE_OPER_IDLE_SLOPE:
271 			params->qav_param.oper_idle_slope =
272 				config.qav_param.oper_idle_slope;
273 			break;
274 		case ETHERNET_QAV_PARAM_TYPE_TRAFFIC_CLASS:
275 			params->qav_param.traffic_class =
276 				config.qav_param.traffic_class;
277 			break;
278 		case ETHERNET_QAV_PARAM_TYPE_STATUS:
279 			params->qav_param.enabled = config.qav_param.enabled;
280 			break;
281 		}
282 
283 	} else if (mgmt_request == NET_REQUEST_ETHERNET_GET_PORTS_NUM) {
284 		type = ETHERNET_CONFIG_TYPE_PORTS_NUM;
285 
286 		ret = api->get_config(dev, type, &config);
287 		if (ret) {
288 			return ret;
289 		}
290 
291 		params->ports_num = config.ports_num;
292 
293 	} else if (mgmt_request == NET_REQUEST_ETHERNET_GET_QBV_PARAM) {
294 		if (!is_hw_caps_supported(dev, ETHERNET_QBV)) {
295 			return -ENOTSUP;
296 		}
297 
298 		config.qbv_param.port_id = params->qbv_param.port_id;
299 		config.qbv_param.type = params->qbv_param.type;
300 		config.qbv_param.state = params->qbv_param.state;
301 
302 		if (config.qbv_param.type ==
303 		    ETHERNET_QBV_PARAM_TYPE_GATE_CONTROL_LIST) {
304 			config.qbv_param.gate_control.row =
305 				params->qbv_param.gate_control.row;
306 		}
307 
308 		type = ETHERNET_CONFIG_TYPE_QBV_PARAM;
309 
310 		ret = api->get_config(dev, type, &config);
311 		if (ret) {
312 			return ret;
313 		}
314 
315 		switch (config.qbv_param.type) {
316 		case ETHERNET_QBV_PARAM_TYPE_STATUS:
317 			params->qbv_param.enabled = config.qbv_param.enabled;
318 			break;
319 		case ETHERNET_QBV_PARAM_TYPE_TIME:
320 			memcpy(&params->qbv_param.cycle_time,
321 			       &config.qbv_param.cycle_time,
322 			       sizeof(params->qbv_param.cycle_time));
323 			memcpy(&params->qbv_param.base_time,
324 			       &config.qbv_param.base_time,
325 			       sizeof(params->qbv_param.base_time));
326 			params->qbv_param.extension_time =
327 				config.qbv_param.extension_time;
328 			break;
329 		case ETHERNET_QBV_PARAM_TYPE_GATE_CONTROL_LIST_LEN:
330 			params->qbv_param.gate_control_list_len =
331 				config.qbv_param.gate_control_list_len;
332 			break;
333 		case ETHERNET_QBV_PARAM_TYPE_GATE_CONTROL_LIST:
334 			memcpy(&params->qbv_param.gate_control,
335 			       &config.qbv_param.gate_control,
336 			       sizeof(params->qbv_param.gate_control));
337 			break;
338 		}
339 
340 	} else if (mgmt_request == NET_REQUEST_ETHERNET_GET_QBU_PARAM) {
341 		if (!is_hw_caps_supported(dev, ETHERNET_QBU)) {
342 			return -ENOTSUP;
343 		}
344 
345 		config.qbu_param.port_id = params->qbu_param.port_id;
346 		config.qbu_param.type = params->qbu_param.type;
347 
348 		type = ETHERNET_CONFIG_TYPE_QBU_PARAM;
349 
350 		ret = api->get_config(dev, type, &config);
351 		if (ret) {
352 			return ret;
353 		}
354 
355 		switch (config.qbu_param.type) {
356 		case ETHERNET_QBU_PARAM_TYPE_STATUS:
357 			params->qbu_param.enabled = config.qbu_param.enabled;
358 			break;
359 		case ETHERNET_QBU_PARAM_TYPE_RELEASE_ADVANCE:
360 			params->qbu_param.release_advance =
361 				config.qbu_param.release_advance;
362 			break;
363 		case ETHERNET_QBU_PARAM_TYPE_HOLD_ADVANCE:
364 			params->qbu_param.hold_advance =
365 				config.qbu_param.hold_advance;
366 			break;
367 		case ETHERNET_QBR_PARAM_TYPE_LINK_PARTNER_STATUS:
368 			params->qbu_param.link_partner_status =
369 				config.qbu_param.link_partner_status;
370 			break;
371 		case ETHERNET_QBR_PARAM_TYPE_ADDITIONAL_FRAGMENT_SIZE:
372 			params->qbu_param.additional_fragment_size =
373 				config.qbu_param.additional_fragment_size;
374 			break;
375 		case ETHERNET_QBU_PARAM_TYPE_PREEMPTION_STATUS_TABLE:
376 			memcpy(&params->qbu_param.frame_preempt_statuses,
377 			     &config.qbu_param.frame_preempt_statuses,
378 			     sizeof(params->qbu_param.frame_preempt_statuses));
379 			break;
380 		}
381 
382 	} else if (mgmt_request == NET_REQUEST_ETHERNET_GET_TXTIME_PARAM) {
383 		if (!is_hw_caps_supported(dev, ETHERNET_TXTIME)) {
384 			return -ENOTSUP;
385 		}
386 
387 		config.txtime_param.queue_id = params->txtime_param.queue_id;
388 		config.txtime_param.type = params->txtime_param.type;
389 
390 		type = ETHERNET_CONFIG_TYPE_TXTIME_PARAM;
391 
392 		ret = api->get_config(dev, type, &config);
393 		if (ret) {
394 			return ret;
395 		}
396 
397 		switch (config.txtime_param.type) {
398 		case ETHERNET_TXTIME_PARAM_TYPE_ENABLE_QUEUES:
399 			params->txtime_param.enable_txtime =
400 				config.txtime_param.enable_txtime;
401 			break;
402 		}
403 	} else if (mgmt_request == NET_REQUEST_ETHERNET_GET_TXINJECTION_MODE) {
404 		if (!is_hw_caps_supported(dev, ETHERNET_TXINJECTION_MODE)) {
405 			return -ENOTSUP;
406 		}
407 
408 		type = ETHERNET_CONFIG_TYPE_TXINJECTION_MODE;
409 
410 		ret = api->get_config(dev, type, &config);
411 		if (ret) {
412 			return ret;
413 		}
414 
415 		params->txinjection_mode = config.txinjection_mode;
416 	} else {
417 		return -EINVAL;
418 	}
419 
420 	return ret;
421 }
422 
423 NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_PRIORITY_QUEUES_NUM,
424 				  ethernet_get_config);
425 
426 NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_QAV_PARAM,
427 				  ethernet_get_config);
428 
429 NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_PORTS_NUM,
430 				  ethernet_get_config);
431 
432 NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_QBV_PARAM,
433 				  ethernet_get_config);
434 
435 NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_QBU_PARAM,
436 				  ethernet_get_config);
437 
438 NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_TXTIME_PARAM,
439 				  ethernet_get_config);
440 
441 NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_ETHERNET_GET_TXINJECTION_MODE,
442 				  ethernet_get_config);
443 
ethernet_mgmt_raise_carrier_on_event(struct net_if * iface)444 void ethernet_mgmt_raise_carrier_on_event(struct net_if *iface)
445 {
446 	net_mgmt_event_notify(NET_EVENT_ETHERNET_CARRIER_ON, iface);
447 }
448 
ethernet_mgmt_raise_carrier_off_event(struct net_if * iface)449 void ethernet_mgmt_raise_carrier_off_event(struct net_if *iface)
450 {
451 	net_mgmt_event_notify(NET_EVENT_ETHERNET_CARRIER_OFF, iface);
452 }
453 
ethernet_mgmt_raise_vlan_enabled_event(struct net_if * iface,uint16_t tag)454 void ethernet_mgmt_raise_vlan_enabled_event(struct net_if *iface, uint16_t tag)
455 {
456 #if defined(CONFIG_NET_MGMT_EVENT_INFO)
457 	net_mgmt_event_notify_with_info(NET_EVENT_ETHERNET_VLAN_TAG_ENABLED,
458 					iface, &tag, sizeof(tag));
459 #else
460 	net_mgmt_event_notify(NET_EVENT_ETHERNET_VLAN_TAG_ENABLED,
461 			      iface);
462 #endif
463 }
464 
ethernet_mgmt_raise_vlan_disabled_event(struct net_if * iface,uint16_t tag)465 void ethernet_mgmt_raise_vlan_disabled_event(struct net_if *iface, uint16_t tag)
466 {
467 #if defined(CONFIG_NET_MGMT_EVENT_INFO)
468 	net_mgmt_event_notify_with_info(NET_EVENT_ETHERNET_VLAN_TAG_DISABLED,
469 					iface, &tag, sizeof(tag));
470 #else
471 	net_mgmt_event_notify(NET_EVENT_ETHERNET_VLAN_TAG_DISABLED, iface);
472 #endif
473 }
474