(The original idea was to do the entire processing in that style, but
it turned out not to be sufficiently flexible for that.)
-* The replies from netinput.c are functions to be called. Decide if
- this is enough, and if it can cover netreply_* as well as netdb_*
- with the same setup. Is this all typesafe?
-
* Must join multicast addresses for local addresses, as described in
http://tools.ietf.org/html/rfc4291 section 2.7.1, ff02::1:ff00:0/102
for solicited-node address. WIDE DHCPv6 server actually needs this.
* tic55x's int.c driver: work out conditions for hibernation sleep.
In hibernation, also shutdown the codec.
+* tic55x should include from separate directory for <stdbool.h>
+
* Append network stack with LLC1 (for TFTP) and LLC2 (for console).
MEM_VLAN_ID,
MEM_BINDING6,
MEM_IP6_DST,
+ MEM_LLC_SSAP,
+ MEM_LLC_DSAP,
+ MEM_LLC_CMD,
+ MEM_LLC_PKTLEN,
+ MEM_LLC_PAYLOAD,
//
// The number of entries in this enum
MEM_NETVAR_COUNT
uint8_t *netreply_icmp6_echo_req (uint8_t *pkt, intptr_t *mem);
uint8_t *netreply_dhcp4_offer (uint8_t *pkt, intptr_t *mem);
uint8_t *netreply_dhcp6_advertise (uint8_t *pout, intptr_t *mem);
+uint8_t *netllc_reply (uint8_t *pout, intptr_t *mem);
+uint8_t *netllc_tftp (uint8_t *pout, intptr_t *mem);
+uint8_t *netllc_console_sabme (uint8_t *pout, intptr_t *mem);
+uint8_t *netllc_console_disc (uint8_t *pout, intptr_t *mem);
+uint8_t *netllc_console_frmr (uint8_t *pout, intptr_t *mem);
+uint8_t *netllc_console_datasentback (uint8_t *pout, intptr_t *mem);
+uint8_t *netllc_console_receiverfeedback (uint8_t *pout, intptr_t *mem);
+
uint8_t *netsend_icmp6_router_solicit (uint8_t *pout, intptr_t *mem);
uint8_t *netsend_icmp6_ngb_sol (uint8_t *pout, intptr_t *mem);
* You should have received a copy of the GNU General Public License
* along with 0cpm Firmerware. If not, see <http://www.gnu.org/licenses/>.
*/
+
+
+/* Below:
+ * - definitions for this architecture to service the top half
+ * - definitions to bind bottom half files together
+ *
+ * From: Rick van Rein <rick@openfortress.nl>
+ */
+
+
+/* The timer is the top 32-bit half of timer0 */
+typedef uint32_t timing_t;
+#define TIME_BEFORE(x,y) (((x)-(y)) >> 31)
+#define TIME_BEFOREQ(x,y) (!(TIME_BEFORE((y),(x))))
+
+#define TIMER_NULL 0
+
+#define TIME_MSEC(x) (((uint32_t) (x)))
+#define TIME_SEC(x) (((uint32_t) (x))*1000)
+#define TIME_MIN(x) (((uint32_t) (x))*1000*60)
+#define TIME_HOUR(x) (((uint32_t) (x))*1000*60*60)
+#define TIME_DAY(x) (((uint32_t) (x))*1000*60*60*24)
+
+
+
objs-bottom-$(CONFIG_PLATFORM_TIC55x) += src/driver/tic55x/int.o src/driver/tic55x/timer.o src/driver/tic55x/isrmap.o #NOPE# src/driver/tic55x/gpio.o #TODO#
+objs-bottom-$(CONFIG_PLATFORM_BLACKFIN) += src/driver/blackfin/timer.o src/driver/blackfin/imaginary.o
metavars-$(CONFIG_TARGET_GRANDSTREAM_BT20x) += SYSCLK1_TO_MS_DIVIDER=122880
# metavars-$(CONFIG_TARGET_GRANDSTREAM_BT20x) += SYSCLK1_TO_MS_DIVIDER=61440
objs-top-$(CONFIG_MAINFUNCTION_BOOTLOADER) += src/function/bootloader.o src/net/llconly.o src/function/netconsole.o
-#TODO# Must replace llconly.o with "real" LLC support in src/net/*
-objs-top-$(CONFIG_FUNCTION_NETCONSOLE) += src/function/netconsole.o src/net/llconly.o
+objs-top-$(CONFIG_FUNCTION_NETCONSOLE) += src/function/netconsole.o
objs-top-$(CONFIG_FUNCTION_FIRMWARE_UPGRADES) += src/function/bootloader.o
#include <0cpm/cons.h>
#include <0cpm/flash.h>
+#include <0cpm/netinet.h>
+#include <0cpm/netfun.h>
/* Sanity check */
static uint16_t blocknum;
static bool sending = false, receiving = false;
+extern uint8_t ether_mine [6];
-/* Handle an incoming TFTP request (over LLC)
+
+/* Handle a TFTP request that came in over LLC1.
*
* This code is rather brutal -- it only does binary transfers,
- * and it supports no options at all.
+ * and it supports no options at all. It is mainly intended for
+ * bootstrapping (bootloading) purposes, offering access to the
+ * flash memory contained in the machine.
*/
-
-void bootloader_datagram (uint8_t *pkt, uint16_t pktlen) {
- void netreply_llc1 (uint8_t *pkt, uint16_t pktlen);
+uint8_t *netllc_tftp (uint8_t *pkt, intptr_t *mem) {
uint16_t cmd;
- uint16_t pktlen2;
+ uint16_t pktlen, pktlen2;
+ uint16_t replylen = 0;
+ uint8_t *llc = (uint8_t *) mem [MEM_ETHER_HEAD];
+ pktlen = mem [MEM_ALL_DONE] - mem [MEM_ETHER_HEAD];
+ memcpy (pkt, llc+6, 6);
+ memcpy (pkt+6, ether_mine, 6);
+ pktlen2 = (llc [12] << 8) | llc [13];
+bottom_printf ("netllc_tftp, pktlen=%d, pktlen2=%d\n", pktlen, pktlen2);
if (pktlen < 12 + 2 + 3 + 4) {
return;
}
- pktlen2 = (pkt [12] << 8) | pkt [13];
if (pktlen < pktlen2 + 12 + 2) {
return;
}
- cmd = (pkt [12 + 2 + 3 + 0] << 8) | pkt [12 + 2 + 3 + 1];
+ cmd = (llc [12 + 2 + 3 + 0] << 8) | llc [12 + 2 + 3 + 1];
+bottom_printf ("Processing TFTP command %d\n", (int) cmd);
if ((cmd == 1) || (cmd == 2)) { /* 1==RRQ, 2=WRQ, new setup */
- pkt [pktlen - 1] = 0;
+ llc [pktlen - 1] = 0;
bottom_printf ("TFTP %s for %s\n",
(cmd == 1)? "RRQ": "WRQ",
- pkt + 12 + 2 + 3 + 2);
+ llc + 12 + 2 + 3 + 2);
current = (struct flashpart *) "TODO"; //TODO// current=flash_find_file(...), return if not found
sending = (current != NULL) && (cmd == 1);
receiving = (current != NULL) && (cmd == 2);
- pktlen = 12 + 2 + 3;
+ replylen = 12 + 2 + 3;
blocknum = 0;
if (sending) {
goto sendblock;
}
if (receiving) {
- pkt [pktlen++] = 0x00; // send ACK
- pkt [pktlen++] = 0x04;
- pkt [pktlen++] = 0x00;
- pkt [pktlen++] = 0x00;
+ pkt [replylen++] = 0x00; // send ACK
+ pkt [replylen++] = 0x04;
+ pkt [replylen++] = 0x00;
+ pkt [replylen++] = 0x00;
}
- netreply_llc1 (pkt, pktlen);
} else if (cmd == 3) { /* 3==DATA, store or burn */
if (!current) {
bottom_printf ("TFTP DATA received without connection\n");
pkt [12 + 2 + 3 + 1] = 0x04;
pkt [12 + 2 + 3 + 2] = blocknum >> 8;
pkt [12 + 2 + 3 + 3] = blocknum & 0xff;
- netreply_llc1 (pkt, 12 + 2 + 3 + 4);
+ replylen = 12 + 2 + 3 + 4;
}
} else if (cmd == 4) { /* 4==ACK, send next if sending */
if (!current) {
pkt [12 + 2 + 3 + 2] = blocknum >> 8;
pkt [12 + 2 + 3 + 3] = blocknum & 0xff;
if (bottom_flash_read (blocknum - 1, pkt + 12 + 2 + 3 + 4)) {
- netreply_llc1 (pkt, 12 + 2 + 3 + 4 + 512);
+ replylen = 12 + 2 + 3 + 4 + 512;
} else {
- netreply_llc1 (pkt, 12 + 2 + 3 + 4 + 0 );
+ replylen = 12 + 2 + 3 + 4 + 0;
}
}
} else if (cmd == 5) { /* 5==ERR */
pkt + 12 + 2 + 3 + 4);
/* no further error handling */
}
-
+ if (replylen) {
+bottom_printf ("TFTP reply consists of %d bytes\n", replylen);
+ // netllc_reply (pkt, mem);
+ pkt [12] = (replylen - 12 - 2) >> 8;
+ pkt [13] = (replylen - 12 - 2) & 0xff;
+ pkt [12 + 2 + 0] = mem [MEM_LLC_SSAP]; /* DSAP */
+ pkt [12 + 2 + 1] = 68; /* SSAP */
+ pkt [12 + 2 + 2] = 0x03; /* UI, unnumbered information */
+ mem [MEM_ETHER_HEAD] = (intptr_t) pkt;
+ mem [MEM_LLC_PAYLOAD] = (intptr_t) pkt + 17;
+ return pkt + replylen;
+ } else {
+bottom_printf ("No TFTP reply package\n");
+ return NULL;
+ }
}
volatile uint16_t toberecorded = 0;
-void top_timer_expiration (timing_t timeout) {
+timing_t top_timer_expiration (timing_t timeout) {
/* Keep the linker happy */ ;
+ return timeout;
}
void top_hook_update (bool offhook) {
#include <0cpm/show.h>
-void top_timer_expiration (timing_t timeout) {
+timing_t top_timer_expiration (timing_t timeout) {
/* Keep the linker happy */ ;
+ return timeout;
}
void top_hook_update (bool offhook) {
bool online = false;
-void top_timer_expiration (timing_t timeout) {
+timing_t top_timer_expiration (timing_t timeout) {
/* Keep the linker happy */ ;
+ return timeout;
}
void top_hook_update (bool offhook) {
#define complete_top_main top_main
-void top_timer_expiration (timing_t timeout) {
+timing_t top_timer_expiration (timing_t timeout) {
/* Keep the linker happy */ ;
+ return timeout;
}
void top_hook_update (bool offhook) {
}
-void top_timer_expiration (timing_t exptime) {
+timing_t top_timer_expiration (timing_t exptime) {
uint16_t ctr;
ledstate ^= LED_STABLE_ON ^ LED_STABLE_OFF;
nextirq += TIME_MSEC(500);
- bottom_timer_set (nextirq);
+ return nextirq;
}
#include <config.h>
#include <0cpm/cons.h>
+#include <0cpm/cpu.h>
+#include <0cpm/irq.h>
+#include <0cpm/timer.h>
/*
}
}
+#ifndef CONFIG_MAINFUNCTION_DEVEL_NETWORK
+static irqtimer_t console_timer;
+static void netcons_interval (irq_t *tmr) {
+ trysend ();
+ //TODO:Efficiency// if (rpos != wpos) {
+ irqtimer_restart ((irqtimer_t *) tmr, TIME_MSEC(20));
+ //TODO// }
+}
+#endif
+
void netcons_connect (struct llc2 *cnx) {
netcons_connection = cnx;
+#ifdef CONFIG_MAINFUNCTION_DEVEL_NETWORK
trysend ();
+#else
+ irqtimer_start (&console_timer, 0, netcons_interval, CPU_PRIO_LOW);
+#endif
}
void netcons_close (void) {
+#ifndef CONFIG_MAINFUNCTION_DEVEL_NETWORK
+ irqtimer_stop (&console_timer);
+#endif
netcons_connection = NULL;
}
minpos += fp [-1] - '0';
goto moremeuk;
case 'c':
- ch = va_arg (argh, char);
+ ch = (char) va_arg (argh, int);
cons_putchar (ch);
break;
case 's':
if (val32bit) {
intval = va_arg (argh, uint32_t);
} else {
- intval = (uint32_t) va_arg (argh, uint16_t);
+ intval = (uint32_t) va_arg (argh, int );
}
cons_putint (intval, 10, minpos);
break;
if (val32bit) {
intval = va_arg (argh, uint32_t);
} else {
- intval = (uint32_t) va_arg (argh, uint16_t);
+ intval = (uint32_t) va_arg (argh, int );
}
cons_putint (intval, 16, minpos);
break;
}
}
}
+#ifdef CONFIG_MAINFUNCTION_DEVEL_NETWORK
trysend ();
+#endif
}
void bottom_console_printf (char *fmt, ...) {
irqtimer_t disptimer;
int nibblepos = 0;
timing_t nextrot = 0;
-void show_info (irqtimer_t *tmr) {
+void show_info (irq_t *tmr) {
int relpos;
//TODO:MANUAL_TIMER_AS_REAL_ONE_FAILS://
#if 0
nibblepos = 0;
}
ht162x_dispdata_notify (3, 14);
- irqtimer_restart (tmr, TIME_MSEC (1000));
+ irqtimer_restart ((irqtimer_t *) tmr, TIME_MSEC (1000));
}
/* The main operational loop for the CPU. Try to run code, and when
*/
void jobhopper (void) {
void ht162x_putchar (uint8_t idx, uint8_t ch, bool notify);
- bottom_printf ("Jobhopper starts.\n");
+ //OVERZEALOUSLOGGER// bottom_printf ("Jobhopper starts.\n");
//TODO:TEST// ht162x_putchar (0, '0', true);
while (cur_prio > CPU_PRIO_ZERO) {
closure_t *here;
}
todo->irq_next = NULL;
bottom_critical_region_end ();
- bottom_printf ("Jobhopper calls interrupt handler.\n");
+ //OVERZEALOUSLOGGER// bottom_printf ("Jobhopper calls interrupt handler.\n");
//TODO:TEST// ht162x_audiolevel (2 << 5);
//TODO:NAAAHHH// if (this->irq_handler)
(*todo->irq_handler) (todo);
}
}
//TODO:TEST// ht162x_putchar (0, '9', true);
- bottom_printf ("Jobhopper ends.\n");
+ //OVERZEALOUSLOGGER// bottom_printf ("Jobhopper ends.\n");
}
goto done;//TODO//break;
}
//TODO:TEST// ht162x_putchar (1, '2', true);
- bottom_printf ("Received a network packet\n");
+ //TODO:OVERZEALOUS// bottom_printf ("Received a network packet\n");
bzero (mymem, sizeof (mymem));
rf = (retfn *) netinput (myrbuf.data, rbuflen, mymem);
//TODO:TEST// ht162x_putchar (1, '3', true);
irqtimer_interrupt_blocked = false;
if (irqtimer_interrupt_occurred) {
timing_t now, next;
- bottom_printf ("Activating deferred timer interrupt\n");
+ //TODO:OVERZEALOUS// bottom_printf ("Activating deferred timer interrupt\n");
now = bottom_time ();
next = top_timer_expiration (now);
if (next != now) {
src/net/6bed4.c:
printf > $@ '#include <stdint.h>\nuint32_t ip4_6bed4 = ( (uint32_t) %d) << 24 | ((uint32_t) %d) << 16 | ((uint32_t) %d) << 8 | ((uint32_t) %d );\n' `echo $(CONFIG_NET_6BED4_SERVER) | sed 's/\./ /g'`
-objs-top-net-y += src/net/core.o src/net/input.o src/net/reply.o src/net/send.o src/net/db.o src/net/6bed4.o
+objs-top-net-y += src/net/core.o src/net/input.o src/net/reply.o src/net/send.o src/net/db.o src/net/llc.o src/net/6bed4.o
struct ip6_hdr *ip6 = (void *) mem [MEM_IP6_HEAD];
struct arphdr *arp = (void *) mem [MEM_ARP_HEAD];
struct ethhdr *eth = (void *) mem [MEM_ETHER_HEAD];
+ bool is_llc = (mem [MEM_LLC_DSAP] != 0) || (mem [MEM_LLC_SSAP] != 0);
uint16_t wlen;
//
// Checksum UDPv6 on IPv6
netset16 (eth->h_proto, ETH_P_IPV6);
} else if (arp) {
netset16 (eth->h_proto, ETH_P_ARP);
+ } else if (is_llc) {
+ ; //TODO// netset16 (eth->h_proto, mem [MEM_ALL_DONE] - mem [MEM_ETHER_HEAD]);
} else {
return;
}
-/* netinput.c
+/* netinput.c -- Incoming network packet parser and switch.
*
* This file is part of 0cpm Firmerware.
*
* along with 0cpm Firmerware. If not, see <http://www.gnu.org/licenses/>.
*/
-
-/* Process networked input and select actions to take.
- *
- * The "assembly language" used below is the BPF pseudo-language,
- * documented in
- *
- * The BSD Packet Filter:
- * A New Architecture for User-Level Packet Capture
- * by Steven McCanne and Van Jacobson
- *
- * ftp://ftp.ee.lbl.gov/papers/bpf-usenix93.ps.Z
- *
- * It serves to analyse frames, set aside the juicy details and
- * return a value which in this case is either the address of a
+/*
+ * This code analyses frames, sets aside the juicy details and
+ * returns a value which in this case is either the address of a
* function to invoke, or NULL if the frame should be dropped.
*
- * It should not be difficult to interpret the consistent assembly
- * instructions (stored in a fixed structure format) from native
- * code, thus leading to extremely efficient network packet handling
- * with a very high level of flexibility for future extensions.
- *
- * This language is designed for speed, and is used in tcpdump et al.
- *
* From: Rick van Rein <rick@openfortress.nl>
*/
#include <0cpm/netfun.h>
+/* Utility functions for packet analyses */
-
-/*
- * The following is written in BPF assembler, because that is a proper
- * form for handling this kind of problem. The language lends itself
- * for optimal translation. In spite of that, it is very flexible.
- *
- * The labels ending in _sel indicate that a definite selection has been
- * made of the kind of frame, but some validation may still be in order.
- *
- * The code below does not calculate checksums yet. It also does not
- * take packet length into account.
- *
- * The code collects various bits of data in the M[] scratchpad array:
- * TODO:OLD:USING MEM_INPUT ENUM NOW
- * M[0] is the ethernet payload
- * M[1] is the IP4.src address (or 0 for native IP6)
- * M[2] is the IP4.dst address (or 0 for native IP6)
- * M[3] is the IP4 payload (or 0 for native IP6)
- * M[4] is the UDP4 src.PORT|dst.PORT (or 0 for native IP6)
- * M[5] is the UDP4 payload (or 0 for native IP6)
- * M[6] is the IP6 frame address (+40 is payload)
- * M[7] is the UDP6 src.PORT|dst.PORT
- * M[8] is the UDP6 payload
- * M[9] is the ethernet header
- *
- * These addresses and values can be used in further analyses, based
- * on the functions returned from the analysis. Note that the first
- * things these functions do is (1) check lengths and (2) check sums.
- *
- * If all that is okay, it can start processing the frame contents.
- */
-
+#define forward(t) here += sizeof (t); fromhere -= sizeof (t);
+#define store(i, t) if (fromhere < sizeof (t)) return NULL; mem [i] = (intptr_t) (t *) here;
+#define store_forward(i, t) store(i,t) forward(t)
+#ifndef get08
+# define get08(o) ((uint8_t) here [o])
+#endif
+#ifndef get16
+# define get16(o) ((((uint16_t) here [o]) << 8) | ((uint16_t) here [o+1]))
+#endif
+#ifndef get32
+# define get32(o) ((((uint32_t) here [o]) << 24) | (((uint32_t) here [o+1]) << 16) | (((uint32_t) here [o+2]) << 8) | ((uint32_t) here [o+3]))
+#endif
/* Analyse incoming network packets.
* for specifically known targets.
*/
-#define forward(t) here += sizeof (t); fromhere -= sizeof (t);
-#define store(i, t) if (fromhere < sizeof (t)) return NULL; mem [i] = (intptr_t) (t *) here;
-#define store_forward(i, t) store(i,t) forward(t)
-#ifndef get08
-# define get08(o) ((uint8_t) here [o])
-#endif
-#ifndef get16
-# define get16(o) ((((uint16_t) here [o]) << 8) | ((uint16_t) here [o+1]))
-#endif
-#ifndef get32
-# define get32(o) ((((uint32_t) here [o]) << 24) | (((uint32_t) here [o+1]) << 16) | (((uint32_t) here [o+2]) << 8) | ((uint32_t) here [o+3]))
-#endif
-
intptr_t netinput (uint8_t *pkt, uint16_t pktlen, intptr_t *mem) {
register uint8_t *here = pkt;
uint16_t udp6_dst;
uint8_t dhcp6_tag;
uint16_t dnssd_flags;
+ uint8_t llc_ssap, llc_dsap;
+ uint16_t llc_cmd;
//
// Store the end of the entire packet
case 0x86dd: goto netin_IP6_sel;
case 0x0800: goto netin_IP4_sel;
case 0x0806: goto netin_ARP_sel;
- default: return NULL;
+ default:
+#if defined(CONFIG_FUNCTION_NETCONSOLE) || defined(CONFIG_FUNCTION_FIRMWARE_UPGRADES)
+ if (ethertp <= 1500) {
+ mem [MEM_LLC_PKTLEN] = (intptr_t) ethertp;
+ goto netin_LLC_sel;
+ }
+#endif
+ return NULL;
}
//
// Finally, a catchall that rejects anything that makes it to here
return NULL;
+
+
+/********** OPTIONAL CODE FOR LLC: NETCONSOLE, FIRMWARE UPGRADES **********/
+
+
+#if defined (CONFIG_FUNCTION_NETCONSOLE) || defined (CONFIG_FUNCTION_FIRMWARE_UPGRADES)
+
+netin_LLC_sel:
+ mem [MEM_LLC_DSAP] = (intptr_t) get08 (0);
+ mem [MEM_LLC_SSAP] = (intptr_t) get08 (1);;
+ mem [MEM_LLC_CMD] = get08 (2);
+ if ((mem [MEM_LLC_CMD] & 0x03) != 0x03) {
+ mem [MEM_LLC_CMD] |= get08 (3) << 8;
+ goto netin_LLC2_sel;
+ }
+ // else, fallthrough to netin_LLC1_sel
+
+netin_LLC1_sel:
+ mem [MEM_LLC_PAYLOAD] = (intptr_t) (here + 3);
+ switch (mem [MEM_LLC_CMD]) {
+#ifdef CONFIG_FUNCTION_FIRMWARE_UPGRADES
+ case 0x03:
+ if (mem [MEM_LLC_DSAP] == 68) {
+ return (intptr_t) netllc_tftp;
+ }
+ break;
+#endif // NETCONSOLE
+#ifdef CONFIG_FUNCTION_FIRMWARE_UPGRADES
+ case 0x7f:
+ if (mem [MEM_LLC_DSAP] == 20) {
+ return (intptr_t) netllc_console_sabme;
+ }
+ break;
+ case 0x53:
+ if (mem [MEM_LLC_DSAP] == 20) {
+ return (intptr_t) netllc_console_disc;
+ }
+ break;
+ case 0x87:
+ if (mem [MEM_LLC_DSAP] == 20) {
+ return (intptr_t) netllc_console_frmr;
+ }
+ break;
+#endif // FIRMWARE_UPGRADES
+ default:
+ break;
+ }
+ return NULL;
+
+#ifdef CONFIG_FUNCTION_NETCONSOLE
+netin_LLC2_sel:
+ mem [MEM_LLC_PAYLOAD] = (intptr_t) (here + 4);
+ if ((mem [MEM_LLC_CMD] & 0x0001) == 0x0000) {
+ return (intptr_t) netllc_console_datasentback;
+ } else if ((mem [MEM_LLC_CMD] & 0x0007) == 0x0001) {
+ return (intptr_t) netllc_console_receiverfeedback;
+ }
+ return NULL;
}
+#endif // NETCONSOLE
+
+#endif // NETCONSOLE || FIRMWARE_UPGRADES
+
--- /dev/null
+/* netllc.c -- Optional LLC handling that plugs into the network stack.
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdarg.h>
+
+// #include <netinet/ip.h>
+// #include <netinet/udp.h>
+// #include <netinet/ip6.h>
+// #include <netinet/ip_icmp.h>
+// #include <netinet/icmp6.h>
+// #include <netinet/if_ether.h>
+
+#include <config.h>
+
+#include <0cpm/cpu.h>
+#include <0cpm/irq.h>
+#include <0cpm/timer.h>
+#include <0cpm/netinet.h>
+#include <0cpm/netfun.h>
+#include <0cpm/netdb.h>
+#include <0cpm/cons.h>
+
+
+/********** OPTIONAL FIRMWARE ACCESS FUNCTIONS **********/
+
+/*
+ * This functionality is located in src/function/bootloader.c
+ */
+
+
+
+/********** OPTIONAL CONSOLE ACCESS FUNCTIONS **********/
+#ifdef CONFIG_FUNCTION_NETCONSOLE
+
+extern uint8_t ether_mine [6];
+
+static bool console_is_connected = false;
+static uint8_t console_remote_mac [6];
+static uint8_t console_remote_sap;
+
+struct llc2 {
+ uint8_t dummy;
+};
+static struct llc2 llc2_dummy_handle;
+
+uint8_t llc_received = 0;
+uint8_t llc_sent = 0;
+uint8_t llc_input = 0;
+
+
+static bool mismatch_console_connection (intptr_t *mem) {
+ if ((mem [MEM_LLC_SSAP] & 0xfe) != console_remote_sap) {
+ return true;
+ }
+ if (memcmp (((uint8_t *) mem [MEM_ETHER_HEAD]) + 6, console_remote_mac, 6)) {
+ return true;
+ }
+ return false;
+}
+
+
+/* Construct an LLC reply start; fill out ethernet addresses and SSAP/DSAP */
+uint8_t *netllc_reply (uint8_t *pout, intptr_t *mem) {
+ memcpy (pout + 0, ((uint8_t *) mem [MEM_ETHER_HEAD] + 6), 6);
+ memcpy (pout + 6, ether_mine, 6);
+ pout [14] = mem [MEM_LLC_SSAP] | 0x00; /* Individual */
+ pout [15] = mem [MEM_LLC_DSAP] | 0x01; /* Response */
+}
+
+/* Construct an LLC1 acknowledgement in reply to an incoming packet */
+uint8_t *netllc_llc1_ack (uint8_t *pout, intptr_t *mem) {
+ netllc_reply (pout, mem);
+ netset16 (*(nint16_t *) (pout + 12), 3);
+ netset8 (*(nint8_t *) (pout + 16), 0x73);
+ return pout + 17;
+}
+
+/* Dummy LLC2 send routine, ignoring "cnx" as there is just one LLC2 connection.
+ * Before sending, the routine will first establish whether the last send
+ * was successful; if not, it will repeat that. The return value is true if at
+ * least the new send was done, relying on future calls to resend if need be.
+ * TODO: Possibly improve on this routine.
+ */
+uint8_t llc_pkt [100];
+uint16_t llc_pktlen;
+bool netsend_llc2 (struct llc2 *cnx, uint8_t *data, uint16_t datalen) {
+ bool newpkt;
+ if (datalen > 80) {
+ return false;
+ }
+ if (!console_is_connected) {
+ return false;
+ }
+ newpkt = (llc_sent == llc_received);
+ if (newpkt) {
+ // Sending is complete, construct new packet as requested
+ memcpy (llc_pkt + 0, console_remote_mac, 6);
+ memcpy (llc_pkt + 6, "\x00\x0b\x82\x19\xa0\xf4", 6);
+ llc_pkt [12] = 0x00;
+ llc_pkt [13] = datalen + 4;
+ llc_pkt [14] = console_remote_sap; // DSAP
+ llc_pkt [15] = 20; // SSAP
+ llc_pkt [16] = llc_sent << 1; // N(S) = 0x00, information frame
+ llc_pkt [17] = llc_input << 1; // N(R) = sent-up-to-here, low bit reset
+ memcpy (llc_pkt + 18, data, datalen);
+ llc_pktlen = 6 + 6 + 2 + 4 + datalen;
+ llc_sent++;
+ llc_sent &= 0x7f;
+ }
+ bottom_network_send (llc_pkt, llc_pktlen);
+ return newpkt;
+}
+
+
+/* Respond to an LLC SABMA console connection request */
+uint8_t *netllc_console_sabme (uint8_t *pout, intptr_t *mem) {
+#if 0
+ if (console_is_connected) {
+ return NULL;
+ }
+#endif
+ memcpy (console_remote_mac, ((uint8_t *) mem [MEM_ETHER_HEAD]) + 6, 6);
+ console_remote_sap = mem [MEM_LLC_SSAP] & 0xfe;
+ llc_sent = llc_received = llc_input = 0x00;
+//TODO: netcons_connect() overwrites memory buffer with 1st llc cnx pkt
+netllc_llc1_ack (pout, mem);
+bottom_network_send (pout, 6+6+2+3);
+ if (!console_is_connected) {
+ netcons_connect (&llc2_dummy_handle);
+ console_is_connected = true;
+ }
+return NULL;
+ return netllc_llc1_ack (pout, mem);
+}
+
+/* Respond to an LLC DISC console disconnect request */
+uint8_t *netllc_console_disc (uint8_t *pout, intptr_t *mem) {
+ if (mismatch_console_connection (mem)) {
+ return NULL;
+ }
+ console_is_connected = false;
+ netcons_close ();
+ return netllc_llc1_ack (pout, mem);
+}
+
+/* Respond to an LLC FRMR frame rejection */
+uint8_t *netllc_console_frmr (uint8_t *pout, intptr_t *mem) {
+ if (mismatch_console_connection (mem)) {
+ return NULL;
+ }
+ llc_received = llc_sent;
+ return NULL;
+}
+
+/* Respond to an LLC data frame sent to the console.
+ * As the console is output-only, the contents are dropped.
+ */
+uint8_t *netllc_console_datasentback (uint8_t *pout, intptr_t *mem) {
+ if (mismatch_console_connection (mem)) {
+ return NULL;
+ }
+ netllc_reply (pout, mem);
+ netset16 (*(nint16_t *) (pout + 12), 4);
+ netset8 (*(nint8_t *) (pout + 16), 0x01);
+ netset8 (*(nint8_t *) (pout + 17), (mem [MEM_LLC_CMD] + 2) & 0xfe);
+ return pout + 18;
+}
+
+/* Respond to an LLC receiver-ready (or receiver-reject) indication for the console */
+uint8_t *netllc_console_receiverfeedback (uint8_t *pout, intptr_t *mem) {
+ if (mismatch_console_connection (mem)) {
+ return NULL;
+ }
+ llc_received = mem [MEM_LLC_CMD] >> 9;
+ return NULL;
+}
+
+
+#endif
+
+
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
+#include <string.h>
#include <config.h>
-/* Send a reply through LLC1.
- * The packet provided have the responded-to MAC/LLC SAPs.
- * The packet size is completed with any reply content.
- * This routine updates MAC addresses and LLC headers.
- */
-void netreply_llc1 (uint8_t *pkt, uint16_t pktlen) {
- uint8_t tmp;
- memcpy (pkt + 0, pkt + 6, 6);
- memcpy (pkt + 6, "\x00\x0b\x82\x19\xa0\xf4", 6);
- pkt [12] = (pktlen - 12 - 2) >> 8;
- pkt [13] = (pktlen - 12 - 2) & 0xff;
- tmp = pkt [14];
- pkt [14] = pkt [15];
- pkt [15] = tmp; // Command flag -- LLC1 only uses commands
- // Send and forget -- LLC1 is not guaranteed delivery
- bottom_network_send (pkt, pktlen);
+
+/* Construct an LLC reply start; fill out ethernet addresses and SSAP/DSAP */
+uint8_t *netreply_llc (uint8_t *pout, intptr_t *mem) {
+ memcpy (pout + 0, ((uint8_t *) mem [MEM_ETHER_HEAD] + 6), 6);
+ memcpy (pout + 6, ether_mine, 6);
+ pout [14] = mem [MEM_LLC_SSAP];
+ pout [15] = mem [MEM_LLC_DSAP];
}
static uint8_t llc_sent;
static uint8_t llc_received;
static uint8_t llc_input;
+static mem [MEM_NETVAR_COUNT];
+
+
+struct llc2 {
+ uint8_t dummy;
+};
+static struct llc2 llc2_dummy_handle;
/* Dummy LLC2 send routine, ignoring "cnx" as there is just one LLC2 connection.
return newpkt;
}
-struct llc2 {
- uint8_t dummy;
-};
-static struct llc2 llc2_dummy_handle;
-
/* LLC-only network packet handling, specifically for:
* - LLC2 console at SAP 20
* - LLC1 firmware access through TFTP at SAP 68
if (cmd == 0x03) { // UI (llc.datagram)
#ifdef CONFIG_FUNCTION_FIRMWARE_UPGRADES
if (pkt [14] == 68) {
- void bootloader_datagram (uint8_t *pkt, uint16_t pktlen);
- bootloader_datagram (pkt, pktlen);
+ uint16_t pktlen;
+ // Setup minimal mem[] array for TFTP over LLC1
+ bzero (mem, sizeof (mem));
+ mem [MEM_ETHER_HEAD] = (intptr_t) pkt;
+ mem [MEM_ALL_DONE] = (intptr_t) &pkt [pktlen];
+ mem [MEM_LLC_DSAP] = pkt [14];
+ mem [MEM_LLC_SSAP] = pkt [15];
+ pkt = netllc_tftp (pkt, pktlen);
+ pktlen = mem [MEM_ALL_DONE] - (intptr_t) pkt;
+ // Send and forget -- LLC1 is unconfirmed transmission
+ bottom_network_send (pkt, pktlen);
} else {
#ifdef CONFIG_DEVEL
bottom_printf ("LLC1 UA is only used for TFTP, use SAP 68 and not %d\n", pkt [14]);
icmp4in = (struct icmphdr *) mem [MEM_ICMP4_HEAD];
netset8 (icmp4out->type, ICMP_ECHOREPLY);
netset8 (icmp4out->code, 0);
- icmp4out->un.echo.id = icmp4in->un.echo.id;
- icmp4out->un.echo.sequence = icmp4in->un.echo.sequence;
+ memcpy (&icmp4out->un.echo, &icmp4in->un.echo, 4);
pout = pout + sizeof (struct icmphdr);
alen = mem [MEM_ALL_DONE] - mem [MEM_ICMP4_HEAD] - sizeof (struct icmphdr);
if ((alen > 0) && (alen < 128)) {
- memcpy (icmp4out + 1, icmp4in + 1, alen);
+ memcpy (pout, &icmp4in [1], alen);
pout += alen;
}
mem [MEM_ICMP4_HEAD] = (intptr_t) icmp4out;
include src/target/Makefile.tic55x
endif
+ifdef CONFIG_PLATFORM_BLACKFIN
+include src/target/Makefile.blackfin
+endif