ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/ether_beos.cpp
Revision: 1.2
Committed: 2004-01-12T15:37:19Z (20 years, 4 months ago) by cebix
Branch: MAIN
Changes since 1.1: +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-2004 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(uint8 *addr)
230 {
231 if (net_open) {
232 OTCopy48BitAddress(net_buffer_ptr->ether_addr, addr);
233 } else {
234 addr[0] = 0x12;
235 addr[1] = 0x34;
236 addr[2] = 0x56;
237 addr[3] = 0x78;
238 addr[4] = 0x9a;
239 addr[5] = 0xbc;
240 }
241 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]));
242 }
243
244
245 /*
246 * Tell add-on to enable multicast address
247 */
248
249 void AO_enable_multicast(uint8 *addr)
250 {
251 D(bug("AO_enable_multicast\n"));
252 if (net_open) {
253 net_packet *p = &net_buffer_ptr->write[wr_pos];
254 if (p->cmd & IN_USE) {
255 D(bug("WARNING: couldn't enable multicast address\n"));
256 } else {
257 memcpy(p->data, addr, 6);
258 p->length = 6;
259 p->cmd = IN_USE | (ADD_MULTICAST << 8);
260 wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
261 release_sem(write_sem);
262 }
263 }
264 }
265
266
267 /*
268 * Tell add-on to disable multicast address
269 */
270
271 void AO_disable_multicast(uint8 *addr)
272 {
273 D(bug("AO_disable_multicast\n"));
274 if (net_open) {
275 net_packet *p = &net_buffer_ptr->write[wr_pos];
276 if (p->cmd & IN_USE) {
277 D(bug("WARNING: couldn't enable multicast address\n"));
278 } else {
279 memcpy(p->data, addr, 6);
280 p->length = 6;
281 p->cmd = IN_USE | (REMOVE_MULTICAST << 8);
282 wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
283 release_sem(write_sem);
284 }
285 D(bug("WARNING: couldn't disable multicast address\n"));
286 }
287 }
288
289
290 /*
291 * Tell add-on to transmit one packet
292 */
293
294 void AO_transmit_packet(mblk_t *mp)
295 {
296 D(bug("AO_transmit_packet\n"));
297 if (net_open) {
298 net_packet *p = &net_buffer_ptr->write[wr_pos];
299 if (p->cmd & IN_USE) {
300 D(bug("WARNING: couldn't transmit packet (buffer full)\n"));
301 num_tx_buffer_full++;
302 } else {
303 D(bug(" write packet pos %d\n", i));
304 num_tx_packets++;
305
306 // Copy packet to buffer
307 uint8 *start;
308 uint8 *bp = start = p->data;
309 while (mp) {
310 uint32 size = mp->b_wptr - mp->b_rptr;
311 memcpy(bp, mp->b_rptr, size);
312 bp += size;
313 mp = mp->b_cont;
314 }
315
316 #if MONITOR
317 bug("Sending Ethernet packet:\n");
318 for (int i=0; i<(uint32)(bp - start); i++) {
319 bug("%02lx ", start[i]);
320 }
321 bug("\n");
322 #endif
323
324 // Notify add-on
325 p->length = (uint32)(bp - start);
326 p->cmd = IN_USE | (SHEEP_PACKET << 8);
327 wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
328 release_sem(write_sem);
329 }
330 }
331 }
332
333
334 /*
335 * Packet reception thread
336 */
337
338 static status_t AO_receive_thread(void *data)
339 {
340 while (ether_thread_active) {
341 if (net_buffer_ptr->read[rd_pos].cmd & IN_USE) {
342 if (ether_driver_opened) {
343 D(bug(" packet received, triggering Ethernet interrupt\n"));
344 SetInterruptFlag(INTFLAG_ETHER);
345 TriggerInterrupt();
346 }
347 }
348 acquire_sem_etc(read_sem, 1, B_TIMEOUT, 25000);
349 }
350 return 0;
351 }
352
353
354 /*
355 * Ethernet interrupt
356 */
357
358 void EtherIRQ(void)
359 {
360 D(bug("EtherIRQ\n"));
361 num_ether_irq++;
362 OTEnterInterrupt();
363
364 // Send received packets to OpenTransport
365 net_packet *p = &net_buffer_ptr->read[rd_pos];
366 while (p->cmd & IN_USE) {
367 if ((p->cmd >> 8) == SHEEP_PACKET) {
368 num_rx_packets++;
369 D(bug(" read packet pos %d\n", i));
370 uint32 size = p->length;
371
372 #if MONITOR
373 bug("Receiving Ethernet packet:\n");
374 for (int i=0; i<size; i++) {
375 bug("%02lx ", p->data[i]);
376 }
377 bug("\n");
378 #endif
379
380 // Wrap packet in message block
381 //!! maybe use esballoc()
382 mblk_t *mp;
383 if ((mp = allocb(size, 0)) != NULL) {
384 D(bug(" packet data at %p\n", mp->b_rptr));
385 memcpy(mp->b_rptr, p->data, size);
386 mp->b_wptr += size;
387 ether_packet_received(mp);
388 } else {
389 D(bug("WARNING: Cannot allocate mblk for received packet\n"));
390 num_rx_no_mem++;
391 }
392 }
393 p->cmd = 0; // Free packet
394 rd_pos = (rd_pos + 1) % READ_PACKET_COUNT;
395 p = &net_buffer_ptr->read[rd_pos];
396 }
397 OTLeaveInterrupt();
398 }