Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change to udpPrepare to handle empty return MAC address #181

Open
luizrrocha opened this issue Mar 8, 2015 · 3 comments
Open

Change to udpPrepare to handle empty return MAC address #181

luizrrocha opened this issue Mar 8, 2015 · 3 comments
Labels

Comments

@luizrrocha
Copy link

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

@njh
Copy link
Owner

njh commented Mar 9, 2015

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.

@jsl123
Copy link

jsl123 commented Jun 15, 2015

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! ;-)

@iz1gww
Copy link

iz1gww commented Dec 22, 2015

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants