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

File Contents

# Content
1 /*
2 * ether_beos.cpp - Ethernet device driver, BeOS specific stuff
3 *
4 * Basilisk II (C) 1997-2008 Christian Bauer
5 * Portions written by Marc Hellwig
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #include "sysdeps.h"
23
24 #include <KernelKit.h>
25 #include <AppKit.h>
26 #include <StorageKit.h>
27 #include <support/List.h>
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <sys/socket.h>
33
34 #include "cpu_emulation.h"
35 #include "main.h"
36 #include "prefs.h"
37 #include "user_strings.h"
38 #include "macos_util.h"
39 #include "ether.h"
40 #include "ether_defs.h"
41
42 #include "sheep_net.h"
43
44 #define DEBUG 0
45 #include "debug.h"
46
47 #define MONITOR 0
48
49
50 // List of attached protocols
51 struct NetProtocol {
52 uint16 type;
53 uint32 handler;
54 };
55
56 static BList prot_list;
57
58
59 // Global variables
60 static thread_id read_thread; // Packet reception thread
61 static bool ether_thread_active = true; // Flag for quitting the reception thread
62
63 static area_id buffer_area; // Packet buffer area
64 static net_buffer *net_buffer_ptr; // Pointer to packet buffer
65 static uint32 rd_pos; // Current read position in packet buffer
66 static uint32 wr_pos; // Current write position in packet buffer
67 static sem_id read_sem, write_sem; // Semaphores to trigger packet reading/writing
68
69 static int fd = -1; // UDP socket fd
70 static bool udp_tunnel = false;
71
72
73 // Prototypes
74 static status_t receive_proc(void *data);
75
76
77 /*
78 * Find protocol in list
79 */
80
81 static NetProtocol *find_protocol(uint16 type)
82 {
83 // All 802.2 types are the same
84 if (type <= 1500)
85 type = 0;
86
87 // Search list (we could use hashing here but there are usually only three
88 // handlers installed: 0x0000 for AppleTalk and 0x0800/0x0806 for TCP/IP)
89 NetProtocol *p;
90 for (int i=0; (p = (NetProtocol *)prot_list.ItemAt(i)) != NULL; i++)
91 if (p->type == type)
92 return p;
93 return NULL;
94 }
95
96
97 /*
98 * Remove all protocols
99 */
100
101 static void remove_all_protocols(void)
102 {
103 NetProtocol *p;
104 while ((p = (NetProtocol *)prot_list.RemoveItem((long)0)) != NULL)
105 delete p;
106 }
107
108
109 /*
110 * Initialization
111 */
112
113 bool ether_init(void)
114 {
115 // Do nothing if no Ethernet device specified
116 if (PrefsFindString("ether") == NULL)
117 return false;
118
119 // Find net_server team
120 i_wanna_try_that_again:
121 bool found_add_on = false;
122 team_info t_info;
123 int32 t_cookie = 0;
124 image_info i_info;
125 int32 i_cookie = 0;
126 while (get_next_team_info(&t_cookie, &t_info) == B_NO_ERROR) {
127 if (strstr(t_info.args,"net_server")!=NULL) {
128
129 // Check if sheep_net add-on is loaded
130 while (get_next_image_info(t_info.team, &i_cookie, &i_info) == B_NO_ERROR) {
131 if (strstr(i_info.name, "sheep_net") != NULL) {
132 found_add_on = true;
133 break;
134 }
135 }
136 }
137 if (found_add_on) break;
138 }
139 if (!found_add_on) {
140
141 // Search for sheep_net in network config file
142 char str[1024];
143 bool sheep_net_found = false;
144 FILE *fin = fopen("/boot/home/config/settings/network", "r");
145 while (!feof(fin)) {
146 fgets(str, 1024, fin);
147 if (strstr(str, "PROTOCOLS"))
148 if (strstr(str, "sheep_net"))
149 sheep_net_found = true;
150 }
151 fclose(fin);
152
153 // It was found, so something else must be wrong
154 if (sheep_net_found) {
155 WarningAlert(GetString(STR_NO_NET_ADDON_WARN));
156 return false;
157 }
158
159 // Not found, inform the user
160 if (!ChoiceAlert(GetString(STR_NET_CONFIG_MODIFY_WARN), GetString(STR_OK_BUTTON), GetString(STR_CANCEL_BUTTON)))
161 return false;
162
163 // Change the network config file and restart the network
164 fin = fopen("/boot/home/config/settings/network", "r");
165 FILE *fout = fopen("/boot/home/config/settings/network.2", "w");
166 bool global_found = false;
167 bool modified = false;
168 while (!feof(fin)) {
169 str[0] = 0;
170 fgets(str, 1024, fin);
171 if (!global_found && strstr(str, "GLOBAL:")) {
172 global_found = true;
173 } else if (global_found && !modified && strstr(str, "PROTOCOLS")) {
174 str[strlen(str)-1] = 0;
175 strcat(str, " sheep_net\n");
176 modified = true;
177 } else if (global_found && !modified && strlen(str) > 2 && str[strlen(str) - 2] == ':') {
178 fputs("\tPROTOCOLS = sheep_net\n", fout);
179 modified = true;
180 }
181 fputs(str, fout);
182 }
183 if (!modified)
184 fputs("\tPROTOCOLS = sheep_net\n", fout);
185 fclose(fout);
186 fclose(fin);
187 remove("/boot/home/config/settings/network.orig");
188 rename("/boot/home/config/settings/network", "/boot/home/config/settings/network.orig");
189 rename("/boot/home/config/settings/network.2", "/boot/home/config/settings/network");
190
191 app_info ai;
192 if (be_roster->GetAppInfo("application/x-vnd.Be-NETS", &ai) == B_OK) {
193 BMessenger msg(NULL, ai.team);
194 if (msg.IsValid()) {
195 while (be_roster->IsRunning("application/x-vnd.Be-NETS")) {
196 msg.SendMessage(B_QUIT_REQUESTED);
197 snooze(500000);
198 }
199 }
200 }
201 BPath path;
202 find_directory(B_BEOS_BOOT_DIRECTORY, &path);
203 path.Append("Netscript");
204 const char *argv[3] = {"/bin/sh", path.Path(), NULL};
205 thread_id net_server = load_image(2, argv, (const char **)environ);
206 resume_thread(net_server);
207 status_t l;
208 wait_for_thread(net_server, &l);
209 goto i_wanna_try_that_again;
210 }
211
212 // Set up communications with add-on
213 area_id handler_buffer;
214 if ((handler_buffer = find_area("packet buffer")) < B_NO_ERROR) {
215 WarningAlert(GetString(STR_NET_ADDON_INIT_FAILED));
216 return false;
217 }
218 if ((buffer_area = clone_area("local packet buffer", (void **)&net_buffer_ptr, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, handler_buffer)) < B_NO_ERROR) {
219 D(bug("EtherInit: couldn't clone packet area\n"));
220 WarningAlert(GetString(STR_NET_ADDON_CLONE_FAILED));
221 return false;
222 }
223 if ((read_sem = create_sem(0, "ether read")) < B_NO_ERROR) {
224 printf("FATAL: can't create Ethernet semaphore\n");
225 return false;
226 }
227 net_buffer_ptr->read_sem = read_sem;
228 write_sem = net_buffer_ptr->write_sem;
229 read_thread = spawn_thread(receive_proc, "Ethernet Receiver", B_URGENT_DISPLAY_PRIORITY, NULL);
230 resume_thread(read_thread);
231 for (int i=0; i<WRITE_PACKET_COUNT; i++)
232 net_buffer_ptr->write[i].cmd = IN_USE | (ACTIVATE_SHEEP_NET << 8);
233 rd_pos = wr_pos = 0;
234 release_sem(write_sem);
235
236 // Get Ethernet address
237 memcpy(ether_addr, net_buffer_ptr->ether_addr, 6);
238 D(bug("Ethernet address %02x %02x %02x %02x %02x %02x\n", ether_addr[0], ether_addr[1], ether_addr[2], ether_addr[3], ether_addr[4], ether_addr[5]));
239
240 // Everything OK
241 return true;
242 }
243
244
245 /*
246 * Deinitialization
247 */
248
249 void ether_exit(void)
250 {
251 // Close communications with add-on
252 for (int i=0; i<WRITE_PACKET_COUNT; i++)
253 net_buffer_ptr->write[i].cmd = IN_USE | (DEACTIVATE_SHEEP_NET << 8);
254 release_sem(write_sem);
255
256 // Quit reception thread
257 ether_thread_active = false;
258 status_t result;
259 release_sem(read_sem);
260 wait_for_thread(read_thread, &result);
261
262 delete_sem(read_sem);
263 delete_area(buffer_area);
264
265 // Remove all protocols
266 remove_all_protocols();
267 }
268
269
270 /*
271 * Reset
272 */
273
274 void ether_reset(void)
275 {
276 remove_all_protocols();
277 }
278
279
280 /*
281 * Add multicast address
282 */
283
284 int16 ether_add_multicast(uint32 pb)
285 {
286 net_packet *p = &net_buffer_ptr->write[wr_pos];
287 if (p->cmd & IN_USE) {
288 D(bug("WARNING: Couldn't enable multicast address\n"));
289 } else {
290 Mac2Host_memcpy(p->data, pb + eMultiAddr, 6);
291 p->length = 6;
292 p->cmd = IN_USE | (ADD_MULTICAST << 8);
293 wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
294 release_sem(write_sem);
295 }
296 return noErr;
297 }
298
299
300 /*
301 * Delete multicast address
302 */
303
304 int16 ether_del_multicast(uint32 pb)
305 {
306 net_packet *p = &net_buffer_ptr->write[wr_pos];
307 if (p->cmd & IN_USE) {
308 D(bug("WARNING: Couldn't enable multicast address\n"));
309 } else {
310 Mac2Host_memcpy(p->data, pb + eMultiAddr, 6);
311 p->length = 6;
312 p->cmd = IN_USE | (REMOVE_MULTICAST << 8);
313 wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
314 release_sem(write_sem);
315 }
316 return noErr;
317 }
318
319
320 /*
321 * Attach protocol handler
322 */
323
324 int16 ether_attach_ph(uint16 type, uint32 handler)
325 {
326 // Already attached?
327 NetProtocol *p = find_protocol(type);
328 if (p != NULL)
329 return lapProtErr;
330 else {
331 // No, create and attach
332 p = new NetProtocol;
333 p->type = type;
334 p->handler = handler;
335 prot_list.AddItem(p);
336 return noErr;
337 }
338 }
339
340
341 /*
342 * Detach protocol handler
343 */
344
345 int16 ether_detach_ph(uint16 type)
346 {
347 NetProtocol *p = find_protocol(type);
348 if (p != NULL) {
349 prot_list.RemoveItem(p);
350 delete p;
351 return noErr;
352 } else
353 return lapProtErr;
354 }
355
356
357 /*
358 * Transmit raw ethernet packet
359 */
360
361 int16 ether_write(uint32 wds)
362 {
363 net_packet *p = &net_buffer_ptr->write[wr_pos];
364 if (p->cmd & IN_USE) {
365 D(bug("WARNING: Couldn't transmit packet (buffer full)\n"));
366 } else {
367
368 // Copy packet to buffer
369 int len = ether_wds_to_buffer(wds, p->data);
370
371 #if MONITOR
372 bug("Sending Ethernet packet:\n");
373 for (int i=0; i<len; i++) {
374 bug("%02x ", p->data[i]);
375 }
376 bug("\n");
377 #endif
378
379 // Notify add-on
380 p->length = len;
381 p->cmd = IN_USE | (SHEEP_PACKET << 8);
382 wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
383 release_sem(write_sem);
384 }
385 return noErr;
386 }
387
388
389 /*
390 * Packet reception thread (non-UDP)
391 */
392
393 static status_t receive_proc(void *data)
394 {
395 while (ether_thread_active) {
396 if (net_buffer_ptr->read[rd_pos].cmd & IN_USE) {
397 D(bug(" packet received, triggering Ethernet interrupt\n"));
398 SetInterruptFlag(INTFLAG_ETHER);
399 TriggerInterrupt();
400 }
401 acquire_sem_etc(read_sem, 1, B_TIMEOUT, 25000);
402 }
403 return 0;
404 }
405
406
407 /*
408 * Packet reception thread (UDP)
409 */
410
411 static status_t receive_proc_udp(void *data)
412 {
413 while (ether_thread_active) {
414 fd_set readfds;
415 FD_ZERO(&readfds);
416 FD_SET(fd, &readfds);
417 struct timeval timeout;
418 timeout.tv_sec = 1;
419 timeout.tv_usec = 0;
420 if (select(fd+1, &readfds, NULL, NULL, &timeout) > 0) {
421 D(bug(" packet received, triggering Ethernet interrupt\n"));
422 SetInterruptFlag(INTFLAG_ETHER);
423 TriggerInterrupt();
424 }
425 }
426 return 0;
427 }
428
429
430 /*
431 * Start UDP packet reception thread
432 */
433
434 bool ether_start_udp_thread(int socket_fd)
435 {
436 fd = socket_fd;
437 udp_tunnel = true;
438 ether_thread_active = true;
439 read_thread = spawn_thread(receive_proc_udp, "UDP Receiver", B_URGENT_DISPLAY_PRIORITY, NULL);
440 resume_thread(read_thread);
441 return true;
442 }
443
444
445 /*
446 * Stop UDP packet reception thread
447 */
448
449 void ether_stop_udp_thread(void)
450 {
451 ether_thread_active = false;
452 status_t result;
453 wait_for_thread(read_thread, &result);
454 }
455
456
457 /*
458 * Ethernet interrupt - activate deferred tasks to call IODone or protocol handlers
459 */
460
461 void EtherInterrupt(void)
462 {
463 D(bug("EtherIRQ\n"));
464 EthernetPacket ether_packet;
465 uint32 packet = ether_packet.addr();
466
467 if (udp_tunnel) {
468
469 ssize_t length;
470
471 // Read packets from socket and hand to ether_udp_read() for processing
472 while (true) {
473 struct sockaddr_in from;
474 socklen_t from_len = sizeof(from);
475 length = recvfrom(fd, Mac2HostAddr(packet), 1514, 0, (struct sockaddr *)&from, &from_len);
476 if (length < 14)
477 break;
478 ether_udp_read(packet, length, &from);
479 }
480
481 } else {
482
483 // Call protocol handler for received packets
484 net_packet *p = &net_buffer_ptr->read[rd_pos];
485 while (p->cmd & IN_USE) {
486 if ((p->cmd >> 8) == SHEEP_PACKET) {
487 Host2Mac_memcpy(packet, p->data, p->length);
488 #if MONITOR
489 bug("Receiving Ethernet packet:\n");
490 for (int i=0; i<p->length; i++) {
491 bug("%02x ", ReadMacInt8(packet + i));
492 }
493 bug("\n");
494 #endif
495 // Get packet type
496 uint16 type = ReadMacInt16(packet + 12);
497
498 // Look for protocol
499 NetProtocol *prot = find_protocol(type);
500 if (prot == NULL)
501 goto next;
502
503 // No default handler
504 if (prot->handler == 0)
505 goto next;
506
507 // Copy header to RHA
508 Mac2Mac_memcpy(ether_data + ed_RHA, packet, 14);
509 D(bug(" header %08lx%04lx %08lx%04lx %04lx\n", ReadMacInt32(ether_data + ed_RHA), ReadMacInt16(ether_data + ed_RHA + 4), ReadMacInt32(ether_data + ed_RHA + 6), ReadMacInt16(ether_data + ed_RHA + 10), ReadMacInt16(ether_data + ed_RHA + 12)));
510
511 // Call protocol handler
512 M68kRegisters r;
513 r.d[0] = type; // Packet type
514 r.d[1] = p->length - 14; // Remaining packet length (without header, for ReadPacket)
515 r.a[0] = packet + 14; // Pointer to packet (Mac address, for ReadPacket)
516 r.a[3] = ether_data + ed_RHA + 14; // Pointer behind header in RHA
517 r.a[4] = ether_data + ed_ReadPacket; // Pointer to ReadPacket/ReadRest routines
518 D(bug(" calling protocol handler %08lx, type %08lx, length %08lx, data %08lx, rha %08lx, read_packet %08lx\n", prot->handler, r.d[0], r.d[1], r.a[0], r.a[3], r.a[4]));
519 Execute68k(prot->handler, &r);
520 }
521 next: p->cmd = 0; // Free packet
522 rd_pos = (rd_pos + 1) % READ_PACKET_COUNT;
523 p = &net_buffer_ptr->read[rd_pos];
524 }
525 }
526 D(bug(" EtherIRQ done\n"));
527 }