Olaf Rempel 12 years ago
commit
3e081d8576
19 changed files with 1595 additions and 0 deletions
  1. 5
    0
      .gitignore
  2. 21
    0
      Makefile
  3. 217
    0
      configfile.c
  4. 15
    0
      configfile.h
  5. 43
    0
      context.c
  6. 35
    0
      context.h
  7. 302
    0
      event.c
  8. 42
    0
      event.h
  9. 268
    0
      list.h
  10. 102
    0
      logging.c
  11. 19
    0
      logging.h
  12. 115
    0
      serial.c
  13. 6
    0
      serial.h
  14. 148
    0
      statemachine.c
  15. 6
    0
      statemachine.h
  16. 156
    0
      xmodem.c
  17. 9
    0
      xmodem.h
  18. 81
    0
      zyxel-revert.c
  19. 5
    0
      zyxel-revert.conf

+ 5
- 0
.gitignore View File

@@ -0,0 +1,5 @@
1
+*.d
2
+*.o
3
+zyxel-revert
4
+*.log
5
+*.rom

+ 21
- 0
Makefile View File

@@ -0,0 +1,21 @@
1
+CFLAGS := -O2 -pipe -Wall
2
+
3
+OBJS := configfile.o event.o logging.o
4
+OBJS += context.o serial.o statemachine.o xmodem.o
5
+
6
+all: zyxel-revert
7
+
8
+zyxel-revert: $(OBJS) zyxel-revert.o
9
+	$(CC) $(CFLAGS) $^ -o $@
10
+
11
+%.o: %.c
12
+	$(CC) $(CFLAGS) -c $< -o $@
13
+
14
+%.d: %.c
15
+	$(CC) $(CFLAGS) -MM -c $< -o $@
16
+
17
+clean:
18
+	rm -f zyxel-revert *.d *.o *.log
19
+
20
+DEPS := $(wildcard *.c)
21
+-include $(DEPS:.c=.d)

+ 217
- 0
configfile.c View File

@@ -0,0 +1,217 @@
1
+/***************************************************************************
2
+ *   Copyright (C) 06/2006 by Olaf Rempel                                  *
3
+ *   razzor@kopf-tisch.de                                                  *
4
+ *                                                                         *
5
+ *   This program is free software; you can redistribute it and/or modify  *
6
+ *   it under the terms of the GNU General Public License as published by  *
7
+ *   the Free Software Foundation; either version 2 of the License, or     *
8
+ *   (at your option) any later version.                                   *
9
+ *                                                                         *
10
+ *   This program is distributed in the hope that it will be useful,       *
11
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13
+ *   GNU General Public License for more details.                          *
14
+ *                                                                         *
15
+ *   You should have received a copy of the GNU General Public License     *
16
+ *   along with this program; if not, write to the                         *
17
+ *   Free Software Foundation, Inc.,                                       *
18
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19
+ ***************************************************************************/
20
+#include <stdio.h>
21
+#include <stdlib.h>
22
+#include <string.h>
23
+#include <unistd.h>
24
+
25
+#include <sys/socket.h>
26
+#include <netinet/in.h>
27
+#include <netinet/ip.h>
28
+#include <arpa/inet.h>
29
+
30
+#include "configfile.h"
31
+#include "list.h"
32
+#include "logging.h"
33
+
34
+#define BUFSIZE 1024
35
+
36
+struct conf_section {
37
+	struct list_head list;
38
+	struct list_head tupel_list;
39
+	const char *name;
40
+};
41
+
42
+struct conf_tupel {
43
+	struct list_head list;
44
+	const char *option;
45
+	const char *parameter;
46
+};
47
+
48
+static LIST_HEAD(config_list);
49
+
50
+static struct conf_section * config_add_section(const char *name)
51
+{
52
+	struct conf_section *section;
53
+	section = malloc(sizeof(struct conf_section) + strlen(name));
54
+	if (section == NULL)
55
+		return NULL;
56
+
57
+	INIT_LIST_HEAD(&section->list);
58
+	INIT_LIST_HEAD(&section->tupel_list);
59
+
60
+	section->name = strdup(name);
61
+	if (section->name == NULL) {
62
+		free(section);
63
+		return NULL;
64
+	}
65
+
66
+	list_add_tail(&section->list, &config_list);
67
+	return section;
68
+}
69
+
70
+static int config_add_tupel(struct conf_section *section, const char *option, const char *parameter)
71
+{
72
+	struct conf_tupel *tupel = malloc(sizeof(struct conf_tupel));
73
+	if (tupel == NULL)
74
+		return -1;
75
+
76
+	INIT_LIST_HEAD(&tupel->list);
77
+	tupel->option = strdup(option);
78
+	tupel->parameter = strdup(parameter);
79
+
80
+	if (tupel->option == NULL || tupel->parameter == NULL) {
81
+		free(tupel);
82
+		return -1;
83
+	}
84
+
85
+	list_add_tail(&tupel->list, &section->tupel_list);
86
+	return 0;
87
+}
88
+
89
+int config_parse(const char *config)
90
+{
91
+	FILE *fz = fopen(config, "r");
92
+	if (fz == NULL) {
93
+		log_print(LOG_ERROR, "config_parse(): %s", config);
94
+		return -1;
95
+	}
96
+
97
+	char *line = malloc(BUFSIZE);
98
+	if (line == NULL) {
99
+		log_print(LOG_ERROR, "config_parse(): out of memory");
100
+		fclose(fz);
101
+		return -1;
102
+	}
103
+
104
+	int linenum = 0;
105
+	struct conf_section *section = NULL;
106
+	while (fgets(line, BUFSIZE, fz) != NULL) {
107
+		linenum++;
108
+
109
+		if (line[0] == '#' || line[0] <= ' ') {
110
+			continue;
111
+
112
+		} else if (line[0] == '[') {
113
+			char *tok = strtok(line +1, " ]\n");
114
+
115
+			if (tok == NULL || (section = config_add_section(tok)) == NULL) {
116
+				log_print(LOG_WARN, "config_parse(): invalid section in row %d", linenum);
117
+				free(line);
118
+				fclose(fz);
119
+				return -1;
120
+			}
121
+			continue;
122
+
123
+		} else if (section == NULL) {
124
+			log_print(LOG_WARN, "config_parse(): missing section in row %d", linenum);
125
+			free(line);
126
+			fclose(fz);
127
+			return -1;
128
+		}
129
+
130
+		char *tok = strtok(line, " \n");
131
+		if (tok != NULL) {
132
+			char *tok2;
133
+			while ((tok2 = strtok(NULL, " \n"))) {
134
+				if (config_add_tupel(section, tok, tok2) != 0)
135
+					log_print(LOG_WARN, "config_parse(): invalid row %d", linenum);
136
+			}
137
+		}
138
+	}
139
+
140
+	fclose(fz);
141
+	free(line);
142
+	return 0;
143
+}
144
+
145
+void config_free(void)
146
+{
147
+	struct conf_section *section, *section_tmp;
148
+	struct conf_tupel *tupel, *tupel_tmp;
149
+
150
+	list_for_each_entry_safe(section, section_tmp, &config_list, list) {
151
+		list_for_each_entry_safe(tupel, tupel_tmp, &section->tupel_list, list) {
152
+			list_del(&tupel->list);
153
+			free((char *)tupel->option);
154
+			free((char *)tupel->parameter);
155
+			free(tupel);
156
+		}
157
+		list_del(&section->list);
158
+		free(section);
159
+	}
160
+}
161
+
162
+static struct conf_section * config_get_section(const char *name)
163
+{
164
+	struct conf_section *section;
165
+
166
+	list_for_each_entry(section, &config_list, list) {
167
+		if (!strcmp(section->name, name))
168
+			return section;
169
+	}
170
+	return NULL;
171
+}
172
+
173
+const char * config_get_string(const char *section_str, const char *option, const char *def)
174
+{
175
+	struct conf_section *section = config_get_section(section_str);
176
+	if (section != NULL) {
177
+		struct conf_tupel *tupel;
178
+		list_for_each_entry(tupel, &section->tupel_list, list) {
179
+			if (!strcmp(tupel->option, option))
180
+				return tupel->parameter;
181
+		}
182
+	}
183
+
184
+	if (def != NULL)
185
+		log_print(LOG_WARN, "config [%s:%s] not found, using default: '%s'",
186
+			section_str, option, def);
187
+	return def;
188
+}
189
+
190
+int config_get_int(const char *section, const char *option, int def)
191
+{
192
+	const char *ret = config_get_string(section, option, NULL);
193
+	if (ret == NULL) {
194
+		log_print(LOG_WARN, "config [%s:%s] not found, using default: '%d'",
195
+			section, option, def);
196
+		return def;
197
+	}
198
+	return atoi(ret);
199
+}
200
+
201
+int config_get_strings(const char *section_str, const char *option,
202
+			int (*callback)(const char *value, void *privdata),
203
+			void *privdata)
204
+{
205
+	struct conf_section *section = config_get_section(section_str);
206
+	if (section == NULL)
207
+		return -1;
208
+
209
+	int cnt = 0;
210
+	struct conf_tupel *tupel;
211
+	list_for_each_entry(tupel, &section->tupel_list, list) {
212
+		if (!strcmp(tupel->option, option))
213
+			if (callback(tupel->parameter, privdata) == 0)
214
+				cnt++;
215
+	}
216
+	return cnt;
217
+}

