From: Paul B. S. <pa...@us...> - 2001-09-03 18:41:08
|
Update of /cvsroot/linux-atm/linux-atm/src/led In directory usw-pr-cvs1:/tmp/cvs-serv10656/led Added Files: Tag: V2_4_0 display.c display.h lec.h address.c address.h zeppelin.8 COPYRIGHT.TUT conn.c conn.h Makefile.am frames.c frames.h join.c join.h main.c frame_defs.h kernel.c kernel.h Log Message: --- NEW FILE: display.c --- /* display.c - display frames, addresses, opcodes, etc. */ /* Copyright (C) 1999 Heikki Vatiainen he...@cs... */ #if HAVE_CONFIG_H #include <config.h> #endif #include <atm.h> #include <atmd.h> #include "display.h" #include "frame_defs.h" #define COMPONENT "display.c" #define MAX_TEXT 1024 /* Buffer size for displaying LE control frames */ static int my_atm2text(unsigned char *atm_addr, char *dest); static const char *lan_dst2text(struct lan_dst *dst); static void display_ready(void *buff); /* Prints out more or less human readable summary of * LE Control Frame pointed by frame. */ void display_frame(void *frame) { struct frame_hdr *hdr; struct ctrl_frame *f; char text[MAX_TEXT]; char *p; hdr = (struct frame_hdr *)frame; if (hdr->opcode == htons(READY_QUERY) || hdr->opcode == htons(READY_IND)) display_ready(frame); p = text; p += sprintf(p, "\n"); p += sprintf(p, "Marker 0x%x\n", ntohs(hdr->marker)); p += sprintf(p, "Protocol 0x%x\n", hdr->protocol); p += sprintf(p, "Version 0x%x\n", hdr->version); p += sprintf(p, "Op-Code 0x%x (%s)\n", ntohs(hdr->opcode), opcode2text(hdr->opcode)); p += sprintf(p, "Status %d (%s)\n", hdr->status, status2text(hdr->status)); p += sprintf(p, "Trans-ID %d\n", ntohl(hdr->tran_id)); p += sprintf(p, "Req Lec-ID %d\n", ntohs(hdr->lec_id)); p += sprintf(p, "Flags 0x%x", ntohs(hdr->flags)); if (hdr->flags & htons(REMOTE_ADDRESS)) p+= sprintf(p, " 'Remote Address'"); if (hdr->flags & htons(V2_CAPABLE)) p+= sprintf(p, " 'V2 Capable'"); if (hdr->flags & htons(V2_REQUIRED)) p+= sprintf(p, " 'V2 Required'"); if (hdr->flags & htons(PROXY_FLAG)) p+= sprintf(p, " 'Proxy Flag'"); if (hdr->flags & htons(TOPO_CHANGE)) p+= sprintf(p, " 'Topology Change'"); p += sprintf(p, "\n"); f = (struct ctrl_frame *)frame; p += sprintf(p, "Source Lan 0x%x (%s)\n", ntohs(f->src_lan_dst.tag), lan_dst2text(&f->src_lan_dst)); p += sprintf(p, "Target Lan 0x%x (%s)\n", ntohs(f->target_lan_dst.tag), lan_dst2text(&f->target_lan_dst)); p += sprintf(p, "Source ATM "); p += my_atm2text(f->src_atm_addr, p); p += sprintf(p, "\n"); p += sprintf(p, "Lan type 0x%x\n", f->lan_type); p += sprintf(p, "Lan MTU 0x%x\n", f->max_frame_size); p += sprintf(p, "# of TLVs 0x%x\n", f->num_tlvs); p += sprintf(p, "Elan Name size 0x%x\n", f->elan_name_size); p += sprintf(p, "Target ATM "); p += my_atm2text(f->target_atm_addr, p); p += sprintf(p, "\n"); p += sprintf(p, "Elan Name ("); memcpy(p, f->elan_name, f->elan_name_size); p += f->elan_name_size; p += sprintf(p, ")\n"); *p = '\0'; diag(COMPONENT, DIAG_DEBUG, "%s\n", text); return; } static void display_ready(void *ready_frame) { diag(COMPONENT, DIAG_DEBUG, "ready frame\n"); return; } /* Poor man's atm2text */ static int my_atm2text(unsigned char *atm_addr, char *dest) { int i, len; len = 0; for (i = 0; i < ATM_ESA_LEN; i++) len += sprintf(dest + len, "%2.2x ", *(atm_addr + i)); return len; } static const char *lan_dst2text(struct lan_dst *dst) { static char text[42]; /* big enough for text + MAC */ char *p = text; switch(ntohs(dst->tag)) { case LAN_DST_NOT_PRESENT: sprintf(text, "Not present"); break; case LAN_DST_MAC_ADDR: p += sprintf(p, "MAC address"); p += sprintf(p, " "); mac2text(p, dst->mac); break; case LAN_DST_ROUTE_DESC: p += sprintf(p, "Route Descriptor"); p += sprintf(p, " "); mac2text(p, dst->mac); break; default: sprintf(text, "<Unknown Lan destination>"); break; } return text; } void mac2text(char *buff, unsigned char *mac_addr) { sprintf(buff, "%02x-%02x-%02x-%02x-%02x-%02x", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); return; } const char *opcode2text(uint16_t opcode) { switch (ntohs(opcode)) { case LE_CONFIG_REQ: return "LE_CONFIG_REQUEST"; break; case LE_CONFIG_RSP: return "LE_CONFIG_RESPONSE"; break; case LE_JOIN_REQ: return "LE_JOIN_REQUEST"; break; case LE_JOIN_RSP: return "LE_JOIN_RESPONSE"; break; case LE_REG_REQ: return "LE_REGISTER_REQUEST"; break; case LE_REG_RSP: return "LE_REGISTER_RESPONSE"; break; case LE_ARP_REQ: return "LE_ARP_REQUEST"; break; case LE_ARP_RSP: return "LE_ARP_RESPONSE"; break; case LE_FLUSH_REQ: return "LE_FLUSH_REQUEST"; break; case LE_FLUSH_RSP: return "LE_FLUSH_RESPONSE"; break; case READY_QUERY: return "READY_QUERY"; break; case READY_IND: return "READY_INDICATION"; break; case LE_TOPO_REQ: return "LE_TOPOLOGY_REQUEST"; break; case LE_NARP_REQ: return "LE_NARP_REQUEST"; break; default: break; } return "<Unknown OP-CODE>"; } const char *tlv2text(uint32_t type) { switch (type) { case MAX_CUM_CTRL_TIMEOUT: return "Max-Cumulative-Control-Time-out"; break; case MAX_UNKNOWN_FRAME_CNT: return "Max-Unknown-Frame-Count"; break; case MAX_UNKNOWN_FRAME_TIME: return "Max-Unknown-Frame-Time"; break; case VCC_TIMEOUT_PERIOD: return "VCC-Timeout-Period"; break; case MAX_RETRY_COUNT: return "Max-Retry-Count"; break; case AGING_TIME: return "Aging-Time"; break; case FORWARD_DELAY_TIME: return "Forward-Delay-Time"; break; case EXPECTED_LE_ARP_TIME: return "Expected-LE_ARP-Response-Time"; break; case FLUSH_TIMEOUT: return "Flush-Time-out"; break; case PATH_SWITCHING_DELAY: return "Path-Switching-Delay"; break; case LOCAL_SEGMENT_ID: return "Local-Segment-ID"; break; case DEF_MCAST_SND_VCC_TYPE: return "Default-Mcast-Send-VCC-Type"; break; case DEF_MCAST_SND_VCC_AVG: return "Default-Mcast-Send-VCC-AvgRate"; break; case DEF_MCAST_SEND_PEAK_RT: return "Default-Mcast-Send-VCC-PeakRate"; break; case CONN_COMPLETION_TIMER: return "Connection-Completion-Timer"; break; case CONFIG_FRAG_INFO: return "Config-Frag-Info"; break; case LAYER3_ADDRESS: return "Layer-3-Address"; break; case ELAN_ID: return "ELAN-ID"; break; case SERVICE_CATEGORY: return "Service-Category"; break; case LLC_MUXED_ATM_ADDR: return "LLC-Muxed-ATM-Address"; break; case X5_ADJUSTMENT: return "X5-Adjustment"; break; case PREFERRED_LES: return "Preferred-LES"; break; case FORE_NAME: return "Fore's LANE client name"; break; default: break; } return "<Unknown TLV type>"; } const char *status2text(uint16_t status) { switch (ntohs(status)) { case 0: return "Success"; break; case 1: return "Version Not Supported"; break; case 2: return "Invalid request parameters"; break; case 4: return "Duplicate LAN Destination registration"; break; case 5: return "Dupliate ATM address"; break; case 6: return "Insufficient resources to grant request"; break; case 7: return "Access denied"; break; case 8: return "Invalid REQUESTOR-ID"; break; case 9: return "Invalid LAN Destination"; break; case 10: return "Invalid ATM Address"; break; case 20: return "No Configuration"; break; case 21: return "LE_CONFIGURE Error"; break; case 22: return "Insufficient Information"; break; case 24: return "TLV Not Found"; break; default: break; } return "<Something not supported in LANEv2>"; } --- NEW FILE: display.h --- /* Copyright (C) 1999 Heikki Vatiainen he...@cs... */ #ifndef DISPLAY_H #define DISPLAY_H void display_frame(void *frame); void mac2text(char *buff, unsigned char *mac_addr); const char *opcode2text(uint16_t opcode); const char *tlv2text(uint32_t type); const char *status2text(uint16_t status); #endif /* DISPLAY_H */ --- NEW FILE: lec.h --- /* Copyright (C) 1999 Heikki Vatiainen he...@cs... */ #ifndef LEC_H #define LEC_H #include "conn.h" /* * LANE client configuration and operation values. * These are in host byte order since there are * some values coming from network and some values * which are used by the host only */ struct lec_params { unsigned char c1n_my_atm_addr[ATM_ESA_LEN]; uint8_t c2_lan_type; uint8_t c3_max_frame_size; int c4_proxy_flag; char c5_elan_name[32 + 1]; char c6_mac_addr[ETH_ALEN]; int c7_ctrl_timeout; int c7i_initial_ctrl_timeout; int c7x_timeout_multiplier; int c7c_current_timeout; /* sum of c7i and c7x, LANEv2 5.3.1.7 */ unsigned char c9_les_atm_addr[ATM_ESA_LEN]; int c10_max_unknown_frames; int c11_max_unknown_frame_time; int c12_vcc_timeout; int c13_max_retry_count; uint16_t c14_lec_id; int c17_aging_time; int c18_forward_delay_time; int c19_topology_change; int c20_le_arp_response_time; int c21_flush_timeout; int c22_path_switching_delay; /* LANE2 variables follow */ int c29_v2_capable; uint32_t c31_elan_id; unsigned char c35_preferred_les[ATM_ESA_LEN]; int c35_contains_address; int c37_min_reconfig_delay; /* milliseconds */ int c38_max_reconfig_delay; /* milliseconds */ /* other stuff */ int itf_num; /* 1 for lec1 and so forth */ int sizeoftlvs; /* total size of TLVs associated with this LEC */ int num_tlvs; /* number of the TLVs */ unsigned char *tlvs; /* the TLVs */ char foreId[255]; /* connections to and from LES/BUS plus listen sockets */ Conn_t *kernel; Conn_t *ctrl_direct; Conn_t *ctrl_listen; /* Closed when join phase is over */ Conn_t *ctrl_dist; Conn_t *mcast_send; /* LANEv2 calls this Default Mcast Send VCC */ Conn_t *mcast_listen; Conn_t *data_listen; }; extern struct lec_params lec_params; #define LAN_TYPE_UNSPEC 0x00 /* Implies Ethernet/IEEE 802.3 */ #define LAN_TYPE_8023 0x01 /* IEEE 802.3 */ #define LAN_TYPE_8025 0x02 /* IEEE 802.5 */ #endif /* LEC_H */ --- NEW FILE: address.c --- /* address.c - functions to query ESI and local ATM address from kernel */ /* * Marko Kiiskila ca...@cs... * * Copyright (c) 1996 * Tampere University of Technology - Telecommunications Laboratory * All rights reserved. * * Permission to use, copy, modify and distribute this * software and its documentation is hereby granted, * provided that both the copyright notice and this * permission notice appear in all copies of the software, * derivative works or modified versions, and any portions * thereof, that both notices appear in supporting * documentation, and that the use of this software is * acknowledged in any publications resulting from using * the software. * * TUT ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION AND DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS * SOFTWARE. * */ /* Copyright (C) 1999 Heikki Vatiainen he...@cs... */ #if HAVE_CONFIG_H #include <config.h> #endif #include <sys/ioctl.h> #include <unistd.h> #include <errno.h> #include <atm.h> #include <linux/atmdev.h> #include <atmd.h> #include "address.h" #define COMPONENT "address.c" /* Gets End System Identifier (MAC address) from kernel * Returns < 0 for error */ int addr_getesi(unsigned char *mac_addr, int phys_itf) { int fd, retval; struct atmif_sioc req; fd = socket(PF_ATMSVC, SOCK_DGRAM, 0); if (fd < 0) { diag(COMPONENT, DIAG_ERROR, "addr_getesi: socket: %s\n", strerror(errno)); return -1; } req.number = phys_itf; req.arg = mac_addr; req.length = ESI_LEN; retval = ioctl(fd, ATM_GETESI, &req); if (retval < 0) diag(COMPONENT, DIAG_ERROR, "ioctl ATM_GETESI: %s\n", strerror(errno)); close(fd); return retval; } /* Gets one of our ATM addresses from kernel. Useful for binding listen sockets. * Returns < 0 for error */ #define MAX_LOCAL_ADDRS 32 int get_listenaddr(unsigned char *atm_addr, int phys_itf) { int fd, retval; struct atmif_sioc req; struct sockaddr_atmsvc listen_addr[MAX_LOCAL_ADDRS]; fd = socket(PF_ATMSVC, SOCK_DGRAM, 0); if (fd < 0) { diag(COMPONENT, DIAG_ERROR, "get_listenaddr: socket: %s\n", strerror(errno)); return -1; } req.number = phys_itf; req.arg = listen_addr; req.length = sizeof(listen_addr); retval = ioctl(fd, ATM_GETADDR, &req); if (retval < 0) diag(COMPONENT, DIAG_ERROR, "ioctl ATM_GETADDR: %s\n", strerror(errno)); close(fd); memcpy(atm_addr, listen_addr[0].sas_addr.prv, ATM_ESA_LEN); return retval; } --- NEW FILE: address.h --- /* * Marko Kiiskila ca...@cs... * * Tampere University of Technology - Telecommunications Laboratory * * Permission to use, copy, modify and distribute this * software and its documentation is hereby granted, * provided that both the copyright notice and this * permission notice appear in all copies of the software, * derivative works or modified versions, and any portions * thereof, that both notices appear in supporting * documentation, and that the use of this software is * acknowledged in any publications resulting from using * the software. * * TUT ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION AND DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS * SOFTWARE. * */ /* Copyright (C) 1999 Heikki Vatiainen he...@cs... */ #ifndef ADDRESS_H #define ADDRESS_H /* Get ESI for the physical ATM interface */ int addr_getesi(unsigned char *mac_addr, int phys_addr); /* Get the ATM address for the physical ATM interface */ int get_listenaddr(unsigned char *atm_addr, int phys_addr); #endif /* ADDRESS_H */ --- NEW FILE: zeppelin.8 --- .TH zeppelin 8 "Nov 29, 1999" "Linux" "Maintenance Commands" .SH NAME zeppelin \- ATM LAN Emulation client demon (LED) Zeppelin .SH SYNOPSIS .B zeppelin .RB [ \-c\ \fILECS_address\fP\ |\ \-s\ \fILES_address\fP ] .RB [ \-e\ \fIesi\fP ] .RB [ \-n\ \fIVLAN_name\fP ] .RB [ \-m\ \fImesg_mask\fP ] .RB [ \-l\ \fIlisten_address\ | \ selector\fP ] .RB [ \-i\ \fIinterface_number\fP ] .RB [ \-I\ \fIphysical_interface_number\fP ] .RB [ \-t\ \fI1516|1580|4544|9234|18190\fP ] .RB [ \-1\ ] .RB [ \-2\ ] .RB [ \-p\ ] .RB [ \-F\ \fIlogfile\fP ] .RB [ \-f\ \fIFore_specific_name\fP ] .SH DESCRIPTION A LAN Emulation Client is an entity in an ATM endstation that performs data forwarding, address resolution and other control functions. It uses the LUNI interface when communicating with other components in emulated LANs. It provides upper protocol layers a MAC like interface similar to IEEE 802.3/Ethernet or IEEE 802.5/Token Ring LAN. .PP LAN Emulation client code is divided into two parts: user space application LAN Emulation Demon called (LED) \fBzeppelin(8)\fP, and the kernel component. \fBZeppelin\fP is responsible for control operations needed in LAN Emulation clienthood. It forms the necessary VCCs and receives all the LE control frames and acts accordingly. It also controls the operation of the LEC kernel component. .PP Linux LEC supports only Ethernet type of emulated LAN. .PP \fBSIGHUP\fP causes restart of the LEC. All resources are released and \fBzeppelin\fP is started. .SH OPTIONS .IP \fB\-c\ \fILECS_address\fP ATM address of \fBlecs(8)\fP (Lan Emulation Configuration Server), if not set, Well-Known server address is used. .IP \fB\-s\ \fILES_address\fP ATM address of \fBles(8)\fP (Lan Emulation Server), can be used in bypassing configuration phase in joining emulated Lan i.e \fBlecs\fP address is not used. .IP \fB\-e\ \fIesi\fP Mac address to use when communicating in Emulated LAN. E.g. 00:20:22:23:04:05 . .IP \fB\-n\ \fIVLAN_name\fP Name of the virtual LAN to which joining is requested. This is used in LE_CONFIGURE_REQUEST to LECS or LE_JOIN_RESPONSE to LES, if configuration phase is bypassed. .IP \fB\-m\ \fImesg_mask\fP Sometimes one wants to know more what is happening in LE daemon e.g. when nothing works. This is a hexadecimal long value setting global message mask. 0 = No messages, ffff = All messages. .IP \fB\-l\ \fIlisten_address\ |\ selector\fP Local ATM address that zeppelin uses as local binding point in signalling. Use this if you are running more than one client or a set of LE servers. The local ATM address can be specified by either giving the full ATM address or the desired selector byte. .IP \fB\-i\ \fIinterface_number\fP Linux LEC supports up to 40+8 network interfaces. The interface_number tells zeppelin to which of these to attach. Ethernet type network interfaces are numbered from "lec0" to "lec39" and Token Ring interfaces are from "lec40" to "lec47". These parameters are tweakable during the kernel compile, see <linux/atmlec.h>. .IP \fB\-I\ \fIphysical_interface_number\fP The physical interface this LANE client should bind to. If your host has multiple ATM network cards, you can use this option to choose which card this zeppelin will use. .IP \fB\-t\ \fIMTU\fP The MTU of ELAN to join. You need to also use \fBifconfig(8)\fP to set the MTU of the LANE interface. .IP \fB\-1\fP Run as LANEv1 client. This is the default. .IP \fB\-2\fP Run as LANEv2 client. This is required by MPOA. .IP \fB\-p\fP Enable proxy. When started with this option, it is possible to bridge packets between ATM and Ethernet. That is, you can use LANE interfaces with normal bridging. See the Bridging mini-Howto for more info. .IP \fB\-F\ \fIlogfile\fP Instead of writing debug messages to \fBstderr\fP, write the messages to the file \fBlogfile\fP. Use \fBsyslog\fP as the file name to use the \fBsyslog(3)\fP facility. .IP \fB\-f\ \fIFore\ specific\ name\fP The LANE servers on Fore ATM switches can display a special name if a client can supply one. This name shows with command \'conf lane les show advanced\'. .SH TOKEN RING CONSIDERATIONS A number of lec interfaces is reserved for Token Ring ELANs when the kernel is compiled with Token Ring (CONFIG_TR) support. See the discussion about interface_number command line option above. The Linux Token Ring LANE client does not support bridging between legacy Token Ring and ATM parts of the ELAN, so using the -p option is not recommended. Token Ring support has received less testing than its Ethernet counterpart. .SH BUGS John Bonham died 1980 and Led Zeppelin broke. .PP Please report any other bugs to Heikki Vatiainen <he...@cs...> .SH AUTHORS Marko Kiiskila, TUT <ca...@cs...> and Heikki Vatiainen, TUT <he...@cs...> .SH "SEE ALSO" lecs(8), mpcd(8), atmsigd(8), les(8), qos(7) .\"{{{}}} --- NEW FILE: COPYRIGHT.TUT --- /* * Marko Kiiskila ca...@cs... * * Tampere University of Technology - Telecommunications Laboratory * * Permission to use, copy, modify and distribute this * software and its documentation is hereby granted, * provided that both the copyright notice and this * permission notice appear in all copies of the software, * derivative works or modified versions, and any portions * thereof, that both notices appear in supporting * documentation, and that the use of this software is * acknowledged in any publications resulting from using * the software. * * TUT ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION AND DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS * SOFTWARE. * */ --- NEW FILE: conn.c --- /* conn.c - functions for handling SVCs, create, accept, send, etc. */ /* * Marko Kiiskila ca...@cs... * * Copyright (c) 1996 * Tampere University of Technology - Telecommunications Laboratory * All rights reserved. * * Permission to use, copy, modify and distribute this * software and its documentation is hereby granted, * provided that both the copyright notice and this * permission notice appear in all copies of the software, * derivative works or modified versions, and any portions * thereof, that both notices appear in supporting * documentation, and that the use of this software is * acknowledged in any publications resulting from using * the software. * * TUT ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION AND DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS * SOFTWARE. * */ /* Copyright (C) 1999 Heikki Vatiainen he...@cs... */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <sys/ioctl.h> #include <atm.h> #include <atmsap.h> #include <linux/atmlec.h> #include <atmd.h> #include "conn.h" #include "display.h" #include "lec.h" #include "frames.h" #include "kernel.h" #define COMPONENT "conn.c" /* status */ #define CONNECTED 42 /* Operational socket */ #define CONNECTING 43 /* Non-blocking socket, not yet connected */ /* type */ #define WEMADE 7 #define THEYMADE 8 #define LISTENING 9 #define KERNEL_SOCK 10 static Conn_t *connlist = NULL; /* Local protos */ static void list_remove_conn(Conn_t *conn); static Conn_t *list_add_conn(unsigned char *dest_atm_addr); static Conn_t *conn_already_exists(unsigned char *atm_addr, Conn_t *current); static const char *get_type_string(int type); static int maxmtu2maxsdu(uint8_t mtu); static uint16_t conn_type2codepoint(int conn_type); static void delete_addr(unsigned char *atm_addr) { struct atmlec_msg msg; msg.type = l_addr_delete; memcpy(msg.content.normal.atm_addr, atm_addr, ATM_ESA_LEN); msg_to_kernel(&msg, sizeof(struct atmlec_msg)); return; } /* Checks if connection to atm_addr already exists. Does not * check against current though. * Returns NULL for no connection, or Conn_t of existing connection. */ static Conn_t *conn_already_exists(unsigned char *atm_addr, Conn_t *current) { Conn_t *conn; conn = connlist; while (conn) { if (conn != current && conn->type != LISTENING && conn->type != KERNEL_SOCK) { if (memcmp(conn->atm_address, atm_addr, ATM_ESA_LEN) == 0) return conn; } conn = conn->next; } return NULL; } /* Initializes and fills in *sap and *qos according to Blli * code point value specified in conn_type. */ void init_conn_params(struct atm_sap *sap, struct atm_qos *qos, uint16_t conn_type) { unsigned int bllicode; int i, sdu; char qos_text[MAX_ATM_QOS_LEN + 1]; diag(COMPONENT, DIAG_DEBUG, "init_conn_params, conn_type %x\n", conn_type); memset(qos, 0, sizeof(struct atm_qos)); memset(sap, 0, sizeof(struct atm_sap)); qos->aal = ATM_AAL5; /* Set the forward and backward Max CPCS-SDU Size */ switch(conn_type) { case CONTROL_CONN: qos->rxtp.max_sdu = 1516; qos->txtp.max_sdu = 1516; break; case DATA_DIRECT_CONN: case MCAST_CONN: sdu = maxmtu2maxsdu(lec_params.c3_max_frame_size); qos->rxtp.max_sdu = sdu; qos->txtp.max_sdu = sdu; break; default: diag(COMPONENT, DIAG_ERROR, "unknown conn_type %x\n", conn_type); break; } /* ATM User Cell Rate/ATM Traffic Descriptor. */ qos->txtp.traffic_class = ATM_UBR; qos->rxtp.traffic_class = ATM_UBR; if (get_verbosity(COMPONENT) >= DIAG_DEBUG) { if (qos2text(qos_text, sizeof(qos_text), qos, 0) < 0) sprintf(qos_text, "<bad qos>"); diag(COMPONENT, DIAG_DEBUG, "init_conn_params, QoS '%s'\n", qos_text); } /* No Broadband High Layer Information in LANE. */ sap->bhli.hl_type = ATM_HL_NONE; /* Broadband Lower Layer Information. */ sap->blli[0].l3_proto = ATM_L3_TR9577; sap->blli[0].l3.tr9577.ipi = NLPID_IEEE802_1_SNAP; sap->blli[0].l3.tr9577.snap[0] = 0x00; sap->blli[0].l3.tr9577.snap[1] = 0xa0; sap->blli[0].l3.tr9577.snap[2] = 0x3e; bllicode = conn_type2codepoint(conn_type); sap->blli[0].l3.tr9577.snap[3] = (unsigned char)(0xff&(bllicode>>8)); sap->blli[0].l3.tr9577.snap[4] = (unsigned char)(0xff&bllicode); if (get_verbosity(COMPONENT) == DIAG_DEBUG) { for(i=0; i < 5; i++) { diag(COMPONENT, DIAG_DEBUG, "snap[%d] = 0x%2.2x", i, sap->blli[0].l3.tr9577.snap[i]); } } return; } /* Returns != 0 if blli indicates Data Direct * connection */ static int is_data_direct(struct atm_blli *blli) { return (blli->l3.tr9577.snap[4] == DATA_DIRECT_8023 || blli->l3.tr9577.snap[4] == DATA_DIRECT_8025); } /* Creates a socket with the specified parameters. * If listen_addr is non NULL binds to it. * Returns < 0 for error or new socket descriptor. */ static int get_socket(struct sockaddr_atmsvc *listen_addr, struct atm_sap *sap, struct atm_qos *qos) { int s, ret; s = socket(PF_ATMSVC, SOCK_DGRAM, 0); if (s < 0) { diag(COMPONENT, DIAG_ERROR, "socket creation failure: %s\n", strerror(errno)); return -1; } diag(COMPONENT, DIAG_DEBUG, "get_socket: got fd %d\n", s); if (setsockopt(s, SOL_ATM, SO_ATMQOS, qos, sizeof(struct atm_qos)) < 0) { diag(COMPONENT, DIAG_ERROR, "get_socket: setsockopt SO_ATMQOS: %s\n", strerror(errno)); close(s); return -1; } if (setsockopt(s, SOL_ATM, SO_ATMSAP, sap, sizeof(struct atm_sap)) < 0) { diag(COMPONENT, DIAG_ERROR, "setup_svc setsockop(SO_ATMSAP)\n"); close(s); return -1; } /* Bind the socket to our local address */ if (listen_addr == NULL) return s; ret = bind(s, (struct sockaddr *)listen_addr, sizeof(struct sockaddr_atmsvc)); if (ret < 0) { diag(COMPONENT, DIAG_ERROR, "bind error: %s\n", strerror(errno)); close(s); return -1; } return s; } /* * You need to check this if setup_svc() returns NULL */ #if 0 if (is_data_direct(&sap->blli[0])) { /* Try to remove possible entry in kernel */ delete_addr(conn->atm_address); } #endif /* Does an active open to dst_addr using pre-filled * parameters in sap and qos. * If listen_addr is non NULL, binds to it. * Data direct SVCs are non-blocking, others block * Returns NULL for error or new connections. */ Conn_t *setup_svc(struct sockaddr_atmsvc *dst_addr, struct sockaddr_atmsvc *listen_addr, struct atm_sap *sap, struct atm_qos *qos) { Conn_t *conn; int s, ret; char buff[MAX_ATM_ADDR_LEN+1]; diag(COMPONENT, DIAG_DEBUG, "Outgoing call setup\n"); /* The code below is commented out due to the following scenario: We have made a connection to another LEC and our address was numerically lower than theirs (LANEv2 8.1.13). The other end has also connected us, but we must not use that VCC. However, if the connection we made gets closed, we can not open it again since a connection to the destination LEC already exists. */ #if 0 /* We don't create connection to an entity where we already have a connection. */ if (conn_already_exists(dst_addr->sas_addr.prv, NULL) && is_data_direct(&sap->blli[0])) return NULL; #endif dst_addr->sas_family = AF_ATMSVC; listen_addr->sas_family = AF_ATMSVC; switch(sap->blli[0].l3.tr9577.snap[4]) { /* Kludge. Eh? */ case CONTROL_CONN: diag(COMPONENT, DIAG_DEBUG, "LE Control SVC setup\n"); break; case DATA_DIRECT_8023: diag(COMPONENT, DIAG_DEBUG, "Data direct 802.3\n"); break; case DATA_DIRECT_8025: diag(COMPONENT, DIAG_DEBUG, "Data direct 802.5\n"); break; case MCAST_CONN_8023: diag(COMPONENT, DIAG_DEBUG, "Multicast 802.3\n"); break; case MCAST_CONN_8025: diag(COMPONENT, DIAG_DEBUG, "Multicast 802.5\n"); break; default: diag(COMPONENT, DIAG_ERROR, "Unknown codepoint in svc setup\n"); } s = get_socket(listen_addr, sap, qos); if (s < 0) return NULL; if (atm2text(buff, sizeof(buff), (struct sockaddr *)dst_addr, A2T_PRETTY | A2T_NAME | A2T_LOCAL) < 0) sprintf(buff, "<Unknown ATM address>"); diag(COMPONENT, DIAG_DEBUG, "Call to %s", buff); /* Make data direct SVCs non-blocking */ if (is_data_direct(&sap->blli[0])) { ret = fcntl(s, F_GETFL); if (ret < 0) { diag(COMPONENT, DIAG_ERROR, "fcntl(s, F_GETFL)\n"); close(s); } else if (fcntl(s, F_SETFL, ret|O_NONBLOCK) < 0) { diag(COMPONENT, DIAG_ERROR, "fcntl(s, F_SETFL, x|O_NONBLOCK)\n"); close(s); return NULL; } } ret = connect(s, (struct sockaddr *)dst_addr, sizeof(struct sockaddr_atmsvc)); if (ret < 0 && errno != EINPROGRESS) { diag(COMPONENT, DIAG_ERROR, "connect error: %s\n", strerror(errno)); close(s); return NULL; } conn = list_add_conn(dst_addr->sas_addr.prv); diag(COMPONENT, DIAG_DEBUG, "Conn:%p\n", conn); if (conn == NULL) { close(s); return NULL; } conn->fd = s; conn->type = WEMADE; conn->codepoint = sap->blli[0].l3.tr9577.snap[4]; if (is_data_direct(&sap->blli[0])) conn->status = CONNECTING; else conn->status = CONNECTED; return conn; } /* Creates listen socket for incoming data direct connections. * Only for data direct, not for Control or Multicast listen sockets. * Returns < 0 for error */ int create_data_listen(void) { struct atm_sap sap; struct atm_qos qos; struct sockaddr_atmsvc addr; memset(&addr, 0, sizeof(struct sockaddr_atmsvc)); memcpy(addr.sas_addr.prv, lec_params.c1n_my_atm_addr, ATM_ESA_LEN); addr.sas_family = AF_ATMSVC; init_conn_params(&sap, &qos, DATA_DIRECT_CONN); lec_params.data_listen = create_listensocket(&addr, &sap, &qos); if (lec_params.data_listen == NULL) { diag(COMPONENT, DIAG_FATAL, "Could not create listen socket for incoming Data Direct VCCs\n"); return -1; } return 0; } /* Opens a Multicast or non-blocking Data Direct VCC to atm_addr. * Not for Control connections. * Returns < 0 for error */ int create_data_svc(unsigned char *atm_addr, int codepoint) { struct atm_sap sap; struct atm_qos qos; struct sockaddr_atmsvc my_addr, dst_addr; Conn_t *conn; memset(&my_addr, 0, sizeof(struct sockaddr_atmsvc)); memcpy(my_addr.sas_addr.prv, lec_params.c1n_my_atm_addr, ATM_ESA_LEN); memset(&dst_addr, 0, sizeof(struct sockaddr_atmsvc)); memcpy(dst_addr.sas_addr.prv, atm_addr, ATM_ESA_LEN); my_addr.sas_family = dst_addr.sas_family = AF_ATMSVC; init_conn_params(&sap, &qos, codepoint); conn = setup_svc(&dst_addr, &my_addr, &sap, &qos); if (conn == NULL) { diag(COMPONENT, DIAG_ERROR, "Could not create Data Direct VCC\n"); delete_addr(dst_addr.sas_addr.prv); return -1; } return 0; } /* Creates a listen socket with parameters specified with * arguments. * Returns NULL for error or Conn_t for new listen socket. */ Conn_t *create_listensocket(struct sockaddr_atmsvc *listen_addr, struct atm_sap *sap, struct atm_qos *qos) { int fd, ret; Conn_t *conn; diag(COMPONENT, DIAG_DEBUG, "conn_create_listensocket\n"); fd = get_socket(listen_addr, sap, qos); if (fd < 0) return NULL; ret = listen(fd, 5); if (ret != 0) { diag(COMPONENT, DIAG_DEBUG, "Listen failed: %s\n", strerror(errno)); close(fd); return NULL; } conn = list_add_conn(NULL); if (conn == NULL) { diag(COMPONENT, DIAG_ERROR, "List_add_conn failed\n"); close(fd); return NULL; } conn->type = LISTENING; conn->fd = fd; diag(COMPONENT, DIAG_DEBUG, "Listen socket created blli:%2.2x %2.2x fd: %d\n", sap->blli[0].l3.tr9577.snap[3], sap->blli[0].l3.tr9577.snap[4], conn->fd); return conn; } /* Accepts a new connection from listen socket in conn. * Returns NULL for error */ Conn_t *accept_conn(Conn_t *conn) { Conn_t *new; struct sockaddr_atmsvc addr; size_t len; int fd; char buff[MAX_ATM_ADDR_LEN+1]; diag(COMPONENT, DIAG_DEBUG, "Accepting connection on fd %d\n", conn->fd); len = sizeof(addr); fd = accept(conn->fd, (struct sockaddr *)&addr, &len); diag(COMPONENT, DIAG_DEBUG, "accept returned %d\n", fd); if (fd < 0) { diag(COMPONENT, DIAG_ERROR, "accept: %s\n", strerror(errno)); return NULL; } if (atm2text(buff, sizeof(buff), (struct sockaddr *)&addr, A2T_PRETTY | A2T_NAME | A2T_LOCAL) < 0) sprintf(buff, "<Unknown ATM address>"); diag(COMPONENT, DIAG_DEBUG, "Call from %s", buff); new = list_add_conn(addr.sas_addr.prv); if (new == NULL) return NULL; new->fd = fd; new->status = CONNECTED; new->type = THEYMADE; if (conn == lec_params.ctrl_listen) new->codepoint = CONTROL_CONN; if (conn == lec_params.mcast_listen) new->codepoint = MCAST_CONN; if (conn == lec_params.data_listen) new->codepoint = DATA_DIRECT_CONN; return new; } /* Close all connections, important or not. */ void close_connections(void) { Conn_t *conn, *next; for(conn = connlist; conn; conn = next) { diag(COMPONENT, DIAG_DEBUG, "Destroying:%p fd:%d type:%d\n", conn, conn->fd, conn->type); next = conn->next; close(conn->fd); list_remove_conn(conn); free(conn); } return; } /* Closes a connection and checks its importance. * Important connections are kernel socket, LES connections, * BUS Default Multicast Send VCC, last Multicast Forward VCC from Bus * and any of the listen sockets. * Returns < 0 for important connection. */ int close_connection(Conn_t *conn) { int bad = 0; Conn_t *mcast; diag(COMPONENT, DIAG_DEBUG, "close_connection %p\n", conn); if (conn == lec_params.kernel || conn == lec_params.ctrl_direct || conn == lec_params.ctrl_dist || conn == lec_params.mcast_send || conn == lec_params.mcast_listen || conn == lec_params.data_listen) bad = -1; else { bad = -1; for (mcast = connlist; mcast; mcast = mcast->next) if (mcast != conn && mcast->type == THEYMADE && mcast->codepoint == MCAST_CONN) bad = 0; } close(conn->fd); list_remove_conn(conn); free(conn); return bad; } /* Accepts a new incoming Data Direct or Multicast Forward connection. * Control connections (LECS/LES) are accepted during configuration/join. * Returns < 0 for serious error such as broken listen socket. */ static int handle_accept(Conn_t *conn) { Conn_t *new; struct atmlec_ioc ioc; new = accept_conn(conn); if (new == NULL) return -1; if (conn == lec_params.mcast_listen) { diag(COMPONENT, DIAG_DEBUG, "Multicast Forward VCC accepted\n"); ioc.receive = 2; } else { diag(COMPONENT, DIAG_DEBUG, "Data Direct VCC accepted\n"); ioc.receive = 0; if (conn_already_exists(new->atm_address, new) && memcmp(lec_params.c1n_my_atm_addr, new->atm_address, ATM_ESA_LEN) < 0) { diag(COMPONENT, DIAG_DEBUG, "Using it only to receive, spec 8.1.1\n"); ioc.receive = 1; } } memcpy(ioc.atm_addr, new->atm_address, ATM_ESA_LEN); ioc.dev_num = lec_params.itf_num; diag(COMPONENT, DIAG_DEBUG, "Attaching a new VCC, fd %d\n", new->fd); if (ioctl(new->fd, ATMLEC_DATA, &ioc) < 0) { diag(COMPONENT, DIAG_ERROR, "VCC attach failed: ioctl: %s\n", strerror(errno)); return -1; } return 0; } /* Reads a LE control frame from conn, usually Data Direct or * Multicast Forward connection. Calls the incoming packet * handler function. * Returns < 0 for serious error such as broken LES connection */ static int handle_data(Conn_t *conn) { char buff[MAX_CTRL_FRAME]; int retval; retval = recv_frame(conn, buff, sizeof(buff)); if (retval < 0) { diag(COMPONENT, DIAG_ERROR, "handle_data: read: %s\n", strerror(errno)); return (close_connection(conn)); } if (retval == 0) { diag(COMPONENT, DIAG_DEBUG, "fd %d, Data or Multicast VCC closed\n", conn->fd); return (close_connection(conn)); } return handle_frame(conn, buff, retval); } /* Checks connections in *fds. The only allowed sockets * in *fds are listen sockets, data direct and control * sockets. * Returns < 0 for serious error such as broken LES connection */ int check_connections(fd_set *fds) { Conn_t *conn, *next; conn = connlist; while (conn != NULL) { next = conn->next; if (!FD_ISSET(conn->fd, fds)) { conn = next; continue; } switch (conn->type) { case LISTENING: if (handle_accept(conn) < 0) return -1; break; case WEMADE: case THEYMADE: if (handle_data(conn) < 0) return -1; break; default: diag(COMPONENT, DIAG_ERROR, "check_connections: bad_type '%s'\n", get_type_string(conn->type)); break; } conn = next; } return 0; } /* Completes a non-blocking connect. * Returns < 0 for serious error */ static int handle_connect(Conn_t *conn) { int retval; struct sockaddr_atmsvc dummy; struct atmlec_msg msg; struct atmlec_ioc ioc; diag(COMPONENT, DIAG_DEBUG, "handle_connect: completing fd %d\n", conn->fd); /* this seems to be common method in Linux-ATM * making sure that nonblocking connect was * completed successfully */ conn->status = CONNECTED; retval = connect(conn->fd, (struct sockaddr *)&dummy, sizeof(struct sockaddr_atmsvc)); if (retval < 0) { diag(COMPONENT, DIAG_DEBUG, "handle_connect: connect: %s\n", strerror(errno)); delete_addr(conn->atm_address); close_connection(conn); return 0; } send_ready_ind(conn); memcpy(ioc.atm_addr, conn->atm_address, ATM_ESA_LEN); ioc.dev_num = lec_params.itf_num; ioc.receive = 0; diag(COMPONENT, DIAG_DEBUG, "Attaching a new active VCC, fd %d\n", conn->fd); if (ioctl(conn->fd, ATMLEC_DATA, &ioc) < 0) { diag(COMPONENT, DIAG_ERROR, "VCC attach failed: ioctl: %s\n", strerror(errno)); return -1; } memset(&msg, 0, sizeof(struct atmlec_msg)); msg.type = l_flush_tran_id; memcpy(msg.content.normal.atm_addr, conn->atm_address, ATM_ESA_LEN); msg.content.normal.flag = send_flush_req(conn); msg_to_kernel(&msg, sizeof(struct atmlec_msg)); return 0; } /* Complete non-blocking connections in *fds. * Returns < 0 for serious error (problems with kernel). */ int complete_connections(fd_set *fds) { Conn_t *conn, *next; int retval; conn = connlist; while (conn) { next = conn->next; if (FD_ISSET(conn->fd, fds)) { retval = handle_connect(conn); if (retval < 0) return -1; } conn = next; } return 0; } /* Send a LE control frame using *conn. * Returns < 0 for serious error */ int send_frame(Conn_t *conn, void *frame, int length) { struct frame_hdr *hdr; int ret; diag(COMPONENT, DIAG_DEBUG, "send_frame: fd:%d len:%ld\n", conn->fd, length); hdr = (struct frame_hdr *)frame; if (hdr->opcode == htons(READY_QUERY) || hdr->opcode == htons(READY_IND)) diag(COMPONENT, DIAG_DEBUG, "%s\n", opcode2text(hdr->opcode)); else display_frame(frame); ret = write(conn->fd, frame, length); if (ret < 0) { diag(COMPONENT, DIAG_ERROR, "send_frame: write: %s\n", strerror(errno)); return -1; } return ret; } /* Receive a LE control frame from *conn. * Returns < 0 for serious error. */ int recv_frame(Conn_t *conn, void *buff, int length) { int ret; diag(COMPONENT, DIAG_DEBUG, "recv_frame: fd:%d\n", conn->fd); ret = read(conn->fd, buff, length); if (ret < 0) { diag(COMPONENT, DIAG_ERROR, "Read failed: %s\n", strerror(errno)); return -1; } #if 0 diag(COMPONENT, DIAG_DEBUG, "recv_frame: read %d bytes\n", ret); if (get_verbosity(COMPONENT) >= DIAG_DEBUG) { int i; for (i = 0; i < 11; i++) diag(COMPONENT, DIAG_DEBUG, "0x%2x", ((unsigned char *)buff)[i]); } #endif return ret; } /* * LANE2: 5.2.1.4 and others, sleep random time before trying to reconnect */ void random_delay(void) { struct timeval tv; int millis, interval; srand(time(NULL)); interval = lec_params.c38_max_reconfig_delay - lec_params.c37_min_reconfig_delay; millis = (rand() % interval) + lec_params.c37_min_reconfig_delay; tv.tv_sec = (millis - (millis % 1000)) / 1000; tv.tv_usec = (millis % 1000) * 1000; diag(COMPONENT, DIAG_DEBUG, "random_delay: sleeping %d.%d seconds\n", tv.tv_sec, tv.tv_usec); (void)select(0, NULL, NULL, NULL, &tv); return; } /* Collect already connected sockets in *fds */ void conn_get_fds(fd_set *fds) { Conn_t *conn; diag(COMPONENT, DIAG_DEBUG, "collecting ready fds "); conn = connlist; while (conn) { if (conn->status != CONNECTING) { FD_SET(conn->fd, fds); diag(COMPONENT, DIAG_DEBUG, "%d type %s", conn->fd, get_type_string(conn->type)); } conn = conn->next; } return; } /* Collect non-blocking connecting sockets in *fds */ void conn_get_connecting_fds(fd_set *fds) { Conn_t *conn; diag(COMPONENT, DIAG_DEBUG, "collecting connecting fds "); conn = connlist; while (conn) { if (conn->status == CONNECTING) { FD_SET(conn->fd, fds); diag(COMPONENT, DIAG_DEBUG, "%d", conn->fd); } conn = conn->next; } } /* Creates Conn_t for fd and marks it as kernel socket * Returns < 0 for error */ int conn_set_kernel_socket(int fd) { Conn_t *conn; conn = list_add_conn(NULL); if (conn == NULL) { diag(COMPONENT, DIAG_ERROR, "conn_set_kernel_socket: list_add_conn failed\n"); return -1; } conn->type = KERNEL_SOCK; conn->status = CONNECTED; conn->fd = fd; lec_params.kernel = conn; return fd; } /* Creates new Conn_t object and allocates memory for it. * atm_addr should be the ATM address of the other end * or NULL if not applicable */ static Conn_t *list_add_conn(unsigned char *atm_addr) { Conn_t *conn; conn = (Conn_t *)malloc(sizeof(Conn_t)); if (!conn) return NULL; memset(conn, 0, sizeof(Conn_t)); if (atm_addr) memcpy(conn->atm_address, atm_addr, ATM_ESA_LEN); conn->next = connlist; conn->previous = NULL; if (connlist) connlist->previous = conn; connlist = conn; diag(COMPONENT, DIAG_DEBUG, "Added conn:%p\n", conn); return conn; } /* Helper for close_connection and close_connections */ static void list_remove_conn(Conn_t *conn) { if (conn->next == NULL && conn->previous == NULL && connlist != conn) return; diag(COMPONENT, DIAG_DEBUG, "Removing conn:%p fd:%d previous:%p next:%p ", conn, conn->fd, conn->previous, conn->next); if (conn->previous) diag(COMPONENT, DIAG_DEBUG, "Previous:%p, fd:%d, next:%p, previous:%p ", conn->previous, conn->previous->fd, conn->previous->next, conn->previous->previous); if (conn->next) diag(COMPONENT, DIAG_DEBUG, "Next:%p, fd:%d next:%p, previous:%p ", conn->next, conn->next->fd, conn->next->next, conn->next->previous); if (conn->previous) { conn->previous->next = conn->next; } else /* First in line */ connlist = conn->next; if (conn->next) conn->next->previous = conn->previous; diag(COMPONENT, DIAG_DEBUG, "Connlist: %p\n", connlist); conn->next=conn->previous= NULL; return; } static const char *get_type_string(int type) { switch(type) { case WEMADE: return "WEMADE"; break; case THEYMADE: return "THEYMADE"; break; case LISTENING: return "LISTENING"; break; case KERNEL_SOCK: return "KERNEL_SOCK"; break; default: break; } return "UNKNOWN"; } static int maxmtu2maxsdu(uint8_t mtu) { int sdu; switch (mtu) { case MTU_1516: sdu = 1516; break; case MTU_1580: /* LANE2: MTU can be 1580 too (IEEE 802.1p/Q) */ sdu = 1580; break; case MTU_4544: sdu = 4544; break; case MTU_9234: sdu = 9234; break; case MTU_18190: sdu = 18190; break; default: sdu = 1516; break; } return sdu; } int maxmtu2itfmtu(uint8_t mtu) { int sdu; switch (mtu) { case MTU_1516: sdu = 1500; break; case MTU_1580: /* LANE2: MTU can be 1580 too (IEEE 802.1p/Q) */ sdu = 1500; break; case MTU_4544: sdu = 4528; break; case MTU_9234: sdu = 9218; break; case MTU_18190: sdu = 18174; break; default: sdu = 1500; break; } return sdu; } /* Convert a type of connection (CONTROL_CONN, DATA_DIRECT and MCAST_CONN) * to a BLLI codepoint which depends on C2 LAN Type. */ static uint16_t conn_type2codepoint(int conn_type) { if (conn_type == CONTROL_CONN) return CONTROL_CONN; if (conn_type == DATA_DIRECT_CONN) { if (lec_params.c2_lan_type == LAN_TYPE_8023 || lec_params.c2_lan_type == LAN_TYPE_UNSPEC) return DATA_DIRECT_8023; else if (lec_params.c2_lan_type == LAN_TYPE_8025) return DATA_DIRECT_8025; diag(COMPONENT, DIAG_ERROR, "conn_type2codepoint, bad lan_type %d", lec_params.c2_lan_type); return DATA_DIRECT_8023; } else if (conn_type == MCAST_CONN) { if (lec_params.c2_lan_type == LAN_TYPE_8023 || lec_params.c2_lan_type == LAN_TYPE_UNSPEC) return MCAST_CONN_8023; else if (lec_params.c2_lan_type == LAN_TYPE_8025) return MCAST_CONN_8025; diag(COMPONENT, DIAG_ERROR, "conn_type2codepoint, bad lan_type %d", lec_params.c2_lan_type); return MCAST_CONN_8023; } diag(COMPONENT, DIAG_ERROR, "conn_type2codepoint, unknown type %d", conn_type); return DATA_DIRECT_8023; } --- NEW FILE: conn.h --- /* * Marko Kiiskila ca...@cs... * * Copyright (c) 1996 * Tampere University of Technology - Telecommunications Laboratory * All rights reserved. * * Permission to use, copy, modify and distribute this * software and its documentation is hereby granted, * provided that both the copyright notice and this * permission notice appear in all copies of the software, * derivative works or modified versions, and any portions * thereof, that both notices appear in supporting * documentation, and that the use of this software is * acknowledged in any publications resulting from using * the software. * * TUT ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION AND DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS * SOFTWARE. * */ /* Copyright (C) 1999 Heikki Vatiainen he...@cs... */ #ifndef CONN_H #define CONN_H typedef struct _conn_t_ { int fd; /* Socket connected to this connection */ int status; /* Connection status */ int type; /* We made, they made, listen socket */ int codepoint; /* One of the below, MCAST_CONN etc. */ unsigned char atm_address[ATM_ESA_LEN]; /* Destination address, not in listen or kernel sockets */ struct _conn_t_ *next; struct _conn_t_ *previous; } Conn_t; void close_connections(void); void init_conn_params(struct atm_sap *sap, struct atm_qos *qos, uint16_t blli_codepoint); int create_data_svc(unsigned char *atm_addr, int codepoint); Conn_t *setup_svc(struct sockaddr_atmsvc *dst_addr, struct sockaddr_atmsvc *listen_addr, struct atm_sap *sap, struct atm_qos *qos); int create_data_listen(void); Conn_t *create_listensocket(struct sockaddr_atmsvc *listen_addr, struct atm_sap *sap, struct atm_qos *qos); Conn_t *accept_conn(Conn_t *conn); int close_connection(Conn_t *conn); int check_connections(fd_set *fds); int complete_connections(fd_set *fds); int send_frame(Conn_t *conn, void *frame, int length); int recv_frame(Conn_t *conn, void *buff, int length); void conn_get_fds(fd_set *fds); void conn_get_connecting_fds(fd_set *fds); int conn_set_kernel_socket(int fd); void random_delay(void); int maxmtu2itfmtu(uint8_t mtu); /* * Connection types for BLLI codepoints. */ #define CONTROL_CONN 1 #define DATA_DIRECT_CONN 2 #define MCAST_CONN 4 #define DATA_DIRECT_8023 2 #define DATA_DIRECT_8025 3 #define MCAST_CONN_8023 4 #define MCAST_CONN_8025 5 /* * MTU sizes */ #define MTU_UNSPEC 0 #define MTU_1516 1 #define MTU_1580 5 /* LANEv2 */ #define MTU_4544 2 #define MTU_9234 3 #define MTU_18190 4 #endif /* CONN_H */ --- NEW FILE: Makefile.am --- sbin_PROGRAMS = zeppelin zeppelin_SOURCES = join.c join.h conn.c conn.h main.c address.c address.h \ frames.c frames.h display.c display.h \ kernel.c kernel.h frame_defs.h lec.h zeppelin_LDADD = $(top_builddir)/src/lib/libatm.la \ $(top_builddir)/src/lib/libatmd.la zeppelin_DEPENDENCIES = $(zeppelin_LDADD) man_MANS = zeppelin.8 EXTRA_DIST = $(man_MANS) COPYRIGHT.TUT --- NEW FILE: frames.c --- /* frames.c - handle incoming frames, prefill outgoing frames, parse TLVs etc. */ /* Copyright (C) 1999 Heikki Vatiainen he...@cs... */ /* Functions for handling LANE control frames used when joining an * ELAN are in lec.c */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <string.h> #include <stdlib.h> #include <atm.h> #include <linux/atmlec.h> #include <atmd.h> #include "conn.h" #include "lec.h" #include "frames.h" #include "display.h" #include "kernel.h" #define COMPONENT "frames.c" static uint32_t transaction_id = 0; static void extract_tlv_value(uint16_t opcode, uint32_t type, unsigned char *tlvp, int len); static void handle_x5(uint16_t opcode); /* Initializes LANE Control frame of type 'type' */ void prefill_frame(void *buff, uint16_t type) { struct frame_hdr *header; memset(buff, 0, sizeof(struct ctrl_frame)); header = (struct frame_hdr *)buff; header->marker = htons(0xff00); header->protocol = 0x01; header->version = 0x01; header->opcode = htons(type); header->status = htons(0x0000); header->tran_id = htonl(transaction_id); header->lec_id = htons(lec_params.c14_lec_id); header->flags = htons(0x0000); transaction_id++; return; } /* Validates incoming Control frames except READY_IND and * READY_QUERY which do not start with the common header. * Also calls display_frame() to print out conforming frames. * Returns < 0 for error */ int validate_frame(unsigned char *buff, int size) { struct ready_frame *hdr; /* Ready is the shortest possible */ if (size < sizeof(struct ready_frame)) { diag(COMPONENT, DIAG_DEBUG, "short frame, size %d\n", size); return -1; } hdr = (struct ready_frame *)buff; if (hdr->marker != htons(0xff00) || hdr->protocol != 0x01 || hdr->version != 0x01) return -1; /* READY_* frames are shorter than others */ if (hdr->opcode == htons(READY_QUERY) || hdr->opcode == htons(READY_IND)) { diag(COMPONENT, DIAG_DEBUG, "Received a %s\n", opcode2text(hdr->opcode)); return 0; } if (size < sizeof(struct ctrl_frame)) { diag(COMPONENT, DIAG_DEBUG, "short frame, size %d\n", size); return -1; } display_frame(buff); return 0; } /* Handle incoming LE_FLUSH_REQUEST frames. */ static void handle_flush_req(struct ctrl_frame *f) { if (memcmp(lec_params.c1n_my_atm_addr, f->target_atm_addr, ATM_ESA_LEN) != 0) return; f->header.opcode = htons(LE_FLUSH_RSP); if (send_frame(lec_params.ctrl_direct, f, sizeof(struct ctrl_frame)) < 0) diag(COMPONENT, DIAG_DEBUG, "could not send LE_FLUSH_RESPONSE\n"); return; } /* Handle incoming LE_FLUSH_RESPONSE frames. */ static void handle_flush_rsp(struct ctrl_frame *f) { struct atmlec_msg msg; if (f->header.lec_id != htons(lec_params.c14_lec_id)) { diag(COMPONENT, DIAG_DEBUG, "Wrong lec_id, ignoring\n"); return; } memset(&msg, 0, sizeof(struct atmlec_msg)); msg.type = l_flush_complete; msg.content.normal.flag = ntohl(f->header.tran_id); msg_to_kernel(&msg, sizeof(struct atmlec_msg)); return; } /* Handle incoming READY_QUERY frames. */ static void handle_ready_query(Conn_t *conn, struct ready_frame *f) { f->opcode = htons(READY_IND); send_frame(conn, f, sizeof(struct ready_frame)); return; } /* Helper for handle_le_arp_req. * If the target_lan_dst was not our MAC address, try to * see if the bridging table in the kernel knows about it. * Returns < 0 for serious error */ static int check_bridge(struct ctrl_frame *frame, int size) { struct atmlec_msg msg; if (lec_params.c4_proxy_flag == 0) return 0; memset(&msg, 0, sizeof(struct atmlec_msg)); msg.type = l_should_bridge; memcpy(msg.content.proxy.mac_addr, frame->target_lan_dst.mac, ETH_ALEN); memcpy(msg.content.proxy.atm_addr, frame->src_atm... [truncated message content] |