Example #1
0
static void kbd_port_events(ipc_callid_t iid, ipc_call_t *icall, void *arg)
{
	/* Ignore parameters, the connection is already opened */
	while (true) {

		ipc_call_t call;
		ipc_callid_t callid = async_get_call(&call);

		int retval = EOK;
		
		if (!IPC_GET_IMETHOD(call)) {
			/* TODO: Handle hangup */
			return;
		}
		
		switch (IPC_GET_IMETHOD(call)) {
		case ADB_REG_NOTIF:
			adb_kbd_reg0_data(IPC_GET_ARG1(call));
			break;
		default:
			retval = ENOENT;
		}
		async_answer_0(callid, retval);
	}
}
Example #2
0
/** Handle one connection to APIC.
 *
 * @param iid   Hash of the request that opened the connection.
 * @param icall Call data of the request that opened the connection.
 * @param arg	Local argument.
 */
static void apic_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
{
	ipc_callid_t callid;
	ipc_call_t call;
	
	/*
	 * Answer the first IPC_M_CONNECT_ME_TO call.
	 */
	async_answer_0(iid, EOK);
	
	while (true) {
		callid = async_get_call(&call);
		
		if (!IPC_GET_IMETHOD(call)) {
			/* The other side has hung up. */
			async_answer_0(callid, EOK);
			return;
		}
		
		switch (IPC_GET_IMETHOD(call)) {
		case IRC_ENABLE_INTERRUPT:
			async_answer_0(callid, apic_enable_irq(IPC_GET_ARG1(call)));
			break;
		case IRC_CLEAR_INTERRUPT:
			/* Noop */
			async_answer_0(callid, EOK);
			break;
		default:
			async_answer_0(callid, EINVAL);
			break;
		}
	}
}
Example #3
0
static void loc_cb_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
{
	while (true) {
		ipc_call_t call;
		ipc_callid_t callid = async_get_call(&call);
		
		if (!IPC_GET_IMETHOD(call)) {
			/* TODO: Handle hangup */
			return;
		}
		
		switch (IPC_GET_IMETHOD(call)) {
		case LOC_EVENT_CAT_CHANGE:
			fibril_mutex_lock(&loc_callback_mutex);
			loc_cat_change_cb_t cb_fun = cat_change_cb;
			fibril_mutex_unlock(&loc_callback_mutex);
			
			async_answer_0(callid, EOK);
			
			if (cb_fun != NULL)
				(*cb_fun)();
			
			break;
		default:
			async_answer_0(callid, ENOTSUP);
		}
	}
}
Example #4
0
static void kbdev_callback_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
{
	kbdev_t *kbdev;
	int retval;
	int type, key;

	/* Kbdev device structure */
	kbdev = arg;

	while (true) {
		ipc_call_t call;
		ipc_callid_t callid;

		callid = async_get_call(&call);
		if (!IPC_GET_IMETHOD(call)) {
			kbdev_destroy(kbdev);
			return;
		}

		switch (IPC_GET_IMETHOD(call)) {
		case KBDEV_EVENT:
			/* Got event from keyboard device */
			retval = 0;
			type = IPC_GET_ARG1(call);
			key = IPC_GET_ARG2(call);
			kbd_push_event(kbdev->kbd_dev, type, key);
			break;
		default:
			retval = ENOTSUP;
			break;
		}

		async_answer_0(callid, retval);
	}
}
Example #5
0
/** Handle loader connection.
 *
 * Receive and carry out commands (of which the last one should be
 * to execute the loaded program).
 */
static void ldr_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
{
	/* Already have a connection? */
	if (connected) {
		async_answer_0(iid, ELIMIT);
		return;
	}
	
	connected = true;
	
	/* Accept the connection */
	async_answer_0(iid, EOK);
	
	/* Ignore parameters, the connection is already open */
	(void) icall;
	
	while (true) {
		int retval;
		ipc_call_t call;
		ipc_callid_t callid = async_get_call(&call);
		
		if (!IPC_GET_IMETHOD(call))
			exit(0);
		
		switch (IPC_GET_IMETHOD(call)) {
		case LOADER_GET_TASKID:
			ldr_get_taskid(callid, &call);
			continue;
		case LOADER_SET_CWD:
			ldr_set_cwd(callid, &call);
			continue;
		case LOADER_SET_PATHNAME:
			ldr_set_pathname(callid, &call);
			continue;
		case LOADER_SET_ARGS:
			ldr_set_args(callid, &call);
			continue;
		case LOADER_SET_FILES:
			ldr_set_files(callid, &call);
			continue;
		case LOADER_LOAD:
			ldr_load(callid, &call);
			continue;
		case LOADER_RUN:
			ldr_run(callid, &call);
			/* Not reached */
		default:
			retval = EINVAL;
			break;
		}
		
		async_answer_0(callid, retval);
	}
}
Example #6
0
/** Handle data requests.
 *
 * @param fun  ddf_fun_t function.
 * @param id   callid
 * @param call IPC request.
 *
 */
