cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

datagram.c (4160B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * File: datagram.c
      4 *
      5 * Datagram (ISI) Phonet sockets
      6 *
      7 * Copyright (C) 2008 Nokia Corporation.
      8 *
      9 * Authors: Sakari Ailus <sakari.ailus@nokia.com>
     10 *          RĂ©mi Denis-Courmont
     11 */
     12
     13#include <linux/kernel.h>
     14#include <linux/slab.h>
     15#include <linux/socket.h>
     16#include <asm/ioctls.h>
     17#include <net/sock.h>
     18
     19#include <linux/phonet.h>
     20#include <linux/export.h>
     21#include <net/phonet/phonet.h>
     22
     23static int pn_backlog_rcv(struct sock *sk, struct sk_buff *skb);
     24
     25/* associated socket ceases to exist */
     26static void pn_sock_close(struct sock *sk, long timeout)
     27{
     28	sk_common_release(sk);
     29}
     30
     31static int pn_ioctl(struct sock *sk, int cmd, unsigned long arg)
     32{
     33	struct sk_buff *skb;
     34	int answ;
     35
     36	switch (cmd) {
     37	case SIOCINQ:
     38		lock_sock(sk);
     39		skb = skb_peek(&sk->sk_receive_queue);
     40		answ = skb ? skb->len : 0;
     41		release_sock(sk);
     42		return put_user(answ, (int __user *)arg);
     43
     44	case SIOCPNADDRESOURCE:
     45	case SIOCPNDELRESOURCE: {
     46			u32 res;
     47			if (get_user(res, (u32 __user *)arg))
     48				return -EFAULT;
     49			if (res >= 256)
     50				return -EINVAL;
     51			if (cmd == SIOCPNADDRESOURCE)
     52				return pn_sock_bind_res(sk, res);
     53			else
     54				return pn_sock_unbind_res(sk, res);
     55		}
     56	}
     57
     58	return -ENOIOCTLCMD;
     59}
     60
     61/* Destroy socket. All references are gone. */
     62static void pn_destruct(struct sock *sk)
     63{
     64	skb_queue_purge(&sk->sk_receive_queue);
     65}
     66
     67static int pn_init(struct sock *sk)
     68{
     69	sk->sk_destruct = pn_destruct;
     70	return 0;
     71}
     72
     73static int pn_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
     74{
     75	DECLARE_SOCKADDR(struct sockaddr_pn *, target, msg->msg_name);
     76	struct sk_buff *skb;
     77	int err;
     78
     79	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|
     80				MSG_CMSG_COMPAT))
     81		return -EOPNOTSUPP;
     82
     83	if (target == NULL)
     84		return -EDESTADDRREQ;
     85
     86	if (msg->msg_namelen < sizeof(struct sockaddr_pn))
     87		return -EINVAL;
     88
     89	if (target->spn_family != AF_PHONET)
     90		return -EAFNOSUPPORT;
     91
     92	skb = sock_alloc_send_skb(sk, MAX_PHONET_HEADER + len,
     93					msg->msg_flags & MSG_DONTWAIT, &err);
     94	if (skb == NULL)
     95		return err;
     96	skb_reserve(skb, MAX_PHONET_HEADER);
     97
     98	err = memcpy_from_msg((void *)skb_put(skb, len), msg, len);
     99	if (err < 0) {
    100		kfree_skb(skb);
    101		return err;
    102	}
    103
    104	/*
    105	 * Fill in the Phonet header and
    106	 * finally pass the packet forwards.
    107	 */
    108	err = pn_skb_send(sk, skb, target);
    109
    110	/* If ok, return len. */
    111	return (err >= 0) ? len : err;
    112}
    113
    114static int pn_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
    115		      int flags, int *addr_len)
    116{
    117	struct sk_buff *skb = NULL;
    118	struct sockaddr_pn sa;
    119	int rval = -EOPNOTSUPP;
    120	int copylen;
    121
    122	if (flags & ~(MSG_PEEK|MSG_TRUNC|MSG_DONTWAIT|MSG_NOSIGNAL|
    123			MSG_CMSG_COMPAT))
    124		goto out_nofree;
    125
    126	skb = skb_recv_datagram(sk, flags, &rval);
    127	if (skb == NULL)
    128		goto out_nofree;
    129
    130	pn_skb_get_src_sockaddr(skb, &sa);
    131
    132	copylen = skb->len;
    133	if (len < copylen) {
    134		msg->msg_flags |= MSG_TRUNC;
    135		copylen = len;
    136	}
    137
    138	rval = skb_copy_datagram_msg(skb, 0, msg, copylen);
    139	if (rval) {
    140		rval = -EFAULT;
    141		goto out;
    142	}
    143
    144	rval = (flags & MSG_TRUNC) ? skb->len : copylen;
    145
    146	if (msg->msg_name != NULL) {
    147		__sockaddr_check_size(sizeof(sa));
    148		memcpy(msg->msg_name, &sa, sizeof(sa));
    149		*addr_len = sizeof(sa);
    150	}
    151
    152out:
    153	skb_free_datagram(sk, skb);
    154
    155out_nofree:
    156	return rval;
    157}
    158
    159/* Queue an skb for a sock. */
    160static int pn_backlog_rcv(struct sock *sk, struct sk_buff *skb)
    161{
    162	int err = sock_queue_rcv_skb(sk, skb);
    163
    164	if (err < 0)
    165		kfree_skb(skb);
    166	return err ? NET_RX_DROP : NET_RX_SUCCESS;
    167}
    168
    169/* Module registration */
    170static struct proto pn_proto = {
    171	.close		= pn_sock_close,
    172	.ioctl		= pn_ioctl,
    173	.init		= pn_init,
    174	.sendmsg	= pn_sendmsg,
    175	.recvmsg	= pn_recvmsg,
    176	.backlog_rcv	= pn_backlog_rcv,
    177	.hash		= pn_sock_hash,
    178	.unhash		= pn_sock_unhash,
    179	.get_port	= pn_sock_get_port,
    180	.obj_size	= sizeof(struct pn_sock),
    181	.owner		= THIS_MODULE,
    182	.name		= "PHONET",
    183};
    184
    185static const struct phonet_protocol pn_dgram_proto = {
    186	.ops		= &phonet_dgram_ops,
    187	.prot		= &pn_proto,
    188	.sock_type	= SOCK_DGRAM,
    189};
    190
    191int __init isi_register(void)
    192{
    193	return phonet_proto_register(PN_PROTO_PHONET, &pn_dgram_proto);
    194}
    195
    196void __exit isi_unregister(void)
    197{
    198	phonet_proto_unregister(PN_PROTO_PHONET, &pn_dgram_proto);
    199}