The first version that was demonstrated to get an IPv6 address
[firmerware] / src / kernel / net.c
1 /* Network multiplexing for incoming traffic.
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
22 /* This is the kernel
23  * interface to the networking code; it mainly involves scheduling.
24  */
25
26
27 #include <stdlib.h>
28 #include <stdint.h>
29 #include <stdbool.h>
30 #include <stdarg.h>
31
32 #include <config.h>
33
34 #include <0cpm/cpu.h>
35 #include <0cpm/irq.h>
36 #include <0cpm/netinet.h>
37 #include <0cpm/netfun.h>
38 #include <0cpm/cons.h>
39
40
41 /* TODO: Current return function from netinput
42  */
43 typedef void *retfn (uint8_t *pout, intptr_t *mem);
44
45
46 /* The can_recv and can_send flags store whether
47  * the network is in a state to permit either of
48  * these operations on the network interface.
49  */
50 static bool can_send = false;
51 static bool can_recv = false;
52
53
54 /* IRQ handling structures dealing with reads and
55  * writes on the network card.
56  */
57 static void network_recv_handler (irq_t *irq);
58 static void network_send_handler (irq_t *irq);
59
60 /* The network receive handler is fired as soon as network
61  * packets arrive.  The network send handler is fired as soon
62  * as network packets have completed sending.
63  */
64 static irq_t recv_irq = { network_recv_handler, NULL, CPU_PRIO_UNKNOWN };
65 static irq_t send_irq = { network_send_handler, NULL, CPU_PRIO_UNKNOWN };
66
67
68
69 /* This upcall is used to report that the network
70  * has new data available.  The bottom half will
71  * call this for the first packet to arrive after
72  * having failed an attempt to read input.
73  * More calls are possible for later arrivals of
74  * even more packets, and will be silently ignored
75  * below.
76  */
77 void top_network_can_recv (void) {
78         if (!can_recv) {
79                 can_recv = true;
80                 irq_fire (&recv_irq);
81 //ht162x_led_set (15, 1, true); // shown as (101)
82         }
83 }
84
85 /* This upcall is used to report that the network
86  * is certain to accept a full-size network packet.
87  * It is called by the bottom half after having
88  * failed an attempt to send output.
89  * Additional calls on the same matter are silently
90  * ignored.
91  */
92 void top_network_can_send (void) {
93         if (!can_send) {
94                 can_send = true;
95                 irq_fire (&send_irq);  // Polling, so safe
96         }
97 }
98
99
100 /* This upcall is made to report that the network
101  * has gone offline.  This may be detected at the
102  * hardware level, as a result of unplugging the
103  * cable and/or loosing sync.
104  * The state resulting from this is implied at the
105  * time of booting the device.
106  */
107 void top_network_offline (void) {
108         can_send = false;
109         netcore_bootstrap_shutdown (); // TODO: wait 5 min, then call the user
110 }
111
112
113 /* This upcall is made to report that the network
114  * has come online.  This is also called when the
115  * network card has been initialised properly.
116  */
117 void top_network_online (void) {
118         top_network_can_send (); // Polling, so safe
119         netcore_bootstrap_initiate ();
120 }
121
122 /* As the processor now has time for it, process
123  * the reception of network packets.  Where simple
124  * stimulus-response action is possible, do that.
125  */
126 packet_t myrbuf;//TODO:ELSEWHERE//
127 packet_t mywbuf; // TODO: Allocate:ELSEWHERE
128 intptr_t mymem [MEM_NETVAR_COUNT];//TODO:ELSEWHERE//
129 static void network_recv_handler (irq_t *irq) {
130 intptr_t netinput (uint8_t *pkt, uint16_t pktlen, intptr_t *mem);
131 void ht162x_putchar (uint8_t idx, uint8_t ch, bool notify);
132         bool go;
133 //TODO:TEST// ht162x_putchar (1, '0', true);
134         go = can_recv;
135         can_recv = false;
136         // TODO: rescheduling would be better than looping
137         while (go) {
138                 uint16_t rbuflen = sizeof (myrbuf.data);
139                 retfn *rf;
140 //TODO:TEST// ht162x_putchar (1, '1', true);
141                 go = bottom_network_recv (myrbuf.data, &rbuflen);
142                 if (!go) {
143                         goto done;//TODO//break;
144                 }
145 //TODO:TEST// ht162x_putchar (1, '2', true);
146                 bottom_printf ("Received a network packet\n");
147                 bzero (mymem, sizeof (mymem));
148                 rf = (retfn *) netinput (myrbuf.data, rbuflen, mymem);
149 //TODO:TEST// ht162x_putchar (1, '3', true);
150                 if (rf != NULL) {
151                         uint8_t *stop = (*rf) (mywbuf.data, mymem);
152 //TODO:TEST// ht162x_putchar (1, '4', true);
153                         if (stop) {
154 //TODO:TEST// ht162x_putchar (1, '5', true);
155                                 mymem [MEM_ALL_DONE] = (intptr_t) stop;
156                                 netcore_send_buffer (mymem, mywbuf.data);
157 //TODO:TEST// ht162x_putchar (1, '6', true);
158                         }
159 //TODO:TEST// else ht162x_putchar (1, '7', true);
160                 }
161         }
162 done://TODO
163         if (go) {
164 //TODO:TEST// ht162x_putchar (1, '8', true);
165                 bottom_critical_region_begin ();
166                 if (!can_recv) {
167                         can_recv = true;
168 if (irq)
169                         irq_fire (irq);
170                 }
171                 bottom_critical_region_end ();
172         }
173 //TODO:TEST// ht162x_putchar (1, '9', true);
174 }
175
176
177 /* As the processor now has time for it, process
178  * the sending of network packets.
179  */
180 static void network_send_handler (irq_t *irq) {
181         bool go = can_send;
182         can_send = false;
183         // TODO: Go over priority queues, bottom_network_send()
184 }
185