ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/BeOS/ether_beos.cpp
Revision: 1.2
Committed: 1999-10-03T21:04:18Z (24 years, 8 months ago) by cebix
Branch: MAIN
CVS Tags: release-0_7-2, snapshot-21101999, snapshot-02111999
Changes since 1.1: +14 -7 lines
Log Message:
- moved protocol removal to a proper function

File Contents

# Content
1 /*
2 * ether_beos.cpp - Ethernet device driver, BeOS specific stuff
3 *
4 * Basilisk II (C) 1997-1999 Christian Bauer
5 * Portions (C) 1997-1999 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 <KernelKit.h>
23 #include <AppKit.h>
24 #include <StorageKit.h>
25 #include <support/List.h>
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "sysdeps.h"
32 #include "cpu_emulation.h"
33 #include "main.h"
34 #include "prefs.h"
35 #include "user_strings.h"
36 #include "macos_util.h"
37 #include "ether.h"
38 #include "ether_defs.h"
39
40 #include "sheep_net.h"
41
42 #define DEBUG 0
43 #include "debug.h"
44
45 #define MONITOR 0
46
47
48 // List of attached protocols
49 struct NetProtocol {
50 uint16 type;
51 uint32 handler;
52 };
53
54 static BList prot_list;
55
56
57 // Global variables
58 static thread_id read_thread; // Packet reception thread
59 static bool ether_thread_active = true; // Flag for quitting the reception thread
60
61 static area_id buffer_area; // Packet buffer area
62 static net_buffer *net_buffer_ptr; // Pointer to packet buffer
63 static uint32 rd_pos; // Current read position in packet buffer
64 static uint32 wr_pos; // Current write position in packet buffer
65 static sem_id read_sem, write_sem; // Semaphores to trigger packet reading/writing
66
67
68 // Prototypes
69 static status_t receive_proc(void *data);
70
71
72 /*
73 * Find protocol in list
74 */
75
76 static NetProtocol *find_protocol(uint16 type)
77 {
78 // All 802.2 types are the same
79 if (type <= 1500)
80 type = 0;
81
82 // Search list (we could use hashing here but there are usually only three
83 // handlers installed: 0x0000 for AppleTalk and 0x0800/0x0806 for TCP/IP)
84 NetProtocol *p;
85 for (int i=0; (p = (NetProtocol *)prot_list.ItemAt(i)) != NULL; i++)
86 if (p->type == type)
87 return p;
88 return NULL;
89 }
90
91
92 /*
93 * Remove all protocols
94 */
95
96 static void remove_all_protocols(void)
97 {
98 NetProtocol *p;
99 while ((p = (NetProtocol *)prot_list.RemoveItem((long)0)) != NULL)
100 delete p;
101 }
102
103
104 /*
105 * Initialization
106 */
107
108 void EtherInit(void)
109 {
110 // Do nothing if no Ethernet device specified
111 if (PrefsFindString("ether") == NULL)
112 return;
113
114 // Find net_server team
115 i_wanna_try_that_again:
116 bool found_add_on = false;
117 team_info t_info;
118 int32 t_cookie = 0;
119 image_info i_info;
120 int32 i_cookie = 0;
121 while (get_next_team_info(&t_cookie, &t_info) == B_NO_ERROR) {
122 if (strstr(t_info.args,"net_server")!=NULL) {
123
124 // Check if sheep_net add-on is loaded
125 while (get_next_image_info(t_info.team, &i_cookie, &i_info) == B_NO_ERROR) {
126 if (strstr(i_info.name, "sheep_net") != NULL) {
127 found_add_on = true;
128 break;
129 }
130 }
131 }
132 if (found_add_on) break;
133 }
134 if (!found_add_on) {
135
136 // Search for sheep_net in network config file
137 char str[1024];
138 bool sheep_net_found = false;
139 FILE *fin = fopen("/boot/home/config/settings/network", "r");
140 while (!feof(fin)) {
141 fgets(str, 1024, fin);
142 if (strstr(str, "PROTOCOLS"))
143 if (strstr(str, "sheep_net"))
144 sheep_net_found = true;
145 }
146 fclose(fin);
147
148 // It was found, so something else must be wrong
149 if (sheep_net_found) {
150 WarningAlert(GetString(STR_NO_NET_ADDON_WARN));
151 return;
152 }
153
154 // Not found, inform the user
155 if (!ChoiceAlert(GetString(STR_NET_CONFIG_MODIFY_WARN), GetString(STR_OK_BUTTON), GetString(STR_CANCEL_BUTTON)))
156 return;
157
158 // Change the network config file and restart the network
159 fin = fopen("/boot/home/config/settings/network", "r");
160 FILE *fout = fopen("/boot/home/config/settings/network.2", "w");
161 bool global_found = false;
162 bool modified = false;
163 while (!feof(fin)) {
164 str[0] = 0;
165 fgets(str, 1024, fin);
166 if (!global_found && strstr(str, "GLOBAL:")) {
167 global_found = true;
168 } else if (global_found && !modified && strstr(str, "PROTOCOLS")) {
169 str[strlen(str)-1] = 0;
170 strcat(str, " sheep_net\n");
171 modified = true;
172 } else if (global_found && !modified && strlen(str) > 2 && str[strlen(str) - 2] == ':') {
173 fputs("\tPROTOCOLS = sheep_net\n", fout);
174 modified = true;
175 }
176 fputs(str, fout);
177 }
178 if (!modified)
179 fputs("\tPROTOCOLS = sheep_net\n", fout);
180 fclose(fout);
181 fclose(fin);
182 remove("/boot/home/config/settings/network.orig");
183 rename("/boot/home/config/settings/network", "/boot/home/config/settings/network.orig");
184 rename("/boot/home/config/settings/network.2", "/boot/home/config/settings/network");
185
186 app_info ai;
187 if (be_roster->GetAppInfo("application/x-vnd.Be-NETS", &ai) == B_OK) {
188 BMessenger msg(NULL, ai.team);
189 if (msg.IsValid()) {
190 while (be_roster->IsRunning("application/x-vnd.Be-NETS")) {
191 msg.SendMessage(B_QUIT_REQUESTED);
192 snooze(500000);
193 }
194 }
195 }
196 BPath path;
197 find_directory(B_BEOS_BOOT_DIRECTORY, &path);
198 path.Append("Netscript");
199 const char *argv[3] = {"/bin/sh", path.Path(), NULL};
200 thread_id net_server = load_image(2, argv, (const char **)environ);
201 resume_thread(net_server);
202 status_t l;
203 wait_for_thread(net_server, &l);
204 goto i_wanna_try_that_again;
205 }
206
207 // Set up communications with add-on
208 area_id handler_buffer;
209 if ((handler_buffer = find_area("packet buffer")) < B_NO_ERROR) {
210 WarningAlert(GetString(STR_NET_ADDON_INIT_FAILED));
211 return;
212 }
213 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) {
214 D(bug("EtherInit: couldn't clone packet area\n"));
215 WarningAlert(GetString(STR_NET_ADDON_CLONE_FAILED));
216 return;
217 }
218 if ((read_sem = create_sem(0, "ether read")) < B_NO_ERROR) {
219 printf("FATAL: can't create Ethernet semaphore\n");
220 return;
221 }
222 net_buffer_ptr->read_sem = read_sem;
223 write_sem = net_buffer_ptr->write_sem;
224 read_thread = spawn_thread(receive_proc, "Ethernet Receiver", B_URGENT_DISPLAY_PRIORITY, NULL);
225 resume_thread(read_thread);
226 for (int i=0; i<WRITE_PACKET_COUNT; i++)
227 net_buffer_ptr->write[i].cmd = IN_USE | (ACTIVATE_SHEEP_NET << 8);
228 rd_pos = wr_pos = 0;
229 release_sem(write_sem);
230
231 // Get Ethernet address
232 memcpy(ether_addr, net_buffer_ptr->ether_addr, 6);
233 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]));
234
235 // Everything OK
236 net_open = true;
237 }
238
239
240 /*
241 * Deinitialization
242 */
243
244 void EtherExit(void)
245 {
246 if (net_open) {
247
248 // Close communications with add-on
249 for (int i=0; i<WRITE_PACKET_COUNT; i++)
250 net_buffer_ptr->write[i].cmd = IN_USE | (DEACTIVATE_SHEEP_NET << 8);
251 release_sem(write_sem);
252
253 // Quit reception thread
254 ether_thread_active = false;
255 status_t result;
256 release_sem(read_sem);
257 wait_for_thread(read_thread, &result);
258
259 delete_sem(read_sem);
260 delete_area(buffer_area);
261
262 // Remove all protocols
263 remove_all_protocols();
264 }
265 }
266
267
268 /*
269 * Reset
270 */
271
272 void EtherReset(void)
273 {
274 remove_all_protocols();
275 }
276
277
278 /*
279 * Add multicast address
280 */
281
282 int16 ether_add_multicast(uint32 pb)
283 {
284 uint8 *addr = Mac2HostAddr(pb + eMultiAddr);
285 net_packet *p = &net_buffer_ptr->write[wr_pos];
286 if (p->cmd & IN_USE) {
287 D(bug("WARNING: Couldn't enable multicast address\n"));
288 } else {
289 memcpy(p->data, addr, 6);
290 p->length = 6;
291 p->cmd = IN_USE | (ADD_MULTICAST << 8);
292 wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
293 release_sem(write_sem);
294 }
295 return noErr;
296 }
297
298
299 /*
300 * Delete multicast address
301 */
302
303 int16 ether_del_multicast(uint32 pb)
304 {
305 uint8 *addr = Mac2HostAddr(pb + eMultiAddr);
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 memcpy(p->data, addr, 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 uint8 *start;
370 uint8 *bp = start = p->data;
371 for (;;) {
372 int len = ReadMacInt16(wds);
373 if (len == 0)
374 break;
375 memcpy(bp, Mac2HostAddr(ReadMacInt32(wds + 2)), len);
376 bp += len;
377 wds += 6;
378 }
379
380 // Set source address
381 memcpy(start + 6, ether_addr, 6);
382
383 #if MONITOR
384 bug("Sending Ethernet packet:\n");
385 for (int i=0; i<(uint32)(bp-start); i++) {
386 bug("%02x ", start[i]);
387 }
388 bug("\n");
389 #endif
390
391 // Notify add-on
392 p->length = (uint32)(bp - start);
393 p->cmd = IN_USE | (SHEEP_PACKET << 8);
394 wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
395 release_sem(write_sem);
396 }
397 return noErr;
398 }
399
400
401 /*
402 * Packet reception thread
403 */
404
405 static status_t receive_proc(void *data)
406 {
407 while (ether_thread_active) {
408 if (net_buffer_ptr->read[rd_pos].cmd & IN_USE) {
409 D(bug(" packet received, triggering Ethernet interrupt\n"));
410 SetInterruptFlag(INTFLAG_ETHER);
411 TriggerInterrupt();
412 }
413 acquire_sem_etc(read_sem, 1, B_TIMEOUT, 25000);
414 }
415 return 0;
416 }
417
418
419 /*
420 * Ethernet interrupt - activate deferred tasks to call IODone or protocol handlers
421 */
422
423 void EtherInterrupt(void)
424 {
425 D(bug("EtherIRQ\n"));
426
427 // Call protocol handler for received packets
428 net_packet *p = &net_buffer_ptr->read[rd_pos];
429 while (p->cmd & IN_USE) {
430 if ((p->cmd >> 8) == SHEEP_PACKET) {
431 #if MONITOR
432 bug("Receiving Ethernet packet:\n");
433 for (int i=0; i<p->length; i++) {
434 bug("%02x ", p->data[i]);
435 }
436 bug("\n");
437 #endif
438 // Get packet type
439 uint16 type = ntohs(*(uint16 *)(p->data + 12));
440
441 // Look for protocol
442 NetProtocol *prot = find_protocol(type);
443 if (prot == NULL)
444 goto next;
445
446 // No default handler
447 if (prot->handler == 0)
448 goto next;
449
450 // Copy header to RHA
451 memcpy(Mac2HostAddr(ether_data + ed_RHA), p->data, 14);
452 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)));
453
454 // Call protocol handler
455 M68kRegisters r;
456 r.d[0] = type; // Packet type
457 r.d[1] = p->length - 14; // Remaining packet length (without header, for ReadPacket)
458 r.a[0] = (uint32)p->data + 14; // Pointer to packet (host address, for ReadPacket)
459 r.a[3] = ether_data + ed_RHA + 14; // Pointer behind header in RHA
460 r.a[4] = ether_data + ed_ReadPacket; // Pointer to ReadPacket/ReadRest routines
461 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]));
462 Execute68k(prot->handler, &r);
463 }
464 next: p->cmd = 0; // Free packet
465 rd_pos = (rd_pos + 1) % READ_PACKET_COUNT;
466 p = &net_buffer_ptr->read[rd_pos];
467 }
468 D(bug(" EtherIRQ done\n"));
469 }