ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/ether_beos.cpp
Revision: 1.6
Committed: 2008-01-01T09:47:38Z (16 years, 4 months ago) by gbeauche
Branch: MAIN
CVS Tags: HEAD
Changes since 1.5: +1 -1 lines
Log Message:
Happy New Year!

File Contents

# Content
1 /*
2 * ether_beos.cpp - SheepShaver Ethernet Device Driver (DLPI), BeOS specific stuff
3 *
4 * SheepShaver (C) 1997-2008 Marc Hellwig and Christian Bauer
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program 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 this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "sysdeps.h"
22 #include "ether.h"
23 #include "ether_defs.h"
24 #include "prefs.h"
25 #include "xlowmem.h"
26 #include "main.h"
27 #include "user_strings.h"
28 #include "sheep_net.h"
29
30 #define DEBUG 0
31 #include "debug.h"
32
33 #define STATISTICS 0
34 #define MONITOR 0
35
36
37 // Global variables
38 static thread_id read_thread; // Packet receiver thread
39 static bool ether_thread_active = true; // Flag for quitting the receiver thread
40
41 static area_id buffer_area; // Packet buffer area
42 static net_buffer *net_buffer_ptr; // Pointer to packet buffer
43 static sem_id read_sem, write_sem; // Semaphores to trigger packet reading/writing
44 static uint32 rd_pos; // Current read position in packet buffer
45 static uint32 wr_pos; // Current write position in packet buffer
46
47 static bool net_open = false; // Flag: initialization succeeded, network device open
48
49
50 // Prototypes
51 static status_t AO_receive_thread(void *data);
52
53
54 /*
55 * Initialize ethernet
56 */
57
58 void EtherInit(void)
59 {
60 // Do nothing if the user disabled the network
61 if (PrefsFindBool("nonet"))
62 return;
63
64 // find net-server team
65 i_wanna_try_that_again:
66 bool found_add_on = false;
67 team_info t_info;
68 int32 t_cookie = 0;
69 image_info i_info;
70 int32 i_cookie = 0;
71 while (get_next_team_info(&t_cookie, &t_info) == B_NO_ERROR) {
72 if (strstr(t_info.args,"net_server")!=NULL) {
73 // check if sheep_net add-on is loaded
74 while (get_next_image_info(t_info.team,&i_cookie,&i_info) == B_NO_ERROR) {
75 if (strstr(i_info.name,"sheep_net")!=NULL) {
76 found_add_on = true;
77 break;
78 }
79 }
80 }
81 if (found_add_on) break;
82 }
83 if (!found_add_on) {
84
85 // Search for sheep_net in network config file
86 char str[1024];
87 bool sheep_net_found = false;
88 FILE *fin = fopen("/boot/home/config/settings/network", "r");
89 while (!feof(fin)) {
90 fgets(str, 1024, fin);
91 if (strstr(str, "PROTOCOLS"))
92 if (strstr(str, "sheep_net"))
93 sheep_net_found = true;
94 }
95 fclose(fin);
96
97 // It was found, so something else must be wrong
98 if (sheep_net_found) {
99 WarningAlert(GetString(STR_NO_NET_ADDON_WARN));
100 return;
101 }
102
103 // Not found, inform the user
104 if (!ChoiceAlert(GetString(STR_NET_CONFIG_MODIFY_WARN), GetString(STR_OK_BUTTON), GetString(STR_CANCEL_BUTTON)))
105 return;
106
107 // Change the network config file and restart the network
108 fin = fopen("/boot/home/config/settings/network", "r");
109 FILE *fout = fopen("/boot/home/config/settings/network.2", "w");
110 bool global_found = false;
111 bool modified = false;
112 while (!feof(fin)) {
113 str[0] = 0;
114 fgets(str, 1024, fin);
115 if (!global_found && strstr(str, "GLOBAL:")) {
116 global_found = true;
117 } else if (global_found && !modified && strstr(str, "PROTOCOLS")) {
118 str[strlen(str)-1] = 0;
119 strcat(str, " sheep_net\n");
120 modified = true;
121 } else if (global_found && !modified && strlen(str) > 2 && str[strlen(str) - 2] == ':') {
122 fputs("\tPROTOCOLS = sheep_net\n", fout);
123 modified = true;
124 }
125 fputs(str, fout);
126 }
127 if (!modified)
128 fputs("\tPROTOCOLS = sheep_net\n", fout);
129 fclose(fout);
130 fclose(fin);
131 remove("/boot/home/config/settings/network.orig");
132 rename("/boot/home/config/settings/network", "/boot/home/config/settings/network.orig");
133 rename("/boot/home/config/settings/network.2", "/boot/home/config/settings/network");
134
135 app_info ai;
136 if (be_roster->GetAppInfo("application/x-vnd.Be-NETS", &ai) == B_OK) {
137 BMessenger msg(NULL, ai.team);
138 if (msg.IsValid()) {
139 while (be_roster->IsRunning("application/x-vnd.Be-NETS")) {
140 msg.SendMessage(B_QUIT_REQUESTED);
141 snooze(500000);
142 }
143 }
144 }
145 BPath path;
146 find_directory(B_BEOS_BOOT_DIRECTORY, &path);
147 path.Append("Netscript");
148 char *argv[3] = {"/bin/sh", (char *)path.Path(), NULL};
149 thread_id net_server = load_image(2, argv, environ);
150 resume_thread(net_server);
151 status_t l;
152 wait_for_thread(net_server, &l);
153 goto i_wanna_try_that_again;
154 }
155
156 // Set up communications with add-on
157 area_id handler_buffer;
158 if ((handler_buffer = find_area("packet buffer")) < B_NO_ERROR) {
159 WarningAlert(GetString(STR_NET_ADDON_INIT_FAILED));
160 return;
161 }
162 if ((buffer_area = clone_area("local packet buffer", &net_buffer_ptr, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, handler_buffer)) < B_NO_ERROR) {
163 D(bug("EtherInit: couldn't clone packet area\n"));
164 WarningAlert(GetString(STR_NET_ADDON_CLONE_FAILED));
165 return;
166 }
167 if ((read_sem = create_sem(0, "ether read")) < B_NO_ERROR) {
168 printf("FATAL: can't create Ethernet semaphore\n");
169 return;
170 }
171 net_buffer_ptr->read_sem = read_sem;
172 write_sem = net_buffer_ptr->write_sem;
173 read_thread = spawn_thread(AO_receive_thread, "ether read", B_URGENT_DISPLAY_PRIORITY, NULL);
174 resume_thread(read_thread);
175 for (int i=0; i<WRITE_PACKET_COUNT; i++)
176 net_buffer_ptr->write[i].cmd = IN_USE | (ACTIVATE_SHEEP_NET << 8);
177 rd_pos = wr_pos = 0;
178 release_sem(write_sem);
179
180 // Everything OK
181 net_open = true;
182 }
183
184
185 /*
186 * Exit ethernet
187 */
188
189 void EtherExit(void)
190 {
191 if (net_open) {
192
193 // Close communications with add-on
194 for (int i=0; i<WRITE_PACKET_COUNT; i++)
195 net_buffer_ptr->write[i].cmd = IN_USE | (DEACTIVATE_SHEEP_NET << 8);
196 release_sem(write_sem);
197
198 // Quit receiver thread
199 ether_thread_active = false;
200 status_t result;
201 release_sem(read_sem);
202 while (wait_for_thread(read_thread, &result) == B_INTERRUPTED) ;
203
204 delete_sem(read_sem);
205 delete_area(buffer_area);
206 }
207
208 #if STATISTICS
209 // Show statistics
210 printf("%ld messages put on write queue\n", num_wput);
211 printf("%ld error acks\n", num_error_acks);
212 printf("%ld packets transmitted (%ld raw, %ld normal)\n", num_tx_packets, num_tx_raw_packets, num_tx_normal_packets);
213 printf("%ld tx packets dropped because buffer full\n", num_tx_buffer_full);
214 printf("%ld packets received\n", num_rx_packets);
215 printf("%ld packets passed upstream (%ld Fast Path, %ld normal)\n", num_rx_fastpath + num_unitdata_ind, num_rx_fastpath, num_unitdata_ind);
216 printf("EtherIRQ called %ld times\n", num_ether_irq);
217 printf("%ld rx packets dropped due to low memory\n", num_rx_no_mem);
218 printf("%ld rx packets dropped because no stream found\n", num_rx_dropped);
219 printf("%ld rx packets dropped because stream not ready\n", num_rx_stream_not_ready);
220 printf("%ld rx packets dropped because no memory for unitdata_ind\n", num_rx_no_unitdata_mem);
221 #endif
222 }
223
224
225 /*
226 * Ask add-on for ethernet hardware address
227 */
228
229 void AO_get_ethernet_address(uint32 arg)
230 {
231 uint8 *addr = Mac2HostAddr(arg);
232 if (net_open) {
233 OTCopy48BitAddress(net_buffer_ptr->ether_addr, addr);
234 } else {
235 addr[0] = 0x12;
236 addr[1] = 0x34;
237 addr[2] = 0x56;
238 addr[3] = 0x78;
239 addr[4] = 0x9a;
240 addr[5] = 0xbc;
241 }
242 D(bug("AO_get_ethernet_address: got address %02x%02x%02x%02x%02x%02x\n", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]));
243 }
244
245
246 /*
247 * Tell add-on to enable multicast address
248 */
249
250 void AO_enable_multicast(uint32 addr)
251 {
252 D(bug("AO_enable_multicast\n"));
253 if (net_open) {
254 net_packet *p = &net_buffer_ptr->write[wr_pos];
255 if (p->cmd & IN_USE) {
256 D(bug("WARNING: couldn't enable multicast address\n"));
257 } else {
258 Mac2host_memcpy(p->data, addr, 6);
259 p->length = 6;
260 p->cmd = IN_USE | (ADD_MULTICAST << 8);
261 wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
262 release_sem(write_sem);
263 }
264 }
265 }
266
267
268 /*
269 * Tell add-on to disable multicast address
270 */
271
272 void AO_disable_multicast(uint32 addr)
273 {
274 D(bug("AO_disable_multicast\n"));
275 if (net_open) {
276 net_packet *p = &net_buffer_ptr->write[wr_pos];
277 if (p->cmd & IN_USE) {
278 D(bug("WARNING: couldn't enable multicast address\n"));
279 } else {
280 Mac2host_memcpy(p->data, addr, 6);
281 p->length = 6;
282 p->cmd = IN_USE | (REMOVE_MULTICAST << 8);
283 wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
284 release_sem(write_sem);
285 }
286 D(bug("WARNING: couldn't disable multicast address\n"));
287 }
288 }
289
290
291 /*
292 * Tell add-on to transmit one packet
293 */
294
295 void AO_transmit_packet(uint32 mp_arg)
296 {
297 D(bug("AO_transmit_packet\n"));
298 if (net_open) {
299 net_packet *p = &net_buffer_ptr->write[wr_pos];
300 if (p->cmd & IN_USE) {
301 D(bug("WARNING: couldn't transmit packet (buffer full)\n"));
302 num_tx_buffer_full++;
303 } else {
304 D(bug(" write packet pos %d\n", i));
305 num_tx_packets++;
306
307 // Copy packet to buffer
308 uint8 *start;
309 uint8 *bp = start = p->data;
310 mblk_t *mp = Mac2HostAddr(mp_arg);
311 while (mp) {
312 uint32 size = mp->b_wptr - mp->b_rptr;
313 memcpy(bp, mp->b_rptr, size);
314 bp += size;
315 mp = mp->b_cont;
316 }
317
318 #if MONITOR
319 bug("Sending Ethernet packet:\n");
320 for (int i=0; i<(uint32)(bp - start); i++) {
321 bug("%02lx ", start[i]);
322 }
323 bug("\n");
324 #endif
325
326 // Notify add-on
327 p->length = (uint32)(bp - start);
328 p->cmd = IN_USE | (SHEEP_PACKET << 8);
329 wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
330 release_sem(write_sem);
331 }
332 }
333 }
334
335
336 /*
337 * Packet reception thread
338 */
339
340 static status_t AO_receive_thread(void *data)
341 {
342 while (ether_thread_active) {
343 if (net_buffer_ptr->read[rd_pos].cmd & IN_USE) {
344 if (ether_driver_opened) {
345 D(bug(" packet received, triggering Ethernet interrupt\n"));
346 SetInterruptFlag(INTFLAG_ETHER);
347 TriggerInterrupt();
348 }
349 }
350 acquire_sem_etc(read_sem, 1, B_TIMEOUT, 25000);
351 }
352 return 0;
353 }
354
355
356 /*
357 * Ethernet interrupt
358 */
359
360 void EtherIRQ(void)
361 {
362 D(bug("EtherIRQ\n"));
363 num_ether_irq++;
364 OTEnterInterrupt();
365
366 // Send received packets to OpenTransport
367 net_packet *p = &net_buffer_ptr->read[rd_pos];
368 while (p->cmd & IN_USE) {
369 if ((p->cmd >> 8) == SHEEP_PACKET) {
370 num_rx_packets++;
371 D(bug(" read packet pos %d\n", i));
372 uint32 size = p->length;
373
374 #if MONITOR
375 bug("Receiving Ethernet packet:\n");
376 for (int i=0; i<size; i++) {
377 bug("%02lx ", p->data[i]);
378 }
379 bug("\n");
380 #endif
381
382 // Wrap packet in message block
383 //!! maybe use esballoc()
384 mblk_t *mp;
385 if ((mp = allocb(size, 0)) != NULL) {
386 D(bug(" packet data at %p\n", (void *)mp->b_rptr));
387 memcpy(mp->b_rptr, p->data, size);
388 mp->b_wptr += size;
389 ether_packet_received(mp);
390 } else {
391 D(bug("WARNING: Cannot allocate mblk for received packet\n"));
392 num_rx_no_mem++;
393 }
394 }
395 p->cmd = 0; // Free packet
396 rd_pos = (rd_pos + 1) % READ_PACKET_COUNT;
397 p = &net_buffer_ptr->read[rd_pos];
398 }
399 OTLeaveInterrupt();
400 }