9 #include <netinet/ether.h>
10 #include <sys/ioctl.h>
18 int startNetwork (struct ngadmin *nga)
25 nga->sock = socket(AF_INET, SOCK_DGRAM, 0);
31 memset(&ifr, 0, sizeof(struct ifreq));
32 strncpy(ifr.ifr_name, nga->iface, IFNAMSIZ - 1);
34 /* get the interface broadcast address */
35 ret = ioctl(nga->sock, SIOCGIFBRDADDR, &ifr);
37 perror("ioctl(SIOCGIFBRDADDR)");
41 nga->brd = (*(struct sockaddr_in*)&ifr.ifr_addr).sin_addr;
43 /* get the interface MAC address */
44 ret = ioctl(nga->sock, SIOCGIFHWADDR, &ifr);
46 perror("ioctl(SIOCGIFHWADDR)");
50 memcpy(&nga->localmac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
53 memset(&nga->local, 0, sizeof(struct sockaddr_in));
54 nga->local.sin_family = AF_INET;
55 nga->local.sin_port = htons(CLIENT_PORT);
57 ret = bind(nga->sock, (struct sockaddr*)&nga->local, sizeof(struct sockaddr_in));
64 /* allow broadcasting */
66 ret = setsockopt(nga->sock, SOL_SOCKET, SO_BROADCAST, &ret, sizeof(ret));
68 perror("setsockopt(SO_BROADCAST)");
72 /* prevent unicast packets from being routed by setting the TTL to 1 */
74 ret = setsockopt(nga->sock, IPPROTO_IP, IP_TTL, &ret, sizeof(ret));
76 perror("setsockopt(IP_TTL)");
85 int stopNetwork (struct ngadmin *nga)
87 return close(nga->sock);
91 int forceInterface (struct ngadmin *nga)
97 As described bellow, when you have multiple interfaces, this forces the packet
98 to go to a particular interface.
100 ret = setsockopt(nga->sock, SOL_SOCKET, SO_BINDTODEVICE, nga->iface, strlen(nga->iface) + 1);
102 perror("setsockopt(SO_BINDTODEVICE)");
107 If the switch's IP is not in your network range, for instance because you do
108 not have DHCP enabled or you started the switch after it, this allows to
109 bypass the routing tables and consider every address is directly reachable on
113 ret = setsockopt(nga->sock, SOL_SOCKET, SO_DONTROUTE, &ret, sizeof(ret));
115 perror("setsockopt(SO_DONTROUTE)");
124 int updateTimeout (struct ngadmin *nga)
129 /* specify receive timeout */
130 ret = setsockopt(nga->sock, SOL_SOCKET, SO_RCVTIMEO, &nga->timeout, sizeof(struct timeval));
132 perror("setsockopt(SO_RCVTIMEO)");
141 int sendNgPacket (struct ngadmin *nga, char code, const List *attr)
145 struct sockaddr_in remote;
146 const struct swi_attr *sa = nga->current;
151 np.maxlen = sizeof(buffer);
153 initNgHeader(np.nh, code, &nga->localmac, sa == NULL ? NULL : &sa->mac, ++nga->seq);
155 ret = addPacketAttributes(&np, attr, sa == NULL ? 0 : sa->ports);
159 memset(&remote, 0, sizeof(struct sockaddr_in));
160 remote.sin_family = AF_INET;
161 remote.sin_port = htons(SWITCH_PORT);
163 /* destination address selection */
164 if (sa != NULL && !nga->keepbroad)
165 remote.sin_addr = sa->nc.ip;
166 else if (nga->globalbroad)
167 remote.sin_addr.s_addr = htonl(INADDR_BROADCAST);
169 remote.sin_addr = nga->brd;
171 ret = sendto(nga->sock, buffer, getPacketTotalSize(&np), 0, (struct sockaddr*)&remote, sizeof(struct sockaddr_in));
180 int recvNgPacket (struct ngadmin *nga, char code, unsigned char *error, unsigned short *attr_error, List *attr)
184 struct sockaddr_in remote;
185 socklen_t slen = sizeof(struct sockaddr_in);
186 const struct swi_attr *sa = nga->current;
194 memset(&remote, 0, sizeof(struct sockaddr_in));
195 remote.sin_family = AF_INET;
202 FD_SET(nga->sock, &fs);
203 select(nga->sock+1, &fs, NULL, NULL, &rem); /* FIXME: non portable */
205 len = recvfrom(nga->sock, buffer, sizeof(buffer), MSG_DONTWAIT, (struct sockaddr*)&remote, &slen);
213 if (ntohs(remote.sin_port) != SWITCH_PORT ||
214 len < (int)sizeof(struct ng_header) ||
215 !validateNgHeader(np.nh, code, &nga->localmac, sa == NULL ? NULL : &sa->mac, nga->seq) ||
216 extractPacketAttributes(&np, attr, sa == NULL ? 0 : sa->ports) < 0)
220 *error = np.nh->error;
221 if (attr_error != NULL)
222 *attr_error = ntohs(np.nh->attr);
233 static int checkErrorCode (unsigned char err, unsigned short attr_error)
237 return attr_error == ATTR_PASSWORD ? ERR_BADPASS : ERR_DENIED;
238 case ERROR_INVALID_VALUE:
246 int readRequest (struct ngadmin *nga, List *attr)
250 unsigned short attr_error;
258 /* add end attribute to end */
259 pushBackList(attr, newEmptyAttr(ATTR_END));
261 i = sendNgPacket(nga, CODE_READ_REQ, attr);
263 /* the list will be filled again by recvNgPacket */
264 clearList(attr, (void(*)(void*))freeAttr);
267 i = recvNgPacket(nga, CODE_READ_REP, &err, &attr_error, attr);
273 ret = ( errno == EAGAIN || errno == EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET;
278 /* check the switch error code */
279 ret = checkErrorCode(err, attr_error);
287 int writeRequest (struct ngadmin *nga, List *attr)
291 unsigned short attr_error;
297 } else if (nga->current == NULL) {
304 attr = createEmptyList();
306 /* add password attribute to start */
307 pushFrontList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
309 /* add end attribute to end */
310 pushBackList(attr, newEmptyAttr(ATTR_END));
312 i = sendNgPacket(nga, CODE_WRITE_REQ, attr);
314 /* the list will be filled again by recvNgPacket
315 but normally it will be still empty */
316 clearList(attr, (void(*)(void*))freeAttr);
319 i = recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error, attr);
325 ret = ( errno==EAGAIN || errno==EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET ;
329 /* check the switch error code */
330 ret = checkErrorCode(err, attr_error);
334 /* the switch replies to write request by just a header (no attributes), so the list can be destroyed */
335 destroyList(attr, (void(*)(void*))freeAttr);
342 void extractSwitchAttributes (struct swi_attr *sa, const List *l)
345 const struct attr *at;
349 memset(sa, 0, sizeof(struct swi_attr));
351 for (ln = l->first; ln != NULL; ln = ln->next) {
357 len = min(at->size, PRODUCT_SIZE);
358 memcpy(sa->product, at->data, len);
359 trim(sa->product, len);
363 len = min(at->size, NAME_SIZE);
364 memcpy(sa->name, at->data, len);
369 memcpy(&sa->mac, at->data, ETH_ALEN);
373 sa->nc.ip = *(struct in_addr*)at->data;
377 sa->nc.netmask = *(struct in_addr*)at->data;
381 sa->nc.gw = *(struct in_addr*)at->data;
385 sa->nc.dhcp = (ntohs(*(unsigned short*)at->data) == 1);
389 len = min(at->size, FIRMWARE_SIZE - 1);
390 memcpy(sa->firmware, at->data, len);
391 sa->firmware[len] = '\0';
394 case ATTR_PORTS_COUNT:
395 sa->ports = *(unsigned char*)at->data;