static void iplink_get_mtu_srv(iplink_srv_t *srv, ipc_callid_t callid, ipc_call_t *call) { int rc; size_t mtu; rc = srv->ops->get_mtu(srv, &mtu); async_answer_1(callid, rc, mtu); }
void remote_audio_mixer_get_item_level( ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call) { audio_mixer_iface_t *mixer_iface = iface; if (!mixer_iface->get_item_level) { async_answer_0(callid, ENOTSUP); return; } const unsigned item = DEV_IPC_GET_ARG1(*call); unsigned current = 0; const int ret = mixer_iface->get_item_level(fun, item, ¤t); async_answer_1(callid, ret, current); }
void remote_config_space_read_32(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call) { assert(iface); pci_dev_iface_t *pci_iface = (pci_dev_iface_t *)iface; if (pci_iface->config_space_read_32 == NULL) { async_answer_0(callid, ENOTSUP); return; } uint32_t address = DEV_IPC_GET_ARG1(*call); uint32_t value; int ret = pci_iface->config_space_read_32(fun, address, &value); if (ret != EOK) { async_answer_0(callid, ret); } else { async_answer_1(callid, EOK, value); } }
static void remote_ahci_get_block_size(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call) { const ahci_iface_t *ahci_iface = (ahci_iface_t *) iface; if (ahci_iface->get_block_size == NULL) { async_answer_0(callid, ENOTSUP); return; } size_t blocks; const int ret = ahci_iface->get_block_size(fun, &blocks); if (ret != EOK) async_answer_0(callid, ret); else async_answer_1(callid, EOK, blocks); }
/** Process the battery_charge_level_get() request from the remote client * * @param fun The function from which the battery charge level is read * @param ops The local ops structure * */ static void remote_battery_charge_level_get(ddf_fun_t *fun, void *ops, ipc_callid_t callid, ipc_call_t *call) { const battery_dev_ops_t *bops = (battery_dev_ops_t *) ops; if (bops->battery_charge_level_get == NULL) { async_answer_0(callid, ENOTSUP); return; } int battery_level; const int rc = bops->battery_charge_level_get(fun, &battery_level); if (rc != EOK) async_answer_0(callid, rc); else async_answer_1(callid, rc, battery_level); }
/** Process the write request from the remote client. * * Receive the write request's parameters from the remote client and pass them * to the local interface. Return the result of the operation processed by the * local interface to the remote client. * * @param fun The function to which the data are written. * @param ops The local ops structure. */ static void remote_char_write(ddf_fun_t *fun, void *ops, ipc_callid_t callid, ipc_call_t *call) { char_dev_ops_t *char_dev_ops = (char_dev_ops_t *) ops; ipc_callid_t cid; size_t len; if (!async_data_write_receive(&cid, &len)) { /* TODO handle protocol error. */ async_answer_0(callid, EINVAL); return; } if (!char_dev_ops->write) { async_data_write_finalize(cid, NULL, 0); async_answer_0(callid, ENOTSUP); return; } if (len > MAX_CHAR_RW_COUNT) len = MAX_CHAR_RW_COUNT; char buf[MAX_CHAR_RW_COUNT]; async_data_write_finalize(cid, buf, len); int ret = (*char_dev_ops->write)(fun, buf, len); if (ret < 0) { /* Some error occured. */ async_answer_0(callid, ret); } else { /* * The operation was successful, return the number of data * written. */ async_answer_1(callid, EOK, ret); } }
/** Handle VHC request for device name. * * @param dev Target virtual device. * @param iid Caller id. * @param icall The call with the request. */ static void ipc_get_name(usbvirt_device_t *dev, ipc_callid_t iid, ipc_call_t *icall) { if (dev->name == NULL) { async_answer_0(iid, ENOENT); } size_t size = str_size(dev->name); ipc_callid_t callid; size_t accepted_size; if (!async_data_read_receive(&callid, &accepted_size)) { async_answer_0(iid, EINVAL); return; } if (accepted_size > size) { accepted_size = size; } async_data_read_finalize(callid, dev->name, accepted_size); async_answer_1(iid, EOK, accepted_size); }
/** VFS_REGISTER protocol function. * * @param rid Hash of the call with the request. * @param request Call structure with the request. * */ void vfs_register(ipc_callid_t rid, ipc_call_t *request) { dprintf("Processing VFS_REGISTER request received from %p.\n", request->in_phone_hash); vfs_info_t *vfs_info; int rc = async_data_write_accept((void **) &vfs_info, false, sizeof(vfs_info_t), sizeof(vfs_info_t), 0, NULL); if (rc != EOK) { dprintf("Failed to deliver the VFS info into our AS, rc=%d.\n", rc); async_answer_0(rid, rc); return; } /* * Allocate and initialize a buffer for the fs_info structure. */ fs_info_t *fs_info = (fs_info_t *) malloc(sizeof(fs_info_t)); if (!fs_info) { dprintf("Could not allocate memory for FS info.\n"); async_answer_0(rid, ENOMEM); return; } link_initialize(&fs_info->fs_link); fs_info->vfs_info = *vfs_info; free(vfs_info); dprintf("VFS info delivered.\n"); if (!vfs_info_sane(&fs_info->vfs_info)) { free(fs_info); async_answer_0(rid, EINVAL); return; } fibril_mutex_lock(&fs_list_lock); /* * Check for duplicit registrations. */ if (fs_name_to_handle(fs_info->vfs_info.instance, fs_info->vfs_info.name, false)) { /* * We already register a fs like this. */ dprintf("FS is already registered.\n"); fibril_mutex_unlock(&fs_list_lock); free(fs_info); async_answer_0(rid, EEXISTS); return; } /* * Add fs_info to the list of registered FS's. */ dprintf("Inserting FS into the list of registered file systems.\n"); list_append(&fs_info->fs_link, &fs_list); /* * Now we want the client to send us the IPC_M_CONNECT_TO_ME call so * that a callback connection is created and we have a phone through * which to forward VFS requests to it. */ fs_info->sess = async_callback_receive(EXCHANGE_PARALLEL); if (!fs_info->sess) { dprintf("Callback connection expected\n"); list_remove(&fs_info->fs_link); fibril_mutex_unlock(&fs_list_lock); free(fs_info); async_answer_0(rid, EINVAL); return; } dprintf("Callback connection to FS created.\n"); /* * The client will want us to send him the address space area with PLB. */ size_t size; ipc_callid_t callid; if (!async_share_in_receive(&callid, &size)) { dprintf("Unexpected call, method = %d\n", IPC_GET_IMETHOD(call)); list_remove(&fs_info->fs_link); fibril_mutex_unlock(&fs_list_lock); async_hangup(fs_info->sess); free(fs_info); async_answer_0(callid, EINVAL); async_answer_0(rid, EINVAL); return; } /* * We can only send the client address space area PLB_SIZE bytes long. */ if (size != PLB_SIZE) { dprintf("Client suggests wrong size of PFB, size = %d\n", size); list_remove(&fs_info->fs_link); fibril_mutex_unlock(&fs_list_lock); async_hangup(fs_info->sess); free(fs_info); async_answer_0(callid, EINVAL); async_answer_0(rid, EINVAL); return; } /* * Commit to read-only sharing the PLB with the client. */ (void) async_share_in_finalize(callid, plb, AS_AREA_READ | AS_AREA_CACHEABLE); dprintf("Sharing PLB.\n"); /* * That was it. The FS has been registered. * In reply to the VFS_REGISTER request, we assign the client file * system a global file system handle. */ fs_info->fs_handle = (fs_handle_t) atomic_postinc(&fs_handle_next); async_answer_1(rid, EOK, (sysarg_t) fs_info->fs_handle); fibril_condvar_broadcast(&fs_list_cv); fibril_mutex_unlock(&fs_list_lock); dprintf("\"%.*s\" filesystem successfully registered, handle=%d.\n", FS_NAME_MAXLEN, fs_info->vfs_info.name, fs_info->fs_handle); }
static void file_bd_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg) { void *fs_va = NULL; ipc_callid_t callid; ipc_call_t call; sysarg_t method; size_t comm_size; unsigned int flags; int retval; uint64_t ba; size_t cnt; /* Answer the IPC_M_CONNECT_ME_TO call. */ async_answer_0(iid, EOK); if (!async_share_out_receive(&callid, &comm_size, &flags)) { async_answer_0(callid, EHANGUP); return; } (void) async_share_out_finalize(callid, &fs_va); if (fs_va == AS_MAP_FAILED) { async_answer_0(callid, EHANGUP); return; } while (true) { callid = async_get_call(&call); method = IPC_GET_IMETHOD(call); if (!method) { /* The other side has hung up. */ async_answer_0(callid, EOK); return; } switch (method) { case BD_READ_BLOCKS: ba = MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call)); cnt = IPC_GET_ARG3(call); if (cnt * block_size > comm_size) { retval = ELIMIT; break; } retval = file_bd_read_blocks(ba, cnt, fs_va); break; case BD_WRITE_BLOCKS: ba = MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call)); cnt = IPC_GET_ARG3(call); if (cnt * block_size > comm_size) { retval = ELIMIT; break; } retval = file_bd_write_blocks(ba, cnt, fs_va); break; case BD_GET_BLOCK_SIZE: async_answer_1(callid, EOK, block_size); continue; case BD_GET_NUM_BLOCKS: async_answer_2(callid, EOK, LOWER32(num_blocks), UPPER32(num_blocks)); continue; default: retval = EINVAL; break; } async_answer_0(callid, retval); } }
static void tcp_sock_recvfrom(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call) { int socket_id; int flags; size_t addr_length, length; socket_core_t *sock_core; tcp_sockdata_t *socket; ipc_call_t answer; ipc_callid_t rcallid; size_t data_len; struct sockaddr_in addr; tcp_sock_t *rsock; int rc; log_msg(LVL_DEBUG, "%p: tcp_sock_recv[from]()", client); socket_id = SOCKET_GET_SOCKET_ID(call); flags = SOCKET_GET_FLAGS(call); sock_core = socket_cores_find(&client->sockets, socket_id); if (sock_core == NULL) { async_answer_0(callid, ENOTSOCK); return; } socket = (tcp_sockdata_t *)sock_core->specific_data; fibril_mutex_lock(&socket->lock); if (socket->conn == NULL) { fibril_mutex_unlock(&socket->lock); async_answer_0(callid, ENOTCONN); return; } (void)flags; log_msg(LVL_DEBUG, "tcp_sock_recvfrom(): lock recv_buffer_lock"); fibril_mutex_lock(&socket->recv_buffer_lock); while (socket->recv_buffer_used == 0 && socket->recv_error == TCP_EOK) { log_msg(LVL_DEBUG, "wait for recv_buffer_cv + recv_buffer_used != 0"); fibril_condvar_wait(&socket->recv_buffer_cv, &socket->recv_buffer_lock); } log_msg(LVL_DEBUG, "Got data in sock recv_buffer"); data_len = socket->recv_buffer_used; rc = socket->recv_error; switch (socket->recv_error) { case TCP_EOK: rc = EOK; break; case TCP_ENOTEXIST: case TCP_ECLOSING: rc = ENOTCONN; break; case TCP_ERESET: rc = ECONNABORTED; break; default: assert(false); } log_msg(LVL_DEBUG, "**** recv result -> %d", rc); if (rc != EOK) { fibril_mutex_unlock(&socket->recv_buffer_lock); fibril_mutex_unlock(&socket->lock); async_answer_0(callid, rc); return; } if (IPC_GET_IMETHOD(call) == NET_SOCKET_RECVFROM) { /* Fill addr */ rsock = &socket->conn->ident.foreign; addr.sin_family = AF_INET; addr.sin_addr.s_addr = host2uint32_t_be(rsock->addr.ipv4); addr.sin_port = host2uint16_t_be(rsock->port); log_msg(LVL_DEBUG, "addr read receive"); if (!async_data_read_receive(&rcallid, &addr_length)) { fibril_mutex_unlock(&socket->recv_buffer_lock); fibril_mutex_unlock(&socket->lock); async_answer_0(callid, EINVAL); return; } if (addr_length > sizeof(addr)) addr_length = sizeof(addr); log_msg(LVL_DEBUG, "addr read finalize"); rc = async_data_read_finalize(rcallid, &addr, addr_length); if (rc != EOK) { fibril_mutex_unlock(&socket->recv_buffer_lock); fibril_mutex_unlock(&socket->lock); async_answer_0(callid, EINVAL); return; } } log_msg(LVL_DEBUG, "data read receive"); if (!async_data_read_receive(&rcallid, &length)) { fibril_mutex_unlock(&socket->recv_buffer_lock); fibril_mutex_unlock(&socket->lock); async_answer_0(callid, EINVAL); return; } if (length > data_len) length = data_len; log_msg(LVL_DEBUG, "data read finalize"); rc = async_data_read_finalize(rcallid, socket->recv_buffer, length); socket->recv_buffer_used -= length; log_msg(LVL_DEBUG, "tcp_sock_recvfrom: %zu left in buffer", socket->recv_buffer_used); if (socket->recv_buffer_used > 0) { memmove(socket->recv_buffer, socket->recv_buffer + length, socket->recv_buffer_used); tcp_sock_notify_data(socket->sock_core); } fibril_condvar_broadcast(&socket->recv_buffer_cv); if (length < data_len && rc == EOK) rc = EOVERFLOW; SOCKET_SET_READ_DATA_LENGTH(answer, length); async_answer_1(callid, EOK, IPC_GET_ARG1(answer)); fibril_mutex_unlock(&socket->recv_buffer_lock); fibril_mutex_unlock(&socket->lock); }
/** * Server side implementation of the hound protocol. IPC connection handler. * @param iid initial call id * @param icall pointer to initial call structure. * @param arg (unused) */ void hound_connection_handler(ipc_callid_t iid, ipc_call_t *icall, void *arg) { /* Accept connection if there is a valid iface*/ if (server_iface) { async_answer_0(iid, EOK); } else { async_answer_0(iid, ENOTSUP); return; } while (1) { ipc_call_t call; ipc_callid_t callid = async_get_call(&call); switch (IPC_GET_IMETHOD(call)) { case IPC_M_HOUND_CONTEXT_REGISTER: { /* check interface functions */ if (!server_iface || !server_iface->add_context) { async_answer_0(callid, ENOTSUP); break; } bool record = IPC_GET_ARG1(call); void *name; /* Get context name */ int ret = async_data_write_accept(&name, true, 0, 0, 0, 0); if (ret != EOK) { async_answer_0(callid, ret); break; } hound_context_id_t id = 0; ret = server_iface->add_context(server_iface->server, &id, name, record); /** new context should create a copy */ free(name); if (ret != EOK) { async_answer_0(callid, ret); } else { async_answer_1(callid, EOK, id); } break; } case IPC_M_HOUND_CONTEXT_UNREGISTER: { /* check interface functions */ if (!server_iface || !server_iface->rem_context) { async_answer_0(callid, ENOTSUP); break; } /* get id, 1st param */ hound_context_id_t id = IPC_GET_ARG1(call); const int ret = server_iface->rem_context(server_iface->server, id); async_answer_0(callid, ret); break; } case IPC_M_HOUND_GET_LIST: { /* check interface functions */ if (!server_iface || !server_iface->get_list) { async_answer_0(callid, ENOTSUP); break; } const char **list = NULL; const int flags = IPC_GET_ARG1(call); size_t count = IPC_GET_ARG2(call); const bool conn = IPC_GET_ARG3(call); char *conn_name = NULL; int ret = EOK; /* get connected actor name if provided */ if (conn) ret = async_data_write_accept( (void**)&conn_name, true, 0, 0, 0, 0); if (ret == EOK) ret = server_iface->get_list( server_iface->server, &list, &count, conn_name, flags); free(conn_name); /* Alloc string sizes array */ size_t *sizes = NULL; if (count) sizes = calloc(count, sizeof(size_t)); if (count && !sizes) ret = ENOMEM; async_answer_1(callid, ret, count); /* We are done */ if (count == 0 || ret != EOK) break; /* Prepare sizes table */ for (unsigned i = 0; i < count; ++i) sizes[i] = str_size(list[i]); /* Send sizes table */ ipc_callid_t id; if (async_data_read_receive(&id, NULL)) { ret = async_data_read_finalize(id, sizes, count * sizeof(size_t)); } free(sizes); /* Proceed to send names */ for (unsigned i = 0; i < count; ++i) { size_t size = str_size(list[i]); ipc_callid_t id; if (ret == EOK && async_data_read_receive(&id, NULL)) { ret = async_data_read_finalize(id, list[i], size); } free(list[i]); } free(list); break; } case IPC_M_HOUND_CONNECT: { /* check interface functions */ if (!server_iface || !server_iface->connect) { async_answer_0(callid, ENOTSUP); break; } void *source = NULL; void *sink = NULL; /* read source name */ int ret = async_data_write_accept(&source, true, 0, 0, 0, 0); /* read sink name */ if (ret == EOK) ret = async_data_write_accept(&sink, true, 0, 0, 0, 0); if (ret == EOK) ret = server_iface->connect( server_iface->server, source, sink); free(source); free(sink); async_answer_0(callid, ret); break; } case IPC_M_HOUND_DISCONNECT: { /* check interface functions */ if (!server_iface || !server_iface->disconnect) { async_answer_0(callid, ENOTSUP); break; } void *source = NULL; void *sink = NULL; /* read source name */ int ret = async_data_write_accept(&source, true, 0, 0, 0, 0); /*read sink name */ if (ret == EOK) ret = async_data_write_accept(&sink, true, 0, 0, 0, 0); if (ret == EOK) ret = server_iface->connect( server_iface->server, source, sink); free(source); free(sink); async_answer_0(callid, ret); break; } case IPC_M_HOUND_STREAM_ENTER: { /* check interface functions */ if (!server_iface || !server_iface->is_record_context || !server_iface->add_stream || !server_iface->rem_stream) { async_answer_0(callid, ENOTSUP); break; } /* get parameters */ hound_context_id_t id = IPC_GET_ARG1(call); const int flags = IPC_GET_ARG2(call); const format_convert_t c = {.arg = IPC_GET_ARG3(call)}; const pcm_format_t f = { .sampling_rate = c.f.rate * 100, .channels = c.f.channels, .sample_format = c.f.format, }; size_t bsize = IPC_GET_ARG4(call); void *stream; int ret = server_iface->add_stream(server_iface->server, id, flags, f, bsize, &stream); if (ret != EOK) { async_answer_0(callid, ret); break; } const bool rec = server_iface->is_record_context( server_iface->server, id); if (rec) { if(server_iface->stream_data_read) { async_answer_0(callid, EOK); /* start answering read calls */ hound_server_write_data(stream); server_iface->rem_stream( server_iface->server, stream); } else { async_answer_0(callid, ENOTSUP); } } else { if (server_iface->stream_data_write) { async_answer_0(callid, EOK); /* accept write calls */ hound_server_read_data(stream); server_iface->rem_stream( server_iface->server, stream); } else { async_answer_0(callid, ENOTSUP); } } break; } case IPC_M_HOUND_STREAM_EXIT: case IPC_M_HOUND_STREAM_DRAIN: /* Stream exit/drain is only allowed in stream context*/ async_answer_0(callid, EINVAL); break; default: async_answer_0(callid, ENOTSUP); return; } } } /** * Read data and push it to the stream. * @param stream target stream, will push data there. */ static void hound_server_read_data(void *stream) { ipc_callid_t callid; ipc_call_t call; size_t size = 0; int ret_answer = EOK; /* accept data write or drain */ while (async_data_write_receive_call(&callid, &call, &size) || (IPC_GET_IMETHOD(call) == IPC_M_HOUND_STREAM_DRAIN)) { /* check drain first */ if (IPC_GET_IMETHOD(call) == IPC_M_HOUND_STREAM_DRAIN) { int ret = ENOTSUP; if (server_iface->drain_stream) ret = server_iface->drain_stream(stream); async_answer_0(callid, ret); continue; } /* there was an error last time */ if (ret_answer != EOK) { async_answer_0(callid, ret_answer); continue; } char *buffer = malloc(size); if (!buffer) { async_answer_0(callid, ENOMEM); continue; } const int ret = async_data_write_finalize(callid, buffer, size); if (ret == EOK) { /* push data to stream */ ret_answer = server_iface->stream_data_write( stream, buffer, size); } } const int ret = IPC_GET_IMETHOD(call) == IPC_M_HOUND_STREAM_EXIT ? EOK : EINVAL; async_answer_0(callid, ret); }