/* Check if the netlink message fits into the remaining bytes */ int nlmsg_ok(const struct nlmsghdr *nlh, int rem) { return rem >= (int)sizeof(struct nlmsghdr) && rem >= nlmsg_len(nlh) && nlmsg_len(nlh) >= (int) sizeof(struct nlmsghdr) && nlmsg_len(nlh) <= (rem); }
extern void *nlmsg_data(struct nlmsg *nlmsg) { char *data = ((char *)nlmsg) + NLMSG_ALIGN(sizeof(struct nlmsghdr)); if (!nlmsg_len(nlmsg)) return NULL; return data; }
static int rtnetlink_rcv_msg(struct sk_buf *skb, struct nlmsghdr *nlh) { // struct net *net = sock_net(skb->sk); rtnl_doit_func doit; int sz_idx, kind; int family; int type; int err; type = nlh->nlmsg_type; if (type > RTM_MAX) { RTE_LOG(ERR, QoS, "Operation not supported!\n"); return -EOPNOTSUPP; } type -= RTM_BASE; /* All the messages must have at least 1 byte length */ if (nlmsg_len(nlh) < (int)sizeof(struct rtgenmsg)) { RTE_LOG(ERR, QoS, "Message is too short!\n"); return 0; } family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family; sz_idx = type>>2; kind = type&3; // if (kind != 2 && !ns_capable(net->user_ns, CAP_NET_ADMIN)) // return -EPERM; // if (kind != 2) { // RTE_LOG(ERR, QoS, "Operation is not permitted!\n"); // return -EPERM; // } if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { // struct sock *rtnl; rtnl_dumpit_func dumpit; rtnl_calcit_func calcit; u16 min_dump_alloc = 0; dumpit = rtnl_get_dumpit(family, type); if (dumpit == NULL) return -EOPNOTSUPP; calcit = rtnl_get_calcit(family, type); if (calcit) min_dump_alloc = calcit(skb, nlh); // __rtnl_unlock(); // rtnl = net->rtnl; { struct netlink_dump_control c = { .dump = dumpit, .min_dump_alloc = min_dump_alloc, }; err = netlink_dump_start(skb, nlh, &c); } // rtnl_lock(); return err; }
/*通信示例函数*/ static void cloud_wlan_nl_get_test(struct nlmsghdr *nlh) { void *payload; struct sk_buff *out_skb; void *out_payload; struct nlmsghdr *out_nlh; int payload_len; // with padding, but ok for echo payload = nlmsg_data(nlh); payload_len = nlmsg_len(nlh); printk("payload_len = %d\n", payload_len); printk("Recievid: %s, From: %d\n", (char *)payload, nlh->nlmsg_pid); out_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); //分配足以存放默认大小的sk_buff if (!out_skb) goto failure; //skb, pid, seq, type, len out_nlh = nlmsg_put(out_skb, 0, 0, CW_NLMSG_RES_OK, MAX_DATA_PAYLOAD, 0); //填充协议头数据 if (!out_nlh) goto failure; out_payload = nlmsg_data(out_nlh); // 在响应中加入字符串,以示区别 snprintf(out_payload, MAX_DATA_PAYLOAD, "[kernel res info]: GETPID[%d] TYPE [%2X] OK\n", nlh->nlmsg_pid, nlh->nlmsg_type); nlmsg_unicast(sk, out_skb, nlh->nlmsg_pid); return; failure: printk(" failed in fun dataready!\n"); }
extern void *nlmsg_data(struct nlmsg *nlmsg) { char *data = ((char *)nlmsg) + NLMSG_HDRLEN; if (!nlmsg_len(nlmsg)) return NULL; return data; }
void nl_recv_msg(struct sk_buff* skb){ struct nlmsghdr *nlh; struct sk_buff* out; struct ec2m_request_st* req; struct ec2m_response_st resp; int pid; int size; char *buf; int r; nlh=(struct nlmsghdr*)skb->data; size = nlmsg_len(nlh);// - NLMSG_HDRLEN; pid = nlh->nlmsg_pid; /*pid of sending process */ /* printk(KERN_INFO "Netlink received a new msg from %d, size: %d\n", pid, size); */ buf = nlmsg_data(nlh); req = (struct ec2m_request_st*)buf; /* printk(KERN_INFO "got a request: %d, len: %d", req->func, req->len); */ switch (req->func) { case REQ_IMPORT_KEY: { mm_256* key; key = (mm_256*) (buf + sizeof(struct ec2m_request_st)); resp.result = k_ec2m_import_key(key); size = sizeof(struct ec2m_response_st); buf = kmalloc(size, GFP_KERNEL); memcpy(buf, &resp, sizeof(resp)); break; } case REQ_PRIVATE_OP: { mm256_point_t* P; mm256_point_t Q; P = (mm256_point_t*) (buf + sizeof(struct ec2m_request_st)); resp.result = k_ec2m_private_op(&Q, P); size = sizeof(struct ec2m_response_st) + sizeof(mm256_point_t); buf = kmalloc(size, GFP_KERNEL); memcpy(buf, &resp, sizeof(resp)); memcpy(buf + sizeof(resp), &Q, sizeof(Q)); break; } } out = nlmsg_new(size, 0); nlh = nlmsg_put(out, 0, 0, NLMSG_DONE, size, 0); NETLINK_CB(out).dst_group = 0; /* not in mcast group */ memcpy(nlmsg_data(nlh), buf, size); r = nlmsg_unicast(sock_fd, out, pid); if (r < 0){ printk(KERN_INFO "forward msg to %d failed, err code %d\n", pid, r); } kfree(buf); }
/* * Change state of port (ie from forwarding to blocking etc) * Used by spanning tree in user space. */ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { struct net *net = sock_net(skb->sk); struct ifinfomsg *ifm; struct nlattr *protinfo; struct net_device *dev; struct net_bridge_port *p; u8 new_state; if (nlmsg_len(nlh) < sizeof(*ifm)) return -EINVAL; ifm = nlmsg_data(nlh); if (ifm->ifi_family != AF_BRIDGE) return -EPFNOSUPPORT; protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO); if (!protinfo || nla_len(protinfo) < sizeof(u8)) return -EINVAL; new_state = nla_get_u8(protinfo); if (new_state > BR_STATE_BLOCKING) return -EINVAL; dev = __dev_get_by_index(net, ifm->ifi_index); if (!dev) return -ENODEV; p = br_port_get_rtnl(dev); if (!p) return -EINVAL; /* if kernel STP is running, don't allow changes */ if (p->br->stp_enabled == BR_KERNEL_STP) return -EBUSY; if (!netif_running(dev) || (!netif_carrier_ok(dev) && new_state != BR_STATE_DISABLED)) return -ENETDOWN; p->state = new_state; br_log_state(p); spin_lock_bh(&p->br->lock); br_port_state_selection(p->br); spin_unlock_bh(&p->br->lock); br_ifinfo_notify(RTM_NEWLINK, p); return 0; }
/* Next netlink message in message stream */ struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining) { struct nlmsghdr *next_nlh = NULL; int len = nlmsg_len(nlh); len = NLMSG_ALIGN(len); if (*remaining > 0 && len <= *remaining && len >= (int) sizeof(struct nlmsghdr)) { next_nlh = (struct nlmsghdr *)((char *)nlh + len); *remaining -= len; } return next_nlh; }
/* * Change state of port (ie from forwarding to blocking etc) * Used by spanning tree in user space. */ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { struct ifinfomsg *ifm; struct nlattr *protinfo; struct net_device *dev; struct net_bridge_port *p; u8 new_state; if (nlmsg_len(nlh) < sizeof(*ifm)) return -EINVAL; ifm = nlmsg_data(nlh); if (ifm->ifi_family != AF_BRIDGE) return -EPFNOSUPPORT; protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO); if (!protinfo || nla_len(protinfo) < sizeof(u8)) return -EINVAL; new_state = nla_get_u8(protinfo); if (new_state > BR_STATE_BLOCKING) return -EINVAL; dev = __if_dev_get_by_index(ifm->ifi_index); if (!dev) return -ENODEV; p = dev->br_port; if (!p) return -EINVAL; /* if kernel STP is running, don't allow changes */ if (p->br->stp_enabled) return -EBUSY; if (!if_dev_admin_up(dev) || (!if_dev_running(dev) && new_state != BR_STATE_DISABLED)) return -ENETDOWN; p->state = new_state; br_log_state(p); return 0; }
/* Receive messages from netlink socket. */ static void ath_netlink_receive(struct sk_buff *__skb) { struct sk_buff *skb = NULL; struct nlmsghdr *nlh = NULL; u_int8_t *data = NULL; u_int32_t uid, pid, seq; skb = skb_get(__skb); if (skb) { /* process netlink message pointed by skb->data */ nlh = (struct nlmsghdr *)skb->data; pid = NETLINK_CREDS(skb)->pid; pid = nlh->nlmsg_pid; uid = NETLINK_CREDS(skb)->uid; seq = nlh->nlmsg_seq; data = NLMSG_DATA(nlh); gpid = pid; ath_netlink_reply(pid, seq, data); rttm_issue_request(data, nlmsg_len(nlh)); kfree_skb(skb); } return ; }
/* Process one complete nfnetlink message. */ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { struct net *net = sock_net(skb->sk); const struct nfnl_callback *nc; const struct nfnetlink_subsystem *ss; int type, err; /* All the messages must at least contain nfgenmsg */ if (nlmsg_len(nlh) < sizeof(struct nfgenmsg)) return 0; type = nlh->nlmsg_type; replay: rcu_read_lock(); ss = nfnetlink_get_subsys(type); if (!ss) { #ifdef CONFIG_MODULES rcu_read_unlock(); request_module("nfnetlink-subsys-%d", NFNL_SUBSYS_ID(type)); rcu_read_lock(); ss = nfnetlink_get_subsys(type); if (!ss) #endif { rcu_read_unlock(); return -EINVAL; } } nc = nfnetlink_find_client(type, ss); if (!nc) { rcu_read_unlock(); return -EINVAL; } { int min_len = nlmsg_total_size(sizeof(struct nfgenmsg)); u_int8_t cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type); struct nlattr *cda[ss->cb[cb_id].attr_count + 1]; struct nlattr *attr = (void *)nlh + min_len; int attrlen = nlh->nlmsg_len - min_len; __u8 subsys_id = NFNL_SUBSYS_ID(type); err = nla_parse(cda, ss->cb[cb_id].attr_count, attr, attrlen, ss->cb[cb_id].policy); if (err < 0) { rcu_read_unlock(); return err; } if (nc->call_rcu) { err = nc->call_rcu(net->nfnl, skb, nlh, (const struct nlattr **)cda); rcu_read_unlock(); } else { rcu_read_unlock(); nfnl_lock(subsys_id); if (rcu_dereference_protected(table[subsys_id].subsys, lockdep_is_held(&table[subsys_id].mutex)) != ss || nfnetlink_find_client(type, ss) != nc) err = -EAGAIN; else if (nc->call) err = nc->call(net->nfnl, skb, nlh, (const struct nlattr **)cda); else err = -EINVAL; nfnl_unlock(subsys_id); } if (err == -EAGAIN) goto replay; return err; } }
/** * Called by kernel for each new netlink socket message receieved */ static void kr_nl_recv(struct sk_buff *skb) { struct nlmsghdr * nlh = (struct nlmsghdr *)skb->data; kr_dataptr data = nlmsg_data(nlh); int size = nlmsg_len(nlh); int pid = nlh->nlmsg_pid; int seq = nlh->nlmsg_seq; KrDb* db = NULL; /* used differently by all switch cases */ KrOutbuf outbuf = kr_outbuf(sizeof(u64)); /* helper macros for reading message data */ #define NEXT_U8() (*(u8* )((data += sizeof(u8)) - sizeof(u8))) #define NEXT_U64() (*(u64*)((data += sizeof(u64)) - sizeof(u64))) #define NEXT_PTR(len) ((data += len) - len) #define GET_DB() do { \ db = kr_db_from_id(NEXT_U8()); \ if (!db) { \ printk(KERN_INFO "GET_DB WITH INVALID ID\n"); \ return; \ } \ } while (0) /* -------------- command type switch */ switch (nlh->nlmsg_type) { //-------------------------------------------------- // Command: OPEN //-------------------------------------------------- case KR_COMMAND_OPEN: { const char * path = (const char *)data; printk(KERN_INFO "KR_COMMAND_OPEN - \"%s\"\n", path); kr_db_open(&db, path); kr_nl_send(pid, seq, KR_COMMAND_OPEN, &db->id, sizeof(db->id)); break; } //-------------------------------------------------- // Command: Close //-------------------------------------------------- case KR_COMMAND_CLOSE: { GET_DB(); //kr_db_close(db); break; } //-------------------------------------------------- // Command: PUT //-------------------------------------------------- case KR_COMMAND_PUT: { KrSlice key, val; GET_DB(); key.size = NEXT_U64(); key.data = NEXT_PTR(key.size); val.size = NEXT_U64(); val.data = NEXT_PTR(val.size); kr_db_put(db, key, val); break; } //-------------------------------------------------- // Command: GET //-------------------------------------------------- case KR_COMMAND_GET: { u64 size; KrSlice key; GET_DB(); key.size = NEXT_U64(); key.data = NEXT_PTR(key.size); kr_db_get(db, key, &outbuf, &size); *(u64 *)outbuf.data = size; kr_nl_send(pid, seq, KR_COMMAND_GET, outbuf.data, sizeof(u64) + size); break; } //-------------------------------------------------- // Command: BENCH //-------------------------------------------------- case KR_COMMAND_BENCH: { GET_DB(); printk(KERN_INFO "Running kr_bench(\"%s\")...\n", db->path); kr_bench(db); printk(KERN_INFO "...done.\n"); } case KR_COMMAND_NOP: default: printk(KERN_INFO "Received unknown command\n"); break; } }
static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { u32 uid, pid, seq, sid; void *data; struct audit_status *status_get, status_set; int err; struct audit_buffer *ab; u16 msg_type = nlh->nlmsg_type; uid_t loginuid; /* loginuid of sender */ struct audit_sig_info *sig_data; char *ctx; u32 len; err = audit_netlink_ok(skb, msg_type); if (err) return err; /* As soon as there's any sign of userspace auditd, * start kauditd to talk to it */ if (!kauditd_task) kauditd_task = kthread_run(kauditd_thread, NULL, "kauditd"); if (IS_ERR(kauditd_task)) { err = PTR_ERR(kauditd_task); kauditd_task = NULL; return err; } pid = NETLINK_CREDS(skb)->pid; uid = NETLINK_CREDS(skb)->uid; loginuid = NETLINK_CB(skb).loginuid; sid = NETLINK_CB(skb).sid; seq = nlh->nlmsg_seq; data = NLMSG_DATA(nlh); switch (msg_type) { case AUDIT_GET: status_set.enabled = audit_enabled; status_set.failure = audit_failure; status_set.pid = audit_pid; status_set.rate_limit = audit_rate_limit; status_set.backlog_limit = audit_backlog_limit; status_set.lost = atomic_read(&audit_lost); status_set.backlog = skb_queue_len(&audit_skb_queue); audit_send_reply(NETLINK_CB(skb).pid, seq, AUDIT_GET, 0, 0, &status_set, sizeof(status_set)); break; case AUDIT_SET: if (nlh->nlmsg_len < sizeof(struct audit_status)) return -EINVAL; status_get = (struct audit_status *)data; if (status_get->mask & AUDIT_STATUS_ENABLED) { err = audit_set_enabled(status_get->enabled, loginuid, sid); if (err < 0) return err; } if (status_get->mask & AUDIT_STATUS_FAILURE) { err = audit_set_failure(status_get->failure, loginuid, sid); if (err < 0) return err; } if (status_get->mask & AUDIT_STATUS_PID) { int old = audit_pid; if (sid) { if ((err = selinux_sid_to_string( sid, &ctx, &len))) return err; else audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, "audit_pid=%d old=%d by auid=%u subj=%s", status_get->pid, old, loginuid, ctx); kfree(ctx); } else audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, "audit_pid=%d old=%d by auid=%u", status_get->pid, old, loginuid); audit_pid = status_get->pid; } if (status_get->mask & AUDIT_STATUS_RATE_LIMIT) err = audit_set_rate_limit(status_get->rate_limit, loginuid, sid); if (status_get->mask & AUDIT_STATUS_BACKLOG_LIMIT) err = audit_set_backlog_limit(status_get->backlog_limit, loginuid, sid); break; case AUDIT_USER: case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG: case AUDIT_FIRST_USER_MSG2...AUDIT_LAST_USER_MSG2: if (!audit_enabled && msg_type != AUDIT_USER_AVC) return 0; err = audit_filter_user(&NETLINK_CB(skb), msg_type); if (err == 1) { err = 0; ab = audit_log_start(NULL, GFP_KERNEL, msg_type); if (ab) { audit_log_format(ab, "user pid=%d uid=%u auid=%u", pid, uid, loginuid); if (sid) { if (selinux_sid_to_string( sid, &ctx, &len)) { audit_log_format(ab, " ssid=%u", sid); /* Maybe call audit_panic? */ } else audit_log_format(ab, " subj=%s", ctx); kfree(ctx); } audit_log_format(ab, " msg='%.1024s'", (char *)data); audit_set_pid(ab, pid); audit_log_end(ab); } } break; case AUDIT_ADD: case AUDIT_DEL: if (nlmsg_len(nlh) < sizeof(struct audit_rule)) return -EINVAL; if (audit_enabled == 2) { ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); if (ab) { audit_log_format(ab, "pid=%d uid=%u auid=%u", pid, uid, loginuid); if (sid) { if (selinux_sid_to_string( sid, &ctx, &len)) { audit_log_format(ab, " ssid=%u", sid); /* Maybe call audit_panic? */ } else audit_log_format(ab, " subj=%s", ctx); kfree(ctx); } audit_log_format(ab, " audit_enabled=%d res=0", audit_enabled); audit_log_end(ab); } return -EPERM; } /* fallthrough */ case AUDIT_LIST: err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid, uid, seq, data, nlmsg_len(nlh), loginuid, sid); break; case AUDIT_ADD_RULE: case AUDIT_DEL_RULE: if (nlmsg_len(nlh) < sizeof(struct audit_rule_data)) return -EINVAL; if (audit_enabled == 2) { ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); if (ab) { audit_log_format(ab, "pid=%d uid=%u auid=%u", pid, uid, loginuid); if (sid) { if (selinux_sid_to_string( sid, &ctx, &len)) { audit_log_format(ab, " ssid=%u", sid); /* Maybe call audit_panic? */ } else audit_log_format(ab, " subj=%s", ctx); kfree(ctx); } audit_log_format(ab, " audit_enabled=%d res=0", audit_enabled); audit_log_end(ab); } return -EPERM; } /* fallthrough */ case AUDIT_LIST_RULES: err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid, uid, seq, data, nlmsg_len(nlh), loginuid, sid); break; case AUDIT_SIGNAL_INFO: err = selinux_sid_to_string(audit_sig_sid, &ctx, &len); if (err) return err; sig_data = kmalloc(sizeof(*sig_data) + len, GFP_KERNEL); if (!sig_data) { kfree(ctx); return -ENOMEM; } sig_data->uid = audit_sig_uid; sig_data->pid = audit_sig_pid; memcpy(sig_data->ctx, ctx, len); kfree(ctx); audit_send_reply(NETLINK_CB(skb).pid, seq, AUDIT_SIGNAL_INFO, 0, 0, sig_data, sizeof(*sig_data) + len); kfree(sig_data); break; default: err = -EINVAL; break; } return err < 0 ? err : 0; }