152153Sbp/* 252153Sbp * Copyright (c) 1999, Boris Popov 352153Sbp * All rights reserved. 452153Sbp * 552153Sbp * Redistribution and use in source and binary forms, with or without 652153Sbp * modification, are permitted provided that the following conditions 752153Sbp * are met: 852153Sbp * 1. Redistributions of source code must retain the above copyright 952153Sbp * notice, this list of conditions and the following disclaimer. 1052153Sbp * 2. Redistributions in binary form must reproduce the above copyright 1152153Sbp * notice, this list of conditions and the following disclaimer in the 1252153Sbp * documentation and/or other materials provided with the distribution. 13165920Simp * 3. Neither the name of the author nor the names of any co-contributors 1452153Sbp * may be used to endorse or promote products derived from this software 1552153Sbp * without specific prior written permission. 1652153Sbp * 1752153Sbp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1852153Sbp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1952153Sbp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2052153Sbp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2152153Sbp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2252153Sbp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2352153Sbp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2452153Sbp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2552153Sbp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2652153Sbp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2752153Sbp * SUCH DAMAGE. 2852153Sbp */ 2984213Sdillon 3084213Sdillon#include <sys/cdefs.h> 3184213Sdillon__FBSDID("$FreeBSD$"); 3284213Sdillon 3352153Sbp#include <stdlib.h> 3452153Sbp#include <string.h> 3552153Sbp#include <sys/types.h> 3652153Sbp#include <sys/socket.h> 3752153Sbp#include <sys/time.h> 3890868Smike#include <arpa/inet.h> 3952153Sbp#include <netipx/ipx.h> 4052153Sbp#include <errno.h> 4152153Sbp#include <unistd.h> 4252153Sbp#include "ipxsap.h" 4352153Sbp 4452153Sbp/* 4552153Sbp * TODO: These should go to ipx headers 4652153Sbp */ 4752153Sbp#define ipx_set_net(x,y) ((x).x_net.s_net[0] = (y).x_net.s_net[0]); \ 4852153Sbp ((x).x_net.s_net[1]=(y).x_net.s_net[1]) 4952153Sbp#define ipx_set_nullnet(x) ((x).x_net.s_net[0]=0); ((x).x_net.s_net[1]=0) 5052153Sbp#define ipx_set_nullhost(x) ((x).x_host.s_host[0] = 0); \ 5152153Sbp ((x).x_host.s_host[1] = 0); ((x).x_host.s_host[2] = 0) 5252153Sbp#define ipx_set_wildnet(x) ((x).x_net.s_net[0] = 0xFFFF); \ 5352153Sbp ((x).x_net.s_net[1]=0xFFFF) 5452153Sbp#define ipx_set_wildhost(x) ((x).x_host.s_host[0] = 0xFFFF); \ 5552153Sbp ((x).x_host.s_host[1] = 0xFFFF); ((x).x_host.s_host[2] = 0xFFFF); 5652153Sbp 5752153Sbp 5852153Sbpstatic struct sap_packet* sap_packet_alloc(int entries); 5952153Sbpstatic int sap_size(int entries, u_short operation); 6052153Sbpint (*sap_sendto_func)(void*,int,struct sockaddr_ipx*,int sock)=NULL; 6152153Sbp 6252153Sbpstatic int 6352153Sbpsap_sendto(void* buffer, int size, struct sockaddr_ipx* daddr, int sock) 6452153Sbp{ 6552153Sbp if (sap_sendto_func) 6652153Sbp return sap_sendto_func(buffer,size,daddr,sock); 6752153Sbp return sendto(sock, (char*)buffer, size, 0, 6852153Sbp (struct sockaddr*)daddr, sizeof(*daddr)); 6952153Sbp} 7052153Sbp 7152153Sbpstatic struct sap_packet* 7252153Sbpsap_packet_alloc(int entries) 7352153Sbp{ 7452153Sbp if (entries > IPX_SAP_MAX_ENTRIES) 7552153Sbp return NULL; 7652153Sbp return 7752153Sbp (struct sap_packet*)malloc(sap_size(entries, IPX_SAP_GENERAL_RESPONSE)); 7852153Sbp} 7952153Sbp 8052153Sbpstatic int 8152153Sbpsap_size(int entries, u_short operation) 8252153Sbp{ 8352153Sbp if (entries <= 0) 8452153Sbp return 0; 8552153Sbp switch (operation) { 8652153Sbp case IPX_SAP_GENERAL_QUERY: 8752153Sbp return entries == 1 ? IPX_SAP_REQUEST_LEN : 0; 8852153Sbp case IPX_SAP_GENERAL_RESPONSE: 8952153Sbp if (entries > IPX_SAP_MAX_ENTRIES) 9052153Sbp return 0; 9152153Sbp return sizeof(struct sap_packet) + (entries - 1) * sizeof(struct sap_entry); 9252153Sbp case IPX_SAP_NEAREST_QUERY: 9352153Sbp return entries == 1 ? IPX_SAP_REQUEST_LEN : 0; 9452153Sbp case IPX_SAP_NEAREST_RESPONSE: 9552153Sbp return entries == 1 ? sizeof(struct sap_packet) : 0; 9652153Sbp default: 9752153Sbp return 0; 9852153Sbp } 9952153Sbp} 10052153Sbp 10152153Sbpvoid 10252153Sbpsap_copyname(char *dest, const char *src) 10352153Sbp{ 10452153Sbp bzero(dest, IPX_SAP_SERVER_NAME_LEN); 10552153Sbp strncpy(dest, src, IPX_SAP_SERVER_NAME_LEN - 1); 10652153Sbp} 10752153Sbp 10852153Sbpint 10952153Sbpsap_rq_init(struct sap_rq* rq, int sock) 11052153Sbp{ 11152153Sbp rq->buffer = sap_packet_alloc(IPX_SAP_MAX_ENTRIES); 11252153Sbp if (rq->buffer == NULL) 11352153Sbp return 0; 11452153Sbp rq->entries = 0; 11552153Sbp rq->buffer->operation = htons(IPX_SAP_GENERAL_QUERY); 11652153Sbp rq->dest_addr.sipx_family = AF_IPX; 11752153Sbp rq->dest_addr.sipx_len = sizeof(struct sockaddr_ipx); 11852153Sbp rq->sock = sock; 11952153Sbp return 1; 12052153Sbp} 12152153Sbp 12252153Sbpint 12352153Sbpsap_rq_flush(struct sap_rq* rq) 12452153Sbp{ 12552153Sbp int result; 12652153Sbp 12752153Sbp if (rq->entries == 0) 12852153Sbp return 0; 12952153Sbp result = sap_sendto(rq->buffer, 13052153Sbp sap_size(rq->entries, ntohs(rq->buffer->operation)), 13152153Sbp &rq->dest_addr, rq->sock); 13252153Sbp rq->entries = 0; 13352153Sbp return result; 13452153Sbp} 13552153Sbp 13652153Sbpvoid 13752153Sbpsap_rq_general_query(struct sap_rq* rq, u_short ser_type) 13852153Sbp{ 13952153Sbp struct sap_entry* sep; 14052153Sbp 14152153Sbp sap_rq_flush(rq); 14252153Sbp rq->buffer->operation = htons(IPX_SAP_GENERAL_QUERY); 14352153Sbp sep = rq->buffer->sap_entries + rq->entries++; 14452153Sbp sep->server_type = htons(ser_type); 14552153Sbp} 14652153Sbp 14752153Sbpvoid 14852153Sbpsap_rq_gns_request(struct sap_rq* rq, u_short ser_type) 14952153Sbp{ 15052153Sbp struct sap_entry* sep; 15152153Sbp 15252153Sbp sap_rq_flush(rq); 15352153Sbp rq->buffer->operation = htons(IPX_SAP_NEAREST_QUERY); 15452153Sbp sep = rq->buffer->sap_entries + rq->entries++; 15552153Sbp sep->server_type = htons(ser_type); 15652153Sbp} 15752153Sbp 15852153Sbpvoid 15952153Sbpsap_rq_general_response(struct sap_rq* rq,u_short type,char *name,struct sockaddr_ipx* addr, u_short hops,int down_allow) 16052153Sbp{ 16152153Sbp struct sap_entry* sep; 16252153Sbp 16352153Sbp if (hops >= IPX_SAP_SERVER_DOWN && !down_allow) return; 16452153Sbp if (rq->entries >= IPX_SAP_MAX_ENTRIES) 16552153Sbp sap_rq_flush(rq); 16652153Sbp if (rq->buffer->operation != htons(IPX_SAP_GENERAL_RESPONSE)){ 16752153Sbp sap_rq_flush(rq); 16852153Sbp rq->buffer->operation = htons(IPX_SAP_GENERAL_RESPONSE); 16952153Sbp } 17052153Sbp sep = rq->buffer->sap_entries + rq->entries; 17152153Sbp sep->server_type = htons(type); 17252153Sbp sap_copyname(sep->server_name, name); 17352153Sbp memcpy(&sep->ipx, &addr->sipx_addr, sizeof(struct ipx_addr)); 17452153Sbp sep->hops = htons(hops); 17552153Sbp rq->entries++; 17652153Sbp} 17752153Sbp 17852153Sbpvoid 17952153Sbpsap_rq_gns_response(struct sap_rq* rq,u_short type,char *name,struct sockaddr_ipx* addr,u_short hops) 18052153Sbp{ 18152153Sbp struct sap_entry* sep; 18252153Sbp 18352153Sbp if (hops >= IPX_SAP_SERVER_DOWN) return; 18452153Sbp sap_rq_flush(rq); 18552153Sbp rq->buffer->operation = htons(IPX_SAP_NEAREST_RESPONSE); 18652153Sbp sep = rq->buffer->sap_entries + rq->entries; 18752153Sbp sep->server_type = htons(type); 18852153Sbp sap_copyname(sep->server_name, name); 18952153Sbp memcpy(&sep->ipx, &addr->sipx_addr, sizeof(struct ipx_addr)); 19052153Sbp sep->hops = htons(hops); 19152153Sbp rq->entries++; 19252153Sbp} 19352153Sbp 19452153Sbpvoid 19552153Sbpsap_rq_set_destination(struct sap_rq* rq,struct ipx_addr *dest) 19652153Sbp{ 19752153Sbp sap_rq_flush(rq); 19852153Sbp memcpy(&rq->dest_addr.sipx_addr,dest,sizeof(struct ipx_addr)); 19952153Sbp} 20052153Sbp 20152153Sbpint 20252153Sbpsap_getsock(int *rsock) { 20352153Sbp struct sockaddr_ipx sap_addr; 20452153Sbp int opt, sock, slen; 20552153Sbp 20652153Sbp sock = socket(AF_IPX, SOCK_DGRAM, 0); 20752153Sbp if (sock < 0) 20852153Sbp return (errno); 20952153Sbp slen = sizeof(sap_addr); 21052153Sbp bzero(&sap_addr, slen); 21152153Sbp sap_addr.sipx_family = AF_IPX; 21252153Sbp sap_addr.sipx_len = slen; 21352153Sbp if (bind(sock, (struct sockaddr*)&sap_addr, slen) == -1) { 21452153Sbp close(sock); 21552153Sbp return(errno); 21652153Sbp } 21752153Sbp opt = 1; 21852153Sbp if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt)) != 0){ 21952153Sbp close(sock); 22052153Sbp return(errno); 22152153Sbp } 22252153Sbp *rsock = sock; 22352153Sbp return(0); 22452153Sbp} 22552153Sbp 22652153Sbpstatic int 22752153Sbpsap_recv(int sock,void *buf,int len,int flags, int timeout){ 22852153Sbp fd_set rd, wr, ex; 22952153Sbp struct timeval tv; 23052153Sbp int result; 23152153Sbp 23252153Sbp FD_ZERO(&rd); 23352153Sbp FD_ZERO(&wr); 23452153Sbp FD_ZERO(&ex); 23552153Sbp FD_SET(sock, &rd); 23652153Sbp 23752153Sbp tv.tv_sec = timeout; 23852153Sbp tv.tv_usec = 0; 23952153Sbp 24052153Sbp if ((result = select(sock + 1, &rd, &wr, &ex, &tv)) == -1) { 24152153Sbp return result; 24252153Sbp } 24352153Sbp if (FD_ISSET(sock, &rd)) { 24452153Sbp result = recv(sock, buf, len, flags); 24552153Sbp } else { 24652153Sbp errno = ETIMEDOUT; 24752153Sbp result = -1; 24852153Sbp } 24952153Sbp return result; 25052153Sbp} 25152153Sbp 25252153Sbpint 25352153Sbpsap_find_nearest(int server_type, struct sockaddr_ipx *daddr, char *server_name) 25452153Sbp{ 25552153Sbp struct ipx_addr addr; 25652153Sbp char data[1024]; 25752153Sbp int sock, error, packets, len; 25852153Sbp struct sap_packet *reply = (struct sap_packet*)&data; 25952153Sbp struct sap_rq sap_rq; 26052153Sbp 26152153Sbp error = sap_getsock(&sock); 26252153Sbp if (error) 26352153Sbp return error; 26452153Sbp bzero(&addr, sizeof(addr)); 26552153Sbp /* BAD: we should enum all ifs (and nets ?) */ 26652153Sbp if (ipx_iffind(NULL, &addr) != 0) { 26752153Sbp return (EPROTONOSUPPORT); 26852153Sbp } 26952153Sbp ipx_set_wildhost(addr); 27052153Sbp addr.x_port = htons(IPXPORT_SAP); 27152153Sbp 27252153Sbp if (!sap_rq_init(&sap_rq, sock)) { 27352153Sbp close(sock); 27452153Sbp return(ENOMEM); 27552153Sbp } 27652153Sbp sap_rq_set_destination(&sap_rq, &addr); 27752153Sbp sap_rq_gns_request(&sap_rq, server_type); 27852153Sbp sap_rq_flush(&sap_rq); 27952153Sbp packets = 5; 28052153Sbp do { 28152153Sbp len = sap_recv(sock, data, sizeof(data), 0, 1); 28252626Sbp if (len >= 66 && 28352626Sbp ntohs(reply->operation) == IPX_SAP_NEAREST_RESPONSE) 28452626Sbp break; 28552626Sbp if (len < 0) 28652626Sbp packets--; 28752626Sbp } while (packets > 0); 28852153Sbp 28952153Sbp if (packets == 0) { 29052153Sbp close(sock); 29152153Sbp return ENETDOWN; 29252153Sbp } 29352153Sbp 29452153Sbp daddr->sipx_addr = reply->sap_entries[0].ipx; 29552153Sbp daddr->sipx_family = AF_IPX; 29652153Sbp daddr->sipx_len = sizeof(struct sockaddr_ipx); 29752153Sbp sap_copyname(server_name, reply->sap_entries[0].server_name); 29852153Sbp errno = 0; 29952153Sbp close(sock); 30052153Sbp return 0; 30152153Sbp} 302