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