Skip to content

Commit 833ef3b

Browse files
jk-ozlabsdavem330
authored andcommitted
mctp: Populate socket implementation
Start filling-out the socket syscalls: bind, sendmsg & recvmsg. This requires an input route implementation, so we add to mctp_route_input, allowing lookups on binds & message tags. This just handles single-packet messages at present, we will add fragmentation in a future change. Signed-off-by: Jeremy Kerr <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 831119f commit 833ef3b

File tree

4 files changed

+491
-10
lines changed

4 files changed

+491
-10
lines changed

include/net/mctp.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/bits.h>
1313
#include <linux/mctp.h>
1414
#include <net/net_namespace.h>
15+
#include <net/sock.h>
1516

1617
/* MCTP packet definitions */
1718
struct mctp_hdr {
@@ -46,6 +47,64 @@ static inline struct mctp_hdr *mctp_hdr(struct sk_buff *skb)
4647
return (struct mctp_hdr *)skb_network_header(skb);
4748
}
4849

50+
/* socket implementation */
51+
struct mctp_sock {
52+
struct sock sk;
53+
54+
/* bind() params */
55+
int bind_net;
56+
mctp_eid_t bind_addr;
57+
__u8 bind_type;
58+
59+
/* list of mctp_sk_key, for incoming tag lookup. updates protected
60+
* by sk->net->keys_lock
61+
*/
62+
struct hlist_head keys;
63+
};
64+
65+
/* Key for matching incoming packets to sockets or reassembly contexts.
66+
* Packets are matched on (src,dest,tag).
67+
*
68+
* Lifetime requirements:
69+
*
70+
* - keys are free()ed via RCU
71+
*
72+
* - a mctp_sk_key contains a reference to a struct sock; this is valid
73+
* for the life of the key. On sock destruction (through unhash), the key is
74+
* removed from lists (see below), and will not be observable after a RCU
75+
* grace period.
76+
*
77+
* any RX occurring within that grace period may still queue to the socket,
78+
* but will hit the SOCK_DEAD case before the socket is freed.
79+
*
80+
* - these mctp_sk_keys appear on two lists:
81+
* 1) the struct mctp_sock->keys list
82+
* 2) the struct netns_mctp->keys list
83+
*
84+
* updates to either list are performed under the netns_mctp->keys
85+
* lock.
86+
*
87+
* - there is a single destruction path for a mctp_sk_key - through socket
88+
* unhash (see mctp_sk_unhash). This performs the list removal under
89+
* keys_lock.
90+
*/
91+
struct mctp_sk_key {
92+
mctp_eid_t peer_addr;
93+
mctp_eid_t local_addr;
94+
__u8 tag; /* incoming tag match; invert TO for local */
95+
96+
/* we hold a ref to sk when set */
97+
struct sock *sk;
98+
99+
/* routing lookup list */
100+
struct hlist_node hlist;
101+
102+
/* per-socket list */
103+
struct hlist_node sklist;
104+
105+
struct rcu_head rcu;
106+
};
107+
49108
struct mctp_skb_cb {
50109
unsigned int magic;
51110
unsigned int net;

include/net/netns/mctp.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,19 @@ struct netns_mctp {
1212
/* Only updated under RTNL, entries freed via RCU */
1313
struct list_head routes;
1414

15+
/* Bound sockets: list of sockets bound by type.
16+
* This list is updated from non-atomic contexts (under bind_lock),
17+
* and read (under rcu) in packet rx
18+
*/
19+
struct mutex bind_lock;
20+
struct hlist_head binds;
21+
22+
/* tag allocations. This list is read and updated from atomic contexts,
23+
* but elements are free()ed after a RCU grace-period
24+
*/
25+
spinlock_t keys_lock;
26+
struct hlist_head keys;
27+
1528
/* neighbour table */
1629
struct mutex neigh_lock;
1730
struct list_head neighbours;

net/mctp/af_mctp.c

Lines changed: 196 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,6 @@
1818

1919
/* socket implementation */
2020

21-
struct mctp_sock {
22-
struct sock sk;
23-
};
24-
2521
static int mctp_release(struct socket *sock)
2622
{
2723
struct sock *sk = sock->sk;
@@ -36,18 +32,160 @@ static int mctp_release(struct socket *sock)
3632

3733
static int mctp_bind(struct socket *sock, struct sockaddr *addr, int addrlen)
3834
{
39-
return 0;
35+
struct sock *sk = sock->sk;
36+
struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk);
37+
struct sockaddr_mctp *smctp;
38+
int rc;
39+
40+
if (addrlen < sizeof(*smctp))
41+
return -EINVAL;
42+
43+
if (addr->sa_family != AF_MCTP)
44+
return -EAFNOSUPPORT;
45+
46+
if (!capable(CAP_NET_BIND_SERVICE))
47+
return -EACCES;
48+
49+
/* it's a valid sockaddr for MCTP, cast and do protocol checks */
50+
smctp = (struct sockaddr_mctp *)addr;
51+
52+
lock_sock(sk);
53+
54+
/* TODO: allow rebind */
55+
if (sk_hashed(sk)) {
56+
rc = -EADDRINUSE;
57+
goto out_release;
58+
}
59+
msk->bind_net = smctp->smctp_network;
60+
msk->bind_addr = smctp->smctp_addr.s_addr;
61+
msk->bind_type = smctp->smctp_type & 0x7f; /* ignore the IC bit */
62+
63+
rc = sk->sk_prot->hash(sk);
64+
65+
out_release:
66+
release_sock(sk);
67+
68+
return rc;
4069
}
4170

4271
static int mctp_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
4372
{
44-
return 0;
73+
DECLARE_SOCKADDR(struct sockaddr_mctp *, addr, msg->msg_name);
74+
const int hlen = MCTP_HEADER_MAXLEN + sizeof(struct mctp_hdr);
75+
int rc, addrlen = msg->msg_namelen;
76+
struct sock *sk = sock->sk;
77+
struct mctp_skb_cb *cb;
78+
struct mctp_route *rt;
79+
struct sk_buff *skb;
80+
81+
if (addr) {
82+
if (addrlen < sizeof(struct sockaddr_mctp))
83+
return -EINVAL;
84+
if (addr->smctp_family != AF_MCTP)
85+
return -EINVAL;
86+
if (addr->smctp_tag & ~(MCTP_TAG_MASK | MCTP_TAG_OWNER))
87+
return -EINVAL;
88+
89+
} else {
90+
/* TODO: connect()ed sockets */
91+
return -EDESTADDRREQ;
92+
}
93+
94+
if (!capable(CAP_NET_RAW))
95+
return -EACCES;
96+
97+
rt = mctp_route_lookup(sock_net(sk), addr->smctp_network,
98+
addr->smctp_addr.s_addr);
99+
if (!rt)
100+
return -EHOSTUNREACH;
101+
102+
skb = sock_alloc_send_skb(sk, hlen + 1 + len,
103+
msg->msg_flags & MSG_DONTWAIT, &rc);
104+
if (!skb)
105+
return rc;
106+
107+
skb_reserve(skb, hlen);
108+
109+
/* set type as fist byte in payload */
110+
*(u8 *)skb_put(skb, 1) = addr->smctp_type;
111+
112+
rc = memcpy_from_msg((void *)skb_put(skb, len), msg, len);
113+
if (rc < 0) {
114+
kfree_skb(skb);
115+
return rc;
116+
}
117+
118+
/* set up cb */
119+
cb = __mctp_cb(skb);
120+
cb->net = addr->smctp_network;
121+
122+
rc = mctp_local_output(sk, rt, skb, addr->smctp_addr.s_addr,
123+
addr->smctp_tag);
124+
125+
return rc ? : len;
45126
}
46127

47128
static int mctp_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
48129
int flags)
49130
{
50-
return 0;
131+
DECLARE_SOCKADDR(struct sockaddr_mctp *, addr, msg->msg_name);
132+
struct sock *sk = sock->sk;
133+
struct sk_buff *skb;
134+
size_t msglen;
135+
u8 type;
136+
int rc;
137+
138+
if (flags & ~(MSG_DONTWAIT | MSG_TRUNC | MSG_PEEK))
139+
return -EOPNOTSUPP;
140+
141+
skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &rc);
142+
if (!skb)
143+
return rc;
144+
145+
if (!skb->len) {
146+
rc = 0;
147+
goto out_free;
148+
}
149+
150+
/* extract message type, remove from data */
151+
type = *((u8 *)skb->data);
152+
msglen = skb->len - 1;
153+
154+
if (len < msglen)
155+
msg->msg_flags |= MSG_TRUNC;
156+
else
157+
len = msglen;
158+
159+
rc = skb_copy_datagram_msg(skb, 1, msg, len);
160+
if (rc < 0)
161+
goto out_free;
162+
163+
sock_recv_ts_and_drops(msg, sk, skb);
164+
165+
if (addr) {
166+
struct mctp_skb_cb *cb = mctp_cb(skb);
167+
/* TODO: expand mctp_skb_cb for header fields? */
168+
struct mctp_hdr *hdr = mctp_hdr(skb);
169+
170+
hdr = mctp_hdr(skb);
171+
addr = msg->msg_name;
172+
addr->smctp_family = AF_MCTP;
173+
addr->smctp_network = cb->net;
174+
addr->smctp_addr.s_addr = hdr->src;
175+
addr->smctp_type = type;
176+
addr->smctp_tag = hdr->flags_seq_tag &
177+
(MCTP_HDR_TAG_MASK | MCTP_HDR_FLAG_TO);
178+
msg->msg_namelen = sizeof(*addr);
179+
}
180+
181+
rc = len;
182+
183+
if (flags & MSG_TRUNC)
184+
rc = msglen;
185+
186+
out_free:
187+
skb_free_datagram(sk, skb);
188+
return rc;
51189
}
52190

