source: src/router/quagga/nhrpd/linux.c @ 31640

Last change on this file since 31640 was 31640, checked in by brainslayer, 2 months ago

update quagga

File size: 3.1 KB
Line 
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 <fcntl.h>
11#include <stdio.h>
12#include <unistd.h>
13#include <string.h>
14#include <sys/ioctl.h>
15#include <sys/socket.h>
16#include <sys/types.h>
17#include <asm/types.h>
18#include <arpa/inet.h>
19#include <linux/netlink.h>
20#include <linux/rtnetlink.h>
21#include <linux/ip.h>
22#include <linux/if_arp.h>
23#include <linux/if_tunnel.h>
24
25#include "nhrp_protocol.h"
26#include "os.h"
27#include "netlink.h"
28
29static int nhrp_socket_fd = -1;
30
31int os_socket(void)
32{
33        if (nhrp_socket_fd < 0)
34                nhrp_socket_fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_NHRP));
35        return nhrp_socket_fd;
36}
37
38int os_sendmsg(const uint8_t *buf, size_t len, int ifindex, const uint8_t *addr, size_t addrlen)
39{
40        struct sockaddr_ll lladdr;
41        struct iovec iov = {
42                .iov_base = (void*) buf,
43                .iov_len = len,
44        };
45        struct msghdr msg = {
46                .msg_name = &lladdr,
47                .msg_namelen = sizeof(lladdr),
48                .msg_iov = &iov,
49                .msg_iovlen = 1,
50        };
51        int status;
52
53        if (addrlen > sizeof(lladdr.sll_addr))
54                return -1;
55
56        memset(&lladdr, 0, sizeof(lladdr));
57        lladdr.sll_family = AF_PACKET;
58        lladdr.sll_protocol = htons(ETH_P_NHRP);
59        lladdr.sll_ifindex = ifindex;
60        lladdr.sll_halen = addrlen;
61        memcpy(lladdr.sll_addr, addr, addrlen);
62
63        status = sendmsg(nhrp_socket_fd, &msg, 0);
64        if (status < 0)
65                return -1;
66
67        return 0;
68}
69
70int os_recvmsg(uint8_t *buf, size_t *len, int *ifindex, uint8_t *addr, size_t *addrlen)
71{
72        struct sockaddr_ll lladdr;
73        struct iovec iov = {
74                .iov_base = buf,
75                .iov_len = *len,
76        };
77        struct msghdr msg = {
78                .msg_name = &lladdr,
79                .msg_namelen = sizeof(lladdr),
80                .msg_iov = &iov,
81                .msg_iovlen = 1,
82        };
83        int r;
84
85        r = recvmsg(nhrp_socket_fd, &msg, MSG_DONTWAIT);
86        if (r < 0)
87                return r;
88
89        *len = r;
90        *ifindex = lladdr.sll_ifindex;
91
92        if (*addrlen <= (size_t) lladdr.sll_addr) {
93                if (memcmp(lladdr.sll_addr, "\x00\x00\x00\x00", 4) != 0) {
94                        memcpy(addr, lladdr.sll_addr, lladdr.sll_halen);
95                        *addrlen = lladdr.sll_halen;
96                } else {
97                        *addrlen = 0;
98                }
99        }
100
101        return 0;
102}
103
104static int linux_configure_arp(const char *iface, int on)
105{
106        struct ifreq ifr;
107
108        strncpy(ifr.ifr_name, iface, IFNAMSIZ);
109        if (ioctl(nhrp_socket_fd, SIOCGIFFLAGS, &ifr))
110                return -1;
111
112        if (on)
113                ifr.ifr_flags &= ~IFF_NOARP;
114        else
115                ifr.ifr_flags |= IFF_NOARP;
116
117        if (ioctl(nhrp_socket_fd, SIOCSIFFLAGS, &ifr))
118                return -1;
119
120        return 0;
121}
122
123static int linux_icmp_redirect_off(const char *iface)
124{
125        char fname[256];
126        int fd, ret = -1;
127
128        sprintf(fname, "/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
139int os_configure_dmvpn(unsigned int ifindex, const char *ifname, int af)
140{
141        int ret = -1;
142
143        switch (af) {
144        case AF_INET:
145                ret  = linux_icmp_redirect_off("all");
146                ret |= linux_icmp_redirect_off(ifname);
147                ret |= netlink_configure_arp(ifindex, AF_INET);
148                ret |= linux_configure_arp(ifname, 1);
149                break;
150        }
151
152        return ret;
153}
Note: See TracBrowser for help on using the repository browser.