/* * Copyright (C) 2019 by Sukchan Lee * * This file is part of Open5GS. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include "arp-nd.h" using namespace::Tins; void _serialize_reply(uint8_t *reply_data, EthernetII &reply) { PDU::serialization_type serialized = reply.serialize(); memcpy(reply_data, serialized.data(), reply.size()); } bool _parse_arp(EthernetII &pdu) { if (pdu.payload_type() == ETHERTYPE_ARP) { const ARP& arp = pdu.rfind_pdu(); return arp.opcode() == ARP::REQUEST && pdu.dst_addr().is_broadcast(); } return false; } bool is_arp_req(uint8_t *data, uint len) { EthernetII pdu(data, len); return _parse_arp(pdu); } bool arp_reply(uint8_t *reply_data, uint8_t *request_data, uint len, const uint8_t *mac) { EthernetII pdu(request_data, len); if (_parse_arp(pdu)) { HWAddress source_mac(mac); const ARP& arp = pdu.rfind_pdu(); EthernetII reply = ARP::make_arp_reply( arp.sender_ip_addr(), arp.target_ip_addr(), arp.sender_hw_addr(), source_mac); _serialize_reply(reply_data, reply); return true; } return false; } bool _parse_nd(EthernetII &pdu) { if (pdu.payload_type() == ETHERTYPE_IPV6) { const ICMPv6& icmp6 = pdu.rfind_pdu(); return icmp6.type() == ICMPv6::NEIGHBOUR_SOLICIT; } return false; } bool is_nd_req(uint8_t *data, uint len) { if (len < MAX_ND_SIZE) { EthernetII pdu(data, len); return _parse_nd(pdu); } return false; } bool nd_reply(uint8_t *reply_data, uint8_t *request_data, uint len, const uint8_t *mac) { EthernetII pdu(request_data, len); if (_parse_nd(pdu)) { HWAddress source_mac(mac); const ICMPv6& icmp6 = pdu.rfind_pdu(); EthernetII reply(pdu.src_addr(), pdu.dst_addr()); ICMPv6 nd_reply(ICMPv6::NEIGHBOUR_ADVERT); nd_reply.target_link_layer_addr(source_mac); nd_reply.target_addr(icmp6.target_addr()); reply /= nd_reply; _serialize_reply(reply_data, reply); return true; } return false; }