123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601 |
- /*
- * Linux 2.6.32 and later Kernel module for VMware MVP PVTCP Server
- *
- * Copyright (C) 2010-2013 VMware, Inc. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; see the file COPYING. If not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- #line 5
- /**
- * @file
- *
- * @brief Pvtcp common code.
- */
- #include "pvtcp.h"
- /*
- * Operation table.
- */
- CommOperationFunc pvtcpOperations[] = {
- [PVTCP_OP_FLOW] = PvtcpFlowOp,
- [PVTCP_OP_IO] = PvtcpIoOp,
- [PVTCP_OP_CREATE] = PvtcpCreateOp,
- [PVTCP_OP_RELEASE] = PvtcpReleaseOp,
- [PVTCP_OP_BIND] = PvtcpBindOp,
- [PVTCP_OP_LISTEN] = PvtcpListenOp,
- [PVTCP_OP_ACCEPT] = PvtcpAcceptOp,
- [PVTCP_OP_CONNECT] = PvtcpConnectOp,
- [PVTCP_OP_SHUTDOWN] = PvtcpShutdownOp,
- [PVTCP_OP_SETSOCKOPT] = PvtcpSetSockOptOp,
- [PVTCP_OP_GETSOCKOPT] = PvtcpGetSockOptOp,
- [PVTCP_OP_IOCTL] = PvtcpIoctlOp,
- [PVTCP_OP_INVALID] = NULL
- };
- /*
- * Implementation block.
- */
- CommImpl pvtcpImpl = {
- .owner = NULL,
- .checkArgs = PvtcpCheckArgs,
- .stateCtor = PvtcpStateAlloc,
- .stateDtor = PvtcpStateFree,
- .dataAlloc = PvtcpBufAlloc,
- .dataFree = PvtcpBufFree,
- .operations = pvtcpOperations,
- .closeNtf = PvtcpCloseNtf,
- .closeNtfData = &pvtcpImpl,
- .ntfCenterID = {
- {
- .d32[0] = 2U, /* x86 host context (vmci, only). */
- .d32[1] = 10000 /* Default, not yet reserved, resource (vmci, only). */
- }
- }
- };
- /*
- * Version array.
- */
- const char *pvtcpVersions[] = {
- [PVTCP_VERS_1_1] = PVTCP_COMM_IMPL_VERS_1_1,
- [PVTCP_VERS_1_0] = PVTCP_COMM_IMPL_VERS_1_0
- };
- const unsigned int pvtcpVersionsSize =
- (sizeof(pvtcpVersions) / sizeof(pvtcpVersions[0]));
- /*
- * Client (pv) channel to offload side. We choose to define it here, although
- * it's only applicable to the pv implementation. The reason is that we can
- * share a common close notification function which does the right thing
- * depending on the channel configuration.
- */
- CommChannel pvtcpClientChannel;
- /*
- * Built-in state interfaces.
- */
- static PvtcpIfConf ifUnbound = {
- .family = PVTCP_PF_UNBOUND
- };
- const PvtcpIfConf *pvtcpIfUnbound = &ifUnbound;
- static PvtcpIfConf ifDeathRow = {
- .family = PVTCP_PF_DEATH_ROW
- };
- const PvtcpIfConf *pvtcpIfDeathRow = &ifDeathRow;
- static PvtcpIfConf ifLoopbackInet4 = {
- .family = PVTCP_PF_LOOPBACK_INET4
- };
- const PvtcpIfConf *pvtcpIfLoopbackInet4 = &ifLoopbackInet4;
- /* Functions */
- /**
- * @brief Checks if the IF configuration has reasonable values.
- * @param conf configuration to check
- * @return zero if successful, -1 otherwise
- */
- static int
- IfCheck(const PvtcpIfConf *conf)
- {
- if (!conf ||
- ((conf->family != PF_INET) &&
- (conf->family != PF_INET6) &&
- (conf->family != PVTCP_PF_UNBOUND) &&
- (conf->family != PVTCP_PF_DEATH_ROW) &&
- (conf->family != PVTCP_PF_LOOPBACK_INET4))) {
- return -1;
- }
- /** @todo Need more checks for IP/netmask format validity. */
- return 0;
- }
- /**
- * @brief Checks if the IF has reasonable values, but restricts types to
- * AF_INET and AF_INET6
- * @param conf IF to check
- * @return zero if successful, -1 otherwise
- */
- static int
- IfRestrictedCheck(const PvtcpIfConf *conf)
- {
- if (IfCheck(conf) ||
- ((conf->family != PF_INET) &&
- (conf->family != PF_INET6))) {
- return -1;
- }
- return 0;
- }
- /**
- * @brief Finds a netif given a state and a configuration. The configuration
- * must have already been checked. This function doesn't lock, so it
- * should not be called when the state, or the netif for the passed
- * configuration may be deleted.
- * @param state state to look for.
- * @param conf configuration to look for.
- * @return netif matching configuration, or NULL.
- */
- PvtcpIf *
- PvtcpStateFindIf(PvtcpState *state,
- const PvtcpIfConf *conf)
- {
- PvtcpIf *netif;
- if (!state) {
- return NULL;
- }
- if (conf->family == PVTCP_PF_UNBOUND) {
- return &state->ifUnbound;
- }
- if (conf->family == PVTCP_PF_DEATH_ROW) {
- return &state->ifDeathRow;
- }
- if (conf->family == PVTCP_PF_LOOPBACK_INET4) {
- return &state->ifLoopbackInet4;
- }
- CommOS_ListForEach(&state->ifList, netif, stateLink) {
- if (netif->conf.family == conf->family) {
- if ((conf->family == PF_INET &&
- !memcmp(&netif->conf.addr.in, &conf->addr.in,
- sizeof(conf->addr.in))) ||
- (conf->family == PF_INET6 &&
- !memcmp(&netif->conf.addr.in6, &conf->addr.in6,
- sizeof(conf->addr.in6)))) {
- return netif;
- }
- }
- }
- return NULL;
- }
- /**
- * @brief Creates and initializes a new netif for a given channel and with
- * the specified configuration. Death row and unbound netifs may not
- * be added using this function.
- * @param[in,out] channel channel to make a new netif in
- * @param conf configuration to set netif to
- * @return 0 if successful, -1 otherwise
- * @sideeffect May allocate memory
- */
- int
- PvtcpStateAddIf(CommChannel channel,
- const PvtcpIfConf *conf)
- {
- int rc = -1;
- PvtcpState *state;
- PvtcpIf *netif;
- if (!channel || IfRestrictedCheck(conf)) {
- return rc;
- }
- if (CommSvc_Lock(channel)) {
- return rc; /* channel isn't active. */
- }
- state = CommSvc_GetState(channel);
- if (!state) {
- goto out;
- }
- if (PvtcpStateFindIf(state, conf)) {
- goto out; /* Already configured. */
- }
- netif = CommOS_Kmalloc(sizeof(*netif));
- if (!netif) {
- goto out;
- }
- INIT_LIST_HEAD(&netif->stateLink);
- INIT_LIST_HEAD(&netif->sockList);
- netif->state = state;
- netif->conf = *conf;
- CommOS_ListAddTail(&state->ifList, &netif->stateLink);
- rc = 0;
- out:
- CommSvc_Unlock(channel);
- return rc;
- }
- /**
- * @brief Removes all sockets associated with the given netif.
- * @param[in,out] netif interface to remove the socket from.
- * @sideeffect Closes sockets.
- */
- static void
- IfReleaseSockets(PvtcpIf *netif)
- {
- PvtcpSock *pvsk;
- PvtcpSock *tmp;
- if (netif) {
- CommOS_ListForEachSafe(&netif->sockList, pvsk, tmp, ifLink) {
- CommOS_ListDel(&pvsk->ifLink);
- PvtcpReleaseSocket(pvsk);
- }
- }
- }
- /**
- * @brief Deallocates the given net interface.
- * @param[in,out] netif netif to deallocate
- * @sideeffect Deallocates memory.
- */
- static void
- IfFree(PvtcpIf *netif)
- {
- if (netif) {
- CommOS_ListDel(&netif->stateLink);
- CommOS_Kfree(netif);
- }
- }
- /**
- * @brief Closes all sockets associated with, and deallocates the netif
- * in the given channel and with the specified configuration.
- * Death row and unbound netifs may not be removed using this function.
- * @param[in,out] channel channel to remove from
- * @param conf configuration specified
- * @return zero if successful, error code otherwise
- * @sideeffect Closes sockets, deallocates memory
- */
- void
- PvtcpStateRemoveIf(CommChannel channel,
- const PvtcpIfConf *conf)
- {
- PvtcpState *state;
- PvtcpIf *netif;
- if (!channel || IfRestrictedCheck(conf)) {
- return;
- }
- if (CommSvc_Lock(channel)) {
- return; /* channel isn't active. */
- }
- state = CommSvc_GetState(channel);
- if (state) {
- netif = PvtcpStateFindIf(state, conf);
- if (netif && netif->state == state) {
- IfReleaseSockets(netif);
- if ((netif->conf.family != PVTCP_PF_UNBOUND) &&
- (netif->conf.family != PVTCP_PF_DEATH_ROW) &&
- (netif->conf.family != PVTCP_PF_LOOPBACK_INET4)) {
- IfFree(netif);
- }
- }
- }
- CommSvc_Unlock(channel);
- }
- /**
- * @brief Adds a socket to an existing netif. If the socket is already on a
- * different netif, it is removed from that netif.
- * It locks the must-be-active channel. We use that lock to guard
- * against concurrent removal of the netif.
- * @param[in,out] channel channel to add to
- * @param conf specified configuration
- * @param[in,out] sock socket to add
- * @return zero if successful, -1 otherwise
- */
- int
- PvtcpStateAddSocket(CommChannel channel,
- const PvtcpIfConf *conf,
- PvtcpSock *sock)
- {
- int rc = -1;
- PvtcpState *state;
- PvtcpIf *netif;
- if (!channel || !sock || (sock->channel != channel) || IfCheck(conf)) {
- return rc;
- }
- if (CommSvc_Lock(channel)) {
- return rc; /* channel isn't active. */
- }
- state = CommSvc_GetState(channel);
- if (!state) {
- goto out;
- }
- netif = PvtcpStateFindIf(state, conf);
- if (!netif) {
- goto out;
- }
- CommOS_ListDel(&sock->ifLink);
- sock->netif = netif;
- CommOS_ListAddTail(&netif->sockList, &sock->ifLink);
- rc = 0;
- out:
- CommSvc_Unlock(channel);
- return rc;
- }
- /**
- * @brief Removes a socket from its netif.
- * It locks the must-be-active channel. We use that lock to guard
- * against concurrent removal of the netif.
- * @param[in,out] channel channel to remove from
- * @param[in,out] sock socket to remove
- * @return zero if successful, -1 otherwise
- */
- int
- PvtcpStateRemoveSocket(CommChannel channel,
- PvtcpSock *sock)
- {
- if (!channel || !sock ||
- (sock->channel && (sock->channel != channel))) {
- return -1;
- }
- if (CommSvc_Lock(channel)) {
- return -1; /* channel isn't active. */
- }
- CommOS_ListDel(&sock->ifLink);
- CommSvc_Unlock(channel);
- return 0;
- }
- /**
- * @brief State constructor called when a channel is created. The netifs
- * 'death row' and 'unbound' are always initialized.
- * @param[in,out] channel channel to initialize
- * @return pointer to a new state structure or NULL
- * @sideeffect Allocates memory
- */
- void *
- PvtcpStateAlloc(CommChannel channel)
- {
- PvtcpState *state;
- state = CommOS_Kmalloc(sizeof(*state));
- if (state) {
- state->channel = channel;
- INIT_LIST_HEAD(&state->ifList);
- /* Initialize always-present netifs. */
- INIT_LIST_HEAD(&state->ifDeathRow.stateLink); /* Irrelevant */
- INIT_LIST_HEAD(&state->ifDeathRow.sockList);
- state->ifDeathRow.state = state;
- state->ifDeathRow.conf.family = PVTCP_PF_DEATH_ROW;
- INIT_LIST_HEAD(&state->ifUnbound.stateLink); /* Irrelevant */
- INIT_LIST_HEAD(&state->ifUnbound.sockList);
- state->ifUnbound.state = state;
- state->ifUnbound.conf.family = PVTCP_PF_UNBOUND;
- INIT_LIST_HEAD(&state->ifLoopbackInet4.stateLink); /* Irrelevant */
- INIT_LIST_HEAD(&state->ifLoopbackInet4.sockList);
- state->ifLoopbackInet4.state = state;
- state->ifLoopbackInet4.conf.family = PVTCP_PF_LOOPBACK_INET4;
- state->namespace = NULL;
- state->mask = ((unsigned int)channel << 4) ^ (unsigned int)state;
- #if defined(__linux__)
- state->id = ((unsigned long long)random32() << 32) |
- (unsigned long long)random32();
- #else
- state->id = (unsigned long long)state;
- #endif
- }
- return state;
- }
- /**
- * @brief State destructor called when a channel is closed.
- * The caller (Comm) guarantees proper locking.
- * @param arg pointer to state structure
- * @sideeffect Destroys all netifs and their sockets, deallocates memory
- */
- void
- PvtcpStateFree(void *arg)
- {
- PvtcpState *state = arg;
- PvtcpIf *netif;
- PvtcpIf *tmp;
- if (state) {
- CommOS_ListForEachSafe(&state->ifList, netif, tmp, stateLink) {
- IfReleaseSockets(netif);
- IfFree(netif);
- }
- IfReleaseSockets(&state->ifLoopbackInet4);
- IfReleaseSockets(&state->ifUnbound);
- IfReleaseSockets(&state->ifDeathRow);
- CommOS_Kfree(state);
- }
- }
- /**
- * @brief Checks transport arguments.
- * @param transpArgs transport arguments.
- * @return zero if successful, < 0 otherwise.
- */
- int
- PvtcpCheckArgs(CommTranspInitArgs *transpArgs)
- {
- int rc = -1;
- const unsigned int minCapacity =
- (PVTCP_SOCK_BUF_SIZE + sizeof(CommPacket)) * 2;
- unsigned int versionIndex = pvtcpVersionsSize;
- if (transpArgs->capacity < minCapacity) {
- return rc;
- }
- while (versionIndex--) {
- if (transpArgs->type == CommTransp_GetType(pvtcpVersions[versionIndex])) {
- /* If a match, overwrite the hash with the actual version (index). */
- transpArgs->type = versionIndex;
- rc = 0;
- break;
- }
- }
- return rc;
- }
- /**
- * @brief Called after a channel is freed.
- * @param ntfData callback data from implementation block.
- * @param transpArgs transport arguments of closed channel.
- * @param inBH whether called in bottom half.
- */
- void
- PvtcpCloseNtf(void *ntfData,
- const CommTranspInitArgs *transpArgs,
- int inBH)
- {
- CommImpl *impl = (CommImpl *)ntfData;
- pvtcpClientChannel = NULL;
- CommOS_Log(("%s: Channel was reset!\n", __func__));
- /*
- * If the impl. block owner is NULL, we're pv client: we attempt to
- * reopen the channel in a few seconds.
- */
- if (impl && !impl->owner && !inBH) {
- CommOS_Log(("%s: Attempting to re-initialize channel.\n", __func__));
- impl->openAtMillis = CommOS_GetCurrentMillis();
- impl->openTimeoutAtMillis =
- CommOS_GetCurrentMillis() + PVTCP_CHANNEL_OPEN_TIMEOUT;
- if (CommSvc_Alloc(transpArgs, impl, inBH, &pvtcpClientChannel)) {
- CommOS_Log(("%s: Failed to initialize channel!\n", __func__));
- }
- }
- }
- /**
- * @brief Initializes the Pvtcp socket common fields.
- * @param pvsk pvtcp socket.
- * @param channel Comm channel this socket is associated with.
- * @return 0 if successful, -1 otherwise.
- */
- int
- PvtcpSockInit(PvtcpSock *pvsk,
- CommChannel channel)
- {
- PvtcpState *state;
- int rc = -1;
- if (pvsk && channel) {
- state = CommSvc_GetState(channel);
- if (state) {
- /* Must _not_ zero out pvsk! */
- CommOS_MutexInit(&pvsk->inLock);
- CommOS_MutexInit(&pvsk->outLock);
- CommOS_SpinlockInit(&pvsk->stateLock);
- CommOS_ListInit(&pvsk->ifLink);
- CommOS_InitWork(&pvsk->work, PvtcpProcessAIO);
- pvsk->netif = NULL;
- pvsk->state = state;
- pvsk->stateID = state->id;
- pvsk->channel = channel;
- pvsk->peerSock = PVTCP_PEER_SOCK_NULL;
- pvsk->peerSockSet = 0;
- CommOS_WriteAtomic(&pvsk->deltaAckSize,
- (1 << PVTCP_SOCK_SMALL_ACK_ORDER));
- CommOS_WriteAtomic(&pvsk->rcvdSize, 0);
- CommOS_WriteAtomic(&pvsk->sentSize, 0);
- CommOS_WriteAtomic(&pvsk->queueSize, 0);
- CommOS_ListInit(&pvsk->queue);
- pvsk->rpcReply = NULL;
- pvsk->rpcStatus = 0;
- pvsk->err = 0;
- rc = 0;
- }
- }
- return rc;
- }
|