/* lecs.c, get MPOA configuration info from LECS */ #if HAVE_CONFIG_H #include #endif #include #include #include /* htons() and friends */ #include #include #include #include #include #include /* for MPOA Device type TLV */ #include "lecs.h" #include "k_interf.h" #define MAXFRAME 1024 static int get_lecs_socket(struct sockaddr_atmsvc *sa); static int send_request(int fd, char *buff, char *lec_addr, char *elan_name); static int get_reply(int fd, char *buff, struct mpc_parameters *params); void get_mpc_config(struct sockaddr_atmsvc *sa, char *lec_addr, char *elan_name) { int s; char buff[MAXFRAME]; struct k_message msg; s = get_lecs_socket(sa); if (s < 0) return; memset(buff, 0, sizeof(buff)); if (send_request(s, buff, lec_addr, elan_name) < 0) { printf("mpcd: lecs.c: send_request failed, using defaults\n"); return; } msg.content.params.mpc_p1 = MPC_P1; msg.content.params.mpc_p2 = MPC_P2; msg.content.params.mpc_p4 = MPC_P4; msg.content.params.mpc_p5 = MPC_P5; msg.content.params.mpc_p6 = MPC_P6; if (get_reply(s, buff, &msg.content.params) < 0) { printf("mpcd: lecs.c: get_config failed, using defaults\n"); return; } msg.type = SET_MPC_PARAMS; send_to_kernel(&msg); printf("mpcd: lecs.c: get_config: about to return\n"); return; } static int send_request(int fd, char *buff, char *lec_addr, char *elan_name) { char *tmp; int retval; struct le_config_frame *frame; frame = (struct le_config_frame *)buff; frame->marker = htons(0xff00); frame->protocol = 0x01; frame->version = 0x01; frame->opcode = htons(0x0001); frame->tran_id = htonl(42); frame->flags = htons(0x002); memcpy(frame->src_atm_addr, lec_addr, ATM_ESA_LEN); frame->num_tlvs = 1; if (elan_name != NULL) { strcpy(frame->elan_name, elan_name); frame->elan_name_size = strlen(elan_name); } /* add the MPOA device type TLV */ tmp = buff + sizeof(struct le_config_frame); *(uint32_t *)tmp = htonl(TLV_MPOA_DEVICE_TYPE); tmp += 4; *tmp++ = 22; /* device type field + MPC's ATM address */ *tmp++ = MPC; *tmp++ = 0; memcpy(tmp, lec_addr, ATM_ESA_LEN); tmp += ATM_ESA_LEN; retval = write(fd, buff, tmp - buff); if (retval < 0 || retval != (tmp - buff)) return -1; return 0; } static int get_reply(int fd, char *buff, struct mpc_parameters *params) { int retval; uint32_t type; uint8_t length, *tlvs, *end_of_tlvs; struct le_config_frame *frame; retval = read(fd, buff, MAXFRAME); if (retval < 0) return -1; frame = (struct le_config_frame *)buff; if (frame->status != 0) { printf("mpcd: lecs.c: get_reply: config status %d\n", frame->status); return -1; } if (frame->num_tlvs == 0) { printf("mpcd: lecs.c: get_reply: no TLVS\n"); return -1; } tlvs = buff + sizeof(struct le_config_frame); end_of_tlvs = buff + retval; while (end_of_tlvs - tlvs >= 5 && frame->num_tlvs-- > 0) { type = (tlvs[0] << 24) | (tlvs[1] << 16) | (tlvs[2] << 8) | tlvs[3]; length = tlvs[4]; tlvs += 5; /* Sampo-Add: start */ switch(type){ case TLV_SC_SETUP_FRAME_COUNT: params->mpc_p1 = (*(tlvs+1)<<8) | (*tlvs); params->mpc_p1 = htons(params->mpc_p1); printf("mpcd: lecs.c: get_reply: MPC_p1 = %d\n",params->mpc_p1); break; case TLV_SC_SETUP_FRAME_TIME: params->mpc_p2 = (*(tlvs+1)<<8) | (*tlvs); params->mpc_p2 = htons(params->mpc_p2); printf("mpcd: lecs.c: get_reply: MPC_p2 = %d\n",params->mpc_p2); break; case TLV_FLOW_DETECTION_PROTOCOLS: memcpy(params->mpc_p3, tlvs, length); printf("mpcd: lecs.c: get_reply: MPC_p3 = %s\n",params->mpc_p3); break; case TLV_MPC_ININTIAL_RETRY_TIME: params->mpc_p4 = (*(tlvs+1)<<8) | (*tlvs); params->mpc_p4 = htons(params->mpc_p4); printf("mpcd: lecs.c: get_reply: MPC_p4 = %d\n",params->mpc_p4); break; case TLV_MPC_RETRY_TIME_MAXIMUM: params->mpc_p5 = (*(tlvs+1)<<8) | (*tlvs); params->mpc_p5 = htons(params->mpc_p5); printf("mpcd: lecs.c: get_reply: MPC_p5 = %d\n",params->mpc_p5); break; case TLV_HOLD_DOWN_TIME: params->mpc_p6 = (*(tlvs+1)<<8) | (*tlvs); params->mpc_p6 = htons(params->mpc_p6); printf("mpcd: lecs.c: get_reply: MPC_p6 = %d\n",params->mpc_p6); break; default: printf("mpcd: lecs.c: get_reply: TLV type 0x%x\n", type); break; } tlvs += length; /* Sampo-Add: end */ } if (end_of_tlvs - tlvs != 0) printf("mpcd: lecs.c: get_reply: ignoring %d bytes of trailing TLV carbage\n", end_of_tlvs - tlvs); return 1; } static int get_lecs_socket(struct sockaddr_atmsvc *sa) { int s, retval; struct atm_qos qos; struct atm_sap sap; s = socket(PF_ATMSVC, SOCK_DGRAM, 0); if (s < 0){ printf("mpcd: lecs.c: socket failed: %s\n", strerror(errno)); return -1; } memset(&qos, 0, sizeof(qos)); memset(&sap, 0, sizeof(sap)); qos.aal = ATM_AAL5; qos.txtp.traffic_class = ATM_UBR; qos.rxtp.traffic_class = ATM_UBR; qos.txtp.max_sdu = 1516; qos.rxtp.max_sdu = 1516; if (setsockopt(s, SOL_ATM,SO_ATMQOS, &qos, sizeof(qos)) < 0){ printf("mpcd: lecs.c: setsockopt SO_ATMQOS failed: %s\n", strerror(errno)); close(s); return -1; } sap.blli[0].l2_proto = ATM_L2_NONE; 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; sap.blli[0].l3.tr9577.snap[3] = 0x00; sap.blli[0].l3.tr9577.snap[4] = 0x01; if (setsockopt(s, SOL_ATM,SO_ATMSAP, &sap, sizeof(sap)) < 0) { printf("mpcd: lecs.c: setsockop SO_ATMSAP failed: %s\n", strerror(errno)); close (s); return -1; } retval = connect(s, (struct sockaddr *)sa, sizeof(struct sockaddr_atmsvc)); if (retval < 0) { printf("mpcd: lecs.c: connect failed: %s\n", strerror(errno)); close (s); return -1; } return s; }