void default_handler(ddf_fun_t *fun, ipc_callid_t id, ipc_call_t *call)
{
    const sysarg_t method = IPC_GET_IMETHOD(*call);
    const size_t size = IPC_GET_ARG1(*call);

    switch (method) {
    case IPC_CHAR_READ:
        if (size <= 4 * sizeof(sysarg_t)) {
            sysarg_t message[4] = {};

            i8042_read(fun, (char *) message, size);
            async_answer_4(id, size, message[0], message[1],
                           message[2], message[3]);
        } else
            async_answer_0(id, ELIMIT);
        break;

    case IPC_CHAR_WRITE:
        if (size <= 3 * sizeof(sysarg_t)) {
            const sysarg_t message[3] = {
                IPC_GET_ARG2(*call),
                IPC_GET_ARG3(*call),
                IPC_GET_ARG4(*call)
            };

            i8042_write(fun, (char *) message, size);
            async_answer_0(id, size);
        } else
            async_answer_0(id, ELIMIT);

    default:
        async_answer_0(id, EINVAL);
    }
}
Example #7
0
/** Default handler for IPC methods not handled by DDF.
 *
 * @param fun     Device function handling the call.
 * @param icallid Call id.
 * @param icall   Call data.
 *
 */
static void default_connection_handler(ddf_fun_t *fun,
    ipc_callid_t icallid, ipc_call_t *icall)
{
	const sysarg_t method = IPC_GET_IMETHOD(*icall);
	xt_kbd_t *kbd = ddf_dev_data_get(ddf_fun_get_dev(fun));

	switch (method) {
	case KBDEV_SET_IND: {
		/*
		 * XT keyboards do not support setting mods,
		 * assume AT keyboard with Scan Code Set 1.
		 */
		const unsigned mods = IPC_GET_ARG1(*icall);
		const uint8_t status = 0 |
		    ((mods & KM_CAPS_LOCK) ? LI_CAPS : 0) |
		    ((mods & KM_NUM_LOCK) ? LI_NUM : 0) |
		    ((mods & KM_SCROLL_LOCK) ? LI_SCROLL : 0);
		uint8_t cmds[] = { KBD_CMD_SET_LEDS, status };
		
		async_exch_t *exch = async_exchange_begin(kbd->parent_sess);
		const ssize_t size = chardev_write(exch, cmds, sizeof(cmds));
		async_exchange_end(exch);
		
		async_answer_0(icallid, size < 0 ? size : EOK);
		break;
	}
	/*
	 * This might be ugly but async_callback_receive_start makes no
	 * difference for incorrect call and malloc failure.
	 */
	case IPC_M_CONNECT_TO_ME: {
		async_sess_t *sess =
		    async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
		
		/* Probably ENOMEM error, try again. */
		if (sess == NULL) {
			ddf_msg(LVL_WARN,
			    "Failed creating callback session");
			async_answer_0(icallid, EAGAIN);
			break;
		}
		
		if (kbd->client_sess == NULL) {
			kbd->client_sess = sess;
			ddf_msg(LVL_DEBUG, "Set client session");
			async_answer_0(icallid, EOK);
		} else {
			ddf_msg(LVL_ERROR, "Client session already set");
			async_answer_0(icallid, ELIMIT);
		}
		
		break;
	}
	default:
		ddf_msg(LVL_ERROR, "Unknown method: %d.", (int)method);
		async_answer_0(icallid, EINVAL);
		break;
	}
}
Example #8
0
/** Character device connection handler */
static void cuda_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
{
	ipc_callid_t callid;
	ipc_call_t call;
	sysarg_t method;
	service_id_t dsid;
	int dev_addr, i;

	/* Get the device handle. */
	dsid = IPC_GET_ARG1(*icall);

	/* Determine which disk device is the client connecting to. */
	dev_addr = -1;
	for (i = 0; i < ADB_MAX_ADDR; i++) {
		if (adb_dev[i].service_id == dsid)
			dev_addr = i;
	}

	if (dev_addr < 0) {
		async_answer_0(iid, EINVAL);
		return;
	}

	/* Answer the IPC_M_CONNECT_ME_TO call. */
	async_answer_0(iid, EOK);

	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;
		}
		
		async_sess_t *sess =
		    async_callback_receive_start(EXCHANGE_SERIALIZE, &call);
		if (sess != NULL) {
			if (adb_dev[dev_addr].client_sess == NULL) {
				adb_dev[dev_addr].client_sess = sess;
				
				/*
				 * A hack so that we send the data to the session
				 * regardless of which address the device is on.
				 */
				for (i = 0; i < ADB_MAX_ADDR; ++i) {
					if (adb_dev[i].service_id == dsid)
						adb_dev[i].client_sess = sess;
				}
				
				async_answer_0(callid, EOK);
			} else
				async_answer_0(callid, ELIMIT);
		} else
			async_answer_0(callid, EINVAL);
	}
}
Example #9
0
static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
{
	async_answer_0(iid, EOK);
	
	while (true) {
		ipc_call_t call;
		ipc_callid_t callid = async_get_call(&call);
		
		if (!IPC_GET_IMETHOD(call)) {
			if (client_sess != NULL) {
				async_hangup(client_sess);
				client_sess = NULL;
			}
			
			async_answer_0(callid, EOK);
			return;
		}
		
		async_sess_t *sess =
		    async_callback_receive_start(EXCHANGE_SERIALIZE, &call);
		if (sess != NULL) {
			if (client_sess == NULL) {
				client_sess = sess;
				async_answer_0(callid, EOK);
			} else
				async_answer_0(callid, ELIMIT);
		} else {
			switch (IPC_GET_IMETHOD(call)) {
			case INPUT_YIELD:
				kbd_devs_yield();
				async_answer_0(callid, EOK);
				break;
			case INPUT_RECLAIM:
				kbd_devs_reclaim();
				async_answer_0(callid, EOK);
				break;
			default:
				async_answer_0(callid, EINVAL);
			}
		}
	}
}
Example #10
0
static void inet_cb_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
{
	while (true) {
		ipc_call_t call;
		ipc_callid_t callid = async_get_call(&call);

		if (!IPC_GET_IMETHOD(call)) {
			/* TODO: Handle hangup */
			return;
		}

		switch (IPC_GET_IMETHOD(call)) {
		case INET_EV_RECV:
			inet_ev_recv(callid, &call);
			break;
		default:
			async_answer_0(callid, ENOTSUP);
		}
	}
}
Example #11
0
static void bd_cb_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
{
	bd_t *bd = (bd_t *)arg;

	(void)bd;

	while (true) {
		ipc_call_t call;
		ipc_callid_t callid = async_get_call(&call);

		if (!IPC_GET_IMETHOD(call)) {
			/* TODO: Handle hangup */
			return;
		}

		switch (IPC_GET_IMETHOD(call)) {
		default:
			async_answer_0(callid, ENOTSUP);
		}
	}
}
Example #12
0
/**
 * Recording callback. Writes recorded data.
 * @param iid IPC call id.
 * @param icall Poitner to IPC call structure.
 * @param arg Argument. Poitner to recording helper structure.
 */
