]> git.proxmox.com Git - mirror_frr.git/blob - nhrpd/linux.c
Merge pull request #11060 from pguibert6WIND/isis_dr_resign_debug
[mirror_frr.git] / nhrpd / linux.c
1 /* NHRP daemon Linux specific glue
2 * Copyright (c) 2014-2015 Timo Teräs
3 *
4 * This file is free software: you may copy, redistribute and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 */
9
10 #include "zebra.h"
11
12 #include <errno.h>
13 #include <linux/if_packet.h>
14
15 #include "nhrp_protocol.h"
16 #include "os.h"
17
18 #ifndef HAVE_STRLCPY
19 size_t strlcpy(char *__restrict dest,
20 const char *__restrict src, size_t destsize);
21 #endif
22
23 static int nhrp_socket_fd = -1;
24
25 int os_socket(void)
26 {
27 if (nhrp_socket_fd < 0)
28 nhrp_socket_fd =
29 socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_NHRP));
30 return nhrp_socket_fd;
31 }
32
33 int os_sendmsg(const uint8_t *buf, size_t len, int ifindex, const uint8_t *addr,
34 size_t addrlen, uint16_t protocol)
35 {
36 struct sockaddr_ll lladdr;
37 struct iovec iov = {
38 .iov_base = (void *)buf, .iov_len = len,
39 };
40 struct msghdr msg = {
41 .msg_name = &lladdr,
42 .msg_namelen = sizeof(lladdr),
43 .msg_iov = &iov,
44 .msg_iovlen = 1,
45 };
46 int status, fd;
47
48 if (addrlen > sizeof(lladdr.sll_addr))
49 return -1;
50
51 memset(&lladdr, 0, sizeof(lladdr));
52 lladdr.sll_family = AF_PACKET;
53 lladdr.sll_protocol = htons(protocol);
54 lladdr.sll_ifindex = ifindex;
55 lladdr.sll_halen = addrlen;
56 memcpy(lladdr.sll_addr, addr, addrlen);
57
58 fd = os_socket();
59 if (fd < 0)
60 return -1;
61
62 status = sendmsg(fd, &msg, 0);
63 if (status < 0)
64 return -errno;
65
66 return status;
67 }
68
69 int os_recvmsg(uint8_t *buf, size_t *len, int *ifindex, uint8_t *addr,
70 size_t *addrlen)
71 {
72 struct sockaddr_ll lladdr;
73 struct iovec iov = {
74 .iov_base = buf, .iov_len = *len,
75 };
76 struct msghdr msg = {
77 .msg_name = &lladdr,
78 .msg_namelen = sizeof(lladdr),
79 .msg_iov = &iov,
80 .msg_iovlen = 1,
81 };
82 int r;
83
84 r = recvmsg(nhrp_socket_fd, &msg, MSG_DONTWAIT);
85 if (r < 0)
86 return r;
87
88 *len = r;
89 *ifindex = lladdr.sll_ifindex;
90
91 if (*addrlen <= (size_t)lladdr.sll_addr) {
92 if (memcmp(lladdr.sll_addr, "\x00\x00\x00\x00", 4) != 0) {
93 memcpy(addr, lladdr.sll_addr, lladdr.sll_halen);
94 *addrlen = lladdr.sll_halen;
95 } else {
96 *addrlen = 0;
97 }
98 }
99
100 return 0;
101 }
102
103 static int linux_configure_arp(const char *iface, int on)
104 {
105 struct ifreq ifr;
106
107 strlcpy(ifr.ifr_name, iface, IFNAMSIZ);
108 if (ioctl(nhrp_socket_fd, SIOCGIFFLAGS, &ifr))
109 return -1;
110
111 if (on)
112 ifr.ifr_flags &= ~IFF_NOARP;
113 else
114 ifr.ifr_flags |= IFF_NOARP;
115
116 if (ioctl(nhrp_socket_fd, SIOCSIFFLAGS, &ifr))
117 return -1;
118
119 return 0;
120 }
121
122 static int linux_icmp_redirect_off(const char *iface)
123 {
124 char fname[PATH_MAX];
125 int fd, ret = -1;
126
127 snprintf(fname, sizeof(fname),
128 "/proc/sys/net/ipv4/conf/%s/send_redirects", iface);
129 fd = open(fname, O_WRONLY);
130 if (fd < 0)
131 return -1;
132 if (write(fd, "0\n", 2) == 2)
133 ret = 0;
134 close(fd);
135
136 return ret;
137 }
138
139 int os_configure_dmvpn(unsigned int ifindex, const char *ifname, int af)
140 {
141 int ret = 0;
142
143 switch (af) {
144 case AF_INET:
145 ret |= linux_icmp_redirect_off("all");
146 ret |= linux_icmp_redirect_off(ifname);
147 break;
148 }
149 ret |= linux_configure_arp(ifname, 1);
150
151 return ret;
152 }