1 /* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
4 RFCNB Utility Routines ...
6 Copyright (C) Richard Sharpe 1996
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #include "portable/socket.h"
32 #include "rfcnb-priv.h"
33 #include "rfcnb-util.h"
37 # define INADDR_NONE -1
40 extern void (*Prot_Print_Routine)(); /* Pointer to protocol print routine */
42 /* Convert name and pad to 16 chars as needed */
43 /* Name 1 is a C string with null termination, name 2 may not be */
44 /* If SysName is true, then put a <00> on end, else space> */
46 void RFCNB_CvtPad_Name(char *name1, char *name2)
53 for (i = 0; i < 16; i++) {
57 c1 = 'C'; c2 = 'A'; /* CA is a space */
62 c1 = (char)((int)c/16 + (int)'A');
63 c2 = (char)((int)c%16 + (int)'A');
71 name2[32] = 0; /* Put in the nll ...*/
75 /* Get a packet of size n */
77 struct RFCNB_Pkt *RFCNB_Alloc_Pkt(int n)
81 if ((pkt = (struct RFCNB_Pkt *)malloc(sizeof(struct RFCNB_Pkt))) == NULL) {
83 RFCNB_errno = RFCNBE_NoSpace;
84 RFCNB_saved_errno = errno;
92 if (n == 0) return(pkt);
94 if ((pkt -> data = (char *)malloc(n)) == NULL) {
96 RFCNB_errno = RFCNBE_NoSpace;
97 RFCNB_saved_errno = errno;
107 /* Free up a packet */
109 void RFCNB_Free_Pkt(struct RFCNB_Pkt *pkt)
111 { struct RFCNB_Pkt *pkt_next; char *data_ptr;
113 while (pkt != NULL) {
115 pkt_next = pkt -> next;
117 data_ptr = pkt -> data;
119 if (data_ptr != NULL)
130 /* Resolve a name into an address */
132 int RFCNB_Name_To_IP(char *host, struct in_addr *Dest_IP)
134 { int addr; /* Assumes IP4, 32 bit network addresses */
137 /* Use inet_addr to try to convert the address */
139 if ((addr = inet_addr(host)) == INADDR_NONE) { /* Oh well, a good try :-) */
141 /* Now try a name look up with gethostbyname */
143 if ((hp = gethostbyname(host)) == NULL) { /* Not in DNS */
145 /* Try NetBIOS name lookup, how the hell do we do that? */
147 RFCNB_errno = RFCNBE_BadName; /* Is this right? */
148 RFCNB_saved_errno = errno;
152 else { /* We got a name */
154 memcpy((void *)Dest_IP, (void *)hp -> h_addr_list[0], sizeof(struct in_addr));
158 else { /* It was an IP address */
160 memcpy((void *)Dest_IP, (void *)&addr, sizeof(struct in_addr));
168 /* Disconnect the TCP connection to the server */
170 int RFCNB_Close(int socket)
176 /* If we want to do error recovery, here is where we put it */
182 /* Connect to the server specified in the IP address.
183 Not sure how to handle socket options etc. */
185 int RFCNB_IP_Connect(struct in_addr Dest_IP, int port)
187 { struct sockaddr_in Socket;
190 /* Create a socket */
192 if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { /* Handle the error */
194 RFCNB_errno = RFCNBE_BadSocket;
195 RFCNB_saved_errno = errno;
199 memset(&Socket, 0, sizeof(Socket));
200 memcpy((char *)&Socket.sin_addr, (char *)&Dest_IP, sizeof(Dest_IP));
202 Socket.sin_port = htons(port);
203 Socket.sin_family = PF_INET;
205 /* Now connect to the destination */
207 if (connect(fd, (struct sockaddr *)&Socket, sizeof(Socket)) < 0) { /* Error */
210 RFCNB_errno = RFCNBE_ConnectFailed;
211 RFCNB_saved_errno = errno;
219 /* handle the details of establishing the RFCNB session with remote
224 int RFCNB_Session_Req(struct RFCNB_Con *con,
228 struct in_addr *Dest_IP,
233 /* Response packet should be no more than 9 bytes, make 16 jic */
237 struct RFCNB_Pkt *pkt, res_pkt;
239 /* We build and send the session request, then read the response */
241 pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Sess_Len);
245 return(RFCNBE_Bad); /* Leave the error that RFCNB_Alloc_Pkt gives) */
249 sess_pkt = pkt -> data; /* Get pointer to packet proper */
251 sess_pkt[RFCNB_Pkt_Type_Offset] = RFCNB_SESSION_REQUEST;
252 RFCNB_Put_Pkt_Len(sess_pkt, RFCNB_Pkt_Sess_Len-RFCNB_Pkt_Hdr_Len);
253 sess_pkt[RFCNB_Pkt_N1Len_Offset] = 32;
254 sess_pkt[RFCNB_Pkt_N2Len_Offset] = 32;
256 RFCNB_CvtPad_Name(Called_Name, (sess_pkt + RFCNB_Pkt_Called_Offset));
257 RFCNB_CvtPad_Name(Calling_Name, (sess_pkt + RFCNB_Pkt_Calling_Offset));
259 /* Now send the packet */
261 if ((len = RFCNB_Put_Pkt(con, pkt, RFCNB_Pkt_Sess_Len)) < 0) {
263 return(RFCNBE_Bad); /* Should be able to write that lot ... */
268 res_pkt.len = sizeof(resp);
271 if ((len = RFCNB_Get_Pkt(con, &res_pkt, sizeof(resp))) < 0) {
277 /* Now analyze the packet ... */
279 switch (RFCNB_Pkt_Type(resp)) {
281 case RFCNB_SESSION_REJ: /* Didnt like us ... too bad */
283 /* Why did we get rejected ? */
285 switch (CVAL(resp,RFCNB_Pkt_Error_Offset)) {
288 RFCNB_errno = RFCNBE_CallRejNLOCN;
291 RFCNB_errno = RFCNBE_CallRejNLFCN;
294 RFCNB_errno = RFCNBE_CallRejCNNP;
297 RFCNB_errno = RFCNBE_CallRejInfRes;
300 RFCNB_errno = RFCNBE_CallRejUnSpec;
303 RFCNB_errno = RFCNBE_ProtErr;
310 case RFCNB_SESSION_ACK: /* Got what we wanted ... */
315 case RFCNB_SESSION_RETARGET: /* Go elsewhere */
317 *redirect = true; /* Copy port and ip addr */
319 memcpy(Dest_IP, (resp + RFCNB_Pkt_IP_Offset), sizeof(struct in_addr));
320 *port = SVAL(resp, RFCNB_Pkt_Port_Offset);
325 default: /* A protocol error */
327 RFCNB_errno = RFCNBE_ProtErr;