static void device_event_callback(ipc_callid_t iid, ipc_call_t *icall, void* arg)
{
	async_answer_0(iid, EOK);
	record_t *rec = arg;
	const size_t buffer_part = rec->buffer.size / BUFFER_PARTS;
	bool record = true;
	while (record) {
		ipc_call_t call;
		ipc_callid_t callid = async_get_call(&call);
		switch(IPC_GET_IMETHOD(call)) {
		case PCM_EVENT_CAPTURE_TERMINATED:
			printf("Recording terminated\n");
			record = false;
			break;
		case PCM_EVENT_FRAMES_CAPTURED:
			printf("%" PRIun " frames\n", IPC_GET_ARG1(call));
			break;
		default:
			printf("Unknown event %" PRIun ".\n", IPC_GET_IMETHOD(call));
			async_answer_0(callid, ENOTSUP);
			continue;
		}

		if (!record) {
			async_answer_0(callid, EOK);
			break;
		}

		/* Write directly from device buffer to file */
		const size_t bytes = fwrite(rec->buffer.position,
		   sizeof(uint8_t), buffer_part, rec->file);
		printf("%zu ", bytes);
		rec->buffer.position += buffer_part;

		if (rec->buffer.position >= (rec->buffer.base + rec->buffer.size))
			rec->buffer.position = rec->buffer.base;
		async_answer_0(callid, EOK);
	}
}
Example #13
0
/**
 * Accept reads and pull data from the stream.
 * @param stream target stream, will pull data from there.
 */