+ 15
- 0
configfile.h View File

@@ -0,0 +1,15 @@
1
+#ifndef _CONFIG_H_
2
+#define _CONFIG_H_
3
+
4
+int config_parse(const char *config);
5
+void config_free(void);
6
+
7
+const char * config_get_string(const char *section_str, const char *option, const char *def);
8
+
9
+int config_get_int(const char *section, const char *option, int def);
10
+
11
+int config_get_strings(const char *section_str, const char *option,
12
+			int (*callback)(const char *value, void *privdata),
13
+			void *privdata);
14
+
15
+#endif /* _CONFIG_H_ */

+ 43
- 0
context.c View File

@@ -0,0 +1,43 @@
1
+#include <stdlib.h>
2
+#include <string.h>
3
+
4
+#include "context.h"
5
+#include "list.h"
6
+#include "logging.h"
7
+
8
+static LIST_HEAD(context_list);
9
+
10
+struct context * create_context(void)
11
+{
12
+	struct context *ctx = malloc(sizeof(struct context));
13
+	if (ctx == NULL) {
14
+		log_print(LOG_WARN, "create_context(): out of memory");
15
+		return NULL;
16
+	}
17
+
18
+	memset(ctx, 0, sizeof(struct context));
19
+
20
+	list_add(&ctx->list, &context_list);
21
+	return ctx;
22
+}
23
+
24
+int destroy_context(struct context *ctx)
25
+{
26
+	list_del(&ctx->list);
27
+
28
+	if (ctx->dev_close != NULL)
29
+		ctx->dev_close(ctx);
30
+
31
+	free(ctx);
32
+	return 0;
33
+}
34
+
35
+int context_close(void)
36
+{
37
+	struct context *ctx, *tmp;
38
+
39
+	list_for_each_entry_safe(ctx, tmp, &context_list, list)
40
+		destroy_context(ctx);
41
+
42
+	return 0;
43
+}

+ 35
- 0
context.h View File

@@ -0,0 +1,35 @@
1
+#ifndef _CONTEXT_H_
2
+#define _CONTEXT_H_
3
+
4
+#include "list.h"
5
+
6
+struct context {
7
+	struct list_head list;
8
+
9
+	/* device local stuff */
10
+	int fd;
11
+	int (* dev_close)(struct context *context);
12
+	int (* dev_setbaudrate)(struct context *context, int baudrate);
13
+	char *devname;
14
+	void *dev_privdata;
15
+
16
+	/* event stuff */
17
+	struct event_fd *event;
18
+
19
+	/* statemachine */
20
+	int state;
21
+
22
+	/* line buffer */
23
+	char linebuf[256];
24
+	int linepos;
25
+
26
+	/* xmodem */
27
+	int lastpkt;
28
+};
29
+
30
+struct context * create_context(void);
31
+int destroy_context(struct context *ctx);
32
+
33
+int context_close(void);
34
+
35
+#endif /* _CONTEXT_H_ */

+ 302
- 0
event.c View File

