1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Management Component Transport Protocol (MCTP) |
4 | * |
5 | * Copyright (c) 2021 Code Construct |
6 | * Copyright (c) 2021 Google |
7 | */ |
8 | |
9 | #include <linux/compat.h> |
10 | #include <linux/if_arp.h> |
11 | #include <linux/net.h> |
12 | #include <linux/mctp.h> |
13 | #include <linux/module.h> |
14 | #include <linux/socket.h> |
15 | |
16 | #include <net/mctp.h> |
17 | #include <net/mctpdevice.h> |
18 | #include <net/sock.h> |
19 | |
20 | #define CREATE_TRACE_POINTS |
21 | #include <trace/events/mctp.h> |
22 | |
23 | /* socket implementation */ |
24 | |
25 | static void mctp_sk_expire_keys(struct timer_list *timer); |
26 | |
27 | static int mctp_release(struct socket *sock) |
28 | { |
29 | struct sock *sk = sock->sk; |
30 | |
31 | if (sk) { |
32 | sock->sk = NULL; |
33 | sk->sk_prot->close(sk, 0); |
34 | } |
35 | |
36 | return 0; |
37 | } |
38 | |
39 | /* Generic sockaddr checks, padding checks only so far */ |
40 | static bool mctp_sockaddr_is_ok(const struct sockaddr_mctp *addr) |
41 | { |
42 | return !addr->__smctp_pad0 && !addr->__smctp_pad1; |
43 | } |
44 | |
45 | static bool mctp_sockaddr_ext_is_ok(const struct sockaddr_mctp_ext *addr) |
46 | { |
47 | return !addr->__smctp_pad0[0] && |
48 | !addr->__smctp_pad0[1] && |
49 | !addr->__smctp_pad0[2]; |
50 | } |
51 | |
52 | static int mctp_bind(struct socket *sock, struct sockaddr *addr, int addrlen) |
53 | { |
54 | struct sock *sk = sock->sk; |
55 | struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk); |
56 | struct sockaddr_mctp *smctp; |
57 | int rc; |
58 | |
59 | if (addrlen < sizeof(*smctp)) |
60 | return -EINVAL; |
61 | |
62 | if (addr->sa_family != AF_MCTP) |
63 | return -EAFNOSUPPORT; |
64 | |
65 | if (!capable(CAP_NET_BIND_SERVICE)) |
66 | return -EACCES; |
67 | |
68 | /* it's a valid sockaddr for MCTP, cast and do protocol checks */ |
69 | smctp = (struct sockaddr_mctp *)addr; |
70 | |
71 | if (!mctp_sockaddr_is_ok(addr: smctp)) |
72 | return -EINVAL; |
73 | |
74 | lock_sock(sk); |
75 | |
76 | /* TODO: allow rebind */ |
77 | if (sk_hashed(sk)) { |
78 | rc = -EADDRINUSE; |
79 | goto out_release; |
80 | } |
81 | msk->bind_net = smctp->smctp_network; |
82 | msk->bind_addr = smctp->smctp_addr.s_addr; |
83 | msk->bind_type = smctp->smctp_type & 0x7f; /* ignore the IC bit */ |
84 | |
85 | rc = sk->sk_prot->hash(sk); |
86 | |
87 | out_release: |
88 | release_sock(sk); |
89 | |
90 | return rc; |
91 | } |
92 | |
93 | static int mctp_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) |
94 | { |
95 | DECLARE_SOCKADDR(struct sockaddr_mctp *, addr, msg->msg_name); |
96 | int rc, addrlen = msg->msg_namelen; |
97 | struct sock *sk = sock->sk; |
98 | struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk); |
99 | struct mctp_skb_cb *cb; |
100 | struct mctp_route *rt; |
101 | struct sk_buff *skb = NULL; |
102 | int hlen; |
103 | |
104 | if (addr) { |
105 | const u8 tagbits = MCTP_TAG_MASK | MCTP_TAG_OWNER | |
106 | MCTP_TAG_PREALLOC; |
107 | |
108 | if (addrlen < sizeof(struct sockaddr_mctp)) |
109 | return -EINVAL; |
110 | if (addr->smctp_family != AF_MCTP) |
111 | return -EINVAL; |
112 | if (!mctp_sockaddr_is_ok(addr)) |
113 | return -EINVAL; |
114 | if (addr->smctp_tag & ~tagbits) |
115 | return -EINVAL; |
116 | /* can't preallocate a non-owned tag */ |
117 | if (addr->smctp_tag & MCTP_TAG_PREALLOC && |
118 | !(addr->smctp_tag & MCTP_TAG_OWNER)) |
119 | return -EINVAL; |
120 | |
121 | } else { |
122 | /* TODO: connect()ed sockets */ |
123 | return -EDESTADDRREQ; |
124 | } |
125 | |
126 | if (!capable(CAP_NET_RAW)) |
127 | return -EACCES; |
128 | |
129 | if (addr->smctp_network == MCTP_NET_ANY) |
130 | addr->smctp_network = mctp_default_net(net: sock_net(sk)); |
131 | |
132 | /* direct addressing */ |
133 | if (msk->addr_ext && addrlen >= sizeof(struct sockaddr_mctp_ext)) { |
134 | DECLARE_SOCKADDR(struct sockaddr_mctp_ext *, |
135 | extaddr, msg->msg_name); |
136 | struct net_device *dev; |
137 | |
138 | rc = -EINVAL; |
139 | rcu_read_lock(); |
140 | dev = dev_get_by_index_rcu(net: sock_net(sk), ifindex: extaddr->smctp_ifindex); |
141 | /* check for correct halen */ |
142 | if (dev && extaddr->smctp_halen == dev->addr_len) { |
143 | hlen = LL_RESERVED_SPACE(dev) + sizeof(struct mctp_hdr); |
144 | rc = 0; |
145 | } |
146 | rcu_read_unlock(); |
147 | if (rc) |
148 | goto err_free; |
149 | rt = NULL; |
150 | } else { |
151 | rt = mctp_route_lookup(net: sock_net(sk), dnet: addr->smctp_network, |
152 | daddr: addr->smctp_addr.s_addr); |
153 | if (!rt) { |
154 | rc = -EHOSTUNREACH; |
155 | goto err_free; |
156 | } |
157 | hlen = LL_RESERVED_SPACE(rt->dev->dev) + sizeof(struct mctp_hdr); |
158 | } |
159 | |
160 | skb = sock_alloc_send_skb(sk, size: hlen + 1 + len, |
161 | noblock: msg->msg_flags & MSG_DONTWAIT, errcode: &rc); |
162 | if (!skb) |
163 | return rc; |
164 | |
165 | skb_reserve(skb, len: hlen); |
166 | |
167 | /* set type as fist byte in payload */ |
168 | *(u8 *)skb_put(skb, len: 1) = addr->smctp_type; |
169 | |
170 | rc = memcpy_from_msg(data: (void *)skb_put(skb, len), msg, len); |
171 | if (rc < 0) |
172 | goto err_free; |
173 | |
174 | /* set up cb */ |
175 | cb = __mctp_cb(skb); |
176 | cb->net = addr->smctp_network; |
177 | |
178 | if (!rt) { |
179 | /* fill extended address in cb */ |
180 | DECLARE_SOCKADDR(struct sockaddr_mctp_ext *, |
181 | extaddr, msg->msg_name); |
182 | |
183 | if (!mctp_sockaddr_ext_is_ok(addr: extaddr) || |
184 | extaddr->smctp_halen > sizeof(cb->haddr)) { |
185 | rc = -EINVAL; |
186 | goto err_free; |
187 | } |
188 | |
189 | cb->ifindex = extaddr->smctp_ifindex; |
190 | /* smctp_halen is checked above */ |
191 | cb->halen = extaddr->smctp_halen; |
192 | memcpy(cb->haddr, extaddr->smctp_haddr, cb->halen); |
193 | } |
194 | |
195 | rc = mctp_local_output(sk, rt, skb, daddr: addr->smctp_addr.s_addr, |
196 | req_tag: addr->smctp_tag); |
197 | |
198 | return rc ? : len; |
199 | |
200 | err_free: |
201 | kfree_skb(skb); |
202 | return rc; |
203 | } |
204 | |
205 | static int mctp_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, |
206 | int flags) |
207 | { |
208 | DECLARE_SOCKADDR(struct sockaddr_mctp *, addr, msg->msg_name); |
209 | struct sock *sk = sock->sk; |
210 | struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk); |
211 | struct sk_buff *skb; |
212 | size_t msglen; |
213 | u8 type; |
214 | int rc; |
215 | |
216 | if (flags & ~(MSG_DONTWAIT | MSG_TRUNC | MSG_PEEK)) |
217 | return -EOPNOTSUPP; |
218 | |
219 | skb = skb_recv_datagram(sk, flags, err: &rc); |
220 | if (!skb) |
221 | return rc; |
222 | |
223 | if (!skb->len) { |
224 | rc = 0; |
225 | goto out_free; |
226 | } |
227 | |
228 | /* extract message type, remove from data */ |
229 | type = *((u8 *)skb->data); |
230 | msglen = skb->len - 1; |
231 | |
232 | if (len < msglen) |
233 | msg->msg_flags |= MSG_TRUNC; |
234 | else |
235 | len = msglen; |
236 | |
237 | rc = skb_copy_datagram_msg(from: skb, offset: 1, msg, size: len); |
238 | if (rc < 0) |
239 | goto out_free; |
240 | |
241 | sock_recv_cmsgs(msg, sk, skb); |
242 | |
243 | if (addr) { |
244 | struct mctp_skb_cb *cb = mctp_cb(skb); |
245 | /* TODO: expand mctp_skb_cb for header fields? */ |
246 | struct mctp_hdr *hdr = mctp_hdr(skb); |
247 | |
248 | addr = msg->msg_name; |
249 | addr->smctp_family = AF_MCTP; |
250 | addr->__smctp_pad0 = 0; |
251 | addr->smctp_network = cb->net; |
252 | addr->smctp_addr.s_addr = hdr->src; |
253 | addr->smctp_type = type; |
254 | addr->smctp_tag = hdr->flags_seq_tag & |
255 | (MCTP_HDR_TAG_MASK | MCTP_HDR_FLAG_TO); |
256 | addr->__smctp_pad1 = 0; |
257 | msg->msg_namelen = sizeof(*addr); |
258 | |
259 | if (msk->addr_ext) { |
260 | DECLARE_SOCKADDR(struct sockaddr_mctp_ext *, ae, |
261 | msg->msg_name); |
262 | msg->msg_namelen = sizeof(*ae); |
263 | ae->smctp_ifindex = cb->ifindex; |
264 | ae->smctp_halen = cb->halen; |
265 | memset(ae->__smctp_pad0, 0x0, sizeof(ae->__smctp_pad0)); |
266 | memset(ae->smctp_haddr, 0x0, sizeof(ae->smctp_haddr)); |
267 | memcpy(ae->smctp_haddr, cb->haddr, cb->halen); |
268 | } |
269 | } |
270 | |
271 | rc = len; |
272 | |
273 | if (flags & MSG_TRUNC) |
274 | rc = msglen; |
275 | |
276 | out_free: |
277 | skb_free_datagram(sk, skb); |
278 | return rc; |
279 | } |
280 | |
281 | /* We're done with the key; invalidate, stop reassembly, and remove from lists. |
282 | */ |
283 | static void __mctp_key_remove(struct mctp_sk_key *key, struct net *net, |
284 | unsigned long flags, unsigned long reason) |
285 | __releases(&key->lock) |
286 | __must_hold(&net->mctp.keys_lock) |
287 | { |
288 | struct sk_buff *skb; |
289 | |
290 | trace_mctp_key_release(key, reason); |
291 | skb = key->reasm_head; |
292 | key->reasm_head = NULL; |
293 | key->reasm_dead = true; |
294 | key->valid = false; |
295 | mctp_dev_release_key(dev: key->dev, key); |
296 | spin_unlock_irqrestore(lock: &key->lock, flags); |
297 | |
298 | if (!hlist_unhashed(h: &key->hlist)) { |
299 | hlist_del_init(n: &key->hlist); |
300 | hlist_del_init(n: &key->sklist); |
301 | /* unref for the lists */ |
302 | mctp_key_unref(key); |
303 | } |
304 | |
305 | kfree_skb(skb); |
306 | } |
307 | |
308 | static int mctp_setsockopt(struct socket *sock, int level, int optname, |
309 | sockptr_t optval, unsigned int optlen) |
310 | { |
311 | struct mctp_sock *msk = container_of(sock->sk, struct mctp_sock, sk); |
312 | int val; |
313 | |
314 | if (level != SOL_MCTP) |
315 | return -EINVAL; |
316 | |
317 | if (optname == MCTP_OPT_ADDR_EXT) { |
318 | if (optlen != sizeof(int)) |
319 | return -EINVAL; |
320 | if (copy_from_sockptr(dst: &val, src: optval, size: sizeof(int))) |
321 | return -EFAULT; |
322 | msk->addr_ext = val; |
323 | return 0; |
324 | } |
325 | |
326 | return -ENOPROTOOPT; |
327 | } |
328 | |
329 | static int mctp_getsockopt(struct socket *sock, int level, int optname, |
330 | char __user *optval, int __user *optlen) |
331 | { |
332 | struct mctp_sock *msk = container_of(sock->sk, struct mctp_sock, sk); |
333 | int len, val; |
334 | |
335 | if (level != SOL_MCTP) |
336 | return -EINVAL; |
337 | |
338 | if (get_user(len, optlen)) |
339 | return -EFAULT; |
340 | |
341 | if (optname == MCTP_OPT_ADDR_EXT) { |
342 | if (len != sizeof(int)) |
343 | return -EINVAL; |
344 | val = !!msk->addr_ext; |
345 | if (copy_to_user(to: optval, from: &val, n: len)) |
346 | return -EFAULT; |
347 | return 0; |
348 | } |
349 | |
350 | return -EINVAL; |
351 | } |
352 | |
353 | static int mctp_ioctl_alloctag(struct mctp_sock *msk, unsigned long arg) |
354 | { |
355 | struct net *net = sock_net(sk: &msk->sk); |
356 | struct mctp_sk_key *key = NULL; |
357 | struct mctp_ioc_tag_ctl ctl; |
358 | unsigned long flags; |
359 | u8 tag; |
360 | |
361 | if (copy_from_user(to: &ctl, from: (void __user *)arg, n: sizeof(ctl))) |
362 | return -EFAULT; |
363 | |
364 | if (ctl.tag) |
365 | return -EINVAL; |
366 | |
367 | if (ctl.flags) |
368 | return -EINVAL; |
369 | |
370 | key = mctp_alloc_local_tag(msk, daddr: ctl.peer_addr, MCTP_ADDR_ANY, |
371 | manual: true, tagp: &tag); |
372 | if (IS_ERR(ptr: key)) |
373 | return PTR_ERR(ptr: key); |
374 | |
375 | ctl.tag = tag | MCTP_TAG_OWNER | MCTP_TAG_PREALLOC; |
376 | if (copy_to_user(to: (void __user *)arg, from: &ctl, n: sizeof(ctl))) { |
377 | unsigned long fl2; |
378 | /* Unwind our key allocation: the keys list lock needs to be |
379 | * taken before the individual key locks, and we need a valid |
380 | * flags value (fl2) to pass to __mctp_key_remove, hence the |
381 | * second spin_lock_irqsave() rather than a plain spin_lock(). |
382 | */ |
383 | spin_lock_irqsave(&net->mctp.keys_lock, flags); |
384 | spin_lock_irqsave(&key->lock, fl2); |
385 | __mctp_key_remove(key, net, flags: fl2, reason: MCTP_TRACE_KEY_DROPPED); |
386 | mctp_key_unref(key); |
387 | spin_unlock_irqrestore(lock: &net->mctp.keys_lock, flags); |
388 | return -EFAULT; |
389 | } |
390 | |
391 | mctp_key_unref(key); |
392 | return 0; |
393 | } |
394 | |
395 | static int mctp_ioctl_droptag(struct mctp_sock *msk, unsigned long arg) |
396 | { |
397 | struct net *net = sock_net(sk: &msk->sk); |
398 | struct mctp_ioc_tag_ctl ctl; |
399 | unsigned long flags, fl2; |
400 | struct mctp_sk_key *key; |
401 | struct hlist_node *tmp; |
402 | int rc; |
403 | u8 tag; |
404 | |
405 | if (copy_from_user(to: &ctl, from: (void __user *)arg, n: sizeof(ctl))) |
406 | return -EFAULT; |
407 | |
408 | if (ctl.flags) |
409 | return -EINVAL; |
410 | |
411 | /* Must be a local tag, TO set, preallocated */ |
412 | if ((ctl.tag & ~MCTP_TAG_MASK) != (MCTP_TAG_OWNER | MCTP_TAG_PREALLOC)) |
413 | return -EINVAL; |
414 | |
415 | tag = ctl.tag & MCTP_TAG_MASK; |
416 | rc = -EINVAL; |
417 | |
418 | spin_lock_irqsave(&net->mctp.keys_lock, flags); |
419 | hlist_for_each_entry_safe(key, tmp, &msk->keys, sklist) { |
420 | /* we do an irqsave here, even though we know the irq state, |
421 | * so we have the flags to pass to __mctp_key_remove |
422 | */ |
423 | spin_lock_irqsave(&key->lock, fl2); |
424 | if (key->manual_alloc && |
425 | ctl.peer_addr == key->peer_addr && |
426 | tag == key->tag) { |
427 | __mctp_key_remove(key, net, flags: fl2, |
428 | reason: MCTP_TRACE_KEY_DROPPED); |
429 | rc = 0; |
430 | } else { |
431 | spin_unlock_irqrestore(lock: &key->lock, flags: fl2); |
432 | } |
433 | } |
434 | spin_unlock_irqrestore(lock: &net->mctp.keys_lock, flags); |
435 | |
436 | return rc; |
437 | } |
438 | |
439 | static int mctp_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) |
440 | { |
441 | struct mctp_sock *msk = container_of(sock->sk, struct mctp_sock, sk); |
442 | |
443 | switch (cmd) { |
444 | case SIOCMCTPALLOCTAG: |
445 | return mctp_ioctl_alloctag(msk, arg); |
446 | case SIOCMCTPDROPTAG: |
447 | return mctp_ioctl_droptag(msk, arg); |
448 | } |
449 | |
450 | return -EINVAL; |
451 | } |
452 | |
453 | #ifdef CONFIG_COMPAT |
454 | static int mctp_compat_ioctl(struct socket *sock, unsigned int cmd, |
455 | unsigned long arg) |
456 | { |
457 | void __user *argp = compat_ptr(uptr: arg); |
458 | |
459 | switch (cmd) { |
460 | /* These have compatible ptr layouts */ |
461 | case SIOCMCTPALLOCTAG: |
462 | case SIOCMCTPDROPTAG: |
463 | return mctp_ioctl(sock, cmd, arg: (unsigned long)argp); |
464 | } |
465 | |
466 | return -ENOIOCTLCMD; |
467 | } |
468 | #endif |
469 | |
470 | static const struct proto_ops mctp_dgram_ops = { |
471 | .family = PF_MCTP, |
472 | .release = mctp_release, |
473 | .bind = mctp_bind, |
474 | .connect = sock_no_connect, |
475 | .socketpair = sock_no_socketpair, |
476 | .accept = sock_no_accept, |
477 | .getname = sock_no_getname, |
478 | .poll = datagram_poll, |
479 | .ioctl = mctp_ioctl, |
480 | .gettstamp = sock_gettstamp, |
481 | .listen = sock_no_listen, |
482 | .shutdown = sock_no_shutdown, |
483 | .setsockopt = mctp_setsockopt, |
484 | .getsockopt = mctp_getsockopt, |
485 | .sendmsg = mctp_sendmsg, |
486 | .recvmsg = mctp_recvmsg, |
487 | .mmap = sock_no_mmap, |
488 | #ifdef CONFIG_COMPAT |
489 | .compat_ioctl = mctp_compat_ioctl, |
490 | #endif |
491 | }; |
492 | |
493 | static void mctp_sk_expire_keys(struct timer_list *timer) |
494 | { |
495 | struct mctp_sock *msk = container_of(timer, struct mctp_sock, |
496 | key_expiry); |
497 | struct net *net = sock_net(sk: &msk->sk); |
498 | unsigned long next_expiry, flags, fl2; |
499 | struct mctp_sk_key *key; |
500 | struct hlist_node *tmp; |
501 | bool next_expiry_valid = false; |
502 | |
503 | spin_lock_irqsave(&net->mctp.keys_lock, flags); |
504 | |
505 | hlist_for_each_entry_safe(key, tmp, &msk->keys, sklist) { |
506 | /* don't expire. manual_alloc is immutable, no locking |
507 | * required. |
508 | */ |
509 | if (key->manual_alloc) |
510 | continue; |
511 | |
512 | spin_lock_irqsave(&key->lock, fl2); |
513 | if (!time_after_eq(key->expiry, jiffies)) { |
514 | __mctp_key_remove(key, net, flags: fl2, |
515 | reason: MCTP_TRACE_KEY_TIMEOUT); |
516 | continue; |
517 | } |
518 | |
519 | if (next_expiry_valid) { |
520 | if (time_before(key->expiry, next_expiry)) |
521 | next_expiry = key->expiry; |
522 | } else { |
523 | next_expiry = key->expiry; |
524 | next_expiry_valid = true; |
525 | } |
526 | spin_unlock_irqrestore(lock: &key->lock, flags: fl2); |
527 | } |
528 | |
529 | spin_unlock_irqrestore(lock: &net->mctp.keys_lock, flags); |
530 | |
531 | if (next_expiry_valid) |
532 | mod_timer(timer, expires: next_expiry); |
533 | } |
534 | |
535 | static int mctp_sk_init(struct sock *sk) |
536 | { |
537 | struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk); |
538 | |
539 | INIT_HLIST_HEAD(&msk->keys); |
540 | timer_setup(&msk->key_expiry, mctp_sk_expire_keys, 0); |
541 | return 0; |
542 | } |
543 | |
544 | static void mctp_sk_close(struct sock *sk, long timeout) |
545 | { |
546 | sk_common_release(sk); |
547 | } |
548 | |
549 | static int mctp_sk_hash(struct sock *sk) |
550 | { |
551 | struct net *net = sock_net(sk); |
552 | |
553 | mutex_lock(&net->mctp.bind_lock); |
554 | sk_add_node_rcu(sk, list: &net->mctp.binds); |
555 | mutex_unlock(lock: &net->mctp.bind_lock); |
556 | |
557 | return 0; |
558 | } |
559 | |
560 | static void mctp_sk_unhash(struct sock *sk) |
561 | { |
562 | struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk); |
563 | struct net *net = sock_net(sk); |
564 | unsigned long flags, fl2; |
565 | struct mctp_sk_key *key; |
566 | struct hlist_node *tmp; |
567 | |
568 | /* remove from any type-based binds */ |
569 | mutex_lock(&net->mctp.bind_lock); |
570 | sk_del_node_init_rcu(sk); |
571 | mutex_unlock(lock: &net->mctp.bind_lock); |
572 | |
573 | /* remove tag allocations */ |
574 | spin_lock_irqsave(&net->mctp.keys_lock, flags); |
575 | hlist_for_each_entry_safe(key, tmp, &msk->keys, sklist) { |
576 | spin_lock_irqsave(&key->lock, fl2); |
577 | __mctp_key_remove(key, net, flags: fl2, reason: MCTP_TRACE_KEY_CLOSED); |
578 | } |
579 | sock_set_flag(sk, flag: SOCK_DEAD); |
580 | spin_unlock_irqrestore(lock: &net->mctp.keys_lock, flags); |
581 | |
582 | /* Since there are no more tag allocations (we have removed all of the |
583 | * keys), stop any pending expiry events. the timer cannot be re-queued |
584 | * as the sk is no longer observable |
585 | */ |
586 | del_timer_sync(timer: &msk->key_expiry); |
587 | } |
588 | |
589 | static void mctp_sk_destruct(struct sock *sk) |
590 | { |
591 | skb_queue_purge(list: &sk->sk_receive_queue); |
592 | } |
593 | |
594 | static struct proto mctp_proto = { |
595 | .name = "MCTP" , |
596 | .owner = THIS_MODULE, |
597 | .obj_size = sizeof(struct mctp_sock), |
598 | .init = mctp_sk_init, |
599 | .close = mctp_sk_close, |
600 | .hash = mctp_sk_hash, |
601 | .unhash = mctp_sk_unhash, |
602 | }; |
603 | |
604 | static int mctp_pf_create(struct net *net, struct socket *sock, |
605 | int protocol, int kern) |
606 | { |
607 | const struct proto_ops *ops; |
608 | struct proto *proto; |
609 | struct sock *sk; |
610 | int rc; |
611 | |
612 | if (protocol) |
613 | return -EPROTONOSUPPORT; |
614 | |
615 | /* only datagram sockets are supported */ |
616 | if (sock->type != SOCK_DGRAM) |
617 | return -ESOCKTNOSUPPORT; |
618 | |
619 | proto = &mctp_proto; |
620 | ops = &mctp_dgram_ops; |
621 | |
622 | sock->state = SS_UNCONNECTED; |
623 | sock->ops = ops; |
624 | |
625 | sk = sk_alloc(net, PF_MCTP, GFP_KERNEL, prot: proto, kern); |
626 | if (!sk) |
627 | return -ENOMEM; |
628 | |
629 | sock_init_data(sock, sk); |
630 | sk->sk_destruct = mctp_sk_destruct; |
631 | |
632 | rc = 0; |
633 | if (sk->sk_prot->init) |
634 | rc = sk->sk_prot->init(sk); |
635 | |
636 | if (rc) |
637 | goto err_sk_put; |
638 | |
639 | return 0; |
640 | |
641 | err_sk_put: |
642 | sock_orphan(sk); |
643 | sock_put(sk); |
644 | return rc; |
645 | } |
646 | |
647 | static struct net_proto_family mctp_pf = { |
648 | .family = PF_MCTP, |
649 | .create = mctp_pf_create, |
650 | .owner = THIS_MODULE, |
651 | }; |
652 | |
653 | static __init int mctp_init(void) |
654 | { |
655 | int rc; |
656 | |
657 | /* ensure our uapi tag definitions match the header format */ |
658 | BUILD_BUG_ON(MCTP_TAG_OWNER != MCTP_HDR_FLAG_TO); |
659 | BUILD_BUG_ON(MCTP_TAG_MASK != MCTP_HDR_TAG_MASK); |
660 | |
661 | pr_info("mctp: management component transport protocol core\n" ); |
662 | |
663 | rc = sock_register(fam: &mctp_pf); |
664 | if (rc) |
665 | return rc; |
666 | |
667 | rc = proto_register(prot: &mctp_proto, alloc_slab: 0); |
668 | if (rc) |
669 | goto err_unreg_sock; |
670 | |
671 | rc = mctp_routes_init(); |
672 | if (rc) |
673 | goto err_unreg_proto; |
674 | |
675 | rc = mctp_neigh_init(); |
676 | if (rc) |
677 | goto err_unreg_routes; |
678 | |
679 | mctp_device_init(); |
680 | |
681 | return 0; |
682 | |
683 | err_unreg_routes: |
684 | mctp_routes_exit(); |
685 | err_unreg_proto: |
686 | proto_unregister(prot: &mctp_proto); |
687 | err_unreg_sock: |
688 | sock_unregister(PF_MCTP); |
689 | |
690 | return rc; |
691 | } |
692 | |
693 | static __exit void mctp_exit(void) |
694 | { |
695 | mctp_device_exit(); |
696 | mctp_neigh_exit(); |
697 | mctp_routes_exit(); |
698 | proto_unregister(prot: &mctp_proto); |
699 | sock_unregister(PF_MCTP); |
700 | } |
701 | |
702 | subsys_initcall(mctp_init); |
703 | module_exit(mctp_exit); |
704 | |
705 | MODULE_DESCRIPTION("MCTP core" ); |
706 | MODULE_AUTHOR("Jeremy Kerr <jk@codeconstruct.com.au>" ); |
707 | |
708 | MODULE_ALIAS_NETPROTO(PF_MCTP); |
709 | |