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 "std-includes.h"
29 #include "rfcnb-priv.h"
30 #include "rfcnb-util.h"
33 extern void (*Prot_Print_Routine)(); /* Pointer to protocol print routine */
35 /* Convert name and pad to 16 chars as needed */
36 /* Name 1 is a C string with null termination, name 2 may not be */
37 /* If SysName is true, then put a <00> on end, else space> */
39 void RFCNB_CvtPad_Name(char *name1, char *name2)
46 for (i = 0; i < 16; i++) {
50 c1 = 'C'; c2 = 'A'; /* CA is a space */
55 c1 = (char)((int)c/16 + (int)'A');
56 c2 = (char)((int)c%16 + (int)'A');
64 name2[32] = 0; /* Put in the nll ...*/
68 /* Converts an Ascii NB Name (16 chars) to an RFCNB Name (32 chars)
69 Uses the encoding in RFC1001. Each nibble of byte is added to 'A'
70 to produce the next byte in the name.
72 This routine assumes that AName is 16 bytes long and that NBName has
73 space for 32 chars, so be careful ...
77 void RFCNB_AName_To_NBName(char *AName, char *NBName)
82 for (i=0; i < 16; i++) {
86 c1 = (char)((c >> 4) + 'A');
87 c2 = (char)((c & 0xF) + 'A');
93 NBName[32] = 0; /* Put in a null */
97 /* Do the reverse of the above ... */
99 void RFCNB_NBName_To_AName(char *NBName, char *AName)
104 for (i=0; i < 16; i++) {
109 c = (char)(((int)c1 - (int)'A') * 16 + ((int)c2 - (int)'A'));
115 AName[i] = 0; /* Put a null on the end ... */
119 /* Print a string of bytes in HEX etc */
121 void RFCNB_Print_Hex(FILE *fd, struct RFCNB_Pkt *pkt, int Offset, int Len)
123 { char c1, c2, outbuf1[33];
126 struct RFCNB_Pkt *pkt_ptr = pkt;
127 static char Hex_List[17] = "0123456789ABCDEF";
131 /* We only want to print as much as sepcified in Len */
133 while (pkt_ptr != NULL) {
136 i < ((Len > (pkt_ptr -> len)?pkt_ptr -> len:Len) - Offset);
139 c = pkt_ptr -> data[i + Offset];
140 c1 = Hex_List[c >> 4];
141 c2 = Hex_List[c & 0xF];
143 outbuf1[j++] = c1; outbuf1[j++] = c2;
145 if (j == 32){ /* Print and reset */
147 fprintf(fd, " %s\n", outbuf1);
154 Len = Len - pkt_ptr -> len; /* Reduce amount by this much */
155 pkt_ptr = pkt_ptr -> next;
159 /* Print last lot in the buffer ... */
164 fprintf(fd, " %s\n", outbuf1);
172 /* Get a packet of size n */
174 struct RFCNB_Pkt *RFCNB_Alloc_Pkt(int n)
178 if ((pkt = (struct RFCNB_Pkt *)malloc(sizeof(struct RFCNB_Pkt))) == NULL) {
180 RFCNB_errno = RFCNBE_NoSpace;
181 RFCNB_saved_errno = errno;
189 if (n == 0) return(pkt);
191 if ((pkt -> data = (char *)malloc(n)) == NULL) {
193 RFCNB_errno = RFCNBE_NoSpace;
194 RFCNB_saved_errno = errno;
204 /* Free up a packet */
206 int RFCNB_Free_Pkt(struct RFCNB_Pkt *pkt)
208 { struct RFCNB_Pkt *pkt_next; char *data_ptr;
210 while (pkt != NULL) {
212 pkt_next = pkt -> next;
214 data_ptr = pkt -> data;
216 if (data_ptr != NULL)
227 /* Print an RFCNB packet */
229 void RFCNB_Print_Pkt(FILE *fd, char *dirn, struct RFCNB_Pkt *pkt, int len)
233 /* We assume that the first fragment is the RFCNB Header */
234 /* We should loop through the fragments printing them out */
236 fprintf(fd, "RFCNB Pkt %s:", dirn);
238 switch (RFCNB_Pkt_Type(pkt -> data)) {
240 case RFCNB_SESSION_MESSAGE:
242 fprintf(fd, "SESSION MESSAGE: Length = %i\n", RFCNB_Pkt_Len(pkt -> data));
243 RFCNB_Print_Hex(fd, pkt, RFCNB_Pkt_Hdr_Len,
244 #ifdef RFCNB_PRINT_DATA
245 RFCNB_Pkt_Len(pkt -> data) - RFCNB_Pkt_Hdr_Len);
250 if (Prot_Print_Routine != 0) { /* Print the rest of the packet */
252 Prot_Print_Routine(fd, strcmp(dirn, "sent"), pkt, RFCNB_Pkt_Hdr_Len,
253 RFCNB_Pkt_Len(pkt -> data) - RFCNB_Pkt_Hdr_Len);
259 case RFCNB_SESSION_REQUEST:
261 fprintf(fd, "SESSION REQUEST: Length = %i\n",
262 RFCNB_Pkt_Len(pkt -> data));
263 RFCNB_NBName_To_AName((char *)(pkt -> data + RFCNB_Pkt_Called_Offset), lname);
264 fprintf(fd, " Called Name: %s\n", lname);
265 RFCNB_NBName_To_AName((char *)(pkt -> data + RFCNB_Pkt_Calling_Offset), lname);
266 fprintf(fd, " Calling Name: %s\n", lname);
270 case RFCNB_SESSION_ACK:
272 fprintf(fd, "RFCNB SESSION ACK: Length = %i\n",
273 RFCNB_Pkt_Len(pkt -> data));
277 case RFCNB_SESSION_REJ:
278 fprintf(fd, "RFCNB SESSION REJECT: Length = %i\n",
279 RFCNB_Pkt_Len(pkt -> data));
281 if (RFCNB_Pkt_Len(pkt -> data) < 1) {
282 fprintf(fd, " Protocol Error, short Reject packet!\n");
285 fprintf(fd, " Error = %x\n", CVAL(pkt -> data, RFCNB_Pkt_Error_Offset));
290 case RFCNB_SESSION_RETARGET:
292 fprintf(fd, "RFCNB SESSION RETARGET: Length = %i\n",
293 RFCNB_Pkt_Len(pkt -> data));
295 /* Print out the IP address etc and the port? */
299 case RFCNB_SESSION_KEEP_ALIVE:
301 fprintf(fd, "RFCNB SESSION KEEP ALIVE: Length = %i\n",
302 RFCNB_Pkt_Len(pkt -> data));
312 /* Resolve a name into an address */
314 int RFCNB_Name_To_IP(char *host, struct in_addr *Dest_IP)
316 { int addr; /* Assumes IP4, 32 bit network addresses */
319 /* Use inet_addr to try to convert the address */
321 if ((addr = ip_getaddr(host)) == INADDR_NONE) { /* Not in DNS */
323 /* Try NetBIOS name lookup, how the hell do we do that? */
325 RFCNB_errno = RFCNBE_BadName; /* Is this right? */
326 RFCNB_saved_errno = errno;
330 else { /* We got an IP address */
332 memcpy((void *)Dest_IP, (void *)&addr, sizeof(struct in_addr));
340 /* Disconnect the TCP connection to the server */
342 int RFCNB_Close(int socket)
348 /* If we want to do error recovery, here is where we put it */
354 /* Connect to the server specified in the IP address.
355 Not sure how to handle socket options etc. */
357 int RFCNB_IP_Connect(struct in_addr Dest_IP, int port)
359 { struct sockaddr_in Socket;
362 /* Create a socket */
364 if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { /* Handle the error */
366 RFCNB_errno = RFCNBE_BadSocket;
367 RFCNB_saved_errno = errno;
371 bzero((char *)&Socket, sizeof(Socket));
372 memcpy((char *)&Socket.sin_addr, (char *)&Dest_IP, sizeof(Dest_IP));
374 Socket.sin_port = htons(port);
375 Socket.sin_family = PF_INET;
377 /* Now connect to the destination */
379 if (connect(fd, (struct sockaddr *)&Socket, sizeof(Socket)) < 0) { /* Error */
382 RFCNB_errno = RFCNBE_ConnectFailed;
383 RFCNB_saved_errno = errno;
391 /* handle the details of establishing the RFCNB session with remote
396 int RFCNB_Session_Req(struct RFCNB_Con *con,
400 struct in_addr *Dest_IP,
405 /* Response packet should be no more than 9 bytes, make 16 jic */
407 char ln1[16], ln2[16], n1[32], n2[32], resp[16];
409 struct RFCNB_Pkt *pkt, res_pkt;
411 /* We build and send the session request, then read the response */
413 pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Sess_Len);
417 return(RFCNBE_Bad); /* Leave the error that RFCNB_Alloc_Pkt gives) */
421 sess_pkt = pkt -> data; /* Get pointer to packet proper */
423 sess_pkt[RFCNB_Pkt_Type_Offset] = RFCNB_SESSION_REQUEST;
424 RFCNB_Put_Pkt_Len(sess_pkt, RFCNB_Pkt_Sess_Len-RFCNB_Pkt_Hdr_Len);
425 sess_pkt[RFCNB_Pkt_N1Len_Offset] = 32;
426 sess_pkt[RFCNB_Pkt_N2Len_Offset] = 32;
428 RFCNB_CvtPad_Name(Called_Name, (sess_pkt + RFCNB_Pkt_Called_Offset));
429 RFCNB_CvtPad_Name(Calling_Name, (sess_pkt + RFCNB_Pkt_Calling_Offset));
431 /* Now send the packet */
435 fprintf(stderr, "Sending packet: ");
439 if ((len = RFCNB_Put_Pkt(con, pkt, RFCNB_Pkt_Sess_Len)) < 0) {
441 return(RFCNBE_Bad); /* Should be able to write that lot ... */
447 fprintf(stderr, "Getting packet.\n");
452 res_pkt.len = sizeof(resp);
455 if ((len = RFCNB_Get_Pkt(con, &res_pkt, sizeof(resp))) < 0) {
461 /* Now analyze the packet ... */
463 switch (RFCNB_Pkt_Type(resp)) {
465 case RFCNB_SESSION_REJ: /* Didnt like us ... too bad */
467 /* Why did we get rejected ? */
469 switch (CVAL(resp,RFCNB_Pkt_Error_Offset)) {
472 RFCNB_errno = RFCNBE_CallRejNLOCN;
475 RFCNB_errno = RFCNBE_CallRejNLFCN;
478 RFCNB_errno = RFCNBE_CallRejCNNP;
481 RFCNB_errno = RFCNBE_CallRejInfRes;
484 RFCNB_errno = RFCNBE_CallRejUnSpec;
487 RFCNB_errno = RFCNBE_ProtErr;
494 case RFCNB_SESSION_ACK: /* Got what we wanted ... */
499 case RFCNB_SESSION_RETARGET: /* Go elsewhere */
501 *redirect = TRUE; /* Copy port and ip addr */
503 memcpy(Dest_IP, (resp + RFCNB_Pkt_IP_Offset), sizeof(struct in_addr));
504 *port = SVAL(resp, RFCNB_Pkt_Port_Offset);
509 default: /* A protocol error */
511 RFCNB_errno = RFCNBE_ProtErr;