@@ -0,0 +1,302 @@
1
+/***************************************************************************
2
+ *   Copyright (C) 10/2006 by Olaf Rempel                                  *
3
+ *   razzor@kopf-tisch.de                                                  *
4
+ *                                                                         *
5
+ *   This program is free software; you can redistribute it and/or modify  *
6
+ *   it under the terms of the GNU General Public License as published by  *
7
+ *   the Free Software Foundation; either version 2 of the License, or     *
8
+ *   (at your option) any later version.                                   *
9
+ *                                                                         *
10
+ *   This program is distributed in the hope that it will be useful,       *
11
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13
+ *   GNU General Public License for more details.                          *
14
+ *                                                                         *
15
+ *   You should have received a copy of the GNU General Public License     *
16
+ *   along with this program; if not, write to the                         *
17
+ *   Free Software Foundation, Inc.,                                       *
18
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19
+ ***************************************************************************/
20
+#include <stdlib.h>
21
+#include <unistd.h>
22
+#include <string.h>
23
+
24
+#include <sys/time.h>
25
+#include <sys/types.h>
26
+
27
+#include "list.h"
28
+#include "logging.h"
29
+
30
+#include "event.h"
31
+
32
+static LIST_HEAD(event_fd_list);
33
+static LIST_HEAD(event_timeout_list);
34
+
35
+struct event_fd {
36
+	struct list_head list;
37
+	unsigned int flags;
38
+	int fd;
39
+	int (*read_cb)(int fd, void *privdata);
40
+	int (*write_cb)(int fd, void *privdata);
41
+	void *read_priv;
42
+	void *write_priv;
43
+};
44
+
45
+struct event_timeout {
46
+	struct list_head list;
47
+	unsigned int flags;
48
+	struct timeval intervall;
49
+	struct timeval nextrun;
50
+	int (*callback)(void *privdata);
51
+	void *privdata;
52
+};
53
+
54
+struct event_fd * event_add_fd(
55
+			struct event_fd *entry,
56
+			int fd,
57
+			int type,
58
+			int (*callback)(int fd, void *privdata),
59
+			void *privdata)
60
+{
61
+	/* check valid filediskriptor */
62
+	if (fd < 0 || fd > FD_SETSIZE) {
63
+		log_print(LOG_ERROR, "event_add_fd(): invalid fd");
64
+		return NULL;
65
+	}
66
+
67
+	/* check valid type (read/write) */
68
+	if (!(type & FD_TYPES)) {
69
+		log_print(LOG_ERROR, "event_add_fd(): invalid type");
70
+		return NULL;
71
+	}
72
+
73
+	/* create new entry */
74
+	if (entry == NULL) {
75
+		entry = malloc(sizeof(struct event_fd));
76
+		if (entry == NULL) {
77
+			log_print(LOG_ERROR, "event_add_fd(): out of memory");
78
+			return NULL;
79
+		}
80
+
81
+		memset(entry, 0, sizeof(struct event_fd));
82
+		entry->flags |= EVENT_NEW;
83
+		entry->fd = fd;
84
+
85
+		/* put it on the list */
86
+		list_add_tail(&entry->list, &event_fd_list);
87
+	}
88
+
89
+	if (type & FD_READ) {
90
+		entry->flags = (callback != NULL) ? (entry->flags | FD_READ) : (entry->flags & ~FD_READ);
91
+		entry->read_cb = callback;
92
+		entry->read_priv = privdata;
93
+
94
+	} else if (type & FD_WRITE) {
95
+		entry->flags = (callback != NULL) ? (entry->flags | FD_WRITE) : (entry->flags & ~FD_WRITE);
96
+		entry->write_cb = callback;
97
+		entry->write_priv = privdata;
98
+	}
99
+
100
+	return entry;
101
+}
102
+
103
+int event_get_fd(struct event_fd *entry)
104
+{
105
+	return (entry != NULL) ? entry->fd: -1;
106
+}
107
+
108
+void event_remove_fd(struct event_fd *entry)
109
+{
110
+	/* mark the event as deleted -> remove in select() loop */
111
+	entry->flags |= EVENT_DELETE;
112
+}
113
+
114
+static void add_timeval(struct timeval *ret, struct timeval *a, struct timeval *b)
115
+{
116
+	ret->tv_usec = a->tv_usec + b->tv_usec;
117
+	ret->tv_sec = a->tv_sec + b->tv_sec;
118
+
119
+	if (ret->tv_usec >= 1000000) {
120
+		ret->tv_usec -= 1000000;
121
+		ret->tv_sec++;
122
+	}
123
+}
124
+
125
+static void sub_timeval(struct timeval *ret, struct timeval *a, struct timeval *b)
126
+{
127
+	ret->tv_usec = a->tv_usec - b->tv_usec;
128
+	ret->tv_sec = a->tv_sec - b->tv_sec;
129
+
130
+	if (ret->tv_usec < 0) {
131
+		ret->tv_usec += 1000000;
132
+		ret->tv_sec--;
133
+	}
134
+}
135
+
136
+static int cmp_timeval(struct timeval *a, struct timeval *b)
137
+{
138
+	if (a->tv_sec > b->tv_sec)
139
+		return -1;
140
+
141
+	if (a->tv_sec < b->tv_sec)
142
+		return 1;
143
+
144
+	if (a->tv_usec > b->tv_usec)
145
+		return -1;
146
+
147
+	if (a->tv_usec < b->tv_usec)
148
+		return 1;
149
+
150
+	return 0;
151
+}
152
+
153
+static void schedule_nextrun(struct event_timeout *entry, struct timeval *now)
154
+{
155
+	add_timeval(&entry->nextrun, now, &entry->intervall);
156
+
157
+	struct event_timeout *search;
158
+	list_for_each_entry(search, &event_timeout_list, list) {
159
+		if (search->nextrun.tv_sec > entry->nextrun.tv_sec) {
160
+			list_add_tail(&entry->list, &search->list);
161
+			return;
162
+
163
+		} else if (search->nextrun.tv_sec == entry->nextrun.tv_sec &&
164
+			   search->nextrun.tv_usec > entry->nextrun.tv_usec) {
165
+				list_add_tail(&entry->list, &search->list);
166
+				return;
167
+		}
168
+	}
169
+	list_add_tail(&entry->list, &event_timeout_list);
170
+}
171
+
172
+struct event_timeout * event_add_timeout(
173
+			struct timeval *timeout,
174
+			int (*callback)(void *privdata),
175
+			void *privdata)
176
+{
177
+	struct event_timeout *entry;
178
+	entry = malloc(sizeof(struct event_timeout));
179
+	if (entry == NULL) {
180
+		log_print(LOG_ERROR, "event_add_timeout(): out of memory");
181
+		return NULL;
182
+	}
183
+
184
+	entry->flags = 0;
185
+	memcpy(&entry->intervall, timeout, sizeof(entry->intervall));
186
+	entry->callback = callback;
187
+	entry->privdata = privdata;
188
+
189
+	struct timeval now;
190
+	gettimeofday(&now, NULL);
191
+
192
+	schedule_nextrun(entry, &now);
193
+	return entry;
194
+}
195
+
196
+void event_remove_timeout(struct event_timeout *entry)
197
+{
198
+	/* mark the event as deleted -> remove in select() loop */
199
+	entry->flags |= EVENT_DELETE;
200
+}
201
+
202
+int event_loop(void)
203
+{
204
+	fd_set *fdsets = malloc(sizeof(fd_set) * 2);
205
+	if (fdsets == NULL) {
206
+		log_print(LOG_ERROR, "event_loop(): out of memory");
207
+		return -1;
208
+	}
209
+
210
+	while (1) {
211
+		struct timeval timeout, *timeout_p = NULL;
212
+		if (!list_empty(&event_timeout_list)) {
213
+			struct timeval now;
214
+			gettimeofday(&now, NULL);
215
+
216
+			struct event_timeout *entry, *tmp;
217
+			list_for_each_entry_safe(entry, tmp, &event_timeout_list, list) {
218
+				if (entry->flags & EVENT_DELETE) {
219
+					list_del(&entry->list);
220
+					free(entry);
221
+					continue;
222
+				}
223
+
224
+				/* timeout not elapsed, exit search (since list is sorted) */
225
+				if (cmp_timeval(&entry->nextrun, &now) == -1)
226
+					break;
227
+
228
+				/* remove event from list */
229
+				list_del(&entry->list);
230
+
231
+				/* execute callback, when callback returns 0 -> schedule event again */
232
+				if (entry->callback(entry->privdata)) {
233
+					free(entry);
234
+
235
+				} else {
236
+					schedule_nextrun(entry, &now);
237
+				}
238
+			}
239
+
240
+			if (!list_empty(&event_timeout_list)) {
241
+				entry = list_entry(event_timeout_list.next, typeof(*entry), list);
242
+
243
+				/* calc select() timeout */
244
+				sub_timeval(&timeout, &entry->nextrun, &now);
245
+				timeout_p = &timeout;
246
+			}
247
+		}
248
+
249
+		fd_set *readfds = NULL, *writefds = NULL;
250
+		struct event_fd *entry, *tmp;
251
+
252
+		list_for_each_entry_safe(entry, tmp, &event_fd_list, list) {
253
+			entry->flags &= ~EVENT_NEW;
254
+
255
+			if (entry->flags & EVENT_DELETE) {
256
+				list_del(&entry->list);
257
+				free(entry);
258
+
259
+			} else if (entry->flags & FD_READ) {
260
+				if (readfds == NULL) {
261
+					readfds = &fdsets[0];
262
+					FD_ZERO(readfds);
263
+				}
264
+				FD_SET(entry->fd, readfds);
265
+
266
+			} else if (entry->flags & FD_WRITE) {
267
+				if (writefds == NULL) {
268
+					writefds = &fdsets[1];
269
+					FD_ZERO(writefds);
270
+				}
271
+				FD_SET(entry->fd, writefds);
272
+			}
273
+		}
274
+
275
+		int i = select(FD_SETSIZE, readfds, writefds, NULL, timeout_p);
276
+		if (i <= 0) {
277
+			/* On error, -1 is returned, and errno is set
278
+			 * appropriately; the sets and timeout become
279
+			 * undefined, so do not rely on their contents
280
+			 * after an error.
281
+			 */
282
+			continue;
283
+
284
+		} else {
285
+			list_for_each_entry(entry, &event_fd_list, list) {
286
+				if ((entry->flags & EVENT_NEW) != 0) {
287
+					/* entry has just been added, execute it next round */
288
+					continue;
289
+				}
290
+
291
+				if ((entry->flags & FD_READ) && FD_ISSET(entry->fd, readfds))
292
+					if (entry->read_cb(entry->fd, entry->read_priv) != 0)
293
+						entry->flags |= EVENT_DELETE;
294
+
295
+				if ((entry->flags & FD_WRITE) && FD_ISSET(entry->fd, writefds))
296
+					if (entry->write_cb(entry->fd, entry->write_priv) != 0)
297
+						entry->flags |= EVENT_DELETE;
298
+			}
299
+		}
300
+	}
301
+	free(fdsets);
302
+}

