Ignore:
File:
1 edited

Legend:

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

    r4e5dabf r466e95f7  
    3434
    3535#include <arch.h>
    36 #include <proc/task.h>
    37 #include <proc/thread.h>
    3836#include <errno.h>
    3937#include <memstr.h>
    40 #include <debug.h>
    4138#include <ipc/ipc.h>
    4239#include <abi/ipc/methods.h>
    4340#include <ipc/sysipc.h>
     41#include <ipc/sysipc_ops.h>
     42#include <ipc/sysipc_priv.h>
    4443#include <ipc/irq.h>
    4544#include <ipc/ipcrsc.h>
     
    4746#include <ipc/kbox.h>
    4847#include <synch/waitq.h>
    49 #include <udebug/udebug_ipc.h>
    5048#include <arch/interrupt.h>
    5149#include <syscall/copy.h>
    5250#include <security/cap.h>
    5351#include <console/console.h>
    54 #include <mm/as.h>
    5552#include <print.h>
    5653#include <macros.h>
    5754
    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 
    6455#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  */
    74 static 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 }
    8256
    8357/** Decide if the interface and method is a system method.
     
    181155 * @param olddata Saved data of the request.
    182156 *
    183  * @return Return 0 on success or an error code.
    184  *
    185  */
    186 static inline int answer_preprocess(call_t *answer, ipc_data_t *olddata)
    187 {
     157 * @return Return EOK on success or a negative error code.
     158 *
     159 */
     160int 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.
     168                 */
     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
    188196        if ((native_t) IPC_GET_RETVAL(answer->data) == EHANGUP) {
    189                 /* In case of forward, hangup the forwared phone,
    190                  * not the originator
    191                  */
    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                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);
    197204                }
    198                 irq_spinlock_unlock(&TASK->answerbox.lock, true);
    199                 mutex_unlock(&answer->data.phone->lock);
     205                mutex_unlock(&phone->lock);
    200206        }
    201207       
    202208        if (!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 
    397 static 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 
    409 static void phones_unlock(phone_t *p1, phone_t *p2)
    410 {
    411         mutex_unlock(&p1->lock);
    412         if (p1 != p2)
    413                 mutex_unlock(&p2->lock);
     209                return rc;
     210
     211        return SYSIPC_OP(answer_preprocess, answer, olddata);
    414212}
    415213
     
    424222static int request_preprocess(call_t *call, phone_t *phone)
    425223{
    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;
     224        call->request_method = IPC_GET_IMETHOD(call->data);
     225        return SYSIPC_OP(request_preprocess, call, phone);
    546226}
    547227
     
    561241                IPC_SET_RETVAL(call->data, EFORWARD);
    562242       
    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 }
     243        SYSIPC_OP(answer_process, call);
     244}
     245
    585246
    586247/** Do basic kernel processing of received call request.
     
    595256static int process_request(answerbox_t *box, call_t *call)
    596257{
    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  */
    635 sysarg_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  */
    694 sysarg_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;
     258        return SYSIPC_OP(request_process, call, box);
    735259}
    736260
     
    864388{
    865389        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
    866396        if (!call)
    867397                return ENOENT;
    868        
     398
     399        if (need_old)
     400                old = call->data;
     401       
     402        if (phone_get(phoneid, &phone) != EOK) {
     403                rc = ENOENT;
     404                goto error;
     405        }
     406       
     407        if (!method_is_forwardable(IPC_GET_IMETHOD(call->data))) {
     408                rc = EPERM;
     409                goto error;
     410        }
     411
    869412        call->flags |= IPC_CALL_FORWARDED;
    870        
    871         phone_t *phone;
    872         if (phone_get(phoneid, &phone) != EOK) {
    873                 IPC_SET_RETVAL(call->data, EFORWARD);
    874                 ipc_answer(&TASK->answerbox, call);
    875                 return ENOENT;
    876         }
    877        
    878         if (!method_is_forwardable(IPC_GET_IMETHOD(call->data))) {
    879                 IPC_SET_RETVAL(call->data, EFORWARD);
    880                 ipc_answer(&TASK->answerbox, call);
    881                 return EPERM;
    882         }
    883413       
    884414        /*
     
    916446        }
    917447       
    918         return ipc_forward(call, phone, &TASK->answerbox, mode);
     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
     456error:
     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;
    919465}
    920466
Note: See TracChangeset for help on using the changeset viewer.