#if HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include /* For UINT_MAX */ #include "io.h" #include "k_interf.h" #include "packets.h" extern struct mpc_control mpc_control; /* from main.c */ extern int keep_alive_sm_running; /* from io.c */ static unsigned char service_category_to_traff_class(uint32_t service_category); #if 0 #define dprintf printf #else #define dprintf(format,args...) #endif int parse_extensions(uint8_t *buff,struct extension_values * values ){ int pos = 0; struct dll_header_extension *dll_ext; struct nhrp_extension_with_value *ext_with_value; struct nhrp_extension *extension = (struct nhrp_extension *)buff; memset(values, 0, sizeof(struct extension_values)); while(ntohs(extension->type) != NHRP_END_OF_EXTENSIONS && ntohs(extension->type) != 0){ switch(ntohs(extension->type)){ case MPOA_DLL_HEADER_EXTENSION: dprintf("mpcd: p_recogn.c: dll_header_extension.\n"); dll_ext = (struct dll_header_extension *)(buff + pos); values->dll_header_present = 1; values->dll_ext.length = dll_ext->length; values->dll_ext.cache_id = dll_ext->cache_id; dprintf("mpcd: p_recogn.c: parse_extentsions() cache_id %d\n", dll_ext->cache_id); values->dll_ext.elan_id = dll_ext->elan_id; values->dll_ext.dh_length = dll_ext->dh_length; memcpy(values->dll_ext.dll_header,dll_ext->dll_header ,dll_ext->dh_length); pos += sizeof(struct dll_header_extension) - sizeof(dll_ext->dll_header) + dll_ext->dh_length; dprintf("mpcd: p_recogn.c: parse_extensions() pos %d values->dll_ext.cache_id %d\n", pos, values->dll_ext.cache_id); break; case MPOA_EGRESS_CACHE_TAG_EXTENSION: dprintf("mpcd: p_recogn.c: mpoa_egress_cache_tag_extension.\n"); values->egress_cache_tag_ext_present = 1; extension = (struct nhrp_extension *)(buff + pos); if(ntohs(extension->length)){ values->tag_present = 1; pos += sizeof(struct nhrp_extension); values->tag = *((uint32_t*)(buff + pos)); pos += sizeof(uint32_t); } else pos += sizeof(struct nhrp_extension); break; case MPOA_ATM_SERVICE_CATEGORY_EXTENSION: printf("mpcd: p_recogn.c: mpoa_atm_service_category_extension."); ext_with_value = (struct nhrp_extension_with_value *)(buff + pos); values->service_category_present = 1; values->service_category = ntohl(ext_with_value->value); pos += sizeof(struct nhrp_extension_with_value); printf("service_category = %u\n",values->service_category); break; case MPOA_KEEPALIVE_LIFETIME_EXTENSION: dprintf("mpcd: p_recogn.c: mpoa_keepalive_lifetime_extension.\n"); ext_with_value = (struct nhrp_extension_with_value *)(buff + pos); values->keep_alive_lifetime_present = 1; values->keep_alive_lifetime = ntohl(ext_with_value->value); pos += sizeof(struct nhrp_extension_with_value); break; case MPOA_HOP_COUNT_EXTENSION: dprintf("mpcd: p_recogn.c: mpoa_hop_count_extension.\n"); ext_with_value = (struct nhrp_extension_with_value *)(buff + pos); values->hop_count_present = 1; values->hop_count = ntohl(ext_with_value->value); pos += sizeof(struct nhrp_extension_with_value); break; case MPOA_ORIGINAL_ERROR_CODE_EXTENSION: dprintf("mpcd: p_recogn.c: mpoa_original_error_code_extension.\n"); ext_with_value = (struct nhrp_extension_with_value *)(buff + pos); values->error_code_present = 1; values->error_code = ntohl(ext_with_value->value); pos += sizeof(struct nhrp_extension_with_value); break; default: printf("mpcd: p_recogn.c: Unrecognized extension: %x\n",ntohs(extension->type)); pos += sizeof(struct nhrp_extension_with_value); break; } extension = (struct nhrp_extension *)(buff + pos); } if(pos) pos += sizeof(struct nhrp_extension); /* End_of_extensions extension */ return pos; } static uint32_t calculate_ip_mask(uint8_t prefix){ int i; uint32_t mask = 0; if(prefix >= 32) return UINT_MAX; for( i = 0; i < prefix - 1; i++){ mask = mask | 1; mask = mask << 1; } mask = mask | 1; mask = mask << (32 - prefix); return mask; } static void print_cie_code(uint8_t code){ printf("mpcd: p_recogn.c: resolution_reply_rcvd: "); switch(code){ case ADMINISTRATIVELY_PROHIBITED: printf("administratively prohibited. \n"); break; case INSUFFICIENT_RESOURCES: printf("insufficient resources. \n"); break; case NO_INET_ADDR_TO_NBMA_ADDR_BINDING_EXISTS: printf("no internet layer address to nbma address binding exists.\n"); break; case UNIQUE_INET_ADDR_ALREADY_REGISTERED: printf("unique internet layer address already registered.\n"); break; case INSUFF_RES_TO_EGRESS_CACHE_ENTRTY: printf("insufficient resources to accept egress cache entry.\n"); break; case INSUFF_RES_TO_SHORTCUT: printf("insufficient resources to accpet shortcut.\n"); break; case INSUFF_RES_TO_EITHER_ENTRY_OR_SHORTCUT: printf("insufficient resources to accept either shortcut or egress cache entry.\n"); break; case UNSUPPORTED_INTERN_LAYER_PROTO: printf("unsupported internetwork layer protocol.\n"); break; case UNSUPPORTED_MAC_LAYER_PROTO: printf("unsupported mac layer protocol.\n"); break; case NOT_AN_MPC: printf("not an mpc.\n"); break; case NOT_AN_MPS: printf("not an mps.\n"); break; case UNSPECIFIED: printf("unspecified.\n"); break; default: printf("unrecognized cie code %d.\n",code); break; } return; } static int nhrp_purge_request(uint8_t *buff){ int pos = 0; int cie_limit = 0; uint32_t ip_mask; uint8_t eg_MPC_data_ATM_addr[ATM_ESA_LEN]; uint32_t eg_MPS_ip_addr; uint32_t purge_ip; struct k_message msg; struct extension_values values; struct nhrp_common_h_no_ip *common_no_ip; struct nhrp_cie_no_nbma *cie_no_nbma; struct nhrp_cie *cie; struct nhrp_fixed_h *fixed = (struct nhrp_fixed_h *)buff; memset(&msg,0,sizeof(struct k_message)); if(ntohs(fixed->ar_extoff)){ cie_limit = ntohs(fixed->ar_extoff); } else{ cie_limit = ntohs(fixed->ar_pktsz); } pos += sizeof(struct nhrp_fixed_h); common_no_ip = (struct nhrp_common_h_no_ip *)(buff + pos); memcpy(eg_MPC_data_ATM_addr, common_no_ip->src_nbma_address ,ATM_ESA_LEN); pos += sizeof(struct nhrp_common_h_no_ip); if(common_no_ip->src_proto_len == PROTO_LEN_IP){ eg_MPS_ip_addr = ntohl((uint32_t)*(buff + pos)); pos += sizeof(eg_MPS_ip_addr); } if(common_no_ip->dst_proto_len == PROTO_LEN_IP) pos += sizeof(uint32_t); while(pos < cie_limit){ cie = (struct nhrp_cie *)(buff + pos); if(cie->cli_addr_tl){ purge_ip = cie->cli_protocol_address; ip_mask = calculate_ip_mask(cie->prefix_length); pos += sizeof(struct nhrp_cie); } else{ cie_no_nbma = (struct nhrp_cie_no_nbma *)(buff + pos); purge_ip = cie_no_nbma->cli_protocol_address; ip_mask = calculate_ip_mask(cie_no_nbma->prefix_length); pos += sizeof(struct nhrp_cie_no_nbma); } msg.type = INGRESS_PURGE_RCVD; msg.ip_mask = ip_mask; msg.content.in_info.in_dst_ip = purge_ip; memcpy(msg.MPS_ctrl, mpc_control.MPS_CTRL_ATM_ADDR, ATM_ESA_LEN); send_to_kernel(&msg); } /* we really do not do anything with the extensions, just parse them */ if(ntohs(fixed->ar_extoff)){ pos += parse_extensions(buff + ntohs(fixed->ar_extoff), &values); } if(!(ntohs(common_no_ip->flags) & FLAG_N )) return send_purge_reply(buff); return 1; } static int mpoa_cache_imposition_request( uint8_t * buff ){ int pos = 0; struct k_message msg; struct nhrp_fixed_h * fixed = (struct nhrp_fixed_h *)buff; struct nhrp_common_h * common; struct nhrp_cie_short * cie_short; struct extension_values values; pos += sizeof( struct nhrp_fixed_h ); memset(&values, 0, sizeof(struct extension_values)); memset(&msg,0,sizeof(struct k_message)); common = (struct nhrp_common_h *)(buff + pos); memcpy(msg.content.eg_info.in_MPC_data_ATM_addr, common->src_nbma_address ,ATM_ESA_LEN); pos += sizeof(struct nhrp_common_h); cie_short = (struct nhrp_cie_short *)(buff + pos); msg.content.eg_info.holding_time = ntohs(cie_short->holding_time); msg.ip_mask = calculate_ip_mask(cie_short->prefix_length); if(ntohs(fixed->ar_extoff)){ pos += parse_extensions(buff + ntohs(fixed->ar_extoff), &values); } if(ntohs(cie_short->holding_time)) { if (values.dll_header_present == 0) { printf("mpcd: p_recogn.c: warning: "); printf("holding time non-zero but MPOA DLL Header Extension missing\n"); return 0; } keep_alive_sm_running = 1; } msg.content.eg_info.cache_id = values.dll_ext.cache_id; msg.content.eg_info.DH_length = values.dll_ext.dh_length; memcpy(msg.content.eg_info.DLL_header, values.dll_ext.dll_header, msg.content.eg_info.DH_length); if(common->src_proto_len) msg.content.eg_info.mps_ip = common->src_protocol_address; if(common->dst_proto_len) msg.content.eg_info.eg_dst_ip = common->dst_protocol_address; msg.content.eg_info.tag = new_tag(msg.content.eg_info.cache_id); memcpy(msg.MPS_ctrl, mpc_control.MPS_CTRL_ATM_ADDR, ATM_ESA_LEN); msg.type = CACHE_IMPOS_RCVD; send_to_kernel(&msg); return send_cache_imposition_reply( buff, msg.content.eg_info.tag, 0x00, 0, MTU_DEFAULT, common->src_nbma_address ); } static int mpoa_egress_cache_purge_reply( uint8_t * buff ){ int pos = 0; struct nhrp_fixed_h *fixed = (struct nhrp_fixed_h *)buff; struct nhrp_common_h *common; struct nhrp_cie *cie; struct extension_values values; struct k_message msg; memset(&values, 0, sizeof(struct extension_values)); memset(&msg,0,sizeof(struct k_message)); pos += sizeof(struct nhrp_fixed_h); common = (struct nhrp_common_h*)(buff + pos); if(!check_incoming(ntohl(common->request_ID), MPOA_EGRESS_CACHE_PURGE_REQUEST)) return -1; pos += sizeof(struct nhrp_common_h); cie = (struct nhrp_cie *)(buff + pos); msg.ip_mask = calculate_ip_mask(cie->prefix_length); if(fixed->ar_extoff) parse_extensions(buff + ntohs(fixed->ar_extoff),&values); else { printf("mpcd: p_recogn.c: warning: "); printf("no extensions in MPOA Egress Cache Purge Reply\n"); return -1; } if (values.dll_header_present == 0) { printf("mpcd: p_recogn.c: warning: "); printf("DLL Header Extension missing in MPOA Egress Cache Purge Reply\n"); return -1; } msg.content.eg_info.cache_id = values.dll_ext.cache_id; msg.type = EGRESS_PURGE_RCVD; memcpy(msg.MPS_ctrl,mpc_control.MPS_CTRL_ATM_ADDR,ATM_ESA_LEN); return send_to_kernel(&msg); } static int mpoa_keep_alive(uint8_t *buff){ int pos = 0; uint32_t sequence_nmbr; struct nhrp_fixed_h *fixed = (struct nhrp_fixed_h *)buff; struct extension_values values; struct nhrp_common_h_no_ip *common; memset(&values, 0, sizeof(struct extension_values)); pos += sizeof(struct nhrp_fixed_h); common = (struct nhrp_common_h_no_ip *)(buff + pos); sequence_nmbr = ntohl(common->request_ID); if(memcmp(common->src_nbma_address,mpc_control.MPS_CTRL_ATM_ADDR,ATM_ESA_LEN)){ printf("mpcd: p_recogn.c: new MPS! \n" ); return -1; } if(ntohs(fixed->ar_extoff)){ parse_extensions(buff + ntohs(fixed->ar_extoff),&values); } /* if extensions were missing sequence_nmbr == 0 => MPS Death */ keep_alive_sm(values.keep_alive_lifetime, sequence_nmbr); return 1; } static int mpoa_trigger( uint8_t * buff ){ int pos = 0; struct k_message msg; struct nhrp_common_h *common; struct extension_values values; struct nhrp_fixed_h *fixed = (struct nhrp_fixed_h*)buff; memset(&values, 0, sizeof(struct extension_values)); pos += sizeof(struct nhrp_fixed_h); common = (struct nhrp_common_h *)(buff + pos); pos += sizeof(struct nhrp_common_h); memset(&msg,0,sizeof(struct k_message)); if(ntohs(fixed->ar_extoff)) { printf("mpcd: p_recogn.c: mpoa_trigger: ar$extoff in Fixed Header != 0\n" ); parse_extensions(buff+ntohs(fixed->ar_extoff),&values); } if(!common->dst_proto_len){ printf("mpcd: p_recogn.c: mpoa_trigger: no destination ip to trigger! \n"); return -1; } if(common->src_proto_len) msg.content.in_info.in_dst_ip = common->dst_protocol_address; /* * If src_proto_len == 0 dst_protocol_address is found in "place" * of dst_ptocol_address. */ else msg.content.in_info.in_dst_ip = common->src_protocol_address; memcpy(msg.MPS_ctrl,mpc_control.MPS_CTRL_ATM_ADDR,ATM_ESA_LEN); msg.type = MPOA_TRIGGER_RCVD; send_to_kernel(&msg); return 1; } static int mpoa_resolution_reply( uint8_t * buff ){ int pos = 0; struct k_message msg; struct extension_values values; struct nhrp_common_h *common; struct nhrp_cie *cie; struct nhrp_fixed_h *fixed = (struct nhrp_fixed_h*)buff; memset(&values, 0, sizeof(struct extension_values)); memset(&msg,0,sizeof(struct k_message)); pos += sizeof(struct nhrp_fixed_h); common = (struct nhrp_common_h*)(buff + pos); if(!check_incoming(ntohl(common->request_ID),MPOA_RESOLUTION_REQUEST)) return -1; pos += sizeof(struct nhrp_common_h); cie = (struct nhrp_cie*)(buff + pos); if(cie->code){ print_cie_code(cie->code); return -1; } msg.content.in_info.holding_time = ntohs(cie->holding_time); if(fixed->ar_extoff) pos += parse_extensions(buff + ntohs(fixed->ar_extoff), &values); if (values.egress_cache_tag_ext_present == 0) { printf("mpcd: p_recogn.c: warning: "); printf("received MPOA Resolution Reply "); printf("with no Egress Cache Tag Extension\n"); } if(values.tag_present && values.tag == 0) { printf("mpcd: p_recogn.c: warning: "); printf("received MPOA Resolution Reply "); printf("with Egress Cache Tag Extension where tag == 0\n"); values.tag_present = 0; } if(values.tag_present){ msg.content.in_info.tag = values.tag; } msg.type = MPOA_RES_REPLY_RCVD; msg.content.in_info.in_dst_ip = common->dst_protocol_address; memcpy(msg.content.in_info.eg_MPC_ATM_addr,cie->cli_nbma_address,ATM_ESA_LEN); memcpy(msg.MPS_ctrl,mpc_control.MPS_CTRL_ATM_ADDR, ATM_ESA_LEN); if(values.service_category_present) msg.qos.txtp.traffic_class = service_category_to_traff_class(values.service_category); else msg.qos.txtp.traffic_class = ATM_UBR; send_to_kernel(&msg); keep_alive_sm_running = 1; return MPOA_RESOLUTION_REPLY; } static int checksum_check(uint8_t *buff){ uint16_t checksum; int length; struct nhrp_fixed_h *fixed = (struct nhrp_fixed_h*)buff; checksum = fixed->ar_chksum; fixed->ar_chksum = 0; length = ntohs(fixed->ar_pktsz); if(checksum != compute_ip_csum(buff,length)) return 0; return 1; } static unsigned char service_category_to_traff_class(uint32_t service_category){ unsigned char traffic_class = 0; if(service_category & CBR) traffic_class |= ATM_CBR; else traffic_class |= ATM_UBR; return traffic_class; } int recognize_packet(uint8_t * buff){ struct nhrp_fixed_h *fixed = (struct nhrp_fixed_h *)buff; uint8_t type; if(!checksum_check(buff)){ printf("mpcd: p_recogn.c: checksum error!\n"); return -1; } if (fixed->ar_extoff > (fixed->ar_pktsz - sizeof(struct nhrp_extension))) { printf("mpcd: p_recogn.c: extension offset beyond packet limits!\n"); return -1; } type = fixed->ar_op_type; dprintf("mpcd: p_recogn.c: "); switch(type){ case NHRP_PURGE_REQUEST : dprintf("purge request received.\n"); return nhrp_purge_request(buff); case MPOA_CACHE_IMPOSITION_REQUEST : dprintf("cache imposition request recieved.\n"); return mpoa_cache_imposition_request(buff); case MPOA_EGRESS_CACHE_PURGE_REPLY : dprintf("mpoa egress cache purge reply recieved.\n"); return mpoa_egress_cache_purge_reply(buff); case MPOA_KEEP_ALIVE : dprintf("keep alive recieved. \n"); return mpoa_keep_alive(buff); case MPOA_TRIGGER : printf("mpoa trigger recieved. \n"); return mpoa_trigger(buff); case MPOA_RESOLUTION_REPLY: dprintf("mpoa resolution reply recieved. \n"); return mpoa_resolution_reply(buff); default: printf("p_recogn.c: unrecognized packet: %d\n",type); return -1; } }