//--------------------------------------------------------------------------- // Search the entity with the IPv4 address 'addr' struct cx_entity *nasmt_CLASS_cx4(struct sk_buff *skb, unsigned char dscp, int *paddr_type, unsigned char *cx_index) { //--------------------------------------------------------------------------- unsigned char cxi; uint32_t daddr; struct cx_entity *cx=NULL; struct classifier_entity *pclassifier=NULL; struct in_addr masked_addr; #ifdef NAS_DEBUG_CLASS printk("nasmt_CLASS_cx4: begin\n"); #endif if (skb!=NULL) { daddr = ((struct iphdr*)(skb_network_header(skb)))->daddr; if (daddr != INADDR_ANY) { #ifdef NAS_DEBUG_CLASS printk("nasmt_CLASS_cx4: SOURCE ADDR %d.%d.%d.%d",NIPADDR(ip_hdr(skb)->saddr)); printk(" DEST ADDR %d.%d.%d.%d\n",NIPADDR(ip_hdr(skb)->daddr)); #endif if (ipv4_is_multicast(ip_hdr(skb)->daddr)) { // TO BE CHECKED *paddr_type = NAS_IPV4_ADDR_MC_SIGNALLING; } else { if (ipv4_is_lbcast(ip_hdr(skb)->daddr)) { // TO BE CHECKED *paddr_type = NAS_IPV4_ADDR_BROADCAST; } else { if (IN_CLASSA(ip_hdr(skb)->daddr) || IN_CLASSB(ip_hdr(skb)->daddr) || IN_CLASSC(ip_hdr(skb)->daddr)) { *paddr_type = NAS_IPV4_ADDR_UNICAST; cxi = 0; (*cx_index)++; pclassifier = gpriv->cx[cxi].sclassifier[dscp]; while (pclassifier!=NULL) { // verify that this is an IPv4 classifier if ((pclassifier->version == NAS_VERSION_4) || (pclassifier->version == NAS_VERSION_DEFAULT)) { nasmt_create_mask_ipv4_addr(&masked_addr, pclassifier->dplen); if (IN_ARE_ADDR_MASKED_EQUAL(&ip_hdr(skb)->daddr, &(pclassifier->daddr.ipv4), &masked_addr)) { #ifdef NAS_DEBUG_CLASS printk("nasmt_CLASS_cx4: IP MASK MATCHED: found cx %d: %d.%d.%d.%d/%d\n",cxi, NIPADDR(pclassifier->daddr.ipv4), pclassifier->dplen); #endif return &gpriv->cx[cxi]; } } // goto to next classification rule for the connection pclassifier = pclassifier->next; } } else { *paddr_type = NAS_IPV4_ADDR_UNKNOWN; } } } } } return cx; }
//--------------------------------------------------------------------------- // Search the sending function for IP Packet void nasmt_CLASS_send(struct sk_buff *skb) { //--------------------------------------------------------------------------- struct classifier_entity *pclassifier, *sp; uint8_t *protocolh = NULL; uint8_t version; uint8_t protocol, dscp; uint16_t classref; struct cx_entity *cx; #ifdef NAS_DEBUG_CLASS char sfct[10], sprotocol[10]; #endif struct net_device *dev = gdev; unsigned char cx_index,no_connection; int addr_type; struct in6_addr masked6_addr; struct in_addr masked_addr; // RARP vars struct arphdr *rarp; unsigned char *rarp_ptr; /* s for "source", t for "target" */ __be32 sip, tip; unsigned char *sha, *tha; #ifdef NAS_DEBUG_CLASS printk("nasmt_CLASS_send: begin -\n"); #endif if (skb==NULL) { printk("nasmt_CLASS_send - input parameter skb is NULL \n"); return; } //*** #ifdef NAS_DEBUG_SEND printk("nasmt_CLASS_send - Received IP packet to transmit:"); if ((skb->data) != NULL) { if (skb->len<100) nasmt_TOOL_print_buffer(skb->data,skb->len); else nasmt_TOOL_print_buffer(skb->data,100); } #endif //*** // find all connections related to socket cx_index = 0; no_connection = 1; cx = NULL; #ifdef NAS_DEBUG_CLASS printk("nasmt_CLASS_send: [before switch on IP protocol version] \n"); #endif // Get mobile connexion entity, protocol and dscp from IP packet switch (ntohs(skb->protocol)) { case ETH_P_IPV6: #ifdef NAS_DEBUG_CLASS printk("nasmt_CLASS_send : skb->protocol : IPv6 \n"); #endif version = NAS_VERSION_6; addr_type = NAS_IPV6_ADDR_UNKNOWN; protocolh = nasmt_TOOL_get_protocol6(ipv6_hdr(skb), &protocol); dscp = nasmt_TOOL_get_dscp6 (ipv6_hdr(skb)); cx = nasmt_CLASS_cx6 (skb, dscp, &addr_type, &cx_index); #ifdef NAS_DEBUG_CLASS printk("nasmt_CLASS_send - ETH_P_IPV6 skb %p dscp %d gpriv %p cx_index %p \n",skb, dscp, gpriv, &cx_index); #endif // find in default DSCP a valid classification if (cx == NULL) { switch (addr_type) { case NAS_IPV6_ADDR_MC_SIGNALLING: case NAS_IPV6_ADDR_UNICAST: pclassifier=(&gpriv->cx[0])->sclassifier[NAS_DSCP_DEFAULT]; while (pclassifier!=NULL) { if ((pclassifier->version == NAS_VERSION_6) || (pclassifier->version == NAS_VERSION_DEFAULT)) { // ok found default classifier for this packet nasmt_create_mask_ipv6_addr(&masked6_addr, pclassifier->dplen); if (IN6_ARE_ADDR_MASKED_EQUAL(&pclassifier->daddr.ipv6, &ipv6_hdr(skb)->daddr, &masked6_addr)) { // then force dscp cx = &gpriv->cx[0]; #ifdef NAS_DEBUG_CLASS printk("nasmt_CLASS_send - ETH_P_IPV6 FOUND NAS_DSCP_DEFAULT with IN6_ARE_ADDR_MASKED_EQUAL(%d bits)\n",pclassifier->dplen); #endif dscp = NAS_DSCP_DEFAULT; break; } else { if(IN6_IS_ADDR_UNSPECIFIED(&pclassifier->daddr.ipv6)) { cx = &gpriv->cx[0]; #ifdef NAS_DEBUG_CLASS printk("nasmt_CLASS_send - ETH_P_IPV6 FOUND NAS_DSCP_DEFAULT with IN6_IS_ADDR_UNSPECIFIED\n"); #endif dscp = NAS_DSCP_DEFAULT; break; } } } pclassifier = pclassifier->next; } break; // should have found a valid classification rule case NAS_IPV6_ADDR_UNKNOWN: default: printk("nasmt_CLASS_send: No corresponding address type\n"); } } break; case ETH_P_ARP: #ifdef NAS_DEBUG_CLASS printk("nasmt_CLASS_send : skb->protocol : ARP \n"); #endif version = NAS_VERSION_4; addr_type = NAS_IPV4_ADDR_BROADCAST; dscp = 0; cx = NULL; // Basic sanity checks can be done without the lock rarp = (struct arphdr *)skb_network_header(skb); if (rarp) { if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd)) { printk("nasmt_CLASS_send: ARP PACKET WRONG ADDR LEN or WRONG ARP HEADER TYPE\n"); break; } } else { printk("nasmt_CLASS_send: ARP HEADER POINTER IS NULL\n"); break; } // If it's not Ethernet, delete it. if (rarp->ar_pro != htons(ETH_P_IP)) { printk("nasmt_CLASS_send: ARP PACKET PROTOCOL IS NOT ETHERNET\n"); break; } rarp_ptr = (unsigned char *) (rarp + 1); sha = rarp_ptr; rarp_ptr += dev->addr_len; memcpy(&sip, rarp_ptr, 4); rarp_ptr += 4; tha = rarp_ptr; rarp_ptr += dev->addr_len; memcpy(&tip, rarp_ptr, 4); #ifdef NAS_DEBUG_CLASS printk("nasmt_CLASS_send: ARP DEST IP transport IP = %d.%d.%d.%d\n",NIPADDR(tip)); #endif pclassifier=(&gpriv->cx[0])->sclassifier[NAS_DSCP_DEFAULT]; while (pclassifier!=NULL) { if ((pclassifier->version == NAS_VERSION_4) || (pclassifier->version == NAS_VERSION_DEFAULT)) { // ok found default classifier for this packet nasmt_create_mask_ipv4_addr(&masked_addr, pclassifier->dplen); #ifdef NAS_DEBUG_CLASS printk("nasmt_CLASS_send: MASK = %d.%d.%d.%d\n",NIPADDR(masked_addr.s_addr)); #endif // if (IN_ARE_ADDR_MASKED_EQUAL(&pclassifier->daddr.ipv4, &tip, &masked_addr.s_addr)) { // then force dscp cx = &gpriv->cx[0]; #ifdef NAS_DEBUG_CLASS printk("nasmt_CLASS_send: ETH_P_ARP FOUND NAS_DSCP_DEFAULT with IN_ARE_ADDR_MASKED_EQUAL(%d bits)\n", pclassifier->dplen); #endif dscp = NAS_DSCP_DEFAULT; break; } else { if (INADDR_ANY == pclassifier->daddr.ipv4) { cx = &gpriv->cx[0]; #ifdef NAS_DEBUG_CLASS printk("nasmt_CLASS_send: ETH_P_ARP FOUND NAS_DSCP_DEFAULT with INADDR_ANY\n"); #endif dscp = NAS_DSCP_DEFAULT; break; } } } pclassifier = pclassifier->next; } break; case ETH_P_IP: #ifdef NAS_DEBUG_CLASS printk("nasmt_CLASS_send : skb->protocol : IPv4 \n"); #endif version = NAS_VERSION_4; addr_type = NAS_IPV4_ADDR_UNKNOWN; dscp = nasmt_TOOL_get_dscp4((struct iphdr *)(skb_network_header(skb))); cx = nasmt_CLASS_cx4(skb, dscp, &addr_type, &cx_index); protocolh = nasmt_TOOL_get_protocol4((struct iphdr *)(skb_network_header(skb)), &protocol); // find in default DSCP a valid classification if (cx == NULL) { switch (addr_type) { case NAS_IPV4_ADDR_MC_SIGNALLING: case NAS_IPV4_ADDR_UNICAST: case NAS_IPV4_ADDR_BROADCAST: pclassifier=(&gpriv->cx[0])->sclassifier[NAS_DSCP_DEFAULT]; while (pclassifier != NULL) { if ((pclassifier->version == NAS_VERSION_4) || (pclassifier->version == NAS_VERSION_DEFAULT)) { // ok found default classifier for this packet nasmt_create_mask_ipv4_addr(&masked_addr, pclassifier->dplen); #ifdef NAS_DEBUG_CLASS printk("nasmt_CLASS_send : MASK = %d.%d.%d.%d\n", NIPADDR(masked_addr.s_addr)); #endif if (IN_ARE_ADDR_MASKED_EQUAL(&pclassifier->daddr.ipv4, &ip_hdr(skb)->daddr, &masked_addr.s_addr)) { // then force dscp cx = &gpriv->cx[0]; #ifdef NAS_DEBUG_CLASS printk("nasmt_CLASS_send : ETH_P_IP FOUND NAS_DSCP_DEFAULT with IN_ARE_ADDR_MASKED_EQUAL(%d bits)\n",pclassifier->dplen); #endif dscp = NAS_DSCP_DEFAULT; break; } else { if(INADDR_ANY == pclassifier->daddr.ipv4) { cx = &gpriv->cx[0]; #ifdef NAS_DEBUG_CLASS printk("nasmt_CLASS_send : ETH_P_IP FOUND NAS_DSCP_DEFAULT with INADDR_ANY\n"); #endif dscp = NAS_DSCP_DEFAULT; break; } } } pclassifier = pclassifier->next; } break; // should have found a valid classification rule case NAS_IPV4_ADDR_UNKNOWN: default: printk("nasmt_CLASS_send: No corresponding address type\n"); } } #ifdef NAS_DEBUG_CLASS //printk("nasmt_CLASS_send: ETH_P_IP Received IPv4 packet (%02X), dscp = %d, cx = %08X\n",ntohs(skb->protocol),dscp,cx); if (cx) printk("nasmt_CLASS_send: ETH_P_IP Received IPv4 packet (%02X), dscp = %d, cx = %d\n",ntohs(skb->protocol),dscp,cx->lcr); else printk("nasmt_CLASS_send: ETH_P_IP Received IPv4 packet (%02X), dscp = %d, No valid connection\n",ntohs(skb->protocol),dscp); #endif break; default: printk("nasmt_CLASS_send: Unknown IP version protocol\n"); version = 0; return; } #ifdef NAS_DEBUG_SEND_DETAIL printk("nasmt_CLASS_send: [before if (cx != NULL)]\n"); #endif // If a valid connection for the DSCP/EXP with destination address // is found scan all protocol-based classification rules if (cx != NULL) { classref = 0; sp = NULL; if (cx->state!=NAS_CX_DCH) { #ifdef NAS_DEBUG_CLASS printk("nasmt_CLASS_send: UE not connected, in state %d. Packet is dropped\n",cx->state); #endif return; } #ifdef NAS_DEBUG_CLASS printk("nasmt_CLASS_send: DSCP %d version %d: looking for classifier entry\n",dscp, version); #endif for (pclassifier=cx->sclassifier[dscp]; pclassifier!=NULL; pclassifier=pclassifier->next) { #ifdef NAS_DEBUG_CLASS printk("nasmt_CLASS_send: DSCP %d p->classref=%d,p->protocol=%d,p->version=%d\n",dscp,pclassifier->classref,pclassifier->protocol,pclassifier->version); #endif // normal rule checks that network protocol version matches if ((pclassifier->version == version) || (pclassifier->version == NAS_VERSION_DEFAULT)) { //printk("nasmt_CLASS_send: IP version are equals\n"); sp=pclassifier; classref=sp->classref; #ifdef NAS_DEBUG_SEND_DETAIL printk("nasmt_CLASS_send: classifier found for dscp %u \n", dscp); #endif break; } } if (sp!=NULL) { #ifdef NAS_DEBUG_CLASS //char sfct[10], sprotocol[10]; // classifier entity found. Print its parameters if (sp->fct==nasmt_COMMON_QOS_send) strcpy(sfct, "data xfer"); if (sp->fct==nasmt_CTL_send) strcpy(sfct, "iocontrol"); if (sp->fct==nasmt_COMMON_del_send) strcpy(sfct, "delete"); if (sp->fct==nasmt_ASCTL_DC_send_sig_data_request) strcpy(sfct, "DC-SAP"); switch(protocol) { case NAS_PROTOCOL_UDP: strcpy(sprotocol, "udp"); printk("udp packet\n"); break; case NAS_PROTOCOL_TCP: strcpy(sprotocol, "tcp"); printk("tcp packet\n"); break; case NAS_PROTOCOL_ICMP4: strcpy(sprotocol, "icmp4"); printk("icmp4 packet\n"); break; case NAS_PROTOCOL_ICMP6: strcpy(sprotocol, "icmp6"); nasmt_TOOL_pk_icmp6((struct icmp6hdr*)protocolh); break; default: strcpy(sprotocol, "other L4"); break; } printk("nasmt_CLASS_send: (dscp %u, %s) received, (classref %u, fct %s, drb_id %u) classifier rule\n", dscp, sprotocol, sp->classref, sfct, sp->rab_id); #endif //forward packet to the correct entity if (sp->fct!=NULL) { sp->fct(skb, cx, sp); } else { printk("\n\nnasmt_CLASS_send: ERROR : CLASSIFIER FUNCTION IS NULL\n\n"); } no_connection = 0; // end : if classifier entry match found } else { printk("nasmt_CLASS_send: no corresponding item in the classifier list, so the message is dropped\n"); printk("nasmt_CLASS_send: packet parameters: dscp %u, %s\n", dscp, sprotocol); nasmt_COMMON_del_send(skb, cx, NULL); // Note MW: LG has commented this line. Why? } } // if connection found #ifdef NAS_DEBUG_CLASS if (no_connection == 1) { printk("nasmt_CLASS_send: no corresponding connection, so the message is dropped\n"); } printk("nasmt_CLASS_send: end\n"); #endif }