เอกสารอ้างอิง Trusty API

Trusty มี API สำหรับการพัฒนาแอปและบริการ 2 ระดับ ได้แก่

  • แอปและบริการที่เชื่อถือได้ซึ่งทำงานบนโปรเซสเซอร์ TEE
  • แอปทั่วไปและแอปที่ไม่น่าเชื่อถือที่ทำงานบนโปรเซสเซอร์หลักและใช้บริการที่แอปที่เชื่อถือได้จัดหาให้

โดยทั่วไปแล้ว Trusty API จะอธิบายระบบการสื่อสารระหว่างกระบวนการ (IPC) ของ Trusty รวมถึงการสื่อสารกับโลกที่ไม่ปลอดภัย ซอฟต์แวร์ที่ทำงานบนตัวประมวลผลหลักสามารถใช้ Trusty API เพื่อเชื่อมต่อกับแอปและบริการที่เชื่อถือได้ และแลกเปลี่ยนข้อความกับแอปและบริการเหล่านั้นได้เช่นเดียวกับบริการเครือข่ายผ่าน IP โดยแอปจะเป็นผู้กำหนดรูปแบบข้อมูลและความหมายของข้อความเหล่านี้โดยใช้โปรโตคอลระดับแอป การส่งข้อความที่เชื่อถือได้ได้รับการรับประกันโดยโครงสร้างพื้นฐาน Trusty ที่อยู่เบื้องหลัง (ในรูปแบบของไดรเวอร์ที่ทำงานบนโปรเซสเซอร์หลัก) และการสื่อสารเป็นแบบไม่พร้อมกันโดยสมบูรณ์

พอร์ตและช่อง

แอปที่เชื่อถือได้จะใช้พอร์ตเพื่อแสดงปลายทางบริการในรูปแบบเส้นทางที่มีชื่อซึ่งไคลเอ็นต์เชื่อมต่อ ซึ่งจะให้รหัสบริการแบบสตริงที่เรียบง่ายสำหรับไคลเอ็นต์ รูปแบบการตั้งชื่อเป็นแบบ DNS แบบย้อนกลับ เช่น com.google.servicename

เมื่อไคลเอ็นต์เชื่อมต่อกับพอร์ต ไคลเอ็นต์จะได้รับช่องทางสำหรับการโต้ตอบกับบริการ บริการต้องยอมรับการเชื่อมต่อขาเข้า และเมื่อยอมรับแล้ว บริการก็จะได้รับช่องด้วย โดยพื้นฐานแล้ว พอร์ตจะใช้เพื่อค้นหาบริการ จากนั้นการสื่อสารจะเกิดขึ้นผ่านคู่แชแนลที่เชื่อมต่อกัน (เช่น อินสแตนซ์การเชื่อมต่อบนพอร์ต) เมื่อไคลเอ็นต์เชื่อมต่อกับพอร์ต ระบบจะสร้างการเชื่อมต่อแบบ 2 ทิศทางแบบสมมาตร เมื่อใช้เส้นทางแบบ Full-Duplex นี้ ไคลเอ็นต์และเซิร์ฟเวอร์จะแลกเปลี่ยนข้อความแบบใดก็ได้จนกว่าฝ่ายใดฝ่ายหนึ่งจะตัดสินใจปิดการเชื่อมต่อ

เฉพาะแอปที่เชื่อถือได้ฝั่งที่ปลอดภัยหรือโมดูลเคอร์เนล Trusty เท่านั้นที่สร้างพอร์ตได้ แอปที่ทำงานในด้านที่ไม่ปลอดภัย (ในโลกปกติ) จะเชื่อมต่อได้เฉพาะกับบริการที่เผยแพร่โดยฝั่งที่ปลอดภัย

แอปที่เชื่อถือได้อาจเป็นทั้งไคลเอ็นต์และเซิร์ฟเวอร์ในเวลาเดียวกัน ทั้งนี้ขึ้นอยู่กับข้อกำหนด แอปที่เชื่อถือได้ซึ่งเผยแพร่บริการ (ในฐานะเซิร์ฟเวอร์) อาจต้องเชื่อมต่อกับบริการอื่นๆ (ในฐานะไคลเอ็นต์)

Handle API

แฮนเดิลคือจำนวนเต็มแบบไม่ลงนามที่แสดงถึงทรัพยากร เช่น พอร์ตและแชแนล ซึ่งคล้ายกับตัวระบุไฟล์ใน UNIX หลังจากสร้างแฮนเดิลแล้ว ระบบจะใส่แฮนเดิลเหล่านั้นลงในตารางแฮนเดิลเฉพาะแอปและสามารถอ้างอิงภายหลังได้

ผู้เรียกสามารถเชื่อมโยงข้อมูลส่วนตัวกับแฮนเดิลได้โดยใช้เมธอด set_cookie()

เมธอดใน Handle API

แฮนเดิลจะใช้ได้เฉพาะในบริบทของแอปเท่านั้น แอปไม่ควรส่งค่าของแฮนเดิลไปยังแอปอื่นๆ เว้นแต่จะระบุไว้อย่างชัดเจน ค่าของแฮนเดิลควรตีความโดยการเปรียบเทียบกับ INVALID_IPC_HANDLE #define, เท่านั้น ซึ่งแอปสามารถใช้เป็นข้อบ่งชี้ว่าแฮนเดิลไม่ถูกต้องหรือไม่ได้รับการตั้งค่า

เชื่อมโยงข้อมูลส่วนตัวที่ผู้โทรระบุไว้กับแฮนเดิลที่ระบุ

long set_cookie(uint32_t handle, void *cookie)

[in] handle: แฮนเดิลที่การเรียก API ใดเรียกให้แสดง

[in] cookie: ตัวชี้ไปยังข้อมูลพื้นที่ผู้ใช้แบบไม่เจาะจงในแอป Trusty

[retval]: NO_ERROR เมื่อดำเนินการสำเร็จ หรือ < 0 เมื่อดำเนินการไม่สำเร็จ

การเรียกใช้นี้จะมีประโยชน์ในการจัดการเหตุการณ์เมื่อเกิดขึ้นในภายหลังหลังจากที่สร้างแฮนเดิลแล้ว กลไกการจัดการเหตุการณ์จะส่งแฮนเดิลและคุกกี้ของแฮนเดิลกลับไปยังตัวจัดการเหตุการณ์

คุณสามารถรอเหตุการณ์โดยใช้การเรียก wait()

wait()

รอให้เหตุการณ์เกิดขึ้นในแฮนเดิลที่ระบุเป็นระยะเวลาที่กําหนด

long wait(uint32_t handle_id, uevent_t *event, unsigned long timeout_msecs)

[in] handle_id: แฮนเดิลที่การเรียก API ใดเรียกให้แสดง

[out] event: ตัวชี้ไปยังโครงสร้างที่แสดงถึงเหตุการณ์ที่เกิดขึ้นในแฮนเดิลนี้

[in] timeout_msecs: ค่าการหมดเวลาเป็นมิลลิวินาที ค่า -1 หมายถึงการหมดเวลาแบบไม่จำกัด

