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; }
static int nl80211_del_mon_if(struct nl80211_state *state, const char *device, const char *mondevice) { int ifindex, ret; struct nl_msg *msg; ifindex = device_ifindex(mondevice); msg = nl80211_nlmsg_xalloc(); genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0, 0, NL80211_CMD_DEL_INTERFACE, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); ret = nl_send_auto_complete(state->nl_sock, msg); if (ret < 0) panic("Cannot send_auto_complete!\n"); ret = nl_wait_for_ack(state->nl_sock); if (ret < 0) panic("Waiting for netlink ack failed!\n"); nlmsg_free(msg); return 0; nla_put_failure: panic("nla put failure!\n"); return -EIO; /* dummy */ }
static int nl80211_add_mon_if(struct nl80211_state *state, const char *device, const char *mondevice) { int ifindex, ret; struct nl_msg *msg; struct nl_cb *cb = NULL; int finished = 0; ifindex = device_ifindex(device); msg = nl80211_nlmsg_xalloc(); genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0, 0, NL80211_CMD_NEW_INTERFACE, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, mondevice); NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR); ret = nl_send_auto_complete(state->nl_sock, msg); if (ret < 0) { if (ret == -ENFILE) { nlmsg_free(msg); return -EBUSY; } panic("Cannot send_auto_complete!\n"); } cb = nl_cb_alloc(NL_CB_CUSTOM); if (!cb) panic("Cannot alloc nl_cb!\n"); nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, nl80211_wait_handler, &finished); nl_cb_err(cb, NL_CB_CUSTOM, nl80211_error_handler, NULL); nl_recvmsgs(state->nl_sock, cb); if (!finished) { ret = nl_wait_for_ack(state->nl_sock); if (ret < 0) { if (ret == -ENFILE) { nlmsg_free(msg); return -EBUSY; } panic("Waiting for netlink ack failed!\n"); } } nl_cb_put(cb); nlmsg_free(msg); return 0; nla_put_failure: panic("nla put failure!\n"); return -EIO; /* dummy */ }
static int send_log_msg(struct nl_handle *handle, struct nl_msg *msg) { int err; err = nl_send_auto_complete(handle, msg); nlmsg_free(msg); if (err < 0) return err; return nl_wait_for_ack(handle); }
int nl80211_createvap(const char *interface, const char *newinterface, char *errstr) { #ifndef HAVE_LINUX_NETLINK snprintf(errstr, LORCON_STATUS_MAX, "LORCON was not compiled with " "netlink/nl80211 support, check the output of ./configure for why"); return -1; #else struct nl_sock *nl_handle; struct nl_cache *nl_cache; struct genl_family *nl80211; struct nl_msg *msg; if (if_nametoindex(newinterface) > 0) return 1; if (nl80211_connect(interface, (void **) &nl_handle, (void **) &nl_cache, (void **) &nl80211, errstr) < 0) return -1; if ((msg = nlmsg_alloc()) == NULL) { snprintf(errstr, LORCON_STATUS_MAX, "nl80211_createvap() failed to allocate " "message"); nl80211_disconnect(nl_handle); return -1; } genlmsg_put(msg, 0, 0, genl_family_get_id(nl80211), 0, 0, NL80211_CMD_NEW_INTERFACE, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(interface)); NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, newinterface); NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR); if (nl_send_auto_complete(nl_handle, msg) < 0 || nl_wait_for_ack(nl_handle) < 0) { nla_put_failure: snprintf(errstr, LORCON_STATUS_MAX, "nl80211_createvap() failed to create " "interface '%s'", newinterface); nlmsg_free(msg); nl80211_disconnect(nl_handle); return -1; } nlmsg_free(msg); nl80211_disconnect(nl_handle); if (if_nametoindex(newinterface) <= 0) { snprintf(errstr, LORCON_STATUS_MAX, "nl80211_createvap() thought we made a " "vap, but it wasn't there when we looked"); return -1; } return 0; #endif }
/** * Delete a neighbour * @arg handle netlink handle * @arg neigh neighbour to delete * * Builds a netlink message by calling rtnl_neigh_build_delete_request(), * sends the request to the kernel and waits for the next ACK to be * received and thus blocks until the request has been fullfilled. * * @return 0 on sucess or a negative error if an error occured. */ int rtnl_neigh_delete(struct nl_handle *handle, struct rtnl_neigh *neigh) { int err; struct nl_msg *m = rtnl_neigh_build_delete_request(neigh); if ((err = nl_send_auto_complete(handle, nl_msg_get(m))) < 0) return err; nl_msg_free(m); return nl_wait_for_ack(handle); }
/** * Add a new rule * @arg handle netlink handle * @arg tmpl template with requested changes * * Builds a netlink message by calling rtnl_rule_build_add_request(), * sends the request to the kernel and waits for the next ACK to be * received and thus blocks until the request has been fullfilled. * * @return 0 on sucess or a negative error if an error occured. */ int rtnl_rule_add(struct nl_handle *handle, struct rtnl_rule *tmpl) { int err; struct nl_msg *m = rtnl_rule_build_add_request(tmpl); if ((err = nl_send_auto_complete(handle, nl_msg_get(m))) < 0) return err; nl_msg_free(m); return nl_wait_for_ack(handle); }
int nl80211_setchannel_cache(const char *interface, void *handle, void *family, int channel, unsigned int chmode, char *errstr) { #ifndef HAVE_LINUX_NETLINK snprintf(errstr, LORCON_STATUS_MAX, "LORCON was not compiled with netlink/nl80211 " "support, check the output of ./configure for why"); // Return the same error as we get if the device doesn't support nlfreq return -22; #else struct nl_sock *nl_handle = (struct nl_sock *) handle; struct genl_family *nl80211 = (struct genl_family *) family; struct nl_msg *msg; int ret = 0; int chanmode[] = { NL80211_CHAN_NO_HT, NL80211_CHAN_HT20, NL80211_CHAN_HT40PLUS, NL80211_CHAN_HT40MINUS }; if (chmode > 4) { snprintf(errstr, LORCON_STATUS_MAX, "Invalid channel mode\n"); return -1; } if ((msg = nlmsg_alloc()) == NULL) { snprintf(errstr, LORCON_STATUS_MAX, "nl80211_setchannel() failed to allocate " "message"); return -1; } genlmsg_put(msg, 0, 0, genl_family_get_id(nl80211), 0, 0, NL80211_CMD_SET_WIPHY, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(interface)); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, ChanToFreq(channel)); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, chanmode[chmode]); if ((ret = nl_send_auto_complete(nl_handle, msg)) >= 0) { if ((ret = nl_wait_for_ack(nl_handle)) < 0) goto nla_put_failure; } nlmsg_free(msg); return 0; nla_put_failure: snprintf(errstr, LORCON_STATUS_MAX, "nl80211_setchannel() could not set channel " "%d/%d on interface '%s' err %d", channel, ChanToFreq(channel), interface, ret); nlmsg_free(msg); return ret; #endif }
int nl80211_setvapflag(const char *interface, char *errstr, int nflags, int *in_flags) { #ifndef HAVE_LINUX_NETLINK snprintf(errstr, LORCON_STATUS_MAX, "LORCON was not compiled with netlink/nl80211 " "support, check the output of ./configure for why"); return -1; #else struct nl_sock *nl_handle; struct nl_cache *nl_cache; struct genl_family *nl80211; struct nl_msg *msg; if (nl80211_connect(interface, (void **) &nl_handle, (void **) &nl_cache, (void **) &nl80211, errstr) < 0) return -1; if ((msg = nlmsg_alloc()) == NULL) { snprintf(errstr, LORCON_STATUS_MAX, "%s failed to allocate message", __FUNCTION__); nl80211_disconnect(nl_handle); return -1; } genlmsg_put(msg, 0, 0, genl_family_get_id(nl80211), 0, 0, NL80211_CMD_SET_INTERFACE, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(interface)); NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR); nl80211_parseflags(nflags, in_flags, msg); if (nl_send_auto_complete(nl_handle, msg) >= 0) { if (nl_wait_for_ack(nl_handle) < 0) { goto nla_put_failure; } } else { nla_put_failure: snprintf(errstr, LORCON_STATUS_MAX, "%s failed to set flags on " "interface '%s': %s", __FUNCTION__, interface, strerror(errno)); nlmsg_free(msg); nl80211_disconnect(nl_handle); return -1; } nlmsg_free(msg); nl80211_disconnect(nl_handle); return 0; #endif }
int xfrmnl_ae_set(struct nl_sock* sk, struct xfrmnl_ae* ae, int flags) { int err; struct nl_msg *msg; if ((err = build_xfrm_ae_message(ae, XFRM_MSG_NEWAE, flags|NLM_F_REPLACE, &msg)) < 0) return err; err = nl_send_auto_complete(sk, msg); nlmsg_free(msg); if (err < 0) return err; return nl_wait_for_ack(sk); }
/** * Delete a classifier * @arg sk Netlink socket. * @arg cls classifier to delete * @arg flags additional netlink message flags * * Builds a netlink message by calling rtnl_cls_build_delete_request(), * sends the request to the kernel and waits for the next ACK to be * received and thus blocks until the request has been processed. * * @return 0 on sucess or a negative error if an error occured. */ int rtnl_cls_delete(struct nl_sock *sk, struct rtnl_cls *cls, int flags) { struct nl_msg *msg; int err; if ((err = rtnl_cls_build_delete_request(cls, flags, &msg)) < 0) return err; err = nl_send_auto_complete(sk, msg); nlmsg_free(msg); if (err < 0) return err; return nl_wait_for_ack(sk); }
/** * Add a new rule * @arg handle netlink handle * @arg tmpl template with requested changes * @arg flags additional netlink message flags * * Builds a netlink message by calling rtnl_rule_build_add_request(), * sends the request to the kernel and waits for the next ACK to be * received and thus blocks until the request has been fullfilled. * * @return 0 on sucess or a negative error if an error occured. */ int rtnl_rule_add(struct nl_handle *handle, struct rtnl_rule *tmpl, int flags) { int err; struct nl_msg *msg; msg = rtnl_rule_build_add_request(tmpl, flags); if (!msg) return nl_errno(ENOMEM); err = nl_send_auto_complete(handle, msg); if (err < 0) return err; nlmsg_free(msg); return nl_wait_for_ack(handle); }
/** * Request addition of new address * @arg handle Netlink handle. * @arg addr Address object representing the new address. * @arg flags Additional netlink message flags. * * Builds a netlink message by calling rtnl_addr_build_add_request(), * sends the request to the kernel and waits for the next ACK to be * received and thus blocks until the request has been fullfilled. * * @see rtnl_addr_build_add_request() * * @return 0 on sucess or a negative error if an error occured. */ int rtnl_addr_add(struct nl_handle *handle, struct rtnl_addr *addr, int flags) { struct nl_msg *msg; int err; msg = rtnl_addr_build_add_request(addr, flags); if (!msg) return nl_get_errno(); err = nl_send_auto_complete(handle, msg); nlmsg_free(msg); if (err < 0) return err; return nl_wait_for_ack(handle); }
int main() { /* create socket */ struct nl_sock *sk = NULL; sk = nl_socket_alloc(); genl_connect(sk); nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, get_cw, NULL); /* setup message */ int driver_id, if_index; struct nl_msg *msg = NULL; driver_id = genl_ctrl_resolve(sk, "nl80211"); if_index = if_nametoindex("wlan0"); msg = nlmsg_alloc(); genlmsg_put(msg, 0, 0, driver_id, 0, 0, NL80211_CMD_GET_WIPHY, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_index); //struct nlattr *nested; //nested = nla_nest_start(msg,NL80211_ATTR_WIPHY_TXQ_PARAMS); //NLA_PUT_U16(msg,NL80211_TXQ_ATTR_CWMIN,cw_min); //NLA_PUT_U16(msg,NL80211_TXQ_ATTR_CWMAX,cw_max); //nla_nest_end(msg,nested); /* send/recv/ack */ int r; r = nl_send_auto_complete(sk, msg); printf("atlasd: nl_send_auto_complete returned %d\n", r); nl_recvmsgs_default(sk); nl_wait_for_ack(sk); nla_put_failure: /* from NLA_PUT_* macros */ fail: if (sk) nl_socket_free(sk); if (msg) nlmsg_free(msg); }
static int handle_interface_del(struct nl80211_state *state, char *phy, char *dev, int argc, char **argv) { int err; struct nl_msg *msg; if (argc) { fprintf(stderr, "too many arguments\n"); return -1; } msg = nlmsg_alloc(); if (!msg) return -1; genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0, 0, NL80211_CMD_DEL_INTERFACE, 0); if (!dev) { fprintf(stderr, "need device\n"); nlmsg_free(msg); return -1; } NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(dev)); if ((err = nl_send_auto_complete(state->nl_handle, msg)) < 0 || (err = nl_wait_for_ack(state->nl_handle)) < 0) { nla_put_failure: fprintf(stderr, "failed to remove interface: %d\n", err); nlmsg_free(msg); return -1; } nlmsg_free(msg); return 0; }
static void copy_cacheinfo_into_route(struct rta_cacheinfo *ci, struct rtnl_route *route) { struct rtnl_rtcacheinfo nci = { .rtci_clntref = ci->rta_clntref, .rtci_last_use = ci->rta_lastuse, .rtci_expires = ci->rta_expires, .rtci_error = ci->rta_error, .rtci_used = ci->rta_used, .rtci_id = ci->rta_id, .rtci_ts = ci->rta_ts, .rtci_tsage = ci->rta_tsage, }; rtnl_route_set_cacheinfo(route, &nci); } static int route_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, struct nlmsghdr *nlh, struct nl_parser_param *pp) { struct rtmsg *rtm; struct rtnl_route *route; struct nlattr *tb[RTA_MAX + 1]; struct nl_addr *src = NULL, *dst = NULL, *addr; int err; route = rtnl_route_alloc(); if (!route) { err = nl_errno(ENOMEM); goto errout; } route->ce_msgtype = nlh->nlmsg_type; err = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, RTA_MAX, route_policy); if (err < 0) goto errout; rtm = nlmsg_data(nlh); rtnl_route_set_family(route, rtm->rtm_family); rtnl_route_set_tos(route, rtm->rtm_tos); rtnl_route_set_table(route, rtm->rtm_table); rtnl_route_set_type(route, rtm->rtm_type); rtnl_route_set_scope(route, rtm->rtm_scope); rtnl_route_set_protocol(route, rtm->rtm_protocol); rtnl_route_set_flags(route, rtm->rtm_flags); if (tb[RTA_DST]) { dst = nla_get_addr(tb[RTA_DST], rtm->rtm_family); if (dst == NULL) goto errout_errno; } else { dst = nl_addr_alloc(0); nl_addr_set_family(dst, rtm->rtm_family); } nl_addr_set_prefixlen(dst, rtm->rtm_dst_len); err = rtnl_route_set_dst(route, dst); if (err < 0) goto errout; nl_addr_put(dst); if (tb[RTA_SRC]) { src = nla_get_addr(tb[RTA_SRC], rtm->rtm_family); if (src == NULL) goto errout_errno; } else if (rtm->rtm_src_len) src = nl_addr_alloc(0); if (src) { nl_addr_set_prefixlen(src, rtm->rtm_src_len); rtnl_route_set_src(route, src); nl_addr_put(src); } if (tb[RTA_IIF]) rtnl_route_set_iif(route, nla_get_string(tb[RTA_IIF])); if (tb[RTA_OIF]) rtnl_route_set_oif(route, nla_get_u32(tb[RTA_OIF])); if (tb[RTA_GATEWAY]) { addr = nla_get_addr(tb[RTA_GATEWAY], route->rt_family); if (addr == NULL) goto errout_errno; rtnl_route_set_gateway(route, addr); nl_addr_put(addr); } if (tb[RTA_PRIORITY]) rtnl_route_set_prio(route, nla_get_u32(tb[RTA_PRIORITY])); if (tb[RTA_PREFSRC]) { addr = nla_get_addr(tb[RTA_PREFSRC], route->rt_family); if (addr == NULL) goto errout_errno; rtnl_route_set_pref_src(route, addr); nl_addr_put(addr); } if (tb[RTA_METRICS]) { struct nlattr *mtb[RTAX_MAX + 1]; int i; err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL); if (err < 0) goto errout; for (i = 1; i <= RTAX_MAX; i++) { if (mtb[i] && nla_len(mtb[i]) >= sizeof(uint32_t)) { uint32_t m = nla_get_u32(mtb[i]); if (rtnl_route_set_metric(route, i, m) < 0) goto errout_errno; } } } if (tb[RTA_MULTIPATH]) { struct rtnl_nexthop *nh; struct rtnexthop *rtnh = nla_data(tb[RTA_MULTIPATH]); size_t tlen = nla_len(tb[RTA_MULTIPATH]); while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) { nh = rtnl_route_nh_alloc(); if (!nh) goto errout; rtnl_route_nh_set_weight(nh, rtnh->rtnh_hops); rtnl_route_nh_set_ifindex(nh, rtnh->rtnh_ifindex); rtnl_route_nh_set_flags(nh, rtnh->rtnh_flags); if (rtnh->rtnh_len > sizeof(*rtnh)) { struct nlattr *ntb[RTA_MAX + 1]; nla_parse(ntb, RTA_MAX, (struct nlattr *) RTNH_DATA(rtnh), rtnh->rtnh_len - sizeof(*rtnh), route_policy); if (ntb[RTA_GATEWAY]) { nh->rtnh_gateway = nla_get_addr( ntb[RTA_GATEWAY], route->rt_family); nh->rtnh_mask = NEXTHOP_HAS_GATEWAY; } } rtnl_route_add_nexthop(route, nh); tlen -= RTNH_ALIGN(rtnh->rtnh_len); rtnh = RTNH_NEXT(rtnh); } } if (tb[RTA_FLOW]) rtnl_route_set_realms(route, nla_get_u32(tb[RTA_FLOW])); if (tb[RTA_CACHEINFO]) copy_cacheinfo_into_route(nla_data(tb[RTA_CACHEINFO]), route); if (tb[RTA_MP_ALGO]) rtnl_route_set_mp_algo(route, nla_get_u32(tb[RTA_MP_ALGO])); err = pp->pp_cb((struct nl_object *) route, pp); if (err < 0) goto errout; err = P_ACCEPT; errout: rtnl_route_put(route); return err; errout_errno: err = nl_get_errno(); goto errout; } static int route_request_update(struct nl_cache *c, struct nl_handle *h) { return nl_rtgen_request(h, RTM_GETROUTE, AF_UNSPEC, NLM_F_DUMP); } /** * @name Cache Management * @{ */ /** * Build a route cache holding all routes currently configured in the kernel * @arg handle netlink handle * * Allocates a new cache, initializes it properly and updates it to * contain all routes currently configured in the kernel. * * @note The caller is responsible for destroying and freeing the * cache after using it. * @return The cache or NULL if an error has occured. */ struct nl_cache *rtnl_route_alloc_cache(struct nl_handle *handle) { struct nl_cache *cache; cache = nl_cache_alloc(&rtnl_route_ops); if (!cache) return NULL; if (handle && nl_cache_refill(handle, cache) < 0) { free(cache); return NULL; } return cache; } /** @} */ /** * @name Route Addition * @{ */ static struct nl_msg *build_route_msg(struct rtnl_route *tmpl, int cmd, int flags) { struct nl_msg *msg; struct nl_addr *addr; int scope, i, oif, nmetrics = 0; struct nlattr *metrics; struct rtmsg rtmsg = { .rtm_family = rtnl_route_get_family(tmpl), .rtm_dst_len = rtnl_route_get_dst_len(tmpl), .rtm_src_len = rtnl_route_get_src_len(tmpl), .rtm_tos = rtnl_route_get_tos(tmpl), .rtm_table = rtnl_route_get_table(tmpl), .rtm_type = rtnl_route_get_type(tmpl), .rtm_protocol = rtnl_route_get_protocol(tmpl), .rtm_flags = rtnl_route_get_flags(tmpl), }; if (rtmsg.rtm_family == AF_UNSPEC) { nl_error(EINVAL, "Cannot build route message, address " \ "family is unknown."); return NULL; } scope = rtnl_route_get_scope(tmpl); if (scope == RT_SCOPE_NOWHERE) { if (rtmsg.rtm_type == RTN_LOCAL) scope = RT_SCOPE_HOST; else { /* XXX Change to UNIVERSE if gw || nexthops */ scope = RT_SCOPE_LINK; } } rtmsg.rtm_scope = scope; msg = nlmsg_alloc_simple(cmd, flags); if (msg == NULL) return NULL; if (nlmsg_append(msg, &rtmsg, sizeof(rtmsg), NLMSG_ALIGNTO) < 0) goto nla_put_failure; addr = rtnl_route_get_dst(tmpl); if (addr) NLA_PUT_ADDR(msg, RTA_DST, addr); addr = rtnl_route_get_src(tmpl); if (addr) NLA_PUT_ADDR(msg, RTA_SRC, addr); addr = rtnl_route_get_gateway(tmpl); if (addr) NLA_PUT_ADDR(msg, RTA_GATEWAY, addr); addr = rtnl_route_get_pref_src(tmpl); if (addr) NLA_PUT_ADDR(msg, RTA_PREFSRC, addr); NLA_PUT_U32(msg, RTA_PRIORITY, rtnl_route_get_prio(tmpl)); oif = rtnl_route_get_oif(tmpl); if (oif != RTNL_LINK_NOT_FOUND) NLA_PUT_U32(msg, RTA_OIF, oif); for (i = 1; i <= RTAX_MAX; i++) if (rtnl_route_get_metric(tmpl, i) != UINT_MAX) nmetrics++; if (nmetrics > 0) { unsigned int val; metrics = nla_nest_start(msg, RTA_METRICS); if (metrics == NULL) goto nla_put_failure; for (i = 1; i <= RTAX_MAX; i++) { val = rtnl_route_get_metric(tmpl, i); if (val != UINT_MAX) NLA_PUT_U32(msg, i, val); } nla_nest_end(msg, metrics); } #if 0 RTA_IIF, RTA_MULTIPATH, RTA_PROTOINFO, RTA_FLOW, RTA_CACHEINFO, RTA_SESSION, RTA_MP_ALGO, #endif return msg; nla_put_failure: nlmsg_free(msg); return NULL; } struct nl_msg *rtnl_route_build_add_request(struct rtnl_route *tmpl, int flags) { return build_route_msg(tmpl, RTM_NEWROUTE, NLM_F_CREATE | flags); } int rtnl_route_add(struct nl_handle *handle, struct rtnl_route *route, int flags) { struct nl_msg *msg; int err; msg = rtnl_route_build_add_request(route, flags); if (!msg) return nl_get_errno(); err = nl_send_auto_complete(handle, msg); nlmsg_free(msg); if (err < 0) return err; return nl_wait_for_ack(handle); } struct nl_msg *rtnl_route_build_del_request(struct rtnl_route *tmpl, int flags) { return build_route_msg(tmpl, RTM_DELROUTE, flags); } int rtnl_route_del(struct nl_handle *handle, struct rtnl_route *route, int flags) { struct nl_msg *msg; int err; msg = rtnl_route_build_del_request(route, flags); if (!msg) return nl_get_errno(); err = nl_send_auto_complete(handle, msg); nlmsg_free(msg); if (err < 0) return err; return nl_wait_for_ack(handle); } /** @} */ static struct nl_af_group route_groups[] = { { AF_INET, RTNLGRP_IPV4_ROUTE }, { AF_INET6, RTNLGRP_IPV6_ROUTE }, { AF_DECnet, RTNLGRP_DECnet_ROUTE }, { END_OF_GROUP_LIST }, }; static struct nl_cache_ops rtnl_route_ops = { .co_name = "route/route", .co_hdrsize = sizeof(struct rtmsg), .co_msgtypes = { { RTM_NEWROUTE, NL_ACT_NEW, "new" }, { RTM_DELROUTE, NL_ACT_DEL, "del" }, { RTM_GETROUTE, NL_ACT_GET, "get" }, END_OF_MSGTYPES_LIST, }, .co_protocol = NETLINK_ROUTE, .co_groups = route_groups, .co_request_update = route_request_update, .co_msg_parser = route_msg_parser, .co_obj_ops = &route_obj_ops, }; static void __init route_init(void) { nl_cache_mngt_register(&rtnl_route_ops); } static void __exit route_exit(void) { nl_cache_mngt_unregister(&rtnl_route_ops); }
static struct nl_msg * build_neigh_msg(struct rtnl_neigh *tmpl, int cmd, int flags) { struct nl_msg *m; struct nlmsghdr n = { .nlmsg_type = cmd, .nlmsg_flags = flags, }; struct ndmsg nm = { .ndm_ifindex = tmpl->n_ifindex, .ndm_family = tmpl->n_dst.a_family, .ndm_state = tmpl->n_state, }; m = nl_msg_build(&n); nl_msg_append_raw(m, &nm, sizeof(nm)); nl_msg_append_tlv(m, NDA_DST, &tmpl->n_dst.a_addr, tmpl->n_dst.a_len); if (tmpl->n_mask & NEIGH_HAS_LLADDR) nl_msg_append_tlv(m, NDA_LLADDR, &tmpl->n_lladdr.a_addr, tmpl->n_lladdr.a_len); return m; } /** * Build netlink request message to add a new neighbour * @arg tmpl template with data of new neighbour * * Builds a new netlink message requesting a addition of a new * neighbour. The netlink message header isn't fully equipped with * all relevant fields and must thus be sent out via nl_send_auto_complete() * or supplemented as needed. \a tmpl must contain the attributes of the new * neighbour set via \c rtnl_neigh_set_* functions. * * The following attributes must be set in the template: * - Interface index (rtnl_neigh_set_ifindex()) * - State (rtnl_neigh_set_state()) * - Destination address (rtnl_neigh_set_dst()) * - Link layer address (rtnl_neigh_set_lladdr()) * * @return The netlink message */ struct nl_msg * rtnl_neigh_build_add_request(struct rtnl_neigh *tmpl) { return build_neigh_msg(tmpl, RTM_NEWNEIGH, NLM_F_CREATE); } /** * Add a new neighbour * @arg handle netlink handle * @arg tmpl template with requested changes * * Builds a netlink message by calling rtnl_neigh_build_add_request(), * sends the request to the kernel and waits for the next ACK to be * received and thus blocks until the request has been fullfilled. * * The following attributes must be set in the template: * - Interface index (rtnl_neigh_set_ifindex()) * - State (rtnl_neigh_set_state()) * - Destination address (rtnl_neigh_set_dst()) * - Link layer address (rtnl_neigh_set_lladdr()) * * @return 0 on sucess or a negative error if an error occured. */ int rtnl_neigh_add(struct nl_handle *handle, struct rtnl_neigh *tmpl) { int err; struct nl_msg *m = rtnl_neigh_build_add_request(tmpl); if ((err = nl_send_auto_complete(handle, nl_msg_get(m))) < 0) return err; nl_msg_free(m); return nl_wait_for_ack(handle); }
static int cls_request_update(struct nl_cache *cache, struct nl_sock *sk) { struct tcmsg tchdr = { .tcm_family = AF_UNSPEC, .tcm_ifindex = cache->c_iarg1, .tcm_parent = cache->c_iarg2, }; return nl_send_simple(sk, RTM_GETTFILTER, NLM_F_DUMP, &tchdr, sizeof(tchdr)); } static int cls_build(struct rtnl_cls *cls, int type, int flags, struct nl_msg **result) { struct rtnl_cls_ops *cops; int err, prio, proto; struct tcmsg *tchdr; err = tca_build_msg((struct rtnl_tca *) cls, type, flags, result); if (err < 0) return err; tchdr = nlmsg_data(nlmsg_hdr(*result)); prio = rtnl_cls_get_prio(cls); proto = rtnl_cls_get_protocol(cls); tchdr->tcm_info = TC_H_MAKE(prio << 16, htons(proto)); cops = rtnl_cls_lookup_ops(cls); if (cops && cops->co_get_opts) { struct nl_msg *opts; if (!(opts = nlmsg_alloc())) { err = -NLE_NOMEM; goto errout; } if (!(err = cops->co_get_opts(cls, opts))) err = nla_put_nested(*result, TCA_OPTIONS, opts); nlmsg_free(opts); if (err < 0) goto errout; } return 0; errout: nlmsg_free(*result); return err; } /** * @name Classifier Addition/Modification/Deletion * @{ */ /** * Build a netlink message to add a new classifier * @arg cls classifier to add * @arg flags additional netlink message flags * @arg result Pointer to store resulting message. * * Builds a new netlink message requesting an addition of a classifier * The netlink message header isn't fully equipped with all relevant * fields and must be sent out via nl_send_auto_complete() or * supplemented as needed. \a classifier must contain the attributes of * the new classifier set via \c rtnl_cls_set_* functions. \a opts * may point to the clsasifier specific options. * * @return 0 on success or a negative error code. */ int rtnl_cls_build_add_request(struct rtnl_cls *cls, int flags, struct nl_msg **result) { return cls_build(cls, RTM_NEWTFILTER, NLM_F_CREATE | flags, result); } /** * Add a new classifier * @arg sk Netlink socket. * @arg cls classifier to add * @arg flags additional netlink message flags * * Builds a netlink message by calling rtnl_cls_build_add_request(), * sends the request to the kernel and waits for the next ACK to be * received and thus blocks until the request has been processed. * * @return 0 on sucess or a negative error if an error occured. */ int rtnl_cls_add(struct nl_sock *sk, struct rtnl_cls *cls, int flags) { struct nl_msg *msg; int err; if ((err = rtnl_cls_build_add_request(cls, flags, &msg)) < 0) return err; err = nl_send_auto_complete(sk, msg); nlmsg_free(msg); if (err < 0) return err; return nl_wait_for_ack(sk); } /** * Build a netlink message to change classifier attributes * @arg cls classifier to change * @arg flags additional netlink message flags * @arg result Pointer to store resulting message. * * Builds a new netlink message requesting a change of a neigh * attributes. The netlink message header isn't fully equipped with * all relevant fields and must thus be sent out via nl_send_auto_complete() * or supplemented as needed. * * @return 0 on success or a negative error code. */ int rtnl_cls_build_change_request(struct rtnl_cls *cls, int flags, struct nl_msg **result) { return cls_build(cls, RTM_NEWTFILTER, NLM_F_REPLACE | flags, result); } /** * Change a classifier * @arg sk Netlink socket. * @arg cls classifier to change * @arg flags additional netlink message flags * * Builds a netlink message by calling rtnl_cls_build_change_request(), * sends the request to the kernel and waits for the next ACK to be * received and thus blocks until the request has been processed. * * @return 0 on sucess or a negative error if an error occured. */ int rtnl_cls_change(struct nl_sock *sk, struct rtnl_cls *cls, int flags) { struct nl_msg *msg; int err; if ((err = rtnl_cls_build_change_request(cls, flags, &msg)) < 0) return err; err = nl_send_auto_complete(sk, msg); nlmsg_free(msg); if (err < 0) return err; return nl_wait_for_ack(sk); } /** * Build a netlink request message to delete a classifier * @arg cls classifier to delete * @arg flags additional netlink message flags * @arg result Pointer to store resulting message. * * Builds a new netlink message requesting a deletion of a classifier. * The netlink message header isn't fully equipped with all relevant * fields and must thus be sent out via nl_send_auto_complete() * or supplemented as needed. * * @return 0 on success or a negative error code. */ int rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags, struct nl_msg **result) { return cls_build(cls, RTM_DELTFILTER, flags, result); } /** * Delete a classifier * @arg sk Netlink socket. * @arg cls classifier to delete * @arg flags additional netlink message flags * * Builds a netlink message by calling rtnl_cls_build_delete_request(), * sends the request to the kernel and waits for the next ACK to be * received and thus blocks until the request has been processed. * * @return 0 on sucess or a negative error if an error occured. */ int rtnl_cls_delete(struct nl_sock *sk, struct rtnl_cls *cls, int flags) { struct nl_msg *msg; int err; if ((err = rtnl_cls_build_delete_request(cls, flags, &msg)) < 0) return err; err = nl_send_auto_complete(sk, msg); nlmsg_free(msg); if (err < 0) return err; return nl_wait_for_ack(sk); } /** @} */ /** * @name Cache Management * @{ */ /** * Build a classifier cache including all classifiers attached to the * specified class/qdisc on eht specified interface. * @arg sk Netlink socket. * @arg ifindex interface index of the link the classes are * attached to. * @arg parent parent qdisc/class * @arg result Pointer to store resulting cache. * * Allocates a new cache, initializes it properly and updates it to * include all classes attached to the specified interface. * * @note The caller is responsible for destroying and freeing the * cache after using it. * @return 0 on success or a negative error code. */ int rtnl_cls_alloc_cache(struct nl_sock *sk, int ifindex, uint32_t parent, struct nl_cache **result) { struct nl_cache * cache; int err; if (!(cache = nl_cache_alloc(&rtnl_cls_ops))) return -NLE_NOMEM; cache->c_iarg1 = ifindex; cache->c_iarg2 = parent; if (sk && (err = nl_cache_refill(sk, cache)) < 0) { nl_cache_free(cache); return err; } *result = cache; return 0; } /** @} */ static struct nl_cache_ops rtnl_cls_ops = { .co_name = "route/cls", .co_hdrsize = sizeof(struct tcmsg), .co_msgtypes = { { RTM_NEWTFILTER, NL_ACT_NEW, "new" }, { RTM_DELTFILTER, NL_ACT_DEL, "del" }, { RTM_GETTFILTER, NL_ACT_GET, "get" }, END_OF_MSGTYPES_LIST, }, .co_protocol = NETLINK_ROUTE, .co_request_update = cls_request_update, .co_msg_parser = cls_msg_parser, .co_obj_ops = &cls_obj_ops, }; static void __init cls_init(void) { nl_cache_mngt_register(&rtnl_cls_ops); } static void __exit cls_exit(void) { nl_cache_mngt_unregister(&rtnl_cls_ops); }
static int handle_interface_add(struct nl80211_state *state, char *phy, char *dev, int argc, char **argv) { char *name; char *mesh_id = NULL; enum nl80211_iftype type; int tpset, err; struct nl_msg *msg; if (argc < 1) { fprintf(stderr, "not enough arguments\n"); return -1; } name = argv[0]; argc--; argv++; tpset = get_if_type(&argc, &argv, &type); if (tpset == 0) fprintf(stderr, "you must specify an interface type\n"); if (tpset <= 0) return -1; if (argc) { if (strcmp(argv[0], "mesh_id") != 0) { fprintf(stderr, "option %s not supported\n", argv[0]); return -1; } argc--; argv++; if (!argc) { fprintf(stderr, "not enough arguments\n"); return -1; } mesh_id = argv[0]; argc--; argv++; } if (argc) { fprintf(stderr, "too many arguments\n"); return -1; } msg = nlmsg_alloc(); if (!msg) { fprintf(stderr, "failed to allocate netlink msg\n"); return -1; } genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0, 0, NL80211_CMD_NEW_INTERFACE, 0); if (dev) NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(dev)); if (phy) return -1; /* XXX TODO */ NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, name); if (tpset) NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, type); if (mesh_id) NLA_PUT(msg, NL80211_ATTR_MESH_ID, strlen(mesh_id), mesh_id); if ((err = nl_send_auto_complete(state->nl_handle, msg)) < 0 || (err = nl_wait_for_ack(state->nl_handle)) < 0) { nla_put_failure: fprintf(stderr, "failed to create interface: %d\n", err); nlmsg_free(msg); return -1; } nlmsg_free(msg); return 0; }