static int std_rcv_pads(struct session* ses, struct pppoe_packet *p_in, struct pppoe_packet **p_out){ if(ses->state != PADS_CODE ){ poe_error(ses,"Unexpected packet: %P",p_in); return 0; } if( verify_packet(ses, p_in) < 0) return 0; if (DEB_DISC) poe_dbglog (ses,"PADS received: %P", p_in); ses->sp.sa_family = AF_PPPOX; ses->sp.sa_protocol = PX_PROTO_OE; ses->sp.sa_addr.pppoe.sid = p_in->hdr->sid; memcpy(ses->sp.sa_addr.pppoe.dev,ses->name, IFNAMSIZ); memcpy(ses->sp.sa_addr.pppoe.remote, p_in->addr.sll_addr, ETH_ALEN); if (DEB_DISC) poe_dbglog (ses,"Got connection: %x %s <--->%E", ses->sp.sa_addr.pppoe.sid, ses->sp.sa_addr.pppoe.dev, ses->sp.sa_addr.pppoe.remote); return 1; }
static int std_rcv_pado(struct session* ses, struct pppoe_packet *p_in, struct pppoe_packet **p_out){ if( verify_packet(ses, p_in) < 0) return -1; if(ses->state != PADO_CODE ){ poe_dbglog(ses,"Unexpected packet: %P",p_in); return 0; } if (DEB_DISC2) { poe_dbglog (ses,"PADO received: %P", p_in); } memcpy(&ses->remote, &p_in->addr, sizeof(struct sockaddr_ll)); memcpy( &ses->curr_pkt.addr, &ses->remote , sizeof(struct sockaddr_ll)); ses->curr_pkt.hdr->code = PADR_CODE; /* The HOST_UNIQ has been verified already... there's no "if" about this */ /* if(ses->filt->htag) */ copy_tag(&ses->curr_pkt,get_tag(p_in->hdr,PTT_HOST_UNIQ)); if (ses->filt->ntag) { ses->curr_pkt.tags[TAG_AC_NAME]=NULL; } // copy_tag(&ses->curr_pkt,get_tag(p_in->hdr,PTT_AC_NAME)); if(ses->filt->stag) { ses->curr_pkt.tags[TAG_SRV_NAME]=NULL; } copy_tag(&ses->curr_pkt,get_tag(p_in->hdr,PTT_SRV_NAME)); copy_tag(&ses->curr_pkt,get_tag(p_in->hdr,PTT_AC_COOKIE)); copy_tag(&ses->curr_pkt,get_tag(p_in->hdr,PTT_RELAY_SID)); ses->state = PADS_CODE; ses->retransmits = 0; send_disc(ses, &ses->curr_pkt); (*p_out) = &ses->curr_pkt; if (ses->np) return 1; return 0; }
static int relay_rcv_padi(struct session* ses, struct pppoe_packet *p_in, struct pppoe_packet **p_out){ char tag_buf[32]; struct pppoe_con *newpc = NULL; struct pppoe_tag *tag = (struct pppoe_tag *) tag_buf; tag->tag_type = PTT_RELAY_SID; tag->tag_len = htons(ETH_ALEN + sizeof(struct session *)); memcpy(tag->tag_data, p_in->addr.sll_addr, ETH_ALEN); memcpy(tag->tag_data + ETH_ALEN, &ses, sizeof(struct session *)); if(! p_in->tags[TAG_RELAY_SID] ){ copy_tag(p_in, tag); } poe_dbglog(ses, "Recv'd PADI: %P",p_in); poe_dbglog(ses, "Recv'd packet: %P",p_in); newpc = get_con( ntohs(tag->tag_len), tag->tag_data ); if(!newpc){ newpc = (struct pppoe_con *) malloc(sizeof(struct pppoe_con)); memset(newpc , 0, sizeof(struct pppoe_con)); newpc->id = pcid++; newpc->key_len = ntohs(p_in->tags[TAG_RELAY_SID]->tag_len); memcpy(newpc->key, p_in->tags[TAG_RELAY_SID]->tag_data, newpc->key_len); memcpy(newpc->client, p_in->addr.sll_addr, ETH_ALEN); memcpy(newpc->server, MAC_BCAST_ADDR, ETH_ALEN); store_con(newpc); } ++newpc->ref_count; memset(p_in->addr.sll_addr, 0xff, ETH_ALEN); p_in->addr.sll_ifindex = ses->remote.sll_ifindex; send_disc(ses, p_in); return 0; }
static int std_init_disc(struct session* ses, struct pppoe_packet *p_in, struct pppoe_packet **p_out){ /* Check if already connected */ if( ses->state != PADO_CODE ){ return -1; } memset(&ses->curr_pkt,0, sizeof(struct pppoe_packet)); ses->curr_pkt.hdr = (struct pppoe_hdr*) ses->curr_pkt.buf; ses->curr_pkt.hdr->ver = 1; ses->curr_pkt.hdr->type = 1; ses->curr_pkt.hdr->code = PADI_CODE; memcpy( &ses->curr_pkt.addr, &ses->remote , sizeof(struct sockaddr_ll)); poe_info (ses,"Sending PADI"); //if (DEB_DISC) // poe_dbglog (ses,"Sending PADI"); fprintf(stderr,"Sending PADI\n"); ses->retransmits = 0 ; if(ses->filt->ntag) { ses->curr_pkt.tags[TAG_AC_NAME]=ses->filt->ntag; poe_info(ses,"overriding AC name\n"); } if(ses->filt->stag) ses->curr_pkt.tags[TAG_SRV_NAME]=ses->filt->stag; if(ses->filt->htag) ses->curr_pkt.tags[TAG_HOST_UNIQ]=ses->filt->htag; ses->retransmits = 0 ; send_disc(ses, &ses->curr_pkt); (*p_out)= &ses->curr_pkt; if (DEB_DISC) poe_dbglog (ses,"Sent PADI: %P", *p_out); return 0; }
static int std_rcv_pads(struct session* ses, struct pppoe_packet *p_in, struct pppoe_packet **p_out){ if( verify_packet(ses, p_in) < 0) return -1; if (DEB_DISC) poe_dbglog (ses,"Got connection: %x", ntohs(p_in->hdr->sid)); ses->sp.sa_family = AF_PPPOX; ses->sp.sa_protocol = PX_PROTO_OE; ses->sp.sa_addr.pppoe.sid = p_in->hdr->sid; memcpy(ses->sp.sa_addr.pppoe.dev,ses->name, IFNAMSIZ); memcpy(ses->sp.sa_addr.pppoe.remote, p_in->addr.sll_addr, ETH_ALEN); return 1; }
/************************************************************************* * * Receive and verify an incoming packet. * *************************************************************************/ static int recv_disc( struct session *ses, struct pppoe_packet *p){ int error = 0; unsigned int from_len = sizeof(struct sockaddr_ll); struct session* hu_val; struct pppoe_tag *pt; p->hdr = (struct pppoe_hdr*)p->buf; error = recvfrom( disc_sock, p->buf, 1500, 0, (struct sockaddr*)&p->addr, &from_len); if(error < 0) return error; extract_tags(p->hdr,p->tags); poe_dbglog(ses,"Recv'd packet: %P",p); return 1; }
static int std_rcv_pads(struct session* ses, struct pppoe_packet *p_in, struct pppoe_packet **p_out){ if( verify_packet(ses, p_in) < 0) return -1; if (DEB_DISC) poe_dbglog (ses,"Got connection: %x", ntohs(p_in->hdr->sid)); poe_info (ses,"Got connection: %x", ntohs(p_in->hdr->sid)); ses->sp.sa_family = AF_PPPOX; ses->sp.sa_protocol = PX_PROTO_OE; ses->sp.sa_addr.pppoe.sid = p_in->hdr->sid; memcpy(ses->sp.sa_addr.pppoe.dev,ses->name, IFNAMSIZ); memcpy(ses->sp.sa_addr.pppoe.remote, p_in->addr.sll_addr, ETH_ALEN); create_msg(BCM_PPPOE_CLIENT_STATE_CONFIRMED); syslog(LOG_CRIT,"PPP session established.\n"); return 1; }
static int relay_rcv_pkt(struct session* ses, struct pppoe_packet *p_in, struct pppoe_packet **p_out){ struct pppoe_con *pc; // char tag_buf[32]; struct pppoe_tag *tag = p_in->tags[TAG_RELAY_SID]; if( !tag ) return 0; pc = get_con(ntohs(tag->tag_len),tag->tag_data); if( !pc ) return 0; poe_dbglog(ses, "Recv'd packet: %P",p_in); if( memcmp(pc->client , p_in->addr.sll_addr , ETH_ALEN ) == 0 ){ memcpy(p_in->addr.sll_addr, pc->server, ETH_ALEN); p_in->addr.sll_ifindex = ses->remote.sll_ifindex; }else{ if( memcmp(pc->server, MAC_BCAST_ADDR, ETH_ALEN) == 0 ){ memcpy(pc->server, p_in->addr.sll_addr, ETH_ALEN); }else if( memcmp(pc->server, p_in->addr.sll_addr, ETH_ALEN) !=0){ return 0; } memcpy(p_in->addr.sll_addr, pc->client, ETH_ALEN); p_in->addr.sll_ifindex = ses->local.sll_ifindex; } send_disc(ses, p_in); return 0; }
/************************************************************************* * * Make a connection -- behaviour depends on callbacks specified in "ses" * *************************************************************************/ int session_connect(struct session *ses) { struct pppoe_packet *p_out=NULL; struct pppoe_packet rcv_packet; int ret; if(ses->init_disc){ ret = (*ses->init_disc)(ses, NULL, &p_out); if( ret != 0 ) return ret; } /* main discovery loop */ while(ses->retransmits < ses->retries || ses->retries==-1 ){ fd_set in; struct timeval tv; FD_ZERO(&in); FD_SET(disc_sock,&in); if(ses->retransmits < 0) ret = select(disc_sock+1, &in, NULL, NULL, NULL); else { ++ses->retransmits; tv.tv_sec = 1 << ses->retransmits; //tv.tv_sec = retransmit_time; tv.tv_usec = 0; again: ret = select(disc_sock+1, &in, NULL, NULL, &tv); } if( ret < 0 && errno != EINTR){ return -1; } else if( ret == 0 ) { if( DEB_DISC ) poe_dbglog(ses, "Re-sending ..."); if( ses->timeout ) { ret = (*ses->timeout)(ses, NULL, &p_out); if( ret != 0 ) return ret; } else if(p_out) send_disc(ses,p_out); continue; } ret = recv_disc(ses, &rcv_packet); /* Should differentiate between system errors and bad packets and the like... */ if( ret < 0 && errno ) return -1; switch (rcv_packet.hdr->code) { case PADI_CODE: { if(ses->rcv_padi){ ret = (*ses->rcv_padi)(ses,&rcv_packet,&p_out); if( ret != 0){ return ret; } } break; } case PADO_CODE: /* wait for PADO */ { if(ses->rcv_pado){ ret = (*ses->rcv_pado)(ses,&rcv_packet,&p_out); if( ret != 0){ return ret; } else goto again; } break; } case PADR_CODE: { if(ses->rcv_padr){ ret = (*ses->rcv_padr)(ses,&rcv_packet,&p_out); if( ret != 0){ return ret; } } break; } case PADS_CODE: /* wait for PADS */ { if(ses->rcv_pads){ ret = (*ses->rcv_pads)(ses,&rcv_packet,&p_out); if( ret != 0){ return ret; } else goto again; } break; } case PADT_CODE: { if( rcv_packet.hdr->sid != ses->sp.sa_addr.pppoe.sid ){ --ses->retransmits; continue; } if(ses->rcv_padt){ ret = (*ses->rcv_padt)(ses,&rcv_packet,&p_out); if( ret != 0){ return ret; } else goto again; }else{ poe_error (ses,"connection terminated"); return (-1); } break; } default: poe_error(ses,"invalid packet %P",&rcv_packet); return (-1); } } return (0); }
static int std_rcv_pado(struct session* ses, struct pppoe_packet *p_in, struct pppoe_packet **p_out){ if( verify_packet(ses, p_in) < 0) return -1; if(ses->state != PADO_CODE ){ poe_error(ses,"Unexpected packet: %P",p_in); return 0; } if (DEB_DISC2) { poe_dbglog (ses,"PADO received: %P", p_in); } // brcm: add code to get service name and put it in the /var/fyi/wan/servicename file if (p_in->tags[0]->tag_type == PTT_SRV_NAME) { char sName[255]=""; char path[64]=""; char cmd[320]=""; memset(sName, 0, p_in->tags[0]->tag_len+1); strncpy(sName, p_in->tags[0]->tag_data, p_in->tags[0]->tag_len); #ifdef BRCM_CMS_BUILD extern char servicename[BUFLEN_264]; /* service name from the connection, defined in options.c */ cmsLog_debug("servicename=%s", sName); strncpy(servicename, sName, sizeof(servicename)); #else //printf("PPPoE Service Name: %s\n", sName); sprintf(path, "%s/%s/%s", "/proc/var/fyi/wan", session_path, "servicename"); sprintf(cmd, "echo %s > %s", sName, path); system(cmd); #endif } memcpy(&ses->remote, &p_in->addr, sizeof(struct sockaddr_ll)); memcpy( &ses->curr_pkt.addr, &ses->remote , sizeof(struct sockaddr_ll)); ses->curr_pkt.hdr->code = PADR_CODE; /* The HOST_UNIQ has been verified already... there's no "if" about this */ /* if(ses->filt->htag) */ copy_tag(&ses->curr_pkt,get_tag(p_in->hdr,PTT_HOST_UNIQ)); if (ses->filt->ntag) { ses->curr_pkt.tags[TAG_AC_NAME]=NULL; } // copy_tag(&ses->curr_pkt,get_tag(p_in->hdr,PTT_AC_NAME)); #if 1 //brcm /* Our service name has been verified against the service name tags offered by * the server in the call to verify_packet(). We can just use it. */ copy_tag(&ses->curr_pkt, ses->filt->stag); #else if(ses->filt->stag) { ses->curr_pkt.tags[TAG_SRV_NAME]=NULL; } copy_tag(&ses->curr_pkt,get_tag(p_in->hdr,PTT_SRV_NAME)); #endif copy_tag(&ses->curr_pkt,get_tag(p_in->hdr,PTT_AC_COOKIE)); copy_tag(&ses->curr_pkt,get_tag(p_in->hdr,PTT_RELAY_SID)); ses->state = PADS_CODE; create_msg(BCM_PPPOE_CLIENT_STATE_PADS, MDMVS_ERROR_NONE); syslog(LOG_CRIT,"PPP server detected.\n"); ses->retransmits = 0; send_disc(ses, &ses->curr_pkt); (*p_out) = &ses->curr_pkt; if (ses->np) return 1; return 0; }
int client_init_ses (struct session *ses, char* devnam) { int i=0; int retval; char dev[IFNAMSIZ+1]; int addr[ETH_ALEN]; int sid; /* do error checks here; session name etc are valid */ // poe_info (ses,"init_ses: creating socket"); //DEB_DISC = 1; //DEB_DISC2 = 1; /* Make socket if necessary */ if( disc_sock < 0 ){ disc_sock = socket(PF_PACKET, SOCK_DGRAM, 0); if( disc_sock < 0 ){ poe_fatal(ses, "Cannot create PF_PACKET socket for PPPoE discovery\n"); } } /* Check for long format */ retval =sscanf(devnam, FMTSTRING(IFNAMSIZ),addr, addr+1, addr+2, addr+3, addr+4, addr+5,&sid,dev); if( retval != 8 ){ /* Verify the device name , construct ses->local */ retval = get_sockaddr_ll(devnam,&ses->local); if (retval < 0) poe_fatal(ses, "client_init_ses: " "Cannot create PF_PACKET socket for PPPoE discovery\n"); ses->state = PADO_CODE; memcpy(&ses->remote, &ses->local, sizeof(struct sockaddr_ll) ); memset( ses->remote.sll_addr, 0xff, ETH_ALEN); }else{ /* long form parsed */ /* Verify the device name , construct ses->local */ retval = get_sockaddr_ll(dev,&ses->local); if (retval < 0) poe_fatal(ses,"client_init_ses(2): " "Cannot create PF_PACKET socket for PPPoE discovery\n"); ses->state = PADS_CODE; ses->sp.sa_family = AF_PPPOX; ses->sp.sa_protocol = PX_PROTO_OE; ses->sp.sa_addr.pppoe.sid = sid; memcpy(&ses->remote, &ses->local, sizeof(struct sockaddr_ll) ); for(; i < ETH_ALEN ; ++i ){ ses->sp.sa_addr.pppoe.remote[i] = addr[i]; ses->remote.sll_addr[i]=addr[i]; } memcpy(ses->sp.sa_addr.pppoe.dev, dev, IFNAMSIZ); } if( retval < 0 ) error("bad device name: %s",devnam); if (DEB_DISC) poe_dbglog (ses,"Local ETH %E", ses->local.sll_addr); retval = bind( disc_sock , (struct sockaddr*)&ses->local, sizeof(struct sockaddr_ll)); if( retval < 0 ){ error("bind to PF_PACKET socket failed: %m"); } /* Make socket if necessary */ if (ses->fd < 0) { ses->fd = socket(AF_PPPOX,SOCK_STREAM,PX_PROTO_OE); if(ses->fd < 0) { poe_fatal(ses,"Failed to create PPPoE socket: %m"); } } ses->init_disc = std_init_disc; ses->rcv_pado = std_rcv_pado; ses->rcv_pads = std_rcv_pads; ses->rcv_padt = std_rcv_padt; /* this should be filter overridable */ ses->retries = retry_num; return ses->fd; }
static int std_rcv_pado(struct session* ses, struct pppoe_packet *p_in, struct pppoe_packet **p_out){ struct pppoe_tag *ac_name, *srv_name; char ac[1024], srv[1024]; if(ses->state != PADO_CODE ){ poe_error(ses,"Unexpected packet: %P",p_in); return 0; } if( verify_packet(ses, p_in) < 0) return 0; if (DEB_DISC2) poe_dbglog (ses,"PADO received: %P", p_in); memcpy(&ses->remote, &p_in->addr, sizeof(struct sockaddr_ll)); memcpy(&ses->curr_pkt.addr, &ses->remote , sizeof(struct sockaddr_ll)); ses->curr_pkt.hdr->code = PADR_CODE; /* The HOST_UNIQ has been verified already... there's no "if" about this */ /* if(ses->filt->htag) */ copy_tag(&ses->curr_pkt,get_tag(p_in->hdr,PTT_HOST_UNIQ)); if (ses->filt->ntag) { ses->curr_pkt.tags[TAG_AC_NAME]=NULL; } ac_name = get_tag(p_in->hdr,PTT_AC_NAME); srv_name = get_tag(p_in->hdr,PTT_SRV_NAME); memset(ac, 0, sizeof(ac)); memset(srv, 0, sizeof(srv)); strncpy(ac, ac_name->tag_data, ntohs(ac_name->tag_len)); strncpy(srv, srv_name->tag_data, ntohs(srv_name->tag_len)); script_setenv("AC_NAME", ac, 1); script_setenv("SRV_NAME", srv, 1); if(ses->filt->stag) { ses->curr_pkt.tags[TAG_SRV_NAME]=NULL; } copy_tag(&ses->curr_pkt,get_tag(p_in->hdr,PTT_SRV_NAME)); copy_tag(&ses->curr_pkt,get_tag(p_in->hdr,PTT_AC_COOKIE)); copy_tag(&ses->curr_pkt,get_tag(p_in->hdr,PTT_RELAY_SID)); ses->state = PADS_CODE; ses->retransmits = 0; send_disc(ses, &ses->curr_pkt); (*p_out) = &ses->curr_pkt; if (DEB_DISC) poe_dbglog (ses,"Sent PADR: %P", *p_out); if (ses->np) return 1; return 0; }
/************************************************************************* * * Make a connection -- behaviour depends on callbacks specified in "ses" * *************************************************************************/ int session_connect(struct session *ses) { int pkt_size=0; int ret_pkt_size=0; struct pppoe_tag *tags = NULL; struct pppoe_packet *p_out=NULL; struct pppoe_packet rcv_packet; int ret; int i=0; #ifdef AUTODISCONN if ((redisconn) || ((!redisconn)&&(strlen(oldsession)))) { while (i++ < 2) { usleep(300000); session_disconnect_pppoe(ses); } usleep(100000); } #endif if(ses->init_disc){ ret = (*ses->init_disc)(ses, NULL, &p_out); if( ret != 0 ) return ret; } /* main discovery loop */ while(ses->retransmits < ses->retries || ses->retries==-1 ){ fd_set in; struct timeval tv; FD_ZERO(&in); FD_SET(disc_sock,&in); if(ses->retransmits>=0){ ++ses->retransmits; //tv.tv_sec = 6; tv.tv_sec = 1 << ses->retransmits; if (tv.tv_sec > 3) tv.tv_sec = 3; tv.tv_usec = 0; ret = select(disc_sock+1, &in, NULL, NULL, &tv); }else{ ret = select(disc_sock+1, &in, NULL, NULL, NULL); } if( ret == 0 ){ if( DEB_DISC ){ poe_dbglog(ses, "Re-sending ..."); } if( ses->timeout ){ ret = (*ses->timeout)(ses, NULL, &p_out); if( ret != 0 ) return ret; }else if(p_out){ send_disc(ses,p_out); } continue; } ret = recv_disc(ses, &rcv_packet); /* Should differentiate between system errors and bad packets and the like... */ if( ret < 0 && errno != EINTR){ return -1; } switch (rcv_packet.hdr->code) { case PADI_CODE: { if(ses->rcv_padi){ ret = (*ses->rcv_padi)(ses,&rcv_packet,&p_out); if( ret != 0){ return ret; } } break; } case PADO_CODE: /* wait for PADO */ { if(ses->rcv_pado){ ret = (*ses->rcv_pado)(ses,&rcv_packet,&p_out); if( ret != 0){ return ret; } } break; } case PADR_CODE: { if(ses->rcv_padr){ ret = (*ses->rcv_padr)(ses,&rcv_packet,&p_out); if( ret != 0){ return ret; } } break; } case PADS_CODE: { if(ses->rcv_pads){ ret = (*ses->rcv_pads)(ses,&rcv_packet,&p_out); memcpy(&old_ses, ses, sizeof(struct session)); if( ret != 0){ return ret; } } break; } case PADT_CODE: { if( rcv_packet.hdr->sid != ses->sp.sa_addr.pppoe.sid ){ --ses->retransmits; continue; } if(ses->rcv_padt){ ret = (*ses->rcv_padt)(ses,&rcv_packet,&p_out); if( ret != 0){ return ret; } }else{ poe_error (ses,"connection terminated"); return (-1); } break; } default: poe_error(ses,"invalid packet %P",&rcv_packet); } } return (0); }
/************************************************************************* * * Construct and send a discovery message. * ************************************************************************/ int send_disc(struct session *ses, struct pppoe_packet *p) { char buf[MAX_PAYLOAD + sizeof(struct pppoe_hdr)]; int data_len = sizeof(struct pppoe_hdr); struct pppoe_hdr *ph = NULL; struct pppoe_tag *tag = NULL; int i, error = 0; int got_host_uniq = 0; int got_srv_name = 0; int got_ac_name = 0; for (i = 0; i < MAX_TAGS; i++) { if (!p->tags[i]) continue; got_host_uniq |= (p->tags[i]->tag_type == PTT_HOST_UNIQ); /* Relay identifiers qualify as HOST_UNIQ's: we need HOST_UNIQ to uniquely identify the packet, PTT_RELAY_SID is sufficient for us for outgoing packets */ got_host_uniq |= (p->tags[i]->tag_type == PTT_RELAY_SID); got_srv_name |= (p->tags[i]->tag_type == PTT_SRV_NAME); got_ac_name |= (p->tags[i]->tag_type == PTT_AC_NAME); data_len += (ntohs(p->tags[i]->tag_len) + sizeof(struct pppoe_tag)); } ph = (struct pppoe_hdr *) buf; memcpy(ph, p->hdr, sizeof(struct pppoe_hdr)); ph->length = __constant_htons(0); /* if no HOST_UNIQ tags --- add one with process id */ if (!got_host_uniq){ data_len += (sizeof(struct pppoe_tag) + sizeof(struct session *)); tag = next_tag(ph); tag->tag_type = PTT_HOST_UNIQ; tag->tag_len = htons(sizeof(struct session *)); memcpy(tag->tag_data, &ses, sizeof(struct session *)); add_tag(ph, tag); } if( !got_srv_name ){ data_len += sizeof(struct pppoe_tag); tag = next_tag(ph); tag->tag_type = PTT_SRV_NAME; tag->tag_len = 0; add_tag(ph, tag); } if(!got_ac_name && ph->code==PADO_CODE){ data_len += sizeof(struct pppoe_tag); tag = next_tag(ph); tag->tag_type = PTT_AC_NAME; tag->tag_len = 0; add_tag(ph, tag); } for (i = 0; i < MAX_TAGS; i++) { if (!p->tags[i]) continue; tag = next_tag(ph); memcpy(tag, p->tags[i], sizeof(struct pppoe_tag) + ntohs(p->tags[i]->tag_len)); add_tag(ph, tag); } /* Now fixup the packet struct to make sure all of its pointers are self-contained */ memcpy( p->hdr , ph, data_len ); extract_tags( p->hdr, p->tags); error = sendto(disc_sock, buf, data_len, 0, (struct sockaddr*) &p->addr, sizeof(struct sockaddr_ll)); poe_dbglog(ses,"Sent packet: %P",p); if(error < 0) // brcm // poe_error(ses,"sendto returned: %m\n"); ; return error; }
/************************************************************************* * * Make a connection -- behaviour depends on callbacks specified in "ses" * *************************************************************************/ int session_connect(struct session *ses) { struct pppoe_packet *p_out=NULL; struct pppoe_packet rcv_packet; int ret; if(ses->init_disc){ ret = (*ses->init_disc)(ses, NULL, &p_out); if( ret != 0 ) return ret; } /* main discovery loop */ while(ses->retransmits <= ses->retries || ses->retries==-1 ){ fd_set in; struct timeval tv; FD_ZERO(&in); FD_SET(disc_sock,&in); if(ses->retransmits>=0){ ++ses->retransmits; tv.tv_sec = 1 << ses->retransmits; tv.tv_usec = 0; ret = select(disc_sock+1, &in, NULL, NULL, &tv); }else{ ret = select(disc_sock+1, &in, NULL, NULL, NULL); } if( ret == 0 ){ if((DEB_DISC) && (ses->retransmits <= ses->retries) ){ poe_dbglog(ses, "Re-sending ..."); } if( ses->timeout ){ ret = (*ses->timeout)(ses, NULL, &p_out); if ( ret != 0 ) { poe_info(ses, "returning - %d", ret); return ret; } } else if (p_out) { send_disc(ses,p_out); } continue; } ret = recv_disc(ses, &rcv_packet); /* Should differentiate between system errors and bad packets and the like... */ if( ret < 0 && errno != EINTR){ poe_info(ses, "couldn't rcv packet"); return -1; } if (DEB_DISC2) syslog(LOG_ERR, "Recieved packet=%x\n", rcv_packet.hdr->code); switch (rcv_packet.hdr->code) { case PADI_CODE: { if(ses->rcv_padi){ ret = (*ses->rcv_padi)(ses,&rcv_packet,&p_out); if( ret != 0){ return ret; } } break; } case PADO_CODE: /* wait for PADO */ { if(ses->rcv_pado){ ret = (*ses->rcv_pado)(ses,&rcv_packet,&p_out); if( ret != 0){ return ret; } } break; } case PADR_CODE: { if(ses->rcv_padr){ ret = (*ses->rcv_padr)(ses,&rcv_packet,&p_out); if( ret != 0){ return ret; } } break; } case PADS_CODE: { if(ses->rcv_pads){ ret = (*ses->rcv_pads)(ses,&rcv_packet,&p_out); if( ret != 0){ return ret; } } break; } case PADT_CODE: { if( rcv_packet.hdr->sid != ses->sp.sa_addr.pppoe.sid ){ --ses->retransmits; continue; } if(ses->rcv_padt){ ret = (*ses->rcv_padt)(ses,&rcv_packet,&p_out); if( ret != 0){ return ret; } }else{ poe_error (ses,"connection terminated"); return (-1); } break; } case 0: /*receiving normal seesion frames*/ { poe_error(ses, "Already in data stream, sending PADT %P\n", &rcv_packet); if (ses->pppoe_kill) { memcpy(&ses->remote,&rcv_packet.addr, sizeof(struct sockaddr_ll)); ses->sp.sa_addr.pppoe.sid = rcv_packet.hdr->sid; session_disconnect(ses); continue; } return (-1); } default: poe_error(ses,"invalid packet %P",&rcv_packet); return (-1); } } if (ses->retransmits > ses->retries) { errno = 62; return -1; } return (0); }