[retval]: NO_ERROR หากเหตุการณ์ที่ถูกต้องเกิดขึ้นภายในช่วงเวลาหมดเวลาที่ระบุ ERR_TIMED_OUT หากหมดเวลาตามที่ระบุแล้ว แต่ไม่มีเหตุการณ์เกิดขึ้น < 0 สำหรับข้อผิดพลาดอื่นๆ

เมื่อดำเนินการสำเร็จ (retval == NO_ERROR) การเรียก wait() จะเติมโครงสร้าง uevent_t ที่ระบุด้วยข้อมูลเกี่ยวกับเหตุการณ์ที่เกิดขึ้น

typedef struct uevent {
    uint32_t handle; /* handle this event is related to */
    uint32_t event;  /* combination of IPC_HANDLE_POLL_XXX flags */
    void    *cookie; /* cookie associated with this handle */
} uevent_t;

ฟิลด์ event มีชุดค่าผสมต่อไปนี้

enum {
  IPC_HANDLE_POLL_NONE    = 0x0,
  IPC_HANDLE_POLL_READY   = 0x1,
  IPC_HANDLE_POLL_ERROR   = 0x2,
  IPC_HANDLE_POLL_HUP     = 0x4,
  IPC_HANDLE_POLL_MSG     = 0x8,
  IPC_HANDLE_POLL_SEND_UNBLOCKED = 0x10,
   more values[TBD]
};

IPC_HANDLE_POLL_NONE - ไม่มีเหตุการณ์ที่รอดำเนินการจริง ๆ ผู้โทรควรเริ่มการรอใหม่

IPC_HANDLE_POLL_ERROR - เกิดข้อผิดพลาดภายในที่ไม่ได้ระบุ

IPC_HANDLE_POLL_READY - ขึ้นอยู่กับประเภทแฮนเดิล ดังนี้

  • สําหรับพอร์ต ค่านี้จะระบุว่ามีการเชื่อมต่อที่รอดำเนินการ
  • สำหรับแชแนล ค่านี้บ่งบอกว่ามีการสร้างการเชื่อมต่อแบบไม่ประสานเวลา (ดู connect())

เหตุการณ์ต่อไปนี้เกี่ยวข้องกับช่องเท่านั้น

  • IPC_HANDLE_POLL_HUP - ระบุว่าช่องถูกปิดโดยบุคคลอื่น
  • IPC_HANDLE_POLL_MSG - บ่งบอกว่ามีข้อความที่รอดำเนินการสำหรับช่องนี้
  • IPC_HANDLE_POLL_SEND_UNBLOCKED - บ่งบอกว่าผู้โทรที่ก่อนหน้านี้ถูกบล็อกไม่ให้ส่งข้อความอาจพยายามส่งข้อความอีกครั้ง (ดูรายละเอียดของ send_msg())

ควรเตรียมตัวให้พร้อมสำหรับตัวแฮนเดิลเหตุการณ์เพื่อจัดการชุดค่าผสมของเหตุการณ์ที่ระบุ เนื่องจากอาจมีการตั้งค่าหลายบิตพร้อมกัน ตัวอย่างเช่น แชแนลหนึ่งอาจมีข้อความที่รอดำเนินการและการเชื่อมต่อที่ปิดโดยพาร์ทเนอร์พร้อมกัน

เหตุการณ์ส่วนใหญ่จะติดอยู่ โดยจะยังคงอยู่ตราบใดที่เงื่อนไขพื้นฐานยังคงอยู่ (เช่น ได้รับข้อความที่รอดำเนินการทั้งหมดและจัดการคําขอการเชื่อมต่อที่รอดําเนินการ) ยกเว้นในกรณีที่มีเหตุการณ์ IPC_HANDLE_POLL_SEND_UNBLOCKED ซึ่งจะล้างออกเมื่ออ่าน และแอปมีเพียง 1 โอกาสในการจัดการ

คุณทำลายแฮนเดิลได้โดยเรียกใช้เมธอด close()

close()

ทำลายทรัพยากรที่เชื่อมโยงกับแฮนเดิลที่ระบุและนำออกจากตารางแฮนเดิล

long close(uint32_t handle_id);

[in] handle_id: แฮนเดิลสำหรับทำลาย

[retval]: 0 หากสําเร็จ หากไม่สําเร็จจะเป็นค่าลบ

Server API

เซิร์ฟเวอร์จะเริ่มด้วยการสร้างพอร์ตที่มีชื่ออย่างน้อย 1 พอร์ต ซึ่งแสดงถึงปลายทางบริการ พอร์ตแต่ละพอร์ตจะแสดงด้วยแฮนเดิล

เมธอดใน Server API

port_create()

สร้างพอร์ตบริการที่มีชื่อ

long port_create (const char *path, uint num_recv_bufs, size_t recv_buf_size,
uint32_t flags)

[in] path: ชื่อสตริงของพอร์ต (ตามที่อธิบายไว้ข้างต้น) ชื่อนี้ควรไม่ซ้ำกันทั่วทั้งระบบ การสร้างชื่อที่ซ้ำกันจะไม่สำเร็จ

[in] num_recv_bufs: จํานวนบัฟเฟอร์สูงสุดที่แชแนลในพอร์ตนี้สามารถจัดสรรล่วงหน้าเพื่ออำนวยความสะดวกในการแลกเปลี่ยนข้อมูลกับไคลเอ็นต์ ระบบจะนับบัฟเฟอร์แยกกันสำหรับข้อมูลที่ส่งและรับในทั้ง 2 ทิศทาง ดังนั้นการระบุ 1 ที่นี่จะหมายถึงมีการจองบัฟเฟอร์การส่ง 1 รายการและบัฟเฟอร์การรับ 1 รายการไว้ล่วงหน้า โดยทั่วไปแล้ว จำนวนบัฟเฟอร์ที่จําเป็นจะขึ้นอยู่กับข้อตกลงโปรโตคอลระดับที่สูงขึ้นระหว่างไคลเอ็นต์กับเซิร์ฟเวอร์ ตัวเลขนี้อาจเป็นเพียง 1 ในกรณีของโปรโตคอลแบบซิงค์กันมาก (ส่งข้อความ รับการตอบกลับก่อนที่จะส่งข้อความอื่น) แต่จำนวนนี้อาจมากกว่าได้หากไคลเอ็นต์คาดว่าจะส่งข้อความมากกว่า 1 รายการก่อนที่การตอบกลับจะปรากฏขึ้น (เช่น ข้อความ 1 รายการเป็นคำนำและอีกข้อความเป็นคำสั่งจริง) ชุดบัฟเฟอร์ที่จัดสรรจะจัดสรรตามช่อง ดังนั้นการเชื่อมต่อ (ช่อง) 2 ช่องแยกกันจะมีชุดบัฟเฟอร์แยกกัน

[in] recv_buf_size: ขนาดสูงสุดของบัฟเฟอร์แต่ละรายการในชุดบัฟเฟอร์ข้างต้น ค่านี้ขึ้นอยู่กับโปรโตคอลและจำกัดขนาดข้อความสูงสุดที่คุณสามารถแลกเปลี่ยนกับคู่สนทนาได้อย่างมีประสิทธิภาพ

[in] flags: ชุดค่าผสมของ Flag ที่ระบุลักษณะการทํางานเพิ่มเติมของพอร์ต

