2 * Copyright (c) 1999, Boris Popov
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Boris Popov.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * $FreeBSD: src/lib/libncp/sap.c,v 1.2 1999/10/29 12:59:59 bp Exp $
33 * $DragonFly: src/lib/libncp/sap.c,v 1.2 2003/06/17 04:26:50 dillon Exp $
38 #include <sys/types.h>
39 #include <sys/socket.h>
41 #include <netipx/ipx.h>
47 * TODO: These should go to ipx headers
49 #define ipx_set_net(x,y) ((x).x_net.s_net[0] = (y).x_net.s_net[0]); \
50 ((x).x_net.s_net[1]=(y).x_net.s_net[1])
51 #define ipx_set_nullnet(x) ((x).x_net.s_net[0]=0); ((x).x_net.s_net[1]=0)
52 #define ipx_set_nullhost(x) ((x).x_host.s_host[0] = 0); \
53 ((x).x_host.s_host[1] = 0); ((x).x_host.s_host[2] = 0)
54 #define ipx_set_wildnet(x) ((x).x_net.s_net[0] = 0xFFFF); \
55 ((x).x_net.s_net[1]=0xFFFF)
56 #define ipx_set_wildhost(x) ((x).x_host.s_host[0] = 0xFFFF); \
57 ((x).x_host.s_host[1] = 0xFFFF); ((x).x_host.s_host[2] = 0xFFFF);
60 static struct sap_packet
* sap_packet_alloc(int entries
);
61 static int sap_size(int entries
, u_short operation
);
62 int (*sap_sendto_func
)(void*,int,struct sockaddr_ipx
*,int sock
)=NULL
;
65 sap_sendto(void* buffer
, int size
, struct sockaddr_ipx
* daddr
, int sock
)
68 return sap_sendto_func(buffer
,size
,daddr
,sock
);
69 return sendto(sock
, (char*)buffer
, size
, 0,
70 (struct sockaddr
*)daddr
, sizeof(*daddr
));
73 static struct sap_packet
*
74 sap_packet_alloc(int entries
)
76 if (entries
> IPX_SAP_MAX_ENTRIES
)
79 (struct sap_packet
*)malloc(sap_size(entries
, IPX_SAP_GENERAL_RESPONSE
));
83 sap_size(int entries
, u_short operation
)
88 case IPX_SAP_GENERAL_QUERY
:
89 return entries
== 1 ? IPX_SAP_REQUEST_LEN
: 0;
90 case IPX_SAP_GENERAL_RESPONSE
:
91 if (entries
> IPX_SAP_MAX_ENTRIES
)
93 return sizeof(struct sap_packet
) + (entries
- 1) * sizeof(struct sap_entry
);
94 case IPX_SAP_NEAREST_QUERY
:
95 return entries
== 1 ? IPX_SAP_REQUEST_LEN
: 0;
96 case IPX_SAP_NEAREST_RESPONSE
:
97 return entries
== 1 ? sizeof(struct sap_packet
) : 0;
104 sap_copyname(char *dest
, const char *src
)
106 bzero(dest
, IPX_SAP_SERVER_NAME_LEN
);
107 strncpy(dest
, src
, IPX_SAP_SERVER_NAME_LEN
- 1);
111 sap_rq_init(struct sap_rq
* rq
, int sock
)
113 rq
->buffer
= sap_packet_alloc(IPX_SAP_MAX_ENTRIES
);
114 if (rq
->buffer
== NULL
)
117 rq
->buffer
->operation
= htons(IPX_SAP_GENERAL_QUERY
);
118 rq
->dest_addr
.sipx_family
= AF_IPX
;
119 rq
->dest_addr
.sipx_len
= sizeof(struct sockaddr_ipx
);
125 sap_rq_flush(struct sap_rq
* rq
)
129 if (rq
->entries
== 0)
131 result
= sap_sendto(rq
->buffer
,
132 sap_size(rq
->entries
, ntohs(rq
->buffer
->operation
)),
133 &rq
->dest_addr
, rq
->sock
);
139 sap_rq_general_query(struct sap_rq
* rq
, u_short ser_type
)
141 struct sap_entry
* sep
;
144 rq
->buffer
->operation
= htons(IPX_SAP_GENERAL_QUERY
);
145 sep
= rq
->buffer
->sap_entries
+ rq
->entries
++;
146 sep
->server_type
= htons(ser_type
);
150 sap_rq_gns_request(struct sap_rq
* rq
, u_short ser_type
)
152 struct sap_entry
* sep
;
155 rq
->buffer
->operation
= htons(IPX_SAP_NEAREST_QUERY
);
156 sep
= rq
->buffer
->sap_entries
+ rq
->entries
++;
157 sep
->server_type
= htons(ser_type
);
161 sap_rq_general_response(struct sap_rq
* rq
,u_short type
,char *name
,struct sockaddr_ipx
* addr
, u_short hops
,int down_allow
)
163 struct sap_entry
* sep
;
165 if (hops
>= IPX_SAP_SERVER_DOWN
&& !down_allow
) return;
166 if (rq
->entries
>= IPX_SAP_MAX_ENTRIES
)
168 if (rq
->buffer
->operation
!= htons(IPX_SAP_GENERAL_RESPONSE
)){
170 rq
->buffer
->operation
= htons(IPX_SAP_GENERAL_RESPONSE
);
172 sep
= rq
->buffer
->sap_entries
+ rq
->entries
;
173 sep
->server_type
= htons(type
);
174 sap_copyname(sep
->server_name
, name
);
175 memcpy(&sep
->ipx
, &addr
->sipx_addr
, sizeof(struct ipx_addr
));
176 sep
->hops
= htons(hops
);
181 sap_rq_gns_response(struct sap_rq
* rq
,u_short type
,char *name
,struct sockaddr_ipx
* addr
,u_short hops
)
183 struct sap_entry
* sep
;
185 if (hops
>= IPX_SAP_SERVER_DOWN
) return;
187 rq
->buffer
->operation
= htons(IPX_SAP_NEAREST_RESPONSE
);
188 sep
= rq
->buffer
->sap_entries
+ rq
->entries
;
189 sep
->server_type
= htons(type
);
190 sap_copyname(sep
->server_name
, name
);
191 memcpy(&sep
->ipx
, &addr
->sipx_addr
, sizeof(struct ipx_addr
));
192 sep
->hops
= htons(hops
);
197 sap_rq_set_destination(struct sap_rq
* rq
,struct ipx_addr
*dest
)
200 memcpy(&rq
->dest_addr
.sipx_addr
,dest
,sizeof(struct ipx_addr
));
204 sap_getsock(int *rsock
) {
205 struct sockaddr_ipx sap_addr
;
208 sock
= socket(AF_IPX
, SOCK_DGRAM
, 0);
211 slen
= sizeof(sap_addr
);
212 bzero(&sap_addr
, slen
);
213 sap_addr
.sipx_family
= AF_IPX
;
214 sap_addr
.sipx_len
= slen
;
215 if (bind(sock
, (struct sockaddr
*)&sap_addr
, slen
) == -1) {
220 if (setsockopt(sock
, SOL_SOCKET
, SO_BROADCAST
, &opt
, sizeof(opt
)) != 0){
229 sap_recv(int sock
,void *buf
,int len
,int flags
, int timeout
){
242 if ((result
= select(sock
+ 1, &rd
, &wr
, &ex
, &tv
)) == -1) {
245 if (FD_ISSET(sock
, &rd
)) {
246 result
= recv(sock
, buf
, len
, flags
);
255 sap_find_nearest(int server_type
, struct sockaddr_ipx
*daddr
, char *server_name
)
257 struct ipx_addr addr
;
259 int sock
, error
, packets
, len
;
260 struct sap_packet
*reply
= (struct sap_packet
*)&data
;
261 struct sap_rq sap_rq
;
263 error
= sap_getsock(&sock
);
266 bzero(&addr
, sizeof(addr
));
267 /* BAD: we should enum all ifs (and nets ?) */
268 if (ipx_iffind(NULL
, &addr
) != 0) {
269 return (EPROTONOSUPPORT
);
271 ipx_set_wildhost(addr
);
272 addr
.x_port
= htons(IPXPORT_SAP
);
274 if (!sap_rq_init(&sap_rq
, sock
)) {
278 sap_rq_set_destination(&sap_rq
, &addr
);
279 sap_rq_gns_request(&sap_rq
, server_type
);
280 sap_rq_flush(&sap_rq
);
283 len
= sap_recv(sock
, data
, sizeof(data
), 0, 1);
285 ntohs(reply
->operation
) == IPX_SAP_NEAREST_RESPONSE
)
289 } while (packets
> 0);
296 daddr
->sipx_addr
= reply
->sap_entries
[0].ipx
;
297 daddr
->sipx_family
= AF_IPX
;
298 daddr
->sipx_len
= sizeof(struct sockaddr_ipx
);
299 sap_copyname(server_name
, reply
->sap_entries
[0].server_name
);