/** * nfnl_open - open a nfnetlink handler * * This function creates a nfnetlink handler, this is required to establish * a communication between the userspace and the nfnetlink system. * * On success, a valid address that points to a nfnl_handle structure * is returned. On error, NULL is returned and errno is set approapiately. */ struct nfnl_handle *nfnl_open(void) { struct nfnl_handle *nfnlh; unsigned int addr_len; nfnlh = malloc(sizeof(*nfnlh)); if (!nfnlh) return NULL; memset(nfnlh, 0, sizeof(*nfnlh)); nfnlh->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER); if (nfnlh->fd == -1) goto err_free; nfnlh->local.nl_family = AF_NETLINK; nfnlh->peer.nl_family = AF_NETLINK; addr_len = sizeof(nfnlh->local); getsockname(nfnlh->fd, (struct sockaddr *)&nfnlh->local, &addr_len); if (addr_len != sizeof(nfnlh->local)) { errno = EINVAL; goto err_close; } if (nfnlh->local.nl_family != AF_NETLINK) { errno = EINVAL; goto err_close; } nfnlh->seq = time(NULL); nfnlh->rcv_buffer_size = NFNL_BUFFSIZE; /* don't set pid here, only first socket of process has real pid !!! * binding to pid '0' will default */ /* let us do the initial bind */ if (recalc_rebind_subscriptions(nfnlh) < 0) goto err_close; /* use getsockname to get the netlink pid that the kernel assigned us */ addr_len = sizeof(nfnlh->local); getsockname(nfnlh->fd, (struct sockaddr *)&nfnlh->local, &addr_len); if (addr_len != sizeof(nfnlh->local)) { errno = EINVAL; goto err_close; } /* sequence tracking enabled by default */ nfnlh->flags |= NFNL_F_SEQTRACK_ENABLED; return nfnlh; err_close: close(nfnlh->fd); err_free: free(nfnlh); return NULL; }
/** * nfnl_subsys_open - open a netlink subsystem * @nfnlh: libnfnetlink handle * @subsys_id: which nfnetlink subsystem we are interested in * @cb_count: number of callbacks that are used maximum. * @subscriptions: netlink groups we want to be subscribed to * * This function creates a subsystem handler that contains the set of * callbacks that handle certain types of messages coming from a netfilter * subsystem. Initially the callback set is empty, you can register callbacks * via nfnl_callback_register(). * * On error, NULL is returned and errno is set appropiately. On success, * a valid address that points to a nfnl_subsys_handle structure is returned. */ struct nfnl_subsys_handle * nfnl_subsys_open(struct nfnl_handle *nfnlh, uint8_t subsys_id, uint8_t cb_count, uint32_t subscriptions) { struct nfnl_subsys_handle *ssh; assert(nfnlh); if (subsys_id > NFNL_MAX_SUBSYS) { errno = ENOENT; return NULL; } ssh = &nfnlh->subsys[subsys_id]; if (ssh->cb) { errno = EBUSY; return NULL; } ssh->cb = calloc(cb_count, sizeof(*(ssh->cb))); if (!ssh->cb) return NULL; ssh->nfnlh = nfnlh; ssh->cb_count = cb_count; ssh->subscriptions = subscriptions; ssh->subsys_id = subsys_id; /* although now we have nfnl_join to subscribe to certain * groups, just keep this to ensure compatibility */ if (recalc_rebind_subscriptions(nfnlh) < 0) { free(ssh->cb); ssh->cb = NULL; return NULL; } return ssh; }
/** * nfnl_open - open a nfnetlink handler * * This function creates a nfnetlink handler, this is required to establish * a communication between the userspace and the nfnetlink system. * * On success, a valid address that points to a nfnl_handle structure * is returned. On error, NULL is returned and errno is set approapiately. */ struct nfnl_handle *nfnl_open(void) { struct nfnl_handle *nfnlh; unsigned int addr_len; int err; nfnlh = malloc(sizeof(*nfnlh)); if (!nfnlh) return NULL; memset(nfnlh, 0, sizeof(*nfnlh)); nfnlh->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER); if (nfnlh->fd == -1) goto err_free; nfnlh->local.nl_family = AF_NETLINK; nfnlh->peer.nl_family = AF_NETLINK; addr_len = sizeof(nfnlh->local); err = getsockname(nfnlh->fd, (struct sockaddr *)&nfnlh->local, &addr_len); if (addr_len != sizeof(nfnlh->local)) { errno = EINVAL; goto err_close; } if (nfnlh->local.nl_family != AF_NETLINK) { errno = EINVAL; goto err_close; } nfnlh->seq = time(NULL); /* don't set pid here, only first socket of process has real pid !!! * binding to pid '0' will default */ /* let us do the initial bind */ if (recalc_rebind_subscriptions(nfnlh) < 0) goto err_close; /* use getsockname to get the netlink pid that the kernel assigned us */ addr_len = sizeof(nfnlh->local); err = getsockname(nfnlh->fd, (struct sockaddr *)&nfnlh->local, &addr_len); if (addr_len != sizeof(nfnlh->local)) { errno = EINVAL; goto err_close; } #if defined(AEI_VDSL_CUSTOMER_NCS) printf("set NETLINK_RECV_NO_ENOBUFS\n"); unsigned int enable=1; setsockopt(nfnlh->fd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &enable, sizeof(enable)); #endif return nfnlh; err_close: close(nfnlh->fd); err_free: free(nfnlh); return NULL; }