ค่านี้ควรเป็นชุดค่าผสมของค่าต่อไปนี้

IPC_PORT_ALLOW_TA_CONNECT - อนุญาตการเชื่อมต่อจากแอปที่ปลอดภัยอื่นๆ

IPC_PORT_ALLOW_NS_CONNECT - อนุญาตการเชื่อมต่อจากโลกที่ไม่ปลอดภัย

[retval]: แฮนเดิลของพอร์ตที่สร้างหากไม่ใช่ค่าลบ หรือข้อผิดพลาดที่เฉพาะเจาะจงหากเป็นค่าลบ

จากนั้นเซิร์ฟเวอร์จะตรวจสอบรายการแฮนเดิลพอร์ตเพื่อหาการเชื่อมต่อขาเข้าโดยใช้การเรียก wait() เมื่อได้รับคำขอเชื่อมต่อที่ระบุโดยบิต IPC_HANDLE_POLL_READY ที่กําหนดไว้ในช่อง event ของโครงสร้าง uevent_t เซิร์ฟเวอร์ควรเรียกใช้ accept() เพื่อเชื่อมต่อให้เสร็จสมบูรณ์และสร้างแชแนล (แสดงโดยแฮนเดิลอื่น) ซึ่งจะทำการสำรวจหาข้อความขาเข้าได้

accept()

ยอมรับการเชื่อมต่อขาเข้าและรับแฮนเดิลของช่อง

long accept(uint32_t handle_id, uuid_t *peer_uuid);

[in] handle_id: แฮนเดิลที่แสดงพอร์ตที่ไคลเอ็นต์เชื่อมต่ออยู่

[out] peer_uuid: ตัวชี้ไปยังโครงสร้าง uuid_t เพื่อป้อน UUID ของแอปไคลเอ็นต์ที่เชื่อมต่อ ระบบจะตั้งค่าเป็น 0 ทั้งหมดหากการเชื่อมต่อมาจากโลกที่ไม่ปลอดภัย

[retval]: แฮนเดิลของแชแนล (หากไม่ใช่ค่าลบ) ที่เซิร์ฟเวอร์สามารถแลกเปลี่ยนข้อความกับไคลเอ็นต์ได้ (หรือรหัสข้อผิดพลาด)

Client API

ส่วนนี้มีเมธอดใน Client API

เมธอดใน Client API

connect()

เริ่มการเชื่อมต่อกับพอร์ตที่ระบุด้วยชื่อ

long connect(const char *path, uint flags);

[in] path: ชื่อพอร์ตที่เผยแพร่โดยแอปที่เชื่อถือได้

[in] flags: ระบุลักษณะการทำงานเพิ่มเติมที่ไม่บังคับ

[retval]: แฮนเดิลของแชแนลที่ใช้แลกเปลี่ยนข้อความกับเซิร์ฟเวอร์ได้ แสดงข้อผิดพลาดหากเป็นค่าลบ

หากไม่ได้ระบุ flags (มีการตั้งค่าพารามิเตอร์ flags เป็น 0) การเรียกใช้ connect() จะเริ่มต้นการเชื่อมต่อแบบซิงค์กับพอร์ตที่ระบุ ซึ่งจะแสดงข้อผิดพลาดทันทีหากไม่มีพอร์ตนั้น และสร้างบล็อกจนกว่าเซิร์ฟเวอร์จะยอมรับการเชื่อมต่อ

คุณเปลี่ยนลักษณะการทํางานนี้ได้โดยระบุค่า 2 ค่าร่วมกันตามที่อธิบายไว้ด้านล่าง

enum {
IPC_CONNECT_WAIT_FOR_PORT = 0x1,
IPC_CONNECT_ASYNC = 0x2,
};

IPC_CONNECT_WAIT_FOR_PORT - บังคับให้connect() การเรียกใช้รอหากพอร์ตที่ระบุไม่อยู่ในการเรียกใช้ทันทีแทนที่จะดำเนินการไม่สำเร็จทันที

IPC_CONNECT_ASYNC - หากตั้งค่าไว้ ระบบจะเริ่มการเชื่อมต่อแบบไม่พร้อมกัน แอปต้องตรวจสอบหาตัวแฮนเดิลที่แสดงผลโดยเรียกใช้ wait() เพื่อดูเหตุการณ์การเชื่อมต่อที่เสร็จสมบูรณ์ซึ่งระบุโดยบิต IPC_HANDLE_POLL_READY ที่กําหนดไว้ในช่องเหตุการณ์ของโครงสร้าง uevent_t ก่อนเริ่มการทํางานตามปกติ

Messaging API

การเรียก Messaging API ช่วยให้สามารถส่งและอ่านข้อความผ่านการเชื่อมต่อ (แชแนล) ที่ตั้งไว้ก่อนหน้านี้ การเรียก Messaging API จะเหมือนกันสำหรับเซิร์ฟเวอร์และไคลเอ็นต์

ไคลเอ็นต์จะได้รับแฮนเดิลของช่องโดยการเรียกใช้connect() และเซิร์ฟเวอร์จะได้รับแฮนเดิลของช่องจากการเรียกใช้ accept() ตามที่อธิบายไว้ข้างต้น

โครงสร้างของข้อความที่เชื่อถือได้

ดังที่แสดงต่อไปนี้ ข้อความที่ Trusty API แลกเปลี่ยนกันจะมีโครงสร้างน้อยที่สุด โดยปล่อยให้เซิร์ฟเวอร์และไคลเอ็นต์ตกลงกันเรื่องความหมายของเนื้อหาจริง

/*
 *  IPC message
 */
typedef struct iovec {
        void   *base;
        size_t  len;
} iovec_t;

typedef struct ipc_msg {
        uint     num_iov; /* number of iovs in this message */
        iovec_t  *iov;    /* pointer to iov array */

        uint     num_handles; /* reserved, currently not supported */
        handle_t *handles;    /* reserved, currently not supported */
} ipc_msg_t;

ข้อความอาจประกอบด้วยบัฟเฟอร์ที่ไม่ต่อเนื่องอย่างน้อย 1 รายการที่แสดงโดยอาร์เรย์ของโครงสร้าง iovec_t Trusty จะทำการกระจายรวบรวมข้อมูลอ่านและเขียนลงในบล็อกเหล่านี้โดยใช้อาร์เรย์ iov เนื้อหาของบัฟเฟอร์ที่อธิบายได้ด้วยอาร์เรย์ iov นั้นขึ้นอยู่กับผู้ใช้

เมธอดใน Messaging API

send_msg()

ส่งข้อความผ่านช่องทางที่ระบุ

long send_msg(uint32_t handle, ipc_msg_t *msg);

[in] handle: แฮนเดิลของช่องที่จะส่งข้อความ

[in] msg: ตัวชี้ไปยัง ipc_msg_t structure ที่อธิบายข้อความ

[retval]: จํานวนไบต์ทั้งหมดที่ส่งเมื่อสําเร็จ หากไม่สําเร็จจะเป็นค่าลบ

