int enc424j600_receivecallback( uint16_t packetlen ) { uint8_t is_the_packet_for_me = 1; unsigned char i; unsigned char ipproto; //First and foremost, make sure we have a big enough packet to work with. if (packetlen < 8) { // ERROR: Received runt packet return 1; } //macto (ignore) our mac filter handles this. enc424j600_dumpbytes( 6 ); enc424j600_popblob( macfrom, 6 ); //Make sure it's ethernet! if (enc424j600_pop8() != 0x08) { // ERROR: Not an ethernet packet return 1; } //Is it ARP? if (enc424j600_pop8() == 0x06) { HandleArp(); return 0; } //otherwise it's standard IP //So, we're expecting a '45 if (enc424j600_pop8() != 0x45) { // ERROR: Not an IP packet return 1; } enc424j600_pop8(); //differentiated services field. iptotallen = enc424j600_pop16(); enc424j600_dumpbytes( 5 ); //ID, Offset+FLAGS+TTL ipproto = enc424j600_pop8(); enc424j600_pop16(); //header checksum enc424j600_popblob( ipsource, 4 ); for (i = 0; i < 4; i++) { unsigned char m = ~MyMask[i]; unsigned char ch = enc424j600_pop8(); if (ch == MyIP[i] || (ch & m) == 0xff) { continue; } is_the_packet_for_me = 0; } //Tricky, for DHCP packets, we have to detect it even if it is not to us. if (ipproto == 17) { remoteport = enc424j600_pop16(); localport = enc424j600_pop16(); } if (!is_the_packet_for_me) { // ERROR: Packet is not for us return 1; } //XXX TODO Handle IPL > 5 (IHL?) switch(ipproto) { // ICMP case 1: { HandleICMP(); break; } // UDP case 17: { HandleUDP(enc424j600_pop16()); break; } default: { break; } } return 0; //finishcb: // enc424j600_finish_callback_now(); }
void HandleDHCP( uint16_t len ) { uint8_t tmpip[4]; uint8_t tmp[4]; uint8_t optionsleft = 48; //We only allow for up to 48 options uint8_t is_ack_packet = 0; uint16_t first4, second4; POP16; //Clear out checksum //Process DHCP! if( POP != 2 ) return; //Not a reply? if( POP != 1 ) return; //Not Ethernet? POP16; //size of packets + Hops //Make sure transaction IDs match. enc424j600_popblob( tmp, 4 ); if( memcmp( tmp, MyMAC, 4 ) != 0 ) { //Not our request? return; } enc424j600_dumpbytes( 8 ); //time elapsed + bootpflags + Client IP address enc424j600_popblob( tmpip, 4 ); //MY IP ADDRESS!!! enc424j600_dumpbytes( 0x18 + 0xc0 ); //Next IP + Relay IP + Mac + Padding + server name + boot name first4 = POP16; second4 = POP16; if( first4 != 0x6382 || second4 != 0x5363 ) { return; } //Ok, we know we have a valid DHCP packet. //We dont want to get stuck, so we will eventually bail if we have an issue pasrsing. while( optionsleft-- ) { uint8_t option = POP; uint8_t length = POP; switch(option) { case 0x35: //DHCP Message Type { if( length < 1 ) return; uint8_t rqt = POP; if( rqt == 0x02 ) { //We have an offer, extend a request. //We will ignore the rest of the packet. enc424j600_finish_callback_now(); RequestNewIP( 3, tmpip, ipsource ); //Request return; } else if( rqt == 0x05 ) // We received an ack, accept it. { //IP Is valid. is_ack_packet = 1; if( 0 == dhcp_seconds_remain ) dhcp_seconds_remain = 0xffff; memcpy( MyIP, tmpip, 4 ); } length--; break; } case 0x3a: //Renewal time { if( length < 4 || !is_ack_packet ) break; first4 = POP16; second4 = POP16; // printf( "LEASE TIME: %d %d\n", first4, second4 ); if( first4 ) { dhcp_seconds_remain = 0xffff; } else { dhcp_seconds_remain = second4; } length -= 4; break; } case 0x01: //Subnet mask { if( length < 4 || !is_ack_packet ) break; enc424j600_popblob( MyMask, 4 ); length -= 4; break; } case 0x03: //Router mask { if( length < 4 || !is_ack_packet ) break; enc424j600_popblob( MyGateway, 4 ); length -= 4; break; } case 0xff: //End of list. enc424j600_finish_callback_now(); if( is_ack_packet ) GotDHCPLease(); return; case 0x42: //Time server case 0x06: //DNS server default: break; } enc424j600_dumpbytes( length ); } }
static void HandleArp (void) { unsigned short i; unsigned char sendermac_ip_and_targetmac[16]; // unsigned char senderip[10]; //Actually sender ip + target mac, put in one to shrink code. unsigned short proto; unsigned char opcode; // unsigned char ipproto; enc424j600_pop16(); //Hardware type proto = enc424j600_pop16(); enc424j600_pop16(); //hwsize, protosize opcode = enc424j600_pop16(); //XXX: This includes "code" as well, it seems. switch( opcode ) { // ARP Request case 1: { unsigned char match; enc424j600_popblob( sendermac_ip_and_targetmac, 16 ); match = 1; //sendhex2( 0xff ); //Target IP (check for copy) for( i = 0; i < 4; i++ ) if( enc424j600_pop8() != MyIP[i] ) match = 0; if( match == 0 ) return; //We must send a response, so we termiante the packet now. enc424j600_finish_callback_now(); enc424j600_startsend( NetGetScratch() ); send_etherlink_header( 0x0806 ); enc424j600_push16( 0x0001 ); //Ethernet enc424j600_push16( proto ); //Protocol enc424j600_push16( 0x0604 ); //HW size, Proto size enc424j600_push16( 0x0002 ); //Reply enc424j600_pushblob( MyMAC, 6 ); enc424j600_pushblob( MyIP, 4 ); enc424j600_pushblob( sendermac_ip_and_targetmac, 10 ); // do not send target mac. enc424j600_endsend(); // Have a match! break; } // ARP Reply case 2: { uint8_t sender_mac_and_ip_and_comp_mac[16]; enc424j600_popblob( sender_mac_and_ip_and_comp_mac, 16 ); enc424j600_finish_callback_now(); //First, make sure that we're the ones who are supposed to receive the ARP. for( i = 0; i < 6; i++ ) { if( sender_mac_and_ip_and_comp_mac[i+10] != MyMAC[i] ) break; } if( i != 6 ) break; //We're the right recipent. Put it in the table. memcpy( &ClientArpTable[ClientArpTablePointer], sender_mac_and_ip_and_comp_mac, 10 ); ClientArpTablePointer = (ClientArpTablePointer+1)%ARP_CLIENT_TABLE_SIZE; break; } default: { //???? don't know what to do. return; } } }