static void hound_server_write_data(void *stream)
{

	ipc_callid_t callid;
	ipc_call_t call;
	size_t size = 0;
	int ret_answer = EOK;
	/* accept data read and drain */
	while (async_data_read_receive_call(&callid, &call, &size)
	    || (IPC_GET_IMETHOD(call) == IPC_M_HOUND_STREAM_DRAIN)) {
		/* drain does not make much sense but it is allowed */
		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;
		}
		int ret = server_iface->stream_data_read(stream, buffer, size);
		if (ret == EOK) {
			ret_answer =
			    async_data_read_finalize(callid, buffer, size);
		}
	}
	const int ret = IPC_GET_IMETHOD(call) == IPC_M_HOUND_STREAM_EXIT
	    ? EOK : EINVAL;

	async_answer_0(callid, ret);
}
Example #14
0
/** Forward a received call to another destination - slow version.
 *
 * This function is the slow verision of the sys_ipc_forward_fast interface.
 * It can copy all five new arguments and the new interface and method from
 * the userspace. It naturally extends the functionality of the fast version.
 * For system methods, it additionally stores the new value of arg3 to ARG4.
 * For non-system methods, it additionally stores the new value of arg3, arg4
 * and arg5, respectively, to ARG3, ARG4 and ARG5, respectively.
 *
 * @param callid  Hash of the call to forward.
 * @param phoneid Phone handle to use for forwarding.
 * @param data    Userspace address of the new IPC data.
 * @param mode    Flags that specify mode of the forward operation.
 *
 * @return 0 on succes, otherwise an error code.
 *
 */
sysarg_t sys_ipc_forward_slow(sysarg_t callid, sysarg_t phoneid,
    ipc_data_t *data, unsigned int mode)
{
	ipc_data_t newdata;
	int rc = copy_from_uspace(&newdata.args, &data->args,
	    sizeof(newdata.args));
	if (rc != 0)
		return (sysarg_t) rc;
	
	return sys_ipc_forward_common(callid, phoneid,
	    IPC_GET_IMETHOD(newdata), IPC_GET_ARG1(newdata),
	    IPC_GET_ARG2(newdata), IPC_GET_ARG3(newdata),
	    IPC_GET_ARG4(newdata), IPC_GET_ARG5(newdata), mode, true); 
}
Example #15
0
static void notification_received(ipc_callid_t callid, ipc_call_t *call)
{
	switch (IPC_GET_IMETHOD(*call)) {
	case VFS_TASK_STATE_CHANGE:
		if (IPC_GET_ARG1(*call) == VFS_PASS_HANDLE)
			vfs_pass_handle(
			    (task_id_t) MERGE_LOUP32(IPC_GET_ARG4(*call),
			    IPC_GET_ARG5(*call)), call->in_task_id,
			    (int) IPC_GET_ARG2(*call));
		break;
	default:
		break;
	}
}
Example #16
0
/** Decide if the caller (e.g. ipc_answer()) should save the old call contents
 * for answer_preprocess().
 *
 * @param call Call structure to be decided.
 *
 * @return true if the old call contents should be saved.
 *
 */
static inline bool answer_need_old(call_t *call)
{
	switch (IPC_GET_IMETHOD(call->data)) {
	case IPC_M_CONNECTION_CLONE:
	case IPC_M_CLONE_ESTABLISH:
	case IPC_M_CONNECT_TO_ME:
	case IPC_M_CONNECT_ME_TO:
	case IPC_M_SHARE_OUT:
	case IPC_M_SHARE_IN:
	case IPC_M_DATA_WRITE:
	case IPC_M_DATA_READ:
	case IPC_M_STATE_CHANGE_AUTHORIZE:
		return true;
	default:
		return false;
	}
}
Example #17
0
/** Default handler for IPC methods not handled by DDF.
 *
 * @param fun     Device function handling the call.
 * @param icallid Call id.
 * @param icall   Call data.
 *
 */
static void default_connection_handler(ddf_fun_t *fun,
                                       ipc_callid_t icallid, ipc_call_t *icall)
{
    const sysarg_t method = IPC_GET_IMETHOD(*icall);
    at_kbd_t *kbd = ddf_dev_data_get(ddf_fun_get_dev(fun));

    switch (method) {
    case KBDEV_SET_IND: {
        async_answer_0(icallid, ENOTSUP);
        break;
    }
    /*
     * This might be ugly but async_callback_receive_start makes no
     * difference for incorrect call and malloc failure.
     */
    case IPC_M_CONNECT_TO_ME: {
        async_sess_t *sess =
            async_callback_receive_start(EXCHANGE_SERIALIZE, icall);

        /* Probably ENOMEM error, try again. */
        if (sess == NULL) {
            ddf_msg(LVL_WARN,
                    "Failed creating callback session");
            async_answer_0(icallid, EAGAIN);
            break;
        }

        if (kbd->client_sess == NULL) {
            kbd->client_sess = sess;
            ddf_msg(LVL_DEBUG, "Set client session");
            async_answer_0(icallid, EOK);
        } else {
            ddf_msg(LVL_ERROR, "Client session already set");
            async_answer_0(icallid, ELIMIT);
        }

        break;
    }
    default:
        ddf_msg(LVL_ERROR, "Unknown method: %d.", (int)method);
        async_answer_0(icallid, EINVAL);
        break;
    }
}
Example #18
0
/** Main IPC call handling from virtual host controller.
 *
 * @param iid   Caller identification
 * @param icall Initial incoming call
 * @param arg   Local argument
 */
