7 // -----------------------------------
8 int startNetwork (struct ngadmin *nga) {
14 memset(&nga->local, 0, sizeof(struct sockaddr_in));
15 nga->local.sin_family=AF_INET;
16 nga->local.sin_port=htons(CLIENT_PORT);
18 memset(&ifr, 0, sizeof(struct ifreq));
19 strncpy(ifr.ifr_name, nga->iface, IFNAMSIZ-1);
21 if ( (nga->sock=socket(AF_INET, SOCK_DGRAM, 0))<0 ) {
27 // get the interface IP address
28 if ( (ret=ioctl(nga->sock, SIOCGIFADDR, &ifr))<0 ) {
29 perror("ioctl(SIOCGIFADDR)");
35 Here we have a problem: when you have multiple interfaces, sending a packet to
36 255.255.255.255 may not send it to the interface you want. If you bind() to
37 the address of the interface, you will not be able to receive broadcasts.
38 The only solution I have found yet is in this case to use
39 setsockopt(SO_BINDTODEVICE) but this requires root priviledges.
41 //local.sin_addr=(*(struct sockaddr_in*)&ifr.ifr_addr).sin_addr; // FIXME
43 // get the interface broadcast address
44 if ( (ret=ioctl(nga->sock, SIOCGIFBRDADDR, &ifr))<0 ) {
45 perror("ioctl(SIOCGIFBRDADDR)");
49 nga->brd=(*(struct sockaddr_in*)&ifr.ifr_addr).sin_addr;
51 // get the interface MAC address
52 if ( (ret=ioctl(nga->sock, SIOCGIFHWADDR, &ifr))<0 ) {
53 perror("ioctl(SIOCGIFHWADDR)");
57 memcpy(&nga->localmac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
60 if ( (ret=bind(nga->sock, (struct sockaddr*)&nga->local, sizeof(struct sockaddr_in)))<0 ) {
68 if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_BROADCAST, &ret, sizeof(ret)))<0 ) {
69 perror("setsockopt(SO_BROADCAST)");
73 // prevent unicast packets from being routed
75 if ( (ret=setsockopt(nga->sock, IPPROTO_IP, IP_TTL, &ret, sizeof(ret)))<0 ) {
76 perror("setsockopt(IP_TTL)");
87 // ----------------------------------
88 int stopNetwork (struct ngadmin *nga) {
90 return close(nga->sock);
96 // -------------------------------------
97 int forceInterface (struct ngadmin *nga) {
103 As described bellow, when you have multiple interfaces, this forces the packet
104 to go to a particular interface.
106 if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_BINDTODEVICE, nga->iface, strlen(nga->iface)+1))<0 ) {
107 perror("setsockopt(SO_BINDTODEVICE)");
112 If the switch's IP is not in your network range, for instance because you do
113 not have DHCP enabled or you started the switch after it, this allows to
114 bypass the routing tables and consider every address is directly reachable on
118 if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_DONTROUTE, &ret, sizeof(ret)))<0 ) {
119 perror("setsockopt(SO_DONTROUTE)");
130 // ------------------------------------
131 int updateTimeout (struct ngadmin *nga) {
136 // specify receive timeout
137 if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_RCVTIMEO, &nga->timeout, sizeof(struct timeval)))<0 ) {
138 perror("setsockopt(SO_RCVTIMEO)");
149 // ----------------------------------------------------------------
150 int sendNgPacket (struct ngadmin *nga, char code, const List *attr) {
156 struct sockaddr_in remote;
157 const struct swi_attr *sa=nga->current;
164 np.maxlen=sizeof(buffer);
166 initNgHeader(np.nh, code, &nga->localmac, sa==NULL ? NULL : &sa->mac , ++nga->seq);
169 for (ln=attr->first; ln!=NULL; ln=ln->next) {
171 addPacketAttr(&np, at->attr, at->size, at->data);
175 memset(&remote, 0, sizeof(struct sockaddr_in));
176 remote.sin_family=AF_INET;
177 remote.sin_port=htons(SWITCH_PORT);
179 if ( sa!=NULL && !nga->keepbroad ) remote.sin_addr=sa->nc.ip;
180 else if ( nga->globalbroad ) remote.sin_addr.s_addr=htonl(INADDR_BROADCAST);
181 else remote.sin_addr=nga->brd;
184 if ( (ret=sendto(nga->sock, buffer, getPacketTotalSize(&np), 0, (struct sockaddr*)&remote, sizeof(struct sockaddr_in)))<0 ) {
195 // ------------------------------------------------------------------------------------------------------------
196 int recvNgPacket (struct ngadmin *nga, char code, unsigned char *error, unsigned short *attr_error, List *attr) {
200 struct sockaddr_in remote;
201 socklen_t slen=sizeof(struct sockaddr_in);
202 const struct swi_attr *sa=nga->current;
207 np.maxlen=sizeof(buffer);
209 memset(&remote, 0, sizeof(struct sockaddr_in));
210 remote.sin_family=AF_INET;
214 len=recvfrom(nga->sock, buffer, sizeof(buffer), 0, (struct sockaddr*)&remote, &slen);
220 if ( ntohs(remote.sin_port)==SWITCH_PORT && len>=(int)sizeof(struct ng_header) && validateNgHeader(np.nh, code, &nga->localmac, sa==NULL ? NULL : &sa->mac , nga->seq) ) {
222 extractPacketAttributes(&np, error, attr_error, attr);
236 int checkErrorCode (unsigned char err, unsigned short attr_error) {
239 if ( err==ERROR_INVALID_PASSWORD && attr_error==ATTR_PASSWORD ) {
243 if ( err==ERROR_INVALID_VALUE ) {
254 // ----------------------------------------------
255 int readRequest (struct ngadmin *nga, List *attr) {
259 unsigned short attr_error;
267 // add end attribute to end
268 pushBackList(attr, newEmptyAttr(ATTR_END));
270 i=sendNgPacket(nga, CODE_READ_REQ, attr);
272 // the list will be filled again by recvNgPacket
273 clearList(attr, (void(*)(void*))freeAttr);
275 if ( i<0 || (i=recvNgPacket(nga, CODE_READ_REP, &err, &attr_error, attr))<0 ) {
276 ret= ( errno==EAGAIN || errno==EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET ;
282 ret=checkErrorCode(err, attr_error);
293 // -----------------------------------------------
294 int writeRequest (struct ngadmin *nga, List *attr) {
298 unsigned short attr_error;
304 } else if ( nga->current==NULL ) {
311 attr=createEmptyList();
314 // add password attribute to start
315 pushFrontList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
317 // add end attribute to end
318 pushBackList(attr, newEmptyAttr(ATTR_END));
320 i=sendNgPacket(nga, CODE_WRITE_REQ, attr);
322 // the list will be filled again by recvNgPacket
323 // but normally it will be still empty
324 clearList(attr, (void(*)(void*))freeAttr);
326 if ( i<0 || (i=recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error, attr))<0 ) {
327 ret= ( errno==EAGAIN || errno==EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET ;
332 ret=checkErrorCode(err, attr_error);
336 // the switch replies to write request by just a header (no attributes), so the list can be destroyed
337 destroyList(attr, (void(*)(void*))freeAttr);