added stdio.h to includes for DBG compilation
[people/asdlkf/gpxe.git] / src / proto / nmb.c
1 #include "stdio.h"
2 #include "resolv.h"
3 #include "string.h"
4 #include "dns.h"
5 #include "nic.h"
6 #include "nmb.h"
7
8 /*
9  * Convert a standard NUL-terminated string to an NBNS query name.
10  *
11  * Returns a pointer to the character following the constructed NBNS
12  * query name.
13  *
14  */
15 static inline char * nbns_make_name ( char *dest, const char *name ) {
16         char nb_name[16];
17         char c;
18         int i;
19         uint16_t *d;
20
21         *(dest++) = 32; /* Length is always 32 */
22
23         /* Name encoding is as follows: pad the name with spaces to
24          * length 15, and add a NUL.  Take this 16-byte string, split
25          * it into nibbles and add 0x41 to each nibble to form a byte
26          * of the resulting name string.
27          */
28         memset ( nb_name, ' ', 15 );
29         nb_name[15] = '\0';
30         memcpy ( nb_name, name, strlen ( name ) ); /* Do not copy NUL */
31
32         d = ( uint16_t * ) dest;
33         for ( i = 0 ; i < 16 ; i++ ) {
34                 c = nb_name[i];
35                 *( d++ )  = htons ( ( ( c | ( c << 4 ) ) & 0x0f0f ) + 0x4141 );
36         }
37         dest = ( char * ) d;
38
39         *(dest++) = 0; /* Terminating 0-length name component */
40         return dest;
41 }
42
43 /*
44  * Resolve a name using NMB
45  *
46  */
47 static int nmb_resolv ( struct in_addr *addr, const char *name ) {
48         struct dns_query query;
49         struct dns_query_info *query_info;
50         struct dns_header *reply;
51         struct dns_rr_info *rr_info;
52         struct dns_rr_info_nb *rr_info_nb;
53         struct sockaddr_in nameserver;
54
55         DBG ( "NMB resolving %s\n", name );
56
57         /* Set up the query data */
58         nameserver.sin_addr.s_addr = INADDR_BROADCAST;
59         nameserver.sin_port = NBNS_UDP_PORT;
60         memset ( &query, 0, sizeof ( query ) );
61         query.dns.id = htons ( 1 );
62         query.dns.flags = htons ( DNS_FLAG_QUERY | DNS_FLAG_OPCODE_QUERY |
63                                   DNS_FLAG_RD | DNS_FLAG_BROADCAST );
64         query.dns.qdcount = htons ( 1 );
65         query_info = ( void * ) nbns_make_name ( query.payload, name );
66         query_info->qtype = htons ( DNS_TYPE_NB );
67         query_info->qclass = htons ( DNS_CLASS_IN );
68
69         /* Issue query, wait for reply */
70         reply = dns_query ( &query,
71                             ( ( ( char * ) query_info )
72                               + sizeof ( *query_info )
73                               - ( ( char * ) &query ) ),
74                             &nameserver );
75         if ( ! reply ) {
76                 DBG ( "NMB got no response via %@ (port %d)\n",
77                       nameserver.sin_addr.s_addr,
78                       nameserver.sin_port );
79                 return 0;
80         }
81
82         /* Search through response for useful answers. */
83         rr_info = dns_find_rr ( &query, reply );
84         if ( ! rr_info ) {
85                 DBG ( "NMB got invalid response\n" );
86                 return 0;
87         }
88
89         /* Check type of response */
90         if ( ntohs ( rr_info->type ) != DNS_TYPE_NB ) {
91                 DBG ( "NMB got answer type %hx (wanted %hx)\n",
92                       ntohs ( rr_info->type ), DNS_TYPE_NB );
93                 return 0;
94         }
95
96         /* Read response */
97         rr_info_nb = ( struct dns_rr_info_nb * ) rr_info;
98         *addr = rr_info_nb->nb_address;
99         DBG ( "NMB found address %@\n", addr->s_addr );
100
101         return 1;
102 }
103
104 struct resolver nmb_resolver __resolver = {
105         .name = "NMB",
106         .resolv = nmb_resolv,
107 };