Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * File: datagram.c
0004  *
0005  * Datagram (ISI) Phonet sockets
0006  *
0007  * Copyright (C) 2008 Nokia Corporation.
0008  *
0009  * Authors: Sakari Ailus <sakari.ailus@nokia.com>
0010  *          Rémi Denis-Courmont
0011  */
0012 
0013 #include <linux/kernel.h>
0014 #include <linux/slab.h>
0015 #include <linux/socket.h>
0016 #include <asm/ioctls.h>
0017 #include <net/sock.h>
0018 
0019 #include <linux/phonet.h>
0020 #include <linux/export.h>
0021 #include <net/phonet/phonet.h>
0022 
0023 static int pn_backlog_rcv(struct sock *sk, struct sk_buff *skb);
0024 
0025 /* associated socket ceases to exist */
0026 static void pn_sock_close(struct sock *sk, long timeout)
0027 {
0028     sk_common_release(sk);
0029 }
0030 
0031 static int pn_ioctl(struct sock *sk, int cmd, unsigned long arg)
0032 {
0033     struct sk_buff *skb;
0034     int answ;
0035 
0036     switch (cmd) {
0037     case SIOCINQ:
0038         lock_sock(sk);
0039         skb = skb_peek(&sk->sk_receive_queue);
0040         answ = skb ? skb->len : 0;
0041         release_sock(sk);
0042         return put_user(answ, (int __user *)arg);
0043 
0044     case SIOCPNADDRESOURCE:
0045     case SIOCPNDELRESOURCE: {
0046             u32 res;
0047             if (get_user(res, (u32 __user *)arg))
0048                 return -EFAULT;
0049             if (res >= 256)
0050                 return -EINVAL;
0051             if (cmd == SIOCPNADDRESOURCE)
0052                 return pn_sock_bind_res(sk, res);
0053             else
0054                 return pn_sock_unbind_res(sk, res);
0055         }
0056     }
0057 
0058     return -ENOIOCTLCMD;
0059 }
0060 
0061 /* Destroy socket. All references are gone. */
0062 static void pn_destruct(struct sock *sk)
0063 {
0064     skb_queue_purge(&sk->sk_receive_queue);
0065 }
0066 
0067 static int pn_init(struct sock *sk)
0068 {
0069     sk->sk_destruct = pn_destruct;
0070     return 0;
0071 }
0072 
0073 static int pn_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
0074 {
0075     DECLARE_SOCKADDR(struct sockaddr_pn *, target, msg->msg_name);
0076     struct sk_buff *skb;
0077     int err;
0078 
0079     if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|
0080                 MSG_CMSG_COMPAT))
0081         return -EOPNOTSUPP;
0082 
0083     if (target == NULL)
0084         return -EDESTADDRREQ;
0085 
0086     if (msg->msg_namelen < sizeof(struct sockaddr_pn))
0087         return -EINVAL;
0088 
0089     if (target->spn_family != AF_PHONET)
0090         return -EAFNOSUPPORT;
0091 
0092     skb = sock_alloc_send_skb(sk, MAX_PHONET_HEADER + len,
0093                     msg->msg_flags & MSG_DONTWAIT, &err);
0094     if (skb == NULL)
0095         return err;
0096     skb_reserve(skb, MAX_PHONET_HEADER);
0097 
0098     err = memcpy_from_msg((void *)skb_put(skb, len), msg, len);
0099     if (err < 0) {
0100         kfree_skb(skb);
0101         return err;
0102     }
0103 
0104     /*
0105      * Fill in the Phonet header and
0106      * finally pass the packet forwards.
0107      */
0108     err = pn_skb_send(sk, skb, target);
0109 
0110     /* If ok, return len. */
0111     return (err >= 0) ? len : err;
0112 }
0113 
0114 static int pn_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
0115               int flags, int *addr_len)
0116 {
0117     struct sk_buff *skb = NULL;
0118     struct sockaddr_pn sa;
0119     int rval = -EOPNOTSUPP;
0120     int copylen;
0121 
0122     if (flags & ~(MSG_PEEK|MSG_TRUNC|MSG_DONTWAIT|MSG_NOSIGNAL|
0123             MSG_CMSG_COMPAT))
0124         goto out_nofree;
0125 
0126     skb = skb_recv_datagram(sk, flags, &rval);
0127     if (skb == NULL)
0128         goto out_nofree;
0129 
0130     pn_skb_get_src_sockaddr(skb, &sa);
0131 
0132     copylen = skb->len;
0133     if (len < copylen) {
0134         msg->msg_flags |= MSG_TRUNC;
0135         copylen = len;
0136     }
0137 
0138     rval = skb_copy_datagram_msg(skb, 0, msg, copylen);
0139     if (rval) {
0140         rval = -EFAULT;
0141         goto out;
0142     }
0143 
0144     rval = (flags & MSG_TRUNC) ? skb->len : copylen;
0145 
0146     if (msg->msg_name != NULL) {
0147         __sockaddr_check_size(sizeof(sa));
0148         memcpy(msg->msg_name, &sa, sizeof(sa));
0149         *addr_len = sizeof(sa);
0150     }
0151 
0152 out:
0153     skb_free_datagram(sk, skb);
0154 
0155 out_nofree:
0156     return rval;
0157 }
0158 
0159 /* Queue an skb for a sock. */
0160 static int pn_backlog_rcv(struct sock *sk, struct sk_buff *skb)
0161 {
0162     int err = sock_queue_rcv_skb(sk, skb);
0163 
0164     if (err < 0)
0165         kfree_skb(skb);
0166     return err ? NET_RX_DROP : NET_RX_SUCCESS;
0167 }
0168 
0169 /* Module registration */
0170 static struct proto pn_proto = {
0171     .close      = pn_sock_close,
0172     .ioctl      = pn_ioctl,
0173     .init       = pn_init,
0174     .sendmsg    = pn_sendmsg,
0175     .recvmsg    = pn_recvmsg,
0176     .backlog_rcv    = pn_backlog_rcv,
0177     .hash       = pn_sock_hash,
0178     .unhash     = pn_sock_unhash,
0179     .get_port   = pn_sock_get_port,
0180     .obj_size   = sizeof(struct pn_sock),
0181     .owner      = THIS_MODULE,
0182     .name       = "PHONET",
0183 };
0184 
0185 static const struct phonet_protocol pn_dgram_proto = {
0186     .ops        = &phonet_dgram_ops,
0187     .prot       = &pn_proto,
0188     .sock_type  = SOCK_DGRAM,
0189 };
0190 
0191 int __init isi_register(void)
0192 {
0193     return phonet_proto_register(PN_PROTO_PHONET, &pn_dgram_proto);
0194 }
0195 
0196 void __exit isi_unregister(void)
0197 {
0198     phonet_proto_unregister(PN_PROTO_PHONET, &pn_dgram_proto);
0199 }