ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/Linux/ether_linux.cpp
Revision: 1.1.1.1 (vendor branch)
Committed: 2002-02-04T16:58:13Z (22 years, 5 months ago) by cebix
Branch: cebix
CVS Tags: start
Changes since 1.1: +0 -0 lines
Log Message:
Imported sources

File Contents

# Content
1 /*
2 * ether_linux.cpp - SheepShaver Ethernet Device Driver (DLPI), Linux specific stuff
3 *
4 * SheepShaver (C) 1997-2002 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 <pthread.h>
22 #include <semaphore.h>
23 #include <unistd.h>
24 #include <fcntl.h>
25 #include <errno.h>
26 #include <sys/ioctl.h>
27 #include <sys/poll.h>
28 #include <stdio.h>
29 #include <string.h>
30
31 #include "sysdeps.h"
32 #include "main.h"
33 #include "macos_util.h"
34 #include "prefs.h"
35 #include "user_strings.h"
36 #include "ether.h"
37 #include "ether_defs.h"
38
39 #define DEBUG 0
40 #include "debug.h"
41
42 #define STATISTICS 0
43 #define MONITOR 0
44
45
46 // Global variables
47 static int fd = -1; // fd of sheep_net device
48
49 static pthread_t ether_thread; // Packet reception thread
50 static bool thread_active = false; // Flag: Packet reception thread installed
51
52 static sem_t int_ack; // Interrupt acknowledge semaphore
53 static uint8 ether_addr[6]; // Our Ethernet address
54
55 static bool net_open = false; // Flag: initialization succeeded, network device open
56 static bool is_ethertap = false; // Flag: Ethernet device is ethertap
57
58
59 // Prototypes
60 static void *receive_func(void *arg);
61
62
63 /*
64 * Initialize ethernet
65 */
66
67 void EtherInit(void)
68 {
69 int nonblock = 1;
70 char str[256];
71
72 // Do nothing if the user disabled the network
73 if (PrefsFindBool("nonet"))
74 return;
75
76 // Do nothing if no Ethernet device specified
77 const char *name = PrefsFindString("ether");
78 if (name == NULL)
79 return;
80
81 // Is it Ethertap?
82 is_ethertap = (strncmp(name, "tap", 3) == 0);
83
84 // Open sheep_net or ethertap device
85 char dev_name[16];
86 if (is_ethertap)
87 sprintf(dev_name, "/dev/%s", name);
88 else
89 strcpy(dev_name, "/dev/sheep_net");
90 fd = open(dev_name, O_RDWR);
91 if (fd < 0) {
92 sprintf(str, GetString(STR_NO_SHEEP_NET_DRIVER_WARN), dev_name, strerror(errno));
93 WarningAlert(str);
94 goto open_error;
95 }
96
97 // Attach to selected Ethernet card
98 if (!is_ethertap && ioctl(fd, SIOCSIFLINK, name) < 0) {
99 sprintf(str, GetString(STR_SHEEP_NET_ATTACH_WARN), strerror(errno));
100 WarningAlert(str);
101 goto open_error;
102 }
103
104 // Set nonblocking I/O
105 ioctl(fd, FIONBIO, &nonblock);
106
107 // Get Ethernet address
108 if (is_ethertap) {
109 pid_t p = getpid(); // If configured for multicast, ethertap requires that the lower 32 bit of the Ethernet address are our PID
110 ether_addr[0] = 0xfe;
111 ether_addr[1] = 0xfd;
112 ether_addr[2] = p >> 24;
113 ether_addr[3] = p >> 16;
114 ether_addr[4] = p >> 8;
115 ether_addr[5] = p;
116 } else
117 ioctl(fd, SIOCGIFADDR, ether_addr);
118 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]));
119
120 // Start packet reception thread
121 if (sem_init(&int_ack, 0, 0) < 0) {
122 WarningAlert("WARNING: Cannot init semaphore");
123 goto open_error;
124 }
125 thread_active = (pthread_create(&ether_thread, NULL, receive_func, NULL) == 0);
126 if (!thread_active) {
127 WarningAlert("WARNING: Cannot start Ethernet thread");
128 goto open_error;
129 }
130
131 // Everything OK
132 net_open = true;
133 return;
134
135 open_error:
136 if (thread_active) {
137 pthread_cancel(ether_thread);
138 pthread_join(ether_thread, NULL);
139 sem_destroy(&int_ack);
140 thread_active = false;
141 }
142 if (fd > 0) {
143 close(fd);
144 fd = -1;
145 }
146 }
147
148
149 /*
150 * Exit ethernet
151 */
152
153 void EtherExit(void)
154 {
155 // Stop reception thread
156 if (thread_active) {
157 pthread_cancel(ether_thread);
158 pthread_join(ether_thread, NULL);
159 sem_destroy(&int_ack);
160 thread_active = false;
161 }
162
163 // Close sheep_net device
164 if (fd > 0)
165 close(fd);
166
167 #if STATISTICS
168 // Show statistics
169 printf("%ld messages put on write queue\n", num_wput);
170 printf("%ld error acks\n", num_error_acks);
171 printf("%ld packets transmitted (%ld raw, %ld normal)\n", num_tx_packets, num_tx_raw_packets, num_tx_normal_packets);
172 printf("%ld tx packets dropped because buffer full\n", num_tx_buffer_full);
173 printf("%ld packets received\n", num_rx_packets);
174 printf("%ld packets passed upstream (%ld Fast Path, %ld normal)\n", num_rx_fastpath + num_unitdata_ind, num_rx_fastpath, num_unitdata_ind);
175 printf("EtherIRQ called %ld times\n", num_ether_irq);
176 printf("%ld rx packets dropped due to low memory\n", num_rx_no_mem);
177 printf("%ld rx packets dropped because no stream found\n", num_rx_dropped);
178 printf("%ld rx packets dropped because stream not ready\n", num_rx_stream_not_ready);
179 printf("%ld rx packets dropped because no memory for unitdata_ind\n", num_rx_no_unitdata_mem);
180 #endif
181 }
182
183
184 /*
185 * Get ethernet hardware address
186 */
187
188 void AO_get_ethernet_address(uint8 *addr)
189 {
190 if (net_open) {
191 OTCopy48BitAddress(ether_addr, addr);
192 } else {
193 addr[0] = 0x12;
194 addr[1] = 0x34;
195 addr[2] = 0x56;
196 addr[3] = 0x78;
197 addr[4] = 0x9a;
198 addr[5] = 0xbc;
199 }
200 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]));
201 }
202
203
204 /*
205 * Enable multicast address
206 */
207
208 void AO_enable_multicast(uint8 *addr)
209 {
210 D(bug("AO_enable_multicast\n"));
211 if (net_open) {
212 if (ioctl(fd, SIOCADDMULTI, addr) < 0) {
213 D(bug("WARNING: couldn't enable multicast address\n"));
214 }
215 }
216 }
217
218
219 /*
220 * Disable multicast address
221 */
222
223 void AO_disable_multicast(uint8 *addr)
224 {
225 D(bug("AO_disable_multicast\n"));
226 if (net_open) {
227 if (ioctl(fd, SIOCDELMULTI, addr) < 0) {
228 D(bug("WARNING: couldn't disable multicast address\n"));
229 }
230 }
231 }
232
233
234 /*
235 * Transmit one packet
236 */
237
238 void AO_transmit_packet(mblk_t *mp)
239 {
240 D(bug("AO_transmit_packet\n"));
241 if (net_open) {
242
243 // Copy packet to buffer
244 uint8 packet[1516], *p = packet;
245 int len = 0;
246 if (is_ethertap) {
247 *p++ = 0; // Ethertap discards the first 2 bytes
248 *p++ = 0;
249 len += 2;
250 }
251 while (mp) {
252 uint32 size = mp->b_wptr - mp->b_rptr;
253 memcpy(p, mp->b_rptr, size);
254 len += size;
255 p += size;
256 mp = mp->b_cont;
257 }
258
259 #if MONITOR
260 bug("Sending Ethernet packet:\n");
261 for (int i=0; i<len; i++) {
262 bug("%02x ", packet[i]);
263 }
264 bug("\n");
265 #endif
266
267 // Transmit packet
268 if (write(fd, packet, len) < 0) {
269 D(bug("WARNING: couldn't transmit packet\n"));
270 num_tx_buffer_full++;
271 } else
272 num_tx_packets++;
273 }
274 }
275
276
277 /*
278 * Packet reception thread
279 */
280
281 static void *receive_func(void *arg)
282 {
283 for (;;) {
284
285 // Wait for packets to arrive
286 struct pollfd pf = {fd, POLLIN, 0};
287 int res = poll(&pf, 1, -1);
288 if (res <= 0)
289 break;
290
291 if (ether_driver_opened) {
292 // Trigger Ethernet interrupt
293 D(bug(" packet received, triggering Ethernet interrupt\n"));
294 SetInterruptFlag(INTFLAG_ETHER);
295 TriggerInterrupt();
296
297 // Wait for interrupt acknowledge by EtherInterrupt()
298 sem_wait(&int_ack);
299 } else
300 usleep(20000);
301 }
302 return NULL;
303 }
304
305
306 /*
307 * Ethernet interrupt
308 */
309
310 void EtherIRQ(void)
311 {
312 D(bug("EtherIRQ\n"));
313 num_ether_irq++;
314 OTEnterInterrupt();
315
316 // Send received packets to OpenTransport
317 uint8 packet[1516];
318 for (;;) {
319
320 if (is_ethertap) {
321
322 // Read packet from ethertap device
323 ssize_t size = read(fd, packet, 1516);
324 if (size < 14)
325 break;
326
327 #if MONITOR
328 bug("Receiving Ethernet packet:\n");
329 for (int i=0; i<size; i++) {
330 bug("%02x ", packet[i]);
331 }
332 bug("\n");
333 #endif
334
335 // Pointer to packet data (Ethernet header)
336 uint8 *p = packet + 2; // Ethertap has two random bytes before the packet
337 size -= 2;
338
339 // Wrap packet in message block
340 num_rx_packets++;
341 mblk_t *mp;
342 if ((mp = allocb(size, 0)) != NULL) {
343 D(bug(" packet data at %p\n", mp->b_rptr));
344 memcpy(mp->b_rptr, p, size);
345 mp->b_wptr += size;
346 ether_packet_received(mp);
347 } else {
348 D(bug("WARNING: Cannot allocate mblk for received packet\n"));
349 num_rx_no_mem++;
350 }
351
352 } else {
353
354 // Get size of first packet
355 int size = 0;
356 if (ioctl(fd, FIONREAD, &size) < 0 || size == 0)
357 break;
358
359 // Discard packets which are too short
360 if (size < 14) {
361 uint8 dummy[14];
362 read(fd, dummy, size);
363 continue;
364 }
365
366 // Truncate packets which are too long
367 if (size > 1514)
368 size = 1514;
369
370 // Read packet and wrap it in message block
371 num_rx_packets++;
372 mblk_t *mp;
373 if ((mp = allocb(size, 0)) != NULL) {
374 D(bug(" packet data at %p\n", mp->b_rptr));
375 read(fd, mp->b_rptr, 1514);
376 #if MONITOR
377 bug("Receiving Ethernet packet:\n");
378 for (int i=0; i<size; i++) {
379 bug("%02x ", ((uint8 *)mp->b_rptr)[i]);
380 }
381 bug("\n");
382 #endif
383 mp->b_wptr += size;
384 ether_packet_received(mp);
385 } else {
386 D(bug("WARNING: Cannot allocate mblk for received packet\n"));
387 num_rx_no_mem++;
388 }
389 }
390 }
391 OTLeaveInterrupt();
392
393 // Acknowledge interrupt to reception thread
394 D(bug(" EtherIRQ done\n"));
395 sem_post(&int_ack);
396 }