/**************************************************************************** * net/arp/arp_acd.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include "arp/arp.h" #include "netlink/netlink.h" #include "utils/utils.h" /**************************************************************************** * Private Data ****************************************************************************/ /**************************************************************************** * Private Function Prototypes ****************************************************************************/ static void arp_acd_try_announce(FAR void *net_dev); /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: arp_acd_arrange_announce * * Description: * creat work_queue to send ARP announce * * Input Parameters: * dev - The device driver structure to use in the send operation * * Returned Value: * none * ****************************************************************************/ static void arp_acd_arrange_announce(FAR struct net_driver_s *dev) { if (dev->d_acd.need_announce == true) { return; } if (!work_available(&dev->d_acd.work)) { nerr("ERROR work unavailable \n"); return; } int ret = work_queue(LPWORK, &dev->d_acd.work, arp_acd_try_announce, (FAR void *)dev, DSEC2TICK(dev->d_acd.ttw)); if (ret != OK) { nerr("ERROR ret %d \n", ret); } } /**************************************************************************** * Name: arp_acd_send_finish * * Description: * send finish process of ARP Address Conflict Detection * * Input Parameters: * dev - The device driver structure to use in the send operation * result - arp send result * * Returned Value: * none * ****************************************************************************/ static void arp_acd_send_finish(FAR struct net_driver_s *dev, int result) { if (result < 0) { nerr("ERROR: arp_send result: %d\n", result); } else { arp_acd_arrange_announce(dev); } } /**************************************************************************** * Name: arp_acd_try_announce * * Description: * process status of ARP Address Conflict Detection * * Input Parameters: * net_dev - The device driver structure to use in the send operation * * Returned Value: * none * ****************************************************************************/ static void arp_acd_try_announce(FAR void *net_dev) { FAR struct net_driver_s *dev = net_dev; if (dev == NULL || dev->d_acd.state != ARP_ACD_STATE_ANNOUNCING) { return; } /* arp_acd_announce */ arp_send_async(dev->d_ipaddr, arp_acd_send_finish); dev->d_acd.sendnum++; if (dev->d_acd.sendnum >= ANNOUNCE_NUM) { dev->d_acd.sendnum = 0; dev->d_acd.ttw = 0; dev->d_acd.state = ARP_ACD_STATE_FINISH; } else { dev->d_acd.ttw = ANNOUNCE_INTERVAL * ARP_ACD_TICKS_PER_SECOND; } } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: arp_acd_update * * Description: * interface of ARP Address Conflict Detection monitor * * Input Parameters: * dev - The device driver structure to use in the send operation * * Returned Value: * none * ****************************************************************************/ void arp_acd_update(FAR struct net_driver_s *dev) { FAR struct arp_hdr_s *arp = ARPBUF; clock_t now = clock_systime_ticks(); if (dev->d_acd.conflict_flag == ARP_ACD_ADDRESS_CONFLICT) { return; } if (!net_ipv4addr_hdrcmp(arp->ah_sipaddr, &dev->d_ipaddr) || (memcmp(arp->ah_shwaddr, dev->d_mac.ether.ether_addr_octet, sizeof(arp->ah_shwaddr)) == 0)) { return; } if ((dev->d_acd.lastconflict > 0) && (now - dev->d_acd.lastconflict) < DSEC2TICK(DEFEND_INTERVAL * ARP_ACD_TICKS_PER_SECOND)) { nerr("ERROR: detect conflict again \n"); dev->d_acd.lastconflict = 0; dev->d_acd.conflict_flag = ARP_ACD_ADDRESS_CONFLICT; if (dev->d_acd.state != ARP_ACD_STATE_ANNOUNCING) { dev->d_acd.state = ARP_ACD_STATE_INIT; dev->d_acd.sendnum = 0; dev->d_acd.ttw = 0; } } else { nerr("ERROR: detect conflict \n"); dev->d_acd.lastconflict = now; if (dev->d_acd.state != ARP_ACD_STATE_ANNOUNCING) { arp_acd_arrange_announce(dev); dev->d_acd.state = ARP_ACD_STATE_ANNOUNCING; dev->d_acd.sendnum = 0; dev->d_acd.ttw = ANNOUNCE_WAIT * ARP_ACD_TICKS_PER_SECOND; } } } /**************************************************************************** * Name: arp_acd_setup * * Description: * set up interface of ARP Address Conflict Detection * * Input Parameters: * dev - The device driver structure to use in the send operation * * Returned Value: * none * ****************************************************************************/ void arp_acd_setup(FAR struct net_driver_s *dev) { if (dev->d_acd.need_announce == false) { return; } dev->d_acd.state = ARP_ACD_STATE_ANNOUNCING; dev->d_acd.sendnum = 0; dev->d_acd.ttw = 0; dev->d_acd.conflict_flag = ARP_ACD_ADDRESS_NO_CONFLICT; dev->d_acd.lastconflict = 0; dev->d_acd.need_announce = false; arp_acd_arrange_announce(dev); } /**************************************************************************** * Name: arp_acd_set_addr * * Description: * setting address interface of ARP Address Conflict Detection * * Input Parameters: * dev - The device driver structure to use in the send operation * * Returned Value: * none * ****************************************************************************/ void arp_acd_set_addr(FAR struct net_driver_s *dev) { if (!net_ipv4addr_cmp(dev->d_ipaddr, INADDR_ANY)) { dev->d_acd.need_announce = true; if (IFF_IS_UP(dev->d_flags)) { arp_acd_setup(dev); } } else { dev->d_acd.need_announce = false; dev->d_acd.state = ARP_ACD_STATE_INIT; } }