10afa8e06SEd Maste /*
20afa8e06SEd Maste * Copyright (c) 2020 Yubico AB. All rights reserved.
30afa8e06SEd Maste * Use of this source code is governed by a BSD-style
40afa8e06SEd Maste * license that can be found in the LICENSE file.
5*2ccfa855SEd Maste * SPDX-License-Identifier: BSD-2-Clause
60afa8e06SEd Maste */
70afa8e06SEd Maste
80afa8e06SEd Maste #include <sys/socket.h>
90afa8e06SEd Maste
100afa8e06SEd Maste #include <linux/genetlink.h>
110afa8e06SEd Maste #include <linux/netlink.h>
120afa8e06SEd Maste #include <linux/nfc.h>
130afa8e06SEd Maste
140afa8e06SEd Maste #include <errno.h>
150afa8e06SEd Maste #include <limits.h>
160afa8e06SEd Maste
170afa8e06SEd Maste #include "fido.h"
180afa8e06SEd Maste #include "netlink.h"
190afa8e06SEd Maste
200afa8e06SEd Maste #ifdef FIDO_FUZZ
210afa8e06SEd Maste static ssize_t (*fuzz_read)(int, void *, size_t);
220afa8e06SEd Maste static ssize_t (*fuzz_write)(int, const void *, size_t);
230afa8e06SEd Maste # define READ fuzz_read
240afa8e06SEd Maste # define WRITE fuzz_write
250afa8e06SEd Maste #else
260afa8e06SEd Maste # define READ read
270afa8e06SEd Maste # define WRITE write
280afa8e06SEd Maste #endif
290afa8e06SEd Maste
300afa8e06SEd Maste #ifndef SOL_NETLINK
310afa8e06SEd Maste #define SOL_NETLINK 270
320afa8e06SEd Maste #endif
330afa8e06SEd Maste
34f540a430SEd Maste #define NETLINK_POLL_MS 100
35f540a430SEd Maste
360afa8e06SEd Maste /* XXX avoid signed NLA_ALIGNTO */
370afa8e06SEd Maste #undef NLA_HDRLEN
380afa8e06SEd Maste #define NLA_HDRLEN NLMSG_ALIGN(sizeof(struct nlattr))
390afa8e06SEd Maste
400afa8e06SEd Maste typedef struct nlmsgbuf {
410afa8e06SEd Maste size_t siz; /* alloc size */
420afa8e06SEd Maste size_t len; /* of payload */
430afa8e06SEd Maste unsigned char *ptr; /* in payload */
440afa8e06SEd Maste union {
450afa8e06SEd Maste struct nlmsghdr nlmsg;
460afa8e06SEd Maste char buf[NLMSG_HDRLEN]; /* align */
470afa8e06SEd Maste } u;
480afa8e06SEd Maste unsigned char payload[];
490afa8e06SEd Maste } nlmsgbuf_t;
500afa8e06SEd Maste
510afa8e06SEd Maste typedef struct genlmsgbuf {
520afa8e06SEd Maste union {
530afa8e06SEd Maste struct genlmsghdr genl;
540afa8e06SEd Maste char buf[GENL_HDRLEN]; /* align */
550afa8e06SEd Maste } u;
560afa8e06SEd Maste } genlmsgbuf_t;
570afa8e06SEd Maste
580afa8e06SEd Maste typedef struct nlamsgbuf {
590afa8e06SEd Maste size_t siz; /* alloc size */
600afa8e06SEd Maste size_t len; /* of payload */
610afa8e06SEd Maste unsigned char *ptr; /* in payload */
620afa8e06SEd Maste union {
630afa8e06SEd Maste struct nlattr nla;
640afa8e06SEd Maste char buf[NLA_HDRLEN]; /* align */
650afa8e06SEd Maste } u;
660afa8e06SEd Maste unsigned char payload[];
670afa8e06SEd Maste } nlamsgbuf_t;
680afa8e06SEd Maste
690afa8e06SEd Maste typedef struct nl_family {
700afa8e06SEd Maste uint16_t id;
710afa8e06SEd Maste uint32_t mcastgrp;
720afa8e06SEd Maste } nl_family_t;
730afa8e06SEd Maste
740afa8e06SEd Maste typedef struct nl_poll {
750afa8e06SEd Maste uint32_t dev;
760afa8e06SEd Maste unsigned int eventcnt;
770afa8e06SEd Maste } nl_poll_t;
780afa8e06SEd Maste
790afa8e06SEd Maste typedef struct nl_target {
800afa8e06SEd Maste int found;
810afa8e06SEd Maste uint32_t *value;
820afa8e06SEd Maste } nl_target_t;
830afa8e06SEd Maste
840afa8e06SEd Maste static const void *
nlmsg_ptr(const nlmsgbuf_t * m)850afa8e06SEd Maste nlmsg_ptr(const nlmsgbuf_t *m)
860afa8e06SEd Maste {
870afa8e06SEd Maste return (&m->u.nlmsg);
880afa8e06SEd Maste }
890afa8e06SEd Maste
900afa8e06SEd Maste static size_t
nlmsg_len(const nlmsgbuf_t * m)910afa8e06SEd Maste nlmsg_len(const nlmsgbuf_t *m)
920afa8e06SEd Maste {
930afa8e06SEd Maste return (m->u.nlmsg.nlmsg_len);
940afa8e06SEd Maste }
950afa8e06SEd Maste
960afa8e06SEd Maste static uint16_t
nlmsg_type(const nlmsgbuf_t * m)970afa8e06SEd Maste nlmsg_type(const nlmsgbuf_t *m)
980afa8e06SEd Maste {
990afa8e06SEd Maste return (m->u.nlmsg.nlmsg_type);
1000afa8e06SEd Maste }
1010afa8e06SEd Maste
1020afa8e06SEd Maste static nlmsgbuf_t *
nlmsg_new(uint16_t type,uint16_t flags,size_t len)1030afa8e06SEd Maste nlmsg_new(uint16_t type, uint16_t flags, size_t len)
1040afa8e06SEd Maste {
1050afa8e06SEd Maste nlmsgbuf_t *m;
1060afa8e06SEd Maste size_t siz;
1070afa8e06SEd Maste
1080afa8e06SEd Maste if (len > SIZE_MAX - sizeof(*m) ||
1090afa8e06SEd Maste (siz = sizeof(*m) + len) > UINT16_MAX ||
1100afa8e06SEd Maste (m = calloc(1, siz)) == NULL)
1110afa8e06SEd Maste return (NULL);
1120afa8e06SEd Maste
1130afa8e06SEd Maste m->siz = siz;
1140afa8e06SEd Maste m->len = len;
1150afa8e06SEd Maste m->ptr = m->payload;
1160afa8e06SEd Maste m->u.nlmsg.nlmsg_type = type;
1170afa8e06SEd Maste m->u.nlmsg.nlmsg_flags = NLM_F_REQUEST | flags;
1180afa8e06SEd Maste m->u.nlmsg.nlmsg_len = NLMSG_HDRLEN;
1190afa8e06SEd Maste
1200afa8e06SEd Maste return (m);
1210afa8e06SEd Maste }
1220afa8e06SEd Maste
1230afa8e06SEd Maste static nlamsgbuf_t *
nla_from_buf(const unsigned char ** ptr,size_t * len)1240afa8e06SEd Maste nla_from_buf(const unsigned char **ptr, size_t *len)
1250afa8e06SEd Maste {
1260afa8e06SEd Maste nlamsgbuf_t h, *a;
1270afa8e06SEd Maste size_t nlalen, skip;
1280afa8e06SEd Maste
1290afa8e06SEd Maste if (*len < sizeof(h.u))
1300afa8e06SEd Maste return (NULL);
1310afa8e06SEd Maste
1320afa8e06SEd Maste memset(&h, 0, sizeof(h));
1330afa8e06SEd Maste memcpy(&h.u, *ptr, sizeof(h.u));
1340afa8e06SEd Maste
1350afa8e06SEd Maste if ((nlalen = h.u.nla.nla_len) < sizeof(h.u) || nlalen > *len ||
1360afa8e06SEd Maste nlalen - sizeof(h.u) > UINT16_MAX ||
1370afa8e06SEd Maste nlalen > SIZE_MAX - sizeof(*a) ||
1380afa8e06SEd Maste (skip = NLMSG_ALIGN(nlalen)) > *len ||
1390afa8e06SEd Maste (a = calloc(1, sizeof(*a) + nlalen - sizeof(h.u))) == NULL)
1400afa8e06SEd Maste return (NULL);
1410afa8e06SEd Maste
1420afa8e06SEd Maste memcpy(&a->u, *ptr, nlalen);
1430afa8e06SEd Maste a->siz = sizeof(*a) + nlalen - sizeof(h.u);
1440afa8e06SEd Maste a->ptr = a->payload;
1450afa8e06SEd Maste a->len = nlalen - sizeof(h.u);
1460afa8e06SEd Maste *ptr += skip;
1470afa8e06SEd Maste *len -= skip;
1480afa8e06SEd Maste
1490afa8e06SEd Maste return (a);
1500afa8e06SEd Maste }
1510afa8e06SEd Maste
1520afa8e06SEd Maste static nlamsgbuf_t *
nla_getattr(nlamsgbuf_t * a)1530afa8e06SEd Maste nla_getattr(nlamsgbuf_t *a)
1540afa8e06SEd Maste {
1550afa8e06SEd Maste return (nla_from_buf((void *)&a->ptr, &a->len));
1560afa8e06SEd Maste }
1570afa8e06SEd Maste
1580afa8e06SEd Maste static uint16_t
nla_type(const nlamsgbuf_t * a)1590afa8e06SEd Maste nla_type(const nlamsgbuf_t *a)
1600afa8e06SEd Maste {
1610afa8e06SEd Maste return (a->u.nla.nla_type);
1620afa8e06SEd Maste }
1630afa8e06SEd Maste
1640afa8e06SEd Maste static nlamsgbuf_t *
nlmsg_getattr(nlmsgbuf_t * m)1650afa8e06SEd Maste nlmsg_getattr(nlmsgbuf_t *m)
1660afa8e06SEd Maste {
1670afa8e06SEd Maste return (nla_from_buf((void *)&m->ptr, &m->len));
1680afa8e06SEd Maste }
1690afa8e06SEd Maste
1700afa8e06SEd Maste static int
nla_read(nlamsgbuf_t * a,void * buf,size_t cnt)1710afa8e06SEd Maste nla_read(nlamsgbuf_t *a, void *buf, size_t cnt)
1720afa8e06SEd Maste {
1730afa8e06SEd Maste if (cnt > a->u.nla.nla_len ||
1740afa8e06SEd Maste fido_buf_read((void *)&a->ptr, &a->len, buf, cnt) < 0)
1750afa8e06SEd Maste return (-1);
1760afa8e06SEd Maste
1770afa8e06SEd Maste a->u.nla.nla_len = (uint16_t)(a->u.nla.nla_len - cnt);
1780afa8e06SEd Maste
1790afa8e06SEd Maste return (0);
1800afa8e06SEd Maste }
1810afa8e06SEd Maste
1820afa8e06SEd Maste static nlmsgbuf_t *
nlmsg_from_buf(const unsigned char ** ptr,size_t * len)1830afa8e06SEd Maste nlmsg_from_buf(const unsigned char **ptr, size_t *len)
1840afa8e06SEd Maste {
1850afa8e06SEd Maste nlmsgbuf_t h, *m;
1860afa8e06SEd Maste size_t msglen, skip;
1870afa8e06SEd Maste
1880afa8e06SEd Maste if (*len < sizeof(h.u))
1890afa8e06SEd Maste return (NULL);
1900afa8e06SEd Maste
1910afa8e06SEd Maste memset(&h, 0, sizeof(h));
1920afa8e06SEd Maste memcpy(&h.u, *ptr, sizeof(h.u));
1930afa8e06SEd Maste
1940afa8e06SEd Maste if ((msglen = h.u.nlmsg.nlmsg_len) < sizeof(h.u) || msglen > *len ||
1950afa8e06SEd Maste msglen - sizeof(h.u) > UINT16_MAX ||
1960afa8e06SEd Maste (skip = NLMSG_ALIGN(msglen)) > *len ||
1970afa8e06SEd Maste (m = nlmsg_new(0, 0, msglen - sizeof(h.u))) == NULL)
1980afa8e06SEd Maste return (NULL);
1990afa8e06SEd Maste
2000afa8e06SEd Maste memcpy(&m->u, *ptr, msglen);
2010afa8e06SEd Maste *ptr += skip;
2020afa8e06SEd Maste *len -= skip;
2030afa8e06SEd Maste
2040afa8e06SEd Maste return (m);
2050afa8e06SEd Maste }
2060afa8e06SEd Maste
2070afa8e06SEd Maste static int
nlmsg_read(nlmsgbuf_t * m,void * buf,size_t cnt)2080afa8e06SEd Maste nlmsg_read(nlmsgbuf_t *m, void *buf, size_t cnt)
2090afa8e06SEd Maste {
2100afa8e06SEd Maste if (cnt > m->u.nlmsg.nlmsg_len ||
2110afa8e06SEd Maste fido_buf_read((void *)&m->ptr, &m->len, buf, cnt) < 0)
2120afa8e06SEd Maste return (-1);
2130afa8e06SEd Maste
2140afa8e06SEd Maste m->u.nlmsg.nlmsg_len = (uint32_t)(m->u.nlmsg.nlmsg_len - cnt);
2150afa8e06SEd Maste
2160afa8e06SEd Maste return (0);
2170afa8e06SEd Maste }
2180afa8e06SEd Maste
2190afa8e06SEd Maste static int
nlmsg_write(nlmsgbuf_t * m,const void * buf,size_t cnt)2200afa8e06SEd Maste nlmsg_write(nlmsgbuf_t *m, const void *buf, size_t cnt)
2210afa8e06SEd Maste {
2220afa8e06SEd Maste if (cnt > UINT32_MAX - m->u.nlmsg.nlmsg_len ||
2230afa8e06SEd Maste fido_buf_write(&m->ptr, &m->len, buf, cnt) < 0)
2240afa8e06SEd Maste return (-1);
2250afa8e06SEd Maste
2260afa8e06SEd Maste m->u.nlmsg.nlmsg_len = (uint32_t)(m->u.nlmsg.nlmsg_len + cnt);
2270afa8e06SEd Maste
2280afa8e06SEd Maste return (0);
2290afa8e06SEd Maste }
2300afa8e06SEd Maste
2310afa8e06SEd Maste static int
nlmsg_set_genl(nlmsgbuf_t * m,uint8_t cmd)2320afa8e06SEd Maste nlmsg_set_genl(nlmsgbuf_t *m, uint8_t cmd)
2330afa8e06SEd Maste {
2340afa8e06SEd Maste genlmsgbuf_t g;
2350afa8e06SEd Maste
2360afa8e06SEd Maste memset(&g, 0, sizeof(g));
2370afa8e06SEd Maste g.u.genl.cmd = cmd;
2380afa8e06SEd Maste g.u.genl.version = NFC_GENL_VERSION;
2390afa8e06SEd Maste
2400afa8e06SEd Maste return (nlmsg_write(m, &g, sizeof(g)));
2410afa8e06SEd Maste }
2420afa8e06SEd Maste
2430afa8e06SEd Maste static int
nlmsg_get_genl(nlmsgbuf_t * m,uint8_t cmd)2440afa8e06SEd Maste nlmsg_get_genl(nlmsgbuf_t *m, uint8_t cmd)
2450afa8e06SEd Maste {
2460afa8e06SEd Maste genlmsgbuf_t g;
2470afa8e06SEd Maste
2480afa8e06SEd Maste memset(&g, 0, sizeof(g));
2490afa8e06SEd Maste
2500afa8e06SEd Maste if (nlmsg_read(m, &g, sizeof(g)) < 0 || g.u.genl.cmd != cmd)
2510afa8e06SEd Maste return (-1);
2520afa8e06SEd Maste
2530afa8e06SEd Maste return (0);
2540afa8e06SEd Maste }
2550afa8e06SEd Maste
2560afa8e06SEd Maste static int
nlmsg_get_status(nlmsgbuf_t * m)2570afa8e06SEd Maste nlmsg_get_status(nlmsgbuf_t *m)
2580afa8e06SEd Maste {
2590afa8e06SEd Maste int status;
2600afa8e06SEd Maste
2610afa8e06SEd Maste if (nlmsg_read(m, &status, sizeof(status)) < 0 || status == INT_MIN)
2620afa8e06SEd Maste return (-1);
2630afa8e06SEd Maste if (status < 0)
2640afa8e06SEd Maste status = -status;
2650afa8e06SEd Maste
2660afa8e06SEd Maste return (status);
2670afa8e06SEd Maste }
2680afa8e06SEd Maste
2690afa8e06SEd Maste static int
nlmsg_setattr(nlmsgbuf_t * m,uint16_t type,const void * ptr,size_t len)2700afa8e06SEd Maste nlmsg_setattr(nlmsgbuf_t *m, uint16_t type, const void *ptr, size_t len)
2710afa8e06SEd Maste {
2720afa8e06SEd Maste int r;
2730afa8e06SEd Maste char *padding;
2740afa8e06SEd Maste size_t skip;
2750afa8e06SEd Maste nlamsgbuf_t a;
2760afa8e06SEd Maste
2770afa8e06SEd Maste if ((skip = NLMSG_ALIGN(len)) > UINT16_MAX - sizeof(a.u) ||
2780afa8e06SEd Maste skip < len || (padding = calloc(1, skip - len)) == NULL)
2790afa8e06SEd Maste return (-1);
2800afa8e06SEd Maste
2810afa8e06SEd Maste memset(&a, 0, sizeof(a));
2820afa8e06SEd Maste a.u.nla.nla_type = type;
2830afa8e06SEd Maste a.u.nla.nla_len = (uint16_t)(len + sizeof(a.u));
2840afa8e06SEd Maste r = nlmsg_write(m, &a.u, sizeof(a.u)) < 0 ||
2850afa8e06SEd Maste nlmsg_write(m, ptr, len) < 0 ||
2860afa8e06SEd Maste nlmsg_write(m, padding, skip - len) < 0 ? -1 : 0;
2870afa8e06SEd Maste
2880afa8e06SEd Maste free(padding);
2890afa8e06SEd Maste
2900afa8e06SEd Maste return (r);
2910afa8e06SEd Maste }
2920afa8e06SEd Maste
2930afa8e06SEd Maste static int
nlmsg_set_u16(nlmsgbuf_t * m,uint16_t type,uint16_t val)2940afa8e06SEd Maste nlmsg_set_u16(nlmsgbuf_t *m, uint16_t type, uint16_t val)
2950afa8e06SEd Maste {
2960afa8e06SEd Maste return (nlmsg_setattr(m, type, &val, sizeof(val)));
2970afa8e06SEd Maste }
2980afa8e06SEd Maste
2990afa8e06SEd Maste static int
nlmsg_set_u32(nlmsgbuf_t * m,uint16_t type,uint32_t val)3000afa8e06SEd Maste nlmsg_set_u32(nlmsgbuf_t *m, uint16_t type, uint32_t val)
3010afa8e06SEd Maste {
3020afa8e06SEd Maste return (nlmsg_setattr(m, type, &val, sizeof(val)));
3030afa8e06SEd Maste }
3040afa8e06SEd Maste
3050afa8e06SEd Maste static int
nlmsg_set_str(nlmsgbuf_t * m,uint16_t type,const char * val)3060afa8e06SEd Maste nlmsg_set_str(nlmsgbuf_t *m, uint16_t type, const char *val)
3070afa8e06SEd Maste {
3080afa8e06SEd Maste return (nlmsg_setattr(m, type, val, strlen(val) + 1));
3090afa8e06SEd Maste }
3100afa8e06SEd Maste
3110afa8e06SEd Maste static int
nla_get_u16(nlamsgbuf_t * a,uint16_t * v)3120afa8e06SEd Maste nla_get_u16(nlamsgbuf_t *a, uint16_t *v)
3130afa8e06SEd Maste {
3140afa8e06SEd Maste return (nla_read(a, v, sizeof(*v)));
3150afa8e06SEd Maste }
3160afa8e06SEd Maste
3170afa8e06SEd Maste static int
nla_get_u32(nlamsgbuf_t * a,uint32_t * v)3180afa8e06SEd Maste nla_get_u32(nlamsgbuf_t *a, uint32_t *v)
3190afa8e06SEd Maste {
3200afa8e06SEd Maste return (nla_read(a, v, sizeof(*v)));
3210afa8e06SEd Maste }
3220afa8e06SEd Maste
3230afa8e06SEd Maste static char *
nla_get_str(nlamsgbuf_t * a)3240afa8e06SEd Maste nla_get_str(nlamsgbuf_t *a)
3250afa8e06SEd Maste {
3260afa8e06SEd Maste size_t n;
3270afa8e06SEd Maste char *s = NULL;
3280afa8e06SEd Maste
3290afa8e06SEd Maste if ((n = a->len) < 1 || a->ptr[n - 1] != '\0' ||
3300afa8e06SEd Maste (s = calloc(1, n)) == NULL || nla_read(a, s, n) < 0) {
3310afa8e06SEd Maste free(s);
3320afa8e06SEd Maste return (NULL);
3330afa8e06SEd Maste }
3340afa8e06SEd Maste s[n - 1] = '\0';
3350afa8e06SEd Maste
3360afa8e06SEd Maste return (s);
3370afa8e06SEd Maste }
3380afa8e06SEd Maste
3390afa8e06SEd Maste static int
nlmsg_tx(int fd,const nlmsgbuf_t * m)3400afa8e06SEd Maste nlmsg_tx(int fd, const nlmsgbuf_t *m)
3410afa8e06SEd Maste {
3420afa8e06SEd Maste ssize_t r;
3430afa8e06SEd Maste
3440afa8e06SEd Maste if ((r = WRITE(fd, nlmsg_ptr(m), nlmsg_len(m))) == -1) {
3450afa8e06SEd Maste fido_log_error(errno, "%s: write", __func__);
3460afa8e06SEd Maste return (-1);
3470afa8e06SEd Maste }
3480afa8e06SEd Maste if (r < 0 || (size_t)r != nlmsg_len(m)) {
3490afa8e06SEd Maste fido_log_debug("%s: %zd != %zu", __func__, r, nlmsg_len(m));
3500afa8e06SEd Maste return (-1);
3510afa8e06SEd Maste }
3520afa8e06SEd Maste fido_log_xxd(nlmsg_ptr(m), nlmsg_len(m), "%s", __func__);
3530afa8e06SEd Maste
3540afa8e06SEd Maste return (0);
3550afa8e06SEd Maste }
3560afa8e06SEd Maste
3570afa8e06SEd Maste static ssize_t
nlmsg_rx(int fd,unsigned char * ptr,size_t len,int ms)3580afa8e06SEd Maste nlmsg_rx(int fd, unsigned char *ptr, size_t len, int ms)
3590afa8e06SEd Maste {
3600afa8e06SEd Maste ssize_t r;
3610afa8e06SEd Maste
3620afa8e06SEd Maste if (len > SSIZE_MAX) {
3630afa8e06SEd Maste fido_log_debug("%s: len", __func__);
3640afa8e06SEd Maste return (-1);
3650afa8e06SEd Maste }
3660afa8e06SEd Maste if (fido_hid_unix_wait(fd, ms, NULL) < 0) {
3670afa8e06SEd Maste fido_log_debug("%s: fido_hid_unix_wait", __func__);
3680afa8e06SEd Maste return (-1);
3690afa8e06SEd Maste }
3700afa8e06SEd Maste if ((r = READ(fd, ptr, len)) == -1) {
3710afa8e06SEd Maste fido_log_error(errno, "%s: read %zd", __func__, r);
3720afa8e06SEd Maste return (-1);
3730afa8e06SEd Maste }
3740afa8e06SEd Maste fido_log_xxd(ptr, (size_t)r, "%s", __func__);
3750afa8e06SEd Maste
3760afa8e06SEd Maste return (r);
3770afa8e06SEd Maste }
3780afa8e06SEd Maste
3790afa8e06SEd Maste static int
nlmsg_iter(nlmsgbuf_t * m,void * arg,int (* parser)(nlamsgbuf_t *,void *))3800afa8e06SEd Maste nlmsg_iter(nlmsgbuf_t *m, void *arg, int (*parser)(nlamsgbuf_t *, void *))
3810afa8e06SEd Maste {
3820afa8e06SEd Maste nlamsgbuf_t *a;
3830afa8e06SEd Maste int r;
3840afa8e06SEd Maste
3850afa8e06SEd Maste while ((a = nlmsg_getattr(m)) != NULL) {
3860afa8e06SEd Maste r = parser(a, arg);
3870afa8e06SEd Maste free(a);
3880afa8e06SEd Maste if (r < 0) {
3890afa8e06SEd Maste fido_log_debug("%s: parser", __func__);
3900afa8e06SEd Maste return (-1);
3910afa8e06SEd Maste }
3920afa8e06SEd Maste }
3930afa8e06SEd Maste
3940afa8e06SEd Maste return (0);
3950afa8e06SEd Maste }
3960afa8e06SEd Maste
3970afa8e06SEd Maste static int
nla_iter(nlamsgbuf_t * g,void * arg,int (* parser)(nlamsgbuf_t *,void *))3980afa8e06SEd Maste nla_iter(nlamsgbuf_t *g, void *arg, int (*parser)(nlamsgbuf_t *, void *))
3990afa8e06SEd Maste {
4000afa8e06SEd Maste nlamsgbuf_t *a;
4010afa8e06SEd Maste int r;
4020afa8e06SEd Maste
4030afa8e06SEd Maste while ((a = nla_getattr(g)) != NULL) {
4040afa8e06SEd Maste r = parser(a, arg);
4050afa8e06SEd Maste free(a);
4060afa8e06SEd Maste if (r < 0) {
4070afa8e06SEd Maste fido_log_debug("%s: parser", __func__);
4080afa8e06SEd Maste return (-1);
4090afa8e06SEd Maste }
4100afa8e06SEd Maste }
4110afa8e06SEd Maste
4120afa8e06SEd Maste return (0);
4130afa8e06SEd Maste }
4140afa8e06SEd Maste
4150afa8e06SEd Maste static int
nl_parse_reply(const uint8_t * blob,size_t blob_len,uint16_t msg_type,uint8_t genl_cmd,void * arg,int (* parser)(nlamsgbuf_t *,void *))4160afa8e06SEd Maste nl_parse_reply(const uint8_t *blob, size_t blob_len, uint16_t msg_type,
4170afa8e06SEd Maste uint8_t genl_cmd, void *arg, int (*parser)(nlamsgbuf_t *, void *))
4180afa8e06SEd Maste {
4190afa8e06SEd Maste nlmsgbuf_t *m;
4200afa8e06SEd Maste int r;
4210afa8e06SEd Maste
4220afa8e06SEd Maste while (blob_len) {
4230afa8e06SEd Maste if ((m = nlmsg_from_buf(&blob, &blob_len)) == NULL) {
4240afa8e06SEd Maste fido_log_debug("%s: nlmsg", __func__);
4250afa8e06SEd Maste return (-1);
4260afa8e06SEd Maste }
4270afa8e06SEd Maste if (nlmsg_type(m) == NLMSG_ERROR) {
4280afa8e06SEd Maste r = nlmsg_get_status(m);
4290afa8e06SEd Maste free(m);
4300afa8e06SEd Maste return (r);
4310afa8e06SEd Maste }
4320afa8e06SEd Maste if (nlmsg_type(m) != msg_type ||
4330afa8e06SEd Maste nlmsg_get_genl(m, genl_cmd) < 0) {
4340afa8e06SEd Maste fido_log_debug("%s: skipping", __func__);
4350afa8e06SEd Maste free(m);
4360afa8e06SEd Maste continue;
4370afa8e06SEd Maste }
4380afa8e06SEd Maste if (parser != NULL && nlmsg_iter(m, arg, parser) < 0) {
4390afa8e06SEd Maste fido_log_debug("%s: nlmsg_iter", __func__);
4400afa8e06SEd Maste free(m);
4410afa8e06SEd Maste return (-1);
4420afa8e06SEd Maste }
4430afa8e06SEd Maste free(m);
4440afa8e06SEd Maste }
4450afa8e06SEd Maste
4460afa8e06SEd Maste return (0);
4470afa8e06SEd Maste }
4480afa8e06SEd Maste
4490afa8e06SEd Maste static int
parse_mcastgrp(nlamsgbuf_t * a,void * arg)4500afa8e06SEd Maste parse_mcastgrp(nlamsgbuf_t *a, void *arg)
4510afa8e06SEd Maste {
4520afa8e06SEd Maste nl_family_t *family = arg;
4530afa8e06SEd Maste char *name;
4540afa8e06SEd Maste
4550afa8e06SEd Maste switch (nla_type(a)) {
4560afa8e06SEd Maste case CTRL_ATTR_MCAST_GRP_NAME:
4570afa8e06SEd Maste if ((name = nla_get_str(a)) == NULL ||
4580afa8e06SEd Maste strcmp(name, NFC_GENL_MCAST_EVENT_NAME) != 0) {
4590afa8e06SEd Maste free(name);
4600afa8e06SEd Maste return (-1); /* XXX skip? */
4610afa8e06SEd Maste }
4620afa8e06SEd Maste free(name);
4630afa8e06SEd Maste return (0);
4640afa8e06SEd Maste case CTRL_ATTR_MCAST_GRP_ID:
4650afa8e06SEd Maste if (family->mcastgrp)
4660afa8e06SEd Maste break;
4670afa8e06SEd Maste if (nla_get_u32(a, &family->mcastgrp) < 0) {
4680afa8e06SEd Maste fido_log_debug("%s: group", __func__);
4690afa8e06SEd Maste return (-1);
4700afa8e06SEd Maste }
4710afa8e06SEd Maste return (0);
4720afa8e06SEd Maste }
4730afa8e06SEd Maste
4740afa8e06SEd Maste fido_log_debug("%s: ignoring nla 0x%x", __func__, nla_type(a));
4750afa8e06SEd Maste
4760afa8e06SEd Maste return (0);
4770afa8e06SEd Maste }
4780afa8e06SEd Maste
4790afa8e06SEd Maste static int
parse_mcastgrps(nlamsgbuf_t * a,void * arg)4800afa8e06SEd Maste parse_mcastgrps(nlamsgbuf_t *a, void *arg)
4810afa8e06SEd Maste {
4820afa8e06SEd Maste return (nla_iter(a, arg, parse_mcastgrp));
4830afa8e06SEd Maste }
4840afa8e06SEd Maste
4850afa8e06SEd Maste static int
parse_family(nlamsgbuf_t * a,void * arg)4860afa8e06SEd Maste parse_family(nlamsgbuf_t *a, void *arg)
4870afa8e06SEd Maste {
4880afa8e06SEd Maste nl_family_t *family = arg;
4890afa8e06SEd Maste
4900afa8e06SEd Maste switch (nla_type(a)) {
4910afa8e06SEd Maste case CTRL_ATTR_FAMILY_ID:
4920afa8e06SEd Maste if (family->id)
4930afa8e06SEd Maste break;
4940afa8e06SEd Maste if (nla_get_u16(a, &family->id) < 0) {
4950afa8e06SEd Maste fido_log_debug("%s: id", __func__);
4960afa8e06SEd Maste return (-1);
4970afa8e06SEd Maste }
4980afa8e06SEd Maste return (0);
4990afa8e06SEd Maste case CTRL_ATTR_MCAST_GROUPS:
5000afa8e06SEd Maste return (nla_iter(a, family, parse_mcastgrps));
5010afa8e06SEd Maste }
5020afa8e06SEd Maste
5030afa8e06SEd Maste fido_log_debug("%s: ignoring nla 0x%x", __func__, nla_type(a));
5040afa8e06SEd Maste
5050afa8e06SEd Maste return (0);
5060afa8e06SEd Maste }
5070afa8e06SEd Maste
5080afa8e06SEd Maste static int
nl_get_nfc_family(int fd,uint16_t * type,uint32_t * mcastgrp)5090afa8e06SEd Maste nl_get_nfc_family(int fd, uint16_t *type, uint32_t *mcastgrp)
5100afa8e06SEd Maste {
5110afa8e06SEd Maste nlmsgbuf_t *m;
5120afa8e06SEd Maste uint8_t reply[512];
5130afa8e06SEd Maste nl_family_t family;
5140afa8e06SEd Maste ssize_t r;
5150afa8e06SEd Maste int ok;
5160afa8e06SEd Maste
5170afa8e06SEd Maste if ((m = nlmsg_new(GENL_ID_CTRL, 0, 64)) == NULL ||
5180afa8e06SEd Maste nlmsg_set_genl(m, CTRL_CMD_GETFAMILY) < 0 ||
5190afa8e06SEd Maste nlmsg_set_u16(m, CTRL_ATTR_FAMILY_ID, GENL_ID_CTRL) < 0 ||
5200afa8e06SEd Maste nlmsg_set_str(m, CTRL_ATTR_FAMILY_NAME, NFC_GENL_NAME) < 0 ||
5210afa8e06SEd Maste nlmsg_tx(fd, m) < 0) {
5220afa8e06SEd Maste free(m);
5230afa8e06SEd Maste return (-1);
5240afa8e06SEd Maste }
5250afa8e06SEd Maste free(m);
5260afa8e06SEd Maste memset(&family, 0, sizeof(family));
5270afa8e06SEd Maste if ((r = nlmsg_rx(fd, reply, sizeof(reply), -1)) < 0) {
5280afa8e06SEd Maste fido_log_debug("%s: nlmsg_rx", __func__);
5290afa8e06SEd Maste return (-1);
5300afa8e06SEd Maste }
5310afa8e06SEd Maste if ((ok = nl_parse_reply(reply, (size_t)r, GENL_ID_CTRL,
5320afa8e06SEd Maste CTRL_CMD_NEWFAMILY, &family, parse_family)) != 0) {
5330afa8e06SEd Maste fido_log_debug("%s: nl_parse_reply: %d", __func__, ok);
5340afa8e06SEd Maste return (-1);
5350afa8e06SEd Maste }
5360afa8e06SEd Maste if (family.id == 0 || family.mcastgrp == 0) {
5370afa8e06SEd Maste fido_log_debug("%s: missing attr", __func__);
5380afa8e06SEd Maste return (-1);
5390afa8e06SEd Maste }
5400afa8e06SEd Maste *type = family.id;
5410afa8e06SEd Maste *mcastgrp = family.mcastgrp;
5420afa8e06SEd Maste
5430afa8e06SEd Maste return (0);
5440afa8e06SEd Maste }
5450afa8e06SEd Maste
5460afa8e06SEd Maste static int
parse_target(nlamsgbuf_t * a,void * arg)5470afa8e06SEd Maste parse_target(nlamsgbuf_t *a, void *arg)
5480afa8e06SEd Maste {
5490afa8e06SEd Maste nl_target_t *t = arg;
5500afa8e06SEd Maste
5510afa8e06SEd Maste if (t->found || nla_type(a) != NFC_ATTR_TARGET_INDEX) {
5520afa8e06SEd Maste fido_log_debug("%s: ignoring nla 0x%x", __func__, nla_type(a));
5530afa8e06SEd Maste return (0);
5540afa8e06SEd Maste }
5550afa8e06SEd Maste if (nla_get_u32(a, t->value) < 0) {
5560afa8e06SEd Maste fido_log_debug("%s: target", __func__);
5570afa8e06SEd Maste return (-1);
5580afa8e06SEd Maste }
5590afa8e06SEd Maste t->found = 1;
5600afa8e06SEd Maste
5610afa8e06SEd Maste return (0);
5620afa8e06SEd Maste }
5630afa8e06SEd Maste
5640afa8e06SEd Maste int
fido_nl_power_nfc(fido_nl_t * nl,uint32_t dev)5650afa8e06SEd Maste fido_nl_power_nfc(fido_nl_t *nl, uint32_t dev)
5660afa8e06SEd Maste {
5670afa8e06SEd Maste nlmsgbuf_t *m;
5680afa8e06SEd Maste uint8_t reply[512];
5690afa8e06SEd Maste ssize_t r;
5700afa8e06SEd Maste int ok;
5710afa8e06SEd Maste
5720afa8e06SEd Maste if ((m = nlmsg_new(nl->nfc_type, NLM_F_ACK, 64)) == NULL ||
5730afa8e06SEd Maste nlmsg_set_genl(m, NFC_CMD_DEV_UP) < 0 ||
5740afa8e06SEd Maste nlmsg_set_u32(m, NFC_ATTR_DEVICE_INDEX, dev) < 0 ||
5750afa8e06SEd Maste nlmsg_tx(nl->fd, m) < 0) {
5760afa8e06SEd Maste free(m);
5770afa8e06SEd Maste return (-1);
5780afa8e06SEd Maste }
5790afa8e06SEd Maste free(m);
5800afa8e06SEd Maste if ((r = nlmsg_rx(nl->fd, reply, sizeof(reply), -1)) < 0) {
5810afa8e06SEd Maste fido_log_debug("%s: nlmsg_rx", __func__);
5820afa8e06SEd Maste return (-1);
5830afa8e06SEd Maste }
5840afa8e06SEd Maste if ((ok = nl_parse_reply(reply, (size_t)r, nl->nfc_type,
5850afa8e06SEd Maste NFC_CMD_DEV_UP, NULL, NULL)) != 0 && ok != EALREADY) {
5860afa8e06SEd Maste fido_log_debug("%s: nl_parse_reply: %d", __func__, ok);
5870afa8e06SEd Maste return (-1);
5880afa8e06SEd Maste }
5890afa8e06SEd Maste
5900afa8e06SEd Maste return (0);
5910afa8e06SEd Maste }
5920afa8e06SEd Maste
5930afa8e06SEd Maste static int
nl_nfc_poll(fido_nl_t * nl,uint32_t dev)5940afa8e06SEd Maste nl_nfc_poll(fido_nl_t *nl, uint32_t dev)
5950afa8e06SEd Maste {
5960afa8e06SEd Maste nlmsgbuf_t *m;
5970afa8e06SEd Maste uint8_t reply[512];
5980afa8e06SEd Maste ssize_t r;
5990afa8e06SEd Maste int ok;
6000afa8e06SEd Maste
6010afa8e06SEd Maste if ((m = nlmsg_new(nl->nfc_type, NLM_F_ACK, 64)) == NULL ||
6020afa8e06SEd Maste nlmsg_set_genl(m, NFC_CMD_START_POLL) < 0 ||
6030afa8e06SEd Maste nlmsg_set_u32(m, NFC_ATTR_DEVICE_INDEX, dev) < 0 ||
6040afa8e06SEd Maste nlmsg_set_u32(m, NFC_ATTR_PROTOCOLS, NFC_PROTO_ISO14443_MASK) < 0 ||
6050afa8e06SEd Maste nlmsg_tx(nl->fd, m) < 0) {
6060afa8e06SEd Maste free(m);
6070afa8e06SEd Maste return (-1);
6080afa8e06SEd Maste }
6090afa8e06SEd Maste free(m);
6100afa8e06SEd Maste if ((r = nlmsg_rx(nl->fd, reply, sizeof(reply), -1)) < 0) {
6110afa8e06SEd Maste fido_log_debug("%s: nlmsg_rx", __func__);
6120afa8e06SEd Maste return (-1);
6130afa8e06SEd Maste }
6140afa8e06SEd Maste if ((ok = nl_parse_reply(reply, (size_t)r, nl->nfc_type,
6150afa8e06SEd Maste NFC_CMD_START_POLL, NULL, NULL)) != 0) {
6160afa8e06SEd Maste fido_log_debug("%s: nl_parse_reply: %d", __func__, ok);
6170afa8e06SEd Maste return (-1);
6180afa8e06SEd Maste }
6190afa8e06SEd Maste
6200afa8e06SEd Maste return (0);
6210afa8e06SEd Maste }
6220afa8e06SEd Maste
6230afa8e06SEd Maste static int
nl_dump_nfc_target(fido_nl_t * nl,uint32_t dev,uint32_t * target,int ms)6240afa8e06SEd Maste nl_dump_nfc_target(fido_nl_t *nl, uint32_t dev, uint32_t *target, int ms)
6250afa8e06SEd Maste {
6260afa8e06SEd Maste nlmsgbuf_t *m;
6270afa8e06SEd Maste nl_target_t t;
6280afa8e06SEd Maste uint8_t reply[512];
6290afa8e06SEd Maste ssize_t r;
6300afa8e06SEd Maste int ok;
6310afa8e06SEd Maste
6320afa8e06SEd Maste if ((m = nlmsg_new(nl->nfc_type, NLM_F_DUMP, 64)) == NULL ||
6330afa8e06SEd Maste nlmsg_set_genl(m, NFC_CMD_GET_TARGET) < 0 ||
6340afa8e06SEd Maste nlmsg_set_u32(m, NFC_ATTR_DEVICE_INDEX, dev) < 0 ||
6350afa8e06SEd Maste nlmsg_tx(nl->fd, m) < 0) {
6360afa8e06SEd Maste free(m);
6370afa8e06SEd Maste return (-1);
6380afa8e06SEd Maste }
6390afa8e06SEd Maste free(m);
6400afa8e06SEd Maste if ((r = nlmsg_rx(nl->fd, reply, sizeof(reply), ms)) < 0) {
6410afa8e06SEd Maste fido_log_debug("%s: nlmsg_rx", __func__);
6420afa8e06SEd Maste return (-1);
6430afa8e06SEd Maste }
6440afa8e06SEd Maste memset(&t, 0, sizeof(t));
6450afa8e06SEd Maste t.value = target;
6460afa8e06SEd Maste if ((ok = nl_parse_reply(reply, (size_t)r, nl->nfc_type,
6470afa8e06SEd Maste NFC_CMD_GET_TARGET, &t, parse_target)) != 0) {
6480afa8e06SEd Maste fido_log_debug("%s: nl_parse_reply: %d", __func__, ok);
6490afa8e06SEd Maste return (-1);
6500afa8e06SEd Maste }
6510afa8e06SEd Maste if (!t.found) {
6520afa8e06SEd Maste fido_log_debug("%s: target not found", __func__);
6530afa8e06SEd Maste return (-1);
6540afa8e06SEd Maste }
6550afa8e06SEd Maste
6560afa8e06SEd Maste return (0);
6570afa8e06SEd Maste }
6580afa8e06SEd Maste
6590afa8e06SEd Maste static int
parse_nfc_event(nlamsgbuf_t * a,void * arg)6600afa8e06SEd Maste parse_nfc_event(nlamsgbuf_t *a, void *arg)
6610afa8e06SEd Maste {
6620afa8e06SEd Maste nl_poll_t *ctx = arg;
6630afa8e06SEd Maste uint32_t dev;
6640afa8e06SEd Maste
6650afa8e06SEd Maste if (nla_type(a) != NFC_ATTR_DEVICE_INDEX) {
6660afa8e06SEd Maste fido_log_debug("%s: ignoring nla 0x%x", __func__, nla_type(a));
6670afa8e06SEd Maste return (0);
6680afa8e06SEd Maste }
6690afa8e06SEd Maste if (nla_get_u32(a, &dev) < 0) {
6700afa8e06SEd Maste fido_log_debug("%s: dev", __func__);
6710afa8e06SEd Maste return (-1);
6720afa8e06SEd Maste }
6730afa8e06SEd Maste if (dev == ctx->dev)
6740afa8e06SEd Maste ctx->eventcnt++;
6750afa8e06SEd Maste else
6760afa8e06SEd Maste fido_log_debug("%s: ignoring dev 0x%x", __func__, dev);
6770afa8e06SEd Maste
6780afa8e06SEd Maste return (0);
6790afa8e06SEd Maste }
6800afa8e06SEd Maste
6810afa8e06SEd Maste int
fido_nl_get_nfc_target(fido_nl_t * nl,uint32_t dev,uint32_t * target)6820afa8e06SEd Maste fido_nl_get_nfc_target(fido_nl_t *nl, uint32_t dev, uint32_t *target)
6830afa8e06SEd Maste {
6840afa8e06SEd Maste uint8_t reply[512];
6850afa8e06SEd Maste nl_poll_t ctx;
6860afa8e06SEd Maste ssize_t r;
6870afa8e06SEd Maste int ok;
6880afa8e06SEd Maste
6890afa8e06SEd Maste if (nl_nfc_poll(nl, dev) < 0) {
6900afa8e06SEd Maste fido_log_debug("%s: nl_nfc_poll", __func__);
6910afa8e06SEd Maste return (-1);
6920afa8e06SEd Maste }
6930afa8e06SEd Maste #ifndef FIDO_FUZZ
6940afa8e06SEd Maste if (setsockopt(nl->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
6950afa8e06SEd Maste &nl->nfc_mcastgrp, sizeof(nl->nfc_mcastgrp)) == -1) {
6960afa8e06SEd Maste fido_log_error(errno, "%s: setsockopt add", __func__);
6970afa8e06SEd Maste return (-1);
6980afa8e06SEd Maste }
6990afa8e06SEd Maste #endif
700f540a430SEd Maste r = nlmsg_rx(nl->fd, reply, sizeof(reply), NETLINK_POLL_MS);
7010afa8e06SEd Maste #ifndef FIDO_FUZZ
7020afa8e06SEd Maste if (setsockopt(nl->fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP,
7030afa8e06SEd Maste &nl->nfc_mcastgrp, sizeof(nl->nfc_mcastgrp)) == -1) {
7040afa8e06SEd Maste fido_log_error(errno, "%s: setsockopt drop", __func__);
7050afa8e06SEd Maste return (-1);
7060afa8e06SEd Maste }
7070afa8e06SEd Maste #endif
7080afa8e06SEd Maste if (r < 0) {
7090afa8e06SEd Maste fido_log_debug("%s: nlmsg_rx", __func__);
7100afa8e06SEd Maste return (-1);
7110afa8e06SEd Maste }
7120afa8e06SEd Maste memset(&ctx, 0, sizeof(ctx));
7130afa8e06SEd Maste ctx.dev = dev;
7140afa8e06SEd Maste if ((ok = nl_parse_reply(reply, (size_t)r, nl->nfc_type,
7150afa8e06SEd Maste NFC_EVENT_TARGETS_FOUND, &ctx, parse_nfc_event)) != 0) {
7160afa8e06SEd Maste fido_log_debug("%s: nl_parse_reply: %d", __func__, ok);
7170afa8e06SEd Maste return (-1);
7180afa8e06SEd Maste }
7190afa8e06SEd Maste if (ctx.eventcnt == 0) {
7200afa8e06SEd Maste fido_log_debug("%s: dev 0x%x not observed", __func__, dev);
7210afa8e06SEd Maste return (-1);
7220afa8e06SEd Maste }
7230afa8e06SEd Maste if (nl_dump_nfc_target(nl, dev, target, -1) < 0) {
7240afa8e06SEd Maste fido_log_debug("%s: nl_dump_nfc_target", __func__);
7250afa8e06SEd Maste return (-1);
7260afa8e06SEd Maste }
7270afa8e06SEd Maste
7280afa8e06SEd Maste return (0);
7290afa8e06SEd Maste }
7300afa8e06SEd Maste
7310afa8e06SEd Maste void
fido_nl_free(fido_nl_t ** nlp)7320afa8e06SEd Maste fido_nl_free(fido_nl_t **nlp)
7330afa8e06SEd Maste {
7340afa8e06SEd Maste fido_nl_t *nl;
7350afa8e06SEd Maste
7360afa8e06SEd Maste if (nlp == NULL || (nl = *nlp) == NULL)
7370afa8e06SEd Maste return;
7380afa8e06SEd Maste if (nl->fd != -1 && close(nl->fd) == -1)
7390afa8e06SEd Maste fido_log_error(errno, "%s: close", __func__);
7400afa8e06SEd Maste
7410afa8e06SEd Maste free(nl);
7420afa8e06SEd Maste *nlp = NULL;
7430afa8e06SEd Maste }
7440afa8e06SEd Maste
7450afa8e06SEd Maste fido_nl_t *
fido_nl_new(void)7460afa8e06SEd Maste fido_nl_new(void)
7470afa8e06SEd Maste {
7480afa8e06SEd Maste fido_nl_t *nl;
7490afa8e06SEd Maste int ok = -1;
7500afa8e06SEd Maste
7510afa8e06SEd Maste if ((nl = calloc(1, sizeof(*nl))) == NULL)
7520afa8e06SEd Maste return (NULL);
7530afa8e06SEd Maste if ((nl->fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC,
7540afa8e06SEd Maste NETLINK_GENERIC)) == -1) {
7550afa8e06SEd Maste fido_log_error(errno, "%s: socket", __func__);
7560afa8e06SEd Maste goto fail;
7570afa8e06SEd Maste }
7580afa8e06SEd Maste nl->saddr.nl_family = AF_NETLINK;
7590afa8e06SEd Maste if (bind(nl->fd, (struct sockaddr *)&nl->saddr,
7600afa8e06SEd Maste sizeof(nl->saddr)) == -1) {
7610afa8e06SEd Maste fido_log_error(errno, "%s: bind", __func__);
7620afa8e06SEd Maste goto fail;
7630afa8e06SEd Maste }
7640afa8e06SEd Maste if (nl_get_nfc_family(nl->fd, &nl->nfc_type, &nl->nfc_mcastgrp) < 0) {
7650afa8e06SEd Maste fido_log_debug("%s: nl_get_nfc_family", __func__);
7660afa8e06SEd Maste goto fail;
7670afa8e06SEd Maste }
7680afa8e06SEd Maste
7690afa8e06SEd Maste ok = 0;
7700afa8e06SEd Maste fail:
7710afa8e06SEd Maste if (ok < 0)
7720afa8e06SEd Maste fido_nl_free(&nl);
7730afa8e06SEd Maste
7740afa8e06SEd Maste return (nl);
7750afa8e06SEd Maste }
7760afa8e06SEd Maste
7770afa8e06SEd Maste #ifdef FIDO_FUZZ
7780afa8e06SEd Maste void
set_netlink_io_functions(ssize_t (* read_f)(int,void *,size_t),ssize_t (* write_f)(int,const void *,size_t))7790afa8e06SEd Maste set_netlink_io_functions(ssize_t (*read_f)(int, void *, size_t),
7800afa8e06SEd Maste ssize_t (*write_f)(int, const void *, size_t))
7810afa8e06SEd Maste {
7820afa8e06SEd Maste fuzz_read = read_f;
7830afa8e06SEd Maste fuzz_write = write_f;
7840afa8e06SEd Maste }
7850afa8e06SEd Maste #endif
786