rx-provide-binding-version-of-init-20040728
[openafs.git] / src / rx / LINUX / rx_knet.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
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
8  */
9
10 /*
11  * rx_knet.c - RX kernel send, receive and timer routines.
12  *
13  * Linux implementation.
14  */
15 #include <afsconfig.h>
16 #include "afs/param.h"
17
18 RCSID
19     ("$Header$");
20
21 #include <linux/version.h>
22 #ifdef AFS_LINUX22_ENV
23 #include "rx/rx_kcommon.h"
24 #if defined(AFS_LINUX24_ENV)
25 #include "h/smp_lock.h"
26 #endif
27 #include <asm/uaccess.h>
28
29 /* rxk_NewSocket
30  * open and bind RX socket
31  */
32 struct osi_socket *
33 rxk_NewSocketHost(afs_uint32 ahost, short aport)
34 {
35     struct socket *sockp;
36     struct sockaddr_in myaddr;
37     int code;
38
39
40 #ifdef LINUX_KERNEL_IS_SELINUX
41     code = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &sockp, 0);
42 #else
43     code = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &sockp);
44 #endif
45     if (code < 0)
46         return NULL;
47
48     /* Bind socket */
49     myaddr.sin_family = AF_INET;
50     myaddr.sin_addr.s_addr = ahost;
51     myaddr.sin_port = aport;
52     code =
53         sockp->ops->bind(sockp, (struct sockaddr *)&myaddr, sizeof(myaddr));
54
55     if (code < 0) {
56 #if defined(AFS_LINUX24_ENV)
57         printk("sock_release(rx_socket) FIXME\n");
58 #else
59         sock_release(sockp);
60 #endif
61         return NULL;
62     }
63
64     return (struct osi_socket *)sockp;
65 }
66
67 struct osi_socket *
68 rxk_NewSocket(short aport)
69 {
70     return rxk_NewSocketHost(htonl(INADDR_ANY), aport);
71 }
72
73 /* free socket allocated by osi_NetSocket */
74 int
75 rxk_FreeSocket(register struct socket *asocket)
76 {
77     AFS_STATCNT(osi_FreeSocket);
78     return 0;
79 }
80
81
82 /* osi_NetSend
83  *
84  * Return codes:
85  * 0 = success
86  * non-zero = failure
87  */
88 int
89 osi_NetSend(osi_socket sop, struct sockaddr_in *to, struct iovec *iov,
90             int iovcnt, afs_int32 size, int istack)
91 {
92     KERNEL_SPACE_DECL;
93     struct msghdr msg;
94     int code;
95     struct iovec tmpvec[RX_MAXWVECS + 2];
96
97     if (iovcnt > RX_MAXWVECS + 2) {
98         osi_Panic("Too many (%d) iovecs passed to osi_NetSend\n", iovcnt);
99     }
100
101     if (iovcnt <= 2) {          /* avoid pointless uiomove */
102         tmpvec[0].iov_base = iov[0].iov_base;
103         tmpvec[0].iov_len = size;
104         msg.msg_iovlen = 1;
105     } else {
106         memcpy(tmpvec, iov, iovcnt * sizeof(struct iovec));
107         msg.msg_iovlen = iovcnt;
108     }
109     msg.msg_iov = tmpvec;
110     msg.msg_name = to;
111     msg.msg_namelen = sizeof(*to);
112     msg.msg_control = NULL;
113     msg.msg_controllen = 0;
114     msg.msg_flags = 0;
115
116     TO_USER_SPACE();
117     code = sock_sendmsg(sop, &msg, size);
118     TO_KERNEL_SPACE();
119     return (code < 0) ? code : 0;
120 }
121
122
123 /* osi_NetReceive
124  * OS dependent part of kernel RX listener thread.
125  *
126  * Arguments:
127  *      so      socket to receive on, typically rx_socket
128  *      from    pointer to a sockaddr_in. 
129  *      iov     array of iovecs to fill in.
130  *      iovcnt  how many iovecs there are.
131  *      lengthp IN/OUT in: total space available in iovecs. out: size of read.
132  *
133  * Return
134  * 0 if successful
135  * error code (such as EINTER) if not
136  *
137  * Environment
138  *      Note that the maximum number of iovecs is 2 + RX_MAXWVECS. This is
139  *      so we have a little space to look for packets larger than 
140  *      rx_maxReceiveSize.
141  */
142 int rxk_lastSocketError;
143 int rxk_nSocketErrors;
144 int
145 osi_NetReceive(osi_socket so, struct sockaddr_in *from, struct iovec *iov,
146                int iovcnt, int *lengthp)
147 {
148     KERNEL_SPACE_DECL;
149     struct msghdr msg;
150     int code;
151     struct iovec tmpvec[RX_MAXWVECS + 2];
152     struct socket *sop = (struct socket *)so;
153
154     if (iovcnt > RX_MAXWVECS + 2) {
155         osi_Panic("Too many (%d) iovecs passed to osi_NetReceive\n", iovcnt);
156     }
157     memcpy(tmpvec, iov, iovcnt * sizeof(struct iovec));
158     msg.msg_name = from;
159     msg.msg_iov = tmpvec;
160     msg.msg_iovlen = iovcnt;
161     msg.msg_control = NULL;
162     msg.msg_controllen = 0;
163     msg.msg_flags = 0;
164
165     TO_USER_SPACE();
166     code = sock_recvmsg(sop, &msg, *lengthp, 0);
167     TO_KERNEL_SPACE();
168
169     if (code < 0) {
170         /* Clear the error before using the socket again.
171          * Oh joy, Linux has hidden header files as well. It appears we can
172          * simply call again and have it clear itself via sock_error().
173          */
174 #ifdef AFS_LINUX22_ENV
175         flush_signals(current); /* We don't want no stinkin' signals. */
176 #else
177         current->signal = 0;    /* We don't want no stinkin' signals. */
178 #endif
179         rxk_lastSocketError = code;
180         rxk_nSocketErrors++;
181     } else {
182         *lengthp = code;
183         code = 0;
184     }
185
186     return code;
187 }
188
189 void
190 osi_StopListener(void)
191 {
192     struct task_struct *listener;
193     extern int rxk_ListenerPid;
194
195 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
196     read_lock(&tasklist_lock);
197 #endif
198     listener = find_task_by_pid(rxk_ListenerPid);
199 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
200     read_unlock(&tasklist_lock);
201 #endif
202     while (rxk_ListenerPid) {
203         struct task_struct *p;
204
205         flush_signals(listener);
206         force_sig(SIGKILL, listener);
207         afs_osi_Sleep(&rxk_ListenerPid);
208     }
209     sock_release(rx_socket);
210     rx_socket = NULL;
211 }
212
213 #endif /* AFS_LINUX22_ENV */