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
46struct 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
53struct fastboot_var {
54    struct fastboot_var *next;
55    const char *name;
56    const char *value;
57};
58
59static struct fastboot_cmd *cmdlist;
60
61void 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
75static struct fastboot_var *varlist;
76
77void 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
89const 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
102int protocol_handle_download(struct protocol_handle *phandle, size_t len)
103{
104    return transport_handle_download(phandle->transport_handle, len);
105}
106
107static 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
113static 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
130void fastboot_fail(struct protocol_handle *phandle, const char *reason)
131{
132    fastboot_ack(phandle, "FAIL", reason);
133}
134
135void fastboot_okay(struct protocol_handle *phandle, const char *info)
136{
137    fastboot_ack(phandle, "OKAY", info);
138}
139
140void 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
151void 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
170struct 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
185int 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