/** * Send a UDP packet across the network to a certain destination * @param udpptr Pointer to UDP control block * @param datalen Length of data to be sent * @param buf Data to be sent * @return OK if packet is sent properly, otherwise SYSERR */ syscall udpSend(struct udp *udpptr, ushort datalen, void *buf) { struct packet *pkt; struct udpPkt *udppkt = NULL; int result; pkt = netGetbuf(); if (SYSERR == (int)pkt) { return SYSERR; } /* Set the length of the packet and set the curr pointer back that * length */ pkt->len = UDP_HDR_LEN + datalen; /* Round the datalength to maintain word alignment */ pkt->curr -= (3 + (ulong)(pkt->len)) & ~0x03; /* Set UDP header fields and fill the packet with the data */ udppkt = (struct udpPkt *)(pkt->curr); udppkt->srcPort = hs2net(udpptr->localpt); udppkt->dstPort = hs2net(udpptr->remotept); udppkt->len = hs2net(pkt->len); udppkt->chksum = 0; /* Zero out the data buffer so empty space is padded with zeroes */ bzero(udppkt->data, datalen); memcpy(udppkt->data, buf, datalen); /* Calculate UDP checksum (which happens to be the same as TCP's) */ udppkt->chksum = udpChksum(pkt, UDP_HDR_LEN + datalen, &(udpptr->localip), &(udpptr->remoteip)); /* Send the UDP packet through IP */ result = ipv4Send(pkt, &(udpptr->localip), &(udpptr->remoteip), IPv4_PROTO_UDP); if (SYSERR == netFreebuf(pkt)) { return SYSERR; } return result; }
static struct packet *makePkt(ushort localpt, ushort remotept, struct netaddr *localip, struct netaddr *remoteip, ushort datalen, void *buf) { struct packet *pkt; struct udpPkt *udppkt = NULL; pkt = netGetbuf(); if (SYSERR == (int)pkt) { return (struct packet *)SYSERR; } /* Set the length of the packet and set the curr pointer back that * length */ pkt->len = UDP_HDR_LEN + datalen; /* Round the datalength to maintain word alignment */ pkt->curr -= (3 + (ulong)(pkt->len)) & ~0x03; /* Set UDP header fields and fill the packet with the data */ udppkt = (struct udpPkt *)(pkt->curr); udppkt->srcPort = hs2net(localpt); udppkt->dstPort = hs2net(remotept); udppkt->len = hs2net(pkt->len); udppkt->chksum = 0; /* Zero out the data buffer so empty space is padded with zeroes */ bzero(udppkt->data, datalen); memcpy(udppkt->data, buf, datalen); udppkt->chksum = udpChksum(pkt, UDP_HDR_LEN + datalen, localip, remoteip); return pkt; }
/** * Receive a UDP packet and place it in the UDP device's input buffer * @param pkt Incoming UDP packet * @param src Source address * @param dst Destination address * @return OK if UDP packet is received properly, otherwise SYSERR */ syscall udpRecv(struct packet *pkt, struct netaddr *src, struct netaddr *dst) { struct udpPkt *udppkt; struct udp *udpptr; struct udpPkt *tpkt; #ifdef TRACE_UDP char strA[20]; char strB[20]; #endif /* TRACE_UDP */ irqmask im; /* Point to the start of the UDP header */ udppkt = (struct udpPkt *)pkt->curr; if (NULL == udppkt) { UDP_TRACE("Invalid UDP packet."); netFreebuf(pkt); return SYSERR; } /* Calculate checksum */ if (0 != udpChksum(pkt, net2hs(udppkt->len), src, dst)) { UDP_TRACE("Invalid UDP checksum."); netFreebuf(pkt); return SYSERR; } /* Convert UDP header fields to host order */ udppkt->srcPort = net2hs(udppkt->srcPort); udppkt->dstPort = net2hs(udppkt->dstPort); udppkt->len = net2hs(udppkt->len); im = disable(); /* Locate the UDP socket (device) for the UDP packet */ udpptr = udpDemux(udppkt->dstPort, udppkt->srcPort, dst, src); if (NULL == udpptr) { #ifdef TRACE_UDP UDP_TRACE("No UDP socket found for this UDP packet."); netaddrsprintf(strA, src); netaddrsprintf(strB, dst); UDP_TRACE("Source: %s:%d, Destination: %s:%d", strA, udppkt->srcPort, strB, udppkt->dstPort); #endif /* TRACE_UDP */ restore(im); /* Send ICMP port unreachable message */ icmpDestUnreach(pkt, ICMP_PORT_UNR); netFreebuf(pkt); return SYSERR; } if (udpptr->icount >= UDP_MAX_PKTS) { UDP_TRACE("UDP buffer is full. Dropping UDP packet."); restore(im); netFreebuf(pkt); return SYSERR; } /* Check "bind first" flag and update connection if set, * and clear the flag */ if (UDP_FLAG_BINDFIRST & udpptr->flags) { udpptr->remotept = udppkt->srcPort; netaddrcpy(&(udpptr->localip), dst); netaddrcpy(&(udpptr->remoteip), src); udpptr->flags &= ~UDP_FLAG_BINDFIRST; } /* Get some buffer space to store the packet */ tpkt = udpGetbuf(udpptr); if (SYSERR == (int)tpkt) { UDP_TRACE("Unable to get UDP buffer from pool. Dropping packet."); netFreebuf(pkt); return SYSERR; } /* Copy the data of the packet into the input buffer at the current * position */ memcpy(tpkt, udppkt, udppkt->len); /* Store the temporary UDP packet in a FIFO buffer */ udpptr->in[(udpptr->istart + udpptr->icount) % UDP_MAX_PKTS] = tpkt; udpptr->icount++; restore(im); signal(udpptr->isem); netFreebuf(pkt); return OK; }
int sendSyslog(uchar *syslogsrvr,char *msg, short port, int null) { int msglen; uchar *syslogmsg; ushort ip_len, sport; struct ether_header *enetp; struct ip *ipp; struct Udphdr *udpp; uchar binip[8], binenet[8], *enetaddr; /* msglen is the length of the message, plus optionally the * terminating null character (-n option of syslog command).. */ msglen = strlen(msg) + null; /* Convert IP address to binary: */ if (IpToBin((char *)syslogsrvr,(unsigned char *)binip) < 0) return(0); /* Get the ethernet address for the IP: */ enetaddr = ArpEther(binip,binenet,0); if (!enetaddr) { printf("ARP failed for %s\n",syslogsrvr); return(0); } /* Retrieve an ethernet buffer from the driver and populate the * ethernet level of packet: */ enetp = (struct ether_header *) getXmitBuffer(); memcpy((char *)&enetp->ether_shost,(char *)BinEnetAddr,6); memcpy((char *)&enetp->ether_dhost,(char *)binenet,6); enetp->ether_type = ecs(ETHERTYPE_IP); /* Move to the IP portion of the packet and populate it * appropriately: */ ipp = (struct ip *) (enetp + 1); ipp->ip_vhl = IP_HDR_VER_LEN; ipp->ip_tos = 0; ip_len = sizeof(struct ip) + sizeof(struct Udphdr) + msglen; ipp->ip_len = ecs(ip_len); ipp->ip_id = ipId(); ipp->ip_off = 0; ipp->ip_ttl = UDP_TTL; ipp->ip_p = IP_UDP; memcpy((char *)&ipp->ip_src.s_addr,(char *)BinIpAddr,4); memcpy((char *)&ipp->ip_dst.s_addr,(char *)binip,4); /* Now UDP... */ sport = port+1; udpp = (struct Udphdr *) (ipp + 1); udpp->uh_sport = ecs(sport); udpp->uh_dport = ecs(port); udpp->uh_ulen = ecs((ushort)(ip_len - sizeof(struct ip))); /* Finally, the SYSLOG data ... */ syslogmsg = (uchar *)(udpp+1); strcpy((char *)syslogmsg,(char *)msg); ipChksum(ipp); /* Compute csum of ip hdr */ udpChksum(ipp); /* Compute UDP checksum */ sendBuffer(ETHERSIZE + IPSIZE + UDPSIZE + msglen); return(0); }
/* processGDB(): * This is the function that allows a remote gdb host to connect to * the monitor with gdb at the udp level. The connection command in * gdb to do this is: * * target remote udp:TARGET_IP:TARGET_PORT */ int processGDB(struct ether_header *ehdr,ushort size) { char *gdbp; struct ip *ihdr, *ti, *ri; struct Udphdr *uhdr, *tu, *ru; struct ether_header *te; /* If SHOW_GDB is set (via ether -vg), then we dump the trace to * the console; otherwise, we use mtrace. */ #if INCLUDE_ETHERVERBOSE if (EtherVerbose & SHOW_GDB) gdbTrace = printf; else #endif gdbTrace = Mtrace; ihdr = (struct ip *)(ehdr + 1); uhdr = (struct Udphdr *)((char *)ihdr + IP_HLEN(ihdr)); gdbp = (char *)(uhdr + 1); size = ecs(uhdr->uh_ulen) - sizeof(struct Udphdr); /* Check for ACK/NAK here: */ if (size == 1) { if ((*gdbp == '+') || (*gdbp == '-')) { gdbTrace("GDB_%s\n",*gdbp == '+' ? "ACK" : "NAK"); return(0); } } /* Copy the incoming udp payload (the gdb command) to gdbIbuf[] * and NULL terminate it... */ memcpy((char *)gdbIbuf,(char *)gdbp,size); gdbIbuf[size] = 0; /* Now that we've stored away the GDB command request, we * initially respond with the GDB acknowledgement ('+')... */ te = EtherCopy(ehdr); ti = (struct ip *) (te + 1); ri = (struct ip *) (ehdr + 1); ti->ip_vhl = ri->ip_vhl; ti->ip_tos = ri->ip_tos; ti->ip_len = ecs((1 + (sizeof(struct ip) + sizeof(struct Udphdr)))); ti->ip_id = ipId(); ti->ip_off = ri->ip_off; ti->ip_ttl = UDP_TTL; ti->ip_p = IP_UDP; memcpy((char *)&(ti->ip_src.s_addr),(char *)BinIpAddr, sizeof(struct in_addr)); memcpy((char *)&(ti->ip_dst.s_addr),(char *)&(ri->ip_src.s_addr), sizeof(struct in_addr)); tu = (struct Udphdr *) (ti + 1); ru = (struct Udphdr *) (ri + 1); tu->uh_sport = ru->uh_dport; tu->uh_dport = ru->uh_sport; tu->uh_ulen = ecs((ushort)(sizeof(struct Udphdr) + 1)); gdbp = (char *)(tu+1); *gdbp = '+'; ipChksum(ti); /* Compute checksum of ip hdr */ udpChksum(ti); /* Compute UDP checksum */ sendBuffer(sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct Udphdr) + 1); /* Wrap the processing of the incoming packet with a set/clear * of the gdbUdp flag so that the other gdb code can act * accordingly. */ gdbUdp = 1; if (gdb_cmd(gdbIbuf) == 0) { gdbUdp = 0; return(0); } gdbUdp = 0; /* Add 1 to the gdbRlen to include the NULL termination. */ gdbRlen++; /* The second respons is only done if gdb_cmd returns non-zero. * It is the response to the gdb command issued by the debugger * on the host. */ te = EtherCopy(ehdr); ti = (struct ip *) (te + 1); ri = (struct ip *) (ehdr + 1); ti->ip_vhl = ri->ip_vhl; ti->ip_tos = ri->ip_tos; ti->ip_len = ecs((gdbRlen + (sizeof(struct ip) + sizeof(struct Udphdr)))); ti->ip_id = ipId(); ti->ip_off = ri->ip_off; ti->ip_ttl = UDP_TTL; ti->ip_p = IP_UDP; memcpy((char *)&(ti->ip_src.s_addr),(char *)BinIpAddr, sizeof(struct in_addr)); memcpy((char *)&(ti->ip_dst.s_addr),(char *)&(ri->ip_src.s_addr), sizeof(struct in_addr)); tu = (struct Udphdr *) (ti + 1); ru = (struct Udphdr *) (ri + 1); tu->uh_sport = ru->uh_dport; tu->uh_dport = ru->uh_sport; tu->uh_ulen = ecs((ushort)(sizeof(struct Udphdr) + gdbRlen)); memcpy((char *)(tu+1),(char *)gdbRbuf,gdbRlen); ipChksum(ti); /* Compute checksum of ip hdr */ udpChksum(ti); /* Compute UDP checksum */ sendBuffer(sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct Udphdr) + gdbRlen); return(1); }
/* BOOTPStartup() * The DHCPDISCOVER is issued as an ethernet broadcast. IF the bootp * flag is non-zero then just do a bootp request (a subset of the * DHCPDISCOVER stuff). */ int BOOTPStartup(short seconds) { struct dhcphdr *dhcpdata; struct bootphdr *bootpdata; struct ether_header *te; struct ip *ti; struct Udphdr *tu; ushort uh_ulen; int optlen; /* Retrieve an ethernet buffer from the driver and populate the * ethernet level of packet: */ te = (struct ether_header *) getXmitBuffer(); memcpy((char *)&te->ether_shost,(char *)BinEnetAddr,6); memcpy((char *)&te->ether_dhost,(char *)BroadcastAddr,6); te->ether_type = ecs(ETHERTYPE_IP); /* Move to the IP portion of the packet and populate it appropriately: */ ti = (struct ip *) (te + 1); ti->ip_vhl = IP_HDR_VER_LEN; ti->ip_tos = 0; ti->ip_id = 0; ti->ip_off = ecs(0x4000); /* No fragmentation allowed */ ti->ip_ttl = UDP_TTL; ti->ip_p = IP_UDP; memset((char *)&ti->ip_src.s_addr,0,4); memset((char *)&ti->ip_dst.s_addr,0xff,4); /* Now udp... */ tu = (struct Udphdr *) (ti + 1); tu->uh_sport = ecs(DhcpClientPort); tu->uh_dport = ecs(DhcpServerPort); /* First the stuff that is the same for BOOTP or DHCP... */ bootpdata = (struct bootphdr *)(tu+1); dhcpdata = (struct dhcphdr *)(tu+1); dhcpdata->op = DHCPBOOTP_REQUEST; dhcpdata->htype = 1; dhcpdata->hlen = 6; dhcpdata->hops = 0; dhcpdata->seconds = ecs(seconds); memset((char *)dhcpdata->bootfile,0, sizeof(dhcpdata->bootfile)); memset((char *)dhcpdata->server_hostname,0, sizeof(dhcpdata->server_hostname)); /* For the first request issued, establish a transaction id based * on a crc32 of the mac address. For each request after that, * just increment. */ if (!BOOTPTransactionId) BOOTPTransactionId = BinEnetAddr[5]; else BOOTPTransactionId++; memcpy((char *)&dhcpdata->transaction_id,(char *)&BOOTPTransactionId,4); memset((char *)&dhcpdata->client_ip,0,4); memset((char *)&dhcpdata->your_ip,0,4); memset((char *)&dhcpdata->server_ip,0,4); memset((char *)&dhcpdata->router_ip,0,4); memcpy((char *)dhcpdata->client_macaddr,(char *)BinEnetAddr,6); dhcpdata->flags = 0; self_ecs(dhcpdata->flags); /* Finally, the DHCP or BOOTP specific stuff... * Based on RFC1534 (Interoperation Between DHCP and BOOTP), any message * received by a DHCP server that contains a 'DHCP_MESSAGETYPE' option * is assumed to have been sent by a DHCP client. A message without the * DHCP_MESSAGETYPE option is assumed to have been sent by a BOOTP * client. */ uh_ulen = optlen = 0; memset((char *)bootpdata->vsa,0,sizeof(bootpdata->vsa)); uh_ulen = sizeof(struct Udphdr) + sizeof(struct bootphdr); tu->uh_ulen = ecs(uh_ulen); ti->ip_len = ecs((sizeof(struct ip) + uh_ulen)); ipChksum(ti); /* Compute checksum of ip hdr */ udpChksum(ti); /* Compute UDP checksum */ DHCPState = BOOTPSTATE_REQUEST; sendBuffer(BOOTPSIZE); return(0); }