หากไคลเอ็นต์ (หรือเซิร์ฟเวอร์) พยายามส่งข้อความผ่านแชแนลและไม่มีที่ว่างในคิวข้อความของคู่ปลายทาง แชแนลอาจเข้าสู่สถานะการส่งถูกบล็อก (ซึ่งไม่ควรเกิดขึ้นกับโปรโตคอลคำขอ/ตอบแบบซิงค์ที่เรียบง่าย แต่อาจเกิดขึ้นในกรณีที่ซับซ้อนมากขึ้น) ซึ่งจะแสดงโดยการส่งรหัสข้อผิดพลาด ERR_NOT_ENOUGH_BUFFER ในกรณีเช่นนี้ ผู้เรียกต้องรอจนกว่าพาร์ทเนอร์จะเพิ่มพื้นที่ว่างในคิวรับโดยดึงข้อมูลการจัดการและข้อความที่เลิกใช้งาน ซึ่งระบุโดยบิต IPC_HANDLE_POLL_SEND_UNBLOCKED ที่กําหนดไว้ในช่อง event ของโครงสร้าง uevent_t ที่การเรียก wait() แสดงผล

get_msg()

รับข้อมูลเมตาเกี่ยวกับข้อความถัดไปในคิวข้อความขาเข้า

ของช่องที่ระบุ

long get_msg(uint32_t handle, ipc_msg_info_t *msg_info);

[in] handle: แฮนเดิลของช่องที่ต้องดึงข้อมูลข้อความใหม่

[out] msg_info: โครงสร้างข้อมูลข้อความที่อธิบายไว้ดังนี้

typedef struct ipc_msg_info {
        size_t    len;  /* total message length */
        uint32_t  id;   /* message id */
} ipc_msg_info_t;

แต่ละข้อความจะได้รับรหัสที่ไม่ซ้ำกันจากชุดข้อความที่รอดำเนินการ และระบบจะกรอกความยาวทั้งหมดของข้อความแต่ละรายการ หากมีการกําหนดค่าและโปรโตคอลอนุญาต ช่องหนึ่งๆ อาจมีข้อความที่รอดําเนินการ (เปิดอยู่) หลายรายการพร้อมกันได้

[retval]: NO_ERROR หากสำเร็จ หรือข้อผิดพลาดเชิงลบหากไม่สำเร็จ

read_msg()

อ่านเนื้อหาของข้อความที่มีรหัสที่ระบุโดยเริ่มจากออฟเซตที่ระบุ

long read_msg(uint32_t handle, uint32_t msg_id, uint32_t offset, ipc_msg_t
*msg);

[in] handle: แฮนเดิลของช่องที่จะอ่านข้อความ

[in] msg_id: รหัสของข้อความที่จะอ่าน

[in] offset: ส่วนเพิ่มในข้อความที่จะเริ่มต้นอ่าน

[out] msg: ตัวชี้ไปยังโครงสร้าง ipc_msg_t ที่อธิบายชุดบัฟเฟอร์สำหรับจัดเก็บข้อมูลข้อความขาเข้า

[retval]: จํานวนไบต์ทั้งหมดที่จัดเก็บไว้ในบัฟเฟอร์ msg เมื่อดำเนินการสำเร็จ หากไม่สำเร็จ ระบบจะแสดงข้อผิดพลาดเชิงลบ

เรียกเมธอด read_msg ได้หลายครั้งโดยเริ่มจากออฟเซตอื่น (ไม่จำเป็นต้องเรียงตามลำดับ) ตามต้องการ

put_msg()

เลิกใช้งานข้อความที่มีรหัสที่ระบุ

long put_msg(uint32_t handle, uint32_t msg_id);

[in] handle: แฮนเดิลของช่องที่ได้รับข้อความ

[in] msg_id: รหัสของข้อความที่จะเลิกใช้งาน

[retval]: NO_ERROR หากสำเร็จ หรือข้อผิดพลาดเชิงลบหากไม่สำเร็จ

คุณจะเข้าถึงเนื้อหาข้อความไม่ได้หลังจากที่ข้อความถูกนำออกแล้ว และมีการปล่อยบัฟเฟอร์ที่ข้อความนั้นใช้อยู่

File Descriptor API

File Descriptor API มีการเรียก read(), write() และ ioctl() การเรียกใช้ทั้งหมดเหล่านี้สามารถทํางานกับชุดตัวบ่งชี้ไฟล์ (แบบคงที่) ที่กําหนดไว้ล่วงหน้า ซึ่งตามปกติจะแสดงด้วยตัวเลขเล็กๆ ในการใช้งานปัจจุบัน พื้นที่ตัวระบุไฟล์จะแยกจากพื้นที่แฮนเดิล IPC File Descriptor API ใน Trusty จะคล้ายกับ API แบบดั้งเดิมที่ใช้ File Descriptor

โดยค่าเริ่มต้นจะมีตัวระบุไฟล์ (มาตรฐานและที่รู้จักกันดี) ที่กําหนดไว้ล่วงหน้า 3 รายการ ดังนี้

  • 0 - อินพุตมาตรฐาน การใช้งานเริ่มต้นของอินพุตมาตรฐาน fd จะเป็นการดำเนินการที่ไม่มีผล (เนื่องจากแอปที่เชื่อถือได้ไม่ควรมีคอนโซลแบบอินเทอร์แอกทีฟ) ดังนั้นการอ่าน การเขียน หรือเรียกใช้ ioctl() ใน fd 0 ควรแสดงข้อผิดพลาด ERR_NOT_SUPPORTED
  • 1 - เอาต์พุตมาตรฐาน ระบบสามารถกำหนดเส้นทางข้อมูลที่เขียนไปยังเอาต์พุตมาตรฐาน (ขึ้นอยู่กับระดับการแก้ไขข้อบกพร่องของ LK) ไปยัง UART และ/หรือบันทึกหน่วยความจำที่มีอยู่ในฝั่งที่ไม่ปลอดภัย ทั้งนี้ขึ้นอยู่กับแพลตฟอร์มและการกำหนดค่า บันทึกการแก้ไขข้อบกพร่องและข้อความที่ไม่ร้ายแรงควรอยู่ในเอาต์พุตมาตรฐาน เมธอด read() และ ioctl() จะไม่ทํางานและควรแสดงข้อผิดพลาด ERR_NOT_SUPPORTED
  • 2 - ข้อผิดพลาดมาตรฐาน ข้อมูลที่เขียนไปยังข้อผิดพลาดมาตรฐานควรกำหนดเส้นทางไปยัง UART หรือบันทึกหน่วยความจำที่มีอยู่ในฝั่งที่ไม่ปลอดภัย ทั้งนี้ขึ้นอยู่กับแพลตฟอร์มและการกำหนดค่า ขอแนะนําให้เขียนเฉพาะข้อความสําคัญไปยังมาตรฐานข้อผิดพลาด เนื่องจากสตรีมนี้มีแนวโน้มที่จะไม่มีการจํากัดอย่างมาก เมธอด read() และ ioctl() จะไม่ทําการใดๆ และควรแสดงข้อผิดพลาด ERR_NOT_SUPPORTED

