1 /*
2 * Copyright (c) 2009-2013, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google, Inc. nor the names of its contributors
15 * may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
25 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <stddef.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include "debug.h"
38 #include "protocol.h"
39 #include "transport.h"
40
41 #define STATE_OFFLINE 0
42 #define STATE_COMMAND 1
43 #define STATE_COMPLETE 2
44 #define STATE_ERROR 3
45
46 struct fastboot_cmd {
47 struct fastboot_cmd *next;
48 const char *prefix;
49 unsigned prefix_len;
50 void (*execute)(struct protocol_handle *phandle, const char *arg);
51 };
52
53 struct fastboot_var {
54 struct fastboot_var *next;
55 const char *name;
56 const char *value;
57 };
58
59 static struct fastboot_cmd *cmdlist;
60
fastboot_register(const char * prefix,void (* phandle)(struct protocol_handle * phandle,const char * arg))61 void fastboot_register(const char *prefix,
62 void (*phandle)(struct protocol_handle *phandle, const char *arg))
63 {
64 struct fastboot_cmd *cmd;
65 cmd = malloc(sizeof(*cmd));
66 if (cmd) {
67 cmd->prefix = prefix;
68 cmd->prefix_len = strlen(prefix);
69 cmd->execute = phandle;
70 cmd->next = cmdlist;
71 cmdlist = cmd;
72 }
73 }
74
75 static struct fastboot_var *varlist;
76
fastboot_publish(const char * name,const char * value)77 void fastboot_publish(const char *name, const char *value)
78 {
79 struct fastboot_var *var;
80 var = malloc(sizeof(*var));
81 if (var) {
82 var->name = name;
83 var->value = value;
84 var->next = varlist;
85 varlist = var;
86 }
87 }
88
fastboot_getvar(const char * name)89 const char *fastboot_getvar(const char *name)
90 {
91 struct fastboot_var *var;
92
93 for (var = varlist; var; var = var->next) {
94 if (!strcmp(var->name, name)) {
95 return var->value;
96 }
97 }
98
99 return "";
100 }
101
protocol_handle_download(struct protocol_handle * phandle,size_t len)102 int protocol_handle_download(struct protocol_handle *phandle, size_t len)
103 {
104 return transport_handle_download(phandle->transport_handle, len);
105 }
106
protocol_handle_write(struct protocol_handle * phandle,char * buffer,size_t len)107 static ssize_t protocol_handle_write(struct protocol_handle *phandle,
108 char *buffer, size_t len)
109 {
110 return transport_handle_write(phandle->transport_handle, buffer, len);
111 }
112
fastboot_ack(struct protocol_handle * phandle,const char * code,const char * reason)113 static void fastboot_ack(struct protocol_handle *phandle, const char *code,
114 const char *reason)
115 {
116 char response[64];
117
118 if (phandle->state != STATE_COMMAND)
119 return;
120
121 if (reason == 0)
122 reason = "";
123
124 snprintf(response, 64, "%s%s", code, reason);
125 phandle->state = STATE_COMPLETE;
126
127 protocol_handle_write(phandle, response, strlen(response));
128 }
129
fastboot_fail(struct protocol_handle * phandle,const char * reason)130 void fastboot_fail(struct protocol_handle *phandle, const char *reason)
131 {
132 fastboot_ack(phandle, "FAIL", reason);
133 }
134
fastboot_okay(struct protocol_handle * phandle,const char * info)135 void fastboot_okay(struct protocol_handle *phandle, const char *info)
136 {
137 fastboot_ack(phandle, "OKAY", info);
138 }
139
fastboot_data(struct protocol_handle * phandle,size_t len)140 void fastboot_data(struct protocol_handle *phandle, size_t len)
141 {
142 char response[64];
143 ssize_t ret;
144
145 snprintf(response, 64, "DATA%08zx", len);
146 ret = protocol_handle_write(phandle, response, strlen(response));
147 if (ret < 0)
148 return;
149 }
150
protocol_handle_command(struct protocol_handle * phandle,char * buffer)151 void protocol_handle_command(struct protocol_handle *phandle, char *buffer)
152 {
153 D(INFO,"fastboot: %s\n", buffer);
154
155 struct fastboot_cmd *cmd;
156
157 for (cmd = cmdlist; cmd; cmd = cmd->next) {
158 if (memcmp(buffer, cmd->prefix, cmd->prefix_len))
159 continue;
160 phandle->state = STATE_COMMAND;
161 cmd->execute(phandle, buffer + cmd->prefix_len);
162 if (phandle->state == STATE_COMMAND)
163 fastboot_fail(phandle, "unknown reason");
164 return;
165 }
166
167 fastboot_fail(phandle, "unknown command");
168 }
169
create_protocol_handle(struct transport_handle * thandle)170 struct protocol_handle *create_protocol_handle(struct transport_handle *thandle)
171 {
172 struct protocol_handle *phandle;
173
174 phandle = calloc(sizeof(struct protocol_handle), 1);
175
176 phandle->transport_handle = thandle;
177 phandle->state = STATE_OFFLINE;
178 phandle->download_fd = -1;
179
180 pthread_mutex_init(&phandle->lock, NULL);
181
182 return phandle;
183 }
184
protocol_get_download(struct protocol_handle * phandle)185 int protocol_get_download(struct protocol_handle *phandle)
186 {
187 int fd;
188
189 pthread_mutex_lock(&phandle->lock);
190 fd = phandle->download_fd;
191 phandle->download_fd = -1;
192 pthread_mutex_unlock(&phandle->lock);
193
194 return fd;
195 }
196