1 /* llconly.c -- Network functions covering LLC only.
3 * This file is part of 0cpm Firmerware.
5 * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
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.
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.
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/>.
22 * This mini network stack is designed for very simple targets,
23 * such as network testing or a bootloader. It only supports
24 * IEEE 802.2, that is, LLC. And it even does a fairly modest
27 * This code is suitable for running a network console over LLC2
28 * and for running TFTP over LLC1. It was not designed with any
29 * higher purpose in mind. It is not designed to integrate with
30 * a more complete network stack like the phone application's.
31 * Hence the name llconly.c!
33 * Use this minimal network stack where you have no other way of
34 * extracting logs, or exchanging bootloadables. There is an
35 * alternative LLC implementation in the "real" phone firmware,
36 * which is much better because it can rely on resend timers.
38 * From: Rick van Rein <rick@openfortress.nl>
50 #include <0cpm/cons.h>
51 #include <0cpm/netinet.h>
52 #include <0cpm/netfun.h>
56 /* Construct an LLC reply start; fill out ethernet addresses and SSAP/DSAP */
57 uint8_t *netreply_llc (uint8_t *pout, intptr_t *mem) {
58 memcpy (pout + 0, ((uint8_t *) mem [MEM_ETHER_HEAD] + 6), 6);
59 bottom_flash_get_mac (pout + 6);
60 pout [14] = mem [MEM_LLC_SSAP];
61 pout [15] = mem [MEM_LLC_DSAP];
65 static bool llc_connected = false;
66 static uint8_t peer_sap;
67 static uint8_t peer_mac [6];
68 static uint8_t llc_ua [6 + 6 + 2 + 3];
69 static uint8_t llc_rr [6 + 6 + 2 + 4];
70 static uint8_t llc_sent;
71 static uint8_t llc_received;
72 static uint8_t llc_input;
73 static intptr_t mem [MEM_NETVAR_COUNT];
79 static struct llc2 llc2_dummy_handle;
82 /* Dummy LLC2 send routine, ignoring "cnx" as there is just one LLC2 connection.
83 * Before sending, the routine will first establish whether the last send
84 * was successful; if not, it will repeat that. The return value is true if at
85 * least the new send was done, relying on future calls to resend if need be.
87 uint8_t llc_pkt [100];
89 bool netsend_llc2 (struct llc2 *cnx, uint8_t *data, uint16_t datalen) {
97 newpkt = (llc_sent == llc_received);
99 // Sending is complete, construct new packet as requested
100 memcpy (llc_pkt + 0, peer_mac, 6);
101 memcpy (llc_pkt + 6, "\x00\x0b\x82\x19\xa0\xf4", 6);
103 llc_pkt [13] = datalen + 4;
104 llc_pkt [14] = peer_sap; // DSAP
105 llc_pkt [15] = 20; // SSAP
106 llc_pkt [16] = llc_sent << 1; // N(S) = 0x00, information frame
107 llc_pkt [17] = llc_input << 1; // N(R) = sent-up-to-here, low bit reset
108 memcpy (llc_pkt + 18, data, datalen);
109 llc_pktlen = 6 + 6 + 2 + 4 + datalen;
113 bottom_network_send (llc_pkt, llc_pktlen);
117 /* LLC-only network packet handling, specifically for:
118 * - LLC2 console at SAP 20
119 * - LLC1 firmware access through TFTP at SAP 68
121 void nethandler_llconly (uint8_t *pkt, uint16_t pktlen) {
126 typelen = (pkt [12] << 8) | pkt [13];
128 if ((pktlen < 14) || (typelen < 46)) {
129 #ifdef CONFIG_MAINFUNCTION_DEVEL_NETWORK
130 bottom_printf ("Unpadded packet length %d received\n", (intptr_t) pktlen);
135 if (typelen > 1500) {
136 #ifdef CONFIG_MAINFUNCTION_DEVEL_NETWORK
137 bottom_printf ("Traffic is not LLC but protocol 0x%4x\n", (intptr_t) typelen);
141 if ((typelen > 64) && (typelen != pktlen - 14)) {
142 #ifdef CONFIG_MAINFUNCTION_DEVEL_NETWORK
143 bottom_printf ("Illegal length %d received (pktlen = %d)\n", (intptr_t) typelen, (intptr_t) pktlen);
148 if (pkt [14] != 20) {
149 #ifdef CONFIG_MAINFUNCTION_DEVEL_NETWORK
150 bottom_printf ("Received LLC traffic for SAP %d instead of 20\n", pkt [14]);
156 type1 = (cmd & 0x03) == 0x03;
158 cmd |= pkt [17] << 8;
160 if (llc_connected && !type1) {
161 if (memcmp (pkt + 6, peer_mac, 6) != 0) {
162 // Peer MAC should be the constant while connected
165 if ((pkt [15] & 0xfe) != peer_sap) {
166 // Peer SAP should be constant while connected
170 if (cmd == 0x03) { // UI (llc.datagram)
171 #ifdef CONFIG_FUNCTION_FIRMWARE_UPGRADES
172 if (pkt [14] == 68) {
174 // Setup minimal mem[] array for TFTP over LLC1
175 bzero (mem, sizeof (mem));
176 mem [MEM_ETHER_HEAD] = (intptr_t) pkt;
177 mem [MEM_ALL_DONE] = (intptr_t) &pkt [pktlen];
178 mem [MEM_LLC_DSAP] = pkt [14];
179 mem [MEM_LLC_SSAP] = pkt [15];
180 pkt = netllc_tftp (pkt, mem);
181 pktlen = mem [MEM_ALL_DONE] - (intptr_t) pkt;
182 // Send and forget -- LLC1 is unconfirmed transmission
183 bottom_network_send (pkt, pktlen);
185 #ifdef CONFIG_MAINFUNCTION_DEVEL_NETWORK
186 bottom_printf ("LLC1 UA is only used for TFTP, use SAP 68 and not %d\n", (intptr_t) pkt [14]);
190 #ifdef CONFIG_MAINFUNCTION_DEVEL_NETWORK
191 bottom_printf ("No bootloader -- ignoring TFTP over LLC1\n");
193 } else if (pkt [14] != 20) {
194 #ifdef CONFIG_MAINFUNCTION_DEVEL_NETWORK
195 bottom_printf ("To access the network console, use SAP 20 and not %d\n", (intptr_t) pkt [14]);
198 } else if (cmd == 0x7f) { // SABME (llc.connect)
199 memcpy (peer_mac, pkt + 6, 6);
200 peer_sap = pkt [15] & 0xfe;
201 llc_sent = llc_received = llc_input = 0x00;
202 llc_connected = true;
203 netcons_connect (&llc2_dummy_handle);
205 } else if (cmd == 0x53) { // DISC (llc.disconnect)
206 llc_connected = false;
209 } else if (cmd == 0x87) { // FRMR (llc.framereject)
210 llc_received = llc_sent;
211 } else if ((cmd & 0x0001) == 0x0000) { // Data sent back (will be ignored)
212 memcpy (llc_rr + 0, peer_mac, 6);
213 memcpy (llc_rr + 6, "\x00\x0b\x82\x19\xa0\xf4", 6);
214 memcpy (llc_rr + 12, "\x00\x04\x00\x15", 4);
215 llc_rr [14] = peer_sap;
216 llc_rr [16] = 0x01; // supervisory, RR
217 llc_rr [17] = (cmd + 2) & 0xfe; // outgoing N(R) = incoming N(S) + 1
218 bottom_network_send (llc_rr, sizeof (llc_rr));
219 } else if ((cmd & 0x0007) == 0x0001) { // Receiver ready / Receiver Reject
220 llc_received = (cmd >> 9);
222 #ifdef CONFIG_MAINFUNCTION_DEVEL_NETWORK
223 bottom_printf ("Selfishly ignoring LLC traffic with cmd bytes 0x%2x%2x\n",
224 (intptr_t) pkt [16], (intptr_t) pkt [17]);
228 memcpy (llc_ua + 0, peer_mac, 6);
229 memcpy (llc_ua + 6, "\x00\x0b\x82\x19\xa0\xf4", 6);
230 memcpy (llc_ua + 12, "\x00\x03\x00\x15\x73", 5);
231 llc_ua [14] = peer_sap;
232 // Try sending; assume repeat will be caused by other/smarter side
233 bottom_network_send (llc_ua, sizeof (llc_ua));