1 /*
2  * Copyright (c) 2019 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(net_mgmt_sock_sample, LOG_LEVEL_DBG);
9 
10 #include <zephyr/kernel.h>
11 #include <errno.h>
12 #include <stdio.h>
13 #include <zephyr/net/socket.h>
14 #include <zephyr/net/socket_net_mgmt.h>
15 #include <zephyr/net/net_if.h>
16 
17 #define MAX_BUF_LEN 64
18 #define STACK_SIZE 1024
19 #if defined(CONFIG_NET_TC_THREAD_COOPERATIVE)
20 #define THREAD_PRIORITY K_PRIO_COOP(CONFIG_NUM_COOP_PRIORITIES - 1)
21 #else
22 #define THREAD_PRIORITY K_PRIO_PREEMPT(8)
23 #endif
24 
25 /* A test thread that spits out events that we can catch and show to user */
trigger_events(void)26 static void trigger_events(void)
27 {
28 	int operation = 0;
29 	struct net_if_addr *ifaddr_v6;
30 	struct net_if *iface;
31 	struct in6_addr addr_v6;
32 	int ret;
33 
34 	iface = net_if_get_default();
35 
36 	net_ipv6_addr_create(&addr_v6, 0x2001, 0x0db8, 0, 0, 0, 0, 0, 0x0003);
37 
38 	while (1) {
39 		switch (operation) {
40 		case 0:
41 			ifaddr_v6 = net_if_ipv6_addr_add(iface, &addr_v6,
42 							 NET_ADDR_MANUAL, 0);
43 			if (!ifaddr_v6) {
44 				LOG_ERR("Cannot add IPv%c address", '6');
45 				break;
46 			}
47 
48 			break;
49 		case 1:
50 			ret = net_if_ipv6_addr_rm(iface, &addr_v6);
51 			if (!ret) {
52 				LOG_ERR("Cannot del IPv%c address", '6');
53 				break;
54 			}
55 
56 			break;
57 		default:
58 			operation = -1;
59 			break;
60 		}
61 
62 		operation++;
63 
64 		k_sleep(K_SECONDS(1));
65 	}
66 }
67 
68 K_THREAD_DEFINE(trigger_events_thread_id, STACK_SIZE,
69 		trigger_events, NULL, NULL, NULL,
70 		THREAD_PRIORITY, 0, -1);
71 
get_ip_addr(char * ipaddr,size_t len,sa_family_t family,struct net_mgmt_msghdr * hdr)72 static char *get_ip_addr(char *ipaddr, size_t len, sa_family_t family,
73 			 struct net_mgmt_msghdr *hdr)
74 {
75 	char *buf;
76 
77 	buf = net_addr_ntop(family, hdr->nm_msg, ipaddr, len);
78 	if (!buf) {
79 		return "?";
80 	}
81 
82 	return buf;
83 }
84 
listener(void * p1,void * p2,void * p3)85 static void listener(void *p1, void *p2, void *p3)
86 {
87 	ARG_UNUSED(p1);
88 	ARG_UNUSED(p2);
89 	ARG_UNUSED(p3);
90 
91 	struct sockaddr_nm sockaddr;
92 	struct sockaddr_nm event_addr;
93 	socklen_t event_addr_len;
94 	char ipaddr[INET6_ADDRSTRLEN];
95 	uint8_t buf[MAX_BUF_LEN];
96 	int fd, ret;
97 
98 	fd = socket(AF_NET_MGMT, SOCK_DGRAM, NET_MGMT_EVENT_PROTO);
99 	if (fd < 0) {
100 		printk("Cannot create net_mgmt socket (%d)\n", errno);
101 		exit(1);
102 	}
103 
104 	memset(&sockaddr, 0, sizeof(sockaddr));
105 
106 	sockaddr.nm_family = AF_NET_MGMT;
107 	sockaddr.nm_ifindex = 0; /* Any network interface */
108 	sockaddr.nm_pid = (uintptr_t)k_current_get();
109 	sockaddr.nm_mask = NET_EVENT_IPV6_DAD_SUCCEED |
110 			    NET_EVENT_IPV6_ADDR_ADD |
111 			    NET_EVENT_IPV6_ADDR_DEL;
112 
113 	ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
114 	if (ret < 0) {
115 		printk("Cannot bind net_mgmt socket (%d)\n", errno);
116 		exit(1);
117 	}
118 
119 	while (1) {
120 		struct net_mgmt_msghdr *hdr;
121 
122 		memset(buf, 0, sizeof(buf));
123 		event_addr_len = sizeof(event_addr);
124 
125 		ret = recvfrom(fd, buf, sizeof(buf), 0,
126 			       (struct sockaddr *)&event_addr,
127 			       &event_addr_len);
128 		if (ret < 0) {
129 			continue;
130 		}
131 
132 		hdr = (struct net_mgmt_msghdr *)buf;
133 
134 		if (hdr->nm_msg_version != NET_MGMT_SOCKET_VERSION_1) {
135 			/* Do not know how to parse the message */
136 			continue;
137 		}
138 
139 		switch (event_addr.nm_mask) {
140 		case NET_EVENT_IPV6_DAD_SUCCEED:
141 			printk("DAD succeed for interface %d (%s)\n",
142 			       event_addr.nm_ifindex,
143 			       get_ip_addr(ipaddr, sizeof(ipaddr),
144 					   AF_INET6, hdr));
145 			break;
146 		case NET_EVENT_IPV6_ADDR_ADD:
147 			printk("IPv6 address added to interface %d (%s)\n",
148 			       event_addr.nm_ifindex,
149 			       get_ip_addr(ipaddr, sizeof(ipaddr),
150 					   AF_INET6, hdr));
151 			break;
152 		case NET_EVENT_IPV6_ADDR_DEL:
153 			printk("IPv6 address removed from interface %d (%s)\n",
154 			       event_addr.nm_ifindex,
155 			       get_ip_addr(ipaddr, sizeof(ipaddr),
156 					   AF_INET6, hdr));
157 			break;
158 		}
159 	}
160 }
161 
main(void)162 int main(void)
163 {
164 	/* The thread start to trigger network management events that
165 	 * we then can catch.
166 	 */
167 	k_thread_start(trigger_events_thread_id);
168 
169 	if (IS_ENABLED(CONFIG_USERSPACE)) {
170 		k_thread_user_mode_enter(listener,
171 					 NULL, NULL, NULL);
172 	} else {
173 		listener(NULL, NULL, NULL);
174 	}
175 	return 0;
176 }
177