ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/ether.cpp
Revision: 1.4
Committed: 2004-05-10T16:16:26Z (20 years ago) by gbeauche
Branch: MAIN
Changes since 1.3: +4 -4 lines
Log Message:
Provide Mac_sysalloc() and Mac_sysfree() for memory allocation in MacOS
system heap zone. Use them for network related data dynamically allocated.

TODO: check performance in emulated mode!

File Contents

# Content
1 /*
2 * ether.cpp - SheepShaver Ethernet Device Driver (DLPI)
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 /*
22 * TODO
23 * - 802.2 TEST/XID
24 * - MIB statistics
25 */
26
27 #include <string.h>
28
29 #include "sysdeps.h"
30 #include "ether.h"
31 #include "ether_defs.h"
32 #include "macos_util.h"
33 #include "cpu_emulation.h"
34 #include "emul_op.h"
35 #include "main.h"
36
37 #define DEBUG 0
38 #include "debug.h"
39
40
41 // Packet types
42 enum {
43 kPktDIX = 0,
44 kPkt8022SAP = 1,
45 kPkt8022GroupSAP = 2,
46 kPkt8022SNAP = 3,
47 kPktIPX = 4,
48 kPktUnknown = 5
49 };
50
51
52 /*
53 * Stream private data structure
54 */
55
56 static const int kGroupSAPMapSize = 128/32; // Number of 32-bit values we need for 128 bits
57 static const int kGSshift = 6;
58 static const int kGSmask = 0x1F;
59
60 struct multicast_node {
61 nw_multicast_node_p next;
62 uint8 addr[kEnetPhysicalAddressLength];
63 };
64
65 struct DLPIStream {
66 void SetGroupSAP(uint8 sap)
67 {
68 group_sap[sap >> kGSshift] |= (1L << ((sap >> 1) & kGSmask));
69 }
70
71 void ClearGroupSAP(uint8 sap)
72 {
73 group_sap[sap >> kGSshift] &= ~(1L << ((sap >> 1) & kGSmask));
74 }
75
76 void ClearAllGroupSAPs(void)
77 {
78 for (int i=0; i<kGroupSAPMapSize; i++)
79 group_sap[i] = 0;
80 }
81
82 bool TestGroupSAP(uint8 sap)
83 {
84 return group_sap[sap >> kGSshift] & (1L << ((sap >> 1) & kGSmask));
85 }
86
87 void AddMulticast(uint8 *addr)
88 {
89 multicast_node *n = (multicast_node *)Mac_sysalloc(sizeof(multicast_node));
90 memcpy(n->addr, addr, kEnetPhysicalAddressLength);
91 n->next = multicast_list;
92 multicast_list = n;
93 }
94
95 void RemoveMulticast(uint8 *addr)
96 {
97 multicast_node *p = multicast_list;
98 while (p) {
99 if (memcmp(addr, p->addr, kEnetPhysicalAddressLength) == 0)
100 goto found;
101 p = p->next;
102 }
103 return;
104 found:
105 multicast_node *q = (multicast_node *)&multicast_list;
106 while (q) {
107 if (q->next == p) {
108 q->next = p->next;
109 Mac_sysfree(p);
110 return;
111 }
112 q = q->next;
113 }
114 }
115
116 uint8 *IsMulticastRegistered(uint8 *addr)
117 {
118 multicast_node *n = multicast_list;
119 while (n) {
120 if (memcmp(addr, n->addr, kEnetPhysicalAddressLength) == 0)
121 return n->addr;
122 n = n->next;
123 }
124 return NULL;
125 }
126
127 nw_uint32 minor_num; // Minor device number of this stream
128 nw_uint32 dlpi_state; // DLPI state of this stream
129 nw_uint32 flags; // Flags
130 nw_uint16 dlsap; // SAP bound to this stream
131 nw_bool framing_8022; // Using 802.2 framing? This is only used to report the MAC type for DL_INFO_ACK and can be set with an ioctl() call
132 nw_queue_p rdq; // Read queue for this stream
133 nw_uint32 group_sap[kGroupSAPMapSize]; // Map of bound group SAPs
134 uint8 snap[k8022SNAPLength]; // SNAP bound to this stream
135 nw_multicast_node_p multicast_list; // List of enabled multicast addresses
136 };
137
138 // Hack to make DLPIStream list initialization early to NULL (do we really need this?)
139 struct DLPIStreamInit {
140 DLPIStreamInit(nw_DLPIStream_p *dlpi_stream_p) { *dlpi_stream_p = NULL; }
141 };
142
143 // Stream flags
144 enum {
145 kSnapStream = 0x00000001,
146 kAcceptMulticasts = 0x00000002,
147 kAcceptAll8022Packets = 0x00000004,
148 kFastPathMode = 0x00000008
149 };
150
151 // List of opened streams (used internally by OpenTransport)
152 static nw_DLPIStream_p dlpi_stream_list;
153 static DLPIStreamInit dlpi_stream_init(&dlpi_stream_list);
154
155 // Are we open?
156 bool ether_driver_opened = false;
157
158 // Our ethernet hardware address
159 static uint8 hardware_address[6] = {0, 0, 0, 0, 0, 0};
160
161 // Statistics
162 int32 num_wput = 0;
163 int32 num_error_acks = 0;
164 int32 num_tx_packets = 0;
165 int32 num_tx_raw_packets = 0;
166 int32 num_tx_normal_packets = 0;
167 int32 num_tx_buffer_full = 0;
168 int32 num_rx_packets = 0;
169 int32 num_ether_irq = 0;
170 int32 num_unitdata_ind = 0;
171 int32 num_rx_fastpath = 0;
172 int32 num_rx_no_mem = 0;
173 int32 num_rx_dropped = 0;
174 int32 num_rx_stream_not_ready = 0;
175 int32 num_rx_no_unitdata_mem = 0;
176
177
178 // Function pointers of imported functions
179 typedef mblk_t *(*allocb_ptr)(size_t size, int pri);
180 static uint32 allocb_tvect = 0;
181 mblk_t *allocb(size_t arg1, int arg2)
182 {
183 return (mblk_t *)CallMacOS2(allocb_ptr, allocb_tvect, arg1, arg2);
184 }
185 typedef void (*freeb_ptr)(mblk_t *);
186 static uint32 freeb_tvect = 0;
187 static inline void freeb(mblk_t *arg1)
188 {
189 CallMacOS1(freeb_ptr, freeb_tvect, arg1);
190 }
191 typedef int16 (*freemsg_ptr)(mblk_t *);
192 static uint32 freemsg_tvect = 0;
193 static inline int16 freemsg(mblk_t *arg1)
194 {
195 return (int16)CallMacOS1(freemsg_ptr, freemsg_tvect, arg1);
196 }
197 typedef mblk_t *(*copyb_ptr)(mblk_t *);
198 static uint32 copyb_tvect = 0;
199 static inline mblk_t *copyb(mblk_t *arg1)
200 {
201 return (mblk_t *)CallMacOS1(copyb_ptr, copyb_tvect, arg1);
202 }
203 typedef mblk_t *(*dupmsg_ptr)(mblk_t *);
204 static uint32 dupmsg_tvect = 0;
205 static inline mblk_t *dupmsg(mblk_t *arg1)
206 {
207 return (mblk_t *)CallMacOS1(dupmsg_ptr, dupmsg_tvect, arg1);
208 }
209 typedef mblk_t *(*getq_ptr)(queue_t *);
210 static uint32 getq_tvect = 0;
211 static inline mblk_t *getq(queue_t *arg1)
212 {
213 return (mblk_t *)CallMacOS1(getq_ptr, getq_tvect, arg1);
214 }
215 typedef int (*putq_ptr)(queue_t *, mblk_t *);
216 static uint32 putq_tvect = 0;
217 static inline int putq(queue_t *arg1, mblk_t *arg2)
218 {
219 return (int)CallMacOS2(putq_ptr, putq_tvect, arg1, arg2);
220 }
221 typedef int (*putnext_ptr)(queue_t *, mblk_t *);
222 static uint32 putnext_tvect = 0;
223 static inline int putnext(queue_t *arg1, mblk_t *arg2)
224 {
225 return (int)CallMacOS2(putnext_ptr, putnext_tvect, arg1, arg2);
226 }
227 typedef int (*putnextctl1_ptr)(queue_t *, int type, int c);
228 static uint32 putnextctl1_tvect = 0;
229 static inline int putnextctl1(queue_t *arg1, int arg2, int arg3)
230 {
231 return (int)CallMacOS3(putnextctl1_ptr, putnextctl1_tvect, arg1, arg2, arg3);
232 }
233 typedef int (*canputnext_ptr)(queue_t *);
234 static uint32 canputnext_tvect = 0;
235 static inline int canputnext(queue_t *arg1)
236 {
237 return (int)CallMacOS1(canputnext_ptr, canputnext_tvect, arg1);
238 }
239 typedef int (*qreply_ptr)(queue_t *, mblk_t *);
240 static uint32 qreply_tvect = 0;
241 static inline int qreply(queue_t *arg1, mblk_t *arg2)
242 {
243 return (int)CallMacOS2(qreply_ptr, qreply_tvect, arg1, arg2);
244 }
245 typedef void (*flushq_ptr)(queue_t *, int flag);
246 static uint32 flushq_tvect = 0;
247 static inline void flushq(queue_t *arg1, int arg2)
248 {
249 CallMacOS2(flushq_ptr, flushq_tvect, arg1, arg2);
250 }
251 typedef int (*msgdsize_ptr)(const mblk_t *);
252 static uint32 msgdsize_tvect = 0;
253 static inline int msgdsize(const mblk_t *arg1)
254 {
255 return (int)CallMacOS1(msgdsize_ptr, msgdsize_tvect, arg1);
256 }
257 typedef void (*otenterint_ptr)(void);
258 static uint32 otenterint_tvect = 0;
259 void OTEnterInterrupt(void)
260 {
261 CallMacOS(otenterint_ptr, otenterint_tvect);
262 }
263 typedef void (*otleaveint_ptr)(void);
264 static uint32 otleaveint_tvect = 0;
265 void OTLeaveInterrupt(void)
266 {
267 CallMacOS(otleaveint_ptr, otleaveint_tvect);
268 }
269 typedef int (*mi_open_comm_ptr)(DLPIStream **mi_opp_orig, size_t size, queue_t *q, void *dev, int flag, int sflag, void *credp);
270 static uint32 mi_open_comm_tvect = 0;
271 static inline int mi_open_comm(DLPIStream **arg1, size_t arg2, queue_t *arg3, void *arg4, int arg5, int arg6, void *arg7)
272 {
273 return (int)CallMacOS7(mi_open_comm_ptr, mi_open_comm_tvect, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
274 }
275 typedef int (*mi_close_comm_ptr)(DLPIStream **mi_opp_orig, queue_t *q);
276 static uint32 mi_close_comm_tvect = 0;
277 static inline int mi_close_comm(DLPIStream **arg1, queue_t *arg2)
278 {
279 return (int)CallMacOS2(mi_close_comm_ptr, mi_close_comm_tvect, arg1, arg2);
280 }
281 typedef DLPIStream *(*mi_next_ptr_ptr)(DLPIStream *);
282 static uint32 mi_next_ptr_tvect = 0;
283 static inline DLPIStream *mi_next_ptr(DLPIStream *arg1)
284 {
285 return (DLPIStream *)CallMacOS1(mi_next_ptr_ptr, mi_next_ptr_tvect, arg1);
286 }
287
288
289 // Prototypes
290 static void ether_ioctl(DLPIStream *the_stream, queue_t* q, mblk_t* mp);
291 static void ether_flush(queue_t* q, mblk_t* mp);
292 static mblk_t *build_tx_packet_header(DLPIStream *the_stream, mblk_t *mp, bool fast_path);
293 static void transmit_packet(mblk_t *mp);
294 static void DLPI_error_ack(DLPIStream *the_stream, queue_t *q, mblk_t *ack_mp, uint32 prim, uint32 err, uint32 uerr);
295 static void DLPI_ok_ack(DLPIStream *the_stream, queue_t *q, mblk_t *ack_mp, uint32 prim);
296 static void DLPI_info(DLPIStream *the_stream, queue_t *q, mblk_t *mp);
297 static void DLPI_phys_addr(DLPIStream *the_stream, queue_t *q, mblk_t *mp);
298 static void DLPI_bind(DLPIStream *the_stream, queue_t *q, mblk_t *mp);
299 static void DLPI_unbind(DLPIStream *the_stream, queue_t *q, mblk_t *mp);
300 static void DLPI_subs_bind(DLPIStream *the_stream, queue_t *q, mblk_t *mp);
301 static void DLPI_subs_unbind(DLPIStream *the_stream, queue_t *q, mblk_t *mp);
302 static void DLPI_enable_multi(DLPIStream *the_stream, queue_t *q, mblk_t *mp);
303 static void DLPI_disable_multi(DLPIStream *the_stream, queue_t *q, mblk_t *mp);
304 static void DLPI_unit_data(DLPIStream *the_stream, queue_t *q, mblk_t *mp);
305
306
307 /*
308 * Initialize ethernet stream module
309 */
310
311 uint8 InitStreamModule(void *theID)
312 {
313 D(bug("InitStreamModule\n"));
314
315 // Don't re-open if already open
316 if (ether_driver_opened)
317 return true;
318 ether_driver_opened = false;
319
320 // Import functions from OTKernelLib
321 allocb_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\006allocb");
322 D(bug("allocb TVECT at %08lx\n", allocb_tvect));
323 if (allocb_tvect == 0)
324 return false;
325 freeb_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\005freeb");
326 D(bug("freeb TVECT at %08lx\n", freeb_tvect));
327 if (freeb_tvect == 0)
328 return false;
329 freemsg_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\007freemsg");
330 D(bug("freemsg TVECT at %08lx\n", freemsg_tvect));
331 if (freemsg_tvect == 0)
332 return false;
333 copyb_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\005copyb");
334 D(bug("copyb TVECT at %08lx\n", copyb_tvect));
335 if (copyb_tvect == 0)
336 return false;
337 dupmsg_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\006dupmsg");
338 D(bug("dupmsg TVECT at %08lx\n", dupmsg_tvect));
339 if (dupmsg_tvect == 0)
340 return false;
341 getq_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\004getq");
342 D(bug("getq TVECT at %08lx\n", getq_tvect));
343 if (getq_tvect == 0)
344 return false;
345 putq_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\004putq");
346 D(bug("putq TVECT at %08lx\n", putq_tvect));
347 if (putq_tvect == 0)
348 return false;
349 putnext_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\007putnext");
350 D(bug("putnext TVECT at %08lx\n", putnext_tvect));
351 if (putnext_tvect == 0)
352 return false;
353 putnextctl1_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\013putnextctl1");
354 D(bug("putnextctl1 TVECT at %08lx\n", putnextctl1_tvect));
355 if (putnextctl1_tvect == 0)
356 return false;
357 canputnext_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\012canputnext");
358 D(bug("canputnext TVECT at %08lx\n", canputnext_tvect));
359 if (canputnext_tvect == 0)
360 return false;
361 qreply_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\006qreply");
362 D(bug("qreply TVECT at %08lx\n", qreply_tvect));
363 if (qreply_tvect == 0)
364 return false;
365 flushq_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\006flushq");
366 D(bug("flushq TVECT at %08lx\n", flushq_tvect));
367 if (flushq_tvect == 0)
368 return false;
369 msgdsize_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\010msgdsize");
370 D(bug("msgdsize TVECT at %08lx\n", msgdsize_tvect));
371 if (msgdsize_tvect == 0)
372 return false;
373 otenterint_tvect = (uint32)FindLibSymbol("\017OTKernelUtilLib", "\020OTEnterInterrupt");
374 D(bug("OTEnterInterrupt TVECT at %08lx\n", otenterint_tvect));
375 if (otenterint_tvect == 0)
376 return false;
377 otleaveint_tvect = (uint32)FindLibSymbol("\017OTKernelUtilLib", "\020OTLeaveInterrupt");
378 D(bug("OTLeaveInterrupt TVECT at %08lx\n", otleaveint_tvect));
379 if (otleaveint_tvect == 0)
380 return false;
381 mi_open_comm_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\014mi_open_comm");
382 D(bug("mi_open_comm TVECT at %08lx\n", mi_open_comm_tvect));
383 if (mi_open_comm_tvect == 0)
384 return false;
385 mi_close_comm_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\015mi_close_comm");
386 D(bug("mi_close_comm TVECT at %08lx\n", mi_close_comm_tvect));
387 if (mi_close_comm_tvect == 0)
388 return false;
389 mi_next_ptr_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\013mi_next_ptr");
390 D(bug("mi_next_ptr TVECT at %08lx\n", mi_next_ptr_tvect));
391 if (mi_next_ptr_tvect == 0)
392 return false;
393
394 // Initialize stream list (which might be leftover)
395 dlpi_stream_list = NULL;
396
397 // Ask add-on for ethernet hardware address
398 AO_get_ethernet_address(hardware_address);
399
400 // Yes, we're open
401 ether_driver_opened = true;
402 return true;
403 }
404
405
406 /*
407 * Terminate ethernet stream module
408 */
409
410 void TerminateStreamModule(void)
411 {
412 D(bug("TerminateStreamModule\n"));
413
414 // This happens sometimes. I don't know why.
415 if (dlpi_stream_list != NULL)
416 printf("FATAL: TerminateStreamModule() called, but streams still open\n");
417
418 // Sorry, we're closed
419 ether_driver_opened = false;
420 }
421
422
423 /*
424 * Open new stream
425 */
426
427 int ether_open(queue_t *rdq, void *dev, int flag, int sflag, void *creds)
428 {
429 D(bug("ether_open(%p,%p,%d,%d,%p)\n", rdq, dev, flag, sflag, creds));
430
431 // Return if driver was closed
432 if (!ether_driver_opened) {
433 printf("FATAL: ether_open(): Ethernet driver not opened\n");
434 return MAC_ENXIO;
435 }
436
437 // If we're being reopened, just return
438 if (rdq->q_ptr != NULL)
439 return 0;
440
441 // Allocate DLPIStream structure
442 int err = mi_open_comm((DLPIStream **)&dlpi_stream_list, sizeof(DLPIStream), rdq, dev, flag, sflag, creds);
443 if (err)
444 return err;
445 DLPIStream *the_stream = (DLPIStream *)rdq->q_ptr;
446 the_stream->rdq = rdq;
447 the_stream->dlpi_state = DL_UNBOUND;
448 the_stream->flags = 0;
449 the_stream->dlsap = 0;
450 the_stream->framing_8022 = false;
451 the_stream->multicast_list = NULL;
452 return 0;
453 }
454
455
456 /*
457 * Close stream
458 */
459
460 int ether_close(queue_t *rdq, int flag, void *creds)
461 {
462 D(bug("ether_close(%p,%d,%p)\n", rdq, flag, creds));
463
464 // Return if driver was closed
465 if (!ether_driver_opened) {
466 printf("FATAL: ether_close(): Ethernet driver not opened\n");
467 return MAC_ENXIO;
468 }
469
470 // Get stream
471 DLPIStream *the_stream = (DLPIStream *)rdq->q_ptr;
472
473 // Don't close if never opened
474 if (the_stream == NULL)
475 return 0;
476
477 // Disable all registered multicast addresses
478 while (the_stream->multicast_list) {
479 AO_disable_multicast(the_stream->multicast_list->addr);
480 the_stream->RemoveMulticast(the_stream->multicast_list->addr);
481 }
482 the_stream->multicast_list = NULL;
483
484 // Delete the DLPIStream
485 return mi_close_comm((DLPIStream **)&dlpi_stream_list, rdq);
486 }
487
488
489 /*
490 * Put something on the write queue
491 */
492
493 int ether_wput(queue_t *q, mblk_t *mp)
494 {
495 D(bug("ether_wput(%p,%p)\n", q, mp));
496
497 // Return if driver was closed
498 if (!ether_driver_opened) {
499 printf("FATAL: ether_wput(): Ethernet driver not opened\n");
500 return MAC_ENXIO;
501 }
502
503 // Get stream
504 DLPIStream *the_stream = (DLPIStream *)q->q_ptr;
505 if (the_stream == NULL)
506 return MAC_ENXIO;
507
508 D(bug(" db_type %d\n", (int)mp->b_datap->db_type));
509 switch (mp->b_datap->db_type) {
510
511 case M_DATA:
512 // Transmit raw packet
513 D(bug(" raw packet\n"));
514 num_tx_raw_packets++;
515 transmit_packet(mp);
516 break;
517
518 case M_PROTO:
519 case M_PCPROTO: {
520 union DL_primitives *dlp = (union DL_primitives *)(void *)mp->b_rptr;
521 uint32 prim = dlp->dl_primitive;
522 D(bug(" dl_primitive %d\n", prim));
523 switch (prim) {
524 case DL_UNITDATA_REQ:
525 // Transmit normal packet
526 num_tx_normal_packets++;
527 DLPI_unit_data(the_stream, q, mp);
528 break;
529
530 case DL_INFO_REQ:
531 DLPI_info(the_stream, q, mp);
532 break;
533
534 case DL_PHYS_ADDR_REQ:
535 DLPI_phys_addr(the_stream, q, mp);
536 break;
537
538 case DL_BIND_REQ:
539 DLPI_bind(the_stream, q, mp);
540 break;
541
542 case DL_UNBIND_REQ:
543 DLPI_unbind(the_stream, q, mp);
544 break;
545
546 case DL_SUBS_BIND_REQ:
547 DLPI_subs_bind(the_stream, q, mp);
548 break;
549
550 case DL_SUBS_UNBIND_REQ:
551 DLPI_subs_unbind(the_stream, q, mp);
552 break;
553
554 case DL_ENABMULTI_REQ:
555 DLPI_enable_multi(the_stream, q, mp);
556 break;
557
558 case DL_DISABMULTI_REQ:
559 DLPI_disable_multi(the_stream, q, mp);
560 break;
561
562 default:
563 D(bug("WARNING: ether_wsrv(): Unknown primitive\n"));
564 DLPI_error_ack(the_stream, q, mp, prim, DL_NOTSUPPORTED, 0);
565 break;
566 }
567 break;
568 }
569
570 case M_IOCTL:
571 ether_ioctl(the_stream, q, mp);
572 break;
573
574 case M_FLUSH:
575 ether_flush(q, mp);
576 break;
577
578 default:
579 D(bug("WARNING: ether_wput(): Unknown message type\n"));
580 freemsg(mp);
581 break;
582 }
583 num_wput++;
584 return 0;
585 }
586
587
588 /*
589 * Dequeue and process messages from the read queue
590 */
591
592 int ether_rsrv(queue_t *q)
593 {
594 mblk_t *mp;
595 while ((mp = getq(q)) != NULL) {
596 if (canputnext(q))
597 putnext(q, mp);
598 else {
599 freemsg(mp);
600 flushq(q, FLUSHDATA);
601 break;
602 }
603 }
604 return 0;
605 }
606
607
608 /*
609 * Handle ioctl calls
610 */
611
612 static void ether_ioctl(DLPIStream *the_stream, queue_t *q, mblk_t *mp)
613 {
614 struct iocblk *ioc = (struct iocblk *)(void *)mp->b_rptr;
615 D(bug(" ether_ioctl(%p,%p) cmd %d\n", q, mp, (int)ioc->ioc_cmd));
616
617 switch (ioc->ioc_cmd) {
618
619 case I_OTSetFramingType: { // Toggles what the general info primitive returns for dl_mac_type in dl_info_ack_t structure
620 mblk_t *info_mp = mp->b_cont;
621 if (info_mp == NULL || ((info_mp->b_wptr - info_mp->b_rptr) != sizeof(uint32))) {
622 ioc->ioc_error = MAC_EINVAL;
623 goto ioctl_error;
624 }
625 uint32 framing_type = ntohl(*(uint32 *)(void *)info_mp->b_rptr);
626 D(bug(" I_OTSetFramingType type %d\n", framing_type));
627 if (framing_type != kOTGetFramingValue)
628 the_stream->framing_8022 = (framing_type == kOTFraming8022);
629 mp->b_cont = NULL;
630 freemsg(info_mp);
631 if (the_stream->framing_8022)
632 ioc->ioc_rval = kOTFraming8022;
633 else
634 ioc->ioc_rval = kOTFramingEthernet;
635 goto ioctl_ok;
636 }
637
638 case DL_IOC_HDR_INFO: { // Special Mentat call, for fast transmits
639 D(bug(" DL_IOC_HDR_INFO\n"));
640 mblk_t *info_mp = mp->b_cont;
641
642 // Copy DL_UNITDATA_REQ block
643 mblk_t *unitdata_mp = copyb(info_mp);
644 if (unitdata_mp == NULL) {
645 ioc->ioc_error = MAC_ENOMEM;
646 goto ioctl_error;
647 }
648 unitdata_mp->b_datap->db_type = M_PROTO;
649
650 // Construct header (converts DL_UNITDATA_REQ -> M_DATA)
651 mblk_t *header_mp = build_tx_packet_header(the_stream, unitdata_mp, true);
652
653 if (header_mp == NULL) {
654 // Could not allocate a message block large enough
655 ioc->ioc_error = MAC_ENOMEM;
656 goto ioctl_error;
657 }
658
659 // Attach header block at the end
660 mp->b_cont->b_cont = header_mp;
661 the_stream->flags |= kFastPathMode;
662 goto ioctl_ok;
663 }
664
665 case I_OTSetRawMode: {
666 mblk_t *info_mp = mp->b_cont;
667 dl_recv_control_t *dlrc;
668 if (info_mp == NULL || ((info_mp->b_wptr - info_mp->b_rptr) != sizeof(dlrc->dl_primitive))) {
669 ioc->ioc_error = MAC_EINVAL;
670 goto ioctl_error;
671 }
672 dlrc = (dl_recv_control_t *)(void *)info_mp->b_rptr;
673 D(bug(" I_OTSetRawMode primitive %d\n", (int)dlrc->dl_primitive));
674 ioc->ioc_error = MAC_EINVAL;
675 goto ioctl_error;
676 }
677
678 default:
679 D(bug("WARNING: Unknown ether_ioctl() call\n"));
680 ioc->ioc_error = MAC_EINVAL;
681 goto ioctl_error;
682 }
683
684 ioctl_ok:
685 ioc->ioc_count = 0;
686 for (mblk_t *mp1 = mp; (mp1 = mp1->b_cont) != NULL;)
687 ioc->ioc_count += mp1->b_wptr - mp1->b_rptr;
688 ioc->ioc_error = 0;
689 mp->b_datap->db_type = M_IOCACK;
690 qreply(q, mp);
691 return;
692
693 ioctl_error:
694 mp->b_datap->db_type = M_IOCNAK;
695 qreply(q, mp);
696 return;
697 }
698
699
700 /*
701 * Flush call, send it up to the read side of the stream
702 */
703
704 static void ether_flush(queue_t* q, mblk_t* mp)
705 {
706 D(bug(" ether_flush(%p,%p)\n", q, mp));
707
708 uint8 *rptr = mp->b_rptr;
709 if (*rptr & FLUSHW)
710 flushq(q, FLUSHALL);
711 if (*rptr & FLUSHR) {
712 flushq(RD(q), FLUSHALL);
713 *rptr &= ~FLUSHW;
714 qreply(q, mp);
715 } else
716 freemsg(mp);
717 }
718
719
720 /*
721 * Classify packet into the different types of protocols
722 */
723
724 static uint16 classify_packet_type(uint16 primarySAP, uint16 secondarySAP)
725 {
726 if (primarySAP >= kMinDIXSAP)
727 return kPktDIX;
728
729 if ((primarySAP == kIPXSAP) && (secondarySAP == kIPXSAP))
730 return kPktIPX;
731
732 if (primarySAP == kSNAPSAP)
733 return kPkt8022SNAP;
734
735 if (primarySAP <= k8022GlobalSAP)
736 return kPkt8022SAP;
737
738 return kPktUnknown;
739 }
740
741
742 /*
743 * Check if the address is a multicast, broadcast or standard address
744 */
745
746 static int32 get_address_type(uint8 *addr)
747 {
748 if (addr[0] & 1) { // Multicast/broadcast flag
749 if (OTIs48BitBroadcastAddress(addr))
750 return keaBroadcast;
751 else
752 return keaMulticast;
753 } else
754 return keaStandardAddress;
755 }
756
757
758 /*
759 * Reuse a message block, make room for more data
760 */
761
762 static mblk_t *reuse_message_block(mblk_t *mp, uint16 needed_size)
763 {
764 mblk_t *nmp;
765
766 if ((mp->b_datap->db_ref == 1) && ((mp->b_datap->db_lim - mp->b_datap->db_base) >= needed_size)) {
767 mp->b_datap->db_type = M_DATA;
768 mp->b_rptr = mp->b_datap->db_base;
769 mp->b_wptr = mp->b_datap->db_base + needed_size;
770 } else {
771 nmp = mp->b_cont; // Grab the M_DATA blocks
772 mp->b_cont = NULL; // Detach the M_(PC)PROTO
773 freemsg(mp); // Free the M_(PC)PROTO
774 mp = nmp; // Point to the M_DATA blocks
775
776 // Try to get space on the first M_DATA block
777 if (mp && (mp->b_datap->db_ref == 1) && ((mp->b_rptr - mp->b_datap->db_base) >= needed_size))
778 mp->b_rptr -= needed_size;
779 else {
780 // Try to allocate a new message
781 if ((nmp = allocb(needed_size, BPRI_HI)) == NULL) {
782 // Could not get a new message block so lets forget about the message altogether
783 freemsg(mp); // Free the original M_DATA portion of the message
784 mp = NULL; // Indicates the reuse failed
785 } else {
786 nmp->b_cont = mp; // Attach the new message block as the head
787 nmp->b_wptr += needed_size;
788 mp = nmp;
789 }
790 }
791 }
792
793 return mp;
794 }
795
796
797 /*
798 * Built header for packet to be transmitted (convert DL_UNITDATA_REQ -> M_DATA)
799 * The passed-in message has the header info in the first message block and the data
800 * in the following blocks
801 */
802
803 static mblk_t *build_tx_packet_header(DLPIStream *the_stream, mblk_t *mp, bool fast_path)
804 {
805 // Only handle unit_data requests
806 dl_unitdata_req_t *req = (dl_unitdata_req_t *)(void *)mp->b_rptr;
807 if (req->dl_primitive != DL_UNITDATA_REQ) {
808 freemsg(mp);
809 return NULL;
810 }
811
812 // Extract destination address and its length
813 uint8 *destAddrOrig = ((uint8 *)req) + req->dl_dest_addr_offset;
814 uint32 destAddrLen = req->dl_dest_addr_length;
815 uint8 ctrl = 0x03;
816
817 // Extract DLSAP
818 uint16 dlsap;
819 switch (destAddrLen) {
820 case kEnetPhysicalAddressLength:
821 dlsap = the_stream->dlsap;
822 break;
823 case kEnetAndSAPAddressLength:
824 dlsap = ntohs(*(uint16 *)(destAddrOrig + kEnetPhysicalAddressLength));
825 break;
826 case kEnetPhysicalAddressLength + k8022DLSAPLength + k8022SNAPLength: // SNAP SAP
827 dlsap = ntohs(*(uint16 *)(destAddrOrig + kEnetPhysicalAddressLength));
828 break;
829 default:
830 dlsap = the_stream->dlsap;
831 break;
832 }
833
834 // Extract data size (excluding header info) and packet type
835 uint16 datasize = msgdsize(mp);
836 uint16 packetType = classify_packet_type(the_stream->dlsap, dlsap);
837
838 // Calculate header size and protocol type/size field
839 uint16 hdrsize, proto;
840 switch (packetType) {
841 case kPktDIX:
842 hdrsize = kEnetPacketHeaderLength;
843 proto = dlsap;
844 break;
845 case kPkt8022SAP:
846 hdrsize = kEnetPacketHeaderLength + k8022BasicHeaderLength;
847 if (fast_path)
848 proto = 0;
849 else
850 proto = datasize + k8022BasicHeaderLength;
851 break;
852 case kPkt8022SNAP:
853 hdrsize = kEnetPacketHeaderLength + k8022SNAPHeaderLength;
854 if (fast_path)
855 proto = 0;
856 else
857 proto = datasize + k8022SNAPHeaderLength;
858 break;
859 case kPktIPX:
860 hdrsize = kEnetPacketHeaderLength;
861 if (fast_path)
862 proto = 0;
863 else
864 proto = datasize;
865 break;
866 default:
867 hdrsize = kEnetPacketHeaderLength;
868 proto = dlsap;
869 break;
870 }
871
872 // We need to copy the dest address info in the message before we can reuse it
873 uint8 destAddrCopy[kMaxBoundAddrLength];
874 memcpy(destAddrCopy, destAddrOrig, destAddrLen);
875
876 // Resize header info in message block
877 if ((mp = reuse_message_block(mp, hdrsize)) == NULL)
878 return NULL;
879 struct T8022FullPacketHeader *packetHeader = (struct T8022FullPacketHeader *)(void *)mp->b_rptr;
880
881 // Set protocol type/size field
882 packetHeader->fEnetPart.fProto = proto;
883
884 // Set destination ethernet address
885 OTCopy48BitAddress(destAddrCopy, packetHeader->fEnetPart.fDestAddr);
886
887 // Set other header fields
888 switch (packetType) {
889 case kPkt8022SAP:
890 packetHeader->f8022Part.fDSAP = (uint8)dlsap;
891 packetHeader->f8022Part.fSSAP = (uint8)the_stream->dlsap;
892 packetHeader->f8022Part.fCtrl = ctrl;
893 break;
894 case kPkt8022SNAP: {
895 uint8 *snapStart;
896 packetHeader->f8022Part.fDSAP = (uint8)dlsap;
897 packetHeader->f8022Part.fSSAP = (uint8)the_stream->dlsap;
898 packetHeader->f8022Part.fCtrl = ctrl;
899 if (destAddrLen >= kEnetAndSAPAddressLength + k8022SNAPLength)
900 snapStart = destAddrCopy + kEnetAndSAPAddressLength;
901 else
902 snapStart = the_stream->snap;
903 OTCopy8022SNAP(snapStart, packetHeader->f8022Part.fSNAP);
904 break;
905 }
906 }
907
908 // Return updated message
909 return mp;
910 }
911
912
913 /*
914 * Transmit packet
915 */
916
917 static void transmit_packet(mblk_t *mp)
918 {
919 EnetPacketHeader *enetHeader = (EnetPacketHeader *)(void *)mp->b_rptr;
920
921 // Fill in length in 802.3 packets
922 if (enetHeader->fProto == 0)
923 enetHeader->fProto = msgdsize(mp) - sizeof(EnetPacketHeader);
924
925 // Fill in ethernet source address
926 OTCopy48BitAddress(hardware_address, enetHeader->fSourceAddr);
927
928 // Tell add-on to transmit packet
929 AO_transmit_packet(mp);
930 freemsg(mp);
931 }
932
933
934 /*
935 * Handle incoming packet (one stream), construct DL_UNITDATA_IND message
936 */
937
938 static void handle_received_packet(DLPIStream *the_stream, mblk_t *mp, uint16 packet_type, int32 dest_addr_type)
939 {
940 // Find address and header length
941 uint32 addr_len;
942 uint32 header_len;
943 switch (packet_type) {
944 case kPkt8022SAP:
945 addr_len = kEnetAndSAPAddressLength;
946 header_len = kEnetPacketHeaderLength + k8022BasicHeaderLength;
947 break;
948 case kPkt8022SNAP:
949 addr_len = kEnetAndSAPAddressLength + k8022SNAPLength;
950 header_len = kEnetPacketHeaderLength + k8022SNAPHeaderLength;
951 break;
952 default: // DIX and IPX
953 addr_len = kEnetAndSAPAddressLength;
954 header_len = kEnetPacketHeaderLength;
955 break;
956 }
957
958 // In Fast Path mode, don't send DL_UNITDATA_IND messages for unicast packets
959 if ((the_stream->flags & kFastPathMode) && dest_addr_type == keaStandardAddress) {
960 mp->b_rptr += header_len;
961 num_rx_fastpath++;
962 putq(the_stream->rdq, mp);
963 return;
964 }
965
966 // Allocate the dl_unitdata_ind_t message
967 mblk_t *nmp;
968 if ((nmp = allocb(sizeof(dl_unitdata_ind_t) + 2*addr_len, BPRI_HI)) == NULL) {
969 freemsg(mp);
970 num_rx_no_unitdata_mem++;
971 return;
972 }
973
974 // Set message type
975 nmp->b_datap->db_type = M_PROTO;
976 dl_unitdata_ind_t *ind = (dl_unitdata_ind_t*)(void *)nmp->b_rptr;
977 ind->dl_primitive = DL_UNITDATA_IND;
978 nmp->b_wptr += (sizeof(dl_unitdata_ind_t) + 2*addr_len);
979
980 // Link M_DATA block
981 nmp->b_cont = mp;
982
983 // Set address fields
984 ind->dl_dest_addr_length = addr_len;
985 ind->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
986 ind->dl_src_addr_length = addr_len;
987 ind->dl_src_addr_offset = sizeof(dl_unitdata_ind_t) + addr_len;
988
989 // Set address type
990 ind->dl_group_address = dest_addr_type;
991
992 // Set address fields
993 T8022FullPacketHeader *packetHeader = (T8022FullPacketHeader *)(void *)mp->b_rptr;
994 T8022AddressStruct *destAddr = ((T8022AddressStruct*)(nmp->b_rptr + ind->dl_dest_addr_offset));
995 T8022AddressStruct *srcAddr = ((T8022AddressStruct*)(nmp->b_rptr + ind->dl_src_addr_offset));
996
997 OTCopy48BitAddress(packetHeader->fEnetPart.fDestAddr, destAddr->fHWAddr);
998 OTCopy48BitAddress(packetHeader->fEnetPart.fSourceAddr, srcAddr->fHWAddr);
999
1000 destAddr->fSAP = packetHeader->f8022Part.fDSAP;
1001 srcAddr->fSAP = packetHeader->f8022Part.fSSAP;
1002
1003 if (packet_type == kPkt8022SNAP) {
1004 OTCopy8022SNAP(packetHeader->f8022Part.fSNAP, destAddr->fSNAP);
1005 OTCopy8022SNAP(packetHeader->f8022Part.fSNAP, srcAddr->fSNAP);
1006 }
1007
1008 // "Hide" the ethernet and protocol header(s)
1009 mp->b_rptr += header_len;
1010
1011 // Pass message up the stream
1012 num_unitdata_ind++;
1013 putq(the_stream->rdq, nmp);
1014 return;
1015 }
1016
1017
1018 /*
1019 * Packet received, distribute it to the streams that want it
1020 */
1021
1022 void ether_packet_received(mblk_t *mp)
1023 {
1024 // Extract address and types
1025 EnetPacketHeader *pkt = (EnetPacketHeader *)(void *)mp->b_rptr;
1026 T8022FullPacketHeader *fullpkt = (T8022FullPacketHeader *)pkt;
1027 uint16 sourceSAP, destSAP;
1028 destSAP = fullpkt->fEnetPart.fProto;
1029 if (destSAP >= kMinDIXSAP) {
1030 // Classic ethernet
1031 sourceSAP = destSAP;
1032 } else {
1033 destSAP = fullpkt->f8022Part.fDSAP;
1034 sourceSAP = fullpkt->f8022Part.fSSAP;
1035 }
1036 uint16 packetType = classify_packet_type(sourceSAP, destSAP);
1037 int32 destAddressType = get_address_type(pkt->fDestAddr);
1038
1039 // Look which streams want it
1040 DLPIStream *the_stream, *found_stream = NULL;
1041 uint16 found_packetType = 0;
1042 int32 found_destAddressType = 0;
1043 for (the_stream = dlpi_stream_list; the_stream != NULL; the_stream = mi_next_ptr(the_stream)) {
1044
1045 // Don't send to unbound streams
1046 if (the_stream->dlpi_state == DL_UNBOUND)
1047 continue;
1048
1049 // Does this stream want all 802.2 packets?
1050 if ((the_stream->flags & kAcceptAll8022Packets) && (destSAP <= 0xff))
1051 goto type_found;
1052
1053 // No, check SAP/SNAP
1054 if (destSAP == the_stream->dlsap) {
1055 if (the_stream->flags & kSnapStream) {
1056 // Check SNAPs if necessary
1057 uint8 sum = fullpkt->f8022Part.fSNAP[0] ^ the_stream->snap[0];
1058 sum |= fullpkt->f8022Part.fSNAP[1] ^ the_stream->snap[1];
1059 sum |= fullpkt->f8022Part.fSNAP[2] ^ the_stream->snap[2];
1060 sum |= fullpkt->f8022Part.fSNAP[3] ^ the_stream->snap[3];
1061 sum |= fullpkt->f8022Part.fSNAP[4] ^ the_stream->snap[4];
1062 if (sum == 0)
1063 goto type_found;
1064 } else {
1065 // No SNAP, found a match since saps match
1066 goto type_found;
1067 }
1068 } else {
1069 // Check for an 802.3 Group/Global (odd)
1070 if (((packetType == kPkt8022SAP) || (packetType == kPkt8022SNAP)) && (destSAP & 1) && the_stream->TestGroupSAP(destSAP))
1071 goto type_found;
1072 }
1073
1074 // No stream for this SAP/SNAP found
1075 continue;
1076
1077 type_found:
1078 // If it's a multicast packet, it must be in the stream's multicast list
1079 if ((destAddressType == keaMulticast) && (the_stream->flags & kAcceptMulticasts) && (!the_stream->IsMulticastRegistered(pkt->fDestAddr)))
1080 continue;
1081
1082 // Send packet to stream
1083 // found_stream keeps a pointer to the previously found stream, so that only the last
1084 // stream gets the original message, the other ones get duplicates
1085 if (found_stream)
1086 handle_received_packet(found_stream, dupmsg(mp), found_packetType, found_destAddressType);
1087 found_stream = the_stream;
1088 found_packetType = packetType;
1089 found_destAddressType = destAddressType;
1090 }
1091
1092 // Send original message to last found stream
1093 if (found_stream)
1094 handle_received_packet(found_stream, mp, found_packetType, found_destAddressType);
1095 else {
1096 freemsg(mp); // Nobody wants it *snief*
1097 num_rx_dropped++;
1098 }
1099 }
1100
1101
1102 /*
1103 * Build and send an error acknowledge
1104 */
1105
1106 static void DLPI_error_ack(DLPIStream *the_stream, queue_t *q, mblk_t *ack_mp, uint32 prim, uint32 err, uint32 uerr)
1107 {
1108 D(bug(" DLPI_error_ack(%p,%p) prim %d, err %d, uerr %d\n", the_stream, ack_mp, prim, err, uerr));
1109 num_error_acks++;
1110
1111 if (ack_mp != NULL)
1112 freemsg(ack_mp);
1113 if ((ack_mp = allocb(sizeof(dl_error_ack_t), BPRI_HI)) == NULL)
1114 return;
1115
1116 ack_mp->b_datap->db_type = M_PCPROTO;
1117 dl_error_ack_t *errp = (dl_error_ack_t *)(void *)ack_mp->b_wptr;
1118 errp->dl_primitive = DL_ERROR_ACK;
1119 errp->dl_error_primitive = prim;
1120 errp->dl_errno = err;
1121 errp->dl_unix_errno = uerr;
1122 ack_mp->b_wptr += sizeof(dl_error_ack_t);
1123 qreply(q, ack_mp);
1124 }
1125
1126
1127 /*
1128 * Build and send an OK acknowledge
1129 */
1130
1131 static void DLPI_ok_ack(DLPIStream *the_stream, queue_t *q, mblk_t *ack_mp, uint32 prim)
1132 {
1133 if (ack_mp->b_datap->db_ref != 1) {
1134 // Message already in use, create a new one
1135 freemsg(ack_mp);
1136 if ((ack_mp = allocb(sizeof(dl_error_ack_t), BPRI_HI)) == NULL)
1137 return;
1138 } else {
1139 // Message free
1140 if (ack_mp->b_cont != NULL) {
1141 freemsg(ack_mp->b_cont);
1142 ack_mp->b_cont = NULL;
1143 }
1144 }
1145
1146 ack_mp->b_datap->db_type = M_PCPROTO;
1147 dl_ok_ack_t *ackp = (dl_ok_ack_t *)(void *)ack_mp->b_rptr;
1148 ackp->dl_primitive = DL_OK_ACK;
1149 ackp->dl_correct_primitive = prim;
1150 ack_mp->b_wptr = ack_mp->b_rptr + sizeof(dl_ok_ack_t);
1151 qreply(q, ack_mp);
1152 }
1153
1154
1155 /*
1156 * Handle DL_INFO_REQ (report general information)
1157 */
1158
1159 static void DLPI_info(DLPIStream *the_stream, queue_t *q, mblk_t *mp)
1160 {
1161 D(bug(" DLPI_info(%p)\n", the_stream));
1162 uint32 saplen = 0;
1163 uint32 addrlen = kEnetPhysicalAddressLength;
1164 uint32 bcastlen = kEnetPhysicalAddressLength;
1165 uint32 hdrlen = kEnetPacketHeaderLength;
1166
1167 // Calculate header length
1168 if (the_stream->dlpi_state != DL_UNBOUND) {
1169 saplen = (the_stream->flags & kSnapStream) ? k8022DLSAPLength+k8022SNAPLength : k8022DLSAPLength;
1170 if (the_stream->dlsap == kSNAPSAP)
1171 hdrlen = kEnetPacketHeaderLength + k8022SNAPHeaderLength; // SNAP address
1172 else if ((the_stream->dlsap <= kMax8022SAP) || (the_stream->dlsap == kIPXSAP))
1173 hdrlen = kEnetPacketHeaderLength + k8022BasicHeaderLength; // SAP or IPX
1174 else
1175 hdrlen = kEnetPacketHeaderLength; // Basic Ethernet
1176 }
1177
1178 // Allocate message block for reply
1179 mblk_t *ack_mp;
1180 if ((ack_mp = allocb(sizeof(dl_info_ack_t) + addrlen + saplen + bcastlen, BPRI_LO)) == NULL) {
1181 DLPI_error_ack(the_stream, q, mp, DL_INFO_REQ, DL_SYSERR, MAC_ENOMEM);
1182 return;
1183 }
1184
1185 // Set up message type
1186 ack_mp->b_datap->db_type = M_PCPROTO;
1187 dl_info_ack_t *ackp = (dl_info_ack_t *)(void *)ack_mp->b_rptr;
1188 ackp->dl_primitive = DL_INFO_ACK;
1189
1190 // Info/version fields
1191 ackp->dl_service_mode = DL_CLDLS;
1192 ackp->dl_provider_style = DL_STYLE1;
1193 ackp->dl_version = DL_VERSION_2;
1194 ackp->dl_current_state = the_stream->dlpi_state;
1195 ackp->dl_mac_type = the_stream->framing_8022 ? DL_CSMACD : DL_ETHER;
1196 ackp->dl_reserved = 0;
1197 ackp->dl_qos_length = 0;
1198 ackp->dl_qos_offset = (uint32)DL_UNKNOWN;
1199 ackp->dl_qos_range_length = 0;
1200 ackp->dl_qos_range_offset = (uint32)DL_UNKNOWN;
1201 ackp->dl_growth = 0;
1202 ackp->dl_min_sdu = 1;
1203 ackp->dl_max_sdu = kEnetTSDU - hdrlen;
1204
1205 // Address fields
1206 ackp->dl_sap_length = -saplen; // Negative to indicate sap follows physical address
1207 ackp->dl_addr_length = addrlen + saplen;
1208 ackp->dl_addr_offset = sizeof(dl_info_ack_t);
1209 T8022AddressStruct *boundAddr = ((T8022AddressStruct *)(ack_mp->b_rptr + ackp->dl_addr_offset));
1210 OTCopy48BitAddress(hardware_address, boundAddr->fHWAddr);
1211 if (saplen) {
1212 boundAddr->fSAP = the_stream->dlsap;
1213 if (the_stream->flags & kSnapStream)
1214 OTCopy8022SNAP(the_stream->snap, boundAddr->fSNAP);
1215 }
1216 ackp->dl_brdcst_addr_length = bcastlen;
1217 ackp->dl_brdcst_addr_offset = sizeof(dl_info_ack_t) + addrlen + saplen;
1218 OTSet48BitBroadcastAddress(ack_mp->b_rptr + ackp->dl_brdcst_addr_offset);
1219
1220 // Advance write pointer
1221 ack_mp->b_wptr += sizeof(dl_info_ack_t) + addrlen + saplen + bcastlen;
1222
1223 // Free request
1224 freemsg(mp);
1225
1226 // Send reply
1227 qreply(q, ack_mp);
1228 return;
1229 }
1230
1231
1232 /*
1233 * Handle DL_PHYS_ADDR_REQ (report physical address)
1234 */
1235
1236 static void DLPI_phys_addr(DLPIStream *the_stream, queue_t *q, mblk_t *mp)
1237 {
1238 D(bug(" DLPI_phys_addr(%p,%p)\n", the_stream, mp));
1239 dl_phys_addr_req_t *req = (dl_phys_addr_req_t *)(void *)mp->b_rptr;
1240
1241 // Allocate message block for reply
1242 mblk_t *ack_mp;
1243 if ((ack_mp = allocb(sizeof(dl_phys_addr_ack_t) + kEnetPhysicalAddressLength, BPRI_HI)) == NULL) {
1244 DLPI_error_ack(the_stream, q, mp, DL_PHYS_ADDR_REQ, DL_SYSERR, MAC_ENOMEM);
1245 return;
1246 }
1247
1248 // Set up message type
1249 ack_mp->b_datap->db_type = M_PCPROTO;
1250 dl_phys_addr_ack_t *ackp = (dl_phys_addr_ack_t *)(void *)ack_mp->b_wptr;
1251 ackp->dl_primitive = DL_PHYS_ADDR_ACK;
1252
1253 // Fill in address
1254 ackp->dl_addr_length = kEnetPhysicalAddressLength;
1255 ackp->dl_addr_offset = sizeof(dl_phys_addr_ack_t);
1256 ack_mp->b_wptr += sizeof(dl_phys_addr_ack_t) + kEnetPhysicalAddressLength;
1257 if (req->dl_addr_type == DL_CURR_PHYS_ADDR || req->dl_addr_type == DL_FACT_PHYS_ADDR)
1258 OTCopy48BitAddress(hardware_address, ack_mp->b_rptr + ackp->dl_addr_offset);
1259 else {
1260 DLPI_error_ack(the_stream, q, mp, DL_PHYS_ADDR_REQ, DL_BADPRIM, 0);
1261 return;
1262 }
1263
1264 // Free request
1265 freemsg(mp);
1266
1267 // Send reply
1268 qreply(q, ack_mp);
1269 return;
1270 }
1271
1272
1273 /*
1274 * Handle DL_BIND_REQ (bind a stream)
1275 */
1276
1277 static void DLPI_bind(DLPIStream *the_stream, queue_t *q, mblk_t *mp)
1278 {
1279 dl_bind_req_t *req = (dl_bind_req_t *)(void *)mp->b_rptr;
1280 uint32 sap = req->dl_sap;
1281 D(bug(" DLPI_bind(%p,%p) SAP %04x\n", the_stream, mp, sap));
1282
1283 // Stream must be unbound
1284 if (the_stream->dlpi_state != DL_UNBOUND) {
1285 DLPI_error_ack(the_stream, q, mp, DL_BIND_REQ, DL_OUTSTATE, 0);
1286 return;
1287 }
1288
1289 // We only support connectionless data link services
1290 if (req->dl_service_mode != DL_CLDLS || req->dl_max_conind != 0) {
1291 DLPI_error_ack(the_stream, q, mp, DL_BIND_REQ, DL_UNSUPPORTED, 0);
1292 return;
1293 }
1294
1295 // Don't bind to 802.2 group saps, can't check 802.2 global sap (0xFF)
1296 // because it looks like IPX
1297 if ((sap <= kMax8022SAP) && (sap & 1)) {
1298 DLPI_error_ack(the_stream, q, mp, DL_BIND_REQ, DL_BADADDR, 0);
1299 return;
1300 }
1301
1302 if (classify_packet_type(sap, sap) == kPktUnknown) {
1303 DLPI_error_ack(the_stream, q, mp, DL_BIND_REQ, DL_BADADDR, 0);
1304 return;
1305 }
1306
1307 // Allocate message block for reply
1308 mblk_t *ack_mp;
1309 if ((ack_mp = allocb(sizeof(dl_bind_ack_t) + kEnetAndSAPAddressLength, BPRI_HI)) == NULL) {
1310 DLPI_error_ack(the_stream, q, mp, DL_BIND_REQ, DL_SYSERR, MAC_ENOMEM);
1311 return;
1312 }
1313
1314 // Set up message type
1315 ack_mp->b_datap->db_type = M_PCPROTO;
1316 dl_bind_ack_t *ackp = (dl_bind_ack_t *)(void *)ack_mp->b_rptr;
1317 ackp->dl_primitive = DL_BIND_ACK;
1318
1319 // Fill in other fields
1320 ackp->dl_sap = sap;
1321 ackp->dl_addr_length = kEnetAndSAPAddressLength;
1322 ackp->dl_addr_offset = sizeof(dl_bind_ack_t);
1323 ackp->dl_max_conind = 0;
1324 ackp->dl_xidtest_flg = 0;
1325
1326 T8022AddressStruct *addrInfo = (T8022AddressStruct *)(ack_mp->b_rptr + sizeof(dl_bind_ack_t));
1327 OTCopy48BitAddress(hardware_address, addrInfo->fHWAddr);
1328 addrInfo->fSAP = sap;
1329
1330 // Must move b_wptr past the address info data
1331 ack_mp->b_wptr = ack_mp->b_rptr + sizeof(dl_bind_ack_t) + kEnetAndSAPAddressLength;
1332
1333 // Set group SAP if necessary
1334 the_stream->ClearAllGroupSAPs();
1335 if (sap <= kMax8022SAP)
1336 the_stream->SetGroupSAP(k8022GlobalSAP);
1337
1338 // The stream is now bound and idle
1339 the_stream->dlpi_state = DL_IDLE;
1340 the_stream->dlsap = sap;
1341 the_stream->flags &= ~kSnapStream;
1342
1343 // Free request
1344 freemsg(mp);
1345
1346 // Send reply
1347 qreply(q, ack_mp);
1348 return;
1349 }
1350
1351
1352 /*
1353 * Handle DL_UNBIND_REQ (unbind a stream)
1354 */
1355
1356 static void DLPI_unbind(DLPIStream *the_stream, queue_t *q, mblk_t *mp)
1357 {
1358 D(bug(" DLPI_unbind(%p,%p)\n", the_stream, mp));
1359
1360 // Stream must be bound and idle
1361 if (the_stream->dlpi_state != DL_IDLE) {
1362 DLPI_error_ack(the_stream, q, mp, DL_UNBIND_REQ, DL_OUTSTATE, 0);
1363 return;
1364 }
1365
1366 // Stream is now unbound
1367 the_stream->dlpi_state = DL_UNBOUND;
1368 the_stream->dlsap = 0;
1369
1370 // Flush all pending outbound messages
1371 flushq(q, FLUSHDATA);
1372
1373 // Flush all inbound messages pending on the stream
1374 flushq(RD(q), FLUSHDATA);
1375 putnextctl1(RD(q), M_FLUSH, FLUSHRW);
1376
1377 // Send reply
1378 DLPI_ok_ack(the_stream, q, mp, DL_UNBIND_REQ);
1379 return;
1380 }
1381
1382
1383 /*
1384 * Handle DL_SUBS_BIND_REQ (register 802.2 SAP group addresses and SNAPs)
1385 */
1386
1387 static void DLPI_subs_bind(DLPIStream *the_stream, queue_t *q, mblk_t *mp)
1388 {
1389 dl_subs_bind_req_t *req = (dl_subs_bind_req_t *)(void *)mp->b_rptr;
1390 uint8 *sap = ((uint8 *)req) + req->dl_subs_sap_offset;
1391 int32 length = req->dl_subs_sap_length;
1392 uint16 theSap = ntohs(*((uint16 *)sap));
1393 int32 error = 0;
1394 D(bug(" DLPI_subs_bind(%p,%p) SAP %02x%02x%02x%02x%02x\n", the_stream, mp, sap[0], sap[1], sap[2], sap[3], sap[4]));
1395
1396 // Stream must be idle
1397 if (the_stream->dlpi_state != DL_IDLE) {
1398 DLPI_error_ack(the_stream, q, mp, DL_SUBS_BIND_REQ, DL_OUTSTATE, 0);
1399 return;
1400 }
1401
1402 // Check if address is valid
1403 switch (req->dl_subs_bind_class) {
1404 case DL_PEER_BIND: // Bind a group address
1405 if (the_stream->dlsap <= kMax8022SAP) {
1406 if ((theSap & 1) && (length == sizeof(theSap)))
1407 the_stream->SetGroupSAP(theSap);
1408 else
1409 if (theSap == 0x0000) // special case to receive all 802.2 packets
1410 the_stream->flags |= kAcceptAll8022Packets;
1411 else
1412 error = DL_BADADDR;
1413 } else
1414 error = DL_UNSUPPORTED;
1415 break;
1416
1417 case DL_HIERARCHICAL_BIND: // Bind an additional SNAP
1418 if (the_stream->dlsap == kSNAPSAP) {
1419 if (the_stream->flags & kSnapStream)
1420 error = DL_TOOMANY; // only one SNAP binding allowed
1421 else {
1422 OTCopy8022SNAP(sap, the_stream->snap);
1423 the_stream->flags |= kSnapStream;
1424 }
1425 } else
1426 error = DL_BADADDR;
1427 break;
1428
1429 default:
1430 error = DL_UNSUPPORTED;
1431 break;
1432 }
1433 if (error) {
1434 DLPI_error_ack(the_stream, q, mp, DL_SUBS_BIND_REQ, error, 0);
1435 return;
1436 }
1437
1438 // Allocate message block for reply
1439 mblk_t *ack_mp;
1440 if ((ack_mp = allocb(sizeof(dl_subs_bind_ack_t) + length, BPRI_HI)) == NULL) {
1441 DLPI_error_ack(the_stream, q, mp, DL_SUBS_BIND_REQ, DL_SYSERR, MAC_ENOMEM);
1442 return;
1443 }
1444
1445 // Set up message type
1446 ack_mp->b_datap->db_type = M_PCPROTO;
1447 dl_subs_bind_ack_t *ackp = (dl_subs_bind_ack_t *)(void *)ack_mp->b_wptr;
1448 memset(ackp, 0, sizeof(dl_subs_bind_ack_t) + length);
1449 ackp->dl_primitive = DL_SUBS_BIND_ACK;
1450
1451 // Fill in other fields
1452 ackp->dl_subs_sap_length = length;
1453 ackp->dl_subs_sap_offset = length ? sizeof(dl_subs_bind_ack_t) : 0;
1454 ack_mp->b_wptr += sizeof(dl_subs_bind_ack_t);
1455 if (length)
1456 memcpy(ack_mp->b_wptr, sap, length);
1457 ack_mp->b_wptr += length;
1458
1459 // Free request
1460 freemsg(mp);
1461
1462 // Send reply
1463 qreply(q, ack_mp);
1464 return;
1465 }
1466
1467
1468 /*
1469 * Handle DL_SUBS_UNBIND_REQ (unregister 802.2 SAP group addresses and snaps)
1470 */
1471
1472 static void DLPI_subs_unbind(DLPIStream *the_stream, queue_t *q, mblk_t *mp)
1473 {
1474 dl_subs_unbind_req_t *req = (dl_subs_unbind_req_t *)(void *)mp->b_rptr;
1475 uint8 *sap = ((uint8 *)req) + req->dl_subs_sap_offset;
1476 int32 length = req->dl_subs_sap_length;
1477 int32 error = 0;
1478 D(bug(" DLPI_subs_unbind(%p,%p) SAP %02x%02x%02x%02x%02x\n", the_stream, mp, sap[0], sap[1], sap[2], sap[3], sap[4]));
1479
1480 // Stream must be idle
1481 if (the_stream->dlpi_state != DL_IDLE) {
1482 DLPI_error_ack(the_stream, q, mp, DL_SUBS_UNBIND_REQ, DL_OUTSTATE, 0);
1483 return;
1484 }
1485
1486 // Check if we are unbinding from an address we are bound to
1487 if (length == k8022SAPLength) {
1488 if ((*sap & 1) && (*sap != kIPXSAP)) {
1489 if (the_stream->dlsap <= kMax8022SAP)
1490 the_stream->ClearGroupSAP(*sap);
1491 else
1492 error = DL_UNSUPPORTED;
1493 } else
1494 error = DL_BADADDR;
1495 } else if (length == k8022SNAPLength) {
1496 if (the_stream->dlsap == kSNAPSAP) {
1497 if (the_stream->flags & kSnapStream) {
1498 if (memcmp(the_stream->snap, sap, length) != 0)
1499 error = DL_BADADDR;
1500 } else
1501 error = DL_BADADDR;
1502 } else
1503 error = DL_UNSUPPORTED;
1504 }
1505 if (error) {
1506 DLPI_error_ack(the_stream, q, mp, DL_SUBS_UNBIND_REQ, error, 0);
1507 return;
1508 }
1509
1510 // Stream is no longer bound to SNAP
1511 the_stream->flags &= ~kSnapStream;
1512
1513 // Send reply
1514 DLPI_ok_ack(the_stream, q, mp, DL_SUBS_UNBIND_REQ);
1515 return;
1516 }
1517
1518
1519 /*
1520 * Handles DL_ENABMULTI_REQ (enable multicast address)
1521 */
1522
1523 static void DLPI_enable_multi(DLPIStream *the_stream, queue_t *q, mblk_t *mp)
1524 {
1525 dl_enabmulti_req_t* req = (dl_enabmulti_req_t*)(void *)mp->b_rptr;
1526 uint8 *reqaddr = (uint8 *)(mp->b_rptr + req->dl_addr_offset);
1527 D(bug(" DLPI_enable_multi(%p,%p) addr %02x%02x%02x%02x%02x%02x\n", the_stream, mp, reqaddr[0], reqaddr[1], reqaddr[2], reqaddr[3], reqaddr[4], reqaddr[5]));
1528
1529 // Address must be a multicast address
1530 if (get_address_type(reqaddr) != keaMulticast) {
1531 DLPI_error_ack(the_stream, q, mp, DL_ENABMULTI_REQ, DL_BADADDR, 0);
1532 return;
1533 }
1534
1535 // Address already in multicast list?
1536 if (the_stream->IsMulticastRegistered(reqaddr)) {
1537 DLPI_error_ack(the_stream, q, mp, DL_ENABMULTI_REQ, DL_BADADDR, 0);
1538 return;
1539 }
1540
1541 // Tell add-on to enable multicast address
1542 AO_enable_multicast(reqaddr);
1543
1544 // Add new address to multicast list
1545 uint8 *addr = (uint8 *)Mac_sysalloc(kEnetPhysicalAddressLength);
1546 OTCopy48BitAddress(reqaddr, addr);
1547 the_stream->AddMulticast(addr);
1548
1549 // On receive now check multicast packets
1550 the_stream->flags |= kAcceptMulticasts;
1551
1552 // Send reply
1553 DLPI_ok_ack(the_stream, q, mp, DL_ENABMULTI_REQ);
1554 return;
1555 }
1556
1557
1558 /*
1559 * Handles DL_DISABMULTI_REQ (disable multicast address)
1560 */
1561
1562 static void DLPI_disable_multi(DLPIStream *the_stream, queue_t *q, mblk_t *mp)
1563 {
1564 dl_disabmulti_req_t *req = (dl_disabmulti_req_t*)(void *)mp->b_rptr;
1565 uint8 *reqaddr = (uint8 *)(mp->b_rptr + req->dl_addr_offset);
1566 D(bug(" DLPI_disable_multi(%p,%p) addr %02x%02x%02x%02x%02x%02x\n", the_stream, mp, reqaddr[0], reqaddr[1], reqaddr[2], reqaddr[3], reqaddr[4], reqaddr[5]));
1567
1568 // Address must be a multicast address
1569 if (get_address_type(reqaddr) != keaMulticast) {
1570 DLPI_error_ack(the_stream, q, mp, DL_DISABMULTI_REQ, DL_BADADDR, 0);
1571 return;
1572 }
1573
1574 // Find address in multicast list
1575 uint8 *addr = the_stream->IsMulticastRegistered(reqaddr);
1576 if (addr == NULL) {
1577 DLPI_error_ack(the_stream, q, mp, DL_DISABMULTI_REQ, DL_BADADDR, 0);
1578 return;
1579 }
1580
1581 // Found, then remove
1582 the_stream->RemoveMulticast(addr);
1583 Mac_sysfree(addr);
1584
1585 // Tell add-on to disable multicast address
1586 AO_disable_multicast(reqaddr);
1587
1588 // No longer check multicast packets if no multicast addresses are registered
1589 if (the_stream->multicast_list == NULL)
1590 the_stream->flags &= ~kAcceptMulticasts;
1591
1592 // Send reply
1593 DLPI_ok_ack(the_stream, q, mp, DL_DISABMULTI_REQ);
1594 return;
1595 }
1596
1597
1598 /*
1599 * Handle DL_UNITDATA_REQ (transmit packet)
1600 */
1601
1602 static void DLPI_unit_data(DLPIStream *the_stream, queue_t *q, mblk_t *mp)
1603 {
1604 D(bug(" DLPI_unit_data(%p,%p)\n", the_stream, mp));
1605 dl_unitdata_req_t *req = (dl_unitdata_req_t *)(void *)mp->b_rptr;
1606
1607 // Stream must be idle
1608 if (the_stream->dlpi_state != DL_IDLE) {
1609
1610 // Not idle, send error response
1611 dl_uderror_ind_t *errp;
1612 mblk_t *bp;
1613
1614 int i = sizeof(dl_uderror_ind_t) + req->dl_dest_addr_length;
1615 if ((bp = allocb(i, BPRI_HI)) == NULL) {
1616 freemsg(mp);
1617 return;
1618 }
1619 bp->b_datap->db_type = M_PROTO;
1620 errp = (dl_uderror_ind_t *)(void *)bp->b_wptr;
1621 errp->dl_primitive = DL_UDERROR_IND;
1622 errp->dl_errno = DL_OUTSTATE;
1623 errp->dl_unix_errno = 0;
1624 errp->dl_dest_addr_length = req->dl_dest_addr_length;
1625 errp->dl_dest_addr_offset = sizeof(dl_uderror_ind_t);
1626 bp->b_wptr += sizeof(dl_uderror_ind_t);
1627 memcpy((uint8 *)bp->b_wptr, ((uint8 *)req) + req->dl_dest_addr_offset, req->dl_dest_addr_length);
1628 bp->b_wptr += req->dl_dest_addr_length;
1629 qreply(q, bp);
1630
1631 freemsg(mp);
1632 return;
1633 }
1634
1635 // Build packet header and transmit packet
1636 if ((mp = build_tx_packet_header(the_stream, mp, false)) != NULL)
1637 transmit_packet(mp);
1638 }