static void callback_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
{
	assert(DEV != NULL);

	async_answer_0(iid, EOK);

	while (true) {
		ipc_callid_t callid;
		ipc_call_t call;

		callid = async_get_call(&call);
		bool processed = usbvirt_ipc_handle_call(DEV, callid, &call);
		if (!processed) {
			if (!IPC_GET_IMETHOD(call)) {
				async_answer_0(callid, EOK);
				return;
			} else
				async_answer_0(callid, EINVAL);
		}
	}
}
Example #19
0
/** Handle incoming IPC call for virtual USB device.
 *
 * @param dev Target USB device.
 * @param callid Caller id.
 * @param call Incoming call.
 * @return Whether the call was handled.
 */
bool usbvirt_ipc_handle_call(usbvirt_device_t *dev,
    ipc_callid_t callid, ipc_call_t *call)
{
	switch (IPC_GET_IMETHOD(*call)) {
	case IPC_M_USBVIRT_GET_NAME:
		ipc_get_name(dev, callid, call);
		break;

	case IPC_M_USBVIRT_CONTROL_READ:
		ipc_control_read(dev, callid, call);
		break;

	case IPC_M_USBVIRT_CONTROL_WRITE:
		ipc_control_write(dev, callid, call);
		break;

	case IPC_M_USBVIRT_INTERRUPT_IN:
		ipc_data_in(dev, USB_TRANSFER_INTERRUPT, callid, call);
		break;

	case IPC_M_USBVIRT_BULK_IN:
		ipc_data_in(dev, USB_TRANSFER_BULK, callid, call);
		break;

	case IPC_M_USBVIRT_INTERRUPT_OUT:
		ipc_data_out(dev, USB_TRANSFER_INTERRUPT, callid, call);
		break;

	case IPC_M_USBVIRT_BULK_OUT:
		ipc_data_out(dev, USB_TRANSFER_BULK, callid, call);
		break;


	default:
		return false;
	}

	return true;
}
Example #20
0
static void mouse_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
{
	async_answer_0(iid, EOK);
	
	async_sess_t *sess =
	    async_callback_receive(EXCHANGE_SERIALIZE);
	fibril_mutex_lock(&client_mutex);
		if (client_sess == NULL) {
			client_sess = sess;
		}
	fibril_mutex_unlock(&client_mutex);

	while (true) {
		ipc_call_t call;
		ipc_callid_t callid = async_get_call(&call);
		
		if (!IPC_GET_IMETHOD(call))
			break;
		
		async_answer_0(callid, ENOTSUP);
	}
}
Example #21
0
/** Forward a received call to another destination
 *
 * Common code for both the fast and the slow version.
 *
 * @param callid  Hash of the call to forward.
 * @param phoneid Phone handle to use for forwarding.
 * @param imethod New interface and method to use for the forwarded call.
 * @param arg1    New value of the first argument for the forwarded call.
 * @param arg2    New value of the second argument for the forwarded call.
 * @param arg3    New value of the third argument for the forwarded call.
 * @param arg4    New value of the fourth argument for the forwarded call.
 * @param arg5    New value of the fifth argument for the forwarded call.
 * @param mode    Flags that specify mode of the forward operation.
 * @param slow    If true, arg3, arg4 and arg5 are considered. Otherwise
 *                the function considers only the fast version arguments:
 *                i.e. arg1 and arg2.
 *
 * @return 0 on succes, otherwise an error code.
 *
 * Warning: Make sure that ARG5 is not rewritten for certain system IPC
 *
 */
