/* Transport used for host->guest communication */ staticconststruct vsock_transport *transport_h2g; /* Transport used for guest->host communication */ staticconststruct vsock_transport *transport_g2h; /* Transport used for DGRAM communication */ staticconststruct vsock_transport *transport_dgram; /* Transport used for local communication */ staticconststruct vsock_transport *transport_local; static DEFINE_MUTEX(vsock_register_mutex);
/**** UTILS ****/
/* Each bound VSocket is stored in the bind hash table and each connected *VSocketisstoredintheconnectedhashtable. * *Unboundsocketsareallputonthesamelistattachedtotheendofthehash *table(vsock_unbound_sockets).Boundsocketsareaddedtothehashtablein *thebucketthattheirlocaladdresshashesto(vsock_bound_sockets(addr) *representsthelistthataddrhashesto). * *Specifically,weinitializethevsock_bind_tablearraytoasizeof *VSOCK_HASH_SIZE+1sothatvsock_bind_table[0]through *vsock_bind_table[VSOCK_HASH_SIZE-1]areforboundsocketsand *vsock_bind_table[VSOCK_HASH_SIZE]isforunboundsockets.Thehashfunction *modswithVSOCK_HASH_SIZEtoensurethis.
*/ #define MAX_PORT_RETRIES 24
/* Autobind this socket to the local address if necessary. */ staticint vsock_auto_bind(struct vsock_sock *vsk)
{ struct sock *sk = sk_vsock(vsk); struct sockaddr_vm local_addr;
if (vsock_addr_bound(&vsk->local_addr)) return0;
vsock_addr_init(&local_addr, VMADDR_CID_ANY, VMADDR_PORT_ANY); return __vsock_bind(sk, &local_addr);
}
staticvoid vsock_init_tables(void)
{ int i;
for (i = 0; i < ARRAY_SIZE(vsock_bind_table); i++)
INIT_LIST_HEAD(&vsock_bind_table[i]);
for (i = 0; i < ARRAY_SIZE(vsock_connected_table); i++)
INIT_LIST_HEAD(&vsock_connected_table[i]);
}
void vsock_remove_sock(struct vsock_sock *vsk)
{ /* Transport reassignment must not remove the binding. */ if (sock_flag(sk_vsock(vsk), SOCK_DEAD))
vsock_remove_bound(vsk);
/* Assign a transport to a socket and call the .init transport callback. * *Note:forconnectionorientedsocketthismustbecalledwhenvsk->remote_addr *isset(e.g.duringtheconnect()orwhenaconnectionrequestonalistener *socketisreceived). *Thevsk->remote_addrisusedtodecidewhichtransporttouse: *-remoteCID==VMADDR_CID_LOCALorg2h->local_cidorVMADDR_CID_HOSTif *g2hisnotloaded,willuselocaltransport; *-remoteCID<=VMADDR_CID_HOSTorh2gisnotloadedorremoteflagsfield *includesVMADDR_FLAG_TO_HOSTflagvalue,willuseguest->hosttransport; *-remoteCID>VMADDR_CID_HOSTwillusehost->guesttransport;
*/ int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk)
{ conststruct vsock_transport *new_transport; struct sock *sk = sk_vsock(vsk); unsignedint remote_cid = vsk->remote_addr.svm_cid;
__u8 remote_flags; int ret;
/* If the packet is coming with the source and destination CIDs higher *thanVMADDR_CID_HOST,thenavsockchannelwhereallthepacketsare *forwardedtothehostshouldbeestablished.Thenthehostwill *needtoforwardthepacketstotheguest. * *Theflagissetonthe(listen)receivepath(pskisnotNULL).On *theconnectpaththeflagcanbesetbytheuserspaceapplication.
*/ if (psk && vsk->local_addr.svm_cid > VMADDR_CID_HOST &&
vsk->remote_addr.svm_cid > VMADDR_CID_HOST)
vsk->remote_addr.svm_flags |= VMADDR_FLAG_TO_HOST;
remote_flags = vsk->remote_addr.svm_flags;
mutex_lock(&vsock_register_mutex);
switch (sk->sk_type) { case SOCK_DGRAM:
new_transport = transport_dgram; break; case SOCK_STREAM: case SOCK_SEQPACKET: if (vsock_use_local_transport(remote_cid))
new_transport = transport_local; elseif (remote_cid <= VMADDR_CID_HOST || !transport_h2g ||
(remote_flags & VMADDR_FLAG_TO_HOST))
new_transport = transport_g2h; else
new_transport = transport_h2g; break; default:
ret = -ESOCKTNOSUPPORT; goto err;
}
if (vsk->transport && vsk->transport == new_transport) {
ret = 0; goto err;
}
/* We increase the module refcnt to prevent the transport unloading *whilethereareopensocketsassignedtoit.
*/ if (!new_transport || !try_module_get(new_transport->module)) {
ret = -ENODEV; goto err;
}
/* It's safe to release the mutex after a successful try_module_get(). *Whichevertransport`new_transport`pointsat,itwon'tgoawayuntil *thelastmodule_put()beloworinvsock_deassign_transport().
*/
mutex_unlock(&vsock_register_mutex);
if (vsk->transport) { /* transport->release() must be called with sock lock acquired. *Thispathcanonlybetakenduringvsock_connect(),wherewe *havealreadyheldthesocklock.Intheothercases,this *functioniscalledonanewsocketwhichisnotassignedto *anytransport.
*/
vsk->transport->release(vsk);
vsock_deassign_transport(vsk);
/* transport's release() and destruct() can touch some socket *state,sincewearereassigningthesockettoanewtransport *duringvsock_connect(),let'sresetthesefieldstohavea *cleanstate.
*/
sock_reset_flag(sk, SOCK_DONE);
sk->sk_state = TCP_CLOSE;
vsk->peer_shutdown = 0;
}
if (sk->sk_type == SOCK_SEQPACKET) { if (!new_transport->seqpacket_allow ||
!new_transport->seqpacket_allow(remote_cid)) {
module_put(new_transport->module); return -ESOCKTNOSUPPORT;
}
}
ret = new_transport->init(vsk, psk); if (ret) {
module_put(new_transport->module); return ret;
}
list_del_init(&vconnected->accept_queue);
sock_put(listener); /* The caller will need a reference on the connected socket so we let *itcallsock_put().
*/
if (vsock_is_pending(sk)) {
vsock_remove_pending(listener, sk);
sk_acceptq_removed(listener);
} elseif (!vsk->rejected) { /* We are not on the pending list and accept() did not reject *us,sowemusthavebeenacceptedbyouruserprocess.We *justneedtodropourreferencestothesocketsandbeon *ourway.
*/
cleanup = false; goto out;
}
/* We need to remove ourself from the global connected sockets list so *incomingpacketscan'tfindthissocket,andtoreducethereference *count.
*/
vsock_remove_connected(vsk);
sk->sk_state = TCP_CLOSE;
out:
release_sock(sk);
release_sock(listener); if (cleanup)
sock_put(sk);
if (addr->svm_port == VMADDR_PORT_ANY) { bool found = false; unsignedint i;
for (i = 0; i < MAX_PORT_RETRIES; i++) { if (port == VMADDR_PORT_ANY ||
port <= LAST_RESERVED_PORT)
port = LAST_RESERVED_PORT + 1;
new_addr.svm_port = port++;
if (!__vsock_find_bound_socket(&new_addr)) {
found = true; break;
}
}
if (!found) return -EADDRNOTAVAIL;
} else { /* If port is in reserved range, ensure caller *hasnecessaryprivileges.
*/ if (addr->svm_port <= LAST_RESERVED_PORT &&
!capable(CAP_NET_BIND_SERVICE)) { return -EACCES;
}
if (__vsock_find_bound_socket(&new_addr)) return -EADDRINUSE;
}
/* Remove connection oriented sockets from the unbound list and add them *tothehashtableforeasylookupbyitsaddress.Theunboundlist *issimplyanextraentryattheendofthehashtable,atrickused *byAF_UNIX.
*/
__vsock_remove_bound(vsk);
__vsock_insert_bound(vsock_bound_sockets(&vsk->local_addr), vsk);
/* First ensure this socket isn't already bound. */ if (vsock_addr_bound(&vsk->local_addr)) return -EINVAL;
/* Now bind to the provided address or select appropriate values if *noneareprovided(VMADDR_CID_ANYandVMADDR_PORT_ANY).Notethat *likeAF_INETpreventsbindingtoanon-localIPaddress(inmost *cases),weonlyallowbindingtoalocalCID.
*/ if (addr->svm_cid != VMADDR_CID_ANY && !vsock_find_cid(addr->svm_cid)) return -EADDRNOTAVAIL;
switch (sk->sk_socket->type) { case SOCK_STREAM: case SOCK_SEQPACKET:
spin_lock_bh(&vsock_table_lock);
retval = __vsock_bind_connectible(vsk, addr);
spin_unlock_bh(&vsock_table_lock); break;
case SOCK_DGRAM:
retval = __vsock_bind_dgram(vsk, addr); break;
sk = sk_alloc(net, AF_VSOCK, priority, &vsock_proto, kern); if (!sk) return NULL;
sock_init_data(sock, sk);
/* sk->sk_type is normally set in sock_init_data, but only if sock is *non-NULL.Wemakesurethatoursocketsalwayshaveatypeby *settingithereifneeded.
*/ if (!sock)
sk->sk_type = type;
/* When "level" is SINGLE_DEPTH_NESTING, use the nested *versiontoavoidthewarning"possiblerecursivelocking *detected".When"level"is0,lock_sock_nested(sk,level) *isthesameaslock_sock(sk).
*/
lock_sock_nested(sk, level);
/* Indicate to vsock_remove_sock() that the socket is being released and *canberemovedfromthebound_table.Unliketransportreassignment *case,wherethesocketmustremainbounddespitevsock_remove_sock() *beingcalledfromthetransportrelease()callback.
*/
sock_set_flag(sk, SOCK_DEAD);
if (vsk->transport)
vsk->transport->release(vsk); elseif (sock_type_connectible(sk->sk_type))
vsock_remove_sock(vsk);
sock_orphan(sk);
sk->sk_shutdown = SHUTDOWN_MASK;
skb_queue_purge(&sk->sk_receive_queue);
/* Clean up any sockets that never were accepted. */ while ((pending = vsock_dequeue_accept(sk)) != NULL) {
__vsock_release(pending, SINGLE_DEPTH_NESTING);
sock_put(pending);
}
/* When clearing these addresses, there's no need to set the family and *possiblyregistertheaddressfamilywiththekernel.
*/
vsock_addr_init(&vsk->local_addr, VMADDR_CID_ANY, VMADDR_PORT_ANY);
vsock_addr_init(&vsk->remote_addr, VMADDR_CID_ANY, VMADDR_PORT_ANY);
put_cred(vsk->owner);
}
staticint vsock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
{ int err;
err = sock_queue_rcv_skb(sk, skb); if (err)
kfree_skb(skb);
timeout = sk->sk_lingertime; if (!timeout) return;
/* Transports must implement `unsent_bytes` if they want to support *SOCK_LINGERthrough`vsock_linger()`sinceweuseittocheckwhen *thesocketcanbeclosed.
*/
unsent = vsk->transport->unsent_bytes; if (!unsent) return;
add_wait_queue(sk_sleep(sk), &wait);
do { if (sk_wait_event(sk, &timeout, unsent(vsk) == 0, &wait)) break;
} while (!signal_pending(current) && timeout);
staticint vsock_shutdown(struct socket *sock, int mode)
{ int err; struct sock *sk;
/* User level uses SHUT_RD (0) and SHUT_WR (1), but the kernel uses *RCV_SHUTDOWN(1)andSEND_SHUTDOWN(2),sowemustincrementmode *hereliketheotheraddressfamiliesdo.Notealsothatthe *incrementmakesSHUT_RDWR(2)intoRCV_SHUTDOWN|SEND_SHUTDOWN(3), *whichiswhatwewant.
*/
mode++;
if ((mode & ~SHUTDOWN_MASK) || !mode) return -EINVAL;
/* If this is a connection oriented socket and it is not connected then *bailoutimmediately.IfitisaDGRAMsocketthenwemustfirst *kickthesocketsothatitwakesupfromanysleepingcalls,for *examplerecv(),andthenafterwardsreturntheerror.
*/
if (sk_is_readable(sk))
mask |= EPOLLIN | EPOLLRDNORM;
if (sock->type == SOCK_DGRAM) { /* For datagram sockets we can read if there is something in *thequeueandwriteaslongasthesocketisn'tshutdownfor *sending.
*/ if (!skb_queue_empty_lockless(&sk->sk_receive_queue) ||
(sk->sk_shutdown & RCV_SHUTDOWN)) {
mask |= EPOLLIN | EPOLLRDNORM;
}
/* Listening sockets that have connections in their accept *queuecanberead.
*/ if (sk->sk_state == TCP_LISTEN
&& !vsock_is_accept_queue_empty(sk))
mask |= EPOLLIN | EPOLLRDNORM;
/* If there is something in the queue then we can read. */ if (transport && transport->stream_is_active(vsk) &&
!(sk->sk_shutdown & RCV_SHUTDOWN)) { bool data_ready_now = false; int target = sock_rcvlowat(sk, 0, INT_MAX); int ret = transport->notify_poll_in(
vsk, target, &data_ready_now); if (ret < 0) {
mask |= EPOLLERR;
} else { if (data_ready_now)
mask |= EPOLLIN | EPOLLRDNORM;
}
}
/* Sockets whose connections have been closed, reset, or *terminatedshouldalsobeconsideredread,andwecheckthe *shutdownflagforthat.
*/ if (sk->sk_shutdown & RCV_SHUTDOWN ||
vsk->peer_shutdown & SEND_SHUTDOWN) {
mask |= EPOLLIN | EPOLLRDNORM;
}
/* Connected sockets that can produce data can be written. */ if (transport && sk->sk_state == TCP_ESTABLISHED) { if (!(sk->sk_shutdown & SEND_SHUTDOWN)) { bool space_avail_now = false; int ret = transport->notify_poll_out(
vsk, 1, &space_avail_now); if (ret < 0) {
mask |= EPOLLERR;
} else { if (space_avail_now) /* Remove EPOLLWRBAND since INET *socketsarenotsettingit.
*/
mask |= EPOLLOUT | EPOLLWRNORM;
}
}
}
/* Simulate INET socket poll behaviors, which sets *EPOLLOUT|EPOLLWRNORMwhenpeerisclosedandnothingtoread, *butlocalsendisnotshutdown.
*/ if (sk->sk_state == TCP_CLOSE || sk->sk_state == TCP_CLOSING) { if (!(sk->sk_shutdown & SEND_SHUTDOWN))
mask |= EPOLLOUT | EPOLLWRNORM;
/* For now, MSG_DONTWAIT is always assumed... */
err = 0;
sk = sock->sk;
vsk = vsock_sk(sk);
lock_sock(sk);
transport = vsk->transport;
err = vsock_auto_bind(vsk); if (err) goto out;
/* If the provided message contains an address, use that. Otherwise *fallbackonthesocket'sremotehandle(ifithasbeenconnected).
*/ if (msg->msg_name &&
vsock_addr_cast(msg->msg_name, msg->msg_namelen,
&remote_addr) == 0) { /* Ensure this address is of the right type and is a valid *destination.
*/
if (remote_addr->svm_cid == VMADDR_CID_ANY)
remote_addr->svm_cid = transport->get_local_cid();
if (remote_addr->svm_cid == VMADDR_CID_ANY)
remote_addr->svm_cid = transport->get_local_cid();
/* XXX Should connect() or this function ensure remote_addr is *bound?
*/ if (!vsock_addr_bound(&vsk->remote_addr)) {
err = -EINVAL; goto out;
}
} else {
err = -EINVAL; goto out;
}
if (!transport->dgram_allow(remote_addr->svm_cid,
remote_addr->svm_port)) {
err = -EINVAL; goto out;
}
staticint vsock_connect(struct socket *sock, struct sockaddr *addr, int addr_len, int flags)
{ int err; struct sock *sk; struct vsock_sock *vsk; conststruct vsock_transport *transport; struct sockaddr_vm *remote_addr; long timeout;
DEFINE_WAIT(wait);
err = 0;
sk = sock->sk;
vsk = vsock_sk(sk);
lock_sock(sk);
/* XXX AF_UNSPEC should make us disconnect like AF_INET. */ switch (sock->state) { case SS_CONNECTED:
err = -EISCONN; goto out; case SS_DISCONNECTING:
err = -EINVAL; goto out; case SS_CONNECTING: /* This continues on so we can move sock into the SS_CONNECTED *stateoncetheconnectionhascompleted(atwhichpointerr *willbesettozeroalso).Otherwise,wewilleitherwait *fortheconnectionorreturn-EALREADYshouldthisbea *non-blockingcall.
*/
err = -EALREADY; if (flags & O_NONBLOCK) goto out; break; default: if ((sk->sk_state == TCP_LISTEN) ||
vsock_addr_cast(addr, addr_len, &remote_addr) != 0) {
err = -EINVAL; goto out;
}
/* Set the remote address that we are connecting to. */
memcpy(&vsk->remote_addr, remote_addr, sizeof(vsk->remote_addr));
err = vsock_assign_transport(vsk, NULL); if (err) goto out;
transport = vsk->transport;
/* The hypervisor and well-known contexts do not have socket *endpoints.
*/ if (!transport ||
!transport->stream_allow(remote_addr->svm_cid,
remote_addr->svm_port)) {
err = -ENETUNREACH; goto out;
}
if (vsock_msgzerocopy_allow(transport)) {
set_bit(SOCK_SUPPORT_ZC, &sk->sk_socket->flags);
} elseif (sock_flag(sk, SOCK_ZEROCOPY)) { /* If this option was set before 'connect()', *whentransportwasunknown,checkthatthis *featureissupportedhere.
*/
err = -EOPNOTSUPP; goto out;
}
err = vsock_auto_bind(vsk); if (err) goto out;
sk->sk_state = TCP_SYN_SENT;
err = transport->connect(vsk); if (err < 0) goto out;
/* sk_err might have been set as a result of an earlier *(failed)connectattempt.
*/
sk->sk_err = 0;
/* Mark sock as connecting and set the error code to in *progressincasethisisanon-blockingconnect.
*/
sock->state = SS_CONNECTING;
err = -EINPROGRESS;
}
/* The receive path will handle all communication until we are able to *entertheconnectedstate.Herewewaitfortheconnectiontobe *completedoranotificationofanerror.
*/
timeout = vsk->connect_timeout;
prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
/* If the socket is already closing or it is in an error state, there *isnopointinwaiting.
*/ while (sk->sk_state != TCP_ESTABLISHED &&
sk->sk_state != TCP_CLOSING && sk->sk_err == 0) { if (flags & O_NONBLOCK) { /* If we're not going to block, we schedule a timeout *functiontogenerateatimeoutontheconnection *attempt,incasethepeerdoesn'trespondina *timelymanner.Weholdontothesocketuntilthe *timeoutfires.
*/
sock_hold(sk);
/* If the timeout function is already scheduled, *rescheduleit,thenungrabthesocketrefcountto *keepitbalanced.
*/ if (mod_delayed_work(system_wq, &vsk->connect_work,
timeout))
sock_put(sk);
/* Skip ahead to preserve error code set above. */ goto out_wait;
}
/* Wait for children sockets to appear; these are the new sockets *createduponconnectionestablishment.
*/
timeout = sock_rcvtimeo(listener, arg->flags & O_NONBLOCK);
prepare_to_wait(sk_sleep(listener), &wait, TASK_INTERRUPTIBLE);
/* If the listener socket has received an error, then we should *rejectthissocketandreturn.Notethatwesimplymarkthe *socketrejected,dropourreference,andletthecleanup *functionhandlethecleanup;thefactthatwefounditin *thelistener'sacceptqueueguaranteesthatthecleanup *functionhasn'trunyet.
*/ if (err) {
vconnected->rejected = true;
} else {
newsock->state = SS_CONNECTED;
sock_graft(connected, newsock); if (vsock_msgzerocopy_allow(vconnected->transport))
set_bit(SOCK_SUPPORT_ZC,
&connected->sk_socket->flags);
}
release_sock(connected);
sock_put(connected);
}
out:
release_sock(listener); return err;
}
staticint vsock_listen(struct socket *sock, int backlog)
{ int err; struct sock *sk; struct vsock_sock *vsk;
sk = sock->sk;
lock_sock(sk);
if (!sock_type_connectible(sk->sk_type)) {
err = -EOPNOTSUPP; goto out;
}
/* Callers should not provide a destination with connection oriented *sockets.
*/ if (msg->msg_namelen) {
err = sk->sk_state == TCP_ESTABLISHED ? -EISCONN : -EOPNOTSUPP; goto out;
}
/* Send data only if both sides are not shutdown in the direction. */ if (sk->sk_shutdown & SEND_SHUTDOWN ||
vsk->peer_shutdown & RCV_SHUTDOWN) {
err = -EPIPE; goto out;
}
/* These checks occur both as part of and after the loop *conditionalsinceweneedtocheckbeforeandafter *sleeping.
*/ if (sk->sk_err) {
err = -sk->sk_err; goto out_err;
} elseif ((sk->sk_shutdown & SEND_SHUTDOWN) ||
(vsk->peer_shutdown & RCV_SHUTDOWN)) {
err = -EPIPE; goto out_err;
}
err = transport->notify_send_pre_enqueue(vsk, &send_data); if (err < 0) goto out_err;
/* Note that enqueue will only write as many bytes as are free *intheproducequeue,sowedon'tneedtoensurelenis *smallerthanthequeuesize.Itisthecaller's *responsibilitytocheckhowmanybyteswewereabletosend.
*/
if (sk->sk_type == SOCK_SEQPACKET) {
written = transport->seqpacket_enqueue(vsk,
msg, len - total_written);
} else {
written = transport->stream_enqueue(vsk,
msg, len - total_written);
}
/* Internal transport error when checking for available *data.XXXThisshouldbechangedtoaconnection *resetinalaterchange.
*/ if (data < 0) return -ENOMEM;
return data;
}
staticint __vsock_stream_recvmsg(struct sock *sk, struct msghdr *msg,
size_t len, int flags)
{ struct vsock_transport_recv_notify_data recv_data; conststruct vsock_transport *transport; struct vsock_sock *vsk;
ssize_t copied;
size_t target; long timeout; int err;
DEFINE_WAIT(wait);
vsk = vsock_sk(sk);
transport = vsk->transport;
/* We must not copy less than target bytes into the user's buffer *beforereturningsuccessfully,sowewaitfortheconsumequeueto *havethatmuchdatatoconsumebeforedequeueing.Notethatthis *makesitimpossibletohandlecaseswheretargetisgreaterthanthe *queuesize.
*/
target = sock_rcvlowat(sk, flags & MSG_WAITALL, len); if (target >= transport->stream_rcvhiwat(vsk)) {
err = -ENOMEM; goto out;
}
timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
copied = 0;
if (sk->sk_err) {
err = -sk->sk_err;
} elseif (sk->sk_shutdown & RCV_SHUTDOWN) {
err = 0;
} else { /* User sets MSG_TRUNC, so return real length of *packet.
*/ if (flags & MSG_TRUNC)
err = msg_len; else
err = len - msg_data_left(msg);
/* Always set MSG_TRUNC if real length of packet is *biggerthanuser'sbuffer.
*/ if (msg_len > len)
msg->msg_flags |= MSG_TRUNC;
}
out: return err;
}
int
__vsock_connectible_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, int flags)
{ struct sock *sk; struct vsock_sock *vsk; conststruct vsock_transport *transport; int err;
sk = sock->sk;
if (unlikely(flags & MSG_ERRQUEUE)) return sock_recv_errqueue(sk, msg, len, SOL_VSOCK, VSOCK_RECVERR);
vsk = vsock_sk(sk);
err = 0;
lock_sock(sk);
transport = vsk->transport;
if (!transport || sk->sk_state != TCP_ESTABLISHED) { /* Recvmsg is supposed to return 0 if a peer performs an *orderlyshutdown.Differentiatebetweenthatcaseandwhena *peerhasnotconnectedoralocalshutdownoccurredwiththe *SOCK_DONEflag.
*/ if (sock_flag(sk, SOCK_DONE))
err = 0; else
err = -ENOTCONN;
/* We don't check peer_shutdown flag here since peer may actually shut *down,buttherecanbedatainthequeuethatalocalsocketcan *receive.
*/ if (sk->sk_shutdown & RCV_SHUTDOWN) {
err = 0; goto out;
}
/* It is valid on Linux to pass in a zero-length receive buffer. This *isnotanerror.Wemayaswellbailoutnow.
*/ if (!len) {
err = 0; goto out;
}
staticint vsock_create(struct net *net, struct socket *sock, int protocol, int kern)
{ struct vsock_sock *vsk; struct sock *sk; int ret;
if (!sock) return -EINVAL;
if (protocol && protocol != PF_VSOCK) return -EPROTONOSUPPORT;
switch (sock->type) { case SOCK_DGRAM:
sock->ops = &vsock_dgram_ops; break; case SOCK_STREAM:
sock->ops = &vsock_stream_ops; break; case SOCK_SEQPACKET:
sock->ops = &vsock_seqpacket_ops; break; default: return -ESOCKTNOSUPPORT;
}
sock->state = SS_UNCONNECTED;
sk = __vsock_create(net, sock, NULL, GFP_KERNEL, 0, kern); if (!sk) return -ENOMEM;
vsk = vsock_sk(sk);
if (sock->type == SOCK_DGRAM) {
ret = vsock_assign_transport(vsk, NULL); if (ret < 0) {
sock->sk = NULL;
sock_put(sk); return ret;
}
}
/* SOCK_DGRAM doesn't have 'setsockopt' callback set in its *proto_ops,sothereisnohandlerforcustomlogic.
*/ if (sock_type_connectible(sock->type))
set_bit(SOCK_CUSTOM_SOCKOPT, &sk->sk_socket->flags);
switch (cmd) { case IOCTL_VM_SOCKETS_GET_LOCAL_CID: /* To be compatible with the VMCI behavior, we prioritize the *guestCIDinsteadofwell-knowhostCID(VMADDR_CID_HOST).
*/
cid = vsock_registered_transport_cid(&transport_g2h); if (cid == VMADDR_CID_ANY)
cid = vsock_registered_transport_cid(&transport_h2g); if (cid == VMADDR_CID_ANY)
cid = vsock_registered_transport_cid(&transport_local);
if (put_user(cid, p) != 0)
retval = -EFAULT; break;
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.55Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.