/* IPX support library - SAP Copyright (C) 1994, 1995 Ales Dryak Copyright (C) 1996, Volker Lendecke This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include "ipxsap.h" #include "ipxd.h" int ipx_sap_size(int n, unsigned short int operation) { if (n <= 0) { return 0; } switch (operation) { case IPX_SAP_OP_REQUEST: return n == 1 ? IPX_SAP_REQUEST_LEN : 0; case IPX_SAP_OP_RESPONSE: if ((unsigned int)n > IPX_SAP_MAX_ENTRIES) { return 0; } return (2 + n * sizeof(struct sap_entry)); case IPX_SAP_OP_GNS_REQUEST: return n == 1 ? IPX_SAP_REQUEST_LEN : 0; case IPX_SAP_OP_GNS_RESPONSE: return n == 1 ? 2 + sizeof(struct sap_entry) : 0; break; default: return 0; } } void ipx_sap_assign_ser_name(ser_name_t dest, ser_name_t src) { memset(dest, 0, IPX_SAP_SERVER_NAME_LEN); strncpy(dest, src, IPX_SAP_SERVER_NAME_LEN); } int ipx_sap_name_equal(ser_name_t n1, ser_name_t n2) { return strncmp(n1, n2, IPX_SAP_SERVER_NAME_LEN) == 0; } int ipx_sap_type_equal(ser_type_t t1, ser_type_t t2) { return t1==IPX_SAP_GENERAL_RQ || t2==IPX_SAP_GENERAL_RQ || t1 == t2; } static int ipx_sap_sendto(int sock, void *buffer, int size, struct sockaddr_ipx *daddr) { if (ipx_sap_output_func != NULL) { return ipx_sap_output_func(sock, buffer, size, daddr); } return 0; } int ipx_sap_output_init(struct sap_output *out, IPXNet net) { out->entries = 0; out->send_error = 0; out->buffer.operation = htons(IPX_SAP_OP_REQUEST); out->dest_addr.sipx_family = AF_IPX; out->dest_addr.sipx_type = IPX_SAP_PTYPE; out->dest_addr.sipx_network = htonl(net); return 0; } void ipx_sap_output_flush(struct sap_output * out) { if (out->entries == 0) { return; } if (out->send_error != 0) { out->entries = 0; return; } if (ipx_sap_sendto(out->sk, &(out->buffer), ipx_sap_size(out->entries, ntohs(out->buffer.operation)), &(out->dest_addr)) < 0) { out->send_error = 1; check_request = 1; } out->entries = 0; } void ipx_sap_output_request(struct sap_output * out, ser_type_t ser_type) { struct sap_entry *se; ipx_sap_output_flush(out); out->buffer.operation = htons(IPX_SAP_OP_REQUEST); se = &(out->buffer.sap_entries[out->entries]); se->ser_type = htons(ser_type); out->entries++; } void ipx_sap_output_gns_request(struct sap_output * out, ser_type_t ser_type) { struct sap_entry *se; ipx_sap_output_flush(out); out->buffer.operation = htons(IPX_SAP_OP_GNS_REQUEST); se = &(out->buffer.sap_entries[out->entries]); se->ser_type = htons(ser_type); out->entries++; } void ipx_sap_output_response(struct sap_output * out, ser_type_t type, ser_name_t name, struct sockaddr_ipx *addr, hop_t hops, int down_allow) { struct sap_entry *se; if (hops >= IPX_SAP_SERVER_DOWN && !down_allow) { return; } if ((unsigned int)out->entries >= IPX_SAP_MAX_ENTRIES) { ipx_sap_output_flush(out); } if (out->buffer.operation != htons(IPX_SAP_OP_RESPONSE)) { ipx_sap_output_flush(out); out->buffer.operation = htons(IPX_SAP_OP_RESPONSE); } if (passive != 0) { return; } se = &(out->buffer.sap_entries[out->entries]); se->ser_type = htons(type); ipx_sap_assign_ser_name(se->ser_name, name); se->network = addr->sipx_network; ipx_assign_node(se->node, addr->sipx_node); se->port = addr->sipx_port; se->hops = htons(hops); out->entries++; } void ipx_sap_output_gns_response(struct sap_output * out, ser_type_t type, ser_name_t name, struct sockaddr_ipx *addr, hop_t hops) { struct sap_entry *se; if (hops >= IPX_SAP_SERVER_DOWN) { return; } ipx_sap_output_flush(out); if (passive != 0) { return; } out->buffer.operation = htons(IPX_SAP_OP_GNS_RESPONSE); se = &(out->buffer.sap_entries[out->entries]); se->ser_type = htons(type); ipx_sap_assign_ser_name(se->ser_name, name); se->network = addr->sipx_network; ipx_assign_node(se->node, addr->sipx_node); se->port = addr->sipx_port; se->hops = htons(hops); out->entries++; } void ipx_sap_output_set_destination(struct sap_output * out, IPXNode node, IPXPort port) { ipx_sap_output_flush(out); ipx_assign_node(out->dest_addr.sipx_node, node); out->dest_addr.sipx_port = htons(port); } void ipx_sap_fprint_name(FILE * file, ser_name_t sname) { char name[IPX_SAP_SERVER_NAME_LEN + 1]; int len; memcpy(name, sname, IPX_SAP_SERVER_NAME_LEN); name[IPX_SAP_SERVER_NAME_LEN] = 0; len = strlen(name); memset(name + len, ' ', IPX_SAP_SERVER_NAME_LEN - len); fprintf(file, name); } static void fprint_entry(FILE * file, struct sap_entry *se) { fprintf(file, "SAP: type: %04X name: ", ntohs(se->ser_type)); ipx_sap_fprint_name(file, se->ser_name); fprintf(file, " \nhops: %i addr: ", ntohs(se->hops)); ipx_fprint_network(file, ntohl(se->network)); fprintf(file, ":"); ipx_fprint_node(file, se->node); fprintf(file, ":"); ipx_fprint_port(file, ntohs(se->port)); fprintf(file, "\n"); } void ipx_sap_dump(struct sap_packet *pkt, int len) { ipx_sap_fdump(stdout, pkt, len); } void ipx_sap_fdump(FILE * file, struct sap_packet *pkt, int len) { int ent; struct sap_entry *se = pkt->sap_entries; if (len < 2) { return; } fprintf(file, "Operation: %i size: %i ", ntohs(pkt->operation), len); switch (ntohs(pkt->operation)) { case IPX_SAP_OP_REQUEST: fprintf(file, "(Request)\n"); if (ipx_sap_size(1, IPX_SAP_OP_REQUEST) != len) { fprintf(file, "Warning: Bad SAP size\n"); } fprintf(file, "SAP: Type: %04X\n", ntohs(se->ser_type)); break; case IPX_SAP_OP_GNS_REQUEST: fprintf(file, "(Get Nearest Server Request)\n"); if (ipx_sap_size(1, IPX_SAP_OP_GNS_REQUEST) != len) { fprintf(file, "Warning: Bad SAP size\n"); } fprintf(file, "SAP: Type: %04X\n", ntohs(se->ser_type)); break; case IPX_SAP_OP_RESPONSE: fprintf(file, "(Response)\n"); ent = (len - 2) / sizeof(struct sap_entry); if (ipx_sap_size(ent, IPX_SAP_OP_RESPONSE) != len) { fprintf(file, "Warning: Bad SAP size\n"); } for (; ent--; se++) { fprint_entry(file, se); } break; case IPX_SAP_OP_GNS_RESPONSE: fprintf(file, "(Get Nearest Server Response)\n"); if (ipx_sap_size(1, IPX_SAP_OP_RESPONSE) != len) { fprintf(file, "Warning: Bad SAP size\n"); } fprint_entry(file, se); break; default: fprintf(file, "(Unknown)\n"); break; } } int (*ipx_sap_output_func) (int sock, void *, int, struct sockaddr_ipx *) = NULL;