#include #include #include #include #include #include #include #include #include #define GENL_FAMILY_NAME "bluetooth" #define GENL_VERSION 0x01 static int family; #define DOWN 0 #define UP 1 enum { ATTR_UNSPEC, INDEX, CHANGED, EVENT, GRPID, /* Add attributes here */ __ATTR_MAX, ATTR_MAX = __ATTR_MAX - 1 }; static struct nla_policy policy[ATTR_MAX + 1] = { [INDEX] = { .type = NLA_U16 }, [CHANGED] = { .type = NLA_U32 }, [EVENT] = { .type = NLA_U16 }, [GRPID] = { .type = NLA_U32 }, }; enum { CMD_UNSPEC, NEWHOST, DELHOST, HOST, GETGRPID, /* Add command here */ __CMD_MAX, CMD_MAX = __CMD_MAX - 1 }; static int parse_cb(struct nl_msg *msg, void *arg) { int err, ret; int *id = arg; int index, changed; struct nlmsghdr *nlh = nlmsg_hdr(msg); struct nlattr *attrs[ATTR_MAX+1]; struct genlmsghdr *ghdr = nlmsg_data(nlh); err = genlmsg_parse(nlh, 0, attrs, ATTR_MAX, NULL); if (err < 0) return -EINVAL; switch (ghdr->cmd) { case HOST: index = nla_get_u16(attrs[INDEX]); changed = nla_get_u32(attrs[CHANGED]); printf("\nHCI%d : changed0x%x\n", index, changed); ret = 0; break; case NEWHOST: index = nla_get_u16(attrs[INDEX]); changed = nla_get_u32(attrs[CHANGED]); printf("\nNew Device HCI%d : changed0x%x\n", index, changed); ret = 0; break; case DELHOST: index = nla_get_u16(attrs[INDEX]); changed = nla_get_u32(attrs[CHANGED]); printf("\nRemoved Device HCI%d : changed0x%x\n", index, changed); ret = 0; break; case GETGRPID: if(!attrs[GRPID]) { printf("\nNo Group ID\n"); ret = -EINVAL; } else *id = nla_get_u32(attrs[GRPID]); ret = 0; break; default: printf("\nUnknown command"); ret = -EINVAL; break; } return ret; } static int ack_handler(struct nl_msg *msg, void *arg) { int *ret = arg; *ret = 0; return NL_STOP; } int get_group_id(struct nl_handle *sock) { int ret = 1, grpid; struct nl_msg *msg; struct nl_cb *cb; msg = nlmsg_alloc(); cb = nl_cb_alloc(NL_CB_DEFAULT); genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_REQUEST, GETGRPID, GENL_VERSION); nl_send_auto_complete(sock, msg); nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &ret); nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, parse_cb, &grpid); while (ret > 0) nl_recvmsgs(sock, cb); nl_cb_put(cb); nlmsg_free(msg); return grpid; } int main() { struct nl_handle *sock; struct nl_msg *msg; int err; int grp_id; sock = nl_handle_alloc(); genl_connect(sock); family = genl_ctrl_resolve(sock, GENL_FAMILY_NAME); if (family < 0) return -1; grp_id = get_group_id(sock); if (grp_id < 0) return -1; err = nl_socket_add_membership(sock, grp_id); if (err < 0) return -1; nl_socket_modify_cb(sock, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, parse_cb, NULL); while(1) err = nl_recvmsgs_default(sock); return 0; }