Changes in kernel/generic/src/ipc/sysipc.c [4e5dabf:466e95f7] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/ipc/sysipc.c
r4e5dabf r466e95f7 34 34 35 35 #include <arch.h> 36 #include <proc/task.h>37 #include <proc/thread.h>38 36 #include <errno.h> 39 37 #include <memstr.h> 40 #include <debug.h>41 38 #include <ipc/ipc.h> 42 39 #include <abi/ipc/methods.h> 43 40 #include <ipc/sysipc.h> 41 #include <ipc/sysipc_ops.h> 42 #include <ipc/sysipc_priv.h> 44 43 #include <ipc/irq.h> 45 44 #include <ipc/ipcrsc.h> … … 47 46 #include <ipc/kbox.h> 48 47 #include <synch/waitq.h> 49 #include <udebug/udebug_ipc.h>50 48 #include <arch/interrupt.h> 51 49 #include <syscall/copy.h> 52 50 #include <security/cap.h> 53 51 #include <console/console.h> 54 #include <mm/as.h>55 52 #include <print.h> 56 53 #include <macros.h> 57 54 58 /**59 * Maximum buffer size allowed for IPC_M_DATA_WRITE and IPC_M_DATA_READ60 * requests.61 */62 #define DATA_XFER_LIMIT (64 * 1024)63 64 55 #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 }82 56 83 57 /** Decide if the interface and method is a system method. … … 181 155 * @param olddata Saved data of the request. 182 156 * 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 */ 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. 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 188 196 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); 197 204 } 198 irq_spinlock_unlock(&TASK->answerbox.lock, true); 199 mutex_unlock(&answer->data.phone->lock); 205 mutex_unlock(&phone->lock); 200 206 } 201 207 202 208 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); 414 212 } 415 213 … … 424 222 static int request_preprocess(call_t *call, phone_t *phone) 425 223 { 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); 546 226 } 547 227 … … 561 241 IPC_SET_RETVAL(call->data, EFORWARD); 562 242 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 585 246 586 247 /** Do basic kernel processing of received call request. … … 595 256 static int process_request(answerbox_t *box, call_t *call) 596 257 { 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); 735 259 } 736 260 … … 864 388 { 865 389 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 866 396 if (!call) 867 397 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 869 412 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 }883 413 884 414 /* … … 916 446 } 917 447 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 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; 919 465 } 920 466
Note:
See TracChangeset
for help on using the changeset viewer.