Included SpanDSP functions for T.38 fax, local aim being TIFF over TFTP
[firmerware] / src / function / bootloader.c
1 /* bootloader.c -- Access to flash partitions
2  *
3  * This file is part of 0cpm Firmerware.
4  *
5  * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
6  *
7  * 0cpm Firmerware is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation, version 3.
10  *
11  * 0cpm Firmerware is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20
21 /* This module can be linked in with various targets, to give
22  * them access to the flash memory, and support updates.
23  *
24  * From: Rick van Rein <rick@openfortress.nl>
25  */
26
27
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <stdint.h>
31 #include <stdbool.h>
32
33 #include <config.h>
34
35 #include <0cpm/cons.h>
36 #include <0cpm/flash.h>
37 #include <0cpm/netinet.h>
38 #include <0cpm/netfun.h>
39
40
41 /* Sanity check */
42
43 #ifndef HAVE_FLASH_PARTITIONS
44 #error "This target does not define a flash partition table yet"
45 #endif
46
47
48 /* Global data */
49
50 static struct flashpart *current = NULL;
51 static uint16_t blocknum;
52 static bool sending = false, receiving = false;
53
54
55 /* Handle a TFTP request that came in over LLC1.
56  *
57  * This code is rather brutal -- it only does binary transfers,
58  * and it supports no options at all.  It is mainly intended for
59  * bootstrapping (bootloading) purposes, offering access to the
60  * flash memory contained in the machine.
61  */
62 uint8_t *netllc_tftp (uint8_t *pkt, intptr_t *mem) {
63         uint16_t cmd;
64         uint16_t pktlen, pktlen2;
65         uint16_t replylen = 0;
66         uint8_t *llc = (uint8_t *) mem [MEM_ETHER_HEAD];
67         pktlen = mem [MEM_ALL_DONE] - mem [MEM_ETHER_HEAD];
68         memcpy (pkt, llc+6, 6);
69         bottom_flash_get_mac (pkt+6);
70         pktlen2 = (llc [12] << 8) | llc [13];
71 bottom_printf ("netllc_tftp, pktlen=%d, pktlen2=%d\n", (intptr_t) pktlen, (intptr_t) pktlen2);
72         if (pktlen < 12 + 2 + 3 + 4) {
73                 return;
74         }
75         if (pktlen < pktlen2 + 12 + 2) {
76                 return;
77         }
78         cmd = (llc [12 + 2 + 3 + 0] << 8) | llc [12 + 2 + 3 + 1];
79 bottom_printf ("Processing TFTP command %d\n", (intptr_t) cmd);
80         if ((cmd == 1) || (cmd == 2)) {         /* 1==RRQ, 2=WRQ, new setup */
81                 llc [pktlen - 1] = 0;
82                 bottom_printf ("TFTP %s for %s\n",
83                         (intptr_t) ((cmd == 1)? "RRQ": "WRQ"),
84                         (intptr_t) (llc + 12 + 2 + 3 + 2));
85                 current = (struct flashpart *) "TODO"; //TODO// current=flash_find_file(...), return if not found
86                 sending   = (current != NULL) && (cmd == 1);
87                 receiving = (current != NULL) && (cmd == 2);
88                 replylen = 12 + 2 + 3;
89                 blocknum = 0;
90                 if (sending) {
91                         goto sendblock;
92                 }
93                 if (receiving) {
94                         pkt [replylen++] = 0x00;        // send ACK
95                         pkt [replylen++] = 0x04;
96                         pkt [replylen++] = 0x00;
97                         pkt [replylen++] = 0x00;
98                 }
99         } else if (cmd == 3) {                  /* 3==DATA, store or burn */
100                 if (!current) {
101                         bottom_printf ("TFTP DATA received without connection\n");
102                 } else if (!receiving) {
103                         bottom_printf ("TFTP DATA received while not receiving\n");
104                 } else if ((pktlen2 != 3 + 4 + 512) && (pktlen2 != 3 + 4 + 0)) {
105                         bottom_printf ("TFTP DATA is not a 512-byte block\n");
106                 } else if (((pkt [12 + 2 + 3 + 2] << 8) | pkt [12 + 2 + 3 + 3]) != (blocknum + 1)) {
107                         bottom_printf ("TFTP DATA numbering out of sequence\n");
108                 } else {
109                         blocknum++;
110                         /* Ignore, do not actually store the block anywhere */
111                         pkt [12 + 2 + 3 + 0] = 0x00;    // send ACK
112                         pkt [12 + 2 + 3 + 1] = 0x04;
113                         pkt [12 + 2 + 3 + 2] = blocknum >> 8;
114                         pkt [12 + 2 + 3 + 3] = blocknum & 0xff;
115                         replylen = 12 + 2 + 3 + 4;
116                 }
117         } else if (cmd == 4) {                  /* 4==ACK, send next if sending  */
118                 if (!current) {
119                         bottom_printf ("TFTP ACK received without connection\n");
120                 } else if (!sending) {
121                         bottom_printf ("TFTP ACK received while not sending\n");
122 #if 0
123                 } else if (pktlen != 12 + 2 + 3 + 4) {
124                         bottom_printf ("TFTP ACK is not of the proper legnth\n");
125 #endif
126                 } else if (((pkt [12 + 2 + 3 + 2] << 8) | pkt [12 + 2 + 3 + 3]) != blocknum) {
127                         bottom_printf ("TFTP ACK numbering out of sequence\n");
128                 } else {
129 sendblock:
130                         /* If more data is available, send it */
131                         blocknum++;
132                         pkt [12 + 2 + 3 + 0] = 0x00;    // send DATA
133                         pkt [12 + 2 + 3 + 1] = 0x03;
134                         pkt [12 + 2 + 3 + 2] = blocknum >> 8;
135                         pkt [12 + 2 + 3 + 3] = blocknum & 0xff;
136                         if (bottom_flash_read (blocknum - 1, pkt + 12 + 2 + 3 + 4)) {
137                                 replylen = 12 + 2 + 3 + 4 + 512;
138                         } else {
139                                 replylen = 12 + 2 + 3 + 4 +   0;
140                         }
141                 }
142         } else if (cmd == 5) {                  /* 5==ERR */
143                 pkt [pktlen-1] = 0;
144                 bottom_printf ("TFTP error %d received: %s\n", 
145                         (intptr_t) ((pkt [12 + 2 + 3 + 2] << 8) | pkt [12 + 2 + 3 + 3]),
146                         (intptr_t) (pkt + 12 + 2 + 3 + 4));
147                 /* no further error handling */
148         }
149         if (replylen) {
150 bottom_printf ("TFTP reply consists of %d bytes\n", replylen);
151                 // netllc_reply (pkt, mem);
152                 pkt [12] = (replylen - 12 - 2) >> 8;
153                 pkt [13] = (replylen - 12 - 2) & 0xff;
154                 pkt [12 + 2 + 0] = mem [MEM_LLC_SSAP];          /* DSAP */
155                 pkt [12 + 2 + 1] = 68;                          /* SSAP */
156                 pkt [12 + 2 + 2] = 0x03;        /* UI, unnumbered information */
157                 mem [MEM_ETHER_HEAD]  = (intptr_t) pkt;
158                 mem [MEM_LLC_PAYLOAD] = (intptr_t) pkt + 17;
159                 return pkt + replylen;
160         } else {
161 bottom_printf ("No TFTP reply package\n");
162                 return NULL;
163         }
164 }
165
166
167
168 /********** END OF LIBRARY FUNCTIONS ***** START OF MAIN PROGRAM **********/
169
170
171
172 #ifdef CONFIG_MAINFUNCTION_BOOTLOADER
173
174 /* Bootloader main program.
175  *
176  * Only included if the bootloader is compiled as the main target.
177  * If not, the bootloader is an optional add-on for the target.
178  */
179
180 uint8_t pkt [700];
181 void top_main (void) {
182         void nethandler_llconly (uint8_t *pkt, uint16_t pktlen);
183         bool active = false;
184         uint16_t pktlen;
185         bottom_critical_region_end ();
186         while (bottom_phone_is_offhook ()) {
187                 if (!active) {
188                         bottom_printf ("TFTP bootloader starts on SAP 68\n");
189                         active = true;
190                 }
191                 pktlen = sizeof (pkt);
192                 if (bottom_network_recv (pkt, &pktlen)) {
193                         nethandler_llconly (pkt, pktlen);
194                 }
195         }
196         if (active) {
197                 bottom_printf ("TFTP bootloader ends\n");
198                 //TODO// Flush and close logging?
199         } else {
200                 bottom_printf ("TFTP bootloader skipped -- reboot offhook to activate\n");
201         }
202 }
203
204 /* If this is the main program, various other functions are
205  * needed to keep the linker happy.
206  */
207 void top_button_press (void) { ; }
208 void top_button_release (void) { ; }
209 void top_hook_update (void) { ; }
210 void top_network_can_recv (void) { ; }
211 void top_network_can_send (void) { ; }
212 void top_network_offline (void) { ; }
213 void top_network_online (void) { ; }
214 void top_timer_expiration (void) { ; }
215 void top_codec_can_play (uint8_t chan) { ; }
216 void top_codec_can_record (uint8_t chan) { ; }
217
218 #endif /* CONFIG_MAINFUNCTION_BOOTLOADER */
219