Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 9956fad9 in mainline


Ignore:
Timestamp:
2012-08-15T09:53:19Z (9 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master
Children:
9a82ac1
Parents:
1cb75de
Message:

Give each system IPC method its dedicated answer preprocess hook.

File:
1 edited

Legend:

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

    r1cb75de r9956fad9  
    174174}
    175175
     176static int a_preprocess_m_connection_clone(call_t *answer, ipc_data_t *olddata)
     177{
     178        int phoneid = (int) IPC_GET_ARG1(*olddata);
     179        phone_t *phone = &TASK->phones[phoneid];
     180
     181        if (IPC_GET_RETVAL(answer->data) != EOK) {
     182                /*
     183                 * The recipient of the cloned phone rejected the offer.  In
     184                 * this case, the connection was established at the request
     185                 * time and therefore we need to slam the phone.  We don't
     186                 * merely hangup as that would result in sending IPC_M_HUNGUP
     187                 * to the third party on the other side of the cloned phone.
     188                 */
     189                mutex_lock(&phone->lock);
     190                if (phone->state == IPC_PHONE_CONNECTED) {
     191                        irq_spinlock_lock(&phone->callee->lock, true);
     192                        list_remove(&phone->link);
     193                        phone->state = IPC_PHONE_SLAMMED;
     194                        irq_spinlock_unlock(&phone->callee->lock, true);
     195                }
     196                mutex_unlock(&phone->lock);
     197        }
     198
     199        return EOK;
     200}
     201
     202static int a_preprocess_m_clone_establish(call_t *answer, ipc_data_t *olddata)
     203{
     204        phone_t *phone = (phone_t *) IPC_GET_ARG5(*olddata);
     205
     206        if (IPC_GET_RETVAL(answer->data) != EOK) {
     207                /*
     208                 * The other party on the cloned phoned rejected our request
     209                 * for connection on the protocol level.  We need to break the
     210                 * connection without sending IPC_M_HUNGUP back.
     211                 */
     212                mutex_lock(&phone->lock);
     213                if (phone->state == IPC_PHONE_CONNECTED) {
     214                        irq_spinlock_lock(&phone->callee->lock, true);
     215                        list_remove(&phone->link);
     216                        phone->state = IPC_PHONE_SLAMMED;
     217                        irq_spinlock_unlock(&phone->callee->lock, true);
     218                }
     219                mutex_unlock(&phone->lock);
     220        }
     221       
     222        return EOK;
     223}
     224
     225static int a_preprocess_m_connect_to_me(call_t *answer, ipc_data_t *olddata)
     226{
     227        int phoneid = (int) IPC_GET_ARG5(*olddata);
     228
     229        if (IPC_GET_RETVAL(answer->data) != EOK) {
     230                /* The connection was not accepted */
     231                phone_dealloc(phoneid);
     232        } else {
     233                /* The connection was accepted */
     234                phone_connect(phoneid, &answer->sender->answerbox);
     235                /* Set 'phone hash' as arg5 of response */
     236                IPC_SET_ARG5(answer->data, (sysarg_t) &TASK->phones[phoneid]);
     237        }
     238
     239        return EOK;
     240}
     241
     242static int a_preprocess_m_connect_me_to(call_t *answer, ipc_data_t *olddata)
     243{
     244        phone_t *phone = (phone_t *) IPC_GET_ARG5(*olddata);
     245
     246        /* If the users accepted call, connect */
     247        if (IPC_GET_RETVAL(answer->data) == EOK)
     248                ipc_phone_connect(phone, &TASK->answerbox);
     249
     250        return EOK;
     251}
     252
     253static int a_preprocess_m_share_out(call_t *answer, ipc_data_t *olddata)
     254{
     255        int rc = EOK;
     256
     257        if (!IPC_GET_RETVAL(answer->data)) {
     258                /* Accepted, handle as_area receipt */
     259
     260                irq_spinlock_lock(&answer->sender->lock, true);
     261                as_t *as = answer->sender->as;
     262                irq_spinlock_unlock(&answer->sender->lock, true);
     263
     264                uintptr_t dst_base = (uintptr_t) -1;
     265                rc = as_area_share(as, IPC_GET_ARG1(*olddata),
     266                    IPC_GET_ARG2(*olddata), AS, IPC_GET_ARG3(*olddata),
     267                    &dst_base, IPC_GET_ARG1(answer->data));
     268                       
     269                if (rc == EOK) {
     270                        rc = copy_to_uspace((void *) IPC_GET_ARG2(answer->data),
     271                            &dst_base, sizeof(dst_base));
     272                }
     273                       
     274                IPC_SET_RETVAL(answer->data, rc);
     275        }
     276
     277        return rc;
     278}
     279
     280static int a_preprocess_m_share_in(call_t *answer, ipc_data_t *olddata)
     281{
     282        if (!IPC_GET_RETVAL(answer->data)) {
     283                irq_spinlock_lock(&answer->sender->lock, true);
     284                as_t *as = answer->sender->as;
     285                irq_spinlock_unlock(&answer->sender->lock, true);
     286                       
     287                uintptr_t dst_base = (uintptr_t) -1;
     288                int rc = as_area_share(AS, IPC_GET_ARG1(answer->data),
     289                    IPC_GET_ARG1(*olddata), as, IPC_GET_ARG2(answer->data),
     290                    &dst_base, IPC_GET_ARG3(answer->data));
     291                IPC_SET_ARG4(answer->data, dst_base);
     292                IPC_SET_RETVAL(answer->data, rc);
     293        }
     294       
     295        return EOK;
     296}
     297
     298static int a_preprocess_m_data_read(call_t *answer, ipc_data_t *olddata)
     299{
     300        ASSERT(!answer->buffer);
     301        if (!IPC_GET_RETVAL(answer->data)) {
     302                /* The recipient agreed to send data. */
     303                uintptr_t src = IPC_GET_ARG1(answer->data);
     304                uintptr_t dst = IPC_GET_ARG1(*olddata);
     305                size_t max_size = IPC_GET_ARG2(*olddata);
     306                size_t size = IPC_GET_ARG2(answer->data);
     307                if (size && size <= max_size) {
     308                        /*
     309                         * Copy the destination VA so that this piece of
     310                         * information is not lost.
     311                         */
     312                        IPC_SET_ARG1(answer->data, dst);
     313                               
     314                        answer->buffer = malloc(size, 0);
     315                        int rc = copy_from_uspace(answer->buffer,
     316                            (void *) src, size);
     317                        if (rc) {
     318                                IPC_SET_RETVAL(answer->data, rc);
     319                                free(answer->buffer);
     320                                answer->buffer = NULL;
     321                        }
     322                } else if (!size) {
     323                        IPC_SET_RETVAL(answer->data, EOK);
     324                } else {
     325                        IPC_SET_RETVAL(answer->data, ELIMIT);
     326                }
     327        }
     328
     329        return EOK;
     330}
     331
     332static int a_preprocess_m_data_write(call_t *answer, ipc_data_t *olddata)
     333{
     334        ASSERT(answer->buffer);
     335        if (!IPC_GET_RETVAL(answer->data)) {
     336                /* The recipient agreed to receive data. */
     337                uintptr_t dst = (uintptr_t)IPC_GET_ARG1(answer->data);
     338                size_t size = (size_t)IPC_GET_ARG2(answer->data);
     339                size_t max_size = (size_t)IPC_GET_ARG2(*olddata);
     340                       
     341                if (size <= max_size) {
     342                        int rc = copy_to_uspace((void *) dst,
     343                            answer->buffer, size);
     344                        if (rc)
     345                                IPC_SET_RETVAL(answer->data, rc);
     346                } else {
     347                        IPC_SET_RETVAL(answer->data, ELIMIT);
     348                }
     349        }
     350        free(answer->buffer);
     351        answer->buffer = NULL;
     352
     353        return EOK;
     354}
     355
     356static int
     357a_preprocess_m_state_change_authorize(call_t *answer, ipc_data_t *olddata)
     358{
     359        int rc = EOK;
     360
     361        if (!IPC_GET_RETVAL(answer->data)) {
     362                /* The recipient authorized the change of state. */
     363                phone_t *recipient_phone;
     364                task_t *other_task_s;
     365                task_t *other_task_r;
     366
     367                rc = phone_get(IPC_GET_ARG1(answer->data),
     368                    &recipient_phone);
     369                if (rc != EOK) {
     370                        IPC_SET_RETVAL(answer->data, ENOENT);
     371                        return ENOENT;
     372                }
     373
     374                mutex_lock(&recipient_phone->lock);
     375                if (recipient_phone->state != IPC_PHONE_CONNECTED) {
     376                        mutex_unlock(&recipient_phone->lock);
     377                        IPC_SET_RETVAL(answer->data, EINVAL);
     378                        return EINVAL;
     379                }
     380
     381                other_task_r = recipient_phone->callee->task;
     382                other_task_s = (task_t *) IPC_GET_ARG5(*olddata);
     383
     384                /*
     385                 * See if both the sender and the recipient meant the
     386                 * same third party task.
     387                 */
     388                if (other_task_r != other_task_s) {
     389                        IPC_SET_RETVAL(answer->data, EINVAL);
     390                        rc = EINVAL;
     391                } else {
     392                        rc = event_task_notify_5(other_task_r,
     393                            EVENT_TASK_STATE_CHANGE, false,
     394                            IPC_GET_ARG1(*olddata),
     395                            IPC_GET_ARG2(*olddata),
     396                            IPC_GET_ARG3(*olddata),
     397                            LOWER32(olddata->task_id),
     398                            UPPER32(olddata->task_id));
     399                        IPC_SET_RETVAL(answer->data, rc);
     400                }
     401
     402                mutex_unlock(&recipient_phone->lock);
     403        }
     404
     405        return rc;
     406}
     407
    176408/** Interpret process answer as control information.
    177409 *
     
    181413 * @param olddata Saved data of the request.
    182414 *
    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 {
     415 * @return Return EOK on success or a negative error code.
     416 *
     417 */
     418static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
     419{
     420        int rc = EOK;
     421
    188422        if ((native_t) IPC_GET_RETVAL(answer->data) == EHANGUP) {
    189423                /* In case of forward, hangup the forwared phone,
     
    201435       
    202436        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;
     437                return rc;
     438       
     439        switch (IPC_GET_IMETHOD(*olddata)) {
     440        case IPC_M_CONNECTION_CLONE:
     441                rc = a_preprocess_m_connection_clone(answer, olddata);
     442                break;
     443        case IPC_M_CLONE_ESTABLISH:
     444                rc = a_preprocess_m_clone_establish(answer, olddata);
     445                break;
     446        case IPC_M_CONNECT_TO_ME:
     447                rc = a_preprocess_m_connect_to_me(answer, olddata);
     448                break;
     449        case IPC_M_CONNECT_ME_TO:
     450                rc = a_preprocess_m_connect_me_to(answer, olddata);
     451                break;
     452        case IPC_M_SHARE_OUT:
     453                rc = a_preprocess_m_share_out(answer, olddata);
     454                break;
     455        case IPC_M_SHARE_IN:
     456                rc = a_preprocess_m_share_in(answer, olddata);
     457                break;
     458        case IPC_M_DATA_READ:
     459                rc = a_preprocess_m_data_read(answer, olddata);
     460                break;
     461        case IPC_M_DATA_WRITE:
     462                rc = a_preprocess_m_data_write(answer, olddata);
     463                break;
     464        case IPC_M_STATE_CHANGE_AUTHORIZE:
     465                rc = a_preprocess_m_state_change_authorize(answer, olddata);
     466                break;
     467        }
     468       
     469        return rc;
    395470}
    396471
Note: See TracChangeset for help on using the changeset viewer.