7 // -----------------------------------
8 int startNetwork (struct ngadmin *nga) {
15 if ( (nga->sock=socket(AF_INET, SOCK_DGRAM, 0))<0 ) {
20 memset(&ifr, 0, sizeof(struct ifreq));
21 strncpy(ifr.ifr_name, nga->iface, IFNAMSIZ-1);
23 // get the interface broadcast address
24 if ( (ret=ioctl(nga->sock, SIOCGIFBRDADDR, &ifr))<0 ) {
25 perror("ioctl(SIOCGIFBRDADDR)");
29 nga->brd=(*(struct sockaddr_in*)&ifr.ifr_addr).sin_addr;
31 // get the interface MAC address
32 if ( (ret=ioctl(nga->sock, SIOCGIFHWADDR, &ifr))<0 ) {
33 perror("ioctl(SIOCGIFHWADDR)");
37 memcpy(&nga->localmac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
40 memset(&nga->local, 0, sizeof(struct sockaddr_in));
41 nga->local.sin_family=AF_INET;
42 nga->local.sin_port=htons(CLIENT_PORT);
44 if ( (ret=bind(nga->sock, (struct sockaddr*)&nga->local, sizeof(struct sockaddr_in)))<0 ) {
52 if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_BROADCAST, &ret, sizeof(ret)))<0 ) {
53 perror("setsockopt(SO_BROADCAST)");
57 // prevent unicast packets from being routed by setting the TTL to 1
59 if ( (ret=setsockopt(nga->sock, IPPROTO_IP, IP_TTL, &ret, sizeof(ret)))<0 ) {
60 perror("setsockopt(IP_TTL)");
71 // ----------------------------------
72 int stopNetwork (struct ngadmin *nga) {
74 return close(nga->sock);
80 // -------------------------------------
81 int forceInterface (struct ngadmin *nga) {
87 As described bellow, when you have multiple interfaces, this forces the packet
88 to go to a particular interface.
90 if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_BINDTODEVICE, nga->iface, strlen(nga->iface)+1))<0 ) {
91 perror("setsockopt(SO_BINDTODEVICE)");
96 If the switch's IP is not in your network range, for instance because you do
97 not have DHCP enabled or you started the switch after it, this allows to
98 bypass the routing tables and consider every address is directly reachable on
102 if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_DONTROUTE, &ret, sizeof(ret)))<0 ) {
103 perror("setsockopt(SO_DONTROUTE)");
114 // ------------------------------------
115 int updateTimeout (struct ngadmin *nga) {
120 // specify receive timeout
121 if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_RCVTIMEO, &nga->timeout, sizeof(struct timeval)))<0 ) {
122 perror("setsockopt(SO_RCVTIMEO)");
133 // ----------------------------------------------------------------
134 int sendNgPacket (struct ngadmin *nga, char code, const List *attr) {
140 struct sockaddr_in remote;
141 const struct swi_attr *sa=nga->current;
146 np.maxlen=sizeof(buffer);
148 initNgHeader(np.nh, code, &nga->localmac, sa==NULL ? NULL : &sa->mac , ++nga->seq);
151 for (ln=attr->first; ln!=NULL; ln=ln->next) {
153 addPacketAttr(&np, at->attr, at->size, at->data);
157 memset(&remote, 0, sizeof(struct sockaddr_in));
158 remote.sin_family=AF_INET;
159 remote.sin_port=htons(SWITCH_PORT);
161 if ( sa!=NULL && !nga->keepbroad ) remote.sin_addr=sa->nc.ip;
162 else if ( nga->globalbroad ) remote.sin_addr.s_addr=htonl(INADDR_BROADCAST);
163 else remote.sin_addr=nga->brd;
166 if ( (ret=sendto(nga->sock, buffer, getPacketTotalSize(&np), 0, (struct sockaddr*)&remote, sizeof(struct sockaddr_in)))<0 ) {
177 // ------------------------------------------------------------------------------------------------------------
178 int recvNgPacket (struct ngadmin *nga, char code, unsigned char *error, unsigned short *attr_error, List *attr) {
182 struct sockaddr_in remote;
183 socklen_t slen=sizeof(struct sockaddr_in);
184 const struct swi_attr *sa=nga->current;
192 memset(&remote, 0, sizeof(struct sockaddr_in));
193 remote.sin_family=AF_INET;
200 FD_SET(nga->sock, &fs);
201 select(nga->sock+1, &fs, NULL, NULL, &rem); // FIXME: non portable
203 len=recvfrom(nga->sock, buffer, sizeof(buffer), MSG_DONTWAIT, (struct sockaddr*)&remote, &slen);
211 ntohs(remote.sin_port)!=SWITCH_PORT ||
212 len<(int)sizeof(struct ng_header) ||
213 !validateNgHeader(np.nh, code, &nga->localmac, sa==NULL ? NULL : &sa->mac , nga->seq) ||
214 extractPacketAttributes(&np, error, attr_error, attr)<0
229 static int checkErrorCode (unsigned char err, unsigned short attr_error) {
234 case ERROR_DENIED: return attr_error==ATTR_PASSWORD ? ERR_BADPASS : ERR_DENIED ;
235 case ERROR_INVALID_VALUE: return ERR_INVARG;
236 default: return ERR_OK;
245 // ----------------------------------------------
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);
266 if ( i<0 || (i=recvNgPacket(nga, CODE_READ_REP, &err, &attr_error, attr))<0 ) {
267 ret= ( errno==EAGAIN || errno==EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET ;
273 ret=checkErrorCode(err, attr_error);
284 // -----------------------------------------------
285 int writeRequest (struct ngadmin *nga, List *attr) {
289 unsigned short attr_error;
295 } else if ( nga->current==NULL ) {
302 attr=createEmptyList();
305 // add password attribute to start
306 pushFrontList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
308 // add end attribute to end
309 pushBackList(attr, newEmptyAttr(ATTR_END));
311 i=sendNgPacket(nga, CODE_WRITE_REQ, attr);
313 // the list will be filled again by recvNgPacket
314 // but normally it will be still empty
315 clearList(attr, (void(*)(void*))freeAttr);
317 if ( i<0 || (i=recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error, attr))<0 ) {
318 ret= ( errno==EAGAIN || errno==EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET ;
323 ret=checkErrorCode(err, attr_error);
327 // the switch replies to write request by just a header (no attributes), so the list can be destroyed
328 destroyList(attr, (void(*)(void*))freeAttr);