-/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
-
- Version 1.0
- RFCNB Utility Routines ...
-
- Copyright (C) Richard Sharpe 1996
-
-*/
-
-/*
- 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 "config.h"
-#include "clibrary.h"
-#include "portable/socket.h"
-#include <errno.h>
-#include <netdb.h>
-
-#include "rfcnb-priv.h"
-#include "rfcnb-util.h"
-#include "rfcnb-io.h"
-
-#ifndef INADDR_NONE
-# define INADDR_NONE -1
-#endif
-
-extern void (*Prot_Print_Routine)(); /* Pointer to protocol print routine */
-
-/* Convert name and pad to 16 chars as needed */
-/* Name 1 is a C string with null termination, name 2 may not be */
-/* If SysName is true, then put a <00> on end, else space> */
-
-void RFCNB_CvtPad_Name(char *name1, char *name2)
-
-{ char c, c1, c2;
- int i, len;
-
- len = strlen(name1);
-
- for (i = 0; i < 16; i++) {
-
- if (i >= len) {
-
- c1 = 'C'; c2 = 'A'; /* CA is a space */
-
- } else {
-
- c = name1[i];
- c1 = (char)((int)c/16 + (int)'A');
- c2 = (char)((int)c%16 + (int)'A');
- }
-
- name2[i*2] = c1;
- name2[i*2+1] = c2;
-
- }
-
- name2[32] = 0; /* Put in the nll ...*/
-
-}
-
-/* Get a packet of size n */
-
-struct RFCNB_Pkt *RFCNB_Alloc_Pkt(int n)
-
-{ RFCNB_Pkt *pkt;
-
- if ((pkt = (struct RFCNB_Pkt *)malloc(sizeof(struct RFCNB_Pkt))) == NULL) {
-
- RFCNB_errno = RFCNBE_NoSpace;
- RFCNB_saved_errno = errno;
- return(NULL);
-
- }
-
- pkt -> next = NULL;
- pkt -> len = n;
-
- if (n == 0) return(pkt);
-
- if ((pkt -> data = (char *)malloc(n)) == NULL) {
-
- RFCNB_errno = RFCNBE_NoSpace;
- RFCNB_saved_errno = errno;
- free(pkt);
- return(NULL);
-
- }
-
- return(pkt);
-
-}
-
-/* Free up a packet */
-
-void RFCNB_Free_Pkt(struct RFCNB_Pkt *pkt)
-
-{ struct RFCNB_Pkt *pkt_next; char *data_ptr;
-
- while (pkt != NULL) {
-
- pkt_next = pkt -> next;
-
- data_ptr = pkt -> data;
-
- if (data_ptr != NULL)
- free(data_ptr);
-
- free(pkt);
-
- pkt = pkt_next;
-
- }
-
-}
-
-/* Resolve a name into an address */
-
-int RFCNB_Name_To_IP(char *host, struct in_addr *Dest_IP)
-
-{ int addr; /* Assumes IP4, 32 bit network addresses */
- struct hostent *hp;
-
- /* Use inet_addr to try to convert the address */
-
- if ((addr = inet_addr(host)) == INADDR_NONE) { /* Oh well, a good try :-) */
-
- /* Now try a name look up with gethostbyname */
-
- if ((hp = gethostbyname(host)) == NULL) { /* Not in DNS */
-
- /* Try NetBIOS name lookup, how the hell do we do that? */
-
- RFCNB_errno = RFCNBE_BadName; /* Is this right? */
- RFCNB_saved_errno = errno;
- return(RFCNBE_Bad);
-
- }
- else { /* We got a name */
-
- memcpy((void *)Dest_IP, (void *)hp -> h_addr_list[0], sizeof(struct in_addr));
-
- }
- }
- else { /* It was an IP address */
-
- memcpy((void *)Dest_IP, (void *)&addr, sizeof(struct in_addr));
-
- }
-
- return 0;
-
-}
-
-/* Disconnect the TCP connection to the server */
-
-int RFCNB_Close(int socket)
-
-{
-
- close(socket);
-
- /* If we want to do error recovery, here is where we put it */
-
- return 0;
-
-}
-
-/* Connect to the server specified in the IP address.
- Not sure how to handle socket options etc. */
-
-int RFCNB_IP_Connect(struct in_addr Dest_IP, int port)
-
-{ struct sockaddr_in Socket;
- int fd;
-
- /* Create a socket */
-
- if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { /* Handle the error */
-
- RFCNB_errno = RFCNBE_BadSocket;
- RFCNB_saved_errno = errno;
- return(RFCNBE_Bad);
- }
-
- memset(&Socket, 0, sizeof(Socket));
- memcpy((char *)&Socket.sin_addr, (char *)&Dest_IP, sizeof(Dest_IP));
-
- Socket.sin_port = htons(port);
- Socket.sin_family = PF_INET;
-
- /* Now connect to the destination */
-
- if (connect(fd, (struct sockaddr *)&Socket, sizeof(Socket)) < 0) { /* Error */
-
- close(fd);
- RFCNB_errno = RFCNBE_ConnectFailed;
- RFCNB_saved_errno = errno;
- return(RFCNBE_Bad);
- }
-
- return(fd);
-
-}
-
-/* handle the details of establishing the RFCNB session with remote
- end
-
-*/
-
-int RFCNB_Session_Req(struct RFCNB_Con *con,
- char *Called_Name,
- char *Calling_Name,
- bool *redirect,
- struct in_addr *Dest_IP,
- int * port)
-
-{ char *sess_pkt;
-
- /* Response packet should be no more than 9 bytes, make 16 jic */
-
- char resp[16];
- int len;
- struct RFCNB_Pkt *pkt, res_pkt;
-
- /* We build and send the session request, then read the response */
-
- pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Sess_Len);
-
- if (pkt == NULL) {
-
- return(RFCNBE_Bad); /* Leave the error that RFCNB_Alloc_Pkt gives) */
-
- }
-
- sess_pkt = pkt -> data; /* Get pointer to packet proper */
-
- sess_pkt[RFCNB_Pkt_Type_Offset] = RFCNB_SESSION_REQUEST;
- RFCNB_Put_Pkt_Len(sess_pkt, RFCNB_Pkt_Sess_Len-RFCNB_Pkt_Hdr_Len);
- sess_pkt[RFCNB_Pkt_N1Len_Offset] = 32;
- sess_pkt[RFCNB_Pkt_N2Len_Offset] = 32;
-
- RFCNB_CvtPad_Name(Called_Name, (sess_pkt + RFCNB_Pkt_Called_Offset));
- RFCNB_CvtPad_Name(Calling_Name, (sess_pkt + RFCNB_Pkt_Calling_Offset));
-
- /* Now send the packet */
-
- if ((len = RFCNB_Put_Pkt(con, pkt, RFCNB_Pkt_Sess_Len)) < 0) {
-
- return(RFCNBE_Bad); /* Should be able to write that lot ... */
-
- }
-
- res_pkt.data = resp;
- res_pkt.len = sizeof(resp);
- res_pkt.next = NULL;
-
- if ((len = RFCNB_Get_Pkt(con, &res_pkt, sizeof(resp))) < 0) {
-
- return(RFCNBE_Bad);
-
- }
-
- /* Now analyze the packet ... */
-
- switch (RFCNB_Pkt_Type(resp)) {
-
- case RFCNB_SESSION_REJ: /* Didnt like us ... too bad */
-
- /* Why did we get rejected ? */
-
- switch (CVAL(resp,RFCNB_Pkt_Error_Offset)) {
-
- case 0x80:
- RFCNB_errno = RFCNBE_CallRejNLOCN;
- break;
- case 0x81:
- RFCNB_errno = RFCNBE_CallRejNLFCN;
- break;
- case 0x82:
- RFCNB_errno = RFCNBE_CallRejCNNP;
- break;
- case 0x83:
- RFCNB_errno = RFCNBE_CallRejInfRes;
- break;
- case 0x8F:
- RFCNB_errno = RFCNBE_CallRejUnSpec;
- break;
- default:
- RFCNB_errno = RFCNBE_ProtErr;
- break;
- }
-
- return(RFCNBE_Bad);
- break;
-
- case RFCNB_SESSION_ACK: /* Got what we wanted ... */
-
- return(0);
- break;
-
- case RFCNB_SESSION_RETARGET: /* Go elsewhere */
-
- *redirect = true; /* Copy port and ip addr */
-
- memcpy(Dest_IP, (resp + RFCNB_Pkt_IP_Offset), sizeof(struct in_addr));
- *port = SVAL(resp, RFCNB_Pkt_Port_Offset);
-
- return(0);
- break;
-
- default: /* A protocol error */
-
- RFCNB_errno = RFCNBE_ProtErr;
- return(RFCNBE_Bad);
- break;
- }
-}