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