/* Handles incoming LE_ARP_RESPONSE frames. * Returns < 0 for serious error */ static int handle_arp_rsp(struct ctrl_frame *frame, int size) { int sizeoftlvs, msglen, retval; char buff[MAX_CTRL_FRAME]; struct atmlec_msg *msg; if (frame->header.lec_id != htons(lec_params.c14_lec_id)) { diag(COMPONENT, DIAG_DEBUG, "Wrong lec_id, ignoring\n"); return 0; } sizeoftlvs = size - sizeof(struct ctrl_frame); msglen = sizeof(struct atmlec_msg) + sizeoftlvs; msg = (struct atmlec_msg *)buff; memset(msg, 0, msglen); msg->type = l_arp_update; memcpy(msg->content.normal.mac_addr, frame->target_lan_dst.mac, ETH_ALEN); memcpy(msg->content.normal.atm_addr, frame->target_atm_addr, ATM_ESA_LEN); msg->content.normal.flag = (frame->header.flags & REMOTE_ADDRESS) ? 1 : 0; msg->sizeoftlvs = sizeoftlvs; if (sizeoftlvs > 0) memcpy(msg + 1, frame + 1, sizeoftlvs); retval = msg_to_kernel(msg, msglen); return retval; }
/* Tell kernel the parameters this ELAN has. * Returns < 0 for serious error */ static int config_kernel(void) { struct atmlec_msg msg; memset(&msg, 0, sizeof(struct atmlec_msg)); msg.type = l_config; msg.content.config.maximum_unknown_frame_count = lec_params.c10_max_unknown_frames; msg.content.config.max_unknown_frame_time = lec_params.c11_max_unknown_frame_time; msg.content.config.max_retry_count = lec_params.c13_max_retry_count; msg.content.config.aging_time = lec_params.c17_aging_time; msg.content.config.forward_delay_time = lec_params.c18_forward_delay_time; msg.content.config.arp_response_time = lec_params.c20_le_arp_response_time; msg.content.config.flush_timeout = lec_params.c21_flush_timeout; msg.content.config.path_switching_delay = lec_params.c22_path_switching_delay; msg.content.config.lane_version = (lec_params.c29_v2_capable) ? 2 : 1; msg.content.config.mtu = maxmtu2itfmtu(lec_params.c3_max_frame_size); msg.content.config.is_proxy = lec_params.c4_proxy_flag; if (msg_to_kernel(&msg, sizeof(struct atmlec_msg)) < 0) { diag(COMPONENT, DIAG_ERROR, "Could not tell kernel ELAN parameters"); return -1; } return 0; }
/* Handles incoming LE_NARP_REQUESTS frames. * Mandatory only in LANEv2. If we are LANEv1, we'll just ignore these. * See LANEv2, 7.1.31-35 LE_NARP_REQUEST/RESPONSE. * For no-source, i.e. no source ATM address, we remove the LE_ARP cache entry. * If the source is non-zero, we first remove the entry * and then add the new entry in the LE_ARP cache. * Returns < 0 for serious error. */ static int handle_narp_req(struct ctrl_frame *frame, int size) { int sizeoftlvs, no_source = 0, retval; struct atmlec_msg *msg; unsigned char empty[ATM_ESA_LEN]; if (frame->header.lec_id == htons(lec_params.c14_lec_id) || lec_params.c29_v2_capable == 0) { diag(COMPONENT, DIAG_DEBUG, "Ignoring LE_NARP_REQUEST\n"); return 0; } memset(empty, 0, ATM_ESA_LEN); if (memcmp(empty, frame->src_atm_addr, ATM_ESA_LEN) == 0) no_source = 1; sizeoftlvs = size - sizeof(struct ctrl_frame); msg = (struct atmlec_msg *)malloc(sizeof(struct atmlec_msg) + sizeoftlvs); if (msg == NULL) return -1; memset(msg, 0, sizeof(struct atmlec_msg)); msg->type = l_narp_req; memcpy(msg->content.normal.mac_addr, frame->src_lan_dst.mac, ETH_ALEN); memcpy(msg->content.normal.atm_addr, frame->src_atm_addr, ATM_ESA_LEN); msg->content.normal.flag = (frame->header.flags & REMOTE_ADDRESS) ? 1 : 0; msg->content.normal.no_source_le_narp = no_source; msg->sizeoftlvs = sizeoftlvs; if (sizeoftlvs > 0) memcpy(msg + 1, frame + 1, sizeoftlvs); retval = msg_to_kernel(msg, sizeof(struct atmlec_msg) + sizeoftlvs); free(msg); return retval; }
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; }
/* Handles incoming LE_TOPOLOGY_REQUEST frames. * Returns < 0 for serious error */ static int handle_topo_req(struct ctrl_frame *frame) { struct atmlec_msg msg; memset(&msg, 0, sizeof(struct atmlec_msg)); msg.type = l_topology_change; if (frame->header.flags & htons(TOPO_CHANGE)) msg.content.normal.flag = 1; return(msg_to_kernel(&msg, sizeof(struct atmlec_msg))); }
/* Tells kernel what our LEC_ID is. * Returns < 0 for serisous error */ static int set_lec_id(uint16_t lec_id) { struct atmlec_msg msg; memset(&msg, 0, sizeof(struct atmlec_msg)); msg.type = l_set_lecid; msg.content.normal.flag = lec_id; if (msg_to_kernel(&msg, sizeof(struct atmlec_msg)) < 0) { diag(COMPONENT, DIAG_ERROR, "Could not tell kernel LEC_ID"); return -1; } return 0; }
/* 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_addr, ATM_ESA_LEN); msg.content.proxy.tran_id = frame->header.tran_id; msg.content.proxy.lec_id = frame->header.lec_id; return msg_to_kernel(&msg, sizeof(struct atmlec_msg)); }
/* 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; }
/* Handles incoming LE_ARP_REQ and targetless LE_ARP_REQ. * See LANEv2, 7.1.5 and 7.1.30 * Returns < 0 for serious error */ static int handle_le_arp_req(struct ctrl_frame *frame, int size) { int sizeoftlvs, sizeofrsp, retval; struct ctrl_frame *rsp; struct atmlec_msg *msg; if (frame->header.lec_id == htons(lec_params.c14_lec_id)) { diag(COMPONENT, DIAG_DEBUG, "Ignoring own LE_ARP_REQUEST\n"); return 0; } retval = 0; if (frame->target_lan_dst.tag == htons(LAN_DST_MAC_ADDR)) { if (memcmp(frame->target_lan_dst.mac, lec_params.c6_mac_addr, ETH_ALEN) != 0) return (check_bridge(frame, size)); /* target was not us */ sizeofrsp = sizeof(struct ctrl_frame) + lec_params.sizeoftlvs; rsp = (struct ctrl_frame *)malloc(sizeofrsp); if (rsp == NULL) return 0; memcpy(rsp, frame, sizeof(struct ctrl_frame)); rsp->header.opcode = htons(LE_ARP_RSP); memcpy(rsp->target_atm_addr, lec_params.c1n_my_atm_addr, ATM_ESA_LEN); rsp->num_tlvs = lec_params.num_tlvs; if (lec_params.num_tlvs > 0) memcpy(rsp + 1, lec_params.tlvs, lec_params.sizeoftlvs); retval = send_frame(lec_params.ctrl_direct, rsp, sizeofrsp); free(rsp); } else if (frame->target_lan_dst.tag == htons(LAN_DST_NOT_PRESENT) && lec_params.c29_v2_capable) { sizeoftlvs = size - sizeof(struct ctrl_frame); msg = (struct atmlec_msg *)malloc(sizeof(struct atmlec_msg) + sizeoftlvs); if (msg == NULL) return -1; memset(msg, 0, sizeof(struct atmlec_msg)); msg->type = l_arp_update; memcpy(msg->content.normal.mac_addr, frame->src_lan_dst.mac, ETH_ALEN); memcpy(msg->content.normal.atm_addr, frame->src_atm_addr, ATM_ESA_LEN); msg->content.normal.flag = (frame->header.flags & REMOTE_ADDRESS) ? 1 : 0; msg->content.normal.targetless_le_arp = 1; msg->sizeoftlvs = sizeoftlvs; if (sizeoftlvs > 0) memcpy(msg + 1, frame + 1, sizeoftlvs); retval = msg_to_kernel(msg, sizeof(struct atmlec_msg) + sizeoftlvs); free(msg); } return retval; }