*/
#include <afsconfig.h>
-#include "../afs/param.h"
+#include "afs/param.h"
-RCSID("$Header$");
-#include "../rx/rx_kcommon.h"
+#include "rx/rx_kcommon.h"
-int osi_NetReceive(osi_socket so, struct sockaddr_in *addr, struct iovec *dvec,
- int nvecs, int *alength)
+#ifdef AFS_DARWIN80_ENV
+#define soclose sock_close
+#endif
+
+#ifdef RXK_UPCALL_ENV
+void
+rx_upcall(socket_t so, void *arg, __unused int waitflag)
{
+ mbuf_t m;
+ int error = 0;
+ int i, flags = 0;
+ struct msghdr msg;
+ struct sockaddr_storage ss;
+ struct sockaddr *sa = NULL;
+ struct sockaddr_in from;
+ struct rx_packet *p;
+ afs_int32 rlen;
+ afs_int32 tlen;
+ afs_int32 savelen; /* was using rlen but had aliasing problems */
+ size_t nbytes, resid, noffset;
+
+ p = rxi_AllocPacket(RX_PACKET_CLASS_RECEIVE);
+ rx_computelen(p, tlen);
+ rx_SetDataSize(p, tlen); /* this is the size of the user data area */
+ tlen += RX_HEADER_SIZE; /* now this is the size of the entire packet */
+ rlen = rx_maxJumboRecvSize; /* this is what I am advertising. Only check
+ * it once in order to avoid races. */
+ tlen = rlen - tlen;
+ if (tlen > 0) {
+ tlen = rxi_AllocDataBuf(p, tlen, RX_PACKET_CLASS_RECV_CBUF);
+ if (tlen > 0) {
+ tlen = rlen - tlen;
+ } else
+ tlen = rlen;
+ } else
+ tlen = rlen;
+ /* add some padding to the last iovec, it's just to make sure that the
+ * read doesn't return more data than we expect, and is done to get around
+ * our problems caused by the lack of a length field in the rx header. */
+ savelen = p->wirevec[p->niovecs - 1].iov_len;
+ p->wirevec[p->niovecs - 1].iov_len = savelen + RX_EXTRABUFFERSIZE;
+
+ resid = nbytes = tlen + sizeof(afs_int32);
+
+ memset(&msg, 0, sizeof(struct msghdr));
+ msg.msg_name = &ss;
+ msg.msg_namelen = sizeof(struct sockaddr_storage);
+ sa =(struct sockaddr *) &ss;
+
+ do {
+ m = NULL;
+ error = sock_receivembuf(so, &msg, &m, MSG_DONTWAIT, &nbytes);
+ if (!error) {
+ size_t sz, offset = 0;
+ noffset = 0;
+ resid = nbytes;
+ for (i=0;i<p->niovecs && resid;i++) {
+ sz=MIN(resid, p->wirevec[i].iov_len);
+ error = mbuf_copydata(m, offset, sz, p->wirevec[i].iov_base);
+ if (error)
+ break;
+ resid-=sz;
+ offset+=sz;
+ noffset += sz;
+ }
+ }
+ } while (0);
+
+ mbuf_freem(m);
+
+ /* restore the vec to its correct state */
+ p->wirevec[p->niovecs - 1].iov_len = savelen;
+
+ if (error == EWOULDBLOCK && noffset > 0)
+ error = 0;
+
+ if (!error) {
+ int host, port;
+
+ nbytes -= resid;
+
+ if (sa->sa_family == AF_INET)
+ from = *(struct sockaddr_in *)sa;
+
+ p->length = nbytes - RX_HEADER_SIZE;;
+ if ((nbytes > tlen) || (p->length & 0x8000)) { /* Bogus packet */
+ if (nbytes <= 0) {
+ if (rx_stats_active) {
+ MUTEX_ENTER(&rx_stats_mutex);
+ rx_stats.bogusPacketOnRead++;
+ rx_stats.bogusHost = from.sin_addr.s_addr;
+ MUTEX_EXIT(&rx_stats_mutex);
+ }
+ dpf(("B: bogus packet from [%x,%d] nb=%d",
+ from.sin_addr.s_addr, from.sin_port, nbytes));
+ }
+ return;
+ } else {
+ /* Extract packet header. */
+ rxi_DecodePacketHeader(p);
+
+ host = from.sin_addr.s_addr;
+ port = from.sin_port;
+ if (p->header.type > 0 && p->header.type < RX_N_PACKET_TYPES) {
+ if (rx_stats_active) {
+ MUTEX_ENTER(&rx_stats_mutex);
+ rx_stats.packetsRead[p->header.type - 1]++;
+ MUTEX_EXIT(&rx_stats_mutex);
+ }
+ }
+
+#ifdef RX_TRIMDATABUFS
+ /* Free any empty packet buffers at the end of this packet */
+ rxi_TrimDataBufs(p, 1);
+#endif
+ /* receive pcket */
+ p = rxi_ReceivePacket(p, so, host, port, 0, 0);
+ }
+ }
+ /* free packet? */
+ if (p)
+ rxi_FreePacket(p);
+
+ return;
+}
+
+/* in listener env, the listener shutdown does this. we have no listener */
+void
+osi_StopNetIfPoller(void)
+{
+ soclose(rx_socket);
+ if (afs_termState == AFSOP_STOP_NETIF) {
+ afs_termState = AFSOP_STOP_COMPLETE;
+ osi_rxWakeup(&afs_termState);
+ }
+}
+#elif defined(RXK_LISTENER_ENV)
+int
+osi_NetReceive(osi_socket so, struct sockaddr_in *addr, struct iovec *dvec,
+ int nvecs, int *alength)
+{
+#ifdef AFS_DARWIN80_ENV
+ socket_t asocket = (socket_t)so;
+ struct msghdr msg;
+ struct sockaddr_storage ss;
+ int rlen;
+ mbuf_t m;
+#else
struct socket *asocket = (struct socket *)so;
struct uio u;
+#endif
int i;
struct iovec iov[RX_MAXIOVECS];
- struct sockaddr *sa;
+ struct sockaddr *sa = NULL;
int code;
+ size_t resid;
int haveGlock = ISAFS_GLOCK();
- /*AFS_STATCNT(osi_NetReceive);*/
+ /*AFS_STATCNT(osi_NetReceive); */
- if (nvecs > RX_MAXIOVECS) {
- osi_Panic("osi_NetReceive: %d: Too many iovecs.\n", nvecs);
- }
+ if (nvecs > RX_MAXIOVECS)
+ osi_Panic("osi_NetReceive: %d: Too many iovecs.\n", nvecs);
- for (i = 0 ; i < nvecs ; i++) {
- iov[i].iov_base = dvec[i].iov_base;
- iov[i].iov_len = dvec[i].iov_len;
- }
+ for (i = 0; i < nvecs; i++)
+ iov[i] = dvec[i];
- u.uio_iov=&iov[0];
- u.uio_iovcnt=nvecs;
- u.uio_offset=0;
- u.uio_resid=*alength;
- u.uio_segflg=UIO_SYSSPACE;
- u.uio_rw=UIO_READ;
- u.uio_procp=NULL;
+ if ((afs_termState == AFSOP_STOP_RXK_LISTENER) ||
+ (afs_termState == AFSOP_STOP_COMPLETE))
+ return -1;
- if (haveGlock) {
- AFS_GUNLOCK();
- }
-#if defined(AFS_DARWIN_ENV) && defined(KERNEL_FUNNEL)
+ if (haveGlock)
+ AFS_GUNLOCK();
+#if defined(KERNEL_FUNNEL)
thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
#endif
+#ifdef AFS_DARWIN80_ENV
+ resid = *alength;
+ memset(&msg, 0, sizeof(struct msghdr));
+ msg.msg_name = &ss;
+ msg.msg_namelen = sizeof(struct sockaddr_storage);
+ sa =(struct sockaddr *) &ss;
+ code = sock_receivembuf(asocket, &msg, &m, 0, alength);
+ if (!code) {
+ size_t offset=0,sz;
+ resid = *alength;
+ for (i=0;i<nvecs && resid;i++) {
+ sz=MIN(resid, iov[i].iov_len);
+ code = mbuf_copydata(m, offset, sz, iov[i].iov_base);
+ if (code)
+ break;
+ resid-=sz;
+ offset+=sz;
+ }
+ }
+ mbuf_freem(m);
+#else
+
+ u.uio_iov = &iov[0];
+ u.uio_iovcnt = nvecs;
+ u.uio_offset = 0;
+ u.uio_resid = *alength;
+ u.uio_segflg = UIO_SYSSPACE;
+ u.uio_rw = UIO_READ;
+ u.uio_procp = NULL;
code = soreceive(asocket, &sa, &u, NULL, NULL, NULL);
-#if defined(AFS_DARWIN_ENV) && defined(KERNEL_FUNNEL)
+ resid = u.uio_resid;
+#endif
+
+#if defined(KERNEL_FUNNEL)
thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
#endif
- if (haveGlock) {
- AFS_GLOCK();
- }
- *alength=*alength-u.uio_resid;
+ if (haveGlock)
+ AFS_GLOCK();
+
+ if (code)
+ return code;
+ *alength -= resid;
if (sa) {
- if (sa->sa_family == AF_INET) {
- if (addr) *addr=*(struct sockaddr_in *)sa;
- } else {
- printf("Unknown socket family %d in NetReceive\n");
- }
+ if (sa->sa_family == AF_INET) {
+ if (addr)
+ *addr = *(struct sockaddr_in *)sa;
+ } else
+ printf("Unknown socket family %d in NetReceive\n", sa->sa_family);
+#ifndef AFS_DARWIN80_ENV
+ FREE(sa, M_SONAME);
+#endif
}
return code;
}
extern int rxk_ListenerPid;
-void osi_StopListener(void)
+void
+osi_StopListener(void)
{
- struct proc *p;
+ struct proc *p;
-#if defined(AFS_DARWIN_ENV) && defined(KERNEL_FUNNEL)
+#if defined(KERNEL_FUNNEL)
thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
#endif
- soclose(rx_socket);
-#if defined(AFS_DARWIN_ENV) && defined(KERNEL_FUNNEL)
+ soclose(rx_socket);
+#if defined(KERNEL_FUNNEL)
thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
#endif
- p=pfind(rxk_ListenerPid);
- if (p)
- psignal(p, SIGUSR1);
+#ifndef AFS_DARWIN80_ENV
+ p = pfind(rxk_ListenerPid);
+ if (p)
+ psignal(p, SIGUSR1);
+#endif
}
+#else
+#error need upcall or listener
+#endif
-/* rx_NetSend - send asize bytes at adata from asocket to host at addr.
- *
- * Now, why do we allocate a new buffer when we could theoretically use the one
- * pointed to by adata? Because PRU_SEND returns after queueing the message,
- * not after sending it. If the sender changes the data after queueing it,
- * we'd see the already-queued data change. One attempt to fix this without
- * adding a copy would be to have this function wait until the datagram is
- * sent; however this doesn't work well. In particular, if a host is down, and
- * an ARP fails to that host, this packet will be queued until the ARP request
- * comes back, which could be hours later. We can't block in this routine that
- * long, since it prevents RPC timeouts from happening.
- */
-/* XXX In the brave new world, steal the data bufs out of the rx_packet iovec,
- * and just queue those. XXX
- */
-
-
-int
-osi_NetSend(asocket, addr, dvec, nvecs, alength, istack)
- register struct socket *asocket;
- struct iovec *dvec;
- int nvecs;
- register afs_int32 alength;
- struct sockaddr_in *addr;
- int istack;
+int
+osi_NetSend(osi_socket so, struct sockaddr_in *addr, struct iovec *dvec,
+ int nvecs, afs_int32 alength, int istack)
{
- register afs_int32 code;
- int s;
- int len;
+#ifdef AFS_DARWIN80_ENV
+ socket_t asocket = (socket_t)so;
+ struct msghdr msg;
+ size_t slen;
+#else
+ struct socket *asocket = (struct socket *)so;
+ struct uio u;
+#endif
+ afs_int32 code;
int i;
struct iovec iov[RX_MAXIOVECS];
- char *tdata;
- struct uio u;
- struct mbuf *nam;
int haveGlock = ISAFS_GLOCK();
AFS_STATCNT(osi_NetSend);
- if (nvecs > RX_MAXIOVECS) {
- osi_Panic("osi_NetSend: %d: Too many iovecs.\n", nvecs);
- }
-
- for (i = 0 ; i < nvecs ; i++) {
- iov[i].iov_base = dvec[i].iov_base;
- iov[i].iov_len = dvec[i].iov_len;
- }
-
- u.uio_iov=&iov[0];
- u.uio_iovcnt=nvecs;
- u.uio_offset=0;
- u.uio_resid=alength;
- u.uio_segflg=UIO_SYSSPACE;
- u.uio_rw=UIO_WRITE;
- u.uio_procp=NULL;
- if (haveGlock) {
+ if (nvecs > RX_MAXIOVECS)
+ osi_Panic("osi_NetSend: %d: Too many iovecs.\n", nvecs);
+
+ for (i = 0; i < nvecs; i++)
+ iov[i] = dvec[i];
+
+ addr->sin_len = sizeof(struct sockaddr_in);
+
+ if ((afs_termState == AFSOP_STOP_RXK_LISTENER) ||
+ (afs_termState == AFSOP_STOP_COMPLETE))
+ return -1;
+
+ if (haveGlock)
AFS_GUNLOCK();
- }
-#if defined(AFS_DARWIN_ENV) && defined(KERNEL_FUNNEL)
+
+#if defined(KERNEL_FUNNEL)
thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
#endif
- nam=m_get(M_DONTWAIT, MT_SONAME);
- if (nam == NULL) {
- code=ENOBUFS;
- goto bad;
- }
- nam->m_len=addr->sin_len=sizeof(struct sockaddr_in);
- memcpy(mtod(nam, caddr_t), (caddr_t)addr, addr->sin_len);
- code = sosend(asocket, mtod(nam, struct sockaddr *), &u, NULL, NULL, 0);
- m_freem(nam);
-bad:
-#if defined(AFS_DARWIN_ENV) && defined(KERNEL_FUNNEL)
+#ifdef AFS_DARWIN80_ENV
+ memset(&msg, 0, sizeof(struct msghdr));
+ msg.msg_name = addr;
+ msg.msg_namelen = ((struct sockaddr *)addr)->sa_len;
+ msg.msg_iov = &iov[0];
+ msg.msg_iovlen = nvecs;
+ code = sock_send(asocket, &msg, 0, &slen);
+#else
+ u.uio_iov = &iov[0];
+ u.uio_iovcnt = nvecs;
+ u.uio_offset = 0;
+ u.uio_resid = alength;
+ u.uio_segflg = UIO_SYSSPACE;
+ u.uio_rw = UIO_WRITE;
+ u.uio_procp = NULL;
+ code = sosend(asocket, (struct sockaddr *)addr, &u, NULL, NULL, 0);
+#endif
+
+#if defined(KERNEL_FUNNEL)
thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
#endif
- if (haveGlock) {
+ if (haveGlock)
AFS_GLOCK();
- }
return code;
}