2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
11 * rx_knet.c - RX kernel send, receive and timer routines.
13 * Linux implementation.
15 #include <afsconfig.h>
16 #include "afs/param.h"
19 #include <linux/version.h>
20 #include "rx/rx_kcommon.h"
22 #include "rx_atomic.h"
23 #include "rx_globals.h"
26 #include "rx_packet.h"
27 #include "rx_internal.h"
28 #if defined(HAVE_LINUX_UACCESS_H)
29 #include <linux/uaccess.h>
31 #include <asm/uaccess.h>
34 #include <linux/errqueue.h>
35 #include <linux/icmp.h>
38 #include "osi_compat.h"
41 * open and bind RX socket
44 rxk_NewSocketHost(afs_uint32 ahost
, short aport
)
47 struct sockaddr_in myaddr
;
50 int pmtu
= IP_PMTUDISC_WANT
;
52 int pmtu
= IP_PMTUDISC_DONT
;
55 #ifdef HAVE_LINUX_SOCK_CREATE_KERN_NS
56 code
= sock_create_kern(&init_net
, AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
, &sockp
);
57 #elif defined(HAVE_LINUX_SOCK_CREATE_KERN)
58 code
= sock_create_kern(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
, &sockp
);
59 #elif defined(LINUX_KERNEL_SOCK_CREATE_V)
60 code
= sock_create(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
, &sockp
, 0);
62 code
= sock_create(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
, &sockp
);
68 myaddr
.sin_family
= AF_INET
;
69 myaddr
.sin_addr
.s_addr
= ahost
;
70 myaddr
.sin_port
= aport
;
72 sockp
->ops
->bind(sockp
, (struct sockaddr
*)&myaddr
, sizeof(myaddr
));
75 printk("sock_release(rx_socket) FIXME\n");
79 kernel_setsockopt(sockp
, SOL_IP
, IP_MTU_DISCOVER
, (char *)&pmtu
,
84 kernel_setsockopt(sockp
, SOL_IP
, IP_RECVERR
, (char *)&recverr
,
88 return (osi_socket
*)sockp
;
92 rxk_NewSocket(short aport
)
94 return rxk_NewSocketHost(htonl(INADDR_ANY
), aport
);
97 /* free socket allocated by osi_NetSocket */
99 rxk_FreeSocket(struct socket
*asocket
)
101 AFS_STATCNT(osi_FreeSocket
);
105 #ifdef AFS_RXERRQ_ENV
107 osi_HandleSocketError(osi_socket so
, char *cmsgbuf
, size_t cmsgbuf_len
)
110 struct cmsghdr
*cmsg
;
111 struct sock_extended_err
*err
;
112 struct sockaddr_in addr
;
114 struct socket
*sop
= (struct socket
*)so
;
116 msg
.msg_name
= &addr
;
117 msg
.msg_namelen
= sizeof(addr
);
118 msg
.msg_control
= cmsgbuf
;
119 msg
.msg_controllen
= cmsgbuf_len
;
122 code
= kernel_recvmsg(sop
, &msg
, NULL
, 0, 0,
123 MSG_ERRQUEUE
|MSG_DONTWAIT
|MSG_TRUNC
);
125 if (code
< 0 || !(msg
.msg_flags
& MSG_ERRQUEUE
))
128 /* kernel_recvmsg changes msg_control to point at the _end_ of the buffer,
129 * and msg_controllen is set to the number of bytes remaining */
130 msg
.msg_controllen
= ((char*)msg
.msg_control
- (char*)cmsgbuf
);
131 msg
.msg_control
= cmsgbuf
;
133 for (cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
&& CMSG_OK(&msg
, cmsg
);
134 cmsg
= CMSG_NXTHDR(&msg
, cmsg
)) {
136 if (cmsg
->cmsg_level
!= SOL_IP
|| cmsg
->cmsg_type
!= IP_RECVERR
) {
140 err
= CMSG_DATA(cmsg
);
141 rxi_ProcessNetError(err
, addr
.sin_addr
.s_addr
, addr
.sin_port
);
149 do_handlesocketerror(osi_socket so
)
151 #ifdef AFS_RXERRQ_ENV
156 cmsgbuf
= rxi_Alloc(cmsgbuf_len
);
161 while (osi_HandleSocketError(so
, cmsgbuf
, cmsgbuf_len
))
164 rxi_Free(cmsgbuf
, cmsgbuf_len
);
175 osi_NetSend(osi_socket sop
, struct sockaddr_in
*to
, struct iovec
*iovec
,
176 int iovcnt
, afs_int32 size
, int istack
)
183 msg
.msg_namelen
= sizeof(*to
);
184 msg
.msg_control
= NULL
;
185 msg
.msg_controllen
= 0;
188 code
= kernel_sendmsg(sop
, &msg
, (struct kvec
*) iovec
, iovcnt
, size
);
191 do_handlesocketerror(sop
);
194 return (code
< 0) ? code
: 0;
199 * OS dependent part of kernel RX listener thread.
202 * so socket to receive on, typically rx_socket
203 * from pointer to a sockaddr_in.
204 * iov array of iovecs to fill in.
205 * iovcnt how many iovecs there are.
206 * lengthp IN/OUT in: total space available in iovecs. out: size of read.
210 * error code (such as EINTER) if not
213 * Note that the maximum number of iovecs is 2 + RX_MAXWVECS. This is
214 * so we have a little space to look for packets larger than
217 int rxk_lastSocketError
;
218 int rxk_nSocketErrors
;
220 osi_NetReceive(osi_socket so
, struct sockaddr_in
*from
, struct iovec
*iov
,
221 int iovcnt
, int *lengthp
)
225 struct iovec tmpvec
[RX_MAXWVECS
+ 2];
226 struct socket
*sop
= (struct socket
*)so
;
228 if (iovcnt
> RX_MAXWVECS
+ 2) {
229 osi_Panic("Too many (%d) iovecs passed to osi_NetReceive\n", iovcnt
);
232 memcpy(tmpvec
, iov
, iovcnt
* sizeof(struct iovec
));
234 #if defined(STRUCT_MSGHDR_HAS_MSG_ITER)
235 msg
.msg_iter
.iov
= tmpvec
;
236 msg
.msg_iter
.nr_segs
= iovcnt
;
238 msg
.msg_iov
= tmpvec
;
239 msg
.msg_iovlen
= iovcnt
;
241 msg
.msg_control
= NULL
;
242 msg
.msg_controllen
= 0;
245 code
= kernel_recvmsg(sop
, &msg
, (struct kvec
*)tmpvec
, iovcnt
,
250 /* Clear the error before using the socket again.
251 * Oh joy, Linux has hidden header files as well. It appears we can
252 * simply call again and have it clear itself via sock_error().
254 flush_signals(current
); /* We don't want no stinkin' signals. */
255 rxk_lastSocketError
= code
;
258 do_handlesocketerror(so
);
268 osi_StopListener(void)
270 extern struct task_struct
*rxk_ListenerTask
;
272 while (rxk_ListenerTask
) {
273 if (rxk_ListenerTask
) {
274 flush_signals(rxk_ListenerTask
);
275 send_sig(SIGKILL
, rxk_ListenerTask
, 1);
277 if (!rxk_ListenerTask
)
279 afs_osi_Sleep(&rxk_ListenerTask
);
281 sock_release(rx_socket
);