static int send_attach(struct socket *so, int proto, struct thread *td) { int error; SEND_LOCK(); if (V_send_so != NULL) { SEND_UNLOCK(); return (EEXIST); } error = priv_check(td, PRIV_NETINET_RAW); if (error) { SEND_UNLOCK(); return(error); } if (proto != IPPROTO_SEND) { SEND_UNLOCK(); return (EPROTONOSUPPORT); } error = soreserve(so, send_sendspace, send_recvspace); if (error) { SEND_UNLOCK(); return(error); } V_send_so = so; SEND_UNLOCK(); return (0); }
static void send_close(struct socket *so) { SEND_LOCK(); if (V_send_so) V_send_so = NULL; SEND_UNLOCK(); }
static int send_modevent(module_t mod, int type, void *unused) { #ifdef __notyet__ VNET_ITERATOR_DECL(vnet_iter); #endif int error; switch (type) { case MOD_LOAD: SEND_LOCK_INIT(); error = pf_proto_register(PF_INET6, &send_protosw); if (error != 0) { printf("%s:%d: MOD_LOAD pf_proto_register(): %d\n", __func__, __LINE__, error); SEND_LOCK_DESTROY(); break; } send_sendso_input_hook = send_input; break; case MOD_UNLOAD: /* Do not allow unloading w/o locking. */ return (EBUSY); #ifdef __notyet__ VNET_LIST_RLOCK_NOSLEEP(); SEND_LOCK(); VNET_FOREACH(vnet_iter) { CURVNET_SET(vnet_iter); if (V_send_so != NULL) { CURVNET_RESTORE(); SEND_UNLOCK(); VNET_LIST_RUNLOCK_NOSLEEP(); return (EBUSY); } CURVNET_RESTORE(); } SEND_UNLOCK(); VNET_LIST_RUNLOCK_NOSLEEP(); error = pf_proto_unregister(PF_INET6, IPPROTO_SEND, SOCK_RAW); if (error == 0) SEND_LOCK_DESTROY(); send_sendso_input_hook = NULL; break; #endif default: error = 0; break; } return (error); }
/* * Send a SeND message to user space, that was either received and has to be * validated or was about to be send out and has to be handled by the SEND * daemon adding SeND ICMPv6 options. */ static int send_input(struct mbuf *m, struct ifnet *ifp, int direction, int msglen __unused) { struct ip6_hdr *ip6; struct sockaddr_send sendsrc; SEND_LOCK(); if (V_send_so == NULL) { SEND_UNLOCK(); return (-1); } /* * Make sure to clear any possible internally embedded scope before * passing the packet to user space for SeND cryptographic signature * validation to succeed. */ ip6 = mtod(m, struct ip6_hdr *); in6_clearscope(&ip6->ip6_src); in6_clearscope(&ip6->ip6_dst); bzero(&sendsrc, sizeof(sendsrc)); sendsrc.send_len = sizeof(sendsrc); sendsrc.send_family = AF_INET6; sendsrc.send_direction = direction; sendsrc.send_ifidx = ifp->if_index; /* * Send incoming or outgoing traffic to user space either to be * protected (outgoing) or validated (incoming) according to rfc3971. */ SOCKBUF_LOCK(&V_send_so->so_rcv); if (sbappendaddr_locked(&V_send_so->so_rcv, (struct sockaddr *)&sendsrc, m, NULL) == 0) { SOCKBUF_UNLOCK(&V_send_so->so_rcv); /* XXX stats. */ m_freem(m); } else { sorwakeup_locked(V_send_so); } SEND_UNLOCK(); return (0); }
/* * cas_send_bs_msg() * * (channel access server send message) */ void cas_send_bs_msg ( struct client *pclient, int lock_needed ) { int status; if ( CASDEBUG > 2 && pclient->send.stk ) { errlogPrintf ( "CAS: Sending a message of %d bytes\n", pclient->send.stk ); } if ( pclient->disconnect ) { if ( CASDEBUG > 2 ) { errlogPrintf ( "CAS: msg Discard for sock %d addr %x\n", pclient->sock, (unsigned) pclient->addr.sin_addr.s_addr ); } pclient->send.stk = 0u; return; } if ( lock_needed ) { SEND_LOCK ( pclient ); } while ( pclient->send.stk && ! pclient->disconnect ) { status = send ( pclient->sock, pclient->send.buf, pclient->send.stk, 0 ); if ( status >= 0 ) { unsigned transferSize = (unsigned) status; if ( transferSize >= pclient->send.stk ) { pclient->send.stk = 0; epicsTimeGetCurrent ( &pclient->time_at_last_send ); break; } else { unsigned bytesLeft = pclient->send.stk - transferSize; memmove ( pclient->send.buf, &pclient->send.buf[transferSize], bytesLeft ); pclient->send.stk = bytesLeft; } } else { int causeWasSocketHangup = 0; int anerrno = SOCKERRNO; char buf[64]; if ( pclient->disconnect ) { pclient->send.stk = 0u; break; } if ( anerrno == SOCK_EINTR ) { continue; } if ( anerrno == SOCK_ENOBUFS ) { errlogPrintf ( "CAS: Out of network buffers, retrying send in 15 seconds\n" ); epicsThreadSleep ( 15.0 ); continue; } ipAddrToDottedIP ( &pclient->addr, buf, sizeof(buf) ); if ( anerrno == SOCK_ECONNABORTED || anerrno == SOCK_ECONNRESET || anerrno == SOCK_EPIPE || anerrno == SOCK_ETIMEDOUT ) { causeWasSocketHangup = 1; } else { char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); errlogPrintf ( "CAS: TCP send to %s failed - %s\n", buf, sockErrBuf); } pclient->disconnect = TRUE; pclient->send.stk = 0u; /* * wakeup the receive thread */ if ( ! causeWasSocketHangup ) { enum epicsSocketSystemCallInterruptMechanismQueryInfo info = epicsSocketSystemCallInterruptMechanismQuery (); switch ( info ) { case esscimqi_socketCloseRequired: if ( pclient->sock != INVALID_SOCKET ) { epicsSocketDestroy ( pclient->sock ); pclient->sock = INVALID_SOCKET; } break; case esscimqi_socketBothShutdownRequired: { int status = shutdown ( pclient->sock, SHUT_RDWR ); if ( status ) { char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); errlogPrintf ("CAS: Socket shutdown error - %s\n", sockErrBuf ); } } break; case esscimqi_socketSigAlarmRequired: epicsSignalRaiseSigAlarm ( pclient->tid ); break; default: break; }; break; } } } if ( lock_needed ) { SEND_UNLOCK(pclient); } DLOG ( 3, ( "------------------------------\n\n" ) ); return; }
/* * cas_send_dg_msg() * * (channel access server send udp message) */ void cas_send_dg_msg ( struct client * pclient ) { int status; int sizeDG; char * pDG; caHdr * pMsg; if ( CASDEBUG > 2 && pclient->send.stk ) { errlogPrintf ( "CAS: Sending a udp message of %d bytes\n", pclient->send.stk ); } SEND_LOCK ( pclient ); if ( pclient->send.stk <= sizeof (caHdr) ) { SEND_UNLOCK(pclient); return; } pDG = pclient->send.buf; pMsg = ( caHdr * ) pDG; sizeDG = pclient->send.stk; assert ( ntohs ( pMsg->m_cmmd ) == CA_PROTO_VERSION ); if ( CA_V411 ( pclient->minor_version_number ) ) { pMsg->m_cid = htonl ( pclient->seqNoOfReq ); pMsg->m_dataType = htons ( sequenceNoIsValid ); } else { pDG += sizeof (caHdr); sizeDG -= sizeof (caHdr); } status = sendto ( pclient->sock, pDG, sizeDG, 0, (struct sockaddr *)&pclient->addr, sizeof(pclient->addr) ); if ( status >= 0 ) { if ( status >= sizeDG ) { epicsTimeGetCurrent ( &pclient->time_at_last_send ); } else { errlogPrintf ( "CAS: System failed to send entire udp frame?\n" ); } } else { char sockErrBuf[64]; char buf[128]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); ipAddrToDottedIP ( &pclient->addr, buf, sizeof(buf) ); errlogPrintf( "CAS: UDP send to %s failed - %s\n", buf, sockErrBuf); } pclient->send.stk = 0u; /* * add placeholder for the first version message should it be needed */ rsrv_version_reply ( pclient ); SEND_UNLOCK(pclient); DLOG ( 3, ( "------------------------------\n\n" ) ); return; }