53191
static int mctp_setsockopt(struct socket *sock, int level, int optname,
@@ -83,16 +221,63 @@ static const struct proto_ops mctp_dgram_ops = {
83221
.sendpage = sock_no_sendpage,
84222
};
85223

224+
static int mctp_sk_init(struct sock *sk)
225+
{
226+
struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk);
227+
228+
INIT_HLIST_HEAD(&msk->keys);
229+
return 0;
230+
}
231+
86232
static void mctp_sk_close(struct sock *sk, long timeout)
87233
{
88234
sk_common_release(sk);
89235
}
90236

237+
static int mctp_sk_hash(struct sock *sk)
238+
{
239+
struct net *net = sock_net(sk);
240+
241+
mutex_lock(&net->mctp.bind_lock);
242+
sk_add_node_rcu(sk, &net->mctp.binds);
243+
mutex_unlock(&net->mctp.bind_lock);
244+
245+
return 0;
246+
}
247+
248+
static void mctp_sk_unhash(struct sock *sk)
249+
{
250+
struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk);
251+
struct net *net = sock_net(sk);
252+
struct mctp_sk_key *key;
253+
struct hlist_node *tmp;
254+
unsigned long flags;
255+
256+
/* remove from any type-based binds */
257+
mutex_lock(&net->mctp.bind_lock);
258+
sk_del_node_init_rcu(sk);
259+
mutex_unlock(&net->mctp.bind_lock);
260+
261+
/* remove tag allocations */
262+
spin_lock_irqsave(&net->mctp.keys_lock, flags);
263+
hlist_for_each_entry_safe(key, tmp, &msk->keys, sklist) {
264+
hlist_del_rcu(&key->sklist);
265+
hlist_del_rcu(&key->hlist);
266+
kfree_rcu(key, rcu);
267+
}
268+
spin_unlock_irqrestore(&net->mctp.keys_lock, flags);
269+
270+
synchronize_rcu();
271+
}
272+
91273
static struct proto mctp_proto = {
92274
.name = "MCTP",
93275
.owner = THIS_MODULE,
94276
.obj_size = sizeof(struct mctp_sock),
277+
.init = mctp_sk_init,
95278
.close = mctp_sk_close,
279+
.hash = mctp_sk_hash,
280+
.unhash = mctp_sk_unhash,
96281
};
97282

98283
static int mctp_pf_create(struct net *net, struct socket *sock,
@@ -147,6 +332,10 @@ static __init int mctp_init(void)
147332
{
148333
int rc;
149334

335+
/* ensure our uapi tag definitions match the header format */
336+
BUILD_BUG_ON(MCTP_TAG_OWNER != MCTP_HDR_FLAG_TO);
337+
BUILD_BUG_ON(MCTP_TAG_MASK != MCTP_HDR_TAG_MASK);
338+
150339
pr_info("mctp: management component transport protocol core\n");
151340

152341
rc = sock_register(&mctp_pf);

0 commit comments

Comments
 (0)