VIRTUAL NETWORK USING ASYNCHRONOUS TRANSFER MODE

Abstract: Asynchronous Transfer Mode Local Area Network (ATM LAN). The ATM LAN is implemented as a set of MAC entities which share a common group address space for the purposes of establishing multicast connections. Each station (10-0) has one or more ATM MAC entities (20-0, 20-1) per physical connection to an ATM network (11). The network ATM LAN service provides the station with ATM LAN configuration information needed for ATM MAC operation. Included in this information is the number of ATM LANs the network has configured for that station.

Description: VIRTUAL NETWORK USING ASYNCHRONOUS TRANSFER MODE BACKGROUND OF THE INVENTION The present invention relates to networks and particularly to networks of computers that communi¬ cate data and other information. Wide Area Networks. With the increased bandwidth available through transmission channels, for example increases from Tl to T3, and with the increase in bandwidth provided by broadband services such as SONET, larger enterprises are evaluating new applications which require higher speed communications. These new applications will dramatically enhance business productivity, but will require vastly improved network control and manage- ment facilities. However, neither private networks nor common carriers have fully addressed the emerging needs of the new communication environment. Computer Networks In the computer field, in order for users to have access to more information and to greater resources than those available on a single computer, computers are connected through networks. In a computer network, computers are separated by distance where the magnitude of the distance has a significant bearing on the nature of communication between computers. The distance can be short, for example, within the same computer housing (internal bus) , can be somewhat longer, for example, extending outside the computer housing but within several meters (external bus) , can be local, for example, within several hundred meters (local area networks, LANs) , within tens of miles (metropolitan area networks, MANs) or can be over long distances, for example, among different cities or different conti¬ nents (wide area networks, WANs) . Multi-Layer Communication Architecture For networks, the communication facilities are viewed as a group of layers, where each layer in the group is adapted to interface with one or more adja- cent layers in the group. Each layer is responsible for some aspect of the intended communication. The number of layers and the functions of the layers differ from network to network. Each layer offers services to the adjacent layers while isolating those adjacent layers from the details of implementing those services. .An interlayer interface exists between each pair of adjacent layers. The interlayer interface defines which operations and services a layer offers to the adjacent layer. Each layer performs a collection of well-defined functions. Many multi-layered communication architectures exist including Digital Equipment's Digital Network Architecture (DNA) , IBM's System Network Architecture (SNA) and the International Standards Organization (ISO) Open System Interface (OSI) . The ISO architecture is representative of multi¬ level architectures and consists of a 7-layer OSI model having a physical link layer, a data link layer, a network layer, a transport layer, a session layer, a presentation layer, and an application layer. In the OSI model, the physical layer is for standardizing network connectors and the electrical properties required to transmit binary l's and 0's as a bit stream. The data link layer breaks the raw bit stream into discrete units and exchanges these units using a data link protocol. The network layer per¬ forms routing. The transport layer provides reli¬ able, end-to-end connections to the higher layers. The session layer enhances the transport layer by adding facilities to help recover from crashes and other problems. The presentation layer standardizes the way data structures are described and represent¬ ed. The application layer includes protocol handling needed for file transfer, electronic mail, virtual terminal, network management and other applications. In the n-layer multi-layer models, layers 1, 2, ..., n are assumed to exist in each host computer. Layers 1, 2, ..., n in one host computer appear to communicate with peer layers 1, 2, ..., n, respec¬ tively, in another host computer. Specifically, layer 1 appears to communicate with layer 1, layer 2 appears to communicate with layer 2 and so on with layer n appearing to communicate with layer n. The rules and conventions used in communications between the peer layers are collectively known as the peer level protocols. Each layer executes processes unique to that layer and the peer processes in one layer on one computer station appear to communicate with corresponding peer processes in the same layer of another computer station using the peer protocol. Although peer layers appear to communicate directly, typically, no data is directly transferred from layer n on one computer station to layer n on another computer station. Instead, each layer n passes data and control information to the n-1 layer immediately below it in the same computer station, until the lowest layer in that computer is reached. The physical medium through which actual communica¬ tion occurs from one computer station to another exists below the top layer n and typically below the bottom layer l. In order to provide communication to the top layer n of an n-layer network, a message, M, is produced by a process running in a top layer n of a source computer station. The message is passed from layer n to layer n-1 according to the definition of the layer n/n-1 interface. In one example where n equals 7, layer 6 transforms the message (for exam- ple, by text compression) , and then passes the new message, M, to the n-2 layer 5 across the layer 5/6 interface. Layer 5, in the 7 layer example, does not modify the message but simply regulates the direction of flow (that is, prevents an incoming message from being handed to layer 6 while layer 6 is busy handing a series of outgoing messages to layer 5) . In many networks, there is no limit to the size of messages accepted by layer 4, but there is a limit imposed by layer 3. Consequently, layer 4 must break up the incoming messages into smaller units, prefix¬ ing a header to each unit. The header includes control information, such as sequence numbers, to allow layer 4 on the destination computer to put the pieces back together in the right order if the lower layers do not maintain sequence. In many layers, headers also contain sizes, times and other control fields. Layer 3 decides which of the outgoing lines to use, attaches its own headers, and passes the data to layer 2. Layer 2 adds not only a header to each piece, but also a trailer, and gives the resulting unit to layer 1 for physical transmission. At the destination computer, the message moves upward, from lower layer 1 to the upper layers, with headers being stripped off as it progresses. None of the headers for layers below n are passed up to layer n. Virtual Peer To Peer Communication .An important distinction exists between the virtual and actual communication and between proto¬ cols and interfaces. The peer processes in source layer 4 and the destination layer 4, for example, interpret their layer 4 communication as being "direct" using the layer 4 protocol without recogni¬ tion that the actual communication transcends down source layers 3, 2, 1 across the physical medium and thereafter up destination layers 1, 2, and 3 before arriving at destination layer 4. The virtual peer process abstraction assumes a model in which each computer station retains control over its domain and its communication facilities within that domain. Communication Networks Generally For more than a century, the primary interna- tional communication system has been the telephone system originally designed for analog voice transm¬ ission. The telephone system (the public switched network) is a circuit switching network because a physical connection is reserved all the way from end to end throughout the duration of a call over the network. The telephone system originally sent all its control information in the 4 kHz voice channel using in-band signaling. To eliminate problems caused by in-band signal- ing, in 1976 AT&T installed a packet switching network separate from the main public switched network. This network, called Common Channel Inter¬ office Signaling (CCIS), runs at 2.4 kbps and was designed to move the signaling traffic out-of-band. With CCIS, when an end office needed to set up a call, it chose a channel on an outgoing trunk of the public switched network. Then it sent a packet on the CCIS network to the next switching office along the chosen route telling which channel had been allocated. The next switching office acting as a CCIS node then chose the next outgoing trunk channel, and reported it on the CCIS network. Thus, the management of the analog connections was done on a separate packet switched network to which the users had no access. The current telephone system has three distinct components, namely, the analog public switched -ς. network primarily for voice, CCIS for controlling the voice network, and packet switching networks for data. Future Communication Networks-ISDN User demands for improved communication services have led to an international undertaking to replace a major portion of the worldwide telephone system with an advanced digital system by the early part of the twenty-first century. This new system, called ISDN (Integrated Services Digital Network) , has as its primary goal the integration of voice and nonvoi- ce services. The investment in the current telephone system is so great that ISDN can only be phased in over a period of decades and will necessarily coexist with the present analog system for many years and may be obsolete before completed. In terms of the OSI model, ISDN will provide a physical layer onto which layers 2 through 7 of the OSI model can be built. Telephone Network Domains In a telephone network, the system architecture from the perspective of the telephone network is viewed predominantly as a single domain. When commu¬ nication between two or more callers (whether people or computers) is to occur, the telephone network operates as a single physical layer domain. Communication Network Architectures Most wide area networks have a collection of end-users communicating via a subnet where the subnet may utilize multiple point-to-point lines between its nodes or a single common broadcast channel. In point-to-point channels, the network contains numerous cables or leased telephone lines, each one connecting a pair of nodes. If two nodes that do not share a cable are to communicate, they do so indi¬ rectly via other nodes. When a message (packet), is sent from one node to another via one or more inter- mediate nodes, the packet is received at each inter¬ mediate node in its entirety, stored there until the required output line is free, and then forwarded. In broadcast channels, a single communication channel is shared by all the computer stations on the network. Packets sent by any computer station are received by all the others. An address field within the packet specifies the intended one or more computer stations. Upon receiving a packet, a computer station checks the address field and if the packet is intended only for some other computer station, it is ignored. Most local area networks use connectionless protocols using shared medium where, for example, all destination and source information is included in each packet and every packet is routed autonomously with no prior knowledge of the connection required. In the above-identified application CONCURRENT MULTI-CHANNEL SEGMENTATION AND REASSEMBLY PROCESSORS FOR ASYNCHRONOUS TRANSFER MODE (ATM) an apparatus for concurrently processing packets in an asynchronous transfer mode (ATM) network is described. Packets that are to be transmitted are segmented into a plurality of cells, concurrently for a plurality of channels, and the cells are transmitted over an asynchronous transfer mode (ATM) channel. Cells received from the asysnchronous transfer mode (ATM) channel are reassembled into packets concurrently for the plurality of channels. Accordingly, there is a need for new networks which satisfy the emerging new requirements and which provide broadband circuit switching, fast packet switching, and intelligent network attachments. -β - SUMMARY OF INVENTION The present invention is an Asynchronous Trans¬ fer Mode Local Area Network (ATM LAN) . The ATM LAN is implemented as a set of MAC entities which share a common group address space for the purposes of estab¬ lishing multicast connections. Each station has one or more ATM MAC entities per physical connection to an ATM network. The network ATM LAN service provides the station with ATM LAN configuration information needed for ATM MAC operation. Included in this information is the number of ATM LANs the network has configured for that station. In the present invention, a communication system includes an ATM network. The ATM network has a plurality of ports, each port having a unique port address. The ATM network includes one or more ATM switches for connecting sending ports to receiving ports. The communication system includes a plurality of stations, each station having a unique station address distinguishing the station from other sta¬ tions. Each station is connected to the ATM network at a port whereby source stations communicate with destination stations. Each station provides packets for transferring information, information including a destination station address, for addressing desti¬ nation stations. Each station includes a packet converter for converting between packets and cells for transfers between stations. The communication system provides address resolution for determining a port address corre¬ sponding to a destination station address. The address resolution includes multicast for multicast¬ ing the destination station address to a group of stations. The communication system provides manage¬ ment for requesting connections through the ATM network connecting sending ports to receiving ports whereby packets are transferred from source stations to destination stations by cell transfers through ATM network. ATM LANs may are extended by bridging several ATM LANs together using transparent MAC bridges and routers. Permanent virtual connections or switched virtual connections may underlie the layer manage- ment. The communication system operates with a multi-level architecture, such as the ISO architec¬ ture, and Logical Link Control (LLC) , Media Access Control (MAC) and addressing functions are performed for ATM LANs. An ATM LAN provides support for the LLC sublayer by means of a connectionless MAC sublay¬ er service in a manner consistent with other IEEE 802 local and metropolitan area networks. The ATM LAN interface is built on the user-to-network interface for ATM and adaptation layers. The communication system including the ATM LAN provides the following benefits: Physical plug-in locations can be moved and changed without changing logical locations. The stations in the communication system are partitionable into multiple work groups. The communication system provides high bandwidth that supports multimedia applications including voice, video, real-time and time-sensitive applica- tions. The communication system integrates Wide Area Networks (WAN) and Local Area Networks (LAN) into one system. The foregoing and other objects, features and advantages of the invention will be apparent from the following detailed description in conjunction with the drawings. BRIEF DESCRIPTION OF THE DRAWINGS FIG. 1 depicts a number of user stations con¬ nected together in an ATM network system. FIG. 2 depicts the multi-level protocol used to connect two or more stations in the ATM network system of FIG. l. FIG. 3 depicts the network layer and the data link layer connected to a ATM interface in the ATM network system of FIGs. 1 and 2. FIG. 4 depicts details of the ATM MAC sublayer and the ATM interface for stations of FIGs. 1 and 2. FIG. 5 depicts details of the ATM LAN Server and the ATM interfaces of the network of FIGs. 1 and 2. FIG. 6 depicts three ATM LANs configured on a three-switch ATM network. FIG. 7 is a representation of the details of the ATM MACs of stations SO, SI, S2 and S3 from FIG. 6. DETAILED DESCRIPTION In FIG. 1, an ATM network system is shown in which two or more computer stations 10 are intercon¬ nected by an ATM network 11 for network communica- tion. The stations 10 include the station SO, SI, ..., Ss designated 10-0, 10-1, ..., 10-s. The ATM network system of FIG. 1 employs, for example, the top six of the seven OSI model layers. The OSI model physical layer 1 is replaced with a ATM interface which operates in an asynchronous transfer mode (ATM) in accordance with the B-ISDN protocol. In FIG. 2, the ATM network 11 connects, by way of example, the SO station 10-0 to the SI station 10- 1. The SO station 10-0 includes the top six OSI layers, namely, the application layer [0, 7] , the presentation layer [0, 6], the session layer [0,5] and the transport layer [0,4] . The layers 7 through 4 in FIG. 2 are designated as the higher layers and operate in the conventional manner for the OSI model. In FIG. 2, the SO station 10-0 includes the network layer [0,3] and the data link layer, [0, 2] . The data link layer [0,2] includes the logical link control (LLC) sublayer and the media access control (MAC) sublayer. The MAC sublayer in the data link layer [0, 2] connects to a ATM interface 13-0. The ATM interface 13-0 operates in accordance with the B- ISDN protocol defined by the CCITT. In FIG. 2, the SI station 10-1 has the higher layers including the application layer [1,7], the presentation layer [1,6], the session layer [1,5] and the transport layer [1,4] . The SI station 10-1 also includes the network layer [1,3] and the data link layer [1,2] that connects to the ATM interface 13-1. In FIG. 2, the ATM interface 13-0 for the SO station 10-0 and the ATM interface 13-1 for the SI station 10-1 connect to a ATM .switch 13' in the ATM network 11. The ATM interfaces 13-0 and 13-1 and ATM switch 13' operate in accordance with an ATM architecture for ATM communicationn. The ATM LAN communication is under control of an ATM LAN server 12 in the ATM network 11. In FIG. 2 each of the higher layers in the SO station 10-0 and in the SI station 10-1 function in a well known manner in accordance with the OSI model. Also, the network layer [0, 3] in the SO station 10-0 and the network layer [1, 3] in the SI station 10-1 conform to the model OSI The data link layer [0,2 in the SO station 10-0 and the data link layer [1,2] in the SI station 10-1 have OSI compatibility. The compatibility with the OSI model at the data link layer enables the ATM network system of FIGs. 1 and 2 to be compatible with other local area networks and other networks that conform to the OSI model from layer [2] and above. Below the OSI layer [2] , the communication and connections are compatible with the B-ISDN model of the CCITT. The FIG. 2 communication network system is a hybrid of the OSI model above layer [1] and asynchr¬ onous transfer mode below the data link layer [2] . In FIG. 3, further details of the SO station 10- 0 are shown and are typical of all of the other stations 10-1, , 10-s of FIG. 1. In FIG. 3, the higher layers 7, 6, 5 and 4 are conventional. Typically the higher layers of the station 10-0 of FIG. 3 are implemented on a processor such as a Sun Workstation. In FIG. 3, the network layer [3] uses any one of a number of standard protocols such as the IP proto¬ col 15, the DEC NET protocol 16, the OSI protocol 17 or the XNS protocol 18. Any other protocol can be implemented in the network layer 3. In FIG. 3, the data link layer [2] includes the LLC sublayer and the MAC sublayer. The LLC sublayer includes the Logical Link Control (LLC) 19 which is conventional in the data link layer of the OSI model. The data link layer [2] also includes the MAC sublayer which as a component of the data link layer [2] . The MAC sublayer typically may include other MAC sublayers in accordance with the standards IEEE 802.3, 802.4, 802.5, 802.6 and FDDI. ATM LANs are, therefore, capable of interoperating with a wide variety of media. ATM LANs interoperate with all IEEE 802 Local Area Networks and Metropolitan Area Networks using transparent bridges and routers. Stations connected to ATM LANs communicate with stations connected to any IEEE 802 LAN or MAN via a bridge. In accordance with the present invention, the data link layer [2] also includes a new ATM MAC sublayer 22 analogous to the other MAC sublayers 23. The ATM MAC sublayer 22 differs from the other MAC sublayers 23 in that the ATM MAC sublayer 22 communi¬ cates with the ATM switch 13 for ATM communication. In FIG. 3, the ATM MAC sublayer 22 includes one or more ATM MACs including, for example, ATM MAC 0, ATM MAC 1, ..., ATM MAC M designated 21-0, 21-1, , 21-M respectively. Each of ATM MACs 21-0, 21-1,..., 21-m defines an ATM local area network (ATM LAN) . The ATM MACs of the ATM MAC sublayer 22 connect between the logical link control 19 and the ATM interface 13-0. The control of which of the stations (like the stations 10-0, 10-1,..., 10-s) are serviced by particular ones of the ATM MACs 21 of FIG. 3 is determined by the station management 20 within the ATM MAC sublayer 22. Other stations (or the same stations) may also be serviced by other local area networks such as Ethernet under control of the other MAC sublayers 23. In FIG. 3, the ATM MAC sublayer is capable of servicing the communication requirements of the stations 10-0 through 10-s of FIG. 1 in one or more - l f- ATM LANs. Stations can be switched from one ATM LAN to another ATM LAN under control of station manage¬ ment 20 without requirement of modifying the physical connection to the station. For this reason, the ATM LANs are virtual LANs. In FIG. 4, further details of the ATM MAC sublayer 22 and the ATM interface 13-0 of FIG. 3 are shown. In FIG. 4 the ATM MAC sublayer includes the station management 20 and the ATM MACs including the ATM MAC 0, , ATM MAC M designated as 21-0, — , 21-M. In FIG. 4, the ATM MAC 0 includes the multicast address resolution 24, the unicast address resolution 25, the frame 26 and the connection management 27. In FIG. 4, the ATM interface 13-0 includes the signaling protocol 28 in the control plane, the ATM ADAPTATION LAYER (AAL) 29, the ATM layer 30 and the physical layer 31. 1 ATM LANs 1.1 Introduction In FIG. 3, the higher layers [7,6,5,5] and [3] are conventional while the data link layer [2] in- eludes the LLC sublayer and the ATM MAC sublayer to implement the Asynchronous Transfer Mode Local Area Networks (ATM LANs) . Such an implementation is provided with newly defined Media Access Control (MAC) including addressing protocols. The ATM LAN provides support for the LLC sublayer by means of connectionless MAC sublayer service in a manner consistent with other IEEE 802 local area networks (LAN) and metropolitan area networks (MAN) . The ATM LAN interface is built on the user-to-network inter- face for the ATM layer and the ATM adaptation layer (AAL) . An ATM LAN includes a set of MAC entities which share a common group address space for the purposes of establishing multicast connections. Each station has one or more ATM MAC entities per physical connec¬ tion to an ATM network. The network ATM LAN service provides the station with ATM LAN configuration information needed for ATM MAC operation. Included in this information is the number of ATM LANs the network has configured for that station. The user-to-network interface at the LLC and MAC levels is defined for the ATM LAN Architecture in a manner analogous to other Data Link Layer architec¬ tures. 1.3 ATM LAN Functionality An ATM LAN has the following characteristics: addressing- all LANs connected by MAC bridges use 48 bit addressing unicast- all stations can send fra¬ mes to any other station in the LAN -It- duplication- frames are not duplicated broadcast- all stations can broadcast to every other station in a LAN multicast- any station can send to any group address and any station can register to receive frames for any group address promiscuity- any station may chose to receive all frames with group destination addresses 1.4 ATM LANs An ATM LAN is a local network having a set of stations which share a common group address space for the purpose of establishing multicast connections. An ATM LAN is implemented using services of ATM LAN MAC, ATM signaling and ATM Adaptation Layers. Stations may participate in more than one ATM LAN. ATM LANs may be bridged together using MAC bridges. ATM LANs are sometimes called Virtual LANs because they are not limited by the limitations of any physical media characteristics. A single under¬ lying ATM network may support many ATM LANs. A station with a single ATM interface may be connected to many separate ATM LANs. There are no inherent limitations in the ATM LAN protocol itself to re¬ strict either the physical extent or the number of stations in a particular ATM LAN. Practical limita¬ tions, such as multicast traffic, usually limit the size and scope of ATM LANs. ATM LANs interoperate with a wide variety of media. ATM LANs can interoperate with all IEEE 802 Local Area Networks and Metropolitan Area Networks using transparent bridges and routers. Stations connected to ATM LANs are able to communicate with stations connected to any IEEE 802 LAN/MAN connected via bridge. 2 ATM LAN Architecture 2.1 Overview An ATM LAN includes a set of procedures and protocols which work together to provide the services found in IEEE 802 LANs. The AAL and ATM protocols defined by CCITT are augmented by the ATM LAN MAC layer which maps unacknowledged MAC PDUs (MAC Proto¬ col Data Units) onto unacknowledged AAL PDUs trans- mitted over virtual connections provided by the ATM physical layer. The ATM MAC manages connections using an ATM signaling protocol. 2.2 Logical Link Control Stations must comply with 802.2 Type I specifi- cation which is defined by ISO 8802. This includes mandatory response to XID (Exchange ID) and Test commands. When SNAP encapsulations are defined for upper layer protocols they are used. 2.3 Station ATM LAN MAC Each station has one ATM LAN module per physical ATM interface. Each ATM LAN module provides MAC services via one or more ATM MAC entities. The ATM LAN server provides the ATM LAN MAC with config- uration parameters. 2.3.1 ATM MAC Functions The ATM MAC layer provides the following func¬ tions: ATM LAN Configuration- determines the number of ATM LANs which have been configured for the station and the operational parame¬ ters needed to establish multicast connections for each ATM LAN. MAC PDU Framing- MAC SDUs (Service Data Units) are encapsulated in an AAL specific framing. Address Resolution- IEEE 802. 48 bit MAC addresses are mapped onto E.164 ATM addresses. Connection Management- establishes and rele¬ ases virtual connections for transmission of MAC PDUs (Protocol Data Units) and reception of frames ad¬ dressed to registered group (multicast) addresses. Multicast Service- protocol and procedur¬ es are defined for trans¬ mission and reception of frames with group address¬ es. The network provides unreliable delivery via multicast service. The interface to the multicast service is AAL specific. The interface to be used is determined by configuration management. 2.3.2 ATM MAC Entity Service Interface The ATM MAC entity provides the following service interface to MAC users. Primitive Parameters MJUNITDATA.request destination address source address mac service data unit M UNITDATA.indication destination address source address mac service data unit M_REGISTER_ADDRESS group address M_UNREGISTER_ADDRESS group address M_REGISTER_ALL M UNREGISTER ALL - /9 - 2.4 ATM Adaptation Layer The adaptation layers provide transmission and reception of frames on virtual connections. The standard CCITT AAL are used. In this application, AAL 3 is used to denote AAL 3/4 when end systems negotiate the use of the multiplexing identifier. AAL 4 is used to identify AAL 3/4 when the multiple¬ xing identifiers used are specified by the network. IEEE 802.2 LLC will be identified by a value of 1 in the protocol id field of AAL 3/4 frames. 2.5 ATM Signaling Protocol The ATM LAN signaling protocol contains a subset of the functions in Q.93B. It provides the following services: o establishment of virtual connections (VCs) o negotiation of the upper layer protocol (ULP) o clearing of connections o dynamic port address assignment o user to network keep alive 2.6 ATM LAN Server The ATM LAN server provides configuration and multicast services. It provides operational parame¬ ters for each ATM LAN in which each ATM station is configured. Membership in ATM LANs is controlled via policies implemented by the server. These policies may vary between ATM LAN providers. The ATM LAN configuration protocol defines the information provided by stations with which servers may implement policies. Two policies which can be implemented are "port based configuration" and "station based config¬ uration" . The ATM LAN server may use the physical cabling to determine LAN membership. This is called "port based configuration" . Alternatively, the ATM LAN server may use station MAC addresses to determine LAN membership. This is called "station based configuration" . The same station to server protocol is used in either case. The station is not affected by the configuration policies implemented. When requesting ATM LAN configuration parameters, the station always provides its MAC address(es) . The station table shown below is an example of the station-based configuration for the system shown in FIG. 6, The port table shown below is an example of port-based configuration for the system shown in FIG. 6. STATION TABLE (VLAN MEMBERSHIP) VLAN MAC_ADDRESS VLAN1 MAC_Add[0] (SO) ,MAC_Add[l] (SI) ,MAC_Add[5] (S5) ... VLAN2 MAC_Add[2] (S2) ,MAC_Add[6] (S6) ... VLAN3 MAC_Add[0] (SO) ,MAC_Add[3] (S3) ,MAC_Add[4] (S4) ... PORT TABLE (VLAN ASSOCIATION) Port Addresses rs/pftl VLAN PA [2,2] , PA [2,3] , PA [2,4] , PA [2,5] VLAN [3] PA [2,6] , PA [2,7] , PA [2,8] , PA [2,9] VLAN [2] PA [2,3] , PA [3,4] VLAN [3] Each station establishes a VC to an ATM LAN server for each physical interface. A well known group address is used. If redundant ATM LAN servers are providing configuration and multicast service, this service is transparent to the ATM station. The servers agree amongst themselves which ones will serve any particular station. The servers may elect to distribute responsibility for multicast service over several servers. This election is transparent to the station. 3. ATM LAN Configuration Management A station may belong to one or more distinct ATM LANs. The station will then have been configured with one or more MAC entities each having a unique MAC address . At power-on, the station establishes a VC to the network ATM LAN server. The station ATM MAC sends a configuration enquiry to the ATM LAN server. The enquiry contains the station's MAC address, alan_mac. struct alan_req { /* configuration request */ u_char alan__proto; u_char alan_pdu_type; u_short alan_seqnum; struct atm_addr alan_mac; }; Using the unique MAC address, alan_mac, the ATM LAN server determines the number of ATM LANs config¬ ured for that station and the configuration for each connected ATM LAN. A configuration response is sent to the station. struct alan_config { u_char alan_proto; u_char alan_pdu_type; u_short alan_seqnum; int alan_num_lans ; struct alan_parms alan_lan [] ; }; The configuration response contains one alans_pa- rms per ATM LAN. For each ATM LAN the configuration manager activates an ATM MAC entity. The parameters in the alan__parms element control the configuration parameters of each ATM LAN "tap". Each ATM LAN 'tap' is described by the following parameters. The alan_config and alan_update messages contain one or more alan_parms structures, struct alan_parms { int alan_version; int alan_aal; struct atm_addr alan_j?ort; struct atm_addr alan_mcast_base; struct atm addr alan Ian uid[] ; int alan_num_mcast; u_short alan_mid; u_short alan_mtu; }; The alan_aal parameter specifies which AAL is used for multicast frames. Currently defined values are 4 and 5 for AALs 4 and 5 respectively. The alan__port is the port address from which VCs are setup for this ATM LAN. The ATM LAN server may specify different port addresses for different taps or may specify the same for all. The ATM MAC entity treats this E.164 address as an unstructured bit string. The ATM LAN manager allocates a range of E.164 group address space for each ATM LAN. The al- an_mcast_base is E.164 group address which is used in conjunction with alan_num_mcast (the number of group addresses allocated to the ATM LAN) to map IEEE 802.1 group addresses onto the E.164 group address space. .AAL and multicast service parameters are protocol specific. AAL multicast service requires that multicast AAL PDUs be transmitted using multiplexing identifiers, (MIDs) , provided by the ATM LAN server. This allows multicast service to be provided via replication functions often found in ATM switch fabrics. Each ATM MAC entity is assigned a LAN unique MID for transmission and must reassemble AAL using the full 10 bit MID. Each ATM LAN is assigned a globally unique identi- fier, alan_lan_uid. This is a 128-bit name created by the ATM LAN server. The ATM LAN server provides alan_parms structures for the requested MAC address¬ es. If the station requests configuration parameters for two MAC addresses which belong to the same ATM LAN, two identical alan_parms elements are returned. Once the ATM MAC entities have been created, the configuration manager periodically sends keep alive frames on the configuration SVC. If the configura¬ tion SVC is released the configuration manager destroys the ATM LAN entities it created. If after some number of retries the ATM LAN server does not respond to keep alive packets, the configuration manager will release the configuration SVC and destroy ATM MAC entities. Configuration Acquisition Protocol State Machine State Event Actions Newstate 4. ATM LAN MAC The ATM MAC maps IEEE 802.1 flat 48 bit addresses to 60 bit hierarchical E.164 ATM addresses by the address resolution function. Individual IEEE 802. addresses are mapped into port addresses via the ATM Address Resolution Protocol, ATM ARP. Group IEEE 802.1 addresses are mapped to ATM group addresses using a fixed algorithm. Once an ATM address is determined, the ATM signal¬ ing protocol is used to establish a virtual connec- tion. The connection is either a unicast connection or a multicast connection depending upon whether the ATM address is an individual or group address. Connection management is responsible for establishing 5 and clearing these connections. Once the appropriate connection has been determined for a frame, it is encapsulated in an AAL specific encapsulation method. AAL 4 and AAL 5 have distinct multicast mechanisms due to the limitations of AAL 5. 0 4.1 Framing 4.1.1 AAL 3/4 ATM LAN uses the same MAC framing as 802.6. ATM LANs use 48 bit MAC addresses to enable interoperab¬ ility with 802 LANs via MAC bridges. As shown in the 5 following table, addresses are encoded as byte quantities as per 802.6. 6 2 3 1 1 3 16 5 4.2 Addresses Two types of addresses are used in an ATM LAN, station MAC addresses and ATM (or port) addresses. Both types of addresses may either be individual or group addresses. 0 MAC station addresses identify individual sta¬ tions connected to an ATM LAN. Station addresses are 48 bit universally administered 802.1 MAC addresses. These MAC addresses enable interoperability with 802.ID LAN MAC bridges. Station addresses are used as MAC frame source or destination addresses. MAC group addresses are used to address frames to multiple destination stations on an ATM LAN. Group addresses are used to set up virtual connections to multiple destination stations without knowledge of those stations' individual addresses. They are used to provide multicast and broadcast services. Broad¬ cast is a a specific instance of multicast with all stations receiving frames with well defined group address, specifically all l's. Group addresses are 48 bit universally or locally administered 802. MAC addresses. The group address with all bits set to one is the broadcast address. ATM Port addresses or port addresses or ATM individual addresses identify physical ports on switches. They are hierarchical 60 bit E.164 ad¬ dresses dynamically assigned by the network. Each virtual connection has a port address for at least one endpoint. Port addresses are used in ATM ARP and Signaling PDUs. ATM group addresses (or multicast port address¬ es) identify an ATM level multicast group. They are used in signaling PDUs. AddressType Padding Address ATM port 11Ox no padding 60 bits address ATM group lllx no padding 60 bits address MAC station 1000 12 bits 48 bits address MAC group 1000 12 bits 48 bits address x - indicates whether the address is publicly or privately administered 4.3 Multicast Service 4.3.1 Background Any station on the LAN can register to receive -20,- frames addressed to specific group addresses. All stations register to receive frames addressed to group address FFFFFFFFFFFF which is defined to be the broadcast group address. Any station can send frames to any group address without the knowledge of which stations want to receive them. 4.3.2 ATM LAN Multicast In an ATM LAN, multicast capability is provided by the multicast server which is part of the LAN server. Stations use that service by establishing virtual connections to the server using the multicast base ATM address provided in the configuration parameters (alan_parms) . The multicast base address is a privately administered group E.164 address. Virtual connections with a group ATM address at one endpoint are multicast VCs. When setting up a multicast VC the station may request transmit only access so that it will not receive frames transmitted on that VC. IEEE 802.1 48 bit addressing provides for up to 2 46 possible group addresses all registered by various stations in one LAN. Few ATM networks could support 2 46 virtual connections. To bridge this gap in service offering and network capability, each ATM LAN is configured to support a small (typically 100s) number of multicast circuits. This number is export¬ ed in the alan_j?arms configuration element. Each ATM MAC entity is also provided with a multicast base address which is treated as a 64-bit integer. These two numbers are used to map many 48-bit IEEE group addresses to fewer ATM group addresses which are then used to setup multicast connections. If al- an_num_multicast is zero, then the 48-bit group address is added to alan_mcast_base. Otherwise the 48-bit group address is treated as a 16 most signif¬ icant bits of the 48-bit group address are Exclusive- Ored into the 32 least-significant bits, the result is divided by alan_num_mcast and the resulting remainder is added to alan_mcast_base. In either case, the result value is used as a group address to set up a multicast connection for that group address. 4.3.3 Registering for a group address Each ATM MAC entity maintains a list of group addresses for which its users have requested it receive frames. Each of these group addresses is mapped onto a ATM group address when the MAC entity is given is alan_parms information, that is, when it becomes active. There after, the ATM MAC entity will maintain a multicast connection for each port address derived from the above computations. Note, several MAC group addresses may map onto one group port address. In this case, only one connection is main¬ tained for those MAC group addresses. If the network releases a multicast connection, the ATM MAC entity will re-establish another one. The ATM MAC entity will always maintain a multic- ast connection for the group port address derived from the broadcast MAC address. 4.3.4 Transmission of Multicast MAC PDUs When an ATM MAC entity is presented with a M_UNITDATA.request with a group destination address it maps the group MAC address to the group ATM address, and transmits the MAC PDU on the connection established to that port address. If no connection is already established, the frame is queued until one is established. Multicast connections setup solely for the transmission of multicast PDUs are aged in the same fashion as those setup for unicast PDUs. 4.3.5 Reception of Multicast MAC PDUs The group destination addresses in received MAC PDUs are checked against the list of registered group addresses. If the group addresses are not regis¬ tered, the frame is dropped. This dropping is necessary because transmitters may map MAC group addresses onto a multicast connection established to register other group addresses. All group addressed frames are not received on corresponding multicast connections. Stations listening for multicast frames must be prepared to receive those frames on either the appropriate multicast VC or the broadcast VC. 4.3.6 Unregistering a group address Multicast connections established for registered group addresses are not aged. They are not released until the last MAC service users want to receive frames addressed to any of the group addresses mapped onto that connection. The ATM MAC entity maintains reference counts on the number of MAC service users which have registered a group address. A reference count on the multicast connection is maintained for each MAC group which maps onto the connections group ATM address. 4.3.7 AAL 4 Multicast Service Stations connected to multicast VCs can receive frames from many sources simultaneously. The multi¬ plexing identifier (MID) in the ALL4 SAR header is used to correctly reassemble these frames. MIDs are unique within a given ATM LAN. The LAN server assigns a unique MID to each port address. Up to 1023 stations may be connected to an ATM .AAL 3/4 LAN. Each station has a globally unique 48- bit address per ATM LAN. Each station is assigned one MID per ATM LAN (local port address to the station) to be used when transmitting frames on multicast VCs. Stations may not transmit more than one frame simultaneously on multicast VCs with the same local port address. Each station implements MAC level address filtering for frames received on multicast VCs. Each station has a multicast filter which is used to filter frames received on broadcast VCs. This filter may be implemented in hardware or software. The filter is necessary because each ATM network provides limited multicast service and stations may broadcast unicast frames. 4.3.8 .AAL 5 Multicast Service AAL 5 does not provide for multiplexing frames on a single VC simultaneously. The mid field in the alan_parms structure is ignored. There is no limit on the number of stations (or ATM MACs) which may belong to an AAL 5 ATM LAN. 4.4 ATM Address Resolution Protocol Individual IEEE 802.1 MAC addresses are mapped into port addresses via the ATM Address Resolution Protocol (ATM ARP) . Once the port address is deter- mined the ATM signaling protocol is used to establish a virtual connection. 4.4.1 ATM ARP Operation Stations connected directly to ATM LANs will, conceptually, have address translation tables to map MAC addresses (both station and group addresses) into virtual connection identifiers. The MAC-to-port table, provides mappings from MAC addresses to port addresses. The MAC transmission function accesses this table to get next hop port address given destination station address. This table is updated when new station address to port address mappings are learned via ATM ARP and when MAC group address to ATM group address mappings are computed. The entries in the MAC to port table are updated when ATM ARP requests and replies are received. When the MAC layer is presented with a frame for transmission, it looks up the destination address in the station to port address table. If an entry is found, connection management selects the appropriate virtual connection upon which the frame should be transmitted. If no entry is found, a new entry is allocated for that MAC address. If the MAC address is a group address, an ATM group address is computed using an AAL specific function. This operation permits the broadcast VC to be established without sending ATM ARP requests. Mapping individual MAC addresses to port addresses is accomplished by broadcasting an ATM ARP request for the MAC addresses to all stations connected to the ATM LAN. The ATM ARP request carries the senders MAC and port address mapping. All stations receive the request. The station with the specified MAC address responds with an ATM ARP reply. The responder updates its MAC-to-port table using the information in the request. The reply carries both the responders' and the requestors MAC and port addresses. When the requestor receives the ATM ARP reply, it updates its port-to-MAC address table. MAC to Port entry Station Address 48 Next Hop Port Status Bit 802.1 MAC Address E.164 The requesting station must transmit MAC frames on broadcast connections until it receives responses to its ATM ARP requests. It may then set up a connection using the port address in the reply. Usually, the responder sets up the connection before replying. The ATM ARP function times out entries in the MAC-to-port table when they have been idle for some time. Connection management is notified when entries in the MAC-to-port table are added, updated or delet- ed. Connection management notifies ATM ARP when connections are established and released. Entries in this table are deleted when an SVC establishment to the port address fails. They are deleted when the connection corresponding to an entry is released. TABLE 5: Port to VPI-VCI entry Local Port Peer Port 00S VPI/VCI Address Address 4.4.2 ATM ARP PDUs ATM ARP requests and replies are encapsulated in 802.2 LLC and the appropriate AAL for the connection upon which they are sent. ATM ARP requests are always broadcast. Therefore they are encapsulated in the AAL used for multicast connections. ATM ARP replies are usually sent on point to point connec¬ tions. The ATM MACs negotiate the AAL to be used for that connection. The reply is then encapsulated in 802.2 LLC and the specific AAL framing. The ATM ARP messages are: /* * ATM Address Resolution Protocol. */ struct atm_arp { u_short aa_llp; /* lower layer protocol */ u_short aa_ulp; /* upper layer protocol */ u_char aa_llp_len; u_char aa_ulp_len; u_short aa_msg_type; u_char aa_sender_j?ort [8] ; u_char aa_sender_mac[6] ; u_char aa_target_port[8] ; u_char aa_target_mac[6] ; }; /* aa_msg_type' s */ #define ATM_ARP_REQUEST 1 #define ATM_ARP_REPLY 2 The aa_ulp_len and aa_llp_len fields are always 6 and 8 respectively. The aa_ulp field is set to 16. The sender mac and port addresses are set to the sender's Mac and Port addresses for request and non-proxy reply messages. The aa_send_mac field in proxy replies contains the aa_target_mac from the corresponding request. The aa_target_mac is always set to the Mac address needing resolution in requests and it is set to the requestor's Mac address in replies. The aa_target_port is undefined in requests and in replies it contains the aa_sender_port from the corresponding request. The recipient of a reply verifies that the aa_target_port corresponds to one of its own port addresses. 4.5 Connection Management Once a MAC address has been resolved to a ATM address a connection to the station receiving frames for that MAC address can be set up and those frames can be transmitted directly to that station rather than broadcast. Connection management is responsible for defining the connection establishment and release policies. The ATM signaling protocol is used to establish connections for ATM LAN MAC frames. A specific upper layer protocol identifier is reserved for ATM LAN MAC frames. 4.5.1 Connect Establishment Connections are established when ah Unacknowl¬ edged Data Request needs to be transmitted to a MAC address for which a MAC-to-ATM address mapping is known, but no connection to that ATM address, is established (or emerging) . It is possible for two MAC entities to simultaneously establish connections to each other. When connection management receives connection setup SDU from ATM signaling, it checks to see if a connection to the peer port address already exists. If another connection exists (or is being established) , the connection initiated from the lower port address is released. Thus there will never be more than one connection established between two ATM MAC entities. While a connection is being setup, frames which would be transmitted on that connection once it is established must be queued or dropped. Frames should not be broadcast. At least one frame must be queued. Implementations may chose to queue more. Once the connection is set up, any queued frames are transmit- ted. The first frame transmitted on a connection initiated by a station must be the ATM ARP response for the an ATM ARP request. 4.5.2 Quality of Service Currently, distinct qualities of service may be defined for ATM MAC PDUs. 4.5.3 Connection Release Connections for which there is no MAC-to-ATM address mapping are held for the product of the number of ATM ARP retries and retry interval and then released. The MAC-to-ATM address mappings are aged separately. When ATM ARP deletes all the translations to a specific ATM address, all connections to that ATM address are released. When a connection is released, the ATM ARP function deletes all MAC to ATM translations for that connection's remote ATM address. 4.6 Frame Reception Frame Reception Stations are responsible for performing filtering of incoming frames. Unicast addressed frames for other stations will be received on the broadcast VC. Multicast frames for unregis¬ tered multicast addresses may be received on multic¬ ast VCs. These frames are not passed up to the MAC service user. 4.7 Address Resolution and Connection Establishment Example In this example, the steps are described that are required for one station, called Lyra, to deliver a MAC UNITDATA SDU to another station, called Altera, assuming neither station has had any prior communica¬ tion. It is assumed that both stations are part of the same ATM LAN. These steps are only required for the initial transmission from Lyra to Altera. Addi¬ tional MAC PDUs may be transmitted on the connection setup by these steps until either station decides it no longer wishes to maintain the connection. In this example, MAC addresses are expressed in xx:xx:xx:xx- :xx:xx form where each pair of hex digits, xx, is one octet for the address. Port addressees are expressed in the same form except that they have 8 octets. o An ATM MAC service user on Lyra provides the ATM MAC with an UNITDATA SDU to be sent to station address 00:80:b2:e0:00:60. The MAC consults its MAC to port address table, but finds no translation. o The MAC creates an ATM ARP request for MAC address 00:80:b2:e0:00:60. The request contains Lyra's own MAC and port addresses, 00:80:b2:e0:00:50 and dl:41:57:80:77:68:00:02 respectively. The ATM ARP is encapsulated in LLC/SNAP. The destination MAC address is ff:ff:ff:ff:ff:ff (the broadcast address) . The ATM MAC recursively invokes itself to transmit the ATM ARP request. o The MAC address to port address table is search¬ ed for the broadcast MAC address and the correspond¬ ing port address is obtained, f1:41:57:80:77:68:01:- 01. The station established a connection to this port address when the ATM LAN MAC entered the active state. The ATM ARP PDU is encapsulated in an 802.6 frame and passed to the AAL 4 function along with the MID associated with this ATM MAC entity for transmis¬ sion of that multicast connection. o The MAC must transmit the MAC SDU. In lieu of a valid MAC address to port address mapping the broad- ■ cast MAC to port mapping and associated connection are used. The MAC SDU is encapsulated in an 802.6 frame and passed to the AAL 4 function with the MID associated with this ATM MAC entity for transmission of that multicast connection. All the above took place on Lyra. The subsequent steps take place on Altera as it receives the ATM ARP and the ATM MAC PDU containing user data. o The ATM ARP is received by all MAC entities including Altera. The other MACs determine that the requested MAC address is not theirs and ignore the request. Altera determines that its MAC address is in the request. Altera updates its MAC to port address table with Lyra's MAC and port addresses provided in the ATM ARP request. Next an ATM ARP reply is con¬ structed using Altera's port and MAC addresses. This request, in the form of an MAC SDU with Lyra's MAC address as the destination, is passed to the ATM MAC entity. o The ATM MAC looks up Lyra's MAC address in the MAC to port address table. It finds Lyra's port address. The port to VCI table is searched using that port address. No entry is found. Connection manage- ment is invoked to establish a connection to Lyra. Connection management passes a SETUP request to ATM signaling. The MAC queues the ATM ARP response until the connection is established. o Altera ATM signaling module sends a SETUP PDU to establish a connection to port address dl:41:57:80:- 77:68:00:02. The upper layer protocol (sometimes called upper layer compatibility) is the ATM LAN MAC. (This is not a function of the ATM MAC. But it is included for illustrative purposes.) o Next all stations receive the MAC SDU containing the user data on the broadcast connection. All sta¬ tions except Altera determine that the destination MAC address is not theirs and drop the frame. Altera accepts the frame strips off the 802.6 and LLC/SNAP overhead and passes the frame up to the user function identified by LLC/SNAP. At this time, the SDU provided to Lyra's ATM MAC has been delivered to the appropriate MAC user on Altera. However, the MAC entities continue connec- tion establishment and address resolution for subse¬ quent communications between the two stations. The next sequence of operations occurs on Lyra. o ATM signaling on Lyra receives a connection setup indication from the network. This indication is passed up to the upper layer protocol which in this instance is the ATM MAC. o The ATM MAC receives a setup indication SDU from signaling. At this point Lyra knows some other station's ATM MAC is trying to setup a connection to it. The port to vci table is searched for a connec¬ tion to the callers port address. In this case none is found. The connection is accepted by passing a CONNECT SDU to ATM signaling. The MAC starts an idle timer for the connection. Note, that the ATM MAC can not use this connection until an ATM ARP request or response is received indicating MAC addresses for stations accessible via the connection. o Lyra's ATM signaling transmits a CONNECT PDU to the network. Typically, network communication is bi-directional. Assuming this is the case the MAC service user on Altera has responded to the MAC SDU indication with a MAC SDU request. The following actions take place on Altera. The ordering of the arrival of MAC SDU and the CONNECT SDU are arbitrary. o The MAC service user passed the ATM MAC an SDU with a destination MAC address of 00:80:b2:e0:00:50 (Lyra's) . The MAC finds the mapping from MAC address to port address learned when the ATM ARP request was received from Lyra. The MAC next finds that it is setting up a connection to Lyra's port address and that the connection is not yet established. A MAC PDU is created from the MAC SDU and queued waiting connection establishment. o Altera ATM signaling receives a connect PDU. This is passed up to the MAC as a SETUP confirmation. The ATM signaling sends a CONNECT acknowledge PDU to Lyra. The connection is considered established. o Altera's ATM MAC, upon receiving the SETUP confirmation, transmits all frames which were queued awaiting connection establishment. The ATM ARP reply is the first frame to transmitted. It is followed by the MAC PDU containing user data. At this TIME, address resolution and connection are complete on Altera. Any further frames addressed to Lyra's MAC address will use the new connection. The connection is not established on Lyra. Also Lyra still does not have a mapping for Altera's MAC address. The following actions complete address resolution and connection establishment on Altera. o The ATM ARP reply is received on the connection which is still being setup. (Note most ATM networks have slower signaling channels than payload channels. Typically the ATM ARP response will be received prior to the CONNECT acknowledge PDU. ) o The MAC enters Lyra's MAC address to port address mapping in the MAC to port table. At this point any MAC UNIT-DATA requests will be queued until -39- the SETUP complete indication for the connection is passed up from ATM signaling. o The MAC PDU containing user data from Lyra's MAC users is received. The 802.6, LLC and SNAP headers are removed and a MAC UNITDATA indication is passed up to the appropriate MAC service user. o Altera's ATM signaling receives a CONNECT_ACK PDU. This moves the connection into established state. The ATM signaling function passes up a SETUP COMPLETE indication informing the ATM MAC it may transmit on the connection. Connection management starts its idle timer for the connection. The connection is now established on both sta¬ tions. One or more MAC UNITDATA SDUs have been deliv¬ ered. The connection will be timed out as per local policy decisions. ATM LAN Code Overview One detailed embodiment of computer software code used in connection with the present invention appears in the VIRTUAL NETWORK USING ASYNCHRONOUS TRANSFER MODE APPENDIX. The ATM LAN MAC code in the appendix is organized by functional components and Operating System (OS) dependencies. The file if_atm.c contains the rou¬ tines which contain OS dependencies and which are typically implemented differently for each OS. The unicast unit 25 and multicast unit 24 ' address resolu¬ tion functions are implemented in the file atmarp.c. The file atmarp.h contains the definitions for the ATM ARP protocol and the structures used by atmarp.c to implement the protocol. The file atm.c implements the function of connection management unit 27. Those routines interact with the ATM signaling function to establish and release connections. The framing unit -Sf - 26 function is implemented in the OS specific file if_niu.c in the routines niuoutputO , atm_mac_input() which encapsulate and decapsulate frames respective¬ ly. The station management unit 28 functions are implmenented in atm_init.c and in parts of the ATM signaling unit 28 in the files svc.c, svc_utl.c and svc_pdu.c. The ATM LAN server unit 12 functions are implemented in the files lm.c, lm_cfg.c, lm_mgmt.c and lm_util.c. In the APPENDIX the configuration management units 20 and 40 are implemented in an alternate embodiment wherein the operational unit 28 PDUs rather than in a switched VCs as previously describe- d. While the invention has been particularly shown and described with reference to preferred embodiments thereof it will be understood by those skilled in the art that various changes in form and details may be made therein without departing from the spirit and scope of the invention. atm.c -2- atm.c /* * COPYRIGHT 1992 ADAPTIVE CORPORATION * ALL RIGHTS RESERVED 7 /* * This file contains: atmJnitO is called at initialization. * atm find_atpO returns an atmif given a MAC and physical l/f. * atm int nacO returns an atmif given a MAC. atm_sdu_handler() Is * the Interface to ATM signaling. atm_release() releases a " VC and * frees any queued packets. atm_find atO searches for an arptab * entry given a mac address. atm_initlate_setupO Initiates VC * establishment. 7 static char sccsid[] = "%A%"; #include "atm.h" #include "svc.h" #include "debug.h" #lnclude "niu.h" #include "atmaφ.h" #include "llch" #include "if_atm.h" int atm_trace = 2; #define TL1 1 #define TL2 atm race > 1 #define TL3 atm_trace>2 #define TL4 atm_trace>3 #define TL5 atm_trace>4 Int atm_assert_panic = 1; #define HASHMA(x) HASH_LOW((x)->aa long[1]) /* pass in a atm_addr */ #define HASH_LOW(partO) (((part0> >8) <: faart0))&0xf) /* pass in low 32 bits * of addr */ /* * atmJnitO is called to allocate atm glob which contains all the * ATM LAN MAC global variables wHich are written after program load. */ atm initO { int i, atm macJnputO, atm_sdu_handler(); struct atm_globs *ag = atm_glob; if (ag->atm_inltialized) -¥/ atm.c -3- return 0; ag->atmifn = NNIU * NATMS; ag->atm_ulp = ulp_register(LMI_MAC_ORG, LMI_MAC_PID, atm_mac_lnput, atm_sdu_handler, 0); ((u_short *) & ag->llc_def)[0] = Oxaaaa; ((u_shoιt *) & ag->llc_def)[1] = 0x0300; ((u_short *) & ag->llc_def)[2] = 0x0; ((u_short *) & ag->llc_def)[3] = 0x0; agό'atmjiull.aaJonglO] = 0; ag->atm_null.aa~long[1] = 0; ag->atm_null.aa_type = AAT_NULL; ag->atm_broadcast.aa_long[0] = 0; ag->atm_broadcast.aa_long[1] = 0; ag->atm_broadcast.aa_type = AAT_MAC; for (i = 0; i < 6; i+ +) ag->atm broadcast.aa_byte[ATM_FIRST_MAC + i] = (u chaT) Oxff; ag->atm_initialized = 1; return; } /* * atm_find_atpO returns an ATM LAN structure pointer, atp, given a * port address and a phys i/f. V struct atmif * atm_find_atp(pc, port) struct pcif *pc; struct atm addr *port; { struct atmif *atp; for (atp = pc->pc_atmif; atp; atp = atp->ati_next) if (ATM_ADDR_EQ(atp->ati_port, *port)) return atp; return (struct atmif *) 0; } /* * atm fint_at() returns a pointer to an atm interface entry to be * use? for a specific MAC address. V struct atmif * J atm.c atm_bzero(&addr, sizeof(addr)); atm_bcopy(mac, &addr.aa_byte[2], 6); addr.aa ype = AAT_MAC; for (pc = svc_glob->svc_pcif; pc < svc_glob->svc pcifn; pc+ +) for (atp = pc->pc_atmif; atp; atp = atp->ati_next) if (ATM_ADDR_EQ(atp->ati_mac, addr)) return atp; return 0; } /* * atm_sdu_handler() handles signaling SDUs from the ATM signaling * module. The necessary ATM ARP routines are called at connection * establishement and release. */ atm_sdu_handler(vp. sdu, len) struct vcte *vp; struct setup *sdu; int len; { struct ulptab *ulp; int rtn; struct vcte *ovp; /* other VC */ ASSERT(VAUD_VP(vp)) ; TR1 (TL2, "atm_sdu_handler(%s)\n u , svc_xdu_type_str(sdu->lmi_pdu_type)); { ^ atm.c -5- ovp = svc_find_vc(vp->vcte_pcif, &vp->vcte_local, I * * atmJncoming_vc_is betterO choses the better VC given two * redundant VCs. We fimit the number for VCs to one between every * pair of ports. When a new VC is initiated we check for a * duplicates. The VC initiated by the station with the lowest port * address is released. It is imperative that both sides use this * algorithm otherwise we could end up in a deadly embrace. atm.c V atm_incoming_vcJs_better(ivp, ovp) struct vcte ~*ivp; /* incoming VC */ struct vcte *ovp; /* outgoing VC (we initiated) */ { struct atm_addr *ours, *theirs; int true; ASSERT(ovp l= Ivp); TR2(TL3, "atm_sdu_handler: dup vcs found %x & %x\n", ivp, ovp); if (ivp->vcte_pcif->pc_flags & PCIF_NIU_TO_NIU) { /* compare MAC addresses */ true = ivp->vcte_pcif->pc_flags & PCIF_OTHER_MAC_ADDR_IS_HIGHER; } else { /* compare port addresses */ ~ true = ATM ADDR GT(ivp->vcte_peer, ivp->vcte_local); } TR2(TL3, "atm incoming_vc_is%s_better(%s) \n", true ? "" : " " not", e160_ntoa(&ivp->vcte_peer)); ASSERT(ovp); /* keep ovp alive */ return true; } /* * atm_releaseO sends a release_req to the svc module and frees any * queued packets. V atm_release(vp, cause) struct vcte *vp; { struct release *rdu; int rtn; if (vp->vcte_packet) atm_f ree_packets(vp) ; if (!(rdu = (struct release *) atm_alloc_msgO)) { printf("atm_release: no memory"); return; } rdu->lmi_proto = LMI PROTOCOL; rdu->lmi_pdu_type •= " SDU_RELEASE_REQ; rdu->lmi_cref_type = vp->vcte_cref_type; rdu->lmi_cref value = vp->vcte_cre?_value; LMI_SET_EL£MENT(&rdu->lmi_cause, LMI_RELEASE_CAUSE, cause); if (rtn = svc_sdu(vp->vcte_pcif7vp, rdu, sizeof(*rdu))) TR1(TL1, "atm release: release failed %d\n", rtn); } 6- atm.c -7- * atm_find_atO searches for an arptab entry given a mac address. * The 'best' entry upon which to send to the mac address is * returned. If the entry has no VC this routine attempts to setup * one. u 7_char atm_macbroadcastaddr[6] = {Oxff, Oxff, Oxff, Oxff, Oxff, Oxff}; struct aate * atm_find_at(atp, dst) struct atmif *atp; u char *dst; { struct vcte *vp = 0; struct aate *at; ASSERT(VAUD_ATP(atp)); at = atm_mac_to_aate(atp, dst); if (!at) /* we queue frames now... 1 1 * !at->aate_vcte) */ at = atm mac to aate (atp, atm macbroadcastaddr); if (lat) " return 0; if (!at->aate_vcte) atm_initiate_setup(atp, at); return at; } /* atm_initiate_setupO initiates a vc setup between to the port * addresses using the specific interface. If there is already a vc * coming up between the two ports using that interface we do not * bother. This huarantees that we do not initiate two VCs to the * same port address. When we get setup indications we must also * check for duplicates and decide which VC to keep. * / atm_initiate_setup(atp, at) struct atmif *atp; struct aate *at; { int rtn; struct pcif *pc = atp->ati_pcif; struct atm_addr * rom = &atp->ati_poιt; struct vcte *vp; struct setup *pdu; /* setup pdu and sdu are the same */ struct Imi jlp *lu; if (pc->pc sig->vcte state != VCS ACTIVE) 4C atm.c -8- /* no signaling yet */ return 0; vp = svc find vc(pc, from, &at->aate atmaddr, atm glob->atm ulp, VCS NOT DEAD_OR DYING); if (vp) " " goto found_a_vc; pdu = (struct setup *) atm alloc msgO; if (Ipdu) return 0; pdu->lmi_proto = LMI_PROTOCOL; pdu->lmi_ncalls = 1; pdu->lml_caller = *from; pdu->lmi_callee = at->aate_atmaddr; pdu->lmi pdu type = SDU SETUP REQ; pdu->lmi_cref_type = LMI £REFTYPE_SVC; pdu->lmi_cref_value = 0;/* let svc module pick one */ lu = (struct Imi ulp *) & pdu[1]; lu->af type = CMI ULP; lu->af~aal = PAYLOAD_AAL_4; lu->af pid = LMI_MAC_PID; lu->arorg = LMI_MAC_ORG; if (rtn = svc_sdu(pc, 0, pdu, sizeof(*pdu) + sizeof(*lu))) TR1(TL2, "atm_initiate_setup: svc_sdu->%d\n", rtn); vp = svc_find_vc(pc, from, &at->aate_atmaddr, atm_glob->atm_uip, VCS_NOT_DEAD_OR_DYING); found a vc: if (vpf{ at->aate_vcte = vp; vp->vcte_atmif = atp; svc_inc(vp); TR1 (TL1, "atm find_at: setup to %s failed\n", el60 ntoa(Sat->aate atmaddr)); } } atm.h /* atm.h * * COPYRIGHT 1992 ADAPTIVE CORPORATION * ALL RIGHTS RESERVED 7 #ifndef NIU_ATM H #define NIU ATM~H included #include "bytes.h" #include "unipdαh" / ** atm mac service interface (asi). This is the same as an ethemet * header so that upper layers can simply assume ATM is an ethemet. 7 struct atmmsi { u_char asi_dst[6]; u_char asi_src[6]; u short asi~type; }; /* * Structure of an ATM mac header for aal type 4, this is an 802.6 * header. 7 struct atmjieader { struct atm_addr atm_dst; struct atm_addr atm_src; union { struct { ujnt mcb_pid:6; ujnt mcb_pad:2; ujnt mcb_delay:3; ujnt mcb_loss:1; ujnt mcb_crc:1; ujnt mcb_elen:3; ujnt mcb_pad1:16; } mcbits; ujnt atm mcbjong; } un mcb; }; #define atm_mcbits un_mcb.atm mcb long #define atm_elen un_mcb.mcbits.mcb_elen #define atm_crc un~mcb.mcbits.mcb~crc #define atπTloss un~mcb.mcbits.mcb~loss #define atm_delay un_mcb.mcbits.mcb_delay #define atm_pid un_mcb.mcbits.mcb_pid atm.h -10- #define ATM PID LLC 1 /* protocol ID for LLC */ #define ATI-I_MCBITS NOCRC 0x04000000 /* protocol id 1 */ #define ATM .DR L£N sizeof(struct atmjieader) #define ATM_PAD_SHIFT 24 * The only header extension defined is a return port address. The * length must be set to ATME_RPA_SIZE. Pad exists to get the 64 bit * address 64 bit aligned relative to the atm header. 7 struct atmjieader ext { u_char atr ejen; u_char atmejype; u_char atme_pad[2]; /* need not be zeros (nnbz) */ struct atm addr atme rpa; /* return port address */ }; #define ATME_RPA_TYPE 112 /* out of SMDS range */ #define ATME RPA BYTES sizeof(struct atmjieader ext) #define ATME~RPA~WORDS ((sizeof (struct atm_header_ext) + 3)/4) /* * multicast address structures are linked to atm_arptabs which are * marked ATF_MULTI. Such entries are not timed out, nor are they * freed when underlying VCs are released. atm_delete lanO tree's * the ATF_MULTI atm_arptab entries and atm addjanφ & * atm_niu o_niuO re-allocate them and re initiate MC VCs for the * registered addresses. 7 struct mcaddr { u_char mc_enaddr[6]; /* multicast address */ u_short mc_count; /* reference count */ struct aate *mc at; /* multicast VC */ }; #define MCADDRMAX 64 /* multicast addr table length */ #define MCCOUNTMAX (32*1024-1) /* multicast addr max * reference count */ /* * atmif, one per atm Ian, used by atm Ian layer 7 struct atmif { atm.h -11- struct niu_aφcom *ati_ac; /* contains arp and ifnet * structures */ struct atmif *ati_next; /* linked off pcif structure */ u_short ati_state; /* basically do we know who ~ * we are */ u_short ati_mid;/* mid used for multicast frames */ u_short ati_mcasts; /* max # multicasts circuits * configured */ struct atm_addr ati_port; struct atm_addr ati_mac; #define ac_mac ati_mac.aa_byte[2] struct pcif *ati_pctf; struct aate *ati_arptab; /* set at initialization */ int ati_num_mcasts; struct mcaddr ati mcaddrs[MCADDRMAX]; }; /* ati state */ #define ATSJNACTIVE 0 #define ATS_ACTIVE 3 /* * global data structure for r/w variables and variables explicitly * initialized. 7 #include "llc.h" struct atm_globs { struct if Jr_hdr *ltrb; struct atmif *atmif; int atmifn; int atmif_used; struct llc_snap llc_def; struct atm_addr atm_broadcast; struct atm_addr atmjiull; struct ulptab *atm_ulp; int atmjnitialized; char static buf [32]; }; #ifndef RT68K extern struct atm globs atm globs; #define atm_glob~ (&atm_gl6bs) #else #define atm_glob atm_get_globO struct atm_globs *atm_get~globO; #endif atm.h -12- #define LEN_FOR_MBUF_PTRS 0xf5560002 #define HASH_MULTICAST_ADDRESS(x) ((x)&0xff) caddr atm_alloc msgO. atm alloc bytesO; #define NATMS 4 /* max # of ATM lans per physical * interface */ #define e160_ntoa svc_e164_ntoa/* these are really E.164 addresses */ #endif /* NIU_ATM_H */ atm init.c -13- /* almjπil.c * * COPYRIGHT 1992 ADAPTIVE CORPORATION * ALL RIGHTS RESERVED * This file contains the ATM LAN configuration routines. They are * called by the ATM signaling module when signaling enters the * ACTIVE state and one or more ATM LANs have been provisioned * "added" by NM and they are called when signaling tranisltions to * the WGRC state to 'deleted' the ATM LANs. * * atm_attachjan0 allocates atmff structures and Initializes them. * atm_addjaπ0 actives an ATM LAN initiates. atm_deletejan0 * deactivates an ATM LAN. atm_niu o_niu0 activates an ATM LAN in * back to back configuration. atm_trace_bufO add a trace record to * the trace buffer. atm race_str0 add a string to the trace * buffer. 7 static char sccsidf] = "%A%"; #include "debug.h" #include "niu.h" #include "atm.h" #include "atmarp.h" #include "svc.h" #include "debug.h" #include "trace.h" #include "if_atm.h" #define TL1 1 #define TL2 atm race > 1 #define TL3 atm race>2 #define TL4 atm race>3 #define TL5 atm race>4 extern int atm race; /* * atm_attachjan0 is called when the maximum number of ATM LANs for * a particular plysical interface is known. The appropriate number * of atm Ian interface structures are allocated and linked into the .* physical interface structure. • 7 atm_attach lan(atp, pc) struct atmif *atp; struct pcif *pc; { struct atmif *an; atm init.c -14- if (an = pc->pc_atmif) { while (an->ati_next) an = an->ati_next; an- > ati next = atp; atp->at _next = 0; } else { atp->ati_next = 0; pc->pc atmif = atp; } atp- > ati pcif = pc; /* * This is called when a real switch tells use some real port * addresses. The mte's were freed when the previous Ian was * deleted. If the mtu is zero this is a null LAN. It should not be * made active. This allows users to configure interfaces starting * at aa2, aa3, etc. 7 atm_addjan(atp, port, mid, mcasts, mtu) struct atmif *atp; struct atm addr *port; { } i atmjnit.c -15- atm_setup_mcasts(atp) struct atmif *atp; { int i; struct mcaddr *mc; for (i = 0; i < atp->ati_num_mcasts; i+ +) { mc = &atp->ati_mcaddrs[i]; ASSERT(mc->mc_at = = 0); mc->mc at = atm ind_at(atp, mc->mc_enaddr); ASSERT(mc-> mc_at); mc->mc_at->aate_flags | = ATF_MULTI; TR1 (TL3, "atm setup_mcast: port = %s\n", e160 ntoa(&mc->mc at- > aate atmaddr)); } } /* * Called to free up any resources tied up by the ATM LAN, atp. The * arptab has been cleared by release indications except for * ATF_MULTI entries. Here we go through list of registered * multicast addresses free those arptab entries refernced. 7 atm_deletejan(atp) struct atmif *atp; { struct mcaddr *mc; atp->ati_state = ATSJNACTIVE; TR1(TL1, "atm delete Ian: port = %s", e160_ntoa(&atp- > ati_port)) ; TR1(TL1, " mac = %s\n", e160_ntoa(&atp->ati_mac)); atp->ati_port.aa_type = AATJMULL; for (mc = atp->ati_mcaddrs; mc < &atp->ati_mcaddrs[atp->ati_num_mcasts]; mc+ +) { ASSERT(mc- > mc_count) ; if (mc->mc at) { ASSERT(mc->mc_at->aate_fiags & ATF_MULTI); mc->mc_at->aate_flags = 0; atm_aate _f ree(mc- > mc_at) ; mc->mc at = 0; } } if delete lan(atp); } /* * set a local port address and mac address based upon mac address in * niu_arpcom referenced by atp. This is used when changing atm Ian * configuration to a niu-to-niu configuration. Also set to atm X init.c -16- * broadcast mte entry and if signaling not debugged install a nailed * up broadcast vc. 7 atm_niuJo_niu(atp) stTuct atmif *atp; extern int gosig, niumtu; atm_bzero(&atp- > ati_port, sizeof (atp- > ati_port)) ; atp- " >ati_port.aa_type = AAT_PORT; atm bcopy(&atp->ati_mac.aa_byte[ATM FIRST_MAC], 5atp->atl_port.aa_byte[ATM_N2N MAC], 6); atp->ati_port.aaJannum = if getjanfatp); atp->ati_state = ATS_ACTIVE; atp->ati_mcasts = 32; /* its arbitrary */ atp->ati_mid = 0; /* must be zero till ALAN aal driver * gets fixed */ if_addjan(atp, 0); /* do not change mtu */ atm_setup_mcasts(atp) ; TR1 (TL2, "atm niu o iiu: port = %s", e160_ntoa(Satp- > ati_port)) ; TR1(TL2, " mac = %s\n", e160 ntoa(&atp->ati_mac)); } svc race_pdu(p, len, in, vci) char *p; { atm race buf(p, atm bcopy, SVC PDU TRACE, len, in, vci); } /* * atm trace bufO add a trace record to the trace buffer. 7 int atm racejimit = 64; atmjrace_buf(p, copyproc, sub, tlen, in, vci) caddr p; int (*copyproc) 0; { struct if _tr_hdr *rb; int s, len; if (tlen > atmjracejimit) len = atmjracejimit; else len = tlen; rb = (struct ifjrjidr *) tr_get_entry(sizeof *rb + len); atm_glob->ltrb = rb; if (Irb) * atmjnitc -17- return; rb->thdr.subsystem = sub; rb->thdr.sss = in; rb->thdr.length ■= len; rb->tlen = tlen; atm_settime(rb->thdr.time); rb->vci = vci; (*copyproc) (p, (char *) &rb[1], len); } /* * atmjrace strO add a string to the trace buffer. 7 atm trace_str(str) char *str; { struct trace_header *tr; int len; for (len = 0; str[len]; len+ +); tr = (struct trace header *) tr get_entry(sizeof *tr + len); if (Itr) return; tr-> subsystem = ASCII J.OG; tr->sss = 0; tr-> length = len; atm_settime(tr- > time) ; atm_bcopy((u char *) str, (u char *) & tr[1], len); } •S " <_- atmarp.c -18- atmarp.c * COPYRIGHT 1992 ADAPTIVE CORPORATION * ALL RIGHTS RESERVED * ATM address resolution protocol. This module contains the routines * which implement atm arp. The two primary entry points are * atm mac to aateO and atm arpJnputO- * - — * atm_macjo_aate0 returns a pointer to and atm aφ table entry. * atm arp inputO handles all atm aφ requests and replies. 7 static char sccsid[] = "%A%"; #ifdef notdef #include "all.h" #include "ip_errs.h" #include "unsp.h" #endif /* notdef */ #include "atm.h" #include "svc.h" #include "atmaφ.h" #include "debug.h" #include "if_atm.h" #define TL1 1 #define TL2 arp Jrace > 1 #define TL3 arp race>2 #define TL4 arpjrace>3 #define TL5 arpjrace>4 int arp trace = 2; int arp_debug = 2; char *atm_mac_sprintfO; #define N_AATE_S 64 struct aate atm aate[N AATE S * ATM_ARP_TABLES]; int atm aate size = N_AATE_S * ATM_ARP_TABLES; int atm arptabs = 0;/* number of tables allocated (1 per * atm Ian) */ struct aate * atm_aφtabJook(atp, addr) struct atmif *atp; u char *addr; { struct aate *ate = atp->ati_aφtab, *end; S1 atmarp.c -19- end = &ate[N_AATE_S]; while (ate < end) { If (atm_bcmp(ate->aate_macaddr, addr, slzeof(ate->aate_macaddr)) = = 0) return ate; else ate+ + ; } return 0; * Broadcast an ATM ARP packet, asking who has addr on atm Ian ac. 7 atm_arprequest(atp, addr) struct atmif *atp; u char *addr; struct atm_arp *aa; TR2(TL3, "atm_arprequest(%x, %s)\n", atp, atm_mac_sprintf(addr, 6)); aa = (struct atm arp *) atm alloc msgO; if (laa) return; /* * atm mac to aatefj returns a pointer to and atm aφ table entry. * — — — * desten is filled in. If there is no entry in aφtab, set one up and * broadcast a request for the MAC address. An aφtab point is * returned if an existing aφtab entry was found, for the mac * address is found (or computed). 7 atmarp.c -20- struct aate * atm_macJo_aate(ac, destmac) struct atmif *ac; u char *destmac; { struct aate *at; TR2CTL4, "atm_mac to_aate(%x, %s)\n", ac, atm_mac_sprintf^clestmac 1 6)); at = atm_arptab look(ac, destmac); if (at = = 0) { /* not found */ at = atm aate alloc(ac->ati aφtab, destmac); If (at = = 0) " panic("atm_macJo_aate: no free entry"); if (!atm_bcmp(destmac, &ac->ac_mac, 6)) { atm bcopy((caddrJ) & ac->ati_port, fcaddrj) & at->aate_atmaddr, (ujnt) sizeof(ac->ati_port)); atm bcopy((caddrJ) & ac->ac_mac, fcaddrj) at->aate_macaddr, (ujnt) sizeof(at->aate_macaddr)); at->aatejimer = 0; at->aate_flags = AATF_COMPLETE; at->aate_vcte = 0; TR2(TL4, " -> %x %s\n", at, svc_e164_ntoa(&at-> aate_atmaddr)); return at; } else if (destmac[0] & 0x1) { /* * Calulate a suitable atm address to make a * connection with for this multicast * address. 7 atmarpmhash(ac, destmac, (caddr t) & at->aate_atmaddr); atm bcopy(destmac, (caddrj) at->aate_macaddr, ujnt) sizeof(at->aate_macaddr)); at- > aate timer = 0; at->aate~flags = AATF_COMPLETE; at->aate_vcte = 0; /* no vcte get */ TR2(TL4, " .-> %x %s\n", at, svc_e164_ntoa(&at- > aate_atmaddr)) ; return at; } /* * Generate an ARP request, AATF_RESOLVING avoids * recursion. 7 at->aate_flags | = AATF_RESOLVING; atm_aφrequest(ac, destmac); 9 atmarp.c -21- at->aate_fiags &= ~AATF_RESOLVING; TR0(TL4, " -> 0\n"); return 0; */ /* * atm arp inputO handles all atm arp requests and replies. 7 atm_arpjnput(atp, aa, src) struct atmif *atp; struct atm_arp *aa; u char *src; { struct aate *at; u_char target_mac[6]; /* copy of target protocol * address */ struct atm_addr *spoιt; TR2(TL2, "atm_arp input(from %s / %s)\n", atm_mac_sprintf (aa- > aa_sender_mac, 6), svc_e164 jιtoa(aa- > aa_sender_port)) ; if (aa->aa_ulp l= ETHERTYPE_ATMMAC) goto drop; /* make a copy of target mac for use later */ atm bcopy((caddrj) aa->aa target nac, (caddrj) target nac, Tujnt) sizeof(target_mac)7; if (!atm_bcmp((caddrj) aa->aa_sender_mac, (caddrj) & atp->ac_mac, C atmarp.c -22- sizeof (aa- > aa_sender_mac)) ) /* its from me so ]ust drop It */ goto drop; I* * Search the local database for senders mac address. Update * the database with new information (first deleting old * infomation). 7 at = atm_arptabJook(atp, aa->aa_sender_mac); if (at) { /* if at is complete and address is * different then free entry */ if (at->aate_flags & AATF_COMPLETE) { if (atm bcmp(aa->aa_sender_port, (caddrj) & at->aate_atmaddr, (uJntJ " sizeof(aa->aa_sender_port)) 1= 0) { /* if different */ atm_aatejree(at); at = 0; } } else { /* if at is incomplete update it */ atm_bcopy((caddrj) aa->aa_sender_port, (caddrj) & at->aate_atmaddr, sizeof(aa->aa_sender port)); at- > aate flags | = AATF COMPLETE; } } /* * If we did'nt find his mac address and he IS looking for * us. Then learn his as well 7 if (at = = 0 && latm_bcmp(target_mac, &atp->ac_mac, sizeof(target_mac))) { /* ensure we have a table entry */ if (at = atm_aate alloc(atp->ati_arptab, aa->aa_sender_mac)) { atm_bcopy((caddrj) aa->aa_sender port, (caddrj) & at->aate_atmaddr, (ujnt) sizeof (aa- > aa_sender_port)f; at- > aate flags | = AATF COMPLETE; } } /* * If we found his mac address and his mac address is NOT the t atmarp.c -23- if (latm_bcmp(target mac, &atp->ac_mac, (ujnt) sizeof(target_mac)) 1 1 atm mac learned " on non atm interface(target_mac)) I * - - - - - * Either we are the target of the aφ request or we * found the target mac address is in our forwarding * database and It was learned on a non-ATM Interface * so we send a proxy atm aφ response because the * atm aφ request can not be forwarded onto that * link. 7 sport = &atp->ati_port; else goto drop; /* * We have decided to respond. Turn the request into a * response by copying the sender's port address into the * target port adr. Copy the senders protocol (MAC) address * into the target address. Copy the target protocol address * (targetjnac) into the senders protocol address and copy * the port selected above into the senders port address. 7 atm bcopy((caddrJ) aa->aa_sender port, (caddrj) aa->aaJarget_port, jjnt) sizeof(aa->aa_sender_portj); atm bcopy((caddrj) aa->aa_sender mac, (caddrj) aa->aajarget_mac, fujnt) sizeof (aa-> aa_serider_mac)); atm bcopy((caddrJ) targetjnacT (caddrj) aa->aa_sender_mac, J jnt) sizeof(aa->aa_sender_mac)); atm bcopy((caddrj) sport, (caddrj) aa->aa_sender_port, jjnt) sizeof(aa->aa_sender_port)); aa->aa_msgjype = htons(ATM_ARP_REPLY); /* go ahead and send it */ atm_send_arp(atp, (caddrj) aa->aajarget mac, aa, sizeof (*aa)); return; drop: atm Jreejnsg ((char *) aa); return; } /* * atm_arptab_allocO allocates an atm aφ table for the atmif * structure atp and schedules the first first timeout for that atm * arp table. Each atm aφ table has uts timeouts scheduled * separately. This is an attempt to spread signaling traffic out * when there are multiple LANs. Zero is returned if no table could * be allocated. 7 £ atmarp.c -24- struct aate * atm_arptab_alloc(atp) struct atmif *atp; { struct aate *at; at = &atm aate[N \ATE S * atm_aφtabs]; if (atm_aφtabs = = ATM~ARPJTABLES) return 0; atp->ati_arptab = at; atm_sched Jimeout(atp) ; atm_aφtabs+ + ; retu?n at; } /* * atm_aatejree0 is called when an atm arp table entry is no longer * in use. If a VC is referenced its reference count is decremented. * If the VCs reference goes to zero atm_releaseO Is called to * release the VC. 7 atm_aatejree(at) struct aate *at; { TR2(TL3, "atm_aate free(%s / %s)\n", atm_mac_sprintf(at->aate_macaddr, 6), svc 3164_ntoa(<Sat- > aate_atmaddr)) ; ASSERT((at->aate_fiags & AATFJ-/ULTICAST) = = 0); at->aatejimer = at->aatejlags = 0; if (at- > aate vcte && (svc_dec(at->aate_vcte) = = 0)) atm_release(at->aate_vcte, VCJDLE); at->aate vcte = 0; } /* * Enter a new address in aate, pushing out the oldest entry from the * bucket if there is no room. This always succeeds since no bucket * can be completely filled with permanent entries (except from * atm arpioctl when testing whether another permanent entry will * fit). ~ 7 struct aate * atm_aate_alloc(at, addr) struct aate *at; /* base of aate table for this Ian */ u_char *addr; { int hiwater = 0; struct aate *victum = 0, *end = &at[N \ATE_S]; atmarp.c -25- TR1CTL3, "atm_aate alloc(%s)\n", atm_mac_sprintf(addr, 6)); while (at < end) { if (at->aatejiags == 0) goto found; If ((at->aate_flags & AATF ΛULTICAST) = = 0 && (at->aatejimer > = hiwater)) { hiwater = at->aate imer; victum = at; } at+ + ; } if (Ivictum) return 0; at = victum; atm_aatejree(at); found: atmJjcopy((caddrj) addr, (caddrj) at->aatejnacaddr, (ujnt) sizeof (aF- > aate macaddr)) ; at->aate_flags = AATFJNUSE; at- > aate vcte = 0; return (atj; } I* * atmarphashO - algorithmicly generates an ATM multicast address * from a 48 bit address. If the number of multicast circuits * supported on this LAN (ati_mcasts) is 0 then use all 48 bits of * the MAC multicast address. The asumption being the network is * providing multicast service via a server with no limit to number * of multicast connections available to each station. If atijncasts * is greater than zero then the 48 bit address is folded into a * unsigned 32 bit integer by exclusive or'ing the first 2 bytes into * the last two bytes. The resulting integer is divided by ati_mcasts * and the resulting number is used as the ATM multicast address. 7 atmarpmhash(atp, mac, port) struct atmif *atp; u_char *mac; struct atm addr *port; { port->aajong[0] = 0; /* clear first word of address */ if (atp->ati_mcasts = = 0) { atmJ_copy(mac, &port->aaJjyte[ATM_FIRST_MAC], 6); } else { port->aa long[1] = ((mac[2] < < 24) | ((mac[3] Λ mac[1]) < < 16) | ((mac[0] Λ mac[4]) << 8) | (mac[5])); port- >aa Jong [1] %= atp->ati_mcasts; L4 atmarp.c -26- /* * This must be flipped in order to get It into * network byte order 7 htonl(port->aa long[1]); port->aa_bytep.TM_FIRST VIAC] = 1; /* set multicast bit */ TR1(TL4, "computed mcast of %x\n", port->aa long[1]); port->aa type = AAT MAC;/* set the type field */ } /* * arp_setupO is called when a new VC is setup. The aφtable is * searched for entries needing a VC to the peer port. Those entries * are updated to reference the new VC. 7 arp_setup(at, vp) struct aate *at; struct vcte *vp; { int i; TR1(TL2, "atm_setup(%s)\n", svc_e164_ntoa(&vp->vcte_peer)); for (i = 0; i < N_AATE S; i+ +, at+ +) { if (!(at->aatejags & AATF_COMPLETE)) continue; if (!atmj_cmp(&at->aate_atmaddr, &vp->vcte_peer, sizeof(vp->vcte peer)) && at->aate_vcte != vp) { at- > aate vcte = vp; svcjnc(vp); } } } /* * arp_releaseO is called when a VC is about to be released. The * arptable is searched for references to the VC. Any entries found * are freed. 7 aφ_release(at, vp) struct aate *at; struct vcte *vp; { int I; TR1(TL2, "arp_release(%s)\n", svc_e164_ntoa(&vp->vcte_peer)); for (I = 0; I < N AATE S; I+ +, at+ +) { if (!(at->aate ags & AATF_COMPLETE)) { atmarp.c -27- ASSERT(at->aate_vcte = = t)); continue; } if (at->aate_vcte 1= vp) continue; at->aate vcte = 0; svc dec(vp); if ((at->aate_fiags & AATFJVIULTICAST) == 0) atm_aate ree(at); /* must clear aate_vcte * first */ else TR1(TL2, "arp_release: skipped AATF_MULTICAST at=%x\n", at); } ASSERT(vp->vcte_refcnt = = 0); } int atmarpjimeol = 24; /* idle timeout */ int atmarpjimeo2 = 3; /* incomplete timeout */ extern int hz; /* * atm_arptimerO scans arp tables for active the ATM LAN atp. VCs ar * established fo registered multicast addresses if none exist. Atm * arp enrties for none registered addresses are timed out. When the * last reference to a VC is freed that VC is released (atm_aatejree * does this). 7 atm_arptimer(atp) struct atmif *atp; { struct aate *at = atp->ati_arptab, *end; int s; TR1(TL3, "atm_aφtimer(%x)\n", at); atm_sched Jimeout(atp) ; if (atp->ati_state = = ATSJNACTIVE) return; s = splimpO; end = &at[N_AATE_S]; for (; at < end; at+ +) { /* set up multicast circuits which have been released */ if ((at->aate_flags & AATF MULTICAST) && (at->aate_vcte = = 0 \J ((1 < < at->aate vcte->vcte_state) & VCS DEAD ORJDYING))) { atm initiate_setupføtp, at); continue; } if (at->aate flags = = 0 1 1 (at->aate_flags & AATFJ\ΛULTICAST)) continue; at->aate timer+ + ; If (at->aatejags & AATFJ30MPLETE) { if (at->aatejimer >= atmarp imeol) atm aate~free(at); } else if Tat- > aate timer > = atmarp Jimeo2) atm aate free(a ); } splx(s); atmarp.h -29- /* atmarp.h * COPYRIGHT 1992 ADAPTIVE CORPORATION * ALL RIGHTS RESERVED #ifndef RT68K #include "sys/types.h" #else #include <stdint.h> #endif /* * ATM Address Resolution Protocol (or ATM ARP) Definitions. 7 #define ETHERTYPE_ATMMAC 0x0805 #define ARPHRD ATM 16 /* * ATM Address Resolution Protocol. 7 struct atm_arp { u_short aajlp; /* lower layer protocol */ u_short aa_ulp; /* upper layer protovol */ u_char aajlpjen; u_char aa_ulpjen; u~short aa_msg type; u_char aa_sender_port[8]; u_char aa_sender_mac[6]; u_char aaJarget_port[8]; u char aa target mac[6]; }: " /* aa msg ype' s */ #define ATM_ARP_REQUEST 1 #define ATM ARP REPLY 2 /* " ~ * MAC to ATM address resolution table, atm arp table entry, aate. 7 struct aate { struct atm_addr aate_atmaddr; /* port address */ struct vcte *aate_vcte; /* vcte reference */ u_char aate_macaddr[6]; /* mac address */ u_char aatejimer; /* ticks */ u char aate flags; /* flags */ }; " /* aate flags field values */ #define AATF INUSE 0x01 #define AATF_COMPLETE 0x02 #define AATF MULTICAST 0x10 #define ATF MULTI AATFJ-/ULTICAST #define AATF PROXY 0x20 atmarp.h -30- #define AATF_RESOLVING 0x40 struct aate *atm_aate allocO, *atm_aφtabjook0, *atm_aφresolveO; struct aate *atm aφtab_allocO. *at " m ind t0: extern struct aate atm_aatefl; #define ATM_ARP_TABLES 16 extern int atm arptabs; 6? bits.c -31- /* bits.c * * COPYRIGHT 1992 ADAPTIVE CORPORATION * ALL RIGHTS RESERVED 7 ******************************* JTtø )****************************************** #ifndef UNIX #define ERRLOG printdbg #define printf printdbg #endif /* ifndef UNIX */ #include <stdint.h> #include "bits.h" bits_getj)it(bits, size) bitsj *bits; int size; maxjjit = size * 8 * SIZEJ3ITS; for (ret = 0; ret < max bit; ret+ +) { BITS 3ET l_MASK(ret, i, mask); if ((bits[i] £ mask) = = 0) { bits[i] | = mask; return (ret); } } return (-1); } bitsjst_bit(bit, bits, size) int bit; bitsj *bits; int size; { int ret; int I; bitsj mask; BITSj3ETJJviASK(bit, i, mask); ret = i < size && (bits[i] & mask) I = 0; return (ret); 7$ bits.c -32- bits_alloc_bit(bit, bits, size) int bit; bitsj *bits; int size; { Int ret; int i; bitsj mask; if (Ibits tst_bit(bit, bits, size)) { BITS ' GET I MASK(bit, i, mask); if (i <T slze)T bits[i] I = mask; return (-1); } else { return (0); } } return (0); } bitsjree bit(bit, bits, size) int bit; bitsj *bits; int size; { int i; bitsj mask; BITS 3ET I /IASK(bit, i, mask); if (i < sizef bits[i] &= -mask; } print _bits(bits, size) bitsj *bits; int size; { int i; for (i = 0; i < size; i+ +) { if (bits[i] = = 0) { printf("0x0 "); printf(Ox%08x ", brts[i]); } } 7/ bits.h -33- /* blts.h * * COPYRIGHT 1992 ADAPTIVE CORPORATION * ALL RIGHTS RESERVED 7 *******************************p EwNnD************************************************************************** #ffndef BITS H #define BITSJH typedef tUINT32 bitsj; #define SIZEJ3ITS (sizeof(bitsj)) #define BITS αET IJ\ΛASK(bit, i, mask) \ ((i) = (bit) / (8 * SIZEJ3ITS),\ (mask) = (bitsj)0x80000000 > > ((bit) % (8 * SIZEJ3ITS))) #endif /* ifdef BITS_H */ if atm.c — -34- /* if_atm.c * * COPYRIGHT 1992 ADAPTIVE CORPORATION * ALL RIGHTS RESERVED * * * * This file contains the operating specific routine for the ATM LAN MAC * for UNIX. The routines defined here are: atm_attachO is called * once per phys i/f at initialization. * * if_set_macO is called get a MAC address from the OS. * * if_addjan() is notify the OS an ATM LAN is ACTIVE. * * if_deletejan() is notify the OS an ATM LAN is INACTIVE. * * atm ree packetsO is called to free packets queued on a VC. * ~ * atm_append packetO appends a packet on VC til it comes up. * * atm_send_packets() is called when a VC becomes established. atm_settimeO Copy OS notion of time into long array of 2. * atm_schedjimeout() schedule the OS to call atm_aφtimer(). svc_schedjimeoutO schedule the OS to call svcJimeoutO- * svcJnitO allocates global memory area for ATM signaling. svc_report_version_conflictO report signaling version conflicts to os: atm_alloc_msgO allocates a msg buffer large enough for signal PDUs. atm ree_msg0 frees message memory pointed to by cp. atm_allocjDytesO is used to allocate memory for data structures * aal_send_msgO sends the pseclfied aal payload on a VC. * * atm_send_arpO send a frame encapsulating in 802.6/LLC/SNAP type=ARP. * * atm nacJnputO handles aal payloads with 802.6 PDUs (ATM LAN). * * svc mac inputO handles aal payloads with SVC PDUs. 7 if atm.c -35- static char sccsid[] = "%A%"; #lfndef INET #define INET /* only support Internet addressing */ #endif #include "../sys/param.h" #include "../sys/systm.h" #include "../sys/mbuf.h" #include "../sys/socket.h" #include "../sys/ermo.h" #include "../sys/ioctl.h" #include "../net/if.h" #include "../net/netisr.h" #include "../net/route.h" #include "„/net/if_arp.h" #include "../sun/openprom.h" #include "../sun4c/mmu.h" #ifdef INET #include "../πetinet/in.h" #include "../netinet/in_systm.h" #include "../netinet/in_var.h" #include "../netinet/ip.h" #endif 7/ if atm.c _ -36- struct niu arpcom niu arpcoms[NNIU * NATMS]; Λ * atm_attach() is called when the maximum number of allowed ATM LANs * for a specific interface have been determined, atm nnius must be * patched with the number of ATM LANs per physical interface before * booting. Only that number of ATM LANs will be configured * regardless of ATM LAN configuration information providled by the * LMI configuration protocol. (We could dynamically attach and * dettach ifnet structures BUT the there is a significant * probability other code In the system assumes ifnets are are static * after boot. So ifnets are statically linked once at boot.) 7 atm_attach(pc) struct pcif *pc; { struct ifnet *ifp; struct atmif *atp; int Ian, ifunit; int niuoutputO, niusoioctlO, mac[2]; if atm.c -37- } Int awl = 0; /* atm watch Interval, for those who * can not type */ int awittgfNNIU]; /* atm watch interval ticks to go */ atm_watch(ifunlt) int ifunit; { struct ifnet *ifp = (struct ifnet *) & niu aφcoms[ifunit]; int iounit = NIUJFUNITJOJtfUNIT(ifunit); int s; ifp->ifjimer = 1; if (ifunit I = 0) return 0; if (awi = = 0) return 0; if (awittg [iounit] < = 0) { printffreseting unit %d from watchdog\n", iounit); s = splimpO; (*niuJnfo[iounit].reset) (iounit, 1); if (niuJnfo[iounit].type = •= NIU TYPEJHW) { setup rxbuf(&niu info[iounit]j } splx(s); awittg [iounit] = awi; } else awittg [iounit]-; return 0; } /* * set ati mac from value provided by os 7 if _et_mac(atp) " struct atmif *atp; { bzero(&atp->ati_mac, sizeof(struct atm_addr)); atp->ati_mac.aajype = AAT_MAC; bcopy (atp- > ati_ac- > ac_enaddr, &atp->ati macaa byte[ATM FIRST MAC], 6); } " LAN is ACTIVE, (and struct atmif *atp; if atm.c ~ " -38- int mtu; if (mtu && mtu < = atp->ati pcif->pcjιwjnaxjτιtu) ((struct ifnet *) atp->ati_ac)->if_mtu = mtu; ~ ((struct ifnet *) atp->ati ac)->if flags | = IFF RUNNING; } " /* * if delete lanO is notify the OS an ATM LAN is INACTIVE. 7 " if_deletejan(atp, mtu) struct atmif *atp; ((struct ifnet *) atp->ati ac)->if flags &= ~IFF_RUNNING; } /* * convert os ifunit to atmif index, this is not called very often. 7 if_getjan(atp) struct atmif *atp; { int i; struct atmif *atp0; for (i = 0, atpO = atp->ati_pcif->pc_atmif; atpO I = atp; atpO = atp0->ati_next, i+ +); return i; } /* * atm free packetsO is called to free packets queued on a VC. 7 " ~ #ifndef KERNEL #define m reem(m) atm free_msg(m) #endif atm ree_packets(vp) struct vcte *vp; { struct mbuf *m = (struct mbuf *) vp->vcte_packet; struct mbuf *m0; while (m) { mO = m->m_act; m reem(m); m = mO; } vp->vcte packet = 0; } ft if atm.c -39- /* * atm_append_packetO appends a packet on VC til it comes up. (we * only queue two packets) a 7tm_append_packet(vp, m) struct vcte *vp; struct mbuf *m; { m->m_act = 0; if (vp->vcte_packet) { if (((struct mbuf *) vp->vcte_packet)->m_act != 0) { mjreem(m); return; } else ((struct mbuf *) vp->vcte_packet)->m_act = m; } else ~ vp->vcte_packet = (caddrj) m; svc_giob- > svcstat.queued Jrames + + ; return; } /* * atm_send_packetsO is called when a VC becomes established. Any * queued packets are sent. 7 atm_send_packets(vp) struct vcte *vp; { struct mbuf *m = (struct mbuf *) vp->vcte_packet; struct mbuf *m0; while (m) { (caddrj) m, } /* * atm settimeO Copy OS notion of time into long array of 2. a 7tm_se " ttime(t) struct timeval *t; { extern struct timeval time; int spl; spl = spl7Q; if atm.c --40- *t = time; splx(spl); } int atm_arptimerO; int atm aφ ms per tick = 10000; /* once every 10 seconds */ /* * atm sched timeoutO schedule the OS to call atm_aφtimerO. 7 atm_schedJimeout(atp) register struct atmif *atp; { #ifdef notdef /* I assumed tcp start jimerO takes seconds ?? */ tcp start timer(&{atp->tmr_entry), ~atm~a _msj erjick / 10 ? ? ?, atm ' arptimeri (caddrj) atp); #else timeout(atm_arptimer, (caddrj) atp, atm_arp_ms_perjick * hz / 1000); #endif } I * * returns true if we are forwarding frames out a specific non-ATM * interface. Otherwise returns false. 7 atm_macJearned_on_non_atmJnterface(mac) caddr F mac; { return 0; } /* * atm_send_arpO send a frame encapsulating in 802.6/LLC/SNAP * type=ARP. 7 atm_send_arp(atp, mac, msg, len) struct atmif *atp; caddr t msg, mac; { struct mbuf *m; struct sockaddr sa; m = dtom(msg); m->m len = len; ASSERT(len < = MLEN); sasajamily = AFJJNSPEC; 7? if atm.c -41- ((struct ether header *) sa.sa data)-> ether Jype = ETHERTYPE_ARP; bcopy(mac, ((struct ether Jieader *) sa.sa_data)->ether_dhost, 6); niuoutput(atp->ati ac, m, &sa); } /* * aal_send_msgO sends the psecifled aal payload on a VC. Sends a * message, msg, of length, len, byte on VC vp using multiplex-id, * mid. If len is LENJ^ORJVIBUFJ^TR then msg is a pointer to an mbuf * chain. Otherwise it is a pointer into an mbuf. There should * probably be separate routines for this... 7 aal send ms v , mid, msg, len) struct mbuf *m; struct ifnet *ifp; struct sockaddr aal sa; if (len = = LEN_FOR MBUF_PTRS) { m - (struct mbuf *) msg; } else { struct setup *pdu; pdu = (struct setup *) msg; TR1 (TL3, "aal_send: %s\n", svc_pdu Jype_str(pdu- > lmi_pdu Jype)) ; if (pdu->lmi_pdujype < = LMIJ^DUJ-AST) svc_glob- > svcstat.pdus_sent[pdu- > lmi_pdu Jype] + + ; m = dtom(msg); m->mjen = len; if ((pdu->lmi_cref type | pdu->lmi_cref_value) && TL2) svc trace pdu(pdu, len, 0, vp->vcte ovpci); } " " vcoutput(vp, m, mid); } /* * atm macJnputO handles aal payloads processing 802.6 & calling * LLC. Should be called at SPUMP. Called by deliver_packetO. * atm_datajnd0 is called to process the ATM MAC header and get a * pointer to the LLC header. Ilc_datajnd0 is called to process * the He frame. 7 86 if atm.c ~ " -42- atm_macjnput(vp, mO) struct mbuf *mO; struct vcte *vp; { struct ifnet *ifp; struct atmjieader *ah; struct llc_shap *lp; u_char *src; ujong *p; Int macjidrjen; int promise = 0; ifp = (struct ifnet *) ((struct atmif *) vp->vcte_atmif)->ati_ac; ifp->if_ipackets+ + ; DB1(DL4, "aa%d: atm_macjnput\n", ifp->if_unit); ah = mtod(mO, struct atm header *); ASSERT((((uJong) ah) & 0x3) = = 0); if (m0->mjen < LLC LEN + ATMJHDRJ.EN + ah->atm_elen * 4) { DB1(DL1, "aa%d: atm πacjnput short frame\n", ifp->if_unit); m freem(mθ); return ENOBUFS; } if (ah->atm_dst.aa byte[2] & 0x01) { if (lniujindmulti(vp->vcte_atmif, &ah->atm_dst.aajjyte[2])) { promise = 1; } } else if (!ATM_ADDRJΞQ(ah->atm_dst, vp->vcte_atmif->ati_mac)) { promise = 1; } Ip = (struct He snap *) ((caddr t) ah + ah->atm_elen * 4 + sizeof pah)); macjidrjen = (caddrj) Ip - (caddrj) ah; src = &ah->atm_src.aaj3yte[2]; if (ifp->if_promisc) /* assume nit interface is active */ niu snitify_8026(ifp, O, macjidrjen, promise); If (promise) m freem(mθ); else { m adj(mO, macjidrjen); if feh->atm p jd \= ATM_PID_LLC) m reem(mO); else He data ind (ifp, mO, src, mac hdr len, Ip); } " " return 0; } /* SI if_atm.c -43- * svc_macjnput0 handles aal payloads with SVC PDUs. Note, SVC PDUs * must fit in one mbuf. Hence the limitation for 4 ATM LANs for * 4.2BSD UNIX implementations. This could be changed by using * clusters for PDUs. 7 svc_macjnput(vp, m) v struct vcte *vp; struct mbuf *m; { int len = mjen(m); if (len > MLEN) { svc_glob-> svcstat.pdujooJ_ig + + ; mjreem(m); return 0; } m = m pullup(m, len); if (m = = 0) { svc_glob->svcstat.pduJost_nomem+ + ; return 0; } ASSERT((mtod(m, int) &3) = = 0); if (m->m_next) { m reem(m- > m iext) ; m->m next = 0; } svc pdu(vp->vcte pcif, mtod(m, caddr t), len); } #include "../sys/domaiπ.h" extern struct domain svcdomain, pvcdomain; #define ADDDOMAIN(x) { \ extern struct domain x/**/domain; \ x/**/domain.dom_next = domains; \ domains = &x/**/domain; \ } /* * svc initO allocates global memory area for ATM signaling. 7 " extern int trjjuf_size; struct vcte svc_vctes[VCTAB 3IZE]; int svcjnit count = 0; struct ulptab svc_ulptab[NULPS]; struct atm_globs atm_globs; struct tr_globs tr_globs; struct svc_globs~svc_globs; char svc_e164_str[32]; svc_initO if atm.c { struct vcte *vp; int svc nacJ iO, svcjnacJnputO; if (svcJnft_cou.it) return; svc_glob-> static _buf = svc_e164_str; svcJnit_count = 1; bzero(&svc_glob->svcstat, sizeof (struct svcstat)); svc_glob->vcteJree = svc_vctes; svc_glob-> vcte base = svc_vctes; svc~glob->ulptab = svc_ulptab; svc glob->ulpJnuse = 0; for ftp = svc_vctes; vp < &svc_vctes[VCTAB_SIZE]; vp+ +) vp->vcte_next_cref = (struct vcte *) & vp[1]; (-vp)->vcte_next_cref = 0; svc glob->sig_ulp = ulp_register(LMI_LMI_ORG, LMI_LMI_PID, svc_mac input, svc_macjmi, 0); svc_glob->svc pcif ~ = (struct pcif *]Tatm_alloc_bytes(sizeof(struct pcif) * NNIU); bzero((caddr_t) svc_glob->svc pcif, slzeof(struct pcif) * NNIU); svc_glob->svc_pcifn = &svc_gTob->svc_pcif[NNIU]; svc_glob->svc_parms = svc_parms; atm glob- > atmif -= (struct atmif *) at " m alloc Jjytes(sizeof (struct atmif) * NATMS * NNIU); bzero([caddrj) atm_glob->atmif, sizeof(struct atmif) * NATMS * NNIU); tr init(tr_glob, trjjuf_size); ADDDOMAIN(pvc); ADDDOMAIN(svc); ADDDOMAIN(llc); pvc initO; } #if O atmj3zero(p, I) atmj3copy(s, d, i) atmj_cmp(s, d, I) fs if_atm.c -45- char *s, *d; { return bcmp(s, d, I); } #endif /* * svc_sched_timeoutO is called to schedule svcJimeoutO to be * called with the argument "pc" when the next signaling tick tack's. * On UNIX this is mapped onto timeoutO converting svc_ms_per_tick * to Hertz. Presumably MS-DOS uses Avis based timeouts. 7 svc_schedjimeout(pc) struct pcif *pc; { int svcJimeoutO; timeout(svcJimeout, (caddrj) pc, (svc ms per tick * hz) / 1000); } I* * svc_report_version_conflictO is called everytime a signaling PDU * with an unsupported version is received. It should report this * using the appropriate OS routines. For UNIX we printf to the * console no more than once every 15 seconds. 7 struct timeval svcJast_conflict; svc_report version conflictO { extern struct timeval time; if ((svcjast confiict.tv_sec + 15) < time.tv_sec) { printf ("niuO: signaling protocol version confiict\n"); svc last conflict.tv sec = time.tv sec; } } /* * atm alloc sgO allocates a msg buffer large enough for signal * PDUs. ~ 7 caddrj atm alloc msgO { struct mbuf *m; m = m_get(M_DONTWAIT, MT_DATA); if atm.c -46- if (!m) return 0; m->m_off == MMINOFF; m->m_len = 0; return mtod(m, caddr t); } struct mbuf *atm_lastfm; /* * atm free msgO frees message memory pointed to by cp. 7 atmjree_msg(cp) char *cp; { ASSERT(IVALID_VP((struct vcte *) cp)); atm lastfm = dtom(cp); m freem(atm lastfm); } /* * atm_alloc_bytesO is used to allocate memory for data structures * which are never freed, e.g., svc pcif tables. 7 caddrj atm_alloc bytes(n) { return kmem alloc(n); } int atm trace to console = 0; /* * Convert address to a hex byte string. The length of the address * is specified with the argument len. 7 char * atm_mac_sprintf(ap, len) u char *ap; { int i; char *cp = atm_glob->static_buf; static char digits[] = "0123456789abcdef ; for (i = 0; i < len; I+ +) { *cp+ + = digits[*ap > > 4] *cp+ + = digits[*ap+ + & Oxfj; *cp+ + = ':'; } *-cp = 0; return atm_glob->static_buf; SS if atm.c -47- if atm_.h -48- /* rf atm.h * ~ * COPYRIGHT 1992 ADAPTIVE CORPORATION * ALL RIGHTS RESERVED /* #ifndef NIU ATM H #define NIU_ATM_H included #include "bytes.h" #include "unipdu.h" I * * atm mac service Interface (asi). This Is the same as an ethemet * header so that upper layers can simply assume ATM Is an ethemet. 7 struct atmmsi { u_char asi_dst[6]; u_char asi_src[6]; u short asi type; }; /* * Structure of an ATM mac header for aal type 4, this is an 802.6 * header. 7 struct atmjieader { struct atm_addr atm_dst; struct atm_addr atm_src; union #define atm_mcblts un_mcb.atm mcb long #define atπTelen un_mcb.mcbiFs.mcB_elen #define atm_crc un_mcb.mcbits.mcb_crc #define atmjoss un_mcb.mcblts.mcb Joss #define atm_delay un_mcb.mcbits.mcb_delay #define atm_pid un_mcb.mcbits.mcb_pid *1 if atm_.h -49- #define ATM_PID LLC 1 /* protocol ID for LLC */ #define ATM MCTBITS NOCRC 0x04000000 /* protocol id 1 */ #define ATM~HDR LEN sizeof(struct atm header) #define ATM_PAD_SHIFT 24 /* * The only header extension defined is a return port address. The * length must be set to ATME_RPA_SIZE. Pad exists to get the 64 bit * address 64 bit aligned relative to the atm header. 7 struct atm_header_ext { #define ATME_RPA_TYPE 112 /* out of SMDS range */ #define ATME_RPA_BYTES sizeof(struct atm_header_ext) #define ATME_RPA_WORDS ((sizeof(struct atm_header_ext) +3)/4) /* * multicast address structures are linked to atm_arptabs which are * marked ATF_MULTI. Such entries are not timed out, nor are they * freed when underlying VCs are released. atm_delete lanO tree's * the ATF_MULTI atm_arptab entries and atm_addjan(5 & * atm_niu_to_niuO re-allocate them and re initiate MC VCs for the * registered addresses. 7 struct mcaddr { u_char mc_enaddr[6]; /* multicast address */ u_short mc_count; /* reference count */ struct aate *mc at; /* multicast VC */ }; #define MCADDRMAX 64 /* multicast addr table length */ #define MCCOUNTMAX (32*1024-1) /* multicast addr max * reference count */ /* * atmif, one per atm Ian, used by atm Ian layer 7 struct atmif { struct niu_arpcom *ati_ac; /* contains aφ and ifnet t ~ if atm_ -50- * structures */ struct atmif *ati_next; /* linked off pcif structure */ u_short ati_state; /* basically do we know who * we are */ u_short atijriid;/* mid used for multicast frames */ u_short ati mcasts; /* max # multicasts circuits * configured */ struct atm_addr ati_port; struct atm_addr ati_mac; #define ac_mac ati_mac.aa_byte[2] struct pcif *ati_pcif; struct aate *ati_arptab; /* set at initialization */ int ati_num_mcasts; struct mcaddr ati mcaddrs[MCADDRMAX]; }; /* ati state */ #define ATSJNACTIVE o #define ATS_ACTIVE 3 /* * global data structure for r/w variables and variables explicitly * initialized. 7 #include "llc.h" struct atm_globs { struct ifjrjidr *ltrb; struct atmif *atmif; int atmifn; int atmif used; struct llc_snap HcTdef; struct atm_addr atm_broadcast; struct atm_addr atm null; struct ulptab *atm ϋlp; int atm initialized; char static buf [32 j; }; #ifndef RT68K extern struct atm globs atm_globs; #define atm_glob (&atm_globs) #else #define atm_glob atm_get_globO struct atm_globs *atm~get_globO; #endif if atm_.h -51- #define LEN_FOR_MBUF_PTRS 0xf5560002 #define HASH_MULTICAST_ADDRESS(x) ((x)&0xff) caddrj atm_alloc msgO. atm alloc_bytesO; #define NATMS 4 /*~max # of ATM lans per physical * Interface */ #define e160_ntoa svc_e164_ntoa/* these are really E.164 addresses */ #endif /* NIU_ATM_H */ 9 if niu.c -52- /* if_niu.c * * COPYRIGHT 1992 ADAPTIVE CORPORATION * ALL RIGHTS RESERVED /* * Description: This file contains the network interface portion of * the niu device driver. * 7 static char sccsid[] = "%A%"; #ifndef KERNEL #define KERNEL #endif #ifndef INET #define INET /* only support internet addressing */ #endif #include " ./sys/param.h" #include " ./sys/systm.h" #include ". ./sys/mbuf.h" #lnclude ". ./sys/socket.h" #inciude ./sys/errno.h" #inciude ./sys/ioctl.h" #include ./sys/time.h" #include ./sys/kernel.h" #include ./sun4c/psl.h" #include "../net/if.h" #include "../net/netisr.h" #include "../net/route.h" #include "../net/if_aφ.h" #include "../sun/openprom.h" #include "../sundev/mbvar.h" #lnclude "../sun4c/mmu.h" ?/ if niu.c -53- #include "atm.h" #lnclude "llch" #include "svch" #include "if iiuaφ.h" #include "atmaφ.h" #include "if_nlu.h" #include "if iiuio.h" #include "trace.h" #lnclude "../net/nltjf.h" #include "snlt.h" Int aal_trace_enable = 1; /* debugging and tracing stuff */ #define DL1 1 #define DL2 niu_debug>1 #define DL3 niu_debug>2 #define DL4 niu_debug>3 #define DL5 niu_debug>4 #define TL1 1 #define TL2 niujrace>1 #define TL3 niu_trace>2 #define TL4 niu_trace>3 #define TL5 niu_trace>4 #define DRAIN_TIME 4 /* the SIOCNIUDBUG will set ALL debugging and tracing levels */ int niu_debug = 1 ; /* conveys important driver * information */ int niujrace = 1 ; /* show excessive detail of the * program stream */ extern int arp_debug; extern int arpjrace; extern int drv_debug; extern int drvjrace; extern int dumpjlag; int niumtu = 2000; int niu_unit_count = 0; /* total number of sw and hw * units installed */ struct niu_dev niu_info[NNIU]; /* network interface device structure */ int niuoutputO, niusoioctlO; /* * Name: niuoutput * * Input: *ifp - pointer to network interface to * use. m - mbuf pointer containing packet to be sent. * dst - ip address of destination. Output: None. 9-L if niu.c -54- * Return: 0 - no error. Error * Unix error code. * Description: This routine is called with a frame and a destination * address. Appropriate address resoltuion is performed for the * destination addresses until a VCI is obtained. The families * supported are: AF INET: An IP address is resloved using ARP * into a 48 bit address. AF UNSPEC: A 48 bit address is resloved * into a 60 bit address and " LLC/SNAP header is added. AF NS: A 48 * bit address is resloved into a 60 bit address but no LLC/SNAP * header is added. AF_CCITT: A 60 bit telephone number is resolved * into a VCI using the port address to vci tables. AF DU: A VCI * is supplied. No resolution is performed. The VCI is in * sockaddr_aal structure. AFJNET, AFJJNSPEC and AF_NS frames are * encapsulated as per 802.6. Other address families are assumed to * be encapsulated already. * * Note: The above families overload existing AF_xxx values. Also raw * aal frames get queued on the first atmlan's ifnet send queue for * lack of a better place to put them. * 7 int niu_reset_on_full = 0, niu_auto_resets = 0; int willie_panic = 0; niuoutput(ifp, m, dstin) struct ifnet *ffp; register struct mbuf *m; struct sockaddr *dstin; { int usetrailers, s, len, ifunit, rate; struct vcte *vp; struct ifqueue *ifq; struct sockaddr Idst; struct mbuf *mh; struct in_addr idst; u_char endest[6]; struct niu_arpcom *ac; struct aafparms *ap; struct llc_snap *lc; int iounit, error = 0; iounit = NIU_IFUNIT_TO_IOUNIT(ifp->if_unit); /* check if network is up */ TR4(TL3, "niuoutput(%x, %x, %x, af=%d)\n", ifp, m, dstin, dstin- >sa family); if ((ifp->if_flags & IFF_UPr= = 0 && dstin- >sa_family != AF_DU) { if iiu.c -55- m freem(m); error = ENETDOWN; goto rtn; } Ifunit = lfp->If_unlt; ac = &niu arpcoms[ifunit]; s = splr(ipTtospl(niu_info[iounlt].priority)); #ifdef INET if (dstin->sa_family == AFJNET) { idst = ((struct sockaddrjn *) dstin)->sin_addr; DB2(DL2, "aa%d: dest = %s\n", ifunit, inet_ntoa(idst)); if (!niu_arpresolve(ac, m, &idst, ldst.sa_data, &usetrailers)) { goto its; } ((struct ether Jieader *) IdsLsa data)->ether_type = ETHERTYPE IP; Idstsa amily = AF_UNSPEC; dstin = &ldst; } else #endif if (dstin->sa_family != AF_DU && dstin- >sa family 1= AF NS && dstin- >sa_famlly != AF~UNSPEC) { printf ("aa%d: can't handle af%d\n", ifp->if_unit, dstin- >sa_family); mjreem(m); niuJnfo[iounit].stats.errors+ + ; error = EAFNOSUPPORT; goto its; } /* * dstin.sa data contains an ethernet header w/o a source adr * & type, " {unless AF DU in which case we have a vci...) 7 if ((m->m off & 0x3) 1 1 M HASCL(m) 1 1 /* make room */ (m->m_off - MMINOFFr< (ATM_DATA_REQ_ROOM + sizeof(struct aal parms))) { if ((mh = m get(M_DONTWAIT, MT_DATA)) == NULL) { m_freem(m); error = ENOBUFS; goto its; FF; } if (dstin- >sa_family = = AFJJNSPEC) { if niu.c ~ -56- /* add LLC and SNAP */ Ic = &(mtod(m, struct llc_snap *)[-1]); *lc = atm_glob->llc deff lc->llcjype = ((struct atmmsl *) dstln->sa_data)->asl_type; m->m_off -= sizeof(*lc); m->m~len += sizeof (*lc); } len = 0; for (mh = m; mh; mh = mh->m_next) len + = mh->m len; ~ if (dstin->sa_family = = AF UNSPEC 1 1 dstin->sa family = = AFJMS) { /* get vci for mac * ~ address */ struct atmjieader *ah = mtod(m, struct atm_header *); struct aate *aat; if ((ifp->if_flags & IFF_RUNNING) = = 0) { m reerή(m); error = ENETDOWN; goto rts; } len + = sizeof (*ah); ah-; ah->atm_dst.aa_long[0] = AAT_MAC < < 28; bcopy(dstin->sa_data, &ah->atm_dst.aa_byte[2], 6); ah->atm_src = atm glob- > atmif [ifunit] .ati mac; ah->atm mcbits = ((ATM PID LLC < < 2JT + ((4 " (len & 3)) & 3)) < < ATM_PAD_SHIFT; ah->atm_elen = 0; m->m_off -= sizeof (*ah); m->mjen + = sizeof (*ah); aat = atm_find_at(&atm_glob-> atmif [ifunit], dstin- >sa_data); if (I aat | | l(vp = aat->aate_vcte)) { mjreem(m); error = EXDEV; goto rts; } if (vp->vcte_state < VCS_ESTAB) { atm_append_packet(vp, m); . goto rts; } } else { ASSERT(dstin->sa_family == AF DU); vp = ((struct sockaddr aal *) dst(n)->saal_vcte; If (vp) ASSERT(VAUD VP(vp)); } m->m_off -= sizeof (struct aal_parms); m->m_len + = sizeof (struct aal_parms); if_niu.c -57- ap = mtod(m, struct aal_parms *); ap->ap_mid = atm_glob->atmlf[ifunit].ati_mid; ap->ap_vpcl = vp->vcte ovpci; ap->ap_rate = vp->vcte~opeak_rate >> 4; /* from 1K bps to 16K * bps units *7 if (vp->vcte aal = = 0) ap->ap_fiags = AALP_RAW_CELL | AALP_CRC_NONE; else ~ ap->ap flags = AALP_CRC_NONE; /* iop, kludge till rev 2 fred i/f with 960 gets implemented */ if ((l(vp->vcte_pcif->pc flags & PCIF_NIU_TO NIU)) && vp->vcte pcif->pc sϊg->vcte_state == VCS_ACTlVE) ap->ap_flags | = AALP_ENABLE_XON_XOFF; vp- > vcte_opackets + + ; ifp- > if opackets++; /* " * if multicast then frame must be single threaded so used * the atm Ian index + 1 to indicate in which outbound queue * the frame should be placed. a 7ρ->ap orderq = (vp->vcte_flags & VCTEF_MCAST_CUENT) ? (Int) (vp->vcte atmif - atm_glob->atmif) + ~ 1 : AALPJJNORDERED; ap->ap_orderq = 4; /* iop, niu bug requires no more than * 1 vci per rate queue */ ap->ap len = len + sizeof *ap; /* * Place packet on interface transmit queue 7 ifq = &niuJnfo[iounit].sendq; if (IF_QFULL(ifq)) { DB0(DL2, "niuouput: interface q full\n"); if (niu_reset_on full 1 1 niuJnfo[iounit].type = = NIU_TYPE_SW 1 1 niu info[iouήit].board id = = NIU_REV3) { ASSERT(willie_panic = = 0); while (m) { m freem(m); IF DEQUEUE(ifq, m); IF~DROP(ifq); } " niu_auto_resets+ + ; (*niu info[iounit].reset) (iounit, 0); TR1(TL1, "aa%d auto reset\n", ifp->lf unit); printf ("aa%d auto reset\n", ifp->rf_unϊt); if (niu_info[iounit].type = = NIU TYPE_HW) { setup ιxbuf(&niu info[iounit]j } } else { IF_DROP(ifq); m reem(m); if niu.c -58- } error = ENOBUFS; } else { TR1(TL3, "%d on queue: ", ifp->if snd.ifqjen); IF ENQUEUE(ifq, m); } (*niu _info[iounit] .sendpkt) (iounit) ; rts: splx(s); rtn: TR3(TL3, "nluoutput->%d, %d q %d d\n", error, ifq->ifq_len, lfq->ifq_drops); return error; } /* * send mbuf chain m on physical interface pc over VC vp using the * aal associated with that vp. mid is the multiplex id for aal 3/4. * It is ignored for aal 5. 7 vcoutput(vp, m, mid) struct mbuf *m; struct vcte *vp; { int s, len; struct ifqueue *ifq; struct mbuf *mh; struct aal_parms *ap; int iounit = vp->vcte_pc'rf->pc_num; int error = 0; ASSERT(VALID_VP(vp)); s = splr(ipltospl(niu_info[iounit].priority)); if ((m->m_off & 0x3) 1 1 M HASCL(m) 1 1 (m->m_off - MMINOFFf< sizeof(struct aal_parms)) { if ((mh = m get(M_DONTWAIT, MTJ5ATA)) = = NULL) { m_freem(m); ~ error = ENOBUFS; goto rts; } mh->m_len = 0; mh->m_off = MMAXOFF; mh->m_next = m; m = mh; } m->m_off -= sizeof (struct aal_parms); m->m~len + = sizeof (struct aS_parms); ap = mtod(m, struct aal_parms *); ap->ap_mid = mid; if niu.c ~~-59- ap->ap_vpci = vp->vcte_ovpci; ap->ap_rate = vp->vcte opeak_rate >> 4; /* from 1K bps to 16K * bps units *7 if (vp->vcte aal = = 0) ap->ap_flags = AALP_RAW_CELL | AALP_CRC_NONE; ap->ap flags = AALP CRC NONE; if ((l(vp->vcte_pcif->pcJags S PCIF_NIU_TO_NIU)) && vp->vcte_pcif->pc_sig && vp->vcte_pcif->pc_sig->vcte_state == VCS_ACTIVE) ap->ap ags | = AALP_ENABLE_XON_XOFF; vp->vcte opackets+ + ; / ** if multicast then frame must be single threaded so used * the atm Ian index + 1 to indicate in which outbound queue * the frame should be placed. ? 9? if niu.c -60- IF_DROP(ifq); m freem(m); } " error = ENOBUFS; } else { TR1(TL1, "%d on queue: ", lfq->ifqjen); IF ENQUEUE(ifq, m); } (*niu_info[lounlt] .sendpkt) (iounit) ; rts: splx(s); TR3fTL1, "vcoutput->%d, %d q %d d\n", error, ifq->ifq_len, ifq->ifq_drops); return error; } struct atmif *atp; if (!niu_esr) return; atp = svc glob- >svc_pcif [unit]. pc_atmif; while (atpjT{ if (((struct ifnet *) atp->ati_ac)->if_snd.ifq_len) (*niuJnfo[unit].sendpkt) (unit); atp = atp- > ati next; } } /* * Name: niusoioctl * * Input: *ifp - pointer to network interface to use. cmd * - command requested. *data - data associated with the command. * Output: *data - data may be filled in by certain commands. * * Return: 0 - no error. Error - Unix error code. * * Description: This is the network interface loctl routine. An ifreq * structure must be used to access this routine. 7 niusoioctl (ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr t data; 9? if niu.c ~-61- { Int error = 0, 1, s, svcJimeoutO; int ifunit = lfp->if_unlt; extern int atmaφ timeδl, atmarp Jimeo2; struct ifreq *ifr = (struct ifreq *) data; struct Ifaddr *ifa = (struct Ifaddr *) data; struct niu_aφcom *ac = (struct nlu_aφCom *) ifp; struct dbjnfo *dbp; struct mcaddr *mca; struct atmif *atp; TR2(TL3, "aa%d(%x): niusoioctl entered\n", ifunit, cmd); switch (cmd) { case SIOCSIFADDR: /* set the interface ip address */ TR1(TL4, "aa%d: ioctl SIOCSIFADDR\n", ifunit); switch (ifa->ifa_addr.sa family) { #ifdef INET case AFJNET: niu_arpcoms[ifunit].acJpaddr = IA_SIN(ifa)->sin_addr; ' ifp->if_flags | = IFFJJP; break; #endif default: break; } break; case SIOCSIFFLAGS: /* set interface flags */ TR3(TL4, "aa%d: ioctl SIOCSIFFLAG (%d)flag=%d\n", ifunit, rfp->lf_flags, ifr->ifr_flags); ifp->ff_flags = lfr->ifr_flags; if (ifp->lf_flags & IFF_UP) { struct niu dev *niu; niu = &niu_info[NIU_IFUNIT_TO IOUNIT(ifp->if_unit)]; if (niu->type = = NIU_TYPE_HWJ " { setup rxbuf(niu); } } break; case SIOCGIFFLAGS: /* get interface flags */ TR2(TL4, "aa%d: loctl SIOCGIFFLAG flag=%d\n", ifunit, ifp->if_flags); ifr->ifr_flags = ifp->lf_flags; if niu.c -62- break; case SIOCGETPORT: /* get port address */ TR3(TL4, "aa%d: ioctl SIOCGETPORT port=%8x%8x\n", ifunit, atm glob- > atmif [if unit] .ati_port.aa_long [0] , atm~glob-> atmif [ffunltj .ati port.aa_long[1 j) ; ifr->ifr " addr.sajamily = AF_CCITT; bcopyf&atm_glob->atmif[ifι_πit].ati_port, if r- > tf r addr.sa_data, sizeof (struct atm_addr)); break; case SIOCNIUDBUG: /* set debug level for the entire niu device */ dbp = (struct dbjnfo *) ffr->ifr_data; niu_debug = dbp->niu_debug; /* network interface */ niu race = dbp->niujrace; arp_debug = dbp->arp_debug; /* arp */ arpjrace = dbp->arpjrace; drv_debug = dbp->drv_debug; /* /dev/nlu */ drvjrace = dbp->drv trace; DB3(DL2, "aa%d: ioctTSIOCSNIUDBUG niu=%d %d\n", ifunit, niu debug, niu trace); DB3(DL2, "aa%d: ioctl SIOCSNIUDBUG arp=%d %d\n", ifunit, arp_debug, arp race); DB3(DL2, "aa%d: ioctl SIOCSNIUDBUG drv=%d %d\n", ifunit, drv_debug, drvjrace); break; case SIOCGIFADDR: case SIOCGMACADDR: /* get the interface ip address */ TR1 (TL2, "aa%d: ioctl SIOCGIFADDR\n", ifunit); bcopy(&niu_arpcoms[ifunit].ac_atmif->ati_mac.aa_byte[2], ifr->ifr_addr.sa_data, 6); ■ rβsk * case SIOCSMACADDR: /* set the interface ip address */ TRKTL2, "aa%d: ioctl SIOCSIFADDR\n", ifunit); bcopy(ifr-> ifr_addr.sa_data, &niu arpcoms[ifunlt].ac_atmif->ati_mac.aa_byte[2] I 6); break; case SIOCGAATIMEOI: bcopy(&atmarp_timeo1, &ifr->ifr_metric, sizeof(int)); sizeof (int)); / / if_niu.c -63- bcopy(&atmarp_timeo2, &ifr->ifr_metric, sizeof(int)); brθsk * case SIOCSAATIME02: bcopy(&ifr->ifr_metric, &atmarp_timeo2, sizeof (int)); brβsk * case SIOCTIMEOUT: if ((atp = atm_glob-> atmif) = = 0) { error = ENXIO; break; } s = splnetO; untimeout(svc Jimeout, atm_glob- > atmif [ifunit] .ati_pclf) ; svc timeout(atm_glob-> atmif [if unit] .ati_pcH); for atp < &atm_glob->atmif[atm_glob->atmif_used]; atp+ +) { if (atp->ati_state = = ATSJNACTIVE) continue; atm arptimer(atp); } splx(s); brθs * case SIOCADDMULTI: TR1 CTL4, "aa%d: ioctl SIOCADDMULTI\n", ifunit); error = niu_addmulti(ifp, ifr->ifr_addr.sa_data); brβπk * case SIOCDELMULTI: TR1 (TL4, "aa%d: ioctl SIOCADDMULTI\n", ifunit); error = niu_delmulti(ifp, ifr->ifr_addr.sa_data); brssk * case SIOCSPROMISC: ifp->if_flags Λ = IFF_PROMISC; printf("aa%d promiscuous %sabled\n", ifunit, ifp->if_fiags & IFF_PROMISC ? "en" : "dis"); break; case SIOCGSTATE: /* get signaling vc state */ TR2(TL4, "aa%d: ioctl SIOCGSTATE state=%d\n", ifunit, atm_glob- > atmif [if unit] .ati_pcif- > pc_sig- > vcte_state) ; tfr->ifr_metric = atm_glob- > atmif [if unit] .ati_pcif- > pc_sig- > vcte_state; break; case SIOCSSTATE: /* get signaling vc state */ TR2(TL4, "aa%d: ioctl SIOCGSTATE state =%d\n", ifunit, atm_glob->atmif[ifunit].ati pcif- >pc_sig-> vcte state); if (ifr->ifr_metric < VCSJNACTIVE 1 1 ifr->ifr metric > VCS_ACTIVE) error = EINVAL; else svc_new_state(atm_glob->atmif[ifunit].ati_pcif->pc_sig, if niu.c -64- ifr->ifr_metric); break; default: DB2(DL2, "aa%d: ioctl bad command =%x\n", ifunit, cmd); error = EINVAL; } return (error); } / ** Find a multicast entry in the multicast filter for atm Ian, atp. 7 struct mcaddr * niujindmulti(atp, mac) struct atmif *atp; u_char *mac; { int i; for (i = 0; i < atp->ati_num_mcasts; i+ +) if (bcmp(atp->ati_mcaddrs[i].mc_enaddr, mac, 6) = = 0) return &atp->ati_mcaddrs[i]; return 0; } /* * Add a multicast address to multicast filter for atm ian, atp. 7 niu_addmulti(ifp, mac) struct ifnet *ifp; u_char *mac; { int i, s, error; struct aate *at; struct mcaddr *mc; struct atmif *atp = ((struct niu_arpcom *) ifp)->ac_atmif; if ((mac[0] & 0x1) = = 0) return EINVAL; /* not a multicast address */ mc = niu_findmulti(atp, mac); s = splimpO; if (mc) { if (mc->mc_count < MCCOUNTMAX) { mc- > mc_count + + ; splx(s); return 0; } else { splx(s); return ENOSPC; niu.c " -65- } } if (atp->ati_num_mcasts = = MCADDRMAX) { splx(s); return ENOSPC; } mc = &atp->ati_mcaddrs[atp->ati_num_mcasts]; mc->mc_count = 1; bcopy(mac, mc->mc_enaddr. 6); at = mc->mc_at = atm_find_at(atp, mac); if (at = = 0) { splx(s); return ENOSPC; } at->aate_flags | = ATF_MULTI; atp- > ati num_mcasts+ +; spix(s); ~ return 0; } /* * Delete a multicast address from multicast filter for atm Ian, atp. 7 niu_delmulti(ifp, mac) struct ifnet *ifp; u_char *mac; { struct mcaddr *mc; int i, s; struct aate *at; struct atmif *atp = ((struct niu_arpcom *) ifp)->ac_atmif; mc = niu_findmulti(atp, mac); if (mc = = 0) return ENXIO; s = splimpO; if (~mc->mc count > 0) { splx(s); return 0; } else if (at = mc->mc at) { ASSERT(at->aate_flags & ATF MULTI); at->aate_flags &= ~ATF_MULTI; atm_aate_free(at); bcopy(&atp->ati_mcaddrs[-atp->ati_num_mcasts], mc, sizeof(*mc)); splx(s); return 0; } if niu.c -66- /* * go steal an ethemets low order 2 bytes and append it two * Adaptive's IEEE prefix. u 7nsigned int def_enaddr[2] = {0x0080b2e0, 0x00010000}; nlu_get_enaddr(unlt, enaddr) ujnt unit; u char *enaddr; { struct ifnet *ifp; extern struct ifnet *ifnet; bcopy(def enaddr, enaddr, 6); for (ifp = ifnet; ifp; ifp = ifp->if_next) if (ifp->if mtu = = 1500) { enaddF[3] = (((struct niu_arpcom *) ifp)->ac_enaddr[3] & 0x1 f) | OxeO; enaddr[4] = ((struct niu_arpcom *) ifp)->ac_enaddr[4]; enaddr[5] = ((struct niu_arpcom *) ifp)->ac_enaddr[5]; break; } enaddr[0] = (u_char) unit < < 1 ; } /* * This routine just looks up the input vci and dispatches the frame * to the appropriate input routine based upon vci. Signaling and * raw user access does not necessarily use 802.6 framing. 7 int svc_send_releases = 1; deliver_packet(unit, mO, vci) int unit; struct mbuf *m0; u short vci; { struct vcte *vp; struct pcif *pc; int s; int plen; plen = mjen(mθ); aal_trace_m(m0. plen, 1, vci); s = splimpO; pc = &svc_glob->svc_pclf[unit]; if (pc->pc_raw_vp) { pc-> pc_raw_vp-> vctejpackets + + ; pvc_input(pc- > pc_raw_vp, mO) ; } else if (vp = ivpci to vcte(pc, vci)) { if (VCS_DATA_IND_OK & VCS_TO_VMASK(vp->vcte_state)) { O if niu.c -67- ASSERT(VAUD_ULP(vp->vcte_ulp)); vp- > vctejpackets + + ; (*vp->vcte_ulp->ulp_data) (vp, mO); } else m freem(mθ); } else! (svc_send_releases && pc->pc_sig) { struct release *pdu; mjreem(mθ); pdu = (struct release *) atm alloc msgO; pdu->lmi_proto = LMI_PROTOCOL; pdu->lmi_pdu_type = IDU_INVAUD_PDU; pdu->lmi_cref_type = LMI_CREFTYPE_PVC; pdu->lmi_cref_value = vci; LMI_SET_ELEMENT(&pdu-> lmi_cause, LMI_RELEASE_CAUSE, VCI UNACCEPTABLE); svc xduTpc, 0, pdu, sizeof *pdu); } splx(s); } /* * niu_snitifyO makes a copy of mO, converts the 802.6/SNAP header * into an ethernet header and calls snit intrO- 7 struct nitjf niu iit; u_short enet_hdr[7]; niu_snitify_8026(ifp, m, hlen, promise) struct ifnet *ifp; struct mbuf *m; { int adj; u_char *sp; /* start of destination adr in 802.6 header */ ASSERT(hlen > = 20); if (m->m_ien < hlen + 3) return; /* not enough for He */ sp = mtod(m, u_char *); bcopy(&sp[2], enet hdr, 6); bcopy(&sp[2 + 8], " &enet hdr[3], 6); if (spfhlen] = = (u_char) Oxaa) { bcopy(&sp[hlen + 6], &enet_hdr[6], 2); adj = hlen + 8; } else { bcopy (&sp[hlen], &enet_hdr[6], 2); adj = hlen + 3; } if (m->m_len < adj) έ return; m->m_len -= adj; m->m_off + = adj; niu_nit.nif_header = (caddrj) enetjidr; niu nitnif idrlen = 14; nlu_nit.nlf_bodylen = m_len(m) - 14; niu_nit.nif_promisc = promise; snit_intr(ifp, m, &niu_nit); m->mjen + = adj; m->m off -= adj; } int dumpjen = 64; int dumpjimit = 0; dump_frame(s, dp, words) char *s; int *dp; int words; int dumpbuf [64]; int dumplen - 64; dump_chain(s, m) char *s; struct mbuf *m; { int left = m_len(m); if (left > dumplen) left = dumplen; m_copydat(m, (char *) dumpbuf, left); left = (left + 3) / 4; dump frame(s, dumpbuf, left); } m_len(m) struct mbuf *m; { int len; /oγ if niu.c -69- for (len = 0; m; m = m->m_next) len + = m->m_len; return len; ~ } atm_arpioctl (ifunit, cmd, data) int cmd; caddr t data; { struct aφreq *ar = (struct arpreq *) data; struct aate *at; int s, error = 0; if (ar->arp_pa.sa_family ! = AFJJNSPEC 1 1 ar->arp ha.sa family 1= AF_CCITT) return (EAFNOSUPPORT); calc_mlen(m) struct mbuf *m; { int len = 0; TR0(TL2, "calc nlen: called\n"); while (m) { len + = m->m_len; m = m->m next; } DB1 (DL3, "calc mien: len=0x%x\n", len); return (len); } m_copydat(m, buf, len) struct mbuf *m; char *buf; int len; { if niu.c ~ " -70- caddr t), buf, J); aaljrace_m(m, tlen, in, vci) struct mbuf *m; { int s; if (!aaljrace_enable) return; s = spl70; atm trace_buf(m, m_copydat, IF_TRACE_LOG, tlen, in, vci); splxTs); } if niu.h -71- /* lf_niu.h * COPYRIGHT 1992 ADAPTIVE CORPORATION * ALL RIGHTS RESERVED /* static char sccsid[] = "@(#) if niu.h 1.12@(#)"; */ /* * The aal interface is implemented as messages send (asynchronously * between the MAC and aal layers. The aal_parms structure preceeds * frames transmitted and received. It is the complete interface * between the aal layer and the aal user. Rather than define some * VC parameters at circuit setup time and pass other per frame * parameters with each frame, all parameters are passed with each * frame. Thus, at the loss of some performance, the interface * betwen the H/W NIU (and 960 OS) and the host is simplified. /* ap_crc32 values */ #define AALP_CRC_NONE 0 #define AALP_CRC_ADAPTIVE 1 #define AALP_CRC_SMDS 2 #define AALP_RAW_CELL 4 #define AALP_ENABLE_XON_XOFF 8 /* enable xon/xoff higher * layer */ #define AALP_LOOP_VCI 0x10 /* loop rev frames at 960 */ /* ap_rate value to specify maximum link rate */ #define AALP_MAX_RATE (~0) /* all one's */ /* ap orderq value if frame has no ordering constraints */ #define AALP UNORDERED 0 /* * niuoutputO sockaddr used for raw aal access with AF_DU. if niu.h -72- ; /* used for SIOCNIUDBUG ioctl */ struct dbjnfo { char niu_debug; char niujrace; char arp_debug; char arpjrace; char drv_debug; char drv trace; }; /* MTU size */ #define AAMTU 9188 /* receive control registger */ #define RCNTL_REG 0 #define RCNTLJDLEJNTR 0x80 /* rx fill interrupt */ #define RCNTL_FILL INTR 0x40 /* rx idle interrupt */ #define RCNTL PASS " IDLE 0x04 /* go through idle on every * cell */ ~ #define RCNTL_STOPJDLE 0x02 /* stop on idle */ #define RCNTL_RESET 0x01 /* reset rx fifo, abort cell, * spill mode */ #define RCNTL_MASK 0xc7 /* bits 3-5 unused */ /* receive status register 1 */ #define RSTAT1 REG 1 #define RSTAT1 UGHT 0x80 /* rx fiber light present */ #define RSTAT1_FIF0 HALF 0x40 /* rx fifo half flag */ #define RSTAT1_FIFO FULL 0x20 /* rx fifo full flag */ #define RSTAT1 FIFO EMPTY 0x20 /* rx fifo empty flag */ /// if niu.h -73- #define RSTAT1_VIOLATION 0x04 /* rx violation */ #define RSTAT1_MASK Oxec /* bits 0,1,4 unused */ /* receive status register 2 */ #define RSTAT2 REG 2 #define RSTAT2JDLE 0x80 rx is idle */ #define RSTAT2_FIFO_OVR 0x40 /* rx fifo overflow */ #define RSTAT2_CMD_OVR 0x20 /* rx command overflow */ #define RSTAT2_CMD_RECV 0x10 /* ix command received */ #define RSTAT2 COMMAND OxOf /* rx command, 4 bits */ #define RSTAT2_INTR_MASK OxdO /* rx interrupt mask */ /* transmit control register */ #define TCNTL_REG 3 #define TCNTL_RESET 0x80 /* tx reset */ #define TCNTLJ.OAD 0x40 /* load tx fffo */ #define TCNTL_SOC_ENBL 0x20 /* start of cell enable */ #define TCNTL_ENABLE 0x10 /* enable send from fifo */ #define TCNTL_COMMAND OxOf /* tx command */ /* transmit status register */ #define TSTAT REG 4 #define TSTAT FIFO FULL 0x80 /* tx fifo full */ #define TSTAT~FIFO~HALF 0x40 /* tx fifo half */ #define TSTAT_FIFO_EMPTY 0x20 /* tx fifo empty */ #define TSTAT_MASK OxeO /* bits 0-4 unused */ #define MAXJNTRJTIME 200 /* dma controller control/status */ #define DMACJNT_PEND 0x00000001 /* interrupt pending */ #define DMAC_ERR_PEND 0x00000002 /* error pending */ #define DMAC_DRAINING OxOOOOOOOc /* draining D cache */ #define DMACJNT_EN 0x00000010 /* interrupt enable */ #define DMAC_FLUSH 0x00000020 /* flush buffer */ #define DMAC_SLAVE_ERR 0x00000040 /* slave error */ #define DMAC_RESET 0x00000080 /* reset DMA */ #define DMACJ/VRITE 0x00000100 /* 1 = memory write; 0 = * memory read */ #define DMAC_EN_DMA 0x00000200 /* enable dma */ #define DMAC_EN_CNT 0x00002000 /* enable counter */ #define DMAC_TC 0x00004000 /* terminal count */ #define DMAC_ALE_AS 0x00100000 /* 1 = addr latch enb; 0 * = addr strobe */ #define DMAC_LANCE_ERR 0x00200000 /* E channel error */ #define DMAC_FASTER 0x00400000 /* fast access for D * channel */ #define DMAC_TCI_DIS 0x00800000 /* TC interrupt disable */ #define DMAC_EN_NEXT 0x01000000 /* enable next */ #define DMAC_DMA_ON 0x02000000 /* DMA on */ if niu.h _ -74- #define DMAC_A_LOADED 0x04000000 /* address loaded */ #define DMAC NAJ.OADED 0x08000000 /* next address loaded */ #define DMACJDEVJD 0x10000000 /* device id */ #define DMACJNTR MASK 0x00000003 /* DMAC Interrupt * pending mask */ /* dma address */ #define DMAC_ADDR_REG 6 /* dma next address */ #define DMAC_ADDRNXT_REG 7 /* dma count */ #define DMAC_COUNT_REG 8 /* dma next count */ #define DMAC_CNTNXT_REG 9 #define SW_NUM_SWREGS 10 /* number of registers on sw * niu */ #define NUM_SWREGS 3 /* number of registers on sw *7ιiu */ #define NUM_SWINTR 1 /* number of interrupts on sw * niu */ struct niu_addr_reg { u_char *rcntl_reg; /* receive control register */ u_char *rstatl_reg; /* receive status 1 register */ u_char *rstat2_reg; /* receive status 2 register */ u_char *tcntl_reg; /* transmit control register */ u char *tstat~reg; /* transmit status register */ }; struct niu_value_reg { u_char rcntl_reg; /* receive control register */ u_char rstat1_reg; /* receive status 1 register */ u_char rstat2~reg; /* receive status 2 register */ u_char tcntl_reg; /* transmit control register */ u char tstat reg; /* transmit status register */ }; " struct hw_niu_reg { ujong *dma_reg;/* LSI dma status register */ u_short *attn_reg; /* niu attention register */ ujong *base_reg; /* niu base register */ u~short *intr_reg; /* niu interrupt acknowledge * register */ u_short *lock_reg; /* niu dma lockout register */ ujong dma_value; /* local copy of dma status ifjiiu.h -75- * register */ u_short attn_value; /* local copy of niu * attention register */ ujong base_value; /* local copy of niu base * register */ j . struct dmac_addr_reg { ujong *status_reg; /* status control register */ ujong *addr_reg; /* address register */ ujong *next_address_reg; /* next address register */ ujong *count_reg; /* count register */ ujong *next_count_reg; /* next count register */ #define NUM_DESC 1 /* up to 1 descriptors in * chain */ typedef struct { caddrj dma_addr; int size; } DMA_DESC_BUF; struct dmac_value_reg { ujong status_reg; /* status control register */ ujong addr_reg; /* address register */ ujong next_address_reg; /* next address register */ ujong count_reg; /* count register */ ujong next_count_reg; /* next count register */ struct niu_stats { ujong ip_opkts; /* number tx ip packets */ ujong ipjpkts; /* number rx ip packets */ ujong arp_opkts; /* number tx ip packets */ ujong arpjpkts; /* number rx ip packets */ ujong drv_opkts; /* number tx driver packets */ ujong drvjpkts; /* number rx driver packets */ ujong crc_errors; /* total number crc errors */ ujong errors; /* total number misc errors */ ujong allocdjailed; /* number of alloc_desc * failures */ ujong finddescjailed; /* number of mismatched * tags */ /* packet direction */ #define NIUJ.ECEIVE 0 /* host receiving packets * from niu */ #define NIUJTRANSMIT 1 /* host trasmitting packets * to niu */ // ≠ if niu.h -76- typedef struct { int injjse; int cmd Jag; struct mbuf *m; int num_desc; caddrj desc addr; DMA_DESC_BUF *desc_ptr; caddTj ~ data addr; } DMA_DESC; #define NUM_DMA_DESC 11 #define COMMAND_SIZE 16 #define NO COMMAND 0 #define REδET_CMD 1 #define STATUS CMD 2 #define CLR_STATS_CMD 3 #define RX_DATA_CMD 4 #define TX_DATA_CMD 5 #define CLRJNTR_CMD 6 #define RESET Q_CMD 7 #define WORK_AROUND_CMD 8 #define BOARD_ID_CMD 9 #define CMDJNTR OFF 0x00 #define CMD INTR~ON 0x01 #define CMD~CRC_MASK 0x06 /* frame level crc */ #define CMD_CRC_ADAPTIVE 0x02 #define CMD_CRC_SMDS 0x04 #define CMD_CRC_NONE 0x00 #define CMD_AAL_MASK 0x18 #define CMD_AAL4 0x00 /* default is aal4 */ #define CMD_AAL5 0x08 /* not yet implemented */ #define CMD_AAL RAW 0x18 /* send raw cell ala s/w niu */ #define CMD_ENABLE XON_XOFF 0x20 /* enable xon/xoff */ #define CMD_LOOP_VCI 0x40 /* loop rev frames at 960 */ typedef struct { u_char param[COMMAND_SIZE - 4]; u_short tag; u char flags; u_char command; } COMMAND; typedef struct { u char param[COMMAND_SIZE - 8]; ujnt board Jd; u_short tag; u char flags; //S if niu.h -77- #define CMD_Q SIZE NUM DMAJ3ESC #define START CMD Q( q ) (&((q)->cmd_q[ 0 ])) #define CUR_C ~ MD_C7( q ) (&((q)->cmd_q[ (q)->cmd_elem ])) #define END_CMD_Q( q ) (&((q)->cmd q[ CMD_Q_SIZE - 1 ])) #define NEXT_CMD_Q( elem ) if (+ + (elenij > = CMD_Q_SIZE)\ (elem) = 0; typedef struct { int cmd_elem; COMMAND *cmd q; } CMD Q; if niu.h -78- u short tx_packets; HWNIU_STATS stats; u char reserved [6]; } ~ NIU_STATUS; typedef struct { caddr t cmd_start; /* command q start */ caddr cmd_end;/* command q end */ caddrj done_start; /* completed q start */ caddrj done_end; /* completed q end */ caddr t status start; /* status location */ } HOST_BA3E; #define MAP_CMD_Q 0 #define MAP DONE Q 1 #define MAP_STATUS 2 #define MAP BASE 3 typedef struct ~{ caddrj base dma; /* host base dma address */ caddrj status_dma; /* status dma address */ caddrj cmd_dma;/* cmd q dma address */ caddr t done dma; /* done q dma address .*/ } ~ DMA_ADDR; /* board ids */ #define NIU REV2 0 #define NIUJ.EV3 1 #define PNIU_REV1 2 #define PNIU_REV2 3 #define PNIU_REV3 4 struct niu_dev { u_char type; u_short tag; /* tag for each command */ CMD_Q cmd_q; /* command q */ CMD Q done_q; /* completed q */ NIU STATUS status; /* hw_niu status location */ HOS ~ T_BASE base; /* host/niu io base structure */ DMA_ADDR dma addr; /* mapped dma address */ int priority; /* interrupt priority */ struct hw_niu_reg niu_reg; /* address of registers on * niu board */ struct niu stats stats; /* niu statistics */ DMA_DE§C desc[CMD_Q_SIZE]; /* descriptor pool */ int intrjimeout; /* interrupt timeout counter */ struct niu_addr_reg niu addr; /* address of registers on * niu board *] struct niu_value reg niu value; /* contents of registers on " * niu Board * " struct dmac addr reg dmac_addr; /* address of registers on * D64853A SBus controller */ if_niu.h -79- struct dmac_value_reg dmac_value; /* contents of registers * on L64853A SBus * controller */ int (*sendpkt) 0; /* hw specific routine to * send queued pkts */ Int (*reset) 0; /* hw specific routine to * reset hw */ #define NIU TYPE SW 1 #define NIU_TYPE_HW 2 u_short direction; /* receive or transmit * packets */ int boardjd; /* niu board revision */ Int intr_state; /* is in interrupt state */ int post xbuf; /* count of rx buffers to be * posted */ struct ffqueue sendq; int macaddr[2]; }; extern struct niu_dev niu_info[]; extern int cell_flag; /* set for trasmission of raw 53 byte * cells */ #define NIU_IFUNIT_TO_IOUNIT(ifunit) (atm_glob- > atmif [if unit] .ati pcrf- > pc_num) / P Im.c -80- /* lm.c * * COPYRIGHT 1992 ADAPTIVE CORPORATION * ALL RIGHTS RESERVED */ *******************************END********************************** #ifdef CERNEL #include "ipc_def.h" #include "net_def.h" #include <global_def.h> #include <driver.h> #undef Imjnit #else /* ifndef CERNEL */ #include <stdint.h> #include <global_def.h> #include <ITC_if.h> #include <driver.h> #include <RT_if.h> #include <timer.h> #include <RT_def.h> #include <enet_if.h> #include <net_def.h> #define ERRLOG printdbg #define printf printdbg #endi /* Hdef CERNEL */ #include "unipdu.h" #include "nnipdus.h" #include "altask_gl.h" #include "sigtask_gl.h" #include "svctask_gl.h" #include "svc_if.h" #include "snmpjncl.h" #include "AAL_if.h" #include "wdb_if.h" #include "q.h" #include "bits.h" #include M lm.h" ImjcbJ *lm_initO; Im.c -81- #ifdef CERNEL #include <stdio.h> main(argc, argv, environ) Int argc; char *argv[]; char **environ[]; { HNT32 generic; HNT32 instance; tlNT32 status; tUINTβ test_mode; generic = TID_LM; instance = 0; if ((status = SetTid(generic, instance)) != RT_SUCCESS) { printf ("lm: SetTid Failed\n"); } else { Im_main0; } } #endif /* ifdef CERNEL */ lm mainO { Imjcb J *tcb; struct TimerBlock *tmr_blk; tUINT32 *msg; HNT32 delay; tUINT32 timerid; tUINT32 timerarg; tcb = ImJnitO; if (tcb = = NULL) { printf ("lm: init failed"); return; } tmr blk = tcb->tmr_blk; timerid = tcb->timerid; timerarg = tcb->timerarg; while (TRUE) { delay = 0; while (delay < = 0) { delay = TimerCheck(tmr blk, &timerid, &timerarg); if (delay < = 0) { im_srvcjimer(2); RTC_TimerSet(tmr_blk, (GetTimeO + (STGRAN)), timerid, timerarg); Im.c -32- } msg = (tUINT32 *) ReqMsg(LM_EX_MSK, delay); if (msg I = NULL) { lm_srvc msg(msg); free(msg); } } lm_srvc timer(delay) tUINT32 delay; { SETUP TCB; ret = RT_SUCCESS; printf ("lm_srvc__msg, MsgType = %d\r\n", msg- > MsgType); endProxyCheckinM _ et ar ype , Im.c -83- MHW_GetSlotldO); break; default: If ((msg-> MsgType > = MSG_WDB BASE) && (msg-> MsgType < = MSG_WDB~TOP)) { wdb process msg(lm_crt_cfg, msg); } else C ret = !RT_SUCCESS; goto err exit; } break; } return (ret); err_exit: return (ret); } lm_srvc_aal_msg(msg) tAAL_TA_IND_RX *msg; { int ret; lm_alan_cfg_enq *aal_msg; tUINT32 pvci; tUINT32 vci; aal_msg = (lm alan cfg_enq_t *) msg->Rx.Buffer; ret = RT_SUCC " ESS; vci = ((lm_atm_hdr_t *) & (msg->RxATM Hdr))->vci; pvci = VCI_TO_PVCIm(vci); if (aal_msg->lmi hdr.lh_pdu type != NN PDU STATUS_ENQ aal_msg->lmi_hdr.lh profo 1 = NNI_PROTOCOL 1 1 pvci 1= NNI_NAC VCl) { ret = IRT_SUCCE " SS; goto err exit; } switch (aal_msg->enq.elem type) { case ALAN_CFG_ENQ: " ret = lm_srvc_alan_cfg_enq(msg); brβsk * case LMI CONFIG_ENQ: ret = lm_srvc_es_cfg_enq(msg); break; default: goto err_exlt; break; } return (ret); s*J Im.c -84- err_exit: return (ret); } lm srvc_alan cfg_enq(msg) tAAL_TA_IND_RX *msg; { Int ret; lm_alan_cfg_enq_t *alan enq; tALANCFG ENQ *enq;~ tALANCFG RESP *resp; tATMADDR paddrs[MAX_PORTS_PER_SLθη; tUINT32 in_srvc; tUINT32 in_srvc_mask; int i; int max_port; lm_port_addrj tst; InrTportJ ~*port; lm macj *mac; qliήkj *link; ret = RT_SUCCESS; alan_enq = (lm_alan_cfg_enqj *) msg->Rx.Buffer; enq = &alan_enq->enq; 0); /AS Im.c -85- if (mac ! = NULL && !IS_EMPTY_Q(mac->mv_q)) { link = HEAD_Q(mac->mv_q); mv = (lm_mac_vlanj *) link->data; tst.aa_lannum = mv " >mlid; paddrsfi] = tst; in_srvc I = in_srvc_mask; } } in srvc mask > > = 1 ; atmjidr = *((lm_atm_hdr t *) & msg->RxATM_Hdr); prefix = *((lm_prefixj *) £ msg->RxPrefix); rx vci = atm hdr.vci; tx~vci = (rx vci & (~SIG_PVCI_MASK)) | PVCI_TO VCIm(NNI_SIG_VCI); rx_shelf = VCI_TO SHELFm(rx_vci); rx_slot = VCI TO SLOTm(rx vci); rx_port = VCI_TO_PORTm(rx_vci); BUILD_ATM_HDR(&atm hdr, tx_vci); BUILD_UCAST_PREFIX(&prefix, rx_shelf, rx_slot, rx_port); lm_send_alan_cfg(prefix, atm_hdr, enq->slotid, ln_srvc, max_port, paddrs); return (ret); err_exit: return (ret); } lm_srvc_es cfg_enq(msg) tAAL TA " IND RX *msg; { m_a m_ r a m_ r; lm_mac_addr_t *mac_addr; lm_port_addrj port_addr; lm_es_cfg_resp *resp; int respjen; int i; SETUP TCB; Im.c -86- ret - RT_SUCCESS; es_enq = (lm_es_cfg_enq_t *) msg->Rx.Buffer; enq = &es_enq->enq; mac_addr = &enq->af_my_address; atm_hdr = *((lm_atm_hdr t *) & msg->RxATM_Hdr); prefix = *((lm_prefix t *) S msg->RxPrefix); rx vci = atm hdr.vclT tx vci = (rx vci & (~SIG PVCI MASK)) | PVCI_TO_VCIm(NNI_SIG_VCI); rx_shelf = VCI TO SHELFm(rx_vci); rx_slot = VCI_?C_5LOTm(rx_vci); rx port = VCI TO PORTm(rx_vci); LMJNIT_PORT_ADDR(&port_addr, tcb->my_node, rx_shelf, rx_slot, rx_port)7 port = FIND_PORT(tcb->port_q, &port_addr); mac = FIND~MAC(tcb->mac_q, mac addr); if (mac •= = NULL) { mac = add_mac(mac_addr); If (port I = NULL) { atch_mac_port(mac, port); lm dup port dfits(port, mac); } } if (port != NULL && (port->mac ! = mac 1 1 mac->port ! = port)) { free_mac_port(port->mac, port); atch mac port(mac, port); } resp = lmj_uild_es_cfg_resp(mac, enq, &respjen); if (resp = = NULL) { ret = IRT_SUCCESS; goto err exit; } BUILD_ATM_HDR(&atm hdr, tx_vci); BUILD_UCAST_PREFIX(&prefix, rx_shelf, rx_slot, rx_port); ret = lm_send_es_cfg_resp(prefix, atm_hdr, resp, respjen); return (ret); err_exit: return (ret); } lm_srvc_svc msg(msg) tAALUSRMSG *msg; { tLMIHDR *lmi_hdr; tSETUP *setup; 4S Im.c -87- default: break; } } lm_srvc_svc reljnd(msg) struct svcif *msg; { } lm srvc svc setu ind ms { ret = RT_SUCCESS; respjen = SVCIF_PDU_OFFSET + sizeof(*tx_setup) + sizeof (struct lmi_parm); resp = (struct svcif *) ReqMsgMemZero(resp len); if (resp = = NULL) { ret = !RT_SUCCESS; goto err exit; Im.c -88- } rx setup = (tSETUP *) & msg->lmi_hdr; tofsetup = (tSETUP *) & resp->lml_hdr; *tx_setup = *rx_setup; lml_hdr = (tLMIHDR *) & tx setup->lml_hdr; lmi_hdr->lh_pdu_type = SD~U_SETUP_RESP; port_addr = rx_setup->lmi_calier; mlid = port_addr.aa_lannum; port_addr.aa_lannum = 0; port = FIND_PORT(tcb->port q, &port addr); if (port = = NULL) { ret = !RT_SUCCESS; goto err exit; } mac = port- > mac; if (mac = = NULL) { ret = !RT_SUCCESS; goto err exit; } mv -= FIND_MLID(mac->mv_q, mlid); if (mv = = NULL) { ret = IRT_SUCCESS; goto err exit; } vlan = mv->vlan; if (vlan = = NULL) { ret = !RT_SUCCESS; goto err exit; } LMJNIT_VC_ADDR(&vc_addr, vlan->vlanjd, &rx_setup->lmi_callee); vc = FIND_VC(vlan->vc q, &vc_addr); if (vc = = NULL) { vc = add vc(&vc addr); } if (vc -= = NULL) { ret = !RT_SUCCESS; goto err exit; } vc->ref cnt+ + ; vpci = ftUINTβ *) tx setup + sizeof (*tx setup); LMI_ADD_ELEMENTl(vpci, LMIJDVPCI, vc->bid); lmi_hdr->lh_cref_type | = LMI_CREFDIRECTION_MASK; ret = im_send_svc_msg(resp, " respjen); return (ret); err exit: Tf (resp ! = NULL) { Im.c -89- lmi_hdr->lh_cref_type | = LMI CREFDIRECTION_MASK; lm_send svc_rel_req(lmi_hdr, TNVAUD_STATE); free(resp7; } return (ret); Im.h -90- /* lm.h * * COPYRIGHT 1992 ADAPTIVE CORPORATION * ALL RIGHTS RESERVED * 7 #ifndef LM H #define UvTjH #define LM VB QUIET (0) #define LM_VB ERRS (1) #define LM_VB~TERSE (2) #define LM_VB_VERBOSE (3) #define LM_VB MSGS (4) #define LM_VB_ALL (999) #define CHK_VB(level) (tcb->verbose > = level) #define LM_MAX_VLAN_NAME (17) #define LM INDENT (2) #define LM_DFLT MTU_SIZE (9100) #define LM_DFLT_NUM_MCASTS (4) #define LM_MAX MUD (256) #define LM_MAX_BID (1024) #define LM_MAX MID (1024) #define MAX_SLOTS (16) #define MAX_PORTS PER SLOT (8) #define MAX_PORTS (MAX_SLOTS * MAX PORTS_PER_SLOT) #define LM_AAL_EX (EXJNDICATION) #define LM_AAL_EX MSK (M_EXJNDICATION) #define LM_START CI (0x3000) #define LM_END_VCI (0x3fff) #define LM INSTANCE (0) #define LM_AAL_SID (MAKE_SSID(TID_LM, LMJNSTANCE, LM_AAL_EX)) #define LM EX MSK (M EX INDICATION) #define SIZE MID BITS lLM~MAX_MID / (8 * SIZE_BITS)) #define SIZE_MUD_BITS (LM_MAX_MUD / (8 * SIZE BITS)) #define SIZE BID_BITS (LM MAX_BlD / (8 * SIZE_BITS)) #define LM_ClR_MAC_ADDR7maddr)\ ((maddr)->aa_long[0] = (maddr)->aa_long[1] = 0, (maddr)->aa_type = AAT MAC) #define LM_CLR_PORT ADDR(paddr)\ ((paddr)->aajong[0f= (paddr)->aa_long[1] = 0, (paddr)->aa_type = AAT_PORT,\ (paddr)->aa_country = USA) #define LM CLR VC ADDR(vcaddr) \ ((vcaddr >vlanjd = 0, LM CLR_MAC_ADDR(&((vcaddr)->mac_addr))) #define LM INIT PORT ADDR paddr, node, shelf, slot, port) \ (LM_CLR_PORT_ADDR(paddr),\ (paddr)->aa_node = node, (paddr)->aa_shelf = shelf, (paddr)->aa_slot = slot,\ Im.h -91- (paddr)->aa port = port, (paddr)->aa_lannum = 0) #define LM_INIT_MAC_ADDR(maddr, mac_addr)\ ((maddr)->aa_long[θ] = (mac_addr)->aa_long[0], \ (maddr)->aa_long[1] = (mac_addr)->aa_long[lj, \ (maddr)->aa_type = AAT_MAC) #define LMJNIT VC ADDR(vcaddr, vid, maddr)\ (LM_CLR VC ADD " R(vcaddr), (vcaddr)->vlan id = (vid).\ LMJNIT MAC_ADDR(&((vcaddr)->mac_addr), maddr)) #define LM NUM ELEM(ary) (sizeof(ary) / sizeof ((ary)[0])) #define BUILD_ITCH(Hdr, len, generic, instance, exch, mtype, mytld) \ {Hdr.Length=len; \ Hdr.Dest.Label.Pid =0; \ Hdr.Dest.Label.Sid = \ MAKE SSID(generic,instance,exch);\ Hdr.Dest.Net = LOCAL_NET; \ Hdr.Dest.Node = LOCAL_NODE; \ GetPid(&Hdr.Orig.Label.Pid); \ Hdr.Orig.Label.Sid = \ MAKE_SSID(mytid.Generic, 0, EXJNDICATION);\ Hdr.MsgType - mtype;} typedef tUINT32 Im mlidj; typedef tUINT32 IπTbidJ; typedef tUINTl 6 Im vlan id t; typedef struct lm refix s #define CLR_PREFIX(pfx) (*((tUINT32*)(pfx)) = 0) #define BUILD UCAST PREFIX fx, shelf, slot, port)\ (CLR_PREFIX(pfx), (p )->tag_a = shelf, (pfx)->tag_b - slot, \ (pfx)->tag_c = port, (pfx)->rp = 1) /* Fix RPA 10 Mar 92 */ /Aό Im.h -92- #define BUILD_MCAST PREFIX(pfx, bid)\ (CLR_PREFIX(pfx), (pfx)->br = 1, (pfx)->tag a = (((bid) & OxfcOO) > > 10),\ (pfx)->tag b = (((bid) & 0x03c0) > > 6), (pfr)->tag_c = ((bid) & 0x003f)) ty edef struct lm atm hdr s { #define SIZE_LM_ATM_HDR (sLzeof(lm_atm_hdr_t)) #define CLR ATM_HDR(hdr) (*((tUINT32*)(hdr)) = 0) #define BUIlϊ>_ATMJ-IDR(hdr, the_vcl)\ (CLR_ATM_HDR(hdr), (hdr)->vci = the_vci) typedef struct lm_alan_cfg_enq_s { struct Imi hdr Imi hdr; tALANCF§_ENQ enq; } lm_alan cfg_enq t; #define SIZE_LM_A AN_CFG_ENQ (sizeof(lm_alan_cfg_enq_t)) typedef struct lm_alan_cfg_resp_s { struct Imi hdr Imi hdr; tALANCFG_ENQ enq; tALANCFG_RESP resp; } lm_alan_cfg_resp_t; #define SIZE_LM_ALAN_CFG_RESP (sizeof(lm_alan_cfg_respJ)) typedef struct lm_es_cfg_resp_s { struct Imi hdr~lmi hdr; tCFGELEM enq; tCFGELEM resp; tPORT_CFGELEM paddr[1]; } Im es cfg resp t; #define SIZE_LM_ES_CFG_RESP (sizeof(lm_es_cfg_respJ)) typedef struct lm_es_cfg_enq_s { struct lmi_hdr lmi_hdr; struct config_elem enq; } Im es cfg enqJ; #define SIZE_LM_ES_CFG_ENQ (sιzeof(lm_es_cfg_enq_t)) typedef struct atm_addr lm_mac_addr_t; #define SIZE_LM_MAC_ADDR (sizeofOm_mac_addr_t)) typedef struct atm_addr lm_port_addrj; #define SIZE_LM_PORT_ADDR (sizeof(lm_port_addr_t)) /3/ Im.h -93- typedef struct lm_vc_addr_s { lm_vianjd_t vlanjd;- struct atm_addr mac addr; } lm_vc_addrj; #define SIZE_LM_VC_ADDR (sizeof(lm_vc_addr_t)) #define aa_country aa_u.aaw.aasw_nibble2 #define aa_shelf aa_u.aaw.aasw_nibble3 #define aa_slot aa_u.aaw.aasw_nibble4 #define aa_port aa_u.aaw.aasw_nibble5 typedef struct lm_tcb_s { tTID mytid; tPID mypid; struct TimerBlock *tmr blk; tUINT32 timerid; tUINT32 timerarg; tATMADDR nac_atm_addr; tUINT32 nacjd; tAAL KEY my_aal_key; tUINT32 my_node; tUINT32 my_shelf; tUINT32 my slot; lm_port_addr portjmplt; tUINT32 cur bid; bitsj bid_bits[SIZE_BID_BITS]; bitsj mlid_bits[SIZE_MUD_BITS] ; tUINT32 dflt_mtu_size; tUINT32 dflt_num_mcasts; tUINT32 verbose; " tUINT32 do_cfg_wrts; char vc_addr_buf[200]; char mac_addr_buf[sizeof(lm_mac_addrj) 3 + 1]; char port_addr buf [40]; char vlan_id_bϋf[10]; queuej port_queue; queuej vlan_queue; queuej mac_queue; queuej my_queue; queuej pv_queue; queuej vc_queue; queuej *port_q; queuej *vian_q; queuej *mac_q; queuej *mv_q; queuej *pv_q; queue t *vc_q; } Im tcb t; #define SIZE_LM_TCB (sizeof(lm cb_t)) Im.h -94- typedef struct lm_mac s { qlink mac Jink; queuej mv_queue; queuej *mv_q; struct lm_port_s *port; Imjnac addrj mac addr; bitsj ~ mlid_b!ts[SIZE_MUD_BITS]; } ~ Im mac t; #define SIZE_CM_MAC (sizeof(lm_mac_t)) t edef struct Im vlan s e ne _ _ szeo m_port_t typedef struct lm_vc_s { qlinkj vcjink; qlink t vlanjink; lm_vϊan_t *vlan; lm_vc_addrj vc_addr; lm_bidj bid; tUINT32 ref_cnt; } lm_vcj; #define SIZE_LM_VC (sizeof(lm_vcJ)) Im.h -95- ty edef struct Im ort vlan s { lm_port_addrj port_addr; } Im port vlanj; #define SIZE_LM_PθRTNLAN (sizeof(lm_port_vlanJ)) ty edef struct Im mac vlan s } # efine IZE_LM_MAC_VLAN (sizeof(lm_mac_vlanJ)) typedef struct lm_cfg_glbl_s { tUINT32 dflt mtu_size; tUINT32 dflt_num_mcasts; } lm_cfg glblj; #define SIZE_LMJ_5FG_GLBL (sizeof(lm_cfg_glblJ)) typedef struct lm_cfg_vlan_s { typedef struct lm_cfg port_s { IUINT32 eljδnto; } lm_cfg~port t; #define SIZE_LM_CFG_PORT (sizeof(lm_cfg_port_t)) typedef struct lm_cfg_mac_s { tUINT32 eljonto; } lm_cfg~mac ; #define SIZE_LM_CFG_MAC (sLzeof(lm_cfg_mac_t)) typedef struct lm_cfg_pv_s { im.h -96- tUINT32 mlid; } Im cfg pv t; #define SIZE_LM_CFG~PV (slzeof(lm_cfg_pv_t)) typedef struct Im cfg mv s { tUINT32 " mlldT; " } Im cfg mv t; #define SIZE_LM_CFG~MV (sizeof(lm_cfg_mv_t)) typedef struct lm_cfg_vc_s { tUINT32 eljonto; } Im cfg vcj; #define SIZE LM CFG VC (sizeof (lm_cfg_vc_t)) typedef struct lm_glbl_cfg key s { tUINT32 tag; } Im glbl cfg key t; #define SIZE_LM_eLBL_CFδ_KEY (sizeof(lm_glbl_cfg_key_t)) typedef struct lm_vlan_cfg_key_s { tUINT32 tag; lm_vlanjdj vlanjd; } lm_vlan_cfg_key t; #define SIZE_LM_VLAN_CFG ~ _KEY (sizeof(lm_vlan_cfg_keyJ)) typedef struct lm_port_cfg_key_s { tUINT32 tag; lm_port_addr_t port_addr; } Im port cfg key t; #define SIZE_LM_PϋRT_CFG_KEY (sizeof(lm_port_cfg_keyJ)) typedef struct lm_mac_cfg_key_s { tUINT32 tag; lm_mac_addr_t mac_addr; } lm mac cfg keyj; #define SIZE_LM_MAC_CFG_KEY (sizeof(lm_mac_cfg_key_t)) typedef struct lm_vc_cfg_key_s { tUINT32 tag; lm_vc_addr_t vc addr; } Im vc cfg key t; #define SIZE_C _VC_CFG_KEY (sizeof(lm_vc_cfg_key_t)) typedef struct lm_py_cfg_key_s { tUINT32 tag; lm_port_addr_t port_addr; lm_vlanjd vlanjd; } Im pv cfg key J; #define SIZE_LM_PV_CFG_KEY (sizeof(lm_pv_cfg_key_t)) /3S Im.h -97- typedef struct lm_mv_cfg_key_s { tUINT32 tag; lm_mac_addr_t mac addr; lm_vlanjd_t " vlanJd } ~ lm_mv_cfg keyj; #define SIZE_LM_MV_CFG_KEY (sιzeof(lm_mv_cfg_key_t)) typedef union cfg_key_u { tUINT32 tag; lm_glbl_cfg_key_t glbl_key; lm_vian_cfg keyj vlan_key; lm_port_cfg_key_t poιt~key; lm_mac_cfg_key_t mac_key; lm_vc_cfg_key_t vc_key; lm_pv_cfg_key_t pv~key; lm_mv_cfg_key_t mv_key; } Im cfg key t; #define SIZE_LM_CFG_KEY (sizeof(lm_cfg_keyJ)) #define NULL_CFG_KEY (0) #define GLBL CFG_KEY (1) #define VLAN CFG_KEY (2) #define PORT CFG_KEY (3) #define MAC CFG_KEY (4) #define VC CFG KEY (5) #define PV~CFG_KEY (6) #define MV_CFG_KEY (7) #ifdef UNIX extern tINTβ *GlobalP; #undef printf #endif #define malloc(size) GetMem(size) #define free(ptr) FreeMem(ptr) #define FREE Q(q, proc) ((int)traverse_q(q, proc, NULL)) #define FREE MV Q(q) FREE_Q(q, free_mv) #define FREE_PV Q(q) FREE_Q(q, free_pv) #define FREE MAC Q(q) FREE_Q(q, free_mac) #define FREE VLAN Q(q) FREE Q(q, free_vlan) #define FREE PORT~Q(q) FREE~Q(q, free port) #define FREE VC Q " Tq) FREE_Q(q, free_vc) #define FREE PORT VLAN Q(q) FREE Q(q, free_port_vlan) #define FREE_MAC_VLAN " Cj(q) FREE " Q(q, free mac_vlan) #define FREE MAC MV Q " fa) FREE " Q(q, free mac_mv) #define FREE " VLAN MV Q(q) FREE Q(q, free " vlan_mv) #define FREE " PORT_PV_Q(q) FREE~Q(q, free~port_pv) #define FREE_VLAN_PV_Q(q) FREE_Q(q, free_vlan_pv) /• & Im. -98- #define ATCH_MAC_MV_Q(q, mac) ((int)traverse_q(q, atch_mac_mv, mac)) #define ATCH_VLAN_MV_Q(q, vlan) ((int)traverse_q(q, atch_ylan_mv, vlan)) #define ATCH_PORT_PV_Q(q, port) ((intjtraverse q(q, atch_port_pv, port)) #define ATCH_VLAN_PV_Q(q, vlan) ((int)traverse~q(q, atch_vlan_pv, vlan)) #define ATCH_MV MAC_Q(q, mv) ((int)traverse_q(q, atch_mv mac, v)) #define ATCH_MV~VLAN_Q(q, mv) ((int)traverse_q(q, atch_mv~vlan, mv)) #define ATCH PV_PORT_Q(q, pv) ((int)traverse_q(q, atch_pv_port, pv)) #define ATCH~PV_VLAN_Q(q, pv) ((int)traverse_q(q, atch_pv_vlan, pv)) #define FIND_MAC(q, mac) ((lm_macj*)traverse_q(q, cmp_mac, mac)) #define FIND_PORT(q, port) ((lm_portJ*)traverse_q(q, cmp_port, port)) #define FIND_VLAN(q, vlan) ((lm_vlan t*)traverse q(q, cmp_vlan, vlan)) #define FIND_VC(q, vc) ((lm_vc_t*Jtraverse_q(cj, cmp vc, vc)) #define FIND_MV(q, mv) ((lm_mac vianj*)traverse_qfa, cmp_mv, mv)) #define FIND_PV(q, pv) ((lm_port_vianj*)traverse_q(q, cmp_pv, pv)) #define FIND_MUD(q, mlid) ((lm_mac_vlan_t*)traverse_q(q, cmp_mlid, mlid)) #define FINDNEXT_MAC(q, mac) ((lm_mac t*)traverse_q(q, cmpnext_mac, mac)) #define FINDNEXT_PORT(q, port) ((lm_port_t*)traverse_q(q, cmpnext_port, port)) #define FINDNEXT~VLAN(q, vlan) ((lm_vlanj*)traverse_q(q, cmpnext vlan, vlan)) #define FINDNEXT_VC(q, vc) ((lm_vc_t*)traverse_q(q, cmpnext_vc, vc)) #define FINDNEXT_MV(q, mv) ((lm_mac_vlanj*)traverse_q(q, cmpnext_mv, mv)) #define FINDNEXT PV(q, pv) ((lm port_vian_t*)traverse_q(q, cmpnext_pv, pv)) #define FINDNEXT_MUD(q, mlid) " f(lm_mac_vlan_t*)traverse_q(q 1 cmpnext_mlid, mlid)) #define PUTQ_SORTED MAC(ϋnk, q) (putq_sorted(link, q, qpsc_mac)) #define PUTQ_SORTED~PORT(link, q) (p tq_sorted(link, q, qpsc_port)) #define PUTQ_SORTED~VU.N(link, q) (putq_sorted(link, q, qpsc_vlan)) #define PUTQ_SORTED_VC(link, q) (putq_sorted(link, q, qpsc_vc)) #define PUTQ_SORTED_PV(link, q) (putq_sorted(link, q, qpsc pv)) #define PUTQ_SORTED_MV(link, q) (putq_sorted(link, q, qpsc nv)) #define PRINT_Q(q, proc, indent) ((int)traverse_q(q, proc, indent)) #define PRINT_VLAN_Q(q, indent) PRINT_Q(q, print_vlan, indent) #define PRINT_MAC_Q(q, indent) PRINT_Q(q, print_mac, indent) #define PRINT_PORT Q(q, indent) PRINT 3(q, print_port, indent) #define PRINT_PV_Q{q, indent) PRINT Q(q, print_pv, indent) #define PRINT_MV_Q(q, indent) PRINT_Q(q, print_mv, indent) #define PRINT_VC_Q(q, indent) PRINT_Q(q, print_vc, indent) #define pGlobalData ((lm_tcb_t*)GlobalP) #define DEFINE TCB lm tcb t *tcb #define SETUP_TCB DEFINE " _TCB = pGlobalData extern struct AgentMsg *lm_cp_mgmt_msgO; extern lm_es_cfg_resp_t *lm build_es_cfg_respO; extern Im nacJ *add_mac(J; extern lm_portJ *add_portO; Im.h -99- extern lm_vlanj *add_vlanO; extern Im_vcj~*add_vc0; extern lm_vc_t *get_free_vcO; extern lm_vc_t *add_free vcO; extern lm_mac_vlanj *a d_mvO; extern lm_port_vlan_t *add_pvO; extern ImjπacJ *cmp_macO; extern lm_portJ *cmp~portO; extern lm_vlanj *cmp_vlanO; extern lm_vc_t *cmp_vcO; extern lm_port_vlanJ *cmp_pvO; extern lm_mac_vlari_t *cmp_mv(); extern lm_mac~vlanj *cmp_mlidO; extern im_mac~t *cmpnext_macO; extern lm_portj *cmpnext_port ; extern lm_vlanj *cmpnext_vlanO; extern lm_vcj *cmpnext_vcO; extern lm_port_vlanj *cmpnext_pvO; extern lm_mac~vlanj *cmpnext_mv(); extern lm_mac_vlanj *cmpnexf mlidO; extern int qpsc_macO; extern int qpsc_port(); extern int qpsc_vlanO; extern int qpsc_vcO; extern int qpsc_pvO; extern int qpsc_mvO; extern int atch_mac_mvO; extern int atch_vlan_mvO; extern int atch_port_pvO; extern int atch_vlan_pvO; extern int atch_pv_vlanO; extern int atch_pv_portO; extern int atch_mv_mac(); extern int atch_mγ_ylanO; extern int free_macO; extern int free_vlanO; extern int free_portO; extern int free~vcO; extern int free_port_vlanO; extern int free_mac_vlanO; extern int free_mac_mvO; extern int free_vlan_mvO; extern int free_port_pvO; extern int free_vlan_pvO; extern int freejnvO; extern int free pvO; extern int print nacO; extern int print_vlanO; extern int print_portO; extern int print vcQ; /3S Im.h -100- extern int print_mvO; extern int print_pvO; extern char *sprint_mac_addrO; extern char *sprint_port_addrO; extern char *sprint_vlan_idO; extern char *sprint_vc_addr(); extern struct TimerBlock *TimerinitO; #endif /* ifndef LM_H */ /39 Im cfg.c ~\01- /* lm_cfg.c * * COPYRIGHT 1992 ADAPTIVE CORPORATION * ALL RIGHTS RESERVED 7 #ifdef CERNEL #include u ipc_def.h" #include "net_def.h" #include <global_def.h> #include <driver.h> #undef Imjnit #else /* ifndef CERNEL */ #include <stdint.h> #include < global def.h> #include <ITCJf.h> #include <driver.h> #include <RT_if.h> #include <timer.h> #include <RT_def.h> #include <enet_if.h> #include <net_3ef.h> #define ERRLOG printdbg #define printf printdbg #endif /* ifdef CERNEL */ #include "unipdu.h" #include "nnipdus.h" #include "altask_gl.h" #include "sigtask_gl.h" #include "svctask_gl.h" #include "svc_if.h" #include "snmp incl.h" #include "AAL ff!h" #include "wdb_if.h" #include "q.h" #include "bits.h" #include "lm.h" #define WDB VERS (1) #define WDB PRI (1) / ■ VO lm cfg.c -102- lm_chg_glbl_cfg(dflt_mtu_size, dflt_num_mcasts, nac_addr, bid_bits, mlid_bits) tUINT32 *dflt_mtu size; tUINT32 *dflt_nunτ_mcasts; tATMADDR *nac_addr; bitsj *bid_bits; bits t *mlid bits; SETUP TCB; if (dflt_mtu size I = NULL) { tcb- > dflt mtu size = *dflt mtu size; } if (dflt_num_mcasts 1 = NULL) { tcb- > dflt num mcasts = *dflt num ncasts; } if (nac_addr != NULL) { tcb- > nac atm addr = *nac_addr; } if (bid bits ! = NULL) { bcopy(bid bits, tcb- > bid bits, sizeof(tcb->bid_bits)); } if (mlid_bits ! = NULL) { bcopy(mlid bits, tcb->mlid bits, sizeof(tcb->mlid_bits)); } lm_wrt_glbl_cfgO; } lm_chg_vlan_cfg(vlan, dflt_mlid, num_mcasts, mtu_size, vlan_name) Im vlan t *vlan; tUINT32 *dflt_mlid; tUINT32 *num_mcasts; tUINT32 *mtu_size; tUINT32 *vlan name; { qlinkj *|ink; Im macj *mac; lm_mac_vian t *mv; SETUP_TCB; / / lm cfg.c -103- vlan->dflt mlid = *dflt_mlid; } } if (num_mcasts I = NULL) { chg num vcs(vlan, *num mcasts); } if (vlan_name l = NULL) { int namejen; namejen = strien(vlan_name); namejen = (name len < LM_MAX VLANJJAME) ? namejen LM MAX_VLAN_NAME - 1; bcopy vlan_name, vlan->vlan_name, namejen); vlan- > vlan namefname len] = 0; } if (mtu_size l = NULL) { vlan- > mtu size = *mtu size; } lm_wrt_vlan_cfg(vlan); for (link = HEAD_Q(vlan->mv_q); link != NULL; link = link- > next) { mv = (lm_mac_vtanj *) link- > data; mac = mv->mac; if (mac ! = NULL) { lm_send es cfg ind (mac); } } } !m_chg_port_cfg(port, mac addr, mlid_bits) if (mac_addr ! = NULL) { if (port->mac l = NULL) { mac = port- > mac; free mac(mac); } mac = add_mac(mac_addr); atch_mac_port(mac, port); Im dup port dflts(port, mac); } " " if (mlid_bits != NULL) { bcopy(mlid bits, port->mlid bits, sizeof(port->mlid bits)); } lm_wrt_port_cfg(port); lm cfg.c -104- } lm_chg_mac_cfg(mac, mlid bits) if (mlid_bits ! = NULL) { bcopy(mlid bits, mac->mlid bits, sizeof (mlid_bits)); } lm_wrt_mac_cfg(mac) ; } lm_chg_vc_cfg(vc, bid, ref_cnt) if (bid ! = NULL) { if (ibits jst_bit(*bid, tcb->bid_bits, SIZE_BID BITS)) { bits Jree_bit(vc-> bid, tcb->bid_bits, SIZE~BID BITS); bits_alloc_bit(*bid, tcb->bid_bits, SIZE_BID_BlTS); vc->bid = *bid; } } if (ref_cnt ! = NULL) { vc->ref cnt = *ref cnt; } • lm_wrt_vc_cfg(vc); } lm_chg_pv_cfg(pv, mlid) lm_port_vlanJ *pv; tUINT32 *mlid; Im portJ *port; SETUP TCB; port = pv->port; if (mlid ! = NULL && port != NULL) { if (Ibits Jst_bit(*mlid, port->mlid_bits, SIZE MUD_BITS)) { bits_free_bit(pv-> mlid, port-> mlid bits, SIZE MUD BITS); bits_alloc_bit(*mlid, port->mlid_biFs, SIZE_MDD_BlTS); pv->mlid = *mlid; } } lm cfg.c -105- lm wit pv cfg(pv); } " " " lm_chg_my_cfg(mv, mlid) Im mac_vlanj *mv; tUiftT32 *mlid; { Im mac t *mac; SETUP_TCB; mac = mv->mac; if (mlid != NULL && mac 1= NULL) { if (Ibits _tst_bit(*mlid, mac->mlid_bits, SIZE_MUD_BITS)) { bits_free_bit(mv->mlid, mac->mlid_bits, SIZE_MUD_BITS); bits_alloc_bit(*mlid, mac->mlid_bits, SIZE_MUD_BITS); mv->mlid = *mlid; } } Im wrt_mv_cfg(mv); if (mac ! = NULL) { Im send es cfg ind(mac); } - - - } Im rm glbl cfgO { lm_glbl_cfg_key key; Im cfg glbl t cfg; SETUP TCB; key.tag = GLBL_CFG_KEY; wdb_send_remove_noack(&key, sizeof (key)) ; } im_rm_vlan_cfg(vian) key.tag = VLAN_CFG_KEY; key.vlan_id = vlan->vlanjd; wdb_send_remove_noack(&key, sizeof (key)) ; } lm_rm_port_cfg(port) lm_port_t *port; lm_cfg.c -106- { lm_port_cfg_key t key; lm_cfg_portj cfg; SETUP_TCB; key.tag = PORT_CFG KEY; key.port_addr = port->port_addr; wdb_send remove_noack(&key, sizeof (key)); } lm_rm_mac_cfg(mac) Im macj *mac; { " lm_mac_cfg_key_t key; IπTcfg mac t cfg; SETUP ΌBT key.tag = MAC_CFG_KEY; key.mac_addr = mac : >mac_addr; wdb_send remove noack(&key, sizeof (key)); } lm_rm_vc_cfg(vc) key.tag = VC_CFG_KEY; key.vc_addr = vc->vc_addr; wdb send remove noack(&key, sizeof (key)); } " ~ lm_rm_pv_cfg(pv) lm port " vlan t *pv; { " ~ lm_pv_cfg_key_t key; Im cfg pv t cfg; SETUP~TCB; key.tag = PV_CFG_KEY; key.port_addr = pv->port_addr; key. vlanjd = pv->vlan_idT wdb send remove noack(&key, sizeof (key)); } / S lm cfg.c ~\07- lm_rm_mv_cfg(mv) 7m mac vlan t *mv; { lm_mv_cfg_key_t key; Im cfg mv t " cfg; SETUP_TCB; key.tag = MV_CFG_KEY; key.mac_addr = mv->mac_addr; key.vlanjd = mv->vlanjdf wdb_send_remove_noack(&key, sizeof (key)) ; } Im wrt glbl cfgO { ~ lm_glbl_cfg_keyj key; lm_cfg glbl t cfg; SETUPJOB; if (tcb->do_cfg wits) { cfg.dflt_mtu_size = tcb->dflt_mtu_size; cfg.dflt_num_mcasts = tcb->dflt_num_mcasts; wdb_send_store noack(&key, sizeof(key), &cfg, sizeof(cfg), WDB VERS, WDB PRI); } } lm_wrt_vlan_cfg(vlan) Im vlan t *vlan; { lm_vlan_cfg_key_t key; lm~cfg_vlan t cfg; SETUPJTCB; if (tcb- > do cfg_wrts) { key.tag = VLAN_CFG_KEY; key.vlanjd = vlan->vlan_id; cfg.dflt_mlid = vlan->dflt_mlid; cfg.num_mcasts = vlan->num_mcasts; cfg.mtu_size = vlan->mtu_size; bcopy(vlan->vlan_name, cfg.vlan_naπιe, sizeof (cfg. vlan_name)); wdb_send_store noack(&key, sizeof(key), &cfg, sizeof(cfg), WDB VERS, WDB PRI); lm_cfg.c -108- lm_wrt_port_cfg(port) lm_port_t *port; { lm_port_cfg_keyj key; lm~cfg_port t cfg; SETUPJTCB " cfg.eljonto = 0; wdb_send store_noack(&key, sizeof(key), &cfg, sizeof(cfg), VVDB_VERS, WDB_PRI); } lm_wrt_mac_cfg(mac) if (tcb->do_cfg_wrts) { key.tag = MAC_CFG_KEY; key.mac_addr = mac->mac_addr; cfg.eljonto = 0; wdb_send_store_noack(&key, sizeof(key), &cfg, sizeof(cfg), WDB VERS, WDB PRI); } lm_wrt_vc_cfg(vc) cfg.eljonto = 0; wdb send store_noack(&key, sizeof(key), &cfg, sizeof(cfg), WDB VERS, WDB PRI); } Im cfg.c -109- } lm_wrt_pv_cfg(pv) lm_port_vlanj *pv; { lm_pv_cfg_key_t key; lm_cfg_pvj " cfg; SETUPJTCB; if (tcb->do cfg wrts) { key.tag = P _CFG_KEY; key.port_addr = pv->port_addr; key.vlanjd = pv->vlan_id; cfg.mlid = pv->mlid; wdb_send_store_noack(&key, sizeof(key), &cfg, sizeof(cfg), WDB VERS, WDB PRI); } } lm_wrt_mv_cfg(mv) Im mac vlan t *mv; { lm_mv_cfg_keyj key; lm_cfg_mv t cfg; SETUPJTCB; if (tcb->do_cfg_wrts) { key.tag = MV_CFG_KEY; key.mac_addr = .mv->mac_addr; key.vlanjd = mv-> vlanjd f cfg.mlid = mv->mlid; wdb_send store noack(&key, sizeof(key), &cfg, sizeof(cfg), WDB \7ERS, WDB PRI); } } lm_crt_cfg(key, kien, cfg, clen) lm_cfg_key *key; int Men; tUINTβ *cfg; int clen; { switch (key- > tag) { case NULL_CFG_KEY: brθs * case GLBL_CFG KEY: lm_crt_glbl_cfg(key, cfg); break; /¥? lm cfg.c -1 0- case VLAN_CFG_KEY: lm_crt_vTan_cfg(key, cfg); brθsk* case PORT_CFG_KEY: lm_crt_port_cfg(key, cfg); brβsk * case MAC_CFG_KEY: lm_crt_mac_cfg(key, cfg); break; case VC_CFG_KEY: lm_crt_vc_cfg(key, cfg); break; case PV_CFG_KEY: lm_crt_pv_cfg(key, cfg); brθflk * case MV_CFG_KEY: lm_crt_mv_cfg(key. cfg); break; default: break; } } lm_crt_glbl_cfg(key, cfg) lm_glbl_cfg keyj *key; lm_cfg_glbl~t *cfg; { SETUPJTCB; lm_chg_glbl_cfg(&cfg->dflt mtu size, &cfg->dflt num_mcasts, NULL, NULL, NULL); } lm_crt_vlan_cfg(key, cfg) lm_vlan_cfg_keyj *key; lm_cfg_vlanj *cfg; { lm_vlan_t *vlan; qlinkj *link; lm_m~ac_vlan t *mv; Im mac t ~ *mac; SETUP_TCB; vlan = FIND_VLAN(tcb->vlan q, key->vlan Id); if (vlan = = NULL) { vlan = add_vlan(key->vlanjd, cfg->mtu_size, cfg->num_mcasts, cfg- > vlan name); } lm_chg_vlan_cfg(vlan, &cfg->dflt_mlid, &cfg->num_mcasts, &cfg->7ntu_size, &cfg->vlan_name); lm_cfg.c -111- } lm_c!t_port_cfg(key, cfg) Im 7 ort_cfg_key_t *key; lm~cfg_portj *cfg; { Im port t *port; SETUP_TCB; port = FIND_PORT(tcb->port_q, &key->port_addr); ii (port = = NULL) { port = add_port(&key->port_addr); } } lm_crt_mac_cfg(key, cfg) lm_mac_cfg_keyj *key; lm_cfg_macj *cfg; { lm mac t *mac; SETUP_TCB; mac = FIND_MAC(tcb->mac_q, &key->mac_addr); if (mac = = NULL) { mac = add mac(&key->mac addr); } } lm_crt_vc_cfg(key, cfg) lm_vc_cfg_keyj *key; Im cfg vc t *cfg; { SETUP TCB; } lm_crt_pv_cfg(key, cfg) lm_pv_cfg_key_t *key; lm_cfg_pv_t *cfg; { lm_port_vlanJ tmp; lm_port_t *port; lm_vlan_t *vlan; lm_port_vlanJ *pv; SETUP_TCB; tmp. vlanjd = key- > vlanjd; tmp.port_addr = key->port_addr; pv = FIND_PV(tcb->pv_q, &tmp); if (pv = = NULL) { /SO lm cfg.c " •■ .12- port = FIND_PORT(tcb->port_q, &key->port_addr); if (port = = NULL) { port = add port(&key->port addr); } if (vlan = = NULL) { vlan - add_vlan(key->vlanjd, tcb->dflt_mtu_slze, tcb- > dflt num mcasts); } " " pv = add pv(&key->port addr, key->vlanjd, cfg->mlid); } lm_chg_pv_cfg(pv, &cfg->mlid); } lm_crt_mv_cfg(key, cfg) lm_mv_cfg_keyj *key; lm_cfg_mvj *cfg; { lm_mac_vlanj *mv; lm_mac_vlan_t tmp; lm_mac_t *mac; Im vlan t *vlan; SETUP_TCB; tmp. vlanjd = key- > vlanjd; tmp.mac_addr = key->mac_addr; mv = FIND_MV(tcb->mv q, &tmp); if (mv = = NULL) { mac = FIND_MAC(tcb->mac_q, &key->mac_addr); if (mac = = NULL) { mac = add mac(&key->mac addr); } if (vlan -= =- NULL) { vlan = add_vlan(key->vlanjd, tcb->dflt_mtu_size, tcb- > dflt num mcasts); } ~ " mv = add mv(&key->mac addr, key->vlan id, cfg->mlid); } lm_chg_mv_cfg(mv, &cfg->miid); /57 lm mgmt.c -113- /* lm mgmt.c * COPYRIGHT 1992 ADAPTIVE CORPORATION * ALL RIGHTS RESERVED V #ifdef CERNEL #include "ipc__def.h" #include "net_def.h" #include <global_def.h> #include <driver.h> #undef Imjnit #else /* ifndef CERNEL */ #include <stdint.h> #include <global_def.h> #include <ITC_if.h> #include <driver.h> #include <RT_if.h> #include <timer.h> #include <RT_def.h> #include <enet_if.h> #include <net_def.h> #define ERRLOG printdbg #define printf printdbg #endif /* ifdef CERNEL */ #include "unipdu.h" #include "nnipdus.h" #include "altask_gl.h" #include "sigtask_gl.h" #include "svctask_gl.h" #include "svcjf.h" #include "snmp incl.h" #include "AAL Eh" #include "q.h" " #include "bits.h" #include "lm.h" extern lm_port_vlanJ *lm_mgmt_find_pvO; extern lm_mac_vlanj *lm_mgmt ind~mv(); extern lm_vlanj *lm_mgmt_find_vlan(y; extern lm_portJ *lm_mgmt ind_port0; / L lm mgmt.c -114- extern lm_mac_t *lm_mgmt_find_macO; extern im_vcj " *lm_mgmt_fiήd_vcO; extern lm_port_vlanJ *lm_mgmt_findnext_pvO; extern lm_mac_vlari_t *lm~mgm tJindnexfmvO; extern Iπf lan *lm_mgmt_findnext_vlanfy; extern lm_portJ *lm_mgmtJindnext_portO; extern lm_mac~t *lm_mgmt findnext_macO; extern lm_vc_t *lm_mgmt_findnext_vcO; lm_srvc_mgmt_get(msg) struct AgentMsg *msg; { int ret; ret = lm_do_mgmt_get(msg, FALSE); return (ret); } lm_srvc_mgmt_getnext(msg) struct AgentMsg *msg; int ret; ret = lm_do_mgmt_get(msg, TRUE); return (ret); } lm_do_mgmt_get(msg, getnext) struct AgentMsg *msg; int getnext; { int ret; struct MB *mb; struct MBH *mb_hdr; struct AgentMsg *tx_msg; ret = RT_SUCCESS; txjnsg = lm_cp_mgmt_msg(msg); mb = &tx_msg->Body; mb hdr = &mb->head; mb_hdr->datoff = 0; switch (mb_hdr->ovcode) { case LM_GLBL_OVN: ret = lm_mgmt_get_glbl(tx_msg, getnext); brβdk * case LM_ATTR_ENT_OVN: ret = lm_mgmt_get_attr_ent(b(_msg, getnext); break; #» lm mgmtc -115- ; e aut: ret = !RT_SUCCESS; mb_hdr->ercode = ERJ3ENERIC; goto err_exit; break; } ret = lm_send_mgmt_rsp(tx_msg); return (ret); err_exit: lm_send_mgmt_rsp(tx_msg) ; return (ret); } lm_mgmt_get_glbl(msg, getnext) struct AgentMsg *msg; int getnext; { int ret; struct MB *mb; struct MBH *mb_hdr; struct OS tmp_os; int num_vlans; int num ports; int numjnacs; int num_mvs; int num_pvs; int num vcs; SETUPJTCB; " if (CHK_VB(LM_VB_MSGS)) { printf("getting globals\r\n"); lm mgmtc — -116- } num_vlans = QUEUE_LEN(tcb->vlan q); num_ports = QUEUE LEN(tcb->port~q); num_macs = QUEUE " LEN (tcb- > mac q); num mvs = QUEUE 0EN(tcb->mv qj; nunrfpvs = QUEUE l£N(tcb->pv q); num_vcs = QUEUE~LEN(tcb->vc~q); ret = RT_SUCCESS; mb = &msg->Body; mb_hdr = &mb->head; tmp_os.length = sizeof(tcb->nac_atm_addr); bcopy(&tcb->nac_atm addr, tmp_os.6iiffer, tmp_os.length); MB_wp_OS(mb, LM_NAC_ADDR_PIX, &tmp_os); tmp_os.length = sizeof(tcb->bid_bits); bcopy(tcb->bid bits, tmp_os. buffer, tmp_os.length); MB_wp_OS(mb, LM_BID_PIX, &tmp_os); tmp_os.length = sizeof(tcb->mlid_blts); bcopy(tcb->mlid bits, tmp_os.buffer, tmp_os.length); MB_wp OS(mb, lM_MUD_BITS PIX, &tmp os); MB_wp_INT(mb, LM_DFLT_MTU " PIX, &tcb- " >dflt mtu_size); MB_wpJNT(mb, LM_DFLT_MCAST_PIX, &tcb->dflt_num_mcasts); MB_wp_INT(mb, LM_NUM_VU\NS_PIX, &num_vlans); MB_wp INT(mb, LM NUM MACS PIX, &num_macs); MB_wp INT(mb, LM_NUM PORTS_PIX, &num_ports); MB_wpJNT(mb, LM_NUM~MVS_PIX, &num mvs); MB_wpJNT(mb, LM_NUM_PVS_PIX, &num pvs); MB_wp_INT(mb, LM_NUM_VCS_PIX, &num_vcs); return (ret); " err_exit: return (ret); } lm_mgmt_get_attr_ent(msg, getnext) struct AgentMsg *msg; Int getnext; { int ret; struct MB *mb; struct MBH *mb_hdr; struct LM_ATTR_ENT_IDX *idx; . Im_vlan t *vlan; struct 0 " δ tmp os; struct LM_ATTR_ENT_IDX tmpjdx; int num_macs; int num ports; SETUPJTCB; " ret = RT SUCCESS; /s& * lm mgmtc -117- lm_cvt_v!anjdx(&vian->vian_id, &tmp_idx); *idx = tmp idx; lm_cvt_idx_os(tmp_idx.LM VLAN, LM_NUM ELEM(tmp_idx.LM_VLAN), &tmp_os); MB_wp_OS(mb, LM_VLAN_PIX, &tmp_os); " tmp_os.length = strlen(vlan->vlan_name); bcopy(vlan->vlan_name, tmp_os. buffer, tmp os.length); MB_wp_OS(mb, LM_VLAN_NAME_PIX, &tmp_os); MB_wp_INT(mb, LM_NUM_MCAST_PIX, &vlan->num_mcasts); MB_wp_INT(mb, LM_MTU_SIZE PIX, &vlan->mtu_size); MB_wp_INT(mb, LM MUD_PIX, " &vlan->dfit mlid); MB_wp INT(mb, LM ATTR NUM PORTS PlX, &num_ports); MB_wp_INT(mb, LM_ATTR_NUM_MACS_PIX, &num_macs); tmp_os.length = sizeof(vlan->mid_bits); bcopy(vlan->mid bits, tmp_os.buffer, tmp_os.length); MB_wp_OS(mb, LM_MID_BITS_PIX, &tmp_os); return (ret); err_exit: return (ret); } lm_mgmt_get_pv(msg, getnext) struct AgentMsg *msg; int getnext; { int ret; struct MB *mb; struct MBH *mb hdr; struct LM_PV IDX *7dx; struct LM_PV_IDX tmpjdx; lm_port vlanj *pv; struct OS tmp os; SETUPJTCB; ret = RT_SUCCESS; mb = &msg->Body; mb_hdr = &mb->head; idx -= (struct LM_PV_IDX *) mb_hdr->iid; pv = lm_mgmt find_pv(idx); if (pv = = NULL) { if (getnext) { pv = lm_mgmt findnext_pv(idx); if (pv = = NULL] { ret = !RT SUCCESS; mb_hdr->ercode = ER_NOSUCHNAME; goto err_exit; } } else { ret = !RT_SUCCESS; mb_hdr->ercode = ER_GENERIC; goto err exit; } } if (CHK_VB(LM_VB_MSGS)) { printf ("getting stats on pv = \r\n"); print_pv(pv, 0); } lm_cvt_pvjdx(pv, &tmp_idx); *idx = tmp idx; MB_wp INT(mb, LM_PV_SHELF_PIX, &tmpJdx.LM PV SHELF); MB_wpJNT(mb, LM_PV_CARD_PIX, &tmp_idx.LM PV CARD); MB_wp INT(mb. LM PV PORT PIX, &tmpJdx.LMjPV_PORη; MB wp INT(mb, LM PV MUD PIX, &pv->mlid); lm_cvtJdx_os(tmpJdx.LM_PV_VLAN, LM_NUM_ELEM(tmp_idx.LM_PV_VLAN), &tmp os); MB_wp_OS(mb, LM_PV_VLAN_PIX, &tmp_os); return (ret); err_exit: return (ret); } l≤1 lm mgmt.c -119- lm_mgmt_get_node_ent(msg, getnext) struct AgentMsg *msg; int getnext; int ret; struct MB *mb; struct MBH *mb hdr; SETUP_TCB; ret = RT_SUCCESS; mb = &msg->Body; mb hdr = &mb->head; print Jcb(tcb, 0); ret = IRT_SUCCESS; mb_hdr->ercode = ERJ3ENERIC; goto err_exit; return (ret); err_exit: return (ret); } lm_mgmt_get_mac_ent(msg, getnext) struct AgentMsg~*msg; int getnext; { int ret; struct MB *mb; struct MBH *mbjιdr; struct LM_MAC_ENTJDX *idx; struct LM_MAC_ENT_IDX tmpjdx; lm_mac_vlanj tmp_mv; lm~mac_addrj mac_addr; lm_mac_vlan t *mv; struct OS " tmp os; SETUPJTCB; ret = RT_SUCCESS; mb = &msg->Body; mb_hdr = &mb->head; idx = (struct LM MAC ENT IDX *) mb_hdr->iid; mv = Im mgmt find mv(idx7; if (mv = = NULf) { if (getnext) { mv = lm_mgmt findnext_mv(idx); if (mv = = NULL) { ret = IRT SUCCESS; /SS Im mgrntc -120- return (ret); err_exit: return (ret); } lm_mgmt_get_mp_ent(msg, getnext) struct AgentMsg *msg; int getnext; { int ret; struct MB *mb; struct MBH *mb_hdr; struct LM_MP ENTJDX *idx; struct LM_MP_ENTJDX tmp_idx; lm_mac_addr_t mac_addr; lm_mac_t *mac; lm_port_t *port; Im port addr port_addr; struct (33 tmp_os; int shelf; int slot; int portjium; int num vlans; SETUP_TCB; " . ret = RT SUCCESS; /S9 lm mgmtc -121- mb = &msg->Body; mbjidr = &mb->head; idx = (struct LM_MP_ENT_IDX *) mb_hdr->iid; mac = Im mgmt findjnac(idx); if (mac = = NULL] { if (getnext) { mac = lm_mgmt findnext_mac(idx); if (mac = = NUL£J { ret = IRT SUCCESS; mb_hdr->ercode = ER_NOSUCHNAME; goto err exit; } } else { ret = !RT_SUCCESS; mb_hdr->ercode = ER_GENERIC; goto err exit; } } if (CHK_VB(LM_VB_MSGS)) { printffgetting stats on mac = %s\r\n", sprint_mac addr(&mac- > mac_addr)) ; } num_vlans •= QUEUE_LEN(mac->my_q); lm_cvt_mac_idx(&mac- > mac_addr, &tmp_idx) ; LM_CLR_PORT_ADDR(&port addr); ii (mac->port l= NULL) { port = mac- > port; LM_INIT_PORT_ADDR(&port_addr, tcb-> my_node, port->port_addr.aa_shelf + 1, port->port_addr.aa_slot + 1, port- > port addr.aa port + 1); } shelf = port_addr.aa_sheIf; slot = port_addr.aa_slot; port_num = port_addr.aa_port; MB_wpJNT(mb, LM MP SHELF PIX, &shelf); MB_wpJNT(mb, LM_MP_CARD_PIX, &s!ot); MB_wp_INT(mb, LM_MP_PORT_PIX, &port_num); MB_wp_INT(mb, LM_MP_NUM_VLANS PIX, &num_vlans); tmp_os.length = sizeof (mac-> mlid bitsj; bcopy(mac->mlid_bits, tmp_os.buffer, tmp os.length); MB wp OS(mb, LM MP MUD BITS PIX, Stmp os); /LD lm mgmt.c -122- return (ret); err_exit: return (ret); } lm_mgmt_get_vc_ent(msg, getnext) struct AgentMsg *msg; Int getnext; int ret; struct MB *mb; struct MBH *mb_hdr; struct LM_VC ENTJDX *idx; struct LM_VC~ENT IDX tmpjdx; lm_vc_addrj vc~addr; lm_vcj *vc; struct " OS tmp os; SETUP_TCB; lm_cvt_idx_os(tmp_idx.LM_VC_MAC, LM_NUM_ELEM(tmpJdx.LM_VC_MAC), lm_mgmt.c -123- &tmp_os); MB_wp_OS(mb, LM_VC_MAC_PIX, &tmp_os); MB_wpJNT(mb, LM_VC_REF_CNT PIX, &vc->ref_cnt); MB_wpJNT(mb, LM_VC_BID_PIX, Svc->bid); return (ret); err_exit: return (ret); } lm_mgmt_get_pm_ent(msg, getnext) struct AgentMsg *msg; int getnext; { int ret; struct MB *mb; struct MBH *mb_hdr; struct LM PM_ENT_IDX *idx; struct LM~PM_ENTJDX tmpjdx; lm_mac_addrj mac_addr; lm_mac_t *mac; imjDortJ *port; lm_port_addrj port_addr; struct OS tmp_os; int shelf; int slot; int ponjnum; int num vlans; SETUP_TCB; ret = RT_SUCCESS; mb = &msg->Body; mb_hdr = &mb->head; idx = (struct LM_PM_ENT IDX *) mb_hdr->iid; port = Im mgmt find portfidx); if (port = = NULLJ { ~ if (getnext) { port = Imjngmt findnext_port(idx); if (port = = NULL) { ret = IRT SUCCESS; mb_hdr->ercode = ER_NOSUCHNAME; goto err exit; } } else { ret = !RT_SUCCESS; mb_hdr->ercode = ERJ3ENERIC; goto err exit; } } /La, lm mgmtc ~-124- num_vlans = QUEUE_LEN(port->pv_q); if (CHK_VB(LM_VB_MSGS)) { printf("getting stats on port %s\r\n", sprint port addr(&port->port addr)); } " " lm_cvt_port_idx(&port- > port_addr, &tmp_idx) ; *idx = tmpjdx; port addr = port->port addr; LM_ " CLR_MAC ADDR(&mac addr); if (port->mac l~= NULL) { " mac = port- > mac; mac_addr = mac->mac addr; } shelf = port_addr.aa_shelf + 1 ; slot = port_addr.aa_slot + 1; port num = port addr.aa port + 1; MB_wpJNT(mb,lM_PM " 3HELF PIX, &shelf); MB_wpJNT(mb, LM_PM_CARD_PIX, &slot); MB_wpJNT(mb, LM_PM PORT_PIX, &port_num); MB_wpJNT(mb, LM_PM_NUM_VLANS_PIX, &num_vlans); tmp_os.length = sizeof(mac_addr) - 2; bcopy((char *) &mac_addr + 2, tmp os.buffer, tmp_os.length); MB_wp_OS(mb, LM_PM_MAC_PIX, £tmp_os); tmp_os.length - sizeof(port->mlid_bits); bcopy(port->mlid_bits, tmp_os. buffer, tmp os. length); MB_wp_OS(mb, LM_PM_MUD_BITS_PiX, &tmp_os); return (ret); err_exit: return (ret); } lm_srvc_mgmt_yalidate(msg) struct AgentMsg *msg; { int ret; struct MB *mb; struct MBH *mb_hdr; struct AgentMsg *tx_msg; ret = RT_SUCCESS; tx msg = lm_cp_mgmt_msg(msg); mb = &tx_msg->Body; mb_hdr = &mb->head; switch (mb_hdr->ovcode) { case LM_GLBL_OVN: ret = lm_mgmt_val_glbl(tx_msg); brβsk* case LM" ATTR ENT OVN: /6ό lm mgmtc -125- ret = !RT_SUCCESS; mb_hdr->ercode = ER_GENERIC; goto err_exit; break; } ret = lm_send_mgmt_rsp(tx_msg); return (ret); err_exit: lm_send_mgmt_rsp(tx_msg); return (ret); } lm_mgmt_val_attr_ent(msg) struct AgentMsg *msg; int ret; struct MB *mb; struct MBH *mb_hdr; struct LM_ATTR_ENT_IDX *idx; lm_vlan_t *vlan; Im vlanjdj vlanjd; tUINT32 mtu slze; tUINT32 num_mcasts; tUINTβ got_mtu_size; tUINTβ got num mcasts; SETUPJTCB; ~ " ret = RT SUCCESS; mb = &msg->Body; mb_hdr = &mb->head; mtu size = numjncasts = -1; idx = (struct LM_ATTR_ENT_IDX *) mb_hdr->iid; vlan = Im mgmt find vlan(idx); if (vlan == NUL£) { V ΘISΘ - got num mcasts = MB_dop(mb, LM_NUM_MCAST_PIX); got_mtu_size = MB_dop(mb, LM MTU_SIZE_PIX); num mcasts = got numjncasts " ? MB_cpJNT(mb,~LM_NUM_MCAST_PIX, &num_mcasts) : -1; mtu size = got mtu size ? ~ MB_cpJNT(mb, LM_MTU_SIZE_PIX, &mtu_size) : -1; } return (ret); err_exit: return (ret); } lm_mgmt_val_pv(msg) struct AgentMsg *msg; { int ret; struct MB *mb; struct MBH *mb_hdr; struct LM_PVJDX *idx; im port vlan t *pv; SETUPJTCB " ret = RT_SUCCESS; mb = &msg->Body; mb_hdr = &mb->head; idx = (struct LM_PVJDX *) mb_hdr->iid; pv = lm_mgmt_find_pv(idx); if (pv = = NULL) { } return (ret); err_exit: return (ret); } lm_mgmt_val_node_ent(msg) struct AgentMsg *msg; { int ret; struct MB *mb; /(,S im mgmt.c -127- struct MBH *mb hdr; SETUPJTCB; ret = RTJ3UCCESS; mb = &msg->Body; mb_hdr = &mb->head; ret = IRT SUCCESS; mb_hdr->ercode = ER_GENERIC; goto err_exit; return (ret); err_exit: return (ret); } lm_mgmt_val_mac_ent(msg) struct AgentMsg *msg; { int ret; struct MB *mb; struct MBH *mb_hdr; lm_mac_vlan_t *mv; SETUP_TCB; ret = RT_SUCCESS; mb = &msg->Body; mbjidr = &mb->head; return (ret); err_exit: return (ret); } lm_mgmt_val_glbl(msg) struct AgentMsg *msg; { int ret; SETUP_TCB; ret = RT_SUCCESS; return (ret); } lm_mgmt_val_mp_ent(msg) struct AgentMsg *msg; { int ret; lm mgrntc -128- struct MB *mb; struct MBH *mb_hdr; struct LM_MP ENT IDX *idx; struct LM_MP_ENTJDX tmpjdx; lm_mac_addr mac_addr; Imjnac " *mac; ~ lm_portJ *port; lm~port_addrJ port_addr; struct OS " tmp_os; int shelf; int slot; int port ium; SETUP_TCB; ret = RT_SUCCESS; mb = &msg->Body; mb hdr = &mb->head; Idx = (struct LM_MP_ENT_IDX *) mb_hdr->iid; mac = lm_mgmt find_mac(idx); if (mac = = NULL) { } else { } return (ret); err_exit: return (ret); } lm_mgmt_val_pm_ent(msg) struct AgentMsg *msg; { int ret; struct MB *mb; struct MBH *mbjιdr; struct LM_PM_ENT_IDX *idx; struct LM_PM_ENTJDX tmpjdx; lm_mac_addr_t mac_addr; lm_mac_t *mac; Im portJ *port; lm_port addrj port_addr; struct C)δ tmp_os; int shelf; int slot; int port num; SETUPJTCB; ret = RT_SUCCESS; mb ■= &msg->Body; mb hdr = &mb->head; Ψ lm_mgmt.c -129- idx - (struct LM_PM_ENT IDX *) mb_hdr->iid; port = Im ngmt find_port idx); if (port = = NULLj { } else { } return (ret); err exit: return (ret); } lm_mgmt_val_vc_ent(msg) struct AgentMsg *msg; { int ret; struct MB *mb; struct MBH *mb hdr; struct LM VC ENTJDX *idx; struct LM_VC_ENTJDX tmpjdx; lm_vc_addr_t vc_addr; lm~vc *vc; struct OS tmp_os; SETUP_TCB; ret = RT_SUCCESS; mb = &msg->Body; mb hdr = &mb->head; idx = (struct LM_VC_ENT IDX *) mb_hdr->iid; vc = lm_mgmt find_vc(idx); if (vc = = NULL) { } else { } return (ret); err_exit: return (ret); } lm_srvc_mgmt_commit(msg) struct AgentMsg *msg; { int ret; struct MB *mb; struct MBH *mb_hdr; struct AgentMsg *tx_msg; ret = RT_SUCCESS; tx_msg = lm_cp_mgmt_msg(msg); mb - &tx_msg->Body; mb hdr = &mb->head; lm rngmtc -130- switch (mb_hdr->ovcode) { case LM_GLBL_OVN: ret = lm_mgmt_cmt_glbl(tx_msg); brββk * case LM_AHR_ENT_OVN: ret = lm_mgmt_cmt_attr_ent(tx_msg); break; hrfiak * case LM_PV_OVN: ret = lm_mgmt_cmt_pv(tx_msg); brθflk * case LM_NODE_ENT_OVN: ret = lm_mgmt_cmt_node_ent(tx_msg); rβdk * case LM ΛAC_ENT_OVN: ret = lm_mgmt_cmt_mac_ent(tx_msg); brθflk * case LM_MP_ENT_OVN: ret = lm_mgmt_cmt_mp_ent(tx_msg); rθsk * case LM_PM_ENT_OVN: ret = lm_mgmt~cmt_pm_ent(tx_msg); brθsk * case LM_VC_ENT_OVN: ret = lm_mgmt_cmt_vc_ent(tx_msg); break; default: ret = !RT_SUCCESS; mbJ^dr->ercode = ERJ3ENERIC; goto err_exit; break; } ret = lm_send_mgmt_rsp(tx_msg); return (ret); err_exit: lm_send_mgmt_rsp(tx_msg) ; return (ret); } lm_mgmt_cmt_glbl(msg) struct AgentMsg *msg; { int ret; int i; struct MB *mb; struct MBH *mb_hdr; struct OS tmp_os; tUINT32 *dflt_mtu_size; tUINT32 *dflt num mcasts; /έ>9 lm mgmt.c -131- tATMADDR *nac_addr; bitsj *bid_bits; bitsj *mlid_bits; tUINT32 dflt_mtu_size_a; tUINT32 dflt_num_mcasts_a; tATMADDR nac_addr_a; bitsj bid bits a[SIZE_BID BITS]; bitsj mlid bits a[SIZE MlJD_BITS]; SETUP_TCB; ret = RT_SUCCESS; mb = &msg->Body; mb_hdr = &mb->head; dflt_mtu size = dflt_num_mcasts = nac_addr = bidjSϊts = mlid_bits = NULL; if (MB_dop(mb, LMJ\AC_ADDR_PIX)) { MB_cp_OS(mb, LM_NAC ADDR_PIX, &tmp_os); if (tmp_os.iength I = sizeόf(nac_addr a)) { ret = IRT_SUCCESS; mbJιdr->ercode = ERJ3ENERIC; goto err exit; } bcopy(tmp_os. buffer, &nac_addr_a, sizeof (nac_addr_a)); nac addr = &nac addr a; } " " if (MB_dop(mb, LM_BID_PIX)) { bzero(bid Jjits_a, sizeof (bid j its_a)) ; MB_cp_OS(mb, LM_BID_PIX, &tmp os); if (tmp_os.length > sizeof(bid_bits_a)) { ret = IRTJ3UCCESS; mb_hdr->ercode = ERJ3ENERIC; goto err exit; } bcopy(tmp os.buffer, bid_bits_a, tmp_os.length); bid bits = " &bid bits a; } " " " if (MB_dop(mb, LM_DFLT_MTU PIX)) { MB_cp_INT(mb, LM_DFLT_MTU_PIX, &dflt_mtu_size_a); dflt mtu size = &dfit mtu size a; } " - - - if (MB_dop(mb, LM DFLT MCAST PIX)) { MB_cp_INT(mb, " LM DFLT_MCAST_PIX, &dflt_num_mcasts_a); dflt num mcasts = " Stdfit num mcasts a; } " " - - - if (MB_dop(mb, LM_MUD_BITS_PIX)) { bzero(mlid bits_I, sizeof(mlicf_bits_a)); MB_cp_OS " (mb, LM_MUD BITS_PIX, &tmp_os); if (tmp_os.length > sizeof(mlid_bits_a)) { ret = !RT_SUCCESS; mb hdr->ercode = ER GENERIC; /To lm mgmtc -132- goto err exit; } bcopy(tmp_os.buffer, mlid_bits_a, tmp_os.length); mlid_bits = &mlid_bits_a; lm_chg_glbl_cfg(dflt_mtu_size, dflt_num_mcasts, nac_addr, bld_bits, mlidjSits); return (ret); err_exit: return (ret); } lm_mgmt_cmt_attr_ent(msg) struct AgentMsg *msg; { ret = RTJ3UCCESS; chngd = FALSE; mb = &msg->Body; mbjidr = &mb->head; a_r = MB_cmp_ix(mb, LM_VLAN_PIX, LM_VLAN_IXO, LM_VLAN_IXL); dflt_mlid = num_mcasts = mtu_size = vlanjiame = NULL; num mcasts a = tcb- > dflt num mcasts; /// lm mgmtc -133- mtu_size a = tcb->dflt_mtu_size; dflt_mlid_a = LM_MAX_MUD; tmp_os.length = 3; bcopy("bob", tmp os.buffer, tmp os.length); if (MB dop(mb, LM MUD_PIX)) J MB_cpJNT(mb, LM_MUD_PIX, &dflt_mlid_a); dflt mlid = &dflt mlid a; } " " " if (MB_dop(mb, LM_NUMJVICAST_PIX)) { MB_cp_INT(mb, LM_NUM_MCAST_PIX, &num_mcasts_a); num mcasts = &num mcasts a; } if (MB_dop(mb, LM MTUJ3IZE PIX)) { MB_cp_INT(mb, LM_MTU_STZE_PIX, &mtu_size_a); mtu size = &mtu size a;~ } " " If (MB_dop(mb, LM_VLAN_NAME_PIX)) { MB_cp_OS(mb, LMJ/LAN NAME_PIX, &tmp_os); if (tmp_os.length > " sizeof (vlan_name_a) - 1) { tmp os.length = sizeof (vlan name " a) - 1 ; } vlan name = &vlan name a; } " " bcopy(tmp_os.buffer, vlan_name_a, tmp_os.length); vlan_name_a[tmp_os.length] = 0; idx = (struct LM_ATTR_ENTJDX *) mb_hdr->iid; vlan •= Im mgmt find vlan(idx); if (vlan = = NULL && " a_r = = MBJXP_CREATE) { lm_cvtJdx_vlan(idx-> LM_VLAN, &vlan_id); vlan = add_vlan(vlanjd, mtu_size_a, num_mcasts_a, vlan name a); } else if (vlan ! = NULL && a_r = = MB_IXP_DELETE) { vlanjd = vlan- > vlanjd; free_vlan(vlan); vlan = NULL; } if (vlan I = NULL) { lm_chg_vlan_cfg(vian, dflt_mlid, num_mcasts, mtu_size, vlan name); } if (vlan ! = NULL) { print_vlan(vlan, 0); } else printf (tried to add vlan %d, a_r = d\r\n", vlanjd, a_r); return (ret); err_exit: return (ret); } / £ lm mgrntc -134- lm_mgmt_cmt_pv(msg) " struct AgentMsg *msg; { int ret; int a_r; struct MB *mb; struct MBH *mb hdr; struct LM_PV_IDX * dx; lm_port_t *port; lm_vlanj *vlan; lm_port_addrj port addr; Im vlan id t vlan id; tUINT32 *mlid; tUINT32 mlid_a; Im port vlan t *pv~ SETUPJTCBf ret = RT_SUCCESS; mb = &msg->Body; mb_hdr = &mb->head; mlid = NULL; a_r = MB cmp ix(mb, LM PV_VLAN_PIX, LM PV_VLAN_IXO, LM_PV_VLAN IXL); idx = (struct UVf PVJDX *7 mb_hdr->iid; pv = Im mgmt find pv(idx); if (pv = = NULL && a_r = = MBJXP_CREATE) { lm_cvt_idx port(&idx->LM PVJ3HELF, &port addr); lm_cvt_idx vlan(&idx->LM_PV_VLAN, &vlan Id); port = FlN _PORT(tcb->port_q, &port_addT); vlan = FIND VLAN (tcb- > vlan q, vlanjd); if (port = = NULL) { port = add port(&port addr); } if (vlan = = NULL) { vlan = add_vian(vlanjd, tcb->dflt_mtu_size, tcb- > dflt num mcasts); } " " pv = add pv(&port addr, vlan id, vlan->dfit_mlid); if (pv = = NULL) { ret = IRT SUCCESS; mb_hdr->ercode = ER_GENERIC; goto err exit; } } else if (pv l= NULL && a_r = = MB_IXP_DELETE) { free_pv(pv); pv = NULL; } if (pv != NULL) { if (MB_dop(mb, LM_PV_MUD_PiX)) { MB_cp_INT(mb, LM_PV_MUD_PIX, &mlid_a); /7& im mgmt.c " -135- mlid = &mlid_a; } } else { ret = !RT_SUCCESS; mb_hdr->ercode = ER_GENERIC; goto err exit; } If (pv I = NULL) { Im chg_pv_cfg(pv, mild); } return (ret); err_exlt: return (ret); } lm_mgmt_cmt_node_ent(msg) struct AgentMsg *msg; { int ret; struct MB *mb; struct MBH *mb hdr; SETUP_TCB; ret » RT_SUCCESS; mb = &msg->Body; mb_hdr -= &mb->head; ret = !RT_SUCCESS; mb_hdr->ercode = ER_GENERIC; goto err_exit; return (ret); err_exit: return (ret); } lm_mgmt_cmt_mac_ent(msg) struct AgentMsg *msg; { int ret; int a r; /* add/remove flag */ struct LM_MAC_ENT_IDX tmpjdx; struct MB " *mb; struct MBH *mb hdr; struct LM_MAC_ENT_IDX *idx; lm_mac_addrj mac_addr; lm_vlan id t vlan id; tUINT32 *mlid~ lm mgmt.c -136- tUINT32 mlid_a; lm_mac_vlan_t *mv; lm_mac_t *mac; IπTportJ *port; Im vlan t *vlan; SETUPJTCB; ret = RT_SUCCESS; mb = &msg->Body; mbjidr = &mb->head; mac == NULL; mlid = NULL; idx = (struct LM MAC ENT IDX *) mb hdr->iid; a_r = MB_cmp_ix(mb, " LM_MAC_VLAN_PIX, LM_MAC_VLAN_IXO, LM_MAC_VLAN_IXL); mv = Im mgmt find mv(idx); if (mv = = NULL && a_r = = MBJXP_CREATE) { lm_cvt_idx_mac(&idx->LM MAC_ADDR, &mac_addr); lm_cvt_idx_vlan(&idx-> LM MAC_VLAN, &vlanjd); mac = FIND MAC(tcb->mac_q, &mac_addr); vlan = FIND~VLAN(tcb->vian_q, vlanjd); if (mac = = NULL) { mac = add mac(&mac addr); } if (vlan = = NULL) { vlan = add_vlan(vlanjd, tcb->dflt_mtu_size, tcb- > dflt num mcasts); } ~ " mv = add_mv(&mac addr, vlanjd, LM_MAX_MID, vlan->dflt_mlid); } else if (mv ! = NULL && a_r = = MB_IXP_DELETE) { mac = mv->mac; free_mv(mv); mv = NULL; } if (mv ! = NULL) { mac = mv->mac; if (MB_dop(mb, LM MAC_MUD_PIX)) { if (mac = = NULl) { ret = !RT_SUCCESS; mb_hdr->ercode = ER_GENERIC; goto err exit; } MB_cp INT(mb, LM_MAC_MUD_PIX, &mlid_a); mlid =Ti.mlid a; } } else { ret = IRT SUCCESS; mb_hdr->ercode = ER_GENERIC; goto err exit; } /7S lm mgmt.c -137- if (mv ! = NULL) { lm_chg_mv_cfg(mv, mlid); } return (ret); err_exit: return (ret); } lm_mgmt_cmt_vc_ent(msg) struct AgentMsg *msg; { int ret; struct MB *mb; struct MBH *mb_hdr; struct LM_VC_ENT IDX *idx; struct LM_VC_ENTJDX tmpjdx; lm_vc_addrj vc_addr; lm_vcj *vc; lm_bidj *bid; tUINT32 *ref_cnt; lm_bidj bid_a; tUINT32 ref_cnt_a; struct OS tmp os; SETUPJTCB; m_c g_vc_cfg vc, bid, re _cnt ; /~f lm mgmt.c "" -13^ return (ret); err exit: Teturn (ret); } lm_mgmt_cmt_pm_ent(msg) struct AgentMsg *msg; { int ret; struct MB *mb; struct MBH *mb hdr; struct LM_PM_ENT DX *idx; struct LM_PM_ENT IDX tmpjdx; lm_mac addrj nriac_addr_a; Jm_mac~addr_t *mac_addr; bitsj *mlid_bits; bitsj mlid_bits_a[SIZE_MUD_BITS]; lm_portJ *port; lm_port_addr_t port_addr; struct OS tmp os; SETUPJTCB; ret = RT_SUCCESS; mb = &msg->Body; mb_hdr = &mb->head; mac_addr = mlid bits = NULL; idx = (struct LM_PM_ENT IDX *) mb_hdr->iid; port = Im mgmt find porfFfidx); if (port = = NULL) { ~ ret = !RT_SUCCESS; mb_hdr->ercode - ER_GENERIC; goto err exit; } if (MB_dop(mb, LM_PM_MAC_PIX)) { LM_CLR MAC ADDR(&mac addr_a); MB_cp 0S(mb, LM_PM_MAC_PIX, &tmp_os); bcopy(tmp_os.buffer, (char *) &mac_addr_a + 2, tmp_os.length); mac addr = &mac addr a; } " " if (MB_dop(mb, LM PM_MUD_BITS PIX)) { MB_cp OS(mb, LM_PM_MUD_BrτS_PIX, &tmp os); bcopy(tmp_os.buffer, mlid_bits_a, tmp_os.length); mlid bits = &mlid bits a; } if (port I = NULL) { Im chg port cfg(port, mac addr, mlid bits); } " " " return (ret); /77 lm mgmt.c -13&- err_exit: return (ret); } lm_mgmt_cmt_mp_ent(msg) " struct AgentMsg *msg; int ret; int a_r; /* add/remove flag */ struct MB *mb; struct MBH *mb hdr; struct LM_MP_ENTJDX *idx; struct LM_MP_ENT_IDX tmpjdx; lm_mac_addrj mac_addr; lm_macj *mac; lm_port~t *port; bitsj *mlid bits; bitsj mlid_bits_a[SIZE_MUD_BITS]; lm_port addrj port_Iddr; struct 0 " S tmp_os; int shelf; int slot; int port num; SETUPJTCB; ~ ret = RT_SUCCESS; mb = &msg->Body; mb_hdr = &mb->head; mlid_bits = NULL; idx = (struct LM MP ENT IDX *) mb hdr->iid; a_r = MB_cmp_DC(mb, LMjMP MAC PIX, LM_MP_MAC_IXO, LM_MP_MACJXL); mac = lm_mgmtjind mac(idx); if (mac = = NULL && a = = MBJXP CREATE) { lm_cvt Jdx_mac(&idx- > LM_MP_MAC, &mac_addr) ; mac = add_mac(&mac_addr); if (mac = = NULL) { ret - !RT_SUCCESS; mb_hdr->ercode = ER_GENERIC; goto err exit; } } if (mac I = NULL && a_r = = MB_IXP_DELETE) { freejτιac(mac); mac = NULL; } if (mac I = NULL) { if (MB dop(mb, LM_MP_MUD_BITS_PIX)) { MB_cp OS(mb, LM_MP_MUD_BITS_PIX, &tmp os); bcopy(tmp_os.buffer, mlid_bits_a, tmp_os.length); mlid bits =~&mlid bits a; /7g lm mgmt.c -140- } } if (mac I = NULL) { Im chg mac cfg(mac, mlid_bits); } return (ret); err_exit: return (ret); } struct AgentMsg * lm_cp_mgmt_msg(msg) struct AgentMsg *msg; { struct AgentMsg *ret; int msgjen; msgjen = msg->Hdr.Length + ITSZ; ret •= (struct AgentMsg *) ReqMsgMemZero(msgJen); if (ret •= = NULL) goto err_exit; bcopy (msg, ret, msgjen); return (ret); err exit: " Crash(993, 0, 0); } ret = NULL; lm_cvt idx_vc(idx, &tmp_vc); vlan = FIND VLAN(tcb->vlan_q, tmp_vc. vlanjd); if (vlan ! = NULL) { ret = FIND VC(vlan->vc q, &tmp vc); } - - - return (ret); lm_port_vlanj /*9 lm mgmt.c -141- lm_mgmt find pvβdx) struct EM PV IDX *idx; lm_port_vianJ tmp_pv; lm_port_vlanJ *ret;~ SETUPJTCB; lm_cvt idx pv(idx, &tmp_pv); ret = FIND~PV(tcb->pv_q, &tmp_pv); return (ret); } lm_mac_vlanj * lm_mgmtjind_mv(idx) struct LM_MAC_ENT_IDX *idx; lm_mac_vlanj *ret; lm_mac_vlan J tmp_mv; lm_mac_vlanj *mv;~ SETUP_TCB; lm_cvt_idx_mv(idx, &tmp_mv); ret = FIND_MV(tcb->mv_q, &tmp_mv); return (ret); } lm_macj * lm_mgmtjind_mac(idx) struct LM_MP_ENT IDX *idx; { lm_macj *ret; Im mac addr mac addr; SETUP_TCB; Im_cvtjdx_mac(idx->LM_MP_MAC, &mac addr); ret = FIND_MAC(tcb->mac_q, &mac_addr] " ; return (ret); } lm_port _t * lm_mgmt find port(idx) struct LM PM ENT IDX *idx; { - - - lm_portj *ret; lm_port_addr t port addr; SEΞTUP_TCB; " lm_cvtJdx_port(&idx->LM_PM SHELF, &port_addr); ret = FIND_PORT(tcb->port_q7&port_addr); return (ret); } lm_vlanj * lm mgmt find vlan(idx) " struct EM_ATTR ENT_IDX *idx; { lm_vlanj *ret; Im vlan id t vlan id; int i; SETUPJTCB; lm_cvt idx_vlan(idx->LM_VI_AN, &vlan id); ret = FΪND_VLAN(tcb->vian_q, vianJdT; return (ret); } lm_vcj * lm_mgmt indnext_vc(idx) struct LM_VC ENTJDX *idx; { lm_vc_addr_t tmp_vc; lm_vc_t *ret; lm_vlan *vlan; SETUPJTCB; ret = NULL; lm_cvtjdx_vc(idx, &tmp_vc); vlan = FIND VLAN (tcb- > vlan q, tmp vcvlan Id); if (vian != NULL) { ret = FINDNEXT VC(vlan->vc_q, &tmp_vc); } if (ret = = NULL) { vlan = FINDNEXT_VLAN(tcb->vlan_q, tmp_vc. vlanjd) ; if (vlan ! = NULL) { ret = FINDNEXT VC(vlan->vc_q, &tmp_vc); } } return (ret); } lm_port_vlan_t * IπTmgmt findnext pv(idx) struct LM PV IDX *idx; { " " lm_port_vlan_t tmp_pv; Im port " vlan t *ret; SETUPJTCB; im_cvtjdx_pv(idx, &tmp pv); ret = FINDNEXT_PV(tcb " >pv_q, &tmp_pv); / / lm mgmtc -143- return (ret); } lm_mac_vlanj * lm_mgmt_findnext mv(idx) struct LM MAC ENT IDX *idx; { lm_mac_vlan_t *ret; lm_mac_vlan_t tmp_mv; lm_mac_addr_t mac_addr; lm_mac vlan t *mv; SETUP TCB " lm_cvtjdx_mv(idx, &tmp_mv); ret = FINDNEXT_MV(tcb->mv_q, &tmp_mv); return (ret); } lm_macj * lm_mgmt indnext_mac(idx) struct LM_MP_ENT_IDX *idx; { lm_mac_t *ret; lm_mac_addr t mac addr; SETUPJTCB; " lm_cvtJdx_mac(idx-> LM_MP_MAC, &mac_addr); ret = FINDNEXT MAC(tcb->mac_q, &mac_addr); return (ret); } lm_port_t * lm_mgmtJindnext_port(idx) struct LM_PM_ENT_IDX *idx; { lm_port_t *ret; Im port addr t port addr; SETUPJTCB; " lm_cvtJdx_port(&idx-> LM_PM_SHELF, &port_addr); ret = FINDNEXT_PORT(tcb->port_q, &port_addr); return (ret); } lm_vlan_t * lm_mgmt indnext vlan(idx) struct LM ATTR ENT IDX *idx; { - - - lm_vlan_t *ret; Im vlan id t vlan id; /•OL lm mgmt.c — -144- int i; SETUP TCB; Im cvt_idx_vlan(idx->LM VLAN, &vlan_id); ret~= FINDNEXT_VLAN(tcb->vlan_q, vtan_ld); return (ret); } lm_cvt_mv_idx(mv, idx) lm_mac_vlanj *mv; struct LM MAC ENT IDX *idx; { bzero(idx, sizeof (*idx)); lm_cvt_mac_idx(&mv->mac addr, idx->LM_MAC_ADDR); lm_cvt vlan idx(&mv->vlan Id, idx->LM_MAC_VLAN); } lm_cvt_pvjdx(pv, Idx) lm_port_vlanj *pv; struct LM PV IDX *idx; { bzerofldx, sizeof (*idx)); idx->LM_PV_SHELF •= pv->port_addr.aa_shelf + 1 ; idx->LM_PV_CARD = pv->port_addr.aa_slot + 1; idx->LM_PV_PORT = pv->port_addr.aa_port + 1; lm_cvt_vian_idx(&pv- > vlanjd, idx- > LM_PV_VLAN) ; } lm_cvt_portJdx(port_addr, idx) lm_port_addrj *port addr; struct LM PM ENT IDX *idx; { bzero(idx, sizeof (*idx)); idx->LM_PM_SHELF = port_addr->aa shelf + 1 ; idx->LM_PM_CARD = port_addr->aa slot + 1 ; idx->LM_PM_PORT = port_addr->aa_port + 1 ; } lm_cvt_vcjdx(vc_addr, idx) lm_vc_addr t *vc addr; struct LM VC ENT IDX *idx; { bzerofldx, sizeof (*idx)); lm_cvt_mac_idx(&vc_addr->mac_addr, idx->LM VC_MAC); lm_cvt_vlanjdx(&vc_addr->vlanjd, idx-> LM_VC_VLAN); } lm_cvt_mac_idx(mac, idx) Im mac addr t *mac; bzerofldx, sizeof (*idx)); for fl = ATM FIRST_MAC; i < sizeofflm mac_addr_t); I+ +) { idx->LM føP_MAC[i - ATM_FIRST_MAC] = mac->aa_byte[i]; } } lm_cvt_vlanjdx(vlan_ld, idx) lm_vlanjdj *vlanjd; struct LM ATTR ENT IDX *idx; { bzerofldx, sizeof (*idx)); idx->LM_VLAN[LM VLAN IXL - 1] = *vlan_id; } /**/ Im cvtjdx_mv(idx, mv) " struct LM_MAC_ENT_IDX *idx; lm_mac_vlan *mv; { Im_cvtjdx_mac(idx->LM_MAC_ADDR, &mv->mac_addr); im_cvt idx vlan(idx->LM MAC VLAN, &mv->vlan id); } lm_cvtjdx_pv(idx, pv) struct LM_PV_IDX *idx; lm_port_vtan t *pv; { lm_cvtJdx_port(&idx->LM_PV_SHELF, &pv->port addr); lm_cvt idx vlan(idx->LM PV VLAN, &pv->vlan id); } Im cvt_idx_vc(idx, vc_addr) " struct LM_VC_ENT_IDX *idx; lm_vc_addr t~ *vc addr; { lm_cvtjdx_mac(idx- > LM_VC_MAC, &vc_addr- > mac_addr); lm_cvt idx vlan(idx->LM VC VLAN, &vc addr->vlan id); } " - - - - lm_cvt_idx_port(idx, port) struct LM PM ENT IDX *idx; lm_port addrl *port; { SETUP TCB; lm mgmtc — -146- LM INIT PORT ADDR(port, tcb->my_node, idx->LM_PM_SHELF - 1, idx->LM PM_CARD - 1, kJx->LM PM PORT - 1); } lm_cvt_idx_mac(idx, mac) struct LM_MP_ENT_IDX *idx; Imjnac addr t *mac; { Int I; LM CLR_MAC_ADDR(mac); for " (i = ATM FIRST MAC; i < sizeof (lm_mac_addrj); i+ +) { mac->aa byte[i] " = idx->LM MP_MAC[i - ATM_FIRST_MAC]; } } lm_cvt_idx_vlan(idx, vlanjd) struct LM_ATTR_ENTJDX *idx; lm_vlan id t *vlan id; { *vlan id = idx->LM VLAN[LM_VLAN_IXL - 1]; } lm_cvtJdx_os(idx, len, os) u_short *idx; int len; struct OS *os; { int i; os->length = len; for fl = 0; i < len; i+ +) { ' os->buffer[i] = idx[i]; } } /*&- lm util.c ■^47- /* Im util.c * COPYRIGHT 1992 ADAPTIVE CORPORATION * ALL RIGHTS RESERVED * Description: * < Description of the general category of file contents > * Routines: * <An OPTIONAL list summarizing the routines in this file> #ifdef CERNEL #include "ipc_def.h" #include "net_def.h" #include <global_def.h> #include <driver.h> #undef Imjnit #else /* ifndef CERNEL */ #include <stdint.h> #include <ITC_if.h> #include <RT_if.h> #include <global_def.h> #include <driver.h> #include <timer.h> #include <RT_def.h> #include <enet_if.h> #include <net_def.h> #include <NAC_shared_def.h> #define ERRLOG printdbg #define printf printdbg #endff /* ifdef CERNEL */ #include "unipduh" #include "nnipdus.h" #include "altask gl.h" #include "sigtask_gl.h" #include "svctask_gl.h" #include "svc_if.h" #include "snmp incl.h" #include "AALjfh" #include "wdb_if.h" #include "q.h" #include "bits.h" #include "Im.h" lm util.c -148- static char hex_dig[] = "0123456789abcdef"; lm_es_cfg_resp_t * lm_build_es_cfg_resp(mac, enq, respjen) Im mac J *mac; tCFGELEM *enq; int *resp_len; lm_es_cfg_respj *ret; int ret Jen; int num_paddrs; tPORT_CFGELEM *paddr; qlinkj *link; lm_mac_vianj *mv; lm_port_t ~*port; struct atm addr port_addr; int ~ i; int mlid; SETUPJTCB; ret = NULL; retjen = 0; if (CHK_VB(LM_VB_MSGS)) { printf( u Sending es_cfg resp msg to mac %s\r\n", sprint mac addrf&mac->mac addr)); } " ~ port = mac- > port; num_paddrs = -1 ; if (port ! = NULL) { for (link = HEAD_Q(mac->mv_q); link ! = NULL; link = link->next) { mv = (lm_mac_vianj *) link- > data; mlid = mv->mlid; printf ("num paddrs = %d, mlid = %d\r\n", num_paddrs, mlid); num_paddrs = (num paddrs < •= mlid) ? mlid : num paddrs; } } num_paddrs+ + ; ret len = SIZE_LM ES_CFG RESP + num_paddrs - \~ * sizeofTtPORT_CFGELEM); ret = (lm_es cfg resp J *) ReqMsgM~emZero(ret len); if (ret = = NULL) goto err_exlt; bzero(ret, ret len); BUILD UNI HDRm(&ret->lmi_hdr, NNI PROTOCOL, NN_PDU_STATUS RESP, LMI STATUS_CONFIG, LMI GLOBAL_CREF_TYPE, LMI GLOBAL CREF VALUE); / 7 Im util.c -149- ret->enq = *enq; port addr = port->port_addr; padcfr •= ret->paddr; for (i = 0; I < num_paddrs; I+ +) { paddr[i].af_type = LMI_PORT_ADDR; paddr[i].af_port = port_addr; ~ paddr[i].af_port.aa lannum = I; } link = HEAD_Q(mac->mv_q); for (link = HEAD_Q(mac->mv_q); link ! = NULL; link = link->next) { mv = (lm_mac_vlanj *) link- > data; mlid = mv->mlid; paddr[mlid].af_type = LMI_PORT_ADDR; paddr[mlid].af_mid = mv->mid; if (mv->vlan = = NULL) { paddr[mlid].af_mcasts = 0; paddr[mlid].af_mtu = 0; } else { paddr[mlid].af_mcasts = mv->vlan->num_mcasts; paddr[mlidj.af mtu = mv->vlan->mtu size; } paddr[mlid].af_port == port_addr; paddr[mlid].af port.aa lannum = mv->mlid; } *resp_len = retjen; return (ret); err_exit: *respjen = 0; return (ret); } lm_send_mgmt_rsp(msg) struct~AgentMsg *msg; { int ret; SETUPJTCB; if (CHK_VB(LM_VB_MSGS)) { printf ("sending a~mgmt rsp\r\n"); } ret = SendProxyMsg(msg, msg->Body.head.mbsize, SNMPA_MGMT_GETRESP) ; return (ret); lm_send_svc_rel_req(lmi_hdr, cause) tLMIHDR *lmi hdr; /?* lm util.c -150- tUINT32 cause; int ret; struct svcif *msg; tUINT32 msgjen; tREL_REQ *rel~req; tUINTβ *rel_cause; tLMIHDR *txjmi_hdr; tlTC HEADER *itc; SETDP TCB; if (CHK_VB(LM_VB_MSGS)) { printf("sending a svc_rel_req msg, cause is %d\r\n", cause); } ret = RT_SUCCESS; msgjen = SVCIF_PDU_OFFSET + sizeof (*rel_req); msg = (struct svcif *) ReqMsgMemZero(msgJen); if (msg = -= NULL) { ret = !RT_SUCCESS; goto err exit; } rel_req = (tREL_REQ *) & msg->lmi_hdr; tx_lmi_hdr = &rel_req->lmi_hdr; *txjmi_hdr = *lmi_hdr; txjmi_hdr->lh_pdu_type = SDU_RELEASE_REQ; rel cause = (tUINTδ *) & rel req~>lmi cause; LMI_ADD_ELEMENT(rel cause, LMI_RELEASE_CAUSE, cause); ret = lm_send_svc_msp^msg, msgjen); return (ret); err_exit: return (ret); } lm_send_svc_msg(itc, len) tlTCJHEADER *itc; tUINT32 len; { int ret; SETUPJTCB; if (CHK_VB(LM_VB_MSGS)) { printf ("sending a svc msg\r\n"); } BUILD JTCH((*itc), len - lASZ, TID_SVC, 0, EX_REQUEST, TA_AAL_IND RECEIVE, tcb->mytid); ret = SendMsg(itcT; return (ret); /r? Im util.c -151- lm_send_alan_cfg(prefix, atm_hdr, slot_num, active_ports, num_paddrs, paddrs) lm_prefix_t prefix; lm_atm_hdr t atm_hdr; tUINTβ " slot num; tUINT32 actlve_ports; tUINT32 num_paddrs; tATMADDR *paddrs; { lm_alan_cfg_resp_t *resp; int ret; int respjen; int I; SETUPJTCB; if (CHK_VB(LM_VB_MSGS)) { printf ("send an alan cfg msg, prefix = Ox%x, atmjidr = Ox%x\r\n", prefix, atm_hdr); printf("\tslot_num =~%d, act_ports = %d, num_paddrs = %d\r\n", slot num, active ports, num paddrs); } respjen = SIZE_LM_ALAN_CFG_RESP + (num_paddrs - 1) * sizeof (tATMADDR); resp = (lm_alan_cfg_resp t *) ReqMsgMemZeroflespJen, 0); if (resp = = NULL) { ret = !RT_SUCCESS; goto err exit; } /* Fill in the NNSTATUS RESP fields */ BUILDJJNI HDRm(&resp->lmi hdr, NNI PROTOCOL, NN_PDU STATUS RESP, LMI STATUS CONFIG, LMI GLO ~ BAL_CREFJTYPE, LMI_GLOBAL_CREF_VALUE) ; /* Fill in the ALANCFG_ENQ fields */ resp- >enq.elem Jype = ALAN_CFG_ENQ; resp->enq.slotid = slot ium; /* Fill in the ALANCFG_RESP fields */ resp->resp.elem_type = ALAN_CFG_RESP; resp->resp.active_ports = active_ports; resp->resp.nac id = tcb->nac_id; ATM_ADDR_CC5 " PY(resp->resp.nac_addr, tcb->nac_atm_addr); resp->resp.num_paddr = num_paddrs; for fl = 0; I < num paddrs; I++) ATM_ADDR_COPY(resp->resp.paddrs[i], paddrsfi]); ret = AAL DataSendNR(&tcb->my_aal key, resp, respjen, *((tUINT32 *) & prefix), *((tUINT32 *) & atm_hdr)); return (ret); lm util.c ■ΛS≥- err_exit: if (resp != NULL) FreeMem(resp); return (ret); } lm_send_es_cfgjnd(mac) Im mac t *mac; { int ret; lm_portJ *port; lm_prefixj prefix; lm_atm_hdrj atm_hdr; tCFGELEM enq; lm es cf es *res ; if (CHK_VB(LM_VB_MSGS)) { printf( u sending es_cfg_ind to mac %s\r\n", sprint mac addr(&mac->mac addr)); } ret = RT_SUCCESS; port = mac- > port; if (port = = NULL) { ret = !RT_SUCCESS; goto err exit; } bzero(&enq, sizeof (enq)); tx_shelf = port->port_addr.aa_shelf; tx_slot = port->port_addr.aa_slot; tx_port = port->port_addr.aa port; tx_vci = SHELF_SLOT_PORT_TO_VCIm(NN_SIG_VCI, tx_shelf, tx_slot, bc_port); enq.af_type = LMI CONFIG ENQ; enq.af_version = LMI_VERSION; enq.af_my address = mac->mac_addr; resp = lm " build_es_cfg resp(mac, &enq, &resp_len); if (resp = = NULL) { goto err exit; } resp- > Imi Jype_spec = LMI_STATUS_IND; BUILD_ATM_HDR(&atm hdr, tx_vci); BUILD UCAST PREFIXφprefix, tx shelf, tx_slot, tx_port); /ft lm util.c -153- ret = lm_send_es_cfg_resp(prefix, atm_hdr, resp, respjen); return (ret); err_exit: return (ret); } lm_send_es_cfg_resp(prefix, atm_hdr, resp, respjen) lm_prefixj prefix; lm_atm_hdrj atmjidr; lm~es cfg resp t *resp; { int ret; SETUPJTCB; if (CHK_VB(LM_VB MSGS)) { printf("sending es_cfg_resp, prefix = Ox%x, atm_hdr = Ox%x\r\n", prefix, atm hdr);~ } if (resp - = NULL) { goto err exit; } ret = AAL_DataSendNR(&tcb->my_aal_key, resp, respjen, *((tUINT32 *) & prefix), *((tUINT32 *) & atmjidr)); return (ret); err exit: Tf (CHK_VB(LM_VB_ERRS)) { printf ("Couldn't send a null aal msg\n"); } return (-1); } send mcast cfgO { int ret; } Imjcb t * ImJnitfJ { Imjcb *ret; int err code; tUINT32 i; int Im_crt_cfg0; struct wdb_msg *wmsg; lm_glbl_cfg_key_t key; ret = (Im tcbj *) malloc(SIZE_LM_TCB); if (ret = = NULL) Im jtil.c -154- goto err_exit; SetGlobalP(ret); bzero(ret, sizeof (*ret)); ret->cur_bid - 0; ret->my_node = MHW_GetNodeNumber(); ret->my_shelf = MHW GetShelfNumberO; ret->my slot = MHW_GetSlotldO; bzero(&ret-> portjmplt, sizeof(ret-> portjmplt)); ret- > port Jmpltaajype = AAT_PORT; ret- > port _tmplt.aa_country = USA; ret- > port Jmpltaa node = ret->my_node; ret- > port mplt.aa~shelf = ret->my_shelf; ret->tmr_blk = Timerlnft(l); LM_INIT_PORT_ADDR(&ret->nac_atm_addr, ret->my_node, ret->my_shelf, ret->my slot, 0); ret->dflt_mtu_sile - LM_DFLT_MTU SIZE; ret->dflt_num_mcasts = LM_DFLT_ TUM_MCASTS; ret- > verbose = LM_VB_ALL; ret->mac_q = &ret->mac_queue; ret->port_q = &ret->port_queue; ret->vlan_q = &ret->vlan_queue; ret->mv_q = &ret->mv_queue; ret->pv_q = &ret->pv_queue; ret->vc_q = &ret->vc_queue; init_q(ret->mac_q); init~q(ret->port_q); init_q(ret->vlan_q); init_q(ret->mv_q); init~q(ret->pv_q); init_q(ret->vc_q); /* throw away the Oth bid, as per jib's recommedation */ bits_get_bit(ret-> bid_bits, SIZE_BID_BITS) ; err_code = AAL_SAP_Create(LM_START_VCI, LM_END_VCI, LM_AAL_SID, &ret->my aal key); #ifdef UNIX GetTid(&ret->mytid); #else /* ifdef UNIX */ ret->mytld.Generic = TID_LM; ret->mytid.lnstance = LMJNSTANCE; #endif /* ifdef UNIX */ GetPid(&ret->mypid); ret->do cfg wrts = TRUE; key.tag = GLBL_CFG_KEY; wmsg = wdb send fetch wait(&key, sizeof (key)); /93 lm util.c -155- if (wmsg = = NULL 1 1 wdb_get_ercode(wmsg) I = 0) { lm_kludge_data_initO ; } else { ret->do_cfg_wrts = FALSE; wdb_send startup_queries(lm_crt_cfg) ; ret->do_crg_wrts = TRUE; SendProxyCheckin(MHW_GetCardTypeO, MHW_GetSlotldO); return (ret); err_exit: return (NULL); } lm_mac_t * add_mac(mac_addr) im mac addr t *mac addr; { - - - lm_mac_t *ret; qlinkj *link; lm_mac t *tmp; SETUPJTCB; if (CHK_VB(LM_VB_TERSE)) { printf ("adding mac addr %s\r\n", sprint_mac_addr(mac_addr)); } mac_addr->aa_type = AAT_MAC; ret = FIND_MAC(tcb->mac_q, mac addr); if (ret ! = NULL) return (ret); ret = (Imjnac t *) malloc(SIZE_LM_MAC); if (ret = = NULL) goto err_exit; bzeroflet, SIZE_LM_MAC); ret->mac_addr = *mac_addr; ret->mac~addr.aa type = AAT_MAC; ret- > port = NUL±T ret->mv_q = &ret->mv_queue; init_q(ret->mv_q); init_qlink(&ret->mac_link, ret); ATCH_MAC_MV_Q(tcb->mv_q, ret); PUTQ_SORTED MAC(&ret->mac_link, tcb->mac_q); im_wrt mac_cfg * -et, NULL); return {ret); err exit: Crash(999, 0, 0); /9J lm_util.c -156- } Im portj * add_poit(port_addr) Im port addr t *port addr; { Im port t *ret; SETUPJTCB; port addr->aa_type = AAT_PORT; port_addr->aa_country = USA; if (CHK VB(LM_VB_TERSE)) { printf ("adding port %s\r\n", sprint_port_addr(port_addr)); } ret = FIND_PORT(tcb->port_q, port_addr); if (ret I = NULL) return (ret); ret = (Im port t *) malloc(SIZE_LM_PORT); if (ret = = NULL) goto err_exit; bzero(ret, SIZE_LM_PORT); ret->port_addr = *port_addr; ret->port~addr.aa_type = AAT_PORT; ret->port~addr.aa lannum - 0; ret->mac~= NULiJ ret->pv_q = &ret->pv_queue; init_q(ret->pv_q); init_qlink(&ret->portJink, ret); ATCH_PORT_PV_Q(tcb->pv_q, ret); PUTQ_SORTED PORT(&ret- > portjink, tcb- > port_q) ; lm_wrt port_cfgTret); return {ret); ~ err_exit: Crash(998, 0, 0); } lm_ylan_t * add_vlan(vlanjd, mtu, numjncasts, name) lm_vlanjd_t vlanjd; int mtu; int numjncasts; char *name; { lm_vtanj *ret; int i; /9f lm_util.c -157- SETUP TCB; If (CHK_VB(LM_VB TERSE)) { printf("adding vlan %d, mtu = %d, num_mcasts = %d, name = %s\r\n", vlanjd, mtu, num mcasts, name); } ret = FIND VLAN (tcb- >vlan_q, vlanjd); if (ret ! = NULL) return (ret); ret = (Im lanj *) malloc(SIZE LMjVLAN); If (ret = = NULL) goto err_exit; bzero(ret, SIZE_LM_VLAN); ret- > vlanjd = vlanjd; ret->mtu_size = mtύ; ret- > numjncasts = 0; ret->dflt_mlid = LM MAXjMLID; strcpy(ret->vlanjιaπ.e, name); ret->mv_q •= &ret->mv_queue; ret->pv_q = &ret->pv_queue; ret->vc_q = &ret->vcj-jueue; ret- > free /cj-i = &ret->free_vcj-|ueue; init j-j (ret- >mv_q); init_q(ret->pv_q); init_q(ret->vc_q); init_q(ret->free_vc q); init~qlink(&ret->vla " njink, ret); chgjιum /cs(ret, numjncasts); ATCH_VLAN VIV_Q(tcb->mv_q, ret); ATCH_VLAN_PV_Q(tcb->pv_q, ret); PUTQ_SORTED_VLAN(&ret->vlanJink, tcb->vlan_q); lm_chg ylan_cfg(ret, &ret->dflt_mlid, NULL, NULL, NULL); return (ret); err exit: " Drash(997, 0, 0); } ret = NULL; /9έ lm util.c -158- link = HEAD_Q(vlan->free vc q); if (link = = NULL) goto errjaxit; ret = (lm_vc_t *) link- > data; rmq(link); PUTQ_SORTED_VC(link, vlan->vc_q); return (ret); if (CHK_VB(LM_VB_TERSE)) { printf ("adding vc %s\r\n", sprint vc_addr(vc_addr)); } ret = NULL; vlan = FINDJ/L-AN(tcb->vlan q, vc_addr->vlanjd); if (vlan = = NULL) goto errjjxit; ret = FINDJ C(vlan->vc_q, vc_addr); if (ret ! = NULL) return (ret); ret = getjree_vc(vlan); if (ret = = NULL) goto err_exit; ret->vc_addr = *vc_addr; ret->ref_cnt = 0; return (ret); err_exit: return (NULL); } chg_num_vcs(vlan, num_vcs) lm vlanj *vlan; tlNT32 num vcs; { /9-7 lm util.c -159- int ret; int delta; int i; qlinkj *link; qlinkj *next; lm_vc_t *vc; int on_vc_q; ret = 0; delta = num_vcs - vian-> numjncasts; if (delta < 0) { on_vc_q = FALSE; link = HEAD_Q(vlan->free_vc_q); for fl = 0; i > delta; I-) { if (link = ■= NULL) { if (on_vc_q) break; link = HEAD_Q(vlan->vc_q); on vc q = TRUE; } if (link = = NULL) break; next = link- > next; vc = (lm_vc_t *) link- > data; free_vc(vc); ret-; link = next; } } else if (delta > 0) { for fl = 0; i < delta; i+ +) { add Jree_vc(vlan) ; ret+ + ; } } vlan- > numjncasts = num_vcs; return (ret); bid = bits get bit(tcb->bid bits, SlZE_BID_BITS); if (bid = = " -.) " goto err exit; Im util.c -160- if (CHK_VB(LM_VB_TERSE)) { printf ("getting a free mcast vc for vlan %s, bid = %d\r\n", sprint vlan id (&vlan-> vlanjd), bid); } ret = (lm_vcj *) malloc(SIZE_LM_VC); if (ret = = NULL) goto err_exit; bzero(ret, SIZEJ.M VC); LM_CLR MAC_ADDR(&mac_addr) ; LMJNIT_VC_ADDR(&ret->vc_addr, vlan->vlanjd, &mac_addr); ret- > bid = bid; ret- > vlan = vlan; init_qlink(&ret->vcjink, ret); initj-jlink(&ret->vlan link, ret); PUTQ J30RTED c &ret- > vcjink, tcb- > vc_q) ; PUTQ _SORTED_VC(&ret- > vlanjink, vlan- >f ree_vc_q) ; return (ret); err exit: " Crash(994, 0, 0); } Imj ort vlanj * id) ; if (CHKJ/B(LM_VB_TERSE)) { printf("adding pv, port addr = %s, vlan = %d, mlid = %d\r\n", sprint port addrfport addr), vlanjd, mlid); } - - - tmp.vlanjd = vlanjd; tmp.port_addr = *port_addr; ret = FIND_PV(tcb->pv_q, &tmp); if (ret I = NULL) return (ret); ret = (lm_port_vlanJ *) malloc(SIZE_LM_PORT_VLAN); if (ret = = NULL) goto err exit; /9? lm util.c -161- bzero(ret, SIZE_LM_PORT_VLAN); ret->port_addr = *port_addr; ret- > vlanjd = vlanjd; ret->port = NULL; ret->vlan = NULL; ret->mlid = mlid; init_qlink(&ret- > pvjink, ret) ; init_qlink(&ret-> portjink, ret); init_qlink(&ret-> vlanjink, ret); ATCH_PV_VLAN Q(tcb->vlan_q, ret); ATCH_PV_PORT_Q(tcb->port_q, ret); PUTQ 30RTED_PV(&ret-> pvjink, tcb->pv_q); lm_wrt pv cfg(ret); return {retJT errjjxit: Crash(996, 0, 0); } lm_mac_vlan_t * add_mv(mac_addr, vlanjd, mid, mlid) lm_mac_addrj *mac_addr; lm_vlanjdj vlanjd; int mid; Im mlid t mlid; { lmjnac_vlanj tmp; lm mac_vian t *ret; SETUP_TCB; if (CHK_VB(LM_VB_TERSE)) { printf("adding mv, mac_addr = %s, vlan = %d, mid = %d, mlid = %d\r\n", sprint mac addrflnac addr), vlan id, mid, mlid); } tmp.mac_addr = *mac_addr; tmp.vian Jd = vlanjd; ret = FIND MV(tcb->mv q, &tmp); if (ret I = NULL) return (ret); ret = (lm_mac vlan *) malloc(SIZE_LM_MAC VLAN); if (ret = = NULL) goto err_exit; bzero(ret, SIZE_LM_MAC_VLAN); ret->mac_addr = *mac_addr; ret- > vlanjd = vlanjd; ret- > mac = NULL; $90 lm util.c 62- ret->vlan = NULL; ret- > mid = mid; ret->mlid = mlid; init_qlink(&ret->mv_link. ret); init_qlink(&ret->mac_link, ret); init_qlink(&ret->vian_link, ret); ATCH_MV_VLAN O(tcb->vlan_q, ret); ATCH MVJVIAC Q(tcb->mac q, ret); PUTQ_SORTED~MV(&ret->mv link, tcb->mv_q); lm .hg mv_cfg(ret, &ret->mlid7; return (Fet); err exit: " Crash(995, 0, 0); } free cbflcb) Im tcb t *tcb; { if (tcb ! = NULL) { FREE_VLAN_Q(tcb- > vlan_q) ; FREE MAC_Q(tcb->mac q); FREE_PORT Q(tcb- > port_q) ; FREE_VC_Q{tcb->vc_q); FREE MV_Q(tcb->mv q); FREE_PV_Q (tcb- > pv_q) ; lmjm jlbl_cfgO; freeflcb); } } free_mac(mac) Im mac t *mac; { SETUPJTCB; if (mac ! = NULL) { if (CHK_VB(LM_VB_TERSE)) { printfCfreeing mac addr = %s\r\n", sprint mac addr(&mac->mac_addr)); } lm_rm_mac_cfg(mac) ; rmq(&mac-> macjink) ; FREE_MV_Q(mac->mv_q); Im send es cfg ind (mac); if (mac->port l= NULL) { mac- > port- > mac = NULL; mac->port = NULL; } JfOI Im util.c -163- free(mac); } return (NULL); free_vlan(vlan) Im vlanj *vlan; { SETUPJTCB; if (vlan ! = NULL) { if (CHK VB(LM_VB_TERSE)) { printf("freeing vlan %s\r\n", sprint vlan id(&vlan->vlanjd)); } lm_rm_vlan_cfg(vlan) ; rmq(&vlan->vlan link); FREE_PV_Q(vlan-> pv_q); FREE MV Q(vlan->mv_q); FREE~VC_Q(vlan->vc_q); FREE_VC_Q(vlan- > free_vc_q) ; bits free bit(vlan->dflt_mlid, tcb->mlid_bits, SIZE_MUD_BITS); freeXvlany " ; } return (NULL); } free_vc(vc) Im vc t *vc; SETUP_TCB; if (vc ! = NULL) { if (CHK_VB(LM_VB_TERSE)) { printfffreeing vc %s\r\n", sprint vc addr(&vc->vc addr)); } lm_rm_vc_cfg(vc) ; rmq(&vc- > vcjink) ; rmq (&vc- > vlan link) ; vc->vlan = NULL; bits free_bit(vc->bid, tcb->bid_bits, SIZE_BID_BITS); freeXvc); } return (NULL); } freej ort(port) Im port t *port; { lm util.c -164- SETUP_TCB; if (port != NULL) { if (CHK VB(LM_VB_TERSE)) { printf("freeing port addr = %s\r\n\ sprint port addr(&port->port_addr)); } lm_rm_port_cfg(port) ; rmq(&port- > portjink) ; if (port->mac != NULL) { port- > mac- > port = NULL; port- > mac = NULL; } FREE_PV_Q(port->pv_q); free(port); } return (NULL); } freejDortj v(pv) lm_port_vlan_t *pv; { lm_portJ *port; if (pv != NULL) { rmq(&pv-> portjink); port = pv->port; if (port ! = NULL) { bits Jree_bit(pv- > mlid, port- > mlid_bits, SIZEJVILIDJ3ITS); pv->port = NULL; } } return (NULL); } free_vlanjDv(pv) lm_port vlan t *pv; { If (pv ! = NULL) { rmq(&pv->vlanjink); pv->vlan = NULL; } return (NULL); } free_pv(pv) lm_util.c -165- if (pv ! = NULL) { if (CHK VB(LM_VB TERSE)) { prinff("freeing pvT port addr = %s, vlan = %d, mlid = %d\r\n", sprint_port_addr " &pv-> port addr), pv-> vlanjd, pv->mlid); } lmjm_pv_cfg(pv); rmq(&pv-> pvjink); free_vlanj v(pv); free port_pv(pv); freefav); } return (NULL); } freejnac_mv(mv) free_vlanjnv(mv) freejnv(mv) Im mac vlan t *mv; { SETUPJTCB; if (mv ! = NULL) { if (CHK_VB(LM_VB_TERSE)) { printf("freeing mv, mac_addr = %s, vlan = %d\r\n", lm util.c ^166- sprint_mac_addr(&mv->mac_addr), mv->vlan_id); } Im rm mv cfg(mv); If (mv->mac l= NULL) Im send_es_cfg ind(mv->mac); rmq(Smv-> mvjink " ; f ree_mac_mv(mv) ; free vlan_mv(mv); free^mv); } return (NULL); } free_mac_port(mac, port) lm_mac_t *mac; Im port t *port; { if (mac ! = NULL) mac->port = NULL; if (port ! = NULL) port- > mac = NULL; return (NULL); } chk -ort_mlid(port, mlid) lm_port_t *port; Im mlid t mlid; { int ret; ret = bits tst_bit(mlid, port->mlid_bits, SIZEJY1LIDJ3ITS); return (retj; } chkjnac_mlid(mac, mlid) Im macJ *mac; lm~mlid t mlid; { int ret; ret = bits tst_bit(mlid, mac->mlid_bits, SIZE_MUD_BITS); return (retj; } ImjnacJ * cmp macflnac, mac_addr) ImjnacJ *mac; Im mac addr t *mac addr; { - - - if (cmp_mac_addr(&mac->mac_addr, mac_addr) = = 0) Im util.c -167- return (mac); return (NULL); } ImjnacJ * cmpnext_mac(mac, mac_addr) lm_mac_t *mac; Im mac~addr t *mac addr; { int ret; ret = cmpjπac addr(&mac->mac_addr, mac_addr); if (ret > = 0) return (mac); return (NULL); } lm_port_t * cmp_port(port, port_addr) Imj ortj *port; Im port addr t *port addr; { if (cmp_port_addr(&port->port_addr, portjaddr) = = 0) return (port); return (NULL); } ret = cmp jport_addr(&port-> portjaddr, portjaddr); if (ret > = 0) return (port); return (NULL); } lm_vlan * cmp_vlan(vlan, vlanjd) lm vlan *vlan; InrTvlan id t vlan id; { - - - if (vlan- > vlanjd = = vlanjd) return (vlan); return (NULL); Im Jtil.c -168- lm_vlanj * cmpnext_vlan(vlan, vlanjd) lm_vlanj *vlan; Im vlan id t vlan id; int ret; ret = cmp_vlan_ld(&vlan->vlanjd, &vlanjd); if (ret > = 0) return (vlan); return (NULL); } lm_vcj * cmp_vc(vc, vcjaddr) lm_vcj *vc; Im vc addr t *vc addr; { if (cmp_vc_addr(&vc->vc_addr, vcjaddr) = = 0) return (vc); return (NULL); } lm_vc_t * cmpnext_vc(vc, vc_addr) im_vc~addrj *vc_addr; int ret; ret = cmp vc_addr(&vc-> vcjaddr, vcjaddr); if (ret > = ϋ) return (vc); return (NULL); } lm_mac_vlan_t * cmp_mv(mv, tst) lm_mac_vlan_t *mv; lm~mac vlan t *tst; { if (cmp_mac addr(&mv->macjaddr, &tst->mac_addr) = = 0 && cmp_vlari~ld(&mv->vlan_id, &tst->vlanjd) = = 0) return (mv); return (NULL); lm util.c -169- lm_mac_vlan t * cmpnext_mv(mv, tst) lm_mac_vlanj *mv; Im mac vlan t *tst; int ret; ret = cmp_mac_addr(&mv->mac_addr, &tst->mac_addr); if (ret > 0) return (mv); if (ret = = 0) { ret = cmp ian_id(&mv->vlanjd, &tst-> vlanjd); if (ret > = 0) return (mv); } return (NULL); } lm_mac /lanj * lm_mac_vlan * cmpnext jnlid(mv, mlid) lm_mac_vlanj *mv; lm mlid t mlid; { int ret; if (mv->mlid > - mlid) return (mv); return (NULL); } lm_port vlan t * cmp_pvfpv, tit) lm_port_vlanJ *pv; Im port vlan t *tst; { if (cmp_portjaddr(&pv-> portjaddr, &tst-> portjaddr) = = 0 && cmp /lan id(&pv->vlanJ.-C &tst-> vlanjd) = = 0) return (pv); return (NULL); Im util.c -170- lm_port_vian t * cmpnext_pv(pv, tst) lm_port_vlan_t *pv; im_port_vian_t *tst; int ret; ret = cmp_portjaddr(&pv->port_addr, &tst->port addr); if (ret > 0) return (pv); if (ret = = 0) { ret = cmp_vlan id(&pv->vlan_id, &tst-> vlanjd); ii (ret > = 0) return (pv); } return (NULL); } atchjnacj3ort(mac, port) ImjnacJ *mac; Imjjort t *port; mac- > port = port; port- > mac = mac; return (NULL); } atchjDortj)v(pv, port) lm_port_vlan_t *pv; lm_port t *port; { int tst; if (cmp port addr(&pv-> portjaddr, &port-> portjaddr) = = 0) { PUTQ_SθRTED_PV(&pv- > portjink, port- > pv_q) ; pv->port = port; if (pv->mlid > = LM ΛAXjVIUD 1 1 bits Jst_bit(pv-> mlid, port->mlid_bits, SIZE_MUD_BITS)) { pv->mlid = bits_get_bit(port->mlid bits, SIZE MUDJ3ITS); printf("replaciήg pv mlid %d with %d\r\n", LM_MAX_MUD, pv->mlid); } else { bits_alloc_bit(pv- > mlid, port- > mlid_bits, SIZE MUD BITS); } } return (NULL); oof Im util.c -171- atch_vlan_pv(pv, vlan) lm_port_vlanJ *pv; Im vlan t ~*vlan; { if (cmp vlan id(&pv->vtanjd, &vlan->vlan Id) = = 0) { PUTQ S<5RTED_PV(&pv-> vlanjink, vlaή->pv_q); pv->vlan = vlanj } return (NULL); } atchjnacjnv(mv, mac) lm_mac_vlan_t *mv; Im mac t *mac; { if (cmp mac addr(&mv->mac_addr, &mac->mac_addr) = = 0) { PUTQ_SO ~ RTED_MV(&mv->mac_link, mac->mv_q); mv->mac = mac; if (mv->mlid > = LM_MAX_MUD 1 1 bitsjst_bit(mv->mlid, mac->mlid_bits, SIZE_MLIDJ3ITS)) { mv->mlid = bits get_bit(mac->mlidj.its, SIZE_MLID BITS); prlntf("replacing mv mlid %d with %d\r\n", LM_MAX_ UD, mv->mlid); } else { bits_alloc_bit(mv-> mlid, mac-> mlid_bits, SIZE MUD BITS); } } return (NULL); } atch /lanjnv(mv, vlan) lmjnac_vlan *mv; lm~vlan t *vlan; { if (cmp_vlanjd(&mv->vlanjd, &vlan->vlan id) = = 0) { PUTQ_SORTED_MV(&mv-> vlanjink, via " ή-> mv_q); mv->vlan = vlan; ii (mv->mid > = LM_MAX_MID) { mv->mid = bits get bit(vlan->mid bits, SIZE MIDJ3ITS); } } return (NULL); } atch_pv_port(port, pv) lm_port_t *port; Im port vlan t *pv; { " " return (atch port pv(pv, port)); } " " Im util.c -172- atch_pv_vlan(vlan, pv) lm_vlan_t *vlan; lm_port_vlan_t *pv; { return (atch vlan pv(pv, vlan)); } atch_mv_mac(mac, mv) lm_mac_t *mac; lm_mac_vlan t *mv; { return (atch mac mvflnv, mac)); } " " atchjnv_vlan(vlan, mv) cmp_port_addr(p1, p2) lm_portjaddrJ *p1 ; Imj ortjaddr t *p2; { int ret; ret = ATM_ADDR_EQ(*p1, *p2) ? 0 : ATM_ADDR 3T(*p1 , *p2) ? 1 : -1 ; return (ret); } cmp_vlanjd(v1, v2) Im /ianJdJ *v1; lm_vlan id t *v2; { int ret; ret = (*v1 = = *v2) ? 0 : *v1 > *v2 ? 1 : -1; return (ret); } cmp_mac_addr(m1, m2) lm_mac_addr *m1; lm_mac addr t *m2; { int ret; lm util.c -173- ret = ATM ADDR EQ(*m1, *m2) ? 0 : ATM_ADDR_GT(*m1. *m2) ? 1 : -1; return (ret); ~ } cmp_vc_addr(vc1, vc2) lm_vc_addr_t *vd ; Im vc addr t *vc2; { " int ret; ret = cmp_mac_addr(&vc1->mac_addr, &vc2->mac_addr); if (ret = = 0) ret = cmp_vlan_id(&vc1->vianjd, &vc2-> vlanjd); return (ret); } cmp_pv_addr(pv1, pv2) Imj ort /laπJ *pv1; Im port vlan t *pv2; { int ret; ret = cmpjDOrt_addr(&pv1-> portjaddr, &pv2->port addr); if (ret = = 0) ret = cmp_vlan_id(&pv1->vian_id, &pv2-> vlanjd); return (ret); } cmpjnv_addr(mv1 , mv2) Imjnac /lan *mv1 ; Im mac vlan t *mv2; { int ret; ret = cmp_mac_addr(&mvl->mac_addr, &mv2->mac_addr); if (ret = = 0) ret = cmp_vlan_id(&mv1->vlan_id, &mv2-> vlanjd); return (ret); } lm_dup_port_dflts(port, mac) lm_port_t *port; lm~mac t *mac; { qlinkj *link; lm_port_vlanJ *pv; for (link = HEAD Q(port->pv q); link != NULL; link = link->next) { imj til.c -174- pv = (Im port_vlanJ *) link->data; add_mv(Smac->mac_addr, pv->vlanjd, LM_MAX_MID, pv->mlid); } } LMJNIT_PORTJ.DDR(&port_addr, tcb->my_node, tcb->my_shelf, min_slot, min_port); for (j = max_slot; j > = min_slot; j-) { if (j = = tcb->my_slot) { portjaddr.aajslot = j; portjaddr.aaj ort = min_port; add j30rt(&port jaddr) ; continue; } port addr.aa_slot = j; for (T = maxjjort; i > = min_port; i-) { port_addr.aa_port = i; add port(&port addr); } } for (i = max vlan; i > = min_vlan; i~) { add vlanfF, tcb->dflt mtu size, tcb->dflt num mcasts, "bob"); } " " " " tcb->my_node, tcb->my_shelf, min_slot, &β lm_util.c -175- qpscjnacflinkl, Iink2) qlinkj *link1 ; qlink t *link2; { int ret; lm_macj *mad ; lm_mac_t *mac2; mad = (ImjnacJ *) Iink1->data; mac2 = (ImjnacJ *) Iink2->data; ret = cmp_macjaddr(&macl->mac_addr, &mac2->mac_addr); return (ret); } qpsc jport(link1 , Iink2) qlinkj *link1; qlink t *link2; { int ret; Im port J *port1 ; lm_port_t *port2; portl = (lm_portj *) Iink1->data; port2 = (lm_port t *) Iink2->data; ret = cmp_port_addr(&port1->port_addr I &port2->port_addr); return (ret); lm_util.c -176- qpsc_vlan(link1, Iink2) qlinkj *link1; qlink t *Hnk2; { int ret; lm_vlan_t *vlan1 ; lm_vlan~t *vlan2; vlan1 = (Im vlan *) Iink1->data; vlan2 = (lm~vlan_t *) Iink2->data; ret = cmp_vlanjd(&vlan1->vlan_id, &vlan2-> vlanjd); return (ret) " } qpsc_vc(link1, Iink2) qlinkj *link1 ; qlinkj *link2; { int ret; lm_vc_t *vc1 ; lm~vcj *vc2; vd = (lm_vc_t *) linkl->data; vc2 = (lm_vc_t *) Iink2->data; ret = cmp_vcjaddr(vd, vc2); return (ret); } qpsc_pv(linkl, Iink2) qlinkj *link1 ; qlinkj *link2; { int ret; lm_port_vian t *pv1 ; lm_port_vlanJ *pv2; pv1 = (lm_port_vlan_t *) link. -> data; pv2 = (lm_port_vlanJ *) Iink2->data; ret = cmp_pv_addr(pv1, pv2); return (ret); } qpscjnvflinkl, Iink2) qlinkj *link1; qlink t *link2; { int ret; lm_mac_vlanj *mv1 ; Im mac vlan t *mv2; ύl Imj til.c -177- mv1 = flm_mac_vlanj *) Iink1->data; mv2 = (lm_mac_vlan t *) Iink2->data; ret = cmp_mv_addr(mv1, mv2); return (ret); } #ifdef UNIX MHW GetNodeNumberO { return (42); } MHW GetShelfNumberO { return (0); } #else /* tfndef CERNEL */ MHW GetNodeNumberO { tSHARED_RW *shr; shr = (tSHARED_RW *) GetSharedPO; return (shr- > Node); } MHW_GetShelfNumberO { return (0); } #endif /* ifdef CERNEL */ <*/έ q.c -178- /* q.c * * COPYRIGHT 1992 ADAPTIVE CORPORATION * ALL RIGHTS RESERVED 7 * Description: * < Description of the general category of file contents > * Routines: * <An OPTIONAL list summarizing the routines in this file> #include "q.h" init_qlink(link, p) qlinkj *link; int *p; { link->prev = NULL; link->next = NULL; link->q = NULL; link- > data = p; } inrt q(q) queuej *q; { q->head = NULL; q->tail = NULL; q-> count = 0; } putqflink, q) queuej *q; qlink t *link; { link->q = q; link->prev = q->tail; link- > next = NULL; if (q->tail = = NULL) { q->head = link; } else { q->tail->next = link; } q->tail = link; q- > count + + ; } putqJ_efore(link, before) qlinkj *link; q.c -179- qlinkj *before; queuej *q; q = before- >q; link->q = q; link->prev = before- >prev; link- > next = before; before- >prev = link; if (IS_HEAD_LINK(link)) { q->head = link; } else { link->prev->next = link; } q- > count + + ; } putqjafterflink, after) qiϊhkj *link; qlinkj *after; { queuej *q; q = after- >q; link->q = q; if (q = = NULL) { link->prev = after; link- > next = after- > next; after- > next •= link; if (IS_TAIL_LINK(link)) { q->tail = link; } else { link->next->prev = link; } q- > count + + ; } } putqjieadflink, q) qfihkj *link; queuej *q; { link->q = q; link- > next = q->head; link->prev = NULL; if (q->head = = NULL) { q->tail = link; } else { q->head->prev = link; } χ 8 q.c -180- q->head = link; q->count+ + ; } putq ailflink, q) qlTnkJ *link; queue t *q; { putqflink, q); } rmqflink) qlink t *link; { queuej *q; q = Iink->q; if (link- > next = = NULL) { q->tail = iink->prev; } else { link- > next- >prev = link->prev; } if flink- >prev = = NULL) { q->head = link- > next; } else { link- >prev-> next = link->next; } link->prev = NULL; link- > next = NULL; link->q = NULL; q-> count-; } int * traverse_q(q, func, arg) queuej *q; int *(*func) 0; int *arg; { qlinkj *link; qlinkj *next; int *ret; ret = NULL; for (link = q->head; link ! = NULL; link = next) { next = link- > next; ret = (*func) (link->data, arg); if (ret ! = NULL) { break; *n q.c -181- } } return (ret); } putq sorted (link, q, func) qlϊhkj *link; queuej *q; int (*func) 0; { qlinkj *cur; qlinkj *next; int ret; ret = 1 ; for (cur = q->head; cur ! = NULL; cur = next) { next = cur- > next; ret = (*func) (link, cur); if (ret < = 0) { putqjDeforeflink, cur); break; } } if (ret > 0) { putq tailflink, q); } 4*P q.h -182- /* q.h * COPYRIGHT 1992 ADAPTIVE CORPORATION * ALL RIGHTS RESERVED *******************************PfJQ ************************************** #ifndef Q_H #defιne Q_H #ifndef NULL #define NULL (0) #endif /* INULL */ struct qlink_s { struct qlink_s *prev; struct qlink_s *next; struct queue s *q; Int *data; }; typedef struct qlinkj. qlinkj; #define SIZE_QLINK (sizeof(qlinkj)) struct queue_s { qlinkj *head; qlinkj *tail; int count; }; typedef struct queuej. queue t; #define SIZE_QUEUE (sizeof(queue_t)) #define QUEUE_LEN(q) ((q)-> count) #define ISjΞMPTY Q(q) ((q)->head = = NULL && (q)->tail = = NULL) #define HEAD Q(qJ ((q)->head) #define TAIL_G(q) ((q)->tail) #define IS_HEAD_UNK(link) (flink)->prev = = NULL) #define IS_TAIL_UNK(link) (flink)->next = = NULL) #endif /* !Q_H */ < ? svc.c -183- /* SVC.C * * COPYRIGHT 1992 ADAPTIVE CORPORATION * ALL RIGHTS RESERVED / static char sccsidf] = "%A%"; #if Idefined(CERNEL) && defined(RT68K) #define ERRLOG printdbg #define printf printdbg #endif #include "atm.h" #include "svch" #lnclude "unipdu.h" #include "debug.h" #include "svc_utl.h" #include "if_atm.h" /* debugging and tracing stuff */ #define TL1 1 #define TL2 svc race > 1 #define TL3 svcjrace > 2 #define TL4 svcjrace > 3 #define TL5 svcjrace > 4 int svcjrace = 2; /* * switch virtual connection service * * This module provides basic virtual connection, or vc, management * services to users of the atm layer services, a service interface * to the SVC signaling protocol is provied via the sduJnputO * routine. In addition the virtual connection data structure, vcte, * provides hooks for upper layer protocols so that they need not * replicate functionality the signaling module requires Itsself. * Each upper layer protocol must register routines to be called when * payload frames arrive and signaling service notifications arrive. * ulp egisterO is used to register upper layer protocols. After a * protocol registers itsself it may interact with the signaling * module by sending/receiving signaling service data units (which * have the same structure as the signaling PDUs, found in unipdu.h). * The service data interface is describe in []. The call reference * field in the setup_request SDU is ignored. The call reference in * all other SDUs is a pointer to the virtual connection data * structure. Protocols may use this pointer to call svcJncO and * svc decQ to add references. Protocols may call svc.c -184- * svc_find_next_peerO to find all the vote's is specific states. * Typically this Is used to find an existing connection to a peer * for re-use. * Pointers, Conventions & Data Structures * * vp points to a virtual connection table entrye, vcte. There is * one vcte per virtual connection. Each vp is on two hash chains, * one linked by call reference and one linked by peer address, pc * points to the physical Interface with which a pdu or vc is * associated. Each physical interface has a pcif structure which * describes the characteristics of the interface and has the virtual * connection hash tables, pc_vcalltab[] & pc_vpeertab[] and incoming * vpci lookup table, pc ivpci ab[]. pdu (points to) a * protocol data unit xdϋ (points to) a protocol or service * data unit sdu (points to) a service data unit pdu, sdu, & * xdu all point to a buffer which can be extended at least as far as * the largest supported UNI transmuted signaling data unit, atp * points to an atm Ian interface structure. Conceptually atm lans * are layered above the virtual circuit (and aal) layers. The * virtual circuit layer needs a list of list port addresses per * physical interface. The atmif structures convenelntly have port * addresses are are statically linked off pcif s at boot so this * module uses (and manages) those port addresses, ulp points to an * upper layer protocol table entry, ulptab. A ulp uniquely * identifies an upper layer protocol to which signaling SDUs and * payload traffic are directed. * * Messages, allocation, non-reuse policy. * * Messages passed to us from below or above must be aligned on 4 byte * boundaries. Messages are not re-used. When this module needs * memory for a message it allocates a newti buffer by calling * atmjallocjnsgO- This routine must provide an aligned buffer at * least 104 bytes long. Messages received are not re-used because * while they may be large enough to hold a signaling pdu there is * not a convenient way to determine where the physical buffer begins * and ends. Rather than pass physical buffer boundaries around with * the buffers they are simply not reused. * * Multicast Server VCs * * VCs with the VCTEF_MCAST_SERVER flag are connections to an ATM LAN * multicast server. The network directs these requests to servers. * These VCs do not actually carry payload. The vctejvpci and * vcte_ovpci fields contain network specific control information for * these VCs. The server supplies these fields via setup request * and response SDUs. 7 _?<2 svc.c -185- #include "niu.h" /* how many interfaces */ /* * Due to the one of brain damaged OSes this code must execute upon * all global variables which are modified at run time must be * accessed via a pointer held by that OS. I int ulptab size = NULPS; int ivpci_tab_size = IVPCI TAB_SIZE; int vctab size = VCTAB aϊZE; int svc_default_qos = LMIjQOS_PRIO_LO; int svc_ms_perjick = 400; svcjnit pcif(unit, in peak rate, out_peak_rate, max_vci, max mtu) { struct pcif *pc; struct vcte *vp; pc = &svc glob- > svc j cif [unit]; atm_bzerofpc, sizeof *pc); pc->pc_num = unit; pc->pcjιum_lans = atm_nnius[unit] < = NATMS ? atm_nnius[unit] : NATMS; pc->pc_hw_max_mtu = maxjntu; pc->pc_hw_max_vci = max_vci; pc->pc_opeak_rate = out_peakjate; pc->pcjpeakjate = in peakjate; pc->pc_sig = lvc_create(pc, LMIj3LOBAL_CREFJΥPE, LMI_GLOBAL CREF VALUE, LMI_VPCI, LMI_VPCI, &atm_glob->atmjιull, &atm_glob->atm_null, svc_glob->sig_ulp, 0, PAYLOAD_AAL_4); if (svcj cm) { svc jιew_state(pc- > pc_sig, VCSJ /GRC) ; } else { svc_new_state(pc-> pc_sig, VCS_ACTIVE); pc->pc sig- > vcte ticks = 0; } if (pc->pc_num lans) atm_attach(pc); /* if atm lans are configured attach * them */ else atmJnitO; /* needed even if no atm lans * configured */ svc sched timeout(pc); } " /* * Once every tick (controlled by svc_ms_per_tick) all the VCs are svc.c -186- * scanned looking for timeout conditions. Both the signaling VC and * payload VCs are serviced from here. When vctejicks is * decremented to 0 either an IDUJTO or and IDU_MAX_RETRIES message * is sent to the VC state machine. " 7 int svc_max_retrans[VCS_LAST + 1] = {0, 0, 0, 7, 7, 0, 7, -1, -1, -1, 7}; int svcjiew ticks[VCS_LAST + 1] = {0, 0, 0, 2, 2, 0. 2, 4, 4, 4, 1 }; int svc_bacROff[] = {1, 2, 4, 8, 16, 24, 24, 24, 24}; int svc max retires = sizeof (svc backoff) / sizeof (int); int svc~timed states = (1 < < VCS WC) | (1 < < VCS WCACK) | (1 < < VCS WRC) | (1 < < VCS WGRC) R1 < < VCS WAR) | fϊ < < VCS .CTIVEJ; int svc_backoff_states = 71 < < VCS_WC) | (1 < < VCS_WCACK) | (1 < < VCSJ/VRC); svcjimeout(pc) struct pcif *pc; { struct vcte *vp, *next; struct release_comp *to; int i; int s; if (pc->pc_sig->vcte_state = = VCSJNACTIVE) { svc_sched Jimeout(pc) ; return; } for (i = 0; i < VCALLTAB_SIZE; i+ +) { s = splimpO; next = pc->pc vca!ltab[i]; while (vp = next) { ASSERT(VALIDJ/P(next)); next = vp->vcte_next_cref; if (vp-> vcte j_ref Jype | vp->vcte_cref_value) /* not global cref */ ASSERT(VAUD_STATE(vp->vcte_state)); if (vp-> vctejicks = = 0) /* no timeouts scheduled */ continue; ASSERT(VAUD_STATE(vp->vcte state)); ASSERT((1 < < vp->vcte_state) 5 svc_timed_states); vp-> vctejicks-; if (vp->vcte ticks < = 0) { /* timer has expired */ if ((to = (struct release comp *) atm alloc msgO) = = 0) { /* " * no memory, schedule a * timeout, and quit 7 vp->vcte_ticks+ + ; /* back off ticks for *This vc */ svc_sched imeout(pc) ; return; svc.c -187- } /* * send IDUJTO if retrans left else * send IDU MAX RETRIES 7 if (vp->vcte_timeouts < svc_max etrans[vp->vcte_state]) { to->lmi_cref_type = vp->vcte_cref_type; to->lmi_cref_value = vp->vcte cref_value; to->lmijxiu ype = IDUJTO; ~ vp-> vctejicks = svc_backoff[vp->vcteJimeouts+ +] * svc_new _ticks[vp- > vcte_state] ; } else to->lmi_pdujype = IDU_MAX_RETRIES; svc_xdu(vp->vcte pcif, vp, to, sizeof (*to)); } } splx(s); } svc sched timeout(pc); } /* * The signaling software is accessed via svcj luO and svc_sduO- * Users call svcjsduO with a sdu and the aal layer calls svc_pduO * with a pdu. The caller is resposnible for pass messages in * contiguous memory properly aligned. The caller is responsible for * providing synchroniztion, i.e., grabbing some global semaphore, * turning off interrupts, etc. This routine horseshoes down but not * up. That is a service request will not trigger calls to an upper * layer sdu routine. * * Before calling svc_xduO the vc table is searched for call reference * in the pdu. If none is found and the call refernece type is PVC * and the pdu type is a release then the call reference is assumed * to be an incoming vci. These are generated when the network * receives payload cells on a release VC. 7 svcjxlu(pc, pdu, length) struct pcif *pc; struct release *pdu; int length; { int bad_pdu; struct vcte *vp; if (pdu->lmi_proto != LMI_PROTOCOL 1 1 !svc_validj iu_type(pdu->lmi_pdu_type)) { svc.c -188- atm Jreejnsg (pd u) ; return PROTOCOL_ERR; /* invalid protocol or pdu * type */ } /* * when sig vc is not active only accept pdus w/ global call * reference I * * svcjsduO does preliminary service data unit parsing and calls * svc xduO for the real work. 7 int bad_pdu; /* If the signaling VC is not active reject service requests */ if (pc->pc_sig->vcte_state != VCS_ACTIVE) { svc.c -189- atm ree msg(pdu); return NETWORK_UNAVAIL; ASSERT((pdu->lmi cref type & LMI_CREFTYPE_MASK) = = LMI_CREFTYPE_SVC); /* * reject service requests with unknown encoding or invalid * request types 7 if (pdu->lmi_proto != LMI_PROTOCOL 1 1 lsvc_valid sdu_type(pdu->lmi_pdu_type)) { atm ree_msg(pdu); return UNKNOWN_MSG; } else if (badj du = svc_parse_xdu(pc, pdu, length)) { svc_glob-> svcstat.parse_causes[bad_pdu] + + ; atm_free_msg(pdu); return ba " d pdu; } return svc_xdu(pc, vp, pdu, length); } /* * svc_xduO service data units and protocol data units come here. * If they failed their respective parsing they have been turned into * IDUJNVALIDs which, in most cases result in release PDUs being * sent, via svcjeject_pduO- Next the state specific routine for vp * is called. If vp is zero the routine for VCS_CLOSED, * svc_closedO, is called. 7 Int svc_closedO, svc_wsrO, svc_wcO, svc_wcackO, svc_estabO, svc_wrcO, svc inactiveO, svcjactiveO, svc_wgrcθT svc_warO, panicO; int (*(svc_state Junctions!])) 0 = { panic, svcj.losed, svc_wsr, svc_wc, svc_wcack, svc_estab, svc wrc, svc inactive, svc wgrc, svc waT, svc active }; " - - - char *svc_state_names[] = {"undefined", "closed", "wsr", "wc", "wcack", "estab", "wrc", "inactive", "wgrc", "war", "active"}; int svcjinames = sizeof (svc_state_names) / sizeof (char *); svc_xdu(pc, vp, pdu, len) struct pcif *pc; /* physical unit */ struct vcte *vp; struct xdu *pdu; int len; { int state, rtn, tracejevel; ASSERT(VAUD PC(pc)); ASSERT(PDU AUGNED(pdu)); 4 svc.c -190- ASSERTflen > = sizeof (struct Imijidr)); if ( p) { state = vp->vcte_state; if (vp->vcte_cref_type | vp->vcte_cref_value) /* if not global call reference */ ASSERT(VAUD_STATE(state)); \ else state = VCS_CLOSED; if (pdu- >lmi_cref Jype | pdu->lmi_cref_value) tracejevel = TL2; else tracejevel = TL3; TR4(traceJevel, "xdu vp=%x %s %s %d\n", vp, svc_state_names[state] , svc_xduJype_str(pdu-> lmi_pdu_type), len); if ((pdu- > Imi iref jype | pdu->lmij.ref_value) && TL2) svcjracej lu(pdu, len, 1, LMIjTPCI); if (pdu->lmi_pdu_type = = IDUJNVAUD_PDU) rtn = svc eject_pdu(pc, pdu, len, vp)f else rtn = (*svc_state Junctions [state]) (pc, pdu, len, vp); TR3 (tracejevel, "xdue vp=%x %s %d\n", vp, vp ? svcjstate_names[vp->vctej5tate] : "was closed", rtn); return rtn; } /* * Clear any previous timers and set new ones. Also log transitions * to new states. 7 svcjιewj-.tate(vp, state) struct vcte *vp; { if (vp->vcte_state != state) svcJog_ήew_state(vp, state); vp->vcteJimeouts = 0; if ((1 < < " state) & svcjimed_states) vp->vctejicks = svc_newjicks[state]; else vp-> vctejicks = 0; vp->vcte state = state; } <a&9 svc.c -191- /* * State function for signaling vc in inactive state should never be * called. 7 svcjnactive(pc, pdu, len, vp) struct pcif *pc; struct xdu *pdu; int len; struct vcte *vp; { atm Jree_msg (pd u) ; } /* * State function for signaling vc in waiting for global release * state. The signaling VC stays in WGRC until we geta a global * release_comp. config status enq/resps are ignored. Other status * enquires and responses are processed normally. There is no limit * to how long we stay in this state (svc_new_stateO resets the * number of timeouts to zero.) * / svc_wgrc(pc, pdu, len, vp) struct pcif *pc; struct xdu *pdu; int len; struct vcte *vp; { switch (pdu->lmij3duj pe) { case LMI_PDU STATUS_RESP: case LMI_PDU_STATUS_ENQ: if (pdu- > Imi j-tatus ype ! = LMI_STATUS_CONFIG) svc_status(pc, pdu, len, vp); case IDUJTO: case IDU VIAXJ.ETRIES: /* fallen into */ svc_new_state(vp, VCSJ7VGRC); /* to reset timer & * timeout count */ svc_send_release(vp) ; br β s * case LMI_PDU_RELEASE: svc_send_release_comp(vp) ; brβdk * case LMI_PDU_RELEASE COMP: svc_new_state(vp, VCSJ/VAR); svc_request_config(pc); break; } atm reejτιsg(pdu); return 0; svc.c -192- /* * State function for signaling vc in waiting for address response * state. This state is left when we receive a response to one of * our config requests. svc_reconfigO actually changes the state to * active, releases and release jomps do not effect us because we * have come through the WGRC state insuring that all VCs have been * cleared and we reject any attempts to setup new VCs in this state. 7 svc vaφc, pdu, len, vp) struct pcif *pc; struct xdu *pdu; int len; struct vcte *vp; { switch (pdu->lmi_pdu_type) { case IDUJTO: case IDU_MAX_RETRIES: svc_new_state(vp, VCSJVAR); /* to reset timer & * timeout count */ svc equest j.onf ig (pc) ; brθdk* case LMI PDU STATUS ENQ: if (pdu->lmi_status type = = LMI_STATUS_CONFIG) svc_send_conf iglpc) ; else svc_status(pc, pdu, len, vp); brθdk * case LMI_PDU STATUS RESP: if (pdu->lmi status_type = == LMI_STATUS_CONFIG) svc_reconfig(pc, pdu, len, vp); /* sets state to ACTIVE */ else svc_status(pc, pdu, len, vp); brosk* case LMI_PDU_RELEASE: svc_send _release_comp(vp) ; brβdk* case LMI_PDU_RELEASE_COMP: break; } atmjreejπsg(pdu) ; return 0; /* * state function for signaling vc is active, we just send keep * alives and hope not to get releases, after max retries we release * all vcs, send a global release & go to waiting for global release * complete. <* svc.c -193- switch (pdu->lmi_pdu_type) { case IDUJTO: svc j-equest_config(pc) ; brΘfl * case LMI_PDU_STATUS_ENQ: if (pdu->lmi_status type = = LMI_STATUS_CONFIG) svc_send_conf ig( c) ; else svc_status(pc, pdu, len, vp); brθsk * case LMI_PDU_STATUS_RESP: if (pdu->lmi_status_type ! = LMI_STATUS_CONFIG) { svc_status(pc, pdu, len, vp); break; } else if (svcj_heck_config(pc, pdu, len)) { vp->vctej_ause = 0; svc_new_state(vp, VCS_ACTIVE); /* config same, reset * timeouts */ break; } else vp->vcte cause = NUMBER CHANGED; /* * If we get here we must delete all atm lans, * release all VCs and vctejiause is set so it gets * logged corectly. We sned a release_comp if a * release triggered this. 7 case IDU_MAX_RETRIES: case LMI_PDU_RELEASE: /* fallen into */ svc _release_all (vp) ; svc_send jelease(vp) ; if (pdu->lmi_pdu type = = LMI_PDU_RELEASE) { svc_set_cause vp) ; svc _send elease_comp(vp) ; } else if (pdu->lmi_pdu ype = = IDU_MAX_RETRIES) vp->vcte_cause = NETWORKJTIMEOUT; svc new_state(vp, VCS_WGRC); for føtp = pc->pc_atmif; atp; atp = atp->ati_next) atm_delete Jan(atp) ; break; SVC.C -194- } free_and_out: atm Jree_msg(pdu) ; return 0; } * svc_check_configO returns true if this config esp is the same as * the last. 7 svc_check_config(pc, pdu, len) struct pcif *pc; struct config *pdu; int len; { int rtn; if (!pc->pcJast_config) { pc->pcJastj_onfig = (uj.har *) atm_alloc_msgO; if (!pc->pcjast config) { printf ("svc_check_config: no memory\n"); return 0; } pc->pc last config len -= 0; } * dumb, simple, but almost foolproof check for configuration * changes. 7 rtn = (pc->pcJastj,onfigJen = = len && (atm_bcmp(pc->pcJast_config, pdu, len) = = 0)); return rtn; } /* * 2. set maximums based on LMI_CONFIG element 3a. if port element * then add one Ian per element. 3a. else configure for back-to-back * operation. 7 svc_reconfig(pc, pdu, len, vp) struct pcif *pc; struct status_enq *pdu; int len; struct vcte *vp; { struct configj3lem *ce; struct port_addr_elem *pae; struct atm ' rf *atp; SVC.C -195- ASSERT(pdu->lmi pdu type = = LMI_PDU_STATUS RESP); ASSERT(pdu->lmi_status_type = = LMI_STATUS_C NFIG); ASSERT(SVC PARSED(LMI CONFIG_ENQ)); ASSERT(SVC_PARSED(LMI~CONFIG_RESP)); ce = (struct config_elem *) SVC_GET(LMI_CONFIG_RESP); pc->pc ιet_max_vci = ce->af_max_vci; pc->pc~net_max_vcs = ce->af_max_vcs; pc->pc_net~max_qos = ce->af_max_qos; if (!pc->pcJast_config) { pc->pcjast config = (u_char *) atm_alloc_msgO; if (lpc->pc_last_config) { printf ("svcj-econfig: no memory\n"); return; } } atmjocopy(pdu, pc->pcJast_config, len); pc->pcJast_configJen = len; svcjιew_state(vp, VCS .CTIVE); if (!SVC_PARSED(LMI_PORT_ADDR)) { if (ce->af_myjaddress.aajype ! = AAT_MAC) { pc->pc_flags = 0; return; } /* configure back-to-back niu's */ pc->pcjags | = PCIF_NIU_TO_NIU; if (ATM_ADDRj3T(ce->af my address, pc->pcjatmif->atijnac)) pc->pc_flags | = PCIF )THER_MAC_ADDRJS HIGHER; for (atp = pc->pc atmif; atp; atp " --= atp~>ati_next " atmjιiuJo_niu(atp); return; } /* configure one atm Ian per port addr element */ pc->pc flags &= ~(PCIF_NIU TCjNIU | PCIF_OTHER_MAC_ADDR_IS_HIGHER); pae = (struct port_addr_elem ~) SVC_GET(LMI_PORT_ADDR); atp = pc->pc_atmif; while (((caddr t) pae < (caddr t) pdu + len) && atp) { ASSERT(pae->af_type = = LMI_PORT_ADDR); atm_add_lan(atp, pae->af_port, pae->af_mid, pae->af_mcasts, pae->af_mtu); pae+ +; atp = atp- > ati next; } } /* * send our configuration in respond to the parsed config enq. Our ° 2{ SVC.C -196- * config elem is based upon compiled table sizes and the h/w vci * lookup " table. 7 svc_send_config(pc) struct pcif *pc; { int len; struct config_elem *ce; struct status_enq *pdu; if (I (pdu = (struct status j-mq *) svcjalloc_pdu(LMI_PDU_STATUS_RESP, pc-> pc_sig))) return 0; pdu->lmi_status type = LMI STATUS .ONFIG; ASSERT(SVC_PARSED(LMI_CONFIG_ENQ)); ce = (struct config_elem *) & pdu[1]; /* copy requestors config info to resp */ *ce+ + = *(struct configj_lem *) SVCj3ET(LMI_CONFIG_ENQ); /* then add our config elem */ ce->af ype = LMI_CC5NFIG_RESP; svc_add_conf ig (pc,~ce) ; len = sizeof(*pdu) + sizeof(*ce) * 2; aal send msg(pc->pc sig, 0, pdu, len); } /* * send request for configuration, include our config_elem 7 svcj-equest_config(pc) struct pcif *pc; { struct config_e!em *ce; struct status_enq *pdu; ASSERT(VALID_PC(pc)); if (!(pdu = (struct status enq *) svc_alloc_pdu(LMI_PDU_STATUS_ENQ, pc-> pc_sig))) return 0; pdu- >lmi_status ype = LMI STATUS_CONFIG; ce = (struct config elem *) £ pdu[1]; ce->af type = LMI_CONFIG_ENQ; svcjacfl config(pc, ce); aal send " msg(pc->pc sig, 0, pdu, sizeof(*pdu) + sizeof(*ce)); } svc_add_config(pc, ce) struct pcif *pc; struct config elem *ce; { ce->af_version = LMI_VERSION; ce->af_max_vci = pc->pc_hw_max_vci; svc.c -197- ce->af_max_vcs = VCTAB_SIZE; ce->af_max_qos = 0; ce->af my address = pc->pc atmif- >ati_mac; } " ~ /* * state function for payload vc, vc is closed, we allocate a vcte * structure, all pdus other than setup are ignored. This should * probably send releases, and hope not to get releases, after max * retries we release all vcs, send a global release & go to waiting * for global release complete. 7 svcj--losed(pc, pdu, len, vp) struct pcif *pc; struct xdu *pdu; int len; struct vcte *vp; { int error = 0; switch (pdu->imi_pdu type) { case SDU SETUP REQ: ASSERT(lvp); ~ vp = svcjalloc vcte(pc, pdu); if (Ivp) { error = NO_RESOURCES; break; } if (error = svc_setup_req_unsalvageable(pdu, vp)) { svc_close(vp); break; } svc_updatejjserJnfo(vp) ; svc_new_state(vp, VCS_WC); svc_send_setup(vp) ; brβcik * case SDU RELEASE REQ: case SDU_SETUP_RESP: atm free msg(pdu); return INVAUD STATE; break; case LMI_PDU SETUP: ASSERT(lvp); vp = svc_alloc_vcte(pc, pdu); /* we need to alloc a vp * to sent a release ! */ if Ovp) break; /* try to get mem when setup SVC.C -198- * retransmitted */ if (svc_setup_unsalvageable(pdu, vp)) { svc_send release(vp); svc :lose(vp); } else { svc ipdatej ser info(vp); svc_new_state(vp; VCS WSR); svc send " setup ind(vpj; } brβsk * case LMI_PDU STATUS ENQ: case LMI_PDU_CONNECT: case LMI_PDU_CONNECT_ACK: /* turn misguided pdu into a * release and send it */ svc_send_release_pdu(pc, pdu, len); return 0; case LMI_PDU_RELEASE: /* our release comp may have been * " dropp~ed */ pdu->lmi_cref_type Λ = LMI_CREFDIRECTION_MASK; pdu->lmi_pdu type = LMI_PDU_RELEASE_COMP; aal_sendjnsg " (pc->pc_sig, 0, pdu, sizeof(struct release_comp)); return 0; case LMI_PDU_RELEASE_COMP: case LMI_PDU_STATUS_RESP: break; } atmjree_msg(pdu); return error; } /* state function for a load vc, vc is waiting for a setup resp from switch (pdu->lmi_pdu type) { case SDU_SETUP_REQ: atm ree msg(pdu) ; return INVAUD STATE; case SDU_SETUP_RESP: ASSERT(VAUD_VP(vp)) ; svc_setup_resp_vcis(pdu, vp); *3? svc.c -199- svc_update jjser Jnf o(vp) ; svc_new_state(vp, VCS_WCACK); svc_send_connect(vp) ; brθsk' case SDU_RELEASE_REQ: svc ipdatejjser info(vp); svc_set_cause(vp) ; svc_new_state(vp, VCSJWRC); svc_send elease(vp) ; brθsk * case LMI_PDU_SETUP: case LMI_PDU CONNECT: case LMI_PDU_CONNECT_ACK: break; /* protocol voilation, ignore */ case LMI_PDU_RELEASE: svc_update_user info(vp); svc j.et_cause(vp) ; svc_send release j--omp(vp) ; case LMI_PDU_RELEASE_COMP: /* fallen into */ svcjsend release_ind(vp); svcj--lose " vp); brβsk' case LMI_PDU STATUS JΞNQ: case LMI_PDUj3TATUS_RESP: svcj.tatus(pc, pdu, len, vp); break; } atm Jree_msg(pdu) ; return 0; } svc.c -200- svc_send_cack(vp) ; svc_update_userJnfo(vp) ; svc _send_setup_conf (vp) ; } else { svc_new_state(vp, VCS_WRC); svc_send_release(vp) ; svc send release ind(vp); } break; case IDUJTO: svc_send_setup(vp) ; break; case IDU_MAX_RETRIES: /* give up and start releasing */ vp->vcte_cause = NO_ANSWER_FROM_USER; svc_new_state(vp, VCS_WRC); svc_send jelease(vp) ; svc_send_release Jnd (vp) ; brβsk * case SDUJ3ETUPJ.EQ: case SDU 3ETUP_RESP: atm Jreejnsg(pdu) ; return INVALID_STATE; case SDU_RELEASE_REQ: /* user releases, start releasing */ svcj pdatejjser info(vp); svc_set_cause(vp) ; svcjιew_state(vp, VCS_WRC); svc_send jeleaseflφ) ; brβsk * case LMI_PDU_RELEASE: svcjjpdatejjser info(vp); svc_set _cause(vp) ; svc_send release comp(vp); case LMI_PDU_RELEASE_COMP: /* fallen into */ svc_send releasejnd(vp); svc_close " (vp); break; case LMI_PDU SETUP: case LMI_PDU_CONNECT_ACK: brβsk * case LMI_PDU STATUS_ENQ: case LMI_PDU_STATUS_RESP: svc_status(pc, pdu, len, vp); break; } atm_free_msg(pdu); ι return 0; } I * J39 SVC.C -201- * connect negoiation, we blindly accept whatever peer incoming vci * he wants; we try to accomodate the peers outgoing vci, reassigning * if necessary. The setup_conf will inform user of final vci's. We * lower out outbound peak to the the peers inbound peak rate. We * told the peer our inbound max. If he is going to send fast we * reject with service unavailable. 7 svc_connect_unsalvageable(pdu, vp) struct vcte *vp; struct connect *pdu; { vpci vci; ujong rate; if (SVC_PARSED(LMIJQOS PEAKJ3W)) { /* reset outbound peak */ rate = SVC_GET(LMI_IQO~S_PEAK_BW); if (rate < vp~>vcte_opeak_rate) vp->vcte opeak rate = rate; } if (SVC_PARSED(LMI _OQOS_PEAK_BW) && svcj3arms[LMI_OQOS_PEAK_BW].par_value > vp->vcte pcif->pcjpeak_rate) return QOSJJNAVAILABLE; /* peer insists on sending * fast than we can recv */ if (vp->vcte_flags & VCTEF_MCAST_SERVER) { ASSERT(vp->vcte_ivpci != 0); ASSERT(vp->vcte_ovpci ! = 0); return 0; /* vci's are ignored on the multicast * server */ } ASSERT(SVC_PARSED(LMIJVPCI)); if ((vci = SVC_GET(LMI_IVPCI)) ! = vp->vcte_ovpci) vp->vcte ovpci = vci; ASSERT(SVC_PARSED(LMI_OVPCI)); if ((vci = SVC 3ET(LMI_OVPCI)) ! = vp->vcte_ivpci) { /* ivpci changed */ if (ivpci_to_vcte(vp->vcte_pcif, vci)) /* if new one already in use */ return vp->vcte_cause = VCIJJNACCEPTABLE; ASSERT(vp->vcte_pcif->pc_fvpci_tab[vp->vcte_ivpci] = = vp); vp->vcte_pcif-> pc_ivpci_tab[vp->vctejvpci] =~0; vp->vcte_pcif->pc_ivpci_tab[vci] = vp; vp->vcte ivpci = vci; } return 0; /* * setup negoiation; we negoiate peer ovpci's and we blindly accept -?4 svc.c -202- * peer ivpci's because we could care less if they want to screw * themselves. After calling this routine both the vci's will be * assigned. The user isn't allowed to change vci's. 7 svc_setup_unsalvageable(pdu, vp) struct connect *pdu; struct vcte *vp; vpci vci; if (Isvc ind parsedjjlpO) return vp-~>vcte cause = ULP UNAVAILABLE; if (vp-> vcte Jags " & VCTEF_MCAST_SERVER) return 0; " /* vci's are ignored on he multicast * server */ /* set peak rates giving preference to requested values */ if (SVC_PARSED(LMIJQOS_PEAK_BW)) { vp->vcte .peakjate = SVC_GET(LMIJQOS_PEAK_BW); if (vp->vcte_opeak_rate > vp->vcte_pcif->pc_opeak_rate) vp->vcte opeak_rate = vp->vcte_pcif->pcJopeak_rate; } else vp->vcte .peakjate = vp->vcte_pcif->pc_opeak_rate; if (SVC_PARSED(LMI_OVPCI)) { /* check that ivpci is * available */ if (ivpci _to_vcte(vp->vcte_pcif, SVC_GET(LMI_OVPCI))) { /* request ivpci is in use, pick another */ if ((vci = svc_get_ivpci(vp->vcte_pcif)) = = 0) return vp->vcte_cause = NO_VCI_AVAIL; 1 ølsg vci = SVC_GET(LMI_OVPCI); } else if ((vci = svc_get_ivpci(vp->vctej_cif)) = = 0) return vp->vcte_cause = NO VCI_AVAIL; vp->vcte_ivpci = vci; vp->vctej if->pcjvpcijab[vci] = vp; /* use requested ovpci, if none requested use ivpci */ if (SVC_PARSED(LMI IVPCI)) vp->vcte_ovpci = SVC_GET(LMI_IVPCI); else vp->vcte_ovpci = vp->vcte_ivpci; return 0; /* * similar to setup pdu negoiation, only the users notion of incoming * is the same as ours. 7 svc_setup_req_unsalvageable(pdu, vp) svc.c -203- struct connect *pdu; struct vcte *vp; { vpcij vci; struct ulptab *ulp; if ((ulp = vp->vcte_ulp) = = 0) return vp->vcte cause = ULPJJNAVAILABLE; if (vp-> vcte Jags " & VCTEF_MCAST_SERVER) { /* use server provided * values */ if (SVC PARSED(LMI IVPCI)) vp->vcte_lvpci = SVC 3ET(LMI_IVPCI); if (SVC_PARSED(LMI OVPCI)) vp->vcte ovpci = 3VC_GET(LMI_OVPCI); return 0; /* do not update pc ivpci tab[] */ } /* set peak rates giving preference to requested values */ vp->vcte_opeak_rate = SVC_PARSED(LMI_OQOS_PEAK BW) ? SVC_GET(LMI_OQOS_PEAK_BW) : vp->vcte_pcif->pc opeak_rate; if (SVC_PARSED(LMI_IVPCI)) { /* user thinks he knows a * good ivpci ! */ if (ivpci Jo vcte(vp->vcte_pcif, SVC_GET(LMIJVPCI))) { /* he was wrong */ ASSERT(vp->vcte_pcif->pc_ivpci_tab[vp->vcte_ivpci] = = vp); /* try to allocate a ivpci not already in use */ if ((vci = svcj et_fvpci(vp->vctej3cif)) = •= 0) return vp->vcte_cause = VCIJJNACCEPTABLE; } else vci = SVC_GET(LMIJVPCI); } else if ((vci = svcjjetjvpci(vp->vcte_pcrf)) = = 0) return vp->vcte_cause ■= VCIJJNACCEPTABLE; vp->vcte_ivpci = vci; vp->vctej.cif->pc ivpci tabfvci] = vp; /* * if user did not request an ovpci then use 0 (which means * non specified yet) 7 if (SVC_PARSED(LMI_OVPCI)) vp->vcte_ovpci = SVC_GET(LMI_OVPCI); else vp->vcte_ovpci = 0; return 0; } /* * setup resp vci allocation for mcast_server VCs. vci's for other * VCs are allocated when the setup pdu or setup request sdu is * received. 7 svc_setup_resp_vcis(pdu, vp) struct connect *pdu; 4& svc.c -204- struct vcte *vp; if (vp->vcte_flags & VCTEF_MCAST_SERVER) { /* use server provided * values */ if (SVC PARSED(LMI IVPCI)) vp->vcte ivpci = SVC GET(LMIJVPCI); if (SVC PAffSED(LMI JDVPCI)) vp->vcte_ovpci = SVC_GET(LMI_OVPCI); /* do not update pc ivpci tab[] */ } return 0; } /* * state function for payload vc, vc is waiting for a connect ack * from initiator 7 svc_wcack(pc, pdu, len, vp) struct pcif *pc; struct xdu *pdu; int len; struct vcte *vp; { switch (pdu->lmijκlujype) { case LMI_PDU_SETUP: /* looks like our connect was dropped */ svcjsend_connect(vp); /* so retransmit it */ break; case LMI_PDU_CONNECT: /* protocol violation */ break; case LMI_PDU_CONNECT_ACK: /* notify user vc is * established */ svc_new_state(vp, VCS ESTAB); svc_send j_etup_comp(vp) ; break; case IDUJTO: /* retransmit connect */ svc _send_connect(vp) ; break; case IDUjλΛAX_RETRIES: /* give up and start releasing */ vp->vcte_cause = NO_ANSWER_FROM_USER; svc_new_state(vp, VCSJWRC); svc_send_release(vp) ; svc_send_release_ind(vp); rGdk * case SDU_SETUP_REQ: case SDU_SETUP_RESP: /* reject confused user requests */ atm Jree msg(pdu) ; return INVALID STATE; case SDU RELEASE REQ: svc.c -205- svc_update_user info(vp); svc_set_cause(vp); svc_new_state(vp, VCSJWRC); svc_send_release(vp) ; brøsk * case LMI_PDU_RELEASE: svc_update_user info(vp); svc_set_cause(vp) ; svc_serid release comp(vp); case LMI_PDU_RELEASE_COMP: /* fallen Into */ svc_send release_ind(vp); svc_close vp); brβsk * case LMI PDU_STATUS_ENQ: case LMI~PDU_STATUS_RESP: svc_status(pc, pdu, len, vp); break; } atm Jree jnsg(pdu) ; return 0;~ } /* * state function for payload vc, vc is established. Just wait * around for release pdu or request. If a setup is received then * release this vc and call closed state function for the pdu. 7 /* ignore all pdus except status enq/resp for PVCs */ if ((vp->vcte_cref_type & LMI CREFTYPE_MASK) = = LMI CREFTYPE_PVC && (pdu->lmi_pdu type = = LMI_PDU_STATUS_ENQ 1 1 pdu->lmi_pdujype = = LMI_PDU_STATUS_RESP)) { atm Jreejnsg(pdu) ; return 0; } switch (pdu->lmi_pdu type) { case LMI_PDU_SETUP: /* closed this VC and start seting up * " another */ vp->vcte cause = NORMAL_RELEASE; svc_send~ releasejnd (vp) ; svcjDlose(vp); return svc .losed(pc, pdu, len, (struct vcte *) 0); case LMI_PDU_CONNECT: /* retransmit connectjack for peer */ svc.c -206- /* duplicate, ignored */ /* fallen into */ /* * state function for payload vc, vc is waiting for a release * complete. No user requests are valid. After max retries or a * release from our peer we close vc out. Everything else (except * status enq/resps) are ignored. 7 svc_wrc(pc, pdu, len, vp) struct pcif *pc; struct xdu *pdu; int len; struct vcte *vp; { switch (pdu->lmi_pdu type) { case SDU SETUP REQ: svc.c -207- case SDU_SETUP_RESP: atm Jree msg(pdu) ; return INVAUD STATE; case LMI_PDU SETUP: case LMI_PDU CONNECT_ACK: case LMI_PDU CONNECT: case SDU_RELEASE_REQ: break; case IDUJTO: svc_send_release(vp) ; brθsk * case LMI_PDU_RELEASE: svc_send jeleasej_omp(vp) ; case IDUJVIAX_RETRIES: /* fallen into */ case LMI_PDU RELEASE_COMP: svc_close(vpJ; brøsk * case LMI_PDU_STATUS_ENQ: case LMI_PDU_STATUS_RESP: svcj3tatus(pc, pdu, len, vp); break; } atm Jree_msg(pdu) ; return 0; } /* * svc_set_causeO is called after a release pdu or release_req sdu * is received, vcte cause is updated. 7 svcj.et_cause(vp) struct vcte *vp; { if (SVC_PARSED(LMI_RELEASE CAUSE)) vp->vcte_cause = SVC_GET(LMI_RELEASE_CAUSE); else vp->vcte cause = NORMAL RELEASE; } /* * this routine updates the userjnfo field of the vcte from the xdu * last parsed. The pdu had better still be around as the parse * routines just set a pointer into the pdu. 7 svc_update_user_info(vp) struct vcte *vp; { struct Imi uinfo *ui; svc.c -208- ff (SVC PARSED(LMI JJSERJNFO)) { ui = lstruct lmi_uinfo *) SVC_GET(LMI_USERJNFO); if (vp->vcte_userJnfo = = 0) vp->vcte~user info = atm_alloc_msgO; ASSERT(ui- " >af_len < = LMI_MAX_UINFO); atm_bcopy(ui->af_value, vp->vcte_userJnfo, ui->afjen); vp->vcte_user_info_len = ui->af_len; } else { if (vp->vcte_user info) atm Jreejnsg (vp- > vcte_user_inf o) ; vp->vcte user info = 0; } } /* * svc_alloc_vcteO allocates a VC table entry and fills in * appropriate fields based upon elements parsed by svc_parse_xduO. * Call references are generated here for setup jeq's, the time * being. 7 struct vcte * svc_alloc_vcte(pc, pdu) struct pcif *pc; struct setup *pdu; { struct vcte *vp; struct atmjaddr *local, *peer; int i; struct Imijjlp *lu; ASSERT(pdu->lmi_pdujype = = LMI_PDU_SETUP pdu->lmi_pdu type = = SDU 3ETUP_REQ); ASSERT(VAUD_PC(pc)); /* grab free vcte entry */ if (l(vp = svc_glob-> vcte Jree)) { svc_glob-> svcstat.msgjallocJailures+ + ; return vp; } svc_glob- > svcstat.vctes + + ; pc->pcjium vcs+ + ; ASSERT(VAUD_VP(vp)); svc_glob-> vcte Jree = vp->vcte_next_cref; /* update free list head */ atm_bzero(vp, sizeof (*vp)); vp->vctejDcif = pc; /* set call reference and insert in cref hash table */ vp->vcte_cref_value = pdu->lmi_cref_value; vp-> vcte jϊref ype = pdu->lmi ;refjype; if (pdu->lmi pdu type = = LMI PDU_SETUP) { svc.c -209- peer = &pdu->lmi_calier; local = &pdu->lmij-allee; } else { /* SDU_SETUP_REQ */ vp->vcte_cref_type | = LMI_CREFDIRECTION_MASK; if (vp->vcte_cref_value = = 0) ~ vp->vcte cref_value = (ujong) vp & Oxffffff; peer = &pdύ->lmi_callee; local = &pdu->lmrcaller; } i = VCALL_HASH(vp->vcte_cref_value); vp->vctejιextj-τef = pc->pc_vcalltab[i]; pc->pc_vcalltab[i] = vp; /* * set local and peer addresses and insert in peer addr hash * table 7 vp->vcteJocal = *local; vp->vcte_peer = *peer; i = VPEER_HASH(&vp->vcte_peer); vp->vctejιext_peer = pc->pc_vpeertab[i]; pc->pc_vpeertab[i] = vp; /* * set mcast and pvc flags, stations and multicast servers * are distinct 7 if (peer- >aa Jype = = AAT_MAC) vp-> vcte Jags = VCTEF J^CASTJCUENT; else if (local- >aa Jype = = AATjVIAC) vp->vctejags = VCTEF_MCAST_SERVER; vp->vcte_ulp = svcJindjaarsed ilpO; ulp tax(vp- > vcte_ulp) ; ASSERT(vp->vcte ulp != 0); if (ISVC PARSEDfllMI JDEST ULP)) { /* symmetric ulps */ lu = (struct Imijilp *) SVCT GET(LMIJJLP); } else { /* peer ulp is different from local */ } lu = (struct Imi - ulp *) SVC - GET(LMI - DEST - ULP); vp->vcte_pid = lu->af_pid; vp->vcte_org = lu->af_org; vp->vcte_aal = iu->af_aal; svc_update_user _info(vp) ; vp->vcte state = VCS CLOSED; vp->vcte_qos = SVC_PARSED(LMIJQOS SERVICE_CLASS) ? SVC 3EΞT(LMIJQOS_SERVICE_CLASS) : svc_default_qos; return vp; svc.c -210- * create a pvc, used for local creating vcs, signaling, raw access * etc. 7 struct vcte * lvc_create(pc, ctype, cvalue, in, out, peer, local, ulp, atp, aal) struct pcif *pc; int in, out; struct atmjaddr *peer, *local; struct ulptab *ulp; struct atmif *atp; { int i; struct vcte *vp; if (ivpci_to_vcte(pc, in)) return (struct vcte *) 0; if (in > = IVPCI_TAB_SIZE) return 0; if (!(vp = svc_glob-> vcte Jree)) { return vp; } svc_glob- > svcstat.vctes + + ; pc- > pc jιum_vcs + + ; ASSERT(VALID_VP(vp)); svc_glob-> vcte Jree = vp->vcte_next_cref; /* update free list head */ atm_bzero(vp, sizeof (*vp)); vp->vcte_crefjype = ctype; vp->vctej_ref_value = cvalue; i = VCALL_HASH(vp->vctej-.ref_value); vp->vctejιextj_fef = pc->pc_vcalltab[i]; pc->pc /calltab[i] = vp; if (local- >aa_type != AATjNIULL) vp->vcteJocal = *local; else vp->vcte_local = atm_glob->atm_null; vp->vctej eer = *peer; i = VPEER_HASH(&vp->vcte_peer); vp->vcte_riext_peer = pc->pc_vpeertab[i]; pc->pc_vpeertab[i] = vp; vp->vcte_pcif = pc; vp->vcte_pcif->pc_ivpci_tab[in] = vp; vp->vcte_ivpci = in; vp->vcte_ovpci = out; vp->vcte_opeak_rate = pc->pc_opeak_rate; vp->vcte ulp = ulp; ulp ax(ϋip); vp- vcte_pid = ulp->ulp_pid; ' 49 svc.c -211- vp->vcte_org = ulp->ulp_org; vp->vcte_aal = aal; vp->vcte atmif = atp; svc_new state(vp, VCS_ESTAB); return vp; svc_free_vcte(vp) struct vcte *vp; { ASSERT(VAUD_VP(vp)) ; if (vp->vcte_user info) atm ree_msg(vp- > vcte_user Jnf o) ; vp->vcte_next_cref = svc_glob->vcte_free; svc_glob->vcte_free = vp; svc~glob- > svcstat.vctes-; vp- > vcte _pcif- > pc _num_vcs-; ulp free(vp->vcte ulp); } VCS_CLOSED) { svc_inc(vp) struct vcte *vp; { ASSERT(VAUD_VP(vp)); ASSERT(vp->vcte_refcnt > = 0); vp->vcte refcnt+ +; } /* * get a free ivpci, does't need to be fast as we only do this as * setup time. 7 vpcij svc_get_ivpci(pc) struct pcif *pc; SP svc.c -212- { int i; for fl = LMI_LAST_RSVD_VCI + 1; i < IVPCI_TAB_SIZE; I+ +) if (pc->pc_ivpci_tab[i] = = 0) return i;~ return 0; } /* * Find the next vcte entry given a local port address (atp), a peer * address and an upper layer protocol and a set of valid states. * Closed vote's are delinked from peer hash chain so do not go * looking for closed vote's. 7 struct vcte * svcjind_next_peer(pc, peer, ulp, np, vstates) struct pcif *pc; struct atmjaddr *peer; struct ulptab *ulp; struct vcte *np; int vstates; { int i; if (!np) { i = VPEERJH ASH (peer); np = pc->pc_vpeertab[i]; } else np = np->vcte_nextj eer; for (; np; np = np->vcte_next_peer) if (np->vcte_peer.aaJong[1] •= = peer->aaJong[1] && np->vcte_peer.aajong[0] = = peer- >aa Jong [0] && ((1 < < np->vcte_state) & vstates) && ulp = = np->vcte_ulp) break; return np; /* * Find an existing VC between the specified port addresses using the * specified upper layer protocol, ulp, in one of the states, states, * setup on interface, pc. 7 struct vcte * svcjind_vc(pc, from, to, ulp, states) struct pcif *pc; struct atmjaddr *from, *to; struct ulptab *ulp; svc.c -213- { struct vcte *vp; vp = svc ind next peer(pc, to, ulp, 0, states); /* get first match *7 while (vp) { if (ATM_ADDR_EQ(*from, vp->vcte_local)) return vp; vp = svcjind next_peer(pc, to, atm_glob->atm_ulp, vp, states); /* get next match */ } return 0; } /* * Lookup VC by call reference and physical interface. 7 struct vcte * svc ind_cref(pc, type, value) struct pcif *pc; int type; u long value; { " struct vcte *np; int i; i = VCALL_HASH(value); for (np = pc->pc_vcalltab[i]; np; np = np->vctejιext_cref) if ((np-> vcte .ref Jype = = type) && (np->vctejjref_value = = value)) break; return np; } /* * Lookup pcif by port address. 7 struct pcif * svc ind_port(adr) struct atm addr *adr; { struct atmif *atp; int i; for fl = 0; i < NNIU; i+ +) { if ((atp = svc_glob->svc_pcif[i].pc_atmif) && ATM_ADDR_EQ(*adr, atp->ati_port)) return &svc glob- > svc pcif[i]; } return 0; } *S2L. svc.c -214- Λ * svc_close is called when a vc goes into closed state. The vcte is * delinked from the call reference and peer address hash chains. 7 svc_close(vp) struct vcte *vp; { struct vcte *np; int i; ASSERT(VAUD VP(vp)); ASSERT(VAUD_ULP(vp->vcte_ulp)); ASSERT(VAUD PC(vp->vcte pcif)); svc new_state(vp, VCS CLOSED); if (l(vp->vctejags & VCTEF JVICAST_SERVER)) vp->vcte_pcif->pcjvpci_tab[vp->vcte_ivpci] = (struct vcte *) 0; /* delete vcte from call reference hash chain */ i = VCALL_HASH(vp->vcte_cref_value); np = vp->vcte pcif->pc vcalltab[i]; ASSERT(np); if (np != vp) { while (np->vcte_nextj-;ref ! = vp) np = np->vcte_next_cref; np->vcte_next_cref = vp->vcte_next_cref; } else vp->vcte_pcif->pc_vcalltab[i] = vp->vcte ιext_cref; /* delete vcte from peer port addr hash chain */ i = VPEER_HASH(&vp->vcte_peer); np = vp->vcte pcif->pc vpeertab[ij; ASSERT(np); if (np ! = vp) { while (np->vcte_next_peer != vp) np = np->vcte_next_peer; np->vcte_next_peer = vp->vcte_next_peer; } else vp->vcte_pcif->pc_vpeertab[i] = vp->vcte_next_peer; /* * all upper layers currently free references on ICS , but * when they do not then the vcte will have to be free here. 7 if (vp->vcte_refcnt = = 0) svc ree_vcte(vp) ; else TR1 (TL1, "svc_close(%x): free defferred\n", vp); JSS. svc.c -215- return; } /* * return a pointer to a port address in one of the atmif structures * linked off the phsyical inetrface pc. 7 struct atmjaddr * svcjind Jocal_port(pc, port) struct pcif *pc; struct atm addr *port; { struct atmif *atp; ASSERT(VAUD_PC(pc)); atp = pc->pc_atmif; while (atp) { if (ATM_ADDR_EQ(atp->ati_port, *port)) return &atp->atij3ort; atp = atp- > ati next; } return 0; } /* upper layer protocol routines * * The upper protocol table manages Q93S saps or ULPs. Upper layer * protocols register IEEE org/pid pairs in the ulptab using * ulpj-egisterO- When upper payer protocols think they are done * using a ULP they call ulp_unregisterO- ulp table entries are * reference counted by svc.c routines. When a vcte to ulp reference * is created the table entry reference count is incremented. * Ukewise when a table reference is destroyed the refcnt is * decremented. * * The protocol running over the adaptation layer is negoiated at * connection setup. SNAP organization and protocol ids are used. * Protocols which expect need be notified when new circuits are * established or when frames arrive on circuits must register using * ulp_registerO. Protocols may not un-register. ulp find is used * to lookup a ulptab entry for a given org.pid pair. This is fairly * infrequent as circuits are given pointer to ulptab enrties when * they are established. 7 struct ulptab * ulpjind(pid, org) int pid, org; svc.c -216- { int i; for fl = 0; i < NULPS; i+ +) if (svc_glob->ulptab[i].ulp_pid = = pid && svc_glot»ulptab[i].ulp_org = = org && svc_glob->ulptab[ij.ulp_registered) return &svc_glob->ulptab[i]; return 0; } ulp alloc pidO { " " int i; for fl = 0; i < NULPS && ulp find(LMI_PID_NET_ATM + i, LMIjDRGjMET); i+ +); return i + LMI PID NET ATM; } - - - /* * register an upper layer protocol for aal dispatch on vpci. 0 * return indicates no room in the table, otherwise a pointer to the * ulptab entry is returned. If both org and pid are zero then this * routine allocates an un-used org/pid within Adaptive Corp's * protocol space. * / struct ulptab * ulpjegister(org, pid, data, Imi, pcb) int org, pid; int (*data) 0; int (*lmi) 0; caddrj pcb; { struct ulptab *up; struct svcjjlobs *sg = svc_glob; if (org > == (1 < < 24) 1 1 pid > = (1 < < 16)) return 0; if (sg->ulp_inuse = = NULPS) return 0; up = ulp find (pid, org); if (up) { " if (up->ulp_lmi = = Imi && up->ulp_data = = data) return up; else return 0; } for (up = sg-> ulptab; up->ulp refcnt > 0 1 1 up->ulp registered; up+ +J; svc.c -217- if (pid = = 0 && org == 0) { org = LMIJDRG JNIET; pid = ulpjalloc pidO; } up->ulp_registered = 1; up- > ulp refcnt = 1; up->ulp~org = org; up->ulp_pid = pid; up->ulp_lmi = Imi; up->ulp_data = data; up->ulp_pcb = pcb; sg->ulp_inuse+ + ; return up; } struct ulptab * ulp_unregister(ulp) struct ulptab *ulp; { ASSERT(ulp-> ulp egistered) ; ulp->ulp registered = 0; ulp_free(ϋlp); } ulpjree(ulp) struct ulptab *ulp; { struct svc_globs *sg = svc jlob; if (~ulp->ulp efcnt < = 0) { ASSERT(ulp->ulp_refcnt = = 0); /* atm_bzero(ulp, sizeof *ulp); */ sg->ulp inuse-; } } ulpjax(ulp) struct ulptab *ulp; { ulp- > ulp refcnt+ +; } /* * Called with sevice data units for the signaling VC. However the * signaling vc should never be in a state where SDUs are passed. It * has a separate state machie. this may change... 7 svcjnac ImiO { svc.c -218- panic("svc_mac_lmi") ; } /* * release all connections sharing the same physical interface as vp. * Connections already in CLOSED or WRC are not effected. PVCs are * not released (the signlaing VC is considered a PVC). 7 svc_release_all(svp) struct vcte *svp; { struct pcif *pc = svp->vcte_pcif; struct vcte *vp; int i; ASSERT(VALID_VP(svp)); ASSERT(VALID_PC(pc)); for fl = 0; i < VPEERTABJ3IZE; i+ +) { for (vp = pc->pc_vpeertab[i]; vp; vp = vp->vcte_nextjoeer) { if (vp = = pc->pc_sig) continue; if ((vp->vcte_cref Jype & LMI_CREFTYPE_MASK) = = LMI_CREFTYPE_PVC) continue; ASSERT(vp->vcte_state != VCS CLOSED); if (vp->vcte_state < -= VCS ESTAB) svc_send elease Jnd (vpj; svc close(vp); } } * This routine handles non-configuration status pdus and sdus. * Unfortunately this routine is expected to grow as ATM Forum adds more LMI functionality. Currenly only vc_status requests are * responded to. Responses are ignored. 7 svc_status(pc, pdu, len, vp) struct pcif *pc; struct xdu *pdu; int len; struct vcte *vp; { struct status_resp *rdu; caddrj end; if (pdu->lmi_pdu_type = = LMI_PDU_STATUS_ENQ) { 1 SVC.C -219- switch (pdu- > Imi status type) { case LMI STATUSjVC: rdu = (struct status_resp *) svc alloc pdu no vp(LMI PDU STATUS RESP, pdu->lmi_c?ef ype * LMI_crREFDTRECTION_MASK, pdu-> lmi_cref_value) ; if (rdu = = 0) break; rdu- >lmi_status ype = pdu->lmi status_type; end = (caddr t) rdu + sizeof(*rdύ); if (vp) { LMI_SET_ELEMENT(end, LMI_VC_STATUS, vp->vcte_state); 1 i 0 J LMI SET ELEMENT(end, LMI VC STATUS, VCS CLOSED); } aal_send msg(pc->pc_sig, 0, rdu, sizeof *rdu) + sizeof (struct Imij arm)); break; default: TR1 (TL2, "svc_status: unsupported status request received, type =%d\n", pdu->lmi status type); } } return; } svcjorpO { return; } svc.h -220- /* svc.h * * COPYRIGHT 1992 ADAPTIVE CORPORATION * ALL RIGHTS RESERVED 7 #lfndef NIU_SVC H #define NIU_SV H included #include "bytes.h" #include "svcjf.h" related definitions are in unipdu.h # nc u e un p u. /* * Virtaul connection (channel or circuit) table entry. * One entry per connection. Each entry is linked into two separate * lists whose heads kept in two hash tables in the pcif structure. * The call reference (its is used to speed up signaling protocol * lookups. The peer port address list is used to speed up ATM MAC * lookups when searching for a connection to a particular * destination. * * Each connection has a pointer to an upper layer protocol table. This * table defines the SNAP encoded protcol identifier, a funciton to * be called with signaling sen/ice data units and a function to be * called for incoming frames. (The signaling protocol has an entry * in this table which is how signaling PDUs are directed to * svcjoduO- The upper layer protocols manipulate vctej acket, * vcte efcnt abd vctejatmif themselves. They are includec in this * structure for conveneince (so the ATM MAC module does not need a * separate VC table of its own). 7 struct vcte { struct vcte *vcte_next_cref; /* linked by callref */ struct vcte *vcte_next_peer; /* linked by peer adr */ struct ulptab *vcte_ulp; /* upper layer protocol, * local binding */ struct atmjaddr vctejocal; /* local port address */ struct atmjaddr vcte_peer; /* atm adr of peer */ struct pcif *vcte pcif; /* physical interface this VC * uses *7 vpci vctejvpci; /* vci pon which frames are 4* svc.h -221- * received */ vpcij vcte_ovpci; /* vci used from transmission */ u_char vcte_state; /* defined in unipdu.h */ u~char vcte imeouts; /* number of timeouts */ u_char vctejicks; /* number of ticks before * next timeout */ u_char vcte_cref type; /* direction is value * expected to ~ be received */ ujong vcte_cref_value; /* random value */ u_char vcte_qos; /* vague notion of quality is * negotiated */ u_char vctejnstance; /* incremeneted every * allocation */ u_char vcte iserjnfojen; /* length of, * vctejjserjnfo buffer */ ujong vcte_opeakjate; /* outbound peak rate * divided by 1024 */ u_short vcte Jags; /* VCTEF_MCAST indicates * multicast vc */ u_short vcte_cause; /* why this vc died */ short vcte_refcnt; /* one per referencing * ' connj . rnte & atmif */ struct atmif *vcte_atmif; /* atm Ian i/f, if * appropriate */ caddrj vcte_packet; /* used by atm mac to queued * a frame */ caddrj vctejjserjnfo; /* pointer to user info * buffer */ ujong vctejpackets; u_short vctejaal; u_short vctej id; ujong vctej-irg; u long vcte opackets; }; /* vcte Jags */ #define VCTEF_MCAST_CUENT 1 /* peer address is multicast */ #define VCTEF_MCAST_SERVER 2 /* local address is multicast */ #define VCTEF_CRC32 4 /* add crc32 to each frame, * used by ulp */ /* table sizes */ #define IVPCI TAB SIZE (8192+2048) /* indexed by incoming vpci */ #define VCTAB_SIZE 256 /* maximum number of VCs supprted */ #define ivpci Jo_vcte(pc, vci) ((vci < IVPCI_TAB_SIZE) ? (pc)->pcjvpci_tab[vci] : (struct vcte *)0) vpcij getJvpciO; svc.h -222- #define BITS IN VCHASH 4 #define VCALLTAB SIZE (1<<(BITS_IN VCHASH)) #define VCALL_HA§H(cref) VCTABS_HAS " H(cref) #define VPEERTAB SIZE (1<<(BITS IN VCHASH)) #define VPEER HASH(adr) VCTABS_HAS~H((adr)->aa_long[1]) #define VCTABS " HASH(value) (((value) Λ \ ((value7>>BITS IN VCHASH) Λ \ ((value) >> BITS IN VCHASH*2) Λ \ ((value) > > BITS~IN~VCHASH*3) Λ \ ((value) >> BITS IN " VCHASH*4)) \ & ((1 < <BITS_IN_VCHASH)-1)) extern struct vcte *setup_indO, *get_vcteO, *os_get_vcteO; * Internal Data Units PDU types for timeouts. 7 #define IDUJTO 18 #define IDU_MAX_RETRIES 19 #define IDUJNVAUD_PDU 20 /* User VC states */ #define VCS_CLOSED 1 /* closed */ #define VCS_WSR 2 /* setup recv, waiting for upper * layer setup response */ #define VCSJWC 3 /* waiting for connect */ #define VCSJ/VCACK 4 /* waiting for connect ack */ #define VCS ESTAB 5 /* waiting for release */ #define VCSjWRC 6 /* waiting for release complete */ /* * states for signaling VC. 7 #define VCSJNACTIVE 7 /* should never be in this state */ #define VCSJ/VGRC 8 /* waiting global release complete */ #define VCS WAR 9 /* waiting address reponse */ #define VCS_ACTIVE 10 /* signaling connection up */ #define VCSJ-AST VCS_ACTIVE #define VCS TOJVMASK(state) (1< < (state)) #define VCSjDATA IND OK ((1 < < VCS WCACK) + (1< < VCS ESTAB) + (1 < < VCS INACTIVE) + \ (1 < < VCS WGRC) + (1< < VCS WAR) + (1< < VCS_ACTIVE)) # d e f i n e V C S N O T D E A D O R D Y I N G ((1 < < VCS WC) + (1 < < VCSjΞSTAB) + (1< < VCS WCACK) + (1 < < VCS J/VSR)) " #define VCS DEAD OR DYING ((1<<VCS CLOSED) + (1<< VCS WRC)) svc.h -223- /* * upper layer protocol table * * one entry per protocol registered to 'manage' virtual circuits which * carried the indicated org and pid in the setup/connect PDUs. 7 struct ulptab { int ulp_org;/* org negotiated at set up */ int ulpjpid;/* protocol id negotiated at setup */ int (*ulpjmi) 0; /* called when a circuit * state changes */ int (*ulp_data) 0; /* called when a frame is * received */ caddrj ulpjjcb;/* protocol specific control block */ int ulp efcnt; int ulp registered; }; #define NULPS 32 extern struct ulptab ulptab[]; struct ulptab *ulp_registerO, *ulp_find0; 1]; /* * pcif, one per physical channel, used by vc layer. We assume one * atm Ian per port address assigned to theis physical interface. So * pc atmif is used for that purpose. There is a spearate incoming * VCI lookup table, pcjvpcijab, per interface. Ther is also * separate hash chains by peer address and call reference. pc_sig * references the signaling channel. 7 struct pcif { u_char pcjium; /* unit number from i/o system */ u_char pc numjans; /* number of ATM LANs * (atmif's) for this i/f */ uj-hort pcjags; #define PCIF NIU TO NIU 1 svc.h -224- #define PCIF_OTHER_MAC_ADDRJS_HIGHER 2 ujong pc_hw_max_mtu; /* maximum MTU h/w supports */ ujong pcjiwjnax vci; /* upper bound on peer * incoming vci */ ujong pcjietjnax vci; /* upper bound on peer * Incoming vci */ ujong pc_net_max_vcs; /* limit on number of vc's * network will allow */ ujong pc_net_max_qos; /* high qos net supports */ ujong pc_opeak ate; /* outgoing peak rate of link * divided by 1024 */ ujong pcjpeakjate; /* incoming peak rate of link * divided by 1024 */ struct atmif *pc_atmif; /* linked list of atm lans */ u_char *pc last_config; /* last atm Ian config pdu */ u~short pcJast_configJen; /* last atm Ian config * pdu */ u_short pc_num_vcs; /* current number of vctes * allocated */ struct vcte *pcj_ig; /* signaling vc */ struct vcte *pc_raw_vp; /* vc collecting all ATM * cells received */ struct vcte *pc_vcalltab[VCALLTAB_SIZE]; /* vcte's by call ref */ struct vcte *pc_vpeertab[VPEERTAB_SIZE]; /* vcte's by peer addr */ struct vcte *pc ivpci tab[IVPCI TAB SIZE]; }; - _ _ _ struct vcte *svcjindjιext peerO, *svcjjetj.ignaling cteO, *lvcj;reate0; struct vcte *svcjindj-.ref(j, *svcjalloc_vcteO, *svcjind /c(); struct atmjaddr *svcjindjocal_pott0; extern int svc_backoff[], svc_max_retrans[]; extern int SVCJTIS perjick; int svcjadufj; int svcjjduO; vpcij svc_get_ivpciO; struct xdu { struct Imi hdr Imi hdr; }; struct xdu *svc_alloc_pduO ; #define PDU_AUGNED(pdu) ((((int)pdu)&3) = =0) extern int svc_new_ticks[]; char *svc_xdu_type_strO; svc.h -225- extern int svc_pcm; extern int svc_default_qos; extern int hz; extern int atm_nnius[]; /* number of atm lans for each * interface */ struct svc_globs { struct pcif *svc_pcif; struct vcte *vcte_free; struct vcte *vcte_base; struct ulptab *ulptab; int ulpjnuse; struct pcif *svc_pcifn; struct ulptab *sig_ulp; struct svc_parm *svc_parms; int svc_parrris_found; struct svcstat svcstat; char *static_buf; }; struct pcif *svcjnd_port0; #ifndef RT68K extern struct svcjjlobs svcjjlobs; #define svc_glob (&svc jjlobs) #else #define svc_glob svcjjetjjjlobO struct svc_globs *svc get_globO; #endif #endif /* NIU 3VC_H */ svc pdu.c -226- /* svc_pdu.c * COPYRIGHT 1992 ADAPTIVE CORPORATION * ALL RIGHTS RESERVED /* static char sccsid[] = "%A%"; #if Idefined(CERNEL) && defined(RT68K) #define ERRLOG printdbg #define printf printdbg #endif #include "atm.h" #include "svch" #include "unipdu.h" #include "debug.h" #include "svcjjtl.h" #include "if_atm.h" /* debugging and tracing stuff */ #define TL1 1 #define TL2 svcjrace > 1 #define TL3 svcjrace > 2 #define TL4 svcjrace > 3 #define TL5 svcjrace > 4 /* * allocate a generic pdu, given call reference and type. 7 struct xdu * svcjalloc pdu no vpflype, ctype, cvalue) { " " struct xdu *pdu; if (pdu = (struct xdu *) atm allocjnsgO) { pdu->lmi_proto = LMi_PROTOCOL; pdu->lmi_pdu_type = type; pdu->lmi_cref ype = ctype; pdu->lmi cref value = cvalue; } ~ " return pdu; } /* * allocate a generic pdu for a vp 7 struct xdu * svcjalloc _pdu(type, vp) svc j du.c -227- int type; struct vcte *vp; { int direction; If (vp 1= vp->vcte pcif->pc sig) { direction = (type < = LMI_PDU_LAST ? LMI_CREFDIRECTION_MASK : 0); return svc_alloc_pdu_no_vp(type, vp->vcte_cref_type Λ direction, vp- > vcte_cref_val ue) ; 1 plop return svc_alloc_pdu_no_vp(type, LMI_GLOBAL_CREF_TYPE, LMI_GLOBAL_CREF_VALUE); } /* * allocate a release pdu for the specified VC. 7 struct release * svc_alloc_release(vp, type, len) struct vcte *vp; int *len; { struct release *pdu; ASSERT(VAUD_VP(vp)) ; if ((pdu = (struct release *) svc_alloc_pdu(type, vp)) = = 0) return pdu; LMIj3ET_ELEMENT(&pdu->lmi_cause, LMI_RELEASE_CAUSE, vp->vcte_cause); if (vp-> vctejjserjnfo) { struct Imi iinfo *ui; ui = (struct Imi iinfo *) ((caddr t) pdu + sizeof (*pdu)); ui->af ype = LMIJJSERJNFO; ui->afjen = vp->vcte_userJnfoJen; atm_bcopy(vp-> vctejjserjnfo, ui->af_value, vp->vcte userjnfojen); *len = sizeof (*pdu) + ((sizeof (*ui) - sizeof(ui->af_valueJ + ui->af_len + 3) / 4) * 4; } else *len = sizeof (*pdu); return pdu; } vpcij in, out; struct setup *pdu, *beg; char *gcp; /* a pointer for the greenhouse svc pdu.c -228- * compiler */ if (I (pdu = (struct setup *) svc_alloc_pdu(type, vp))) return 0; beg = pdu; ASSERT(pdu->lmi_pdu_type = = type); pdu->lmi_ncalls = 1 ; svc fill ports(vp, pdu); if (type = = LMI_PDU_SETUP 1 1 type = = LMI_PDU_CONNECT) { in = vp->vcte_ivpci; out = vp->vcte ovpci; } else if (type = = SDU_SETUPJND 1 1 type = = SDU_SETUP_CONF) { out = vp->vcte_ivpci; in = vp->vcte ovpci; } gcp = ((caddr t) pdu) + sizeof (*pdu); if (out) LMI ADD ELEMENT(gcp, LMIjDVPCI, out); if (in) LMI -.DD_ELEMENT(gcp, LMIJVPCI, in); if (vp->vcte_qos ! = svc_defaultj-jos) { LMI_ADD_ELEMENT(gcp, LMIJQOSj3ERVICE_CLASS, vp->vcte_qos); LMI ADD ELEMENT(gcp, LMI_OQOSj3ERVICE_CLASS, vp->vcte_qos); } LMI_ADD_ELEMENT(gcp, LMI OQOS_PEAK_BW, vp->vctej_peak ate); LMI_ADD_ELEMENT(gcp, LMf IQOS_PEAK_BW, vp->vcte_pcif-> pcjpeakjate); if (vp->vcte_userJnfo) { struct Imijiinfo *ui; ui = (struct Imijiinfo *) gcp; ui->afjype = LMIJJSERJNFO; ui->afjen = vp->vcte_userJnfoJen; atm_bcopy(vp-> vctejjserjnfo, ui->af_value, vp->vctejjser infojen); gcp + = ((ui->af len + 5) / 4) * 4; } if (type = = LMI_PDUj3ETUP) { ((struct Imijjlp *) gcp)->af_type = LMIJJLP; ((struct lmi_ulp *) gcp)->af_aal = vp->vcte_aal; ((struct lmi_ulp *) gcp)->af_pid = vp->vcte_pid; ((struct Imijilp *) gcp)->afj)rg = vp->vcte_org; gcp + = sizeof (struct Imi ulp); } *length = gcp - (caddrj) beg; return beg; } /* * send a release 7 svc_sendjelease pdu(pc, pdu, len) struct pcif *pc; svc pdu.c 529- struct release *pdu; int len; { struct release *pduO; if (len < sizeof *pdu) { pduO = (struct release *) atm_alloc_msgO; if flpduO) { atm _f ree_msg (pdu) ; return; } *pduO = *pdu; atm Jreejnsg(pdu) ; pdu = pduO; } pdu->lmi_cref_type Λ = LMI_CREFDIRECTION_MASK; pdu->lmi pdu type = LMI PDU RELEASE; LMI_SET_ELEMENT(&pdu->lmi_ " cause, LMI_RELEASE_CAUSE, INVAUD_CALL_REF); aalj_endjnsg(pc->pc_sig, 0, pdu, sizeof (*pdu)); return 0; } /* * send a release and initiate local release if appropriate 7 svc_reject_pdu(pc, pdu, len, vp) struct pcif *pc; struct release *pdu; int len; struct vcte *vp; { struct atmif *atp; if Ovp) { pdu->lmi_pdu_type = LMI_PDU_RELEASE; ASSERT(pdu->lmi_cause.afJype = = LMI_RELEASE_CAUSE); aalj.end_msg(pc->pc_sig, 0, pdu, sizeof (*pdu)); return 0; } else if (vp->vcte_state < VCSJWRC) { #ifndef lint int dummy; LMI_GET_ELEMENT(&pdu->lmi_cause, vp->vcte_cause, dummy); #endif } atm_deletejan(atp) ; svc pdu.c -230- } atm Jree_msg(pdu) ; return 0; } struct setup *svc_alloc_setup_xduO; svcj.end_setup(vp) sfruct vcte *vp; { int len; struct setup *pdu; ASSERT(VALID_VP(vp)); if (pdu = svc_alloc_setup_xdu(vp, LMI PDU_SETUP, &len)) aal_send_msg(vp->vcte pcff->pc sig, 0, pdu, len); } svc jjend jsetup Jnd (vp) struct vcte *vp; { int len; struct setup *pdu; ASSERT(VAUD_VP(vp)); if (pdu = svcjallocj.etup_xdu(vp, SDU_SETUP_IND, &len)) (*vp->vcte ulp->ulp Imi) (vp, pdu, len); } svcj.endj.etupj;onf(vp) struct vcte *vp; { int len; struct setup *pdu; ASSERT(VALID_VP(vp)); if (pdu = svc_alloc_setup_xdu(vp, SDU_SETUP_CONF, &len)) (*vp->vcte ulp->ulp_lmi) (vp, pdu, len); } svc_send_setup_comp(vp) struct vcte *vp; { struct xdu *pdu; ASSERT(VAUD_VP(vp)); if (pdu = (struct xdu *) svc_alloc_pdu(SDU SETUP_COMP, vp)) (*vp->vcte_ulp->ulpjmi)~(vp, pdu, sizeof(*pdu)); return; } svc pdu.c -231- svc_send_connect(vp) struct vcte *vp; { struct setup *pdu; int len; ASSERT(VAUD_VP(vp)); if (pdu = svc_alloc_setup_xdu(vp, LMI_PDU_CONNECT, &len)) aal_send_msg(vp->vcte_pcif->pc_slg, 0, pdu, len); } svc_send_cack(vp) struct vcte *vp; { struct connect jack *pdu; ASSERT(VAUD_VP(vp)); if (pdu = (struct connectjack *) svcjalloc pdu(LMI_PDU_CONNECT_ACK, vp)) aal_send_msg(vp->vcte_pcif->pc_sig, 0, pdu, sizeof (*pdu)); } svc_sendj-eleasej-.omp(vp) struct vcte *vp; { struct release comp *pdu; ASSERT(VAUD_VP(vp)); if (pdu = (struct release_comp *) svc_allocj lu(LMI_PDU_RELEASE_COMP, vp)) aal_send msg(vp->vcte pcif->pc_sig, 0, pdu, size " of(*pdu)); } svcj.end_release(vp) struct vcte *vp; { struct release *pdu; int len; ASSERT(VAUD_VP(vp)) ; if (pdu = svcjalloc_release(vp, LMI_PDU_RELEASE, &len)) aal_send msg(vp->vcte pcif->pc_sig, 0, pdu, len); } svc_send_release Jnd (vp) struct vcte *vp; { int len; #if O struct release *pdu; ASSERT(VAUD_VP(vp)); if (pdu = svcjalloc elease(vp, SDU_RELEASE_IND, &len)) (*vp->vcte_ulp->ulpjmi) (vp, pdu, len); #else struct setup *pdu; ■370 svc_pdu.c -232- caddrj cp; ASSERT(VAUD_VP(vp)); if (pdu = (struct setup *) svc_alloc_pdu(SDU_RELEASE_IND, vp)) { svc_fill_ports(vp, pdu); cp = (caddr t) & pdu[1]; LMI_ADD_ELEMENT(cp, LMI_RELEASE_CAUSE, vp->vcte_cause); len = cp " (caddr ) pdu; (*vp->vcte ulp->ulp Imi) (vp, pdu, len); } #endif } svc_fill_ports(vp, pdu) struct vcte *vp; struct setup *pdu; { if (vp->vcte cref_type & LMI_CREFDIRECTION_MASK) { pdu->lmfcaller = vp->vcteJocal; /* we initiated setup */ pdu->lmi_callee = vp->vcte_peer; } else { pdu->lmi_cailee = vp->vcteJocal; /* peer initiated setup */ pdu->lmi~caller = vp->vcte peer; } } svc utl.c -233- /* svcutl.c * COPYRIGHT 1992 ADAPTIVE CORPORATION * ALL RIGHTS RESERVED 7 / ** * This file contains svc utility and pdu parsing routines. * 7 static char sccsid[] - "%A%"; #if Idefined(CERNEL) && defined (RT68K) #define ERRLOG printdbg #define printf printdbg #endif #ifdef notdef #include "all.h" #include "ip_errs.h" #include "unsp.h" #endif /* notdef */ #include "atm.h" #include "svch" #include "unipdu.h" #include "debug.h" #include "trace.h" #include "svcjjtl.h" extern int svcjrace; #define TL2 svcjrace >1 char *svc_xdu_names[] = {"unknown", "setup", "connect", "connectjack", /* 4 */ "status_enquiry", "status esponse", "release", "releasej-omplete", /* 8 */ "setup _request", "setup jesponse", "release jequest", "status_request", /* 12 */ "releasejndication", "setup_complete", "setup_confirm", "known_sdu", /* 16 */ "setup indication", "statusjesponse", "timeout", "max retries", /* 20 */ "invalud pdu"}; char * svc_xd u_type_str(type) u int type; { if (type < IDUJNVAUD_PDU) return svc_xdujιames[type]; AfJb svcj tl.c -234- else return svc xdu names[0]; } char * svc_pdu_type_str(type) ujnt type; { if (type < LMI_PDU_LAST) return svc_xdu_names[type]; else return svc xdu names[0]; } svc_valid_sdu_type(type) if (type < SDU_SETUP_REQ 1 1 type > SDU_STATUS_RESP 1 1 type = = 15 /* I */ ) return 0; return 1 ; } svc valid pdu typeflype) { if (type < LMI_PDU_SETUP 1 1 type > LMI_PDU_LAST) return 0; return 1 ; } char * svc_e164jιtoa(adr) struct atm addr *adr; { u_char *cp = (u_char *) adr; sprintf(svc_glob-> static J-uf, "%x:%x:%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); return svc glob-> static buf; } /* * parse pdu returns the event cooresponding to the pdu type. In * addition global flags are set to reference the parameters In the * pdu. If there is any problem with the PDU this routine should * catch it. This just checks static pdu validity for protocol * violations. A zero return indicates the pdu does not violate any * encoding rules. Caller and callee addresses are checked as they * are considered static. The vci's are not checked as they are * subject to pdu specific negoiation. a.7*. svcj tl.c -235- 7 /* Following was moved to svc.h to give other files access to it */ #ifndef notdef #define CONjΞLEMS ((1 < <LMI_IVPCI) + (1 < <LMI_OVPCI)+(1 < <LMI_USERJNFO) + (1 < <LM_IQOS_PEA (1 < <LMI_OQOS_PEAK_BW) + (1 < <LMI_IQOS_SERVICE_CLASS) + (1 < <LMI_OQOS_SERVICE_CLA #endif /* NOT notdef */ int setup_validj3lems = -1 /* CON ELEMS +(1 < < LMI ULP) */ ; int connect valid elems = -1 /* CON ELEMS */ ; int release_valid_elems = (1 < < LMI_ " RELEASE_CAUSE) + (1 < < LMIJJSERJNFO); int no_valid_elems = 0; int valid esponse elems[LMI_STATUS_NTYPES] = /* indexed by status type */ { (1 < < LMI_CONFIG_ENQ) | (1 < < LMI_CONFIG_RESP) | (1 < < LMI_PORT_ADDR), 0, 0, 0, 0, 0}; int valid j_nquiry_eiems[LMI_STATUS_NTYPES] = /* indexed by status type */ { (1 < < LMI_CONFIG_ENQ), 0, 0, (1 < < LMI_VC_STATUS), 0, 0}; svcj arse u(pc, pdu, len) struct pcif *pc; struct xdu *pdu; int len; { int reason; reason = svc_parse_xdujeal(pc, pdu, len); if (reason) { TR1 (TL2, "svcj3arse_xdu0 ->%d\n", reason); svc tracej du(pdu, len, 1, pc->pc sig->vcte ivpci); } return reason; } svcj3arse_xdu_real(pc, pdu, len) struct pcif *pc; struct xdu *pdu; int len; { int reason = 0; struct port_addr_elem *pae; int j; int swap_pdu; #ifdef little_endian if (pdu->lmi_pdu ype < = LMI_PDU_LAST) { OS REVERSE32(pdu->lmi cref value); SVC Utl.C -23-5- swap_pdu = 1; } else #endif swap_pdu = 0; ASSERT(PDU_AUGNED(pdu)); /* validate call reference if not sdu setup request */ if ((pdu->lmi cref type & LMI CREFTYPE " MASK) != LMI CREFTYPE_SVC && (pdu- >lmf cref ype & LMf CREFTYPEjMASK) != I_MΓCREFTYPE_PVC && (pdu->lmi pdu type != SDTJ_SETUP_REQ)) return INVAUD_ " CALL_REF; /* * reverse caller/callee for multicast when stations are back * to back 7 if (pc->pcjags & PCIFjNIU TOj IU) { if ((pdu->lmi_pdujype = = LMI_PDU_CONNECT && ((struct setup *) pdu)->lmi_caller.aa_type •= •= AATjΛAC)) svcJixup_mcast_connect(pc, pdu); else if (pdu->lmi_pdu_type = = LMI_PDU_SETUP && ((struct setup *) pdu)->lmi_callee.aa_type = = AAT_MAC) svc fixup mcast setup(pc, pdu); } " " switch (pdu->lmi_pdu ype) { case LMI_PDU 3E=TUP: case SDU_SEΞTUP_RESP: if (!svc_validjDeerj30rt(&((struct setup *) pdu)->lmi_caller)) return INVAUD SRC ADDR; if (((struct setup *] pdu7->lmijιcalls != 1) return INVAUD_MSG ELEMENT; reason = svc_set _pts caddr ) pdu + sizeof(struct setup), len - sizeof (struct setup), pdu->lmi_pdujype = = LMI_PDU_SETUP ? setup valid_elems : connect alidj3lems, swap_pdu); if (pdu->lmi_pdu_type = = LMI_PDU_SETUP && !svc_find_parsed_ulpO) return ULP_UNAVAILABLE; break; case SDU SETUP REQ: case LMI_PDU_C<5NNECT: if (!svc_valid_peer_port(&((struct setup *) pdu)->lmi_callee)) return INVAUD SRC ADDR; if (((struct setup *] pdu7->lmi_ncalls != 1) return INVAUD_MSG ELEMENT; reason = svc_set_opts caddr ) pdu + sizeof (struct setup), ien - sizeof (struct setup), pdu->lmi_pdu_type = = SDU_SETUP_REQ ? S.7S svc utl.c -237- setup_valid elems : connect_valid_elems, swap pdu); If (pdu->lmi " pdu type = = LMI PDU CONNECT&& I (SVC PAP7SEDTLMI IVPCI) &£ SVC_PARSED(LMI OVPCI))) return ELEMENT_MISSING; break; case SDU STATUS_REQ: case LMI_PDU STATUS_ENQ: if (pdu->lmi " status_type > = LMI_STATUS_NTYPES) return UNKNOWN_MSG; reason = svc_set_opts((caddr t) pdu + sizeof (struct xdu), len - sizeof (struct xdϋj, valid enquiry elems[pdu->lmi_status type - LMI_STATUS_CONFIG], swap_pdu); if (pdu->lmi status type = = LMI_STATUS_CC5NFIG) { if (ISVC_PARSED(LMI_CONFIG_ENQ)) return ELEMENT_MISSING; if (((struct config elem *) SVC_GET(LMI_CONFIG_ENQ))->af_version 1= LMI 7ERSI0N) { svc eport version conflictO; return LMI " VERSION CONFLICT; } } brθsK * case LMI_PDU STATUS RESP: if (pdu- > Imi jstatus Jype > = LMI_STATUS_NTYPES) return UNKNOWN ΛSG; if (reason == svc_set .pts((caddr_t) pdu + sizeof (struct xdu), len - sizeof (struct xdu), valid_response_elems[pdu->lmi_status ype - LMI_STATUS_CONFIG], swap_pdu)) { svc_b (pdu, reason); break; } switch (pdu- > Imi status type) { case LMI STATUS_CONFIG: if (!SV( _PARSED(LMI CONFIG ENQ) 1 1 !SVC_PARSED(LMI CONFIGJ.ESP)) return ELEMENT MISSING; if (((struct config elem *) SVC_GET(LMI_CONFIG_RESP))->af_version != LMIJ/ERSION) { svc_report_versionj-.onfiictO; return LMI VERSION CONFUCT; } if (SVC PARSED(LMI PORT ADDR)) { /* " " * port addr elements must be * contiguous 7 pae = (struct pott_addr_elem *) SVC_GET(LMI_PORT_ADDR); for (j = 0; j < svc_glob->svc_parms[LMI_PORT_ADDR].par_ndups; j+ +, pae+ +) svc tl.c -238- if (pae[1].af ype != LMI_PORT_ADDR) return INVAUD MSGjΞLEMENT; } brβsk * case LMI STATUS VC: If (ISVC PARSED(LMI VC STATUS)) return~ELEMENT_MTSSING; break; default: reason = UNKNOWN MSG; } brøsk* case LMI_PDU_CONNECT_ACK: case LMI_PDU_RELEASE_COMP: reason = svc_setjapts ((caddr t) pdu + sizeof(struct xdu), len - sizeof (struct xdϋj, no_valid_elems, swap_pdu); brssk* case SDU RELEASE REQ: case LMI_PDU_RELEASE: reason = svc _etjopts((caddr t) pdu + sizeof(struct xdu), len - sizeof(struct xdu7, release alidj-lems, swapjodu); break; default: ASSERT(0); /* should not get here */ return UNKNOWN MSG; } return reason; } /* * This routine fixes up multicast setup/connect when back to back * nius are signaling to that we go throught the promiscuous mode * setup logic. The callee (multicast) is moved to the caller. A * local port address for the interface is copied into the callee * address. The lanid from the last byte is copied. 7 svcjixup_mcast_setup(pc, pdu) struct pcif *pc; struct setup *pdu; { int Ian; struct atmif *atp; Ian = pdu->lmi caller.aajannum; pdu->lmi_caller = pdu->lmij_-allee; for (atp = pc->pc_atmif; atp; atp = atp->ati_next) { 3.77 SVC_Utl.C •239- if (atp->atij_ort.aaJannum = = Ian) { pdu->lmi_callee = atp->ati_port; pdu->lmij_allee.aa_lannum = Ian; return; } } /* else we will fail later as no * local port addresses are defined */ } /* * peer is sending a connect back (we are back-to-back) with his port * adr as the callee and the mcast adr as the caller, we need to put * our port adr as the caller and the mcast as the callee. 7 svcjixupjπcast κ.nnect(pc, pdu) struct pcif *pc; struct setup *pdu; { int Ian; struct atmif *atp; Ian = pdu->lmi_callee.aajannum; pdu->lmi_callee = pdu->lmi_caller; for (atp = pc->pc_atmif; atp; atp = atp->ati_next) { if (atp->atij ort.aaJannum = = Ian) { pdu->lmi_caller = atp->atij30rt; pdu->lmi_caller.aajannum = Ian; return; } } /* else we will fail later as no * local port addresses are defined */ } svc_validj3eerj3ort(port) struct atmjaddr *port; { if (port- >aa ype = = AAT_MAC) /* if MAC addr then must be multicast */ return port->aa_byte[ATM FIRST MAC] & 0x1 ; else if (port->aa_type ! = AAT PORT) return 0; /* not mac, not port, then invalid */ return 1 ; /* not very selective */ } /* * If there was a source ulp then return ulptab entry for it (if * found) otherwise return ulptab entry for LMIJJLP. LMI_SRC_ULP * only appears in SDU_SETUP_REQ SDUs. When parsing them we want to * verify that there is a SDU handler for this curcuit. LMI_SRC_ULP * allows different ULPs on each end of a connection. 4 ? svcjjtl.c -240- 7 struct ulptab * svcjind parsed ulpO { if (SVC_PARSED(LMI_ULP)) return ulp_find(((struct Imi ulp *) svc_glob->svc parms[LMI_ULP].par_ptr)->af pid, ((struct Imi jlp *) svc~glob->svc_parms[LMl_ULP].par_ptr)->af_org); else return 0; } struct svc_parm svc_parms[LMI_LASTjΞLEMENT + 1] = { {"no_element", 0, 0}, {"relase_cause", 4, 0}, {"ivpci", 4, 0}, {"ovpci", 4, 0}, {"iqos_peak_bw", 4, 0}, {"iqos_ave_bw", 4, 0}, {"iqos_peak_dur", 4, 0}, {"iqos -riority", 4, 0}, {"oqos_peak_bw", 4, 0}, {"oqosjave bw", 4, 0}, {"oqosjDeak -ur", 4, 0}, {"oqos_proTrity", 4, 0}, {"ulp", sizeof(struct Imijjlp), LMI_PAR_REFERENCE}, {"userjnfo", 4, LMI_PAR_REFERENCE}, {"config_enq", sizeof(struct configjalem), LMI PAR_REFERENCE}, {"portjaddress", sizeof(struct port_addr elemj LMI_PAR_REFERENCE}, {"config resp", sizeof(struct config eleπϋ), LMI PAR REFERENCE}, fdestjϊfp", sizeof(struct lml_ulp), CMI_PAR_REFERENCE}, {"vc_status", 4, 0}, }; int svc_parms_size = sizeof (svc_parms); /* * svc_set .ptsO extracts optional paramaters from xdu's and places * them in the svcj arms structure. The values in svcj arms are only * valid until svcjjetjoptsO is called again or the buffer being * parsed is modified or freed. svc_swap_optsO performs byte swap * operations on fields of the pdu which are not accessed via * add/get/set element macroes. Those macroes perform the byte * swapping as the pdus are built / parsed. svc_swap_pdu is called * immediately after a signaling pdu is received and just prior to * transmission, atmjaddr structures are always kept in network * order so no swapping is required. atmarpmhashO is the only * routine which mucks about with atm addr structures and it takes * responsibility for getting the bytes right. Only PDUs are swapped * from network order to host order. 7 svc_set_opts(cp, left, valid_elems, swap_pdu) u_char *cp; { ^7 SVC Utl.C -241- int i; struct svc_parm *par; u_char *ep = cp + left; svc_glob->svc_parms_found = 0; if (swapj du) svc swap_opts(cp, left); while Xcp < ep) { if (*cp > LMI_LAST_ELEMENT 1 1 (valid_elems & (1 < < *cp)) = = 0) return INVAUD_MSG_ELEMENT; par = &svc_glob->svc parms[*cp]; if (left < par->par_size return INVAUD_MSG_ELEMENT; if (svc_glob->svc_parms_found & (1 < < *cp)) { /* dup, just count and skip */ if (+ +par->par ndups < = par->par_max_dups) return INVAUD_MSG_ELEMENT; } else { svc_glob->svc_parms_found | = (1 < < *cp); par->par ndups = 0; if (par-> par Jags & LMI_PAR_REFERENCE) par->par_ptr - (caddrj) cp; else LMI GET ELEMENT(cp, par- > par value, i); } " " if (*cp = = LMI_USER_INFO) { i = cp[1]; if fl > LMI MAX UINFO 1 1 cp + i > ep) return INVAUDjVISG ELEMENT; cp + = ((2 + i + 3) / 4j " * 4; } else cp + = par- > par size; } return 0; } /* * svc swap optsO - this routine swaps all non lmi_parm elements. * 7. svc_swap_opts(cp, left) u_char *cp; int left; { int i, type; struct svc_parm *par; u_char *ep = cp + left; while (cp < ep) { SVC_Utl.C -242- /* if af type is invalid */ if (*cp > LMI LASTJΞLEMENT) return INVAUD_MSG_ELEMENT; par = &svc_glob->svc parms[*cp]; /* get parm table " * pointer for this type */ if (left < par->par_size) G_RESP) { ; } return 0; char * svc cause to str(cause) { switch (cause) { case UASSIGNED SRC ADDR:return "UASSIGNED SRC ADDR" case UASSIGNED j5ST \DDR: return "UASSIGNED DST ADDR"; case NO )ESTINATIO~N ROUTE: return "NO_DESTINATTθN ROUTE"; case VCIJJNACCEPTABLE: return "VCI UNACCEPTABLE"; 221 SVCJ tl.C -243- case NORMAL_RELEASE: return "NORMAL RELEASE"; case NO_ANSWER_FROM_USER: return "NO ANSWER FROMJJSER"; case VC IDLE: return 's VC IDLE"; case VC_REDUNDANT: return "VC REDUNDANT"; case NO_VCT AVAIL: return "NO /CI AVAIL"; case NETWORK DNAVAIL: return "NETWϋRKJJNAVAIL"; case TEMPORARY_FAILURE: return TEMPORARY_FAILURE"; case NO_RESOURCES: return "NO_RESOURCES"; case QOS UNAVAILABLE: return "QOS UNAVAILABLE"; case ULPJ NAVAILABLE: return "ULP_UNAVAILABLE"; case INVAUD_CALL_REF: return "INVALID_CALL_REF"; case INVAUD SRC ADDR: return "INVAUD δRC ADDR"; case INVALID_DST_ADDR: return "INVAUD DST_ADDR"; case INVALID_MS " G_ELEMENT: return "INVAUD_MSG ELEMENT"; case ELEMENT_MISSING: return "ELEMENT_MISSING"; case INVAUDJ3TATE: return "INVALID STATE"; case INVALIDjSlSVCI: return "INVALID SIGVCI"; case UNKNOWN ΛSG: return "UNKNOWN_MSG"; case UNSUPPORTED SERVICE: return "UNSUPPORTED SERVICE"; case PROTOCOL ERR: return "PROTOCOLjΞRR"; case NETWORK TIMEOUT: return "NETWORK TIMEOUT"; case LMI VERSION CONFUCT: return "LMI_VERSION_CONFUCT"; default: return "unknown cause"; } SVC utl.c -244- /* * svcjog new stateO maintains a circular buffer of VC state * information. The cause, time, call reference, port or card, * caller/callee addresses are logged. Logging may be disabled by * setiing svc rlog to zero. 7 int svc log_enabled = 1; void svc_logjιew_state(vp, new_state) struct vcte *vp; { register struct svcjog *s; If (!svcJog_enabled) return; s = (struct svc rlog *) tr get entry(sizeof *s); if As) return; s->thdr.subsystem = SVC_STATE_LOG; s->thdr.sss = vp->vcte pcif->pc_num; s->thdr.length = sizeof(*s); s->newjjtate = new_state; s-> timeouts = vp->vcteJimeouts; s->oldj>tate = vp->vctej_tate; s->cref_type = vp-> vcte jjref Jype; s->cref_value = vp->vcte_cref_value; s-> cause = vp->vctej^use; s->caller = vp->vcteJocal; s-> callee = vp->vctej eer; s->ipackets = vp-> vctejpackets; s->opackets = vp->vcte_opackets; atm j>ettime(s- > time) ; return; } #ifdef Iittlej3ndian svc_swapjκJu(pdu, len) struct xdu *pdu; int len; { int reason = 0; struct portjaddr elem *pae; int j; /* * All pdus have an Imijidr. The only thing In the header * that must be swapped is the ujong lmi_cref_value. Do it * now. 483 SVCJ tl. -245- 7 OS_REVERSE32(pdu->lmi_cref_value); /* * I think that I only need to convert LMI pdus vs SDU pdus. * I believe that SDU pdus are generated locally or are * modified versions of allready converted LMI pdus. 7 switch (pdu->lmi_pdu type) { case LMI PDU SETUP: /* " " * The setup pdu has an lmi_hdr (already swapped * above), two atmjaddr (already in correct byte * order because they are written via byte accesses * and possible optional imi parms * — 7 case LMI PDU CONNECT: /* * NOTE Imijvci and lmi_ovci are acctually treated * just like ImijDarms. Therefore swapped via * LMI_GET_ELEM and LMI_SET_ELEM. So ... just skip * over a setup size struct to get to "additonal" * opts. 7 svc_swapj-ιpts((caddrj) pdu + sizeof(struct setup), len - sizeof (struct setup)); break; case LMI_PDU_STATUS_ENQ: case LMI_PDU STATUS RESP: case LMI_PDU~CONNECT_ACK: case LMI_PDU_RELEASE_COMP: case LMI_PDU_RELEASE: /* status enq is just an Imijidr addtional opts */ svc_swap_opts((caddrj) pdu + sizeof(struct xdu), len - sizeof (struct xdu)); break; default: break; } return; } #endif /* little endian */ vlm.c -246- /* vlm.c * * COPYRIGHT 1992 ADAPTIVE CORPORATION * ALL RIGHTS RESERVED */ * Description: * < Description of the general category of file contents > * Routines: * <An OPTIONAL list summarizing the routines in this file> *******************************C #ifdef UNIX #include <signal.h> frapO { print my tcbO; } " " main(argc, argv) int argc; char *argv[]; { Envlnit(argc, argv); OpenComm(MHW_GetSlotldO, GetGenericO); signal(SIGUSR1, frap); Im mainO; } AAL_SAP CreateO { return (1); } AAL_DataSendNR(key, data, len, prefix, atmjidr) int *key; short *data; int len; int prefix; int *atm hdr; { return (1); } #endif

Claims: -ΦS- CLAIMS 1. A communication system comprising, an ATM network having a plurality of ports, each port having a unique port address, and said ATM network including one or more ATM switches for con¬ necting sending ports to receiving ports, a plurality of stations, each station having a unique station address distinguishing the station from other stations, each station connected to the ATM network at a port whereby source stations commu¬ nicate with destination stations, each station including, packet means for providing packets for transferring information, said information including a destination station address for addressing destination stations, packet converter means for converting between packets and cells for transfers between stations, address resolution means for determining a port address corresponding to a destination station ad¬ dress, said address resolution means including multicast means for multicasting the destination station address to a group of said stations, management means for requesting connections through said ATM network connecting sending ports to receiving ports whereby packets are transferred from source stations to destination stations by cell transfers through said ATM network. 2. The system of Claim 1 wherein said ATM network includes means for connecting a sending port to many receiving ports. 3. The system of Claim 1 wherein said management means includes means for transfering configuration parameters between stations and said ATM network. -SB. - 4. The system of Claim 3 wherein said management means includes means for transfering multicast configuration parameters between stations and said ATM network. 5. The system of Claim 1 wherein said management means includes means for transfering unicast configu¬ ration parameters between stations. 6. The system of Claim 1 wherein said multicast means includes, response means for providing the receiving port address for a destination station, reply means for transmitting the receiving port address to the sending port through said ATM network. 7. The system of Claim 6 wherein said reply means includes, means for establishing a port-to-port connection between a destination station at the receiving port and the source station at the sending port. 8. The system of Claim 1 wherein, said multicast means includes, response means for providing the receiv¬ ing port address for a destination station, reply means for establishing a port-to- port connection between the destination station at the receiving port and the source station at the sending port, and said management means including means for trans¬ mitting cells between said source station and said destination station over said port-to-port connection. -wt- 9. The system of Claim 1 wherein said group of stations that receive the multicast destination station address constitute a local network and wherein said ATM network includes, local network management means for controlling the stations that are included within said group of stations that receive the multicast destination station address. 10. The system of Claim 9 wherein said local network management means includes a station table for storing station addresses for indicating the stations that are included within the local network. 11. The system of Claim 10 wherein local network management means includes, means for adding and deleting a station address to said station table for adding and deleting, respectively, stations to and from the local network. 12. The system of Claim 11 wherein each station includes, means for communicating with said local network management means for communicating that the station is included in said local network. 13. The system of Claim 9 wherein said local network management means includes a port table for indicating the ports that are included within the local network. 14. The system of Claim 13 wherein local network management means includes, means for adding and deleting a port address to said port table for adding and deleting, respective- ly, ports to and from the local network. -S2S- 15. A communication system comprising, an ATM network having a plurality of ports, each port having a unique port address and said ATM network including an ATM switch for connecting sending ports to receiving ports, a plurality of stations, each station having a unique station address distinguishing the station from other stations, each station connected to the ATM network at a port whereby source stations commu- nicate with destination stations, each station including, packet means for providing packets for transferring information, said information including a destination station address for addressing destination stations, packet converter means for converting between packets and cells for transfers between stations, means for establishing a plurality of groups of stations, each group constituting a local network of the stations in the group, address resolution means for determining a port address corresponding to a destination station ad¬ dress, said address resolution means including multicast means for multicasting the destination station address from a source station to the local network of stations for the group of stations includ¬ ing the source station, management means for requesting connections through said ATM network to connect sending ports to receiving ports whereby packets are transferred from source stations to destination stations by cell transfers through said ATM network. 16. The system of Claim 15 wherein said ATM network includes means for connecting a sending port to many receiving ports. -A 0 )- 17. The system of Claim 15 wherein said management means includes means for transfering configuration parameters between stations and said ATM network. 18. The system of Claim 17 wherein said management means includes means for transfering multicast configuration parameters between stations and said ATM network. 19. The system of Claim 15 wherein said management means includes means for transfering unicast configu¬ ration parameters between stations. 20. The system of Claim 15 wherein said multicast means includes, response means for providing the receiving port address for a destination station, reply means for transmitting the receiving port address to the sending port through said ATM network. 21. The system of Claim 20 wherein said reply means includes, means for establishing a port-to-port connection between a destination station at the receiving port and the source station at the sending port. 22. The system of Claim 15 wherein, said multicast means includes, response means for providing the receiv- ing port address for a destination station, reply means for establishing a port-to- port connection between the destination station at the receiving port and the source station at the sending port, and said connection means including means for trans¬ mitting cells between said source station and said destination station over said port-to-port -tfo- connection. 23. The system of Claim 15 wherein said ATM network includes, local network management means for controlling the stations that are included within each of said groups of stations that form local networks. 24. The system of Claim 23 wherein said local network management means includes a port table for indicating the ports that are included within the local network. 25. The system of Claim 24 wherein local network management means includes, means for adding and deleting a port address to said port table for adding and deleting, respective¬ ly, ports to and from the local network. 26. The system of Claim 15 wherein said ATM network includes, local network management means for transmitting the port address controlling the stations that are included within each of said groups of stations that form local networks. 27. The system of Claim 26 wherein said local network management means includes station table means for storing station addresses for indicating the stations that are included within each of said local networks. -01- 28. The system of Claim 27 wherein local network management means includes, means for adding and deleting a station address to said station table means and thereby for adding and deleting, respectively, stations to and from the local networks. 29. The system of Claim 28 wherein local network management means includes, means for adding and deleting a station address to said station table means and thereby for adding and deleting, respectively, one or more stations to and from a plurality of said local networks. 30. The system of Claim 29 wherein local network management means includes each of one or more sta¬ tions in two or more local networks. 31. The system of Claim 30 wherein one of said one or more stations is a bridge station connecting said one or more stations to another local network. 32. The system of Claim 30 wherein one of said one or more stations is a router station connecting said one or more stations to another local network. 33. The system of Claim 18 wherein each station includes, means for communicating with said local network management means for communicating the ones of the local networks with which the station is associated. 34. The system of Claim 18 wherein each station has a physical connection to a port of said ATM network and wherein said network management means controls the one or more local networks with which the station is associated independently of the physical connect¬ ion.

Inventors: BURNETTE JOHN LINDSAY, NEWMAN PETER, BURNETTE, JOHN, LINDSAY, NEWMAN, PETER
Applicants: NETWORK EQUIPMENT TECH, NETWORK EQUIPMENT TECHNOLOGIES, INC.
Application year: 1993
Main classification: H04J3
IPC codes: H04L12, H04Q3, H04Q11