+ 42
- 0
event.h View File

@@ -0,0 +1,42 @@
1
+#ifndef _EVENT_H_
2
+#define _EVENT_H_
3
+
4
+#include <sys/time.h>
5
+
6
+#define EVENT_NEW	0x1000
7
+#define EVENT_DELETE	0x2000
8
+
9
+#define FD_READ		0x0001
10
+#define FD_WRITE	0x0002
11
+#define FD_TYPES	(FD_READ | FD_WRITE)
12
+
13
+#define event_add_readfd(entry, fd, callback, privdata) \
14
+	event_add_fd(entry, fd, FD_READ, callback, privdata)
15
+
16
+#define event_add_writefd(entry, fd, callback, privdata) \
17
+	event_add_fd(entry, fd, FD_WRITE, callback, privdata)
18
+
19
+/* inner details are not visible to external users (TODO: size unknown) */
20
+struct event_fd;
21
+struct event_timeout;
22
+
23
+struct event_fd * event_add_fd(
24
+			struct event_fd *entry,
25
+			int fd,
26
+			int type,
27
+			int (*callback)(int fd, void *privdata),
28
+			void *privdata);
29
+
30
+int event_get_fd(struct event_fd *entry);
31
+void event_remove_fd(struct event_fd *entry);
32
+
33
+struct event_timeout * event_add_timeout(
34
+			struct timeval *timeout,
35
+			int (*callback)(void *privdata),
36
+			void *privdata);
37
+
38
+void event_remove_timeout(struct event_timeout *entry);
39
+
40
+int event_loop(void);
41
+
42
+#endif /* _EVENT_H_ */

+ 268
- 0
list.h View File

