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)
120 As described bellow, when you have multiple interfaces, this forces the packet
121 to go to a particular interface.
123 ret = setsockopt(nga->sock, SOL_SOCKET, SO_BINDTODEVICE, nga->iface, strlen(nga->iface) + 1);
125 perror("setsockopt(SO_BINDTODEVICE)");
130 If the switch's IP is not in your network range, for instance because you do
131 not have DHCP enabled or you started the switch after it, this allows to
132 bypass the routing tables and consider every address is directly reachable on
136 ret = setsockopt(nga->sock, SOL_SOCKET, SO_DONTROUTE, &ret, sizeof(ret));
138 perror("setsockopt(SO_DONTROUTE)");
147 static int checkErrorCode (const struct nsdp_cmd *nc)
152 return (nc->attr_error == ATTR_PASSWORD) ? ERR_BADPASS : ERR_DENIED;
154 case ERROR_INVALID_VALUE:
163 void prepareSend (struct ngadmin *nga, struct nsdp_cmd *nc, unsigned char code)
165 struct swi_attr *sa = nga->current;
168 memset(nc, 0, sizeof(struct nsdp_cmd));
169 memcpy(&nc->client_mac, &nga->localmac, ETH_ALEN);
170 nc->remote_addr.sin_family = AF_INET;
171 nc->remote_addr.sin_port = htons(SWITCH_PORT);
173 memcpy(&nc->switch_mac, &sa->mac, ETH_ALEN);
174 nc->ports = sa->ports;
177 /* destination address selection */
178 if (sa != NULL && !nga->keepbroad)
179 nc->remote_addr.sin_addr = sa->nc.ip;
180 else if (nga->globalbroad)
181 nc->remote_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
183 nc->remote_addr.sin_addr = nga->brd;
185 nc->seqnum = ++nga->seq;
190 void prepareRecv (struct ngadmin *nga, struct nsdp_cmd *nc, unsigned char code)
192 struct swi_attr *sa = nga->current;
195 memset(nc, 0, sizeof(struct nsdp_cmd));
196 memcpy(&nc->client_mac, &nga->localmac, ETH_ALEN);
197 nc->remote_addr.sin_family = AF_INET;
198 nc->remote_addr.sin_port = htons(SWITCH_PORT);
200 memcpy(&nc->switch_mac, &sa->mac, ETH_ALEN);
201 nc->ports = sa->ports;
204 /* set filter on switch IP */
206 nc->remote_addr.sin_addr.s_addr = htonl(INADDR_ANY);
208 nc->remote_addr.sin_addr = sa->nc.ip;
210 nc->seqnum = nga->seq;
215 int readRequest (struct ngadmin *nga, List *attr)
226 /* add end attribute to end */
227 pushBackList(attr, newEmptyAttr(ATTR_END));
229 prepareSend(nga, &nc, CODE_READ_REQ);
230 i = sendNsdpPacket(nga->sock, &nc, attr);
232 /* do not destroy the list, it will be filled again later by recvNsdpPacket */
233 clearList(attr, (void(*)(void*))freeAttr);
236 prepareRecv(nga, &nc, CODE_READ_REP);
237 i = recvNsdpPacket(nga->sock, &nc, attr, &nga->timeout);
244 ret = (errno == EAGAIN || errno == EWOULDBLOCK) ? ERR_TIMEOUT : ERR_NET;
249 /* check the switch error code */
250 ret = checkErrorCode(&nc);
258 int writeRequest (struct ngadmin *nga, List *attr)
268 } else if (nga->current == NULL) {
275 attr = createEmptyList();
277 /* add password attribute to start */
278 at = newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password));
279 if (nga->encrypt_pass)
280 passwordEndecode(at->data, at->size);
281 pushFrontList(attr, at);
283 /* add end attribute to end */
284 pushBackList(attr, newEmptyAttr(ATTR_END));
286 prepareSend(nga, &nc, CODE_WRITE_REQ);
287 i = sendNsdpPacket(nga->sock, &nc, attr);
289 /* the list will be filled again by recvNgPacket
290 but normally it will be still empty */
291 clearList(attr, (void(*)(void*))freeAttr);
294 prepareRecv(nga, &nc, CODE_WRITE_REP);
295 i = recvNsdpPacket(nga->sock, &nc, attr, &nga->timeout);
302 ret = (errno == EAGAIN || errno == EWOULDBLOCK) ? ERR_TIMEOUT : ERR_NET;
306 /* check the switch error code */
307 ret = checkErrorCode(&nc);
311 /* the switch replies to write request by just a header (no attributes), so the list can be destroyed */
312 destroyList(attr, (void(*)(void*))freeAttr);
319 void extractSwitchAttributes (struct swi_attr *sa, const List *l)
322 const struct attr *at;
326 memset(sa, 0, sizeof(struct swi_attr));
328 for (ln = l->first; ln != NULL; ln = ln->next) {
334 len = min(at->size, PRODUCT_SIZE);
335 memcpy(sa->product, at->data, len);
336 trim(sa->product, len);
340 len = min(at->size, NAME_SIZE);
341 memcpy(sa->name, at->data, len);
346 memcpy(&sa->mac, at->data, ETH_ALEN);
350 sa->nc.ip = *(struct in_addr*)at->data;
354 sa->nc.netmask = *(struct in_addr*)at->data;
358 sa->nc.gw = *(struct in_addr*)at->data;
362 sa->nc.dhcp = (ntohs(*(unsigned short*)at->data) == 1);
366 len = min(at->size, FIRMWARE_SIZE - 1);
367 memcpy(sa->firmware, at->data, len);
368 sa->firmware[len] = '\0';
371 case ATTR_PORTS_COUNT:
372 sa->ports = *(unsigned char*)at->data;