Change to udpPrepare to handle empty return MAC address
luizrrocha opened this issue · 3 comments
Hi, I am using sendUdp to reply to a packet sent by a Cacti temperature logger. It is not working and using WireShark I discovered that the return package has 00:00:00:00:00:00 as the destination MAC address, which makes the packet to be ignored at the destination.
Analyzing your library, in udpPrepare() it is assumed that we already have the MAC in destmacaddr, which is not the case in a program the just uses udpServerListenOnPort() to receive and sendUdp() to reply. I have seen solutions such as setting setGwIp() to the sender's IP to force the ARP search for the sender's IP and load destmacaddr but I wanted a more default behavior from sendUdp().
I found that the following modification to udpPrepare() fixes the issue for me and would like to see if you can validate it and perhaps use it as a basis to fix the issue in the official code:
void EtherCard::udpPrepare (uint16_t sport, const uint8_t *dip, uint16_t dport) {
if(is_lan(myip, dip)) { // this works because both dns mac and destinations mac are stored in same variable - destmacaddr
if (!has_dest_mac) // we don't have the destination mac,
setMACandIPs(gPB + ETH_SRC_MAC, dip); // assume it is the same as the source UDP packet's mac
else
setMACandIPs(destmacaddr, dip); // at different times. The program could have separate variable for dns mac, then here should be
} else { // checked if dip is dns ip and separately if dip is hisip and then use correct mac.
setMACandIPs(gwmacaddr, dip);
}
Best regards,
Luiz Roberto Rocha
Rio de Janeiro - Brazil
I have experienced this problem as well.
The problems started when the is_lan() code was added to EtherCard - previously everything was sent to the Gateway MAC address, which forwarded it on to final destination, even if the IP was actually on the same subnet. This was a bit nasty but it make things a lot simpler.
When EtherCard is being used as a 'server' and replying to a UDP request, then we can just copy the SRC MAC address into the destination MAC address, for local IPs.
However if EtherCard is initiating a request, then we most perform an ARP request and create a MAC<->IP mapping for every IP we need to talk to. It starts getting complex.
Hi!
I had the same problems at first. But I think you should get better results if you don't rely on the example code... I think the problem is the missing
ether.packetLoop(ether.packetReceive());
in "loop()". (in udpClientSendOnly.ino)
Because the packetLoop has some logic to do ARP request for "hisip" to destmacaddr if it's not already there. But there are more problems:
First is that your first (few) sendUdp()s might get send out w/o a correct MAC (all zeros) and
if the first req. is lost, there will be no more "re-asking" and of course there is no timing out of (old) ARP data....
But hey! You're on a ATmega32! ;-)
i have the same problem sending udp packet to destination sw running on windows. the destination mac address remain empty so the the windows software discard packet. i solved adding two cloned methon udpPrepare->UdpPrepareMacAddr and sendUdp->sendUdpMacAddr, in this two cloned method you can specify destination mac address... this work for my use, in wire shark now i can see the right destination mac address...
void EtherCard::udpPrepareMacAddr (uint16_t sport, const uint8_t dip, uint16_t dport, const uint8_t *destmacaddr) {
setMACandIPs(destmacaddr, dip); // at different times. The program could have separate variable for dns mac, then here should be
// see http://tldp.org/HOWTO/Multicast-HOWTO-2.html
// multicast or broadcast address, #59
if ((dip[0] & 0xF0) == 0xE0 || *((unsigned long) dip) == 0xFFFFFFFF || !memcmp(broadcastip,dip,4))
EtherCard::copyMac(gPB + ETH_DST_MAC, allOnes);
gPB[ETH_TYPE_H_P] = ETHTYPE_IP_H_V;
gPB[ETH_TYPE_L_P] = ETHTYPE_IP_L_V;
memcpy_P(gPB + IP_P,iphdr,9);
gPB[IP_TOTLEN_H_P] = 0;
gPB[IP_PROTO_P] = IP_PROTO_UDP_V;
gPB[UDP_DST_PORT_H_P] = (dport>>8);
gPB[UDP_DST_PORT_L_P] = dport;
gPB[UDP_SRC_PORT_H_P] = (sport>>8);
gPB[UDP_SRC_PORT_L_P] = sport;
gPB[UDP_LEN_H_P] = 0;
gPB[UDP_CHECKSUM_H_P] = 0;
gPB[UDP_CHECKSUM_L_P] = 0;
}
void EtherCard::sendUdpMacAddr (const char *data, uint8_t datalen, uint16_t sport,
const uint8_t *dip, uint16_t dport, const uint8_t *destmacaddr) {
udpPrepareMacAddr(sport, dip, dport, destmacaddr);
if (datalen>220)
datalen = 220;
memcpy(gPB + UDP_DATA_P, data, datalen);
udpTransmit(datalen);
}
sorry for my english and for any form error in C++
bye
Alex