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