File: /usr/src/linux/drivers/net/sk98lin/skaddr.c
1 /******************************************************************************
2 *
3 * Name: skaddr.c
4 * Project: GEnesis, PCI Gigabit Ethernet Adapter
5 * Version: $Revision: 1.40 $
6 * Date: $Date: 2001/02/14 14:04:59 $
7 * Purpose: Manage Addresses (Multicast and Unicast) and Promiscuous Mode.
8 *
9 ******************************************************************************/
10
11 /******************************************************************************
12 *
13 * (C)Copyright 1998-2001 SysKonnect GmbH.
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * The information in this file is provided "AS IS" without warranty.
21 *
22 ******************************************************************************/
23
24 /******************************************************************************
25 *
26 * History:
27 *
28 * $Log: skaddr.c,v $
29 * Revision 1.40 2001/02/14 14:04:59 rassmann
30 * Editorial changes.
31 *
32 * Revision 1.39 2001/01/30 10:30:04 rassmann
33 * Editorial changes.
34 *
35 * Revision 1.38 2001/01/25 16:26:52 rassmann
36 * Ensured that logical address overrides are done on net's active port.
37 *
38 * Revision 1.37 2001/01/22 13:41:34 rassmann
39 * Supporting two nets on dual-port adapters.
40 *
41 * Revision 1.36 2000/08/07 11:10:39 rassmann
42 * Editorial changes.
43 *
44 * Revision 1.35 2000/05/04 09:38:41 rassmann
45 * Editorial changes.
46 * Corrected multicast address hashing.
47 *
48 * Revision 1.34 1999/11/22 13:23:44 cgoos
49 * Changed license header to GPL.
50 *
51 * Revision 1.33 1999/05/28 10:56:06 rassmann
52 * Editorial changes.
53 *
54 * Revision 1.32 1999/03/31 10:59:20 rassmann
55 * Returning Success instead of DupAddr if address shall be overridden
56 * with same value.
57 *
58 * Revision 1.31 1999/01/14 16:18:17 rassmann
59 * Corrected multicast initialization.
60 *
61 * Revision 1.30 1999/01/04 10:30:35 rassmann
62 * SkAddrOverride only possible after SK_INIT_IO phase.
63 *
64 * Revision 1.29 1998/12/29 13:13:10 rassmann
65 * An address override is now preserved in the SK_INIT_IO phase.
66 * All functions return an int now.
67 * Extended parameter checking.
68 *
69 * Revision 1.28 1998/12/01 11:45:53 rassmann
70 * Code cleanup.
71 *
72 * Revision 1.27 1998/12/01 09:22:49 rassmann
73 * SkAddrMcAdd and SkAddrMcUpdate returned SK_MC_FILTERING_INEXACT
74 * too often.
75 *
76 * Revision 1.26 1998/11/24 12:39:44 rassmann
77 * Reserved multicast entry for BPDU address.
78 * 13 multicast entries left for protocol.
79 *
80 * Revision 1.25 1998/11/17 16:54:23 rassmann
81 * Using exact match for up to 14 multicast addresses.
82 * Still receiving all multicasts if more addresses are added.
83 *
84 * Revision 1.24 1998/11/13 17:24:31 rassmann
85 * Changed return value of SkAddrOverride to int.
86 *
87 * Revision 1.23 1998/11/13 16:56:18 rassmann
88 * Added macro SK_ADDR_COMPARE.
89 * Changed return type of SkAddrOverride to SK_BOOL.
90 *
91 * Revision 1.22 1998/11/04 17:06:17 rassmann
92 * Corrected McUpdate and PromiscuousChange functions.
93 *
94 * Revision 1.21 1998/10/29 14:34:04 rassmann
95 * Clearing SK_ADDR struct at startup.
96 *
97 * Revision 1.20 1998/10/28 18:16:34 rassmann
98 * Avoiding I/Os before SK_INIT_RUN level.
99 * Aligning InexactFilter.
100 *
101 * Revision 1.19 1998/10/28 11:29:28 rassmann
102 * Programming physical address in SkAddrMcUpdate.
103 * Corrected programming of exact match entries.
104 *
105 * Revision 1.18 1998/10/28 10:34:48 rassmann
106 * Corrected reading of physical addresses.
107 *
108 * Revision 1.17 1998/10/28 10:26:13 rassmann
109 * Getting ports' current MAC addresses from EPROM now.
110 * Added debug output.
111 *
112 * Revision 1.16 1998/10/27 16:20:12 rassmann
113 * Reading MAC address byte by byte.
114 *
115 * Revision 1.15 1998/10/22 11:39:09 rassmann
116 * Corrected signed/unsigned mismatches.
117 *
118 * Revision 1.14 1998/10/19 17:12:35 rassmann
119 * Syntax corrections.
120 *
121 * Revision 1.13 1998/10/19 17:02:19 rassmann
122 * Now reading permanent MAC addresses from CRF.
123 *
124 * Revision 1.12 1998/10/15 15:15:48 rassmann
125 * Changed Flags Parameters from SK_U8 to int.
126 * Checked with lint.
127 *
128 * Revision 1.11 1998/09/24 19:15:12 rassmann
129 * Code cleanup.
130 *
131 * Revision 1.10 1998/09/18 20:18:54 rassmann
132 * Added HW access.
133 * Implemented swapping.
134 *
135 * Revision 1.9 1998/09/16 11:32:00 rassmann
136 * Including skdrv1st.h again. :(
137 *
138 * Revision 1.8 1998/09/16 11:09:34 rassmann
139 * Syntax corrections.
140 *
141 * Revision 1.7 1998/09/14 17:06:34 rassmann
142 * Minor changes.
143 *
144 * Revision 1.6 1998/09/07 08:45:41 rassmann
145 * Syntax corrections.
146 *
147 * Revision 1.5 1998/09/04 19:40:19 rassmann
148 * Interface enhancements.
149 *
150 * Revision 1.4 1998/09/04 12:14:12 rassmann
151 * Interface cleanup.
152 *
153 * Revision 1.3 1998/09/02 16:56:40 rassmann
154 * Updated interface.
155 *
156 * Revision 1.2 1998/08/27 14:26:09 rassmann
157 * Updated interface.
158 *
159 * Revision 1.1 1998/08/21 08:30:22 rassmann
160 * First public version.
161 *
162 ******************************************************************************/
163
164 /******************************************************************************
165 *
166 * Description:
167 *
168 * This module is intended to manage multicast addresses, address override,
169 * and promiscuous mode on GEnesis adapters.
170 *
171 * Address Layout:
172 * port address: physical MAC address
173 * 1st exact match: logical MAC address
174 * 2nd exact match: RLMT multicast
175 * exact match 3-13: OS-specific multicasts
176 *
177 * Include File Hierarchy:
178 *
179 * "skdrv1st.h"
180 * "skdrv2nd.h"
181 *
182 ******************************************************************************/
183
184 #ifndef lint
185 static const char SysKonnectFileId[] =
186 "@(#) $Id: skaddr.c,v 1.40 2001/02/14 14:04:59 rassmann Exp $ (C) SysKonnect.";
187 #endif /* !defined(lint) */
188
189 #define __SKADDR_C
190
191 #ifdef __cplusplus
192 #error C++ is not yet supported.
193 extern "C" {
194 #endif /* cplusplus */
195
196 #include "h/skdrv1st.h"
197 #include "h/skdrv2nd.h"
198
199 /* defines ********************************************************************/
200
201
202 #define CRC32_POLY 0xEDB88320UL /* CRC32-Poly - XMAC: Little Endian */
203 #define HASH_BITS 6 /* #bits in hash */
204 #define SK_MC_BIT 0x01
205
206 /* Error numbers and messages. */
207
208 #define SKERR_ADDR_E001 (SK_ERRBASE_ADDR + 0)
209 #define SKERR_ADDR_E001MSG "Bad Flags."
210 #define SKERR_ADDR_E002 (SKERR_ADDR_E001 + 1)
211 #define SKERR_ADDR_E002MSG "New Error."
212
213 /* typedefs *******************************************************************/
214
215 /* None. */
216
217 /* global variables ***********************************************************/
218
219 /* 64-bit hash values with all bits set. */
220
221 SK_U16 OnesHash[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
222
223 /* local variables ************************************************************/
224
225 #ifdef DEBUG
226 static int Next0[SK_MAX_MACS] = {0, 0};
227 #endif /* DEBUG */
228
229 /* functions ******************************************************************/
230
231 /******************************************************************************
232 *
233 * SkAddrInit - initialize data, set state to init
234 *
235 * Description:
236 *
237 * SK_INIT_DATA
238 * ============
239 *
240 * This routine clears the multicast tables and resets promiscuous mode.
241 * Some entries are reserved for the "logical MAC address", the
242 * SK-RLMT multicast address, and the BPDU multicast address.
243 *
244 *
245 * SK_INIT_IO
246 * ==========
247 *
248 * All permanent MAC addresses are read from EPROM.
249 * If the current MAC addresses are not already set in software,
250 * they are set to the values of the permanent addresses.
251 * The current addresses are written to the corresponding XMAC.
252 *
253 *
254 * SK_INIT_RUN
255 * ===========
256 *
257 * Nothing.
258 *
259 * Context:
260 * init, pageable
261 *
262 * Returns:
263 * SK_ADDR_SUCCESS
264 */
265 int SkAddrInit(
266 SK_AC *pAC, /* the adapter context */
267 SK_IOC IoC, /* I/O context */
268 int Level) /* initialization level */
269 {
270 int j;
271 SK_U32 i;
272 SK_U8 *InAddr;
273 SK_U16 *OutAddr;
274 SK_ADDR_PORT *pAPort;
275
276 switch (Level) {
277 case SK_INIT_DATA:
278 SK_MEMSET((char *)&pAC->Addr, 0, sizeof(SK_ADDR));
279
280 for (i = 0; i < SK_MAX_MACS; i++) {
281 pAPort = &pAC->Addr.Port[i];
282 pAPort->PromMode = SK_PROM_MODE_NONE;
283
284 pAPort->FirstExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
285 pAPort->FirstExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV;
286 pAPort->NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
287 pAPort->NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV;
288
289 #if 0
290 /* Don't do this here ... */
291
292 /* Reset Promiscuous mode. */
293 (void)SkAddrPromiscuousChange(
294 pAC,
295 IoC,
296 i,
297 SK_PROM_MODE_NONE);
298 #endif /* 0 */
299 }
300
301 #ifdef DEBUG
302 for (i = 0; i < SK_MAX_MACS; i++) {
303 if (pAC->Addr.Port[i].NextExactMatchRlmt <
304 SK_ADDR_FIRST_MATCH_RLMT) {
305 Next0[i] |= 4;
306 }
307 }
308 #endif /* DEBUG */
309
310 /* pAC->Addr.InitDone = SK_INIT_DATA; */
311 break;
312
313 case SK_INIT_IO:
314 for (i = 0; i < SK_MAX_NETS; i++) {
315 pAC->Addr.Net[i].ActivePort = pAC->Rlmt.Net[i].ActivePort;
316 }
317
318 #ifdef DEBUG
319 for (i = 0; i < SK_MAX_MACS; i++) {
320 if (pAC->Addr.Port[i].NextExactMatchRlmt <
321 SK_ADDR_FIRST_MATCH_RLMT) {
322 Next0[i] |= 8;
323 }
324 }
325 #endif /* DEBUG */
326
327 /* Read permanent logical MAC address from Control Register File. */
328 for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
329 InAddr = (SK_U8 *)&pAC->Addr.Net[0].PermanentMacAddress.a[j];
330 SK_IN8(IoC, B2_MAC_1 + j, InAddr);
331 }
332
333 if (!pAC->Addr.Net[0].CurrentMacAddressSet) {
334 /* Set the current logical MAC address to the permanent one. */
335 pAC->Addr.Net[0].CurrentMacAddress =
336 pAC->Addr.Net[0].PermanentMacAddress;
337 pAC->Addr.Net[0].CurrentMacAddressSet = SK_TRUE;
338 }
339
340 /* Set the current logical MAC address. */
341 pAC->Addr.Port[pAC->Addr.Net[0].ActivePort].Exact[0] =
342 pAC->Addr.Net[0].CurrentMacAddress;
343
344 #if SK_MAX_NETS > 1
345 /* Set logical MAC address for net 2 to (log | 3). */
346 if (!pAC->Addr.Net[1].CurrentMacAddressSet) {
347 pAC->Addr.Net[1].PermanentMacAddress =
348 pAC->Addr.Net[0].PermanentMacAddress;
349 pAC->Addr.Net[1].PermanentMacAddress.a[5] |= 3;
350 /* Set the current logical MAC address to the permanent one. */
351 pAC->Addr.Net[1].CurrentMacAddress =
352 pAC->Addr.Net[1].PermanentMacAddress;
353 pAC->Addr.Net[1].CurrentMacAddressSet = SK_TRUE;
354 }
355 #endif /* SK_MAX_NETS > 1 */
356
357 #ifdef xDEBUG
358 SK_DBG_MSG(
359 pAC,
360 SK_DBGMOD_ADDR,
361 SK_DBGCAT_INIT,
362 ("Permanent MAC Address: %02X %02X %02X %02X %02X %02X\n",
363 pAC->Addr.PermanentMacAddress.a[0],
364 pAC->Addr.PermanentMacAddress.a[1],
365 pAC->Addr.PermanentMacAddress.a[2],
366 pAC->Addr.PermanentMacAddress.a[3],
367 pAC->Addr.PermanentMacAddress.a[4],
368 pAC->Addr.PermanentMacAddress.a[5]))
369 SK_DBG_MSG(
370 pAC,
371 SK_DBGMOD_ADDR,
372 SK_DBGCAT_INIT,
373 ("Logical MAC Address: %02X %02X %02X %02X %02X %02X\n",
374 pAC->Addr.CurrentMacAddress.a[0],
375 pAC->Addr.CurrentMacAddress.a[1],
376 pAC->Addr.CurrentMacAddress.a[2],
377 pAC->Addr.CurrentMacAddress.a[3],
378 pAC->Addr.CurrentMacAddress.a[4],
379 pAC->Addr.CurrentMacAddress.a[5]))
380 #endif /* DEBUG */
381
382 #if 0
383 /* Don't do this here ... */
384
385 (void)SkAddrMcUpdate(pAC, IoC, pAC->Addr.ActivePort);
386 #endif /* 0 */
387
388 for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
389 pAPort = &pAC->Addr.Port[i];
390
391 /* Read permanent port addresses from Control Register File. */
392 for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
393 InAddr = (SK_U8 *)&pAPort->PermanentMacAddress.a[j];
394 SK_IN8(IoC, B2_MAC_2 + 8 * i + j, InAddr);
395 }
396
397 if (!pAPort->CurrentMacAddressSet) {
398 /*
399 * Set the current and previous physical MAC address
400 * of this port to its permanent MAC address.
401 */
402 pAPort->CurrentMacAddress = pAPort->PermanentMacAddress;
403 pAPort->PreviousMacAddress = pAPort->PermanentMacAddress;
404 pAPort->CurrentMacAddressSet = SK_TRUE;
405 }
406
407 /* Set port's current MAC addresses. */
408 OutAddr = (SK_U16 *)&pAPort->CurrentMacAddress.a[0];
409 XM_OUTADDR(IoC, i, XM_SA, OutAddr);
410
411 #ifdef xDEBUG
412 SK_DBG_MSG(
413 pAC,
414 SK_DBGMOD_ADDR,
415 SK_DBGCAT_INIT,
416 ("Permanent Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
417 pAPort->PermanentMacAddress.a[0],
418 pAPort->PermanentMacAddress.a[1],
419 pAPort->PermanentMacAddress.a[2],
420 pAPort->PermanentMacAddress.a[3],
421 pAPort->PermanentMacAddress.a[4],
422 pAPort->PermanentMacAddress.a[5]))
423 SK_DBG_MSG(
424 pAC,
425 SK_DBGMOD_ADDR,
426 SK_DBGCAT_INIT,
427 ("Phsical MAC Address: %02X %02X %02X %02X %02X %02X\n",
428 pAPort->CurrentMacAddress.a[0],
429 pAPort->CurrentMacAddress.a[1],
430 pAPort->CurrentMacAddress.a[2],
431 pAPort->CurrentMacAddress.a[3],
432 pAPort->CurrentMacAddress.a[4],
433 pAPort->CurrentMacAddress.a[5]))
434 #endif /* DEBUG */
435 }
436 /* pAC->Addr.InitDone = SK_INIT_IO; */
437 break;
438
439 case SK_INIT_RUN:
440 #ifdef DEBUG
441 for (i = 0; i < SK_MAX_MACS; i++) {
442 if (pAC->Addr.Port[i].NextExactMatchRlmt <
443 SK_ADDR_FIRST_MATCH_RLMT) {
444 Next0[i] |= 16;
445 }
446 }
447 #endif /* DEBUG */
448
449 /* pAC->Addr.InitDone = SK_INIT_RUN; */
450 break;
451
452 default: /* error */
453 break;
454 }
455
456 return (SK_ADDR_SUCCESS);
457 } /* SkAddrInit */
458
459
460 /******************************************************************************
461 *
462 * SkAddrMcClear - clear the multicast table
463 *
464 * Description:
465 * This routine clears the multicast table
466 * (either entry 2 or entries 3-16 and InexactFilter) of the given port.
467 * If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated
468 * immediately.
469 *
470 * Context:
471 * runtime, pageable
472 * may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY
473 * may be called after SK_INIT_IO without limitation
474 *
475 * Returns:
476 * SK_ADDR_SUCCESS
477 * SK_ADDR_ILLEGAL_PORT
478 */
479 int SkAddrMcClear(
480 SK_AC *pAC, /* adapter context */
481 SK_IOC IoC, /* I/O context */
482 SK_U32 PortNumber, /* Index of affected port */
483 int Flags) /* permanent/non-perm, sw-only */
484 {
485 int i;
486
487 if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
488 return (SK_ADDR_ILLEGAL_PORT);
489 }
490
491 if (Flags & SK_ADDR_PERMANENT) {
492
493 /* Clear RLMT multicast addresses. */
494 pAC->Addr.Port[PortNumber].NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
495 }
496 else { /* not permanent => DRV */
497
498 /* Clear InexactFilter. */
499
500 for (i = 0; i < 8; i++) {
501 pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
502 }
503
504 /* Clear DRV multicast addresses. */
505
506 pAC->Addr.Port[PortNumber].NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV;
507 }
508
509 if (!(Flags & SK_MC_SW_ONLY)) {
510 (void)SkAddrMcUpdate(pAC, IoC, PortNumber);
511 }
512
513 return (SK_ADDR_SUCCESS);
514 } /* SkAddrMcClear */
515
516 #ifndef SK_ADDR_CHEAT
517
518 /******************************************************************************
519 *
520 * SkCrc32McHash - hash multicast address
521 *
522 * Description:
523 * This routine computes the hash value for a multicast address.
524 *
525 * Notes:
526 * The code was adapted from the XaQti data sheet.
527 *
528 * Context:
529 * runtime, pageable
530 *
531 * Returns:
532 * Hash value of multicast address.
533 */
534 unsigned SkCrc32McHash(
535 unsigned char *pMc) /* Multicast address */
536 {
537 unsigned Idx;
538 unsigned Bit;
539 unsigned Data;
540 unsigned Crc;
541
542 Crc = 0xFFFFFFFFUL;
543 for (Idx = 0; Idx < SK_MAC_ADDR_LEN; Idx++) {
544 Data = *pMc++;
545 for (Bit = 0; Bit < 8; Bit++, Data >>= 1) {
546 Crc = (Crc >> 1) ^ (((Crc ^ Data) & 1) ? CRC32_POLY : 0);
547 }
548 }
549
550 return (Crc & ((1 << HASH_BITS) - 1));
551 } /* SkCrc32McHash */
552
553 #endif /* not SK_ADDR_CHEAT */
554
555 /******************************************************************************
556 *
557 * SkAddrMcAdd - add a multicast address to a port
558 *
559 * Description:
560 * This routine enables reception for a given address on the given port.
561 *
562 * Notes:
563 * The return code is only valid for SK_PROM_MODE_NONE.
564 *
565 * In the current version, only RLMT may add addresses to the non-active
566 * port.
567 *
568 * The multicast bit is only checked if there are no free exact match
569 * entries.
570 *
571 * Context:
572 * runtime, pageable
573 * may be called after SK_INIT_DATA
574 *
575 * Returns:
576 * SK_MC_FILTERING_EXACT
577 * SK_MC_FILTERING_INEXACT
578 * SK_MC_ILLEGAL_ADDRESS
579 * SK_MC_ILLEGAL_PORT
580 * SK_MC_RLMT_OVERFLOW
581 */
582 int SkAddrMcAdd(
583 SK_AC *pAC, /* adapter context */
584 SK_IOC IoC, /* I/O context */
585 SK_U32 PortNumber, /* Port Number */
586 SK_MAC_ADDR *pMc, /* multicast address to be added */
587 int Flags) /* permanent/non-permanent */
588 {
589 int i;
590 SK_U8 Inexact;
591 #ifndef SK_ADDR_CHEAT
592 unsigned HashBit;
593 #endif /* !defined(SK_ADDR_CHEAT) */
594
595 if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
596 return (SK_ADDR_ILLEGAL_PORT);
597 }
598
599 if (Flags & SK_ADDR_PERMANENT) {
600 #ifdef DEBUG
601 if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt <
602 SK_ADDR_FIRST_MATCH_RLMT) {
603 Next0[PortNumber] |= 1;
604 return (SK_MC_RLMT_OVERFLOW);
605 }
606 #endif /* DEBUG */
607
608 if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt >
609 SK_ADDR_LAST_MATCH_RLMT) {
610 return (SK_MC_RLMT_OVERFLOW);
611 }
612
613 /* Set an RLMT multicast address. */
614
615 pAC->Addr.Port[PortNumber].Exact[
616 pAC->Addr.Port[PortNumber].NextExactMatchRlmt++] = *pMc;
617
618 return (SK_MC_FILTERING_EXACT);
619 }
620
621 #if 0
622 /* Not PERMANENT => DRV */
623 if (PortNumber != pAC->Addr.ActivePort) {
624 /* Only RLMT is allowed to do this. */
625 return (SK_MC_ILLEGAL_PORT);
626 }
627 #endif /* 0 */
628
629 #ifdef DEBUG
630 if (pAC->Addr.Port[PortNumber].NextExactMatchDrv <
631 SK_ADDR_FIRST_MATCH_DRV) {
632 Next0[PortNumber] |= 2;
633 return (SK_MC_RLMT_OVERFLOW);
634 }
635 #endif /* DEBUG */
636
637 if (pAC->Addr.Port[PortNumber].NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) {
638
639 /* Set exact match entry. */
640 pAC->Addr.Port[PortNumber].Exact[
641 pAC->Addr.Port[PortNumber].NextExactMatchDrv++] = *pMc;
642
643 /* Clear InexactFilter. */
644 for (i = 0; i < 8; i++) {
645 pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
646 }
647 }
648 else {
649 if (!(pMc->a[0] & SK_MC_BIT)) {
650 /*
651 * Hashing only possible with
652 * multicast addresses.
653 */
654 return (SK_MC_ILLEGAL_ADDRESS);
655 }
656 #ifndef SK_ADDR_CHEAT
657 /* Compute hash value of address. */
658 HashBit = 63 - SkCrc32McHash(&pMc->a[0]);
659
660 /* Add bit to InexactFilter. */
661 pAC->Addr.Port[PortNumber].InexactFilter.Bytes[HashBit / 8] |=
662 1 << (HashBit % 8);
663 #else /* SK_ADDR_CHEAT */
664 /* Set all bits in InexactFilter. */
665 for (i = 0; i < 8; i++) {
666 pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0xFF;
667 }
668 #endif /* SK_ADDR_CHEAT */
669 }
670
671 for (Inexact = 0, i = 0; i < 8; i++) {
672 Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
673 }
674
675 if (Inexact == 0 && pAC->Addr.Port[PortNumber].PromMode == 0) {
676 return (SK_MC_FILTERING_EXACT);
677 }
678 else {
679 return (SK_MC_FILTERING_INEXACT);
680 }
681 } /* SkAddrMcAdd */
682
683
684 /******************************************************************************
685 *
686 * SkAddrMcUpdate - update the HW MC address table and set the MAC address
687 *
688 * Description:
689 * This routine enables reception of the addresses contained in a local
690 * table for a given port.
691 * It also programs the port's current physical MAC address.
692 *
693 * Notes:
694 * The return code is only valid for SK_PROM_MODE_NONE.
695 *
696 * Context:
697 * runtime, pageable
698 * may be called after SK_INIT_IO
699 *
700 * Returns:
701 * SK_MC_FILTERING_EXACT
702 * SK_MC_FILTERING_INEXACT
703 * SK_ADDR_ILLEGAL_PORT
704 */
705 int SkAddrMcUpdate(
706 SK_AC *pAC, /* adapter context */
707 SK_IOC IoC, /* I/O context */
708 SK_U32 PortNumber) /* Port Number */
709 {
710 SK_U32 i;
711 SK_U8 Inexact;
712 SK_U16 *OutAddr;
713 SK_U16 LoMode; /* Lower 16 bits of XMAC Mode Reg. */
714 SK_ADDR_PORT *pAPort;
715
716 if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
717 return (SK_ADDR_ILLEGAL_PORT);
718 }
719
720 SK_DBG_MSG(
721 pAC,
722 SK_DBGMOD_ADDR,
723 SK_DBGCAT_CTRL,
724 ("SkAddrMcUpdate on Port %u.\n", PortNumber))
725
726 pAPort = &pAC->Addr.Port[PortNumber];
727
728 #ifdef DEBUG
729 SK_DBG_MSG(
730 pAC,
731 SK_DBGMOD_ADDR,
732 SK_DBGCAT_CTRL,
733 ("Next0 on Port %d: %d\n", PortNumber, Next0[PortNumber]))
734 #endif /* DEBUG */
735
736 /* Start with 0 to also program the logical MAC address. */
737 for (i = 0; i < pAPort->NextExactMatchRlmt; i++) {
738 /* Set exact match address i on HW. */
739 OutAddr = (SK_U16 *)&pAPort->Exact[i].a[0];
740 XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr);
741 }
742
743 /* Clear other permanent exact match addresses on HW. */
744 if (pAPort->NextExactMatchRlmt <= SK_ADDR_LAST_MATCH_RLMT) {
745 SkXmClrExactAddr(
746 pAC,
747 IoC,
748 PortNumber,
749 pAPort->NextExactMatchRlmt,
750 SK_ADDR_LAST_MATCH_RLMT);
751 }
752
753 for (i = pAPort->FirstExactMatchDrv; i < pAPort->NextExactMatchDrv; i++) {
754 OutAddr = (SK_U16 *)&pAPort->Exact[i].a[0];
755 XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr);
756 }
757
758 /* Clear other non-permanent exact match addresses on HW. */
759 if (pAPort->NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) {
760 SkXmClrExactAddr(
761 pAC,
762 IoC,
763 PortNumber,
764 pAPort->NextExactMatchDrv,
765 SK_ADDR_LAST_MATCH_DRV);
766 }
767
768 for (Inexact = 0, i = 0; i < 8; i++) {
769 Inexact |= pAPort->InexactFilter.Bytes[i];
770 }
771
772 if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) {
773 /* Set all bits in 64-bit hash register. */
774 XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash);
775
776 /* Set bit 15 in mode register. */
777 XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
778 LoMode |= XM_MD_ENA_HSH;
779 XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
780 }
781 else if (Inexact != 0) {
782 /* Set 64-bit hash register to InexactFilter. */
783 XM_OUTHASH(IoC, PortNumber, XM_HSM, &pAPort->InexactFilter.Bytes[0]);
784
785 /* Set bit 15 in mode register. */
786 XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
787 LoMode |= XM_MD_ENA_HSH;
788 XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
789 }
790 else {
791 /* Clear bit 15 in mode register. */
792 XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
793 LoMode &= ~XM_MD_ENA_HSH;
794 XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
795 }
796
797 if (pAPort->PromMode != SK_PROM_MODE_NONE) {
798 (void)SkAddrPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode);
799 }
800
801 /* Set port's current MAC address. */
802 OutAddr = (SK_U16 *)&pAPort->CurrentMacAddress.a[0];
803 XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr);
804
805 #ifdef xDEBUG
806 for (i = 0; i < pAPort->NextExactMatchRlmt; i++) {
807 SK_U8 InAddr8[6];
808 SK_U16 *InAddr;
809
810 /* Get exact match address i from port PortNumber. */
811 InAddr = (SK_U16 *)&InAddr8[0];
812 XM_INADDR(IoC, PortNumber, XM_EXM(i), InAddr);
813 SK_DBG_MSG(
814 pAC,
815 SK_DBGMOD_ADDR,
816 SK_DBGCAT_CTRL,
817 ("MC address %d on Port %u: %02x %02x %02x %02x %02x %02x -- %02x %02x %02x %02x %02x %02x.\n",
818 i,
819 PortNumber,
820 InAddr8[0],
821 InAddr8[1],
822 InAddr8[2],
823 InAddr8[3],
824 InAddr8[4],
825 InAddr8[5],
826 pAPort->Exact[i].a[0],
827 pAPort->Exact[i].a[1],
828 pAPort->Exact[i].a[2],
829 pAPort->Exact[i].a[3],
830 pAPort->Exact[i].a[4],
831 pAPort->Exact[i].a[5]))
832 }
833 #endif /* DEBUG */
834
835 /* Determine return value. */
836 if (Inexact == 0 && pAPort->PromMode == 0) {
837 return (SK_MC_FILTERING_EXACT);
838 }
839 else {
840 return (SK_MC_FILTERING_INEXACT);
841 }
842 } /* SkAddrMcUpdate */
843
844
845 /******************************************************************************
846 *
847 * SkAddrOverride - override a port's MAC address
848 *
849 * Description:
850 * This routine overrides the MAC address of one port.
851 *
852 * Context:
853 * runtime, pageable
854 * may be called after SK_INIT_IO
855 *
856 * Returns:
857 * SK_ADDR_SUCCESS if successful.
858 * SK_ADDR_DUPLICATE_ADDRESS if duplicate MAC address.
859 * SK_ADDR_MULTICAST_ADDRESS if multicast or broadcast address.
860 * SK_ADDR_TOO_EARLY if SK_INIT_IO was not executed before.
861 */
862 int SkAddrOverride(
863 SK_AC *pAC, /* adapter context */
864 SK_IOC IoC, /* I/O context */
865 SK_U32 PortNumber, /* Port Number */
866 SK_MAC_ADDR *pNewAddr, /* new MAC address */
867 int Flags) /* logical/physical MAC address */
868 {
869 SK_EVPARA Para;
870 SK_U32 NetNumber;
871 SK_U32 i;
872 SK_U16 *OutAddr;
873
874 NetNumber = pAC->Rlmt.Port[PortNumber].Net->NetNumber;
875
876 if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
877 return (SK_ADDR_ILLEGAL_PORT);
878 }
879
880 if (pNewAddr != NULL && (pNewAddr->a[0] & SK_MC_BIT) != 0) {
881 return (SK_ADDR_MULTICAST_ADDRESS);
882 }
883
884 if (!pAC->Addr.Net[NetNumber].CurrentMacAddressSet) {
885 return (SK_ADDR_TOO_EARLY);
886 }
887
888 if (Flags & SK_ADDR_SET_LOGICAL) { /* Activate logical MAC address. */
889 /* Parameter *pNewAddr is ignored. */
890 for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
891 if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
892 return (SK_ADDR_TOO_EARLY);
893 }
894 }
895
896 /* Set PortNumber to number of net's active port. */
897 PortNumber = pAC->Rlmt.Net[NetNumber].
898 Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
899
900 pAC->Addr.Port[PortNumber].Exact[0] =
901 pAC->Addr.Net[NetNumber].CurrentMacAddress;
902
903 /* Write address to first exact match entry of active port. */
904 (void)SkAddrMcUpdate(pAC, IoC, PortNumber);
905 }
906 else if (Flags & SK_ADDR_CLEAR_LOGICAL) {
907 /* Deactivate logical MAC address. */
908 /* Parameter *pNewAddr is ignored. */
909 for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
910 if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
911 return (SK_ADDR_TOO_EARLY);
912 }
913 }
914
915 /* Set PortNumber to number of net's active port. */
916 PortNumber = pAC->Rlmt.Net[NetNumber].
917 Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
918
919 for (i = 0; i < SK_MAC_ADDR_LEN; i++ ) {
920 pAC->Addr.Port[PortNumber].Exact[0].a[i] = 0;
921 }
922
923 /* Write address to first exact match entry of active port. */
924 (void)SkAddrMcUpdate(pAC, IoC, PortNumber);
925 }
926 else if (Flags & SK_ADDR_PHYSICAL_ADDRESS) { /* Physical MAC address. */
927 if (SK_ADDR_EQUAL(pNewAddr->a,
928 pAC->Addr.Net[NetNumber].CurrentMacAddress.a)) {
929 return (SK_ADDR_DUPLICATE_ADDRESS);
930 }
931
932 for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
933 if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
934 return (SK_ADDR_TOO_EARLY);
935 }
936
937 if (SK_ADDR_EQUAL(pNewAddr->a,
938 pAC->Addr.Port[i].CurrentMacAddress.a)) {
939 if (i == PortNumber) {
940 return (SK_ADDR_SUCCESS);
941 }
942 else {
943 return (SK_ADDR_DUPLICATE_ADDRESS);
944 }
945 }
946 }
947
948 pAC->Addr.Port[PortNumber].PreviousMacAddress =
949 pAC->Addr.Port[PortNumber].CurrentMacAddress;
950 pAC->Addr.Port[PortNumber].CurrentMacAddress = *pNewAddr;
951
952 /* Change port's address. */
953 OutAddr = (SK_U16 *)pNewAddr;
954 XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr);
955
956 /* Report address change to RLMT. */
957 Para.Para32[0] = PortNumber;
958 Para.Para32[0] = -1;
959 SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_PORT_ADDR, Para);
960 }
961 else { /* Logical MAC address. */
962 if (SK_ADDR_EQUAL(pNewAddr->a,
963 pAC->Addr.Net[NetNumber].CurrentMacAddress.a)) {
964 return (SK_ADDR_SUCCESS);
965 }
966
967 for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
968 if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
969 return (SK_ADDR_TOO_EARLY);
970 }
971
972 if (SK_ADDR_EQUAL(pNewAddr->a,
973 pAC->Addr.Port[i].CurrentMacAddress.a)) {
974 return (SK_ADDR_DUPLICATE_ADDRESS);
975 }
976 }
977
978 /* Set PortNumber to number of net's active port. */
979 PortNumber = pAC->Rlmt.Net[NetNumber].
980 Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
981
982 pAC->Addr.Net[NetNumber].CurrentMacAddress = *pNewAddr;
983 pAC->Addr.Port[PortNumber].Exact[0] = *pNewAddr;
984
985 #ifdef DEBUG
986 SK_DBG_MSG(
987 pAC,
988 SK_DBGMOD_ADDR,
989 SK_DBGCAT_CTRL,
990 ("Permanent MAC Address: %02X %02X %02X %02X %02X %02X\n",
991 pAC->Addr.Net[NetNumber].PermanentMacAddress.a[0],
992 pAC->Addr.Net[NetNumber].PermanentMacAddress.a[1],
993 pAC->Addr.Net[NetNumber].PermanentMacAddress.a[2],
994 pAC->Addr.Net[NetNumber].PermanentMacAddress.a[3],
995 pAC->Addr.Net[NetNumber].PermanentMacAddress.a[4],
996 pAC->Addr.Net[NetNumber].PermanentMacAddress.a[5]))
997 SK_DBG_MSG(
998 pAC,
999 SK_DBGMOD_ADDR,
1000 SK_DBGCAT_CTRL,
1001 ("New logical MAC Address: %02X %02X %02X %02X %02X %02X\n",
1002 pAC->Addr.Net[NetNumber].CurrentMacAddress.a[0],
1003 pAC->Addr.Net[NetNumber].CurrentMacAddress.a[1],
1004 pAC->Addr.Net[NetNumber].CurrentMacAddress.a[2],
1005 pAC->Addr.Net[NetNumber].CurrentMacAddress.a[3],
1006 pAC->Addr.Net[NetNumber].CurrentMacAddress.a[4],
1007 pAC->Addr.Net[NetNumber].CurrentMacAddress.a[5]))
1008 #endif /* DEBUG */
1009
1010 /* Write address to first exact match entry of active port. */
1011 (void)SkAddrMcUpdate(pAC, IoC, PortNumber);
1012 }
1013
1014 return (SK_ADDR_SUCCESS);
1015 } /* SkAddrOverride */
1016
1017
1018 /******************************************************************************
1019 *
1020 * SkAddrPromiscuousChange - set promiscuous mode for given port
1021 *
1022 * Description:
1023 * This routine manages promiscuous mode:
1024 * - none
1025 * - all LLC frames
1026 * - all MC frames
1027 *
1028 * Context:
1029 * runtime, pageable
1030 * may be called after SK_INIT_IO
1031 *
1032 * Returns:
1033 * SK_ADDR_SUCCESS
1034 * SK_ADDR_ILLEGAL_PORT
1035 */
1036 int SkAddrPromiscuousChange(
1037 SK_AC *pAC, /* adapter context */
1038 SK_IOC IoC, /* I/O context */
1039 SK_U32 PortNumber, /* port whose promiscuous mode changes */
1040 int NewPromMode) /* new promiscuous mode */
1041 {
1042 int i;
1043 SK_BOOL InexactModeBit;
1044 SK_U8 Inexact;
1045 SK_U8 HwInexact;
1046 SK_FILTER64 HwInexactFilter;
1047 SK_U16 LoMode; /* Lower 16 bits of XMAC Mode Register. */
1048 int CurPromMode = SK_PROM_MODE_NONE;
1049
1050 if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
1051 return (SK_ADDR_ILLEGAL_PORT);
1052 }
1053
1054 /* Read CurPromMode from Hardware. */
1055 XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
1056
1057 if (LoMode & XM_MD_ENA_PROM) {
1058 CurPromMode |= SK_PROM_MODE_LLC;
1059 }
1060
1061 for (Inexact = 0xFF, i = 0; i < 8; i++) {
1062 Inexact &= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
1063 }
1064 if (Inexact == 0xFF) {
1065 CurPromMode |= (pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_ALL_MC);
1066 }
1067 else {
1068 /* Read InexactModeBit (bit 15 in mode register). */
1069 XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
1070
1071 InexactModeBit = (LoMode & XM_MD_ENA_HSH) != 0;
1072
1073 /* Read 64-bit hash register from HW. */
1074 XM_INHASH(IoC, PortNumber, XM_HSM, &HwInexactFilter.Bytes[0]);
1075
1076 for (HwInexact = 0xFF, i = 0; i < 8; i++) {
1077 HwInexact &= HwInexactFilter.Bytes[i];
1078 }
1079
1080 if (InexactModeBit && (HwInexact == 0xFF)) {
1081 CurPromMode |= SK_PROM_MODE_ALL_MC;
1082 }
1083 }
1084
1085 pAC->Addr.Port[PortNumber].PromMode = NewPromMode;
1086
1087 if (NewPromMode == CurPromMode) {
1088 return (SK_ADDR_SUCCESS);
1089 }
1090
1091 if ((NewPromMode & SK_PROM_MODE_ALL_MC) &&
1092 !(CurPromMode & SK_PROM_MODE_ALL_MC)) { /* All MC. */
1093 /* Set all bits in 64-bit hash register. */
1094 XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash);
1095
1096 /* Set bit 15 in mode register. */
1097 XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
1098 LoMode |= XM_MD_ENA_HSH;
1099 XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
1100 }
1101 else if ((CurPromMode & SK_PROM_MODE_ALL_MC) &&
1102 !(NewPromMode & SK_PROM_MODE_ALL_MC)) { /* Norm MC. */
1103 for (Inexact = 0, i = 0; i < 8; i++) {
1104 Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
1105 }
1106 if (Inexact == 0) {
1107 /* Clear bit 15 in mode register. */
1108 XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
1109 LoMode &= ~XM_MD_ENA_HSH;
1110 XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
1111 }
1112 else {
1113 /* Set 64-bit hash register to InexactFilter. */
1114 XM_OUTHASH(
1115 IoC,
1116 PortNumber,
1117 XM_HSM,
1118 &pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0]);
1119
1120 /* Set bit 15 in mode register. */
1121 XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
1122 LoMode |= XM_MD_ENA_HSH;
1123 XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
1124 }
1125 }
1126
1127 if ((NewPromMode & SK_PROM_MODE_LLC) &&
1128 !(CurPromMode & SK_PROM_MODE_LLC)) { /* Prom. LLC */
1129 /* Set promiscuous bit in mode register. */
1130 XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
1131
1132 #if 0
1133 /* Receive MAC frames. */
1134 LoMode |= XM_MD_RX_MCTRL;
1135 #endif /* 0 */
1136
1137 LoMode |= XM_MD_ENA_PROM;
1138 XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
1139 }
1140 else if ((CurPromMode & SK_PROM_MODE_LLC) &&
1141 !(NewPromMode & SK_PROM_MODE_LLC)) { /* Norm. LLC. */
1142 /* Clear promiscuous bit in mode register. */
1143 XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
1144
1145 #if 0
1146 /* Don't receive MAC frames. */
1147 LoMode &= ~XM_MD_RX_MCTRL;
1148 #endif /* 0 */
1149
1150 LoMode &= ~XM_MD_ENA_PROM;
1151 XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
1152 }
1153
1154 return (SK_ADDR_SUCCESS);
1155 } /* SkAddrPromiscuousChange */
1156
1157
1158 /******************************************************************************
1159 *
1160 * SkAddrSwap - swap address info
1161 *
1162 * Description:
1163 * This routine swaps address info of two ports.
1164 *
1165 * Context:
1166 * runtime, pageable
1167 * may be called after SK_INIT_IO
1168 *
1169 * Returns:
1170 * SK_ADDR_SUCCESS
1171 * SK_ADDR_ILLEGAL_PORT
1172 */
1173 int SkAddrSwap(
1174 SK_AC *pAC, /* adapter context */
1175 SK_IOC IoC, /* I/O context */
1176 SK_U32 FromPortNumber, /* Port1 Index */
1177 SK_U32 ToPortNumber) /* Port2 Index */
1178 {
1179 int i;
1180 SK_U8 Byte;
1181 SK_MAC_ADDR MacAddr;
1182 SK_U32 DWord;
1183
1184 if (FromPortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
1185 return (SK_ADDR_ILLEGAL_PORT);
1186 }
1187
1188 if (ToPortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
1189 return (SK_ADDR_ILLEGAL_PORT);
1190 }
1191
1192 if (pAC->Rlmt.Port[FromPortNumber].Net != pAC->Rlmt.Port[ToPortNumber].Net) {
1193 return (SK_ADDR_ILLEGAL_PORT);
1194 }
1195
1196 /*
1197 * Swap
1198 * - Exact Match Entries
1199 * - FirstExactMatchRlmt;
1200 * - NextExactMatchRlmt;
1201 * - FirstExactMatchDrv;
1202 * - NextExactMatchDrv;
1203 * - 64-bit filter
1204 * - Promiscuous Mode
1205 * of ports.
1206 */
1207
1208 for (i = 0; i < SK_ADDR_EXACT_MATCHES; i++) {
1209 MacAddr = pAC->Addr.Port[FromPortNumber].Exact[i];
1210 pAC->Addr.Port[FromPortNumber].Exact[i] =
1211 pAC->Addr.Port[ToPortNumber].Exact[i];
1212 pAC->Addr.Port[ToPortNumber].Exact[i] = MacAddr;
1213 }
1214
1215 for (i = 0; i < 8; i++) {
1216 Byte = pAC->Addr.Port[FromPortNumber].InexactFilter.Bytes[i];
1217 pAC->Addr.Port[FromPortNumber].InexactFilter.Bytes[i] =
1218 pAC->Addr.Port[ToPortNumber].InexactFilter.Bytes[i];
1219 pAC->Addr.Port[ToPortNumber].InexactFilter.Bytes[i] = Byte;
1220 }
1221
1222 i = pAC->Addr.Port[FromPortNumber].PromMode;
1223 pAC->Addr.Port[FromPortNumber].PromMode = pAC->Addr.Port[ToPortNumber].PromMode;
1224 pAC->Addr.Port[ToPortNumber].PromMode = i;
1225
1226 DWord = pAC->Addr.Port[FromPortNumber].FirstExactMatchRlmt;
1227 pAC->Addr.Port[FromPortNumber].FirstExactMatchRlmt =
1228 pAC->Addr.Port[ToPortNumber].FirstExactMatchRlmt;
1229 pAC->Addr.Port[ToPortNumber].FirstExactMatchRlmt = DWord;
1230
1231 DWord = pAC->Addr.Port[FromPortNumber].NextExactMatchRlmt;
1232 pAC->Addr.Port[FromPortNumber].NextExactMatchRlmt =
1233 pAC->Addr.Port[ToPortNumber].NextExactMatchRlmt;
1234 pAC->Addr.Port[ToPortNumber].NextExactMatchRlmt = DWord;
1235
1236 DWord = pAC->Addr.Port[FromPortNumber].FirstExactMatchDrv;
1237 pAC->Addr.Port[FromPortNumber].FirstExactMatchDrv =
1238 pAC->Addr.Port[ToPortNumber].FirstExactMatchDrv;
1239 pAC->Addr.Port[ToPortNumber].FirstExactMatchDrv = DWord;
1240
1241 DWord = pAC->Addr.Port[FromPortNumber].NextExactMatchDrv;
1242 pAC->Addr.Port[FromPortNumber].NextExactMatchDrv =
1243 pAC->Addr.Port[ToPortNumber].NextExactMatchDrv;
1244 pAC->Addr.Port[ToPortNumber].NextExactMatchDrv = DWord;
1245
1246 /* CAUTION: Solution works if only ports of one adapter are in use. */
1247 for (i = 0; (SK_U32)i < pAC->Rlmt.Net[pAC->Rlmt.Port[ToPortNumber].
1248 Net->NetNumber].NumPorts; i++) {
1249 if (pAC->Rlmt.Net[pAC->Rlmt.Port[ToPortNumber].Net->NetNumber].
1250 Port[i]->PortNumber == ToPortNumber) {
1251 pAC->Addr.Net[pAC->Rlmt.Port[ToPortNumber].Net->NetNumber].
1252 ActivePort = i;
1253 /* 20001207 RA: Was "ToPortNumber;". */
1254
1255 }
1256 }
1257 (void)SkAddrMcUpdate(pAC, IoC, FromPortNumber);
1258 (void)SkAddrMcUpdate(pAC, IoC, ToPortNumber);
1259
1260 return (SK_ADDR_SUCCESS);
1261 } /* SkAddrSwap */
1262
1263 #ifdef __cplusplus
1264 }
1265 #endif /* __cplusplus */
1266
1267