1 /*
2  * Copyright (c) 2024 Nordic Semiconductor
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(net_ethernet_vlan, CONFIG_NET_L2_ETHERNET_LOG_LEVEL);
9 
10 #include <zephyr/net/net_core.h>
11 #include <zephyr/net/net_l2.h>
12 #include <zephyr/net/net_if.h>
13 #include <zephyr/net/net_mgmt.h>
14 #include <zephyr/net/ethernet.h>
15 #include <zephyr/net/ethernet_mgmt.h>
16 #include <zephyr/net/virtual.h>
17 #include <zephyr/random/random.h>
18 
19 #include "net_private.h"
20 
21 #if defined(CONFIG_NET_VLAN_TXRX_DEBUG)
22 #define DEBUG_TX 1
23 #define DEBUG_RX 1
24 #else
25 #define DEBUG_TX 0
26 #define DEBUG_RX 0
27 #endif
28 
29 /* If the VLAN interface count is 0, then only priority tagged (tag 0)
30  * Ethernet frames can be received. In this case we do not need to
31  * allocate any memory for VLAN interfaces.
32  */
33 #if CONFIG_NET_VLAN_COUNT > 0
34 
35 #define MAX_VIRT_NAME_LEN MIN(sizeof("<not attached>"), \
36 			      CONFIG_NET_L2_VIRTUAL_MAX_NAME_LEN)
37 
38 static void vlan_iface_init(struct net_if *iface);
39 static int vlan_interface_attach(struct net_if *vlan_iface,
40 				 struct net_if *iface);
41 static enum net_verdict vlan_interface_recv(struct net_if *iface,
42 					    struct net_pkt *pkt);
43 static int vlan_interface_send(struct net_if *iface, struct net_pkt *pkt);
44 static int vlan_interface_stop(const struct device *dev);
45 static enum virtual_interface_caps vlan_get_capabilities(struct net_if *iface);
46 static int vlan_interface_start(const struct device *dev);
47 static int virt_dev_init(const struct device *dev);
48 
49 static K_MUTEX_DEFINE(lock);
50 
51 struct vlan_context {
52 	struct net_if *iface;
53 	struct net_if *attached_to;
54 	uint16_t tag;
55 	bool status : 1;    /* Is the interface enabled or not */
56 	bool is_used : 1;   /* Is there active config on this context */
57 	bool init_done : 1; /* Is interface init called for this context */
58 };
59 
60 static const struct virtual_interface_api vlan_iface_api = {
61 	.iface_api.init = vlan_iface_init,
62 
63 	.get_capabilities = vlan_get_capabilities,
64 	.start = vlan_interface_start,
65 	.stop = vlan_interface_stop,
66 	.send = vlan_interface_send,
67 	.recv = vlan_interface_recv,
68 	.attach = vlan_interface_attach,
69 };
70 
71 #define ETH_DEFINE_VLAN(x, _)						\
72 	static struct vlan_context vlan_context_data_##x = {		\
73 		.tag = NET_VLAN_TAG_UNSPEC,				\
74 	};								\
75 	NET_VIRTUAL_INTERFACE_INIT_INSTANCE(vlan_##x,			\
76 					    "VLAN_" #x,			\
77 					    x,				\
78 					    virt_dev_init,		\
79 					    NULL,			\
80 					    &vlan_context_data_##x,	\
81 					    NULL, /* config */		\
82 					    CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
83 					    &vlan_iface_api,		\
84 					    NET_ETH_MTU)
85 
86 LISTIFY(CONFIG_NET_VLAN_COUNT, ETH_DEFINE_VLAN, (;), _);
87 
88 #define INIT_VLAN_CONTEXT_PTR(x, _)					\
89 	[x] = &vlan_context_data_##x					\
90 
91 static struct vlan_context *vlan_ctx[] = {
92 	LISTIFY(CONFIG_NET_VLAN_COUNT, INIT_VLAN_CONTEXT_PTR, (,), _)
93 };
94 
95 #define INIT_VLAN_CONTEXT_IFACE(x, _)					\
96 	vlan_context_data_##x.iface = NET_IF_GET(vlan_##x, x)
97 
init_context_iface(void)98 static void init_context_iface(void)
99 {
100 	static bool init_done;
101 
102 	if (init_done) {
103 		return;
104 	}
105 
106 	init_done = true;
107 
108 	LISTIFY(CONFIG_NET_VLAN_COUNT, INIT_VLAN_CONTEXT_IFACE, (;), _);
109 }
110 
virt_dev_init(const struct device * dev)111 static int virt_dev_init(const struct device *dev)
112 {
113 	ARG_UNUSED(dev);
114 
115 	init_context_iface();
116 
117 	return 0;
118 }
119 
get_vlan_ctx(struct net_if * main_iface,uint16_t vlan_tag,bool any_tag)120 static struct vlan_context *get_vlan_ctx(struct net_if *main_iface,
121 					 uint16_t vlan_tag,
122 					 bool any_tag)
123 {
124 	struct virtual_interface_context *vctx, *tmp;
125 	sys_slist_t *interfaces;
126 	struct vlan_context *ctx;
127 
128 	interfaces = &main_iface->config.virtual_interfaces;
129 
130 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(interfaces, vctx, tmp, node) {
131 		enum virtual_interface_caps caps;
132 
133 		if (vctx->virtual_iface == NULL) {
134 			continue;
135 		}
136 
137 		caps = net_virtual_get_iface_capabilities(vctx->virtual_iface);
138 		if (!(caps & VIRTUAL_INTERFACE_VLAN)) {
139 			continue;
140 		}
141 
142 		ctx = net_if_get_device(vctx->virtual_iface)->data;
143 
144 		if (any_tag) {
145 			if (ctx->tag != NET_VLAN_TAG_UNSPEC) {
146 				return ctx;
147 			}
148 		} else {
149 			if ((vlan_tag == NET_VLAN_TAG_UNSPEC ||
150 			     vlan_tag == ctx->tag)) {
151 				return ctx;
152 			}
153 		}
154 	}
155 
156 	return NULL;
157 }
158 
get_vlan(struct net_if * iface,uint16_t vlan_tag)159 static struct vlan_context *get_vlan(struct net_if *iface,
160 				     uint16_t vlan_tag)
161 {
162 	struct vlan_context *ctx = NULL;
163 
164 	k_mutex_lock(&lock, K_FOREVER);
165 
166 	/* If the interface is NULL, then get the VLAN that has the tag */
167 	if (iface == NULL) {
168 		ARRAY_FOR_EACH(vlan_ctx, i) {
169 			if (vlan_ctx[i] == NULL || !vlan_ctx[i]->is_used) {
170 				continue;
171 			}
172 
173 			if (vlan_tag == vlan_ctx[i]->tag) {
174 				ctx = vlan_ctx[i];
175 				break;
176 			}
177 		}
178 
179 		goto out;
180 	}
181 
182 	/* If the interface is the main Ethernet one, then we only need
183 	 * to go through its attached virtual interfaces.
184 	 */
185 	if (net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET)) {
186 
187 		ctx = get_vlan_ctx(iface, vlan_tag, false);
188 		goto out;
189 
190 	}
191 
192 	if (net_if_l2(iface) != &NET_L2_GET_NAME(VIRTUAL)) {
193 		goto out;
194 	}
195 
196 	/* If the interface is virtual, then it should be the VLAN one.
197 	 * Just get the Ethernet interface it points to get the context.
198 	 */
199 	ctx = get_vlan_ctx(net_virtual_get_iface(iface), vlan_tag, false);
200 
201 out:
202 	k_mutex_unlock(&lock);
203 
204 	return ctx;
205 }
206 
set_priority(struct net_pkt * pkt)207 static void set_priority(struct net_pkt *pkt)
208 {
209 	uint8_t vlan_priority;
210 
211 	vlan_priority = net_priority2vlan(net_pkt_priority(pkt));
212 	net_pkt_set_vlan_priority(pkt, vlan_priority);
213 }
214 
net_eth_get_vlan_iface(struct net_if * iface,uint16_t tag)215 struct net_if *net_eth_get_vlan_iface(struct net_if *iface, uint16_t tag)
216 {
217 	struct vlan_context *ctx;
218 
219 	ctx = get_vlan(iface, tag);
220 	if (ctx == NULL) {
221 		if (tag == NET_VLAN_TAG_PRIORITY) {
222 			return iface;
223 		}
224 
225 		return NULL;
226 	}
227 
228 	return ctx->iface;
229 }
230 
net_eth_get_vlan_main(struct net_if * iface)231 struct net_if *net_eth_get_vlan_main(struct net_if *iface)
232 {
233 	struct vlan_context *ctx;
234 
235 	ctx = get_vlan(iface, NET_VLAN_TAG_UNSPEC);
236 	if (ctx == NULL) {
237 		return NULL;
238 	}
239 
240 	return ctx->attached_to;
241 }
242 
enable_vlan_iface(struct vlan_context * ctx,struct net_if * iface)243 static bool enable_vlan_iface(struct vlan_context *ctx,
244 			      struct net_if *iface)
245 {
246 	int iface_idx = net_if_get_by_iface(iface);
247 	char name[MAX_VIRT_NAME_LEN];
248 	int ret;
249 
250 	if (iface_idx < 0) {
251 		return false;
252 	}
253 
254 	ret = net_virtual_interface_attach(ctx->iface, iface);
255 	if (ret < 0) {
256 		NET_DBG("Cannot attach iface %d to %d",
257 			net_if_get_by_iface(ctx->iface),
258 			net_if_get_by_iface(ctx->attached_to));
259 		return false;
260 	}
261 
262 	ctx->is_used = true;
263 
264 	snprintk(name, sizeof(name), "VLAN to %d",
265 		 net_if_get_by_iface(ctx->attached_to));
266 	net_virtual_set_name(ctx->iface, name);
267 
268 	return true;
269 }
270 
disable_vlan_iface(struct vlan_context * ctx,struct net_if * iface)271 static bool disable_vlan_iface(struct vlan_context *ctx,
272 			       struct net_if *iface)
273 {
274 	int iface_idx = net_if_get_by_iface(iface);
275 	char name[MAX_VIRT_NAME_LEN];
276 
277 	if (iface_idx < 0) {
278 		return false;
279 	}
280 
281 	(void)net_virtual_interface_attach(iface, NULL);
282 	ctx->is_used = false;
283 
284 	snprintk(name, sizeof(name), "<not attached>");
285 	net_virtual_set_name(iface, name);
286 
287 	return true;
288 }
289 
is_vlan_enabled_for_iface(struct net_if * iface)290 static bool is_vlan_enabled_for_iface(struct net_if *iface)
291 {
292 	int iface_idx = net_if_get_by_iface(iface);
293 	struct vlan_context *ctx;
294 	bool ret = false;
295 
296 	if (iface_idx < 0) {
297 		return false;
298 	}
299 
300 	k_mutex_lock(&lock, K_FOREVER);
301 
302 	ctx = get_vlan_ctx(iface, NET_VLAN_TAG_UNSPEC, true);
303 	ret = (ctx != NULL);
304 
305 	k_mutex_unlock(&lock);
306 
307 	return ret;
308 }
309 
net_eth_is_vlan_enabled(struct ethernet_context * ctx,struct net_if * iface)310 bool net_eth_is_vlan_enabled(struct ethernet_context *ctx,
311 			     struct net_if *iface)
312 {
313 	ARG_UNUSED(ctx);
314 
315 	return is_vlan_enabled_for_iface(iface);
316 }
317 
net_eth_get_vlan_tag(struct net_if * iface)318 uint16_t net_eth_get_vlan_tag(struct net_if *iface)
319 {
320 	uint16_t tag = NET_VLAN_TAG_UNSPEC;
321 
322 	k_mutex_lock(&lock, K_FOREVER);
323 
324 	ARRAY_FOR_EACH(vlan_ctx, i) {
325 		if (vlan_ctx[i] == NULL || !vlan_ctx[i]->is_used) {
326 			continue;
327 		}
328 
329 		if (vlan_ctx[i]->iface == iface) {
330 			tag = vlan_ctx[i]->tag;
331 			break;
332 		}
333 	}
334 
335 	k_mutex_unlock(&lock);
336 
337 	return tag;
338 }
339 
net_eth_is_vlan_interface(struct net_if * iface)340 bool net_eth_is_vlan_interface(struct net_if *iface)
341 {
342 	enum virtual_interface_caps caps;
343 
344 	if (net_if_l2(iface) != &NET_L2_GET_NAME(VIRTUAL)) {
345 		return false;
346 	}
347 
348 	caps = net_virtual_get_iface_capabilities(iface);
349 	if (!(caps & VIRTUAL_INTERFACE_VLAN)) {
350 		return false;
351 	}
352 
353 	return true;
354 }
355 
net_eth_get_vlan_status(struct net_if * iface)356 bool net_eth_get_vlan_status(struct net_if *iface)
357 {
358 	bool status = false;
359 	struct vlan_context *ctx;
360 
361 	k_mutex_lock(&lock, K_FOREVER);
362 
363 	ctx = get_vlan_ctx(iface, NET_VLAN_TAG_UNSPEC, true);
364 	if (ctx != NULL) {
365 		status = ctx->status;
366 	}
367 
368 	k_mutex_unlock(&lock);
369 
370 	return status;
371 }
372 
setup_link_address(struct vlan_context * ctx)373 static void setup_link_address(struct vlan_context *ctx)
374 {
375 	struct net_linkaddr *ll_addr;
376 
377 	ll_addr = net_if_get_link_addr(ctx->attached_to);
378 
379 	(void)net_if_set_link_addr(ctx->iface,
380 				   ll_addr->addr,
381 				   ll_addr->len,
382 				   ll_addr->type);
383 }
384 
net_eth_vlan_enable(struct net_if * iface,uint16_t tag)385 int net_eth_vlan_enable(struct net_if *iface, uint16_t tag)
386 {
387 	struct ethernet_context *ctx = net_if_l2_data(iface);
388 	const struct ethernet_api *eth = net_if_get_device(iface)->api;
389 	struct vlan_context *vlan;
390 	int ret;
391 
392 	if (!eth) {
393 		return -ENOENT;
394 	}
395 
396 	if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET)) {
397 		return -EINVAL;
398 	}
399 
400 	if (!(net_eth_get_hw_capabilities(iface) & ETHERNET_HW_VLAN)) {
401 		NET_DBG("Interface %d does not support VLAN",
402 			net_if_get_by_iface(iface));
403 		return -ENOTSUP;
404 	}
405 
406 	if (!ctx->is_init) {
407 		return -EPERM;
408 	}
409 
410 	if (tag >= NET_VLAN_TAG_UNSPEC) {
411 		return -EBADF;
412 	}
413 
414 	vlan = get_vlan(iface, tag);
415 	if (vlan != NULL) {
416 		return -EALREADY;
417 	}
418 
419 	/* This will make sure that the tag is not yet in use by some
420 	 * other interface.
421 	 */
422 	vlan = get_vlan(NULL, tag);
423 	if (vlan != NULL) {
424 		return -EALREADY;
425 	}
426 
427 	ret = -ENOSPC;
428 
429 	k_mutex_lock(&lock, K_FOREVER);
430 
431 	ARRAY_FOR_EACH(vlan_ctx, i) {
432 		if (vlan_ctx[i] == NULL || vlan_ctx[i]->is_used) {
433 			continue;
434 		}
435 
436 		vlan = vlan_ctx[i];
437 		vlan->tag = tag;
438 
439 		if (!enable_vlan_iface(vlan, iface)) {
440 			continue;
441 		}
442 
443 		NET_DBG("[%zd] Adding vlan tag %d to iface %d (%p) attached to %d (%p)",
444 			i, vlan->tag, net_if_get_by_iface(vlan->iface), vlan->iface,
445 			net_if_get_by_iface(iface), iface);
446 
447 		/* Use MAC address of the attached Ethernet interface so that
448 		 * packet reception works without any tweaks.
449 		 */
450 		setup_link_address(vlan);
451 
452 		if (eth->vlan_setup) {
453 			eth->vlan_setup(net_if_get_device(iface),
454 					iface, vlan->tag, true);
455 		}
456 
457 		ethernet_mgmt_raise_vlan_enabled_event(vlan->iface, vlan->tag);
458 
459 		ret = 0;
460 		break;
461 	}
462 
463 	k_mutex_unlock(&lock);
464 
465 	return ret;
466 }
467 
net_eth_vlan_disable(struct net_if * iface,uint16_t tag)468 int net_eth_vlan_disable(struct net_if *iface, uint16_t tag)
469 {
470 	const struct ethernet_api *eth;
471 	struct vlan_context *vlan;
472 
473 	if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET) &&
474 	    net_if_l2(iface) != &NET_L2_GET_NAME(VIRTUAL)) {
475 		return -EINVAL;
476 	}
477 
478 	if (tag == NET_VLAN_TAG_UNSPEC) {
479 		return -EBADF;
480 	}
481 
482 	vlan = get_vlan(iface, tag);
483 	if (!vlan) {
484 		return -ESRCH;
485 	}
486 
487 	eth = net_if_get_device(vlan->attached_to)->api;
488 
489 	k_mutex_lock(&lock, K_FOREVER);
490 
491 	NET_DBG("Removing vlan tag %d from VLAN iface %d (%p) attached to %d (%p)",
492 		vlan->tag, net_if_get_by_iface(vlan->iface), vlan->iface,
493 		net_if_get_by_iface(vlan->attached_to), vlan->attached_to);
494 
495 	vlan->tag = NET_VLAN_TAG_UNSPEC;
496 
497 	if (eth->vlan_setup) {
498 		eth->vlan_setup(net_if_get_device(vlan->attached_to),
499 				vlan->attached_to, tag, false);
500 	}
501 
502 	ethernet_mgmt_raise_vlan_disabled_event(vlan->iface, tag);
503 
504 	(void)disable_vlan_iface(vlan, vlan->iface);
505 
506 	k_mutex_unlock(&lock);
507 
508 	return 0;
509 }
510 
vlan_get_capabilities(struct net_if * iface)511 static enum virtual_interface_caps vlan_get_capabilities(struct net_if *iface)
512 {
513 	ARG_UNUSED(iface);
514 
515 	return VIRTUAL_INTERFACE_VLAN;
516 }
517 
vlan_interface_start(const struct device * dev)518 static int vlan_interface_start(const struct device *dev)
519 {
520 	struct vlan_context *ctx = dev->data;
521 
522 	if (!ctx->is_used) {
523 		NET_DBG("VLAN interface %d not configured yet.",
524 			net_if_get_by_iface(ctx->iface));
525 		return -ENOENT;
526 	}
527 
528 	if (ctx->status) {
529 		return -EALREADY;
530 	}
531 
532 	ctx->status = true;
533 
534 	NET_DBG("Starting iface %d", net_if_get_by_iface(ctx->iface));
535 
536 	/* You can implement here any special action that is needed
537 	 * when the network interface is coming up.
538 	 */
539 
540 	return 0;
541 }
542 
vlan_interface_stop(const struct device * dev)543 static int vlan_interface_stop(const struct device *dev)
544 {
545 	struct vlan_context *ctx = dev->data;
546 
547 	if (!ctx->is_used) {
548 		NET_DBG("VLAN interface %d not configured yet.",
549 			net_if_get_by_iface(ctx->iface));
550 		return -ENOENT;
551 	}
552 
553 	if (!ctx->status) {
554 		return -EALREADY;
555 	}
556 
557 	ctx->status = false;
558 
559 	NET_DBG("Stopping iface %d", net_if_get_by_iface(ctx->iface));
560 
561 	/* You can implement here any special action that is needed
562 	 * when the network interface is going down.
563 	 */
564 
565 	return 0;
566 }
567 
vlan_interface_send(struct net_if * iface,struct net_pkt * pkt)568 static int vlan_interface_send(struct net_if *iface, struct net_pkt *pkt)
569 {
570 	struct vlan_context *ctx = net_if_get_device(iface)->data;
571 
572 	if (ctx->attached_to == NULL) {
573 		return -ENOENT;
574 	}
575 
576 	net_pkt_set_vlan_tag(pkt, ctx->tag);
577 	net_pkt_set_iface(pkt, ctx->attached_to);
578 	set_priority(pkt);
579 
580 	if (DEBUG_TX) {
581 		char str[sizeof("TX iface xx (tag xxxx)")];
582 
583 		snprintk(str, sizeof(str), "TX iface %d (tag %d)",
584 			 net_if_get_by_iface(net_pkt_iface(pkt)),
585 			 ctx->tag);
586 
587 		net_pkt_hexdump(pkt, str);
588 	}
589 
590 	return net_send_data(pkt);
591 }
592 
vlan_interface_recv(struct net_if * iface,struct net_pkt * pkt)593 static enum net_verdict vlan_interface_recv(struct net_if *iface,
594 					    struct net_pkt *pkt)
595 {
596 	struct vlan_context *ctx = net_if_get_device(iface)->data;
597 
598 	if (net_pkt_vlan_tag(pkt) != ctx->tag) {
599 		return NET_CONTINUE;
600 	}
601 
602 	if (DEBUG_RX) {
603 		char str[sizeof("RX iface xx (tag xxxx)")];
604 
605 		snprintk(str, sizeof(str), "RX iface %d (tag %d)",
606 			 net_if_get_by_iface(iface),
607 			 net_pkt_vlan_tag(pkt));
608 
609 		net_pkt_hexdump(pkt, str);
610 	}
611 
612 	return NET_OK;
613 }
614 
vlan_alloc_buffer(struct net_if * iface,struct net_pkt * pkt,size_t size,uint16_t proto,k_timeout_t timeout)615 int vlan_alloc_buffer(struct net_if *iface, struct net_pkt *pkt,
616 		      size_t size, uint16_t proto, k_timeout_t timeout)
617 {
618 	enum virtual_interface_caps caps;
619 	int ret = 0;
620 
621 	caps = net_virtual_get_iface_capabilities(iface);
622 	if (caps & VIRTUAL_INTERFACE_VLAN) {
623 		ret = net_pkt_alloc_buffer_with_reserve(pkt, size,
624 							sizeof(struct net_eth_vlan_hdr),
625 							proto, timeout);
626 	}
627 
628 	return ret;
629 }
630 
vlan_interface_attach(struct net_if * vlan_iface,struct net_if * iface)631 static int vlan_interface_attach(struct net_if *vlan_iface,
632 				 struct net_if *iface)
633 {
634 	struct vlan_context *ctx = net_if_get_device(vlan_iface)->data;
635 
636 	if (iface == NULL) {
637 		NET_DBG("VLAN interface %d (%p) detached from %d (%p)",
638 			net_if_get_by_iface(vlan_iface), vlan_iface,
639 			net_if_get_by_iface(ctx->attached_to), ctx->attached_to);
640 	} else {
641 		NET_DBG("VLAN interface %d (%p) attached to %d (%p)",
642 			net_if_get_by_iface(vlan_iface), vlan_iface,
643 			net_if_get_by_iface(iface), iface);
644 	}
645 
646 	ctx->attached_to = iface;
647 
648 	return 0;
649 }
650 
vlan_iface_init(struct net_if * iface)651 static void vlan_iface_init(struct net_if *iface)
652 {
653 	struct vlan_context *ctx = net_if_get_device(iface)->data;
654 	char name[MAX_VIRT_NAME_LEN];
655 
656 	if (ctx->init_done) {
657 		return;
658 	}
659 
660 	ctx->iface = iface;
661 	net_if_flag_set(iface, NET_IF_NO_AUTO_START);
662 
663 	snprintk(name, sizeof(name), "not attached");
664 	net_virtual_set_name(iface, name);
665 
666 	(void)net_virtual_set_flags(ctx->iface, NET_L2_MULTICAST);
667 
668 	ctx->init_done = true;
669 }
670 
671 #else /* CONFIG_NET_VLAN_COUNT > 0 */
672 
673 /* Dummy functions if VLAN is not really used. This is only needed
674  * if priority tagged frames (tag 0) are supported.
675  */
net_eth_is_vlan_enabled(struct ethernet_context * ctx,struct net_if * iface)676 bool net_eth_is_vlan_enabled(struct ethernet_context *ctx,
677 			     struct net_if *iface)
678 {
679 	ARG_UNUSED(ctx);
680 	ARG_UNUSED(iface);
681 
682 	return true;
683 }
684 
net_eth_get_vlan_iface(struct net_if * iface,uint16_t tag)685 struct net_if *net_eth_get_vlan_iface(struct net_if *iface, uint16_t tag)
686 {
687 	if (tag == NET_VLAN_TAG_PRIORITY) {
688 		return iface;
689 	}
690 
691 	return NULL;
692 }
693 #endif /* CONFIG_NET_VLAN_COUNT > 0 */
694