Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/ipc/sysipc.c

    r466e95f7 r4e5dabf  
    3434
    3535#include <arch.h>
     36#include <proc/task.h>
     37#include <proc/thread.h>
    3638#include <errno.h>
    3739#include <memstr.h>
     40#include <debug.h>
    3841#include <ipc/ipc.h>
    3942#include <abi/ipc/methods.h>
    4043#include <ipc/sysipc.h>
    41 #include <ipc/sysipc_ops.h>
    42 #include <ipc/sysipc_priv.h>
    4344#include <ipc/irq.h>
    4445#include <ipc/ipcrsc.h>
     
    4647#include <ipc/kbox.h>
    4748#include <synch/waitq.h>
     49#include <udebug/udebug_ipc.h>
    4850#include <arch/interrupt.h>
    4951#include <syscall/copy.h>
    5052#include <security/cap.h>
    5153#include <console/console.h>
     54#include <mm/as.h>
    5255#include <print.h>
    5356#include <macros.h>
    5457
     58/**
     59 * Maximum buffer size allowed for IPC_M_DATA_WRITE and IPC_M_DATA_READ
     60 * requests.
     61 */
     62#define DATA_XFER_LIMIT  (64 * 1024)
     63
    5564#define STRUCT_TO_USPACE(dst, src)  copy_to_uspace((dst), (src), sizeof(*(src)))
     65
     66/** Get phone from the current task by ID.
     67 *
     68 * @param phoneid Phone ID.
     69 * @param phone   Place to store pointer to phone.
     70 *
     71 * @return EOK on success, EINVAL if ID is invalid.
     72 *
     73 */
     74static int phone_get(sysarg_t phoneid, phone_t **phone)
     75{
     76        if (phoneid >= IPC_MAX_PHONES)
     77                return EINVAL;
     78       
     79        *phone = &TASK->phones[phoneid];
     80        return EOK;
     81}
    5682
    5783/** Decide if the interface and method is a system method.
     
    155181 * @param olddata Saved data of the request.
    156182 *
    157  * @return Return EOK on success or a negative error code.
    158  *
    159  */
    160 int answer_preprocess(call_t *answer, ipc_data_t *olddata)
    161 {
    162         int rc = EOK;
    163 
    164         spinlock_lock(&answer->forget_lock);
    165         if (answer->forget) {
    166                 /*
    167                  * This is a forgotten call and answer->sender is not valid.
     183 * @return Return 0 on success or an error code.
     184 *
     185 */
     186static inline int answer_preprocess(call_t *answer, ipc_data_t *olddata)
     187{
     188        if ((native_t) IPC_GET_RETVAL(answer->data) == EHANGUP) {
     189                /* In case of forward, hangup the forwared phone,
     190                 * not the originator
    168191                 */
    169                 spinlock_unlock(&answer->forget_lock);
    170 
    171                 SYSIPC_OP(answer_cleanup, answer, olddata);
    172                 return rc;
    173         } else {
    174                 ASSERT(answer->active);
    175 
    176                 /*
    177                  * Mark the call as inactive to prevent _ipc_answer_free_call()
    178                  * from attempting to remove the call from the active list
    179                  * itself.
    180                  */
    181                 answer->active = false;
    182 
    183                 /*
    184                  * Remove the call from the sender's active call list.
    185                  * We enforce this locking order so that any potential
    186                  * concurrently executing forget operation is forced to
    187                  * release its active_calls_lock and lose the race to
    188                  * forget this soon to be answered call.
    189                  */
    190                 spinlock_lock(&answer->sender->active_calls_lock);
    191                 list_remove(&answer->ta_link);
    192                 spinlock_unlock(&answer->sender->active_calls_lock);
    193         }
    194         spinlock_unlock(&answer->forget_lock);
    195 
    196         if ((native_t) IPC_GET_RETVAL(answer->data) == EHANGUP) {
    197                 phone_t *phone = answer->caller_phone;
    198                 mutex_lock(&phone->lock);
    199                 if (phone->state == IPC_PHONE_CONNECTED) {
    200                         irq_spinlock_lock(&phone->callee->lock, true);
    201                         list_remove(&phone->link);
    202                         phone->state = IPC_PHONE_SLAMMED;
    203                         irq_spinlock_unlock(&phone->callee->lock, true);
    204                 }
    205                 mutex_unlock(&phone->lock);
     192                mutex_lock(&answer->data.phone->lock);
     193                irq_spinlock_lock(&TASK->answerbox.lock, true);
     194                if (answer->data.phone->state == IPC_PHONE_CONNECTED) {
     195                        list_remove(&answer->data.phone->link);
     196                        answer->data.phone->state = IPC_PHONE_SLAMMED;
     197                }
     198                irq_spinlock_unlock(&TASK->answerbox.lock, true);
     199                mutex_unlock(&answer->data.phone->lock);
    206200        }
    207201       
    208202        if (!olddata)
    209                 return rc;
    210 
    211         return SYSIPC_OP(answer_preprocess, answer, olddata);
     203                return 0;
     204       
     205        if (IPC_GET_IMETHOD(*olddata) == IPC_M_CONNECTION_CLONE) {
     206                int phoneid = IPC_GET_ARG1(*olddata);
     207                phone_t *phone = &TASK->phones[phoneid];
     208               
     209                if (IPC_GET_RETVAL(answer->data) != EOK) {
     210                        /*
     211                         * The recipient of the cloned phone rejected the offer.
     212                         * In this case, the connection was established at the
     213                         * request time and therefore we need to slam the phone.
     214                         * We don't merely hangup as that would result in
     215                         * sending IPC_M_HUNGUP to the third party on the
     216                         * other side of the cloned phone.
     217                         */
     218                        mutex_lock(&phone->lock);
     219                        if (phone->state == IPC_PHONE_CONNECTED) {
     220                                irq_spinlock_lock(&phone->callee->lock, true);
     221                                list_remove(&phone->link);
     222                                phone->state = IPC_PHONE_SLAMMED;
     223                                irq_spinlock_unlock(&phone->callee->lock, true);
     224                        }
     225                        mutex_unlock(&phone->lock);
     226                }
     227        } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_CLONE_ESTABLISH) {
     228                phone_t *phone = (phone_t *) IPC_GET_ARG5(*olddata);
     229               
     230                if (IPC_GET_RETVAL(answer->data) != EOK) {
     231                        /*
     232                         * The other party on the cloned phoned rejected our
     233                         * request for connection on the protocol level.
     234                         * We need to break the connection without sending
     235                         * IPC_M_HUNGUP back.
     236                         */
     237                        mutex_lock(&phone->lock);
     238                        if (phone->state == IPC_PHONE_CONNECTED) {
     239                                irq_spinlock_lock(&phone->callee->lock, true);
     240                                list_remove(&phone->link);
     241                                phone->state = IPC_PHONE_SLAMMED;
     242                                irq_spinlock_unlock(&phone->callee->lock, true);
     243                        }
     244                        mutex_unlock(&phone->lock);
     245                }
     246        } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_CONNECT_TO_ME) {
     247                int phoneid = IPC_GET_ARG5(*olddata);
     248               
     249                if (IPC_GET_RETVAL(answer->data) != EOK) {
     250                        /* The connection was not accepted */
     251                        phone_dealloc(phoneid);
     252                } else {
     253                        /* The connection was accepted */
     254                        phone_connect(phoneid, &answer->sender->answerbox);
     255                        /* Set 'phone hash' as arg5 of response */
     256                        IPC_SET_ARG5(answer->data,
     257                            (sysarg_t) &TASK->phones[phoneid]);
     258                }
     259        } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_CONNECT_ME_TO) {
     260                /* If the users accepted call, connect */
     261                if (IPC_GET_RETVAL(answer->data) == EOK) {
     262                        ipc_phone_connect((phone_t *) IPC_GET_ARG5(*olddata),
     263                            &TASK->answerbox);
     264                }
     265        } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_SHARE_OUT) {
     266                if (!IPC_GET_RETVAL(answer->data)) {
     267                        /* Accepted, handle as_area receipt */
     268                       
     269                        irq_spinlock_lock(&answer->sender->lock, true);
     270                        as_t *as = answer->sender->as;
     271                        irq_spinlock_unlock(&answer->sender->lock, true);
     272                       
     273                        uintptr_t dst_base = (uintptr_t) -1;
     274                        int rc = as_area_share(as, IPC_GET_ARG1(*olddata),
     275                            IPC_GET_ARG2(*olddata), AS, IPC_GET_ARG3(*olddata),
     276                            &dst_base, IPC_GET_ARG1(answer->data));
     277                       
     278                        if (rc == EOK)
     279                                rc = copy_to_uspace((void *) IPC_GET_ARG2(answer->data),
     280                                    &dst_base, sizeof(dst_base));
     281                       
     282                        IPC_SET_RETVAL(answer->data, rc);
     283                        return rc;
     284                }
     285        } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_SHARE_IN) {
     286                if (!IPC_GET_RETVAL(answer->data)) {
     287                        irq_spinlock_lock(&answer->sender->lock, true);
     288                        as_t *as = answer->sender->as;
     289                        irq_spinlock_unlock(&answer->sender->lock, true);
     290                       
     291                        uintptr_t dst_base = (uintptr_t) -1;
     292                        int rc = as_area_share(AS, IPC_GET_ARG1(answer->data),
     293                            IPC_GET_ARG1(*olddata), as, IPC_GET_ARG2(answer->data),
     294                            &dst_base, IPC_GET_ARG3(answer->data));
     295                        IPC_SET_ARG4(answer->data, dst_base);
     296                        IPC_SET_RETVAL(answer->data, rc);
     297                }
     298        } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_DATA_READ) {
     299                ASSERT(!answer->buffer);
     300                if (!IPC_GET_RETVAL(answer->data)) {
     301                        /* The recipient agreed to send data. */
     302                        uintptr_t src = IPC_GET_ARG1(answer->data);
     303                        uintptr_t dst = IPC_GET_ARG1(*olddata);
     304                        size_t max_size = IPC_GET_ARG2(*olddata);
     305                        size_t size = IPC_GET_ARG2(answer->data);
     306                        if (size && size <= max_size) {
     307                                /*
     308                                 * Copy the destination VA so that this piece of
     309                                 * information is not lost.
     310                                 */
     311                                IPC_SET_ARG1(answer->data, dst);
     312                               
     313                                answer->buffer = malloc(size, 0);
     314                                int rc = copy_from_uspace(answer->buffer,
     315                                    (void *) src, size);
     316                                if (rc) {
     317                                        IPC_SET_RETVAL(answer->data, rc);
     318                                        free(answer->buffer);
     319                                        answer->buffer = NULL;
     320                                }
     321                        } else if (!size) {
     322                                IPC_SET_RETVAL(answer->data, EOK);
     323                        } else {
     324                                IPC_SET_RETVAL(answer->data, ELIMIT);
     325                        }
     326                }
     327        } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_DATA_WRITE) {
     328                ASSERT(answer->buffer);
     329                if (!IPC_GET_RETVAL(answer->data)) {
     330                        /* The recipient agreed to receive data. */
     331                        uintptr_t dst = (uintptr_t)IPC_GET_ARG1(answer->data);
     332                        size_t size = (size_t)IPC_GET_ARG2(answer->data);
     333                        size_t max_size = (size_t)IPC_GET_ARG2(*olddata);
     334                       
     335                        if (size <= max_size) {
     336                                int rc = copy_to_uspace((void *) dst,
     337                                    answer->buffer, size);
     338                                if (rc)
     339                                        IPC_SET_RETVAL(answer->data, rc);
     340                        } else {
     341                                IPC_SET_RETVAL(answer->data, ELIMIT);
     342                        }
     343                }
     344                free(answer->buffer);
     345                answer->buffer = NULL;
     346        } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_STATE_CHANGE_AUTHORIZE) {
     347                if (!IPC_GET_RETVAL(answer->data)) {
     348                        /* The recipient authorized the change of state. */
     349                        phone_t *recipient_phone;
     350                        task_t *other_task_s;
     351                        task_t *other_task_r;
     352                        int rc;
     353
     354                        rc = phone_get(IPC_GET_ARG1(answer->data),
     355                            &recipient_phone);
     356                        if (rc != EOK) {
     357                                IPC_SET_RETVAL(answer->data, ENOENT);
     358                                return ENOENT;
     359                        }
     360
     361                        mutex_lock(&recipient_phone->lock);
     362                        if (recipient_phone->state != IPC_PHONE_CONNECTED) {
     363                                mutex_unlock(&recipient_phone->lock);
     364                                IPC_SET_RETVAL(answer->data, EINVAL);
     365                                return EINVAL;
     366                        }
     367
     368                        other_task_r = recipient_phone->callee->task;
     369                        other_task_s = (task_t *) IPC_GET_ARG5(*olddata);
     370
     371                        /*
     372                         * See if both the sender and the recipient meant the
     373                         * same third party task.
     374                         */
     375                        if (other_task_r != other_task_s) {
     376                                IPC_SET_RETVAL(answer->data, EINVAL);
     377                                rc = EINVAL;
     378                        } else {
     379                                rc = event_task_notify_5(other_task_r,
     380                                    EVENT_TASK_STATE_CHANGE, false,
     381                                    IPC_GET_ARG1(*olddata),
     382                                    IPC_GET_ARG2(*olddata),
     383                                    IPC_GET_ARG3(*olddata),
     384                                    LOWER32(olddata->task_id),
     385                                    UPPER32(olddata->task_id));
     386                                IPC_SET_RETVAL(answer->data, rc);
     387                        }
     388
     389                        mutex_unlock(&recipient_phone->lock);
     390                        return rc;
     391                }
     392        }
     393       
     394        return 0;
     395}
     396
     397static void phones_lock(phone_t *p1, phone_t *p2)
     398{
     399        if (p1 < p2) {
     400                mutex_lock(&p1->lock);
     401                mutex_lock(&p2->lock);
     402        } else if (p1 > p2) {
     403                mutex_lock(&p2->lock);
     404                mutex_lock(&p1->lock);
     405        } else
     406                mutex_lock(&p1->lock);
     407}
     408
     409static void phones_unlock(phone_t *p1, phone_t *p2)
     410{
     411        mutex_unlock(&p1->lock);
     412        if (p1 != p2)
     413                mutex_unlock(&p2->lock);
    212414}
    213415
     
    222424static int request_preprocess(call_t *call, phone_t *phone)
    223425{
    224         call->request_method = IPC_GET_IMETHOD(call->data);
    225         return SYSIPC_OP(request_preprocess, call, phone);
     426        switch (IPC_GET_IMETHOD(call->data)) {
     427        case IPC_M_CONNECTION_CLONE: {
     428                phone_t *cloned_phone;
     429                if (phone_get(IPC_GET_ARG1(call->data), &cloned_phone) != EOK)
     430                        return ENOENT;
     431               
     432                phones_lock(cloned_phone, phone);
     433               
     434                if ((cloned_phone->state != IPC_PHONE_CONNECTED) ||
     435                    phone->state != IPC_PHONE_CONNECTED) {
     436                        phones_unlock(cloned_phone, phone);
     437                        return EINVAL;
     438                }
     439               
     440                /*
     441                 * We can be pretty sure now that both tasks exist and we are
     442                 * connected to them. As we continue to hold the phone locks,
     443                 * we are effectively preventing them from finishing their
     444                 * potential cleanup.
     445                 *
     446                 */
     447                int newphid = phone_alloc(phone->callee->task);
     448                if (newphid < 0) {
     449                        phones_unlock(cloned_phone, phone);
     450                        return ELIMIT;
     451                }
     452               
     453                ipc_phone_connect(&phone->callee->task->phones[newphid],
     454                    cloned_phone->callee);
     455                phones_unlock(cloned_phone, phone);
     456               
     457                /* Set the new phone for the callee. */
     458                IPC_SET_ARG1(call->data, newphid);
     459                break;
     460        }
     461        case IPC_M_CLONE_ESTABLISH:
     462                IPC_SET_ARG5(call->data, (sysarg_t) phone);
     463                break;
     464        case IPC_M_CONNECT_ME_TO: {
     465                int newphid = phone_alloc(TASK);
     466                if (newphid < 0)
     467                        return ELIMIT;
     468               
     469                /* Set arg5 for server */
     470                IPC_SET_ARG5(call->data, (sysarg_t) &TASK->phones[newphid]);
     471                call->flags |= IPC_CALL_CONN_ME_TO;
     472                call->priv = newphid;
     473                break;
     474        }
     475        case IPC_M_SHARE_OUT: {
     476                size_t size = as_area_get_size(IPC_GET_ARG1(call->data));
     477                if (!size)
     478                        return EPERM;
     479               
     480                IPC_SET_ARG2(call->data, size);
     481                break;
     482        }
     483        case IPC_M_DATA_READ: {
     484                size_t size = IPC_GET_ARG2(call->data);
     485                if (size > DATA_XFER_LIMIT) {
     486                        int flags = IPC_GET_ARG3(call->data);
     487                        if (flags & IPC_XF_RESTRICT)
     488                                IPC_SET_ARG2(call->data, DATA_XFER_LIMIT);
     489                        else
     490                                return ELIMIT;
     491                }
     492                break;
     493        }
     494        case IPC_M_DATA_WRITE: {
     495                uintptr_t src = IPC_GET_ARG1(call->data);
     496                size_t size = IPC_GET_ARG2(call->data);
     497               
     498                if (size > DATA_XFER_LIMIT) {
     499                        int flags = IPC_GET_ARG3(call->data);
     500                        if (flags & IPC_XF_RESTRICT) {
     501                                size = DATA_XFER_LIMIT;
     502                                IPC_SET_ARG2(call->data, size);
     503                        } else
     504                                return ELIMIT;
     505                }
     506               
     507                call->buffer = (uint8_t *) malloc(size, 0);
     508                int rc = copy_from_uspace(call->buffer, (void *) src, size);
     509                if (rc != 0) {
     510                        free(call->buffer);
     511                        return rc;
     512                }
     513               
     514                break;
     515        }
     516        case IPC_M_STATE_CHANGE_AUTHORIZE: {
     517                phone_t *sender_phone;
     518                task_t *other_task_s;
     519
     520                if (phone_get(IPC_GET_ARG5(call->data), &sender_phone) != EOK)
     521                        return ENOENT;
     522
     523                mutex_lock(&sender_phone->lock);
     524                if (sender_phone->state != IPC_PHONE_CONNECTED) {
     525                        mutex_unlock(&sender_phone->lock);
     526                        return EINVAL;
     527                }
     528
     529                other_task_s = sender_phone->callee->task;
     530
     531                mutex_unlock(&sender_phone->lock);
     532
     533                /* Remember the third party task hash. */
     534                IPC_SET_ARG5(call->data, (sysarg_t) other_task_s);
     535                break;
     536        }
     537#ifdef CONFIG_UDEBUG
     538        case IPC_M_DEBUG:
     539                return udebug_request_preprocess(call, phone);
     540#endif
     541        default:
     542                break;
     543        }
     544       
     545        return 0;
    226546}
    227547
     
    241561                IPC_SET_RETVAL(call->data, EFORWARD);
    242562       
    243         SYSIPC_OP(answer_process, call);
    244 }
    245 
     563        if (call->flags & IPC_CALL_CONN_ME_TO) {
     564                if (IPC_GET_RETVAL(call->data))
     565                        phone_dealloc(call->priv);
     566                else
     567                        IPC_SET_ARG5(call->data, call->priv);
     568        }
     569       
     570        if (call->buffer) {
     571                /*
     572                 * This must be an affirmative answer to IPC_M_DATA_READ
     573                 * or IPC_M_DEBUG/UDEBUG_M_MEM_READ...
     574                 *
     575                 */
     576                uintptr_t dst = IPC_GET_ARG1(call->data);
     577                size_t size = IPC_GET_ARG2(call->data);
     578                int rc = copy_to_uspace((void *) dst, call->buffer, size);
     579                if (rc)
     580                        IPC_SET_RETVAL(call->data, rc);
     581                free(call->buffer);
     582                call->buffer = NULL;
     583        }
     584}
    246585
    247586/** Do basic kernel processing of received call request.
     
    256595static int process_request(answerbox_t *box, call_t *call)
    257596{
    258         return SYSIPC_OP(request_process, call, box);
     597        if (IPC_GET_IMETHOD(call->data) == IPC_M_CONNECT_TO_ME) {
     598                int phoneid = phone_alloc(TASK);
     599                if (phoneid < 0) {  /* Failed to allocate phone */
     600                        IPC_SET_RETVAL(call->data, ELIMIT);
     601                        ipc_answer(box, call);
     602                        return -1;
     603                }
     604               
     605                IPC_SET_ARG5(call->data, phoneid);
     606        }
     607       
     608        switch (IPC_GET_IMETHOD(call->data)) {
     609        case IPC_M_DEBUG:
     610                return -1;
     611        default:
     612                break;
     613        }
     614       
     615        return 0;
     616}
     617
     618/** Make a fast call over IPC, wait for reply and return to user.
     619 *
     620 * This function can handle only three arguments of payload, but is faster than
     621 * the generic function (i.e. sys_ipc_call_sync_slow()).
     622 *
     623 * @param phoneid Phone handle for the call.
     624 * @param imethod Interface and method of the call.
     625 * @param arg1    Service-defined payload argument.
     626 * @param arg2    Service-defined payload argument.
     627 * @param arg3    Service-defined payload argument.
     628 * @param data    Address of user-space structure where the reply call will
     629 *                be stored.
     630 *
     631 * @return 0 on success.
     632 * @return ENOENT if there is no such phone handle.
     633 *
     634 */
     635sysarg_t sys_ipc_call_sync_fast(sysarg_t phoneid, sysarg_t imethod,
     636    sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, ipc_data_t *data)
     637{
     638        phone_t *phone;
     639        if (phone_get(phoneid, &phone) != EOK)
     640                return ENOENT;
     641       
     642        call_t *call = ipc_call_alloc(0);
     643        IPC_SET_IMETHOD(call->data, imethod);
     644        IPC_SET_ARG1(call->data, arg1);
     645        IPC_SET_ARG2(call->data, arg2);
     646        IPC_SET_ARG3(call->data, arg3);
     647       
     648        /*
     649         * To achieve deterministic behavior, zero out arguments that are beyond
     650         * the limits of the fast version.
     651         */
     652        IPC_SET_ARG4(call->data, 0);
     653        IPC_SET_ARG5(call->data, 0);
     654       
     655        int res = request_preprocess(call, phone);
     656        int rc;
     657       
     658        if (!res) {
     659#ifdef CONFIG_UDEBUG
     660                udebug_stoppable_begin();
     661#endif
     662                rc = ipc_call_sync(phone, call);
     663#ifdef CONFIG_UDEBUG
     664                udebug_stoppable_end();
     665#endif
     666               
     667                if (rc != EOK) {
     668                        /* The call will be freed by ipc_cleanup(). */
     669                        return rc;
     670                }
     671               
     672                process_answer(call);
     673        } else
     674                IPC_SET_RETVAL(call->data, res);
     675       
     676        rc = STRUCT_TO_USPACE(&data->args, &call->data.args);
     677        ipc_call_free(call);
     678        if (rc != 0)
     679                return rc;
     680       
     681        return 0;
     682}
     683
     684/** Make a synchronous IPC call allowing to transmit the entire payload.
     685 *
     686 * @param phoneid Phone handle for the call.
     687 * @param request User-space address of call data with the request.
     688 * @param reply   User-space address of call data where to store the
     689 *                answer.
     690 *
     691 * @return Zero on success or an error code.
     692 *
     693 */
     694sysarg_t sys_ipc_call_sync_slow(sysarg_t phoneid, ipc_data_t *request,
     695    ipc_data_t *reply)
     696{
     697        phone_t *phone;
     698        if (phone_get(phoneid, &phone) != EOK)
     699                return ENOENT;
     700       
     701        call_t *call = ipc_call_alloc(0);
     702        int rc = copy_from_uspace(&call->data.args, &request->args,
     703            sizeof(call->data.args));
     704        if (rc != 0) {
     705                ipc_call_free(call);
     706                return (sysarg_t) rc;
     707        }
     708       
     709        int res = request_preprocess(call, phone);
     710       
     711        if (!res) {
     712#ifdef CONFIG_UDEBUG
     713                udebug_stoppable_begin();
     714#endif
     715                rc = ipc_call_sync(phone, call);
     716#ifdef CONFIG_UDEBUG
     717                udebug_stoppable_end();
     718#endif
     719               
     720                if (rc != EOK) {
     721                        /* The call will be freed by ipc_cleanup(). */
     722                        return rc;
     723                }
     724               
     725                process_answer(call);
     726        } else
     727                IPC_SET_RETVAL(call->data, res);
     728       
     729        rc = STRUCT_TO_USPACE(&reply->args, &call->data.args);
     730        ipc_call_free(call);
     731        if (rc != 0)
     732                return rc;
     733       
     734        return 0;
    259735}
    260736
     
    388864{
    389865        call_t *call = get_call(callid);
    390         phone_t *phone;
    391         bool need_old = answer_need_old(call);
    392         bool after_forward = false;
    393         ipc_data_t old;
    394         int rc;
    395 
    396866        if (!call)
    397867                return ENOENT;
    398 
    399         if (need_old)
    400                 old = call->data;
    401        
     868       
     869        call->flags |= IPC_CALL_FORWARDED;
     870       
     871        phone_t *phone;
    402872        if (phone_get(phoneid, &phone) != EOK) {
    403                 rc = ENOENT;
    404                 goto error;
     873                IPC_SET_RETVAL(call->data, EFORWARD);
     874                ipc_answer(&TASK->answerbox, call);
     875                return ENOENT;
    405876        }
    406877       
    407878        if (!method_is_forwardable(IPC_GET_IMETHOD(call->data))) {
    408                 rc = EPERM;
    409                 goto error;
    410         }
    411 
    412         call->flags |= IPC_CALL_FORWARDED;
     879                IPC_SET_RETVAL(call->data, EFORWARD);
     880                ipc_answer(&TASK->answerbox, call);
     881                return EPERM;
     882        }
    413883       
    414884        /*
     
    446916        }
    447917       
    448         rc = ipc_forward(call, phone, &TASK->answerbox, mode);
    449         if (rc != EOK) {
    450                 after_forward = true;
    451                 goto error;
    452         }
    453 
    454         return EOK;
    455 
    456 error:
    457         IPC_SET_RETVAL(call->data, EFORWARD);
    458         (void) answer_preprocess(call, need_old ? &old : NULL);
    459         if (after_forward)
    460                 _ipc_answer_free_call(call, false);
    461         else
    462                 ipc_answer(&TASK->answerbox, call);
    463 
    464         return rc;
     918        return ipc_forward(call, phone, &TASK->answerbox, mode);
    465919}
    466920
Note: See TracChangeset for help on using the changeset viewer.