แม้ว่าชุดตัวระบุไฟล์นี้จะขยายเพื่อใช้งานเพิ่มเติมได้fds (เพื่อใช้งานส่วนขยายเฉพาะแพลตฟอร์ม) แต่คุณควรใช้ตัวระบุไฟล์แบบขยายด้วยความระมัดระวัง การขยายตัวบ่งชี้ไฟล์มีแนวโน้มที่จะทำให้เกิดข้อขัดแย้ง และโดยทั่วไปเราไม่แนะนําให้ทำ

เมธอดใน File Descriptor API

read()

พยายามอ่านข้อมูลสูงสุด count ไบต์จากตัวระบุไฟล์ที่ระบุ

long read(uint32_t fd, void *buf, uint32_t count);

[in] fd: ตัวบอกไฟล์ที่จะอ่าน

[out] buf: ตัวชี้ไปยังบัฟเฟอร์ที่จะจัดเก็บข้อมูล

[in] count: จํานวนไบต์สูงสุดที่จะอ่าน

[retval]: จำนวนไบต์ที่อ่านได้ หากไม่สำเร็จ ระบบจะแสดงข้อผิดพลาดเชิงลบ

write()

เขียนข้อมูลสูงสุด count ไบต์ไปยังตัวระบุไฟล์ที่ระบุ

long write(uint32_t fd, void *buf, uint32_t count);

[in] fd: ตัวระบุไฟล์ที่จะเขียน

[out] buf: ตัวชี้ไปยังข้อมูลที่จะเขียน

[in] count: จํานวนไบต์สูงสุดที่จะเขียน

[retval]: จำนวนไบต์ที่เขียนแล้วที่แสดงผล หากไม่แสดงผล ระบบจะแสดงข้อผิดพลาดเชิงลบ

ioctl()

เรียกใช้คำสั่ง ioctl ที่ระบุสำหรับตัวระบุไฟล์ที่ระบุ

long ioctl(uint32_t fd, uint32_t cmd, void *args);

[in] fd: ตัวระบุไฟล์ที่จะเรียกใช้ ioctl()

[in] cmd: คำสั่ง ioctl

[เข้า/ออก] args: ตัวชี้ไปยังอาร์กิวเมนต์ ioctl()

API อื่นๆ

เมธอดใน Miscellaneous API

gettime()

แสดงเวลาปัจจุบันของระบบ (เป็นนาโนวินาที)

long gettime(uint32_t clock_id, uint32_t flags, int64_t *time);

[in] clock_id: ขึ้นอยู่กับแพลตฟอร์ม ให้ส่งค่า 0 เป็นค่าเริ่มต้น

[in] flags: สงวนไว้ ควรเป็น 0

[out] time: ตัวชี้ไปยังค่า int64_t สำหรับจัดเก็บเวลาปัจจุบัน

[retval]: NO_ERROR หากสำเร็จ หรือข้อผิดพลาดเชิงลบหากไม่สำเร็จ

nanosleep()

ระงับการเรียกใช้แอปการโทรเป็นระยะเวลาหนึ่งตามที่ระบุไว้ และกลับมาทำงานต่อหลังจากระยะเวลาดังกล่าว

long nanosleep(uint32_t clock_id, uint32_t flags, uint64_t sleep_time)

[in] clock_id: สงวนไว้ ควรเป็น 0

[in] flags: สงวนไว้ ควรเป็น 0

[in] sleep_time: เวลาพักเป็นนาโนวินาที

[retval]: NO_ERROR หากสำเร็จ หรือข้อผิดพลาดเชิงลบหากไม่สำเร็จ

ตัวอย่างเซิร์ฟเวอร์แอปที่เชื่อถือได้

แอปตัวอย่างต่อไปนี้แสดงการใช้งาน API ข้างต้น ตัวอย่างนี้จะสร้างบริการ "echo" ที่จัดการการเชื่อมต่อขาเข้าหลายรายการ และแสดงข้อความทั้งหมดที่ได้รับจากไคลเอ็นต์ซึ่งมาจากฝั่งที่ปลอดภัยหรือไม่ปลอดภัยกลับไปยังผู้เรียก

