4 * Datagram (ISI) Phonet sockets
6 * Copyright (C) 2008 Nokia Corporation.
8 * Contact: Remi Denis-Courmont <remi.denis-courmont@nokia.com>
9 * Original author: Sakari Ailus <sakari.ailus@nokia.com>
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * version 2 as published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
26 #include <linux/kernel.h>
27 #include <linux/slab.h>
28 #include <linux/socket.h>
29 #include <asm/ioctls.h>
32 #include <linux/phonet.h>
33 #include <linux/export.h>
34 #include <net/phonet/phonet.h>
36 static int pn_backlog_rcv(struct sock
*sk
, struct sk_buff
*skb
);
38 /* associated socket ceases to exist */
39 static void pn_sock_close(struct sock
*sk
, long timeout
)
41 sk_common_release(sk
);
44 static int pn_ioctl(struct sock
*sk
, int cmd
, unsigned long arg
)
52 skb
= skb_peek(&sk
->sk_receive_queue
);
53 answ
= skb
? skb
->len
: 0;
55 return put_user(answ
, (int __user
*)arg
);
57 case SIOCPNADDRESOURCE
:
58 case SIOCPNDELRESOURCE
: {
60 if (get_user(res
, (u32 __user
*)arg
))
64 if (cmd
== SIOCPNADDRESOURCE
)
65 return pn_sock_bind_res(sk
, res
);
67 return pn_sock_unbind_res(sk
, res
);
74 /* Destroy socket. All references are gone. */
75 static void pn_destruct(struct sock
*sk
)
77 skb_queue_purge(&sk
->sk_receive_queue
);
80 static int pn_init(struct sock
*sk
)
82 sk
->sk_destruct
= pn_destruct
;
86 static int pn_sendmsg(struct kiocb
*iocb
, struct sock
*sk
,
87 struct msghdr
*msg
, size_t len
)
89 struct sockaddr_pn
*target
;
93 if (msg
->msg_flags
& ~(MSG_DONTWAIT
|MSG_EOR
|MSG_NOSIGNAL
|
97 if (msg
->msg_name
== NULL
)
100 if (msg
->msg_namelen
< sizeof(struct sockaddr_pn
))
103 target
= (struct sockaddr_pn
*)msg
->msg_name
;
104 if (target
->spn_family
!= AF_PHONET
)
105 return -EAFNOSUPPORT
;
107 skb
= sock_alloc_send_skb(sk
, MAX_PHONET_HEADER
+ len
,
108 msg
->msg_flags
& MSG_DONTWAIT
, &err
);
111 skb_reserve(skb
, MAX_PHONET_HEADER
);
113 err
= memcpy_fromiovec((void *)skb_put(skb
, len
), msg
->msg_iov
, len
);
120 * Fill in the Phonet header and
121 * finally pass the packet forwards.
123 err
= pn_skb_send(sk
, skb
, target
);
125 /* If ok, return len. */
126 return (err
>= 0) ? len
: err
;
129 static int pn_recvmsg(struct kiocb
*iocb
, struct sock
*sk
,
130 struct msghdr
*msg
, size_t len
, int noblock
,
131 int flags
, int *addr_len
)
133 struct sk_buff
*skb
= NULL
;
134 struct sockaddr_pn sa
;
135 int rval
= -EOPNOTSUPP
;
138 if (flags
& ~(MSG_PEEK
|MSG_TRUNC
|MSG_DONTWAIT
|MSG_NOSIGNAL
|
143 *addr_len
= sizeof(sa
);
145 skb
= skb_recv_datagram(sk
, flags
, noblock
, &rval
);
149 pn_skb_get_src_sockaddr(skb
, &sa
);
153 msg
->msg_flags
|= MSG_TRUNC
;
157 rval
= skb_copy_datagram_iovec(skb
, 0, msg
->msg_iov
, copylen
);
163 rval
= (flags
& MSG_TRUNC
) ? skb
->len
: copylen
;
165 if (msg
->msg_name
!= NULL
)
166 memcpy(msg
->msg_name
, &sa
, sizeof(struct sockaddr_pn
));
169 skb_free_datagram(sk
, skb
);
175 /* Queue an skb for a sock. */
176 static int pn_backlog_rcv(struct sock
*sk
, struct sk_buff
*skb
)
178 int err
= sock_queue_rcv_skb(sk
, skb
);
182 return err
? NET_RX_DROP
: NET_RX_SUCCESS
;
185 /* Module registration */
186 static struct proto pn_proto
= {
187 .close
= pn_sock_close
,
190 .sendmsg
= pn_sendmsg
,
191 .recvmsg
= pn_recvmsg
,
192 .backlog_rcv
= pn_backlog_rcv
,
193 .hash
= pn_sock_hash
,
194 .unhash
= pn_sock_unhash
,
195 .get_port
= pn_sock_get_port
,
196 .obj_size
= sizeof(struct pn_sock
),
197 .owner
= THIS_MODULE
,
201 static struct phonet_protocol pn_dgram_proto
= {
202 .ops
= &phonet_dgram_ops
,
204 .sock_type
= SOCK_DGRAM
,
207 int __init
isi_register(void)
209 return phonet_proto_register(PN_PROTO_PHONET
, &pn_dgram_proto
);
212 void __exit
isi_unregister(void)
214 phonet_proto_unregister(PN_PROTO_PHONET
, &pn_dgram_proto
);