xref: /aosp_15_r20/external/ethtool/libmnl/examples/rtnl/rtnl-addr-add.c (revision 1b481fc3bb1b45d4cf28d1ec12969dc1055f555d)
1 /* This example is placed in the public domain. */
2 #include <netinet/in.h>
3 #include <arpa/inet.h>
4 #include <time.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <strings.h>
9 #include <net/if.h>
10 
11 #include <libmnl/libmnl.h>
12 #include <linux/if_link.h>
13 #include <linux/rtnetlink.h>
14 
main(int argc,char * argv[])15 int main(int argc, char *argv[])
16 {
17 	struct mnl_socket *nl;
18 	char buf[MNL_SOCKET_BUFFER_SIZE];
19 	struct nlmsghdr *nlh;
20 	struct ifaddrmsg *ifm;
21 	uint32_t seq, portid;
22 	union {
23 		in_addr_t ip;
24 		struct in6_addr ip6;
25 	} addr;
26 	int ret, family = AF_INET;
27 
28 	uint32_t prefix;
29 	int iface;
30 
31 
32 	if (argc <= 3) {
33 		printf("Usage: %s iface destination cidr\n", argv[0]);
34 		printf("Example: %s eth0 10.0.1.12 32\n", argv[0]);
35 		printf("	 %s eth0 ffff::10.0.1.12 128\n", argv[0]);
36 		exit(EXIT_FAILURE);
37 	}
38 
39 	iface = if_nametoindex(argv[1]);
40 	if (iface == 0) {
41 		perror("if_nametoindex");
42 		exit(EXIT_FAILURE);
43 	}
44 
45 	if (!inet_pton(AF_INET, argv[2], &addr)) {
46 		if (!inet_pton(AF_INET6, argv[2], &addr)) {
47 			perror("inet_pton");
48 			exit(EXIT_FAILURE);
49 		}
50 		family = AF_INET6;
51 	}
52 
53 	if (sscanf(argv[3], "%u", &prefix) == 0) {
54 		perror("sscanf");
55 		exit(EXIT_FAILURE);
56 	}
57 
58 	nlh = mnl_nlmsg_put_header(buf);
59 	nlh->nlmsg_type	= RTM_NEWADDR;
60 
61 	nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE | NLM_F_ACK;
62 	nlh->nlmsg_seq = seq = time(NULL);
63 
64 	ifm = mnl_nlmsg_put_extra_header(nlh, sizeof(struct ifaddrmsg));
65 
66 	ifm->ifa_family = family;
67 	ifm->ifa_prefixlen = prefix;
68 	ifm->ifa_flags = IFA_F_PERMANENT;
69 
70 	ifm->ifa_scope = RT_SCOPE_UNIVERSE;
71 	ifm->ifa_index = iface;
72 
73 	/*
74 	 * The exact meaning of IFA_LOCAL and IFA_ADDRESS depend
75 	 * on the address family being used and the device type.
76 	 * For broadcast devices (like the interfaces we use),
77 	 * for IPv4 we specify both and they are used interchangeably.
78 	 * For IPv6, only IFA_ADDRESS needs to be set.
79 	 */
80 	if (family == AF_INET) {
81 		mnl_attr_put_u32(nlh, IFA_LOCAL, addr.ip);
82 		mnl_attr_put_u32(nlh, IFA_ADDRESS, addr.ip);
83 	} else {
84 		mnl_attr_put(nlh, IFA_ADDRESS, sizeof(struct in6_addr), &addr);
85 	}
86 
87 	nl = mnl_socket_open(NETLINK_ROUTE);
88 	if (nl == NULL) {
89 		perror("mnl_socket_open");
90 		exit(EXIT_FAILURE);
91 	}
92 
93 	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
94 		perror("mnl_socket_bind");
95 		exit(EXIT_FAILURE);
96 	}
97 	portid = mnl_socket_get_portid(nl);
98 
99 	if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
100 		perror("mnl_socket_sendto");
101 		exit(EXIT_FAILURE);
102 	}
103 
104 	ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
105 	if (ret < 0) {
106 		perror("mnl_socket_recvfrom");
107 		exit(EXIT_FAILURE);
108 	}
109 
110 	ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL);
111 	if (ret < 0) {
112 		perror("mnl_cb_run");
113 		exit(EXIT_FAILURE);
114 	}
115 
116 	mnl_socket_close(nl);
117 
118 	return 0;
119 }
120