]> git.sur5r.net Git - ngadmin/blob - lib/src/session.c
Raw: refactor attribute encoding and decoding
[ngadmin] / lib / src / session.c
1
2 #include <errno.h>
3
4 #include <ngadmin.h>
5
6 #include <nsdp/attr.h>
7 #include <nsdp/protocol.h>
8
9 #include "lib.h"
10 #include "network.h"
11
12
13 int ngadmin_scan (struct ngadmin *nga)
14 {
15         int i;
16         List *attr, *swiList;
17         struct swi_attr *sa;
18         struct nsdp_cmd nc;
19         /* sent by official win client:
20          * ATTR_PRODUCT
21          * ATTR_UNK2
22          * ATTR_NAME
23          * ATTR_MAC
24          * ATTR_UNK5
25          * ATTR_IP
26          * ATTR_NETMASK
27          * ATTR_GATEWAY
28          * ATTR_DHCP
29          * ATTR_UNK12
30          * ATTR_FIRM_VER
31          * ATTR_UNK14
32          * ATTR_UNK15
33          * ATTR_END
34          *
35          * one may be tempted to add ATTR_ENCPASS so we can now early if the
36          * switch uses password encryption, but this would cause (at least)
37          * switches that do not support this feature not to reply to the
38          * discovery request at all
39          */
40         static const unsigned short hello[] = {
41                 ATTR_PRODUCT,
42                 ATTR_NAME,
43                 ATTR_MAC,
44                 ATTR_IP,
45                 ATTR_NETMASK,
46                 ATTR_GATEWAY,
47                 ATTR_DHCP,
48                 ATTR_FIRM_VER,
49                 ATTR_PORTS_COUNT,
50                 ATTR_END
51         };
52         
53         
54         if (nga == NULL)
55                 return ERR_INVARG;
56         
57         free(nga->swi_tab);
58         nga->swi_tab = NULL;
59         nga->swi_count = 0;
60         nga->current = NULL;
61         
62         
63         /* create attributes for an "hello" request */
64         attr = createEmptyList();
65         for (i = 0; ; i++) {
66                 pushBackList(attr, newEmptyAttr(hello[i]));
67                 if (hello[i] == ATTR_END)
68                         break;
69         }
70         
71         /* send request to all potential switches */
72         prepareSend(nga, &nc, CODE_READ_REQ);
73         i = sendNsdpPacket(nga->sock, &nc, attr);
74         clearList(attr, (void(*)(void*))freeAttr);
75         if (i == -EINVAL)
76                 return ERR_INVARG;
77         else if (i < 0)
78                 return ERR_NET;
79         
80         /* try to receive any packets until timeout */
81         swiList = createEmptyList();
82         /* FIXME: end after timeout whatever received packet is good or not */
83         while (1) {
84                 prepareRecv(nga, &nc, CODE_READ_REP);
85                 if (recvNsdpPacket(nga->sock, &nc, attr, &nga->timeout) < 0)
86                         break;
87                 
88                 sa = malloc(sizeof(struct swi_attr));
89                 if (sa == NULL)
90                         return ERR_MEM;
91                 
92                 extractSwitchAttributes(sa, attr);
93                 clearList(attr, (void(*)(void*))freeAttr);
94                 pushBackList(swiList, sa);
95         }
96         
97         nga->swi_count = swiList->count;
98         nga->swi_tab = convertToArray(swiList, sizeof(struct swi_attr));
99         destroyList(swiList, free);
100         destroyList(attr, (void(*)(void*))freeAttr);
101         
102         
103         return ERR_OK;
104 }
105
106
107 const struct swi_attr* ngadmin_getSwitchTab (struct ngadmin *nga, int *nb)
108 {
109         if (nga == NULL || nb == NULL)
110                 return NULL;
111         
112         *nb = nga->swi_count;
113         
114         return nga->swi_tab;
115 }
116
117
118 const struct swi_attr* ngadmin_getCurrentSwitch (struct ngadmin *nga)
119 {
120         if (nga == NULL)
121                 return NULL;
122         
123         return nga->current;
124 }
125
126
127 int ngadmin_login (struct ngadmin *nga, int id)
128 {
129         List *attr;
130         struct attr *at;
131         int ret = ERR_OK;
132         struct swi_attr *sa;
133         
134         
135         if (nga == NULL)
136                 return ERR_INVARG;
137         else if (id < 0 || id >= nga->swi_count)
138                 return ERR_BADID;
139         
140         sa = &nga->swi_tab[id];
141         nga->current = sa;
142         nga->encrypt_pass = false;
143         
144         /* determine if the switch uses password encryption
145          * as explained in ngadmin_scan, it cannot be done at discovery
146          * stage
147          */
148         attr = createEmptyList();
149         pushBackList(attr, newEmptyAttr(ATTR_ENCPASS));
150         ret = readRequest(nga, attr);
151         if (ret != ERR_OK)
152                 goto end;
153         
154         filterAttributes(attr, ATTR_ENCPASS, ATTR_END);
155         if (attr->first != NULL) {
156                 at = attr->first->data;
157                 nga->encrypt_pass = (at->size == 4 && *(unsigned int*)at->data == 1);
158         }
159         clearList(attr, (void(*)(void*))freeAttr);
160         
161         /* strangely, passwords must never be encrypted inside a read request,
162          * or it will be rejected. Seems more to be a firmware bug
163          */
164         pushBackList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
165         ret = readRequest(nga, attr);
166         if (ret == ERR_OK ) {
167                 /* login succeeded */
168                 /* TODO: if keep broadcasting is disabled, connect() the UDP
169                  * socket so icmp errors messages (port unreachable, TTL exceeded
170                  * in transit, ...) can be received
171                  */
172         } else {
173                 /* login failed */
174                 nga->current = NULL;
175         }
176         
177 end:
178         destroyList(attr, (void(*)(void*))freeAttr);
179         
180         
181         return ret;
182 }
183
184