Line data Source code
1 : /* 2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. 3 : * Copyright Contributors to the OpenSDN project 4 : */ 5 : 6 : #include <stdint.h> 7 : #include <vr_defs.h> 8 : #include <cmn/agent_cmn.h> 9 : #include <pkt/pkt_init.h> 10 : #include <pkt/control_interface.h> 11 : #include <oper/interface_common.h> 12 : #include <services/icmp_proto.h> 13 : #include <boost/scoped_array.hpp> 14 : 15 0 : IcmpHandler::IcmpHandler(Agent *agent, boost::shared_ptr<PktInfo> info, 16 0 : boost::asio::io_context &io) 17 0 : : ProtoHandler(agent, info, io), icmp_(pkt_info_->transp.icmp) { 18 0 : icmp_len_ = ntohs(pkt_info_->ip->ip_len) - (pkt_info_->ip->ip_hl * 4); 19 0 : } 20 : 21 0 : IcmpHandler::~IcmpHandler() { 22 0 : } 23 : 24 0 : bool IcmpHandler::Run() { 25 : 26 0 : IcmpProto *icmp_proto = agent()->GetIcmpProto(); 27 : Interface *itf = 28 0 : agent()->interface_table()->FindInterface(GetInterfaceIndex()); 29 0 : if (itf == NULL) { 30 0 : icmp_proto->IncrStatsIntfNotInst(); 31 0 : return true; 32 : } 33 0 : VmInterface *vm_itf = static_cast<VmInterface *>(itf); 34 0 : if (!vm_itf->layer3_forwarding()) { 35 0 : icmp_proto->IncrStatsNoL3Fwd(); 36 0 : return true; 37 : } 38 0 : switch (icmp_->icmp_type) { 39 0 : case ICMP_ECHO: 40 0 : if (CheckPacket()) { 41 0 : icmp_proto->IncrStatsGwPing(); 42 0 : SendResponse(vm_itf); 43 : } else 44 0 : icmp_proto->IncrStatsGwPingErr(); 45 0 : return true; 46 : 47 0 : default: 48 0 : icmp_proto->IncrStatsDrop(); 49 0 : return true; 50 : } 51 : } 52 : 53 0 : bool IcmpHandler::CheckPacket() { 54 0 : if (pkt_info_->len < (sizeof(struct ether_header) + ntohs(pkt_info_->ip->ip_len))) 55 0 : return false; 56 : 57 0 : uint16_t checksum = icmp_->icmp_cksum; 58 0 : icmp_->icmp_cksum = 0; 59 0 : if (checksum == Csum((uint16_t *)icmp_, icmp_len_, 0)) 60 0 : return true; 61 : 62 0 : return false; 63 : } 64 : 65 0 : void IcmpHandler::SendResponse(VmInterface *vm_intf) { 66 : // Max size of buffer 67 0 : char *ptr = (char *)pkt_info_->pkt; 68 0 : uint16_t buf_len = pkt_info_->max_pkt_len; 69 : 70 : // Copy the ICMP payload 71 0 : boost::scoped_array<char> icmp_payload(new char[icmp_len_]); 72 0 : memcpy(icmp_payload.get(), icmp_, icmp_len_); 73 : 74 0 : uint16_t len = 0; 75 : 76 : // Form ICMP Packet with following 77 : // EthHdr - IP Header - ICMP Header 78 0 : len += EthHdr(ptr + len, buf_len - len, 79 0 : MacAddress(pkt_info_->eth->ether_dhost), 80 0 : MacAddress(pkt_info_->eth->ether_shost), 81 0 : ETHERTYPE_IP, vm_intf->tx_vlan_id()); 82 : 83 0 : uint16_t ip_len = sizeof(struct ip) + icmp_len_; 84 : 85 0 : len += IpHdr(ptr + len, buf_len - len, ip_len, 86 0 : htonl(pkt_info_->ip_daddr.to_v4().to_ulong()), 87 0 : htonl(pkt_info_->ip_saddr.to_v4().to_ulong()), 88 : IPPROTO_ICMP, DEFAULT_IP_ID, DEFAULT_IP_TTL); 89 : 90 : // Restore the ICMP header copied earlier 91 0 : struct icmp *hdr = (struct icmp *) (ptr + len); 92 0 : memcpy(ptr + len, icmp_payload.get(), icmp_len_); 93 0 : len += icmp_len_; 94 : 95 : // Change type to reply 96 0 : hdr->icmp_type = ICMP_ECHOREPLY; 97 : // Recompute ICMP checksum 98 0 : IcmpChecksum((char *)hdr, icmp_len_); 99 0 : pkt_info_->set_len(len); 100 : 101 : uint32_t interface = 102 0 : ((pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ? 103 0 : pkt_info_->agent_hdr.cmd_param : GetInterfaceIndex()); 104 : uint16_t command = 105 0 : ((pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ? 106 0 : AgentHdr::TX_ROUTE : AgentHdr::TX_SWITCH); 107 0 : Send(interface, pkt_info_->vrf, command, PktHandler::ICMP); 108 0 : }