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 ) {
26 // get the interface IP address
27 if ( (ret=ioctl(nga->sock, SIOCGIFADDR, &ifr))<0 ) {
28 perror("ioctl(SIOCGIFADDR)");
33 Here we have a problem: when you have multiple interfaces, sending a packet to
34 255.255.255.255 may not send it to the interface you want. If you bind() to
35 the address of the interface, you will not be able to receive broadcasts.
36 The only solution I have found yet is in this case to use
37 setsockopt(SO_BINDTODEVICE) but this requires root priviledges.
39 //local.sin_addr=(*(struct sockaddr_in*)&ifr.ifr_addr).sin_addr; // FIXME
41 // get the interface MAC address
42 if ( (ret=ioctl(nga->sock, SIOCGIFHWADDR, &ifr))<0 ) {
43 perror("ioctl(SIOCGIFHWADDR)");
47 memcpy(&nga->localmac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
50 if ( (ret=bind(nga->sock, (struct sockaddr*)&nga->local, sizeof(struct sockaddr_in)))<0 ) {
58 if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_BROADCAST, &ret, sizeof(ret)))<0 ) {
59 perror("setsockopt(SO_BROADCAST)");
63 // prevent unicast packets from being routed
65 if ( (ret=setsockopt(nga->sock, IPPROTO_IP, IP_TTL, &ret, sizeof(ret)))<0 ) {
66 perror("setsockopt(IP_TTL)");
77 // ----------------------------------
78 int stopNetwork (struct ngadmin *nga) {
80 return close(nga->sock);
86 // -------------------------------------
87 int forceInterface (struct ngadmin *nga) {
93 As described bellow, when you have multiple interfaces, this forces the packet
94 to go to a particular interface.
96 if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_BINDTODEVICE, nga->iface, strlen(nga->iface)+1))<0 ) {
97 perror("setsockopt(SO_BINDTODEVICE)");
102 If the switch's IP is not in your network range, for instance because you do
103 not have DHCP enabled or you started the switch after it, this allows to
104 bypass the routing tables and consider every address is directly reachable on
108 if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_DONTROUTE, &ret, sizeof(ret)))<0 ) {
109 perror("setsockopt(SO_DONTROUTE)");
120 // ------------------------------------
121 int updateTimeout (struct ngadmin *nga) {
126 // specify receive timeout
127 if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_RCVTIMEO, &nga->timeout, sizeof(struct timeval)))<0 ) {
128 perror("setsockopt(SO_RCVTIMEO)");
139 // ----------------------------------------------------------------
140 int sendNgPacket (struct ngadmin *nga, char code, const List *attr) {
146 struct sockaddr_in remote;
147 const struct swi_attr *sa=nga->current;
153 np.maxlen=sizeof(buffer);
155 initNgHeader(np.nh, code, &nga->localmac, sa==NULL ? &nullMac : &sa->mac , ++nga->seq);
158 for (ln=attr->first; ln!=NULL; ln=ln->next) {
160 addPacketAttr(&np, at->attr, at->size, at->data);
164 memset(&remote, 0, sizeof(struct sockaddr_in));
165 remote.sin_family=AF_INET;
166 remote.sin_addr.s_addr= sa==NULL || nga->keepbroad ? htonl(INADDR_BROADCAST) : sa->nc.ip.s_addr ;
167 remote.sin_port=htons(SWITCH_PORT);
169 if ( (ret=sendto(nga->sock, buffer, getPacketTotalSize(&np), 0, (struct sockaddr*)&remote, sizeof(struct sockaddr_in)))<0 ) {
180 // -------------------------------------------------------------------------------------------------------------
181 int recvNgPacket (struct ngadmin *nga, char code, unsigned short *error, unsigned short *attr_error, List *attr) {
185 struct sockaddr_in remote;
186 socklen_t slen=sizeof(struct sockaddr_in);
187 const struct swi_attr *sa=nga->current;
192 np.maxlen=sizeof(buffer);
194 memset(&remote, 0, sizeof(struct sockaddr_in));
195 remote.sin_family=AF_INET;
199 len=recvfrom(nga->sock, buffer, sizeof(buffer), 0, (struct sockaddr*)&remote, &slen);
205 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) ) {
207 extractPacketAttributes(&np, error, attr_error, attr);
221 int checkErrorCode (unsigned short err, unsigned short attr_error) {
224 if ( err==0x0700 && attr_error==ATTR_PASSWORD ) {
239 // ----------------------------------------------
240 int readRequest (struct ngadmin *nga, List *attr) {
243 unsigned short err, attr_error;
251 // add end attribute to end
252 pushBackList(attr, newEmptyAttr(ATTR_END));
254 i=sendNgPacket(nga, CODE_READ_REQ, attr);
256 // the list will be filled again by recvNgPacket
257 clearList(attr, (void(*)(void*))freeAttr);
259 if ( i<0 || (i=recvNgPacket(nga, CODE_READ_REP, &err, &attr_error, attr))<0 ) {
260 ret= ( errno==EAGAIN || errno==EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET ;
266 ret=checkErrorCode(err, attr_error);
277 // -----------------------------------------------
278 int writeRequest (struct ngadmin *nga, List *attr) {
281 unsigned short err, attr_error;
287 } else if ( nga->current==NULL ) {
294 attr=createEmptyList();
297 // add password attribute to start
298 pushFrontList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
300 // add end attribute to end
301 pushBackList(attr, newEmptyAttr(ATTR_END));
303 i=sendNgPacket(nga, CODE_WRITE_REQ, attr);
305 // the list will be filled again by recvNgPacket
306 // but normally it will be still empty
307 clearList(attr, (void(*)(void*))freeAttr);
309 if ( i<0 || (i=recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error, attr))<0 ) {
310 ret= ( errno==EAGAIN || errno==EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET ;
315 ret=checkErrorCode(err, attr_error);
319 // the switch replies to write request by just a header (no attributes), so the list can be destroyed
320 destroyList(attr, (void(*)(void*))freeAttr);