Annotation of qemu/roms/SLOF/lib/libvirtio/p9.c, revision 1.1.1.1

1.1       root        1: /******************************************************************************
                      2:  * Copyright (c) 2011 IBM Corporation
                      3:  * All rights reserved.
                      4:  * This program and the accompanying materials
                      5:  * are made available under the terms of the BSD License
                      6:  * which accompanies this distribution, and is available at
                      7:  * http://www.opensource.org/licenses/bsd-license.php
                      8:  *
                      9:  * Contributors:
                     10:  *     IBM Corporation - initial implementation
                     11:  *****************************************************************************/
                     12: 
                     13: #include <stdio.h>
                     14: #include <stdint.h>
                     15: #include <string.h>
                     16: #include <byteorder.h>
                     17: #include "p9.h"
                     18: 
                     19: 
                     20: /* Protocol stack marshaling. */
                     21: uint8_t *sp;
                     22: 
                     23: #define GET_08(s,i)    (s)[(i)]
                     24: #define GET_16(s,i)    le16_to_cpu(*(uint16_t*)(&(s)[(i)]))
                     25: #define GET_32(s,i)    le32_to_cpu(*(uint32_t*)(&(s)[(i)]))
                     26: #define GET_64(s,i)    le64_to_cpu(*(uint64_t*)(&(s)[(i)]))
                     27: 
                     28: #define SET_08(s,i,v)  (s)[(i)] = (v)
                     29: #define SET_16(s,i,v)  *(uint16_t*)(&(s)[(i)]) = cpu_to_le16(v)
                     30: #define SET_32(s,i,v)  *(uint32_t*)(&(s)[(i)]) = cpu_to_le32(v)
                     31: #define SET_64(s,i,v)  *(uint64_t*)(&(s)[(i)]) = cpu_to_le64(v)
                     32: 
                     33: #define PUT_08(v)      sp[0] = (v);sp+=1
                     34: #define PUT_16(v)      *(uint16_t*)(&sp[0]) = cpu_to_le16(v);sp+=2
                     35: #define PUT_32(v)      *(uint32_t*)(&sp[0]) = cpu_to_le32(v);sp+=4
                     36: #define PUT_64(v)      *(uint64_t*)(&sp[0]) = cpu_to_le64(v);sp+=8
                     37: 
                     38: #define PUT_HD(m,t)    PUT_32(0);PUT_08(m);PUT_16(t)
                     39: #define PUT_SN(v,n)    PUT_16(n);memcpy(sp,(v),(n));sp+=n
                     40: #define PUT_ST(v)      PUT_16(strlen(v));memcpy(sp,(v),strlen(v));\
                     41:                                sp+=strlen(v)
                     42: 
                     43: #define GET_SIZE       (sp - tx)
                     44: 
                     45: 
                     46: /* General defines. */
                     47: #define MIN(a,b)       ((a)>(b)?(b):(a))
                     48: 
                     49: #define NOTAG          ((uint16_t)~0)
                     50: #define NOFID          ((uint32_t)~0)
                     51: #define TAG            1
                     52: #define BUF_SIZE       (8*1024)
                     53: 
                     54: #define VERSION                        "9P2000.u"
                     55: #define UNKNOWN_VER            "unknown"
                     56: 
                     57: #define MSG_SIZE               0
                     58: #define MSG_ID                 4
                     59: #define MSG_ERR                        0x6b
                     60: #define MSG_ERR_STR            9
                     61: #define MSG_ERR_STR_LEN                7
                     62: #define MSG_TAG                        5
                     63: #define MSG_VER_MSIZE          7
                     64: #define MSG_VER_STR_LEN                11
                     65: #define MSG_VER_STR            13
                     66: #define MSG_WALK_TX_ELMT       15
                     67: #define MSG_WALK_RX_ELMT       7
                     68: #define MSG_SIZE               0
                     69: #define MSG_WALK_MAX_ELMT      16
                     70: #define MSG_QID_SIZE           13
                     71: #define MSG_WALK_RX_HDR_SIZE   9
                     72: #define MSG_OPEN_IOUNIT                20
                     73: #define MSG_OPEN_MODE_MASK     0x5f
                     74: #define MSG_READ_COUNT         7
                     75: #define MSG_READ_DATA          11
                     76: #define MSG_STAT_LEN           42
                     77: #define MSG_STAT_TYPE          17
                     78: 
                     79: #define T_VERSION      100
                     80: #define R_VERSION      (T_VERSION + 1)
                     81: #define T_ATTACH       104
                     82: #define R_ATTACH       (T_ATTACH + 1)
                     83: #define T_ERROR                106
                     84: #define R_ERROR                (T_ERROR + 1)
                     85: #define T_WALK         110
                     86: #define R_WALK         (T_WALK + 1)
                     87: #define T_OPEN         112
                     88: #define R_OPEN         (T_OPEN + 1)
                     89: #define T_READ         116
                     90: #define R_READ         (T_READ + 1)
                     91: #define T_CLUNK                120
                     92: #define R_CLUNK                (T_CLUNK + 1)
                     93: #define T_STAT         124
                     94: #define R_STAT         (T_STAT + 1)
                     95: 
                     96: static p9_transact_t transact;
                     97: static void *transact_opaque;
                     98: static uint8_t *tx;
                     99: static uint8_t *rx;
                    100: 
                    101: 
                    102: /**
                    103:  * p9_reg_transport
                    104:  *
                    105:  * Registers a transport function for use by the P9 protocol. The transport
                    106:  * connects the P9 Client (this library) to a server instance.
                    107:  *
                    108:  * @param transact_func[in]    Function pointer to type p9_transact_t.
                    109:  * @param tx_buffer[in]                TX buffer, must be 8k in size.
                    110:  * @param rx_buffer[in]                RX buffer, must be 8k in size.
                    111:  */
                    112: void p9_reg_transport(p9_transact_t transact_func, void *opaque,
                    113:                      uint8_t *tx_buffer, uint8_t *rx_buffer)
                    114: {
                    115:        transact = transact_func;
                    116:        transact_opaque = opaque;
                    117:        tx = tx_buffer;
                    118:        rx = rx_buffer;
                    119: }
                    120: 
                    121: /**
                    122:  * reset_buffers
                    123:  *
                    124:  * Reset the RX and TX buffers to BUF_SIZE (8k) and reset the Stack Pointer
                    125:  * for the TX buffer, which is referenced by the PUT_* macro's.
                    126:  */
                    127: void reset_buffers(void)
                    128: {
                    129:        memset(tx, 0, BUF_SIZE);
                    130:        memset(rx, 0, BUF_SIZE);
                    131:        sp = tx;
                    132: }
                    133: 
                    134: /**
                    135:  * p9_transaction
                    136:  *
                    137:  * Perform a transaction (send/recv) over the registered transport.
                    138:  *
                    139:  * @param connection[in|out]   Connection object.
                    140:  * @return     0 = success, -ve = error.
                    141:  */
                    142: int p9_transaction(p9_connection_t *connection)
                    143: {
                    144:        int rc;
                    145:        int tx_size = GET_SIZE;
                    146:        int rx_size = connection->message_size;
                    147: 
                    148:        if (transact == NULL) {
                    149:                return P9_NO_TRANSPORT;
                    150:        }
                    151:        if (tx == NULL || rx == NULL) {
                    152:                return P9_NO_BUFFER;
                    153:        }
                    154:        if (connection->message_size > BUF_SIZE) {
                    155:                return P9_MSG_SIZE_TOO_BIG;
                    156:        }
                    157:        if (tx_size > connection->message_size) {
                    158:                return P9_MSG_TOO_LONG;
                    159:        }
                    160: 
                    161:        SET_32(tx, MSG_SIZE, tx_size);
                    162:        rc = transact(transact_opaque, tx, tx_size, rx, &rx_size);
                    163: 
                    164:        if (rc != 0) {
                    165:                return P9_TRANSPORT_ERROR;
                    166:        }
                    167:        if (GET_16(tx, MSG_TAG) != GET_16(rx, MSG_TAG)) {
                    168:                return P9_UNEXPECTED_TAG;
                    169:        }
                    170:        if (GET_08(rx, MSG_ID) == MSG_ERR) {
                    171:                char error_string[200];
                    172: 
                    173:                memset(error_string, 0, 200);
                    174:                strncpy(error_string, (char *)&rx[MSG_ERR_STR],
                    175:                                MIN(200 - 1, GET_16(rx, MSG_ERR_STR_LEN)));
                    176: #ifndef TEST
                    177:                printf("\nError: %s\n", error_string);
                    178: #endif
                    179:                return P9_R_ERROR;
                    180:        }
                    181:        if ((GET_08(tx, MSG_ID) + 1) != GET_08(rx, MSG_ID)) {
                    182:                return P9_UNEXPECTED_MSG;
                    183:        }
                    184: 
                    185:        return 0;
                    186: }
                    187: 
                    188: /**
                    189:  * p9_version
                    190:  *
                    191:  * Called to start a session. Negotiates the maximum message size for the
                    192:  * P9 protocol.
                    193:  *
                    194:  * @param connection[in|out]   Connection object, contains message_size.
                    195:  * @return     0 = success, -ve = error.
                    196:  *
                    197:  * @remark
                    198:  * size[4] Tversion tag[2] msize[4] version[s]
                    199:  * size[4] Rversion tag[2] msize[4] version[s]
                    200:  */
                    201: int p9_version(p9_connection_t *connection)
                    202: {
                    203:        int rc;
                    204:        char *ver_str;
                    205:        int ver_len;
                    206: 
                    207:        reset_buffers();
                    208: 
                    209:        /* Build message. */
                    210:        PUT_HD(T_VERSION, NOTAG);
                    211:        PUT_32(connection->message_size);
                    212:        PUT_ST(VERSION);
                    213: 
                    214:        /* Send message. */
                    215:        rc = p9_transaction(connection);
                    216:        if (rc != 0) {
                    217:                return rc;
                    218:        }
                    219: 
                    220:        /* Handle response. */
                    221:        connection->message_size = MIN(connection->message_size,
                    222:                        GET_32(rx, MSG_VER_MSIZE));
                    223: 
                    224:        ver_str = (char *)&rx[MSG_VER_STR];
                    225:        ver_len = GET_16(rx, MSG_VER_STR_LEN);
                    226:        if (strncmp(UNKNOWN_VER, ver_str, ver_len) == 0) {
                    227:                return P9_UNKNOWN_VERSION;
                    228:        }
                    229: 
                    230: 
                    231:        return 0;
                    232: }
                    233: 
                    234: /**
                    235:  * p9_attach
                    236:  *
                    237:  * Called to open a connection for a user to a file tree on the server. There
                    238:  * is no authorisation undertaken (NOFID).
                    239:  *
                    240:  * @param connection[in|out]   Connection object, contains uname and aname as
                    241:  *     well as the connection fid and returned qid.
                    242:  * @return     0 = success, -ve = error.
                    243:  *
                    244:  * @remark
                    245:  * size[4] Tattach tag[2] fid[4] afid[4] uname[s] aname[s] n_uname[4]
                    246:  * size[4] Rattach tag[2] qid[13]
                    247:  */
                    248: int p9_attach(p9_connection_t *connection)
                    249: {
                    250:        int rc;
                    251:        int length = 19 + strlen(connection->uname) + strlen(connection->aname);
                    252: 
                    253:        if (length > connection->message_size) {
                    254:                return P9_MSG_TOO_LONG;
                    255:        }
                    256: 
                    257:        reset_buffers();
                    258: 
                    259:        /* Build message. */
                    260:        PUT_HD(T_ATTACH, TAG);
                    261:        PUT_32(connection->fid);        
                    262:        PUT_32(NOFID);
                    263:        PUT_ST(connection->uname);
                    264:        PUT_ST(connection->aname);
                    265:        PUT_32(~0); /* ??? */
                    266: 
                    267:        /* Send message. */
                    268:        rc = p9_transaction(connection);
                    269:        if (rc != 0) {
                    270:                return rc;
                    271:        }
                    272: 
                    273: 
                    274:        return 0;
                    275: }
                    276: 
                    277: /**
                    278:  * p9_clunk
                    279:  *
                    280:  * Called when closing a file or connection (or after failed opens). Tells the
                    281:  * server that the supplied fid is no longer needed by this client.
                    282:  *
                    283:  * @param connection[in|out]   Connection object.
                    284:  * @param fid[in]      Fid to be clunked (released) on the server.
                    285:  * @return     0 = success, -ve = error.
                    286:  *
                    287:  * @remark
                    288:  * size[4] Tclunk tag[2] fid[4]
                    289:  * size[4] Rclunk tag[2]
                    290:  */
                    291: int p9_clunk(p9_connection_t *connection, uint32_t fid)
                    292: {
                    293:        int rc;
                    294: 
                    295:        reset_buffers();
                    296: 
                    297:        /* Build message. */
                    298:        PUT_HD(T_CLUNK, TAG);
                    299:        PUT_32(fid);
                    300: 
                    301:        /* Send message. */
                    302:        rc = p9_transaction(connection);
                    303:        if (rc != 0) {
                    304:                return rc;
                    305:        }
                    306: 
                    307: 
                    308:        return 0;
                    309: }
                    310: 
                    311: /**
                    312:  * p9_walk
                    313:  *
                    314:  * Walk the provided path to a file (or directory) starting at the directory
                    315:  * indicated by fid and assigning new_fid to the last successfully walked
                    316:  * element. If not all elements of the path can be walked then the pos
                    317:  * pointer is set to the part of the path following the last successful
                    318:  * walked element. The function can be called again to walk the remainder
                    319:  * of the path (or produce an error).
                    320:  *
                    321:  * @param connection[in]       Connection object.
                    322:  * @param fid[in]      Fid to start walk from, must be directory or root (from
                    323:  *     call to p9_attach).
                    324:  * @param new_fid[in]  Fid to be used for the last walked element.
                    325:  * @param pos[in|out]  Position in path that remains to be walked. If the
                    326:  *     path was completely walked without error this will point to the NULL
                    327:  *     at the end of path.
                    328:  * @return     1 = partial walk, 0 = success, -ve = error.
                    329:  *
                    330:  * @remark
                    331:  * size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s])
                    332:  * size[4] Rwalk tag[2] nwqid[2] nwqid*(qid[13])
                    333:  */
                    334: int p9_walk(p9_connection_t *connection, uint32_t fid, uint32_t new_fid,
                    335:                uint8_t **pos)
                    336: {
                    337:        int rc;
                    338:        const char *path = (const char *)*pos;
                    339:        uint8_t *s_tok;
                    340:        uint8_t *e_tok;
                    341:        int element_count = 0;
                    342: 
                    343:        if (path == NULL) {
                    344:                *pos = NULL;
                    345:                return P9_NULL_PATH;
                    346:        }
                    347: 
                    348:        reset_buffers();
                    349: 
                    350:        /* Build message. */
                    351:        PUT_HD(T_WALK, TAG);    /* Length to 0, set later. */
                    352:        PUT_32(fid);
                    353:        PUT_32(new_fid);
                    354:        PUT_16(0);              /* Element count to 0, set later. */
                    355: 
                    356:        /* Get elements from path, and append to message. */
                    357:        s_tok = (uint8_t *)path;
                    358:        e_tok = s_tok;
                    359: 
                    360:        while (*s_tok != 0) {
                    361:                while (*s_tok == '/') {
                    362:                        s_tok++;
                    363:                }
                    364:                e_tok = s_tok;
                    365:                while ((*e_tok != '/') && (*e_tok != 0)) {
                    366:                        e_tok++;
                    367:                }
                    368: 
                    369:                /* Check the element is OK. */
                    370:                if (strncmp(".", (const char *)s_tok, (e_tok - s_tok)) == 0) {
                    371:                        /* Don't send ".", continue to next. */
                    372:                        s_tok = e_tok;
                    373:                        continue;
                    374:                }
                    375:                int tx_size = (e_tok - s_tok + 2 + GET_SIZE);
                    376:                int rx_size = ((element_count + 1) * MSG_QID_SIZE
                    377:                                + MSG_WALK_RX_HDR_SIZE);
                    378:                if ((tx_size > connection->message_size)
                    379:                        || (rx_size > connection->message_size)) {
                    380:                        /*
                    381:                         * Element makes TX msg too long OR expected RX msg
                    382:                         * too long. Move pos to previous element and do
                    383:                         * partial walk.
                    384:                         */
                    385:                        e_tok = s_tok;
                    386:                        if (*(e_tok - 1) == '/') {
                    387:                                e_tok--;
                    388:                        }
                    389:                        break;
                    390:                }
                    391: 
                    392:                /* Add the element to the message. */
                    393:                PUT_SN(s_tok, e_tok - s_tok);
                    394:                element_count++;
                    395: 
                    396:                /* Server supports no more than 16 elements, partial walk. */
                    397:                if (element_count == MSG_WALK_MAX_ELMT) {
                    398:                        break;
                    399:                }
                    400: 
                    401:                /* Ready to find the next element. */
                    402:                s_tok = e_tok;
                    403:        }
                    404: 
                    405:        if ((element_count == 0) && (strlen(path) > 0)) {
                    406:                return P9_PATH_ELEMENT_TOO_LONG;
                    407:        }
                    408: 
                    409:        *pos = e_tok;
                    410: 
                    411:        /* Update counts and then send message. */
                    412:        SET_16(tx, MSG_WALK_TX_ELMT, element_count);
                    413:        rc = p9_transaction(connection);
                    414:        if (rc != 0) {
                    415:                return rc;
                    416:        }
                    417: 
                    418:        /* Check for special return conditions. */
                    419:        if (element_count != GET_16(rx, MSG_WALK_RX_ELMT)) {
                    420:                /* Find the last element successfully walked */
                    421:                s_tok = (uint8_t *)path;
                    422:                e_tok = s_tok;
                    423:                element_count = GET_16(rx, MSG_WALK_RX_ELMT);
                    424: 
                    425:                while (element_count--) {
                    426:                        while (*s_tok == '/') {
                    427:                                s_tok++;
                    428:                        }
                    429: 
                    430:                        e_tok = s_tok;
                    431: 
                    432:                        while ((*e_tok != '/') && (*e_tok != 0)) {
                    433:                                e_tok++;
                    434:                        }
                    435: 
                    436:                        s_tok = e_tok;
                    437:                }
                    438: 
                    439:                *pos = e_tok;
                    440:        }
                    441:        if (**pos != 0) {
                    442:                rc = P9_PARTIAL_WALK;
                    443:        }
                    444: 
                    445: 
                    446:        return rc;
                    447: }
                    448: 
                    449: /**
                    450:  * p9_open
                    451:  *
                    452:  * Opens the file represented by fid with associated mode bit mask. The iounit
                    453:  * size returned from the server is written to the connection object.
                    454:  *
                    455:  * @param file[in|out] File object, contains fid for file.
                    456:  * @param mode[in]     Mode to open with. Bit's 0=R, 1=W, 2=RW, 3=EX, 4=Trunc
                    457:  *     and 6=Delete on Close.
                    458:  * @return     0 = success, -ve = error.
                    459:  *
                    460:  * @remark
                    461:  * size[4] Topen tag[2] fid[4] mode[1]
                    462:  * size[4] Ropen tag[2] qid[13] iounit[4]
                    463:  */
                    464: int p9_open(p9_file_t *file, uint8_t mode)
                    465: {
                    466:        int rc;
                    467:        p9_connection_t *connection = file->connection;
                    468: 
                    469:        reset_buffers();
                    470:        file->iounit = 0;
                    471: 
                    472:        /* Build message. */
                    473:        PUT_HD(T_OPEN, TAG);
                    474:        PUT_32(file->fid);
                    475:        PUT_08(mode & MSG_OPEN_MODE_MASK);
                    476: 
                    477:        /* Send message. */
                    478:        rc = p9_transaction(connection);
                    479:        if (rc != 0) {
                    480:                return rc;
                    481:        }
                    482: 
                    483:        /* Handle response. */
                    484:        file->iounit = GET_32(rx, MSG_OPEN_IOUNIT);
                    485: 
                    486: 
                    487:        return 0;
                    488: }
                    489: 
                    490: /**
                    491:  * p9_read
                    492:  *
                    493:  * Reads the file in to buffer.
                    494:  *
                    495:  * @param file[in]     File object, contains fid for file.
                    496:  * @param buffer[out]  Buffer for data.
                    497:  * @param count[in]    Number of bytes to read (less bytes than requested
                    498:  *      may be read).
                    499:  * @param offset[in]   Offset in file to read from.
                    500:  * @return     Bytes read, -ve = error.
                    501:  *
                    502:  * @remark
                    503:  * size[4] Tread tag[2] fid[4] offset[8] count[4]
                    504:  * size[4] Rread tag[2] count[4] data[count]
                    505:  */
                    506: int p9_read(p9_file_t *file, uint8_t *buffer,
                    507:                uint32_t count, uint64_t offset)
                    508: {
                    509:        int rc;
                    510:        p9_connection_t *connection = file->connection;
                    511:        uint32_t got;
                    512: 
                    513:        reset_buffers();
                    514:        count = MIN((connection->message_size - MSG_READ_DATA), count);
                    515: 
                    516:        /* Build message. */
                    517:        PUT_HD(T_READ, TAG);
                    518:        PUT_32(file->fid);
                    519:        PUT_64(offset);
                    520:        PUT_32(count);
                    521: 
                    522:        /* Send message. */
                    523:        rc = p9_transaction(connection);
                    524:        if (rc != 0) {
                    525:                return rc;
                    526:        }
                    527:        got = GET_32(rx, MSG_READ_COUNT);
                    528:        if (got > count) {
                    529:                return P9_READ_UNEXPECTED_DATA;
                    530:        }
                    531: 
                    532:        /* Handle response. */
                    533:        memcpy(buffer, &rx[MSG_READ_DATA], got);
                    534: 
                    535:        return got;
                    536: }
                    537: 
                    538: /**
                    539:  * p9_stat
                    540:  *
                    541:  * Stat's the fid and writes the type and length to the file object.
                    542:  *
                    543:  * @param file[in|out] File object, contains fid for file.
                    544:  * @return     0 = success, -ve = error.
                    545:  *
                    546:  * @remark
                    547:  * size[4] Tstat tag[2] fid[4]
                    548:  * size[4] Rstat tag[2] size[2] stat[n]
                    549:  */
                    550: int p9_stat(p9_file_t *file)
                    551: {
                    552:        int rc;
                    553:        p9_connection_t *connection = file->connection;
                    554: 
                    555:        reset_buffers();
                    556:        file->length = 0;
                    557:        file->type = 0;
                    558: 
                    559:        /* Build message. */
                    560:        PUT_HD(T_STAT, TAG);
                    561:        PUT_32(file->fid);
                    562: 
                    563:        /* Send message. */
                    564:        rc = p9_transaction(connection);
                    565:        if (rc != 0) {
                    566:                return rc;
                    567:        }
                    568: 
                    569:        /* Handle response. */
                    570:        file->length = GET_64(rx, MSG_STAT_LEN);
                    571:        file->type = GET_08(rx, MSG_STAT_TYPE);
                    572: 
                    573: 
                    574:        return 0;
                    575: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.