1 /* Part of libhgfs - (c) 2009, D.C. van Moolenbroek */
2
3 #include "inc.h"
4
5 #define CMD_XFER 0x1E /* vmware backdoor transfer command */
6
7 enum {
8 XFER_OPEN, /* open transfer channel */
9 XFER_SENDLEN, /* specify length of data to send */
10 XFER_SEND, /* send data */
11 XFER_RECVLEN, /* get length of data to receive */
12 XFER_RECV, /* receive data */
13 XFER_RECVACK, /* acknowledge receipt of data */
14 XFER_CLOSE /* close transfer channel */
15 };
16
17 #define STATUS(p) (HIWORD((p)[2]) & 0xff)
18
19 /*===========================================================================*
20 * channel_open *
21 *===========================================================================*/
channel_open(struct channel * ch,u32_t type)22 int channel_open(
23 struct channel *ch, /* struct describing the new channel */
24 u32_t type /* channel type: CH_IN or CH_OUT */
25 )
26 {
27 /* Open a new backdoor channel. Upon success, the given channel structure will
28 * be filled with information and can be used in subsequent channel calls.
29 * Return OK on success, or a negative error code on error.
30 */
31 u32_t ptr[6];
32
33 ptr[1] = type | 0x80000000;
34 ptr[2] = MAKELONG(CMD_XFER, XFER_OPEN);
35
36 backdoor(ptr);
37
38 if ((STATUS(ptr) & 1) == 0) return EIO;
39
40 ch->id = HIWORD(ptr[3]);
41 ch->cookie1 = ptr[4];
42 ch->cookie2 = ptr[5];
43
44 return OK;
45 }
46
47 /*===========================================================================*
48 * channel_close *
49 *===========================================================================*/
channel_close(struct channel * ch)50 void channel_close(
51 struct channel *ch /* backdoor channel to close */
52 )
53 {
54 /* Close a previously opened backdoor channel.
55 */
56 u32_t ptr[6];
57
58 ptr[2] = MAKELONG(CMD_XFER, XFER_CLOSE);
59 ptr[3] = MAKELONG(0, ch->id);
60 ptr[4] = ch->cookie1;
61 ptr[5] = ch->cookie2;
62
63 backdoor(ptr);
64 }
65
66 /*===========================================================================*
67 * channel_send *
68 *===========================================================================*/
channel_send(struct channel * ch,char * buf,int len)69 int channel_send(
70 struct channel *ch, /* backdoor channel to send to */
71 char *buf, /* buffer to send data from */
72 int len /* size of the data to send */
73 )
74 {
75 /* Receive data over a backdoor channel. Return OK on success, or a negative
76 * error code on error.
77 */
78 u32_t ptr[7];
79
80 ptr[1] = len;
81 ptr[2] = MAKELONG(CMD_XFER, XFER_SENDLEN);
82 ptr[3] = MAKELONG(0, ch->id);
83 ptr[4] = ch->cookie1;
84 ptr[5] = ch->cookie2;
85
86 backdoor(ptr);
87
88 if ((STATUS(ptr) & 1) == 0) return EIO;
89
90 if (len == 0) return OK;
91
92 ptr[1] = MAKELONG(0, 1);
93 ptr[2] = len;
94 ptr[3] = MAKELONG(0, ch->id);
95 ptr[4] = (u32_t)buf;
96 ptr[5] = ch->cookie2;
97 ptr[6] = ch->cookie1;
98
99 backdoor_out(ptr);
100
101 return OK;
102 }
103
104 /*===========================================================================*
105 * channel_recv *
106 *===========================================================================*/
channel_recv(struct channel * ch,char * buf,int max)107 int channel_recv(
108 struct channel *ch, /* backdoor channel to receive from */
109 char *buf, /* buffer to receive data into */
110 int max /* size of the buffer */
111 )
112 {
113 /* Receive data on a backdoor channel. Return the number of bytes received, or
114 * a negative error code on error.
115 */
116 u32_t ptr[7];
117 int len;
118
119 ptr[2] = MAKELONG(CMD_XFER, XFER_RECVLEN);
120 ptr[3] = MAKELONG(0, ch->id);
121 ptr[4] = ch->cookie1;
122 ptr[5] = ch->cookie2;
123
124 backdoor(ptr);
125
126 if ((STATUS(ptr) & 0x81) == 0) return EIO;
127
128 if ((len = ptr[1]) == 0 || (STATUS(ptr) & 3) == 1) return 0;
129
130 if (len > max) return E2BIG;
131
132 ptr[1] = MAKELONG(0, 1);
133 ptr[2] = len;
134 ptr[3] = MAKELONG(0, ch->id);
135 ptr[4] = ch->cookie1;
136 ptr[5] = (u32_t)buf;
137 ptr[6] = ch->cookie2;
138
139 backdoor_in(ptr);
140
141 ptr[1] = 1;
142 ptr[2] = MAKELONG(CMD_XFER, XFER_RECVACK);
143 ptr[3] = MAKELONG(0, ch->id);
144 ptr[4] = ch->cookie1;
145 ptr[5] = ch->cookie2;
146
147 backdoor(ptr);
148
149 return len;
150 }
151