9 #include <netinet/ether.h>
10 #include <sys/ioctl.h>
12 #include <nsdp/attr.h>
13 #include <nsdp/misc.h>
15 #include <nsdp/protocol.h>
20 int startNetwork (struct ngadmin *nga)
27 nga->sock = socket(AF_INET, SOCK_DGRAM, 0);
33 memset(&ifr, 0, sizeof(struct ifreq));
34 strncpy(ifr.ifr_name, nga->iface, IFNAMSIZ - 1);
36 /* get the interface MAC address */
37 ret = ioctl(nga->sock, SIOCGIFHWADDR, &ifr);
39 perror("ioctl(SIOCGIFHWADDR)");
43 memcpy(&nga->localmac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
46 memset(&nga->local, 0, sizeof(struct sockaddr_in));
47 nga->local.sin_family = AF_INET;
48 nga->local.sin_port = htons(CLIENT_PORT);
50 ret = bind(nga->sock, (struct sockaddr*)&nga->local, sizeof(struct sockaddr_in));
57 /* allow broadcasting */
59 ret = setsockopt(nga->sock, SOL_SOCKET, SO_BROADCAST, &ret, sizeof(ret));
61 perror("setsockopt(SO_BROADCAST)");
65 /* prevent unicast packets from being routed by setting the TTL to 1 */
67 ret = setsockopt(nga->sock, IPPROTO_IP, IP_TTL, &ret, sizeof(ret));
69 perror("setsockopt(IP_TTL)");
78 int setBroadcastType (struct ngadmin *nga, bool value)
84 nga->globalbroad = value;
86 nga->brd.s_addr = (in_addr_t)0;
90 memset(&ifr, 0, sizeof(struct ifreq));
91 strncpy(ifr.ifr_name, nga->iface, IFNAMSIZ - 1);
93 /* get the interface broadcast address */
94 ret = ioctl(nga->sock, SIOCGIFBRDADDR, &ifr);
96 perror("ioctl(SIOCGIFBRDADDR)");
97 nga->brd.s_addr = (in_addr_t)0;
98 nga->globalbroad = true;
102 nga->brd = (*(struct sockaddr_in*)&ifr.ifr_addr).sin_addr;
108 int stopNetwork (struct ngadmin *nga)
110 return close(nga->sock);
114 int forceInterface (struct ngadmin *nga)
119 /* as described bellow, when you have multiple interfaces, this
120 * forces the packet to go to a particular interface
122 ret = setsockopt(nga->sock, SOL_SOCKET, SO_BINDTODEVICE, nga->iface, strlen(nga->iface) + 1);
124 perror("setsockopt(SO_BINDTODEVICE)");
128 /* if the switch's IP is not in your network range, for instance
129 * because you do not have DHCP enabled or you started the switch
130 * after your DHCP server, this allows to bypass the routing tables
131 * and consider every address is directly reachable on the interface
134 ret = setsockopt(nga->sock, SOL_SOCKET, SO_DONTROUTE, &ret, sizeof(ret));
136 perror("setsockopt(SO_DONTROUTE)");
145 static int checkErrorCode (const struct nsdp_cmd *nc)
153 return (nc->attr_error == ATTR_PASSWORD) ? ERR_BADPASS : ERR_DENIED;
155 case ERROR_INVALID_VALUE:
164 void prepareSend (struct ngadmin *nga, struct nsdp_cmd *nc, unsigned char code)
166 struct swi_attr *sa = nga->current;
169 memset(nc, 0, sizeof(struct nsdp_cmd));
170 memcpy(&nc->client_mac, &nga->localmac, ETH_ALEN);
171 nc->remote_addr.sin_family = AF_INET;
172 nc->remote_addr.sin_port = htons(SWITCH_PORT);
174 memcpy(&nc->switch_mac, &sa->mac, ETH_ALEN);
176 /* destination address selection */
177 if (sa != NULL && !nga->keepbroad)
178 nc->remote_addr.sin_addr = sa->nc.ip;
179 else if (nga->globalbroad)
180 nc->remote_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
182 nc->remote_addr.sin_addr = nga->brd;
184 nc->seqnum = ++nga->seq;
189 void prepareRecv (struct ngadmin *nga, struct nsdp_cmd *nc, unsigned char code)
191 struct swi_attr *sa = nga->current;
194 memset(nc, 0, sizeof(struct nsdp_cmd));
195 memcpy(&nc->client_mac, &nga->localmac, ETH_ALEN);
196 nc->remote_addr.sin_family = AF_INET;
197 nc->remote_addr.sin_port = htons(SWITCH_PORT);
199 memcpy(&nc->switch_mac, &sa->mac, ETH_ALEN);
201 /* set filter on switch IP */
203 nc->remote_addr.sin_addr.s_addr = htonl(INADDR_ANY);
205 nc->remote_addr.sin_addr = sa->nc.ip;
207 nc->seqnum = nga->seq;
212 int readRequest (struct ngadmin *nga, List *attr)
223 /* add end attribute to end */
224 pushBackList(attr, newEmptyAttr(ATTR_END));
226 prepareSend(nga, &nc, CODE_READ_REQ);
227 i = sendNsdpPacket(nga->sock, &nc, attr);
229 /* do not destroy the list, it will be filled again later by recvNsdpPacket */
230 clearList(attr, (void(*)(void*))freeAttr);
233 prepareRecv(nga, &nc, CODE_READ_REP);
234 i = recvNsdpPacket(nga->sock, &nc, attr, &nga->timeout);
241 ret = (errno == EAGAIN || errno == EWOULDBLOCK) ? ERR_TIMEOUT : ERR_NET;
246 /* check the switch error code */
247 ret = checkErrorCode(&nc);
255 int writeRequest (struct ngadmin *nga, List *attr)
265 } else if (nga->current == NULL) {
272 attr = createEmptyList();
274 /* add password attribute to start */
275 at = newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password));
276 if (nga->encrypt_pass)
277 passwordEndecode(at->data, at->size);
278 pushFrontList(attr, at);
280 /* add end attribute to end */
281 pushBackList(attr, newEmptyAttr(ATTR_END));
283 prepareSend(nga, &nc, CODE_WRITE_REQ);
284 i = sendNsdpPacket(nga->sock, &nc, attr);
286 /* the list will be filled again by recvNgPacket
287 * but normally it will be still empty
289 clearList(attr, (void(*)(void*))freeAttr);
292 prepareRecv(nga, &nc, CODE_WRITE_REP);
293 i = recvNsdpPacket(nga->sock, &nc, attr, &nga->timeout);
300 ret = (errno == EAGAIN || errno == EWOULDBLOCK) ? ERR_TIMEOUT : ERR_NET;
304 /* check the switch error code */
305 ret = checkErrorCode(&nc);
309 /* the switch replies to write request by just a header (no attributes), so the list can be destroyed */
310 destroyList(attr, (void(*)(void*))freeAttr);
317 void extractSwitchAttributes (struct swi_attr *sa, const List *l)
320 const struct attr *at;
324 memset(sa, 0, sizeof(struct swi_attr));
326 for (ln = l->first; ln != NULL; ln = ln->next) {
332 len = min(at->size, PRODUCT_SIZE);
333 memcpy(sa->product, at->data, len);
334 trim(sa->product, len);
338 len = min(at->size, NAME_SIZE);
339 memcpy(sa->name, at->data, len);
344 memcpy(&sa->mac, at->data, ETH_ALEN);
348 sa->nc.ip = *(struct in_addr*)at->data;
352 sa->nc.netmask = *(struct in_addr*)at->data;
356 sa->nc.gw = *(struct in_addr*)at->data;
360 /* Note: DHCP attribute is special, it is 2 two bytes long when sent
361 * by the switch but only 1 byte long when sent by the client
363 sa->nc.dhcp = (at->size == 2) && ((*(unsigned short*)at->data) == 1);
367 len = min(at->size, FIRMWARE_SIZE - 1);
368 memcpy(sa->firmware, at->data, len);
369 sa->firmware[len] = '\0';
372 case ATTR_PORTS_COUNT:
373 sa->ports = *(unsigned char*)at->data;