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