Annotation of qemu/roms/SLOF/lib/libvirtio/p9.c, revision 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.