int netlink_request_simple(void *request, __u32 request_len) { struct nl_msg *msg; int error; msg = nlmsg_alloc(); if (!msg) { log_err("Could not allocate the request; it seems we're out of memory."); return -ENOMEM; } if (!genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, family, 0, 0, JOOL_COMMAND, 1)) { log_err("Unknown error building the packet to the kernel."); nlmsg_free(msg); return -EINVAL; } error = nla_put(msg, ATTR_DATA, request_len, request); if (error) { log_err("Could not write on the packet to kernelspace."); nlmsg_free(msg); return netlink_print_error(error); } error = nl_send_auto(sk, msg); nlmsg_free(msg); if (error < 0) { log_err("Could not dispatch the request to kernelspace."); return netlink_print_error(error); } return 0; }
int xfrmnl_ae_get_kernel(struct nl_sock* sock, struct nl_addr* daddr, unsigned int spi, unsigned int protocol, unsigned int mark_mask, unsigned int mark_value, struct xfrmnl_ae** result) { struct nl_msg *msg = NULL; struct nl_object *obj; int err; if ((err = xfrmnl_ae_build_get_request(daddr, spi, protocol, mark_mask, mark_value, &msg)) < 0) return err; err = nl_send_auto(sock, msg); nlmsg_free(msg); if (err < 0) return err; if ((err = nl_pickup(sock, &xfrm_ae_msg_parser, &obj)) < 0) return err; /* We have used xfrm_ae_msg_parser(), object is definitely a xfrm ae */ *result = (struct xfrmnl_ae *) obj; /* If an object has been returned, we also need to wait for the ACK */ if (err == 0 && obj) nl_wait_for_ack(sock); return 0; }
int match_nl_create_update_destroy_table(struct nl_sock *nsd, uint32_t pid, unsigned int ifindex, int family, struct net_mat_tbl *table, uint8_t cmd) { struct nlattr *tb[NET_MAT_MAX+1]; struct nlattr *nest, *nest1; struct nlmsghdr *nlh; struct match_msg *msg; sigset_t bs; int err = 0; msg = match_nl_alloc_msg(cmd, pid, NLM_F_REQUEST|NLM_F_ACK, 0, family); if (!msg) { MAT_LOG(ERR, "Error: Allocation failure\n"); return -ENOMSG; } if (nla_put_u32(msg->nlbuf, NET_MAT_IDENTIFIER_TYPE, NET_MAT_IDENTIFIER_IFINDEX) || nla_put_u32(msg->nlbuf, NET_MAT_IDENTIFIER, ifindex)) { MAT_LOG(ERR, "Error: Identifier put failed\n"); match_nl_free_msg(msg); return -EMSGSIZE; } nest = nla_nest_start(msg->nlbuf, NET_MAT_TABLES); if (!nest) { match_nl_free_msg(msg); return -EMSGSIZE; } nest1 = nla_nest_start(msg->nlbuf, NET_MAT_TABLE); match_put_table(msg->nlbuf, table); nla_nest_end(msg->nlbuf, nest1); nla_nest_end(msg->nlbuf, nest); nl_send_auto(nsd, msg->nlbuf); match_nl_free_msg(msg); sigemptyset(&bs); sigaddset(&bs, SIGINT); sigprocmask(SIG_UNBLOCK, &bs, NULL); msg = match_nl_recv_msg(nsd, &err); sigprocmask(SIG_BLOCK, &bs, NULL); if (!msg) return -EINVAL; nlh = msg->msg; err = genlmsg_parse(nlh, 0, tb, NET_MAT_MAX, match_get_tables_policy); if (err < 0) { MAT_LOG(ERR, "Warning: unable to parse create table msg\n"); match_nl_free_msg(msg); return err; } match_nl_free_msg(msg); return 0; }
indigo_error_t indigo_port_stats_get( of_port_stats_request_t *port_stats_request, of_port_stats_reply_t **port_stats_reply_ptr) { of_port_no_t req_of_port_num; of_port_stats_reply_t *port_stats_reply; indigo_error_t err = INDIGO_ERROR_NONE; port_stats_reply = of_port_stats_reply_new(port_stats_request->version); if (port_stats_reply == NULL) { err = INDIGO_ERROR_RESOURCE; goto out; } of_list_port_stats_entry_t list; of_port_stats_reply_entries_bind(port_stats_reply, &list); of_port_stats_request_port_no_get(port_stats_request, &req_of_port_num); int dump_all = req_of_port_num == OF_PORT_DEST_NONE_BY_VERSION(port_stats_request->version); /* Refresh statistics */ nl_cache_refill(route_cache_sock, link_cache); struct nl_msg *msg = ind_ovs_create_nlmsg(ovs_vport_family, OVS_VPORT_CMD_GET); if (dump_all) { nlmsg_hdr(msg)->nlmsg_flags |= NLM_F_DUMP; } else { nla_put_u32(msg, OVS_VPORT_ATTR_PORT_NO, req_of_port_num); } /* Ask kernel to send us one or more OVS_VPORT_CMD_NEW messages */ if (nl_send_auto(ind_ovs_socket, msg) < 0) { err = INDIGO_ERROR_UNKNOWN; goto out; } ind_ovs_nlmsg_freelist_free(msg); /* Handle OVS_VPORT_CMD_NEW messages */ nl_cb_set(netlink_callbacks, NL_CB_VALID, NL_CB_CUSTOM, port_stats_iterator, &list); if (nl_recvmsgs(ind_ovs_socket, netlink_callbacks) < 0) { err = INDIGO_ERROR_UNKNOWN; goto out; } out: if (err != INDIGO_ERROR_NONE) { of_port_stats_reply_delete(port_stats_reply); port_stats_reply = NULL; } *port_stats_reply_ptr = port_stats_reply; return err; }
int netlink_request(void *request, __u32 request_len, jool_response_cb cb, void *cb_arg) { struct nl_msg *msg; struct response_cb callback = { .cb = cb, .arg = cb_arg }; int error; error = nl_socket_modify_cb(sk, NL_CB_MSG_IN, NL_CB_CUSTOM, response_handler, &callback); if (error < 0) { log_err("Could not register response handler."); log_err("I will not be able to parse Jool's response, so I won't send the request."); return netlink_print_error(error); } msg = nlmsg_alloc(); if (!msg) { log_err("Could not allocate the message to the kernel; it seems we're out of memory."); return -ENOMEM; } if (!genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, family, 0, 0, JOOL_COMMAND, 1)) { log_err("Unknown error building the packet to the kernel."); nlmsg_free(msg); return -EINVAL; } error = nla_put(msg, ATTR_DATA, request_len, request); if (error) { log_err("Could not write on the packet to kernelspace."); nlmsg_free(msg); return netlink_print_error(error); } error = nl_send_auto(sk, msg); nlmsg_free(msg); if (error < 0) { log_err("Could not dispatch the request to kernelspace."); return netlink_print_error(error); } error = nl_recvmsgs_default(sk); if (error < 0) { if (error_handler_called) { error_handler_called = false; return error; } log_err("Error receiving the kernel module's response."); return netlink_print_error(error); } return 0; }
int main() { struct nl_sock * sk; int cbarg; // nl_debug = 4; // setup netlink socket sk = nl_socket_alloc(); nl_socket_disable_seq_check(sk); // disable sequence number check genl_connect(sk); int id = genl_ctrl_resolve(sk, DEMO_FAMILY_NAME); struct nl_msg * msg; // create a messgae msg = nlmsg_alloc(); genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, id, 0, // hdrlen 0, // flags DEMO_CMD, // numeric command identifier DEMO_VERSION // interface version ); nla_put_string(msg, DEMO_ATTR1_STRING, "hola"); nla_put_u16(msg, DEMO_ATTR2_UINT16, 0xf1); // send it nl_send_auto(sk, msg); // handle reply struct nl_cb * cb = NULL; cb = nl_cb_alloc(NL_CB_CUSTOM); //nl_cb_set_all(cb, NL_CB_DEBUG, NULL, NULL); nl_cb_set_all(cb, NL_CB_CUSTOM, cb_handler, &cbarg); nl_cb_err(cb, NL_CB_DEBUG, NULL, NULL); int nrecv = nl_recvmsgs_report(sk, cb); printf("cbarg %d nrecv %d\n", cbarg, nrecv); // cleanup nlmsg_free(msg); nl_close(sk); nl_socket_free(sk); return 0; }
static void show(void) { struct nl_msg *msg = nlmsg_alloc(); struct ovs_header *hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, ovs_datapath_family, sizeof(*hdr), NLM_F_DUMP, OVS_DP_CMD_GET, OVS_DATAPATH_VERSION); hdr->dp_ifindex = 0; if (nl_send_auto(sk, msg) < 0) { abort(); } nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, show_datapath__, NULL); nl_recvmsgs_default(sk); }
int mod_subflow( struct mptcp_state *mp_state, uint32_t src_ip, uint32_t src_locid, struct connection *conn, int command) { int rc = 0; struct nl_sock_data *nlsd; struct nl_sock *sock; struct nl_msg *msg; msg = nlmsg_alloc(); nlsd = (struct nl_sock_data *)mptcp_state_get_comms(mp_state); sock = nlsd->sock; genlmsg_put(msg, 0, 0, nlsd->family_id, CA_PM_GENL_HDRLEN, 0, command, CA_PM_GENL_VERSION); //print_debug("Subflow: %s -> %s:%d\n", src->name, ip_to_str(htonl(conn->daddr)), conn->dport); rc = nla_put_u32 (msg, CONTEXT_MPTCP_TOKEN, conn->token); if(rc < 0) print_error("NLA PUT ERROR CONTEXT_MPTCP_TOKEN\n"); rc = nla_put_u32 (msg, CONTEXT_SRC_ADDR, src_ip); if(rc < 0) print_error("NLA PUT ERROR CONTEXT_SRC_ADDR\n"); rc = nla_put_u32 (msg, CONTEXT_DST_ADDR, conn->daddr); if(rc < 0) print_error("NLA PUT ERROR CONTEXT_DST_ADDR\n"); rc = nla_put_u16 (msg, CONTEXT_DST_PORT, conn->dport); if(rc < 0) print_error("NLA PUT ERROR CONTEXT_DST_PORT\n"); rc = nla_put_u16 (msg, CONTEXT_LOC_ID, src_locid); if(rc < 0) print_error("NLA PUT ERROR CONTEXT_LOC_ID\n"); nl_send_auto(sock, msg); nlmsg_free(msg); return 0; }
static void show_vports__(int dp_ifindex) { struct nl_msg *msg = nlmsg_alloc(); struct ovs_header *hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, ovs_vport_family, sizeof(*hdr), NLM_F_DUMP, OVS_VPORT_CMD_GET, OVS_VPORT_VERSION); hdr->dp_ifindex = dp_ifindex; if (nl_send_auto(sk2, msg) < 0) { abort(); } nl_socket_modify_cb(sk2, NL_CB_VALID, NL_CB_CUSTOM, show_vport__, NULL); nl_recvmsgs_default(sk2); nlmsg_free(msg); }
int nf10_reg_wr(uint32_t addr, uint32_t val) { struct nl_msg *msg; int err; err = driver_connect(); if(err) return err; msg = nlmsg_alloc(); if(msg == NULL) { driver_disconnect(); return -NLE_NOMEM; } /* genlmsg_put will fill in the fields of the nlmsghdr and the genlmsghdr. */ genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, nf10_genl_family, 0, 0, NF10_GENL_C_REG_WR, NF10_GENL_FAMILY_VERSION); nla_put_u32(msg, NF10_GENL_A_ADDR32, addr); nla_put_u32(msg, NF10_GENL_A_REGVAL32, val); /* nl_send_auto will automatically fill in the PID and the sequence number, * and also add an NLM_F_REQUEST flag. It will also add an NLM_F_ACK * flag unless the netlink socket has the NL_NO_AUTO_ACK flag set. */ err = nl_send_auto(nf10_genl_sock, msg); if(err < 0) { nlmsg_free(msg); driver_disconnect(); return err; } nlmsg_free(msg); nl_socket_modify_cb(nf10_genl_sock, NL_CB_ACK, NL_CB_CUSTOM, nf10_reg_wr_recv_ack_cb, NULL); /* FIXME: this function will return even if there's no ACK in the buffer. I.E. it doesn't * seem to wait for the ACK to be received... Ideally we'd have the behavior that getting an * ACK tells us everything is OK, otherwise we time out on waiting for an ACK and tell this * to the user. */ err = nl_recvmsgs_default(nf10_genl_sock); driver_disconnect(); return err; }
int nlt_get_ifinfo(struct nl_sock *sk, struct nlt_ifinfo *ifinfo) { struct nl_msg *msg = nlmsg_alloc(); if (!msg) return -1; int flags = NLM_F_DUMP; int family_id = genl_ctrl_resolve(sk, "nl80211"); genlmsg_put(msg, 0, NL_AUTO_SEQ, family_id, 0, flags, NL80211_CMD_GET_INTERFACE, 0); // NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, 0); nl_send_auto(sk, msg); int err; struct nl_cb *nl_cb = nl_cb_alloc(NL_CB_CUSTOM); nl_cb_set(nl_cb, NL_CB_VALID, NL_CB_CUSTOM, get_ifinfo_cb, ifinfo); nl_cb_err(nl_cb, NL_CB_CUSTOM, error_handler, &err); int nlr; // do { nlr = nl_recvmsgs(sk, nl_cb); // printf("round %d\n",nlr); // }while(1);; //int nlr = nl_recvmsgs_default(sk); // cw_log(LOG_ERR, "iGet if index: Make if %d - %s", nlr, nl_geterror(nlr)); // nla_put_failure: nlmsg_free(msg); return 0; }
/* Replacement for nl_send_sync that returns the real error code */ static int transact(struct nl_sock *sk, struct nl_msg *msg) { if (nl_send_auto(sk, msg) < 0) { return -EBADE; } nlmsg_free(msg); struct nlmsghdr *reply; struct sockaddr_nl nla; if (nl_recv(sk, &nla, (unsigned char **)&reply, NULL) < 0) { return -EBADE; } assert(reply->nlmsg_type == NLMSG_ERROR); int err = ((struct nlmsgerr *)nlmsg_data(reply))->error; free(reply); return err; }
/* * See the OF_PORT_DEST_USE_TABLE comment in ind_ovs_translate_actions. * This is mostly the same as ind_ovs_handle_packet_miss but does * not reuse the original message for the execute command since * the incoming message has a userdata attribute. * It also doesn't install a kflow or update flow stats. */ static void ind_ovs_handle_packet_table(struct ind_ovs_upcall_thread *thread, struct ind_ovs_port *port, struct nl_msg *msg, struct nlattr **attrs) { struct nlattr *key = attrs[OVS_PACKET_ATTR_KEY]; struct nlattr *packet = attrs[OVS_PACKET_ATTR_PACKET]; assert(key && packet); struct ind_ovs_parsed_key pkey; ind_ovs_parse_key(key, &pkey); /* Lookup the flow in the userspace flowtable. */ struct ind_ovs_flow *flow; if (ind_ovs_lookup_flow(&pkey, &flow) != 0) { ind_ovs_upcall_request_pktin(pkey.in_port, port, packet, key, OF_PACKET_IN_REASON_NO_MATCH); return; } /* Send OVS_PACKET_CMD_EXECUTE. */ /* TODO ensure the message is large enough */ struct nl_msg *reply = ind_ovs_create_nlmsg(ovs_packet_family, OVS_PACKET_CMD_EXECUTE); ind_ovs_translate_actions(&pkey, flow->of_list_action, reply, OVS_PACKET_ATTR_ACTIONS); nla_put(reply, OVS_PACKET_ATTR_KEY, nla_len(key), nla_data(key)); nla_put(reply, OVS_PACKET_ATTR_PACKET, nla_len(packet), nla_data(packet)); struct nlattr *actions = nlmsg_find_attr(nlmsg_hdr(reply), sizeof(struct genlmsghdr) + sizeof(struct ovs_header), OVS_PACKET_ATTR_ACTIONS); /* Don't send the packet back out if it would be dropped. */ if (nla_len(actions) > 0) { nl_send_auto(port->notify_socket, reply); } ind_ovs_nlmsg_freelist_free(reply); }
int nf10_reg_rd(uint32_t addr, uint32_t *val_ptr) { struct nl_msg *msg; int err; err = driver_connect(); if(err) return err; msg = nlmsg_alloc(); if(msg == NULL) { driver_disconnect(); return -NLE_NOMEM; } /* genlmsg_put will fill in the fields of the nlmsghdr and the genlmsghdr. */ genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, nf10_genl_family, 0, 0, NF10_GENL_C_REG_RD, NF10_GENL_FAMILY_VERSION); nla_put_u32(msg, NF10_GENL_A_ADDR32, addr); /* nl_send_auto will automatically fill in the PID and the sequence number, * and also add an NLM_F_REQUEST flag. It will also add an NLM_F_ACK * flag unless the netlink socket has the NL_NO_AUTO_ACK flag set. */ err = nl_send_auto(nf10_genl_sock, msg); if(err < 0) { nlmsg_free(msg); driver_disconnect(); return err; } nlmsg_free(msg); nl_socket_modify_cb(nf10_genl_sock, NL_CB_VALID, NL_CB_CUSTOM, nf10_reg_rd_recv_msg_cb, (void*)val_ptr); err = nl_recvmsgs_default(nf10_genl_sock); driver_disconnect(); return err; }
/** * Construct and transmit a Netlink message * @arg sk Netlink socket (required) * @arg type Netlink message type (required) * @arg flags Netlink message flags (optional) * @arg buf Data buffer (optional) * @arg size Size of data buffer (optional) * * Allocates a new Netlink message based on `type` and `flags`. If `buf` * points to payload of length `size` that payload will be appended to the * message. * * Sends out the message using `nl_send_auto()` and frees the message * afterwards. * * @see nl_send_auto() * * @return Number of characters sent on success or a negative error code. * @retval -NLE_NOMEM Unable to allocate Netlink message */ int nl_send_simple(struct nl_sock *sk, int type, int flags, void *buf, size_t size) { int err; struct nl_msg *msg; msg = nlmsg_alloc_simple(type, flags); if (!msg) return -NLE_NOMEM; if (buf && size) { err = nlmsg_append(msg, buf, size, NLMSG_ALIGNTO); if (err < 0) goto errout; } err = nl_send_auto(sk, msg); errout: nlmsg_free(msg); return err; }
static void dump_flows(const char *datapath) { unsigned int dp_ifindex = if_nametoindex(datapath); if (dp_ifindex == 0) { fprintf(stderr, "Failed: no such datapath '%s'\n", datapath); exit(1); } struct nl_msg *msg = nlmsg_alloc(); struct ovs_header *hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, ovs_flow_family, sizeof(*hdr), NLM_F_DUMP, OVS_FLOW_CMD_GET, OVS_FLOW_VERSION); hdr->dp_ifindex = dp_ifindex; if (nl_send_auto(sk2, msg) < 0) { abort(); } nl_socket_modify_cb(sk2, NL_CB_VALID, NL_CB_CUSTOM, show_kflow__, NULL); nl_recvmsgs_default(sk2); nlmsg_free(msg); }
struct match_msg *match_nl_alloc_msg(uint8_t type, uint32_t pid, int flags, int size, int family) { struct match_msg *msg; static uint32_t seq = 0; msg = (struct match_msg *) malloc(sizeof(struct match_msg)); if (!msg) return NULL; msg->nlbuf = nlmsg_alloc(); msg->msg = genlmsg_put(msg->nlbuf, 0, seq, family, (int)size, flags, type, NET_MAT_GENL_VERSION); msg->seq = seq++; if (pid) { struct nl_msg *nl_msg = msg->nlbuf; struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK, .nl_pid = pid, .nl_groups = 0, }; nlmsg_set_dst(nl_msg, &nladdr); } return msg; } struct match_msg *match_nl_get_msg(struct nl_sock *nsd, uint8_t cmd, uint32_t pid, unsigned int ifindex, int family) { struct match_msg *msg; sigset_t bs; int err; msg = match_nl_alloc_msg(cmd, pid, NLM_F_REQUEST|NLM_F_ACK, 0, family); if (!msg) { MAT_LOG(ERR, "Error: Allocation failure\n"); return NULL; } nla_put_u32(msg->nlbuf, NET_MAT_IDENTIFIER_TYPE, NET_MAT_IDENTIFIER_IFINDEX); nla_put_u32(msg->nlbuf, NET_MAT_IDENTIFIER, ifindex); nl_send_auto(nsd, msg->nlbuf); match_nl_free_msg(msg); sigemptyset(&bs); sigaddset(&bs, SIGINT); sigprocmask(SIG_UNBLOCK, &bs, NULL); msg = match_nl_recv_msg(nsd, &err); sigprocmask(SIG_BLOCK, &bs, NULL); return msg; } static int match_nl_get_port(struct nl_sock *nsd, uint32_t pid, unsigned int ifindex, int family, uint8_t cmd, struct net_mat_port *ports, uint32_t *port_id, uint32_t *glort) { struct net_mat_port *port_query = NULL; struct match_msg *msg; sigset_t bs; int err; msg = match_nl_alloc_msg(cmd, pid, NLM_F_REQUEST|NLM_F_ACK, 0, family); if (!msg) { MAT_LOG(ERR, "Error: Allocation failure\n"); return -ENOMEM; } if (nla_put_u32(msg->nlbuf, NET_MAT_IDENTIFIER_TYPE, NET_MAT_IDENTIFIER_IFINDEX) || nla_put_u32(msg->nlbuf, NET_MAT_IDENTIFIER, ifindex)) { match_nl_free_msg(msg); return -EMSGSIZE; } err = match_put_ports(msg->nlbuf, ports); if (err) { match_nl_free_msg(msg); return -EMSGSIZE; } nl_send_auto(nsd, msg->nlbuf); match_nl_free_msg(msg); sigemptyset(&bs); sigaddset(&bs, SIGINT); sigprocmask(SIG_UNBLOCK, &bs, NULL); msg = match_nl_recv_msg(nsd, &err); if (msg) { struct nlmsghdr *nlh = msg->msg; struct nlattr *tb[NET_MAT_MAX+1]; int err; err = genlmsg_parse(nlh, 0, tb, NET_MAT_MAX, match_get_tables_policy); if (err < 0) { MAT_LOG(ERR, "Warning: unable to parse pci to lport msg\n"); match_nl_free_msg(msg); return -EINVAL; } if (match_nl_table_cmd_to_type(stdout, true, NET_MAT_PORTS, tb)) { match_nl_free_msg(msg); return -EINVAL; } if (tb[NET_MAT_PORTS]) { err = match_get_ports(stdout, verbose, tb[NET_MAT_PORTS], &port_query); if (err) { match_nl_free_msg(msg); return -EINVAL; } } if (!port_query) { match_nl_free_msg(msg); return -EINVAL; } if (cmd == NET_MAT_PORT_CMD_GET_LPORT) *port_id = port_query[0].port_id; else if (cmd == NET_MAT_PORT_CMD_GET_PHYS_PORT) *port_id = port_query[0].port_phys_id; if (glort) *glort = port_query[0].glort; } match_nl_free_msg(msg); free(port_query); return 0; } int match_nl_pci_lport(struct nl_sock *nsd, uint32_t pid, unsigned int ifindex, int family, uint8_t bus, uint8_t device, uint8_t function, uint32_t *lport, uint32_t *glort) { struct net_mat_port port = {.pci = {0}, .port_id = NET_MAT_PORT_ID_UNSPEC, .mac_addr = 0, .port_phys_id = 0}; struct net_mat_port ports[2] = {{0}, {0}}; int err; ports[0] = ports[1] = port; ports[0].pci.bus = bus; ports[0].pci.device = device; ports[0].pci.function = function; err = match_nl_get_port(nsd, pid, ifindex, family, NET_MAT_PORT_CMD_GET_LPORT, ports, lport, glort); return err; } int match_nl_mac_lport(struct nl_sock *nsd, uint32_t pid, unsigned int ifindex, int family, uint64_t mac, uint32_t *lport, uint32_t *glort) { struct net_mat_port port = {.pci = {0}, .port_id = NET_MAT_PORT_ID_UNSPEC, .mac_addr = 0, .port_phys_id = 0}; struct net_mat_port ports[2] = {{0}, {0}}; int err; ports[0] = ports[1] = port; ports[0].mac_addr = mac; err = match_nl_get_port(nsd, pid, ifindex, family, NET_MAT_PORT_CMD_GET_LPORT, ports, lport, glort); return err; } int match_nl_lport_to_phys_port(struct nl_sock *nsd, uint32_t pid, unsigned int ifindex, int family, uint32_t lport, uint32_t *phys_port, uint32_t *glort) { struct net_mat_port port = {.pci = {0}, .port_id = NET_MAT_PORT_ID_UNSPEC, .mac_addr = 0, .port_phys_id = 0}; struct net_mat_port ports[2] = {{0}, {0}}; int err; ports[0] = ports[1] = port; ports[0].port_id = lport; err = match_nl_get_port(nsd, pid, ifindex, family, NET_MAT_PORT_CMD_GET_PHYS_PORT, ports, phys_port, glort); return err; }
/** * Send netlink message. * @arg sk Netlink socket. * @arg msg Netlink message to be sent. * @arg iov iovec to be sent. * @arg iovlen number of struct iovec to be sent. * @see nl_sendmsg() * @return Number of characters sent on success or a negative error code. */ int nl_send_iovec(struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsigned iovlen) { struct sockaddr_nl *dst; struct ucred *creds; struct msghdr hdr = { .msg_name = (void *) &sk->s_peer, .msg_namelen = sizeof(struct sockaddr_nl), .msg_iov = iov, .msg_iovlen = iovlen, }; /* Overwrite destination if specified in the message itself, defaults * to the peer address of the socket. */ dst = nlmsg_get_dst(msg); if (dst->nl_family == AF_NETLINK) hdr.msg_name = dst; /* Add credentials if present. */ creds = nlmsg_get_creds(msg); if (creds != NULL) { char buf[CMSG_SPACE(sizeof(struct ucred))]; struct cmsghdr *cmsg; hdr.msg_control = buf; hdr.msg_controllen = sizeof(buf); cmsg = CMSG_FIRSTHDR(&hdr); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_CREDENTIALS; cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred)); memcpy(CMSG_DATA(cmsg), creds, sizeof(struct ucred)); } return nl_sendmsg(sk, msg, &hdr); } /** * Send netlink message. * @arg sk Netlink socket. * @arg msg Netlink message to be sent. * @see nl_sendmsg() * @return Number of characters sent on success or a negative error code. */ int nl_send(struct nl_sock *sk, struct nl_msg *msg) { struct iovec iov = { .iov_base = (void *) nlmsg_hdr(msg), .iov_len = nlmsg_hdr(msg)->nlmsg_len, }; return nl_send_iovec(sk, msg, &iov, 1); } void nl_complete_msg(struct nl_sock *sk, struct nl_msg *msg) { struct nlmsghdr *nlh; nlh = nlmsg_hdr(msg); if (nlh->nlmsg_pid == 0) nlh->nlmsg_pid = sk->s_local.nl_pid; if (nlh->nlmsg_seq == 0) nlh->nlmsg_seq = sk->s_seq_next++; if (msg->nm_protocol == -1) msg->nm_protocol = sk->s_proto; nlh->nlmsg_flags |= NLM_F_REQUEST; if (!(sk->s_flags & NL_NO_AUTO_ACK)) nlh->nlmsg_flags |= NLM_F_ACK; } void nl_auto_complete(struct nl_sock *sk, struct nl_msg *msg) { nl_complete_msg(sk, msg); } /** * Automatically complete and send a netlink message * @arg sk Netlink socket. * @arg msg Netlink message to be sent. * * This function takes a netlink message and passes it on to * nl_auto_complete() for completion. * * Checks the netlink message \c nlh for completness and extends it * as required before sending it out. Checked fields include pid, * sequence nr, and flags. * * @see nl_send() * @return Number of characters sent or a negative error code. */ int nl_send_auto(struct nl_sock *sk, struct nl_msg *msg) { struct nl_cb *cb = sk->s_cb; nl_complete_msg(sk, msg); if (cb->cb_send_ow) return cb->cb_send_ow(sk, msg); else return nl_send(sk, msg); } int nl_send_auto_complete(struct nl_sock *sk, struct nl_msg *msg) { return nl_send_auto(sk, msg); } /** * Send netlink message and wait for response (sync request-response) * @arg sk Netlink socket * @arg msg Netlink message to be sent * * This function takes a netlink message and sends it using nl_send_auto(). * It will then wait for the response (ACK or error message) to be * received. Threfore this function will block until the operation has * been completed. * * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause * this function to return immediately after sending. In this case, * it is the responsibility of the caller to handle any eventual * error messages returned. * * @see nl_send_auto(). * * @return 0 on success or a negative error code. */ int nl_send_sync(struct nl_sock *sk, struct nl_msg *msg) { int err; err = nl_send_auto(sk, msg); nlmsg_free(msg); if (err < 0) return err; return wait_for_ack(sk); }
int match_nl_set_del_rules(struct nl_sock *nsd, uint32_t pid, unsigned int ifindex, int family, struct net_mat_rule *rule, uint8_t cmd) { struct nlattr *tb[NET_MAT_MAX+1]; struct match_msg *msg; struct nlmsghdr *nlh; struct nlattr *rules; sigset_t bs; int err = 0; pp_rule(stdout, true, rule); msg = match_nl_alloc_msg(cmd, pid, NLM_F_REQUEST|NLM_F_ACK, 0, family); if (!msg) { MAT_LOG(ERR, "Error: Allocation failure\n"); return -ENOMSG; } if (nla_put_u32(msg->nlbuf, NET_MAT_IDENTIFIER_TYPE, NET_MAT_IDENTIFIER_IFINDEX) || nla_put_u32(msg->nlbuf, NET_MAT_IDENTIFIER, ifindex)) { MAT_LOG(ERR, "Error: Identifier put failed\n"); match_nl_free_msg(msg); return -EMSGSIZE; } err = match_put_rule_error(msg->nlbuf, NET_MAT_RULES_ERROR_CONT_LOG); if (err) { match_nl_free_msg(msg); return err; } rules = nla_nest_start(msg->nlbuf, NET_MAT_RULES); if (!rules) { match_nl_free_msg(msg); return -EMSGSIZE; } match_put_rule(msg->nlbuf, rule); nla_nest_end(msg->nlbuf, rules); nl_send_auto(nsd, msg->nlbuf); match_nl_free_msg(msg); /* message sent handle recv */ sigemptyset(&bs); sigaddset(&bs, SIGINT); sigprocmask(SIG_UNBLOCK, &bs, NULL); msg = match_nl_recv_msg(nsd, &err); sigprocmask(SIG_BLOCK, &bs, NULL); if (!msg) return -EINVAL; nlh = msg->msg; err = genlmsg_parse(nlh, 0, tb, NET_MAT_MAX, match_get_tables_policy); if (err < 0) { MAT_LOG(ERR, "Warning: unable to parse set rules msg\n"); match_nl_free_msg(msg); return err; } err = match_nl_table_cmd_to_type(stdout, true, 0, tb); if (err) { match_nl_free_msg(msg); return err; } if (tb[NET_MAT_RULES]) { MAT_LOG(ERR, "Failed to set:\n"); match_get_rules(stdout, verbose, tb[NET_MAT_RULES], NULL); match_nl_free_msg(msg); return -EINVAL; } match_nl_free_msg(msg); return 0; }
int match_nl_set_port(struct nl_sock *nsd, uint32_t pid, unsigned int ifindex, int family, struct net_mat_port *port) { uint8_t cmd = NET_MAT_PORT_CMD_SET_PORTS; struct nlattr *tb[NET_MAT_MAX+1]; struct nlattr *nest, *nest1; struct nlmsghdr *nlh; struct match_msg *msg; sigset_t bs; int err = 0; msg = match_nl_alloc_msg(cmd, pid, NLM_F_REQUEST|NLM_F_ACK, 0, family); if (!msg) { MAT_LOG(ERR, "Error: Allocation failure\n"); return -ENOMSG; } if (nla_put_u32(msg->nlbuf, NET_MAT_IDENTIFIER_TYPE, NET_MAT_IDENTIFIER_IFINDEX) || nla_put_u32(msg->nlbuf, NET_MAT_IDENTIFIER, ifindex)) { MAT_LOG(ERR, "Error: Identifier put failed\n"); match_nl_free_msg(msg); return -EMSGSIZE; } nest = nla_nest_start(msg->nlbuf, NET_MAT_PORTS); if (!nest) { match_nl_free_msg(msg); return -EMSGSIZE; } nest1 = nla_nest_start(msg->nlbuf, NET_MAT_PORTS); match_put_port(msg->nlbuf, port); nla_nest_end(msg->nlbuf, nest1); nla_nest_end(msg->nlbuf, nest); nl_send_auto(nsd, msg->nlbuf); match_nl_free_msg(msg); sigemptyset(&bs); sigaddset(&bs, SIGINT); sigprocmask(SIG_UNBLOCK, &bs, NULL); msg = match_nl_recv_msg(nsd, &err); sigprocmask(SIG_BLOCK, &bs, NULL); if (!msg) return -EINVAL; nlh = msg->msg; err = genlmsg_parse(nlh, 0, tb, NET_MAT_MAX, match_get_tables_policy); if (err < 0) { MAT_LOG(ERR, "Warning: unable to parse set port msg\n"); match_nl_free_msg(msg); return err; } err = match_nl_table_cmd_to_type(stdout, true, 0, tb); if (err) { match_nl_free_msg(msg); return err; } if (tb[NET_MAT_PORTS]) { MAT_LOG(ERR, "Failed to set:\n"); match_get_ports(stdout, verbose, tb[NET_MAT_PORTS], NULL); match_nl_free_msg(msg); return -EINVAL; } match_nl_free_msg(msg); return 0; }
struct net_mat_port *match_nl_get_ports(struct nl_sock *nsd, uint32_t pid, unsigned int ifindex, int family, uint32_t min, uint32_t max) { uint8_t cmd = NET_MAT_PORT_CMD_GET_PORTS; struct nlattr *tb[NET_MAT_MAX+1]; struct net_mat_port *port = NULL; struct match_msg *msg; struct nlmsghdr *nlh; struct nlattr *ports; sigset_t bs; int err = 0; msg = match_nl_alloc_msg(cmd, pid, NLM_F_REQUEST|NLM_F_ACK, 0, family); if (!msg) { MAT_LOG(ERR, "Error: Allocation failure\n"); return NULL; } if (nla_put_u32(msg->nlbuf, NET_MAT_IDENTIFIER_TYPE, NET_MAT_IDENTIFIER_IFINDEX) || nla_put_u32(msg->nlbuf, NET_MAT_IDENTIFIER, ifindex)) { MAT_LOG(ERR, "Error: Identifier put failed\n"); goto out; } err = match_put_rule_error(msg->nlbuf, NET_MAT_RULES_ERROR_CONT_LOG); if (err) goto out; ports = nla_nest_start(msg->nlbuf, NET_MAT_PORTS); if (!ports) { MAT_LOG(ERR, "Error: get_port attributes failed\n"); goto out; } if (min) { err = nla_put_u32(msg->nlbuf, NET_MAT_PORT_MIN_INDEX, min); if (err) goto out; } if (max) { err = nla_put_u32(msg->nlbuf, NET_MAT_PORT_MAX_INDEX, max); if (err) goto out; } nla_nest_end(msg->nlbuf, ports); nl_send_auto(nsd, msg->nlbuf); match_nl_free_msg(msg); /* message sent handle recv */ sigemptyset(&bs); sigaddset(&bs, SIGINT); sigprocmask(SIG_UNBLOCK, &bs, NULL); msg = match_nl_recv_msg(nsd, &err); sigprocmask(SIG_BLOCK, &bs, NULL); if (msg) { nlh = msg->msg; err = genlmsg_parse(nlh, 0, tb, NET_MAT_MAX, match_get_tables_policy); if (err < 0) { MAT_LOG(ERR, "Warning: unable to parse get rules msg\n"); goto out; } if (match_nl_table_cmd_to_type(stdout, true, NET_MAT_PORTS, tb)) goto out; if (tb[NET_MAT_PORTS]) { err = match_get_ports(stdout, verbose, tb[NET_MAT_PORTS], &port); if (err) goto out; } } match_nl_free_msg(msg); return port; out: match_nl_free_msg(msg); return NULL; }
/** * @deprecated Please use nl_send_auto() */ int nl_send_auto_complete(struct nl_sock *sk, struct nl_msg *msg) { return nl_send_auto(sk, msg); }
/** * Transmit Netlink message (taking IO vector) * @arg sk Netlink socket (required) * @arg msg Netlink message to be sent (required) * @arg iov IO vector to be sent (required) * @arg iovlen Number of struct iovec to be sent (required) * * This function is identical to nl_send() except that instead of taking a * `struct nl_msg` object it takes an IO vector. Please see the description * of `nl_send()`. * * @callback This function triggers the `NL_CB_MSG_OUT` callback. * * @see nl_send() * * @return Number of bytes sent on success or a negative error code. * * @lowlevel */ int nl_send_iovec(struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsigned iovlen) { struct sockaddr_nl *dst; struct ucred *creds; struct msghdr hdr = { .msg_name = (void *) &sk->s_peer, .msg_namelen = sizeof(struct sockaddr_nl), .msg_iov = iov, .msg_iovlen = iovlen, }; /* Overwrite destination if specified in the message itself, defaults * to the peer address of the socket. */ dst = nlmsg_get_dst(msg); if (dst->nl_family == AF_NETLINK) hdr.msg_name = dst; /* Add credentials if present. */ creds = nlmsg_get_creds(msg); if (creds != NULL) { char buf[CMSG_SPACE(sizeof(struct ucred))]; struct cmsghdr *cmsg; hdr.msg_control = buf; hdr.msg_controllen = sizeof(buf); cmsg = CMSG_FIRSTHDR(&hdr); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_CREDENTIALS; cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred)); memcpy(CMSG_DATA(cmsg), creds, sizeof(struct ucred)); } return nl_sendmsg(sk, msg, &hdr); } /** * Transmit Netlink message * @arg sk Netlink socket (required) * @arg msg Netlink message (required) * * Transmits the Netlink message `msg` over the Netlink socket using the * `sendmsg()` system call. This function is based on `nl_send_iovec()` but * takes care of initializing a `struct iovec` based on the `msg` object. * * The message is addressed to the peer as specified in the socket by either * the nl_socket_set_peer_port() or nl_socket_set_peer_groups() function. * The peer address can be overwritten by specifying an address in the `msg` * object using nlmsg_set_dst(). * * If present in the `msg`, credentials set by the nlmsg_set_creds() function * are added to the control buffer of the message. * * @par Overwriting Capability: * Calls to this function can be overwritten by providing an alternative using * the nl_cb_overwrite_send() function. * * @callback This function triggers the `NL_CB_MSG_OUT` callback. * * @attention * Unlike `nl_send_auto()`, this function does *not* finalize the message in * terms of automatically adding needed flags or filling out port numbers. * * @see nl_send_auto() * @see nl_send_iovec() * @see nl_socket_set_peer_port() * @see nl_socket_set_peer_groups() * @see nlmsg_set_dst() * @see nlmsg_set_creds() * @see nl_cb_overwrite_send() * * @return Number of bytes sent on success or a negative error code. */ int nl_send(struct nl_sock *sk, struct nl_msg *msg) { struct nl_cb *cb = sk->s_cb; if (cb->cb_send_ow) return cb->cb_send_ow(sk, msg); else { struct iovec iov = { .iov_base = (void *) nlmsg_hdr(msg), .iov_len = nlmsg_hdr(msg)->nlmsg_len, }; return nl_send_iovec(sk, msg, &iov, 1); } } /** * Finalize Netlink message * @arg sk Netlink socket (required) * @arg msg Netlink message (required) * * This function finalizes a Netlink message by completing the message with * desirable flags and values depending on the socket configuration. * * - If not yet filled out, the source address of the message (`nlmsg_pid`) * will be set to the local port number of the socket. * - If not yet specified, the next available sequence number is assigned * to the message (`nlmsg_seq`). * - If not yet specified, the protocol field of the message will be set to * the protocol field of the socket. * - The `NLM_F_REQUEST` Netlink message flag will be set. * - The `NLM_F_ACK` flag will be set if Auto-ACK mode is enabled on the * socket. */ void nl_complete_msg(struct nl_sock *sk, struct nl_msg *msg) { struct nlmsghdr *nlh; nlh = nlmsg_hdr(msg); if (nlh->nlmsg_pid == NL_AUTO_PORT) nlh->nlmsg_pid = nl_socket_get_local_port(sk); if (nlh->nlmsg_seq == NL_AUTO_SEQ) nlh->nlmsg_seq = sk->s_seq_next++; if (msg->nm_protocol == -1) msg->nm_protocol = sk->s_proto; nlh->nlmsg_flags |= NLM_F_REQUEST; if (!(sk->s_flags & NL_NO_AUTO_ACK)) nlh->nlmsg_flags |= NLM_F_ACK; } /** * Finalize and transmit Netlink message * @arg sk Netlink socket (required) * @arg msg Netlink message (required) * * Finalizes the message by passing it to `nl_complete_msg()` and transmits it * by passing it to `nl_send()`. * * @callback This function triggers the `NL_CB_MSG_OUT` callback. * * @see nl_complete_msg() * @see nl_send() * * @return Number of bytes sent or a negative error code. */ int nl_send_auto(struct nl_sock *sk, struct nl_msg *msg) { nl_complete_msg(sk, msg); return nl_send(sk, msg); } /** * Finalize and transmit Netlink message and wait for ACK or error message * @arg sk Netlink socket (required) * @arg msg Netlink message (required) * * Passes the `msg` to `nl_send_auto()` to finalize and transmit it. Frees the * message and waits (sleeps) for the ACK or error message to be received. * * @attention * Disabling Auto-ACK (nl_socket_disable_auto_ack()) will cause this function * to return immediately after transmitting the message. However, the peer may * still be returning an error message in response to the request. It is the * responsibility of the caller to handle such messages. * * @callback This function triggers the `NL_CB_MSG_OUT` callback. * * @attention * This function frees the `msg` object after transmitting it by calling * `nlmsg_free()`. * * @see nl_send_auto(). * @see nl_wait_for_ack() * * @return 0 on success or a negative error code. */ int nl_send_sync(struct nl_sock *sk, struct nl_msg *msg) { int err; err = nl_send_auto(sk, msg); nlmsg_free(msg); if (err < 0) return err; return wait_for_ack(sk); }