rx: avoid nat ping during shutdown
[openafs.git] / src / rx / DARWIN / 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 #include <afsconfig.h>
11 #include "afs/param.h"
12
13
14 #include "rx/rx_kcommon.h"
15 #include "rx/rx_atomic.h"
16 #include "rx/rx_stats.h"
17
18 #ifdef AFS_DARWIN80_ENV
19 #define soclose sock_close
20 #endif
21
22 #ifdef RXK_UPCALL_ENV
23 void
24 rx_upcall(socket_t so, void *arg, __unused int waitflag)
25 {
26     mbuf_t m;
27     int error = 0;
28     int i, flags = 0;
29     struct msghdr msg;
30     struct sockaddr_storage ss;
31     struct sockaddr *sa = NULL;
32     struct sockaddr_in from;
33     struct rx_packet *p;
34     afs_int32 rlen;
35     afs_int32 tlen;
36     afs_int32 savelen;          /* was using rlen but had aliasing problems */
37     size_t nbytes, resid, noffset;
38
39     p = rxi_AllocPacket(RX_PACKET_CLASS_RECEIVE);
40     rx_computelen(p, tlen);
41     rx_SetDataSize(p, tlen);    /* this is the size of the user data area */
42     tlen += RX_HEADER_SIZE;     /* now this is the size of the entire packet */
43     rlen = rx_maxJumboRecvSize; /* this is what I am advertising.  Only check
44                                  * it once in order to avoid races.  */
45     tlen = rlen - tlen;
46     if (tlen > 0) {
47         tlen = rxi_AllocDataBuf(p, tlen, RX_PACKET_CLASS_RECV_CBUF);
48         if (tlen > 0) {
49             tlen = rlen - tlen;
50         } else
51             tlen = rlen;
52     } else
53         tlen = rlen;
54     /* add some padding to the last iovec, it's just to make sure that the
55      * read doesn't return more data than we expect, and is done to get around
56      * our problems caused by the lack of a length field in the rx header. */
57     savelen = p->wirevec[p->niovecs - 1].iov_len;
58     p->wirevec[p->niovecs - 1].iov_len = savelen + RX_EXTRABUFFERSIZE;
59
60     resid = nbytes = tlen + sizeof(afs_int32);
61
62     memset(&msg, 0, sizeof(struct msghdr));
63     msg.msg_name = &ss;
64     msg.msg_namelen = sizeof(struct sockaddr_storage);
65     sa =(struct sockaddr *) &ss;
66
67     do {
68         m = NULL;
69         error = sock_receivembuf(so, &msg, &m, MSG_DONTWAIT, &nbytes);
70         if (!error) {
71             size_t sz, offset = 0;
72             noffset = 0;
73             resid = nbytes;
74             for (i=0;i<p->niovecs && resid;i++) {
75                 sz=MIN(resid, p->wirevec[i].iov_len);
76                 error = mbuf_copydata(m, offset, sz, p->wirevec[i].iov_base);
77                 if (error)
78                     break;
79                 resid-=sz;
80                 offset+=sz;
81                 noffset += sz;
82             }
83         }
84     } while (0);
85
86     mbuf_freem(m);
87
88     /* restore the vec to its correct state */
89     p->wirevec[p->niovecs - 1].iov_len = savelen;
90
91     if (error == EWOULDBLOCK && noffset > 0)
92         error = 0;
93
94     if (!error) {
95         int host, port;
96
97         nbytes -= resid;
98
99         if (sa->sa_family == AF_INET)
100             from = *(struct sockaddr_in *)sa;
101
102         p->length = nbytes - RX_HEADER_SIZE;;
103         if ((nbytes > tlen) || (p->length & 0x8000)) {  /* Bogus packet */
104             if (nbytes <= 0) {
105                 if (rx_stats_active) {
106                     MUTEX_ENTER(&rx_stats_mutex);
107                     rx_atomic_inc(&rx_stats.bogusPacketOnRead);
108                     rx_stats.bogusHost = from.sin_addr.s_addr;
109                     MUTEX_EXIT(&rx_stats_mutex);
110                 }
111                 dpf(("B: bogus packet from [%x,%d] nb=%d",
112                      from.sin_addr.s_addr, from.sin_port, nbytes));
113             }
114             return;
115         } else {
116             /* Extract packet header. */
117             rxi_DecodePacketHeader(p);
118
119             host = from.sin_addr.s_addr;
120             port = from.sin_port;
121             if (p->header.type > 0 && p->header.type < RX_N_PACKET_TYPES) {
122                 if (rx_stats_active) {
123                     rx_atomic_inc(&rx_stats.packetsRead[p->header.type - 1]);
124                 }
125             }
126
127 #ifdef RX_TRIMDATABUFS
128             /* Free any empty packet buffers at the end of this packet */
129             rxi_TrimDataBufs(p, 1);
130 #endif
131             /* receive pcket */
132             p = rxi_ReceivePacket(p, so, host, port, 0, 0);
133         }
134     }
135     /* free packet? */
136     if (p)
137         rxi_FreePacket(p);
138
139     return;
140 }
141
142 /* in listener env, the listener shutdown does this. we have no listener */
143 void
144 osi_StopNetIfPoller(void)
145 {
146     shutdown_rx();
147     soclose(rx_socket);
148     if (afs_termState == AFSOP_STOP_NETIF) {
149         afs_termState = AFSOP_STOP_COMPLETE;
150         osi_rxWakeup(&afs_termState);
151     }
152 }
153 #elif defined(RXK_LISTENER_ENV)
154 int
155 osi_NetReceive(osi_socket so, struct sockaddr_in *addr, struct iovec *dvec,
156                int nvecs, int *alength)
157 {
158 #ifdef AFS_DARWIN80_ENV
159     socket_t asocket = (socket_t)so;
160     struct msghdr msg;
161     struct sockaddr_storage ss;
162     int rlen;
163     mbuf_t m;
164 #else
165     struct socket *asocket = (struct socket *)so;
166     struct uio u;
167 #endif
168     int i;
169     struct iovec iov[RX_MAXIOVECS];
170     struct sockaddr *sa = NULL;
171     int code;
172     size_t resid;
173
174     int haveGlock = ISAFS_GLOCK();
175     /*AFS_STATCNT(osi_NetReceive); */
176
177     if (nvecs > RX_MAXIOVECS)
178         osi_Panic("osi_NetReceive: %d: Too many iovecs.\n", nvecs);
179
180     for (i = 0; i < nvecs; i++)
181         iov[i] = dvec[i];
182
183     if ((afs_termState == AFSOP_STOP_RXK_LISTENER) ||
184         (afs_termState == AFSOP_STOP_COMPLETE))
185         return -1;
186
187     if (haveGlock)
188         AFS_GUNLOCK();
189 #if defined(KERNEL_FUNNEL)
190     thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
191 #endif
192 #ifdef AFS_DARWIN80_ENV
193     resid = *alength;
194     memset(&msg, 0, sizeof(struct msghdr));
195     msg.msg_name = &ss;
196     msg.msg_namelen = sizeof(struct sockaddr_storage);
197     sa =(struct sockaddr *) &ss;
198     code = sock_receivembuf(asocket, &msg, &m, 0, alength);
199     if (!code) {
200         size_t offset=0,sz;
201         resid = *alength;
202         for (i=0;i<nvecs && resid;i++) {
203             sz=MIN(resid, iov[i].iov_len);
204             code = mbuf_copydata(m, offset, sz, iov[i].iov_base);
205             if (code)
206                 break;
207             resid-=sz;
208             offset+=sz;
209         }
210     }
211     mbuf_freem(m);
212 #else
213
214     u.uio_iov = &iov[0];
215     u.uio_iovcnt = nvecs;
216     u.uio_offset = 0;
217     u.uio_resid = *alength;
218     u.uio_segflg = UIO_SYSSPACE;
219     u.uio_rw = UIO_READ;
220     u.uio_procp = NULL;
221     code = soreceive(asocket, &sa, &u, NULL, NULL, NULL);
222     resid = u.uio_resid;
223 #endif
224
225 #if defined(KERNEL_FUNNEL)
226     thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
227 #endif
228     if (haveGlock)
229         AFS_GLOCK();
230
231     if (code)
232         return code;
233     *alength -= resid;
234     if (sa) {
235         if (sa->sa_family == AF_INET) {
236             if (addr)
237                 *addr = *(struct sockaddr_in *)sa;
238         } else
239             printf("Unknown socket family %d in NetReceive\n", sa->sa_family);
240 #ifndef AFS_DARWIN80_ENV
241         FREE(sa, M_SONAME);
242 #endif
243     }
244     return code;
245 }
246
247 extern int rxk_ListenerPid;
248 void
249 osi_StopListener(void)
250 {
251     struct proc *p;
252
253 #if defined(KERNEL_FUNNEL)
254     thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
255 #endif
256     soclose(rx_socket);
257 #if defined(KERNEL_FUNNEL)
258     thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
259 #endif
260 #ifndef AFS_DARWIN80_ENV
261     p = pfind(rxk_ListenerPid);
262     if (p)
263         psignal(p, SIGUSR1);
264 #endif
265 }
266 #else
267 #error need upcall or listener
268 #endif
269
270 int
271 osi_NetSend(osi_socket so, struct sockaddr_in *addr, struct iovec *dvec,
272             int nvecs, afs_int32 alength, int istack)
273 {
274 #ifdef AFS_DARWIN80_ENV
275     socket_t asocket = (socket_t)so;
276     struct msghdr msg;
277     size_t slen;
278 #else
279     struct socket *asocket = (struct socket *)so;
280     struct uio u;
281 #endif
282     afs_int32 code;
283     int i;
284     struct iovec iov[RX_MAXIOVECS];
285     int haveGlock = ISAFS_GLOCK();
286
287     AFS_STATCNT(osi_NetSend);
288     if (nvecs > RX_MAXIOVECS)
289         osi_Panic("osi_NetSend: %d: Too many iovecs.\n", nvecs);
290
291     for (i = 0; i < nvecs; i++)
292         iov[i] = dvec[i];
293
294     addr->sin_len = sizeof(struct sockaddr_in);
295
296     if ((afs_termState == AFSOP_STOP_RXK_LISTENER) ||
297         (afs_termState == AFSOP_STOP_COMPLETE))
298         return -1;
299
300     if (haveGlock)
301         AFS_GUNLOCK();
302
303 #if defined(KERNEL_FUNNEL)
304     thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
305 #endif
306 #ifdef AFS_DARWIN80_ENV
307     memset(&msg, 0, sizeof(struct msghdr));
308     msg.msg_name = addr;
309     msg.msg_namelen = ((struct sockaddr *)addr)->sa_len;
310     msg.msg_iov = &iov[0];
311     msg.msg_iovlen = nvecs;
312     code = sock_send(asocket, &msg, 0, &slen);
313 #else
314     u.uio_iov = &iov[0];
315     u.uio_iovcnt = nvecs;
316     u.uio_offset = 0;
317     u.uio_resid = alength;
318     u.uio_segflg = UIO_SYSSPACE;
319     u.uio_rw = UIO_WRITE;
320     u.uio_procp = NULL;
321     code = sosend(asocket, (struct sockaddr *)addr, &u, NULL, NULL, 0);
322 #endif
323
324 #if defined(KERNEL_FUNNEL)
325     thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
326 #endif
327     if (haveGlock)
328         AFS_GLOCK();
329     return code;
330 }