blob: 5da3ef7d62037036ed85519d09dc165edce01bc8 [file] [log] [blame]
Lukas Hänelca267132012-09-04 12:28:40 +02001/*
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02002 * MobiCore KernelApi module
3 *
Lukas Hänelca267132012-09-04 12:28:40 +02004 * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#include <linux/module.h>
11#include <linux/init.h>
12
13#include <linux/kernel.h>
14#include <linux/sched.h>
15#include <linux/netlink.h>
16#include <linux/kthread.h>
Lukas Hänelca267132012-09-04 12:28:40 +020017#include <linux/device.h>
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +020018#include <net/sock.h>
19
20#include <linux/list.h>
21
22#include "connection.h"
23#include "common.h"
24
25#define MC_DAEMON_NETLINK 17
26
27struct mc_kernelapi_ctx {
28 struct sock *sk;
29 struct list_head peers;
30 atomic_t counter;
31};
32
Lukas Hänelca267132012-09-04 12:28:40 +020033struct mc_kernelapi_ctx *mod_ctx;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +020034
Lukas Hänelca267132012-09-04 12:28:40 +020035/* Define a MobiCore Kernel API device structure for use with dev_debug() etc */
36struct device_driver mc_kernel_api_name = {
37 .name = "mckernelapi"
38};
39
40struct device mc_kernel_api_subname = {
41 .init_name = "", /* Set to 'mcapi' at mcapi_init() time */
42 .driver = &mc_kernel_api_name
43};
44
45struct device *mc_kapi = &mc_kernel_api_subname;
46
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +020047/* get a unique ID */
Lukas Hänelca267132012-09-04 12:28:40 +020048unsigned int mcapi_unique_id(void)
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +020049{
Lukas Hänelca267132012-09-04 12:28:40 +020050 return (unsigned int)atomic_inc_return(&(mod_ctx->counter));
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +020051}
52
Lukas Hänelca267132012-09-04 12:28:40 +020053static struct connection *mcapi_find_connection(uint32_t seq)
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +020054{
55 struct connection *tmp;
56 struct list_head *pos;
57
58 /* Get session for session_id */
59 list_for_each(pos, &mod_ctx->peers) {
60 tmp = list_entry(pos, struct connection, list);
61 if (tmp->sequence_magic == seq)
62 return tmp;
63 }
64
65 return NULL;
66}
67
Lukas Hänelca267132012-09-04 12:28:40 +020068void mcapi_insert_connection(struct connection *connection)
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +020069{
70 list_add_tail(&(connection->list), &(mod_ctx->peers));
71 connection->socket_descriptor = mod_ctx->sk;
72}
73
Lukas Hänelca267132012-09-04 12:28:40 +020074void mcapi_remove_connection(uint32_t seq)
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +020075{
76 struct connection *tmp;
77 struct list_head *pos, *q;
78
Lukas Hänelca267132012-09-04 12:28:40 +020079 /*
80 * Delete all session objects. Usually this should not be needed as
81 * closeDevice() requires that all sessions have been closed before.
82 */
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +020083 list_for_each_safe(pos, q, &mod_ctx->peers) {
84 tmp = list_entry(pos, struct connection, list);
85 if (tmp->sequence_magic == seq) {
86 list_del(pos);
87 break;
88 }
89 }
90}
91
Lukas Hänelca267132012-09-04 12:28:40 +020092static int mcapi_process(struct sk_buff *skb, struct nlmsghdr *nlh)
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +020093{
94 struct connection *c;
95 int length;
96 int seq;
97 pid_t pid;
98 int ret;
99
100 pid = nlh->nlmsg_pid;
101 length = nlh->nlmsg_len;
102 seq = nlh->nlmsg_seq;
Lukas Hänelca267132012-09-04 12:28:40 +0200103 MCDRV_DBG_VERBOSE(mc_kapi, "nlmsg len %d type %d pid 0x%X seq %d\n",
104 length, nlh->nlmsg_type, pid, seq);
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200105 do {
106 c = mcapi_find_connection(seq);
107 if (!c) {
Lukas Hänelca267132012-09-04 12:28:40 +0200108 MCDRV_ERROR(mc_kapi,
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900109 "Invalid incoming connection - seq=%u!",
Lukas Hänelca267132012-09-04 12:28:40 +0200110 seq);
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200111 ret = -1;
112 break;
113 }
114
115 /* Pass the buffer to the appropriate connection */
116 connection_process(c, skb);
117
118 ret = 0;
119 } while (false);
120 return ret;
121}
122
Lukas Hänelca267132012-09-04 12:28:40 +0200123static void mcapi_callback(struct sk_buff *skb)
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200124{
125 struct nlmsghdr *nlh = nlmsg_hdr(skb);
126 int len = skb->len;
127 int err = 0;
128
129 while (NLMSG_OK(nlh, len)) {
130 err = mcapi_process(skb, nlh);
131
132 /* if err or if this message says it wants a response */
133 if (err || (nlh->nlmsg_flags & NLM_F_ACK))
134 netlink_ack(skb, nlh, err);
135
136 nlh = NLMSG_NEXT(nlh, len);
137 }
138}
139
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200140static int __init mcapi_init(void)
141{
Oana Medvesaneedd9e92013-02-21 19:39:04 +0100142#if defined MC_NETLINK_COMPAT || defined MC_NETLINK_COMPAT_V37
143 struct netlink_kernel_cfg cfg = {
144 .input = mcapi_callback,
145 };
146#endif
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100147
Lukas Hänelca267132012-09-04 12:28:40 +0200148 dev_set_name(mc_kapi, "mcapi");
149
150 dev_info(mc_kapi, "Mobicore API module initialized!\n");
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200151
152 mod_ctx = kzalloc(sizeof(struct mc_kernelapi_ctx), GFP_KERNEL);
Oana Medvesan92fbeda2013-10-25 16:16:11 +0200153 if (mod_ctx == NULL) {
154 MCDRV_DBG_ERROR(mc_kapi, "Allocation failure");
155 return -ENOMEM;
156 }
Oana Medvesaneedd9e92013-02-21 19:39:04 +0100157#ifdef MC_NETLINK_COMPAT_V37
158 mod_ctx->sk = netlink_kernel_create(&init_net, MC_DAEMON_NETLINK,
159 &cfg);
160#elif defined MC_NETLINK_COMPAT
161 mod_ctx->sk = netlink_kernel_create(&init_net, MC_DAEMON_NETLINK,
162 THIS_MODULE, &cfg);
163#else
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200164 /* start kernel thread */
165 mod_ctx->sk = netlink_kernel_create(&init_net, MC_DAEMON_NETLINK, 0,
Lukas Hänelca267132012-09-04 12:28:40 +0200166 mcapi_callback, NULL, THIS_MODULE);
Oana Medvesaneedd9e92013-02-21 19:39:04 +0100167#endif
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200168
169 if (!mod_ctx->sk) {
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900170 MCDRV_ERROR(mc_kapi, "register of receive handler failed");
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200171 return -EFAULT;
172 }
173
174 INIT_LIST_HEAD(&mod_ctx->peers);
175 return 0;
176}
177
178static void __exit mcapi_exit(void)
179{
Lukas Hänelca267132012-09-04 12:28:40 +0200180 dev_info(mc_kapi, "Unloading Mobicore API module.\n");
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200181
182 if (mod_ctx->sk != NULL) {
183 netlink_kernel_release(mod_ctx->sk);
184 mod_ctx->sk = NULL;
185 }
186 kfree(mod_ctx);
187 mod_ctx = NULL;
188}
189
190module_init(mcapi_init);
191module_exit(mcapi_exit);
192
193MODULE_AUTHOR("Giesecke & Devrient GmbH");
194MODULE_LICENSE("GPL v2");
195MODULE_DESCRIPTION("MobiCore API driver");