static sysarg_t sys_ipc_forward_common(sysarg_t callid, sysarg_t phoneid,
    sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3,
    sysarg_t arg4, sysarg_t arg5, unsigned int mode, bool slow)
{
	call_t *call = get_call(callid);
	phone_t *phone;
	bool need_old = answer_need_old(call);
	bool after_forward = false;
	ipc_data_t old;
	int rc;

	if (!call)
		return ENOENT;

	if (need_old)
		old = call->data;
	
	if (phone_get(phoneid, &phone) != EOK) {
		rc = ENOENT;
		goto error;
	}
	
	if (!method_is_forwardable(IPC_GET_IMETHOD(call->data))) {
		rc = EPERM;
		goto error;
	}

	call->flags |= IPC_CALL_FORWARDED;
	
	/*
	 * User space is not allowed to change interface and method of system
	 * methods on forward, allow changing ARG1, ARG2, ARG3 and ARG4 by
	 * means of imethod, arg1, arg2 and arg3.
	 * If the interface and method is immutable, don't change anything.
	 */
	if (!method_is_immutable(IPC_GET_IMETHOD(call->data))) {
		if (method_is_system(IPC_GET_IMETHOD(call->data))) {
			if (IPC_GET_IMETHOD(call->data) == IPC_M_CONNECT_TO_ME)
				phone_dealloc(IPC_GET_ARG5(call->data));
			
			IPC_SET_ARG1(call->data, imethod);
			IPC_SET_ARG2(call->data, arg1);
			IPC_SET_ARG3(call->data, arg2);
			
			if (slow)
				IPC_SET_ARG4(call->data, arg3);
			
			/*
			 * For system methods we deliberately don't
			 * overwrite ARG5.
			 */
		} else {
			IPC_SET_IMETHOD(call->data, imethod);
			IPC_SET_ARG1(call->data, arg1);
			IPC_SET_ARG2(call->data, arg2);
			if (slow) {
				IPC_SET_ARG3(call->data, arg3);
				IPC_SET_ARG4(call->data, arg4);
				IPC_SET_ARG5(call->data, arg5);
			}
		}
	}
	
	rc = ipc_forward(call, phone, &TASK->answerbox, mode);
	if (rc != EOK) {
		after_forward = true;
		goto error;
	}

	return EOK;

error:
	IPC_SET_RETVAL(call->data, EFORWARD);
	(void) answer_preprocess(call, need_old ? &old : NULL);
	if (after_forward)
		_ipc_answer_free_call(call, false);
	else
		ipc_answer(&TASK->answerbox, call);

	return rc;
}
Example #22
0
/** 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);
}
Example #23
0
static void vfs_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
{
	bool cont = true;
	
	/*
	 * The connection was opened via the IPC_CONNECT_ME_TO call.
	 * This call needs to be answered.
	 */
	async_answer_0(iid, EOK);
	
	while (cont) {
		ipc_call_t call;
		ipc_callid_t callid = async_get_call(&call);
		
		if (!IPC_GET_IMETHOD(call))
			break;
		
		switch (IPC_GET_IMETHOD(call)) {
		case VFS_IN_REGISTER:
			vfs_register(callid, &call);
			cont = false;
			break;
		case VFS_IN_MOUNT:
			vfs_mount(callid, &call);
			break;
		case VFS_IN_UNMOUNT:
			vfs_unmount(callid, &call);
			break;
		case VFS_IN_OPEN:
			vfs_open(callid, &call);
			break;
		case VFS_IN_CLOSE:
			vfs_close(callid, &call);
			break;
		case VFS_IN_READ:
			vfs_read(callid, &call);
			break;
		case VFS_IN_WRITE:
			vfs_write(callid, &call);
			break;
		case VFS_IN_SEEK:
			vfs_seek(callid, &call);
			break;
		case VFS_IN_TRUNCATE:
			vfs_truncate(callid, &call);
			break;
		case VFS_IN_FSTAT:
			vfs_fstat(callid, &call);
			break;
		case VFS_IN_STAT:
			vfs_stat(callid, &call);
			break;
		case VFS_IN_MKDIR:
			vfs_mkdir(callid, &call);
			break;
		case VFS_IN_UNLINK:
			vfs_unlink(callid, &call);
			break;
		case VFS_IN_RENAME:
			vfs_rename(callid, &call);
			break;
		case VFS_IN_SYNC:
			vfs_sync(callid, &call);
			break;
		case VFS_IN_DUP:
			vfs_dup(callid, &call);
			break;
		case VFS_IN_WAIT_HANDLE:
			vfs_wait_handle(callid, &call);
			break;
		case VFS_IN_MTAB_GET:
			vfs_get_mtab(callid, &call);
			break;
		default:
			async_answer_0(callid, ENOTSUP);
			break;
		}
	}
	
	/*
	 * Open files for this client will be cleaned up when its last
	 * connection fibril terminates.
	 */
}
Example #24
0
/**
 * 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);
}
Example #25
0
static void tcp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
{
	ipc_callid_t callid;
	ipc_call_t call;
	tcp_client_t client;

	/* Accept the connection */
	async_answer_0(iid, EOK);

	client.sess = async_callback_receive(EXCHANGE_SERIALIZE);
	socket_cores_initialize(&client.sockets);

	while (true) {
		callid = async_get_call(&call);
		if (!IPC_GET_IMETHOD(call))
			break;

		log_msg(LVL_DEBUG, "tcp_sock_connection: METHOD=%d\n",
		    (int)IPC_GET_IMETHOD(call));

		switch (IPC_GET_IMETHOD(call)) {
		case NET_SOCKET:
			tcp_sock_socket(&client, callid, call);
			break;
		case NET_SOCKET_BIND:
			tcp_sock_bind(&client, callid, call);
			break;
		case NET_SOCKET_LISTEN:
			tcp_sock_listen(&client, callid, call);
			break;
		case NET_SOCKET_CONNECT:
			tcp_sock_connect(&client, callid, call);
			break;
		case NET_SOCKET_ACCEPT:
			tcp_sock_accept(&client, callid, call);
			break;
		case NET_SOCKET_SEND:
			tcp_sock_send(&client, callid, call);
			break;
		case NET_SOCKET_SENDTO:
			tcp_sock_sendto(&client, callid, call);
			break;
		case NET_SOCKET_RECV:
		case NET_SOCKET_RECVFROM:
			tcp_sock_recvfrom(&client, callid, call);
			break;
		case NET_SOCKET_CLOSE:
			tcp_sock_close(&client, callid, call);
			break;
		case NET_SOCKET_GETSOCKOPT:
			tcp_sock_getsockopt(&client, callid, call);
			break;
		case NET_SOCKET_SETSOCKOPT:
			tcp_sock_setsockopt(&client, callid, call);
			break;
		default:
			async_answer_0(callid, ENOTSUP);
			break;
		}
	}

	/* Clean up */
	log_msg(LVL_DEBUG, "tcp_sock_connection: Clean up");
	async_hangup(client.sess);
	socket_cores_release(NULL, &client.sockets, &gsock, tcp_free_sock_data);
}
Example #26
0
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);
}
Example #27
0
	list_foreach(*list, cur) {
		call_t *call = list_get_instance(cur, call_t, ab_link);
		
#ifdef __32_BITS__
		printf("%10p ", call);
#endif
		
#ifdef __64_BITS__
		printf("%18p ", call);
#endif
		
		spinlock_lock(&call->forget_lock);

		printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
		    " %-6" PRIun " %-6" PRIun " %-7x",
		    IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
		    IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
		    IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
		    call->flags);

		if (call->forget) {
			printf(" ? (call forgotten)\n");
		} else {
			printf(" %" PRIu64 " (%s)\n",
			    call->sender->taskid, call->sender->name);
		}

		spinlock_unlock(&call->forget_lock);
	}
}
Example #28
0
static void udp_sock_recvfrom(udp_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;
	udp_sockdata_t *socket;
	ipc_call_t answer;
	ipc_callid_t rcallid;
	size_t data_len;
	udp_error_t urc;
	udp_sock_t rsock;
	struct sockaddr_in addr;
	int rc;

	log_msg(LVL_DEBUG, "%p: udp_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 = (udp_sockdata_t *)sock_core->specific_data;
	fibril_mutex_lock(&socket->lock);

	if (socket->assoc == NULL) {
		fibril_mutex_unlock(&socket->lock);
		async_answer_0(callid, ENOTCONN);
		return;
	}

	(void)flags;

	log_msg(LVL_DEBUG, "udp_sock_recvfrom(): lock recv_buffer lock");
	fibril_mutex_lock(&socket->recv_buffer_lock);
	while (socket->recv_buffer_used == 0 && socket->recv_error == UDP_EOK) {
		log_msg(LVL_DEBUG, "udp_sock_recvfrom(): wait for cv");
		fibril_condvar_wait(&socket->recv_buffer_cv,
		    &socket->recv_buffer_lock);
	}

	log_msg(LVL_DEBUG, "Got data in sock recv_buffer");

	rsock = socket->recv_fsock;
	data_len = socket->recv_buffer_used;
	urc = socket->recv_error;

	log_msg(LVL_DEBUG, "**** recv data_len=%zu", data_len);

	switch (urc) {
	case UDP_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, "**** udp_uc_receive -> %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 */
		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);

	if (length < data_len && rc == EOK)
		rc = EOVERFLOW;

	log_msg(LVL_DEBUG, "read_data_length <- %zu", length);
	IPC_SET_ARG2(answer, 0);
	SOCKET_SET_READ_DATA_LENGTH(answer, length);
	SOCKET_SET_ADDRESS_LENGTH(answer, sizeof(addr));
	async_answer_3(callid, EOK, IPC_GET_ARG1(answer),
	    IPC_GET_ARG2(answer), IPC_GET_ARG3(answer));

	socket->recv_buffer_used = 0;

	fibril_condvar_broadcast(&socket->recv_buffer_cv);
	fibril_mutex_unlock(&socket->recv_buffer_lock);
	fibril_mutex_unlock(&socket->lock);
}
Example #29
0
static void udp_sock_sendto(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
{
	int socket_id;
	int fragments;
	int index;
	struct sockaddr_in *addr;
	size_t addr_size;
	socket_core_t *sock_core;
	udp_sockdata_t *socket;
	udp_sock_t fsock, *fsockp;
	ipc_call_t answer;
	ipc_callid_t wcallid;
	size_t length;
	uint8_t buffer[UDP_FRAGMENT_SIZE];
	udp_error_t urc;
	int rc;

	log_msg(LVL_DEBUG, "udp_sock_send()");

	addr = NULL;

	if (IPC_GET_IMETHOD(call) == NET_SOCKET_SENDTO) {
		rc = async_data_write_accept((void **) &addr, false,
		    0, 0, 0, &addr_size);
		if (rc != EOK) {
			async_answer_0(callid, rc);
			goto out;
		}

		if (addr_size != sizeof(struct sockaddr_in)) {
			async_answer_0(callid, EINVAL);
			goto out;
		}

		fsock.addr.ipv4 = uint32_t_be2host(addr->sin_addr.s_addr);
		fsock.port = uint16_t_be2host(addr->sin_port);
		fsockp = &fsock;
	} else {
		fsockp = NULL;
	}

	socket_id = SOCKET_GET_SOCKET_ID(call);
	fragments = SOCKET_GET_DATA_FRAGMENTS(call);
	SOCKET_GET_FLAGS(call);

	sock_core = socket_cores_find(&client->sockets, socket_id);
	if (sock_core == NULL) {
		async_answer_0(callid, ENOTSOCK);
		goto out;
	}

	if (sock_core->port == 0) {
		/* Implicitly bind socket to port */
		rc = socket_bind(&client->sockets, &gsock, SOCKET_GET_SOCKET_ID(call),
		    addr, addr_size, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END,
		    last_used_port);
		if (rc != EOK) {
			async_answer_0(callid, rc);
			goto out;
		}
	}

	socket = (udp_sockdata_t *)sock_core->specific_data;
	fibril_mutex_lock(&socket->lock);

	if (socket->assoc->ident.local.addr.ipv4 == UDP_IPV4_ANY) {
		/* Determine local IP address */
		inet_addr_t loc_addr, rem_addr;

		rem_addr.ipv4 = fsockp ? fsock.addr.ipv4 :
		    socket->assoc->ident.foreign.addr.ipv4;

		rc = inet_get_srcaddr(&rem_addr, 0, &loc_addr);
		if (rc != EOK) {
			fibril_mutex_unlock(&socket->lock);
			async_answer_0(callid, rc);
			log_msg(LVL_DEBUG, "udp_sock_sendto: Failed to "
			    "determine local address.");
			return;
		}

		socket->assoc->ident.local.addr.ipv4 = loc_addr.ipv4;
		log_msg(LVL_DEBUG, "Local IP address is %x",
		    socket->assoc->ident.local.addr.ipv4);
	}


	assert(socket->assoc != NULL);

	for (index = 0; index < fragments; index++) {
		if (!async_data_write_receive(&wcallid, &length)) {
			fibril_mutex_unlock(&socket->lock);
			async_answer_0(callid, EINVAL);
			goto out;
		}

		if (length > UDP_FRAGMENT_SIZE)
			length = UDP_FRAGMENT_SIZE;

		rc = async_data_write_finalize(wcallid, buffer, length);
		if (rc != EOK) {
			fibril_mutex_unlock(&socket->lock);
			async_answer_0(callid, rc);
			goto out;
		}

		urc = udp_uc_send(socket->assoc, fsockp, buffer, length, 0);

		switch (urc) {
		case UDP_EOK:
			rc = EOK;
			break;
/*		case TCP_ENOTEXIST:
			rc = ENOTCONN;
			break;
		case TCP_ECLOSING:
			rc = ENOTCONN;
			break;
		case TCP_ERESET:
			rc = ECONNABORTED;
			break;*/
		default:
			assert(false);
		}

		if (rc != EOK) {
			fibril_mutex_unlock(&socket->lock);
			async_answer_0(callid, rc);
			goto out;
		}
	}
	
	IPC_SET_ARG1(answer, 0);
	SOCKET_SET_DATA_FRAGMENT_SIZE(answer, UDP_FRAGMENT_SIZE);
	async_answer_2(callid, EOK, IPC_GET_ARG1(answer),
	    IPC_GET_ARG2(answer));
	fibril_mutex_unlock(&socket->lock);
	
out:
	if (addr != NULL)
		free(addr);
}
Example #30
0
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);
	}
}