|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24: /* Copyright (c) 1993 NeXT Computer, Inc. All rights reserved.
25: *
26: * TokenRing.m - TokenRing device-independent abstract superclass
27: *
28: * The TokenRing superclass contains the device-independent functions
29: * that are common to most token-ring drivers. The hardware-specific
30: * driver should be a subclass of TokenRing.
31: *
32: * HISTORY
33: * 25-Jan-93 Joel Greenblatt at NeXT
34: * created
35: *
36: */
37:
38:
39: #define MACH_USER_API 1
40:
41:
42: #import <mach/mach_types.h>
43: #import <mach/message.h>
44: #import <machkit/NXLock.h>
45: #import <driverkit/generalFuncs.h>
46: #import <driverkit/interruptMsg.h>
47: #import <driverkit/kernelDriver.h>
48: #import <netinet/in.h>
49: #import <kernserv/prototypes.h>
50: #import <net/tokensr.h>
51: #import <sys/errno.h>
52:
53: #import <driverkit/IOTokenRing.h>
54:
55: static void TokenRingTimeout(IOTokenRing *device);
56:
57: static char TRDeviceName[] = "tr";
58: static char TRDeviceType[] = "TokenRing";
59: static int TRDeviceCount = 0;
60:
61: extern int ipforwarding; // flag in kernel to control ip lan-to-lan routing
62:
63: /*
64: * Attach virtual drivers
65: */
66: extern void vtrip_config(int unit, int flags, int mtu, int tokpri);
67:
68: #define IP_SRCROUTING 0x1 /* enable IP source routing */
69:
70:
71: /*
72: * Configuration strings in Instance.table
73: */
74: static const char ITRingSpeed[] = "Ring Speed";
75: static const char ITNodeAddress[] = "Node Address";
76: static const char ITGroupAddress[] = "Group Address";
77: static const char ITFunctionalAddress[] = "Functional Address";
78: static const char ITEarlyToken[] = "16Mb Early Token";
79: static const char ITAutoRecovery[] = "Auto Recovery";
80: static const char ITIPAttach[] = "IP Attach";
81: static const char ITIPMtu[] = "IP Mtu";
82: static const char ITIPTokenPriority[] = "IP Token Priority";
83: static const char ITIPSourceRouting[] = "IP 802.5 Source Routing";
84:
85: static const char ITipFowarding[] = "IP LAN-to-LAN Routing";
86:
87:
88: @interface DriverCmdtr:Object
89: {
90: @private
91: port_t _driverPort_kern;
92: id _interLock;
93: #define OPDONE 1
94: #define BUSY 2
95: #define IDLE 3
96: int _oper;
97: #define RESET_ON 1
98: #define RESET_OFF 2
99: #define TERMINATE 4
100: int _ret;
101: }
102: @end
103:
104: @implementation DriverCmdtr
105:
106: - initPort:(port_t)port
107: {
108: [super init];
109:
110: _interLock = [[NXConditionLock alloc] initWith:IDLE];
111: _driverPort_kern = IOGetKernPort(port);
112:
113: return self;
114: }
115:
116:
117: - free
118: {
119: [_interLock free];
120:
121: port_release(_driverPort_kern);
122:
123: return [super free];
124: }
125:
126: - (int)oper
127: {
128: return (_oper);
129: }
130:
131: - (void)done:(int)ret
132: {
133: if ([_interLock condition] == BUSY) {
134: [_interLock lock];
135: _ret = ret;
136: [_interLock unlockWith:OPDONE];
137: }
138: }
139:
140: - (int)send:(int)oper
141: {
142: msg_header_t msg = { 0 };
143: int result;
144:
145: [_interLock lockWhen:IDLE];
146:
147: _oper = oper;
148:
149: msg.msg_size = sizeof (msg);
150: msg.msg_remote_port = _driverPort_kern;
151: msg.msg_id = IO_COMMAND_MSG;
152:
153: [_interLock unlockWith:BUSY];
154:
155: result = msg_send_from_kernel(&msg, MSG_OPTION_NONE, 0);
156: if (result == SEND_SUCCESS) {
157: [_interLock lockWhen:OPDONE];
158: result = _ret;
159: }
160: else
161: [_interLock lock];
162:
163: [_interLock unlockWith:IDLE];
164:
165: return (result);
166: }
167:
168: @end
169:
170: @implementation IOTokenRing
171:
172: /*
173: * Private Methods
174: */
175:
176: /*
177: * Set maximum packet size based on ring speed. Unfortunately, there may
178: * be different interpretations for token-ring. Subclass can override if it
179: * disagrees, or must reduce due to implementation limitations.
180: */
181: -(void)_set8025FrameSizes
182: {
183: /*
184: * The maximum allowable packet size is a function of ring speed
185: * (per IEEE 802.5 standard).
186: */
187: if(_ringSpeed == 4) {
188: _maxInfoFieldSize = MAC_INFO_4MB;
189: }
190: if(_ringSpeed == 16) {
191: _maxInfoFieldSize = MAC_INFO_16MB;
192: }
193: }
194:
195: /*
196: * Get info from Instance.table (some params are just saved for
197: * optional subclass use).
198: */
199: - (int)_getInstanceTable:(IODeviceDescription *)devDesc
200: {
201:
202: IOConfigTable *confTable;
203: const char *s;
204:
205: confTable = [devDesc configTable];
206: if(confTable == nil) {
207: IOLog("%s: couldn't get Instance%d.table\n",
208: [self name], [self unit]);
209: return 1;
210: }
211:
212: /*
213: * MAC layer parms ...
214: */
215:
216: s = [confTable valueForStringKey: ITRingSpeed]; // ring speed
217: if (!strcmp(s, "4"))
218: _ringSpeed = 4;
219: else if (strcmp(s, "16") == 0)
220: _ringSpeed = 16;
221: else {
222: IOLog("%s: invalid ring speed in Instance.table\n", [self name]);
223: _ringSpeed = 16;
224: }
225: [confTable freeString:s];
226:
227: s = [confTable valueForStringKey: ITNodeAddress]; // Node address
228: #if 0
229: /*
230: * Unsupported for now. The subclass is free to access the config
231: * table directly to read the node address and use it.
232: */
233: if (strcmp(s, "")) {
234: //_nodeAddress
235: IOLog("%s: cannot override burned-in addr\n", [self name]);
236: }
237: else
238: IOLog("%s: will use burned-in node address\n", [self name]);
239: #endif
240: [confTable freeString:s];
241:
242: #if 0
243: s = [confTable valueForStringKey: ITGroupAddress]; // Group addr
244: if (strcmp(s, "")) {
245: //_groupAddress
246: IOLog("%s: cannot set Group addr\n", [self name]);
247: }
248: else
249: IOLog("%s: no Group Addresses enabled\n", [self name]);
250: [confTable freeString:s];
251:
252: s = [confTable valueForStringKey: ITFunctionalAddress]; // Func addr
253: if (strcmp(s, "")) {
254: //_functionalAddress
255: IOLog("%s: cannot set Functional addr\n", [self name]);
256: }
257: else
258: IOLog("%s: no Functional Addresses enabled\n", [self name]);
259: [confTable freeString:s];
260: #endif 0
261:
262: s = [confTable valueForStringKey: ITEarlyToken]; // early token
263: if (!strcmp(s, "YES"))
264: _flags._isEarlyTokenEnabled = 1;
265: else
266: _flags._isEarlyTokenEnabled = 0;
267: [confTable freeString:s];
268:
269: s = [confTable valueForStringKey: ITAutoRecovery]; // auto recov
270: if (!strcmp(s, "YES"))
271: _flags._shouldAutoRecover = 1;
272: else
273: _flags._shouldAutoRecover = 0;
274: [confTable freeString:s];
275:
276: #if 0
277: /*
278: * IP params ...
279: */
280:
281: s = [confTable valueForStringKey: ITIPAttach]; // attach i/f
282: if (!strcmp(s, "YES"))
283: _flags._shouldAttachIP = 1;
284: else
285: _flags._shouldAttachIP = 0;
286: [confTable freeString:s];
287:
288: s = [confTable valueForStringKey: ITIPMtu]; // mtu
289: _ipMtu = strtol(s, 0, 10);
290: [confTable freeString:s];
291:
292: s = [confTable valueForStringKey: ITIPTokenPriority]; // token pri
293: if (!strcmp(s, "DEFAULT"))
294: _ipTokenPriority = 8;
295: else
296: _ipTokenPriority = strtol(s, 0, 10);
297: [confTable freeString:s];
298:
299: s = [confTable valueForStringKey: ITIPSourceRouting]; // source rtng
300: if (!strcmp(s, "YES"))
301: _flags._doesIPSourceRouting = 1;
302: else
303: _flags._doesIPSourceRouting = 0;
304: [confTable freeString:s];
305:
306: /*
307: * Allow fowarding of packets between interfaces in a multi-homed
308: * host (a don't care for hosts with single i-faces). Note that
309: * if no param is specified we don't touch ipforwarding (as of
310: * this writing this parameter is left out of our Default.table).
311: */
312: s = [confTable valueForStringKey: ITipFowarding];
313: if (!strcmp(s, "YES"))
314: ipforwarding = 1;
315: if (!strcmp(s, "NO"))
316: ipforwarding = 0;
317: [confTable freeString:s];
318: #endif 0
319:
320: /*
321: * Set these defaults here for now. We'll support them in the instance
322: * table eventually.
323: */
324: _flags._shouldAttachIP = 1;
325: _ipMtu = 8100;
326: _ipTokenPriority = 8;
327: _flags._doesIPSourceRouting = 1;
328: ipforwarding = 0;
329:
330: return 0;
331: }
332:
333:
334: /*
335: * Public Methods
336: */
337:
338: /*
339: * Normally invoked from subclass method of same name.
340: */
341: - initFromDeviceDescription:(IODeviceDescription *)devDesc
342: {
343: char devName[8];
344: int unit;
345:
346: if ([super initFromDeviceDescription:devDesc] == nil)
347: return nil;
348:
349: if ([self startIOThread] != IO_R_SUCCESS) {
350: [self free];
351: return nil;
352: }
353:
354: unit = TRDeviceCount++;
355:
356: sprintf(devName, "%s%d", TRDeviceName, unit);
357: [self setName:devName];
358: [self setDeviceKind:TRDeviceType];
359: [self setUnit:unit];
360:
361: if([self _getInstanceTable:devDesc]) {
362: [self free];
363: return nil;
364: }
365:
366: _driverCmd = [[DriverCmdtr alloc] initPort:[self interruptPort]];
367:
368: [self _set8025FrameSizes];
369:
370: return self;
371: }
372:
373: - free
374: {
375: [self clearTimeout];
376: if (_driverCmd) {
377: [_driverCmd send:TERMINATE];
378: [_driverCmd free];
379: }
380: if (_netif)
381: [_netif free];
382: return [super free];
383: }
384:
385: /*
386: * Subclass must invoke this method to attach our networking interfaces
387: * (typically done after successful hardware init).
388: */
389: - (IONetwork *)attachToNetworkWithAddress:(token_addr_t)addrs
390: {
391: int vtripf = 0;
392: int i;
393:
394: [self registerDevice];
395:
396: _nodeAddress = addrs;
397:
398: /*
399: * Netif for "real" (hdw) driver interface.
400: */
401: _netif = [[IONetwork alloc] initForNetworkDevice:self
402: name:TRDeviceName unit:[self unit]
403: type:IFTYPE_TOKENRING
404: maxTransferUnit:_maxInfoFieldSize
405: flags:0];
406:
407: /*
408: * Netif for IP to get to us.
409: */
410: if(_flags._shouldAttachIP) {
411: if(_flags._doesIPSourceRouting) vtripf |= IP_SRCROUTING;
412: vtrip_config([self unit], vtripf, _ipMtu, _ipTokenPriority);
413: }
414:
415: /*
416: * Emit the node address
417: */
418: IOLog("%s: Token Ring Node address %02x:%02x:%02x:%02x:%02x:%02x\n",
419: [self name],
420: _nodeAddress.ta_byte[0],_nodeAddress.ta_byte[1],
421: _nodeAddress.ta_byte[2],_nodeAddress.ta_byte[3],
422: _nodeAddress.ta_byte[4],_nodeAddress.ta_byte[5]);
423:
424: #if 0
425: /*
426: * Emit the group address, if non-zero
427: */
428: for (i = 2 ; i < 4 ; ++i) {
429: if (_groupAddress.ta_byte[i]) {
430: IOLog("%s: Token Ring Group address "
431: "%02x:%02x:%02x,%02x:%02x:%02x\n",
432: [self name],
433: _groupAddress.ta_byte[0], _groupAddress.ta_byte[1],
434: _groupAddress.ta_byte[2], _groupAddress.ta_byte[3],
435: _groupAddress.ta_byte[4], _groupAddress.ta_byte[5]);
436: break;
437: }
438: }
439:
440: /*
441: * Emit the functional address, if non-zero
442: */
443:
444: for (i = 2 ; i < 4 ; ++i) {
445: if (_functionalAddress.ta_byte[i]) {
446: IOLog("%s: Token Ring Functional address "
447: "%02x:%02x:%02x,%02x:%02x:%02x\n",
448: [self name],
449: _functionalAddress.ta_byte[0], _functionalAddress.ta_byte[1],
450: _functionalAddress.ta_byte[2], _functionalAddress.ta_byte[3],
451: _functionalAddress.ta_byte[4], _functionalAddress.ta_byte[5]);
452: break;
453: }
454: }
455: #endif 0
456: return _netif;
457: }
458:
459: - (IONetwork *)networkInterface
460: {
461: return _netif;
462: }
463:
464: - (BOOL)isRunning
465: {
466: return (BOOL)_flags._isRunning;
467: }
468:
469: - (void)setRunning:(BOOL)running
470: {
471: _flags._isRunning = running;
472: }
473:
474: /*
475: * Implement driver timeouts.
476: */
477:
478: - (unsigned int)relativeTimeout
479: {
480: ns_time_t timestamp;
481:
482: if (_absTimeout == 0)
483: return (0);
484:
485: IOGetTimestamp(×tamp);
486:
487: if (_absTimeout <= timestamp) {
488: _absTimeout = 0; return (0);
489: }
490:
491: return ((unsigned int) ((_absTimeout - timestamp) / (1000 * 1000)));
492: }
493:
494: - (void)setRelativeTimeout:(unsigned int)timeout
495: {
496: if (_absTimeout > 0)
497: (void)ns_untimeout((func)TokenRingTimeout, self);
498:
499: IOGetTimestamp(&_absTimeout);
500:
501: _absTimeout += ((ns_time_t)timeout * (1000 * 1000));
502:
503: ns_abstimeout((func)TokenRingTimeout, self,
504: _absTimeout, CALLOUT_PRI_THREAD);
505: }
506:
507: - (void)clearTimeout
508: {
509: if (_absTimeout > 0) {
510: (void)ns_untimeout((func)TokenRingTimeout, self);
511: _absTimeout = 0;
512: }
513: }
514:
515: - (BOOL)earlyTokenEnabled
516: {
517: return (BOOL)_flags._isEarlyTokenEnabled;
518: }
519:
520: - (BOOL)shouldAutoRecover
521: {
522: return (BOOL)_flags._shouldAutoRecover;
523: }
524:
525: - (unsigned)ringSpeed
526: {
527: return _ringSpeed;
528: }
529:
530: - (unsigned)maxInfoFieldSize
531: {
532: return _maxInfoFieldSize;
533: }
534:
535: - (void)setMaxInfoFieldSize:(unsigned)size
536: {
537: //sanity check?
538: _maxInfoFieldSize = size;
539: }
540:
541: /*
542: * Hardware Address Methods
543: */
544:
545: - (token_addr_t)nodeAddress
546: {
547: return _nodeAddress;
548: }
549:
550: #if 0
551:
552: - (token_addr_t)groupAddress
553: {
554: return _groupAddress;
555: }
556:
557: - (token_addr_t)functionalAddress
558: {
559: return _functionalAddress;
560: }
561:
562: #endif 0
563:
564: /*
565: * Implement the IONetworkDeviceMethods protocol
566: */
567:
568: - (int)finishInitialization
569: {
570: int result = 0;
571:
572: if (!_flags._isRunning)
573: result = [_driverCmd send:RESET_ON];
574:
575: return (result);
576: }
577:
578: - (BOOL)resetAndEnable:(BOOL)enable
579: {
580: return YES;
581: }
582:
583: - (void)transmit:(netbuf_t)pkt
584: {
585: nb_free(pkt);
586: }
587:
588:
589: /*
590: * Token-ring transmit. Invokes [self transmit] in subclass
591: * to do actual hardware-specific transmission.
592: */
593: - (int)outputPacket :(netbuf_t)nb address:(void *)dest_addr
594: {
595:
596: int maclen;
597: tokenHeader_t *th = (tokenHeader_t *)dest_addr;
598:
599: /*
600: * Bail out if our hardware is down.
601: */
602: if(!_flags._isRunning) {
603: nb_free(nb);
604: return TRINGDOWN;
605: }
606:
607: /*
608: * Return error if data-field too large (shouldn't happen by
609: * well behaved code, but we include for safety).
610: */
611: if(nb_size(nb) > _maxInfoFieldSize) {
612: IOLog("%s: netOutput bad frame size=%d\n",
613: [self name], nb_size(nb));
614: nb_free(nb);
615: return TBADFSIZE;
616: }
617:
618: /*
619: * Get the callers MAC header length (which is variable, due
620: * to the source routing field).
621: */
622: maclen = get_8025_hdr_len(th);
623: if(maclen < 0) {
624: IOLog("%s: bad mac header\n", [self name]);
625: nb_free(nb);
626: return TBADFSIZE;
627: }
628:
629: /*
630: * Add the 802.5 MAC header to the net buffer. Note that when
631: * we allocate buffers we reserve MAC_HDR_MAX (the largest possible
632: * MAC header). Here we grow the buffer so that the actual MAC header
633: * just fits. The packet data is therefore contiguous (as opposed to
634: * a gap between the unused portion of the MAC header and the data
635: * field). This saves the subclass from needing to deal with
636: * fragmentation. This is all great as long as the subclass
637: * hardware only requires even-aligned data. Otherwise the subclass
638: * must implement its' own outputPacket method or copy the data
639: * (sorry).
640: */
641: nb_grow_top(nb, maclen); // grow buffer so that mac header just fits
642: th = (tokenHeader_t *)nb_map(nb);
643: bcopy(dest_addr, th, maclen); /* copy da to tx buf */
644: th->ac &= 0xf0; /* mask all but token priority & mon bits */
645:
646: /*
647: * Subclass does hdw-specific transmit.
648: */
649: [self transmit:nb];
650:
651: return 0;
652: }
653:
654: /*
655: * Netif get-buffer method.
656: *
657: * This generic version doesn't insure buffer alignment or prevent page
658: * spanning. Subclass should override if needed (as does TokenExpress).
659: */
660: - (netbuf_t)allocateNetbuf
661: {
662: netbuf_t nb;
663:
664: nb = nb_alloc(_maxInfoFieldSize + MAC_HDR_MAX);
665: if (nb)
666: nb_shrink_top(nb, MAC_HDR_MAX); /* reserve space for max 802.5 hdr */
667:
668: return nb;
669: }
670:
671: /*
672: * Netif command method.
673: */
674: - (int)performCommand:(const char *)command data:(void *)data
675: {
676: int rtn = 0;
677:
678: if (strcmp(command, IFCONTROL_SETFLAGS) == 0)
679: return(rtn);
680:
681: else if (strcmp(command, IFCONTROL_GETADDR) == 0) {
682: bcopy((void *)&_nodeAddress, data, sizeof(_nodeAddress));
683: }
684:
685: else {
686: rtn = EINVAL;
687: }
688:
689: return (rtn);
690: }
691:
692: @end
693:
694: @implementation IOTokenRing(PrivateMethods)
695:
696: //
697: // Used to handle a synchronous
698: // command sent by another thread
699: // to the driver thread.
700: //
701: - (void)commandRequestOccurred
702: {
703: int oper = [_driverCmd oper];
704: int result = 0;
705:
706: switch (oper) {
707:
708: case RESET_ON:
709: if (!_flags._isRunning) {
710: if (![self resetAndEnable:TRUE])
711: result = EIO;
712: }
713: [_driverCmd done:result];
714: break;
715:
716: case RESET_OFF:
717: [self resetAndEnable:FALSE];
718: _flags._isRunning = FALSE;
719: [_driverCmd done:result];
720: break;
721:
722: case TERMINATE:
723: [_driverCmd done:result];
724: IOExitThread();
725: break;
726: }
727: }
728:
729: @end
730:
731: static void
732: TokenRingTimeout(IOTokenRing *device)
733: {
734: msg_header_t msg = { 0 };
735:
736: if (device->_absTimeout > 0) {
737: device->_absTimeout = 0;
738:
739:
740: msg.msg_size = sizeof (msg);
741: msg.msg_remote_port = IOGetKernPort([device interruptPort]);
742: msg.msg_id = IO_TIMEOUT_MSG;
743:
744: msg_send_from_kernel(&msg, MSG_OPTION_NONE, 0);
745: }
746: }
747:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.