@@ -0,0 +1,268 @@
1
+#ifndef _LIST_H_
2
+#define _LIST_H_
3
+
4
+/*
5
+ * stolen from linux kernel 2.6.11 (http://kernel.org/)
6
+ * linux/include/linux/stddef.h (offsetoff)
7
+ * linux/include/linux/kernel.h (container_of)
8
+ * linux/include/linux/list.h (*list*)
9
+ * linux/include/linux/netfilter_ipv4/listhelp.h (LIST_FIND)
10
+ *
11
+ * modified by Olaf Rempel <razzor@kopf-tisch.de>
12
+ */
13
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
14
+
15
+#define container_of(ptr, type, member) ({ \
16
+		const typeof( ((type *)0)->member ) *__mptr = (ptr); \
17
+		(type *)( (char *)__mptr - offsetof(type,member) );})
18
+
19
+struct list_head {
20
+	struct list_head *next, *prev;
21
+};
22
+
23
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
24
+
25
+#define LIST_HEAD(name) \
26
+	struct list_head name = LIST_HEAD_INIT(name)
27
+
28
+#define INIT_LIST_HEAD(ptr) do { \
29
+	(ptr)->next = (ptr); (ptr)->prev = (ptr); \
30
+} while (0)
31
+
32
+/*
33
+ * Insert a new entry between two known consecutive entries.
34
+ *
35
+ * This is only for internal list manipulation where we know
36
+ * the prev/next entries already!
37
+ */
38
+static inline void __list_add(struct list_head *new,
39
+			      struct list_head *prev,
40
+			      struct list_head *next)
41
+{
42
+	next->prev = new;
43
+	new->next = next;
44
+	new->prev = prev;
45
+	prev->next = new;
46
+}
47
+
48
+/*
49
+ * list_add - add a new entry
50
+ * @new: new entry to be added
51
+ * @head: list head to add it after
52
+ *
53
+ * Insert a new entry after the specified head.
54
+ * This is good for implementing stacks.
55
+ */
56
+static inline void list_add(struct list_head *new, struct list_head *head)
57
+{
58
+	__list_add(new, head, head->next);
59
+}
60
+
61
+/*
62
+ * list_add_tail - add a new entry
63
+ * @new: new entry to be added
64
+ * @head: list head to add it before
65
+ *
66
+ * Insert a new entry before the specified head.
67
+ * This is useful for implementing queues.
68
+ */
69
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
70
+{
71
+	__list_add(new, head->prev, head);
72
+}
73
+
74
+/*
75
+ * Delete a list entry by making the prev/next entries
76
+ * point to each other.
77
+ *
78
+ * This is only for internal list manipulation where we know
79
+ * the prev/next entries already!
80
+ */
81
+static inline void __list_del(struct list_head * prev, struct list_head * next)
82
+{
83
+	next->prev = prev;
84
+	prev->next = next;
85
+}
86
+
87
+/*
88
+ * list_del - deletes entry from list.
89
+ * @entry: the element to delete from the list.
90
+ * Note: list_empty on entry does not return true after this, the entry is
91
+ * in an undefined state.
92
+ */
93
+static inline void list_del(struct list_head *entry)
94
+{
95
+	__list_del(entry->prev, entry->next);
96
+	entry->next = NULL;
97
+	entry->prev = NULL;
98
+}
99
+
100
+/*
101
+ * list_del_init - deletes entry from list and reinitialize it.
102
+ * entry: the element to delete from the list.
103
+ */
104
+static inline void list_del_init(struct list_head *entry)
105
+{
106
+	__list_del(entry->prev, entry->next);
107
+	INIT_LIST_HEAD(entry);
108
+}
109
+
110
+/*
111
+ * list_move - delete from one list and add as another's head
112
+ * @list: the entry to move
113
+ * @head: the head that will precede our entry
114
+ */
115
+static inline void list_move(struct list_head *list, struct list_head *head)
116
+{
117
+        __list_del(list->prev, list->next);
118
+        list_add(list, head);
119
+}
120
+
121
+/*
122
+ * list_move_tail - delete from one list and add as another's tail
123
+ * @list: the entry to move
124
+ * @head: the head that will follow our entry
125
+ */
126
+static inline void list_move_tail(struct list_head *list,
127
+				  struct list_head *head)
128
+{
129
+        __list_del(list->prev, list->next);
130
+        list_add_tail(list, head);
131
+}
132
+
133
+/*
134
+ * list_empty - tests whether a list is empty
135
+ * @head: the list to test.
136
+ */
137
+static inline int list_empty(const struct list_head *head)
138
+{
139
+	return head->next == head;
140
+}
141
+
142
+static inline void __list_splice(struct list_head *list,
143
+				 struct list_head *head)
144
+{
145
+	struct list_head *first = list->next;
146
+	struct list_head *last = list->prev;
147
+	struct list_head *at = head->next;
148
+
149
+	first->prev = head;
150
+	head->next = first;
151
+
152
+	last->next = at;
153
+	at->prev = last;
154
+}
155
+
156
+/*
157
+ * list_splice - join two lists
158
+ * @list: the new list to add.
159
+ * @head: the place to add it in the first list.
160
+ */
161
+static inline void list_splice(struct list_head *list, struct list_head *head)
162
+{
163
+	if (!list_empty(list))
164
+		__list_splice(list, head);
165
+}
166
+
167
+/*
168
+ * list_splice_init - join two lists and reinitialise the emptied list.
169
+ * @list: the new list to add.
170
+ * @head: the place to add it in the first list.
171
+ *
172
+ * The list at @list is reinitialised
173
+ */
174
+static inline void list_splice_init(struct list_head *list,
175
+				    struct list_head *head)
176
+{
177
+	if (!list_empty(list)) {
178
+		__list_splice(list, head);
179
+		INIT_LIST_HEAD(list);
180
+	}
181
+}
182
+
183
+/*
184
+ * list_entry - get the struct for this entry
185
+ * @ptr:	the &struct list_head pointer.
186
+ * @type:	the type of the struct this is embedded in.
187
+ * @member:	the name of the list_struct within the struct.
188
+ */
189
+#define list_entry(ptr, type, member) \
190
+	container_of(ptr, type, member)
191
+
192
+/*
193
+ * list_for_each	-	iterate over a list
194
+ * @pos:	the &struct list_head to use as a loop counter.
195
+ * @head:	the head for your list.
196
+ */
197
+#define list_for_each(pos, head) \
198
+	for (pos = (head)->next; pos != (head); pos = pos->next)
199
+
200
+/*
201
+ * list_for_each_prev	-	iterate over a list backwards
202
+ * @pos:	the &struct list_head to use as a loop counter.
203
+ * @head:	the head for your list.
204
+ */
205
+#define list_for_each_prev(pos, head) \
206
+	for (pos = (head)->prev; pos != (head); pos = pos->prev)
207
+
208
+/*
209
+ * list_for_each_safe	-	iterate over a list safe against removal of list entry
210
+ * @pos:	the &struct list_head to use as a loop counter.
211
+ * @n:		another &struct list_head to use as temporary storage
212
+ * @head:	the head for your list.
213
+ */
214
+#define list_for_each_safe(pos, n, head) \
215
+	for (pos = (head)->next, n = pos->next; pos != (head); \
216
+		pos = n, n = pos->next)
217
+
218
+/*
219
+ * list_for_each_entry	-	iterate over list of given type
220
+ * @pos:	the type * to use as a loop counter.
221
+ * @head:	the head for your list.
222
+ * @member:	the name of the list_struct within the struct.
223
+ */
224
+#define list_for_each_entry(pos, head, member)				\
225
+	for (pos = list_entry((head)->next, typeof(*pos), member);	\
226
+	     &pos->member != (head); 					\
227
+	     pos = list_entry(pos->member.next, typeof(*pos), member))
228
+
229
+/*
230
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
231
+ * @pos:	the type * to use as a loop counter.
232
+ * @head:	the head for your list.
233
+ * @member:	the name of the list_struct within the struct.
234
+ */
235
+#define list_for_each_entry_reverse(pos, head, member)			\
236
+	for (pos = list_entry((head)->prev, typeof(*pos), member);	\
237
+	     &pos->member != (head); 					\
238
+	     pos = list_entry(pos->member.prev, typeof(*pos), member))
239
+
240
+/*
241
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
242
+ * @pos:	the type * to use as a loop counter.
243
+ * @n:		another type * to use as temporary storage
244
+ * @head:	the head for your list.
245
+ * @member:	the name of the list_struct within the struct.
246
+ */
247
+#define list_for_each_entry_safe(pos, n, head, member)			\
248
+	for (pos = list_entry((head)->next, typeof(*pos), member),	\
249
+		n = list_entry(pos->member.next, typeof(*pos), member);	\
250
+	     &pos->member != (head); 					\
251
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
252
+
253
+
254
+/* Return pointer to first true entry, if any, or NULL.  A macro
255
+   required to allow inlining of cmpfn. */
256
+#define LIST_FIND(head, cmpfn, type, args...)           \
257
+({                                                      \
258
+        const struct list_head *__i, *__j = NULL;       \
259
+                                                        \
260
+        list_for_each(__i, (head))                      \
261
+                if (cmpfn((const type)__i , ## args)) { \
262
+                        __j = __i;                      \
263
+                        break;                          \
264
+                }                                       \
265
+        (type)__j;                                      \
266
+})
267
+
268
+#endif /* _LIST_H_ */

+ 102
- 0
logging.c View File

@@ -0,0 +1,102 @@
1
+/***************************************************************************
2
+ *   Copyright (C) 06/2006 by Olaf Rempel                                  *
3
+ *   razzor@kopf-tisch.de                                                  *
4
+ *                                                                         *
5
+ *   This program is free software; you can redistribute it and/or modify  *
6
+ *   it under the terms of the GNU General Public License as published by  *
7
+ *   the Free Software Foundation; either version 2 of the License, or     *
8
+ *   (at your option) any later version.                                   *
9
+ *                                                                         *
10
+ *   This program is distributed in the hope that it will be useful,       *
11
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13
+ *   GNU General Public License for more details.                          *
14
+ *                                                                         *
15
+ *   You should have received a copy of the GNU General Public License     *
16
+ *   along with this program; if not, write to the                         *
17
+ *   Free Software Foundation, Inc.,                                       *
18
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19
+ ***************************************************************************/
20
+#include <stdio.h>
21
+#include <stdlib.h>
22
+#include <time.h>
23
+#include <stdarg.h>
24
+#include <errno.h>
25
+#include <string.h>
26
+
27
+#include "logging.h"
28
+
29
+#define BUFSIZE 8192
30
+
31
+static FILE *log_fd = NULL;
32
+static int log_prio = LOG_EVERYTIME;
33
+static char *buffer = NULL;
34
+
35
+int log_print(int prio, const char *fmt, ...)
36
+{
37
+	va_list az;
38
+	int len = 0, retval;
39
+
40
+	if (prio < log_prio)
41
+		return 0;
42
+
43
+	if (buffer == NULL) {
44
+		buffer = malloc(BUFSIZE);
45
+		if (buffer == NULL) {
46
+			fprintf(stderr, "log_print(): out of memory\n");
47
+			return -1;
48
+		}
49
+	}
50
+
51
+	if (log_fd != NULL) {
52
+		time_t  tzgr;
53
+		time(&tzgr);
54
+
55
+		len += strftime(buffer, BUFSIZE, "%b %d %H:%M:%S :", localtime(&tzgr));
56
+	}
57
+
58
+	va_start(az, fmt);
59
+	len += vsnprintf(buffer + len, BUFSIZE - len, fmt, az);
60
+	va_end(az);
61
+
62
+	if (len < 0 || len >= BUFSIZE) {
63
+		errno = 0;
64
+		return log_print(LOG_ERROR, "log_print: arguments too long");
65
+	}
66
+
67
+	if (errno) {
68
+		len += snprintf(buffer + len, BUFSIZE - len, ": %s", strerror(errno));
69
+		errno = 0;
70
+	}
71
+
72
+	retval = fprintf((log_fd ? log_fd : stderr), "%s\n", buffer);
73
+	fflush(log_fd);
74
+	return retval;
75
+}
76
+
77
+void log_close(void)
78
+{
79
+	if (buffer)
80
+		free(buffer);
81
+
82
+	if (log_fd)
83
+		fclose(log_fd);
84
+}
85
+
86
+int log_init(const char *logfile)
87
+{
88
+	if (log_fd != NULL)
89
+		log_close();
90
+
91
+	log_fd = fopen(logfile, "a");
92
+	if (log_fd == NULL) {
93
+		fprintf(stderr, "log_init(): can not open logfile");
94
+		return -1;
95
+	}
96
+	return 0;
97
+}
98
+
99
+void log_setprio(int prio)
100
+{
101
+	log_prio = prio;
102
+}

+ 19
- 0
logging.h View File

@@ -0,0 +1,19 @@
1
+#ifndef _LOGGING_H_
2
+#define _LOGGING_H_
3
+
4
+#define LOG_DEBUG 5
5
+#define LOG_INFO  4
6
+#define LOG_NOTICE 3
7
+#define LOG_WARN 2
8
+#define LOG_ERROR 1
9
+#define LOG_CRIT 0
10
+
11
+#define LOG_EVERYTIME 0
12
+
13
+int log_init(const char *logfile);
14
+void log_close(void);
15
+void log_setprio(int prio);
16
+
17
+int log_print(int prio, const char *fmt, ... );
18
+
19
+#endif /* _LOGGING_H_ */

+ 115
- 0
serial.c View File

@@ -0,0 +1,115 @@
1
+#include <stdio.h>
2
+#include <stdlib.h>
3
+#include <unistd.h>
4
+#include <string.h>
5
+
6
+#include <fcntl.h>
7
+#include <termios.h>
8
+
9
+#include "configfile.h"
10
+#include "context.h"
11
+#include "event.h"
12
+#include "logging.h"
13
+#include "statemachine.h"
14
+
15
+struct serial_device {
16
+	struct termios oldtio;
17
+	struct termios newtio;
18
+};
19
+
20
+static int open_serial(struct context *ctx, const char *devname)
21
+{
22
+	struct serial_device *sdev = (struct serial_device *)ctx->dev_privdata;
23
+
24
+	ctx->fd = open(devname, O_RDWR);
25
+	if (ctx->fd < 0) {
26
+		log_print(LOG_ERROR, "open_serial(): open(%s)", devname);
27
+		return -1;
28
+	}
29
+
30
+	ctx->devname = strdup(devname);
31
+
32
+	if (tcgetattr(ctx->fd, &sdev->oldtio) != 0) {
33
+		log_print(LOG_WARN, "open_serial(): tcgetattr()");
34
+		close(ctx->fd);
35
+		return -1;
36
+	}
37
+
38
+	bzero(&sdev->newtio, sizeof(struct termios));
39
+	sdev->newtio.c_cflag = B9600 | CRTSCTS | CS8 | CLOCAL | CREAD;
40
+
41
+	tcflush(ctx->fd, TCIOFLUSH);
42
+
43
+	if (tcsetattr(ctx->fd, TCSANOW, &sdev->newtio) != 0) {
44
+		log_print(LOG_WARN, "open_serial(): tcsetattr()");
45
+		close(ctx->fd);
46
+		return -1;
47
+	}
48
+
49
+	return 0;
50
+}
51
+
52
+static int setbaudrate(struct context *ctx, int baudrate)
53
+{
54
+	struct serial_device *sdev = (struct serial_device *)ctx->dev_privdata;
55
+
56
+	cfsetispeed(&sdev->newtio, baudrate);
57
+	cfsetospeed(&sdev->newtio, baudrate);
58
+
59
+	/* flush linebuffer */
60
+	ctx->linepos = 0;
61
+
62
+	if (tcsetattr(ctx->fd, TCSANOW, &sdev->newtio) != 0) {
63
+		log_print(LOG_WARN, "open_serial(): tcsetattr()");
64
+		close(ctx->fd);
65
+		return -1;
66
+	}
67
+
68
+	return 0;
69
+}
70
+
71
+static int close_serial(struct context *ctx)
72
+{
73
+	struct serial_device *sdev = (struct serial_device *)ctx->dev_privdata;
74
+
75
+	event_remove_fd(ctx->event);
76
+
77
+	tcsetattr(ctx->fd, TCSANOW, &sdev->oldtio);
78
+	free(ctx->devname);
79
+	close(ctx->fd);
80
+	return 0;
81
+}
82
+
83
+static int serial_init_cb(const char *parameter, void *privdata)
84
+{
85
+	struct context *ctx = create_context();
86
+	if (ctx == NULL)
87
+		return -1;
88
+
89
+	ctx->dev_privdata = malloc(sizeof(struct serial_device));
90
+	if (ctx->dev_privdata == NULL) {
91
+		log_print(LOG_WARN, "serial_init_cb(): out of memory");
92
+		destroy_context(ctx);
93
+		return -1;
94
+	}
95
+
96
+	if (open_serial(ctx, parameter) < 0) {
97
+		free(ctx->dev_privdata);
98
+		destroy_context(ctx);
99
+		return -1;
100
+	}
101
+
102
+	log_print(LOG_EVERYTIME, "listen on %s", ctx->devname);
103
+
104
+	ctx->dev_close = close_serial;
105
+	ctx->dev_setbaudrate = setbaudrate;
106
+
107
+	ctx->event = event_add_readfd(NULL, ctx->fd, statemachine_read, ctx);
108
+	return 0;
109
+}
110
+
111
+int serial_init(void)
112
+{
113
+	config_get_strings("ports", "serial", serial_init_cb, NULL);
114
+	return 0;
115
+}

+ 6
- 0
serial.h View File

@@ -0,0 +1,6 @@
1
+#ifndef _SERIAL_H_
2
+#define _SERIAL_H_
3
+
4
+int serial_init(void);
5
+
6
+#endif /* _SERIAL_H_ */

+ 148
- 0
statemachine.c View File

@@ -0,0 +1,148 @@
1
+#include <stdio.h>
2
+#include <stdlib.h>
3
+#include <unistd.h>
4
+#include <string.h>
5
+
6
+#include <termios.h>
7
+
8
+#include "context.h"
9
+#include "logging.h"
10
+#include "xmodem.h"
11
+
12
+/* states */
13
+enum {
14
+	STATE_NONE = 0,
15
+	STATE_DEBUG_ASK,	/* waiting for "Press any key.." */
16
+	STATE_DEBUG,		/* debug mode entered */
17
+	STATE_SWITCH_BAUDRATE,	/* switching baudrate */
18
+	STATE_XMODEM,		/* xmodem active */
19
+	STATE_XMODEM_COMPLETE,	/* xmodem complete */
20
+	STATE_BOOT,		/* booting firmware */
21
+};
22
+
23
+/* messages */
24
+char *rx_msg[] = {
25
+	"Press any key to enter debug mode within 3 seconds.",
26
+	"Enter Debug Mode",
27
+	"Now, console speed will be changed to 115200 bps",
28
+	"OK",
29
+	"Console speed will be changed to 9600 bps",
30
+	NULL
31
+};
32
+
33
+/* message IDs */
34
+enum {
35
+	MSG_DEBUG_ASK = 0,
36
+	MSG_DEBUG,
37
+	MSG_BAUD_HIGH,
38
+	MSG_XMODEM_OK,
39
+	MSG_BAUD_LOW,
40
+};
41
+
42
+static int my_readline(int fd, struct context *ctx, char **retval)
43
+{
44
+	/* TODO: not tested */
45
+	char *newline = memchr(ctx->linebuf, '\r', ctx->linepos);
46
+	if (newline != NULL) {
47
+		*newline = '\0';
48
+		*retval = strdup(ctx->linebuf);
49
+
50
+		ctx->linepos -= (newline - ctx->linebuf);
51
+		memmove(ctx->linebuf, newline +1, ctx->linepos);
52
+
53
+		return 0;
54
+	}
55
+
56
+	char buf[32];
57
+	int len = read(fd, buf, sizeof(buf));
58
+	if (len <= 0)
59
+		return -1;
60
+
61
+	int i;
62
+	for (i = 0; i < len; i++) {
63
+		/* "understand" backspace */
64
+		if (buf[i] == 0x08 && ctx->linepos > 0) {
65
+			ctx->linepos--;
66
+
67
+		/* export buffer */
68
+		} else if (buf[i] == '\r' && *retval == NULL) {
69
+			ctx->linebuf[ctx->linepos] = '\0';
70
+
71
+			if (ctx->linepos > 0)
72
+				*retval = strdup(ctx->linebuf);
73
+
74
+			ctx->linepos = 0;
75
+
76
+		/* copy */
77
+		} else if (buf[i] >= ' ') {
78
+			ctx->linebuf[ctx->linepos++] = buf[i];
79
+		}
80
+	}
81
+	return 0;
82
+}
83
+
84
+int statemachine_read(int fd, void *privdata)
85
+{
86
+	struct context *ctx = (struct context *)privdata;
87
+
88
+	if (ctx->state == STATE_XMODEM) {
89
+		if (xmodem_read(fd, privdata) < 0)
90
+			ctx->state = STATE_XMODEM_COMPLETE;
91
+
92
+		return 0;
93
+	}
94
+
95
+	char *line = NULL;
96
+	if (my_readline(fd, ctx, &line) < 0)
97
+		return -1;
98
+
99
+	if (line == NULL)
100
+		return 0;
101
+
102
+	log_print(LOG_DEBUG, "%s: '%s'", ctx->devname, line);
103
+
104
+	int msg = 0;
105
+	while (rx_msg[msg] != NULL) {
106
+		if (strcmp(line, rx_msg[msg]) == 0)
107
+			break;
108
+
109
+		msg++;
110
+	}
111
+
112
+	/* wait for "Press any key" */
113
+	if (msg == MSG_DEBUG_ASK) {
114
+		ctx->state = STATE_DEBUG_ASK;
115
+		write(fd, "\r\n", 2);
116
+
117
+	/* debug mode entered */
118
+	} else if (msg == MSG_DEBUG) {
119
+		/* if device supports it, switch to high baudrate */
120
+		if (ctx->dev_setbaudrate != NULL) {
121
+			ctx->state = STATE_SWITCH_BAUDRATE;
122
+			write(fd, "ATBA5\r\n", 7);
123
+
124
+		} else {
125
+			ctx->state = STATE_XMODEM;
126
+			write(fd, "ATLC\r\n", 6);
127
+		}
128
+
129
+	/* follow device to high baudrate */
130
+	} else if (msg == MSG_BAUD_HIGH) {
131
+		ctx->dev_setbaudrate(ctx, B115200);
132
+
133
+		ctx->state = STATE_XMODEM;
134
+		write(fd, "ATLC\r\n", 6);
135
+
136
+	/* transfer was success */
137
+	} else if (msg == MSG_XMODEM_OK && ctx->state == STATE_XMODEM_COMPLETE) {
138
+		ctx->state = STATE_BOOT;
139
+		write(fd, "ATGR\r\n", 6);
140
+
141
+	/* follow device to low baudrate */
142
+	} else if (msg == MSG_BAUD_LOW) {
143
+		ctx->dev_setbaudrate(ctx, B9600);
144
+	}
145
+
146
+	free(line);
147
+	return 0;
148
+}

+ 6
- 0
statemachine.h View File

@@ -0,0 +1,6 @@
1
+#ifndef _STATEMACHINE_H_
2
+#define _STATEMACHINE_H_
3
+
4
+int statemachine_read(int fd, void *privdata);
5
+
6
+#endif /* _STATEMACHINE_H_ */

+ 156
- 0
xmodem.c View File

@@ -0,0 +1,156 @@
1
+#include <stdio.h>
2
+#include <stdlib.h>
3
+#include <unistd.h>
4
+#include <string.h>
5
+#include <stdint.h>
6
+
7
+#include <sys/types.h>
8
+#include <sys/stat.h>
9
+#include <fcntl.h>
10
+
11
+#include "configfile.h"
12
+#include "context.h"
13
+#include "logging.h"
14
+
15
+static char *filedata;
16
+static int filesize;
17
+
18
+enum {
19
+	XM_SOH = 0x01,
20
+	XM_EOT = 0x04,
21
+	XM_ACK = 0x06,
22
+	XM_NACK = 0x15,
23
+	XM_C = 0x43
24
+};
25
+
26
+struct xmodem_pkt {
27
+	uint8_t header;
28
+	uint8_t count;
29
+	uint8_t ncount;
30
+	uint8_t data[128];
31
+	uint16_t crc;
32
+} __attribute__((packed));
33
+
34
+
35
+static void calc_crc(struct xmodem_pkt *pkt)
36
+{
37
+	uint16_t crc = 0;
38
+	uint8_t *ptr = pkt->data;
39
+
40
+	int i, j;
41
+	for (i = 0; i < sizeof(pkt->data); i++) {
42
+		crc = crc ^ (*ptr++ << 8);
43
+
44
+		for (j = 0; j < 8; j++)
45
+			crc = (crc & 0x8000) ? (crc << 1 ^ 0x1021) : (crc << 1);
46
+	}
47
+
48
+	/* byteswap */
49
+	pkt->crc = ((crc & 0xFF00) >> 8) | ((crc & 0xFF) << 8);
50
+}
51
+
52
+int xmodem_read(int fd, void *privdata)
53
+{
54
+	struct context *ctx = (struct context *)privdata;
55
+
56
+	struct xmodem_pkt pkt;
57
+
58
+	int len = read(fd, &pkt, sizeof(pkt));
59
+	if (len <= 0) {
60
+		log_print(LOG_WARN, "xmodem_read(): read()");
61
+		return -1;
62
+	}
63
+
64
+	int pktnum = 0;
65
+
66
+	switch (pkt.header) {
67
+	case XM_C:	/* first packet */
68
+		log_print(LOG_DEBUG, "%s: XMODEM started", ctx->devname);
69
+		pktnum = 0;
70
+		break;
71
+
72
+	case XM_ACK:	/* next packet */
73
+		if (ctx->lastpkt * 128 == filesize)
74
+			return -1;
75
+
76
+		pktnum = ctx->lastpkt +1;
77
+		break;
78
+
79
+	case XM_NACK:	/* resend last packet */
80
+		pktnum = ctx->lastpkt;
81
+		break;
82
+	}
83
+
84
+	if (pktnum * 128 < filesize) {
85
+		pkt.header = XM_SOH;
86
+		pkt.count = ((pktnum +1) & 0xFF);
87
+		pkt.ncount = 0xFF - pkt.count;
88
+
89
+		memcpy(pkt.data, filedata + pktnum * 128, 128);
90
+
91
+		calc_crc(&pkt);
92
+		write(fd, &pkt, sizeof(pkt));
93
+
94
+	} else {
95
+		log_print(LOG_DEBUG, "%s: XMODEM completed", ctx->devname);
96
+		pkt.header = XM_EOT;
97
+		write(fd, &pkt, 1);
98
+	}
99
+
100
+	ctx->lastpkt = pktnum;
101
+	return 0;
102
+}
103
+
104
+static int load_file_data(const char *filename)
105
+{
106
+	int fd = open(filename, O_RDONLY);
107
+	if (fd < 0) {
108
+		log_print(LOG_WARN, "load_file_content(): open()");
109
+		return -1;
110
+	}
111
+
112
+	struct stat filestat;
113
+	if (fstat(fd, &filestat) < 0) {
114
+		log_print(LOG_WARN, "load_file_content(): fstat()");
115
+		close(fd);
116
+		return -1;
117
+	}
118
+
119
+	filesize = filestat.st_size;
120
+
121
+	filedata = malloc(filesize);
122
+	if (filedata == NULL) {
123
+		log_print(LOG_WARN, "load_file_content(): malloc()");
124
+		close(fd);
125
+		return -1;
126
+	}
127
+
128
+	/* TODO: padding */
129
+	int readsize = read(fd, filedata, filesize);
130
+	if (readsize != filesize) {
131
+		log_print(LOG_WARN, "load_file_content(): read()");
132
+		free(filedata);
133
+		close(fd);
134
+		return -1;
135
+	}
136
+
137
+	close(fd);
138
+	return 0;
139
+}
140
+
141
+int xmodem_init(void)
142
+{
143
+	const char *filename = config_get_string("global", "configdata", NULL);
144
+	if (filename == NULL)
145
+		return -1;
146
+
147
+	if (load_file_data(filename) < 0)
148
+		return -1;
149
+
150
+	return 0;
151
+}
152
+
153
+void xmodem_close(void)
154
+{
155
+	free(filedata);
156
+}

+ 9
- 0
xmodem.h View File

@@ -0,0 +1,9 @@
1
+#ifndef _XMODEM_H_
2
+#define _XMODEM_H_
3
+
4
+int xmodem_init(void);
5
+void xmodem_close(void);
6
+
7
+int xmodem_read(int fd, void *privdata);
8
+
9
+#endif /* _XMODEM_H_ */

+ 81
- 0
zyxel-revert.c View File

@@ -0,0 +1,81 @@
1
+#include <stdio.h>
2
+#include <stdlib.h>
3
+#include <unistd.h>
4
+#include <string.h>
5
+
6
+#include <getopt.h>
7
+
8
+#include "configfile.h"
9
+#include "context.h"
10
+#include "event.h"
11
+#include "serial.h"
12
+#include "xmodem.h"
13
+
14
+#define DEFAULT_CONFIG "zyxel-revert.conf"
15
+
16
+static struct option opts[] = {
17
+	{"config",	1, 0, 'c'},
18
+	{"debug",	0, 0, 'd'},
19
+	{"help",	0, 0, 'h'},
20
+	{0, 0, 0, 0}
21
+};
22
+
23
+int main(int argc, char *argv[])
24
+{
25
+	char *config = DEFAULT_CONFIG;
26
+	int code, arg = 0, debug = 0;
27
+
28
+	do {
29
+		code = getopt_long(argc, argv, "c:dh", opts, &arg);
30
+
31
+		switch (code) {
32
+		case 'c':	/* config */
33
+				config = optarg;
34
+				break;
35
+
36
+		case 'd':	/* debug */
37
+				debug = 1;
38
+				break;
39
+
40
+		case 'h':	/* help */
41
+				printf("Usage: zyxel-revert [options]\n"
42
+					"Options: \n"
43
+					"  --config       -c  configfile  use this configfile\n"
44
+					"  --debug        -d              do not fork and log to stderr\n"
45
+					"  --help         -h              this help\n"
46
+					"\n");
47
+				exit(0);
48
+				break;
49
+
50
+		case '?':	/* error */
51
+				exit(-1);
52
+				break;
53
+
54
+		default:	/* unknown / all options parsed */
55
+				break;
56
+		}
57
+	} while (code != -1);
58
+
59
+	if (config_parse(config))
60
+		exit(1);
61
+
62
+	if (serial_init())
63
+		exit(1);
64
+
65
+//	if (network_init()) {
66
+//		context_close();
67
+//		exit(1);
68
+//	}
69
+
70
+	if (xmodem_init()) {
71
+		context_close();
72
+		exit(1);
73
+	}
74
+
75
+	event_loop();
76
+
77
+	xmodem_close();
78
+	context_close();
79
+
80
+	return 0;
81
+}

+ 5
- 0
zyxel-revert.conf View File

@@ -0,0 +1,5 @@
1
+[global]
2
+configdata 350LI2C1.rom
3
+
4
+[ports]
5
+serial /dev/ttyUSB0

Loading…
Cancel
Save