#include <uapi/err.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <trusty_ipc.h>
#define LOG_TAG "echo_srv"
#define TLOGE(fmt, ...) \
    fprintf(stderr, "%s: %d: " fmt, LOG_TAG, __LINE__, ##__VA_ARGS__)

# define MAX_ECHO_MSG_SIZE 64

static
const char * srv_name = "com.android.echo.srv.echo";

static uint8_t msg_buf[MAX_ECHO_MSG_SIZE];

/*
 *  Message handler
 */
static int handle_msg(handle_t chan) {
  int rc;
  struct iovec iov;
  ipc_msg_t msg;
  ipc_msg_info_t msg_inf;

  iov.iov_base = msg_buf;
  iov.iov_len = sizeof(msg_buf);

  msg.num_iov = 1;
  msg.iov = &iov;
  msg.num_handles = 0;
  msg.handles = NULL;

  /* get message info */
  rc = get_msg(chan, &msg_inf);
  if (rc == ERR_NO_MSG)
    return NO_ERROR; /* no new messages */

  if (rc != NO_ERROR) {
    TLOGE("failed (%d) to get_msg for chan (%d)\n",
      rc, chan);
    return rc;
  }

  /* read msg content */
  rc = read_msg(chan, msg_inf.id, 0, &msg);
  if (rc < 0) {
    TLOGE("failed (%d) to read_msg for chan (%d)\n",
      rc, chan);
    return rc;
  }

  /* update number of bytes received */
  iov.iov_len = (size_t) rc;

  /* send message back to the caller */
  rc = send_msg(chan, &msg);
  if (rc < 0) {
    TLOGE("failed (%d) to send_msg for chan (%d)\n",
      rc, chan);
    return rc;
  }

  /* retire message */
  rc = put_msg(chan, msg_inf.id);
  if (rc != NO_ERROR) {
    TLOGE("failed (%d) to put_msg for chan (%d)\n",
      rc, chan);
    return rc;
  }

  return NO_ERROR;
}

/*
 *  Channel event handler
 */
static void handle_channel_event(const uevent_t * ev) {
  int rc;

  if (ev->event & IPC_HANDLE_POLL_MSG) {
    rc = handle_msg(ev->handle);
    if (rc != NO_ERROR) {
      /* report an error and close channel */
      TLOGE("failed (%d) to handle event on channel %d\n",
        rc, ev->handle);
      close(ev->handle);
    }
    return;
  }
  if (ev->event & IPC_HANDLE_POLL_HUP) {
    /* closed by peer. */
    close(ev->handle);
    return;
  }
}

/*
 *  Port event handler
 */
static void handle_port_event(const uevent_t * ev) {
  uuid_t peer_uuid;

  if ((ev->event & IPC_HANDLE_POLL_ERROR) ||
    (ev->event & IPC_HANDLE_POLL_HUP) ||
    (ev->event & IPC_HANDLE_POLL_MSG) ||
    (ev->event & IPC_HANDLE_POLL_SEND_UNBLOCKED)) {
    /* should never happen with port handles */
    TLOGE("error event (0x%x) for port (%d)\n",
      ev->event, ev->handle);
    abort();
  }
  if (ev->event & IPC_HANDLE_POLL_READY) {
    /* incoming connection: accept it */
    int rc = accept(ev->handle, &peer_uuid);
    if (rc < 0) {
      TLOGE("failed (%d) to accept on port %d\n",
        rc, ev->handle);
      return;
    }
    handle_t chan = rc;
    while (true){
      struct uevent cev;

      rc = wait(chan, &cev, INFINITE_TIME);
      if (rc < 0) {
        TLOGE("wait returned (%d)\n", rc);
        abort();
      }
      handle_channel_event(&cev);
      if (cev.event & IPC_HANDLE_POLL_HUP) {
        return;
      }
    }
  }
}


/*
 *  Main app entry point
 */
int main(void) {
  int rc;
  handle_t port;

  /* Initialize service */
  rc = port_create(srv_name, 1, MAX_ECHO_MSG_SIZE,
    IPC_PORT_ALLOW_NS_CONNECT |
    IPC_PORT_ALLOW_TA_CONNECT);
  if (rc < 0) {
    TLOGE("Failed (%d) to create port %s\n",
      rc, srv_name);
    abort();
  }
  port = (handle_t) rc;

  /* enter main event loop */
  while (true) {
    uevent_t ev;

    ev.handle = INVALID_IPC_HANDLE;
    ev.event = 0;
    ev.cookie = NULL;

    /* wait forever */
    rc = wait(port, &ev, INFINITE_TIME);
    if (rc == NO_ERROR) {
      /* got an event */
      handle_port_event(&ev);
    } else {
      TLOGE("wait returned (%d)\n", rc);
      abort();
    }
  }
  return 0;
}

เมธอด run_end_to_end_msg_test() จะส่งข้อความ 10,000 รายการแบบไม่พร้อมกันไปยังบริการ "echo" และจัดการการตอบกลับ

static int run_echo_test(void)
{
  int rc;
  handle_t chan;
  uevent_t uevt;
  uint8_t tx_buf[64];
  uint8_t rx_buf[64];
  ipc_msg_info_t inf;
  ipc_msg_t   tx_msg;
  iovec_t     tx_iov;
  ipc_msg_t   rx_msg;
  iovec_t     rx_iov;

  /* prepare tx message buffer */
  tx_iov.base = tx_buf;
  tx_iov.len  = sizeof(tx_buf);
  tx_msg.num_iov = 1;
  tx_msg.iov     = &tx_iov;
  tx_msg.num_handles = 0;
  tx_msg.handles = NULL;

  memset (tx_buf, 0x55, sizeof(tx_buf));

  /* prepare rx message buffer */
  rx_iov.base = rx_buf;
  rx_iov.len  = sizeof(rx_buf);
  rx_msg.num_iov = 1;
  rx_msg.iov     = &rx_iov;
  rx_msg.num_handles = 0;
  rx_msg.handles = NULL;

  /* open connection to echo service */
  rc = sync_connect(srv_name, 1000);
  if(rc < 0)
    return rc;

  /* got channel */
  chan = (handle_t)rc;

  /* send/receive 10000 messages asynchronously. */
  uint tx_cnt = 10000;
  uint rx_cnt = 10000;

  while (tx_cnt || rx_cnt) {
    /* send messages until all buffers are full */
while (tx_cnt) {
    rc = send_msg(chan, &tx_msg);
      if (rc == ERR_NOT_ENOUGH_BUFFER)
      break;  /* no more space */
    if (rc != 64) {
      if (rc > 0) {
        /* incomplete send */
        rc = ERR_NOT_VALID;
}
      goto abort_test;
}
    tx_cnt--;
  }

  /* wait for reply msg or room */
  rc = wait(chan, &uevt, 1000);
  if (rc != NO_ERROR)
    goto abort_test;

  /* drain all messages */
  while (rx_cnt) {
    /* get a reply */
      rc = get_msg(chan, &inf);
    if (rc == ERR_NO_MSG)
        break;  /* no more messages  */
  if (rc != NO_ERROR)
goto abort_test;

  /* read reply data */
    rc = read_msg(chan, inf.id, 0, &rx_msg);
  if (rc != 64) {
    /* unexpected reply length */
    rc = ERR_NOT_VALID;
    goto abort_test;
}

  /* discard reply */
  rc = put_msg(chan, inf.id);
  if (rc != NO_ERROR)
    goto abort_test;
  rx_cnt--;
  }
}

abort_test:
  close(chan);
  return rc;
}

API และแอปที่ไม่ปลอดภัย

ชุดบริการที่เชื่อถือได้ซึ่งเผยแพร่จากฝั่งที่ปลอดภัยและทําเครื่องหมายด้วยแอตทริบิวต์ IPC_PORT_ALLOW_NS_CONNECT จะเข้าถึงเคอร์เนลและโปรแกรมสเปซผู้ใช้ที่ทํางานในฝั่งที่ไม่ปลอดภัยได้

สภาพแวดล้อมการดําเนินการในด้านที่ไม่ปลอดภัย (เคอร์เนลและพื้นที่ผู้ใช้) จะแตกต่างจากสภาพแวดล้อมการดําเนินการในด้านที่ปลอดภัยอย่างมาก ดังนั้นจึงมี API 2 ชุดที่แตกต่างกันแทนที่จะเป็นไลบรารีเดียวสำหรับทั้ง 2 สภาพแวดล้อม ในเคอร์เนล Client API จะมาจากไดรเวอร์เคอร์เนล trusty-ipc และลงทะเบียนโหนดอุปกรณ์แบบอักขระที่กระบวนการในพื้นที่ผู้ใช้สามารถใช้เพื่อสื่อสารกับบริการที่ทำงานในด้านที่ปลอดภัย

User space Trusty IPC Client API

ไลบรารี Trusty IPC Client API ในพื้นที่ผู้ใช้เป็นเลเยอร์บางๆ ที่อยู่ด้านบนของโหนดอุปกรณ์ fd

โปรแกรมพื้นที่ผู้ใช้เริ่มเซสชันการสื่อสารโดยเรียกใช้ tipc_connect() เพื่อเริ่มต้นการเชื่อมต่อกับบริการ Trusty ที่ระบุ การทำงานภายในคือการเรียก tipc_connect() จะเปิดโหนดอุปกรณ์ที่ระบุเพื่อรับตัวระบุไฟล์ และเรียกใช้การเรียก TIPC_IOC_CONNECT ioctl() ด้วยพารามิเตอร์ argp ที่ชี้ไปยังสตริงที่มีชื่อบริการที่จะเชื่อมต่อ

#define TIPC_IOC_MAGIC  'r'
#define TIPC_IOC_CONNECT  _IOW(TIPC_IOC_MAGIC, 0x80, char *)

ตัวระบุไฟล์ที่ได้จะใช้เพื่อสื่อสารกับบริการที่สร้างตัวระบุไฟล์นั้นเท่านั้น คุณควรปิดตัวระบุไฟล์โดยเรียกใช้ tipc_close() เมื่อไม่จำเป็นต้องใช้การเชื่อมต่ออีกต่อไป

ตัวระบุไฟล์ที่ได้จากการเรียกใช้ tipc_connect() จะทํางานเป็นโหนดอุปกรณ์แบบอักขระทั่วไป โดยตัวระบุไฟล์จะมีลักษณะดังนี้

  • เปลี่ยนเป็นโหมดที่ไม่มีการบล็อกได้หากจำเป็น
  • สามารถเขียนโดยใช้การเรียก write() แบบมาตรฐานเพื่อส่งข้อความไปยังอีกฝั่ง
  • ทำการสำรวจได้ (โดยใช้การเรียก poll() หรือ select()) เพื่อดูความพร้อมของข้อความขาเข้าในฐานะตัวระบุไฟล์ปกติ
  • อ่านเพื่อดึงข้อมูลข้อความขาเข้าได้

ผู้โทรส่งข้อความไปยังบริการ Trusty โดยการเรียกใช้การเขียนสำหรับ fd ที่ระบุ ข้อมูลทั้งหมดที่ส่งไปยังwrite() callข้างต้นจะเปลี่ยนรูปแบบเป็นข้อความโดยไดรเวอร์ trusty-ipc ระบบจะส่งข้อความไปยังฝั่งที่ปลอดภัยซึ่งข้อมูลจะได้รับการจัดการโดยระบบย่อย IPC ในเคอร์เนล Trusty และส่งไปยังปลายทางที่เหมาะสม รวมถึงส่งไปยังลูปเหตุการณ์ของแอปเป็นเหตุการณ์ IPC_HANDLE_POLL_MSG ในตัวแฮนเดิลแชแนลหนึ่งๆ บริการ Trusty อาจส่งข้อความตอบกลับอย่างน้อย 1 รายการที่ส่งกลับไปยังฝั่งที่ไม่ปลอดภัยและวางไว้ในคิวข้อความตัวระบุไฟล์ของแชแนลที่เหมาะสมเพื่อให้แอปพื้นที่ทำงานของผู้ใช้เรียกread()ใช้

tipc_connect()

เปิดโหนดอุปกรณ์ tipc ที่ระบุและเริ่มการเชื่อมต่อกับบริการ Trusty ที่ระบุ

int tipc_connect(const char *dev_name, const char *srv_name);

[in] dev_name: เส้นทางไปยังโหนดอุปกรณ์ Trusty IPC ที่เปิด

[in] srv_name: ชื่อบริการ Trusty ที่เผยแพร่ซึ่งจะเชื่อมต่อ

[retval]: ตัวระบุไฟล์ที่ถูกต้องหากดำเนินการสำเร็จ หรือ -1 หากไม่สำเร็จ

tipc_close()

ปิดการเชื่อมต่อกับบริการ Trusty ที่ระบุโดยตัวระบุไฟล์

int tipc_close(int fd);

[in] fd: ตัวระบุไฟล์ที่เปิดก่อนหน้านี้โดยเรียกใช้ tipc_connect()

Kernel Trusty IPC Client API

Trusty IPC Client API ของเคอร์เนลพร้อมใช้งานสำหรับไดรเวอร์เคอร์เนล ระบบจะใช้ Trusty IPC API ของพื้นที่ผู้ใช้บน API นี้

โดยทั่วไป การใช้งานทั่วไปของ API นี้ประกอบด้วยผู้เรียกที่สร้างออบเจ็กต์ struct tipc_chan โดยใช้ฟังก์ชัน tipc_create_channel() จากนั้นใช้การเรียก tipc_chan_connect() เพื่อเริ่มต้นการเชื่อมต่อกับบริการ Trusty IPC ที่ทำงานในด้านที่ปลอดภัย คุณสามารถสิ้นสุดการเชื่อมต่อกับฝั่งระยะไกลได้โดยเรียกใช้ tipc_chan_shutdown() ตามด้วย tipc_chan_destroy() เพื่อล้างทรัพยากร

เมื่อได้รับการแจ้งเตือน (ผ่านhandle_event()การติดต่อกลับ) ว่าการเชื่อมต่อสําเร็จแล้ว ผู้โทรจะทำดังนี้

  • รับบัฟเฟอร์ข้อความโดยใช้การเรียก tipc_chan_get_txbuf_timeout()
  • เขียนข้อความ และ
  • จัดคิวข้อความโดยใช้tipc_chan_queue_msg()วิธีนี้เพื่อนำส่งไปยังบริการที่เชื่อถือได้ (ฝั่งที่ปลอดภัย) ซึ่งเชื่อมต่อกับแชแนล

หลังจากจัดคิวเรียบร้อยแล้ว ผู้เรียกใช้ไม่ควรสนใจบัฟเฟอร์ข้อความเนื่องจากบัฟเฟอร์ข้อความจะกลับไปที่พูลบัฟเฟอร์ว่างในท้ายที่สุดหลังจากประมวลผลโดยฝั่งระยะไกล (เพื่อใช้ซ้ำในภายหลังสำหรับข้อความอื่นๆ) ผู้ใช้ต้องเรียกใช้ tipc_chan_put_txbuf() เฉพาะในกรณีที่จัดคิวบัฟเฟอร์ดังกล่าวไม่สำเร็จหรือไม่จําเป็นต้องใช้อีกต่อไป

ผู้ใช้ API จะได้รับข้อความจากฝั่งระยะไกลโดยการจัดการการเรียกกลับhandle_msg()การแจ้งเตือน (ซึ่งเรียกใช้ในบริบทของ workqueue rx ของ trusty-ipc) ที่ให้พอยน์เตอร์ไปยังบัฟเฟอร์ rx ที่มีข้อความขาเข้าที่จะจัดการ

การติดตั้งใช้งาน handle_msg() callback ควรแสดงผลพอยน์เตอร์ไปยัง struct tipc_msg_buf ที่ถูกต้อง ซึ่งอาจเป็นบัฟเฟอร์ข้อความขาเข้าได้หากจัดการในเครื่องและไม่จำเป็นต้องใช้อีกต่อไป หรืออาจเป็นบัฟเฟอร์ใหม่ที่ได้รับจากtipc_chan_get_rxbuf() call หากบัฟเฟอร์ขาเข้าอยู่ในคิวเพื่อประมวลผลเพิ่มเติม คุณต้องติดตามบัฟเฟอร์ rx ที่แยกออก และปล่อยบัฟเฟอร์ดังกล่าวเมื่อไม่จําเป็นต้องใช้แล้วโดยใช้การเรียก tipc_chan_put_rxbuf()

เมธอดใน Kernel Trusty IPC Client API

tipc_create_channel()

สร้างและกําหนดค่าอินสแตนซ์ของแชแนล Trusty IPC สําหรับอุปกรณ์ trusty-ipc เครื่องหนึ่งๆ

struct tipc_chan *tipc_create_channel(struct device *dev,
                          const struct tipc_chan_ops *ops,
                              void *cb_arg);

[in] dev: ตัวชี้ไปยัง trusty-ipc ที่สร้างขึ้นสำหรับแชแนลอุปกรณ์

[in] ops: ชี้ไปยัง struct tipc_chan_ops ที่มีข้อมูลการเรียกกลับเฉพาะผู้โทร

[in] cb_arg: ตัวชี้ไปยังข้อมูลที่ส่งไปยังการเรียกกลับ tipc_chan_ops

[retval]: ชี้ไปยังอินสแตนซ์ของ struct tipc_chan ที่สร้างขึ้นใหม่หากสําเร็จ หรือ ERR_PTR(err) หากไม่สําเร็จ

โดยทั่วไป ผู้เรียกต้องระบุการเรียกกลับ 2 รายการที่เรียกใช้แบบไม่พร้อมกันเมื่อกิจกรรมที่เกี่ยวข้องเกิดขึ้น

void (*handle_event)(void *cb_arg, int event)มีการเรียกเหตุการณ์เพื่อแจ้งเตือนผู้โทรเกี่ยวกับการเปลี่ยนแปลงสถานะของช่อง

[in] cb_arg: ตัวชี้ไปยังข้อมูลที่ส่งไปยังการเรียกใช้ tipc_create_channel()

[in] event: เหตุการณ์ที่มีค่าใดค่าหนึ่งต่อไปนี้

  • TIPC_CHANNEL_CONNECTED - บ่งบอกว่าเชื่อมต่อกับฝั่งระยะไกลสำเร็จ
  • TIPC_CHANNEL_DISCONNECTED - ระบุว่าฝั่งระยะไกลปฏิเสธคำขอเชื่อมต่อใหม่หรือขอยกเลิกการเชื่อมต่อสำหรับแชแนลที่เชื่อมต่อไว้ก่อนหน้านี้
  • TIPC_CHANNEL_SHUTDOWN - ระบุว่าฝั่งระยะไกลกำลังปิดระบบ ซึ่งจะสิ้นสุดการเชื่อมต่อทั้งหมดอย่างถาวร

ระบบจะเรียกใช้ struct tipc_msg_buf *(*handle_msg)(void *cb_arg, struct tipc_msg_buf *mb) callback เพื่อแจ้งเตือนว่าได้รับข้อความใหม่ผ่านช่องทางที่ระบุ

  • [in] cb_arg: ตัวชี้ไปยังข้อมูลที่ส่งไปยังการเรียกใช้ tipc_create_channel()
  • [in] mb: ชี้ไปยัง struct tipc_msg_buf ที่อธิบายข้อความขาเข้า
  • [retval]: การใช้งานการเรียกกลับควรแสดงผลพอยน์เตอร์ไปยัง struct tipc_msg_buf ซึ่งอาจเป็นพอยน์เตอร์เดียวกับที่ได้รับเป็นพารามิเตอร์ mb หากระบบจัดการข้อความในเครื่องและไม่จำเป็นต้องใช้อีกต่อไป (หรืออาจเป็นบัฟเฟอร์ใหม่ที่ได้รับจากการเรียก tipc_chan_get_rxbuf())

tipc_chan_connect()

เริ่มการเชื่อมต่อกับบริการ Trusty IPC ที่ระบุ

int tipc_chan_connect(struct tipc_chan *chan, const char *port);

[in] chan: ตัวชี้ไปยังแชแนลที่การเรียกใช้ tipc_create_chan() แสดงผล

[in] port: ตัวชี้ไปยังสตริงที่มีชื่อบริการที่จะเชื่อมต่อ

[retval]: 0 หากสําเร็จ ไม่เช่นนั้นจะเป็นข้อผิดพลาดเชิงลบ

ผู้โทรจะได้รับการแจ้งเตือนเมื่อการเชื่อมต่อเกิดขึ้นโดยได้รับhandle_eventการโทรกลับ

tipc_chan_shutdown()

สิ้นสุดการเชื่อมต่อกับบริการ Trusty IPC ที่เรียกใช้ก่อนหน้านี้โดยtipc_chan_connect()

int tipc_chan_shutdown(struct tipc_chan *chan);

[in] chan: ตัวชี้ไปยังแชแนลที่การเรียก tipc_create_chan() แสดงผล

tipc_chan_destroy()

ทำลายช่องทาง IPC ที่เชื่อถือได้ซึ่งระบุ

void tipc_chan_destroy(struct tipc_chan *chan);

[in] chan: ตัวชี้ไปยังแชแนลที่การเรียกใช้ tipc_create_chan() แสดงผล

tipc_chan_get_txbuf_timeout()

รับบัฟเฟอร์ข้อความที่ใช้ส่งข้อมูลผ่านแชแนลที่ระบุได้ หากบัฟเฟอร์ไม่พร้อมใช้งานทันที ระบบอาจบล็อกผู้โทรไว้ตามระยะหมดเวลาที่ระบุ (เป็นมิลลิวินาที)

struct tipc_msg_buf *
tipc_chan_get_txbuf_timeout(struct tipc_chan *chan, long timeout);

[in] chan: ตัวชี้ไปยังแชแนลที่จะจัดคิวข้อความ

[in] chan: ระยะหมดเวลาที่สูงสุดที่จะรอจนกว่าบัฟเฟอร์ tx จะพร้อมใช้งาน

[retval]: บัฟเฟอร์ข้อความที่ถูกต้องเมื่อดำเนินการสำเร็จ หรือERR_PTR(err) เมื่อเกิดข้อผิดพลาด

tipc_chan_queue_msg()

จัดคิวข้อความที่จะส่งผ่านแชแนล Trusty IPC ที่ระบุ

int tipc_chan_queue_msg(struct tipc_chan *chan, struct tipc_msg_buf *mb);

[in] chan: ตัวชี้ไปยังแชแนลที่จะจัดคิวข้อความ

[in] mb: ตัวชี้ไปยังข้อความที่จะจัดคิว (รับจากการเรียกใช้ tipc_chan_get_txbuf_timeout())

[retval]: 0 หากสําเร็จ ไม่เช่นนั้นจะเป็นข้อผิดพลาดเชิงลบ

tipc_chan_put_txbuf()

ปล่อยบัฟเฟอร์ข้อความ Tx ที่ระบุซึ่งได้รับก่อนหน้านี้จากการเรียกใช้ tipc_chan_get_txbuf_timeout()

void tipc_chan_put_txbuf(struct tipc_chan *chan,
                         struct tipc_msg_buf *mb);

[in] chan: ตัวชี้ไปยังแชแนลที่บัฟเฟอร์ข้อความนี้อยู่

[in] mb: ตัวชี้ไปยังบัฟเฟอร์ข้อความที่จะปล่อย

[retval]: ไม่มี

tipc_chan_get_rxbuf()

รับบัฟเฟอร์ข้อความใหม่ที่ใช้รับข้อความผ่านแชแนลที่ระบุได้

struct tipc_msg_buf *tipc_chan_get_rxbuf(struct tipc_chan *chan);

[in] chan: ตัวชี้ไปยังช่องที่บัฟเฟอร์ข้อความนี้อยู่

[retval]: บัฟเฟอร์ข้อความที่ถูกต้องเมื่อดำเนินการสำเร็จ ERR_PTR(err) เมื่อเกิดข้อผิดพลาด

tipc_chan_put_rxbuf()

ปล่อยบัฟเฟอร์ข้อความที่ระบุซึ่งได้รับก่อนหน้านี้จากการเรียกใช้ tipc_chan_get_rxbuf()

void tipc_chan_put_rxbuf(struct tipc_chan *chan,
                         struct tipc_msg_buf *mb);

[in] chan: ตัวชี้ไปยังช่องที่บัฟเฟอร์ข้อความนี้อยู่

[in] mb: ตัวชี้ไปยังบัฟเฟอร์ข้อความที่จะปล่อย

[retval]: ไม่มี