From owner-p4-projects@FreeBSD.ORG Sun Jun 3 09:52:04 2007 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 893F016A469; Sun, 3 Jun 2007 09:52:04 +0000 (UTC) X-Original-To: perforce@FreeBSD.org Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 349BE16A41F for ; Sun, 3 Jun 2007 09:52:04 +0000 (UTC) (envelope-from taleks@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [69.147.83.41]) by mx1.freebsd.org (Postfix) with ESMTP id 2411613C4B7 for ; Sun, 3 Jun 2007 09:52:04 +0000 (UTC) (envelope-from taleks@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.8/8.13.8) with ESMTP id l539q4Td056287 for ; Sun, 3 Jun 2007 09:52:04 GMT (envelope-from taleks@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.8/8.13.8/Submit) id l539q3eC056262 for perforce@freebsd.org; Sun, 3 Jun 2007 09:52:03 GMT (envelope-from taleks@FreeBSD.org) Date: Sun, 3 Jun 2007 09:52:03 GMT Message-Id: <200706030952.l539q3eC056262@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to taleks@FreeBSD.org using -f From: Alexey Tarasov To: Perforce Change Reviews Cc: Subject: PERFORCE change 120824 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 03 Jun 2007 09:52:05 -0000 http://perforce.freebsd.org/chv.cgi?CH=120824 Change 120824 by taleks@taleks_th on 2007/06/03 09:51:31 pxe_dns: implemented simple DNS resolving using UDP sockets. pxe_core: added set nameserver function, updated receiving cycle. pxe_filter: small changes to remove debug information. pxe_sock: first dummy implementation for UDP. pxe_udp: checksum calculation and socket writing update. Affected files ... .. //depot/projects/soc2007/taleks-pxe_http/pxe_arp.c#6 edit .. //depot/projects/soc2007/taleks-pxe_http/pxe_core.c#12 edit .. //depot/projects/soc2007/taleks-pxe_http/pxe_core.h#10 edit .. //depot/projects/soc2007/taleks-pxe_http/pxe_dns.c#2 edit .. //depot/projects/soc2007/taleks-pxe_http/pxe_dns.h#2 edit .. //depot/projects/soc2007/taleks-pxe_http/pxe_filter.c#2 edit .. //depot/projects/soc2007/taleks-pxe_http/pxe_sock.c#5 edit .. //depot/projects/soc2007/taleks-pxe_http/pxe_sock.h#5 edit .. //depot/projects/soc2007/taleks-pxe_http/pxe_udp.c#2 edit Differences ... ==== //depot/projects/soc2007/taleks-pxe_http/pxe_arp.c#6 (text+ko) ==== @@ -183,15 +183,17 @@ * or for proxy server. Default arp_table size is 8. It seems more than enough. */ - if (NULL != pxe_arp_table_search(arp_reply->body.src_paddr)) { + const MAC_ADDR *kmac = pxe_arp_table_search(arp_reply->body.src_paddr); + if (NULL != kmac) { #ifdef PXE_DEBUG uint8_t *octet = (uint8_t *)&arp_reply->body.src_paddr; uint8_t *mac = arp_reply->body.src_hwaddr; printf("MAC of %d.%d.%d.%d already known: %x:%x:%x:%x:%x:%x\n", octet[0], octet[1], octet[2], octet[3], - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] + (*kmac)[0], (*kmac)[1], (*kmac)[2], (*kmac)[3], (*kmac)[4], (*kmac)[5] ); #endif + /* NOTE: theoretically it's possible mac != known mac. Ignore for now. */ return (0); } @@ -282,9 +284,6 @@ if (timeToDie == 0) { -#ifdef PXE_DEBUG_HELL - printf("."); -#endif --trysLeft; if (trysLeft == 0) { /* have not recieved anything, return nothing */ ==== //depot/projects/soc2007/taleks-pxe_http/pxe_core.c#12 (text+ko) ==== @@ -752,7 +752,7 @@ } #ifdef PXE_DEBUG - printf("recv_packets(): size = %d, proto = %d, frame_length = %d bytes\n.", buffer_size, protocol, frame_size); + printf("recv_packets(): size = %d, proto = %d, frame_length = %d bytes.\n", buffer_size, protocol, frame_size); #endif /* we are interested in ARP & IP packets */ @@ -776,7 +776,6 @@ drop_flag = 1; /* drop this packet */ } - /* checking first fragment, this may help to avoid memory allocation * and memblock copy in main cycle below */ @@ -814,7 +813,7 @@ (!core_protocol[iphdr->protocol](&dummy_pack, (buffer_size == frame_size) ? PXE_CORE_HANDLE : PXE_CORE_FRAG, NULL)) ) { - drop_flag = 1; + drop_flag = 1; } else { pack = pxe_core_alloc_packet(buffer_size); @@ -845,6 +844,8 @@ } } + received = frame_size; + while (received < buffer_size) { if (!pxe_core_get_packet(PXENV_UNDI_ISR_IN_GET_NEXT, undi_isr)) @@ -898,8 +899,9 @@ func = PXENV_UNDI_ISR_IN_GET_NEXT; - if (received == buffer_size) +/* if (received == buffer_size) return processed_packets; +*/ goto packet_start; @@ -1029,6 +1031,13 @@ return ns_ip.ip; } +void +pxe_set_nsip32(uint32_t new_ip) +{ + + ns_ip.ip = new_ip; +} + const MAC_ADDR* pxe_get_mymac() { ==== //depot/projects/soc2007/taleks-pxe_http/pxe_core.h#10 (text+ko) ==== @@ -118,5 +118,6 @@ /* returns nameserver ip */ uint32_t pxe_get_nsip32(); +void pxe_set_nsip32(uint32_t new_ns); #endif // PXE_CORE_H_INCLUDED ==== //depot/projects/soc2007/taleks-pxe_http/pxe_dns.c#2 (text+ko) ==== @@ -4,56 +4,375 @@ #include "pxe_dns.h" #include "pxe_sock.h" +/* write_question_for()- writes labels for provided domain name + * in: + * question - where to write + * name - domain name + * out: + * NULL - if failed + * non NULL- ponits to the next byte after labeled name. + */ +char * +write_question_for(uint8_t *question, const char *name) +{ + size_t len = strlen(name); + + if (len > 255) { /* oversize */ + return (NULL); + } + + size_t ind = len; + uint8_t symbol_count = 0; + uint8_t *res = question + len; + char *np = name + len - 1; + question[len + 1] = 0; /* label end of question */ + + /* placing from the end, replacing dots with symbol counter */ + for ( ; ind != 0; --ind) { + + *res = *np; + + if ( *res == '.') { + + if (symbol_count == 0) { /* example..of.error */ + return (NULL); + } + + *res = symbol_count; + symbol_count = 0; + + } else { + ++symbol_count; + } + + --res; + --np; + } + + *res = symbol_count; /* length for first label */ + + /* +1 for first length, +1 for \0 */ + return (question + len + 2); +} + +/* create_dns_packet()- creates DNS request packet + * in: + * name - domain name to resolve + * data - buffer for request packet. + * max_size - size of buffer [NOT IMPLEMENTED] + * id - request id to distinguish requests + * out: + * 0 - failed + * >0 - size of created packet + */ int -create_dns_packet(char *name, void *data, int max_size) { +create_dns_packet(char *name, void *data, int max_size, uint16_t id, uint16_t query_type) { PXE_DNS_REQUEST_HDR *request = (PXE_DNS_REQUEST_HDR *)data; + uint8_t *question = (uint8_t *)(data + sizeof(PXE_DNS_REQUEST_HDR)); - /* data must be set with zeroes, so fill only needed values */ - request->id = le2be16(1); + pxe_memset(request, 0, sizeof(PXE_DNS_REQUEST_HDR)); + + /* header set with zeroes, so fill only needed values */ + request->id = le2be16(id); request->flags = le2be16(PXE_DNS_DEFAULT_FLAGS); - request->questions_num = le2be16(1); + request->qdcount = le2be16(1); + + question = write_question_for(question, name); + + if (question == NULL) /* failed to write question section */ + return (0); /* may be, name size is to big */ + + PXE_DNS_REQUEST_FOOT *foot = (PXE_DNS_REQUEST_FOOT *)question; + + /* finishing creating of packet */ + foot->qtype = le2be16(query_type); + foot->qclass = le2be16(PXE_DNS_CLASS_IN); + + question += sizeof(PXE_DNS_REQUEST_FOOT); + + /* return total size of packet */ + return (((void *)question) - data); +} + +/* skip_name() - gets name from answers + * in: + * org - pointer to packet data start + * off - offset to name or part of name to get + * to_place - where to place name. NULL, if not interesting for us + * out: + * bytes, read from offset (name definition length) + */ +int +skip_name(uint8_t *org, uint16_t off, uint8_t *to_place) +{ + uint8_t label[64]; + label[0] = 0; + + int res =0 ; + uint8_t *data = org + off; + + while (*data != 0) { + + if (*data < 64) { /* just a label */ + pxe_memcpy(data + 1, label, *data); + label[*data] = 0; + + if (to_place != 0) { /* updating to_pace, if interesting */ + + if (to_place[0] != 0) /* add dot, if there is part of name in buffer */ + strcat((char *)to_place, "."); + + strcat((char *)to_place, (const char*)label); + } + + res += (1 + *data); + data += (1 + *data); + + } else {/* compression enabled, this is part of pointer */ + uint16_t off = (((*data) & 0x3f) << 8) + *(data + 1); + skip_name(org, off, to_place); + + res += 1; + break; + } + } - /* TODO: finish it after sleeping. - * 1. count number of symbols in domain name part betweenn dots - * 2. place name to request - * 3. place query type and class - */ + res += 1; /* ending zero skip */ + return (res); } +/* parse_dns_reply() - parses reply from DNS server + * in: + * data - pointer to buffer, containing packet data + * size - buffer size + * name - domain name to resolve + * canme - where to store cname if found. + * out: + * 0 - parsing failed, or packet has no information about our domain + * ip - success, 32bit ip4 address + */ uint32_t -pxe_gethostbyname(char *name) +parse_dns_reply(uint8_t* data, int size, char *name, uint16_t id, uint8_t *cname) { - /* sanity check */ - if (name == NULL) { + + cname[0] = 0; + + if (size < sizeof(PXE_DNS_REQUEST_HDR) + 8) { /* too small packet to be with data */ +#ifdef PXE_DEBUG + printf("parse_dns_reply(): too small packet.\n"); +#endif + return (0); + } + + PXE_DNS_REQUEST_HDR *hdr = (PXE_DNS_REQUEST_HDR *)data; + uint8_t *answer = data + sizeof(PXE_DNS_REQUEST_HDR); + + if ( hdr->id != le2be16(id)) { /* wrong id */ +#ifdef PXE_DEBUG + printf("parse_dns_reply(): wrong id %d, expected %d.\n", le2be16(hdr->id), id); +#endif + return (0); + } + + uint16_t flags = le2be16(hdr->flags); + + if ( (flags & 0xf800) != 0x8000) { /* QR != 1 */ +#ifdef PXE_DEBUG + printf("parse_dns_reply(): got request. Ignoring it.\n"); +#endif return (0); } - int socket = pxe_socket(); +#ifdef PXE_DEBUG + printf("parse_dns_reply(): query/answer/ns/additional = %d/%d/%d/%d\n", + le2be16(hdr->qdcount), le2be16(hdr->ancount), le2be16(hdr->nscount), le2be16(hdr->arcount) + ); +#endif + /* getting server return code */ + int rcode = (flags & 0x000f); - if (socket == -1) { - printf("pxe_gethostbyname(): failed to create socket.\n"); + switch(rcode) { + case 0: /* good */ + break; + case 1: + printf("parse_dns_reply(): server said format error.\n"); + return (0); + break; + case 2: + printf("parse_dns_reply(): server failed.\n"); + return (0); + break; + case 3: + printf("parse_dns_reply(): name error, domain not exists?\n"); + return (0); + break; + case 4: + printf("parse_dns_reply(): requested operation not implemented.\n"); + return (0); + break; + case 5: + printf("parse_dns_reply(): access refused.\n"); + return (0); + break; + default: + printf("parse_dns_reply(): don't know nothing about rcode = %d.\n", rcode); return (0); + break; } - uint8_t dns_pack[512]; + /* server reported success */ - pxe_memset(dns_pack, 0, 512); + if (hdr->ancount == 0) { /* there is no answers */ + printf("parse_dns_reply(): there are no answers in DNS server reply.\n"); + return (0); + } + + uint8_t aname[256]; /* storage for domain names in answers */ - int size = create_dns_packet(name, dns_pack, 512); + switch (le2be16(hdr->qdcount)) { + case 0: /* best case, nothing must be skipped to get answer data */ + break; + case 1: + + aname[0] = 0; + answer += skip_name(data, answer - data, aname); +#ifdef PXE_DEBUG + printf("question: %s\n", aname); +#endif + /* answer points to zero, skipping claas/type */ + answer += sizeof(PXE_DNS_REQUEST_FOOT); + break; - if (size == 0) { - goto ret; + default: /* error */ + printf("parse_dns_reply(): me sent only one query, but server says %d.\n", le2be16(hdr->qdcount)); + return (0); } - int trys = PXE_MAX_DNS_TRYS; - int time = 0; + + /* parsing answers, authorative section and additional section, hoping to find A resource record */ + uint16_t index = le2be16(hdr->ancount) + le2be16(hdr->nscount) + le2be16(hdr->arcount); + + while (index) { + + aname[0] = 0; + answer += skip_name(data, answer - data, aname); + +#ifdef PXE_DEBUG + printf("answer: %s", aname); +#endif + PXE_DNS_REQUEST_FOOT *ans_foot = (PXE_DNS_REQUEST_FOOT *)answer; + + if (le2be16(ans_foot->qclass) != PXE_DNS_CLASS_IN) { + printf("parse_dns_reply(): IN expected, got 0x%x.\n", le2be16(ans_foot->qclass)); + return (0); + } + + answer += sizeof(PXE_DNS_REQUEST_FOOT); + + PXE_DNS_REQUEST_FOOT2 *ans_foot2 = (PXE_DNS_REQUEST_FOOT2 *)answer; + + answer += sizeof(PXE_DNS_REQUEST_FOOT2); + + uint16_t qtype = le2be16(ans_foot->qtype); + uint16_t rdlength = le2be16(ans_foot2->rdlength); + + if (qtype == PXE_DNS_QUERY_A) { + /* successfully got A record */ + + if ( (!strcmp(aname, name)) || /* A for our address */ + ((cname[0]) && (!strcmp(aname, cname))) /* A for our CNAME */ + ) + + { + /* sanity check */ + if (rdlength != 4) { /* wrong length of ip4 adrress length*/ + return (0); + } + + /* answer points to rdata = ip4 */ + PXE_IPADDR ret; + + ret.octet[0] = answer[0]; + ret.octet[1] = answer[1]; + ret.octet[2] = answer[2]; + ret.octet[3] = answer[3]; +#ifdef PXE_DEBUG + printf(" = %d.%d.%d.%d\n", + ret.octet[0], ret.octet[1], ret.octet[2], ret.octet[3] + ); +#endif + return ret.ip; + } + +#ifdef PXE_DEBUG + printf("parse_dns_reply(): A resource record '%s' is strange. Ignoring it.\n", aname); +#endif + } + + if (qtype == PXE_DNS_QUERY_CNAME) { + + cname[0] = 0; + skip_name(data, answer - data, cname); +#ifdef PXE_DEBUG + printf(" is alias to %s\n", (char *)cname); +#endif + + } else { + printf("parse_dns_reply(): A or CNAME expected, but got 0x%x, rdlength: %d.\n", qtype, rdlength); + } + + answer += rdlength; + --index; + } + + /* have not found anyrhing good */ + return (0); +} +/* pxe_gethostbyname() - returns ip4 address by domain name + * in: + * name - domain name to resolve + * out: + * 0 - if failed + * ip4addr - if success + */ +uint32_t +pxe_gethostbyname(char *name) +{ + /* sanity check */ + if (name == NULL) { + return (0); + } + + /* 512 bytes is limit for packet, sent via UDP */ + uint8_t dns_pack[512]; + uint8_t cname[256]; + + pxe_memset(dns_pack, 0, 512); + + int size = 0; + int trys = PXE_MAX_DNS_TRYS; + int time = 0; + uint16_t id = 1; while (trys) { -#ifdef PXE_DEBUG - printf("?"); -#endif + + int socket = pxe_socket(); + + if (socket == -1) { + printf("pxe_gethostbyname(): failed to create socket.\n"); + return (0); + } + + + size = create_dns_packet(name, dns_pack, 512, id, PXE_DNS_QUERY_A); + + if (size == 0) { + printf("pxe_gethostbyname(): failed to create request.\n"); + return (0); + } + if (size != pxe_sendto(socket, pxe_get_nsip32(), 53, dns_pack, size)) { printf("pxe_gethostbyname(): failed to send DNS request.\n"); pxe_close(socket); @@ -61,7 +380,7 @@ } time = 0; - + while (time < PXE_MAX_DNS_TIMEOUT) { if (!pxe_core_recv_packets()) { @@ -72,16 +391,42 @@ size = pxe_recv(socket, dns_pack, 512); if (size > 0) { - /* TODO: process dns reply */ - printf("pxe_gethostbyname(): Received DNS reply (%d bytes).\n", size); - goto ret; +#ifdef PXE_DEBUG + printf("pxe_gethostbyname(): Received DNS reply (%d bytes).\n", size); +#endif + uint32_t res = parse_dns_reply(dns_pack, size, name, id, cname); + + if (res != 0) { + pxe_close(socket); + return (res); + } + + pxe_sock_rewind(socket, size); /* NOTE: remove this after normal implementing of sockets */ + + if (cname[0] != 0) { /* failed to get A, but found CNAME, need to send other request */ + + size = create_dns_packet(name, dns_pack, 512, id, PXE_DNS_QUERY_CNAME); + + if (size == 0) { + printf("pxe_gethostbyname(): failed to create request.\n"); + break; /* next try */ + } + + if (size != pxe_send(socket, dns_pack, size)) { + printf("pxe_gethostbyname(): failed to send DNS request.\n"); + pxe_close(socket); + return (0); + } + } + } } trys -= 1; + id += 1; + + pxe_close(socket); } -ret: - pxe_close(socket); return (0); } ==== //depot/projects/soc2007/taleks-pxe_http/pxe_dns.h#2 (text+ko) ==== @@ -3,17 +3,20 @@ #include +/* + * Reference: RFC 1035 + */ /* max seconds to wait DNS reply in milliseconds */ #define PXE_MAX_DNS_TIMEOUT 10000 /* how many times to try, if there is no reply */ #define PXE_MAX_DNS_TRYS 3 -/* query flags */ +/* query flags, set only RecursionDesired bit */ #define PXE_DNS_DEFAULT_FLAGS 0x0100 /* query A and CNAME records */ #define PXE_DNS_QUERY_A 0x0001 -#define PXE_DNS_CNAME 0x0005 +#define PXE_DNS_QUERY_CNAME 0x0005 /* query class */ -#define PXE_DNS_CLASS_INET 0x0001 +#define PXE_DNS_CLASS_IN 0x0001 /* returns ip address by name, or 0 if failed */ uint32_t pxe_gethostbyname(char *name); @@ -21,15 +24,59 @@ typedef struct pxe_dns_request_hdr { uint16_t id; /* query identifier */ uint16_t flags; - uint16_t questions_num; - uint16_t answers_num; - uint16_t auths_num; - uint16_t adds_num; + + + uint16_t qdcount; /* number of entries in the question section */ + uint16_t ancount; /* number of resource records in the answer section*/ + uint16_t nscount; /* name server resource records in the authority + * records section. + */ + uint16_t arcount; /* number of resource records in the additional + * records section. + */ } __packed PXE_DNS_REQUEST_HDR; +/* flags are (copied from RFC 1035): + * 1 1 1 1 1 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * |QR| Opcode |AA|TC|RD|RA| Z | RCODE | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * QR - 0 for query, 1 for reply + * OPCODE - kind of query + * 0 - a standard query (QUERY) + * 1 - an inverse query (IQUERY) + * 2 - a server status request (STATUS) + * AA - set if authorative + * TC - set if message truncated + * RD - set if recursion desired + * RA - set if recursion available + * Z - reserved, must be zeroed + * RCODE - return code: + * 0 - no error + * 1 - format error + * 2 - server failed + * 3 - name error + * 4 - not implemented + * 5 - refused + */ + +/* RCODE values */ +#define PXE_RCODE_NOERROR 0x0 +#define PXE_RCODE_FORMAT_ERROR 0x1 +#define PXE_RCODE_SERVER_FAILED 0x2 +#define PXE_RCODE_NAME_ERROR 0x3 +#define PXE_RCODE_NOT_IMPLEMENTED 0x4 +#define PXE_RCODE_REFUSED 0x5 + typedef struct pxe_dns_request_foot { - uint16_t type; - uint16_t class; -} __packed PXE_FNS_REQUEST_FOOT; + uint16_t qtype; /* type of query, e.g. A */ + uint16_t qclass; /* class of query, e.g. IN */ +} __packed PXE_DNS_REQUEST_FOOT; + +typedef struct pxe_dns_request_foot2 { + uint32_t ttl; /* seconds answer will be valid to cache */ + uint16_t rdlength; /* length of data, followed by this structure */ +} __packed PXE_DNS_REQUEST_FOOT2; #endif ==== //depot/projects/soc2007/taleks-pxe_http/pxe_filter.c#2 (text+ko) ==== @@ -47,14 +47,19 @@ free_head->prev = NULL; ++all_filters; } - + +#ifdef PXE_DEBUG_HELL + printf("_pxe_filter_alloc(): entry = 0x%x, head = 0x%x.\n", res, free_head); +#endif return (res); } void _pxe_filter_free(PXE_FILTER_ENTRY *entry) { - +#ifdef PXE_DEBUG_HELL + printf("_pxe_filter_free(): entry = 0x%x, head = 0x%x.\n", entry, free_head); +#endif entry->next = free_head; entry->prev = NULL; @@ -72,9 +77,14 @@ PXE_FILTER_ENTRY * pxe_filter_add(uint32_t src_ip, uint16_t src_port, uint32_t dst_ip, uint16_t dst_port, void *socket, uint8_t proto) { - +#ifdef PXE_DEBUG + if (socket == NULL) { + printf("pxe_filter_add(): NULL socket.\n"); + return (NULL); + } +#endif if (free_head == NULL) { - printf("pxe_filter_add(): filter table is full.\n"); + printf("pxe_filter_add(): filter table is full (all_filter = %d).\n", all_filters); return (NULL); /* there is no space for filters */ } @@ -212,6 +222,15 @@ int pxe_filter_remove(PXE_FILTER_ENTRY *filter) { +#ifdef PXE_DEBUG + if (filter == NULL) { + printf("pxe_filter_remove(): NULL filter.\n"); + return (0); + } + + printf("pxe_filter_remove(): removing filter 0x%x.\n", filter); + +#endif if (filter != filters_head) { /* non head filter */ ==== //depot/projects/soc2007/taleks-pxe_http/pxe_sock.c#5 (text+ko) ==== @@ -40,11 +40,12 @@ sock->state = PXE_SOCKET_FREE; +/* NOTE: may be it's not good place for it if (sock->filter) { pxe_filter_remove(sock->filter); sock->filter = NULL; } - +*/ return (1); } @@ -58,33 +59,39 @@ if (socket == -1) return (-1); +#ifdef PXE_DEBUG + printf("pxe_socket(): created socket %d.\n", socket); +#endif /* creating buffers */ - PXE_SOCKET *sock = &pxe_sockets[socket]; + PXE_BUFFER *rbuf = &pxe_sockets[socket].recv_buffer; + PXE_BUFFER *sbuf = &pxe_sockets[socket].send_buffer; - sock->send_buffer.data = pxe_alloc(PXE_DEFAULT_SEND_BUFSIZE); + sbuf->data = pxe_alloc(PXE_DEFAULT_SEND_BUFSIZE); - if (sock->send_buffer.data == NULL) { + if (sbuf->data == NULL) { pxe_socket_free(socket); return (-1); } - sock->send_buffer.bufsize = PXE_DEFAULT_SEND_BUFSIZE; - sock->send_buffer.bufleft = PXE_DEFAULT_SEND_BUFSIZE; - sock->send_buffer.next_data = sock->send_buffer.data; + sbuf->bufsize = PXE_DEFAULT_SEND_BUFSIZE; + sbuf->bufleft = PXE_DEFAULT_SEND_BUFSIZE; + sbuf->free_start = sbuf->data; + sbuf->free_end = sbuf->data + sbuf->bufsize; - sock->recv_buffer.data = pxe_alloc(PXE_DEFAULT_RECV_BUFSIZE); + rbuf->data = pxe_alloc(PXE_DEFAULT_RECV_BUFSIZE); - if (sock->recv_buffer.data == NULL) { + if (rbuf->data == NULL) { - pxe_free(sock->send_buffer.data); + pxe_free(rbuf->data); pxe_socket_free(socket); return (-1); } - sock->recv_buffer.bufsize = PXE_DEFAULT_RECV_BUFSIZE; - sock->recv_buffer.bufleft = PXE_DEFAULT_RECV_BUFSIZE; - sock->recv_buffer.next_data = sock->recv_buffer.data; + rbuf->bufsize = PXE_DEFAULT_RECV_BUFSIZE; + rbuf->bufleft = PXE_DEFAULT_RECV_BUFSIZE; + rbuf->free_start = rbuf->data; + rbuf->free_end = rbuf->data + rbuf->bufsize; return (socket); } @@ -92,12 +99,30 @@ int pxe_close(int socket) { +#ifdef PXE_DEBUG + printf("pxe_close(): closing socket %d\n", socket); +#endif + if ( (socket >= PXE_DEFAULT_SOCKETS) || (socket == -1)) { + printf("pxe_close(): invalid socket %d\n", socket); + return (0); + } + + PXE_SOCKET *sock = &pxe_sockets[socket]; - if (socket > PXE_DEFAULT_SOCKETS) { + if (sock->state == PXE_SOCKET_FREE) { +#ifdef PXE_DEBUG + printf("pxe_close(): socket %d already closed.\n", socket); +#endif return (0); } - PXE_SOCKET *sock = &pxe_sockets[socket]; + if (sock->filter != NULL) + pxe_filter_remove(sock->filter); + else { +#ifdef PXE_DEBUG + printf("pxe_close(): filter for socket already NULL.\n"); +#endif + } pxe_free(sock->send_buffer.data); pxe_free(sock->recv_buffer.data); @@ -115,7 +140,9 @@ PXE_FILTER_ENTRY *filter = pxe_filter_add(0, 0, pxe_get_myip32(), port, &pxe_sockets[socket], proto); if (filter == NULL) { +#ifdef PXE_DEBUG printf("pxe_listen(): failed to add filter.\n"); +#endif return (-1); } @@ -143,7 +170,7 @@ pxe_accept(int socket) { - if (socket > PXE_DEFAULT_SOCKETS) { + if ( (socket >= PXE_DEFAULT_SOCKETS) || (socket == -1)) { return (-1); } @@ -196,7 +223,7 @@ if (sock->state == PXE_SOCKET_FREE) continue; - printf("%d: filter 0x%x, recv/send: %d/%d, waiting: %d.\n ", + printf("%d: filter 0x%x, recv/send: %d/%d, waiting: %d.\n", socket, sock->filter, sock->recv, sock->sent, sock->waiting ); } @@ -205,7 +232,7 @@ int pxe_sock_bufspace(int socket) { - if (socket > PXE_DEFAULT_SOCKETS) { + if ( (socket >= PXE_DEFAULT_SOCKETS) || (socket == -1)) { return (-1); } @@ -215,51 +242,66 @@ int pxe_sock_place(int socket, void* data, uint16_t size) { -#ifdef PXE_DEBUG_HELL - printf("pxe_sock_place(): sock: %d, data: 0x%x, size: %d\n", socket, data, size); +#ifdef PXE_DEBUG + printf("pxe_sock_place(): socket: %d, data: 0x%x, size: %d\n", socket, data, size); #endif - if (socket > PXE_DEFAULT_SOCKETS) { + if ( (socket >= PXE_DEFAULT_SOCKETS) || (socket == -1)) { return (-1); } - PXE_SOCKET *sock = &pxe_sockets[socket]; + PXE_BUFFER *rbuf = &pxe_sockets[socket].recv_buffer; uint16_t copy_size = size; /* there is no enogh space available in recv buffer * try as much as possible. */ - if (sock->recv_buffer.bufleft < size) { + if (rbuf->bufleft < size) { - copy_size = sock->recv_buffer.bufleft; + copy_size = rbuf->bufleft; if (copy_size == 0) return (0); } - pxe_memcpy(data, sock->recv_buffer.next_data, copy_size); + pxe_memcpy(data, rbuf->free_start, copy_size); - sock->recv_buffer.next_data += copy_size; - sock->recv_buffer.bufleft -= copy_size; - + rbuf->free_start += copy_size; + rbuf->bufleft -= copy_size; + +#ifdef PXE_DEBUG + printf("pxe_sock_place(): left: %d\n", rbuf->bufleft); +#endif return (copy_size); } int +pxe_sock_get(PXE_SOCKET *sock) +{ + int res = sock - pxe_sockets; + + if (res > PXE_DEFAULT_SOCKETS) + return (-1); + + return (res); +} + +int pxe_sock_rewind(int socket, uint16_t size) { - if (socket > PXE_DEFAULT_SOCKETS) { + + if ( (socket >= PXE_DEFAULT_SOCKETS) || (socket == -1)) { return (-1); } PXE_SOCKET *sock = &pxe_sockets[socket]; - uint16_t rew_bytes = sock->recv_buffer.next_data - sock->recv_buffer.data; + uint16_t rew_bytes = sock->recv_buffer.free_start - sock->recv_buffer.data; /* if data to rewind enough, than rewing size, else only available rew_bytes */ if (rew_bytes > size) rew_bytes = size; - sock->recv_buffer.next_data -= rew_bytes; + sock->recv_buffer.free_start -= rew_bytes; sock->recv_buffer.bufleft += rew_bytes; return (rew_bytes); @@ -284,9 +326,6 @@ pxe_sendto(int socket, uint32_t ip, uint16_t port, void *data, uint16_t size) { -#ifdef PXE_DEBUG - printf("pxe_sendto(): ip:port = %8x:%d, size = %d bytes.\n", ip, port, size); -#endif if (size + sizeof(PXE_UDP_PACKET) > PXE_DEFAULT_SEND_BUFSIZE) { printf("pxe_sendto(): send buffer too small for %d bytes.\n", size); return (-1); @@ -311,7 +350,11 @@ * is local port. */ uint16_t lport = filter->dst_port; - + +#ifdef PXE_DEBUG + printf("pxe_sendto(): %8x:%d -> %8x:%d, size = %d bytes.\n", pxe_get_myip32(), lport, ip, port, size); +#endif + if (!pxe_udp_send(udp_pack, ip, port, lport, size + sizeof(PXE_UDP_PACKET), 1)) { printf("pxe_sendto(): failed to send data.\n"); return (-1); @@ -326,7 +369,7 @@ pxe_connect(int socket, uint32_t ip, uint16_t port, uint8_t proto) { - if (socket > PXE_DEFAULT_SOCKETS) { + if ( (socket >= PXE_DEFAULT_SOCKETS) || (socket == -1)) { return (0); } @@ -355,23 +398,81 @@ return (0); } + sock->filter = entry; + /* all is ok */ return (1); } - +/* assuming socket is UDP, need to think about TCP/UDP functions calling, + * also, need to understand how to update buffer for multiple received dgrams >>> TRUNCATED FOR MAIL (1000 lines) <<<