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

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

update quagga

File size: 3.3 KB
Line 
1/* Netlink helpers for zbuf
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 <errno.h>
12#include <string.h>
13#include <unistd.h>
14#include <sys/types.h>
15#include <sys/socket.h>
16#include <linux/netlink.h>
17#include <linux/rtnetlink.h>
18
19#include "znl.h"
20
21#define ZNL_ALIGN(len)          (((len)+3) & ~3)
22
23void *znl_push(struct zbuf *zb, size_t n)
24{
25        return zbuf_pushn(zb, ZNL_ALIGN(n));
26}
27
28void *znl_pull(struct zbuf *zb, size_t n)
29{
30        return zbuf_pulln(zb, ZNL_ALIGN(n));
31}
32
33struct nlmsghdr *znl_nlmsg_push(struct zbuf *zb, uint16_t type, uint16_t flags)
34{
35        struct nlmsghdr *n;
36
37        n = znl_push(zb, sizeof(*n));
38        if (!n) return NULL;
39
40        *n = (struct nlmsghdr) {
41                .nlmsg_type = type,
42                .nlmsg_flags = flags,
43        };
44        return n;
45}
46
47void znl_nlmsg_complete(struct zbuf *zb, struct nlmsghdr *n)
48{
49        n->nlmsg_len = zb->tail - (uint8_t*)n;
50}
51
52struct nlmsghdr *znl_nlmsg_pull(struct zbuf *zb, struct zbuf *payload)
53{
54        struct nlmsghdr *n;
55        size_t plen;
56
57        n = znl_pull(zb, sizeof(*n));
58        if (!n) return NULL;
59
60        plen = n->nlmsg_len - sizeof(*n);
61        zbuf_init(payload, znl_pull(zb, plen), plen, plen);
62        zbuf_may_pulln(zb, ZNL_ALIGN(plen) - plen);
63
64        return n;
65}
66
67struct rtattr *znl_rta_push(struct zbuf *zb, uint16_t type, const void *val, size_t len)
68{
69        struct rtattr *rta;
70        uint8_t *dst;
71
72        rta = znl_push(zb, ZNL_ALIGN(sizeof(*rta)) + ZNL_ALIGN(len));
73        if (!rta) return NULL;
74
75        *rta = (struct rtattr) {
76                .rta_type = type,
77                .rta_len  = ZNL_ALIGN(sizeof(*rta)) + len,
78        };
79
80        dst = (uint8_t *)(rta+1);
81        memcpy(dst, val, len);
82        memset(dst+len, 0, ZNL_ALIGN(len) - len);
83
84        return rta;
85}
86
87struct rtattr *znl_rta_push_u32(struct zbuf *zb, uint16_t type, uint32_t val)
88{
89        return znl_rta_push(zb, type, &val, sizeof(val));
90}
91
92struct rtattr *znl_rta_nested_push(struct zbuf *zb, uint16_t type)
93{
94        struct rtattr *rta;
95
96        rta = znl_push(zb, sizeof(*rta));
97        if (!rta) return NULL;
98
99        *rta = (struct rtattr) {
100                .rta_type = type,
101        };
102        return rta;
103}
104
105void znl_rta_nested_complete(struct zbuf *zb, struct rtattr *rta)
106{
107        size_t len = zb->tail - (uint8_t*) rta;
108        size_t align = ZNL_ALIGN(len) - len;
109
110        if (align) {
111                void *dst = zbuf_pushn(zb, align);
112                if (dst) memset(dst, 0, align);
113        }
114        rta->rta_len = len;
115}
116
117struct rtattr *znl_rta_pull(struct zbuf *zb, struct zbuf *payload)
118{
119        struct rtattr *rta;
120        size_t plen;
121
122        rta = znl_pull(zb, sizeof(*rta));
123        if (!rta) return NULL;
124
125        if (rta->rta_len > sizeof(*rta)) {
126                plen = rta->rta_len - sizeof(*rta);
127                zbuf_init(payload, znl_pull(zb, plen), plen, plen);
128        } else {
129                zbuf_init(payload, NULL, 0, 0);
130        }
131
132        return rta;
133}
134
135int znl_open(int protocol, int groups)
136{
137        struct sockaddr_nl addr;
138        int fd, buf = 128 * 1024;
139
140        fd = socket(AF_NETLINK, SOCK_RAW, protocol);
141        if (fd < 0)
142                return -1;
143
144        fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
145        fcntl(fd, F_SETFD, FD_CLOEXEC);
146        if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buf, sizeof(buf)) < 0)
147                goto error;
148
149        memset(&addr, 0, sizeof(addr));
150        addr.nl_family = AF_NETLINK;
151        addr.nl_groups = groups;
152        if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
153                goto error;
154
155        return fd;
156error:
157        close(fd);
158        return -1;
159}
160
Note: See TracBrowser for help on using the repository browser.